Skip to content

[cli][acceptance] D4対照を回帰化し、新規inline検査の固定前受付と最終判定を整合させる #488

Description

@Kewton

問題と目標

D4限定対照のC5版では、新規inline Node検査が形成・登録を通った後、最終受入では同じ検査がweakとなり、固定した検査をアプリ編集で直せず停止する境界の不整合を確認した。

今回扱う1箇所は、検査を固定する前の受付境界。最終受入を妨げる不適合候補を、要求を保った再提案へ返し、登録の迂回でも固定しない。 既存実装を再利用し、対象baselineで不足を再現できた箇所だけを修正する。

版差・既存Issueとの関係

対象 確認できたこと 今回の位置づけ
C5 f0aceed8c44748855a543ae7a122e3ffefb43cbc 下記24ケースを実行。Admission・登録を通過後、O/V1/SWALLOWがweak 過去の限定対照の根拠
公開develop 85dd5fdd12b831deb49e7b3fe9e996c01f1fab67(2026-09-17確認) Admission::formverifier_formation::require_formedを呼ぶ。pure import・package-script形成処理あり。登録関数には下記WIPのverify_evidence呼出しはない 静的確認のみ。通常planner全体で同じ受付漏れがあるとは未確定
ローカルdevelop HEAD e99f1ebe1e777fb792a9343407736ca754e41bdf+既存WIP verify_evidenceが最終分類器を使い、通常lint・登録でweak-inlineを拒否する。source_verifier_admissionと関連テストも存在。C5のadmission.rsfixed_verifier_routing.rsはこの作業ツリーにはない HEAD単体・公開developとは別物。動的な充足確認は未実施

D4で確認した範囲

C-2保存由来のcommand/pageと新しい限定契約を使い、形成→登録→固定→分類・受入→固定検査専用の停止判断を実関数で接続した。12条件×2回=24ケースの主判定は一致した。形成・登録は全24件で通過した。

条件 実command 分類・静的受入 固定検査専用の停止返値 診断用combined結果
正規表現+throw(O) 正常成功/文字欠落失敗 weak・拒否 正常はfixed_verifier_requires_new_plan、欠落は専用停止なし 両方失敗
正規表現+assert(V1) 正常成功/文字欠落失敗 weak・拒否 Oと同じ 両方失敗
includes+assert(V2) 正常成功/文字欠落失敗 Test・静的証拠pass 両方専用停止なし 正常pass/欠落失敗
catchで失敗を握り潰す検査 正常・文字欠落とも成功 weak・拒否 両方fixed_verifier_requires_new_plan 両方失敗
O+固定後の契約byte変更 成功 weak fixed_verifier_contract_binding_changed 失敗
O+別要件不足/compile不良 成功 weakと別不良が併存 専用停止なし 失敗
V2+合成の業務負例 成功 Test・静的証拠pass 専用停止なし 独立oracle→behavior/gateで失敗

専用停止なし(assess=None)は、一般修復先や後続修復が正しいという証明ではない。

C5分類器は正規表現等を保守的に未認識とするため、実際に欠落を検出するO/V1もweakとなる。node_smoke_without_assertionという既存reasonから「assertがない」「失敗経路がない」と断定しない。

証拠の限界

  • 初期契約・Config・planは新規対照。profile reportは合成、external/combinedも診断用の接続を含む。業務負例は合成観測への独立assertであり実アプリの動作ではない。
  • 通常plannerのaugmentation/lint全体、モデル呼出し、アプリbuild、ブラウザ、実修復、Recovery全経路を通した試行ではない。過去6件の全真因やライブ成功率を確定していない。
  • 補助classification.argv24欄は別parserを使った記録不備のため不採用。実プロセスargvと、同じC5・同じcommandの検証済みclassifier parser出力を別監査で照合した。旧記録は不変。
  • 旧計測器を再利用する場合は、分類本体と同じparserに修正し、引用符・escapeを含む正常/失敗例で実Nodeのargv/stdout/stderr/exitとの一致を再資格確認する。新規記録先を使う。歴史的24ケースの再実行そのものは完了条件にしない。

