fix(adapter): scope the memory dir glob fallback to the project dir's own slug [adapter, tests, docs] - #1801
Conversation
… own slug `adapter/claude/hooks/on-session-start.sh` の 2 箇所の glob fallback (self-eval log lookup / MEMORY_DIR 解決)に scope guard を追加し、別ワークスペースの memory ディレクトリへ到達する経路を塞いだ。 背景:#1796 は 2 つのワークスペースから同時にこの越境を実測している。いずれも自分の memory ディレクトリは存在するが空で、`memory_dir_populated()` がそれを未 populated として 飛ばし、glob が第三のワークスペース(`C--Users-smile-Code`)の 5 件を promotion candidates として掴んでいた。populated 判定は slug の内側で正しい規則であって、slug 間の選択に使う 道具ではない。promotion candidates も observation surface も self-eval head も当該セッションの observe stage 入力であり、別ワークスペースの観測はこのワークスペースの観測ではない。 変更内容: - `memory_slug_encloses_project()` を追加。候補 slug が `CCD_SLUG` と一致するか、`-` 境界での 接頭辞(= `CLAUDE_PROJECT_DIR` を内包するディレクトリ)である場合のみ採用する。slug 不一致時の 救済という fallback 本来の役目は残し、横方向への到達だけを落とす。逆方向(自分より深い slug)は 必要とした観測が無いため入れていない - self-eval log の glob fallback を `head -n 1` から guard 付きの走査へ変更。MEMORY_DIR 側は 既存の while ループに guard 条件を 1 行追加した。populated 条件と scope 条件は別軸で、両方が成立 する必要がある - 空の memory ディレクトリは「観測材料が無い」と読まれ silent skip になる、という既存の振る舞いは 維持している - `tests/` に契約テストを 2 本追加:自 scope 外の slug を掴まないこと(observation surface と self_eval_head の両方で確認)、および内包 slug には従来どおり到達すること。既存の `test_claude_glob_fallback_skips_unpopulated_project_slugs` は、populated 条件だけを測るよう 両候補を scope 内の slug へ寄せた - `docs/6.-Adapter.md` の `MEMORY_DIR` 解決規則に探索範囲の項を追加 codex port(`.sh` / `.ps1` の両方)は射程外。ホスト側に per-slug memory レイアウトが存在せず workspace-local な `memory/` しか見ないため、構造的にこの欠陥に到達しない。 #1796
brake 1 — parallel subagent eval (N=3, M=all axes, P=1)対象 SHA =
所見 1 — 軸3(テストの弁別力)/ 3体中3体
3体とも、PR のテストファイルを保ったまま 理由も3体一致している。変更前のコードは scope 制限を一切持たず、populated な slug なら内包・非内包を問わず採用するため、「唯一の populated 候補が内包 slug である」fixture は旧コードでも自明に満たされる。したがって guard の有無を区別できない。 3体とも「rescue が保たれていることの非回帰チェックとしての価値」には言及しているが、本軸の literal(変更前でも通る追加テストは修正を測っていない)に照らして所見として挙げている。 同軸の他2本は clean: 所見 2 — 軸4(docs と source の対応)/ 3体中3体
本軸が比較対象として名指した面(当 PR が変更した hook source = 3体とも、軸の scope 外での確認として codex 側 2ファイルを実際に読み、命題自体は事実として正しいことを付記している( 同軸の他7命題は3体とも対応を確認:内包条件、slug 文字列・ 所見 3 — 固定軸(impression-literal 検出)/ 3体中2体
2体は removal test を当該文へ適用し、直後の文( 1体は clean と判定。追加ブロック全体を Negative の保護カテゴリ(既知の誤読を防ぐ explanatory rationale)として読み、flagged 無しで報告している。 3体とも Positive 4カテゴリ(push surplus / 結果状態の修辞的評価 / 情緒的形容 / 参照先無き借用語彙)には該当無しと報告。掃引規模は 54-55 added / 3 removed lines、対象は当 PR で 所見の無い軸
|
brake 1(N=3、単一ラウンド、対象 SHA `401b721`)の集約所見3件を突き合わせ、 3件とも採用した。#1796 所見1(軸3 テストの弁別力 / 3体中3体)— accept。 `test_claude_glob_fallback_reaches_an_enclosing_project_slug` が変更前 body でも 通ることを、当該テストのみを変更前 hook に対して実行して確認した(pass)。所見の literal は 成立する。ただし「内包 slug に到達する」ことだけを主張する fixture は、変更前コードが populated な slug をすべて採用する以上、原理的に変更前で落ちない。テスト自体は guard を exact-slug 一致へ絞りすぎる回帰を捕まえる面で load-bearing なので、削除ではなく 弁別力を持たせる方向で修正した:strictly newer な非内包 slug を同じ fixture に置き、 どちらか一方しか選択されない状況を作って「内包側が選ばれること」を assert する。 検証:変更前 hook で fail、guard を exact 一致へ絞った版でも fail、本 PR の実装で pass。 `test_claude_glob_fallback_prefers_an_enclosing_slug_over_a_newer_outsider` へ改名。 所見2(軸4 docs と source の対応 / 3体中3体)— accept(修正して採用)。 `docs/6.-Adapter.md` の codex port 記述に、本 PR が変更した claude 側 hook source の 内側で照合できる対応物が無い、という所見は成立する。ただし当該命題は issue #1796 の制約「codex port には手を入れない(parity を理由に同形の変更を 持ち込まないこと)」を運ぶ面であり、`docs/6.-Adapter.md` は両 port を扱う文書なので、 記述の置き場所自体は正しい。欠けていたのは解決可能な参照先だったため、削除ではなく 検証面の明示(codex 側2ファイルのパスと、`.claude/projects` による再実行可能な走査)を 追加した。命題自体が事実として正しいことは3体とも確認済みで、こちらでも再確認した。 所見3(固定軸 impression-literal / 3体中2体)— accept。 `skills/evolution-impression-literal-detection/SKILL.md` Aggregation は 「2 or more of N=3 flag the same literal → refine immediately」を絶対しきい値として 定めており、多数決読みではなくこのしきい値が発火する。flagged された `adapter/claude/hooks/on-session-start.sh:428-431` の4行(#1796 が何を実測したかの 経緯叙述)を削除し、規範内容を運んでいる直後の文だけを残した。removal test の結果は 2体の判定どおりで、削除後も behavior semantic は変わらない。実測記録は `docs/6.-Adapter.md` の理由項と本 commit body が保持しているため、失われていない。 Divergence handling(本軸は 2-of-3 split なので実施): - same-question check = No。flag した2体は文単位で removal test を適用し、clean と 判定した1体は追加ブロック全体を1単位として Negative の保護カテゴリ (explanatory rationale that prevents a known misinterpretation)に当てている。 同じ問いに答えていないため、所見は criteria ではなく軸の wording 側に立つ。 - why-diverged は question 1 が No のため問わない(spec の順序どおり)。 - 記録内容:固定軸の prompt literal は判定単位を「each phrase」と述べる一方、 Negative リストの protected カテゴリは explanatory rationale というブロック規模の 単位で書かれており、両者の単位が一致していない。文単位で読めば Positive の provenance-in-text tell に当たり、ブロック単位で読めば Negative の保護対象に当たる、 という今回の split はここから出ている。しきい値の発火はこの結果とは独立に成立する (spec 明記)。merge を gate するものではなく、spec-gap observation として `rules/evolution/promotion-judgment.md` の経路へ回す。tally は parent 側の memory に 属するため本 subagent は書き込まず、report で surface する。 #1796
smileygames
left a comment
There was a problem hiding this comment.
自己レビュー(親、semi_auto)
受入条件の照合 — pass。
issue #1796 の目的(glob fallback が slug 境界を越えて別ワークスペースの memory を observe stage 入力に採る経路を塞ぐ)を満たしている。制約もすべて守られている:memory_dir_populated() は未変更で populated 条件と scope 条件が別軸のまま両方成立を要求する形になっており、空の memory ディレクトリは「観測材料が無い」として silent skip する挙動が保たれ、codex port(.sh / .ps1 両方)は未変更である。fallback は撤去されておらず、内包 slug への救済は残っている。
brake 1
N=3 / M=all axes / P=1、単一ラウンド。所見は PR 上の集約コメント(#issuecomment-5395946538)。軸1・軸2 が 3/3 clean、軸3 と軸4 が 3/3 所見、固定軸が 2/3 所見。
ラウンド計上の記録。 1回目の spawn は 3体とも利用枠でターミネートし、verdict を1つも返さなかった。skills/evolution-parallel-agent-eval/SKILL.md Procedure step 7 の再実行条件を (a) 返った verdict が N>=3 の床に達していない(0件)、(b) baseline の PR commit SHA が初回と同一(401b721)の両方で満たすため、2回目は同一ラウンドの継続であり round 2 ではない。プロンプトは無変更なので verdict の retire も発生していない。cause は条件語ではない旨も同節が明示している。
著者の裁定と、親による検証
3所見とも accept、commit 9a6c060。裁定の検証は著者の報告に依らず親が独立に実施した。
- 所見1(テストの弁別力) — 著者は削除ではなく強化で応じ、同一 fixture に「より新しい scope 外 slug」を置いて排他にし、
test_claude_glob_fallback_prefers_an_enclosing_slug_over_a_newer_outsiderへ改名した。親が scratch clone で再現:PR head では3本とも pass、hook だけをorigin/mainへ差し替えると 2本が fail(当該テストは outsider を掴んで落ちる)。さらに guard を exact match へ狭めた場合も fail することを確認した。過剰削除と過剰狭窄の両方向を捕まえており、著者の三方向検証の主張は成立する。 - 所見2(docs↔source 対応) — 検証可能な referent が追加され、codex 側2ファイルのパスと再実行可能な確認手段が本文に入った。
docs/6.-Adapter.md:79を実読して確認。 - 所見3(固定軸 2/3) —
on-session-start.sh:428-431の4行が除去されていることを実読で確認(当該文字列の grep が0件)。著者は多数決ではなくskills/evolution-impression-literal-detection/SKILL.mdAggregation の絶対閾値が発火した旨を明記しており、閾値の適用先として正しい。
親が訂正すべき点は見つからなかった。訂正ラウンドは0回。却下として残った所見は無い(3件とも accept)。
実行条件のうち仕様と異なる点(記録)
Procedure step 2 の operational copy は適用していない。当 PR の対象は hook script body / docs/ / tests/ であり、いずれも subagent context へ自動注入される集合に入らない(skills/evolution-parallel-agent-eval/SKILL.md Constraint: Character_Instance non-inheritance — .claude/hooks/*.sh script bodies are readable via the Read tool but not auto-loaded)。step 2 自身の条件が成立しないため、step 5 の restore も同じ理由で不要であり実施していない。評価者は named SHA を直接読む経路で走っている。
brake 2
非該当。当 PR は layer: L1-model を宣言するファイルを1つも変更しない。変更3ファイルの frontmatter / 種別を実読して確認しており、隣接ファイルからの一般化ではない(adapter/claude/hooks/on-session-start.sh は frontmatter を持たない shell script、docs/6.-Adapter.md と tests/ は L1 ではない)。
派生した観測の行き先
著者が停止条件の報告で、固定軸の spec 内部に unit の食い違い(held prompt literal は "each phrase"、Negative 保護カテゴリは block 規模で書かれている)が在ると指摘した。2/3 の割れはここから出ている。閾値は割れとは独立に発火しているため何もゲートしていない。tally は親側にあるため親が memory/promotion_tally.md へ新規クラスタとして記録した(tally 1、Axis statement form 系とは修理面が異なるため別クラスタ)。
マージ状態
origin/main が #1799 で進んだため BEHIND になっていた。rebase + force push ではなく merge で追従させた(gh pr update-branch)。force push は rules/operations/main-agent-procedures.md Human confirmation required の人間ゲート対象であり、squash マージで消える追従に対してそのゲートを消費する理由が無い。追従後 CI 再実行 green(governance ×2 pass)、mergeStateStatus = CLEAN。
リリース種別
patch。 rules/operations/release-version-rule.md に照らし、observe stage 入力の解決範囲の修理であって user/system observable な挙動変化を伴わない。semi_auto の patch は人間ゲート無しで AI 直接マージ。L1 brake 2 override は非該当。
次段
squash マージへ進む。マージ後、memory/self-evolution-observation.md へ観測エントリを起票する。
Closes #1796
adapter/claude/hooks/on-session-start.shの 2 箇所の glob fallback(self-eval log lookup / MEMORY_DIR 解決)に scope guard を入れ、別ワークスペースの memory ディレクトリを当該セッションの observe stage 入力として採用する経路を塞いだ。採用条件は「候補 slug が
CCD_SLUGと一致するか、-境界での接頭辞(=CLAUDE_PROJECT_DIRを内包するディレクトリ)であること」。slug 不一致時の救済という fallback 本来の役目は残し、横方向への到達だけを落としている。populated 条件は撤去しておらず、scope 条件と別軸で両方が成立する必要がある。tests/に契約テストを 2 本追加(自 scope 外を掴まないこと / 内包 slug には到達すること)、docs/6.-Adapter.mdのMEMORY_DIR解決規則に探索範囲の項を追加。codex port は issue 記載のとおり射程外で、手を入れていない。影響範囲: adapter (claude hook), tests, docs