Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.ko.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions codegoose-setup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ parameters:
gpt-4o for openai, anthropic/claude-sonnet-4 for openrouter,
accounts/fireworks/models/deepseek-v4-flash-0731 for fireworks-ai)

- key: goose_verify_model
input_type: string
requirement: optional
default: ""
description: >
Optional model for the verification (reflection) pass only.
Leave empty to reuse goose_model for both passes (default).
Example for fireworks-ai:
accounts/fireworks/models/glm-5p3-flash

- key: verification_gate
input_type: select
requirement: required
Expand Down Expand Up @@ -110,6 +120,7 @@ prompt: |
- review_style: {{ review_style }}
- ci_provider: {{ ci_provider }}
- goose_model: {{ goose_model }}
- goose_verify_model: {{ goose_verify_model }} (empty = same as goose_model)
- verification_gate: {{ verification_gate }}
- verify_gate_profile: {{ verify_gate_profile }}
(Provider -> secret name: ollama_cloud=OLLAMA_CLOUD_API_KEY,
Expand Down Expand Up @@ -153,6 +164,19 @@ prompt: |
- Status (created/updated) + config file path, and that it was rendered by the
deterministic pipeline (not authored by the LLM).
- GOOSE_MODEL: {{ goose_model }} (hardcoded into the config by the renderer).
- Verification model: {{ goose_verify_model }} — the model the reflection
pass uses. GITHUB ONLY: the renderer rejects --verify-model on
gitlab/gitea/teamcity (exit 2), so if {{ ci_platform }} is not github
and the user set a value, report the constraint and RE-RUN WITHOUT the
flag instead of passing it. If the user left it empty, run the Step 2
command exactly as written (both passes then use GOOSE_MODEL; never
pass an empty --verify-model value — it would swallow the next flag).
If set AND the platform is github, ADD one line into the Step 2 command
right after --model:
--verify-model {{ goose_verify_model }} \\

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 WARNING — codegoose-setup.yaml:172 [P2] 레시피가 Step 2 명령에 --verify-model {{ goose_verify_model }}을 추가하라고 지시하는데, 이 지시가 플랫폼 구분 없이 공통으로 기술되어 있다. 그러나 scripts/render.py:219는 --verify-model을 GitHub에서만 허용하고 나머지(GitLab/Gitea/TeamCity)에서는 return 2로 실패시킨다. 따라서 해당 플랫폼을 선택하면서 검증 모델을 입력한 사용자는 레시피 지시를 그대로 따르다가 렌더 단계에서 반드시 실패한다. 실패는 명시적(소리 내며 fail)이라 조용한 오류는 아니지만, 레시피 프롬프트는 "GitHub에서만 유효"라는 비고를 추가해 비-GitHub 사용자의 동작 경로를 문서화할 필요가 있다(레시피는 렌더러 제약의 Source of Truth여야 하므로).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied — a294437: Step 4 가이드에 GITHUB ONLY 제약을 명시했습니다 — 비-github 플랫폼에서 검증 모델이 설정되면 렌더러가 exit 2로 거부함을 레시피가 먼저 알려주고, 행동 경로도 제시합니다("제약을 보고하고 플래그 없이 재실행"). 레시피가 렌더러 제약의 source of truth 역할을 하도록 정렬했습니다.

(keep the trailing \\ continuation; must be a model from the SAME
provider {{ ci_provider }} — the rewritten config keeps the review
provider).
- Provider secret that the user must add, e.g. for {{ ci_provider }} the
required repo secret name from the mapping above.
- How to trigger: open/update a pull request; CI posts the {{ review_style }}
Expand Down
4 changes: 2 additions & 2 deletions docs/launch.html

Large diffs are not rendered by default.

42 changes: 40 additions & 2 deletions scripts/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
base URL that render.py used (release-only distribution model).

Placeholders (all __UPPER__):
__PROVIDER__ __GOOSE_MODEL__ __LANGUAGE__ __API_KEY_NAME__
__PROVIDER__ __GOOSE_MODEL__ __GOOSE_VERIFY_MODEL__ __LANGUAGE__ __API_KEY_NAME__
__VERIFY_PROFILE__ __VERIFY_MODE__ (verification gate, on/shadow only)
__STYLE_ASSET__ (asset basename, e.g. instructions.graded.md; the
rendered config downloads it at CI runtime and substitutes
Expand All @@ -28,7 +28,9 @@
off the #[verify:begin]/#[verify:end] marked region is REMOVED
The reflection instructions (instructions.reflection.md asset) are
downloaded at CI runtime with the same pattern as inline_threads.py,
so a single model/provider/config serves both passes.
so a single model/provider/config serves both passes unless
--verify-model overrides __GOOSE_VERIFY_MODEL__ (the reflection
pass rewrites the config before its first goose invocation).
"""
import argparse
import os
Expand Down Expand Up @@ -191,6 +193,11 @@ def main():
ap.add_argument("platform", choices=list(SOURCES))
ap.add_argument("--provider", required=True)
ap.add_argument("--model", required=True)
ap.add_argument("--verify-model", default=None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 SUGGESTION — scripts/render.py:196 [nit] --verify-model이 GitHub 전용임을 show-help 문구에만 적고 있고, --verification off를 함께 주면 값이 조용히 무시된다. GitHub+off 조합에서도 디플래그가 무시될 수 있음을 커맨드라인 도움말에 한 줄 짚어주면 혼란을 줄일 수 있다.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied — a294437: 두 층위에서 반영했습니다. ① argparse help에 "With --verification off the value is unused" 추가, ② 렌더러가 github + --verify-model + --verification off 조합에서 WARN을 출력하도록 했습니다(fail은 아님 — 렌더 자체는 유효하고 값이 no-op 입력일 뿐). 실측: WARN 메시지 출력 + 출력물에 스위치 0건 확인.

help="model for the verification (reflection) pass; "
"defaults to --model (single-model behavior). "
"GitHub workflows only — rejected elsewhere. "
"With --verification off the value is unused")
ap.add_argument("--style", required=True, choices=["graded-review", "changes-summary"])
ap.add_argument("--language", default="Korean")
ap.add_argument("--local", action="store_true",
Expand All @@ -210,6 +217,36 @@ def main():
print(f"FAIL: unknown provider {args.provider}")
return 2

if args.verify_model and args.platform != "github":
# The __GOOSE_VERIFY_MODEL__ switch only exists in the GitHub workflow
# template; on other platforms the flag would silently no-op and the
# reflection pass would keep the review model. Fail loud instead.
print("FAIL: --verify-model is only supported on the github platform")
return 2
if args.verify_model and args.verification == "off":
# --verification off strips the whole verify region including the
# model switch, so --verify-model would be dead input. Warn (not
# fail): the render is still valid, the user just gave a no-op value.
print("WARN: --verify-model has no effect with --verification off")
Comment on lines +220 to +230

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 WARNING — scripts/render.py:220-230 [P2]: if args.verify_model and args.platform != "github" 검증은 플랫폼과 --verification off 조합만 확인하고, --verify-model 값이 --provider와 같은 provider의 모델인지는 전혀 검증하지 않는다. --verify-model 치환은 scripts/render.py:261의 args.verify_model or args.model 그대로 들어가며, 사용자가 review provider와 다른 provider의 모델을 넣으면 강제되지 않는다. 이 경우 워크플로는 핵심 binding 하나(__API_KEY_NAME__)만 env로 가진 상태에서 reflection goose run(templates/github.workflow.yml:181)이 인증 실패 → reflect-parse 실패 → 1회 재시도 → fail-open(D-2)으로 이어져, CI는 초록인 채 검증 게이트가 조용히 무력화된다. 최소한 prefix 기반 휴리스틱이라도 render 시 WARN으로 출력하거나, 모델 식별자를 'provider::model' 형태로 요구하는 검증을 추가하길 권장한다.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied — 224acdd (WARN 휴리스틱 채택): 제안대로 prefix 기반 경고를 render 시점에 추가했습니다. accounts/fireworks/models/, gpt-/o1/o3, claude- 등 알려진 provider별 prefix가 선택된 provider와 어긋나면 WARN: --verify-model looks like a <provider> model but the config keeps provider <provider>를 출력합니다. 치명적 포인트를 정확히 짚어주셨습니다 — 이 실패 체인(reflection auth fail → reflect-parse fail → retry → fail-open)은 CI가 초록인 채 게이트만 무력화되므로 render 시점 경고가 최소 비용의 가시성입니다. 카탈로그가 아니라 휴리스틱이라는 점(미지 prefix는 통과)도 코드 주석에 명시했습니다. 실측: claude 모델 + fireworks provider → WARN 출력, 동일 provider → WARN 없음.

# Cheap prefix heuristic: warn when the verify model id looks like it
# belongs to a different provider than the one configured. The rewritten
# config keeps the REVIEW provider, so a mismatched model id fails at
# runtime — and the reflection gate fails open (review still posts).
# This is a heuristic, not a catalog check: unknown prefixes pass.
if args.verify_model and args.verify_model != args.model:
_pfx = {"fireworks-ai": "accounts/fireworks/models/",
"openai": ["gpt-", "o1", "o3", "chatgpt"],
"anthropic": ["claude-"],
"openrouter": [],
"ollama_cloud": []}
_own = _pfx.get(provider, [])
_own_list = _own if isinstance(_own, list) else [_own]
if _own_list and not any(args.verify_model.startswith(p) for p in _own_list):
_foreign = [name for name, pfx in _pfx.items()
if name != provider and any(args.verify_model.startswith(p) for p in (pfx if isinstance(pfx, list) else [pfx]))]
Comment on lines +236 to +246

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 WARNING — scripts/render.py:236-246 [P2] 확인/검증 모델의 프로바이더 경계 강제가 휴리스틱 경고뿐인데, 생성된 워크플로는 GOOSE_PROVIDER를 리뷰 프로바이더로 유지한다(templates/github.workflow.yml:64). 서로 다른 프로바이더의 verify model을 넘기면 런타임 인증 실패가 발생하고, 코드 주석이 스스로 밝히듯 reflection 게이트는 fail-open(리뷰는 그대로 게시)이라 "검증 없이 게시"되는 결과를 낳는다. 콘솔 경고만 의존하기보다 주요 프로바이더는 불일치를 하드 에러로 처리하거나, 적어도 워크플로 렌더 결과에 리스크를 명시하는 방안 검토를 권한다.

if _foreign:
print(f"WARN: --verify-model looks like a {_foreign[0]} model but the config keeps provider {provider} — the reflection pass will fail auth if the provider does not serve it")

spec = SOURCES[args.platform]
if args.local:
# Development mode: render straight from the working-tree templates
Expand Down Expand Up @@ -239,6 +276,7 @@ def main():
("__RECIPES_BASE__", release_base()),
("__PROVIDER__", provider),
("__GOOSE_MODEL__", args.model),
("__GOOSE_VERIFY_MODEL__", args.verify_model or args.model),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 WARNING — scripts/render.py:247 [P2]: --verify-model로 치환되는 __GOOSE_VERIFY_MODEL__을 실제로 소비하는 템플릿은 templates/github.workflow.yml(templates/github.workflow.yml:163-167의 GOOSE_MODEL: __GOOSE_VERIFY_MODEL__ heredoc)가 유일하다. templates/gitlab.ci.yml, templates/gitea.workflow.yml, templates/teamcity.settings.kts는 모두 reflection 패스가 여전히 __GOOSE_MODEL__ 기반 config를 그대로 사용하므로, GitLab/Gitea/TeamCity로 렌더링할 때 사용자가 --verify-model과 recipe의 goose_verify_model을 지정해도 검증 패스는 리뷰 모델로 계속 실행된다. 사용자에게 어떤 피드백도 없이(오류도, 로그도) 조용히 무시되는 것이므로 이 PR의 핵심 기능이 4개 플랫폼 중 3곳에서 무력화된다. 나머지 플랫폼 템플릿에도 동일한 config 재작성 블록을 넣거나, 지원하지 않는 플랫폼에서는 --verify-model을 명시적으로 거부(에러)하도록 해야 한다.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied — 4538348 (guard 방식 채택, 템플릿 포팅은 보류):

  • 사실 확인: 정확합니다. grep -c GOOSE_VERIFY_MODEL로 재검증한 결과 gitlab.ci.yml / gitea.workflow.yml / teamcity.settings.kts는 모두 0건이고, 세 템플릿의 reflection 패스(gitlab L109, gitea L151, teamcity L120)는 리뷰 모델 config를 그대로 사용합니다. --verify-model이 조용히 무시되는 상태였습니다.
  • 채택한 수정: render.py가 --verify-model을 github 외 플랫폼에서 exit 2로 명시적 거부하도록 했습니다 (실패 시 FAIL: --verify-model is only supported on the github platform). 조용한 무효화보다 요청 시점에 실패하는 것이 계약적으로 정확합니다.
  • 보류한 부분(템플릿 3종 포팅): reflection config 재작성 블록은 플랫폼별로 들여쓰기/스텝 구조(main.yml은 10-space verify-region 마커 규칙, TeamCity는 Kotlin DSL 문자열)가 달라, 검증 없이 동일 PR에 패치하면 설치 4천 곳의 CI가 깨질 수 있습니다. 별도 이슈로 추적하고 이 PR은 fail-loud로 마무리합니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 SUGGESTION — scripts/render.py:255 [P3] args.verify_model or args.model을 그대로 치환할 뿐, 검증 모델이 리뷰 프로바이더와 다른 프로바이더의 모델인지는 검증하지 않는다. 재작성된 config의 GOOSE_PROVIDER: __PROVIDER__는 리뷰 프로바이더로 고정되므로, 다른 공급자의 모델을 지정하면 런타임에 프로바이더/모델 불일치로 실패한다. 사용자 오류 범위라 차단 수준은 아니지만 옵션 도움말/레시피에 "동일 provider 내 모델만 지정"을 명시하면 좋겠다.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied — a294437 (문서화): 재작성된 config가 리뷰 provider를 유지하므로 "동일 provider의 모델만 지정" 요건을 레시피 Step 4 가이드에 명시했습니다. 프로바이더 간 모델 검증은 렌더러가 모델 카탈로그를 갖고 있지 않아 정적 검증이 불가능하므로, 사용자 오류 시 런타임 실패 + 문서화로 대응하는 게 적절하다고 판단했습니다.

("__API_KEY_NAME__", API_KEY_NAMES[provider]),
("__VERIFY_PROFILE__", args.verify_profile),
("__VERIFY_MODE__", verify_mode),
Expand Down
9 changes: 9 additions & 0 deletions templates/github.workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ jobs:
python3 verify_findings.py hunks --diff pr.diff --findings findings.json --out hunks.txt
cat hunks.txt
} >> reflection_input.txt
# Verify-model switch (render.py --verify-model): swap ONLY the
# GOOSE_MODEL line for the reflection + retry invocations. Runs
# only here — findings exist. (A head-move after this point is
# tolerated: the post step's live guard skips a stale review.)
# When --verify-model is unset the substituted value equals the
# review model and this sed is a value no-op. sed (not a full
# rewrite) so keys added to Configure goose by future releases
# survive into the reflection pass.
sed -i.bak 's|^GOOSE_MODEL: .*|GOOSE_MODEL: __GOOSE_VERIFY_MODEL__|' ~/.config/goose/config.yaml && rm -f ~/.config/goose/config.yaml.bak

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 WARNING — templates/github.workflow.yml:180 [P2] sed 's|^GOOSE_MODEL: .*|GOOSE_MODEL: __GOOSE_VERIFY_MODEL__|'은 매칭 라인이 없어도 exit 0으로 성공한다(무소음 no-op). 현재 Configure goose 스텝(templates/github.workflow.yml:63-66)이 정확히 GOOSE_MODEL: <model> 형식으로 쓰고 있어 동작하지만, 향후 해당 키 포맷이 변경되면(예: GOOSE_MODEL= 또는 들여쓰기 추가) 사용자가 명시한 --verify-model이 아무 신호 없이 무시되고 reflection 패스가 리뷰 모델로 실행된다. 이 저장소의 "fail loud / silent error 금지" 원칙에 비춰, 재작성 전후 값을 비교하거나 grep -q '^GOOSE_MODEL:' && sed ... 형태로 매칭 실패 시 명시 실패하도록 가드를 추가하는 것을 권장한다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 SUGGESTION — templates/github.workflow.yml:180 [P3] 런타임 사이드이펙트로 공용 ~/.config/goose/config.yaml을 sed로 변경하는 방식은 이후 Configure goose의 키 추가·변경 시 취약하다. reflection 전용 goose run 호출에 모델 파라미터를 전달하는 방식(현재 파이프라인 구조상 제약이 있지만)으로 전환하거나, 아니면 values-are-preserved 순수 sed 방식이 아닌 원자적 재작성 헬퍼로 위험을 국소화하는 편이 견고하다.

goose run --instructions reflection_input.txt > reflect_raw.txt
if python3 verify_findings.py reflect-parse --raw reflect_raw.txt --out scores.json; then
python3 verify_findings.py merge --body body.md --scores scores.json \
Expand Down
Loading