対応範囲

1. 受付条件と権限

不足が再現した場合の新規ルールは、以下すべてを満たす候補に限定する。各値の取得元を実装対象baselineで明記する。

  1. 信頼済みrun設定・host planがNext.js/createを示す。
  2. current runのprovenanceで所有が確認された生成契約であり、configured契約ではない。
  3. 既存の正規化・shell/path許可検証・artifact/profile検査の後に残る、未登録の最終成功検査候補である。
  4. 正規化後のliteral inline Nodeが、アプリ内容に依存せず最終分類でweakとなる。最終分類器を共有し、独自の文字列判定を二重実装しない。
  5. 信頼済み契約の要求集合に対し、そのweakが最終受入の阻害要因となる。要求空集合の早期pass、obligation正規化、gateに無関係なweakを除く既存処理を含めて整合させる。

モデル自身のgoal・step名・再提案本文を権限根拠にしない。複合commandは既存の正規化で安全に分割できた候補ごとに確認し、分割不能や非literalを新たに許可しない。

現行WIPのweak_inline_node_checkは追加オプション・非literalも拒否し得る広い既存規則で、C5の狭いpredicateとは同一でない。本件の狭い適用条件を理由に既存の拒否・権限を緩めない。各条件を一つずつ外した対照で「新規ルール非適用」と「既存規則による拒否」を区別する。

2. 再提案と要求保持

  • 元command・正規化後command・step・拒否理由・元要求の出典を診断証拠として保存し、既存plannerの再提案経路へ返す。
  • 固定前に拒否された下書き検査は、対象・条件・期待結果・失敗検出を保持または強化する明示的な書換えを認める。元の文字列を診断証拠として残すことと、その文字列の再登録を必須にすることを混同しない。
  • その他の検査、必須出力、model/hostそれぞれの担当義務、expected result、実行順序・境界を保持する。有限fixtureと追跡する義務の対応を設計し、任意JavaScriptの同値性証明には広げない。確認できない変更は予算内で正直に拒否する。
  • verify_evidence(分類器が失敗検出を認識するか)とsource_verifier_admission(保存API名の文字確認を動作証拠に代用していないか)は独立して維持する。片方の通過で他方を免除しない。
  • 既存reason/eventの互換性を保ち、説明は「現在の分類器が失敗経路を認識できない」ことを伝える。V1にもassertがあるため、assert追加やincludes化だけで解決すると案内しない。

3. 登録の全件検証

通常のcommand登録、StepPlan登録、空の生成契約へのhandoff補充を棚卸しし、対象となる全入口を防御する。候補検証で失敗した場合、同一登録単位の契約bytes・command集合・verifier作成義務を変更せず、登録成功eventを出さない。黙った除外、部分登録、登録済みcommandの置換で通さない。これは候補検証に対する全件性であり、一般的なクラッシュ耐性の新設は対象外。

4. 試行上限・返却経路

既存3回のplanner提案試行内で、通信成功のmock応答による次の系列を確認する。

  • 不適合→要求を保持した適格修正:妥当案を受理する。
  • 不適合3回:第4提案・登録・実行へ進まず停止する。
  • 不適合→条件/出力/担当義務を欠落させた案:欠落案を採用しない。
  • last_valid_plan・setup fallbackへの遷移:すべての返却経路で受付条件と保持義務を確認し、不適合fallbackを固定しない。

実際にproviderへ渡す要求本文と返却planを捕捉し、要求保持を確認する。provider通信再試行と提案試行は別計数とし、Recovery予算への付け替え・上限増加をしない。mock確認とlive試験を明確に区別する。

実装先の確認

  • 公開develop側:src/planner/recovery_step_plan_binding/{admission,verifier_formation,formation_scope}.rssrc/planner/recovery_contract_authority.rs、同verifier_obligations.rs
  • 既存WIP側:src/planner/verify_evidence.rssrc/planner/profiles/nextjs/source_verifier_admission.rs、関連lint/driver/登録の配線とテスト。WIPを無断で上書き・混入させない。
  • 共通確認:src/minimal_loop/evidence/verify_command_classification.rsと最終受入の要求判定。C5のsrc/planner/adjudication/fixed_verifier_routing.rsは対照結果の参照先であり、現行実装先と決めつけない。

