spec(update): detect a clone that cannot fetch branches on the exists path - #1921
Conversation
… path clone mode の `exists` 経路は `fetch --tags` が branch も進めることを前提に していたが、`remote.origin.fetch` が `refs/heads/` を 1 本も持たない clone でも tag だけは解決するため、bootstrap は毎セッション正常完走し branch の遅れだけが 無症状で蓄積していた(実測: 374 コミット遅れが約 5 ヶ月、発見は偶発)。 検出のみを足す。修理はしない(issue の 解(a))。 - `Li+update.md` clone mode `exists` 経路に step a を追加し、既存 a-e を b-f へ繰り下げ - on-session-start hook の 3 port に verify 軸 4 を実装。 `remote.origin.fetch` が source 側を `refs/heads/` 以下に持つ refspec を 1 本も持たない場合、既存の marker reason surface へ `clone-refspec-no-branch-mapping` を積む(`sentinel-tag(...)` と同じ経路)。 clone でないディレクトリ(api mode)と `git` 不在は無言 skip - `adapter/*/CLAUDE.md` `AGENTS.md` の「`unnecessary` が何を verify 済みと言うか」 の列挙と、`docs/C.-Update.md` / `docs/6.-Adapter.md` の写しを同一 PR で更新 - `tests/test_clone_refspec_branch_check.py` = 3 port の behavioural(tag のみ / refspec 皆無 / wildcard / single-branch / clone でない / 修理しないこと)と 5 surface の parity 現行 literal は壊れていない。この state は現行の `not exists` 経路からは生まれず、 仕様の穴は「作ること」ではなく「検出しないこと」の側にある。 #1911 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Axis A — issue requirement issue #1911 の本文(purpose / premise 1-5 / constraints / Axis B — rule violation diff の追加/変更行を、 Fixed axis — impression-literal detection
flag 1件:
この2行のうち後半「 |
brake 1 round 1 の fixed axis(impression-literal detection)の指摘を受理。 `adapter/codex/hooks/on-session-start.ps1` の `-cmatch` コメント末尾 `#1804 is the same split, on another value.` を removal test にかけたところ、 除去しても rule の behavior semantic は変わらない。残る前半が要求 (ref 名は case-sensitive、bash 2 port は case-sensitive な grep)を それ自体の言葉で述べており、revision stability も変わらない。 #1911 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
brake 1 round 1 — 裁定(実装 subagent)対象 commit = Axis A — issue requirement:finding なし不一致なしの報告。裁定対象なし。 Axis B — rule violation:finding なし違反なしの報告。裁定対象なし。 Fixed axis — impression-literal detection:flag 1 件 → 受理(1/1)finding: 判定 = 受理。 removal test を
適用:当該一文を削除( Positive / Negative リストの境界上に乗る flag ではなかったため、spec-gap 観察としての routing は行っていない。 その他の追加行( |
…marker 報告先の設計変更(issue #1911 の改訂された 解 / target files)。述語と 「検出のみ、修理はしない」の立場は変わらない。 `LI_PLUS_UPDATE_STATUS` は報告面ではなく adapter startup 手順 step 2 の 起動条件であり、reason による分岐を持たない。健全性の欠陥をそこに積むと、 検出のみのはずの検査が更新手続きを起動する経路を持つ。普通の diff-only section は逆向きに外す —— body が変わらないため初回だけ出て、慢性化した 瞬間に黙る。 載せ先は section key を持たず diff-only の外に置かれる surface class (Promotion Tally Expiry Surface / Self-Evolution Observation Surface と同じ)。 - `rules/evolution/cold-start-synthesis.md` — Clone Branch Fetch Surface 節を 新設。trigger 種は 3 つ目で、既存 2 面の date-driven に対し state-driven。 借りるのは surface class の性質だけで日付の語彙は借りない。lifecycle を 持たないこと、その不在が欠落ではないこと(足すと条件消失後も残るエントリを 生む)を明記。Hook Emission Contract の coordination 一覧と marker 抑止条件も更新 - hook 3 port — 軸 4 を撤去し、tally surface の隣で emit する block を追加。 no-new-material marker の抑止条件に加算 - `Li+update.md` / `docs/C.-Update.md` — `exists` 経路 step a の報告先を差し替え - `adapter/claude/CLAUDE.md` / `adapter/codex/AGENTS.md` — `unnecessary` の 保証列挙を改訂前へ戻す(載せ先が marker でなくなったため対象外) - `docs/6.-Adapter.md` / `docs/2.-Evolution.md` — surface 一覧、marker 抑止、 diff-only 除外理由(state 駆動という別向きの非対称)を更新 - tests — surface の behavioural(3 port)に加え、marker に載っていないこと、 2 回目の startup でも黙らないこと(対照として健全 clone では marker が出ること)、 lifecycle 不在が本文に書かれていることを pin #1911 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Axis A — issue #1911 との不一致不一致 1件。 issue #1911 本文(
diff 側の述語実装は、configured refspec 全体(複数行を空白結合した文字列、または配列全要素)に対する部分文字列一致であり、
それ以外は issue 本文と一致を確認した: Axis B — rule violation違反 3件(同一パターン、3 ポートに重複)。
拘束する rule literal(この diff 自身が
上記 3 行は refspec 全体に対する部分文字列一致で判定しており、「source 側」限定を実装していない。3 ポートとも同一の近似のため、port 間 parity の欠陥ではなく、rule literal 自身に対する 3 箇所の不一致。 このほか、diff が追加・変更した行を Fixed axis — impression-literal detectionフラグ 3件(同一文型、3 ポートに重複)。
いずれも 参考: 同ファイル内の変更されていない既存コメントに同型の issue 番号引用が複数件ある( |
brake 1 round 1(再設計後の baseline)の指摘を受理。Axis A 1 件 / Axis B 3 件 (同一実体、3 port)、fixed axis 3 件。 述語が refspec 全体に対する部分文字列一致になっており、`[+]<src>:<dst>` の src 側限定を実装していなかった。`+refs/tags/v1:refs/heads/mirror` のように dst 側にしか `refs/heads/` が現れない構成は branch を 1 本も引かないのに 健全と読まれる。本 PR 自身が新設した contract literal(source side)に対する 不一致であり、3 port とも同じ近似のため port 間 parity の問題ではない。 - hook 3 port — refspec を 1 本ずつ読み、先頭 `+` を落として `:` の手前を source 側とし、`refs/heads/` 以下かを判定する。`^<pattern>` は exclusion で mapping を成立させないため除外。ps1 は Ordinal 比較(ref 名は case-sensitive) - `rules/evolution/cold-start-synthesis.md` / `docs/6.-Adapter.md` — src 側の 読み方と exclusion の扱いを本文に明記(実装と literal を一致させる) - tests — dst 側にのみ `refs/heads/` を持つ fixture と exclusion 単独の fixture を 追加し、いずれも報告されることを pin。複合 fixture もこの 2 本を含める形に更新 - hook 3 port のコメントから括弧書きの issue 番号を除去(fixed axis 3 件)。 除去しても canonical contract へのパス参照が残り behavior semantic は変わらない #1911 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
brake 1 round 1(再設計後 baseline)— 裁定(実装 subagent)対象 commit = Axis A — issue requirement:不一致 1 件 → 受理finding:述語が configured refspec 全体に対する部分文字列一致であり、issue 本文が明示する「source 側」限定になっていない( 判定 = 受理。 source を確認したところ指摘のとおりだった。 追加テストがこの差分を検出しないという指摘も、そのとおりだった。 Axis B — rule violation:3 件(同一実体、3 port)→ 受理finding:本 PR 自身が新設した 判定 = 受理。 Axis A と同一の実体であり、拘束する literal がこの diff 自身の新設分であるという読みも source と一致する。3 port が同じ近似であるため port 間 parity の欠陥ではなく、rule literal に対する 3 箇所の不一致という切り分けもそのとおり。 適用(Axis A / B)
Fixed axis — impression-literal detection:3 件(同一文型、3 port)→ 受理finding: 判定 = 受理。 removal test を
適用:3 port の当該箇所から括弧書きを除去( 評価者が付記した「同ファイル内の未変更コメントに同型の先例が多数ある」という参考情報は、判定に用いていない(skill が count を判定材料にしないと定める)。同時に、それらは本 round の findings ではないため掃き出しも行っていない。 Positive / Negative リストの境界上に乗る flag は無かったため、spec-gap 観察としての routing は行っていない。 ローカル: |
Axis A — issue #1911 との不一致不一致なし。 SHA Axis B — rule violation違反なし。 diff の追加/変更行を、 Fixed axis — impression-literal detectionフラグなし。 スコープ対象 5 ファイル( |
smileygames
left a comment
There was a problem hiding this comment.
self-review(parent、Claude Lay)
受け入れ基準
issue #1911 の purpose は「bootstrap が clone の branch fetch 能力を一度も確かめない」ことの解消。7ac43c9 の diff は Li+update.md clone mode exists 経路に検査を置き、3 port が実際に emit する形まで通っている。constraints を個別に確認した。
- 現行 literal を「壊れている」と書かない:
not exists経路の 2 コマンド literal は未変更 exists経路のみが対象: そのとおり- 検出のみ、修理しない: 3 port とも config を書き換えない。テストがそれを pin している
- 報告先は
LI_PLUS_UPDATE_STATUSではない: 新規変数がUPDATE_REASONSに合流していないことを round 2 の Axis B が source で確認済み。parent 側でも diff を読んで同じ結論 - state-driven / lifecycle 不在の明記:
rules/evolution/cold-start-synthesis.mdの新節に、trigger 種が 3 つ目であること、verdict_state/expiresを持たないこと、その不在が設計であることが入っている
scope 逸脱
無し。ただし裁定側が finding の射程を 1 箇所広げており、それを自己申告している(exclusion refspec ^<pattern> の除外)。parent 判断 = 妥当。 ^refs/heads/main は「source 側が refs/heads/ 以下」を字面では満たしながら mapping を成立させないので、finding が名指した false-healthy と同じクラスに入る。加えて、実装だけを広げず contract 本文の側にも書いている点を評価する —— rules/model/liplus-coding-rule.md Body States Behavior が本文に behavior を置くことを求めており、実装が literal を追い越す形を作っていない。
brake 1
この PR は brake を 2 度走らせている。1 度目は差し替え前の設計に対するもので、往復の計数を引き継いでいない。
- 改訂前(報告先 =
LI_PLUS_UPDATE_STATUSの reason): evaluator round 1 / round trip 1。finding 1 件(固定軸、ps1 の provenance 一文)、採用 - 改訂: parent が issue 本文の決定節を差し替え、通常の委譲として実装変更を投げた(brake の relay ではない)
- 改訂後(報告先 = cold-start の state-driven surface): evaluator rounds 2 / round trips 1 / N=1 各 round。finding 7 件(Axis A 1 / Axis B 3 / 固定軸 3)、全件採用、却下ゼロ。round 2 は 3 軸すべて指摘なしで clean exit
計数を 1 から数え直したのは規定の適用ではなく parent の判断である。 cap の literal(at most three evaluator rounds and three author responses)は baseline 変更時の扱いを持たず、step 7 の Re-run は「verdict を返さなかった round の再試行」を the baseline it ran against — the PR commit SHA — is unchanged の条件で扱う。今回は verdict が返っていて baseline が動く形で、どちらの枝にも当たらない。判断の理由は、round 1 が評価したのが差し替え前の設計であり、Axis A が突き合わせた issue 本文も差し替わったこと。同じ instrument が同じものを測っていない以上、往復を引き継ぐと cap が測っていないものを数える。
却下はゼロなので、standing rejection の再裁定は無い。
手順の逸脱
無し。
- step 2 の operational copy は改訂後の 2 round とも適用した。
rules/evolution/cold-start-synthesis.mdはrules/**/*.mdであり、評価者の型による例外を持たない mandatory 側。改訂前の round では対象がadapter/claude/CLAUDE.mdで、step 2 の名指し 2 bullet には載らないが preamble の条件(注入文脈として届くか)で適用が要る側だった。どちらも適用し、各 round の post 後・resume 前に step 5 で restore、sha256 一致を確認(607a2d35.../a9f7b067...) - **適用の仕方に 1 つ判断がある。**ワークスペースの
.claude/はbuild-2026-09-07.4の中身で main より 1 行古く、PR の diff は main に対するものなので base が食い違う。**diff を当てるのではなく、PR の SHA におけるファイル本体をそのまま書いた。**結果、適用中の手元は「main + draft」になる。部分適用は draft でも main でもない第三の状態を作るため、こちらを採った - step 3 の material は PR URL / SHA / green CI run URL のみ。親クローン内のパスは渡していない
- step 4 は finding のある round のみ発火。round 2 は clean のため author を resume せず step 8 で exit
rule effect measurement
unmeasured (outside the firing condition)。governed body(rules/** / skills/** / adapter/**)は rules/evolution/cold-start-synthesis.md が +31/-2、hook 3 port が計 +185/-12 で、削除が追加を上回っていない。
parent 側で記録しておくもの
テストが在ることと、その欠陥を捕まえられることは別という形が実物で出た。round 1 の Axis A / B が指した述語の誤り(refspec を src:dst に割らない)に対して、**同じ PR が追加した fixture 3 本(TAG_ONLY / WILDCARD / SINGLE_BRANCH)はいずれも refs/heads/ を destination 側に置いておらず、この欠陥を検出できなかった。**評価者がそこまで報告し、裁定側も認めている。述語を書いた側が fixture も書いたため、**盲点が両方に写っている。**修理では dst 側のみ・exclusion 単独の 2 本が追加され、どちらも旧実装に対して落ちることが確認されている。
これは #1920(tests/** の規範的散文がどの軸の射程にも入らない)とは別の軸 —— あちらは散文が読まれない話、こちらはテストの網が実装と同じ形に歪む話。1 件なので起票していない。post-merge observation に載せる。
release type と mode gate
patch。理由は observable でないことではなく、large でないこと。 壊れた clone のあるワークスペースでは起動時に 1 行増えるので、これは system observable な変化である。rules/operations/release-version-rule.md の minor は large refactor or large structural change that is user/system observable であり 両方を要する。増分は検出 1 本と surface 1 行ぶんで large に当たらないため、everything else として patch に落ちる。
execution_mode = semi_auto かつ patch のため人のレビュー gate は立たない(rules/operations/execution-mode.md Mode matrix)。self-review pass をもって direct merge に進む。
Closes #1911
clone mode の
exists経路に整合性チェックを 1 つ足し、検出のみを行う(issue の 解(a))。自動修復は採らない。remote.origin.fetchが source 側をrefs/heads/以下に持つ refspec を 1 本も持たない clone でも tag は解決するため、fetch --tagsは成功し、素のgit fetch originもエラーではなく no-op として成功する。何も落ちないまま branch の遅れだけが積み上がる(実測: 374 コミット遅れが約 5 ヶ月、発見は偶発)。報告先(2026-09-09 改訂後の 解)
LI_PLUS_UPDATE_STATUSには載せない。 同 marker は報告面ではなく adapter startup 手順 step 2 の起動条件であり、reason による分岐を持たない。健全性の欠陥をそこに積むと、検出のみのはずの検査が更新手続きを起動する経路を持つ。普通の diff-only section にも載せない。 body が変わらないため初回だけ出て、慢性化した瞬間に黙る。
載せ先は section key を持たず diff-only の外に置かれる surface class(Promotion Tally Expiry Surface / Self-Evolution Observation Surface と同じ)。ただし trigger 種は 3 つ目で、既存 2 面の date-driven に対しこの面は state-driven。借りるのは class の性質だけで、日付の語彙は借りない。
state-driven は lifecycle を持たない。 条件が成立しなくなった時点で出なくなるため
verdict_stateもexpiresも除去手順も要らない。この不在が欠落ではないことを本文に明記した —— 明記しないと次に読む人が lifecycle を足しにかかり、条件が消えたのに残るエントリという逆向きの実害が生まれる。変更点
rules/evolution/cold-start-synthesis.md— Clone Branch Fetch Surface 節を新設。Hook Emission Contract の coordination 一覧と no-new-material marker 抑止条件も更新.gitを持たないディレクトリ(api mode)とgit不在は silent skipLi+update.md/docs/C.-Update.md— clone modeexists経路に step a(検査)を追加、既存 a-e を b-f へ繰り下げ。報告先は上記 surface を指すdocs/6.-Adapter.md/docs/2.-Evolution.md— surface 一覧、marker 抑止条件、diff-only 除外理由(state 駆動という別向きの非対称)tests/test_clone_refspec_branch_check.py— 3 port の behavioural(tag のみ / refspec 皆無 / wildcard / single-branch / clone でない / 修理しないこと)、marker に載っていないこと、2 回目の startup でも黙らないこと(対照として健全 clone では marker が出ることを同じ fixture で確認)、lifecycle 不在の明記改訂前から対象外へ戻したもの:
adapter/claude/CLAUDE.md/adapter/codex/AGENTS.mdのunnecessary保証列挙。載せ先が marker でなくなったため、branch を引けるかはその保証内容ではない。impact scope
cold-start の surface 1 面(条件成立時のみ emit、健全な clone では出力ゼロ)+
Li+update.mdclone modeexists経路 + その docs 写し。LI_PLUS_UPDATE_STATUSの挙動は変更なし。判断の記録
refs/heads/以下の refspec が 1 本以上」。--single-branchの clone は branch を追えており本欠陥に当たらないため、literal 一致では毎セッション誤報するgit呼び出しを resume / clear / compact / fork で払わない)-cmatch(bash 2 port の case-sensitive な照合と揃える)release type =
patch(検出のみ。健全な clone に observable な変化なし)。Li+update.mdとrules/evolution/cold-start-synthesis.mdを含むため self-evolution PR にあたり brake 1 が発火する。ローカル:
python -m unittest discover235 tests OK(bash / pwsh / node / git すべて実在するホスト)。🤖 Generated with Claude Code