Port live-memory promotion detectors to both Codex hooks and align flat memory filename references - #1650
Conversation
#1635 が Claude ポートの promotion candidate 検出器 3 本を live な書式へ 直したが、Codex の 2 ポートは旧書式のまま残っていた。検出器 1 は `root_cause:` / `tags:` というどの spec も規定しない行構文を読み、検出器 2・3 は平置きの `feedback.md` / `project.md` を固定で走査していた。host auto-memory は 1 memory = 1 file であり両ファイルは存在しないため、Codex ホストでは 3 本とも黙って何も出さない。読み手は「noise floor を越えたもの が無い」と「検出器がファイルを見られていない」を区別できない。 `rules/evolution/evolution.md` の Pattern Detection Surfacing At Cold-start は検出対象 3 軸を定め、しきい値と具体ロジックを adapter 裁量としている。 本 issue の主眼は 3 ポート間の挙動一致なので、Claude 側の実装をそのまま 移植し、独自設計にはしていない: - 検出器 1 = `skills/evolution-self-eval/SKILL.md` Recording が規定する 「同一の観察軸が複数 entry で miss と tag されている」を読む。live log の 1 行形と箇条書き形の 2 種を併用しているため両方を読む - 検出器 2 = entry の単位をファイルそのものに変え、mtime で 7 日以内を判定 - 検出器 3 = title 由来 token と Li+ source の全語一致。同一 source file に 別々の token が THRESHOLD_N 個以上落ちた pair のみ報告し、source は リポジトリ相対パスで表示する - MEMORY_DIR の marker 集合を per-topic 接頭辞へ更新 - 一覧型 2 本に SURFACE_CAP=10 の表示上限(総件数は必ず併記) `.ps1` は awk / sed / `case` が case-sensitive であることに合わせ、対応する 比較をすべて `-cmatch` / `-ccontains` / `-cnotcontains` と ordinal comparer で 書いた(#1632 F5 と同じ規律)。`ToLowerInvariant` は awk `tolower` の代替。 検出器 3 の source 側照合は substring から全語一致へ変えており、これで `user` が `users` の内側に当たらなくなり 3 ポートの「一致」の定義が揃う。 検証: live な memory 46 ファイル + live な rules/ skills/ の複製に対して 3 ポートを走らせ、promotion candidates セクションが 3 ポートで byte 一致 することを確認した(検出器 3 の上限適用後の並びまで一致)。 テストは PromotionCandidateDetectorTest を新設し、1 つの fixture に対して 3 ポートすべてを本番形の payload で走らせて判定を突き合わせる。fixture は live と同じ per-topic 構成で書いてあるため、旧書式のままのポートは何も 出さない。修正前の状態で codex_sh / codex_ps1 の 4 件が赤くなることを確認 済み。表示ではなく判定(どの軸がしきい値を越えたか、どの entry が recent か、どの pair が隣接か、宣言された総件数)を読み出す形にしてあり、bullet 形状や見出し文言や並び順は pin していない。 Refs #1636
…layout 平置きの `feedback.md` / `project.md` を前提にした記述が rules / skills に 4 ファイル残っていた。#1635 は `adapter/*/CLAUDE.md` `AGENTS.md` の `Memory_Write_Autonomy` 行だけを直しており、同じドリフトの残りが以下: - `rules/evolution/memory-entry-format.md` Position の file set 列挙。 per-topic entry file(1 memory 1 file)と index / 運用ファイルを分けて 列挙し、実体に無かった `self-evolution-observation.md` を加えた(同 ファイルの Scope 節が既に扱っている面である) - `rules/evolution/promotion-judgment.md` Exception の override 置き場。 「`memory/feedback.md` 内の override section」は per-topic 構成では成立 しないため「tally の外の memory ファイル」へ改めた - `skills/model-agentic-search/SKILL.md` の失敗ケース記録先 - `skills/task-subagent-prompt/SKILL.md` の subagent 非継承の対象。 ここは entry 本体が継承されない点が要旨であり、index の `MEMORY.md` は `skills/evolution-parallel-agent-eval/SKILL.md` が注入対象として挙げて いるため、entry file を名指しする形に直した あわせて `docs/2.-Evolution.md` の同一文(memory-entry-format の日本語 ミラー)も直した。docs/ が正本である以上、片方だけ直すと同じドリフトを 作り直すことになる。 Refs #1636
brake 1 の指摘裁定にもとづく修正 2 件。
1. detector 3 の `$pairs` を `@{}` リテラルから Ordinal comparer 付き
Hashtable へ変更。PowerShell のハッシュテーブルリテラルは文字列キーを
case-insensitive に扱うが、bash ポートが使う awk 連想配列は
case-sensitive。このキーは entry title と source path を原文の大小文字の
まま連結しているため、リテラルのままでは bash ポートが別物として数える
ペアを併合しうる。同ファイルのコメントが「case-sensitive 扱いを網羅した」
と述べている対象から漏れていた 1 箇所。$wanted / $seen / $srcHits は
小文字化済みトークンをキーにしているため既定 comparer で等価。
2. Ordinal sort の根拠コメントを訂正。「bash ports sort bytewise」と
断定していたが、どの bash ポートも LC_ALL=C を固定していないため、
これは環境依存で成立しているだけで保証ではない。culture-aware locale
下では bash 側の順序がこちらと食い違いうる、と明記した。
ロケール固定そのもの・self-eval 軸名の正規化・inline Axis tags の
末尾テキスト混入は 3 ポート共通の既存事項につき、本 PR の port-verbatim
制約の外として別 issue へ分離する。
Refs #1636
liplus-lin-lay
left a comment
There was a problem hiding this comment.
セルフレビュー(semi_auto / patch)
CI green(80ae42c)、MERGEABLE / CLEAN。brake 1・brake 2 とも通過につき直マージする。
brake 2(L1 root-criteria 評価者)= PASS
本 PR は skills/model-agentic-search/SKILL.md を触っており、同ファイルは frontmatter に layer: L1-model を持つ。issue #1636 の「L1 には触れない」という前提のほうが誤っていた(同 issue が対象ファイルに挙げていた当のファイルが L1)。rules/evolution/initiator-autonomy.md Two-stage brake は L1 ファイル内の 1 行変更でも該当と定めているため brake 2 を適用した。
評価者判定 = PASS。旧文が存在しない memory/feedback.md を書き込み先として名指していた状態を実在の形へ揃えた修正であり、trigger 条件・閾値・手順・挙動セマンティクスのいずれも不変、という理由。
brake 1 = N=3 / 単一ラウンド / sonnet 床 / 5 軸、verdict = partial
軸 = 印象リテラル検出(固定軸)/3 ポート挙動パリティ/live 形式に対する検出正しさ/散文 5 行の意味保存/完了条件とテスト十分性。
軸 3(意味保存)と軸 4(完了条件・テスト)は 3/3 CLEAN。3 体とも独立に repo 全体を sweep し、修正漏れの flat ファイル名参照はゼロと確認。3 体とも「本テストは pre-PR の hook に対して実際に落ちる」を独立に追跡し、assert_ports_agree が codex_sh / codex_ps1 の空結果と claude_sh の非空結果の不一致で失敗することを確認している(本番ファイルを subprocess.run で直接起動する形であることも確認済み)。
採用 2 件(commit 80ae42c)
- 1/3 採用(C 単独)。detector 3 の
$pairs = @{}は PowerShell のハッシュテーブルリテラルで文字列キーが case-insensitive。キーは entry title と source path を原文の大小文字のまま連結しており、bash 側の awk 連想配列(case-sensitive)が別物として数えるペアを併合しうる。実物確認で$wanted/$seen/$srcHitsは小文字化済みトークンをキーにしていて既定 comparer で等価、$pairsだけが漏れていた。同ファイルのコメントが「case-sensitive 扱いを網羅した」と述べている網から落ちた 1 箇所。Ordinal comparer 付き Hashtable へ変更。票数でなくリテラル確認で採用。 - 2/3 採用。
.ps1の Ordinal sort 根拠コメントが「bash ports sort bytewise」を断定していたが、どの bash ポートもLC_ALL=Cを固定していない。環境依存で成立しているだけで保証ではない旨に訂正。
却下 2 件
- 3/3 一致だが却下 — 「
find -mtime -7の日単位切り捨てが.ps1の(Get-Date).AddDays(-7)と 7 日境界でずれる」。切り捨てが効くのは-mtime +n/-mtime nであり-mtime -nではfloor(x) < 7 ⟺ x < 7で恒等。実測で確認(6.99 日前 = ヒット、7.01 日前 = 非ヒット)。両実装は 7 日ちょうどの瞬間以外で一致する。3 体一致の指摘を実測で覆した事例。 - 1/3 却下 — Windows の
Get-ChildItem -Filterが case-insensitive。ファイルシステムの性質でありスクリプトが制御する面ではない(同点を「OS 性質につき欠陥に数えない」とした評価者の判断を採る)。
軸 0(固定軸)= 1/3 CONCERN、record only。指摘対象 2 文のうち SURFACE_CAP の文は変更対象外の adapter/claude/hooks/on-session-start.sh に逐語で既存であり、削除は移植元との乖離を作る。他 2 体は同じ 2 文を「閾値・実測値・named actor を伴う」として protected と判定。skills/evolution-impression-literal-detection の 2/3 refine 閾値未満につき記録のみ。
分離 4 件 → #1651。ロケール固定そのもの / self-eval 軸名の表記ゆれによる閾値埋没 / inline **Axis tags**: 末尾セグメントへの後続テキスト混入 / **Axis tags**: 書式を規定した spec の不在。いずれも 3 ポート共通の天井であり、片方だけ直すと新たな 3 ポート間食い違いを作る。本 PR の port-verbatim 制約の外。4 件目は #1632 観測エントリが「最大の残余」として既に名指ししていたもの。
逸脱記録: brake 1 第 1 ラウンドの中断と再走
評価者 3 体の初回 spawn は 3 体とも You've hit your monthly spend limit の API エラーで途中終了し、verdict がひとつも出なかった。評価者の欠陥でも対象 PR の欠陥でもなく、インフラ側の停止。
skills/evolution-parallel-agent-eval/SKILL.md Procedure step 6 は、verdict の出なかったラウンドを新ラウンドとして扱う retry path を rules/* の permission-gate 経路に限定し、「評価者のクラッシュ・不正プロンプト・タイムアウトへ一般化するな」と明示している。本件は文字通りその禁止側に該当し、再 spawn は単巡 cap のリテラルに反する。一方 brake 1 は自己進化 PR に必須で、親の N=1 自己チェックは Constraint で禁止 — 3 条件の交差で PR が規則上どこへも進めない状態になった。
この cap リテラルを今回外す判断は Master が降ろした(再走を選択)。実地データ点は #1647(本 gap の追跡 issue)へ記録済み。仕様側で retry path を開く場合、「インフラ停止は round に数えない」だけでは足りず、再走が外部資源を消費する場合の human gate を同時に定める必要がある点も併記した。
運用コピー
rules/** を触る PR につき、評価者の注入文脈が旧ルールで下書きを覆わないよう .claude/rules/ へ draft を適用して評価し、評価後に origin/main の blob から byte 単位で復元。適用前に記録した sha256 と一致を確認済み。
リリース種別 = patch
既に仕様として定まっている挙動(rules/evolution/evolution.md Pattern Detection Surfacing At Cold-start が要求する observe 段の出力契約)が Codex 2 ポートで死んでいた欠陥の修正。large refactor でも large structural change でもなく、rules/operations/release-version-rule.md の minor 条件(large かつ user/system observable)に該当しない。
スコープ超過(申告)
docs/2.-Evolution.md は #1636 の対象ファイル列挙外。rules/evolution/memory-entry-format.md Position の日本語ミラーであり同一のドリフトを持つため、rules/operations/operations.md の「Docs update must be in same PR as implementation」に従って同 PR で修正した。評価者 2 体が独立に同じ判定(正当なスコープ追加であり欠陥ではない)を出している。
Closes #1636
概要
#1635 が Claude ポートの promotion candidate 検出器 3 本を live な memory 形式へ直したあと、Codex の 2 ポート(
.sh/.ps1)が旧形式のまま残っていた残余分を閉じる。あわせて平置きfeedback.md/project.mdを前提にした記述を per-topic 構成へ揃える。変更内容
1. Codex hook の検出器 3 本を live 形式へ(
.sh/.ps1両方)Claude 側の実装をそのまま移植した。
rules/evolution/evolution.mdの Pattern Detection Surfacing At Cold-start はしきい値と具体ロジックを adapter 裁量としているが、本 issue の主眼は 3 ポート間の挙動一致なので独自設計にはしていない。root_cause:/tags:というどの spec も規定しない行構文を捨て、skills/evolution-self-eval/SKILL.mdRecording が規定する「同一の観察軸が複数 entry で miss と tag されている」を読む。live log の 1 行形と箇条書き形の 2 種を併用しているため両方を読むname:、無ければファイル名 stemTHRESHOLD_N個以上落ちた pair のみ報告し、source はリポジトリ相対パスで表示するMEMORY_DIRの marker 集合を per-topic 接頭辞(feedback*.md/project*.md/reference*.md/user*.md)へ更新SURFACE_CAP=10 の表示上限(総件数は必ず併記するので省略が隠蔽にならない).ps1は awk / sed /caseが case-sensitive であることに合わせ、対応する比較をすべて-cmatch/-ccontains/-cnotcontainsと ordinal comparer で書いた(#1632 F5 と同じ規律)。検出器 3 の source 側照合は substring から全語一致へ変えており、これでuserがusersの内側に当たらなくなり 3 ポートの「一致」の定義が揃う。2. 平置きファイル名を前提にした記述の修正
rules/evolution/memory-entry-format.md/rules/evolution/promotion-judgment.md/skills/model-agentic-search/SKILL.md/skills/task-subagent-prompt/SKILL.mdの 4 ファイル。単純置換ではなく、その文が実際に何を指しているかを読んでから直した。promotion-judgment.mdの「memory/feedback.md内の override section」は per-topic 構成では成立しないため「tally の外の memory ファイル」へ改めたtask-subagent-prompt.mdは entry 本体が subagent へ継承されない点が要旨であり、index のMEMORY.mdはskills/evolution-parallel-agent-eval/SKILL.mdが注入対象として挙げているため、entry file を名指しする形に直したmemory-entry-format.mdの file set 列挙には、同ファイルの Scope 節が既に扱っているself-evolution-observation.mdを加えたdocs/2.-Evolution.mdの同一文(memory-entry-format の日本語ミラー)も直した。docs/ が正本である以上、片方だけ直すと同じドリフトを作り直すことになる。issue の対象ファイル一覧には無いが、同根の 1 行である。3. テスト
PromotionCandidateDetectorTestを新設し、1 つの fixture に対して 3 ポートすべてを本番形の payload で走らせて判定を突き合わせる。fixture は live と同じ per-topic 構成で書いてあるため、旧書式のままのポートは何も出さない。表示ではなく判定(どの軸がしきい値を越えたか、どの entry が recent か、どの pair が隣接か、宣言された総件数)を読み出す形にしてあり、bullet 形状・見出し文言・並び順は pin していない(既存テストと同じ方針)。
検証
rules/skills/の複製に対して 3 ポートを走らせ、promotion candidates セクションが 3 ポートで byte 一致することを確認(検出器 3 の上限適用後の並びまで一致)注意: 本 PR は L1 Model Layer source に触れる
issue #1636 の制約には「L1 Model Layer には触れない。対象はいずれも L2 / L6 面」と書かれているが、同 issue の対象ファイル一覧にある
skills/model-agentic-search/SKILL.mdは frontmatter がlayer: L1-modelである。issue 本文の前提が事実と食い違っている。該当の変更は失敗ケースの記録先ファイル名を 1 行直すだけで、rule の behavior semantic には触れていない。ただし
rules/evolution/initiator-autonomy.mdTwo-stage brake の「L1 に触れる = PR diff 内の L1 ファイルに追加 / 変更 / 削除行が 1 行でもある」に該当するため、brake 2(L1 root-criteria evaluator)が brake 1 に加えて必要であり、semi_auto の patch auto-merge はこれを迂回しない。merge 前の判断は親側に委ねる。リリース種別
patch を提案する。既に spec 化されている挙動を復旧する不具合修正であり、large refactor でも large structural change でもない。