判定・診断はleaf moduleへ置き、runner/loopは最小配線。docs/dev/dev-guardrails.mdに従い、guardrail baseline、既存event schema、固定後contract/hash、歴史証拠、live .anvil/を維持する。

受入条件

  • 対象baselineと版差・既存充足範囲を記録し、実形成/登録/最終受入経路で未充足部分を再現した。全充足の場合は新機構を追加せず証拠で結論づけた。
  • O/V1/V2/SWALLOWの正確なcommand、正常・各条件欠落fixture、最小契約、段階別期待結果を追跡可能なtests/corpus/apps/ fixtureへ収録し、既存corpusとの差分を示した。旧計測器を再利用する場合は上記の再資格確認を完了した。
  • 適用対象のO/V1/SWALLOWは固定前に再提案へ返る。文字欠落fixtureの有無でsource-independent分類が変わらない。権限・要求条件を一つずつ外した対照も確認した。
  • V2はこのweak受付だけでは拒否せず、source-verifier admission等の既存gateは維持した。V2文字欠落は実command失敗として拒否した。合成業務負例は独立oracle失敗をbehavior/gateへ渡す境界で拒否し、実アプリ成功の証明とは扱わない。
  • 要求を保った下書き検査の書換えを受理し、条件・対象・出力・担当義務・expected result・順序を落とす案を拒否した。元commandと書換えの対応記録が残る。
  • 上記4つのmock提案系列で、実要求本文、返却plan、提案回数、fallback結果を確認した。3回枯渇後は登録/実行せず、通信再試行・Recovery予算とも区別した。
  • 適格+不適格候補の両順序を各登録入口で拒否し、契約bytes・command集合・作成義務の不変と登録成功eventなしを確認した。全件適格の肯定対照も通した。
  • configured/unowned/既に閉じた契約、他profile、非literal、複合command、許可されないcommand、generated hookの既存扱いを維持した。既存の広い拒否を緩和しない。
  • 別要件不足・compile不良・業務失敗を固定検査だけの不良へまとめず、identity変更の独立した拒否を維持した。対象版での等価な安全性を確認し、C5の専用routing移植を前提にしない。
  • focused tests、関連corpus、cargo fmt --all -- --checkcargo clippy --all-targets -- -D warningscargo testを確認した。

対象外・完了の意味

完了は「不適合な新規検査を固定前に返し、要求を保持した妥当案を既存予算内で採用でき、登録防御と既存gateが保たれること」。任意JavaScriptの解析、業務oracleの自動生成品質、実アプリの保存/更新成功、D1〜D7全体の解決、C5採用は別の確認事項。

ローカル証拠と再現材料

保存記録はローカル限定で、GitHub公開済みの添付ではない。

  • workspace/tmp/0915/recovery-improvement-execution-01/c5-d4-linked-controls-20260916-01/report.mdrepair-spec.mdfreeze.jsoninputs/cases.jsonreports/results.jsonreports/input-output-audit.json
  • 前提:同親のc5-independent-review-20260916-01/README.mdc5-causal-controls-runs/20260916-01/cause-report-D4.md
  • Issue案はCodex2がread-onlyでレビューし、版差、適用条件、登録の全件性、要求保持、予算/fallback、診断の責任分担、証拠範囲、再現材料の8点を反映した。動的な現行版再現確認は今後の開始条件。
O/V1/V2/SWALLOWの保存commandと最小入力仕様

以下のcommandは保存ケースからそのまま転記(表示はJSON文字列なので実行時には一度JSON decodeする)。パスは隔離fixture内。分類を通すための一般的な推奨形という意味ではない。

O

