From 5475391647a29d5fcb8eec4b416cfa14cf4d4a2c Mon Sep 17 00:00:00 2001 From: Agent Control Runner Date: Fri, 16 Oct 2026 01:54:03 +0900 Subject: [PATCH] =?UTF-8?q?P04-01:=20=E5=90=8C=E6=99=82=E7=99=BA=E7=94=9F?= =?UTF-8?q?=E3=81=AE=E6=9B=B4=E6=96=B0=E8=A6=8F=E7=B4=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../execution/p04-01/CHECKER_PROTOCOL.md | 115 ++++ .../execution/p04-01/EVIDENCE_COLLECTION.md | 233 +++++++ .../execution/p04-01/c-native-validation.json | 576 ++++++++++++++++++ .../p04-01/checker_applicability_fixtures.py | 89 +++ .../p04-01/checker_native_fixtures.py | 191 ++++++ .../p04-01/checker_negative_fixtures.py | 19 +- .../execution/p04-01/repair4-context.json | 69 +++ tools/check_p04_order_evidence.py | 477 ++++++++++++++- 8 files changed, 1752 insertions(+), 17 deletions(-) create mode 100644 docs/plans/original-completion-2026-10-02/execution/p04-01/EVIDENCE_COLLECTION.md create mode 100644 docs/plans/original-completion-2026-10-02/execution/p04-01/c-native-validation.json create mode 100644 docs/plans/original-completion-2026-10-02/execution/p04-01/checker_applicability_fixtures.py create mode 100644 docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py create mode 100644 docs/plans/original-completion-2026-10-02/execution/p04-01/repair4-context.json diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/CHECKER_PROTOCOL.md b/docs/plans/original-completion-2026-10-02/execution/p04-01/CHECKER_PROTOCOL.md index 91c6259..b756cbe 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p04-01/CHECKER_PROTOCOL.md +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/CHECKER_PROTOCOL.md @@ -1,5 +1,120 @@ # 初期監査の検証器 +## repair6 現在値(2026-10-16) + +旧値: C全体は `native ordering bytes` によりblocked、実applicabilityは拒否、 +whole native未確認。以下の「今回のPython確認と入力不整合」は旧bundleの履歴。 +新値: 補正済み `build_dir/audit-support/native-first-current/` に対し +verify_native、ownership/save/ledger個別検査、applicabilityが成功した。 +checker_native_fixtures.py、checker_negative_fixtures.py、 +checker_applicability_fixtures.py --native-bundle は各1回実行しexit 0。 +旧23負例と新2負例(signature行だけのSHA、後続コメントを除いたSHA)を全て拒否。 +既存fixture14件も拒否、A/Bの登録版・production版・行移動正対照成功、3負例拒否。 +正規bundleを合成補正せず検査し、結果・旧値・新版SHAはc-native-validation.jsonに保存。 +全文rawの `old == new` および +`sha256(new[function]) == production_body_sha256 == registered_body_sha256` が必須。 +whole gateは未実行。原15条件+EV、7領域、安全性3結果、30/88の分母、予算、 +repair上限は変更せず、formal_original_credit=0。正式受入はRunner・独立レビュー・ +オーナー判断待ち。以下の旧blocked記述を現在のC検査結果として扱わない。 + +## C段階追補(本節がrepair4以前の状態説明に優先) + +`verify_native(base)` は供給済み `native-first-current` 形式の有限adapter。 +Rootのprobe/Reader/wrapperは起動・再実装しない。A/B、verify、coverage、 +boundary_conditions、15条件、reachable EV、7領域、3安全性結果は維持する。 +既存scalar検査は宣言の整合性検査として残すが、これだけでは成功しない。 + +whole gateのindexには追加で `native_bundle` が必要。 +`manifest` は evidence directory相対の `OWNERSHIP_RAW_PROVENANCE.json`、 +`sha256` はその実SHA。manifestの親をbundle rootとして以下を照合する。 +絶対パス・親参照・symlinkは既存safe規則で拒否する。 +native production_commitはtested HEADと一致させる。別版資料をA/Bの一致だけで +流用しない。今回のproduction版とworker checkoutは区別したまま保持する。 + +1. SOURCE_MANIFESTの76 fileとOWNERSHIP_RAW_PROVENANCEの96 fileは、 + 各bytesとSHAを実体から再計算する。由来のsource絶対パスは開かない。 + 3 runのimport/parse/repro、formalのwriter/reader、合計10プロセスは + started→process→endedのPID、owner、argv、時刻順、実終了codeを照合する。 + execution・phase receipt・actual phase・cleanupのPID集合と埋込記録も一致必須。 + stdout/stderr/native logのSHA、通常終了、cleanupのwait結果とerrors空を要求する。 + Writer/Readerは別PID・別profileで、profile receipt・環境・5 slotのパスも結合する。 +2. production_commitは3結果資料とapplicabilityで一致し、specの6登録pinと + production Git blobから計算した6 current pinを区別する。各runのsource_beforeと + selected_source_mapにも結合する。20関数は既存A/Bと同じ全文raw比較を行う。 + 後続トップレベルdoc commentを含む抽出全文rawのSHAだけを許可する。 + signature行のみ、コメント除外prefix等の候補は許可しない。 +3. `observations.json` の5点と対応 `midnight-*.json` を結合する。 + receiptはtransaction IDを一意にし、row重複を拒否し、順序・多重度を保持した + 台帳差分との完全一致を要求する。Readerの生receipt、first/replayも同じ行に結合する。 + SERVICE_SALEにservice_idを要求しない。after snapshotの + `/systems/runtime/economy/idempotency` の `service.payment.` から + transaction_idを得て、sale・guest wallet・facility revenue・cash sweepを結合する。 + 固定のPID・価格・transaction番号を使わない。元価格と時間はproduction Gitの + facility .tres、run inputのpin、初期facility/service/requestと照合する。 + PAUSEDはstateに加え `interruption_reason=RELATED_FACILITY_INACTIVE` を要求し、 + 進捗・service ID・予約IDを保持、売上0、財布差分0を再計算する。 + request存在系列、予約requester/facility/ACTIVE→CONSUMED、復帰1回課金を照合する。 + 最後のGuest despawn時は残存台帳から財布を再計算し、Guest辞書の存在を偽定しない。 + maintenanceは同一transaction・施設・金額のaccrual/paymentを対にする。 + 発生1439と支払い1440は同分扱いせず、観測したmidnightとその直前として照合する。 +4. 正式保存は5点×4member×writer/reader=40実ファイルを照合する。 + execution.formal_before/afterの20 member map一致と実SHA/bytes一致を要求する。 + typed 14件はwriter-persisted 5、reader-loaded 5、reader-replayed 4(before以外)。 + 原order-evidence .varおよびrun固定input pinと実SHAを照合する。 + .var decodeは行わず、値の判定はnative JSON receipt/stateを根拠とする。 + +このadapterが返す条件はdependency_stop/recovery_completion/paused_midnightの +有限系列だけ。正式保存member同一性は、全save_restore条件達成を意味しない。 +whole gateは固定15条件+EVとこの結果の差集合を未収集としてfailする。 +非ゼロ給与×シフト交代×00:00、command再送、停電→閉店同Tick、退出/予約解放、 +破壊、EV等をscalar=trueで埋めることはできない。原条件の加点は常に0。 + +### 今回のPython確認と入力不整合 + +供給rawのownership/save/ledger個別検査は成功。applicability資料は +`native ordering bytes` で拒否する。4関数のbody SHAが複数行シグネチャの +途中までしか含まないためで、詳細はEVIDENCE_COLLECTION.mdに記録した。 +実raw全体を合格とは報告しない。 + +checker_native_fixtures.pyはallowed_paths内の一時コピーで23負例を検査する。 +通常の負例ではmanifest SHAも再計算し、hashだけを理由とする失敗を避ける。 +1byte改竄、member欠落、PID/profile同一化、ended異常、cleanup欠落、 +receipt二重化/削除、PAUSED売上、予約孤立、財布差分、idempotency誤結合、 +commit/pin不一致、typed/member変更、scalar自己申告を全て拒否する。 +PAUSED売上と予約孤立にはJSON側も同時変更する対抗例を含む。 +一時コピーのapplicabilityのみGit全文hashへ差し替えた合成正対照はあるが、 +これを正規native証拠として保存・採用しない。 + +旧synthetic_controlはnative rawを持たないため現在はexit 1が正しい。 +既存13負例も維持し、全14件を拒否。A/Bの正対照と3負例も維持する。 +本番の未収集indexに対する重複validateは行わない。 + +## repair4差分(未完成・blocked) + +今回のA/B実装では、以下の旧説明の「6不変pin=実checkout」および +reachabilityのstart/end/text形式を置き換えた。詳細と未供給入力は +`EVIDENCE_COLLECTION.md` を参照。Cのowned_outer/raw台帳結合とD/Eの残項目が +未完成のため、このcheckerを正式受入には使用しない。 + +- `registered_pins` はspec.current_source_pinsと一致し、登録Git blob SHAをcheckerが再計算する。 +- `versions` はexecution_origin(9767b0aの完全SHA)、registered(deb1bcbの完全SHA)、 + tested(HEAD)、integration(null)の4キー。candidate_commitもHEADを維持。 +- `applicability_delta` は登録版..HEADのautoload/scriptsのGD変更関数の + path/function配列。checkerの計算順と完全一致。`delta_cases` は + `path:function` → 条件ID → engine case ID。条件集合はchecker内固定の保守的判定。 +- 全autoload/scripts GDがsource_map必須で、実checkoutとHEADのraw一致も必須。 +- reachability.source_refsはpath/sha256/function/anchor_sha256/line_count。 + 絶対行位置は使用せず、関数内のraw本文アンカーを一意に解決する。 +- 20順序関数は固定抽出規則で登録Git blobとtestedをraw比較する。 + +Python確認結果: 既存合成正対照1件exit 0、負例13件exit 1。 +別のA/B対照は登録=testedと実production Git blobの合法delta(25変更単位)の +2件成功、両版で+7行のアンカー解決成功、delta欠落/境界case欠落/版誤表示の +3負例を拒否した。全てengine証拠ではなくPython検証のみ。 +owned/count/restore/別候補receipt流用の新負例は未実装であり、上記に含めない。 + +以下はrepair3時点の記録。置換対象以外もC修正完了の証明として扱わない。 + `python3 tools/check_p04_order_evidence.py --verify-only` は環境変数 `BUILD_OUTPUT_DIR` の `p04-evidence/index.json` を読み、書込み・試験・Runner操作をしない。欠落時は非0。原30/88の受入・完了を確定しない。 D05-P04-DEPENDENCYとD05-P04-SHIFT-1800は承認済み。固定必須条件と証拠が揃えばmachine_verified=true、formal_acceptance=false、exit 0。残るD05の帰属pendingを一括failにしない。必須authority pending・証拠欠落は非0。独立レビュー・通常統合までは正式受入0。 diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/EVIDENCE_COLLECTION.md b/docs/plans/original-completion-2026-10-02/execution/p04-01/EVIDENCE_COLLECTION.md new file mode 100644 index 0000000..012029c --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/EVIDENCE_COLLECTION.md @@ -0,0 +1,233 @@ +# P04-01: C段階の結合とrepair4収集契約の履歴 + +## repair6 現在値(2026-10-16、以下の旧blocked記述に優先) + +旧値: 実applicabilityは `native ordering bytes` で拒否、C全体blocked、 +whole native未確認。新値: 補正済みbundleのverify_native成功、 +ownership/save/ledger個別検査とapplicability成功。供給bundleへの書込みは0。 +全文rawの登録版/production一致と両body SHAの全文SHA一致だけを認める。 +後続コメント除外prefixを許す暫定処理は削除した。 + +下記3本のPythonコマンドを各1回実行しexit 0を確認。 +native fixtureは既存23負例+signature行SHA/コメント除外SHAの2負例を全て拒否。 +合成補正コピーは廃止し、補正済み供給rawをそのまま正対照に使用。 +既存fixture14件拒否、A/Bの登録版・production版・行移動正対照成功、3負例拒否、 +native applicability成功。実行結果、旧検査値、新旧bundle pin、検査コードSHAは +c-native-validation.jsonに記録。verify_nativeは有限C検査でありwhole gateは未実行。 +原未達の条件、formal_original_credit=0、15条件+EV/7領域/安全性3結果、 +30/88の分母、予算、repair上限を維持する。Root追加paid/再送は今回の範囲外。 +engine、全回帰、製品、Runner、config、DB、git書込み、他agentは全て0。 +正式検証・独立レビュー・オーナー判断待ち。以下の「今回」は旧検査履歴を指す。 + +## C段階の追補対象 + +供給rawの現在位置は `build_dir/audit-support/native-first-current/`。 +所有権、台帳・service・予約、正式保存の結合を追加する対象であり、 +この資料の存在だけでは原受入を満たさない。formal_original_creditは0を維持する。 + +## 今回のC実装と入力blocker + +変更はchecker、Python fixtureと本ディレクトリ内のdocsだけ。 +Root helperはコピー・再実装せず、既存native成果物を読む。 +結合の正確な規則はCHECKER_PROTOCOL.mdのC追補を参照。 +新規engine/全回帰/Runner操作/git書込み/他agent起動は全て0。 +旧39rawを読了・採用した数も0。repair4-context.jsonの旧履歴は保持した。 + +供給rawでは次の個別Python検査が成功した。 + +- OWNERSHIP_RAW_PROVENANCEの96 fileのbytes/SHAと10プロセスのlifecycle/cleanup。 +- Writer/Readerの5点×4member、元20member不変、typed .var 14件の実SHA結合。 +- 生receipt 8行、service.paymentのidempotency経由での1回課金、財布差分、 + PAUSED時の進捗・予約保持、復帰後の消費、維持費発生1439→支払い1440。 + +ただし `POST_P18_CURRENT_SOURCE_APPLICABILITY.json` の4関数の +registered_body_sha256/production_body_sha256は本文を含まない。 +実Git blobで検算すると、以下の関数先頭からのprefix SHAに一致した。 + +| path | function | hash対象のbyte数(本文を含まない) | +|---|---|---:| +| autoload/simulation_runtime.gd | _complete_service_transaction | 140 | +| scripts/facility/facility_service.gd | _prepare_service_for_tick | 87 | +| scripts/facility/facility_service.gd | _complete_service | 113 | +| scripts/facility/facility_service.gd | _fail_service | 119 | + +4つとも複数行引数の後の `) -> ...` より前で終わる。全文比較は別途成立するが、 +報告されたbody hashとの一致は成立しないため、実bundleは +`native ordering bytes` でfailする。workerはこの供給資料もmanifestも変更していない。 +Root側で同じproduction Git blobの全文を対象にapplicabilityとそのmanifestを +再生成する必要がある。engineの再起動を必要とする不整合ではない。 +旧暫定処理では後続トップレベルdoc commentの有無だけの2関数差をraw prefix一致 +として扱っていた。repair6で撤去し、現在は全文SHA一致のみ必須とする。 + +この入力不整合が残るため、C段階の実raw全体の成功は未確認(blocked)。 +これは原P04-01未達とは別のblockerであり、修正済みの合成コピーで全C検査が +通ることを原証拠の合格へ換算しない。 + +## 有限の検証 + +実行したのは次のPython確認のみ。全て一時ファイルをallowed_paths内へ限定し削除する。 + +```sh +python3 -B docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py /Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build/audit-support/native-first-current +python3 -B docs/plans/original-completion-2026-10-02/execution/p04-01/checker_negative_fixtures.py +python3 -B docs/plans/original-completion-2026-10-02/execution/p04-01/checker_applicability_fixtures.py --native-bundle /Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build/audit-support/native-first-current +``` + +Cの結果は `c-native-validation.json`。23負例を拒否し、実rawの3個別検査成功、 +実applicability拒否、修正した合成applicabilityの組合せ正対照成功を区別する。 +既存fixtureはscalarのみの旧正対照を含む14件を拒否。 +A/Bは登録版・production版の正対照と行移動の正対照、3負例、C資料の拒否を確認した。 +未収集indexに対するwhole gate/validateは再実行していない。 + +## 固定の原未達 + +非ゼロ給与のシフト交代×00:00、command再送、停電→閉店同Tick、退出/予約孤立、 +破壊、EVは未収集。正式保存のSHA同一性は全原条件のsave_restore証明とは別。 +15条件、reachable EV、7領域、安全性3結果を減らさず、未収集をfalse/pending扱いとする。 +原30/88のformal_original_credit=0、独立レビュー・通常統合未実施を維持する。 + +以下はrepair4時点の履歴であり、C追補の実装・検証状態には上記が優先する。 + +本修正は未完成であり、収集開始・machine gate・原受入の承認ではない。 +原30/88、7領域、部分点0を維持する。D05全体はpending、既存の承認2条件を +超える規則は作らない。D-034/A01の再承認は求めない。 + +## 読取確認 + +`.review-material` はこのcheckoutには存在しない。指定された実体 +`build_dir/audit-support/p04-native-existing-sources/` のwrapper 4本とGD probe +6本、および `tools/run_all_tests.py`、`tools/regression/owned_outer.py` を確認した。 +10本のraw SHA/sizeは配布SOURCE_MANIFEST.jsonと一致し、`repair4-context.json` +に保存した。外部旧worktreeのartifactパスは由来としてのみ扱った。 + +実checkout HEADは `9767b0a28ca8d252520307dbbac60a1d8cfb87ab`、Runtimeは +`d52a995ae715542bbc550f68d35889540658275d12e04ae0b21ac276f5843f39`。 +提供されたproduction資料の版は `5f6bc11d6bb6e92d22d787989b219fef3a435bc1`、 +Runtimeは `7f01b2dcdf28bc965c7588173c2dc70054633faf7204b1ac38ba0f4369331b47`。 +productionのGit objectも存在する。production資料を実checkoutのsource_mapとして +流用しない。登録版は `deb1bcb2374eb378b840ca345db952bd8572cb6e`。 + +## A/Bの変更 + +checkerはspecのcurrent_source_pinsを登録pinとして保持し、登録Git blobのSHAを +独立計算する。indexはregistered_pinsとversionsのexecution_origin/registered/ +tested/integrationを分離する。integrationは未統合のためnullのみ。 +testedのautoload/scripts全GDはcheckoutとHEAD blobの一致を必須にする。 + +20関数の抽出はchecker内固定。行頭func/static funcから次の行頭関数までの +raw bytesを比較し、コメント・空白・改行を正規化しない。先頭宣言は +`` 単位としてdiffに含める。追加・削除関数も含む。 +`git diff --no-ext-diff --no-renames --name-only -z base..HEAD -- autoload/ scripts/` +で変更GDを列挙し、Git blobから変更関数を計算する。applicability_deltaは +path/function順の配列と完全一致させる。未知の変更も無影響と推定せず、 +delta_casesに保守的な全条件被覆を要求する。境界case IDの存在は後続coverageで +検証するが、**Cの生証拠結合は未実装なので、この段階では適用可の最終判断に使えない**。 + +REACH_REFSはpath/function/anchor_sha256/line_countに変更。実tested関数内で +本文raw bytesのアンカーを一意に解決する。旧固定範囲が隣接関数へ跨がる +reserve/rescue箇所は関数単位に分割した。行位置が7行移動しても解決し、 +本文変更・欠落・重複アンカーは失敗する。 + +## 新collectorを作らず残す既存実行パターン + +Root側の既存wrapper修正で保持すべき順序は、`r.source_refs(R)` → +明示QA上書きしたrefs → `r.copy_source` によるprivate stage → bootstrap → +cacheの `cp -c` と別inode確認 → parse-paths/contracts → `execute_phase` → +finallyの `owned_outer.finish_captured` → fixed_guardと不変性確認。 +このworkerはwrapperを起動・変更していない。適用可能なパラメータ化patchと +全不足probeはまだ提出できていないため、以下は実行済みの契約ではなく残作業である。 + +- R/OUT/QA/testpath/cache/input manifestは最終tested checkoutに対して固定する。 + 1299件数や旧source-after.json一致をauthorityにしない。現r.source_refsがauthority。 +- checkout mapと、testpathにQAを明示上書きしたselected mapを別に記録する。 + source_map=tested、probeの元pathとSHA、QA_overrides、実stageの同SHAを結合する。 + 候補製品source overrideは持ち込まない。 +- source_before/after、default_player_before/after、doc4_before/after、stage inventory、 + parse-paths、contracts、wrapper raw、phase receipt、started/ended、 + outer-owned-finally、execution.jsonを保存する。booleanだけでは不変性の代用にならない。 +- case receiptはphaseのactual_pidとexecution.actual_captured_PIDs、cleanupの全PID集合に + 結合する。cleanup_errorsが空、全childのengine_ended、終了codeを実成果物間で照合する。 +- 各条件のscalarに加え、生台帳・service/settlement ID・予約配列とのcount_eqまたは + same_literalが必要。save_restoreはWriter保存直前と正式Reader復元直後の + 台帳・予約のsame_literal、および別PIDを要求する。nonceやログ文言では代用しない。 + +## 負履歴(起動禁止) + +10本すべてのSHAはrepair4-context.jsonに記録した。特に以下を再実行しない。 + +- shift-end-repro-r03.gdは1080で「課金なし・予約保持」を期待し、承認済みの + 完了段階先行と矛盾する。対応native-r03.pyには旧1299 pinもある。 +- formal-boundary-reload-native-r03.pyは旧candidate sealと製品2件overrideを使う。 + SHAを書換えて別候補receiptとして使わない。 +- formal-boundary-reload-r01.gdのmanifest.source_refs==1299も旧前提。 +- midnight native-r01とpower native-r04も固定1299と旧full-run cacheに依存する。 + power readerは旧Writerの二つの正式保存slotに依存し、fresh Writerではない。 + +## 15+EVの被覆確認(未収集) + +同一プロセス内でも条件ごとのseed、before/after、case receiptを保持する。 +以下のartifact名は既存probeが出すもの。不足欄を合格扱いにしない。 + +| 条件 | 既存probe / phase / artifact | 不足 | +|---|---|---| +| midnight_settlement, midnight_replay | midnight-boundary-r01 / repro / observations.json, midnight-*.var | countとraw台帳の結合、同minute再送の明示 | +| paused_midnight | midnight-boundary-r01は開業サービスのみ | 停止した同一serviceの日跨ぎ系列 | +| night_staff_absent | shift-end-repro-r03 / repro / 18-01観測 | 旧誤期待を除いた独立caseと非完了service | +| power_stop, recovery_completion | power-formal-recovery-r04 / reader-a,b / recovery-*.var | fresh停止入力、台帳JSON、旧Writer依存の解消 | +| dependency_stop | 供給6 probe内に専用系列なし | 関連施設停止・進捗/予約/service ID保持 | +| exit_release | exit-boundary-r01 / repro / queued-*.var, observations.json | raw stateとcount結合 | +| patience_release, closure_release | 供給6 probe内に専用系列なし | 待機解放、開始済み継続を区別したcase | +| same_minute_replay | exit/destruction/midnightはsnapshot巻戻し再実行 | 同minuteコマンド再送の独立条件 | +| shift_completion | shift-end-repro-r03 / repro / 18-00各phase観測 | 誤期待の修正、課金1回のraw結合 | +| overtime_task | 供給6 probe内に専用系列なし | interrupt_level=0残業・勤務記録1回 | +| destruction_stop | destruction-completion-boundary-r02 / repro / unfinished-*.var | raw台帳結合。completeは別帰結として維持 | +| save_restore | formal-boundary-reload-r01 / writer,reader / *.var, writer.json, reader.json | final版の入力seal、JSON台帳/予約、owned PID結合 | +| EV | 供給6 probe内に専用系列なし | staff予約→EV移動→停止→到着の実状態 | + +transportはreach=falseのソース根拠のみで、別engine条件は追加しない。 + +## 再利用の有限条件と未供給資料 + +input.jsonのevidence_refsは旧証拠の参照であり、生証拠そのものではない。 +今回の供給先で確認できたのはsource、監査、適用性診断とgate失敗ログである。 +旧39件のraw receipt/state/packageを照合して採用した件数は0。 +「20関数一致」だけで39件を採用することは禁止する。 + +必要な追加のローカルraw資料: + +1. 旧39件のexecution/phase/started/ended/outer-owned-finally/log/state一式と + 元source/config/input/environment pin。既存input.jsonのreference SHAで照合する。 +2. formal-boundary-reload-input-r02.json + (wrapper記録SHA `195cb767e597008d1767aa0b6c8300711b83e8cf101863166e7932d9bd4ed612`) + と、そのwhole_typed_inputs、元exact_execution、保存package全4メンバー。 +3. power original writer.json + (wrapper記録SHA `cf3850c262012e5e52743bfb8b41af7ef5608689fb10c059c8a494216b0aff52`) + と参照slot。旧candidateは比較用負履歴に限定する。 + +原則は最終の正確な版で再実行する。登録版証拠を再利用する有限条件は、A(i)の +20関数raw一致、A(ii)の全delta一致、A(iii)の変更境界をtested engine caseで被覆し、 +さらに当該旧caseのsource/config/input/environmentとraw状態を独立照合できること。 +relationship restore/schema変更は正式Writer/Reader再実行、build/path/arrivalに +関係する変更は当該経路に到達するcaseの再実行が必要。今回の資料だけでは再利用0。 + +## Rootのコマンドと残る作業 + +現在実行できるのは次のPython確認のみ(engineプロセス0)。 + +```sh +python3 docs/plans/original-completion-2026-10-02/execution/p04-01/checker_applicability_fixtures.py +python3 docs/plans/original-completion-2026-10-02/execution/p04-01/checker_negative_fixtures.py +BUILD_OUTPUT_DIR=/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build python3 tools/check_p04_order_evidence.py --verify-only +``` + +最後のコマンドはindex未収集ならexit 1が期待値。Python正対照はengine証明ではない。 +**Cのchecker強化、Dのparameter patch/不足probe、Eのowned/count/restore/他候補流用負例は未完成。** +旧checkerのscalar/receipt自己申告を受入可能な証拠とみなしてはならない。 +現在のcheckerを正式受入に使用せず、修正全体をblockedとしてRootへ返す。 + +native収集の正確なコマンド列は、上記入力と未完成patchがないため提示できない。 +仮のコマンドを実行可能と偽って提示しない。共有stageでimport+parseを2プロセス、 +midnight/power/exit/shift/destruction/save Writer/save Reader/EVを8プロセスに +束ねられれば計10プロセスが計画目安になるが、これは確定数・目標数ではない。 +条件ごとに必要な状態系列とguard成立を優先する。 +Rootのnative収集→validate→別セッション独立レビュー→通常統合は未実施。 diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/c-native-validation.json b/docs/plans/original-completion-2026-10-02/execution/p04-01/c-native-validation.json new file mode 100644 index 0000000..47c7854 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/c-native-validation.json @@ -0,0 +1,576 @@ +{ + "scope": "C Python controls on supplied raw; no formal acceptance", + "formal_original_credit": 0, + "engine_runs": 0, + "results": [ + { + "control": "native_ownership_supplied_raw", + "result": "pass" + }, + { + "control": "native_saves_supplied_raw", + "result": "pass" + }, + { + "control": "native_ledger_supplied_raw", + "result": "pass" + }, + { + "control": "supplied_applicability", + "result": "pass" + }, + { + "control": "verify_native_supplied_raw", + "result": "pass", + "details": { + "service_id": "service_00000001", + "transaction_id": "ledger_00000081", + "receipt_rows": 8, + "formal_original_credit": 0, + "production_commit": "5f6bc11d6bb6e92d22d787989b219fef3a435bc1", + "owned_processes": 10, + "verified_conditions": [ + "dependency_stop", + "recovery_completion", + "paused_midnight" + ] + } + }, + { + "control": "signature_line_sha", + "result": "rejected", + "error": "native ordering bytes", + "manifest_hashes_refreshed": true + }, + { + "control": "trailing_comment_excluded_sha", + "result": "rejected", + "error": "native ordering bytes", + "manifest_hashes_refreshed": true + }, + { + "control": "one_byte_raw", + "result": "rejected", + "error": "native SHA: actual-native/repro/stdout.log", + "manifest_hashes_refreshed": false + }, + { + "control": "missing_member", + "result": "rejected", + "error": "missing/outside file: dependency-formal-native/formal-packages/reader/paused/world.bin", + "manifest_hashes_refreshed": true + }, + { + "control": "writer_reader_same_pid", + "result": "rejected", + "error": "native writer reader PID binding", + "manifest_hashes_refreshed": true + }, + { + "control": "writer_reader_same_profile", + "result": "rejected", + "error": "native writer reader profile reused", + "manifest_hashes_refreshed": true + }, + { + "control": "abnormal_ended", + "result": "rejected", + "error": "native process bindings", + "manifest_hashes_refreshed": true + }, + { + "control": "process_pid_changed", + "result": "rejected", + "error": "native PID chain", + "manifest_hashes_refreshed": true + }, + { + "control": "cleanup_missing", + "result": "rejected", + "error": "native owned cleanup binding", + "manifest_hashes_refreshed": true + }, + { + "control": "execution_owned_pid_deleted", + "result": "rejected", + "error": "native execution cleanup membership", + "manifest_hashes_refreshed": true + }, + { + "control": "reader_receipt_row_duplicated", + "result": "rejected", + "error": "native duplicate receipt row", + "manifest_hashes_refreshed": true + }, + { + "control": "reader_receipt_row_deleted", + "result": "rejected", + "error": "native reader receipt delta", + "manifest_hashes_refreshed": true + }, + { + "control": "observation_receipt_deleted", + "result": "rejected", + "error": "native ledger receipt delta", + "manifest_hashes_refreshed": true + }, + { + "control": "paused_sale_injected", + "result": "rejected", + "error": "native ledger receipt delta", + "manifest_hashes_refreshed": true + }, + { + "control": "paused_sale_joined_ledger_wallet", + "result": "rejected", + "error": "native PAUSED sale/progress/reason", + "manifest_hashes_refreshed": true + }, + { + "control": "reservation_orphaned", + "result": "rejected", + "error": "native reservation snapshot binding", + "manifest_hashes_refreshed": true + }, + { + "control": "reservation_orphaned_both_snapshots", + "result": "rejected", + "error": "native orphan reservation relation", + "manifest_hashes_refreshed": true + }, + { + "control": "wallet_wrong", + "result": "rejected", + "error": "native wallet delta", + "manifest_hashes_refreshed": true + }, + { + "control": "idempotency_wrong_transaction", + "result": "rejected", + "error": "native sale service join", + "manifest_hashes_refreshed": true + }, + { + "control": "production_commit_mismatch", + "result": "rejected", + "error": "native production commit mismatch", + "manifest_hashes_refreshed": true + }, + { + "control": "current_source_pin_mismatch", + "result": "rejected", + "error": "native current_source_pins mismatch", + "manifest_hashes_refreshed": true + }, + { + "control": "input_source_pin_mismatch", + "result": "rejected", + "error": "native input source pin mismatch", + "manifest_hashes_refreshed": true + }, + { + "control": "original_member_changed", + "result": "rejected", + "error": "native original members changed", + "manifest_hashes_refreshed": true + }, + { + "control": "typed_var_changed", + "result": "rejected", + "error": "native typed SHA mismatch", + "manifest_hashes_refreshed": true + }, + { + "control": "self_reported_scalar_true", + "result": "rejected", + "error": "native reader receipt delta", + "manifest_hashes_refreshed": true + } + ], + "previous_validation": { + "scope": "C Python controls only; synthetic corrected applicability is not native proof", + "formal_original_credit": 0, + "engine_runs": 0, + "results": [ + { + "control": "native_ownership_supplied_raw", + "result": "pass" + }, + { + "control": "native_saves_supplied_raw", + "result": "pass" + }, + { + "control": "native_ledger_supplied_raw", + "result": "pass" + }, + { + "control": "supplied_applicability", + "result": "rejected", + "error": "native ordering bytes" + }, + { + "control": "synthetic_corrected_applicability_composition", + "result": "pass", + "native_acceptance": false + }, + { + "control": "one_byte_raw", + "result": "rejected", + "error": "native SHA: actual-native/repro/stdout.log", + "manifest_hashes_refreshed": false + }, + { + "control": "missing_member", + "result": "rejected", + "error": "missing/outside file: dependency-formal-native/formal-packages/reader/paused/world.bin", + "manifest_hashes_refreshed": true + }, + { + "control": "writer_reader_same_pid", + "result": "rejected", + "error": "native writer reader PID binding", + "manifest_hashes_refreshed": true + }, + { + "control": "writer_reader_same_profile", + "result": "rejected", + "error": "native writer reader profile reused", + "manifest_hashes_refreshed": true + }, + { + "control": "abnormal_ended", + "result": "rejected", + "error": "native process bindings", + "manifest_hashes_refreshed": true + }, + { + "control": "process_pid_changed", + "result": "rejected", + "error": "native PID chain", + "manifest_hashes_refreshed": true + }, + { + "control": "cleanup_missing", + "result": "rejected", + "error": "native owned cleanup binding", + "manifest_hashes_refreshed": true + }, + { + "control": "execution_owned_pid_deleted", + "result": "rejected", + "error": "native execution cleanup membership", + "manifest_hashes_refreshed": true + }, + { + "control": "reader_receipt_row_duplicated", + "result": "rejected", + "error": "native duplicate receipt row", + "manifest_hashes_refreshed": true + }, + { + "control": "reader_receipt_row_deleted", + "result": "rejected", + "error": "native reader receipt delta", + "manifest_hashes_refreshed": true + }, + { + "control": "observation_receipt_deleted", + "result": "rejected", + "error": "native ledger receipt delta", + "manifest_hashes_refreshed": true + }, + { + "control": "paused_sale_injected", + "result": "rejected", + "error": "native ledger receipt delta", + "manifest_hashes_refreshed": true + }, + { + "control": "paused_sale_joined_ledger_wallet", + "result": "rejected", + "error": "native PAUSED sale/progress/reason", + "manifest_hashes_refreshed": true + }, + { + "control": "reservation_orphaned", + "result": "rejected", + "error": "native reservation snapshot binding", + "manifest_hashes_refreshed": true + }, + { + "control": "reservation_orphaned_both_snapshots", + "result": "rejected", + "error": "native orphan reservation relation", + "manifest_hashes_refreshed": true + }, + { + "control": "wallet_wrong", + "result": "rejected", + "error": "native wallet delta", + "manifest_hashes_refreshed": true + }, + { + "control": "idempotency_wrong_transaction", + "result": "rejected", + "error": "native sale service join", + "manifest_hashes_refreshed": true + }, + { + "control": "production_commit_mismatch", + "result": "rejected", + "error": "native production commit mismatch", + "manifest_hashes_refreshed": true + }, + { + "control": "current_source_pin_mismatch", + "result": "rejected", + "error": "native current_source_pins mismatch", + "manifest_hashes_refreshed": true + }, + { + "control": "input_source_pin_mismatch", + "result": "rejected", + "error": "native input source pin mismatch", + "manifest_hashes_refreshed": true + }, + { + "control": "original_member_changed", + "result": "rejected", + "error": "native original members changed", + "manifest_hashes_refreshed": true + }, + { + "control": "typed_var_changed", + "result": "rejected", + "error": "native typed SHA mismatch", + "manifest_hashes_refreshed": true + }, + { + "control": "self_reported_scalar_true", + "result": "rejected", + "error": "native reader receipt delta", + "manifest_hashes_refreshed": true + } + ], + "validated_source_sha256": { + "tools/check_p04_order_evidence.py": "98b2692c604055d7b970e6ef9e3ad1795f35823c3c19d1acad5b80ad2ec7a378", + "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py": "26bbdcee483816b8bc60c250bbc63bf0a72a194dce2ba9b690abace9b6b17bbc" + }, + "supplied_bundle_pins": { + "SOURCE_MANIFEST.json": "381b439fb1d4ee5f30e21243b03ad755c3ab654a9e414af5648004054d67b5f4", + "OWNERSHIP_RAW_PROVENANCE.json": "51d746879b4197445a09cd44a88dd918c365fa98025d9cd652a740cee09a9040", + "POST_P18_CURRENT_SOURCE_APPLICABILITY.json": "ecb92215b7bfb4368ddeb6d44dcd467d13e97d677ca2f29df3ab9684f6c757c7" + }, + "whole_native_status": "blocked: supplied applicability body hashes exclude four function bodies", + "whole_gate_executed": false + }, + "whole_native_status": "pass: corrected supplied bundle; strict full raw SHA", + "whole_gate_executed": false, + "validation_invocations": { + "native": 1, + "existing_fixtures": 1, + "applicability_ab": 1 + }, + "existing_fixtures": { + "scope": "A/B and optional C applicability controls; no native acceptance", + "results": [ + { + "control": "registered_equals_tested", + "revision": "deb1bcb2374eb378b840ca345db952bd8572cb6e", + "changed_units": 0, + "result": "pass" + }, + { + "control": "line_shift_resolves", + "revision": "deb1bcb2374eb378b840ca345db952bd8572cb6e", + "result": "pass" + }, + { + "control": "legal_delta", + "revision": "5f6bc11d6bb6e92d22d787989b219fef3a435bc1", + "changed_units": 25, + "result": "pass" + }, + { + "control": "line_shift_resolves", + "revision": "5f6bc11d6bb6e92d22d787989b219fef3a435bc1", + "result": "pass" + }, + { + "control": "undeclared_delta", + "result": "rejected", + "error": "git diff/applicability_delta mismatch" + }, + { + "control": "missing_boundary_case", + "result": "rejected", + "error": "boundary delta coverage: autoload/simulation_runtime.gd:_build_facility_precheck" + }, + { + "control": "wrong_tested_revision", + "result": "rejected", + "error": "version roles" + }, + { + "control": "native_applicability", + "result": "pass" + } + ] + }, + "applicability_ab": { + "scope": "Synthetic checker checks only; no engine evidence or formal acceptance", + "py_compile": true, + "results": [ + { + "fixture": "synthetic_scalar_only_rejected", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "native bundle required; self-reported scalar evidence is insufficient" + } + }, + { + "fixture": "forged_registered_pin", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "registered pin declaration" + } + }, + { + "fixture": "false_delta", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "git diff/applicability_delta mismatch" + } + }, + { + "fixture": "wrong_reach_anchor", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "unknown reachability anchor" + } + }, + { + "fixture": "missing_index", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "missing/outside file: index.json" + } + }, + { + "fixture": "duplicate_key", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "duplicate JSON key: schema_version" + } + }, + { + "fixture": "symlink", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "symlink: stdout.json" + } + }, + { + "fixture": "hash_mismatch", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "artifact hash: stdout" + } + }, + { + "fixture": "stale_pin", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "stale pin: autoload/simulation_runtime.gd" + } + }, + { + "fixture": "unexecuted_receipt", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "unexecuted/incomplete receipt" + } + }, + { + "fixture": "pending_authority", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "pending/missing authority" + } + }, + { + "fixture": "missing_condition", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "mandatory conditions missing/unknown" + } + }, + { + "fixture": "unsupported_reach_false", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "unsupported reach=false: transport" + } + }, + { + "fixture": "owner_hash_mismatch", + "exit_code": 1, + "result": { + "task_id": "P04-01", + "machine_verified": false, + "formal_acceptance": false, + "error": "owner approval hash mismatch" + } + } + ] + }, + "validated_source_sha256": { + "tools/check_p04_order_evidence.py": "afe8c7cc3d3b511bacdaa1965fb06a0eefd1b204b7e9b930eb29767c4d320824", + "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py": "634b5e3a3491cdcdab549ed5d812935f73c2958d8cca008ce35c80b6ebb298e4" + }, + "supplied_bundle_pins": { + "SOURCE_MANIFEST.json": "dbaab3c293c191eb5f3aff34854945e2d564f824df50a92802b3a7eda55321a8", + "OWNERSHIP_RAW_PROVENANCE.json": "51d746879b4197445a09cd44a88dd918c365fa98025d9cd652a740cee09a9040", + "POST_P18_CURRENT_SOURCE_APPLICABILITY.json": "46e0cc35cb95496d5f26d3cab7d3a31cb29faacaa16714daab3aefdf65b420a3" + } +} diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_applicability_fixtures.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_applicability_fixtures.py new file mode 100644 index 0000000..5953c0a --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_applicability_fixtures.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +"""Python-only A/B controls. Real Git blobs, synthetic case IDs; no engine proof.""" +import copy +import argparse +import importlib.util +import json +from pathlib import Path +import subprocess +import sys +import tempfile + +sys.dont_write_bytecode = True +ROOT = Path(__file__).resolve().parents[5] +spec = importlib.util.spec_from_file_location('p04_gate', ROOT / 'tools/check_p04_order_evidence.py') +gate = importlib.util.module_from_spec(spec) +spec.loader.exec_module(gate) +PRODUCTION = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1' + + +def run(native_bundle=None): + results = [] + registered_spec = gate.load(gate.SPEC) + # Bind Git reads to the actual repository while testing exported raw blobs. + # No branch/index/checkout operation and no synthetic Git command output. + gate.git_bytes = lambda *args: subprocess.check_output(['git', *args], cwd=ROOT) + with tempfile.TemporaryDirectory(prefix='.applicability-fixtures-', dir=Path(__file__).parent) as tmp: + for revision in (gate.REGISTERED_COMMIT, PRODUCTION): + base = Path(tmp) / revision + source = {} + for name in gate.git_bytes('ls-tree', '-r', '--name-only', '-z', revision, + '--', 'autoload/', 'scripts/').split(b'\0'): + if not name.endswith(b'.gd'): + continue + path = name.decode() + target = base / path + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(gate.git_bytes('show', revision + ':' + path)) + source[path] = gate.sha(target) + gate.ROOT = base + delta = gate.source_delta(gate.REGISTERED_COMMIT, revision) + index = dict(registered_pins=registered_spec['current_source_pins'], + versions=dict(execution_origin=gate.EXECUTION_ORIGIN, registered=gate.REGISTERED_COMMIT, + tested=revision, integration=None), applicability_delta=delta, + conditions={cid: {'case_id': cid} for cid in gate.REQUIRED}, + reachability={'EV': {'case_id': 'EV'}}, delta_cases={}) + index['delta_cases'] = {r['path'] + ':' + r['function']: { + cid: cid for cid in gate.boundary_conditions(r['path'], r['function'])} for r in delta} + gate.applicability(index, registered_spec, source, revision) + results.append(dict(control='registered_equals_tested' if not delta else 'legal_delta', + revision=revision, changed_units=len(delta), result='pass')) + for name, refs in gate.REACH_REFS.items(): + for path, function, digest, lines in refs: + data = (base / path).read_bytes() + gate.resolve_anchor(data, function, digest, lines) + # Seven lines added before the function must not break reachability. + gate.resolve_anchor(b'\n' * 7 + data, function, digest, lines) + results.append(dict(control='line_shift_resolves', revision=revision, result='pass')) + if delta: + for label, mutate in ( + ('undeclared_delta', lambda i: i['applicability_delta'].pop()), + ('missing_boundary_case', lambda i: i['delta_cases'][next(iter(i['delta_cases']))].clear()), + ('wrong_tested_revision', lambda i: i['versions'].update(tested=gate.REGISTERED_COMMIT)), + ): + altered = copy.deepcopy(index) + mutate(altered) + try: + gate.applicability(altered, registered_spec, source, revision) + except ValueError as exc: + results.append(dict(control=label, result='rejected', error=str(exc))) + else: + raise AssertionError('negative fixture accepted: ' + label) + gate.ROOT = ROOT + if native_bundle is not None: + try: + gate.native_applicability(native_bundle) + except ValueError as exc: + # A/B Git equality must not turn an inconsistent native report into + # applicable evidence. The C mutation suite tests a corrected copy. + assert str(exc) == 'native ordering bytes', str(exc) + results.append(dict(control='native_report_body_hash_gap', result='rejected', error=str(exc))) + else: + results.append(dict(control='native_applicability', result='pass')) + return {'scope': 'A/B and optional C applicability controls; no native acceptance', 'results': results} + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--native-bundle', type=Path) + print(json.dumps(run(parser.parse_args().native_bundle), ensure_ascii=False, indent=2)) diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py new file mode 100644 index 0000000..f9b97af --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +"""C component controls and raw mutations. No engine, Runner or acceptance.""" +import argparse +import copy +import hashlib +import importlib.util +import json +import re +from pathlib import Path +import shutil +import sys +import tempfile + +sys.dont_write_bytecode = True +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[4] +spec = importlib.util.spec_from_file_location('p04_native_gate', ROOT / 'tools/check_p04_order_evidence.py') +gate = importlib.util.module_from_spec(spec) +spec.loader.exec_module(gate) + + +def run(source): + results = [] + for function in (gate.native_ownership, gate.native_saves, gate.native_ledger): + function(source) + results.append({'control': function.__name__ + '_supplied_raw', 'result': 'pass'}) + gate.native_applicability(source) + results.append({'control': 'supplied_applicability', 'result': 'pass'}) + native = gate.verify_native(source) + results.append({'control': 'verify_native_supplied_raw', 'result': 'pass', 'details': native}) + with tempfile.TemporaryDirectory(prefix='.native-fixtures-', dir=HERE) as tmp: + base = Path(tmp) / 'raw' + shutil.copytree(source, base) + app_path = 'POST_P18_CURRENT_SOURCE_APPLICABILITY.json' + originals = {p.relative_to(base).as_posix(): p.read_bytes() for p in base.rglob('*') if p.is_file()} + changed = set() + + def edit(name, mutation): + path = base / name + value = gate.load(path) + mutation(value) + path.write_text(json.dumps(value)) + changed.add(name) + + def refresh(): + for manifest, key, field in (('OWNERSHIP_RAW_PROVENANCE.json', 'copied', 'target'), + ('SOURCE_MANIFEST.json', 'files', 'copy')): + def update(value): + for row in value[key]: + path = base / row[field] + if path.is_file(): + row.update(bytes=path.stat().st_size, sha256=gate.sha(path)) + edit(manifest, update) + + def check(name, function, mutation, error, rehash=True): + for path in changed: + (base / path).write_bytes(originals[path]) + changed.clear() + mutation() + if rehash: + refresh() + try: + function(base) + except (ValueError, KeyError, TypeError) as exc: + assert error in str(exc), (name, str(exc)) + results.append({'control': name, 'result': 'rejected', 'error': str(exc), + 'manifest_hashes_refreshed': rehash}) + else: + raise AssertionError('negative fixture accepted: ' + name) + + def truncated_hash(kind): + def mutate(app): + for row in app['ordering_functions']: + body = gate.function_bytes(gate.git_bytes( + 'show', app['production_commit'] + ':' + row['path']))[row['function']] + if kind == 'signature': + if row['function'] != '_complete_service_transaction': + continue + truncated = body.splitlines(keepends=True)[0] + else: + offsets = [m.start() for m in re.finditer(rb'(?m)^#', body)] + offsets = [i for i in offsets if all( + not line.strip() or line.startswith(b'#') for line in body[i:].splitlines())] + if not offsets: + continue + truncated = body[:offsets[0]] + assert truncated != body + digest = hashlib.sha256(truncated).hexdigest() + row.update(registered_body_sha256=digest, production_body_sha256=digest) + return + raise AssertionError('no truncation target: ' + kind) + edit(app_path, mutate) + check('signature_line_sha', gate.native_applicability, + lambda: truncated_hash('signature'), 'native ordering bytes') + check('trailing_comment_excluded_sha', gate.native_applicability, + lambda: truncated_hash('comment'), 'native ordering bytes') + + formal = 'dependency-formal-native/' + obs = 'dependency-midnight-native/order-evidence/observations.json' + reader = formal + 'restart-evidence/reader.json' + def corrupt(): + name = 'actual-native/repro/stdout.log' + data = bytearray((base / name).read_bytes()) + data[0] ^= 1 + (base / name).write_bytes(data) + changed.add(name) + check('one_byte_raw', gate.native_ownership, corrupt, 'native SHA', False) + def remove_member(): + name = formal + 'formal-packages/reader/paused/world.bin' + (base / name).unlink() + changed.add(name) + check('missing_member', gate.native_saves, remove_member, 'missing/outside') + check('writer_reader_same_pid', gate.native_ownership, + lambda: edit(reader, lambda d: d.update(pid=gate.load(base / (formal + 'restart-evidence/writer.json'))['pid'])), + 'PID binding') + check('writer_reader_same_profile', gate.native_ownership, + lambda: edit(reader, lambda d: d.update(profile=gate.load(base / (formal + 'restart-evidence/writer.json'))['profile'])), + 'profile reused') + check('abnormal_ended', gate.native_ownership, + lambda: edit(formal + 'reader/ended.json', lambda d: d.update(exit_code=1)), 'process bindings') + check('process_pid_changed', gate.native_ownership, + lambda: edit(formal + 'reader/process.json', lambda d: d.update(pid=d['pid'] + 1)), 'PID chain') + check('cleanup_missing', gate.native_ownership, + lambda: edit(formal + 'reader/outer-owned-finally.json', lambda d: d.update(cleanup=[])), 'cleanup binding') + check('execution_owned_pid_deleted', gate.native_ownership, + lambda: edit(formal + 'execution.json', lambda d: d['actual_captured_PIDs'].pop()), 'cleanup membership') + check('reader_receipt_row_duplicated', gate.native_ledger, + lambda: edit(reader, lambda d: d['results'][0]['receipts'][-1]['rows'].append(copy.deepcopy(d['results'][0]['receipts'][-1]['rows'][0]))), + 'duplicate receipt row') + check('reader_receipt_row_deleted', gate.native_ledger, + lambda: edit(reader, lambda d: d['results'][0]['receipts'][-1]['rows'].pop()), 'reader receipt delta') + check('observation_receipt_deleted', gate.native_ledger, + lambda: edit(obs, lambda d: d['observations'][3]['receipts'].pop()), 'ledger receipt delta') + check('paused_sale_injected', gate.native_ledger, + lambda: edit(obs, lambda d: d['observations'][1]['receipts'].append(copy.deepcopy(d['observations'][3]['receipts'][-1]))), + 'ledger receipt delta') + def joined_paused_sale(): + observation = gate.load(base / obs) + receipt = copy.deepcopy(observation['observations'][3]['receipts'][-1]) + sale = next(r for r in receipt['rows'] if r['category'] == 'SERVICE_SALE') + def inject(d): + paused = d['observations'][1] + paused['receipts'].append(receipt) + paused['wallet'] -= sale['amount'] + paused['guest']['wallet_gold'] = paused['wallet'] + edit(obs, inject) + edit('dependency-midnight-native/order-evidence/midnight-midnight.json', + lambda d: d['systems']['runtime']['economy']['entries'].extend(receipt['rows'])) + check('paused_sale_joined_ledger_wallet', gate.native_ledger, joined_paused_sale, 'PAUSED sale/progress/reason') + check('reservation_orphaned', gate.native_ledger, + lambda: edit(obs, lambda d: d['observations'][1]['reservations']['reservations'][0].update(requester_id='orphan')), + 'reservation snapshot binding') + def joined_orphan(): + edit(obs, lambda d: d['observations'][1]['reservations']['reservations'][0].update(requester_id='orphan')) + edit('dependency-midnight-native/order-evidence/midnight-midnight.json', + lambda d: d['systems']['runtime']['inventory']['reservations'][0].update(requester_id='orphan')) + check('reservation_orphaned_both_snapshots', gate.native_ledger, joined_orphan, 'orphan reservation relation') + check('wallet_wrong', gate.native_ledger, + lambda: edit(obs, lambda d: d['observations'][3].update(wallet=d['observations'][3]['wallet'] + 1)), 'wallet delta') + state = 'dependency-midnight-native/order-evidence/midnight-after.json' + check('idempotency_wrong_transaction', gate.native_ledger, + lambda: edit(state, lambda d: next(r for r in d['systems']['runtime']['economy']['idempotency'] if r['key'].startswith('service.payment.')).update(transaction_id='wrong')), + 'sale service join') + check('production_commit_mismatch', gate.native_applicability, + lambda: edit('ROOT_APPROVED_DEPENDENCY_FORMAL_RESULT.json', lambda d: d.update(production_commit=gate.REGISTERED_COMMIT)), + 'production commit mismatch') + check('current_source_pin_mismatch', gate.native_applicability, + lambda: edit(app_path, lambda d: d['registered_source_pins'][0].update(production_sha256='0' * 64)), + 'current_source_pins mismatch') + check('input_source_pin_mismatch', gate.native_applicability, + lambda: edit(formal + 'runner-input.json', lambda d: d['selected_source_map'].update({'autoload/simulation_runtime.gd': '0' * 64})), + 'input source pin mismatch') + check('original_member_changed', gate.native_saves, + lambda: edit(formal + 'execution.json', lambda d: d['formal_after']['before']['world.bin'].update(sha256='0' * 64)), + 'original members changed') + def typed_corrupt(): + name = formal + 'restart-evidence/reader-before-loaded.var' + (base / name).write_bytes(b'forged typed bytes') + changed.add(name) + check('typed_var_changed', gate.native_saves, typed_corrupt, 'typed SHA mismatch') + check('self_reported_scalar_true', gate.native_ledger, + lambda: edit(reader, lambda d: d.update(results=[{'receipts': [], 'sale_count': 1}], + passed=True, formal_save_restored=True)), 'reader receipt delta') + return {'scope': 'C Python controls on supplied raw; no formal acceptance', + 'formal_original_credit': 0, 'engine_runs': 0, 'results': results} + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('native_bundle', type=Path) + print(json.dumps(run(parser.parse_args().native_bundle), ensure_ascii=False, indent=2)) diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_negative_fixtures.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_negative_fixtures.py index e4de641..663e301 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_negative_fixtures.py +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/checker_negative_fixtures.py @@ -37,6 +37,8 @@ def run(): return aid oldmap = gate.load(ROOT / 'docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/historical-source-map.json') source = {p: gate.sha(ROOT / p) for p in oldmap if p.endswith('.gd') and p.startswith(('autoload/', 'scripts/'))} + for folder in ('autoload', 'scripts'): + source.update({p.relative_to(ROOT).as_posix(): gate.sha(p) for p in (ROOT / folder).rglob('*.gd')}) add('fixture_environment', b'SYNTHETIC CHECKER FIXTURE - NOT AN ENGINE') environment = dict(os='synthetic-checker-fixture', **{ k: {'fixture_environment.json': artifacts['fixture_environment']['sha256']} @@ -94,13 +96,21 @@ def run(): reachability = {} for name, refs in gate.REACH_REFS.items(): reachability[name] = dict(reach=name == 'EV', reason='Synthetic static-chain fixture', - source_refs=[dict(path=p, sha256=source[p], start=s, end=e, - text='\n'.join((ROOT / p).read_text().splitlines()[s-1:e])) for p,s,e in refs]) + source_refs=[dict(path=p, sha256=source[p], function=f, anchor_sha256=h, + line_count=n) for p,f,h,n in refs]) reachability['EV']['case_id'] = 'ev_stop' index = dict(schema_version=1, task_id='P04-01', formal_acceptance=False, candidate_commit=subprocess.check_output(['git','rev-parse','HEAD'], cwd=ROOT, text=True).strip(), source_map=source, environment=environment, artifacts=artifacts, authority=authority, domains=domains, conditions=conditions, reachability=reachability, review_status='pending_review') + index['registered_pins'] = gate.load(gate.SPEC)['current_source_pins'] + index['versions'] = dict(execution_origin=gate.EXECUTION_ORIGIN, + registered=gate.REGISTERED_COMMIT, tested=index['candidate_commit'], integration=None) + index['applicability_delta'] = gate.source_delta(gate.REGISTERED_COMMIT, index['candidate_commit']) + index['delta_cases'] = {row['path'] + ':' + row['function']: { + cid: ('ev_stop' if cid == 'EV' else cid) + for cid in gate.boundary_conditions(row['path'], row['function'])} + for row in index['applicability_delta']} original_files = {p.name:p.read_bytes() for p in evidence.iterdir()} index = copy.deepcopy(index) def check(name, mutate, error): @@ -120,7 +130,10 @@ def run(): assert proc.returncode == (0 if error is None else 1), (name, proc.stdout, proc.stderr) assert error is None or error in output.get('error',''), (name, output) results.append(dict(fixture=name, exit_code=proc.returncode, result=output)) - check('synthetic_control', lambda i: None, None) + check('synthetic_scalar_only_rejected', lambda i: None, 'native bundle required') + check('forged_registered_pin', lambda i: i['registered_pins'].update({'autoload/simulation_runtime.gd':'0'*64}), 'registered pin declaration') + check('false_delta', lambda i: i['applicability_delta'].append({'path':'autoload/simulation_runtime.gd','function':'initialize'}), 'git diff/applicability_delta mismatch') + check('wrong_reach_anchor', lambda i: i['reachability']['EV']['source_refs'][0].update(anchor_sha256='0'*64), 'unknown reachability anchor') check('missing_index', lambda i: None, 'missing/outside') check('duplicate_key', lambda i: None, 'duplicate JSON key') def symlink(i): diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/repair4-context.json b/docs/plans/original-completion-2026-10-02/execution/p04-01/repair4-context.json new file mode 100644 index 0000000..36d5c22 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/repair4-context.json @@ -0,0 +1,69 @@ +{ + "supplied_sources": [ + { + "name": "p04-01-shift-end-repro-r03.gd", + "sha256": "97e20c3f68b85bbb85fd37e85e97dec277cca5ebc791107120b0606d1138cc0a", + "bytes": 9518, + "historical_only": true + }, + { + "name": "p04-01-shift-end-repro-native-r03.py", + "sha256": "995a9b159533f40f79a4ef639c1338b689e8e98720eed638f8eae169d8a03e11", + "bytes": 6268, + "historical_only": true + }, + { + "name": "p04-01-midnight-boundary-r01.gd", + "sha256": "4f587cc90a3bbd310b53c6216e54cda1deacfa87fa4312411b41288e534de527", + "bytes": 11677, + "historical_only": true + }, + { + "name": "p04-01-midnight-boundary-native-r01.py", + "sha256": "3da084530941658ee396b05b9343f0342bf2a981962ef3361ed0f82475dd73dd", + "bytes": 6317, + "historical_only": true + }, + { + "name": "p04-01-power-formal-recovery-r04.gd", + "sha256": "887d3097fa4178675caf253c428d56cc842b506b8c32d6f7925505f17c32e2ff", + "bytes": 10062, + "historical_only": true + }, + { + "name": "p04-01-power-formal-recovery-native-r04.py", + "sha256": "d115a1ec5f985cfa4d7bd751eace0f2f5e93e1f4809434a0e2685c0fe0b8b23e", + "bytes": 8425, + "historical_only": true + }, + { + "name": "p04-01-formal-boundary-reload-r01.gd", + "sha256": "56e193a2c1d44c62c83374442b61c63935a69fdc1665ffa09bb549b0dfd8d14b", + "bytes": 7624, + "historical_only": true + }, + { + "name": "p04-01-formal-boundary-reload-native-r03.py", + "sha256": "fcd22729c9d045eb9656fae5db6c2116a27ab54fdb24f91c8125925b02a9d47a", + "bytes": 8677, + "historical_only": true + }, + { + "name": "p04-01-destruction-completion-boundary-r02.gd", + "sha256": "a9d58e7d5fcdf4793075552ae5be1ba6f5c2d45423b245b3d4617530260df37b", + "bytes": 12257, + "historical_only": true + }, + { + "name": "p04-01-exit-boundary-r01.gd", + "sha256": "6d7f32d801e4d8fb241a5e5695d6e31a8e7c47ad8021228ded460efcb1967254", + "bytes": 12726, + "historical_only": true + } + ], + "evidence_references": 39, + "raw_reuse_confirmed": 0, + "engine_runs": 0, + "runner_operations": 0, + "formal_acceptance": false +} diff --git a/tools/check_p04_order_evidence.py b/tools/check_p04_order_evidence.py index fa44ebd..0e795c1 100644 --- a/tools/check_p04_order_evidence.py +++ b/tools/check_p04_order_evidence.py @@ -18,6 +18,21 @@ SPEC = ROOT / 'docs/spec/acceptance/P04-01.json' SPEC_HASH = '9ec722e7dfb0bee178d291624a026420c08412574e238bba1fde012c7a6f7881' DOMAINS = {'閉店', '停電', '破壊', '退出', '課金', 'シフト交代', '00:00決算'} OWNER_HASH = '4583ee9aad45c4db183d72df4420df48aa8e0897e3b5efda13016f0b5cdbd68e' +REGISTERED_COMMIT = 'deb1bcb2374eb378b840ca345db952bd8572cb6e' +EXECUTION_ORIGIN = '9767b0a28ca8d252520307dbbac60a1d8cfb87ab' +# Fixed membership, never supplied by the evidence index. +ORDER_FUNCTIONS = { + 'scripts/core/simulation_kernel.gd': ('advance_one_minute', '_run_phase', '_handle_time_boundaries'), + 'scripts/core/command_queue.gd': ('_comes_before',), + 'autoload/simulation_runtime.gd': ( + '_process_tick_commands', '_advance_operations_time', '_run_operations_deferred_suffix', + '_advance_mana', '_advance_facilities', '_advance_guest_vitals', '_advance_staff_ai', + '_advance_guest_ai_decisions', '_release_closed_business_queues', + '_release_closed_business_request', '_complete_service_transaction'), + 'scripts/facility/facility_service.gd': ( + 'advance_one_minute', '_prepare_service_for_tick', '_complete_service', '_fail_service'), + 'scripts/operations/operations_coordinator.gd': ('_process_minute_boundaries',), +} # Condition -> (domain, authority refs, required engine measurements). # Measurements describe safety/counts, not the still-pending attribution policy. REQUIRED = { @@ -38,13 +53,16 @@ REQUIRED = { 'overtime_task': ('シフト交代', ('BASELINE:67',), {'interrupt_level': 0, 'is_overtime': True, 'duty_recorded_once': True}), } REACH_REFS = { - 'EV': [('autoload/simulation_runtime.gd', 6733, 6742), - ('scripts/staff/task_dispatcher.gd', 256, 261), - ('autoload/simulation_runtime.gd', 9141, 9170), - ('autoload/simulation_runtime.gd', 8986, 8987), - ('scripts/transport/elevator_service.gd', 279, 284)], - 'transport': [('autoload/simulation_runtime.gd', 12023, 12030), - ('autoload/simulation_runtime.gd', 12976, 13050)], + 'EV': [ + ('autoload/simulation_runtime.gd', '_execute_create_staff_task', '8b83aff45ead128b70931343271dbd03a1024b90238d1f46f93e4856290aa0d8', 10), + ('scripts/staff/task_dispatcher.gd', '_reserve_pair', '48e2e593c117bd675236a165a294c9cc6233f87018010249cd8e675aff01fc3c', 6), + ('autoload/simulation_runtime.gd', '_reserve_staff_task_items', '4f2add093de47cb08abfa45e9d2285f00d906c9bceadb2d98ffa42faae9ede67', 28), + ('autoload/simulation_runtime.gd', '_advance_staff_task_travel', '53937aefeec533a5f16169bba4dd6a69b5246101d09de77ca95db7ca174c63ce', 2), + ('scripts/transport/elevator_service.gd', 'set_powered', '925f4bf2d109421956fb2958981758d7d84a1ca586a9d4eb51572b8b9677cfba', 6)], + 'transport': [ + ('autoload/simulation_runtime.gd', '_on_staff_task_completed', '46daaa0197ce85c08883614112efb2d12a2cc0a02fe14ffec8314c73cbba61fc', 8), + ('autoload/simulation_runtime.gd', '_handle_rescue_arrival', '11f8d43d0c089b95006009eddfc8bd3d4375a666b29ff19f36e1fa008f3946dd', 24), + ('autoload/simulation_runtime.gd', '_advance_staff_rescue', '86bb31b40606fd624cc6b273dfdf7e3e4b3e1bc9997df825dd74136efb69a38f', 52)], } @@ -109,6 +127,106 @@ def literal(a, b): return type(a) is type(b) and json.dumps(a, sort_keys=True) == json.dumps(b, sort_keys=True) +def git_bytes(*args): + return subprocess.check_output(['git', *args], cwd=ROOT) + + +def function_bytes(data): + """Top-level named func through next named func, preserving every raw byte. + + The prefix is an explicit non-function unit. Nested lambdas do not start + a unit. Comments, whitespace, signatures and trailing declarations remain + included; uncertain edits fail conservatively, never normalize as equal. + """ + matches = list(re.finditer(rb'(?m)^(?:static )?func ([A-Za-z_][A-Za-z_0-9]*)\(', data)) + result = {'': data[:matches[0].start()] if matches else data} + for i, match in enumerate(matches): + name = match[1].decode('ascii') + require(name not in result, 'ambiguous function: ' + name) + result[name] = data[match.start():matches[i + 1].start() if i + 1 < len(matches) else len(data)] + return result + + +def resolve_anchor(data, function, digest, line_count): + body = function_bytes(data).get(function) + require(body is not None, 'reachability function missing: ' + function) + lines = body.splitlines(keepends=True) + hits = [b''.join(lines[i:i + line_count]) for i in range(len(lines) - line_count + 1) + if hashlib.sha256(b''.join(lines[i:i + line_count])).hexdigest() == digest] + require(len(hits) == 1, 'reachability anchor missing/ambiguous: ' + function) + return hits[0] + + +def source_delta(base, head): + """Compute changed function units from Git, including added/deleted files. + + Only game autoload/scripts GDScript belongs to this applicability scope. + The complete tested map still pins every supplied dependency separately. + """ + paths = git_bytes('diff', '--no-ext-diff', '--no-renames', '--name-only', '-z', + base + '..' + head, '--', 'autoload/', 'scripts/').split(b'\0') + base_paths = set(git_bytes('ls-tree', '-r', '--name-only', '-z', base).split(b'\0')) + head_paths = set(git_bytes('ls-tree', '-r', '--name-only', '-z', head).split(b'\0')) + delta = [] + for encoded in sorted(p for p in paths if p.endswith(b'.gd')): + path = encoded.decode('utf-8') + old = function_bytes(git_bytes('show', base + ':' + path)) if encoded in base_paths else {} + new = function_bytes(git_bytes('show', head + ':' + path)) if encoded in head_paths else {} + for name in sorted(old.keys() | new.keys()): + if old.get(name) != new.get(name): + delta.append({'path': path, 'function': name}) + return delta + + +def boundary_conditions(path, function): + # Conservative coverage: new/changed Runtime setup can reach every boundary. + if path == 'autoload/simulation_runtime.gd': + if any(word in function for word in ('relationship', 'restore', 'snapshot', 'save')): + return {'save_restore'} + return set(REQUIRED) | {'EV'} + if '/relationship/' in path or '/save/' in path: + return {'save_restore'} + if any(part in path for part in ('/world/', '/transport/', '/staff/')): + return {'exit_release', 'closure_release', 'shift_completion', 'EV', 'save_restore'} + # No inferred non-impact exemption for previously unseen dependencies. + return set(REQUIRED) | {'EV'} + + +def applicability(index, spec, source, head): + registered = spec['current_source_pins'] + require(index.get('registered_pins') == registered, 'registered pin declaration') + for path, digest in registered.items(): + require(hashlib.sha256(git_bytes('show', REGISTERED_COMMIT + ':' + path)).hexdigest() == digest, + 'registered Git pin: ' + path) + require(index.get('versions') == {'execution_origin': EXECUTION_ORIGIN, + 'registered': REGISTERED_COMMIT, 'tested': head, 'integration': None}, 'version roles') + # Refuse uncommitted game bytes; otherwise Git diff would not describe tested. + game_paths = git_bytes('ls-tree', '-r', '--name-only', '-z', head, '--', 'autoload/', 'scripts/').split(b'\0') + for encoded in game_paths: + if not encoded.endswith(b'.gd'): + continue + path = encoded.decode('utf-8') + require(path in source and sha(safe(ROOT, path)) == hashlib.sha256(git_bytes('show', head + ':' + path)).hexdigest(), + 'tested game differs from Git: ' + path) + delta = source_delta(REGISTERED_COMMIT, head) + require(index.get('applicability_delta') == delta, 'git diff/applicability_delta mismatch') + for path, names in ORDER_FUNCTIONS.items(): + old = function_bytes(git_bytes('show', REGISTERED_COMMIT + ':' + path)) + new = function_bytes(safe(ROOT, path).read_bytes()) + for name in names: + require(name in old and name in new and old[name] == new[name], 'stale ordering function: ' + path + ':' + name) + bindings = index.get('delta_cases') + require(isinstance(bindings, dict) and set(bindings) == {r['path'] + ':' + r['function'] for r in delta}, 'delta case bindings') + for row in delta: + key = row['path'] + ':' + row['function'] + required = boundary_conditions(row['path'], row['function']) + cases = bindings[key] + require(isinstance(cases, dict) and set(cases) == required, 'boundary delta coverage: ' + key) + for cid, case_id in cases.items(): + declaration = index['reachability']['EV'] if cid == 'EV' else index['conditions'][cid] + require(case_id == declaration.get('case_id'), 'boundary delta engine case: ' + key) + + def coverage(index, raw, source): authority = index['authority'] for ref in {r for _, refs, _ in REQUIRED.values() for r in refs}: @@ -174,11 +292,12 @@ def coverage(index, raw, source): and decision['reason'].strip(), 'unsupported reach=false: ' + name) for ref in refs: require(ref.get('path') in source and ref.get('sha256') == source[ref['path']], 'reachability source pin') - lines = safe(ROOT, ref['path']).read_text().splitlines() - start, end = ref.get('start'), ref.get('end') - require(type(start) is int and type(end) is int and 1 <= start <= end <= len(lines), 'reachability lines') - require(ref.get('text') == '\n'.join(lines[start - 1:end]), 'reachability source text') - require(set(REACH_REFS[name]) <= {(r['path'], r['start'], r['end']) for r in refs}, 'missing static reachability chain: ' + name) + identity = (ref['path'], ref.get('function'), ref.get('anchor_sha256'), ref.get('line_count')) + require(identity in REACH_REFS[name], 'unknown reachability anchor') + resolve_anchor(safe(ROOT, ref['path']).read_bytes(), *identity[1:]) + require(len(refs) == len(REACH_REFS[name]) and set(REACH_REFS[name]) == { + (r['path'], r['function'], r['anchor_sha256'], r['line_count']) for r in refs}, + 'missing static reachability chain: ' + name) # Staff dispatch reserves task items before travel. A guest-only exclusion # must not hide this reachable EV reservation path. if name == 'EV': @@ -197,6 +316,324 @@ def coverage(index, raw, source): require(decision.get('reach') is False, 'transport reservation/payment exclusion') +NATIVE_RUNS = { + 'actual-native': ('import', 'parse', 'repro'), + 'dependency-midnight-native': ('import', 'parse', 'repro'), + 'dependency-formal-native': ('import', 'parse', 'writer', 'reader'), +} +SAVE_POINTS = ('before', 'midnight', 'paused', 'after', 'next') +SAVE_MEMBERS = {'journal.log', 'manifest.json', 'thumbnail.png', 'world.bin'} + + +def native_file(base, name, pin): + path = safe(base, name) + require(type(pin.get('bytes')) is int and path.stat().st_size == pin['bytes'], 'native bytes: ' + name) + require(sha(path) == pin.get('sha256'), 'native SHA: ' + name) + return path + + +def native_cleanup(value): + require(value.get('engine_ended') is True and value.get('errors') == [] + and literal(value.get('actual_process_exit_code'), 0), 'native cleanup failed') + attempts = value.get('attempts') + require(isinstance(attempts, list) and attempts, 'native cleanup attempts missing') + for attempt in attempts: + require(attempt.get('errors') == [] and attempt.get('kill_attempted') is False + and attempt.get('wait_completed') is True + and literal(attempt.get('wait_returned_code'), 0), 'native cleanup abnormal wait') + + +def native_ownership(base): + provenance = load(safe(base, 'OWNERSHIP_RAW_PROVENANCE.json'))['copied'] + targets = set() + for row in provenance: + require(row['target'] not in targets, 'duplicate native provenance target') + targets.add(row['target']) + native_file(base, row['target'], row) + pids = {} + for run, phases in NATIVE_RUNS.items(): + execution = load(safe(base, run + '/execution.json')) + inputs = load(safe(base, run + '/runner-input.json')) + require([p['phase'] for p in execution['phases']] == list(phases), 'native phase membership') + run_pids = [] + cleanups = [] + for phase, phase_receipt in zip(phases, execution['phases']): + prefix = run + '/' + phase + '/' + names = ('started.json', 'process.json', 'ended.json', 'outer-owned-finally.json', + 'adapter-owned-cleanup.json', 'stdout.log', 'stderr.log', 'engine-native.log') + require({prefix + n for n in names} <= targets, 'native provenance lifecycle missing') + start, process, end, outer, cleanup = [load(safe(base, prefix + n)) for n in names[:5]] + pid = start['actual_pid'] + require(type(pid) is int and pid > 0 and pid not in pids.values(), 'native PID reused') + require(start['pid'] == process['pid'] == end['pid'] == end['actual_pid'] == pid, + 'native PID chain') + require(start['event'] == 'ENGINE_STARTED' and end['event'] == 'ENGINE_ENDED' + and start['owner_pid'] == end['owner_pid'] == inputs['owner_runner_pid'] + and start['command'] == start['argv'] == process['argv'] == end['argv'] == end['command'] + and start['monotonic_ns'] < end['monotonic_ns'], 'native lifecycle identity') + require(process['actual_start_binding'] == start and process['actual_end_binding'] == end, + 'native process bindings') + require(start['current_process_identity']['pid'] == pid + and start['current_process_identity']['ppid'] == start['owner_pid'], 'native owner identity') + require(load(safe(base, run + '/' + phase + '-receipt.json')) == phase_receipt + == load(safe(base, run + '/' + phase + '-actual-phase.json')), 'native phase receipt binding') + for record in (process, end, phase_receipt): + require(literal(record.get('exit_code'), 0), 'native abnormal exit') + require(end.get('engine_ended') is True and end.get('timed_out') is False + and process.get('timed_out') is False and end.get('lifecycle_error') is None + and process.get('lifecycle_error') is None and literal(end.get('actual_process_exit_code'), 0) + and phase_receipt.get('engine_ended') is True, 'native abnormal end') + require(phase_receipt['actual_pid'] == pid and phase_receipt['native_process'] == process, + 'native execution process binding') + require(outer['actual_captured_pids'] == [pid] and outer['outer_cleanup_errors'] == [] + and outer.get('all_captured_ended') is True and outer.get('adapter_exception') is None + and len(outer['cleanup']) == 1 and outer['cleanup'][0]['pid'] == pid + and outer['cleanup'][0]['outer_cleanup_errors'] == [] + and outer['cleanup'][0]['cleanup'] == cleanup == process['adapter_owned_cleanup'], + 'native owned cleanup binding') + native_cleanup(cleanup) + for stream in ('stdout', 'stderr'): + require(sha(safe(base, prefix + stream + '.log')) == process[stream + '_sha256'], + 'native stream hash') + for field in ('stdout', 'stderr'): + require(safe(base, prefix + field + '.log').is_file(), 'native log missing') + native_file(base, prefix + 'engine-native.log', phase_receipt['raw_native_log']) + pids[run + '/' + phase] = pid + run_pids.append(pid) + cleanups.extend(outer['cleanup']) + require(execution['actual_captured_PIDs'] == run_pids and execution['cleanup'] == cleanups + and execution['cleanup_errors'] == [], 'native execution cleanup membership') + formal = 'dependency-formal-native/' + records = [load(safe(base, formal + 'restart-evidence/' + role + '.json')) for role in ('writer', 'reader')] + require(records[0]['profile'] != records[1]['profile'], 'native writer reader profile reused') + for role, record in zip(('writer', 'reader'), records): + require(record['pid'] == pids[formal + role], 'native writer reader PID binding') + profile = load(safe(base, formal + role + '-profile.json')) + phase = load(safe(base, formal + role + '-receipt.json')) + require(record['profile'] == profile['actual_user_data_dir'] == profile['expected_user_data_dir'] + == phase['controlled_environment']['THE_TREE_PACK_PROFILE_EXPECTED'], 'native profile binding') + require(record['slots'] == {p: record['profile'] + '/saves/p04_boundary/' + p for p in SAVE_POINTS}, + 'native formal profile slots') + return pids + + +def native_applicability(base): + """Production evidence identity, separate from A/B checkout applicability.""" + app = load(safe(base, 'POST_P18_CURRENT_SOURCE_APPLICABILITY.json')) + production = app['production_commit'] + require(re.fullmatch('[0-9a-f]{40}', production) is not None, 'native production commit') + registered = load(SPEC)['current_source_pins'] + pin_rows = app['registered_source_pins'] + require(len(pin_rows) == len(registered) and {r['path'] for r in pin_rows} == set(registered), + 'native current_source_pins membership') + current = {} + for row in pin_rows: + path = row['path'] + current[path] = hashlib.sha256(git_bytes('show', production + ':' + path)).hexdigest() + require(row['registered_sha256'] == registered[path] and row['production_sha256'] == current[path], + 'native current_source_pins mismatch') + rows = app['ordering_functions'] + require(len(rows) == sum(map(len, ORDER_FUNCTIONS.values())) and + {(r['path'], r['function']) for r in rows} == {(p, f) for p, fs in ORDER_FUNCTIONS.items() for f in fs}, + 'native ordering membership') + for path, functions in ORDER_FUNCTIONS.items(): + old = function_bytes(git_bytes('show', REGISTERED_COMMIT + ':' + path)) + new = function_bytes(git_bytes('show', production + ':' + path)) + for function in functions: + row = next(r for r in rows if (r['path'], r['function']) == (path, function)) + body = new[function] + require(old[function] == body and hashlib.sha256(body).hexdigest() == + row['production_body_sha256'] == row['registered_body_sha256'], + 'native ordering bytes') + for run, result in zip(NATIVE_RUNS, ('SHIFT_CURRENT', 'DEPENDENCY_MIDNIGHT', 'DEPENDENCY_FORMAL')): + summary = load(safe(base, 'ROOT_APPROVED_' + result + '_RESULT.json')) + require(summary['production_commit'] == production, 'native production commit mismatch') + inputs = load(safe(base, run + '/runner-input.json')) + for path, digest in current.items(): + require(inputs['source_before'][path]['sha256'] == digest + == inputs['selected_source_map'][path], 'native input source pin mismatch') + return production + + +def native_saves(base): + prefix = 'dependency-formal-native/' + execution = load(safe(base, prefix + 'execution.json')) + before, after = execution['formal_before'], execution['formal_after'] + require(set(before) == set(after) == set(SAVE_POINTS) and before == after, 'native original members changed') + summary = load(safe(base, 'ROOT_APPROVED_DEPENDENCY_FORMAL_RESULT.json')) + members = summary['formal_member_pins'] + require(len(members) == 20 and {(r['point'], r['member']) for r in members} == + {(p, m) for p in SAVE_POINTS for m in SAVE_MEMBERS}, 'native formal member membership') + for point in SAVE_POINTS: + require(set(before[point]) == SAVE_MEMBERS, 'native original member missing') + for member in SAVE_MEMBERS: + for role in ('writer', 'reader'): + path = native_file(base, prefix + 'formal-packages/' + role + '/' + point + '/' + member, before[point][member]) + row = next(r for r in members if (r['point'], r['member']) == (point, member)) + require(sha(path) == row['sha256'], 'native formal member pin') + typed = summary['typed_outputs_14_sha_match_original_native'] + expected = {role + '-' + p + suffix + '.var': p for p in SAVE_POINTS + for role, suffix in (('writer', '-persisted'), ('reader', '-loaded'))} + expected.update({'reader-replayed-' + p + '.var': p for p in SAVE_POINTS if p != 'before'}) + require(len(typed) == len(expected) and {Path(r['output']).name for r in typed} == set(expected), + 'native typed member membership') + inputs = load(safe(base, prefix + 'runner-input.json'))['fixed_input_pins'] + for row in typed: + name = Path(row['output']).name + original = 'midnight-' + expected[name] + '.var' + require(Path(row['original']).name == original, 'native typed original identity') + source = safe(base, 'dependency-midnight-native/order-evidence/' + original) + output = safe(base, prefix + 'restart-evidence/' + name) + require(sha(source) == sha(output) == row['sha256'], 'native typed SHA mismatch') + pin = [p for p in inputs if p['path'] == row['original']] + require(len(pin) == 1, 'native typed input missing') + native_file(base, 'dependency-midnight-native/order-evidence/' + original, pin[0]) + + +def receipt_rows(receipts): + """Keep multiplicity: sets must never hide duplicated ledger rows.""" + require(isinstance(receipts, list), 'native receipts missing') + ids, rows = set(), [] + for receipt in receipts: + require(receipt['id'] not in ids and receipt['rows'], 'native duplicate/empty receipt') + ids.add(receipt['id']) + for row in receipt['rows']: + require(row['transaction_id'] == receipt['id'] and type(row['amount']) is int + and row['amount'] >= 0, 'native receipt transaction') + require(row not in rows, 'native duplicate receipt row') + rows.append(row) + return rows + + +def native_ledger(base): + prefix = 'dependency-midnight-native/order-evidence/' + observations = load(safe(base, prefix + 'observations.json')) + series = observations['observations'] + require(len(series) == len(SAVE_POINTS), 'native observation series missing') + initial = series[0] + service = initial['service'] + require(service['state'] == 'ACTIVE' and service['elapsed_minutes'] == service['duration_minutes'] - 1, + 'native initial service progress') + identity = ('service_id', 'request_id', 'facility_id', 'guest_ids', 'inventory_reservations', 'price_snapshot') + require(service['inventory_reservations'] and len(service['guest_ids']) == 1, 'native service identity missing') + guest_id = service['guest_ids'][0] + account = 'GUEST_WALLET:' + guest_id + final_state = load(safe(base, prefix + 'midnight-after.json'))['systems']['runtime'] + links = [r for r in final_state['economy']['idempotency'] if r['key'] == 'service.payment.' + service['service_id']] + require(len(links) == 1, 'native service idempotency missing/duplicate') + transaction = links[0]['transaction_id'] + previous_rows = [] + states = [] + for position, (point, observation) in enumerate(zip(SAVE_POINTS, series)): + snapshot = load(safe(base, prefix + 'midnight-' + point + '.json')) + state = snapshot['systems']['runtime'] + states.append(state) + facilities = [f for f in state['facilities']['instances'] if f['instance_id'] == service['facility_id']] + require(len(facilities) == 1, 'native facility identity') + facility = facilities[0] + if position == 0: + definition_id = facility['definition_id'] + require(re.fullmatch('[a-zA-Z0-9_]+', definition_id) is not None, 'native definition identity') + definition_path = 'data/facilities/' + definition_id + '.tres' + production = load(safe(base, 'POST_P18_CURRENT_SOURCE_APPLICABILITY.json'))['production_commit'] + definition = git_bytes('show', production + ':' + definition_path) + inputs = load(safe(base, 'dependency-midnight-native/runner-input.json')) + require(inputs['selected_source_map'][definition_path] == + inputs['source_before'][definition_path]['sha256'] == hashlib.sha256(definition).hexdigest(), + 'native original definition pin') + for field, value in (('base_price', service['price_snapshot']), ('base_service_minutes', service['duration_minutes'])): + matches = re.findall(rb'(?m)^' + field.encode() + rb' = ([0-9]+)$', definition) + require(len(matches) == 1 and int(matches[0]) == value == facility[field], 'native original definition value') + current = observation['service'] + require(all(current[k] == service[k] for k in identity), 'native service identity changed') + require(observation['minute'] == initial['minute'] + position == snapshot['clock']['absolute_minute'], + 'native minute series') + require(current in state['facilities']['service_history'] or any( + current in f['active_services'] for f in state['facilities']['instances']), 'native service snapshot binding') + require(observation['reservations'] == state['inventory'], 'native reservation snapshot binding') + rows = receipt_rows(observation['receipts']) + ledger = state['economy']['entries'] + initial_ledger = states[0]['economy']['entries'] + require(ledger[:len(initial_ledger)] == initial_ledger and ledger[len(initial_ledger):] == rows, + 'native ledger receipt delta') + require(rows[:len(previous_rows)] == previous_rows, 'native receipt history changed') + wallet_delta = sum(r['amount'] * ((r['debit_account'] == account) - (r['credit_account'] == account)) for r in rows) + require(observation['wallet'] == initial['wallet'] + wallet_delta, 'native wallet delta') + require(observation['wallet'] == sum(r['amount'] * ((r['debit_account'] == account) - + (r['credit_account'] == account)) for r in ledger), 'native ledger wallet balance') + if observation['guest']: + require(observation['guest']['wallet_gold'] == observation['wallet'] + and observation['guest']['guest_id'] == guest_id, 'native guest wallet binding') + else: + require(point == 'next', 'native guest missing before completion') + sales = [r for r in rows if r['category'] == 'SERVICE_SALE'] + paused = current['state'] == 'PAUSED' + if position in (1, 2): + require(paused and current['interruption_reason'] == 'RELATED_FACILITY_INACTIVE' + and current['elapsed_minutes'] == service['elapsed_minutes'] and not sales, + 'native PAUSED sale/progress/reason') + elif position >= 3: + require(current['state'] == 'COMPLETED' and len(sales) == 1 + and current['elapsed_minutes'] == current['duration_minutes'], 'native completion sale count') + sale = sales[0] + require(sale['transaction_id'] == transaction and sale['credit_account'] == account + and sale['source_entity_id'] == service['facility_id'] + and sale['debit_account'] == 'FACILITY_REVENUE:' + service['facility_id'] + and sale['amount'] == service['price_snapshot'] + and sale['absolute_minute'] == current['completed_at'], 'native sale service join') + reservations = observation['reservations']['reservations'] + require(len(reservations) == len(service['inventory_reservations']) and + {r['reservation_id'] for r in reservations} == set(service['inventory_reservations']), + 'native orphan reservation membership') + requests = state['facilities']['requests'] + matching_requests = [r for r in requests if r['request_id'] == service['request_id']] + require(len(matching_requests) == (1 if position < 3 else 0), 'native request series') + if matching_requests: + request = matching_requests[0] + require(request['facility_id'] == service['facility_id'] and request['guest_ids'] == service['guest_ids'] + and request['quoted_price'] == service['price_snapshot'] + and request['reserved_inventory_ids'] == service['inventory_reservations'], 'native request service join') + for reservation in reservations: + require(reservation['requester_id'] == service['request_id'] + and reservation['owner_inventory_id'] == 'facility.inventory:' + service['facility_id'] + and reservation['state'] == ('ACTIVE' if position < 3 else 'CONSUMED'), + 'native orphan reservation relation') + previous_rows = rows + require(receipt_rows(observations['first_receipts']) == previous_rows + == receipt_rows(observations['replay_receipts']), 'native midnight replay receipts') + reader = load(safe(base, 'dependency-formal-native/restart-evidence/reader.json')) + require(len(reader['results']) == 1 and receipt_rows(reader['results'][0]['receipts']) == previous_rows, + 'native reader receipt delta') + sweep = [r for r in previous_rows if r['category'] == 'SERVICE_CASH_SWEEP'] + require(len(sweep) == 1 and sweep[0]['transaction_id'] == transaction + and sweep[0]['amount'] == service['price_snapshot'] + and sweep[0]['credit_account'] == 'FACILITY_REVENUE:' + service['facility_id'] + and sweep[0]['debit_account'] == 'PLAYER_CASH', 'native sale cash sweep') + maintenance = [r for r in previous_rows if r['category'].startswith('MAINTENANCE_')] + accruals = [r for r in maintenance if r['category'] == 'MAINTENANCE_ACCRUAL'] + payments = [r for r in maintenance if r['category'] == 'MAINTENANCE_PAYMENT'] + require(accruals and len(accruals) == len(payments), 'native maintenance pairs') + for accrual in accruals: + matches = [r for r in payments if r['transaction_id'] == accrual['transaction_id'] + and r['source_entity_id'] == accrual['source_entity_id'] and r['amount'] == accrual['amount'] + and r['absolute_minute'] == series[1]['minute'] == accrual['absolute_minute'] + 1] + require(len(matches) == 1, 'native maintenance accrual/payment join') + return {'service_id': service['service_id'], 'transaction_id': transaction, + 'receipt_rows': len(previous_rows), 'formal_original_credit': 0} + + +def verify_native(base): + """Finite C-layer check, never a replacement for the 15+EV whole gate.""" + for row in load(safe(base, 'SOURCE_MANIFEST.json'))['files']: + native_file(base, row['copy'], row) + production = native_applicability(base) + pids = native_ownership(base) + native_saves(base) + result = native_ledger(base) + return dict(result, production_commit=production, owned_processes=len(pids), + verified_conditions=['dependency_stop', 'recovery_completion', 'paused_midnight']) + + def verify(directory): # Contract hashes the supplied spec string, while the checked-in JSON has # one final LF. Accept only that exact representation difference. @@ -213,8 +650,7 @@ def verify(directory): require(index.get('candidate_commit') == head, 'candidate_commit mismatch') source = index.get('source_map') pins(source, ROOT) - for name, digest in spec['current_source_pins'].items(): - require(source.get(name) == digest, 'immutable source pin: ' + name) + applicability(index, spec, source, head) oldmap = load(ROOT / 'docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/historical-source-map.json') required = {p for p in oldmap if p.endswith('.gd') and p.startswith(('autoload/', 'scripts/'))} require(required <= source.keys(), 'missing runtime/service dependency source pins') @@ -284,6 +720,19 @@ def verify(directory): require(result, name + ': predicate failed') require(index.get('review_status') in {'pending_review', 'approved'}, 'review status') coverage(index, raw, source) + # Scalar conditions remain necessary declarations, never sufficient proof. + binding = index.get('native_bundle') + require(isinstance(binding, dict), 'native bundle required; self-reported scalar evidence is insufficient') + manifest = safe(evidence, binding['manifest']) + require(manifest.name == 'OWNERSHIP_RAW_PROVENANCE.json' and sha(manifest) == binding['sha256'], + 'native bundle provenance pin') + native = verify_native(manifest.parent) + require(native['production_commit'] == head, 'native production/tested mismatch; A/B reuse coverage required') + # This adapter covers only the supplied dependency/formal series. Never + # promote it to the missing original scenarios through scalar booleans. + missing = (set(REQUIRED) | {'EV'}) - set(native['verified_conditions']) + require(not missing, 'uncollected original boundaries: ' + ', '.join(sorted(missing)) + + '; formal_original_credit=0') def main():