P04-01: 同時発生の更新規約

This commit is contained in:
Agent Control Runner
2026-10-16 08:35:40 +09:00
parent 16207d353a
commit 8418560aaf
17 changed files with 2011 additions and 932 deletions
@@ -1,177 +1,52 @@
# 初期監査の検証器
# Current checker protocol — repair22
## repair7 定義(以前の版識別説明に優先)
Source preparation, NOT RUN. ORDER_AUDIT.md and order-audit.json are the single
current seven-domain table. REPAIR17–21 remain untouched historical records;
their current-status and B1 power-credit claims are superseded.
registered は deb1bcb、execution_origin は 9767b0a、checker は実際に
実行したcheckerのcommitとbytes、product_target は
`{main_anchor, submitted, composed_tree}` とする。checkerのSHAを製品版に
代用しない。提出後にしか確定しない自己blob照合は未実施としてRootが検証する。
The registry remains exactly15 conditions + EV. No accepted originals, counts,
CurrentAlphaScope, three safety outcomes or30/88 denominator change. Original
13/88 gains no credit. P04 main9b stays frozen; no integration is claimed.
`duty_payments` は決算日のpayroll settlement取引のうち、
ShiftInstance.record_duty_minute の勤務recordとstaff_id/day単位で
結合できる取引の件数。期待値は1のまま。独立した通貨項目ではない。
collectorはpayroll行と勤務recordの実rawを結合し、結合不能なら失敗する。
C's NATIVE_RUNS / native_ownership / verify_native block is unchanged. C25 and
all existing fixture cases remain. R's verify_shift_completion derives three
distinct process IDs from the existing raw start/process/end joins, with all
end flags, exit0 and complete SHA checks retained. The one1080 SALE joins the
original serviceID and priceSnapshot via service.payment.<serviceID>, actual
receipt entries and idempotency transaction ID; no fixed PID or ledger number.
融資の公開返済API `repay_loan_principal` とledger分類
`LOAN_PRINCIPAL_REPAID` / `financing_principal_outflows` は存在する。
自動返済や全UIの完成は主張しない。「融資機構がない」という説明は撤回する。
S1 uses the full existing writer-<case>-observations Variant data in
B/p04-s1-native-r02. The pre-travel ACTIVE reservation, requester/task, assigned
staff and original staff_cell join the later boarded task and trip. Reserve
exhaustion is measured before the normal tick, and depleted raw must show
mana0 and the actual elevator unpowered. JSON summaries do not replace typed raw.
midnight_replayは同minuteの決算API再呼出しによる実測までpending。
1442完了やservice request再送を1440売上・決算API再呼出しの証明にしない。
shift_completionはapproved-shift-current-r01.gdの1080観測を使う。
D05のEV停止帰属、停電と休業の厳密な順序、費用時点の未確定部分はpending。
全case収集、登録validate、独立whole review、統合準備の順序を維持する。
本修理での試験・engine実行はworkerでは行わない。
S3 B1 remains a combined dependency/closure diagnostic. Its actual interruption
reason is RELATED_FACILITY_INACTIVE. It supplies no power_stop evidence and no
priority approval. The strict power-vs-closure order is D05 pending/unknown.
## repair6 現在値(2026-10-16)
Only S4 supplies power_stop. The new verifier requires source-pinned native
ownership, complete product1338 + sole QA override, three whole4-member formal
packages per process, separate Writer/Reader, exact Runtime typed restoration
and full typed replay. Actual NO_POWER, operating dependency, powered/ACTIVE
kitchen, positive mana and open operator are mandatory. Raw graph edges and
revision prove the isolated consumer and exact reconnect; source-derived
evaluation/hold determines recovery. Duration−1, zero stopped charges, original
service/reservation identity, one SALE and unchanged replay are joined from raw.
Every intervening held minute is retained and checked. No normalization or
dropped Runtime fields is allowed. S4 is pending Root execution, not accepted.
旧値: 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検査結果として扱わない。
checker_join_fixtures retains every previous case and adds rejection controls
for B1 masquerading as power, dependency false, kitchen unpowered, closure,
pre-travel mismatch, absent outage, wrong PID and transaction join. Consistently
renamed dynamic PID/transaction/service IDs are positive controls. These fixtures
have NOT RUN. They require actual S4 raw for the S4 positive control.
## 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.<service_id>` から
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。
内部JSON形式は `P04_ORDER_EVIDENCE_PROTOCOL.json` を基に次の有限サブセットを実装した。重複JSONキー、NaN/Infinity、絶対・親参照・symlink・重複artifact pathを拒否する。全ハッシュは生バイトSHA256。indexに合格booleanや試験数があっても判定には使用しない。
- `schema_version: 1`, `task_id: P04-01`, checkout HEADと一致する `candidate_commit`, `formal_acceptance: false`。
- `source_map`: repository相対パス→SHA256。specの6不変pinと旧map内autoload/scriptsの全GDScript依存を必須とする。追加sourceも実ファイルと照合する。
- `environment`: 非空 `os` と `engine`, `configuration`, `inputs` の証拠ディレクトリ相対パス→SHA256 map。engineは実行バイナリのコピー。OSの自己申告だけではnative証明にならない。
- `artifacts`: ID→`path`, `bytes`(整数), `sha256`, `type`。typeは observation/state/receipt/stdout/native_log/save/authority のいずれか。
- `authority`: ref→`status`(original/approved), `artifact_id`。raw文書の存在を確認するが内容の原規約適合は独立レビューを要する。pendingは失敗。
- `domains`: 正確な7領域名→`source_refs`, `authority_refs`, `cases`, `invariants`, `applicability`。source_refは `path/function/sha256`。applicabilityはindexと同じ `source_map/environment`。
- 各caseは一意な `id` とartifact IDの `input/before/operation/after/receipt`。receipt JSONは正整数 `start_pid`、同じ `end_pid`、整数 `exit_code: 0`、`engine_ended: true`、一致する `source_map/environment`、raw `stdout/native_log` artifact IDを要求する。receiptのcase_idとinput/before/operation/afterのartifact_hashesを照合する。caseにもraw_origin=engineを要求する。ログの意味と実行由来の独立確認はRoot/reviewerが行う。
- 各invariantは `artifact_id/json_pointer/operator/authority_ref/raw_origin`。raw_originはengineのみ。root derivationはformula検証未対応のため拒否する。RFC6901 pointerでraw JSONから値を読む。eqはexpectedとの型を含むliteral一致、nonnegativeはboolean以外の数値が0以上、count_eqは配列/辞書長と整数expectedの一致。same_literal/distinctは `paired_artifact_id/paired_json_pointer` の値との型を含む比較。未知operatorは失敗。
## 固定必須条件
checkerのREQUIREDが唯一の必須条件定義であり、indexから条件を受け取らない。conditionsはそのIDと完全一致するmap。各値はcase_id、固定順のauthority_refs、nativeWindows: pending。各条件は指定domainのengine caseと全metricのeq invariantを必要とする。観測はcase.afterの /conditions/<condition_id>/<metric> に置き、invariantのcase_id、artifact_id、pointer、expectedを固定定義と照合する。pass booleanや試験数は使わない。測定値は実際のengine観測から出すこと。手書き合成fixtureはchecker分岐検証専用であり、受入証拠には使用不可。
- 停止課金0: power_stop / destruction_stop / dependency_stop。依存先停止は進捗差分0・予約とservice ID保持も必要。
- 完了・課金1回: shift_completion(1080、交代前)/ recovery_completion / same_minute_replay(再送・重複生成0)。
- 孤立0: closure_release / exit_release / patience_release / paused_midnight。直接休業ではD-034の開始済み継続と待機予約解放を区別。停止日跨ぎは停止中課金0と復帰完了課金各1回。
- 決算1回: midnight_settlement / midnight_replay / save_restore。売上・給与・維持費・勤務分の支払い各1回、非ゼロ給与を必須とし、帰属先は新しく決めない。
- night_staff_absent: 1081、夜番0、WAITING_FOR_STAFF。
- overtime_task: 既存interrupt_level=0の残業と勤務分記録1回(staff_service:1409-1412)。
authorityの参照名はREQUIREDに固定。BASELINE文書、D-034文書、既存A01を記録した入力草案のraw bytesをcheckoutと照合する。A01を再承認しない。承認2条件はauthority typeの同梱D05_OWNER_APPROVAL.jsonと同一SHA256(4583ee9aad45c4db183d72df4420df48aa8e0897e3b5efda13016f0b5cdbd68e)を要求する。origin=direct_user_reply、formal_acceptance=falseと承認IDも確認する。
save_restore条件にはsave_artifact(type=save)とrestore_receiptを追加する。元caseのreceiptのsaved_sha256、readerのrestored_sha256を保存raw hashと照合し、別の正整数PID・終了・exit 0・source/environment一致・stdout/native_logを要求する。保存packageの意味的完全性・正式保存APIの利用は生証拠の独立レビュー対象。
reachabilityはEV/transportのみ。各source_refはpath/sha256/start/end/textで、固定REACH_REFSの経路を全て含み、実際の行本文と一致すること。reason必須。救護搬送は課金予約reach=false。EVはスタッフ移動前予約経路があるためreach=trueとcase_idを必要とする。停電domainのengine case.afterのev.reserved_before_travel=true、power_stopped=true、orphan_reservations=0のeq invariantを要求する。客の到着後予約だけを根拠にEV全体を除外できない。
specは契約文字列hashと照合し、checkoutの末尾LF一つの表現差だけを許容する。その他のraw hashは正規化しない。
## worker確認
checker_negative_fixtures.pyはallowed_paths内の一時ディレクトリをBUILD_OUTPUT_DIRに使用し、終了後削除する。py_compile、対照用合成index(exit 0、正式受入false)、指定10負例(各exit 1、対応エラー)を確認済み。実engine試験・Runner操作は0。Runnerがp04-acceptanceを正式実行し、Rootが現版適用性、別セッションのreviewerが生証拠由来と意味を独立確認する。
The fresh R collection is B/audit-support/p04-raw-collect-r22. It re-reads existing
C/S1/S2a/S2b/S3 without native reruns and newly collected S4; no result scalar is
authority. It binds the current verifier hash. The old r17/r20 collection and
21615-check proof remain immutable. New checker bytes differ; no1339 identity
claim. Missing raw, changed pins, mandatory undefined rules or unsupported
joins must fail. Final index/applicability, registered validation, support53cb
registered rebind, independent review, normal integration and individual
nativeWindows obligations remain Root work. No final acceptance is asserted.
@@ -1,233 +1,64 @@
# P04-01: C段階の結合とrepair4収集契約の履歴
# Current evidence plan — repair22, NOT RUN
## repair6 現在値(2026-10-16、以下の旧blocked記述に優先)
Use s4/S4_ROOT_RUN.md for the exact finite fresh plan and complete input, QA,
source and output footprints inside own B. One native collection has four
phases: import, parse, Writer, Reader. Do not rerun C/S1/S2a/S2b/S3. Preserve all
existing raw and full R17 relocation. External old paths are provenance only.
旧値: 実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内へ限定し削除する。
After S4 succeeds on this auto-submitted source, Root runs the existing eight
local suites once. The worker has executed none. First run these seven from the submitted checkout:
```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
export B=/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build
export E=docs/plans/original-completion-2026-10-02/execution/p04-01
export BUILD_OUTPUT_DIR="$B"
export PYTHONDONTWRITEBYTECODE=1
python3 "$E/bulk_reader_equivalence.py"
python3 "$E/checker_negative_fixtures.py"
python3 "$E/checker_applicability_fixtures.py" --native-bundle "$B/audit-support/native-first-current"
python3 "$E/checker_native_fixtures.py" "$B/audit-support/native-first-current"
python3 "$E/checker_series_fixtures.py" --build "$B"
python3 "$E/checker_encoder_fixtures.py"
python3 "$E/checker_join_fixtures.py" --build "$B"
```
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を比較し、コメント・空白・改行を正規化しない。先頭宣言は
`<top-level>` 単位として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)。
The read-only R verifier/collector must then bind the new verifier to all existing
raw plus S4. This does not launch native runs or overwrite old collections:
```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
python3 "$E/collect_p04_native.py" --build "$B"
```
最後のコマンドはindex未収集ならexit 1が期待値。Python正対照はengine証明ではない。
**Cのchecker強化、Dのparameter patch/不足probe、Eのowned/count/restore/他候補流用負例は未完成。**
旧checkerのscalar/receipt自己申告を受入可能な証拠とみなしてはならない。
現在のcheckerを正式受入に使用せず、修正全体をblockedとしてRootへ返す。
Its exclusive destination is B/audit-support/p04-raw-collect-r22. The index
builder/checker now reference that collection and all five series. Root must
prepare the corresponding current index through the normal schema2 path before
its role/cross-gate controls can succeed; an old r20 index is not valid new
evidence. After the new R collection and normal index preparation, run the eighth
suite against that refreshed index:
native収集の正確なコマンド列は、上記入力と未完成patchがないため提示できない。
仮のコマンドを実行可能と偽って提示しない。共有stageでimport+parseを2プロセス、
midnight/power/exit/shift/destruction/save Writer/save Reader/EVを8プロセスに
束ねられれば計10プロセスが計画目安になるが、これは確定数・目標数ではない。
条件ごとに必要な状態系列とguard成立を優先する。
Rootのnative収集→validate→別セッション独立レビュー→通常統合は未実施。
```sh
python3 "$E/checker_role_fixtures.py" --build "$B" --evidence "$B/p04-evidence"
```
No Root command or metadata bypass is invented here. Use registered
runner.validate("P04-01") with its unchanged timeout and exact new submission,
then the normal independent review/integration process.
Rebind support53cb through its normal registered task after the new P04 source
is known. Do not edit metadata to force applicability. Source-only preparation
does not wait for future Root-native/index/cross-gate work.
The existing21615-check full proof is immutable. Its1339 selected map contains
exactly the R17 product1338 plus the checker; static raw-map comparison found no
product hash difference. The178 product suites do not execute this checker;
the316-file .gd parse roster excludes .py. Thus the prior proof is a QA-only
product applicability candidate, conditional on Root checking the complete
source/config/input/environment dependencies. It is not new-checker validation,
S4 evidence, a byte-identical1339 proof, or final acceptance. Never splice raw
from different versions.
No blanket full run now. If formal policy requires an exact final1339 run,
perform it once only after all fixes, S4 raw, local checks/eight suites and the
support rebind are bundled on the final source, to a fresh destination. Existing
full/parse/marker outputs are neither regenerated nor relabelled by this worker.
15 conditions + EV, seven domains, three safety outcomes,30/88 and original
13/88 remain unchanged. S4 and all new validation are pending.
@@ -1,52 +1,21 @@
# P04-01 監査状態
# P04-01 current order audit — repair22
原単位は未完了。D05-P04-DEPENDENCY と D05-P04-SHIFT-1800 は direct_user_reply により承認済み(同梱 D05_OWNER_APPROVAL.json、SHA256 4583ee9aad45c4db183d72df4420df48aa8e0897e3b5efda13016f0b5cdbd68e)。承認は試験合格を意味しない。A01の00:00保有時間按分維持費は承認済みで再確認しない。
Source preparation only; tests and S4 native collection **NOT RUN**. No final acceptance or integration. This is the single current seven-domain table; matching machine data is in order-audit.json.
正式試験はRunnerが実行する。旧証跡参照は来歴であり、現版の生証跡・ソース・設定・入力・環境の適用性確認なしに合格として再利用しない。
| Domain | Normative rule | Current source | Evidence | Approved authority | Pending D05 |
| --- | --- | --- | --- | --- | --- |
| 閉店 | D-034: direct closure releases waiting requests and continues started service. Approved dependency closure holds progress/payment and preserves reservation/service ID until one completion. | Runtime._advance_facilities; Runtime._advance_guest_queues; Runtime._release_closed_business_queues; FacilityService._prepare_service_for_tick | C dependency/formal and S2a paused-midnight are existing raw candidates. S3 B1 is combined dependency/closure diagnostic only; no power_stop or priority credit. | D-034; D05-P04-DEPENDENCY | Strict power-vs-closure/dependency priority remains unknown; B1 does not approve it. |
| 停電 | BASELINE:183 mana depletion stops facilities. A legitimately power-stopped service must not progress/charge; retain reservation identity and complete once after recovery. This does not approve a simultaneous-cause priority. | Runtime._advance_mana; ManaNetworkService.advance_one_minute; ManaNetworkService._evaluate_component; mana_power_projection.apply; FacilityService._prepare_service_for_tick | S1 existing raw covers reserved staff/EV safety, not a paid service. S4 ONLY supplies power_stop; pending Root execution, no raw/credit yet. S3 B1 excluded. | BASELINE:183; P04-01 safety acceptance | Strict power-vs-closure priority and unspecified EV/cost ordering remain pending. |
| 破壊 | No charge while legitimately failed/stopped and no orphan reservation. Distinguish command destruction before facility processing from late INCIDENTS event destruction after completion; observation is not normative priority approval. | Runtime._process_tick_commands; Runtime._advance_defense; FacilityService._prepare_service_for_tick; FacilityService._fail_service | S3 B4a completion then destruction and B4b next-tick failure/release are existing raw candidates; C remains frozen. | P04-01 safety acceptance; BASELINE:183 (existing fixed registry; no new destruction priority authority) | Any mandatory destruction-vs-completion priority beyond approved sources requires owner decision; current code alone is not authority. |
| 退出 | Leave/abandon releases the owned reservation once; no orphan or duplicate charge. Preserve D-034. Completion, queue release and later normal despawn are distinct observations. | Runtime._execute_leave_facility_queue; Runtime._leave_guest_queue_boundary; Runtime._advance_guest_queues; Runtime._advance_guest_ai_decisions | S3 B2a/B2b/B3 raw completion/leave/patience; B1 normal departure history diagnostic. S4 has no departure trigger at outage/hold. | D-034; P04-01 safety acceptance | Unspecified simultaneous exit/cost priority remains pending; no inferred priority from labels. |
| 課金 | No stopped charge; one sale per completed service and idempotent resend. Reservation consumption, actual sale and payment key must join by service ID and original priceSnapshot. | FacilityService._complete_service; Runtime._complete_service_transaction; Runtime._apply_service_transaction; EconomyService.post | C dependency/recovery, S2a paid midnight and resend, S3 diagnostic completions are existing raw. S4 isolated stop/one recovery sale pending Root. | P04-01 safety acceptance; D05-P04-DEPENDENCY; D05-P04-SHIFT-1800 | Other cost timing/attribution is not supplied or approved here. |
| シフト交代 | Approved [17:59,18:00) work belongs to day staff: complete/pay once at18:00 then switch; night work starts [18:00,18:01). | Runtime._advance_facilities; Runtime._advance_staff_ai; StaffService.advance_one_minute; Runtime._sync_facility_staffing | C actual-native first1080 sale with dynamic PID/transaction joins; S2b no-night1081 and overtime. Paid-midnight filenames do not substitute for C shift completion. | BASELINE:64; BASELINE:67; D05-P04-SHIFT-1800 | Approved shift interval is not reopened; any additional simultaneous-cause priority remains pending. |
| 00:00決算 | A01 approved ownership-prorated upkeep at midnight is retained. One daily close/payroll/upkeep, no duplicate replay/reload; distinguish prior [0,1440) accounting and sale at1440. | Runtime._advance_facility_upkeep; Runtime._advance_operations_time; OperationsCoordinator._process_minute_boundaries; OperationsCoordinator._process_daily_close | C paused-midnight/formal and S2a full raw nonzero payroll/upkeep/service/typed restore are existing candidates. S1/S2b/S3 cannot substitute settlement proof; S4 adds none. | BASELINE:71; BASELINE:72; A01; D05-P04-DEPENDENCY | Unspecified cost/day attribution remains pending; do not reopen A01. |
## 現行ソースの観測
The full source bodies, actual line numbers, hashes and graph-restore analysis are in REPAIR22_SOURCE_FACTS.json. The existing R17 source relocation contains all1338 product inputs. Existing raw is available in own B; old external paths are provenance only. Source observations do not approve design priorities.
`scripts/core/simulation_kernel.gd:123-153` の順序は APPLY_COMMANDS → 時計増分・日境界signal → TIME_BOUNDARIES → MANA → CONSTRUCTION → LOGISTICS → FACILITY_COMPLETION → VITALS_AND_ENVIRONMENT → INCIDENTS_AND_EVENTS → FACILITY_QUEUES → AI_DECISIONS → PUBLISH_SNAPSHOT。同phase内はhandler IDの辞書順(242行)。Runtimeの登録は364-427行。時計や製品ロジックは変更していない。
S4 captures the normal 960 evaluation outage, 961 held point and 970 recovery after the source-derived ten-minute hold. It keeps the linked kitchen OPEN / network ACTIVE, global mana positive and operator open. It adds no counted condition. B1 remains a combined dependency/closure diagnostic only. Strict power-vs-closure priority is D05 pending/unknown. If priority is mandatory, the owner can approve dependency-first or power-first reason selection while retaining no-charge/hold safety; neither candidate is approved here.
| 領域 | 現行呼出しと先後 | 原本・承認・不足 |
| --- | --- | --- |
| 閉店 | `_advance_facilities` の後、`_advance_guest_queues` が `_release_closed_business_queues` を実行し、patienceより先に予約解放を試みる。 | 直接休業はD-034の開始済サービス継続。依存先休業は承認済D05の進捗・課金停止、予約・ID保持、復帰後1回完了。旧business試験は部分候補。open serviceの00:00証拠を代用しない。 |
| 停電 | `_advance_mana` → `mana_power_projection.apply` → FacilityService `_prepare_service_for_tick`。NO_POWERはpause、復電はresume。 | 草案の961停止/962復電/963不変は生証跡未確認。進捗・予約・帳簿・通知を現版で確認する必要がある。 |
| 破壊 | commandはAPPLY_COMMANDSで先行。`_advance_defense` は完了後のINCIDENTS。BROKENはサービス準備時に失敗。 | 先行破壊44と後段完了45を区別。失敗診断も保持し、原本適合と断定しない。 |
| 退出 | 公開queue leave → 完了 → INCIDENTS → queue patience解放 → AI再計画/予定退出。LEAVINGのdespawnは入状態分より後。 | 公開leave・自動patience・overdue退出の正式保存/別PID証跡は参照のみ。孤立0を現版で証明する必要がある。 |
| 課金 | `_complete_service` callback → `_complete_service_transaction` → `_apply_service_transaction`。予約消費後、service IDによるpayment keyで記帳し、通知scopeを終了。 | 原価格・時間を変えない。静的なidempotency keyの存在や試験数だけで二重課金・二重生成なしとしない。 |
| シフト交代 | 完了後の `_advance_staff_ai` 内でstaff更新・commute・staffing投影。 | 原本64/67行の18:00交代を保持。承認済D05により[17:59,18:00)は昼番、18:00完了・課金後に交代。夜番は[18:00,18:01)から。1080診断を承認規約に格上げしない。 |
| 00:00決算 | TIME_BOUNDARIESのweather/upkeep/operationsが完了より先。OperationsCoordinatorのdaily closeと同分service売上は別区間。 | 原本71/72行、承認済A01を保持。1440一回/1441不変の生証跡と適用性が必要。給与0fixtureを非ゼロ給与証拠に数えない。 |
REPAIR17–21 documents (listed in order-audit.json) remain untouched historical records and are superseded for current status by this table, CHECKER_PROTOCOL.md, EVIDENCE_COLLECTION.md and REPAIR22_STATUS.md. Prior B1 power credit and blanket final1339 rerun directions are superseded.
## 再利用の制限
詳細ハッシュ・7領域の不足は `order-audit.json` に記録した。ローカル旧mapはSHA256 `df8328ea8b6a7bc400caad8a52f6ead710c01942a726e5a6b530b82411c55da5`、1299件、欠落0件。主要6ソースの指定pinは一致。旧mapとの差は14件で、契約記載のRuntime/main/preview/performance/path/2試験の7件に加え、Kenney同梱サンプル/URL7件がバイト不一致だった。追加7件は後述のRunner支援入力で分類し、素材を編集していない。
修正入力で旧Runtimeのローカルrawコピーを受領し、SHA256 `2d7e2cea5424585e9aa4302ab66d1fc4dbaefe743ce4328fccc1efa2f19b82e4` を確認した。`git diff --no-index` による現Runtimeとの差分は4箇所で、客候補経路batch、施設入口の経路費用比較、客/スタッフの移動時間推定、connector credit helper抽出に関わる。Runtime内のphase登録・施設完了順序はこの差分では変わらないが、変更されたPathServiceと到達性・選択・到着・勤務見積りへの影響を個別確認する必要がある。追加7素材差分はRunner supportがCRLF→LFのみと報告し、現raw hashを照合した。旧raw素材は未供給のため正規化一致を独立再現したとは扱わない。
ローカル入力は旧summary/map/draftであり、生の保存package・stdout・engineログ・開始終了記録・設定・入力・環境証拠は提供されていない。外部worktreeのartifactパスは来歴に留め、読んでいない。正式保存8境界27状態、fresh Reader A/B、P04-02/fullの成功記載は未検証参照で、P04-01受入を意味しない。
## 提出状態と有限検証計画
今回の承認2条件と既存権限(BASELINE:64/67/71/72/183、D-034、A01)を分け、checker内の固定条件レジストリに対応付けた。費用時点・日跨ぎの帰属など残るD05はpendingのまま補完しないが、一括failの理由にはしない。売上・給与・維持費・勤務分の各1回、非ゼロ給与、停止の00:00またぎでも完了課金1回・予約孤立0は必須である。全条件を満たすとmachine_verified=true、formal_acceptance=false、exit 0。必須条件のauthorityがpendingなら失敗する。
承認4文書は全てバイト数とSHA256を再計算し、SOURCE_MANIFESTと一致。必要な承認JSONのみ2073 bytesを同梱した。初期空き容量約1.8GiB、旧39 artifactの複製なし。39件の原パスは来歴であり、今回のミラーは承認4文書のみ。生証拠・入力・設定・環境が不足しているので、境界の適用性合格は宣言しない。
順序関数20本は今回個別に本文を再ハッシュし、供給されたhistorical_body_sha256と20/20一致した(詳細はJSON repair3)。旧監査の29本とは合算しない。旧Runtime rawも再ハッシュし、git diff --no-indexでは5個の@@区間(候補batchの開始・終了が別区間)、論理的な変更は記録の4箇所と確認した。関数一致は経路・候補・到着の適用性を保証しない。PathService変更を含め、停電・破壊・退出の影響ケースはRootが生証拠と設定を照合し、不適用の場合だけ新しい有限境界証拠を作る。production Runtime 4696df4aとcheckout d52a995の差も統合前にRootが確認する。
### 到達性
- 営業時間による閉店: autoload/scriptsの検索ではset_opening_hoursの定義とサービスの委譲のみ。既定[0,1440)で製品呼出しなし。直接休業と依存先休業の証拠は引き続き必須。
- 客の通常EV移動: Runtime:8898-8922の到着後にqueueを要求し、7421-7445で予約する。この移動前予約経路は対象外。
- スタッフEV: 対象外にできない。公開create_staff_task(Runtime:329、6733-6742)でrequired_itemsを渡せる。task_dispatcher:256-261、293-294、309-314が移動前に予約し、Runtime:9141-9170が在庫予約を実施、12009-12013で移動へ進み、8755-8763、8946-8987からEVを利用する。set_powered(elevator_service:279-284)による停電はこの予約保持経路に到達する。checkerはEV全体のreach=falseを拒否し、予約保持中停電のengine caseと孤立0 invariantを要求する。EV停止規則や期限は新設しない。
- 救護搬送: Runtime:12023-12030は治療状態を更新するだけ、12976-13050は救護タスク生成・移動・取消でrequired_items・課金処理を持たない。物理搬送自体でなく、課金・予約の到達性がfalse。静的根拠の行・本文・hashを必須とし、7領域の分母に加えない。
### 有限検証と残件
workerはpython3 -m py_compileとchecker_negative_fixtures.pyを実行。index欠落、重複キー、symlink、hash不一致、stale pin、未実行receipt、pending authority、必須条件欠落、根拠なしreach=false、承認hash不一致の10例が期待した理由でexit 1。合成対照のみexit 0であり、エンジン由来の製品証拠ではない。最初の対照実行はspec pinで失敗した。契約のspec文字列は末尾LFなし、checkout JSONは末尾LF一つ付きであり、その厳密な表現差のみ許容後、上記確認が通った。仕様ファイルは変更していない。
1. Runnerがp04-acceptanceを正式実行する。
2. Rootが旧証拠の適用性と不足を独立確認する。非ゼロ給与の00:00、停止の00:00またぎ、再送、正式保存→別PID復元、夜番不在18:01、既存残業タスク、予約保持中EV停電の証拠を揃える。
3. 別セッション独立レビューと通常統合のfinalまで正式受入加算0。nativeWindowsは条件ごとにpending。
エンジン実行・Runner操作・Git書込み・他エージェント起動は0。原30パッケージ/88成果の既存1単位内の準備であり、成果追加0、正式完了0。
15 conditions + EV, seven domains, three safety outcomes and30 packages/88 deliveries remain fixed. Original13/88 gains no credit; CurrentAlphaScope and P04 main9b stay frozen. Required Root execution, exact-version binding, support53cb registered rebind, independent review and integration remain pending. A01 and the two approved D05 choices are not reopened.
@@ -61,5 +61,38 @@
"unexecuted proof, incomplete7domain or required boundary coverage",
"selfreported pass/test count as substitute for actual state invariants"
],
"implementation_note": "Implement this finite mechanical protocol and document exact supported predicates. If evidence is absent, output actual missing IDs and exit nonzero. No requirement to create fake pass evidence. Do not change source/Clock/game numbers; no engine/test run by worker."
"implementation_note": "Implement this finite mechanical protocol and document exact supported predicates. If evidence is absent, output actual missing IDs and exit nonzero. No requirement to create fake pass evidence. Do not change source/Clock/game numbers; no engine/test run by worker.",
"revision": "repair22",
"status": "source preparation; NOT RUN; no final acceptance",
"accepted_index_schema_versions": [
1,
2
],
"schema2_note": "Current candidate-role/index binding uses the existing schema2 implementation. Legacy field descriptions below are not a replacement schema.",
"current_order_table": "order-audit.json",
"series_collection": "BUILD_OUTPUT_DIR/audit-support/p04-raw-collect-r22",
"power_stop_binding": {
"only_series": "S4",
"status": "pending Root execution",
"required_reason": "NO_POWER",
"related_facility_operating": true,
"kitchen_power_available": true,
"global_mana": ">0",
"operator_open": true,
"formal_points": [
"boundary",
"held",
"recovered"
],
"canonicalization": false,
"dropped_fields": false
},
"B1": {
"scope": "combined dependency/closure diagnostic only",
"power_stop_evidence": false,
"priority_approval": false
},
"D05_power_vs_closure": "pending/unknown; approval candidates in order-audit.json",
"history": "REPAIR17-21 untouched historical documents, superseded for current status by repair22.",
"version_policy": "Product1338 unchanged; checker differs. Preserve21615-check proof; QA-only applicability requires complete dependency checks. No1339 byte identity claim; support53cb normal registered rebind; at most one final exact full rerun if required after bundling."
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,73 @@
{
"scope": "AST/static source checks and in-memory compile ONLY; no module imports or execution of task code",
"python": [
{
"path": "tools/check_p04_order_evidence.py",
"bytes": 78399,
"sha256": "a61c5b496e656f60c66898e42500bc9a2d45f947690ce8f5f19a03984ebbc850",
"AST": "parsed",
"in_memory_compile": "compiled; not executed"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/p04_native_series.py",
"bytes": 72591,
"sha256": "667c95e10c451239292b08589706bfef978de730b321151ae7845dd10a06c411",
"AST": "parsed",
"in_memory_compile": "compiled; not executed"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_join_fixtures.py",
"bytes": 7888,
"sha256": "f89ee6b835a8b0dc47f804686f7e338e7178c24a5a30a8a25bcd8bf59dfbea0c",
"AST": "parsed",
"in_memory_compile": "compiled; not executed"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_series_fixtures.py",
"bytes": 6779,
"sha256": "f91b2d7003fd5c8cd196f849ad392d37479317e7d109eb584ccde5e5073e5bee",
"AST": "parsed",
"in_memory_compile": "compiled; not executed"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/collect_p04_native.py",
"bytes": 2996,
"sha256": "d727230de0af94dfc7e68bec40e84ecaa86a5b98d5e5bc16c2a35fe9c67fa12d",
"AST": "parsed",
"in_memory_compile": "compiled; not executed"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/build_p04_index.py",
"bytes": 9246,
"sha256": "47ae05b7bec617063e5d4fca2d8687f25e2eee0f809b5676ec91cf21c3223773",
"AST": "parsed",
"in_memory_compile": "compiled; not executed"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s4/run_s4_native.py",
"bytes": 18623,
"sha256": "03a0aaab7e824d1b516ee4c6b456913439515c03daa687b5822cdfefb4d54c46",
"AST": "parsed",
"in_memory_compile": "compiled; not executed"
}
],
"gd_validation": "static text/declaration review only; engine parse NOT RUN",
"gd_sha256": "ceb592d853fd50063f20496c7b6df05257528dbe1c0d0d80bc6a8ccb1f9dd6d7",
"C_frozen": {
"exact_equal_to_immutable_full_stage": true,
"bytes": 20918,
"sha256": "5d778b3cfab7c139ca03812489508ce9aae90c1d17f8c2249c340f30d1496b3b",
"body_with_one_final_LF_sha256": "33ae2af6afb98b48919ed679ab8519b7da7ddfda68c00f71c557d5cc9aad4a6c"
},
"required_registry_unchanged": true,
"required_conditions": 15,
"EV": "additional existing obligation, unchanged",
"domains": 7,
"product_input_files": 1338,
"parse_gd_files": 316,
"native_runs": 0,
"fixture_runs": 0,
"tests": "NOT RUN",
"S4_raw": "pending Root execution",
"formal_acceptance": false
}
@@ -0,0 +1,82 @@
# Repair22 — source-ready submission; NOT RUN
This batch changes only `tools/check_p04_order_evidence.py` and this P04-01
documentation subtree. No Git command, test/fixture, engine, Runner operation,
agent, manual commit or integration was performed. The normal autosubmit owns
the submitted revision; the contract base SHA is not a new evidence version.
S3 B1 no longer supplies `power_stop`. Its full diagnostic checks remain under
`dependency_closure_diagnostic`, including the actual dependency reason,
closure/release, departure history and recovery sale. It approves no priority.
Strict power-vs-closure order remains D05 pending/unknown. The existing approvals
cover dependency hold and the18:00 shift interval only; A01 is not reopened.
S4 is a new minimal single-case QA probe using the existing ActorHardening,
physical-kitchen and guarded Writer/Reader pattern. It cuts the actual sole
cafeteria edge at959, waits for normal evaluation/projection at960, retains the
held state at961, reconnects that same edge, and waits normally through the
source-derived hold until970. Source constants were re-read as10/10. No forced
evaluation, hold bypass, direct power/progress/patience/capacity writes or
product edits are introduced. Kitchen Facility.OPEN / network ACTIVE, positive
mana, operating dependency and open operator distinguish it from B1.
Three formal Writer points and separate-process Reader restores retain every
typed Runtime field and all four SaveService members. Reconnect resend at970
must leave the full Runtime unchanged; normal971 and Reader replay add no
extra sale/completion. Full intermediate phase raw is preserved. All graph
nodes, cut/restored edge sets, revisions, allocation and derived dependency
restoration are checked. Normal post-completion guest redecision/despawn is
retained, not forced or concealed; no exit accompanies the outage/hold.
R now derives shift PID and sale IDs from the existing full raw joins. S1 joins
the existing pre-travel reservation/task/staff cell to the boarded task/trip,
and checks actual mana0 and elevator loss of power. The existing join fixtures
are retained and extended with the requested semantic negatives and consistent
dynamic-ID positive controls. Existing C25 and all other fixture sources remain
in place. No fixture result is claimed: S4 positives await actual Root raw.
ORDER_AUDIT.md and order-audit.json are one current seven-domain table with
normative rules, source, C/S1/S2a/S2b/S3 evidence, pending S4, approved authority
and pending D05. REPAIR17–21 remain untouched historical documents and outputs;
their current-status claims are superseded by repair22. The current protocol,
collection plan and this status agree: no final acceptance.
Static validation is recorded in REPAIR22_STATIC_VALIDATION.json:
- Seven Python files parsed with AST and compiled in memory; none imported or
executed. GDScript received static text/source review only; engine parse NOT RUN.
- The entire frozen C region is byte-identical to the preserved full-stage
checker. Its one-final-LF body hash is
`33ae2af6afb98b48919ed679ab8519b7da7ddfda68c00f71c557d5cc9aad4a6c`, matching
the supplied repair21 C_FULL_BLOCK_EXACT receipt. Existing C checks are intact.
- The complete15-condition registry matches that immutable source; EV, seven
domains and three safety outcomes are unchanged. Product1338 inputs and the
316-file `.gd` parse roster were counted from the actual relocation manifest.
- The five supplied public power bodies were compared to their actual relocated
source. Full bodies, hashes, timing and restore analysis are retained in
REPAIR22_SOURCE_FACTS.json.
The exact finite Root plan is `s4/S4_ROOT_RUN.md`: one fresh own-B four-phase
collection, with explicit arguments and full input/QA/source footprints. All
old C/S1/S2a/S2b/S3 raw and all R17 sources remain accessible and are not rerun.
S4 remains **missing/pending Root execution**. Future native/index/cross-gate
work does not block this source submission. The updated collector/index
references use a fresh r22 destination; no r17/r20 evidence is overwritten.
Preserve the21615-check proof. Static full-map comparison found exactly the
unchanged product1338 plus the old checker in its1339 map. The new checker hash
differs; never claim1339 byte identity. The178 product suites do not invoke the
checker and `.py` is excluded from the316 parse roster, so reuse requires the
explicit QA-only source/config/input/environment applicability argument in
EVIDENCE_COLLECTION.md. New-checker validation and S4 are separate, pending.
Root must rebind support53cb through its normal registered task once the new
source is known, without metadata bypass. Only if an exact final1339 full proof
is required, perform one run after all fixes, S4 raw, local checks, eight suites
and rebind are bundled; do not splice versions or perform a blanket full now.
No required source context is missing for this preparation. Remaining D05
choices are explicitly pending and not silently implemented. Formal validation,
independent review, exact final-source applicability and normal integration
remain pending. CurrentAlphaScope,30 packages/88 deliveries, original13/88 and
P04 main9b are unchanged. P04 receives no credit; nothing is integrated.
@@ -74,8 +74,8 @@ def payload(build, gate=None):
for row in gate.load(native / 'OWNERSHIP_RAW_PROVENANCE.json')['copied']:
references['C/' + row['target']] = descriptor(gate.safe(native, row['target']))
series = {}
collection = build / 'audit-support/p04-raw-collect-r20'
for name in ('s1', 's2a', 's2b', 's3'):
collection = build / 'audit-support/p04-raw-collect-r22'
for name in ('s1', 's2a', 's2b', 's3', 's4'):
series[name] = gate.load(collection / (name + '.json'))
relocation = gate.load(build / 'audit-support/p04-r17-full-inputs-r01/MANIFEST.json')
authorities = {}
@@ -26,10 +26,12 @@ def run(build):
raise AssertionError('negative accepted: ' + name)
context = series.Series(build, 's3')
series.power_stop(context)
series.dependency_closure_diagnostic(context)
reject('B1_cannot_supply_power_stop', lambda: series.power_stop(context))
results.append({'case': 'B1_real_despawn_positive', 'result': 'accepted'})
original_value = context.value
for name, label, mutate in (
('dependency_reason_relabelled_as_NO_POWER', 'after', lambda r: r['service'].update(interruption_reason='NO_POWER')),
('B1_missing_at_closure', 'after', lambda r: r['guests'].update({'p04.s3.guest.b': {}})),
('B1_synthetic_later_guest', 'next', lambda r: r['guests'].update({'p04.s3.guest.b': {'patience_remaining': 45}})),
('B1_wrong_release_minute', 'next', lambda r: r['reservations'][1].update(terminal_at=961)),
@@ -42,7 +44,7 @@ def run(build):
mutate(value)
return value
with patch.object(context, 'value', altered):
reject(name, lambda: series.power_stop(context))
reject(name, lambda: series.dependency_closure_diagnostic(context))
gate.verify_shift_completion(base)
results.append({'case': 'R2_real_first_1080_positive', 'result': 'accepted'})
original_load = gate.load
@@ -61,6 +63,89 @@ def run(build):
return value
with patch.object(gate, 'load', altered):
reject(name, lambda: gate.verify_shift_completion(base))
# Dynamic IDs are legitimate when every raw join agrees. These are semantic
# overlays of already verified raw, not replacement native evidence.
shift = gate.verify_shift_completion(base)
old_pids = gate.native_ownership(base)
replacements = {pid: pid + 1000000 for pid in old_pids.values()}
replacements[shift['transaction_id']] = 'dynamic-sale-repair22'
def remap(value):
if isinstance(value, dict): return {k: remap(v) for k, v in value.items()}
if isinstance(value, list): return [remap(v) for v in value]
if isinstance(value, (str, int)) and not isinstance(value, bool):
return replacements.get(value, value)
return value
with patch.object(gate, 'load', lambda path: remap(original_load(path))):
dynamic = gate.verify_shift_completion(base)
assert dynamic['transaction_id'] == 'dynamic-sale-repair22'
results.append({'case': 'R2_dynamic_PID_and_transaction_positive', 'result': 'accepted'})
wrong_end = base / 'actual-native' / gate.NATIVE_RUNS['actual-native'][0] / 'ended.json'
def wrong_pid(path):
value = original_load(path)
if path == wrong_end: value['actual_pid'] += 1
return value
with patch.object(gate, 'load', wrong_pid):
reject('R2_wrong_PID_join', lambda: gate.verify_shift_completion(base))
s1 = series.Series(build, 's1')
series.s1_semantics(s1)
s1_value = s1.value
for name, mutate in (
('S1_pre_travel_mismatch', lambda r: r['reserved_before_travel'].update(staff_cell=(6, 0, 1))),
('S1_no_actual_outage', lambda r: r['reserve_exhausted_before_tick']['snapshot']['game_state']['resources'].update(mana=1)),
):
def altered(key, mutate=mutate):
value = copy.deepcopy(s1_value(key))
if key == 'writer-landing-observations': mutate(value)
return value
with patch.object(s1, 'value', altered):
reject(name, lambda: series.s1_semantics(s1))
# S4 is deliberately unavailable until the single Root collection exists.
# Never substitute B1 or manufacture a positive raw fixture for it.
s4 = series.S4Series(build)
series.power_stop(s4)
results.append({'case': 'S4_real_NO_POWER_positive', 'result': 'accepted'})
s4_value = s4.value
def facility_change(row, field, value, kitchen=False):
target = row['kitchen' if kitchen else 'facility']
target[field] = value
for f in series.runtime(row)['facilities']['instances']:
if f['instance_id'] == target['instance_id']: f[field] = value
for name, mutate in (
('S4_related_facility_operating_false', lambda r: r.update(related_facility_operating=False)),
('S4_kitchen_unpowered', lambda r: facility_change(r, 'power_available', False, kitchen=True)),
('S4_closure_confound', lambda r: facility_change(r, 'operator_open', False)),
('S4_no_actual_outage', lambda r: facility_change(r, 'power_available', True)),
('S4_wrong_transaction_join', lambda r: series.runtime(r)['economy']['idempotency'].clear()),
):
def altered(key, mutate=mutate, name=name):
value = copy.deepcopy(s4_value(key))
label = 'recovered' if name == 'S4_wrong_transaction_join' else 'boundary'
if key == 'writer-S4-' + label: mutate(value)
return value
with patch.object(s4, 'value', altered):
reject(name, lambda: series.power_stop(s4))
# Rename every occurrence, including service.payment.<serviceID> keys.
original = s4_value('writer-S4-before')['service']
paid = series.sales(s4_value('writer-S4-recovered'))[0]
id_map = {original['service_id']: 'dynamic-service-22', paid['transaction_id']: 'dynamic-sale-22',
'service.payment.' + original['service_id']: 'service.payment.dynamic-service-22'}
def dynamic_ids(value):
if isinstance(value, dict): return {id_map.get(k, k): dynamic_ids(v) for k, v in value.items()}
if isinstance(value, list): return [dynamic_ids(v) for v in value]
return id_map.get(value, value) if isinstance(value, str) else value
with patch.object(s4, 'value', lambda key: dynamic_ids(s4_value(key))):
assert series.power_stop(s4)['transaction_id'] == 'dynamic-sale-22'
results.append({'case': 'S4_dynamic_service_and_sale_positive', 'result': 'accepted'})
return {'scope': 'semantic controls only; no new native execution', 'results': results}
@@ -46,7 +46,7 @@ def run(build):
results.append({'series': 'shared', 'class': 'small_synthetic_positive', 'result': 'pass'})
link = base / 'symlink.gd'
link.symlink_to(path)
for name in s.RUNS:
for name in s.NATIVE_PINS:
context = s.Series.__new__(s.Series)
context.build, context.run, context.references = base, s.RUNS[name], {}
body_row = {'path': 'body.gd', 'function': 'boundary',
@@ -16,7 +16,7 @@ def encoded(value):
def collect(build):
build = Path(build).absolute()
destination = build / 'audit-support/p04-raw-collect-r20'
destination = build / 'audit-support/p04-raw-collect-r22'
series.require(not destination.exists() and not destination.is_symlink(), 'collection destination already exists')
for p in (destination.parent, *destination.parents):
series.require(not p.is_symlink(), 'collection parent symlink')
@@ -1,520 +1,182 @@
{
"input_hashes": {
"docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/ORDER_CONTRACT_DRAFT.md": "c4dd8b907321b8859ba0744b9ae3d1447615d98fbe548983f9bb9fcad2d9d989",
"docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/input.json": "1286f865656aafb6146c7bcd95c92c53c00b6c706f3f690d96e998d5e45e2b79",
"docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/historical-audit.json": "90d2dbd3c04aed7ab409afa4f05f884832a4661cc506d28b818c72aadc352950",
"docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/historical-source-map.json": "df8328ea8b6a7bc400caad8a52f6ead710c01942a726e5a6b530b82411c55da5"
},
"source_pins": {
"autoload/simulation_runtime.gd": {
"expected": "d52a995ae715542bbc550f68d35889540658275d12e04ae0b21ac276f5843f39",
"actual": "d52a995ae715542bbc550f68d35889540658275d12e04ae0b21ac276f5843f39",
"matches": true
},
"scripts/facility/facility_service.gd": {
"expected": "ceb4a3e9224587423f273cdb2b56e6843ab176ac1fc4fe79dd498b5ed5c33b77",
"actual": "ceb4a3e9224587423f273cdb2b56e6843ab176ac1fc4fe79dd498b5ed5c33b77",
"matches": true
},
"scripts/economy/economy_service.gd": {
"expected": "95aedd0a0421c93e8fa39f0f76fa890cd0a46905d9a25c88c8b17c4d6d47728e",
"actual": "95aedd0a0421c93e8fa39f0f76fa890cd0a46905d9a25c88c8b17c4d6d47728e",
"matches": true
},
"scripts/guest/guest_service.gd": {
"expected": "56880410e9a00816f9a95d30821982955532de8dd976980934e12016a9f2b21e",
"actual": "56880410e9a00816f9a95d30821982955532de8dd976980934e12016a9f2b21e",
"matches": true
},
"scripts/staff/staff_service.gd": {
"expected": "355ad5c3c9f85dc4d4ffc3bc4293e36f81078c403d1662512a735b2c8d815fb3",
"actual": "355ad5c3c9f85dc4d4ffc3bc4293e36f81078c403d1662512a735b2c8d815fb3",
"matches": true
},
"scripts/mana/mana_network_service.gd": {
"expected": "96f195cf2a28b0966d12cd7c6fab86d13eae97c8342d07d70f52e598fbf49af9",
"actual": "96f195cf2a28b0966d12cd7c6fab86d13eae97c8342d07d70f52e598fbf49af9",
"matches": true
}
},
"historical_map_entries": 1299,
"differences": [
{
"path": "assets/kenney/tiny_dungeon/Tiled/sampleMap.tmx",
"old_sha256": "fc545787837e2655c9d2078cc1b167df0d9ea2755f6ec3912c7987e8501339e3",
"current_sha256": "3849e083e3d4f6a71dbf725d8473e93fa6ef8cdc9d314368eee15c980cf41775"
},
{
"path": "assets/kenney/tiny_dungeon/Tiled/sampleSheet.tsx",
"old_sha256": "02f1b90cfdb37bcccddc83d074954272aaffd297ed4fabce7bb670f2f3f4be71",
"current_sha256": "a2cca2c5e50b14023ce00f5d4112fb0b8264bfff9407d7a5198656e28d67fa16"
},
{
"path": "assets/kenney/tiny_dungeon/Visit Kenney.url",
"old_sha256": "0dd1a0b295582cd3185547f0c1d92b4d5392c7782b90a428e192944a496052e0",
"current_sha256": "6787defa3ecb6118622e1903b65802c0200628fae5164b51b4fd467f92f3f284"
},
{
"path": "assets/kenney/tiny_dungeon/Visit Patreon.url",
"old_sha256": "84be5ef26b07905fa7e196e943c9807bf84138c3a71d87f51c6fd57b85c48c34",
"current_sha256": "2fcba31333935f4aa35e9de2e74e2b7ba1b1a8011540e08016ff6d81e9dd7490"
},
{
"path": "assets/kenney/tiny_town/Tiny Dungeon (base pack).url",
"old_sha256": "6cf442be20ad3364ba87183461744da9e979b5d4f243c83e2404f2cf884500d9",
"current_sha256": "6d93bb958f9b7d5f21ceb8cbd24c184dc5c9f87aee7c680b336ecba7a89823d8"
},
{
"path": "assets/kenney/tiny_town/Visit Kenney.url",
"old_sha256": "0dd1a0b295582cd3185547f0c1d92b4d5392c7782b90a428e192944a496052e0",
"current_sha256": "6787defa3ecb6118622e1903b65802c0200628fae5164b51b4fd467f92f3f284"
},
{
"path": "assets/kenney/tiny_town/Visit Patreon.url",
"old_sha256": "84be5ef26b07905fa7e196e943c9807bf84138c3a71d87f51c6fd57b85c48c34",
"current_sha256": "2fcba31333935f4aa35e9de2e74e2b7ba1b1a8011540e08016ff6d81e9dd7490"
},
{
"path": "autoload/simulation_runtime.gd",
"old_sha256": "2d7e2cea5424585e9aa4302ab66d1fc4dbaefe743ce4328fccc1efa2f19b82e4",
"current_sha256": "d52a995ae715542bbc550f68d35889540658275d12e04ae0b21ac276f5843f39"
},
{
"path": "scenes/main/main.gd",
"old_sha256": "a7ae44c680eb9b70a117ddc8c6cbf0ca290b8e8d485eac41b4122698fde2a620",
"current_sha256": "a3d7d7ddd08a8df1f987806e60accf51792d728cf71c06e6b822f5a31d8ed3e3"
},
{
"path": "scenes/main/world_preview.gd",
"old_sha256": "3df29be32d3a016d8fb9dc1ee2bd32e2360ac8fad9810293f6be9b58d26046e0",
"current_sha256": "75d5b0bd23204f5a485540512e44b89e1d2a4596b368f70177a238ba078ff42d"
},
{
"path": "scripts/core/performance_budget.gd",
"old_sha256": "79d18e8f0dcc3932801cd02ea8a8ba037af02ef57665387cba8dbe3b3e9af917",
"current_sha256": "0e2278f88d29919a0634fc1b527328a0d0c12d87e2cd612f3eee1526aabdb073"
},
{
"path": "scripts/world/path_service.gd",
"old_sha256": "2e68653e4898387cb5a76402813a10595bd5ca7d5fb841c7ed8c55af77d7a918",
"current_sha256": "447135729a1106639a6eee6754af3195c8a8b458ca26980ae91fa39d80dcfbd4"
},
{
"path": "tests/s1/test_path_service.gd",
"old_sha256": "0f48bb44c27e32f08477b9aed61a0db5c8808219490928f734c3570a07efb251",
"current_sha256": "17d9fd42b35004376bf96e435f53d6bce41e79258ec7f6daf3ab04ae5d8c3e1d"
},
{
"path": "tests/ui/test_pixel_tower.gd",
"old_sha256": "93bdbb195f2ceec07dbe052e0d0a3017d84b56f1e8ec46b87be8d98105ec0f88",
"current_sha256": "f149f4b5507247dadf623e777e90b9bdb81f54324b406a8f55adaf89b649866a"
}
],
"missing_map_paths": [],
"revision": "repair22",
"status": "source preparation; NOT RUN; no final acceptance",
"task_id": "P04-01",
"base_commit": "deb1bcb2374eb378b840ca345db952bd8572cb6e",
"status": "submitted",
"original_unit_complete": false,
"counted_units_added": 0,
"tests_executed": false,
"authority": {
"owner_approved": {
"artifact": "D05_OWNER_APPROVAL.json",
"sha256": "4583ee9aad45c4db183d72df4420df48aa8e0897e3b5efda13016f0b5cdbd68e",
"bytes": 2073,
"origin": "direct_user_reply",
"formal_acceptance": false,
"conditions": [
"D05-P04-DEPENDENCY",
"D05-P04-SHIFT-1800"
],
"approval_is_not_test_pass": true
},
"existing": [
"BASELINE:64/67/71/72/183",
"D-034 docs/DESIGN_DECISIONS.md:252-258",
"A01 already approved; not reopened"
"current_table": true,
"scope": {
"conditions": 15,
"additional_EV_obligation": true,
"domains": 7,
"safety_outcomes": [
"no stopped charging",
"no double midnight settlement",
"no orphan reservations"
],
"remaining_pending": "Cost/day attribution remains pending; do not infer new policy. Required safety counts remain mandatory; no blanket D05 rejection."
"packages": 30,
"deliveries": 88,
"original_credit": "13/88 unchanged; P04 receives zero credit",
"CurrentAlphaScope": "unchanged",
"main_9b": "frozen; nothing integrated"
},
"phase_order": "scripts/core/simulation_kernel.gd:123-153: APPLY_COMMANDS, clock increment/calendar boundary signals, TIME_BOUNDARIES, MANA, CONSTRUCTION, LOGISTICS, FACILITY_COMPLETION, VITALS_AND_ENVIRONMENT, INCIDENTS_AND_EVENTS, FACILITY_QUEUES, AI_DECISIONS, PUBLISH_SNAPSHOT. Handler IDs sorted lexically within phase at line242.",
"domains": [
{
"domain": "閉店",
"current_functions": [
"simulation_runtime._advance_facilities",
"simulation_runtime._advance_guest_queues",
"simulation_runtime._release_closed_business_queues",
"simulation_runtime._release_closed_business_request"
"normative_rule": "D-034: direct closure releases waiting requests and continues started service. Approved dependency closure holds progress/payment and preserves reservation/service ID until one completion.",
"current_source": [
"Runtime._advance_facilities",
"Runtime._advance_guest_queues",
"Runtime._release_closed_business_queues",
"FacilityService._prepare_service_for_tick"
],
"order": "Direct closure follows D-034: release waiting requests, continue started services. Dependency closure pauses progress/payment and preserves reservation/service IDs until recovery under D05-P04-DEPENDENCY.",
"old_evidence": "Historical phases 001/002: business closure/operations; midnight open-service proof cannot establish closure behavior.",
"missing": "Exact-version direct/dependency closure evidence; approval is supplied, not a pass."
"evidence": "C dependency/formal and S2a paused-midnight are existing raw candidates. S3 B1 is combined dependency/closure diagnostic only; no power_stop or priority credit.",
"approved_authority": [
"D-034",
"D05-P04-DEPENDENCY"
],
"pending_D05": [
"Strict power-vs-closure/dependency priority remains unknown; B1 does not approve it."
]
},
{
"domain": "停電",
"current_functions": [
"simulation_runtime._advance_mana",
"normative_rule": "BASELINE:183 mana depletion stops facilities. A legitimately power-stopped service must not progress/charge; retain reservation identity and complete once after recovery. This does not approve a simultaneous-cause priority.",
"current_source": [
"Runtime._advance_mana",
"ManaNetworkService.advance_one_minute",
"ManaNetworkService._evaluate_component",
"mana_power_projection.apply",
"FacilityService._prepare_service_for_tick",
"FacilityService._complete_service"
"FacilityService._prepare_service_for_tick"
],
"order": "Commands precede MANA power projection, then facility completion. NO_POWER pauses active service and power recovery resumes it.",
"old_evidence": "Draft reports formal 961 stop/962 recovery, fresh Reader A/B, one consume/notification and unchanged economy at 963; raw not supplied.",
"missing": "Exact-source/config/input/environment raw stop/recovery proofs including same reservations and all ledgers."
"evidence": "S1 existing raw covers reserved staff/EV safety, not a paid service. S4 ONLY supplies power_stop; pending Root execution, no raw/credit yet. S3 B1 excluded.",
"approved_authority": [
"BASELINE:183",
"P04-01 safety acceptance"
],
"pending_D05": [
"Strict power-vs-closure priority and unspecified EV/cost ordering remain pending."
]
},
{
"domain": "破壊",
"current_functions": [
"simulation_runtime._process_tick_commands",
"simulation_runtime._advance_defense",
"normative_rule": "No charge while legitimately failed/stopped and no orphan reservation. Distinguish command destruction before facility processing from late INCIDENTS event destruction after completion; observation is not normative priority approval.",
"current_source": [
"Runtime._process_tick_commands",
"Runtime._advance_defense",
"FacilityService._prepare_service_for_tick",
"FacilityService._fail_service"
],
"order": "Command destruction precedes facility processing; INCIDENTS_AND_EVENTS destruction follows completion. BROKEN fails during service preparation.",
"old_evidence": "Draft reports early failure44/charge0/release once, late destruction after completion45 and next-minute failure for incomplete service.",
"missing": "Verified raw early/late destruction and failed diagnostic history; current infrastructure/path applicability."
"evidence": "S3 B4a completion then destruction and B4b next-tick failure/release are existing raw candidates; C remains frozen.",
"approved_authority": [
"P04-01 safety acceptance",
"BASELINE:183 (existing fixed registry; no new destruction priority authority)"
],
"pending_D05": [
"Any mandatory destruction-vs-completion priority beyond approved sources requires owner decision; current code alone is not authority."
]
},
{
"domain": "退出",
"current_functions": [
"simulation_runtime._execute_leave_facility_queue",
"simulation_runtime._leave_guest_queue_boundary",
"simulation_runtime._advance_guest_queues",
"simulation_runtime._advance_guest_ai_decisions"
"normative_rule": "Leave/abandon releases the owned reservation once; no orphan or duplicate charge. Preserve D-034. Completion, queue release and later normal despawn are distinct observations.",
"current_source": [
"Runtime._execute_leave_facility_queue",
"Runtime._leave_guest_queue_boundary",
"Runtime._advance_guest_queues",
"Runtime._advance_guest_ai_decisions"
],
"order": "Public leave command precedes completion; patience release occurs in queues; AI replanning/planned exit follows. LEAVING despawns only after state-entered minute.",
"old_evidence": "Draft reports public reservation release, automatic45-minute patience and completion-before-exit boundaries.",
"missing": "Exact-version leave/patience and overdue-LEAVING reload proofs, no orphan reservations and replay generation checks."
"evidence": "S3 B2a/B2b/B3 raw completion/leave/patience; B1 normal departure history diagnostic. S4 has no departure trigger at outage/hold.",
"approved_authority": [
"D-034",
"P04-01 safety acceptance"
],
"pending_D05": [
"Unspecified simultaneous exit/cost priority remains pending; no inferred priority from labels."
]
},
{
"domain": "課金",
"current_functions": [
"normative_rule": "No stopped charge; one sale per completed service and idempotent resend. Reservation consumption, actual sale and payment key must join by service ID and original priceSnapshot.",
"current_source": [
"FacilityService._complete_service",
"simulation_runtime._complete_service_transaction",
"simulation_runtime._apply_service_transaction",
"Runtime._complete_service_transaction",
"Runtime._apply_service_transaction",
"EconomyService.post"
],
"order": "Completion callback consumes reservations then posts service.payment.<service_id>; notification scope ends after transaction effects. Static code alone does not prove all boundary rollback paths.",
"old_evidence": "P04-02 and historical full are references only; test counts do not establish P04-01 original acceptance.",
"missing": "Raw ledger/inventory/notification proof for stopped, failed, replay and paid completion paths; closure/shift rule dependent proof."
"evidence": "C dependency/recovery, S2a paid midnight and resend, S3 diagnostic completions are existing raw. S4 isolated stop/one recovery sale pending Root.",
"approved_authority": [
"P04-01 safety acceptance",
"D05-P04-DEPENDENCY",
"D05-P04-SHIFT-1800"
],
"pending_D05": [
"Other cost timing/attribution is not supplied or approved here."
]
},
{
"domain": "シフト交代",
"current_functions": [
"simulation_runtime._advance_facilities",
"simulation_runtime._advance_staff_ai",
"normative_rule": "Approved [17:59,18:00) work belongs to day staff: complete/pay once at18:00 then switch; night work starts [18:00,18:01).",
"current_source": [
"Runtime._advance_facilities",
"Runtime._advance_staff_ai",
"StaffService.advance_one_minute",
"simulation_runtime._sync_facility_staffing"
"Runtime._sync_facility_staffing"
],
"order": "Approved D05-P04-SHIFT-1800: [17:59,18:00) belongs to day shift, completion/payment once at 18:00 before switching; night shift begins [18:00,18:01).",
"old_evidence": "Historical phase083 hardening includes shift-end interruption; draft retains diagnostic1080 predicate failure without claiming original violation.",
"missing": "Applicable 1080 completion/replay, 1081 WAITING_FOR_STAFF with no night staff, and existing overtime task evidence."
"evidence": "C actual-native first1080 sale with dynamic PID/transaction joins; S2b no-night1081 and overtime. Paid-midnight filenames do not substitute for C shift completion.",
"approved_authority": [
"BASELINE:64",
"BASELINE:67",
"D05-P04-SHIFT-1800"
],
"pending_D05": [
"Approved shift interval is not reopened; any additional simultaneous-cause priority remains pending."
]
},
{
"domain": "00:00決算",
"current_functions": [
"simulation_runtime._advance_facility_upkeep",
"simulation_runtime._advance_operations_time",
"normative_rule": "A01 approved ownership-prorated upkeep at midnight is retained. One daily close/payroll/upkeep, no duplicate replay/reload; distinguish prior [0,1440) accounting and sale at1440.",
"current_source": [
"Runtime._advance_facility_upkeep",
"Runtime._advance_operations_time",
"OperationsCoordinator._process_minute_boundaries",
"OperationsCoordinator._process_daily_close",
"simulation_runtime._complete_service_transaction"
"OperationsCoordinator._process_daily_close"
],
"order": "TIME_BOUNDARIES weather/upkeep/operations precedes facility completion; prior day[0,1440) accounting differs from sale at1440. A01 upkeep already approved.",
"old_evidence": "Draft reports real settlement/payroll/upkeep once, service25 once, unchanged ledgers/history1441; zero payroll fixture is not proof of nonzero payroll.",
"missing": "Current raw midnight/retry/reload idempotency proof and applicable nonzero payroll boundary; full original conformity review."
"evidence": "C paused-midnight/formal and S2a full raw nonzero payroll/upkeep/service/typed restore are existing candidates. S1/S2b/S3 cannot substitute settlement proof; S4 adds none.",
"approved_authority": [
"BASELINE:71",
"BASELINE:72",
"A01",
"D05-P04-DEPENDENCY"
],
"pending_D05": [
"Unspecified cost/day attribution remains pending; do not reopen A01."
]
}
],
"old_evidence_applicability": {
"raw_available_for_reuse": false,
"assessment": "39 references in supplied recheck retain old Runtime 2d7e2cea provenance; raw artifacts not supplied here. 20 function bodies independently rehashed in this checkout, matching supplied historical hashes, not the old 29-function count. No blanket boundary reuse.",
"source": "14 byte differences, zero missing mapped paths; six immutable current pins match.",
"config_input_environment": "Not established by raw local evidence; each required proof must pin these independently.",
"runtime_git": "Verified supplied old SHA2d7e2cea; git diff --no-index compared exact raw old/current Runtime. Four hunks affect _project_guest_candidates batching, _find_facility_access_path cost selection, _estimated_actor_path_minutes and extracted connector-credit helper. Completion/phase registration unchanged in this file; callees PathService changed, therefore reachability, choice, arrival and staff estimates require finite applicability evidence.",
"known_difference_impact": "Runtime/PathService may alter infrastructure, movement, staffing, guest selection and recovery boundary reachability; UI/main/preview and performance budget changes prevent blanket whole-full reuse. Two changed tests cannot supply old exact-version evidence. Seven additional Kenney metadata/sample byte differences require applicability classification, not product edits."
},
"blockers": [
"D05 dependency closure and 18:00 interval are approved; approval is not test success.",
"Raw 39 historical artifacts, settings/input/environment and engine receipts are not mirrored here. Their hashes in recheck are provenance, not verified current evidence.",
"Nonzero-payroll midnight, paused midnight, replay/separate-PID save restoration and reachable EV reservation safety need applicable raw evidence.",
"Root must independently assess affected power/destruction/exit paths and production Runtime 4696df4a versus checkout d52a995 before integration."
"source_facts": "REPAIR22_SOURCE_FACTS.json",
"authority": "D05_OWNER_APPROVAL.json approves dependency and shift only; original BASELINE/D-034/A01 retain their scope",
"historical_superseded": [
"REPAIR17_STATUS.md",
"REPAIR18_STATUS.md",
"REPAIR19_CORRIGENDUM.md",
"REPAIR19_STATUS.md",
"REPAIR20_CORRIGENDUM.md",
"REPAIR20_STATUS.md",
"REPAIR21_STATUS.md"
],
"validation_plan": [
"Runner runs p04-acceptance; worker only py_compile and synthetic negative fixture checks.",
"Root verifies source/config/input/environment applicability for power, destruction, exit cases affected by four Runtime hunks and PathService changes; fresh finite boundaries only if reuse fails.",
"Require nonzero payroll midnight, stop crossing midnight, same-minute resend, formal save and different PID restore, no-night-staff 18:01, existing overtime task, and reachable reserved-staff EV safety evidence.",
"Do not reopen A01 or invent cost/day attribution. Pending unrelated D05 does not fail the whole gate.",
"Root rechecks production Runtime 4696df4a against immutable checkout d52a995, then independent review in separate session and normal integration. Formal credit remains zero."
"history_policy": "REPAIR17-21 retained byte-for-byte as historical; this table and REPAIR22_STATUS.md supersede current-status/collection claims.",
"evidence_policy": "Existing complete C/S1/S2a/S2b/S3 raw and full R17 relocated sources are accessible in own B. Old manifest production paths are provenance lookup keys only; never follow them. All current semantic verifiers/tests NOT RUN by worker.",
"pending": [
"S4 four-phase Root collection",
"eight local suites and normal registered validation",
"current checker/QA/source applicability and index/cross-gate binding",
"support53cb rebind through registered task",
"independent review and normal integration",
"nativeWindows obligations individually pending"
],
"repair_support": {
"hashes": {
"support.json": "36f7443daabf37070ecc331e708a6749816630bf0466ebb2a814aaf647a84410",
"runtime-diff.patch": "7ba08537c5e86d0505f2b4df56d29877064c70acc4fa9f12089fefa09e78b707",
"historical-runtime.txt": "2d7e2cea5424585e9aa4302ab66d1fc4dbaefe743ce4328fccc1efa2f19b82e4"
},
"historical_runtime_verified": true,
"production_differences": 7,
"managed_differences": 14,
"additional7_classification": "Runner support reports CRLF to LF only; current raw hashes checked. Old raw metadata absent, normalization not independently reproduced; no acceptance equivalence claim."
},
"repair3": {
"space_available": "1.8 GiB before work; bounded source reads and ~small text changes, no raw archive copies needed",
"approval_material_verification": [
{
"file": "D05_OWNER_APPROVAL.json",
"bytes": 2073,
"sha256": "4583ee9aad45c4db183d72df4420df48aa8e0897e3b5efda13016f0b5cdbd68e",
"manifest_matches": true
},
{
"file": "README.md",
"bytes": 1029,
"sha256": "7b1c8992a8c5298d3ad416a5ff667a49f6e1eafea149fb6abb9e91e517e47c0f",
"manifest_matches": true
},
{
"file": "recheck.json",
"bytes": 46479,
"sha256": "44b32fa297c3c8f81691505878232756b3d63e0d5a801a6ae15173b84894bd22",
"manifest_matches": true
},
{
"file": "OPUS_D05_CANDIDATE.json",
"bytes": 6653,
"sha256": "54cd83971467744b1009e72c56e7b5d558c97073540d027640e486f7b5b5a34b",
"manifest_matches": true
}
],
"ordering_functions": [
{
"path": "scripts/core/simulation_kernel.gd",
"function": "advance_one_minute",
"line": 122,
"sha256": "b9587ef722d8c8640248025462819374ae5eca1c3d8bbe600b6bc9c328567777",
"matches_supplied_historical_body_hash": true
},
{
"path": "scripts/core/simulation_kernel.gd",
"function": "_run_phase",
"line": 236,
"sha256": "52461eeb288892a4bb4b6a99570185af08a30758ef88b0046a911baaa6f318e1",
"matches_supplied_historical_body_hash": true
},
{
"path": "scripts/core/simulation_kernel.gd",
"function": "_handle_time_boundaries",
"line": 254,
"sha256": "2ced47a2911b36def9d89de82a43afc69148ead44d19db6a2a6c7bce5a910ae9",
"matches_supplied_historical_body_hash": true
},
{
"path": "scripts/core/command_queue.gd",
"function": "_comes_before",
"line": 409,
"sha256": "21f7f9f7c0923121fd0a022a2f7546b7bb7117a9979c1ed25d0b33b96e28ab28",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_process_tick_commands",
"line": 5736,
"sha256": "9de66a4bb84b12304300d49085f44546412319bd4aee91e67b61becf97e50294",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_operations_time",
"line": 1894,
"sha256": "511580d1fac3d2785072e94c2981065fa47ba18b1c97122922645dac5c0d94ab",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_run_operations_deferred_suffix",
"line": 1683,
"sha256": "12075307b12cbb66ffda47a26097194a07fad9d6467e3e557bd7269315c98982",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_mana",
"line": 10633,
"sha256": "05c54626ce6e355acd92994ab80aaf2177c5cf194885e66934552139e087599e",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_facilities",
"line": 8421,
"sha256": "f1efd0c23bdd60d1ef19a21879640b53b8b4d88844c0c881fe7cd724387ec274",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_guest_vitals",
"line": 8427,
"sha256": "8226ca18c983ac576a74e772cc3088e9fe52b362ffba1b71255bd1d7623c1234",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_staff_ai",
"line": 8597,
"sha256": "0e222987f7c5e25583dbaba8fe63784aa563715067396e8d31d10bd191e7179b",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_guest_ai_decisions",
"line": 8677,
"sha256": "e33b41294e88dba840affd5cc0a5c58fe5d46f5d98a80a8d5f4e907a3b9a7b93",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_release_closed_business_queues",
"line": 12562,
"sha256": "3a05fbe94877eeb750fb0d692501954555ab6a8005448ab3b6023dab9bad816b",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_release_closed_business_request",
"line": 12580,
"sha256": "6dbde3a3d425e47a049dcc4f05eae6f01fe9784f473c0fb1019a0633c239d83b",
"matches_supplied_historical_body_hash": true
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_complete_service_transaction",
"line": 11707,
"sha256": "f2b6e96a8eeef3dd3f8419b4d9d5ef4e1d13241600ce970bdd78a924428cac6c",
"matches_supplied_historical_body_hash": true
},
{
"path": "scripts/facility/facility_service.gd",
"function": "advance_one_minute",
"line": 544,
"sha256": "59c0e89b4dca291e3ec02601b3f7c5544dba7c823fc137e0e7a50e7d5319e0ed",
"matches_supplied_historical_body_hash": true
},
{
"path": "scripts/facility/facility_service.gd",
"function": "_prepare_service_for_tick",
"line": 853,
"sha256": "b35c2c0fb23a04258b71995dd7c3b6dfacbbcdf36106e2e3348acef0e18d21cc",
"matches_supplied_historical_body_hash": true
},
{
"path": "scripts/facility/facility_service.gd",
"function": "_complete_service",
"line": 895,
"sha256": "494edfd11cb3e896d73c2c6fdbe7c1193efce6d869b105e526d2f1dfd1168142",
"matches_supplied_historical_body_hash": true
},
{
"path": "scripts/facility/facility_service.gd",
"function": "_fail_service",
"line": 933,
"sha256": "56f61b255217bddb4c8a6ad3af6ed1f9edc3b6a6e928dacf2105be6698936de5",
"matches_supplied_historical_body_hash": true
},
{
"path": "scripts/operations/operations_coordinator.gd",
"function": "_process_minute_boundaries",
"line": 882,
"sha256": "1312166dc17aee0ef470069a73ff3fe6b86d11d04ca7de76f3d04f1d2d14674e",
"matches_supplied_historical_body_hash": true
}
],
"ordering_function_count": 20,
"historical_29_not_combined": true,
"nativeWindows": {
"power_stop": "pending",
"destruction_stop": "pending",
"dependency_stop": "pending",
"shift_completion": "pending",
"recovery_completion": "pending",
"same_minute_replay": "pending",
"closure_release": "pending",
"exit_release": "pending",
"patience_release": "pending",
"paused_midnight": "pending",
"midnight_settlement": "pending",
"midnight_replay": "pending",
"save_restore": "pending",
"night_staff_absent": "pending",
"overtime_task": "pending",
"EV": "pending"
},
"spec_representation": {
"raw_sha256": "d28aadb044633f7d804de5a92c8d4c4a7438dfbf44c3243dca978951f4def25f",
"contract_sha256": "9ec722e7dfb0bee178d291624a026420c08412574e238bba1fde012c7a6f7881",
"difference": "exactly one final LF; no spec edits"
},
"worker_validation": {
"py_compile": "passed",
"negative_fixture_count": 10,
"negative_results": "all exit 1 with intended error; synthetic control exit 0/formal_acceptance=false",
"engine_runs": 0,
"runner_operations": 0,
"formal_acceptance": false
},
"runtime_diff_hunks": 5,
"reachability": {
"guest_EV": {
"reach": false,
"scope": "normal guest automatic service reservation before arrival",
"source_refs": [
"Runtime:8898-8922 arrival -> queue -> create_service_request",
"Runtime:7421-7445 reserve -> create request"
]
},
"staff_EV": {
"reach": true,
"scope": "public create_staff_task required_items can reserve before EV travel",
"source_refs": [
"Runtime:329,6733-6742 public task creation",
"task_dispatcher.gd:256-261,293-294,309-314 reserve before assignment",
"Runtime:5320,9141-9170 inventory callback",
"Runtime:12009-12013 begin_moving",
"Runtime:8755-8763,8946-8987 EV travel",
"elevator_service.gd:279-284 set_powered"
],
"required": "power-stop case with reserved-before-travel items; orphan_reservations=0; nativeWindows pending"
},
"transport": {
"reach": false,
"scope": "rescue transport payment/reservation only; physical movement is reachable",
"source_refs": [
"Runtime:12023-12030 completion heals only",
"Runtime:12976-13050 rescue pickup/transport creation, no required_items/reservation/payment"
],
"counted_domain_added": false
},
"opening_hours": {
"reach": false,
"scope": "production time-of-day closure",
"source_refs": [
"facility_instance.gd default [0,1440)",
"set_opening_hours: definitions/service wrapper only; no autoload caller"
],
"direct_closure_remains_required": true
}
},
"path_applicability": {
"source_refs": [
"scripts/world/path_service.gd:1055-1101",
"scripts/world/path_service.gd:1302-1319",
"Runtime:9222-9268,9296-9300,12798-12812,12838-12848"
],
"power": "Stop/resume core unchanged, but if fixture reaches a facility through guest candidate/connector routes or staff arrival, pins/function equality alone do not prove the same stopped-service boundary. Root must inspect route and arrival observations.",
"destruction": "Command-before-completion and incident-after-completion order unchanged; infrastructure/connector destruction can alter selected/access path and arrival, so only those route-dependent cases need current applicability confirmation.",
"exit": "Release callbacks unchanged; MOVING target selection/arrival/overdue exit can use the changed paths, so confirm their raw state and arrival minute before reuse.",
"path_service": "Batch only with connectors, default layers and empty access; settled tree path/cost, fallback on unusable tree/wrapped cost. Caller estimate can affect arrival even though phase functions match.",
"verdict": "No affected case accepted from summaries alone; raw source/config/input/environment evidence remains a Root prerequisite."
},
"runtime_logical_change_groups": 4,
"runtime_diff_note": "Default git diff emits 5 textual hunks: batch begin/end split into two; four logical change groups in commander direction."
}
"priority_candidates_if_required": [
"Approve dependency-first reason when both dependency and power fail, retaining stop/hold/no-charge safety.",
"Approve power-first reason when both fail, with separate approved implementation task if code must change."
],
"collection_plan": "s4/S4_ROOT_RUN.md",
"formal_acceptance": false,
"original_unit_complete": false
}
@@ -17,7 +17,7 @@ MANIFEST_SHA256 = 'a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c
MANIFEST_BYTES = 1244135
PRODUCT = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1'
RUNS = {'s1': 'p04-s1-native-r02', 's2a': 'p04-s2a-native-r03',
's2b': 'p04-s2b-native-r02', 's3': 'p04-s3-native-r01'}
's2b': 'p04-s2b-native-r02', 's3': 'p04-s3-native-r01', 's4': 'p04-s4-native-r22'}
# Native descriptors pinned from literal files, never ROOT result passed fields.
NATIVE_PINS = {
's1': ('1e26d9585396da9415747d87d77b70f23425a3ee0714e4fca114748f9479fd4e', '01372beb0ffec181c892d3b4e88bce32001e08fb2007938d7bf19135511a7acc', '0b6d11eb34d8af64b22cb806caeb06eed4ec521fa9ee24d1204ea185345e655c'),
@@ -509,6 +509,41 @@ def sales(observation):
return [r for r in observation['ledger'] if r['category'] == 'SERVICE_SALE']
def s1_pretravel(s, branch, points):
"""Join the full existing pre-travel observation, never a summary boolean."""
observations = s.value('writer-' + branch + '-observations')
pre = observations['reserved_before_travel']
exhausted = observations['reserve_exhausted_before_tick']
boarded, depleted = points['boarded'], points['depleted']
task, trip = boarded['task'], boarded['trip']
prior = pre['task']
require(prior['task_id'] == task['task_id'] and
prior['assigned_staff_id'] == task['assigned_staff_id'] and
prior['reservation_ids'] == task['reservation_ids'] and
pre['reservations'] == boarded['reservations'] and
all(r['state'] == 'ACTIVE' and r['requester_id'] == prior['task_id']
for r in pre['reservations']), 'S1 pre-travel reservation/task mismatch')
state = runtime(pre)
workers = [w for w in state['staff']['staff'] if w['staff_id'] == prior['assigned_staff_id']]
require(len(workers) == 1 and tuple(workers[0]['current_cell']) == pre['staff_cell'] == (5, 0, 1)
and workers[0]['current_task_id'] == prior['task_id'] and
prior in state['staff']['tasks'] and pre['reservations'] == state['inventory']['reservations'],
'S1 pre-travel staff cell/task/raw reservation join')
require(pre['trip'] == {} and pre['elevator_report']['trips'] == [] and
pre['minute'] < trip['enqueued_at'] <= boarded['minute'] and
trip['actor_id'] == 'staff:' + prior['assigned_staff_id'], 'S1 reservation precedes travel')
require(exhausted['minute'] == boarded['minute'] and exhausted['trip'] == trip and
exhausted['task'] == task and exhausted['reservations'] == boarded['reservations'] and
exhausted['snapshot']['game_state']['resources']['mana'] == 0 and
depleted['snapshot']['game_state']['resources']['mana'] == 0 and
depleted['minute'] == exhausted['minute'] + 1, 'S1 actual reserve exhaustion/tick')
for point, powered in ((boarded, True), (depleted, False)):
shafts = [r for r in point['elevator_report']['shafts'] if r['shaft_id'] == trip['shaft_id']]
saved = [r for r in runtime(point)['elevators']['shafts'] if r['config']['shaft_id'] == trip['shaft_id']]
require(len(shafts) == len(saved) == 1 and shafts[0]['powered'] is powered and
saved[0]['powered'] is powered, 'S1 actual elevator power outage')
def s1_semantics(s):
for branch in ('landing', 'no-safe-landing'):
points = {}
@@ -517,6 +552,7 @@ def s1_semantics(s):
w, r = s.typed('writer-' + label), s.typed('reader-' + label)
require(w.at('snapshot').raw == r.at('snapshot').raw, 'S1 typed formal replay mismatch')
points[point] = w.plain()
s1_pretravel(s, branch, points)
boarded = points['boarded']
task, trip = boarded['task'], boarded['trip']
require(trip['state'] == 'BOARDED' and trip['actor_id'] == 'staff:' + task['assigned_staff_id'], 'S1 task/trip actor join')
@@ -691,12 +727,12 @@ def s3_semantics(s):
sales(terminal)[0]['amount'] == 25, 'completion-before-exit/event actual charge')
observed[case] = {'sales': len(sales(terminal)), 'amount': sum(r['amount'] for r in sales(terminal)),
'reservation_states': [r['state'] for r in terminal['reservations']]}
observed['B1_power'] = power_stop(s)
return ['closure_release', 'exit_release', 'patience_release', 'destruction_stop', 'power_stop'], observed
observed['B1_dependency_closure_diagnostic'] = dependency_closure_diagnostic(s)
return ['closure_release', 'exit_release', 'patience_release', 'destruction_stop'], observed
def power_stop(s):
"""B1's observed power boundary, retaining its actual dependency reason."""
def dependency_closure_diagnostic(s):
"""B1 combined dependency/closure diagnostic; no power_stop or priority credit."""
labels = ('before', 'after', 'next', 'recovered', 'duplicate_guard')
points = [s.value('writer-B1-' + label) for label in labels]
before, after, next_, recovered, guard = points
@@ -805,6 +841,231 @@ def power_stop(s):
'payment': 25, 'interruption_reason': 'RELATED_FACILITY_INACTIVE'}
def power_stop(s):
"""Only the isolated S4 native NO_POWER path can supply this condition."""
require(s.name == 's4', 'power_stop requires S4; B1 is dependency/closure diagnostic only')
points = [s.value('writer-S4-' + label) for label in
('before', 'boundary', 'held', 'recovered', 'duplicate_guard')]
before, boundary, held, recovered, guard = points
pin = s.resolver.manifest['product_source']['scripts/mana/mana_network_service.gd']
source = s.resolver.read(pin['path'], pin).decode()
interval, hold = [int(re.search(r'const ' + key + r' := (\d+)\b', source)[1])
for key in ('EVALUATION_INTERVAL_MINUTES', 'MINIMUM_OFF_HOLD_MINUTES')]
resume = ((boundary['minute'] + hold + interval - 1) // interval) * interval
require(before['minute'] == 959 and boundary['minute'] == 960 and held['minute'] == 961 and
boundary['minute'] % interval == 0 and recovered['minute'] == resume and
guard['minute'] == resume + 1, 'S4 source-derived evaluation/hold minutes')
original = before['service']
fid, sid = original['facility_id'], original['service_id']
require(len(before['reservations']) == len(original['inventory_reservations']) == 1, 'S4 one original reservation')
topology = before['inputs']['recovery']['original_graph']
neighbour = before['inputs']['recovery']['neighbour']
edge = sorted([fid, neighbour])
require(edge in topology['edges'] and sum(fid in e for e in topology['edges']) == 1,
'S4 actual sole previous neighbour')
identity = ('service_id', 'request_id', 'facility_id', 'guest_ids', 'inventory_reservations',
'price_snapshot', 'duration_minutes', 'started_at', 'staff_ids')
for index, point in enumerate(points):
state, facility, service, kitchen = runtime(point), point['facility'], point['service'], point['kitchen']
graph = state['mana']
require(point['ledger'] == state['economy']['entries'] and
point['reservations'] == state['inventory']['reservations'], 'S4 full raw economy/inventory join')
requests = [r for r in state['facilities']['requests'] if r['request_id'] == original['request_id']]
if index < 3:
require(len(requests) == 1 and requests[0] == point['requests'][original['request_id']] and
requests[0]['reserved_inventory_ids'] == original['inventory_reservations'], 'S4 active request/reservation owner')
else:
require(requests == [] and point['requests'][original['request_id']] == {} and
len(point['reservations']) == 1 and point['reservations'][0]['terminal_at'] == resume,
'S4 consumed reservation/no orphan request')
require([f for f in state['facilities']['instances'] if f['instance_id'] == fid] == [facility] and
[f for f in state['facilities']['instances'] if f['instance_id'] == facility['related_facility_id']] == [kitchen],
'S4 raw facility/dependency join')
candidates = state['facilities']['service_history'] + [v for f in state['facilities']['instances'] for v in f['active_services']]
require([v for v in candidates if v['service_id'] == sid] == [service] and
all(service[k] == original[k] for k in identity), 'S4 original service identity')
require(point['related_facility_operating'] is True and kitchen['power_available'] is True and
kitchen['state'] == 'OPEN' and kitchen['operator_open'] is True,
'S4 related facility must remain operating/powered')
require(facility['operator_open'] is True and facility['durability'] == before['facility']['durability'] > 0 and
point['event'] == {} and facility['active_staff_ids'] == before['facility']['active_staff_ids'] and
len(facility['active_staff_ids']) >= facility['staff_min'], 'S4 closure/damage/shift confound')
guest = point['guests'][original['guest_ids'][0]]
require(point['snapshot']['game_state']['resources']['mana'] > 0, 'S4 global outage confound')
if index < 3:
require(guest['planned_exit_at'] > resume and guest['state'] == 'RECEIVING_SERVICE',
'S4 no exit at outage/hold')
require(point['graph_invariants'] == {'valid': True, 'errors': []}, 'S4 graph invariants')
expected_edges = [e for e in topology['edges'] if e != edge] if index < 3 else topology['edges']
require(graph['edges'] == expected_edges and graph['revision'] == topology['revision'] + (1 if index < 3 else 2),
'S4 exact cut/reconnect topology and revision')
nodes = {n['id']: n for n in graph['nodes']}
require(len(nodes) == len(graph['nodes']) and set(nodes) == {n['id'] for n in topology['nodes']},
'S4 graph node membership')
for prior in topology['nodes']:
require(all(nodes[prior['id']][k] == v for k, v in prior.items()
if k not in ('allocated', 'state', 'state_reasons', 'hold_until')),
'S4 unchanged node supply/demand/capacity/priority/enabled fields')
node = nodes[fid]
require(nodes[kitchen['instance_id']]['state'] == 0, 'S4 kitchen network consumer ACTIVE')
# Isolated consumer has no source or storage: generation and discharge are zero.
require(node['kind'] == 1 and node['demand'] > 0 and node['enabled'] is True,
'S4 positive-demand consumer')
connected = {neighbour}
while True:
expanded = connected | {v for e in graph['edges'] if any(v in connected for v in e) for v in e}
if expanded == connected: break
connected = expanded
require(kitchen['instance_id'] in connected and
sum(n.get('output', 0) for k, n in nodes.items() if k in connected and n['kind'] == 0 and n['enabled']) > 0,
'S4 main bus/kitchen supply remains live')
if index < 3:
require(fid not in connected and not any(fid in e for e in graph['edges']), 'S4 actual isolated consumer')
require(service['elapsed_minutes'] == original['duration_minutes'] - 1 and not sales(point) and
point['ledger'] == before['ledger'] and point['wallets'] == before['wallets'] and
point['player_cash'] == before['player_cash'], 'S4 stopped progress/zero charge')
require(point['reservations'] == before['reservations'], 'S4 held reservation unchanged')
service_reservations(point, 'ACTIVE')
if index:
require(service['state'] == 'PAUSED' and service['interruption_reason'] == 'NO_POWER' and
facility['power_available'] is False and node['state'] == 2 and node['allocated'] == 0 and
node['hold_until'] == boundary['minute'] + hold and graph['last_evaluation_minute'] == 960,
'S4 actual NO_POWER path, not relabelled dependency')
else:
require(service['state'] == 'ACTIVE' and facility['power_available'] is True and node['state'] == 0,
'S4 before normal evaluation')
else:
require(node['state'] == 0 and node['allocated'] == node['demand'] and facility['power_available'] is True and
node['hold_until'] == boundary['minute'] + hold and
graph['last_evaluation_minute'] == resume and service['state'] == 'COMPLETED' and
service['completed_at'] == resume and service['elapsed_minutes'] == original['duration_minutes'],
'S4 normal evaluation recovery and one completion')
service_reservations(point, 'CONSUMED')
for minute in range(held['minute'] + 1, resume):
point = s.value('writer-S4-phase-' + str(minute) + '-PUBLISH_SNAPSHOT')
require(point['minute'] == minute and point['service'] == held['service'] and
point['ledger'] == before['ledger'] and point['reservations'] == before['reservations'] and
point['receipts'] == [] and point['related_facility_operating'] is True and
point['kitchen']['power_available'] is True and point['facility']['operator_open'] is True and
point['facility']['power_available'] is False and
point['snapshot']['game_state']['resources']['mana'] > 0,
'S4 normal intervening minutes hold progress/reservation/zero charge')
paid = sales(recovered)
require(len(paid) == 1 and paid[0]['amount'] == original['price_snapshot'] and
paid[0]['absolute_minute'] == resume and paid[0]['source_entity_id'] == fid and
paid[0]['credit_account'] == 'GUEST_WALLET:' + original['guest_ids'][0], 'S4 exact single SALE')
links = [v for v in runtime(recovered)['economy']['idempotency'] if v['key'] == 'service.payment.' + sid]
require(links == [{'key': 'service.payment.' + sid, 'transaction_id': paid[0]['transaction_id']}], 'S4 transaction/service join')
require(len(recovered['receipts']) == 1 and recovered['receipts'][0]['id'] == paid[0]['transaction_id'] and
recovered['ledger'] == before['ledger'] + recovered['receipts'][0]['entries'] and
recovered['player_cash'] == before['player_cash'] + original['price_snapshot'] and
recovered['wallets'][original['guest_ids'][0]] == before['wallets'][original['guest_ids'][0]] - original['price_snapshot'] and
guard['ledger'] == recovered['ledger'] and guard['receipts'] == recovered['receipts'] and
guard['service'] == recovered['service'] and guard['reservations'] == recovered['reservations'],
'S4 exact receipt/no second charge or completion')
return {'interruption_reason': 'NO_POWER', 'stopped_minutes': [960, 961],
'completion_minute': resume, 'evaluation_interval': interval, 'minimum_hold': hold,
'service_id': sid, 'transaction_id': paid[0]['transaction_id'], 'priority_approved': False}
class S4Series(Series):
"""Fresh S4: all verifier inputs live in own B; profile paths are provenance."""
def __init__(self, build):
self.name, self.build, self.run = 's4', Path(build), RUNS['s4']
self.base = self.build / self.run
self.resolver = Resolver(self.build / 'audit-support/p04-r17-full-inputs-r01/MANIFEST.json')
self.references, self.nodes, self.pids, self.phase_pairs = {}, {}, [], 0
self.inputs = loads(self.read('runner-input.json'))
self.inventory = loads(self.read('raw-inventory.json'))
self.execution = loads(self.read('execution.json'))
inputs, execution = self.inputs, self.execution
source = loads(self.read('source_before.json'))
product = self.resolver.manifest['product_source']
require(set(source) == set(product) and len(source) == 1338 and
source == inputs['source_before'] == loads(self.read('source_after.json')), 'S4 complete unchanged product set')
for name, pin in source.items():
require(all(pin[k] == product[name][k] for k in ('bytes', 'sha256')), 'S4 product pin')
self.resolver.read(product[name]['path'], product[name])
qa = HERE / 's4/p04_s4_power_probe.gd'
require(inputs['QA']['sha256'] == digest(qa.read_bytes()) and
inputs['wrapper_sha256'] == digest((HERE / 's4/run_s4_native.py').read_bytes()), 'S4 exact QA/wrapper version')
selected = {k: v['sha256'] for k, v in source.items()}
require(inputs['QA_overrides'] == ['tests/s3/test_runtime_staff_assignment.gd'], 'S4 sole QA override')
selected[inputs['QA_overrides'][0]] = digest(qa.read_bytes())
require(selected == inputs['selected_source_map'], 'S4 selected source map')
for pin in inputs['fixed_input_pins'] + [inputs['QA'], inputs['engine']]:
path = Path(pin['path'])
require(path.is_relative_to(self.build), 'S4 material outside own B')
self.read_build(path.relative_to(self.build).as_posix(), pin)
require(execution['error'] is None and execution['guard_errors'] == [] and execution['cleanup_errors'] == [] and
[p['phase'] for p in execution['phases']] == ['import', 'parse', 'writer', 'reader'], 'S4 native phase/guard failure')
for phase in execution['phases']:
require(phase['command'][0] == inputs['engine']['path'], 'S4 actual pinned executable command')
self.ownership(phase)
require(len(set(self.pids)) == 4 and self.pids == execution['actual_captured_PIDs'] ==
loads(self.read('PID-set.json'))['engine_PIDs'], 'S4 distinct owned PIDs')
for path, pin in self.inventory.items(): self.read('raw/' + path, pin)
self.formal_s4()
def formal_s4(self):
slots = {'S4-boundary', 'S4-held', 'S4-recovered'}
before = self.execution['formal_before']
require(set(before) == slots and before == self.execution['formal_after'], 'S4 three unchanged formal slots')
relocated = loads(self.read('formal-relocation.json'))
require(set(relocated) == {'writer', 'reader'}, 'S4 separate formal roles')
inodes, profiles = [], []
for role in ('writer', 'reader'):
receipt = loads(self.read('raw/' + role + '.json'))
profiles.append(receipt['profile'])
require(set(receipt['slots']) == set(relocated[role]) == slots and set(receipt['branches']) == {'S4'}, 'S4 formal membership')
for slot in slots:
row = relocated[role][slot]
require(row['provenance'] == receipt['slots'][slot] and row['relative'] == 'formal/' + role + '/' + slot and
row['members'] == before[slot] and set(row['members']) ==
{'journal.log', 'manifest.json', 'thumbnail.png', 'world.bin'}, 'S4 whole formal package join')
directory = self.base / row['relative']
require({p.name for p in directory.iterdir()} == set(row['members']), 'S4 no dropped/extra formal members')
for member, pin in row['members'].items():
self.read(row['relative'] + '/' + member, pin)
st = ordinary(directory / member).stat()
inodes.append((st.st_dev, st.st_ino))
require(len(set(inodes)) == len(inodes) and profiles[0] != profiles[1], 'S4 independent Reader package/profile')
for slot in slots:
require(self.typed('writer-' + slot).at('snapshot').raw ==
self.typed('reader-' + slot + '-restored').at('snapshot').raw, 'S4 full typed Runtime restore; no canonicalization')
for field in ('related_facility_operating', 'kitchen', 'graph_invariants'):
require(self.typed('writer-' + slot).at(field).raw ==
self.typed('reader-' + slot + '-restored').at(field).raw, 'S4 restored graph/dependency invariants')
reader_case = self.value('reader-S4-case')
require(set(reader_case['member_hashes']) == slots, 'S4 Reader IO1 member map')
for slot, row in reader_case['member_hashes'].items():
require(row['original'] == relocated['writer'][slot]['provenance'] and
row['copy'] == relocated['reader'][slot]['provenance'] and
set(row['members']) == set(before[slot]), 'S4 Reader IO1 exact mapping')
for member, hashes in row['members'].items():
require(set(hashes) == {'original_before', 'copy_before', 'original_after', 'copy_after'} and
all(h == before[slot][member]['sha256'] for h in hashes.values()), 'S4 Reader entire member unchanged')
for label in ('held', 'recovered', 'duplicate_guard'):
require(self.typed('writer-S4-' + label).raw == self.typed('reader-S4-' + label + '-replay').raw,
'S4 full typed replay unchanged')
reconnect = self.typed('writer-S4-reconnect-replay')
require(reconnect.raw == self.typed('reader-S4-reconnect-replay').raw and
reconnect.at('accepted').plain() is True and reconnect.at('before').raw == reconnect.at('after').raw and
reconnect.at('before').raw == self.typed('writer-S4-recovered').at('snapshot').raw,
'S4 public reconnect replay leaves complete Runtime unchanged')
for path in self.inventory:
if path.startswith('reader-S4-phase-'):
other = 'writer-' + path[len('reader-'):]
require(other in self.inventory and self.read('raw/' + path) == self.read('raw/' + other), 'S4 exact replay phase')
if path.endswith('.var'): self.phase_pairs += 1
require(self.phase_pairs > 0, 'S4 replay phases missing')
def verify_s4(build):
s = S4Series(build)
return s.result(['power_stop'], power_stop(s))
def verify_s1(build):
s = Series(build, 's1')
return s.result(s1_semantics(s), {'paid_service_power_claim': False})
@@ -0,0 +1,109 @@
# S4 finite Root collection — NOT RUN
This adds only the existing `power_stop` evidence obligation. It adds no counted
condition, product change, acceptance or priority approval. Run once after this
source batch is auto-submitted. Do not rerun C/S1/S2a/S2b/S3. Do not run the full
product suite now. Preserve all existing raw and REPAIR17–21 history.
From the clean auto-submitted checkout, stage these three exact reviewed files
in the fresh own-B source directory. Copy the installed engine executable there as an independently pinned native input. This staging is a Root action, not a worker
execution. The wrapper refuses QA outside own B. All input/QA/source footprints
below are within the registered B; external manifest paths are lookup keys and
provenance only. Never open their original production locations.
```sh
export B=/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build
export E=docs/plans/original-completion-2026-10-02/execution/p04-01
export PYTHONDONTWRITEBYTECODE=1
mkdir "$B/audit-support/p04-s4-source-r22"
cp "$E/s4/run_s4_native.py" "$E/s4/p04_s4_power_probe.gd" "$E/s4/S4_ROOT_RUN.md" "$B/audit-support/p04-s4-source-r22/"
cp /Applications/Godot.app/Contents/MacOS/Godot "$B/audit-support/p04-s4-source-r22/Godot"
python3 "$B/audit-support/p04-s4-source-r22/run_s4_native.py" \
--project-root "$B/audit-support/p04-r17-full-inputs-r01/product" \
--output "$B/p04-s4-native-r22" --plan "$B/p04-s4-plan-r22.json" \
--cache-run "$B/p04-final-product-full-r01" \
--godot "$B/audit-support/p04-s4-source-r22/Godot" --check-only
python3 "$B/audit-support/p04-s4-source-r22/run_s4_native.py" \
--project-root "$B/audit-support/p04-r17-full-inputs-r01/product" \
--output "$B/p04-s4-native-r22" --plan "$B/p04-s4-plan-r22.json" \
--cache-run "$B/p04-final-product-full-r01" \
--godot "$B/audit-support/p04-s4-source-r22/Godot"
```
The first invocation only prepares the pinned plan: zero engine launches. The
second is one collection, exactly four sequential owned processes: import,
parse, Writer, Reader. Each retains the framework's native diagnostics,
ownership, exit/end checks, full stream SHA, default-player protection, private
profiles, source-before/after guards and cleanup. Failure stops the collection;
do not overwrite or silently repeat it. The ordinary framework creates its
normal private user profiles; these are process outputs, not external source
inputs. Reader uses only the existing IO1 formal package mapping.
Exact input footprints:
- `B/audit-support/p04-r17-full-inputs-r01/MANIFEST.json`, SHA256
`a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c8a8`.
- All 1338 files below that relocation's `product/`, each matched to the
manifest by bytes/SHA. No source is omitted and no old path is followed.
- Its `fixed/6ce6b28c5985e8a4f13b78bfeb1f1e09f6216d874fb01e0656ec1633bfa01cd7/completion_marker_contracts.json`.
- `B/audit-support/p04-review-repair22-r01/ACTUAL_CURRENT_PUBLIC_POWER_FUNCTIONS.json`.
- The three staged S4 files above, pinned by the plan, and the staged native
executable at B/audit-support/p04-s4-source-r22/Godot, pinned before native
admission and checked unchanged after collection. The only stage override
is `tests/s3/test_runtime_staff_assignment.gd` with the S4 probe. Harness and
kitchen fixture are the unchanged product files; inherited sources are
included in the full1338 map. The parse roster is all316 `.gd` inputs.
- `B/p04-final-product-full-r01/{runner-input.json,runner-ended.json,stage/.godot/**}`:
immutable ended cache. Its selected1339 map equals the complete product1338
plus the checker. Cache cloning uses separate inodes; normal import and parse
still run. The checker is not a `.gd` parse input or a product-suite dependency.
Exact output footprints are `B/p04-s4-plan-r22.json` and the fresh
`B/p04-s4-native-r22/**`: private selected source stage, complete phase receipts
and logs, raw JSON/Variant points and all phase observations, full source maps,
PID and cleanup receipts. `formal/{writer,reader}/S4-{boundary,held,recovered}/`
mirrors all four formal members (`journal.log`, `manifest.json`, `thumbnail.png`,
`world.bin`) with a provenance-only `formal-relocation.json`. R reads these
own-B mirrors, never profile paths from old manifests.
Scenario and source-derived timing:
1. Use the existing public cafeteria + physical FLEX kitchen fixture and normal
DAY server commute. Queue using the definition's original price and duration;
advance naturally to duration−1 at959. Derive the cafeteria's sole neighbour
from the actual graph and call public `disconnect_nodes` on exactly that edge.
2. Advance normally to960. The source's modulo10 evaluation finds an isolated
consumer with zero generation/storage. Normal `mana_power_projection.apply`
makes only the cafeteria unpowered; preparation reaches `NO_POWER` with its
dependency operating. Save **boundary** at960, then **held** at961. Mana stays
positive; operator stays open; linked kitchen is Facility `OPEN` and network
consumer `ACTIVE`. No closure, damage, shift or exit triggers accompany outage.
3. At961 reconnect the same edge. Verify the complete original edge set and
graph invariants. Advance each minute, retaining full phase raw. The saved
hold deadline is960+10=970; the next permitted normal evaluation is970.
Progress, reservation and sale stay held through969. Save **recovered** at970
after one completion/payment. Resend connect_nodes on the same edge at970,
comparing the complete Runtime before/after;971 is the duplicate guard. Ordinary guest
redecision/despawn after completed service is retained in raw, never forced
or suppressed; the outage and held service have no exit confound.
4. A distinct Reader copies all four members at each point. Normal SaveService
load and Runtime restore must reproduce the full typed snapshot, including
graph and all unrelated fields. No canonicalization, dropped fields, forced
evaluation or hold bypass. Replay from the960 formal boundary through961,
reconnect,970 and971; compare complete typed points and phase states. No
additional condition is credited for this formal preservation check.
`REPAIR22_SOURCE_FACTS.json` contains full actual source bodies and graph restore
invariants. The source normalizes saved node IDs/reasons, checks valid endpoints,
rebuilds symmetric edges, preserves revision/evaluation time and checks storage
capacity and consumer allocation. Transient `_last_report` is cleared on normal
restore and is not part of Runtime snapshot equality. The derived
`related_facility_operating` flag is measured separately and checked after restore.
After successful S4, Root can perform the eight local suites and fresh read-only
R collection described in EVIDENCE_COLLECTION.md. S4 is missing until the actual
collection succeeds. Subsequent index/cross-gate work is not a source-preparation
blocker. Rebind support53cb through its normal registered task against the new
source. Preserve the21615-check proof. Only if exact final1339 evidence is
required, perform one full run after all fixes, S4, local checks, eight suites
and rebind are bundled. Never splice different-version raw or claim1339 identity.
@@ -0,0 +1,431 @@
extends "res://tests/s3/test_runtime_actor_hardening.gd"
const CASES: Array[String] = ["S4"]
const SEEDS: Dictionary = {"S4": 420440}
const GUEST: StringName = &"p04.s4.guest.a"
const REQUEST: StringName = &"p04.s4.request.a"
const QUEUED_GUEST: StringName = &"p04.s4.guest.b"
const QUEUED_REQUEST: StringName = &"p04.s4.request.b"
const SERVERS: Array[StringName] = [&"p04.order.server.a", &"p04.order.server.b"]
var _evidence_dir: String = ""
var _mode: String = ""
var _case: String = ""
var _serial: int = 0
var _facility_id: StringName = &""
var _service_id: StringName = &""
var _boundary: int = 960
var _price: int = 0
var _duration: int = 0
var _patience: int = 0
var _reserve: int = 0
var _recovery: Dictionary = {}
var _commands: Array = []
var _results: Array = []
var _receipts: Array = []
var _phases: Array = []
var _points: Dictionary = {}
var _branches: Dictionary = {}
var _slots: Dictionary = {}
func _run() -> void:
_evidence_dir = OS.get_environment("THE_TREE_S4_EVIDENCE")
_mode = OS.get_environment("THE_TREE_S4_MODE")
if _evidence_dir.is_empty() or _mode not in ["writer", "reader"]:
quit(2)
return
_expect(DirAccess.make_dir_recursive_absolute(_evidence_dir) == OK, "external evidence directory")
if _mode == "writer":
for branch: String in CASES:
_case = branch
_writer_case()
else:
_reader()
_write(_mode, {&"pid": OS.get_process_id(), &"profile": OS.get_user_data_dir(), &"slots": _slots,
&"branches": _branches, &"checks": _checks, &"failures": _failures,
&"whole_goal_accepted": false, &"unit_accepted": false}, true)
_cleanup()
print("S4 power: %d checks, %d failures" % [_checks, _failures])
quit(1 if _failures else 0)
func _fresh() -> void:
_serial = 0
_facility_id = &""
_service_id = &""
_boundary = 960
_price = 0
_duration = 0
_patience = 0
_reserve = 0
_recovery = {}
_commands = []
_results = []
_receipts = []
_phases = []
_points = {}
_reset_runtime(SEEDS[_case])
_runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
_runtime.command_completed.connect(func(result: CommandResult) -> void:
_results.append({&"minute": _clock.absolute_minute, &"result": result.to_dictionary()})
_expect(result.is_success(), "actual public command completion " + str(result.command_id))
)
func _cmd(kind: StringName, payload: Dictionary, at: int = -1) -> CommandResult:
_serial += 1
var key: StringName = StringName("p04.s4.%s.command.%d" % [_case, _serial])
var result: CommandResult = _runtime.submit_command(kind, payload, &"player", &"", 10, at, key)
_commands.append({&"serial": _serial, &"kind": kind, &"payload": payload.duplicate(true),
&"at": at, &"issued_at": _clock.absolute_minute, &"idempotency_key": key, &"result": result.to_dictionary()})
_expect(result.is_success(), "public command " + String(kind))
return result
func _queue(guest_id: StringName, request_id: StringName, exit_at: int) -> void:
_cmd(&"spawn_guest", {&"guest_id": guest_id, &"guest_type_id": &"traveler", &"gold": _price * 2,
&"options": {&"state": GuestRuntime.State.DECIDING, &"current_cell": Vector3i.ZERO, &"planned_exit_at": exit_at}})
_cmd(&"create_service_request", {&"facility_id": _facility_id, &"request_id": request_id, &"guest_ids": [guest_id]})
var guest: GuestRuntime = _runtime.guest_service.get_guest(guest_id)
var request: ServiceRequest = _runtime.facility_service.get_request(request_id)
_expect(guest != null and request != null, "actual Guest and request exist")
if guest == null or request == null: return
_expect(guest.state == GuestRuntime.State.QUEUING and guest.queue_request_id == request_id, "actual queued ownership before advancing clock")
_expect(request.quoted_price == _price and request.service_minutes == _duration and request.reserved_inventory_ids.size() == 1, "definition price/duration and one meal reservation")
for id: StringName in request.reserved_inventory_ids:
var reservation: InventoryReservation = _runtime.inventory_service.get_reservation(id)
_expect(reservation != null and reservation.is_active() and reservation.requester_id == request_id, "public queue actually reserves meal")
func _prepare() -> bool:
_fresh()
var facility: FacilityInstance = _build_cafeteria(true)
if facility == null: return false
_facility_id = facility.instance_id
var definition: FacilityDefinition = _runtime.definition_registry.get_facility(facility.definition_id)
_price = definition.base_price
_duration = definition.base_service_minutes
_patience = _runtime.guest_service.get_definition(&"traveler").base_patience
for id: StringName in SERVERS:
_cmd(&"register_staff", {&"staff_id": id, &"role_id": &"server", &"options": {&"state": StaffRuntime.State.OFF_DUTY, &"current_cell": Vector3i.ZERO}})
_cmd(&"set_staff_work_assignment", {&"staff_id": id, &"template_id": &"DAY", &"facility_id": _facility_id})
_clock.advance_minutes(_boundary - _duration - 1 - _clock.absolute_minute)
_expect(facility.active_staff_ids == SERVERS, "normal public staff attendance")
_expect(_stock(facility.local_inventory_id, &"ingredient/basic_meal", 1, &"p04.s4.stock"), "one actual meal")
_queue(GUEST, REQUEST, _boundary + _duration)
_clock.advance_one_minute()
var active: Array = _runtime.facility_service.get_active_services(_facility_id)
_expect(active.size() == 1, "one started service")
if active.size() != 1: return false
var service: ServiceInstance = active[0]
_service_id = service.service_id
_expect(service.started_at + _duration == _boundary, "source definition duration aligns completion")
_clock.advance_minutes(_boundary - 1 - _clock.absolute_minute)
var graph: Dictionary = _runtime.mana_network_service.create_snapshot()
var adjacent: Array = []
for edge: Array in graph[&"edges"]:
if edge.has(String(_facility_id)):
adjacent.append(edge[1] if edge[0] == String(_facility_id) else edge[0])
_expect(adjacent.size() == 1, "actual sole cafeteria neighbour")
if adjacent.size() != 1: return false
_recovery = {&"neighbour": StringName(adjacent[0]), &"original_graph": graph,
&"interval": ManaNetworkService.EVALUATION_INTERVAL_MINUTES,
&"hold": ManaNetworkService.MINIMUM_OFF_HOLD_MINUTES}
_expect(_boundary % int(_recovery[&"interval"]) == 0, "boundary is normal evaluation")
_expect(_runtime.mana_network_service.disconnect_nodes(_facility_id, _recovery[&"neighbour"]), "public disconnect exact existing edge")
_expect(_runtime.mana_network_service.validate_invariants()[&"valid"], "symmetric cut graph invariants")
_reserve = _state.get_resource(&"mana")
_expect(_reserve > 0 and service.elapsed_minutes == _duration - 1, "positive mana and natural duration-1 progress")
return _clock.absolute_minute == _boundary - 1
func _connect_observations() -> void:
_runtime.economy_service.transaction_posted.connect(func(id: StringName, entries: Array) -> void:
var rows: Array = []
for entry: LedgerEntry in entries: rows.append(entry.to_dictionary())
_receipts.append({&"id": id, &"minute": _clock.absolute_minute, &"entries": rows})
)
_clock.tick_phase_started.connect(func(phase: int, minute: int) -> void:
var label: String = "phase-%d-%s" % [minute, SimulationKernel.TickPhase.keys()[phase]]
var row: Dictionary = _capture()
row[&"phase"] = SimulationKernel.TickPhase.keys()[phase]
_assert_phase(row)
_phases.append(_write(label, row))
)
func _assert_phase(point: Dictionary) -> void:
# Every phase is retained as complete typed raw; semantics are checked at points.
_expect(point[&"snapshot"][&"game_state"][&"resources"][&"mana"] > 0, "no global depletion")
func _capture() -> Dictionary:
var snapshot: Dictionary = _runtime.create_snapshot()
var operations: Dictionary = snapshot[&"systems"][&"runtime"][&"operations"]
var facility: FacilityInstance = _runtime.facility_service.get_instance(_facility_id)
var service: ServiceInstance = _runtime.facility_service.get_service(_service_id)
var event: EventInstance = _runtime.event_service.get_instance(&"p04.destroy.instance")
var kitchen: FacilityInstance = _runtime.facility_service.get_instance(facility.related_facility_id)
var actors: Dictionary = {}
var requests: Dictionary = {}
var wallets: Dictionary = {}
for id: StringName in [GUEST, QUEUED_GUEST]:
var guest: GuestRuntime = _runtime.guest_service.get_guest(id)
actors[String(id)] = guest.create_snapshot() if guest != null else {}
wallets[String(id)] = _runtime.economy_service.get_balance(StringName("GUEST_WALLET:" + String(id)))
for id: StringName in [REQUEST, QUEUED_REQUEST]:
var request: ServiceRequest = _runtime.facility_service.get_request(id)
requests[String(id)] = request.create_snapshot() if request != null else {}
var reservations: Array = []
for reservation: InventoryReservation in _runtime.inventory_service.get_reservations(false): reservations.append(reservation.create_snapshot())
var ledger: Array = []
for entry: LedgerEntry in _runtime.economy_service.get_entries(): ledger.append(entry.to_dictionary())
return {&"snapshot": snapshot, &"minute": _clock.absolute_minute,
&"inputs": {&"case": _case, &"seed": SEEDS[_case], &"serial": _serial, &"facility_id": _facility_id, &"service_id": _service_id,
&"boundary": _boundary, &"price": _price, &"duration": _duration, &"patience": _patience, &"reserve": _reserve, &"recovery": _recovery.duplicate(true),
&"kitchen_premise": "ActorHardening physical FLEX fixture; not natural hire/unlock"},
&"related_facility_operating": facility.related_facility_operating, &"kitchen": kitchen.create_snapshot(), &"graph_invariants": _runtime.mana_network_service.validate_invariants(),
&"facility": facility.create_snapshot(), &"service": service.create_snapshot() if service != null else {},
&"event": event.create_snapshot() if event != null else {}, &"guests": actors, &"requests": requests, &"wallets": wallets,
&"reservations": reservations, &"ledger": ledger, &"receipts": _receipts.duplicate(true),
&"player_cash": _runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT),
&"available_meals": _runtime.inventory_service.available_quantity(facility.local_inventory_id, &"ingredient/basic_meal"),
&"active_services": _runtime.facility_service.get_active_services(_facility_id).size(),
&"operations_enabled": operations[&"enabled"], &"saved_coordinator": operations[&"coordinator"],
&"actual_coordinator_absent": _runtime.operations_coordinator == null, &"unrelated_getters_called": false}
func _labels() -> Array[String]:
return ["boundary", "held", "recovered"]
func _advance(label: String) -> void:
if label == "duplicate_guard":
var before_replay: Dictionary = _runtime.create_snapshot()
var accepted: bool = _runtime.mana_network_service.connect_nodes(_facility_id, _recovery[&"neighbour"])
var after_replay: Dictionary = _runtime.create_snapshot()
_expect(accepted and var_to_bytes(before_replay) == var_to_bytes(after_replay), "public reconnect replay changes no Runtime field")
_write("reconnect-replay", {&"before": before_replay, &"after": after_replay, &"accepted": accepted})
if label == "recovered":
_expect(_clock.absolute_minute == _boundary + 1, "reconnect only after held observation")
_expect(_runtime.mana_network_service.connect_nodes(_facility_id, _recovery[&"neighbour"]), "reconnect exact cut edge")
var graph: Dictionary = _runtime.mana_network_service.create_snapshot()
_expect(var_to_bytes(graph[&"edges"]) == var_to_bytes(_recovery[&"original_graph"][&"edges"]), "all original edges restored")
_expect(_runtime.mana_network_service.validate_invariants()[&"valid"], "reconnected graph invariants")
var node: Dictionary = _runtime.mana_network_service.get_node(_facility_id)
var resume_at: int = int(node[&"hold_until"])
var interval: int = int(_recovery[&"interval"])
while resume_at % interval != 0: resume_at += 1
_expect(resume_at > _clock.absolute_minute and resume_at < _boundary + _duration, "finite normal hold/evaluation recovery before exit")
while _clock.absolute_minute < resume_at:
_clock.advance_one_minute()
if _clock.absolute_minute < resume_at: _assert_stopped(_capture())
else:
_clock.advance_one_minute()
func _writer_case() -> void:
if not _prepare(): return
var before: Dictionary = _capture()
_assert_before(before)
_points["before"] = _write("before", before)
_connect_observations()
for label: String in _labels():
_advance(label)
var actual: Dictionary = _capture()
_assert_outcome(before, actual)
_save_point(label, actual)
_advance("duplicate_guard")
var guard: Dictionary = _capture()
_assert_outcome(before, guard)
_points["duplicate_guard"] = _write("duplicate_guard", guard)
_branches[_case] = _write("case", {&"points": _points.duplicate(true), &"phases": _phases.duplicate(true),
&"commands": _write("commands", {&"submitted": _commands, &"completed_including_fixture": _results})})
func _assert_before(point: Dictionary) -> void:
_assert_unconfounded(point)
_expect(point[&"service"][&"state"] == "ACTIVE" and point[&"facility"][&"power_available"], "before normal projection remains powered")
_expect(point[&"service"][&"elapsed_minutes"] == _duration - 1 and point[&"reservations"].size() == 1, "natural duration-1 and one reservation")
func _assert_unconfounded(point: Dictionary) -> void:
_expect(not point[&"operations_enabled"] and point[&"actual_coordinator_absent"], "existing isolated fixture")
_expect(point[&"facility"][&"operator_open"] and point[&"related_facility_operating"], "open operator and operating dependency")
_expect(point[&"facility"][&"durability"] > 0 and point[&"event"].is_empty(), "no destruction event")
_expect(point[&"kitchen"][&"power_available"] and point[&"kitchen"][&"state"] == "OPEN", "kitchen stays active/powered")
_expect(point[&"snapshot"][&"game_state"][&"resources"][&"mana"] > 0, "positive global reserve")
_expect(point[&"facility"][&"active_staff_ids"] == SERVERS, "no shift confound")
if point[&"service"][&"state"] != "COMPLETED":
_expect(point[&"guests"][String(GUEST)][&"planned_exit_at"] > point[&"minute"] and point[&"guests"][String(GUEST)][&"state"] == "RECEIVING_SERVICE", "no exit at outage/hold")
_expect(point[&"graph_invariants"][&"valid"], "graph allocation/storage/symmetry valid")
_expect(_runtime.mana_network_service.get_consumer_state(StringName(point[&"kitchen"][&"instance_id"])) == ManaNetworkService.ConsumerState.ACTIVE, "kitchen network consumer ACTIVE")
func _assert_stopped(point: Dictionary) -> void:
_assert_unconfounded(point)
_expect(not point[&"facility"][&"power_available"] and point[&"service"][&"state"] == "PAUSED" and point[&"service"][&"interruption_reason"] == "NO_POWER", "actual isolated NO_POWER path")
_expect(point[&"service"][&"elapsed_minutes"] == _duration - 1 and point[&"receipts"].is_empty(), "stopped progress held and no payment")
func _assert_reservation(before: Dictionary, point: Dictionary, request_id: StringName, state: String, terminal: int) -> void:
var prior: Array = []
var current: Array = []
for row: Dictionary in before[&"reservations"]:
if row[&"requester_id"] == String(request_id): prior.append(row)
for row: Dictionary in point[&"reservations"]:
if row[&"requester_id"] == String(request_id): current.append(row)
_expect(prior.size() == 1 and current.size() == 1, "one original reservation per request")
if prior.size() != 1 or current.size() != 1: return
_expect(prior[0][&"reservation_id"] == current[0][&"reservation_id"] and current[0][&"state"] == state and current[0][&"terminal_at"] == terminal, "same reservation ID/state/terminal time; no second release")
if state == "ACTIVE":
_expect(var_to_bytes(prior[0]) == var_to_bytes(current[0]), "entire held reservation unchanged")
var request: Dictionary = point[&"requests"][String(request_id)]
_expect(not request.is_empty() and request[&"reserved_inventory_ids"].has(current[0][&"reservation_id"]), "active reservation has live request owner")
else:
_expect(point[&"requests"][String(request_id)].is_empty(), "terminal reservation has no orphan request")
if state == "RELEASED":
var release_count: int = 0
var inventory: Dictionary = point[&"snapshot"][&"systems"][&"runtime"][&"inventory"]
for operation: Dictionary in inventory[&"idempotency_results"]:
var result: Dictionary = operation[&"result"]
if operation[&"action"] == "release" and String(result.get(&"reservation_id", "")) == current[0][&"reservation_id"]:
release_count += 1
_expect(bool(result.get(&"ok", false)) and result.get(&"quantity", 0) == current[0][&"quantity"], "release returned actual reserved quantity, not an orphan repair/retry")
_expect(release_count == 1, "one raw inventory release operation for original reservation")
func _assert_outcome(before: Dictionary, point: Dictionary) -> void:
_assert_unconfounded(point)
var service: Dictionary = point[&"service"]
_expect(service[&"service_id"] == before[&"service"][&"service_id"], "same service ID")
var paid: bool = service[&"state"] == "COMPLETED"
if not paid:
_assert_stopped(point)
_expect(var_to_bytes(point[&"ledger"]) == var_to_bytes(before[&"ledger"]), "zero stopped ledger delta")
_assert_reservation(before, point, REQUEST, "ACTIVE", -1)
else:
var node: Dictionary = _runtime.mana_network_service.get_node(_facility_id)
_expect(point[&"facility"][&"power_available"] and service[&"elapsed_minutes"] == _duration and service[&"completed_at"] >= int(node[&"hold_until"]), "resume and complete after hold")
_expect(point[&"receipts"].size() == 1, "one payment only")
var expected: Array = before[&"ledger"].duplicate(true)
for receipt: Dictionary in point[&"receipts"]: expected.append_array(receipt[&"entries"])
_expect(var_to_bytes(expected) == var_to_bytes(point[&"ledger"]), "whole ledger exactly one receipt")
_assert_reservation(before, point, REQUEST, "CONSUMED", service[&"completed_at"])
_expect(point[&"wallets"][String(GUEST)] == _price * (1 if paid else 2) and point[&"player_cash"] == before[&"player_cash"] + (_price if paid else 0), "exact one price or zero")
func _save_point(label: String, point: Dictionary) -> void:
_points[label] = _write(label, point)
var path: String = "user://saves/p04_s4/" + _case + "-" + label
var saved: Dictionary = SaveService.save_snapshot(path, point[&"snapshot"])
var inspected: Dictionary = SaveService.inspect_snapshot(path)
_expect(bool(saved.get(&"ok", false)) and bool(inspected.get(&"ok", false)) and bool(inspected.get(&"read_only", false)), "public formal save/inspect")
_expect(var_to_bytes(inspected.get(&"snapshot", {})) == var_to_bytes(point[&"snapshot"]), "all typed fields preserved by formal package")
_expect(var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(point[&"snapshot"]), "formal saving leaves Runtime unchanged")
_slots[_case + "-" + label] = ProjectSettings.globalize_path(path)
# Snapshot bytes exist once in point raw and once in the required formal
# package; indexes do not embed inspection/load copies of those bytes.
func _write(label: String, value: Variant, global_name: bool = false) -> Dictionary:
var name: String = label if global_name else _mode + "-" + _case + "-" + label
var reference: Dictionary = {}
for extension: String in ["var", "json"]:
var path: String = _evidence_dir.path_join(name + "." + extension)
_expect(not FileAccess.file_exists(path), "raw point written exactly once " + name)
var file: FileAccess = FileAccess.open(path, FileAccess.WRITE)
_expect(file != null, "raw file " + name)
if file == null: continue
if extension == "var": file.store_buffer(var_to_bytes(value))
else: file.store_string(JSON.stringify(value, "\t"))
file.flush()
file.close()
reference[extension] = {&"path": path, &"sha256": FileAccess.get_sha256(path)}
return reference
func _read(reference: Dictionary) -> Dictionary:
var item: Dictionary = reference["var"]
var path: String = item["path"]
_expect(FileAccess.get_sha256(path) == item["sha256"], "raw typed SHA")
var json_ref: Dictionary = reference["json"]
_expect(FileAccess.get_sha256(json_ref["path"]) == json_ref["sha256"], "raw JSON SHA")
var file: FileAccess = FileAccess.open(path, FileAccess.READ)
_expect(file != null, "typed input readable")
if file == null: return {}
var value: Variant = bytes_to_var(file.get_buffer(file.get_length()))
file.close()
_expect(value is Dictionary, "typed input dictionary")
return value if value is Dictionary else {}
func _restore_inputs(point: Dictionary) -> void:
var inputs: Dictionary = point[&"inputs"]
_expect(_serial == 0, "Reader starts with serial zero before importing external inputs")
_serial = inputs[&"serial"]
_facility_id = inputs[&"facility_id"]
_service_id = inputs[&"service_id"]
_boundary = inputs[&"boundary"]
_price = inputs[&"price"]
_duration = inputs[&"duration"]
_patience = inputs[&"patience"]
_reserve = inputs[&"reserve"]
_recovery = inputs[&"recovery"].duplicate(true)
func _load_point(path: String, expected: Dictionary) -> bool:
_fresh()
_restore_inputs(expected)
var loaded: Dictionary = SaveService.load_snapshot(path)
_expect(bool(loaded.get(&"ok", false)), "public formal load")
if not bool(loaded.get(&"ok", false)): return false
_expect(var_to_bytes(loaded[&"snapshot"]) == var_to_bytes(expected[&"snapshot"]), "all saved typed fields equal Writer")
var restored: bool = _runtime.restore_snapshot(loaded[&"snapshot"])
_expect(restored, "public Runtime restore")
_expect(var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(expected[&"snapshot"]), "all restored typed fields equal Writer")
return restored
func _reader() -> void:
var file: FileAccess = FileAccess.open(_evidence_dir.path_join("writer.json"), FileAccess.READ)
_expect(file != null, "Writer receipt")
if file == null: return
var writer: Dictionary = JSON.parse_string(file.get_as_text())
file.close()
_expect(int(writer["pid"]) != OS.get_process_id() and writer["profile"] != OS.get_user_data_dir(), "independent Reader PID/profile")
for branch: String in CASES:
_case = branch
var writer_case: Dictionary = _read(writer["branches"][branch])
var hashes: Dictionary = {}
var restored_refs: Dictionary = {}
for label: String in _labels():
var key: String = branch + "-" + label
var original: String = writer["slots"][key]
var target: String = ProjectSettings.globalize_path("user://saves/p04_s4/" + key)
_expect(DirAccess.make_dir_recursive_absolute(target) == OK, "private Reader formal slot")
var directory: DirAccess = DirAccess.open(original)
_expect(directory != null, "Writer formal slot readable")
if directory == null: return
var members: PackedStringArray = directory.get_files()
members.sort()
_expect(directory.get_directories().is_empty() and members == PackedStringArray(["journal.log", "manifest.json", "thumbnail.png", "world.bin"]), "all formal members enumerated")
var member_hashes: Dictionary = {}
for member: String in members:
var sha: String = FileAccess.get_sha256(original.path_join(member))
_expect(DirAccess.copy_absolute(original.path_join(member), target.path_join(member)) == OK, "copy every formal member")
var copied_sha: String = FileAccess.get_sha256(target.path_join(member))
_expect(not sha.is_empty() and sha == copied_sha, "original/copy member SHA equality")
member_hashes[member] = {&"original_before": sha, &"copy_before": copied_sha}
hashes[key] = {&"original": original, &"copy": target, &"members": member_hashes}
_slots[key] = target
var expected: Dictionary = _read(writer_case[&"points"][label])
if not _load_point(target, expected): return
restored_refs[label] = _write(label + "-restored", _capture())
var before: Dictionary = _read(writer_case[&"points"]["before"])
var boundary: Dictionary = _read(writer_case[&"points"]["boundary"])
if not _load_point(_slots[branch + "-boundary"], boundary): return
_assert_stopped(_capture())
_connect_observations()
var replay_refs: Dictionary = {}
for label: String in ["held", "recovered", "duplicate_guard"]:
_advance(label)
var actual: Dictionary = _capture()
var expected: Dictionary = _read(writer_case[&"points"][label])
_expect(var_to_bytes(actual) == var_to_bytes(expected), "replay complete typed point including Runtime, inputs, receipts " + label)
_assert_outcome(before, actual)
replay_refs[label] = _write(label + "-replay", actual)
var expected_phases: Array = []
for reference: Dictionary in writer_case[&"phases"]:
if int(_read(reference)[&"minute"]) > _boundary: expected_phases.append(reference)
_expect(_phases.size() == expected_phases.size(), "complete phase count")
if _phases.size() == expected_phases.size():
for index: int in range(_phases.size()):
_expect(var_to_bytes(_read(_phases[index])) == var_to_bytes(_read(expected_phases[index])), "same phase order and all typed phase state")
for key: String in hashes:
var row: Dictionary = hashes[key]
for member: String in row[&"members"]:
var item: Dictionary = row[&"members"][member]
item[&"original_after"] = FileAccess.get_sha256(String(row[&"original"]).path_join(member))
item[&"copy_after"] = FileAccess.get_sha256(String(row[&"copy"]).path_join(member))
_expect(item[&"original_before"] == item[&"original_after"] and item[&"copy_before"] == item[&"copy_after"], "original/copy unchanged after all loads and replay")
_branches[branch] = _write("case", {&"restored": restored_refs, &"replay": replay_refs, &"phases": _phases,
&"member_hashes": hashes, &"recovery_commands": _commands, &"replay_completed_commands": _results})
@@ -0,0 +1,317 @@
#!/usr/bin/env python3
"""S4-only native entry. --check-only never loads ownership helpers or starts Godot."""
from pathlib import Path
import argparse
import hashlib
import importlib.util
import json
import os
import shutil
import subprocess
import sys
sys.dont_write_bytecode = True
HERE = Path(__file__).resolve().parent
BUILD = Path("/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build")
PRODUCT = BUILD / "audit-support/p04-r17-full-inputs-r01/product"
CACHE_RUN = BUILD / "p04-final-product-full-r01"
TEST = "tests/s3/test_runtime_staff_assignment.gd"
QA = HERE / "p04_s4_power_probe.gd"
ENGINE = HERE / "Godot"
MANIFEST = BUILD / "audit-support/p04-r17-full-inputs-r01/MANIFEST.json"
MANIFEST_SHA = "a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c8a8"
CONTRACTS = BUILD / "audit-support/p04-r17-full-inputs-r01/fixed/6ce6b28c5985e8a4f13b78bfeb1f1e09f6216d874fb01e0656ec1633bfa01cd7/completion_marker_contracts.json"
CASES = ["S4"]
LABELS = {"S4": ["boundary", "held", "recovered"]}
SLOTS = ["S4-" + label for label in sorted(LABELS["S4"])]
MATERIALS = [MANIFEST, BUILD / "audit-support/p04-review-repair22-r01/ACTUAL_CURRENT_PUBLIC_POWER_FUNCTIONS.json"]
def template_guard(root):
if root != PRODUCT.resolve() or not HERE.is_relative_to(BUILD.resolve()):
raise ValueError("Root must stage this exact QA/wrapper/plan inside own B")
if pin(MANIFEST)["sha256"] != MANIFEST_SHA:
raise ValueError("immutable full R17 relocation manifest")
manifest = json.loads(MANIFEST.read_text())
for name, source in manifest["product_source"].items():
# Old absolute paths are lookup keys only. Never open them.
row = manifest["original_to_relocated"][source["path"]]
actual = pin(root / name)
if Path(row["relocated"]).resolve() != root / name or any(
actual[k] != source[k] or actual[k] != row[k] for k in ("bytes", "sha256")):
raise ValueError("relocated product differs: " + name)
probe = QA.read_text()
import re
if ":=" in probe or re.search(r"\bvar\s+\w+\s*=", probe) or re.search(r"\bfor\s+\w+\s+in\b", probe):
raise ValueError("explicit typed declarations/loops required")
if re.search(r"\.(?:patience_remaining|elapsed_minutes|power_available|capacity|hold_until)\s*=(?!=)", probe):
raise ValueError("forbidden direct state mutation")
for forbidden in ["evaluate_now(", "configure_operations(", "._update_shift_states(", ".record_duty_minute("]:
if forbidden in probe:
raise ValueError("forbidden bypass: " + forbidden)
# Constants and public bodies are read from the actual selected source, not a memo.
mana = (root / "scripts/mana/mana_network_service.gd").read_text()
for key in ("EVALUATION_INTERVAL_MINUTES", "MINIMUM_OFF_HOLD_MINUTES"):
if not re.search(r"const " + key + r" := 10\b", mana):
raise ValueError("source timing changed: " + key)
def module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
value = importlib.util.module_from_spec(spec)
spec.loader.exec_module(value)
return value
def pin(path):
path = Path(path)
if path.is_symlink() or not path.is_file():
raise ValueError("missing exact input: " + str(path))
data = path.read_bytes()
return dict(path=str(path), bytes=len(data), sha256=hashlib.sha256(data).hexdigest())
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--project-root", type=Path, default=PRODUCT)
parser.add_argument("--output", type=Path, default=BUILD / "p04-s4-native-r22")
parser.add_argument("--plan", type=Path, default=BUILD / "p04-s4-plan-r22.json")
parser.add_argument("--cache-run", type=Path, default=CACHE_RUN)
parser.add_argument("--godot", type=Path, default=ENGINE)
parser.add_argument("--check-only", action="store_true")
args = parser.parse_args()
if args.godot.resolve() != ENGINE.resolve():
raise ValueError("use the exact own-B staged engine")
if args.cache_run.resolve() != CACHE_RUN.resolve():
raise ValueError("only registered own-B full-run cache")
root = args.project_root.resolve()
out = args.output.resolve()
if not out.is_relative_to(BUILD.resolve()) or not args.plan.resolve().is_relative_to(BUILD.resolve()):
raise ValueError("plan/output must stay in task build")
r = module("s4_standard_runner", root / "tools/run_all_tests.py")
# Preserve the reviewed source_refs -> exactly one QA override order.
source_before = r.source_refs(root)
refs = dict(source_before)
refs[TEST] = pin(QA)
template_guard(root)
expected = {n: dict(bytes=p["bytes"], sha256=p["sha256"]) for n, p in refs.items()}
fixed = [pin(p) for p in MATERIALS + [
QA, Path(__file__), HERE / "S4_ROOT_RUN.md",
root / "tests/transport/test_runtime_transport.gd",
root / "tests/staff/test_rescue_elevator.gd",
CONTRACTS,
]]
selected = dict(root_before=source_before, map={n: p["sha256"] for n, p in refs.items()}, timeout=1200)
cache_note = None
cache_receipts = []
for leaf in ["runner-ended.json", "runner-input.json"]:
path = args.cache_run / leaf
try:
cache_receipts.append(pin(path))
except OSError as caught:
cache_note = dict(path=str(path), error=type(caught).__name__ + ": " + str(caught),
required_before_native=True)
break
plan = dict(protocol="p04-s4-preparation-v1", project_root=str(root), output=str(out), engine_path=str(args.godot.resolve()),
source_before=source_before, selected_source_map=selected["map"],
QA_overrides=[TEST], fixed_input_pins=fixed, cache_run=str(args.cache_run),
cache_receipts=cache_receipts, cache_access=cache_note,
phases=["import", "parse", "writer", "reader"],
native_engine_launches=0, whole_goal_accepted=False, unit_accepted=False)
# Check-only only reads source/materials and writes the plan in task build.
# It deliberately does not read default-player data, inspect processes or stat Godot.
if args.check_only:
args.plan.parent.mkdir(parents=True, exist_ok=True)
if args.plan.exists():
r.require(r.read(args.plan) == plan, "existing plan differs; use a fresh plan path")
else:
r.write(args.plan, plan)
print(json.dumps(dict(check_only=True, engines=0, source_files=len(source_before),
QA_overrides=[TEST], fixed_pins=len(fixed), plan=str(args.plan),
plan_sha256=r.sha(args.plan), cache_access=cache_note), ensure_ascii=False))
return 0
r.require(root == PRODUCT.resolve() and len(source_before) == 1338, "Root native requires product 1338; worker plan is not native evidence")
r.require(args.plan.is_file() and r.read(args.plan) == plan, "run exact check-only plan first")
engine_descriptor = None
def fixed_guard():
template_guard(root)
if engine_descriptor is not None:
r.require(pin(engine_descriptor["path"]) == engine_descriptor, "engine changed during collection")
for value in fixed + cache_receipts:
r.require(pin(value["path"]) == value, "fixed input changed: " + value["path"])
fixed_guard()
# Native admission is Root-only and fails closed on unreadable cache.
r.require(cache_note is None, "Root must read exact cache receipts: " + str(cache_note))
old = args.cache_run
r.require(r.read(old / "runner-ended.json")["passed"], "ended cache run must have passed")
old_map = r.read(old / "runner-input.json")["selected_source_map"]
current_map = {n: p["sha256"] for n, p in source_before.items()}
r.require({k: v for k, v in old_map.items() if k != "tools/check_p04_order_evidence.py"} == current_map and len(old_map) == 1339, "immutable full cache: all 1338 product inputs equal; checker is not parsed/executed by product suites")
protected = r.default_player(root)
outer = module("s4_owned_outer", r.SUPPORT / "owned_outer.py")
r.require(not outer.native.helper["live_engines"](), "another Godot owns CPU")
engine = args.godot.resolve()
r.require(engine.is_file(), "Root native Godot path")
engine_descriptor = pin(engine)
r.require(engine_descriptor["sha256"] == r.read(old / "runner-input.json")["engine_sha256"],
"staged engine matches preserved full proof; no environment substitution")
r.require(shutil.disk_usage(out.parent).free >= 1024**3 + engine.stat().st_size + 136*1024**2,
"reviewed native disk admission")
r.require(not out.exists(), "fresh output required; preserve previous attempts")
out.mkdir()
stage = out / "stage"
stage.mkdir()
(out / "starters").mkdir()
(out / "bootstrap").mkdir()
phases = []
previous = {}
error = None
guards = []
cleanup = []
cleanup_errors = []
cache_before = None
formal_before = None
formal_after = None
original_phase = outer.run_phase
def run_phase(argv, folder, timeout, env, **kwargs):
env = dict(env)
if folder.name in ["writer", "reader"]:
env.update(THE_TREE_S4_EVIDENCE=str(out / "raw"), THE_TREE_S4_MODE=folder.name)
return original_phase(argv, folder, timeout, env, **kwargs)
outer.run_phase = run_phase
r.write(out / "runner-started.json", dict(started=r.now(), owner_runner_pid=os.getpid(),
plan=pin(args.plan), engines_launched=0))
try:
r.write(out / "source_before.json", source_before)
r.write(out / "selected-source-map.json", refs)
# Private source stage first, then literal reviewed bootstrap.
for name, value in refs.items():
target = stage / name
target.parent.mkdir(parents=True, exist_ok=True)
r.copy_source(Path(value["path"]), target)
r.require(r.inventory(stage, stage=True) == expected, "whole private source")
for name, value in r.read(r.SUPPORT / "bootstrap-scripts.json").items():
data = value["text"].encode()
r.require(hashlib.sha256(data).hexdigest() == value["sha256"], "bootstrap pin")
(out / "bootstrap" / name).write_bytes(data)
cache = old / "stage/.godot"
cache_before = r.inventory(cache)
r.require(bool(cache_before), "nonempty ended cache")
for name in cache_before:
src = cache / name
dst = stage / ".godot" / name
dst.parent.mkdir(parents=True, exist_ok=True)
subprocess.run(["/bin/cp", "-c", str(src), str(dst)], check=True)
r.require((src.stat().st_dev, src.stat().st_ino) != (dst.stat().st_dev, dst.stat().st_ino),
"cache clone is a separate inode")
r.require(r.inventory(stage / ".godot") == cache_before, "whole cache clone hashes")
r.write(out / "cache-reuse.json", dict(ended_run=str(old), receipts=cache_receipts,
whole_cache=cache_before, independent_inode=True,
ordinary_import_required=True, ordinary_parse_required=True))
paths = ["res://" + n for n in sorted(refs) if n.endswith(".gd")]
r.write(out / "parse-paths.json", paths)
markers = module("s4_markers", root / "tools/strict_test_markers.py")
contracts = markers.load_contracts(CONTRACTS)
contracts[TEST] = dict(test=TEST, template="S4 power: <checks> checks, <failures> failures", required=True)
policy = r.read(r.SUPPORT / "suite-policy.json")
r.require(TEST not in policy["suite_policies"], "no normal suite watchdog/policy override")
r.write(out / "contracts.json", contracts)
r.write(out / "runner-input.json", dict(plan, owner_runner_pid=os.getpid(),
wrapper_sha256=r.sha(__file__), QA=pin(QA), engine=engine_descriptor, runner_sha256=r.sha(root / "tools/run_all_tests.py"),
default_player_before=protected, fixed_input_pins=fixed,
functional_watchdog_seconds=1200, source_adoption=False))
diagnostics = module("s4_diagnostics", r.SUPPORT / "diagnostic_gate.py")
owners = module("s4_owners", r.SUPPORT / "ordinary_proof_gate.py")
audio = module("s4_audio", r.SUPPORT / "audio_evidence_gate.py")
public = (stage / "project.godot").read_bytes()
for phase, test in [("import", None), ("parse", None), ("writer", TEST), ("reader", TEST)]:
if phase == "reader":
writer = r.read(out / "raw/writer.json")
formal_before = {n: r.inventory(Path(p)) for n, p in writer["slots"].items()}
r.require(sorted(formal_before) == SLOTS, "exact three formal points for isolated power case")
row = r.execute_phase(str(engine), stage, out, phase, test, selected, expected,
previous, policy, contracts, paths, public, protected, root,
outer, markers, diagnostics, owners, audio)
phases.append(row)
# execute_phase uses the same test log name; retain each phase's exact log too.
if test and row.get("log"):
(out / (phase + "-combined-raw.log")).write_bytes((out / row["log"]).read_bytes())
row["strict_runner_log_path"] = row["log"]
row["log"] = phase + "-combined-raw.log"
r.write(out / (phase + "-actual-phase.json"), row)
print(json.dumps(dict(phase=phase, passed=row["passed"], error=row.get("validation_error"))), flush=True)
r.require(row["passed"], "first strict phase failure: " + phase)
if phase in ["writer", "reader"]:
receipt = r.read(out / ("raw/" + phase + ".json"))
r.require(receipt["checks"] > 0 and receipt["failures"] == 0,
"S4 actual outcome receipt")
r.require(sorted(receipt["branches"]) == CASES,
"exact one independent Writer/Reader case")
r.require(sorted(receipt["slots"]) == SLOTS, "all formal point slots")
r.require(receipt["pid"] == row["actual_pid"], "actual native PID/receipt")
writer = r.read(out / "raw/writer.json")
reader = r.read(out / "raw/reader.json")
r.require(writer["pid"] != reader["pid"] and writer["profile"] != reader["profile"], "distinct formal processes")
formal_after = {n: r.inventory(Path(p)) for n, p in writer["slots"].items()}
r.require(formal_before == formal_after, "Reader leaves Writer packages unchanged")
except BaseException as caught:
error = type(caught).__name__ + ": " + str(caught)
finally:
cleanup, cleanup_errors = outer.finish_captured(outer.OWNED)
try:
r.write(out / "outer-owned-finally.json", dict(cleanup=cleanup, errors=cleanup_errors))
except BaseException as caught:
guards.append("finally receipt: " + type(caught).__name__ + ": " + str(caught))
# Fixed guard always follows ownership cleanup, even if setup or an engine failed.
try:
fixed_guard()
after = r.source_refs(root)
r.write(out / "source_after.json", after)
r.require(after == source_before, "whole product source unchanged")
r.require(r.default_player(root) == protected, "default player unchanged")
if (stage / "project.godot").exists():
r.require(r.inventory(stage, stage=True) == dict(expected, **previous), "whole private source unchanged")
if cache_before is not None:
r.require(r.inventory(old / "stage/.godot") == cache_before, "original cache unchanged")
if formal_before is not None:
writer = r.read(out / "raw/writer.json")
formal_after = {n: r.inventory(Path(p)) for n, p in writer["slots"].items()}
r.require(formal_before == formal_after, "Writer formal packages unchanged after Reader, including failure")
except BaseException as caught:
guards.append(type(caught).__name__ + ": " + str(caught))
pids = [p.pid for p in outer.OWNED]
passed = (error is None and not guards and not cleanup_errors and len(phases) == 4
and all(p["passed"] for p in phases) and len(pids) == len(set(pids)) == 4
and all(p["engine_ended"] for p in cleanup))
execution = dict(passed=passed, error=error, guard_errors=guards, phases=phases,
actual_captured_PIDs=pids, cleanup=cleanup, cleanup_errors=cleanup_errors,
formal_before=formal_before, formal_after=formal_after,
whole_goal_accepted=False, unit_accepted=False)
# IO1 has already copied all four members into a separate Reader profile.
# Mirror those exact complete directories to own B for read-only R verification.
# Original profile paths are provenance after this step, never verifier inputs.
if passed:
relocated = {}
for role in ("writer", "reader"):
receipt = r.read(out / ("raw/" + role + ".json"))
relocated[role] = {}
for slot, original in receipt["slots"].items():
target = out / "formal" / role / slot
target.mkdir(parents=True)
members = r.inventory(Path(original))
r.require(set(members) == {"journal.log", "manifest.json", "thumbnail.png", "world.bin"}, "all formal members")
for member in members:
shutil.copyfile(Path(original) / member, target / member)
r.require(r.inventory(target) == members == formal_before[slot], "whole formal mirror")
relocated[role][slot] = dict(provenance=original, relative=str(target.relative_to(out)), members=members)
r.write(out / "formal-relocation.json", relocated)
r.write(out / "raw-inventory.json", r.inventory(out / "raw"))
r.write(out / "PID-set.json", dict(owner_runner_pid=os.getpid(), engine_PIDs=pids))
r.write(out / "execution.json", execution)
r.write(out / "runner-ended.json", dict(execution, ended=r.now()))
print(json.dumps(dict(passed=passed, error=error, guard_errors=guards, output=str(out))))
return 0 if passed else 1
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as caught:
print(type(caught).__name__ + ": " + str(caught), file=sys.stderr)
raise SystemExit(2)
+10 -7
View File
@@ -985,8 +985,8 @@ def verify_shift_completion(base):
native_file(base, row['copy'], row)
require(native_applicability(base) == TESTED_PRODUCT, 'shift tested revision')
pids = native_ownership(base)
require([pids['actual-native/' + phase] for phase in NATIVE_RUNS['actual-native']]
== [77462, 77504, 77536], 'shift ended PID identity')
shift_pids = [pids['actual-native/' + phase] for phase in NATIVE_RUNS['actual-native']]
require(len(shift_pids) == len(set(shift_pids)) == 3, 'shift ended PID identity')
inputs = load(safe(base, 'actual-native/runner-input.json'))
expected = product_manifest(tree_entries(TESTED_PRODUCT))
require(len(inputs['source_before']) == 1338 and
@@ -1002,6 +1002,7 @@ def verify_shift_completion(base):
paid_rows = None
original_service = None
completed_service = None
transaction_id = None
for i, label in enumerate(labels):
rows = [r for r in observations['observations'] if r['label'] == label]
require(len(rows) == 1, 'shift phase membership')
@@ -1055,13 +1056,15 @@ def verify_shift_completion(base):
require(service['state'] == 'COMPLETED' and service['completed_at'] == 1080 and len(sale) == 1,
'shift single completion')
transaction = sale[0]
require(transaction['transaction_id'] == 'ledger_00000006' and transaction['amount'] == 25 and
if transaction_id is None:
transaction_id = transaction['transaction_id']
require(transaction['transaction_id'] == transaction_id and transaction['amount'] == service['price_snapshot'] and
transaction['absolute_minute'] == 1080 and transaction['source_entity_id'] == service['facility_id']
and transaction['credit_account'] == 'GUEST_WALLET:' + service['guest_ids'][0], 'shift sale identity')
receipts = receipt_rows(observation['receipts'])
require(receipts == [r for r in ledger if r['transaction_id'] == 'ledger_00000006'], 'shift receipt raw join')
require(receipts == [r for r in ledger if r['transaction_id'] == transaction_id], 'shift receipt raw join')
require([r for r in state['economy']['idempotency'] if r['key'] == 'service.payment.' + service_id]
== [{'key': 'service.payment.' + service_id, 'transaction_id': 'ledger_00000006'}],
== [{'key': 'service.payment.' + service_id, 'transaction_id': transaction_id}],
'shift idempotency join')
if i == 2:
completed_service = service
@@ -1073,7 +1076,7 @@ def verify_shift_completion(base):
observation['receipts'] == paid_rows, 'shift extra charge/completion')
previous_ledger = ledger
points.append(label)
return {'verified_conditions': ['shift_completion'], 'phases': points, 'transaction_id': 'ledger_00000006'}
return {'verified_conditions': ['shift_completion'], 'phases': points, 'transaction_id': transaction_id}
def combine_native_series(directory, native):
@@ -1089,7 +1092,7 @@ def combine_native_series(directory, native):
module_spec.loader.exec_module(series)
c_base = directory / 'audit-support/native-first-current'
require(native == verify_native(c_base), 'C result must be recomputed from raw')
base = directory / 'audit-support/p04-raw-collect-r20'
base = directory / 'audit-support/p04-raw-collect-r22'
manifest_path = safe(base, 'MANIFEST.json')
manifest = load(manifest_path)
require(manifest['protocol'] == 'p04-native-series-collection-v1' and