{
  "command": "node -e \"const s=require('fs').readFileSync('src/app/page.tsx','utf8'); if(!/data-anvil-action=\\\"primary\\\"/.test(s))throw new Error('missing primary'); if(!/data-anvil-action=\\\"input\\\"/.test(s))throw new Error('missing input'); if(!/data-anvil-state/.test(s))throw new Error('missing state'); if(!/JSON\\.stringify/.test(s))throw new Error('missing JSON snapshot'); console.log('ok')\"",
  "sha256": "e5c561799e5d8da640ae8d6b8420f7d8417db8d80ed72105373a6214d8eb4283"
}

V1

{
  "command": "node -e \"const assert=require('node:assert/strict');const s=require('fs').readFileSync('src/app/page.tsx','utf8'); assert(/data-anvil-action=\\\"primary\\\"/.test(s),\\\"missing primary\\\"); assert(/data-anvil-action=\\\"input\\\"/.test(s),\\\"missing input\\\"); assert(/data-anvil-state/.test(s),\\\"missing state\\\"); assert(/JSON\\\\.stringify/.test(s),\\\"missing JSON snapshot\\\"); console.log('ok')\"",
  "sha256": "21cbfbd24dd78a0050556defd4b4240c54d182fd740124acd8dd49122bb2b1db"
}

V2

{
  "command": "node -e \"const assert=require('node:assert/strict');const s=require('fs').readFileSync('src/app/page.tsx','utf8'); assert(s.includes('data-anvil-action=\\\"primary\\\"'),\\\"missing primary\\\"); assert(s.includes('data-anvil-action=\\\"input\\\"'),\\\"missing input\\\"); assert(s.includes('data-anvil-state'),\\\"missing state\\\"); assert(s.includes('JSON.stringify'),\\\"missing JSON snapshot\\\"); console.log('ok')\"",
  "sha256": "396e99a87c78d3b8a4e683dc0586cdb792aa71ca1c310798c05b7486e65596ab"
}

SWALLOW

{
  "command": "node -e \"const assert=require('node:assert/strict');const s=require('fs').readFileSync('src/app/page.tsx','utf8'); try{assert(s.includes('data-anvil-action=\\\"primary\\\"'),\\\"missing primary\\\");}catch(error){}; try{assert(s.includes('data-anvil-action=\\\"input\\\"'),\\\"missing input\\\");}catch(error){}; try{assert(s.includes('data-anvil-state'),\\\"missing state\\\");}catch(error){}; try{assert(s.includes('JSON.stringify'),\\\"missing JSON snapshot\\\");}catch(error){}; console.log('ok')\"",
  "sha256": "d1e4ef5a2270edddb5b0ec3f0a68147b38c0d1499ff7d29389eab5e256c405e8"
}

初期契約(保存対照の入力)

{
  "required_paths": [
    "README.md",
    "src/app/page.tsx"
  ],
  "protected_paths": [],
  "verify_commands": [],
  "profile": "nextjs",
  "goal": "Verify saved source markers",
  "required_capabilities": [],
  "deterministic_oracles": [],
  "required_evidence": [
    "requested_content_evidence"
  ],
  "evidence_hint_tokens": [],
  "required_obligations": [],
  "deferred_verify_requirements": [],
  "verify_repair_cap": 2
}

host planはprofile=nextjs, intent=create。Configはprofile=nextjs, completion_contract_path=Noneとし、begin_runrecord_generated_contractで当該run所有の契約を設定する。単なるJSON配置を所有権の証明にしない。提案はVerify/passの1step、instruction="Check the saved source markers."expected_paths=[]verify=[対象command]。通常plannerの統合試験では別途、model/hostのowner・出力義務を含める。

新規の最小文字検査用正常fixtureは、src/app/page.tsxに次の4行を含め、READMEも配置する(Next.jsアプリとしてのbuild fixtureではない)。

data-anvil-action="primary"
data-anvil-action="input"
data-anvil-state
JSON.stringify

各条件欠落fixtureは1行ずつ除いた4種類とし、正常以外にfile欠落も確認する。O/V1/V2は正常exit 0・各条件欠落nonzero、SWALLOWは文字欠落でもexit 0を期待する。これらの縮約fixtureは今後の回帰テスト用であり、保存された24ケースそのものの再実行結果ではない。保存対照はC-2由来のpage正常/欠落版を使用した。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions