Repository navigation
Description
Machine-Readable Contract
contract_schema_version: v1
issue_kind: implementation
parent_issue: none
goal_ref: "legacy CONTRACT_REVIEW_RESULT_V1 の必須 checks を検証し、不完全な current go を stale として controlled lane から fresh snapshot へ置換可能にする"
change_kind: workflowParent Issue
なし(単独改善)
Parent Goal Ref
- Goal: impl-review-loop が schema 準拠の
CONTRACT_REVIEW_RESULT_V1 status: goだけを実装開始の根拠にする。 - Desired Destination: Issue 実装: CI_VERDICT_SUMMARY_V1 のreview event重複skipped check誤集約を防ぐ #1456 の legacy snapshot 再利用ブロッカーを、production の controlled
contract_snapshot.publish経路で解消する。
Current Validated Scope
run_contract_review_once.pyが Product Spec evaluator のproduct_spec_check/v1payload をCONTRACT_REVIEW_RESULT_V1.checks.product_spec_checkに保持する。ensure_contract_snapshot.pyの既存 go 採用判定で、現在の実装開始に必要なchecks.product_spec_checkpayload を含む必須 fields を検証する。- 必須 payload を欠く legacy go は
existing_goとして成功返却せず、同一 Issue body に対する fresh review と投稿へ進める。 - controlled
contract_snapshot.publishがこの stale 判定を含む publisher を固定 argv-list のまま呼び、fresh snapshot URL の成功 readback を返す。 - 回帰テストは producer payload、snapshot 判定、controlled publisher invocation に限定する。
Remaining Parent Gaps
なし。Issue #1456 の CI verdict 集約実装そのものは本 Issue の対象外。
Background
Issue #1456 には body hash が current の status: go snapshot があるが、旧 schema のため checks.product_spec_check を持たない。ensure_contract_snapshot.py は body hash だけでその snapshot を existing_go として再利用し、controlled executor は --mode auto --post 固定のため fresh schema 準拠 snapshot を生成できない。さらに producer は Product Spec の判定文字列だけを checks.product_spec に保持している。決定論的な required-payload freshness 判定、producer payload 保持、controlled production lane のテストを採用し、prompt 注記・手動コメント投稿・既存 snapshot の迂回再利用は採用しない。
Outcome
run_contract_review_once.py が product_spec_check/v1 payload を schema 準拠の CONTRACT_REVIEW_RESULT_V1.checks.product_spec_check に保持し、legacy go がその必須 payload を欠く場合、controlled contract_snapshot.publish がそれを stale として fresh schema 準拠 snapshot を投稿・readback できる状態。
In Scope
run_contract_review_once.pyが Product Spec evaluator のproduct_spec_check/v1payload をchecks.product_spec_checkに保持するよう拡張し、その回帰テストを追加する。ensure_contract_snapshot.pyのis_go_currentを拡張し、current body hash に加えてchecks.product_spec_checkの有効なproduct_spec_check/v1payload を既存 go 採用条件にする。- stale legacy go に対して
--mode auto --postが freshCONTRACT_REVIEW_RESULT_V1を materialize する回帰テストを追加する。 controlled_skill_mutation_exec.pyのcontract_snapshot.publishが stale legacy snapshot を更新する publisher invocation と成功結果を保持する回帰テストを追加する。
Out of Scope
- Issue 実装: CI_VERDICT_SUMMARY_V1 のreview event重複skipped check誤集約を防ぐ #1456 の
CI_VERDICT_SUMMARY_V1実装、Issue 本文、または acceptance criteria の変更 CONTRACT_REVIEW_RESULT_V1の公開 schema version・既存 field 名・GitHub comment parser の変更issue-contract-reviewの Product Spec 判定基準や Product Spec checker 自体の変更- 手動 GitHub comment 投稿、prompt workaround、controlled lane 外の
--post呼び出し
Acceptance Criteria
- AC1:
run_contract_review_once.pyはproduct_spec_check/v1の schema を持つ Product Spec evaluator payload を、判定値とともにCONTRACT_REVIEW_RESULT_V1.checks.product_spec_checkに保持する。 - AC2:
is_go_currentは currentbody_sha256でもchecks.product_spec_checkを欠く legacy go を current と認めない。 - AC3:
checks.product_spec_checkに有効なproduct_spec_check/v1payload を持つ current-body go は既存どおりexisting_goとして再利用する。 - AC4: legacy go だけがある
--mode auto --postは review result が go の場合に fresh snapshot を投稿し、source: materialized_goと非空の URL を返す。 - AC5:
contract_snapshot.publishは AC4 の stale 判定を含む publisher を固定の argv-list・shell=False・policy 束縛 artifact directory で起動し、fresh URL を成功として readback する。 - AC6: producer payload 保持、legacy stale 判定、fresh materialization、controlled publisher の対象 Python unit tests が pass する。
- AC7: required payload 欠落以外の stale body hash、blocked latest result、postcondition failure の fail-closed 挙動を変更しない。
Verification Commands
# AC1
# baseline-expect: pass
$ uv run --locked pytest .claude/skills/issue-contract-review/tests/test_run_contract_review_once.py -v
# AC2
# baseline-expect: pass
$ uv run --locked pytest .claude/skills/impl-review-loop/tests/test_ensure_contract_snapshot.py -v
# AC3
# baseline-expect: pass
$ uv run --locked pytest .claude/skills/impl-review-loop/tests/test_ensure_contract_snapshot.py -v
# AC4
# baseline-expect: pass
$ uv run --locked pytest .claude/skills/impl-review-loop/tests/test_ensure_contract_snapshot.py -v
# AC5
# baseline-expect: pass
$ uv run --locked pytest scripts/agent-guards/tests/test_controlled_issue_metadata_exec.py -v
# AC6
# baseline-expect: pass
$ uv run --locked pytest .claude/skills/issue-contract-review/tests/test_run_contract_review_once.py -v
# AC7
# baseline-expect: pass
$ uv run --locked pytest .claude/skills/impl-review-loop/tests/test_ensure_contract_snapshot.py -vAllowed Paths
.claude/skills/issue-contract-review/scripts/run_contract_review_once.py.claude/skills/issue-contract-review/tests/test_run_contract_review_once.py.claude/skills/impl-review-loop/scripts/ensure_contract_snapshot.py.claude/skills/impl-review-loop/tests/test_ensure_contract_snapshot.pyscripts/agent-guards/controlled_skill_mutation_exec.pyscripts/agent-guards/tests/test_controlled_issue_metadata_exec.py
Stop Conditions
- Allowed Paths 外の変更が必要と判明した場合
- In Scope の固定契約(キー集合・スキーマ・型定義)の変更が必要になった場合
- 新規 Issue の起票が必要と判断した場合(スコープ分割が発生する場合)
- 後続 Phase / 別スコープへの波及が判明した場合
- nested SubAgent delegation が必要になった場合
- 外部サービス利用・権限昇格・既存テスト大規模改変が必要になった場合
Required Skills
- Python / pytest
Required Design References
- docs/dev/workflow.md#Implementation issue canonical contract
- docs/dev/agent-skill-boundaries.md#contract_snapshot.publish の publisher authority 固定(AC8)
Runtime Verification Applicability
decision: not_applicable
reason: GitHub API を模倣する Python unit test で producer payload、snapshot 採用、controlled publisher の境界を検証でき、実動作検証を伴わない。Scope Delta(任意)
- 追加:
run_contract_review_once.pyと対応 unit test を Allowed Paths に加え、Product Spec evaluator のproduct_spec_check/v1payload を producer が保持する根本修正を In Scope / AC / VC に追加した。 - 維持: 既存の snapshot consumer、controlled publisher、関連回帰 test の Allowed Paths と、Product Spec 判定基準・公開 schema・手動投稿を対象外とする境界。
Delivery Rule
- 1 Issue = 1 PR
.claude/worktrees/issue-<番号>-legacy-contract-snapshot-refresh/を使用する- Draft PR で開始する
Related Work
- blocked_consumer: 実装: CI_VERDICT_SUMMARY_V1 のreview event重複skipped check誤集約を防ぐ #1456
- source_comment: 実装: CI_VERDICT_SUMMARY_V1 のreview event重複skipped check誤集約を防ぐ #1456 (comment)
Notes for Reviewer
- Anchor verification:
run_contract_review_once,ensure_contract_snapshot,is_go_current,_run_contract_snapshot_publish,TestAllChecksCalledB1,TestFreshGoSnapshots,TestContractSnapshotPublishを起票前に確認する。 - この Issue は parent を持たず、Issue 実装: CI_VERDICT_SUMMARY_V1 のreview event重複skipped check誤集約を防ぐ #1456 を dependency としては登録しない。実装: CI_VERDICT_SUMMARY_V1 のreview event重複skipped check誤集約を防ぐ #1456 は修正完了後に snapshot refresh を再実行する consumer である。
Activity
squne121 commentedon Jul 11, 2026
Contract Review Result
squne121 commentedon Jul 11, 2026
人間判断が必要です。\n\nfresh
gosnapshot(https://github.com/squne121/loop-protocol/issues/1459#issuecomment-4945216228)は投稿済みで、`issue-contract-review executeの preflight も pass しています。\n\nただし現行 publisher はchecks.product_spec_checkを出力せず、checks.product_spec: passのみを出力します。#1459 はこの修正を担当するため、impl-review-loop` の product-spec gate が Step 1 開始を fail-closed にし、bootstrap deadlock になっています。通常の Step 1 は強行しません。\n\n次のいずれかを判断してください。\n\n1. #1459 に限定して、product-spec gate の bootstrap bypass を一回だけ許可する。\n2. 先にプロトコル仕様または fixture を更新する別 Issue を承認する。\n\nyaml\nIMPL_REVIEW_LOOP_RESULT_V1:\n status: blocked\n termination_reason: human_escalation\n issue_number: 1459\n reason: bootstrap_deadlock_missing_product_spec_check\nsqune121 commentedon Jul 11, 2026
敵対的レビュー結果
判定: REQUEST CHANGES — 現在の Issue 契約では実装開始不可です。
Issue #1459 が特定した障害自体は正しいです。関連 Issue #1456 で、本文 hash は現行でも
checks.product_spec_checkを持たない旧 snapshot が再利用され、後段 gate がrefresh_contract_snapshotに戻す不整合が実際に露呈しています。#1445 / PR #1448 で追加された freshness 判定は本文 hash と VC classifications までしか見ておらず、今回の修正方向も妥当です。ただし、以下のブロッカーがあります。
P0-1. Allowed Paths のままでは fresh schema を生成できない
run_contract_review_once.pyはcheck_product_spec_contract.pyから完全なproduct_spec_jsonを受け取っていますが、返却結果にはchecks.product_spec: "pass"というスカラーだけを残し、完全な payload を破棄しています。その後の
_build_contract_review_comment()も、次の旧形式しか出力しません。checks.readinesschecks.blockerschecks.product_specchecks.vc_preflightchecks.product_spec_checkは生成されません。一方、正本の output schema は
checks.product_spec_checkを最低必須項目にしています。つまり、Issue の Allowed Paths に含まれる
ensure_contract_snapshot.pyだけでは、失われた payload を正しく復元できません。checker を再実行すれば見かけ上は生成できますが、同じ preflight を二重実行し、Issue 本文取得時点もずれるため、producer と publisher の判定が別物になります。必要な修正
Allowed Paths に少なくとも次を追加してください。
run_contract_review_once.pyが、実際に判定に使った完全な payload を例えば次の形で保持する必要があります。これは
CONTRACT_REVIEW_ONCE_RESULT_V1の additive schema change でもあるため、「schema 変更は Out of Scope」という現在の記述とも整合させる必要があります。P0-2. AC1・AC2 の「fresh」の定義が弱すぎる
Issue は「
product_spec_checkが存在すること」を中心に記述していますが、実際の payload は単なるpass値ではありません。最低でも以下を持つオブジェクトです。schemaapplicabilitydecisiontriggersconditionsblocked_reasonsbody_sha256source_provenanceさらに型、enum、evidence 構造まで検証されています。
現状の AC2 の「
checks.product_spec_checkがpass」という表現では、以下の誤実装でも AC 達成扱いになり得ます。または、
どちらも後段 evaluator では invalid です。欠落または不正 payload は
refresh_contract_snapshotに戻されます。is_go_current()の成立条件を明文化すべきです。特に nested
body_sha256の一致がないと、別バージョンの本文に対して実行された Product Spec 判定を流用できます。P0-3. AC3 は旧 schema を投稿しても合格できる
現在の AC3 は概ね以下だけを確認しています。
source: materialized_gopost_status: postedしかし、現行
_build_contract_review_comment()もこれらを返せます。投稿されたコメントが旧 schema のままでも AC3 は通ります。テストは URL や mock の返却値ではなく、実際に生成されたコメント本文を検証する必要があります。
最低限、次の一連を一つの回帰テストにしてください。
auto --postparse_contract_review_results()で parseevaluate_product_spec_check()がrouting_action: continueis_go_current()が truesource: existing_go現在の parser は
status、generated_by、generated_at、issue_urlしか基本妥当性を検査しないため、consumer 側の完全性テストが不可欠です。P1-1. controlled executor の「readback」は実装されていない
_run_contract_snapshot_publish()は子プロセス stdout を JSON parse し、だけで成功扱いにしています。投稿された GitHub comment を再取得して、marker・status・body hash・
product_spec_checkを検査していません。入力 schema では以下を要求していますが、値は validation 後に一度も使われません。
expected_latest_contract_review_statusexpected_contract_markeroperation_reasonしたがって、現行 AC4 の「readback を維持」は事実と一致しません。正しくは「readback を新規実装する」です。
GitHub の Create Comment API はレスポンスとして
id、html_url、bodyを返し、comment ID 指定の再取得 API もあります。URL文字列だけを信頼する必要はありません。([GitHub Docs]1)推奨する postcondition は次です。
また、現在返している次のフィールドは実態と異なります。
contract_snapshot.publish経路では、その marker を書いていません。削除するか、remote_postcondition_verifiedなど実態に合う名称へ変更すべきです。P1-2. POST 直前確認と POST の間に TOCTOU が残る
現在は本文とコメントを確認した後、別 API 呼び出しで comment を POST します。確認直後に Issue 本文が編集された場合、旧本文向け snapshot を投稿して
status: okを返せます。完全な原子的更新はできなくても、false success は防げます。
failed_after_mutationまたはstale_or_conflicting_snapshot「副作用が発生していない」とは主張できませんが、「fresh snapshot が確立した」という誤った成功判定は防止できます。
P1-3. 「schema 準拠」が何を意味するか未確定
正本ドキュメントは
product_spec_check以外にも、以下を最低フィールドとして挙げています。checks.next_actionnext_actionblocked_reasonswarnings現行 auto publisher はこれらも出力していません。
Issue の目的が「完全な
CONTRACT_REVIEW_RESULT_V1準拠」なら、product_spec_checkだけの修正では未完です。今回のスコープを限定するなら、Outcome を次のように狭めるべきです。
「fresh schema 準拠」という広い表現は外してください。
推奨する Issue 改訂内容
Outcome
次の三点を明示してください。
product_spec_check/v1payload を snapshot に保持する。Acceptance Criteria
追加・修正すべき AC は以下です。
applicability: applicable|not_applicableかつdecision: passの valid payload のみ再利用する。existing_goとなり、review/post がゼロ回である。latest_blockedprecedence、stale outer hash、tracked-diff postcondition を維持する。実装方式
完全な payload の YAML 埋め込みは、手書きインデントではなく
json.dumps()で JSON object として埋め込む方式が安全です。JSON は YAML 1.2 の subset なので、既存の YAML parser で構造を保持して読めます。([Python documentation]2)controlled executor の argv-list /
shell=False方針は維持してください。Python 公式も引数 sequence を推奨しており、shell を暗黙起動しない場合は shell metacharacter が shell injection として解釈されません。([Python documentation]3)最終判断
問題設定は正しいものの、現在の Issue は producer が必要データを破棄している事実を scope に取り込めていません。
Allowed Paths、schema change の扱い、validity predicate、remote readback AC を修正するまでは、実装すると「legacy snapshot を stale と判定するが、fresh snapshot は生成できない」状態になる可能性が高いです。
上記 P0 三件を Issue 契約へ反映した後であれば、実装着手可能です。
squne121 commentedon Jul 11, 2026
bootstrap bypass 承認後に scope rollup preflight を実行した結果、Issue #1447 / PR #1448 を含む構造的競合候補として
human_review_requiredに route されました。#1459 の create issue overlap preflight は
safe_new_issue (C0)でしたが、impl-review-loop 規約により scope rollup のhuman_review_requiredは実装開始前に停止します。人間による判断をお願いします。#1459 を #1447/#1448 と統合する、依存関係として扱う、または現スコープのまま続行する、のいずれかを選択してください。
squne121 commentedon Jul 11, 2026
implementation-worker の mandatory overlap preflight により、実装開始前に停止しました。
OPEN の #481 / #666 / #667 / #901 はいずれも Allowed Paths 欠落、
source_complete=false、source_saturated=trueであり、human_review_requiredです。これは #1447 / #1448 に対する keep separate 判断とは別の新規ブロッカーです。候補 Issue との重複・依存関係を人間が判断するまで実装を開始しません。
squne121 commentedon Jul 11, 2026
Refinement Loop: Human Escalation Required
The loop has terminated and requires human review. Cause: human judgment required
human_escalationhuman_judgment_requiredBlockers
squne121 commentedon Jul 11, 2026
impl-review-loop: Allowed Paths 境界ブロッカー
ユーザー承認済みの overlap bypass 後、implementation worker が根本原因を確認しました。Allowed Paths 内の snapshot 更新だけでは不十分で、producer とそのテストも変更する必要があります。
必要な変更先は、現在の Allowed Paths 外です。
.claude/skills/issue-contract-review/scripts/run_contract_review_once.py.claude/skills/issue-contract-review/tests/test_run_contract_review_once.pyStop Conditions に従い、実装開始前に停止します。上記パスを契約の Allowed Paths に追加した fresh contract snapshot が必要です。
squne121 commentedon Jul 11, 2026
squne121 commentedon Jul 11, 2026
Contract Review Result
squne121 commentedon Jul 11, 2026
Refinement Loop: Approved (Contract Review Refresh Required)
Issue #1459 の issue-refinement-loop は
approvedで終了しました。approve/ blockers: 0new_allowed_path_layerを検知したが、OWNER の ANCHOR_SCOPE_REFRAME_V1 承認コメント(https://github.com/squne121/loop-protocol/issues/1459#issuecomment-4945428425)によりexcluded_by_anchor_reframe: trueで解消ただし、直近の
CONTRACT_REVIEW_RESULT_V1(#1459 (comment), generated_at 2026-07-11T11:18:57Z, body_sha256 sha256:5f7dfb88ed6976fe542ff95bc462917fcb32f6c2891a61e216ae78c8e341623c)は現在の本文ハッシュ(sha256:826729574281cc324a3c2319e658dacf09c3b888d21c48199aab95ca12a8dd61)と一致しない stale な snapshot です。実装着手(impl-review-loop 起動)前にissue-contract-reviewを再実行して fresh go を取得してください。test: snapshot regression test を整形する (#1459)
squne121 commentedon Jul 11, 2026
impl-review-loop: 完了
fix: contract snapshot publish を再検証する (#1459)
test: contract snapshot readback を整形する (#1459)
fix: contract_snapshot.publish の legacy marker deadlock と live body 再…
squne121 commentedon Jul 12, 2026
impl-review-loop: iteration 2 完了・human判断待ち
人間レビュアーの REQUEST_CHANGES(P1 blocker 3件: legacy_refresh_duplicate_marker_deadlock / post_publish_live_body_not_revalidated / evaluator_missing_from_module_trust_chain)はすべて実diff確認済みで解消され、pr-reviewer が現在の head
6c8dcaaf52354542519f27dad09604283b8b6f18に対して APPROVE を投稿しました(blockers: []、Allowed Paths gate: ok)。ただし PR の
mergeStateStatusはUNSTABLEです。原因はdeploy-pr(non-required check、#1476 / Draft PR #1480 で別追跡中)の失敗のみで、mainの branch protection required_status_checks には含まれていないことを確認済みです。impl-review-loopの正本ポリシー(step-5-mergeability-handling.md)ではAPPROVE + merge_ready:false + merge_state_status:UNSTABLEは無条件で「人間判断」に routing され、termination_reason: approvedを自動では立てられません。pr-reviewer 自己申告のmerge_ready: trueは本ポリシーと矛盾するため採用せず、正本ルールに従ってmerge_ready: falseとして扱いました。次アクション(人間判断が必要な点)
deploy-prの non-required failure によるUNSTABLEを、この PR のマージ判断上「無視してよい」と扱うか確認してください。問題なければ人間の判断で Draft 解除・マージを進めてください(レビュー内容自体は APPROVE 済みでブロッカーなし)。fix: legacy contract snapshot を更新可能にする (#1463)
実装: contract snapshotのtrusted publisher identityとcomment ID bindingを検…