Compare commits

...
7 Commits
13 changed files with 3214 additions and 51 deletions
@@ -0,0 +1,147 @@
{
"at": 1792524526.738174,
"helper_task": "P28-01-RESTART",
"project": "the-tree-p28-01-restart",
"state": "completed",
"all4_normal_gates_passed": true,
"acceptance_ids": [
"P28-01-RS1",
"P28-01-RS2",
"P28-01-RS3",
"P28-01-RS4",
"P28-01-RS5",
"P28-01-RS6",
"P28-01-RS7",
"P28-01-RS8"
],
"helper_acceptance": {
"completed": 8,
"total": 8
},
"S": "954528a7c5a0e27e2e50b642373168fa0a550aba",
"Q": "3ac2cedc8dc977778fd5a3ba152197cc6cf00fa2",
"M": "3086af2ccd970ddee271a184214dad037bd1d6af",
"approval": {
"task_id": "P28-01-RESTART",
"candidate": "3ac2cedc8dc977778fd5a3ba152197cc6cf00fa2",
"main_base": "3086af2ccd970ddee271a184214dad037bd1d6af",
"owner": "Codex Root acting under existing user explicit main/push permission and delegation of candidate judgment; exact Q3ac2ced verified in ROOT_CANDIDATE_3AC2CED_QUALIFICATION.json SHA5bd8030acddc385eb728441286f6a740ec1ee966125474b60ef4b1efe2a2c343; not a new human SHA-specific statement.",
"created": 1792524415.091752
},
"normal_evidence_join": [
{
"id": 8,
"task_id": "P28-01-RESTART",
"kind": "validation",
"commit_sha": "954528a7c5a0e27e2e50b642373168fa0a550aba",
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p28-01-restart/runs/335b64bb98804e9bb39e353e9bd017e2-validation.json",
"passed": 1,
"artifact_sha256": "52b59357dca6888896212feb40fde6d154c45b4493e399ddbd316290132975b8",
"checks": [
{
"id": "p28-01-restart-unit",
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p28-01-restart/runs/8b7f60346fc1460b81fa6c9078fd34fc",
"raw": {
"command.json": {
"bytes": 743,
"sha256": "0bdf9f0c8e885154a4f5c91cdd065c87a198512f6d05be136f6f4dd273ed1f39"
},
"stdout.log": {
"bytes": 178,
"sha256": "6b7ff3a63727394e801467b7a75bc60c81c712838c7f9d6c1ff8bb4a3e0ee30a"
},
"stderr.log": {
"bytes": 2497,
"sha256": "e8b19c5284b54009e4afbfd06dc605ebe63fea13c287590d0d930f60588fe8e6"
}
}
}
]
},
{
"id": 9,
"task_id": "P28-01-RESTART",
"kind": "review",
"commit_sha": "954528a7c5a0e27e2e50b642373168fa0a550aba",
"artifact": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/restart-independent-review-954528a-r01/actual-output-after-receiver-timeout/result.json",
"passed": 1,
"artifact_sha256": "b8fff13e8789797a4a50a5e2900f3d84ef20a6682a8f25feca225edc7fe00300",
"checks": []
},
{
"id": 10,
"task_id": "P28-01-RESTART",
"kind": "integration",
"commit_sha": "3ac2cedc8dc977778fd5a3ba152197cc6cf00fa2",
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p28-01-restart/runs/aa8aad481aa346c8a3358847a21f431e-integration.json",
"passed": 1,
"artifact_sha256": "85caa375586e707d3c736042b45b68acad8ab2821b6f52753dde62c3d6ed75f3",
"checks": [
{
"id": "p28-01-restart-unit",
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p28-01-restart/runs/f1e305c37cd9498ab3210d4aae76b074",
"raw": {
"command.json": {
"bytes": 744,
"sha256": "699b9c7e76930685a98eb6468a4a4e0bffbb6c08602330f947c179c8613e0c8b"
},
"stdout.log": {
"bytes": 172,
"sha256": "d40088aec669a9bbcad7191068385673beb897b9f4ef1557a5b2858cef3b5ccd"
},
"stderr.log": {
"bytes": 2497,
"sha256": "6df4c67bfbf0419620b40ef379fa125e2be762ad4d3f34e5c19ad44182dad5e9"
}
}
}
]
},
{
"id": 11,
"task_id": "P28-01-RESTART",
"kind": "final",
"commit_sha": "3ac2cedc8dc977778fd5a3ba152197cc6cf00fa2",
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p28-01-restart/runs/67f2fc17aca343bb9a92dd7d04b0f2b6-final.json",
"passed": 1,
"artifact_sha256": "856450b4401b9c3bb29688937d66dcdc5965adb014c6b5c4149a25b3c7f18308",
"checks": [
{
"id": "p28-01-restart-unit",
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p28-01-restart/runs/f0f3945d5b9b41438f8d771326134572",
"raw": {
"command.json": {
"bytes": 738,
"sha256": "b2bd6b6162ed297828f5c0a0fe7cab9858c332f55f78670a0361e1ad6d40e323"
},
"stdout.log": {
"bytes": 175,
"sha256": "ebbafcedb3072d5593fabca1b15aa440ed536383df3b55ac8aad979a8dd9745f"
},
"stderr.log": {
"bytes": 2497,
"sha256": "35b7c82b3c6ebfdf0e2ad458d64afe26514b4c1db297c140eb7aac1eb2a7da86"
}
}
}
]
}
],
"traceability_path": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p28-01-restart/traceability/P28-01-RESTART.json",
"traceability_sha256": "1febc7a16824fd8701a01e9d2d9f4482ee99e7a744742dd8b4267d06049c9ce4",
"native_execution_sha256": "c1ec566402896f9f3fdefdfc268de6ed0bc46b8a37a9eb6bfb252b0cc4ebb514",
"native_Root243_sha256": "6dbb3cbb4ac1838b66034323cab22a9c5a968c1da0efe8d34676073b3f980cfb",
"candidate_qualification_sha256": "5bd8030acddc385eb728441286f6a740ec1ee966125474b60ef4b1efe2a2c343",
"independent_reviewer_session": "local_251adf7f-dd2e-4726-9141-fff58a45eb14",
"actual_result_sha256": "b8fff13e8789797a4a50a5e2900f3d84ef20a6682a8f25feca225edc7fe00300",
"review_high_medium": 0,
"review_low": 3,
"receiver_timeout_kept_failed": true,
"new_reviewer_inference_on_rejoin": false,
"CLI_auth_recovered": false,
"original_credit": 0,
"original_completed": 22,
"original_total": 88,
"original_P28_01_whole_unit_accepted": false,
"remaining_original_gate_plan": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/P28-01_WHOLE_UNIT_GATE_PLAN_DESKTOP_233.md"
}
@@ -0,0 +1,173 @@
{
"status": "draft r02; not registered, dispatched or run. Root commits gate/SPEC.md and gate/TASK_INSTRUCTIONS.md to main and fills base_commit with that actual SHA.",
"assignment": {
"implementation": {
"worker": "codex",
"model": "gpt-6-astra",
"reason": "Bounded in code size but evidence-heavy: exact SHA/source-map/scope bindings across 7 evidence groups with strong rejection tests. Astra has the full collector/RESTART context and a reliable record here; OpenCode previously failed on tool truncation in this repository."
},
"independent_review": {
"model": "claude-opus-5-5",
"context": "fresh",
"transport": "separate Desktop session (CLI Claude auth expired); async delivery per REVIEW_DELIVERY_PLAN.md"
},
"run_decision": "Desktop governor gives the actual RUN decision after registration, in the 3-key commander schema"
},
"register_project": {
"project": "the-tree-p28-01-gate",
"repo": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部",
"worktrees": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-01-gate",
"baseline": [
{
"id": "P28-01-G0",
"requirement_id": "P28-01",
"text": "原work: 実Runtimeの20,000マス・200客・50職員・150施設を基準にTick、経路、snapshot、描画、保存を測る。原acceptance: 機種、ビルド、シード、速度、測定区間、平均・P95・最大を残す。",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
},
{
"id": "P28-01-G1",
"requirement_id": "P28",
"text": "原本条件とUI操作が一致",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
},
{
"id": "P28-01-G2",
"requirement_id": "P28",
"text": "Runtimeの実利用・会計・行動へ接続",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
},
{
"id": "P28-01-G3",
"requirement_id": "P28",
"text": "途中保存・再起動で再現",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
},
{
"id": "P28-01-G4",
"requirement_id": "P28",
"text": "異常/境界/中断を検証",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
},
{
"id": "P28-01-G5",
"requirement_id": "P28",
"text": "関連回帰PASS",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
},
{
"id": "P28-01-G6",
"requirement_id": "P28",
"text": "要件別ログとソースハッシュを保存",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
},
{
"id": "P28-01-U1",
"requirement_id": "P28-01",
"text": "補助(原本の条件ではない): 未達と、実施していない分岐を、合格に数えずに開示する。",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
},
{
"id": "P28-01-U2",
"requirement_id": "P28-01",
"text": "補助(原本の条件ではない): 再利用する各証拠が、それ自身の source・設定・engine・marker・入力・範囲に正確に適用できる。",
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
]
}
],
"validations": {
"p28-01-gate-unit": {
"argv": [
"{python}",
"docs/plans/original-completion-2026-10-02/execution/p28-01/gate/test_verify_p28_01_evidence.py"
]
},
"p28-01-gate-verify": {
"argv": [
"{python}",
"docs/plans/original-completion-2026-10-02/execution/p28-01/gate/verify_p28_01_evidence.py",
"--project-root",
"."
]
}
},
"validation_note": "p28-01-gate-verify requires the real E1-E7 bundle at $BUILD_OUTPUT_DIR/p28-01-gate-evidence and fails when it or BUILD_OUTPUT_DIR is absent; it writes its per-condition JSON to $BUILD_OUTPUT_DIR/p28-01-gate-verify.json and stdout (no argv placeholder needed). Synthetic unit PASS alone never accepts."
},
"register_task_contract": {
"id": "P28-01-GATE",
"title": "原P28-01 whole-unit 受入ゲート(既存証拠の結合)",
"requirement_ids": [
"P28-01",
"P28"
],
"acceptance_ids": [
"P28-01-G0",
"P28-01-G1",
"P28-01-G2",
"P28-01-G3",
"P28-01-G4",
"P28-01-G5",
"P28-01-G6",
"P28-01-U1",
"P28-01-U2"
],
"spec_ref": "docs/plans/original-completion-2026-10-02/execution/p28-01/gate/SPEC.md",
"base_commit": "TBD: actual main SHA that adds gate/SPEC.md and gate/TASK_INSTRUCTIONS.md",
"worker": "codex",
"allowed_paths": [
"docs/plans/original-completion-2026-10-02/execution/p28-01/gate/**"
],
"depends_on": [],
"resource_locks": [
"p28-01-gate"
],
"validation_ids": [
"p28-01-gate-unit",
"p28-01-gate-verify"
],
"max_repair_attempts": null
},
"evidence_bundle": {
"place_under": "$BUILD_OUTPUT_DIR/p28-01-gate-evidence/<repo-relative path>",
"files": "SPEC.md §3 E1-E7 artifacts/ entries, byte copies, read-only; docs/ entries are read from the checkout",
"required_for": [
"validation",
"integration",
"final"
]
},
"policy_note": "New project: align max_llm_runs to null under the existing owner delegation with the same owner script protocol, recorded honestly.",
"credit": "Gate completion is the only step that moves P28-01 to 23/88; P28 package stays in_progress.",
"unchanged": [
"original 30/88",
"budgets",
"product source map 1407",
"collector Q and RESTART Q bytes",
"permissions/auth/billing"
]
}
@@ -0,0 +1,11 @@
# P28-01-GATE 独立レビューの非同期配送(判断)
**判断: 採用します。** 推論は1回だけで、Runner 本体、権限、認証、課金は変更しません。
1. **凍結(受信待ちはまだ始めない)**: 正式な validation が合格した後、Root は Runner の通常の手順で、review の W・.review-material・packet・schema・target を作ります。それらを凍結し、packet の SHA と manifest の SHA を `READY_FOR_DESKTOP_REVIEW.json` に記録します。900秒の受信待ちは、まだ始めません。
2. **独立レビュー(1回)**: Desktop の管制が、新しい別セッション(claude-opus-5-5、fresh、読取専用、engine と試験は無し)を起動します。担当は packet と資料の SHA を自分で確かめ、schema に一致する結果だけを `DESKTOP_RESULT.json` に新規保存します。管制は、担当のセッションが終わった後に `DESKTOP_DELIVERY.json` を最後に作ります。
3. **受け入れ(1回)**: Root は delivery ができた後で、通常の review の受信を1回だけ実行します。その前に、次の条件を照合します。
- 同じ凍結 W であること、資料の全 SHA、packet の bytes、S、schema、target が一致すること。
- 未編集の結果を、通常の check_schema → review の判定 → evidence/state に通すこと。
- 一致しない場合は取り込まず、管制に戻します。
4. **記録**: Desktop の独立セッションの ID と結果の SHA、CLI の認証が切れていたこと(回復とはしない)、受信の失敗があればそれを、事実として記録します。
@@ -0,0 +1,43 @@
{
"authority": "Existing user instructed complete original plan, actual Desktop Opus266/268 gate design, Root delegated ordinary implementation/acceptance judgment; not new human SHA-specific statement",
"governor_session": "local_a7f85421-3eed-4482-8030-c0dca669573a",
"model": "claude-opus-5-5",
"role": "commander",
"implementation_model_chosen": "gpt-6-astra",
"adopted_from": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/p28-whole-unit-gate-draft-3ac2ced-r01",
"files": [
{
"path": "docs/plans/original-completion-2026-10-02/execution/p28-01/gate/SPEC.md",
"sha256": "e2bff09a16db9e8cf2646eac7fcc48b1fe7704fbf35ace34b7dab67ce5d4fde2"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p28-01/gate/TASK_INSTRUCTIONS.md",
"sha256": "246f80d101c27d472e2ebfd21b348ba27fd5a8129385c6fc4fa7fc52dcce43fa"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p28-01/gate/REGISTRATION_PROPOSAL.json",
"sha256": "6b154161b3b05c24683ee6a0f92b957be33867b5fa125b20326973dd9bad17c5"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p28-01/gate/REVIEW_DELIVERY_PLAN.md",
"sha256": "464fe1135930862bd21315b8649311e0a4042d7ce03f19e5b6c5fdd54d3475cf"
}
],
"original_conditions_unchanged": true,
"original_denominator": [
30,
88
],
"formal_completed": 22,
"partial_credit": false,
"baseline_count": 9,
"original_work_acceptance_and_cross6": 7,
"evidence_quality_support_conditions": 2,
"real_bundle_validation_required": true,
"synthetic_unit_alone_never_accepts": true,
"gate_registered": false,
"base_commit": "Registration will resolve actual commit containing these exact files; proposal TBD is not an execution value.",
"G3_independent_adjudication_required": true,
"no_engine_full9_192_reexecution": true,
"spec_draft_label": "Immutable commander draft is adopted by this record without editing its bytes."
}
@@ -0,0 +1,145 @@
# P28-01-GATE 仕様(原 P28-01 whole-unit 受入ゲート、spec_ref の草案 r02)
- 状態: 草案です。Root が原本の条件と受入を照合し、この文書を `docs/plans/original-completion-2026-10-02/execution/p28-01/gate/SPEC.md` として main に commit します。その実 SHA を base にしてから、通常の登録をします。数値や条件を独自に変えるものではありません。
- 前提: Desktop の計画(`P28-01_WHOLE_UNIT_GATE_PLAN_DESKTOP_233.md`、`bc222542…`)と、Root の対応表(`P28_WHOLE_UNIT_GATE_BINDING_FOLLOWUP_954528A.json`)を、現在の正式記録に合わせて具体化したものです。
## 1. 原本の条件(変更しない)
- 成果単位 P28-01「現HEADの性能基準」(`work_packages.json` の P28.remaining_deliverables[0])
- work: 実Runtimeの20,000マス・200客・50職員・150施設を基準にTick、経路、snapshot、描画、保存を測る。
- acceptance: 機種、ビルド、シード、速度、測定区間、平均・P95・最大を残す。
- P28 の横断条件6件(cross_cutting_acceptance の原文):
1. 原本条件とUI操作が一致
2. Runtimeの実利用・会計・行動へ接続
3. 途中保存・再起動で再現
4. 異常/境界/中断を検証
5. 関連回帰PASS
6. 要件別ログとソースハッシュを保存
- 分母は 30/88 で、部分点はありません。このゲートが完了した場合に限り、P28-01 を 22→23 とします。P28 パッケージは in_progress のままです。
## 2. baseline(9件。原本の原文は G0 と G1〜G6 の7件。U1/U2 は証拠の品質を保つための補助)
| id | 内容 |
|---|---|
| G0 | 原 work と原 acceptance(§1 の原文) |
| G1〜G6 | 横断条件1〜6(§1 の原文) |
| U1 | 未達と、実施していない分岐を、合格に数えずに開示する |
| U2 | 再利用する各証拠が、それ自身の source・設定・engine・marker・入力・範囲に正確に適用できること(全証拠に共通の1つの入力を仮定しない) |
U1 と U2 は原本の条件ではありません。「原本の9条件」として扱ってはいけません。
## 3. 結合する証拠(path は repository からの相対。SHA256 は完全な値)
Root は E1〜E7 の全ファイルを、bytes をそのまま `$BUILD_OUTPUT_DIR/p28-01-gate-evidence/<repository からの相対 path>` に読取専用で置きます。`docs/` の下のものは、validation の checkout から直接読みます。
**E1 collector の正式完了**
- `docs/plans/original-completion-2026-10-02/execution/p28-01/COLLECTOR_FORMAL_COMPLETION_0F53A67.json` `2886547ae2ccd000a85cf8374304f292f85ed2899d9ebe9818833600dc9ff55f`
- `docs/plans/original-completion-2026-10-02/execution/p28-01/COLLECTOR_INDEPENDENT_REVIEW_5DB97D7.json` `23eed6741996a7b9327fcceda2e852104315954105c9c09f0dfcdf35c88c8d41`
- 検査: task が completed で、4つの gate がすべて pass。Q `0f53a67210227207efa63045de88a9a7c6e45409`。collector の4ファイル(`execution/p28-01/collector/*`)が、base の bytes と一致すること。
**E2 統合版の全9 phase(実際の commit は `db9d6132a8349928560dc4a4a99306d27a81e332`。新しい Q での実測ではない)**
- `artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/full-measurement-db9d613-r01/run/execution.json` `a4d10e9b1a75a17b981792265338d64fac61178cb6f87dd646c5b486292db73c`
- 同じ dir の `run/admission.json` `c4a3b5ba7a2b6427e55a6f85f037ded08e0c6bfd8c0a766647747ea9cc94378d`
- 同じ dir の `ROOT_RAW_ACCEPTANCE_JOIN.json` `a76082f767e0a0d52cb70e2f66fa371b62a88754e9be319da3c08d4b48e78ba0`(`docs/…/INTEGRATED_FULL9_MEASUREMENT_DB9D613.json` も同じ SHA)
- 検査:
- admission の commit と source map は1407件(`651f7036…`)。
- R0/P1/P2/O0/P3/P4 の各 report に、`metadata.machine`、`metadata.build`、seed、speed、区間(開始/終了のゲーム分、wall 時刻、frame 数)、平均・P95・最大・標本数がある。
- R の登録は 20,000/200/50/150 で、稼働は100施設。P2 の warm は 31分(150分と書き換えない)。
- **描画の CPU は P1〜P4 だけで取得されている**(件数 P1 150、P2 50、P3 2398、P4 745)。R0 と O0 は、CPU も GPU も null で、理由は `zero_from_api_on_gl_compatibility_unsupported_or_unmeasured`。GPU は全 phase で null と同じ理由。
**E3 r02(経路・snapshot・保存・読込。headless・Ops OFF・x1 の観測だけ)**
- dir `artifacts/original-completion-2026-10-02/p14-03-representative-perf-r01/`:
- `run-r02/execution.json` `553971f55635e529b48634ef86ad7d4198c8bafe04d5a6a5ef778a4de0439fc1`
- `run-r02/readiness.json` `da93aecdd2c1648952e2a80382acb7e3f30cfe48a7e5df982315791161fedde2`
- `run-r02/after/evidence/report.json` `f1d447937158a884a1b287c3b5be38b6e73b73c5d748f9576401877402dabe1b`
- `run-r02/after/measure.stdout.log` `294730160536fc862ca657654fbae290b874acc65b77a6d24aaccd9a859907f7`
- `run-r02/before/evidence/report.json` `a070c061ca783aaec37152bf66ad6b6e6dc69b80d9c4c024eceab916d4c5d4e9`
- 実行した script: `run-r02/measure.gd` `95e5967835cb05ad96e8e6f257689d0bd831792aa9c228c022e3af81448ff76a`、`run-r02/guarded.gd` `c9deebb39ee643d312a77bae64f74cf6851697bb31036fc56d67dd7c4037ee09`、`run-r02/profile_guard.gd` `597696c705cc8f0e79a35265ca3ef8df55f7fc3c4e0e5a2ce9a4e20e29e29a6f`、`collect_perf.py` `43f3e42900a670957a01cfcaca7e485809527b79912a358917c935c57ea9c063`
- 入力: `artifacts/original-completion-2026-10-02/p28-current1299-runtime-scale-build-candidate-native-r01/fixture/reference.variant` `eb4f770071eb07cd7e136fe54c3f78768cc8de7a4264e62a9af1f06a8f90f9bd`
- 検査(1407 の source の一致だけで済ませない):
- execution の after/measure phase の report の SHA が `f1d44793…` で、PID が 46264。report は raw の stdout の `P14_03_PERF_REPORT=` の行と同じ。
- report の `input_sha256` が入力の SHA と同じ。`prepared_state_sha256`(`9ca8f809…`)、`migrated_input_state_sha256`、`running_state_sha256` を記録する。`counts_prepared` は 20,000/200/50/150。
- engine は readiness の `engine_sha256` `c7cccbf8fb143e34e02fd6521e09be2c2b974f0d5db080b19071c9c570718ccf`(4.7.2-stable official)。probe は `95e59678…`、runner は `43f3e429…`。hardware は `Mac16,10`・10・10・25769803776。
- source: readiness の after `83b170a4c7176761b0b18d8e9292017d990e80a9`(1407件)の source map が、E4 の selected_source_map と一致し、それが現在の source map とも一致する。
- speed は x1(`advance_one_minute_wall_ms_x1`)。区間と標本数は、各統計の count(x1 300、経路 cold 245 など)。統計は平均・P95・最大。
- seed: r02 の report には seed の欄がありません。値を作らず、入力の SHA が E2 の R と同じであることと、E2 の R の report の seed(28012026)を根拠として記録します。
- marker: r02 は回帰ではないので、marker 契約は適用外。理由を記録します。
**E4 正式192(関連回帰)**
- dir `artifacts/original-completion-2026-10-02/p14-03-formal-regression-83b170a-r01/`: `runner-input.json` `5bc9760c0c114a80a3c9e93634e733fc8fa93d4eeea5d8bcfda85d8e4eebd094`、`runner-ended.json` `705fb2c12007bab125548742dc8d9b07918e30cae3a63c7d89e965c43b8b5f7b`、`all-tests.json` `31da4c4672f4321469183996e12fb23064b3772a69e8330052ab3e2ea66044f1`
- marker 契約: `docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json` `0ff86a20891da66d84295f0c66ae7517ef586b54a1a668acb7778a450d473cd2`
- 検査: 192/192、22,198 checks、失敗0。input の marker_contract_sha256 と engine_sha256 が一致する。selected_source_map が、validation の checkout の現在の product source map(`tools/run_all_tests.source_refs`)と完全一致する。
**E5 RESTART の正式完了**
- `artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/RESTART_3AC2CED_FORMAL_DB_JOIN.json` `5c9b82a70f6bdb972d720aaa64f5d27aa54130f27f9d1f7cea1c7b02524f84be`
- `artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/ROOT_CANDIDATE_3AC2CED_QUALIFICATION.json` `5bd8030acddc385eb728441286f6a740ec1ee966125474b60ef4b1efe2a2c343`
- 検査: completed 8/8、4つの gate がすべて pass。S `954528a7c5a0e27e2e50b642373168fa0a550aba`、Q `3ac2cedc8dc977778fd5a3ba152197cc6cf00fa2`、M `3086af2ccd970ddee271a184214dad037bd1d6af`。承認は、既存の委任に基づくもの(新しい人間の発言ではない)。
**E6 RESTART の native(最終 S)**
- `artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/native-restart-954528a-r01/run/execution.json` `c1ec566402896f9f3fdefdfc268de6ed0bc46b8a37a9eb6bfb252b0cc4ebb514`
- 同じ dir の `ROOT_RAW_ACCEPTANCE_JOIN.json` `6dbb3cbb4ac1838b66034323cab22a9c5a968c1da0efe8d34676073b3f980cfb`
- 検査:
- 7 phase とも PASS。writer と reader の PID がすべて異なる。
- `restart/probe/*` の4ファイルが、base(= Q `3ac2ced` 以降の main)の bytes と一致する(再利用の条件)。
- R/O とも K=30 で、毎分の typed SHA が一致。改ざんは CHECKSUM_MISMATCH で拒否される。O の390分の記録は ID 9〜24 が連番で、counter 24。
**E7 独立レビュー**
- `artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/restart-independent-review-954528a-r01/DESKTOP_RESULT.json` `b8fff13e8789797a4a50a5e2900f3d84ef20a6682a8f25feca225edc7fe00300`(delivery `90b6943d86bf370599c3a8629c57a69806374a5863ce18957a7b7d696a5be9fd`)
- 以前の changes_requested: `independent-review-bc703c9-changes-requested-r01/result.json` `f2e67cb2adbef9c9294ec1e879da70b500fa27d2220d9ae1b9fb50c96cbdc3b2`
- 検査: 最終が pass であること。low 3件を消さずに記録すること。
各証拠は、それぞれの source・設定・engine・marker・入力・範囲にだけ適用します。たとえば r02 の値を windowed の値と言い換えたり、full9 を Q での実測と言い換えたりしません。
## 4. 条件表(verifier は結合を確かめ、whole-unit の独立レビューが判定する)
| 条件 | 根拠 | 範囲と未達 |
|---|---|---|
| G0 work | Tick と描画(CPU は P1〜P4)は E2。経路・snapshot・保存・読込は E3 | 稼働していた施設は100。GPU は null。E3 は headless・Ops OFF・x1 |
| G0 acceptance | E2 と E3 の各 report の欄 | 記録の項目がそろえば成立する。予算の合否は条件に含まれない |
| G1 | collector C1/C9(`_set_speed`→`_process`、main)と RESTART RS1(UI での保存と読込) | 測定の範囲は Mac(Mac16,10)。Windows での最終受入は未達のまま |
| G2 | 既定の autoload の世界、O の実際の Ops ON、RESTART の実際の継続 | O は小さな入力(客0〜2)。200客での Ops ON は上限100のため不可 |
| G3 | RESTART RS1〜RS5(E5、E6)と、下の明示した証拠 | 下の判断材料を参照。最終的な判定は whole-unit の独立レビューが行う |
| G4 | collector の停止契約と phase の失敗の記録、RESTART の改ざん・停止・境界 | 実施していない分岐は U1 で開示する |
| G5 | E4 を再利用(source と marker の一致)。collector と RESTART の unit validation | 製品が変わったら、全 roster をやり直す |
| G6 | 全 receipt の SHA、Root の結合、verifier の manifest | — |
**G3 の判断材料**(これらは証拠の提示であって、合否はそこから導きません):
- E7 の最終 review の RS5 の判断(「overload は条件付きの分岐で、実施されていないことを開示し、保持されるとは主張しない」)と、low の1件目(「0でない backlog の保持は実施していない」)。
- 製品の契約: `scripts/core/simulation_kernel.gd:217-231`(`restore_clock` が `_accumulator` を0に戻し、`_skip_next_process` を立てる)と、snapshot の範囲(`autoload/simulation_runtime.gd:521-583`)。1分未満の accumulator は、保存される状態の外にある。
- 「発生しなかった」ことは、保存できたことの証明ではありません。独立レビューは、原本の条件「途中保存・再起動で再現」が、overload で止まって backlog が0でない状態の保存と、1分未満の実時間の位相までを要求するかどうかを、原文と上の証拠から判断します。要求すると判断した場合は、未達として changes_requested にします。
## 5. U1: 開示する未達(合否には含めない。P28 / P28-02 / P28-03 に残す)
- 予算の未達: P1 x1 平均 479.210 ms > 4、P1 stall 最大 4809.099 ms > 50、P2 x3 P95 5062.697 ms > 12、P2 stall 最大 5891.466 ms > 50。
- 200客での Operations ON(不可)。O の P3/P4 の合格は、小さな入力に限られる。
- GPU 時間は null(gl_compatibility)。R0 と O0 は CPU も null。
- 同一の Windows 実機、長期の操作感とバランス、ゲーム全体の受入。
- RESTART の low 3件と、G3 の判断の結果。
## 6. 成果物(worker。allowed_paths は `docs/plans/original-completion-2026-10-02/execution/p28-01/gate/**` のみ)
- `verify_p28_01_evidence.py`: engine を使わない verify-only の検査です。§3 の全証拠を、`EVIDENCE_BUNDLE_MANIFEST.json`(全ファイルの bytes と SHA)と、上に固定した SHA で結合します。
- `--project-root .` は必須。`--evidence-root` を省略すると、`$BUILD_OUTPUT_DIR/p28-01-gate-evidence` を使います。どちらも無い場合、または証拠が欠けている場合は、**失敗**にします(スキップしない)。
- 条件ごとの結果の JSON を stdout に出力し、`$BUILD_OUTPUT_DIR` が設定されていれば `$BUILD_OUTPUT_DIR/p28-01-gate-verify.json` にも書き出します(`--json <path>` で、書出し先を明示的に指定することもできます)。source の木には書き込みません。
- 失敗は、構造化した検査の失敗として返します(traceback で終わらせない)。
- `EVIDENCE_BUNDLE_MANIFEST.json`、`GATE_CONDITIONS.json`(§4 と §5 の機械可読版。各条件の根拠になる path と SHA、範囲、未達)。
- `test_verify_p28_01_evidence.py`: 合成した証拠を使う正常試験と拒否試験。
## 7. verifier と試験が必ず拒否するもの
- manifest の外のファイル、SHA の不一致、証拠の欠落、改ざん。
- 範囲を外れた適用:
- full9 の commit を Q と表記すること
- r02 を windowed の値と言い換えること
- r02 の seed を作ること
- R0/O0 の CPU を取得済みとすること
- 予算の false を合格として扱うこと。GPU の null を0や合格に置き換えること。
- R の稼働数(100施設)を登録数として扱うこと。O の小さな入力を「200客」と表記すること。
- RESTART の4つの gate のどれかが欠けていること。probe の bytes が Q と一致しないこと。
- E4 の source map または marker が、現在のものと一致しないこと。
- U1 の項目が欠けていること。U1/U2 を原本の条件として数えること。G3 を「発生しなかった」だけで合格とすること。
## 8. 対象外
- engine、全192、full9、collector、RESTART の再実行。
- 製品、依存、予算値、原本の分母の変更。Runner 本体、権限、認証、課金の変更。
@@ -0,0 +1,13 @@
# P28-01-GATE worker 指示
仕様は同じディレクトリの `SPEC.md` です。この指示と仕様は変更しないでください。
- 作るもの(allowed_paths `docs/plans/original-completion-2026-10-02/execution/p28-01/gate/**` の中だけ): `verify_p28_01_evidence.py`、`EVIDENCE_BUNDLE_MANIFEST.json`、`GATE_CONDITIONS.json`、`test_verify_p28_01_evidence.py`。
- 実装する範囲: SPEC の §3 の全結合、§4 と §5 の条件表と開示、§7 の拒否のすべて(それぞれに拒否試験を置く)。
- 証拠は、Root が `$BUILD_OUTPUT_DIR/p28-01-gate-evidence/<repository からの相対 path>` に読取専用で置きます。manifest は、その実際の bundle を読んで作ります。SPEC §3 に固定した SHA と食い違うファイルがあれば、manifest に入れずに blocked にして報告します。
- validation は2つです。`p28-01-gate-unit`(合成した証拠の試験)と、`p28-01-gate-verify`(実際の bundle に対して `verify_p28_01_evidence.py --project-root .` を実行するもの。結果の JSON は `$BUILD_OUTPUT_DIR/p28-01-gate-verify.json` と stdout)。実際の bundle が無い場合、verify は必ず失敗します。合成の試験の PASS だけで受入にはなりません。
- 試験には、欠損、改ざん、範囲を外れた適用(SPEC §7)を拒否するものを含めます。
- 外部の import は標準ライブラリだけにします。製品の Python は import しません。必要なら、`tools/run_all_tests.py` の `source_refs` だけを読取専用で使ってかまいません。
- しないこと: engine の起動、全回帰、製品やほかの task のファイルの変更、commit。
- 提出前に、engine を使わない `python3 test_verify_p28_01_evidence.py` を局所で実行して全件 PASS を確かめ、生出力をそのまま報告します。一時ディレクトリは `BUILD_OUTPUT_DIR` か `tempfile.gettempdir()` の下に作り、source には書き込みません。
- 承認された範囲の中の通常の実装上の選択は、worker の判断でかまいません。決めきれない不足は、具体的な箇所を示した場合に限り blocked にします。
@@ -0,0 +1,735 @@
#!/usr/bin/env python3
"""RESTART evidence validation; typed state comparisons execute in Godot."""
import ast
import copy
import hashlib
import importlib.util
import json
import math
from pathlib import Path
import re
import sys
import sysconfig
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[6]
BASE = "docs/plans/original-completion-2026-10-02/execution/p28-01/"
DEPENDENCIES = {
"tools/run_all_tests.py": "320ca668732b4ff72fc4449998af2327d4e5c527b06896740806aaf0487282b4",
"tools/regression/owned_outer.py": "c2e3483b76db1a3ff940f23f88ea0083fc78736e874ebcdb385d766dde8866e7",
"tools/regression/owned_diagnostic_process.py": "e31e93c6e2c5ea46a7d954ef8bc0b4caec1c08b86b8aef19e93b52ef24993087",
"tools/regression/p09_owned_engine_process.py": "c007e712c281573254faa1233c2ac92e100ab87393256a6dc096b35283e43037",
BASE + "collector/collect_p28_01.py": "a43e1f963ef8505ddd5acf8bf747d9bfac22a028cbb805c0b964ee11b9b40a14",
BASE + "collector/check_p28_01_report.py": "6c0851d498ca80bdc120fad047b072255f48713f63114521f3d4dfc902b2512b",
}
LOCAL = {BASE + "restart/probe/" + n for n in
("restart_pair.py", "check_restart.py", "test_restart.py", "restart_probe.gd")}
SIDECAR = "p28_restart/evidence/report_full.json"
TIMINGS = ("duration_us", "runtime_duration_us")
SAVE_EVENTS = {
"SAVE_CHECKPOINT_SUCCEEDED", "SAVE_CHECKPOINT_FAILED", "SAVE_LOADED", "SAVE_LOAD_FAILED",
"SAVE_MIGRATION_SUCCEEDED", "SAVE_MIGRATION_FAILED", "SAVE_RECOVERY_LOADED",
"SAVE_RECOVERY_CANDIDATE_LOADED", "SAVE_RECOVERY_FAILED",
}
PHASES = ["import", "parse-base", "parse-wrapper", "R-writer", "R-reader", "O-writer", "O-reader"]
CROSS = [
{"condition": "原本条件とUI操作が一致", "applicable": False, "reference": "collector C1/C2",
"reason": "既存collectorのUI経路受入を参照。このtaskは再開の比較を担当する。"},
{"condition": "Runtimeの実利用・会計・行動へ接続", "applicable": False, "reference": "collector C2/C3",
"reason": "既存collectorの実Runtime観測を参照。製品の接続は変更しない。"},
{"condition": "途中保存・再起動で再現", "applicable": True, "reference": "RS1/RS2/RS3/RS4/RS5",
"reason": "別PIDのR/O writerとreaderで適用する。"},
{"condition": "異常/境界/中断を検証", "applicable": False, "reference": "collector C5/C6/C7",
"reason": "横断受入は既存collectorを参照。再開固有の異常と境界はRS5で検証する。"},
{"condition": "関連回帰PASS", "applicable": False, "reference": "collector C8",
"reason": "既存collectorの正式回帰証拠を参照。workerは全回帰を実行しない。"},
{"condition": "要件別ログとソースハッシュを保存", "applicable": False, "reference": "collector C6/C7/C9",
"reason": "既存collectorの証拠契約を参照。再開のraw結合はRS7で保存する。"},
]
def require(condition, message):
if not condition:
raise ValueError(message)
def sha(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def pin(path):
path = Path(path)
require(path.is_file() and not path.is_symlink(), "missing/symlink evidence")
return {"sha256": sha(path), "bytes": path.stat().st_size}
def check_dependencies(root=ROOT):
for name, expected in DEPENDENCIES.items():
require(sha(root / name) == expected, "dependency SHA: " + name)
def check_imports(text, external=None):
tree = ast.parse(text)
if external is not None:
require(external in DEPENDENCIES, "external AST closure")
# The explicitly forbidden run_all_tests.main imports are not executed.
tree.body = [node for node in tree.body if not (
isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == "main")]
allowed = {Path(p).stem for p in set(DEPENDENCIES) | LOCAL}
for node in ast.walk(tree):
if isinstance(node, (ast.Import, ast.ImportFrom)):
names = [node.module] if isinstance(node, ast.ImportFrom) else [a.name for a in node.names]
for name in names:
require(name and (standard_library(name.split(".")[0]) or name in allowed),
"import outside closure")
if isinstance(node, ast.Call):
name = node.func.id if isinstance(node.func, ast.Name) else getattr(node.func, "attr", "")
require(name not in ("__import__", "eval", "import_module"), "dynamic code forbidden")
require(name != "exec" or external == "tools/regression/owned_diagnostic_process.py",
"unapproved exec")
if name == "spec_from_file_location":
for sub in ast.walk(node):
if isinstance(sub, ast.Constant) and isinstance(sub.value, str):
for path in re.findall(r"[\w./-]+\.py", sub.value):
require(path in DEPENDENCIES or path in LOCAL or
path in {Path(p).name for p in DEPENDENCIES}, "loader outside closure")
if external and isinstance(node, ast.BinOp):
for sub in ast.walk(node):
if isinstance(sub, ast.Constant) and isinstance(sub.value, str) and sub.value.endswith(".py"):
require(sub.value in DEPENDENCIES or sub.value in {Path(p).name for p in DEPENDENCIES},
"external loader path outside closure")
def standard_library(name):
# Python 3.9 on the native host has no sys.stdlib_module_names.
spec = importlib.util.find_spec(name)
if spec is None:
return False
if spec.origin in ("built-in", "frozen"):
return True
if not spec.origin:
return False
path = Path(spec.origin).resolve()
return path.is_relative_to(Path(sysconfig.get_path("stdlib")).resolve()) and not any(
part in ("site-packages", "dist-packages") for part in path.parts)
def check_modules(modules=None, root=ROOT):
for module in (sys.modules if modules is None else modules).values():
name = getattr(module, "__file__", None)
if name:
path = Path(name).resolve()
if path.is_relative_to(root):
require(path.relative_to(root).as_posix() in set(DEPENDENCIES) | LOCAL,
"loaded project module outside closure")
def check_probe(text):
# Focused guard for direct Variant inference only, not GDScript compilation.
# Root's actual Godot parse remains required.
lines = [raw.split("#", 1)[0] for raw in text.splitlines()]
variant_names = set()
variant_functions = {"field"}
for line in lines:
declaration = re.match(r"^var\s+(\w+)\s*:\s*Variant\b", line)
if declaration:
variant_names.add(declaration[1])
declaration = re.match(r"^func\s+(\w+)\s*\(.*\)\s*->\s*Variant\b", line)
if declaration:
variant_functions.add(declaration[1])
function = None
blocks = []
pauses = 0
watchdog_calls = 0
for raw in text.splitlines():
line = raw.split("#", 1)[0]
inferred = re.match(r"^\s*var\s+\w+\s*:=\s*(\w+)\b(.*)", line)
if inferred:
require(not (inferred[1] in variant_names or
(inferred[1] in variant_functions and inferred[2].lstrip().startswith("("))),
"direct Variant inference requires an explicit type")
match = re.match(r"^func (\w+)\(", line)
if match:
function = match[1]
if function == "deterministic_step":
blocks.append([])
if function == "deterministic_step":
blocks[-1].append(line)
require(not re.search(r"set_paused\s*\(\s*false|\bclear\s*\(|spawn_guest|SimulationRuntime\.new|\binitialize\s*\(|enable_production_|_toggle_pause", line),
"forbidden probe API")
if re.search(r"\badvance_", line):
require(function == "deterministic_step" and line.strip() == "GameClock.advance_minutes(1)",
"advance outside deterministic_step")
if "set_paused(" in line:
require(function == "on_tick" and line.strip() == "GameClock.set_paused(true)", "pause outside tick")
pauses += 1
if "Time." in line:
require(function == "deadline_timer_seconds" and
line.strip() == "return Time.get_ticks_msec() / 1000.0", "timing API outside watchdog")
watchdog_calls += 1
# Literal names are used only by the finite evidence redaction routine.
timing_line = line.strip() == 'for key: String in ["duration_us", "runtime_duration_us"]:'
require(not re.search(r"\b\w+_(?:us|ms)\b|Performance\.|get_performance_report", line)
or (function == "redact_payload" and timing_line),
"performance instrumentation")
require(len(blocks) == 1 and pauses == 1 and watchdog_calls == 1, "deterministic/tick/watchdog functions required")
block = "\n".join(blocks[0])
require(block.count("GameClock.advance_minutes(1)") == 1 and
"io_ready" in block and "GameClock.paused" in block, "step admission")
def event_id(counter):
require(type(counter) is int and counter >= 0, "counter type")
return "domain_event.%012d" % (counter + 1)
def transform(witness, event):
"""Consistency oracle for recorded IO paths, not a Godot state decoder."""
result = copy.deepcopy(witness)
eid = event_id(witness["counter"])
ids, recent = witness["published_ids"], witness["recent_events"]
require(event["event_id"] == eid, "IO event ID")
require(ids == sorted(set(ids)) and eid not in ids and len(recent) <= 256, "event history")
require(len({x["event_id"] for x in recent}) == len(recent) and
all(x["event_id"] in ids for x in recent), "recent IDs")
result["counter"] += 1
result["published_ids"] = sorted(ids + [eid])
result["recent_events"] = (recent[1:] if len(recent) == 256 else recent) + [event]
return result
def exact(row):
require(row["method"] == "var_to_bytes" and row["equal"] is True and row["diff_paths"] == [],
"typed bytes differ")
require(row["excluded_paths"] == [], "state path exclusion")
require(re.fullmatch("[0-9a-f]{64}", row["expected_sha256"]) and
row["actual_sha256"] == row["expected_sha256"], "typed comparison contradiction")
def check_io(row, kind):
require(row["kind"] == kind and row["signal_count"] == 1, "one IO signal required")
signal, latest, ev = row["signal_payload"], row["latest"], row["event"]
require(signal == latest == ev["payload"], "signal/latest/event mismatch")
require(row["signal_projection"] == "_save_event_payload" and row["payload_bytes_equal"] is True,
"typed payload comparison")
success = kind != "tamper"
require(type(signal["ok"]) is bool and signal["ok"] is success and
((signal["code"] == "OK") is success), "IO result")
require(signal["operation"] == ("save" if kind == "save" else "load"), "operation")
require(signal["save_path"].startswith("user://p28_restart/") and ".." not in signal["save_path"],
"private IO path")
require(row["return_kind"] == ("bool" if kind == "save" else "void"), "return kind")
require(row["return_value"] is signal["ok"] if kind == "save" else row["return_value"] is None,
"return/signal mismatch")
expected_type = {"save": "SAVE_CHECKPOINT_SUCCEEDED", "load": "SAVE_LOADED",
"tamper": "SAVE_LOAD_FAILED"}[kind]
require(ev["event_type"] == expected_type and ev["source_service"] == "save_service" and
ev["entity_ids"] == [] and ev["causation_command_id"] == 0, "event shape")
require(ev["absolute_minute"] == row["minute_after"] == row["minute_before"], "IO minute")
require(row["after"] == transform(row["before"], ev), "not X(P,event)")
require(row["dropped"] == (row["before"]["recent_events"][0]
if len(row["before"]["recent_events"]) == 256 else None), "wrong dropped head")
exact(row["comparison"])
if success:
require(signal["saved_absolute_minute"] == row["minute_after"] and bool(signal["save_id"]),
"save identity")
require(row["paused_after"] is True, "IO clock not paused")
else:
failure = row["failure"]
require(failure["preload_pause_restored"] is True and
failure["loaded_clock_paused"] is row["paused_before"] and
row["paused_after"] is row["paused_before"], "tamper pause")
if failure["recovery_report"] is not None:
require(failure["recovery_report"]["restore_committed"] is False, "tamper restore")
require(type(failure["migration_attempted"]) is bool, "migration observation")
def save_event(event):
return isinstance(event, dict) and event.get("source_service") == "save_service" and \
event.get("event_type") in SAVE_EVENTS
def payload_paths(report):
"""The complete W2 closure; no recursive payload-name exemption."""
result = {}
for i, row in enumerate(report["io"]):
prefix = "/report/io/%d" % i
for name in ("signal_payload", "latest"):
result[prefix + "/" + name] = row[name]
events = [(prefix + "/event", row["event"]), (prefix + "/dropped", row["dropped"])]
for side in ("before", "after"):
events.extend((prefix + "/" + side + "/recent_events/%d" % j, event)
for j, event in enumerate(row[side]["recent_events"]))
for path, event in events:
if save_event(event):
result[path + "/payload"] = event["payload"]
for k, row in enumerate(report["minutes"]):
if save_event(row["replacement"]):
result["/report/minutes/%d/replacement/payload" % k] = row["replacement"]["payload"]
return result
def walk(value, path=""):
if isinstance(value, dict):
for key, child in value.items():
pointer = path + "/" + key.replace("~", "~0").replace("/", "~1")
yield pointer, key, child
yield from walk(child, pointer)
elif isinstance(value, list):
for i, child in enumerate(value):
yield from walk(child, path + "/" + str(i))
def redact_report(verbatim):
"""Also validates the full sidecar report before producing its unique public form."""
full = json.loads(json.dumps(verbatim))
allowed = payload_paths(full)
for path, key, _ in walk(full, "/report"):
require(key != "timing_redactions", "reserved marker in verbatim evidence")
require(not key.endswith(("_us", "_ms")) or
(path.rsplit("/", 1)[0] in allowed and key in TIMINGS), "timing outside W2 closure")
require(key not in ("performance", "statistics", "fps", "budget_verdict"),
"sidecar performance use")
for path, payload in allowed.items():
require(isinstance(payload, dict) and all(k in payload for k in TIMINGS), "both timing keys required")
payload["timing_redactions"] = [
{"original_key": key, "sidecar_ref": path + "/" + key} for key in TIMINGS]
for key in TIMINGS:
del payload[key]
check_no_metrics(full)
return full
def resolve_pointer(sidecar, pointer):
require(pointer.startswith("/report/"), "pointer outside report")
value = sidecar
for part in pointer[1:].split("/"):
part = part.replace("~1", "/").replace("~0", "~")
value = value[int(part)] if isinstance(value, list) else value[part]
return value
def json_sha(value):
# JSON numbers are represented uniformly across Godot's JSON float parser
# and Python. Fixed decimal form is valid JSON; keys and strings remain verbatim.
def encode(v):
if isinstance(v, dict):
require(len({str(k) for k in v}) == len(v), "canonical_key_collision")
require(all(type(k) is str for k in v), "canonical JSON requires text keys")
return "{" + ",".join(json.dumps(k, ensure_ascii=False) + ":" + encode(v[k])
for k in sorted(v)) + "}"
if isinstance(v, list):
return "[" + ",".join(encode(x) for x in v) + "]"
if type(v) in (int, float):
require(math.isfinite(v), "nonfinite JSON")
return format(v, ".17f")
return json.dumps(v, ensure_ascii=False, separators=(",", ":"), allow_nan=False)
return hashlib.sha256(encode(value).encode()).hexdigest()
def canonical_event(event, eid):
return {"event_id": eid, "replaced_for_cross_pid_compare": True} \
if event["event_id"] == eid else event
def check_sidecar(public, sidecar):
require(isinstance(sidecar, dict) and set(sidecar) == {"report", "at_390_event_verbatim"},
"sidecar root/missing")
check_no_metrics(public)
full = sidecar["report"]
require(full.get("stop_reason") != "canonical_key_collision", "canonical_key_collision")
require(public == redact_report(full), "public redaction differs from W2")
restored = copy.deepcopy(public)
for path, payload in payload_paths(restored).items():
expected = [{"original_key": k, "sidecar_ref": path + "/" + k} for k in TIMINGS]
require(payload.pop("timing_redactions") == expected, "redaction marker/pointer mismatch")
for marker in expected:
payload[marker["original_key"]] = resolve_pointer(sidecar, marker["sidecar_ref"])
require(restored == full, "entire restored report differs")
events = sidecar["at_390_event_verbatim"]
require(isinstance(events, list), "at390 verbatim array")
observation = full.get("at_390")
summaries = observation["events"] if observation is not None else []
require(len(events) == len(summaries), "at390 verbatim count")
for event, summary in zip(events, summaries):
for path, key, _ in walk(event):
require(key != "timing_redactions" and key not in
("performance", "statistics", "fps", "budget_verdict"), "at390 forbidden field")
require(not key.endswith(("_us", "_ms")) or
(save_event(event) and path == "/payload/" + key and key in TIMINGS),
"at390 timing outside SAVE payload")
if save_event(event):
require(all(k in event["payload"] for k in TIMINGS), "at390 both timing keys")
require(set(summary) == {"event_id", "event_type", "absolute_minute",
"raw_event_sha256", "canonical_sha256"}, "at390 summary shape")
require(all(event[k] == summary[k] for k in ("event_id", "event_type", "absolute_minute")),
"at390 verbatim order/metadata")
require(json_sha(event) == summary["raw_event_sha256"] and
json_sha(canonical_event(event, full["event_id"])) == summary["canonical_sha256"],
"at390 raw/canonical SHA")
return full
def check_deadline(value, complete=True):
require(set(value) == {"limit_seconds_from_engine_start", "engine_elapsed_at_begin_seconds",
"timer_seconds"}, "deadline shape")
elapsed, timer = value["engine_elapsed_at_begin_seconds"], value["timer_seconds"]
require(type(elapsed) in (int, float) and type(timer) in (int, float) and
math.isfinite(elapsed) and math.isfinite(timer) and elapsed >= 0 and
value["limit_seconds_from_engine_start"] == 1740 and timer == 1740 - elapsed,
"engine elapsed deadline formula")
require(not complete or timer > 0, "expired deadline")
def overload_case(report):
backlog = report["paused_idle"]["before"]["backlog"]
overloads = report["overloads"]
require(isinstance(overloads, list) and type(backlog) is int and backlog >= 0, "overload facts")
expected = {"exercised": bool(overloads and backlog > 0),
"overloads": len(overloads), "backlog_at_save": backlog}
require(report["overload_case"] == expected and
type(report["overload_case"]["exercised"]) is bool and
set(report["overload_case"]) == set(expected), "overload disclosure")
for _, key, value in walk(report):
if key in ("nonzero_backlog_preserved", "overload_persistence",
"across_restart_backlog_persistence_claimed"):
require(value is False, "unsupported overload/persistence claim")
return expected
def coverage(reports):
detail = {r["role"]: overload_case(r) for r in reports if r["role"].endswith("writer")}
return {"overload_nonzero_backlog":
"exercised_recorded" if detail and all(x["exercised"] for x in detail.values()) else "not_exercised",
"per_role": detail, "across_restart_backlog_persistence_claimed": False}
def check_no_arrival_diagnostic(report):
require(report["role"] == "O-writer" and report["boundary"] is None and
report["boundary_reason"] == report["stop_reason"] == "no_arrival_within_cap",
"no-arrival reason/null")
require(report["ui_ticks"] and
report["ui_ticks"][-1]["clock"] - report["start_minute"] == 120 and
all(t["guest_auto_count"] == 0 and t["guest_auto_ids"] == [] for t in report["ui_ticks"]),
"no-arrival cap/facts")
return True
def check_report(report, sidecar=None):
check_no_metrics(report)
require(sidecar is not None, "sidecar required")
report = check_sidecar(report, sidecar)
if report["stop_reason"] == "no_arrival_within_cap":
check_no_arrival_diagnostic(report)
require(report["schema"] == "p28-restart-v1" and report["stop_reason"] == "complete", "incomplete probe")
require(report["role"] in PHASES[3:] and type(report["pid"]) is int and report["pid"] > 0, "role/PID")
require(report["main_added"] is True and report["k_target"] == 30 and report["actual_k"] == 30, "main/K")
require(report["comparison_scope"] == "complete_typed_var_to_bytes" and report["excluded_paths"] == [],
"partial digest/path exclusion")
require(report["transfer_before_guard_writes"] == 0 and report["probe_deadline_seconds"] == 1740,
"profile/deadline")
check_deadline(report["probe_deadline"])
writer = report["role"].endswith("writer")
kinds = ["save"] if writer else ["tamper", "load"]
require(len(report["io"]) == len(kinds), "IO sequence")
for row, kind in zip(report["io"], kinds):
check_io(row, kind)
if writer:
overload_case(report)
exact(report["package_matches_before"])
require(report["package_matches_before"]["actual_sha256"] == report["states"]["P"]["sha256"],
"P not package snapshot")
else:
require(report["failure_event_absent"] is True and report["transfer_verified"] is True,
"failed event survived/transfer not verified")
io = report["io"][-1]
require(report["event_id"] == io["event"]["event_id"] and report["saved_minute"] == io["minute_after"],
"continuation IO identity")
require(report["paused_idle"]["before"] == report["paused_idle"]["after"], "paused clock consumed backlog")
require(report["paused_idle"]["before"]["paused"] is True, "paused observation")
exact(report["paused_idle"]["comparison"])
rows = report["minutes"]
require(len(rows) == 30, "actual K not 30")
previous, lost = report["saved_minute"], False
for row in rows:
require(row["before"] == previous and row["after"] == previous + 1, "K counts actual minute advances")
require(row["paused"] is True and row["backlog_before"] == row["backlog_after"], "step consumed backlog")
require(row["scope"] == "complete_typed_var_to_bytes" and row["excluded_paths"] == [], "partial state")
require(re.fullmatch("[0-9a-f]{64}", row["sha256"]), "minute SHA")
if row["replacement"] is not None:
require(not lost and row["replacement"] == io["event"] and row["replacement_count"] == 1,
"replacement must be unchanged in-window E")
else:
lost = True
require(row["replacement_count"] == 0, "replacement after E left window")
require(0 <= row["recent_count"] <= 256, "recent limit")
require(len(row["recent_ids"]) == len(set(row["recent_ids"])) == row["recent_count"] and
row["recent_ids"].count(report["event_id"]) == row["replacement_count"],
"replacement does not match actual window")
previous = row["after"]
require(report["final_minute"] == previous, "final minute")
for name, entry in report["states"].items():
require(re.fullmatch("[0-9a-f]{64}", entry["sha256"]) and entry["bytes"] > 0 and
entry["path"] == "p28_restart/evidence/" + name + ".bin", "state binding")
required = {"P", "after_save", "final"} if writer else {"P", "B", "after_tamper", "after_load", "final"}
require(set(report["states"]) == required, "missing complete state files")
require(report["states"]["after_save" if writer else "after_load"]["sha256"] ==
io["comparison"]["actual_sha256"], "IO state file differs")
if not writer:
require(report["states"]["after_tamper"]["sha256"] == report["io"][0]["comparison"]["actual_sha256"],
"tamper state file differs")
if report["role"].startswith("O-"):
observation = report["at_390"]
require(isinstance(observation, dict) and observation["clock"] == {"absolute_minute": 390},
"at390 missing/clock")
require(isinstance(observation["operations"], dict) and
type(observation["domain_event_counter"]) is int and
type(observation["published_ids_count"]) is int and
observation["domain_event_counter"] >= observation["published_ids_count"] >= 0,
"at390 report/counter")
require(isinstance(observation["processed_arrival_minutes"], list) and
observation["processed_arrival_minutes"] == sorted(set(observation["processed_arrival_minutes"])) and
all(type(m) is int and m <= 390 for m in observation["processed_arrival_minutes"]),
"at390 processed minutes")
ids = observation["guest_auto_ids"]
require(isinstance(ids, list) and ids == sorted(set(ids)) and
type(observation["guest_auto_count"]) is int and
len(ids) == observation["guest_auto_count"] and
all(x.startswith("guest-auto-") for x in ids), "at390 guests")
require(all(type(e["absolute_minute"]) is int and
report["saved_minute"] < e["absolute_minute"] <= 390
for e in observation["events"]), "at390 event window")
event_ids = [e["event_id"] for e in observation["events"]]
require(len(event_ids) == len(set(event_ids)), "at390 duplicate event")
at_rows = [r for r in rows if r["after"] == 390]
require(len(at_rows) == 1 and at_rows[0]["operations_observation"] ==
{k: v for k, v in observation.items() if k != "events"}, "at390 minute consistency")
require(all(e in at_rows[0]["recent_ids"] for e in event_ids), "at390 event window IDs")
boundary = report["boundary"]
require(boundary is not None and boundary["guest_auto_count"] > 0, "arrival not processed")
require(len(boundary["guest_auto_ids"]) == len(set(boundary["guest_auto_ids"])) ==
boundary["guest_auto_count"], "arrival IDs")
require(all(x.startswith("guest-auto-") for x in boundary["guest_auto_ids"]), "arrival identity")
require(boundary["clock"] == report["saved_minute"] and boundary["processed_arrival_minutes"],
"arrival boundary not processed")
if writer:
require(0 < report["saved_minute"] - report["start_minute"] <= 120, "arrival cap")
ticks = report["ui_ticks"]
require(ticks and ticks[-1] == boundary and all(t["guest_auto_count"] == 0 for t in ticks[:-1]),
"not first arrival tick")
next_boundary = report["next_boundary"]
added = [m for m in next_boundary["after"] if m not in next_boundary["before"]]
require(next_boundary["before"] == boundary["processed_arrival_minutes"] and
added == [next_boundary["minute"]] and next_boundary["processed_once"] is True and
next_boundary["minute"] > boundary["clock"] and
next_boundary["minute"] <= report["final_minute"], "next arrival missing/duplicate")
minutes = next_boundary["after"]
require(minutes == sorted(set(minutes)), "duplicate processed arrivals")
require([r["minute"] for r in next_boundary["arrival_reports"]] == minutes,
"arrival report duplicates/omissions")
else:
require(report["boundary"] is None and report["next_boundary"] is None and
report["at_390"] is None, "R Operations boundary")
return True
def check_no_metrics(value):
if isinstance(value, dict):
for key, child in value.items():
require(not key.endswith(("_us", "_ms")) and key not in
("performance", "statistics", "fps", "budget_verdict"), "performance field forbidden")
check_no_metrics(child)
elif isinstance(value, list):
for child in value:
check_no_metrics(child)
def canonical_observation(observation, eid):
result = copy.deepcopy(observation)
if result is not None:
result["events"] = [
{"event_id": eid, "replaced_for_cross_pid_compare": True,
"canonical_sha256": e["canonical_sha256"]} if e["event_id"] == eid else e
for e in result["events"]]
return result
def check_pair(writer, reader, writer_sidecar=None, reader_sidecar=None):
check_report(writer, writer_sidecar)
check_report(reader, reader_sidecar)
writer, reader = writer_sidecar["report"], reader_sidecar["report"]
require(writer["role"].replace("writer", "reader") == reader["role"] and writer["pid"] != reader["pid"],
"pair roles/PID")
require(writer["event_id"] == reader["event_id"] and writer["saved_minute"] == reader["saved_minute"],
"pair IO identity")
require(writer["states"]["P"] == reader["states"]["P"], "package P differs")
require(writer["io"][0]["before"] == reader["io"][1]["before"], "package history differs")
for left, right in zip(writer["minutes"], reader["minutes"]):
require(all(left[k] == right[k] for k in
("before", "after", "sha256", "scope", "replacement_count", "recent_count")),
"cross-PID complete typed state mismatch")
require(writer["boundary"] == reader["boundary"] and writer["next_boundary"] == reader["next_boundary"],
"Operations boundary differs")
require(canonical_observation(writer["at_390"], writer["event_id"]) ==
canonical_observation(reader["at_390"], reader["event_id"]), "at390 pair differs")
def bound_raw(folder, row):
folder = Path(folder)
require(set(row["raw"]) == {"stdout.log", "stderr.log", "engine-native.log"}, "all raw required")
for name, expected in {**row["raw"], **row["owned_files"]}.items():
require(Path(name).name == name and pin(folder / name) == expected, "raw/owned SHA mismatch")
require(set(row["owned_files"]) == {"process.json", "started.json", "ended.json",
"adapter-owned-cleanup.json", "outer-owned-finally.json"}, "owned receipts missing")
require(json.loads((folder / "process.json").read_text()) == row["process"], "process receipt mismatch")
process, capture = row["process"], row["capture"]
require(row["passed"] is True and process["exit_code"] == 0 and process["helper_exit_code"] == 0 and
process["timed_out"] is False and process["error_lines"] == [] and process["lifecycle_error"] is None and
process["external_process_or_group_signals"] == 0 and process["owned_popen_ended"] is True and
process["old_helper_engine_ended"] is True and process["start_receipt_written"] is True and
process["end_receipt_written"] is True, "owned phase failed")
require(capture["passed"] is True and capture["all_captured_ended"] is True and
capture["outer_cleanup_errors"] == [] and capture["adapter_exception"] is None and
capture["foreign_process_or_group_signals"] == 0 and
capture["all_cleanup_before_outer_receipt"] is True and capture["outer_receipt_written"] is True and
capture["outer_receipt_error"] is None and len(capture["actual_captured_pids"]) == 1, "outer capture")
actual = json.loads((folder / "outer-owned-finally.json").read_text())
require(actual == {k: v for k, v in capture.items() if k not in
("passed", "outer_receipt_written", "outer_receipt_error")}, "outer raw differs")
pid = capture["actual_captured_pids"][0]
require(process["pid"] == pid and process["argv"] == row["argv"], "process PID/argv")
for filename, key in (("started.json", "actual_start_binding"), ("ended.json", "actual_end_binding")):
binding = json.loads((folder / filename).read_text())
require(binding == process[key] and binding["pid"] == binding["actual_pid"] == pid and
binding["argv"] == binding["command"] == row["argv"] and binding["owner_pid"] > 0,
"START/END binding")
require(process["actual_start_binding"]["owner_pid"] == process["actual_end_binding"]["owner_pid"],
"START/END owners differ")
require(json.loads((folder / "adapter-owned-cleanup.json").read_text()) == process["adapter_owned_cleanup"]
and process["adapter_owned_cleanup"]["engine_ended"] is True and
process["adapter_owned_cleanup"]["errors"] == [], "adapter cleanup binding")
require(process["stdout_sha256"] == row["raw"]["stdout.log"]["sha256"] and
process["stderr_sha256"] == row["raw"]["stderr.log"]["sha256"], "process raw binding")
require(row["timeout_seconds"] == 1800 and row["diagnostics"] == [], "phase timeout/diagnostics")
raw = (folder / "stdout.log").read_text()
for name in ("stdout.log", "stderr.log", "engine-native.log"):
require(not re.search(r"SCRIPT ERROR|Parse Error|ERROR:", (folder / name).read_text()),
"raw engine error")
if row["phase"] not in PHASES[3:]:
require("P28_RESTART_REPORT=" not in raw, "parse/import report")
if row["phase"].startswith("parse"):
require("--check-only" in row["argv"], "parse not check-only")
return None
reports = [s.partition("=")[2] for s in raw.splitlines() if s.startswith("P28_RESTART_REPORT=")]
closes = [s.partition("=")[2] for s in raw.splitlines() if s.startswith("P28_RESTART_AUDIO_CLOSE=")]
require(len(reports) == len(closes) == 1, "report/audio close count")
report, close = json.loads(reports[0]), json.loads(closes[0])
require(report == row["report"] and report["role"] == row["phase"] and
capture["actual_captured_pids"] == [report["pid"]], "raw report/PID binding")
require(close.get("coordinator") is True and close.get("passed") is True and
close.get("owned_engine_pid") == report["pid"] and close.get("all_owned_targets_released") is True and
close.get("deadline_reached") is False and close.get("clock_process_held_stopped") is True and
close.get("window_input_held_disabled") is True and close.get("restored_before_quit") is False and
close.get("shared_bus_deleted") is False and close.get("settings_mutated") is False, "audio close")
check_report(report, bound_sidecar(folder.parent, row))
return report
def bound_sidecar(out, row):
binding = row["sidecar"]
require(set(binding) == {"path", "sha256", "bytes"} and binding["path"] == SIDECAR,
"sidecar binding/path")
expected = {k: binding[k] for k in ("sha256", "bytes")}
path = Path(out) / (row["phase"] + "-states") / "report_full.json"
require(pin(path) == expected and pin(Path(row["runtime_profile"]) / SIDECAR) == expected,
"sidecar SHA/private profile binding")
return json.loads(path.read_text())
def check_receipt(receipt, out):
from restart_pair import COLLECTOR_PINS, check_transfer
out = Path(out)
require(receipt["passed"] is True and receipt["error"] is None and receipt["cleanup_errors"] == [],
"execution failed")
require(receipt["source_before"] == receipt["source_after"] and len(receipt["source_before"]) == 1407,
"source map mismatch")
require(receipt["default_player_before"] == receipt["default_player_after"], "ordinary player changed")
require(receipt["dependencies_before"] == receipt["dependencies_after"] == DEPENDENCIES, "dependency pins")
require(receipt["collector_before"] == receipt["collector_after"] == COLLECTOR_PINS,
"collector changed")
require(receipt["worker_before"] == receipt["worker_after"] and set(receipt["worker_before"]) ==
{"restart_pair.py", "restart_probe.gd", "check_restart.py", "test_restart.py"}, "worker changed")
require(receipt["cross_cutting"] == CROSS, "cross-cutting record")
require(receipt["original_credit"] == 0 and receipt["windows_verified"] is False and
receipt["operations_200_guests_verified"] is False, "scope expanded")
rows = receipt["phases"]
require([r["phase"] for r in rows] == PHASES, "phase order/incomplete execution")
pids = []
for row in rows:
report = bound_raw(out / row["phase"], row)
pids.extend(row["capture"]["actual_captured_pids"])
require(row["stage_before"] == row["stage_after"] if row["phase"] != "import"
else row["stage_preserved"] is True, "stage changed")
require(row["source_preserved"] is True and row["player_preserved"] is True, "phase preservation")
startup = row["startup_project"]
require(startup["fresh_before"] is True and sha(startup["path"]) == startup["sha256"], "startup profile")
if report:
guard = row["guard"]
expected = {"verified": True, "conditions": [True] * 5, "conditions_checked": 5,
"actual_user_data_dir": row["runtime_profile"],
"expected_user_data_dir": row["runtime_profile"],
"globalized_probe": str(Path(row["runtime_profile"]) / "guard-probe"),
"custom_user_dir_name": row["runtime_name"], "fresh_before_parent_initialize": True,
"profile_writes_before_guard": 0, "project_settings_persisted": False}
require(all(type(guard.get(k)) is type(v) and guard[k] == v for k, v in expected.items()),
"guard mismatch")
guard_path = out / (row["phase"] + "-guard.json")
require(sha(guard_path) == row["guard_sha256"] and json.loads(guard_path.read_text()) == guard,
"guard raw binding")
for name, evidence in report["states"].items():
require(pin(out / (row["phase"] + "-states") / (name + ".bin")) ==
{k: evidence[k] for k in ("sha256", "bytes")}, "state bytes SHA")
require(receipt["profiles"][row["runtime_profile"]].get(SIDECAR) ==
{k: row["sidecar"][k] for k in ("sha256", "bytes")}, "sidecar absent from file map")
require(len(set(pids)) == len(pids), "reused PID")
require({r["pid"] for r in receipt["cleanup"]} == set(pids) and all(
r["engine_ended"] is True and r["outer_cleanup_errors"] == [] and
r["foreign_process_or_group_signals"] == 0 for r in receipt["cleanup"]), "cleanup mismatch")
for start in (3, 5):
check_pair(rows[start]["report"], rows[start + 1]["report"],
bound_sidecar(out, rows[start]), bound_sidecar(out, rows[start + 1]))
transfer = out / (rows[start]["phase"][0] + "-transfer")
manifest_path = transfer / "manifest.json"
manifest = json.loads(manifest_path.read_text())
check_transfer(transfer, manifest)
require(rows[start + 1]["report"]["transfer_manifest_sha256"] == sha(manifest_path),
"reader manifest SHA")
for phase_index, kinds in ((start, ("good",)), (start + 1, ("good", "tampered"))):
profile = rows[phase_index]["runtime_profile"]
for kind in kinds:
for name, expected in manifest["files"][kind].items():
relative = "p28_restart/" + kind + "/" + name
require(receipt["profiles"][profile].get(relative) == expected,
"private package differs from transfer")
for path, expected in receipt["script_pins"].items():
require(sha(path) == expected, "executed script changed")
check_probe((out / "restart_probe.gd").read_text())
require(sha(out / "restart_probe.gd") == receipt["worker_before"]["restart_probe.gd"],
"executed probe differs from submitted source")
require(receipt["owned_writes"] == [], "probe/driver wrote owned folder")
require(receipt["coverage"] == coverage([bound_sidecar(out, r)["report"] for r in rows[3:]]),
"overload coverage/persistence claim")
return True
def main():
import argparse
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("execution", type=Path)
args = parser.parse_args()
check_receipt(json.loads(args.execution.read_text()), args.execution.parent)
print("P28_RESTART_CHECK=PASS")
if __name__ == "__main__":
main()
@@ -0,0 +1,322 @@
#!/usr/bin/env python3
"""Root-only four-PID RESTART driver. --check performs no writes or launches."""
import argparse
import importlib.util
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import uuid
sys.dont_write_bytecode = True
import check_restart as check
HERE, ROOT = check.HERE, check.ROOT
COLLECTOR = check.BASE + "collector/collect_p28_01.py"
COLLECTOR_PINS = {
"collect_p28_01.py": check.DEPENDENCIES[COLLECTOR],
"check_p28_01_report.py": check.DEPENDENCIES[check.BASE + "collector/check_p28_01_report.py"],
"measure_p28_01.gd": "4acef88bce4ac77f3f5d2659d766afcc5fd139cee381118839012022772946bb",
"test_collect_p28_01.py": "99d86ea723c976c95dbd283acbb85981eabf427b30994e652002ec0e76dc4ab0",
}
def load_dependencies():
check.check_dependencies()
for name in check.DEPENDENCIES:
check.check_imports((ROOT / name).read_text(), external=name)
for name in ("restart_pair.py", "check_restart.py", "test_restart.py"):
check.check_imports((HERE / name).read_text())
check.check_modules()
sys.path.insert(0, str((ROOT / COLLECTOR).parent))
spec = importlib.util.spec_from_file_location("restart_collector", ROOT / COLLECTOR)
collector = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = collector
spec.loader.exec_module(collector)
standard = collector.load_tool(collector.EXTERNAL_IMPORTS[0])
outer = collector.load_tool(collector.EXTERNAL_IMPORTS[1])
check.check_modules()
check.check_modules({"collector": collector, "standard": standard, "outer": outer, "native": outer.native})
check.require(Path(outer.native.helper["__file__"]).resolve() ==
ROOT / "tools/regression/p09_owned_engine_process.py", "exec helper closure")
return collector, standard, outer
def collector_pins():
actual = {name: check.sha((ROOT / COLLECTOR).parent / name) for name in COLLECTOR_PINS}
check.require(actual == COLLECTOR_PINS, "collector differs from Q")
return actual
def plan(collector, engine, out):
stage, wrapper = out / "stage", out / "guarded.gd"
return [collector.argv_for(engine, stage, wrapper, True),
collector.parse_argv(engine, stage, out / "restart_probe.gd"),
collector.parse_argv(engine, stage, wrapper)] + [
collector.argv_for(engine, stage, wrapper) for _ in range(4)]
def schedule(rows):
for index, label in enumerate(check.PHASES):
check.require(all(row["passed"] is True for row in rows), "previous phase failed")
if label.endswith("reader"):
check.require(rows and rows[-1]["phase"] == label.replace("reader", "writer") and
rows[-1].get("report", {}).get("stop_reason") == "complete",
"reader requires successful writer")
yield index, label
check.require(len(rows) == index + 1 and rows[-1]["phase"] == label and rows[-1]["passed"] is True,
"phase did not complete")
def safe_inventory(directory):
directory = Path(directory)
check.require(directory.is_dir() and not directory.is_symlink(), "package missing/symlink")
result = {}
for path in sorted(directory.rglob("*")):
check.require(not path.is_symlink(), "package symlink")
if path.is_file():
result[path.relative_to(directory).as_posix()] = check.pin(path)
check.require(result, "empty package")
return result
def create_transfer(source, destination, write):
"""Copy only after writer exit; never pre-populate the reader profile."""
before = safe_inventory(source)
check.require("world.bin" in before and not destination.exists(), "transfer admission")
destination.mkdir()
shutil.copytree(source, destination / "good")
check.require(safe_inventory(destination / "good") == before, "good copy differs")
shutil.copytree(destination / "good", destination / "tampered")
world = destination / "tampered/world.bin"
data = bytearray(world.read_bytes())
check.require(data, "empty world")
offset = len(data) // 2
data[offset] ^= 1
world.write_bytes(data)
manifest = {"files": {"good": before, "tampered": safe_inventory(destination / "tampered")},
"tamper": {"file": "world.bin", "offset": offset, "xor": 1,
"before_sha256": before["world.bin"]["sha256"], "after_sha256": check.sha(world)}}
write(destination / "manifest.json", manifest)
check_transfer(destination, manifest)
check.require(safe_inventory(source) == before, "writer package changed")
return manifest
def check_transfer(directory, manifest):
check.require(set(manifest["files"]) == {"good", "tampered"}, "transfer kinds")
for kind in ("good", "tampered"):
check.require(safe_inventory(directory / kind) == manifest["files"][kind], "transfer SHA mismatch")
good = (directory / "good/world.bin").read_bytes()
bad = (directory / "tampered/world.bin").read_bytes()
tamper = manifest["tamper"]
check.require(len(good) == len(bad) > 0 and tamper["offset"] == len(good) // 2 and tamper["xor"] == 1,
"tamper location")
expected = bytearray(good)
expected[len(good) // 2] ^= 1
check.require(bytes(expected) == bad and tamper["before_sha256"] == check.sha(directory / "good/world.bin")
and tamper["after_sha256"] == check.sha(directory / "tampered/world.bin"), "tamper bytes")
for name, value in manifest["files"]["good"].items():
if name != "world.bin":
check.require(manifest["files"]["tampered"].get(name) == value, "extra tamper difference")
check.require(set(manifest["files"]["good"]) == set(manifest["files"]["tampered"]), "tamper inventory")
def fresh_profile(path):
check.require(not path.exists(), "profile must be fresh; pre-guard writes forbidden")
def committed_source(source, commit):
"""Read-only Git operations: the 1407 files must be the actual HEAD bytes."""
tracked = subprocess.check_output(["git", "-C", str(ROOT), "ls-tree", "-r", commit], text=True)
selected = {}
for line in tracked.splitlines():
metadata, name = line.split("\t", 1)
if name.split("/", 1)[0] in ("autoload", "scripts", "scenes", "data", "tests", "assets", "tools") or \
name in ("project.godot", "export_presets.cfg", "Makefile", "AGENTS.md"):
if Path(name).name != ".DS_Store" and "__pycache__" not in Path(name).parts:
selected[name] = metadata.split()[2]
check.require(set(selected) == set(source), "source map differs from HEAD")
for name, expected in selected.items():
actual = subprocess.check_output(["git", "-C", str(ROOT), "hash-object", str(ROOT / name)], text=True).strip()
check.require(actual == expected, "dirty product source: " + name)
def bind_report(out, label, row):
text = (out / label / "stdout.log").read_text()
reports = [s.partition("=")[2] for s in text.splitlines() if s.startswith("P28_RESTART_REPORT=")]
check.require(len(reports) == 1, "one raw report required")
row["report"] = json.loads(reports[0])
copy_states(out, row)
check.bound_raw(out / label, row)
return row["report"]
def copy_states(out, row):
folder = out / (row["phase"] + "-states")
folder.mkdir()
profile = Path(row["runtime_profile"])
source = profile / check.SIDECAR
row["sidecar"] = {"path": check.SIDECAR, **check.pin(source)}
shutil.copyfile(source, folder / "report_full.json")
check.require(check.pin(source) == check.pin(folder / "report_full.json"), "sidecar copy differs")
for name, expected in row["report"]["states"].items():
source = profile / expected["path"]
check.require(source.resolve().is_relative_to(profile.resolve()) and
check.pin(source) == {k: expected[k] for k in ("bytes", "sha256")}, "state binding")
shutil.copyfile(source, folder / (name + ".bin"))
check.require(check.pin(source) == check.pin(folder / (name + ".bin")), "state copy differs")
def main():
parser = argparse.ArgumentParser(description=__doc__)
mode = parser.add_mutually_exclusive_group(required=True)
mode.add_argument("--check", action="store_true")
mode.add_argument("--run", action="store_true")
for name in ("readonly", "fixture", "engine", "output"):
parser.add_argument("--" + name, type=Path, required=True)
args = parser.parse_args()
collector, standard, outer = load_dependencies()
pinned = collector_pins()
readonly, fixture, engine, out = (p.resolve() for p in (args.readonly, args.fixture, args.engine, args.output))
inputs = collector.inputs(readonly)
check.require(check.sha(fixture) == collector.FIXTURE_SHA and check.sha(engine) == collector.ENGINE_SHA,
"fixture/engine SHA")
check.check_probe((HERE / "restart_probe.gd").read_text())
source = collector.source_map(standard, ROOT)
check.require(len(source) == 1407, "source count")
commit = subprocess.check_output(["git", "-C", str(ROOT), "rev-parse", "HEAD"], text=True).strip()
committed_source(source, commit)
worker_pins = {name: check.sha(HERE / name) for name in
("restart_pair.py", "restart_probe.gd", "check_restart.py", "test_restart.py")}
commands = plan(collector, engine, out)
admission = {"commit": commit, "source_map": source, "readonly": inputs, "planned_argv": commands,
"engine_sha256": check.sha(engine), "fixture_sha256": check.sha(fixture),
"dependencies": check.DEPENDENCIES, "collector_Q": pinned,
"worker_pins": worker_pins,
"phases": check.PHASES, "engines_started": 0}
check.require(not out.exists(), "new output required")
if args.check:
print(json.dumps(admission, ensure_ascii=False, indent=2))
return 0
check.require(sys.platform == "darwin", "reviewed native platform is macOS")
collector.no_live_engine()
check.require(shutil.disk_usage(out.parent).free >= 1200000000, "disk space")
player = standard.default_player(ROOT)
out.mkdir(parents=True)
collector.write(out / "admission.json", admission)
rows, profiles = [], []
error = None
scripts = {}
receipt = {}
try:
stage = out / "stage"
stage.mkdir()
for name in source:
target = stage / name
target.parent.mkdir(parents=True, exist_ok=True)
standard.copy_source(ROOT / name, target)
expected = standard.inventory(stage, stage=True)
check.require(expected == source, "stage source differs")
probe, guard, wrapper = (out / n for n in ("restart_probe.gd", "profile_guard.gd", "guarded.gd"))
probe.write_bytes((HERE / probe.name).read_bytes())
guard.write_bytes((readonly / "run-r02/profile_guard.gd").read_bytes())
wrapper.write_text("extends " + json.dumps(str(probe)) + "\nconst Guard = preload(" +
json.dumps(str(guard)) + ")\nfunc _initialize() -> void:\n"
"\tif not Guard.activate():\n\t\tquit(97)\n\t\treturn\n\tsuper._initialize()\n")
scripts = {str(p): check.sha(p) for p in (probe, guard, wrapper)}
public = (stage / "project.godot").read_bytes()
for index, label in schedule(rows):
check.check_dependencies()
collector_pins()
check.check_modules()
check.require(collector.source_map(standard, ROOT) == source and standard.default_player(ROOT) == player,
"source/player changed before phase")
check.require(standard.inventory(stage, stage=True) == expected and
all(check.sha(p) == value for p, value in scripts.items()) and
all(check.sha(HERE / p) == value for p, value in worker_pins.items()),
"stage/scripts changed")
startup_name = "TheTree-PCK-tests-" + uuid.uuid4().hex + "-restart-startup"
runtime_name = "TheTree-PCK-tests-" + uuid.uuid4().hex + "-restart-runtime"
startup, runtime = (standard.profile_path(n) for n in (startup_name, runtime_name))
fresh_profile(startup)
fresh_profile(runtime)
profiles.extend([startup, runtime])
transfer = out / (label[0] + "-transfer")
env = {"THE_TREE_PACK_PROFILE_NAME": runtime_name, "THE_TREE_PACK_PROFILE_EXPECTED": str(runtime),
"THE_TREE_PACK_PROFILE_REPORT": str(out / (label + "-guard.json")),
"THE_TREE_RESTART_ROLE": label, "THE_TREE_RESTART_K": "30",
"THE_TREE_RESTART_TRANSFER": str(transfer),
"THE_TREE_RESTART_TRANSFER_MANIFEST": str(transfer / "manifest.json"),
"THE_TREE_P28_FIXTURE": str(fixture), "THE_TREE_P28_FIXTURE_SHA": collector.FIXTURE_SHA}
if label.endswith("reader"):
check_transfer(transfer, json.loads((transfer / "manifest.json").read_text()))
before_stage = collector.digest(expected)
row = collector.run_private_engine(standard, outer, commands[index], out / label, env,
stage, public, startup_name)
row["phase"] = label
rows.append(row)
check.require(row["passed"], "owned engine failure: " + label)
after_stage = standard.inventory(stage, stage=True)
collector.stage_gate(expected, after_stage, importing=label == "import")
row.update(stage_before=before_stage, stage_after=collector.digest(after_stage), stage_preserved=True,
source_preserved=collector.source_map(standard, ROOT) == source,
player_preserved=standard.default_player(ROOT) == player)
expected = after_stage
if label in check.PHASES[3:]:
guard_path = out / (label + "-guard.json")
observation = json.loads(guard_path.read_text())
collector.guard_gate(observation, runtime, runtime_name)
row.update(runtime_profile=str(runtime), runtime_name=runtime_name,
guard=observation, guard_sha256=check.sha(guard_path))
report = bind_report(out, label, row)
collector.write(out / (label + "-report.json"), report)
if label.endswith("writer"):
create_transfer(runtime / "p28_restart/good", transfer, collector.write)
else:
check.require(report["transfer_manifest_sha256"] == check.sha(transfer / "manifest.json"),
"reader transfer manifest binding")
check.check_pair(rows[-2]["report"], report, check.bound_sidecar(out, rows[-2]),
check.bound_sidecar(out, row))
else:
check.bound_raw(out / label, row)
check.require(row["source_preserved"] and row["player_preserved"] and
check.sha(fixture) == collector.FIXTURE_SHA and
all(check.sha(p) == value for p, value in scripts.items()), "post-phase preservation")
except BaseException as caught:
error = repr(caught)
finally:
cleanup, cleanup_errors = outer.finish_captured(outer.OWNED)
receipt = {"admission": admission, "phases": rows, "error": error, "passed": error is None,
"source_before": source, "source_after": collector.source_map(standard, ROOT),
"default_player_before": player, "default_player_after": standard.default_player(ROOT),
"dependencies_before": check.DEPENDENCIES,
"dependencies_after": {p: check.sha(ROOT / p) for p in check.DEPENDENCIES},
"collector_before": pinned,
"collector_after": {p: check.sha((ROOT / COLLECTOR).parent / p) for p in pinned},
"script_pins": scripts, "cleanup": cleanup, "cleanup_errors": cleanup_errors,
"worker_before": worker_pins,
"worker_after": {p: check.sha(HERE / p) for p in worker_pins},
"profiles": {str(p): collector.profile_files(p) for p in profiles}, "owned_writes": [],
"cross_cutting": check.CROSS, "original_credit": 0,
"windows_verified": False, "operations_200_guests_verified": False}
try:
receipt["coverage"] = check.coverage([
check.bound_sidecar(out, row)["report"] for row in rows if "sidecar" in row])
except (ValueError, KeyError, TypeError, OSError) as caught:
receipt["coverage"] = {"overload_nonzero_backlog": "not_exercised",
"error": repr(caught)}
receipt.update(passed=False, error=receipt["error"] or "coverage: " + repr(caught))
if receipt["passed"]:
try:
check.check_receipt(receipt, out)
except (ValueError, KeyError, TypeError, OSError) as caught:
receipt.update(passed=False, error="checker: " + repr(caught))
collector.write(out / "execution.json", receipt)
return 0 if receipt["passed"] else 1
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,603 @@
extends SceneTree
## Root-owned execution only. All files are written after Guard.activate().
var GameClock: Variant
var runtime: Variant
var main: Variant
var report: Dictionary = {}
var signals: Array = []
var key_forms: Dictionary = {}
var role := ""
var start_minute := 0
var selected_tick := false
var overloaded := false
var io_ready := false
var finished := false
var E := ""
var package: Dictionary = {}
var failure_event: Dictionary = {}
var boundary: Variant = null
var at_390_event_verbatim: Array = []
var at_390_pending: Array = []
var redaction_ok := true
var canonical_key_collision := false
const SAVE_EVENTS := ["SAVE_CHECKPOINT_SUCCEEDED", "SAVE_CHECKPOINT_FAILED", "SAVE_LOADED",
"SAVE_LOAD_FAILED", "SAVE_MIGRATION_SUCCEEDED", "SAVE_MIGRATION_FAILED",
"SAVE_RECOVERY_LOADED", "SAVE_RECOVERY_CANDIDATE_LOADED", "SAVE_RECOVERY_FAILED"]
func canonical_json(value: Variant) -> String:
if value is Dictionary:
var keys: Array = value.keys()
keys.sort_custom(func(a, b): return str(a) < str(b))
for index: int in range(1, keys.size()):
if str(keys[index - 1]) == str(keys[index]):
canonical_key_collision = true
# Unwind serialization before emitting failure evidence.
call_deferred("finish", "canonical_key_collision")
return ""
var parts: PackedStringArray = []
for key: Variant in keys:
parts.append(JSON.stringify(str(key)) + ":" + canonical_json(value[key]))
return "{" + ",".join(parts) + "}"
if value is Array:
var parts: PackedStringArray = []
for child: Variant in value:
parts.append(canonical_json(child))
return "[" + ",".join(parts) + "]"
if value is int or value is float:
return "%.17f" % float(value)
return JSON.stringify(value)
func event_summary(event: Dictionary) -> Dictionary:
var canonical: Dictionary = {"event_id": E, "replaced_for_cross_pid_compare": true} \
if field(event, "event_id") == E else event
return {"event_id": field(event, "event_id"), "event_type": field(event, "event_type"),
"absolute_minute": field(event, "absolute_minute"),
"raw_event_sha256": bytes_hash(canonical_json(event).to_utf8_buffer()),
"canonical_sha256": bytes_hash(canonical_json(canonical).to_utf8_buffer())}
func observe_390() -> void:
if not role.begins_with("O-") or GameClock.absolute_minute != 390 or report.at_390 != null:
return
var observed := operations_observation()
var state := witness(runtime.create_snapshot())
report.at_390 = {"clock": {"absolute_minute": GameClock.absolute_minute},
"operations": observed.operations, "processed_arrival_minutes": observed.processed_arrival_minutes,
"guest_auto_ids": observed.guest_auto_ids, "guest_auto_count": observed.guest_auto_count,
"published_ids_count": state.published_ids.size(), "domain_event_counter": state.counter,
"events": []}
at_390_pending = state.recent_events.duplicate(true)
if report.has("saved_minute"):
bind_390_events()
func bind_390_events() -> void:
if report.at_390 == null:
return
at_390_event_verbatim = []
report.at_390.events = []
for event: Dictionary in at_390_pending:
var minute: int = field(event, "absolute_minute")
if minute > report.saved_minute and minute <= 390:
at_390_event_verbatim.append(event.duplicate(true))
report.at_390.events.append(event_summary(event))
func deadline_timer_seconds() -> float:
return Time.get_ticks_msec() / 1000.0
func field(d: Variant, name: String) -> Variant:
if d is Dictionary:
if d.has(StringName(name)):
key_forms[name] = "StringName"
return d[StringName(name)]
if d.has(String(name)):
key_forms[name] = "String"
return d[String(name)]
key_forms[name] = "missing_product_field"
return null
func _initialize() -> void:
call_deferred("begin")
func bytes_hash(data: PackedByteArray) -> String:
var context := HashingContext.new()
context.start(HashingContext.HASH_SHA256)
context.update(data)
return context.finish().hex_encode()
func runtime_part(snapshot: Dictionary) -> Dictionary:
return field(field(snapshot, "systems"), "runtime")
func witness(snapshot: Dictionary) -> Dictionary:
var part := runtime_part(snapshot)
var events: Dictionary = field(part, "domain_events")
return {"counter": field(field(field(part, "id_generator"), "counters"), "domain_event"),
"published_ids": field(events, "published_ids").duplicate(true),
"recent_events": field(events, "recent_events").duplicate(true)}
func different_paths(a: Variant, b: Variant, path := "$", depth := 0) -> Array:
var result: Array = []
if var_to_bytes(a) == var_to_bytes(b):
return result
if depth >= 4 or typeof(a) != typeof(b):
return [path]
if a is Dictionary:
for key: Variant in a:
if not b.has(key):
result.append(path + "." + str(key))
else:
result.append_array(different_paths(a[key], b[key], path + "." + str(key), depth + 1))
for key: Variant in b:
if not a.has(key):
result.append(path + "." + str(key))
elif a is Array and a.size() == b.size():
for index in range(a.size()):
result.append_array(different_paths(a[index], b[index], path + "[%d]" % index, depth + 1))
else:
result.append(path)
# Typed container/key/order differences can exist without value differences.
if result.is_empty():
result.append(path)
return result
func compare(expected: Dictionary, actual: Dictionary) -> Dictionary:
var a := var_to_bytes(expected)
var b := var_to_bytes(actual)
return {"method": "var_to_bytes", "equal": a == b, "expected_sha256": bytes_hash(a),
"actual_sha256": bytes_hash(b), "excluded_paths": [],
"diff_paths": different_paths(expected, actual)}
func record_state(name: String, value: Dictionary) -> bool:
var path := "user://p28_restart/evidence/" + name + ".bin"
if DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(path).get_base_dir()) != OK:
return false
var data := var_to_bytes(value)
var file := FileAccess.open(path, FileAccess.WRITE)
if file == null:
return false
file.store_buffer(data)
file.close()
report.states[name] = {"path": path.trim_prefix("user://"), "bytes": data.size(),
"sha256": bytes_hash(data)}
return FileAccess.get_sha256(path) == report.states[name].sha256
func on_save(result: Dictionary) -> void:
signals.append(result.duplicate(true))
func auto_ids() -> Array:
var ids: Array = []
for guest: Variant in runtime.guest_service.get_guests():
if str(guest.guest_id).begins_with("guest-auto-"):
ids.append(str(guest.guest_id))
ids.sort()
return ids
func operations_observation() -> Dictionary:
var ids := auto_ids()
var processed: Array = []
var arrivals: Array = []
if runtime.operations_coordinator != null:
var state: Dictionary = runtime.operations_coordinator.create_snapshot()
processed = field(state, "processed_arrival_minutes").duplicate()
arrivals = runtime.operations_coordinator.get_arrival_reports().duplicate(true)
return {"clock": GameClock.absolute_minute, "guest_auto_ids": ids, "guest_auto_count": ids.size(),
"operations": runtime.get_operations_report(), "processed_arrival_minutes": processed,
"arrival_reports": arrivals}
func on_tick(minute: int) -> void:
# During deterministic stepping the observation is made after advance returns.
if not io_ready:
observe_390()
if io_ready or finished or selected_tick:
return
var observed := operations_observation()
if role == "O-writer":
report.ui_ticks.append(observed)
var stop: bool = (role == "R-writer" and minute - start_minute >= 10) or \
(role == "O-writer" and (observed.guest_auto_count > 0 or minute - start_minute >= 120))
if stop:
GameClock.set_paused(true)
selected_tick = true
func on_overload(backlog: int) -> void:
overloaded = true
report.overloads.append({"minute": GameClock.absolute_minute, "backlog": backlog})
func clock_observation() -> Dictionary:
return {"minute": GameClock.absolute_minute, "paused": GameClock.paused,
"backlog": GameClock.get_backlog_minutes(),
"accumulator_hex": PackedFloat64Array([GameClock.get("_accumulator")]).to_byte_array().hex_encode()}
func begin() -> void:
GameClock = root.get_node("GameClock")
runtime = root.get_node("SimulationRuntime")
role = OS.get_environment("THE_TREE_RESTART_ROLE")
report = {"schema": "p28-restart-v1", "role": role, "pid": OS.get_process_id(),
"main_added": false, "k_target": 30, "actual_k": 0, "io": [], "states": {},
"minutes": [], "ui_ticks": [], "overloads": [], "boundary": null, "next_boundary": null,
"at_390": null,
"comparison_scope": "complete_typed_var_to_bytes", "excluded_paths": [],
"transfer_before_guard_writes": 0, "transfer_verified": false,
"probe_deadline_seconds": 1740}
var elapsed := deadline_timer_seconds()
var interval := 1740.0 - elapsed
report["probe_deadline"] = {"limit_seconds_from_engine_start": 1740,
"engine_elapsed_at_begin_seconds": elapsed, "timer_seconds": interval}
if interval <= 0:
finish("probe_deadline")
return
create_timer(interval).timeout.connect(func() -> void: finish("probe_deadline"))
if OS.get_environment("THE_TREE_RESTART_K") != "30" or role not in ["R-writer", "R-reader", "O-writer", "O-reader"]:
finish("invalid_environment")
return
# No await before main: the default autoload clock cannot process here.
if role == "R-writer":
var fixture := OS.get_environment("THE_TREE_P28_FIXTURE")
if FileAccess.get_sha256(fixture) != OS.get_environment("THE_TREE_P28_FIXTURE_SHA"):
finish("fixture_sha")
return
var file := FileAccess.open(fixture, FileAccess.READ)
if file == null:
finish("fixture_missing")
return
var value: Variant = file.get_var(false)
file.close()
if not value is Dictionary or not runtime.restore_snapshot(value):
finish("fixture_restore")
return
main = load("res://scenes/main/main.tscn").instantiate()
root.add_child(main)
report.main_added = true
report["startup"] = {"start_report": main.get("_operations_start_report").duplicate(true),
"operations": runtime.get_operations_report(), "clock": clock_observation()}
if role != "R-writer" and not GameClock.paused:
finish("main_did_not_pause")
return
var start_result: Dictionary = report.startup.start_report
var operations_enabled: Variant = field(report.startup.operations, "enabled")
if role == "R-writer":
if operations_enabled != false or field(start_result, "code") != "INVALID_START_TIME":
finish("unexpected_R_start")
return
elif operations_enabled != true or field(start_result, "ok") != true or GameClock.absolute_minute != 360:
finish("unexpected_fresh_start")
return
runtime.save_operation_completed.connect(on_save)
GameClock.tick_completed.connect(on_tick)
GameClock.simulation_overloaded.connect(on_overload)
start_minute = GameClock.absolute_minute
report["start_minute"] = start_minute
if role.ends_with("writer"):
main.call("_set_speed", 1)
while not GameClock.paused and not finished:
await process_frame
if finished:
return
if not selected_tick and not overloaded:
finish("unexpected_ui_stop")
return
if role == "O-writer" and auto_ids().is_empty():
report["boundary"] = null
report["boundary_reason"] = "no_arrival_within_cap" if GameClock.absolute_minute - start_minute >= 120 else "stopped_before_arrival"
finish(report.boundary_reason)
return
if not writer_save():
finish("save_comparison_failed")
return
else:
if not import_transfer():
finish("transfer_failed")
return
if not reader_load():
finish("load_comparison_failed")
return
report["event_id"] = E
report["saved_minute"] = GameClock.absolute_minute
bind_390_events()
boundary = operations_observation() if role.begins_with("O-") else null
report["boundary"] = boundary
var idle_before: Dictionary = runtime.create_snapshot()
var clock_before := clock_observation()
await process_frame
await process_frame
if finished:
return
var idle_after: Dictionary = runtime.create_snapshot()
report["paused_idle"] = {"before": clock_before, "after": clock_observation(),
"comparison": compare(idle_before, idle_after)}
if not report.paused_idle.comparison.equal or report.paused_idle.before != report.paused_idle.after:
finish("paused_backlog_consumed")
return
io_ready = true
for _index in range(30):
if not deterministic_step():
finish("no_tick_advance_or_invalid_state")
return
# Keep the event loop responsive to deadline/audio while remaining paused.
await process_frame
if finished:
return
if not record_state("final", runtime.create_snapshot()):
finish("state_write_failed")
return
report["final_minute"] = GameClock.absolute_minute
if role.begins_with("O-"):
if report.at_390 == null:
finish("at_390_not_reached")
return
var last := operations_observation()
var added: Array = []
for minute: Variant in last.processed_arrival_minutes:
if minute not in boundary.processed_arrival_minutes:
added.append(minute)
report["next_boundary"] = {"minute": added[0] if added.size() == 1 else null,
"processed_once": added.size() == 1, "before": boundary.processed_arrival_minutes,
"after": last.processed_arrival_minutes, "arrival_reports": last.arrival_reports,
"guest_auto_ids": last.guest_auto_ids}
if added.size() != 1:
finish("next_arrival_boundary_missing_or_duplicate")
return
finish("complete")
func io_proof(base: Dictionary, after: Dictionary, kind: String, returned: Variant) -> bool:
var row := {"kind": kind, "signal_count": signals.size(),
"return_kind": "bool" if kind == "save" else "void", "return_value": returned}
report.io.append(row)
if signals.size() != 1:
return false
var signal_result: Dictionary = signals[0]
var payload: Dictionary = runtime.call("_save_event_payload", signal_result)
var latest: Dictionary = runtime.latest_save_operation_result.duplicate(true)
row["signal_projection"] = "_save_event_payload"
row["signal_payload"] = payload
row["latest"] = latest
row["payload_bytes_equal"] = var_to_bytes(payload) == var_to_bytes(latest)
var before := witness(base)
var after_witness := witness(after)
var eid := "domain_event.%012d" % (int(before.counter) + 1)
var found: Array = []
for event: Dictionary in after_witness.recent_events:
if field(event, "event_id") == eid:
found.append(event)
if found.size() != 1 or before.published_ids.has(eid):
return false
var event: Dictionary = found[0]
row["event"] = event
row["before"] = before
row["after"] = after_witness
row["minute_before"] = field(field(base, "clock"), "absolute_minute")
row["minute_after"] = field(field(after, "clock"), "absolute_minute")
row["paused_before"] = field(field(base, "clock"), "paused")
row["paused_after"] = field(field(after, "clock"), "paused")
row["dropped"] = before.recent_events[0] if before.recent_events.size() == 256 else null
var expected := base.duplicate(true)
var part := runtime_part(expected)
var counters: Dictionary = field(field(part, "id_generator"), "counters")
counters["domain_event"] = int(before.counter) + 1
var events: Dictionary = field(part, "domain_events")
var ids: Array = field(events, "published_ids")
ids.append(eid)
ids.sort()
var recent: Array = field(events, "recent_events")
if recent.size() > 256:
return false
if recent.size() == 256:
recent.pop_front()
recent.append(event.duplicate(true))
row["comparison"] = compare(expected, after)
var expected_type := {"save": "SAVE_CHECKPOINT_SUCCEEDED", "load": "SAVE_LOADED", "tamper": "SAVE_LOAD_FAILED"}
var ok: bool = row.payload_bytes_equal and row.comparison.equal and \
var_to_bytes(field(event, "payload")) == var_to_bytes(payload) and \
field(event, "event_type") == expected_type[kind] and field(event, "source_service") == "save_service" and \
field(event, "entity_ids").is_empty() and field(event, "causation_command_id") == 0 and \
row.minute_before == row.minute_after and field(event, "absolute_minute") == row.minute_after
if kind == "tamper":
var recovery: Variant = field(signal_result, "recovery_report")
var migration: Variant = field(signal_result, "migration_attempted")
row["failure"] = {"preload_pause_restored": field(signal_result, "preload_pause_restored"),
"loaded_clock_paused": field(signal_result, "loaded_clock_paused"), "recovery_report": recovery,
"migration_attempted": migration == true}
failure_event = event.duplicate(true)
return ok and field(payload, "ok") == false and field(payload, "code") != "OK" and \
row.failure.preload_pause_restored == true and row.failure.loaded_clock_paused == row.paused_before and \
row.paused_before == row.paused_after and (recovery == null or field(recovery, "restore_committed") == false)
E = eid
return ok and field(payload, "ok") == true and field(payload, "code") == "OK" and \
(returned == true if kind == "save" else returned == null) and row.paused_after == true and \
field(payload, "saved_absolute_minute") == row.minute_after
func writer_save() -> bool:
var before: Dictionary = runtime.create_snapshot()
var backlog: int = GameClock.get_backlog_minutes()
report["overload_case"] = {"exercised": not report.overloads.is_empty() and backlog > 0,
"overloads": report.overloads.size(), "backlog_at_save": backlog}
signals = []
var returned: bool = main.call("_save_manual_at_path", "user://p28_restart/good", "P28 RESTART")
var after: Dictionary = runtime.create_snapshot()
var loaded := SaveService.load_snapshot("user://p28_restart/good")
if field(loaded, "ok") != true:
return false
package = field(loaded, "snapshot")
report["package_matches_before"] = compare(before, package)
if not record_state("P", package) or not record_state("after_save", after):
return false
return report.package_matches_before.equal and io_proof(package, after, "save", returned)
func import_transfer() -> bool:
var transfer := OS.get_environment("THE_TREE_RESTART_TRANSFER")
var manifest_path := OS.get_environment("THE_TREE_RESTART_TRANSFER_MANIFEST")
if not transfer.is_absolute_path() or not manifest_path.is_absolute_path():
return false
var manifest: Variant = JSON.parse_string(FileAccess.get_file_as_string(manifest_path))
if not manifest is Dictionary:
return false
for kind: String in ["good", "tampered"]:
var target := "user://p28_restart/" + kind
if DirAccess.dir_exists_absolute(target):
return false
for relative: String in manifest.files[kind]:
if relative.is_absolute_path() or ".." in relative.split("/") or "\\" in relative:
return false
var source := transfer.path_join(kind).path_join(relative)
var expected: Dictionary = manifest.files[kind][relative]
if FileAccess.get_sha256(source) != expected.sha256:
return false
var data := FileAccess.get_file_as_bytes(source)
if data.size() != int(expected.bytes):
return false
var destination := target.path_join(relative)
if DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(destination).get_base_dir()) != OK:
return false
var file := FileAccess.open(destination, FileAccess.WRITE)
if file == null:
return false
file.store_buffer(data)
file.close()
if FileAccess.get_sha256(destination) != expected.sha256:
return false
report["transfer_manifest_sha256"] = FileAccess.get_sha256(manifest_path)
report["transfer_verified"] = true
return true
func reader_load() -> bool:
var loaded := SaveService.load_snapshot("user://p28_restart/good")
if field(loaded, "ok") != true:
return false
package = field(loaded, "snapshot")
var before: Dictionary = runtime.create_snapshot()
if not record_state("P", package) or not record_state("B", before):
return false
signals = []
main.call("_load_manual_at_path", "user://p28_restart/tampered", true)
var failed: Dictionary = runtime.create_snapshot()
if not record_state("after_tamper", failed) or not io_proof(before, failed, "tamper", null):
return false
signals = []
main.call("_load_manual_at_path", "user://p28_restart/good", true)
var after: Dictionary = runtime.create_snapshot()
if not record_state("after_load", after) or not io_proof(package, after, "load", null):
return false
report["failure_event_absent"] = true
for event: Dictionary in witness(after).recent_events:
if var_to_bytes(event) == var_to_bytes(failure_event):
report.failure_event_absent = false
return report.failure_event_absent
func deterministic_step() -> bool:
if not io_ready or not GameClock.paused:
return false
var before: int = GameClock.absolute_minute
var backlog: int = GameClock.get_backlog_minutes()
GameClock.advance_minutes(1)
var after: int = GameClock.absolute_minute
if after != before + 1:
return false
observe_390()
var state: Dictionary = runtime.create_snapshot()
var normalized := state.duplicate(true)
var recent: Array = field(field(runtime_part(normalized), "domain_events"), "recent_events")
var replacement: Variant = null
var count := 0
var recent_ids: Array = []
for index in range(recent.size()):
recent_ids.append(field(recent[index], "event_id"))
if field(recent[index], "event_id") == E:
replacement = recent[index].duplicate(true)
recent[index] = {"event_id": E, "replaced_for_cross_pid_compare": true}
count += 1
if count > 1:
return false
report.minutes.append({"before": before, "after": after, "paused": GameClock.paused,
"backlog_before": backlog, "backlog_after": GameClock.get_backlog_minutes(),
"sha256": bytes_hash(var_to_bytes(normalized)), "scope": "complete_typed_var_to_bytes",
"excluded_paths": [], "replacement": replacement, "replacement_count": count,
"recent_count": recent.size(), "recent_ids": recent_ids})
report.actual_k += after - before
if role.begins_with("O-") and after == 390:
var observation: Dictionary = report.at_390.duplicate(true)
observation.erase("events")
report.minutes[-1]["operations_observation"] = observation
return GameClock.paused and backlog == GameClock.get_backlog_minutes()
func is_save_event(event: Variant) -> bool:
return event is Dictionary and field(event, "source_service") == "save_service" and \
field(event, "event_type") in SAVE_EVENTS
func redact_payload(payload: Dictionary, pointer: String) -> void:
if payload.has("timing_redactions"):
redaction_ok = false
return
var markers: Array = []
for key: String in ["duration_us", "runtime_duration_us"]:
if not payload.has(key):
redaction_ok = false
return
markers.append({"original_key": key, "sidecar_ref": pointer + "/" + key})
payload.erase(key)
payload["timing_redactions"] = markers
func redact_event(event: Variant, pointer: String) -> void:
if is_save_event(event):
redact_payload(event.payload, pointer + "/payload")
func public_report(full: Dictionary) -> Dictionary:
var result: Dictionary = full.duplicate(true)
for i in range(result.io.size()):
var row: Dictionary = result.io[i]
var pointer := "/report/io/%d" % i
for name: String in ["signal_payload", "latest"]:
if row.has(name):
redact_payload(row[name], pointer + "/" + name)
for name: String in ["event", "dropped"]:
if row.has(name):
redact_event(row[name], pointer + "/" + name)
for side: String in ["before", "after"]:
if row.has(side):
for j in range(row[side].recent_events.size()):
redact_event(row[side].recent_events[j], pointer + "/" + side + "/recent_events/%d" % j)
for k in range(result.minutes.size()):
redact_event(result.minutes[k].replacement, "/report/minutes/%d/replacement" % k)
return result
func public_has_forbidden(value: Variant) -> bool:
if value is Dictionary:
for key: Variant in value:
if str(key).ends_with("_" + "us") or str(key).ends_with("_" + "ms") or \
str(key) in ["performance", "statistics", "fps", "budget_verdict"]:
return true
if public_has_forbidden(value[key]):
return true
elif value is Array:
for child: Variant in value:
if public_has_forbidden(child):
return true
return false
func finish(reason: String) -> void:
if finished:
return
if canonical_key_collision:
reason = "canonical_key_collision"
finished = true
report["stop_reason"] = reason
report["key_forms"] = key_forms
var sidecar_path := "user://p28_restart/evidence/report_full.json"
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(sidecar_path).get_base_dir())
var file := FileAccess.open(sidecar_path, FileAccess.WRITE)
if file == null:
quit(1)
return
file.store_string(JSON.stringify({"report": report, "at_390_event_verbatim": at_390_event_verbatim}, "", true, true))
file.close()
# Partial failure evidence stays in the sidecar. Never emit a leaking public payload.
var public: Dictionary = public_report(report)
if not redaction_ok or public_has_forbidden(public) or public.is_empty():
print("P28_RESTART_EVIDENCE_FAILURE=" + reason)
else:
print("P28_RESTART_REPORT=" + JSON.stringify(public, "", true, true))
if is_instance_valid(main) and main.is_inside_tree():
main.ui_audio_window_close_drained.connect(emit_audio_close, CONNECT_ONE_SHOT)
get_root().close_requested.emit()
else:
quit(1)
func emit_audio_close(result: Dictionary) -> void:
print("P28_RESTART_AUDIO_CLOSE=" + JSON.stringify(result))
@@ -0,0 +1,876 @@
#!/usr/bin/env python3
"""Engine-free positive and adversarial controls. No native acceptance claimed."""
import copy
import hashlib
import json
import os
from pathlib import Path
import sys
import tempfile
import time
from types import SimpleNamespace
import unittest
from unittest.mock import patch
sys.dont_write_bytecode = True
import check_restart as check
import restart_pair as driver
DATA = b"synthetic typed bytes fixture (not engine evidence)"
HASH = hashlib.sha256(DATA).hexdigest()
def comparison():
return {"method": "var_to_bytes", "equal": True, "diff_paths": [], "excluded_paths": [],
"expected_sha256": HASH, "actual_sha256": HASH}
def history(count=256):
ids = ["domain_event.%012d" % n for n in range(1, count + 1)]
return {"counter": count, "published_ids": ids,
"recent_events": [{"event_id": eid, "event_type": "OLD", "payload": {"n": n}}
for n, eid in enumerate(ids)]}
def io(kind, minute=612, count=256):
before = history(count)
payload = {"ok": kind != "tamper", "code": "OK" if kind != "tamper" else "CORRUPT_WORLD",
"operation": "save" if kind == "save" else "load",
"save_path": "user://p28_restart/" + ("tampered" if kind == "tamper" else "good"),
"save_id": "synthetic", "saved_absolute_minute": minute,
"duration_us": 124, "runtime_duration_us": 57}
event = {"event_id": check.event_id(count),
"event_type": {"save": "SAVE_CHECKPOINT_SUCCEEDED", "load": "SAVE_LOADED",
"tamper": "SAVE_LOAD_FAILED"}[kind],
"source_service": "save_service", "entity_ids": [], "causation_command_id": 0,
"absolute_minute": minute, "payload": copy.deepcopy(payload)}
return {"kind": kind, "signal_count": 1, "signal_payload": payload, "latest": copy.deepcopy(payload),
"event": event, "signal_projection": "_save_event_payload", "payload_bytes_equal": True,
"return_kind": "bool" if kind == "save" else "void",
"return_value": True if kind == "save" else None,
"before": before, "after": check.transform(before, event),
"dropped": before["recent_events"][0] if count == 256 else None,
"comparison": comparison(), "minute_before": minute, "minute_after": minute,
"paused_before": True, "paused_after": True,
"failure": {"preload_pause_restored": True, "loaded_clock_paused": True,
"migration_attempted": False, "recovery_report": {"restore_committed": False}}}
def report(role="R-writer", pid=100):
writer, ops = role.endswith("writer"), role.startswith("O-")
minute = 361 if ops else 612
rows = [io("save", minute)] if writer else [io("tamper", 360, 3), io("load", minute)]
names = ["P", "after_save", "final"] if writer else ["P", "B", "after_tamper", "after_load", "final"]
event = rows[-1]["event"]
boundary = {"clock": minute, "guest_auto_ids": ["guest-auto-00000001"], "guest_auto_count": 1,
"operations": {"enabled": True}, "processed_arrival_minutes": [360],
"arrival_reports": [{"minute": 360}]} if ops else None
next_boundary = {"minute": 390, "processed_once": True, "before": [360], "after": [360, 390],
"arrival_reports": [{"minute": 360}, {"minute": 390}],
"guest_auto_ids": ["guest-auto-00000001", "guest-auto-00000002"]} if ops else None
clock = {"minute": minute, "paused": True, "backlog": 121, "accumulator_hex": "00"}
result = {"schema": "p28-restart-v1", "role": role, "pid": pid, "stop_reason": "complete",
"main_added": True, "k_target": 30, "actual_k": 30, "comparison_scope": "complete_typed_var_to_bytes",
"excluded_paths": [], "transfer_before_guard_writes": 0, "probe_deadline_seconds": 1740,
"probe_deadline": {"limit_seconds_from_engine_start": 1740,
"engine_elapsed_at_begin_seconds": 12.25, "timer_seconds": 1727.75},
"overloads": [],
"overload_case": {"exercised": False, "overloads": 0, "backlog_at_save": 121},
"io": rows, "package_matches_before": comparison(), "failure_event_absent": True,
"transfer_verified": True, "event_id": event["event_id"], "saved_minute": minute,
"start_minute": 360 if ops else 602, "final_minute": minute + 30,
"states": {n: {"path": "p28_restart/evidence/" + n + ".bin", "bytes": len(DATA), "sha256": HASH}
for n in names},
"paused_idle": {"before": clock, "after": copy.deepcopy(clock), "comparison": comparison()},
"boundary": boundary, "next_boundary": next_boundary, "ui_ticks": [copy.deepcopy(boundary)] if ops else [],
"minutes": [{"before": minute + n, "after": minute + n + 1, "paused": True,
"backlog_before": 121, "backlog_after": 121, "sha256": HASH,
"scope": "complete_typed_var_to_bytes", "excluded_paths": [],
"replacement": copy.deepcopy(event) if n < 5 else None,
"replacement_count": 1 if n < 5 else 0, "recent_count": 256,
"recent_ids": history(255)["published_ids"] +
([event["event_id"]] if n < 5 else ["domain_event.000000000256"])}
for n in range(30)], "at_390": None}
if ops:
result["at_390"] = {"clock": {"absolute_minute": 390}, "operations": {"enabled": True},
"processed_arrival_minutes": [360],
"guest_auto_ids": ["guest-auto-00000001"], "guest_auto_count": 1,
"domain_event_counter": 300, "published_ids_count": 300, "events": []}
result["minutes"][28]["operations_observation"] = {
k: copy.deepcopy(v) for k, v in result["at_390"].items() if k != "events"}
return result
def evidence(full, events=None):
sidecar = {"report": copy.deepcopy(full), "at_390_event_verbatim": copy.deepcopy(events or [])}
return check.redact_report(full), sidecar
def validate_report(full):
public, sidecar = evidence(full)
return check.check_report(public, sidecar)
def validate_pair(writer, reader):
public_writer, sw = evidence(writer)
public_reader, sr = evidence(reader)
return check.check_pair(public_writer, public_reader, sw, sr)
def summarize(event, eid):
return {**{k: event[k] for k in ("event_id", "event_type", "absolute_minute")},
"raw_event_sha256": check.json_sha(event),
"canonical_sha256": check.json_sha(check.canonical_event(event, eid))}
def write(path, value):
with Path(path).open("x") as stream:
json.dump(value, stream)
def audio(pid):
return {"coordinator": True, "passed": True, "owned_engine_pid": pid,
"all_owned_targets_released": True, "deadline_reached": False,
"clock_process_held_stopped": True, "window_input_held_disabled": True,
"restored_before_quit": False, "shared_bus_deleted": False, "settings_mutated": False}
def synthetic_receipt(out):
rows = []
profiles = {}
source_package = out / "synthetic-package"
source_package.mkdir()
(source_package / "world.bin").write_bytes(DATA)
(source_package / "manifest.json").write_text("{}")
transfers = {kind: driver.create_transfer(source_package, out / (kind + "-transfer"), write)
for kind in ("R", "O")}
for index, label in enumerate(check.PHASES):
folder = out / label
folder.mkdir()
pid = 100 + index
process = {"exit_code": 0, "helper_exit_code": 0, "timed_out": False, "error_lines": [],
"lifecycle_error": None, "external_process_or_group_signals": 0,
"owned_popen_ended": True, "old_helper_engine_ended": True,
"start_receipt_written": True, "end_receipt_written": True}
capture = {"passed": True, "all_captured_ended": True, "actual_captured_pids": [pid],
"outer_cleanup_errors": [], "adapter_exception": None, "foreign_process_or_group_signals": 0,
"all_cleanup_before_outer_receipt": True, "outer_receipt_written": True,
"outer_receipt_error": None, "cleanup": []}
write(folder / "outer-owned-finally.json", {k: v for k, v in capture.items() if k not in
("passed", "outer_receipt_written", "outer_receipt_error")})
for filename, key in (("started.json", "actual_start_binding"), ("ended.json", "actual_end_binding")):
binding = {"pid": pid, "actual_pid": pid, "owner_pid": 99,
"argv": ["fake", "--check-only"], "command": ["fake", "--check-only"]}
write(folder / filename, binding)
process[key] = binding
process["adapter_owned_cleanup"] = {"engine_ended": True, "errors": []}
write(folder / "adapter-owned-cleanup.json", process["adapter_owned_cleanup"])
process.update(pid=pid, argv=["fake", "--check-only"])
raw = ""
row = {"phase": label, "passed": True, "process": process, "capture": capture,
"timeout_seconds": 1800, "diagnostics": [], "argv": ["fake", "--check-only"],
"stage_before": HASH, "stage_after": HASH, "stage_preserved": True,
"source_preserved": True, "player_preserved": True}
startup = out / (label + "-startup")
startup.write_bytes(DATA)
row["startup_project"] = {"fresh_before": True, "path": str(startup), "sha256": HASH}
if index >= 3:
observed = report(label, pid)
if label.endswith("reader"):
observed["transfer_manifest_sha256"] = check.sha(out / (label[0] + "-transfer/manifest.json"))
public, sidecar = evidence(observed)
row["report"] = public
raw = "P28_RESTART_REPORT=" + json.dumps(public) + "\nP28_RESTART_AUDIO_CLOSE=" + json.dumps(audio(pid)) + "\n"
profile = str(out / (label + "-private"))
row.update(runtime_profile=profile, runtime_name=label)
profiles[profile] = {}
for kind in (("good",) if label.endswith("writer") else ("good", "tampered")):
for name, value in transfers[label[0]]["files"][kind].items():
profiles[profile]["p28_restart/" + kind + "/" + name] = value
guard = {"verified": True, "conditions": [True] * 5, "conditions_checked": 5,
"actual_user_data_dir": profile, "expected_user_data_dir": profile,
"globalized_probe": str(Path(profile) / "guard-probe"), "custom_user_dir_name": label,
"fresh_before_parent_initialize": True, "profile_writes_before_guard": 0,
"project_settings_persisted": False}
guard_path = out / (label + "-guard.json")
write(guard_path, guard)
row.update(guard=guard, guard_sha256=check.sha(guard_path))
states = out / (label + "-states")
states.mkdir()
sidecar_path = Path(profile) / check.SIDECAR
sidecar_path.parent.mkdir(parents=True)
write(sidecar_path, sidecar)
(states / "report_full.json").write_bytes(sidecar_path.read_bytes())
row["sidecar"] = {"path": check.SIDECAR, **check.pin(sidecar_path)}
profiles[profile][check.SIDECAR] = check.pin(sidecar_path)
for name in observed["states"]:
(states / (name + ".bin")).write_bytes(DATA)
for name, content in (("stdout.log", raw), ("stderr.log", ""), ("engine-native.log", "native\n")):
(folder / name).write_text(content)
row["raw"] = {n: check.pin(folder / n) for n in ("stdout.log", "stderr.log", "engine-native.log")}
process.update(stdout_sha256=row["raw"]["stdout.log"]["sha256"],
stderr_sha256=row["raw"]["stderr.log"]["sha256"])
write(folder / "process.json", process)
row["owned_files"] = {n: check.pin(folder / n) for n in
("process.json", "started.json", "ended.json", "adapter-owned-cleanup.json", "outer-owned-finally.json")}
rows.append(row)
probe = out / "restart_probe.gd"
probe.write_bytes((check.HERE / probe.name).read_bytes())
source = {str(i): {"bytes": 1, "sha256": HASH} for i in range(1407)}
worker = {n: check.sha(check.HERE / n) for n in
("restart_pair.py", "restart_probe.gd", "check_restart.py", "test_restart.py")}
return {"passed": True, "error": None, "cleanup_errors": [], "phases": rows,
"source_before": source, "source_after": copy.deepcopy(source),
"default_player_before": {}, "default_player_after": {},
"dependencies_before": check.DEPENDENCIES.copy(), "dependencies_after": check.DEPENDENCIES.copy(),
"collector_before": driver.COLLECTOR_PINS.copy(), "collector_after": driver.COLLECTOR_PINS.copy(),
"worker_before": worker, "worker_after": worker.copy(), "profiles": profiles,
"cross_cutting": copy.deepcopy(check.CROSS), "original_credit": 0,
"windows_verified": False, "operations_200_guests_verified": False,
"coverage": check.coverage([report("R-writer"), report("O-writer")]),
"script_pins": {str(probe): check.sha(probe)}, "owned_writes": [],
"cleanup": [{"pid": 100 + n, "engine_ended": True, "outer_cleanup_errors": [],
"foreign_process_or_group_signals": 0} for n in range(7)]}
class RestartTests(unittest.TestCase):
@staticmethod
def here_inventory():
return {str(path.relative_to(check.HERE)): hashlib.sha256(path.read_bytes()).hexdigest()
for path in check.HERE.rglob("*") if path.is_file()}
@classmethod
def setUpClass(cls):
cls.inventory_before = cls.here_inventory()
def setUp(self):
# Check after every test, including failures, independently of test order.
self.addCleanup(lambda: self.assertEqual(self.here_inventory(), self.inventory_before))
def test_zz_here_inventory_unchanged(self):
# unittest's default ordering places this after all twelve existing tests.
self.assertIn("test_restart.py", self.inventory_before)
self.assertEqual(self.here_inventory(), self.inventory_before)
def actual_canonical_sidecar(self):
relative = Path("native-e524ff2-canonical-failure-r01/report_full.json")
roots = [check.ROOT / "build",
check.ROOT.parent / ".runtime" / "P28-01-RESTART" / "build"]
if os.environ.get("BUILD_OUTPUT_DIR"):
roots.insert(0, Path(os.environ["BUILD_OUTPUT_DIR"]))
path = next((root / relative for root in roots if (root / relative).is_file()), None)
self.assertIsNotNone(path, "required retained native-e524ff2 sidecar is missing")
raw = path.read_bytes()
self.addCleanup(lambda: self.assertEqual(path.read_bytes(), raw))
return json.loads(raw)
def test_z1_actual_text_key_order_hash(self):
sidecar = self.actual_canonical_sidecar()
events = sidecar["at_390_event_verbatim"]
self.assertEqual(len(events), 16)
first = events[0]
self.assertEqual(first["event_id"], "domain_event.000000000009")
self.assertEqual(first["absolute_minute"], 362)
self.assertEqual(first["payload"],
{"old_state": 1, "reason": "ENTRY_COMPLETED", "state": 2})
self.assertEqual(check.json_sha(first),
"9ca80bec0c605ecd288f7671952d30fe66c67f291c5a618ea54623f07394edb9")
for key in ("raw_event_sha256", "canonical_sha256"):
self.assertEqual(sidecar["report"]["at_390"]["events"][0][key],
"f28afa0899d7efea59ab99ae06276ba354779a73cac705fa4801162f27c592d7")
with self.assertRaisesRegex(ValueError, "at390 raw/canonical SHA"):
check.check_sidecar(check.redact_report(sidecar["report"]), sidecar)
def test_z1_all_actual_event_bindings(self):
original = self.actual_canonical_sidecar()
sidecar = copy.deepcopy(original)
full = sidecar["report"]
self.assertEqual(len(sidecar["at_390_event_verbatim"]), 16)
self.assertEqual(len(full["at_390"]["events"]), 16)
for event, summary in zip(sidecar["at_390_event_verbatim"], full["at_390"]["events"]):
summary["raw_event_sha256"] = check.json_sha(event)
summary["canonical_sha256"] = check.json_sha(
check.canonical_event(event, full["event_id"]))
self.assertEqual(sidecar["at_390_event_verbatim"], original["at_390_event_verbatim"])
self.assertEqual(check.check_sidecar(check.redact_report(full), sidecar), full)
for index in range(16):
with self.subTest(index=index):
changed = copy.deepcopy(sidecar)
changed["report"]["at_390"]["events"][index]["raw_event_sha256"] = "0" * 64
with self.assertRaisesRegex(ValueError, "at390 raw/canonical SHA"):
check.check_sidecar(check.redact_report(changed["report"]), changed)
def test_z2_collision_rejected(self):
for ambiguous in ({1: "numeric", "1": "text"},
{"nested": [{1: "numeric", "1": "text"}]}):
with self.subTest(value=ambiguous), self.assertRaisesRegex(
ValueError, "canonical_key_collision"):
check.json_sha(ambiguous)
full = report()
full["stop_reason"] = "canonical_key_collision"
public, sidecar = evidence(full)
with self.assertRaisesRegex(ValueError, "canonical_key_collision"):
check.check_report(public, sidecar)
public["stop_reason"] = "complete"
with self.assertRaises(ValueError):
check.check_report(public, sidecar)
def rejects(self, original, mutations, validator):
for name, mutation in mutations.items():
with self.subTest(rejection=name):
value = copy.deepcopy(original)
mutation(value)
with self.assertRaises((ValueError, KeyError, TypeError)):
validator(value)
def test_rs1_signal_bool_void(self):
for kind in ("save", "load", "tamper"):
check.check_io(io(kind), kind)
self.rejects(io("save"), {
"true only": lambda x: x.pop("signal_count"),
"no signal": lambda x: x.update(signal_count=0),
"duplicate signal": lambda x: x.update(signal_count=2),
"bool differs": lambda x: x.update(return_value=False),
"latest differs": lambda x: x["latest"].update(code="FAILED"),
"payload typed mismatch": lambda x: x.update(payload_bytes_equal=False),
"state mismatch": lambda x: x["comparison"].update(equal=False),
}, lambda x: check.check_io(x, "save"))
self.rejects(io("load"), {
"void success": lambda x: x.update(return_value=True),
"void coerced bool": lambda x: x.update(return_kind="bool"),
"missing signal": lambda x: x.update(signal_count=0),
}, lambda x: check.check_io(x, "load"))
def test_rs2_exact_event_transform(self):
for kind in ("save", "load", "tamper"):
for count in (0, 255, 256):
check.check_io(io(kind, count=count), kind)
self.rejects(io(kind), {
"two events": lambda x: x["after"]["recent_events"].append(copy.deepcopy(x["event"])),
"different E": lambda x: x["event"].update(event_id="domain_event.000009999999"),
"counter": lambda x: x["after"].update(counter=x["before"]["counter"] + 2),
"missing ID": lambda x: x["after"]["published_ids"].pop(0),
"duplicate ID": lambda x: x["after"]["published_ids"].append(x["event"]["event_id"]),
"unsorted IDs": lambda x: x["after"]["published_ids"].reverse(),
"drop tail": lambda x: x["after"].update(recent_events=x["before"]["recent_events"][:-1] + [x["event"]]),
"wrong dropped record": lambda x: x.update(dropped=x["before"]["recent_events"][-1]),
"excluded path": lambda x: x["comparison"].update(excluded_paths=["systems.runtime.economy"]),
"diff hidden": lambda x: x["comparison"].update(diff_paths=["$.clock"]),
"digest only": lambda x: x["comparison"].update(method="SimulationDigest"),
"bytes SHA disagreement": lambda x: x["comparison"].update(actual_sha256="f" * 64),
}, lambda x: check.check_io(x, kind))
def test_clarification01_tamper(self):
self.rejects(io("tamper"), {
"failure event ignored": lambda x: x.update(after=x["before"]),
"failure ok": lambda x: x["signal_payload"].update(ok=True),
"failure OK code": lambda x: x["signal_payload"].update(code="OK"),
"not restored": lambda x: x["failure"].update(preload_pause_restored=False),
"paused differs": lambda x: x.update(paused_after=False),
"loaded pause differs": lambda x: x["failure"].update(loaded_clock_paused=False),
"restore committed": lambda x: x["failure"]["recovery_report"].update(restore_committed=True),
"migration unrecorded": lambda x: x["failure"].pop("migration_attempted"),
}, lambda x: check.check_io(x, "tamper"))
self.rejects(report("R-reader"), {
"failed event retained": lambda x: x.update(failure_event_absent=False),
"backlog consumed": lambda x: x["paused_idle"]["after"].update(backlog=120),
"reader not paused": lambda x: x["io"][1].update(paused_after=False),
}, validate_report)
def test_rs3_actual_k_full_typed_cross_pid(self):
writer, reader = report(), report("R-reader", 101)
validate_pair(writer, reader)
self.rejects(reader, {
"K call count": lambda x: x["minutes"][0].update(after=x["saved_minute"]),
"different K": lambda x: x.update(actual_k=29),
"missing minute": lambda x: x["minutes"].pop(),
"partial digest": lambda x: x["minutes"][0].update(scope="SimulationDigest"),
"minute SHA": lambda x: x["minutes"][0].update(sha256="f" * 64),
"wrong replacement": lambda x: x["minutes"][0]["replacement"].update(event_id="other"),
"two replacements": lambda x: x["minutes"][0].update(replacement_count=2),
"after window": lambda x: x["minutes"][6].update(replacement=x["io"][-1]["event"], replacement_count=1),
"excluded path": lambda x: x["minutes"][0].update(excluded_paths=["clock"]),
"same PID": lambda x: x.update(pid=100),
}, lambda x: validate_pair(writer, x))
def test_rs4_rs5_arrival_boundary(self):
writer, reader = report("O-writer"), report("O-reader", 101)
validate_pair(writer, reader)
self.rejects(writer, {
"boundary only": lambda x: x["boundary"].update(guest_auto_count=0),
"null arrival": lambda x: x.update(boundary=None),
"unprocessed": lambda x: x["boundary"].update(processed_arrival_minutes=[]),
"not first tick": lambda x: x["ui_ticks"].insert(0, copy.deepcopy(x["boundary"])),
"duplicate guest": lambda x: x["boundary"]["guest_auto_ids"].append("guest-auto-00000001"),
"next missing": lambda x: x["next_boundary"].update(processed_once=False),
"next duplicate": lambda x: x["next_boundary"]["after"].append(420),
"cap exceeded": lambda x: x.update(start_minute=200),
}, validate_report)
def test_d1_import_closure(self):
check.check_dependencies()
check.check_modules()
for name in ("restart_pair.py", "check_restart.py", "test_restart.py"):
check.check_imports((check.HERE / name).read_text())
for text in ("import forbidden_project_module", "from tools.strict_test_markers import main",
"importlib.util.spec_from_file_location('x', 'tools/evil.py')",
"__import__('tools.evil')", "exec('import tools.evil')"):
with self.subTest(text=text), self.assertRaises(ValueError):
check.check_imports(text)
with self.assertRaises(ValueError):
check.check_modules({"bad": SimpleNamespace(__file__=str(check.ROOT / "tools/evil.py"))})
for path in check.DEPENDENCIES:
original = check.sha
with self.subTest(pin=path), patch.object(check, "sha", side_effect=lambda p:
"0" * 64 if Path(p) == check.ROOT / path else original(p)), self.assertRaises(ValueError):
check.check_dependencies()
def test_d2_order_and_check_plan(self):
collector, _, _ = driver.load_dependencies()
commands = driver.plan(collector, Path("/engine"), Path("/out"))
self.assertEqual(len(commands), 7)
self.assertIn("--import", commands[0])
self.assertIn("--check-only", commands[1])
self.assertIn("--check-only", commands[2])
rows = []
for _, label in driver.schedule(rows):
rows.append({"phase": label, "passed": True, "report": {"stop_reason": "complete"}})
self.assertEqual([r["phase"] for r in rows], check.PHASES)
rows = []
iterator = driver.schedule(rows)
for _ in range(4):
_, label = next(iterator)
rows.append({"phase": label, "passed": True, "report": {"stop_reason": "complete"}})
rows[-1]["passed"] = False
with self.assertRaises(ValueError):
next(iterator)
rows[-1]["passed"] = True
rows[-1]["report"]["stop_reason"] = "failed"
iterator = driver.schedule([])
next(iterator)
with self.assertRaises(ValueError):
next(iterator)
def test_d3_transfer_and_fresh_profiles(self):
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
base = Path(temporary)
source = base / "source"
source.mkdir()
(source / "world.bin").write_bytes(b"0123456789")
(source / "manifest.json").write_text("{}")
target = base / "transfer"
manifest = driver.create_transfer(source, target, write)
driver.check_transfer(target, manifest)
self.assertEqual((target / "tampered/world.bin").read_bytes(), b"0123446789")
driver.fresh_profile(base / "new-profile")
with self.assertRaises(ValueError):
driver.fresh_profile(source)
self.rejects(manifest, {
"SHA": lambda x: x["files"]["good"]["world.bin"].update(sha256="f" * 64),
"offset": lambda x: x["tamper"].update(offset=0),
"xor": lambda x: x["tamper"].update(xor=2),
}, lambda x: driver.check_transfer(target, x))
(target / "tampered/manifest.json").write_text("changed")
with self.assertRaises(ValueError):
driver.check_transfer(target, manifest)
def test_d4_d5_d7_probe_static(self):
text = (check.HERE / "restart_probe.gd").read_text()
check.check_probe(text)
snippets = ["GameClock.advance_minutes(1)", "GameClock.set_paused(false)",
"x.clear()", "spawn_guest()", "SimulationRuntime.new()", "initialize()",
"enable_production_checkpoint()", "main._toggle_pause()", "GameClock.set_paused(true)",
"var elapsed_us = 1", "Time.get_ticks_usec()"]
for snippet in snippets:
with self.subTest(snippet=snippet), self.assertRaises(ValueError):
check.check_probe(text + "\nfunc bad():\n\t" + snippet + "\n")
for replacement in ("GameClock.advance_minutes(2)", "Time.get_ticks_usec()",
"GameClock.advance_one_minute()"):
with self.subTest(step=replacement), self.assertRaises(ValueError):
check.check_probe(text.replace("GameClock.advance_minutes(1)", replacement))
def test_y2_direct_variant_inference_guard(self):
text = (check.HERE / "restart_probe.gd").read_text()
check.check_probe(text)
snippets = [
"var x := GameClock.get_backlog_minutes()",
'var y := field(d,"k")',
"var x := runtime.create_snapshot()",
"var x := main",
"var x := other_variant.value",
"var x := other_field(d)",
]
declarations = "\nvar other_variant: Variant\nfunc other_field(d) -> Variant:\n\treturn d\n"
for snippet in snippets:
with self.subTest(snippet=snippet), self.assertRaisesRegex(ValueError, "direct Variant inference"):
check.check_probe(text + declarations + "\nfunc bad():\n\t" + snippet + "\n")
for snippet in (
"var x: int = GameClock.get_backlog_minutes()",
'var y: Variant = field(d,"k")',
"var x := 1",
"var x := witness(d)",
"var x := GameClock_extra.get_backlog_minutes()",
):
with self.subTest(allowed=snippet):
check.check_probe(text + "\nfunc allowed():\n\t" + snippet + "\n")
def test_rs7_rs8_full_receipt_rejections(self):
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
out = Path(temporary)
receipt = synthetic_receipt(out)
check.check_receipt(receipt, out)
self.rejects(receipt, {
"source map": lambda x: x["source_after"].pop("0"),
"ordinary player": lambda x: x["default_player_after"].update(changed=True),
"guard": lambda x: x["phases"][3]["guard"].update(profile_writes_before_guard=1),
"raw SHA": lambda x: x["phases"][3]["raw"]["stdout.log"].update(sha256="f" * 64),
"PID": lambda x: x["phases"][3]["capture"].update(actual_captured_pids=[999]),
"owned write": lambda x: x["owned_writes"].append("R-writer/report.json"),
"cleanup": lambda x: x["cleanup"][0].update(engine_ended=False),
"stage": lambda x: x["phases"][1].update(stage_after="f" * 64),
"collector": lambda x: x["collector_after"].pop("measure_p28_01.gd"),
"dependency": lambda x: x["dependencies_after"].update({"tools/run_all_tests.py": "f" * 64}),
"cross-cutting": lambda x: x["cross_cutting"].pop(),
"source count": lambda x: (x["source_after"].pop("1"), x["source_before"].pop("1")),
"phase order": lambda x: x["phases"].reverse(),
"foreign signal": lambda x: x["phases"][0]["capture"].update(foreign_process_or_group_signals=1),
}, lambda x: check.check_receipt(x, out))
(out / "R-reader-states/B.bin").write_bytes(b"changed")
with self.assertRaises(ValueError):
check.check_receipt(receipt, out)
def test_d6_raw_report_and_audio(self):
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
out = Path(temporary)
receipt = synthetic_receipt(out)
row = receipt["phases"][3]
folder = out / "R-writer"
original = (folder / "stdout.log").read_text()
for text in ("", original + original, original.split("P28_RESTART_AUDIO_CLOSE=")[0],
original.replace('"owned_engine_pid": 103', '"owned_engine_pid": 999')):
(folder / "stdout.log").write_text(text)
row["raw"]["stdout.log"] = check.pin(folder / "stdout.log")
with self.assertRaises(ValueError):
check.bound_raw(folder, row)
def test_d2_d6_real_owned_outer_fake_child(self):
collector, _, outer = driver.load_dependencies()
child = (
"import os,sys,json,time,pathlib\n"
"mode=sys.argv[1]\n"
"identity={'pid':os.getpid(),'ppid':os.getppid(),'pgid':os.getpgrp(),"
"'args':' '.join([sys.executable]+sys.argv)}\n"
"path=pathlib.Path(sys.argv[0]).parent/(mode+'-identity')\n"
"tmp=path.with_suffix('.tmp'); tmp.write_text(json.dumps(identity)); tmp.replace(path)\n"
"pathlib.Path(sys.argv[sys.argv.index('--log-file')+1]).write_text('native raw\\n')\n"
"print('Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org',flush=True)\n"
"time.sleep(0.15)\n"
"if mode=='timeout': time.sleep(5)\n"
"sys.exit(3 if mode=='exit' else 0)\n")
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
base = Path(temporary)
script = base / "fake-child"
script.write_text(child)
def diagnostic(command, folder, timeout, env, **kwargs):
def probe(pid):
path = base / (command[2] + "-identity")
deadline = time.monotonic() + 2
while time.monotonic() < deadline:
if path.exists():
identity = json.loads(path.read_text())
if identity["pid"] == pid:
return identity
time.sleep(.005)
raise RuntimeError("fake child identity unavailable")
return outer.native.run_owned_diagnostic(command, folder, timeout, env, probe_fn=probe, **kwargs)
for mode in ("ok", "exit", "timeout"):
folder = base / mode
def run_phase(command, destination, limit, env, **kwargs):
self.assertEqual(limit, 1800)
return outer.run_phase(command, destination, .3 if mode == "timeout" else 5,
env, diagnostic_fn=diagnostic, **kwargs)
def guarded_write(path, value):
self.assertFalse(Path(path).is_relative_to(folder), "driver writes owned folder")
write(path, value)
def real_phase(*args, **kwargs):
kwargs["dump_fn"] = write
return run_phase(*args, **kwargs)
with patch.object(collector, "live_engines", return_value=[]), \
patch.object(collector, "write", side_effect=guarded_write):
row = collector.run_engine(SimpleNamespace(run_phase=real_phase),
[sys.executable, str(script), mode], folder, {})
row["phase"] = "import"
self.assertEqual(row["passed"], mode == "ok", row)
self.assertTrue(row["capture"]["all_captured_ended"])
if mode == "ok":
check.bound_raw(folder, row)
else:
with self.assertRaises(ValueError):
check.bound_raw(folder, row)
_, errors = outer.finish_captured(outer.OWNED)
self.assertEqual(errors, [])
def test_v1_at390_required_and_pair_consistency(self):
writer, reader = report("O-writer"), report("O-reader", 101)
validate_pair(writer, reader)
self.rejects(writer, {
"absent": lambda x: x.pop("at_390"),
"null": lambda x: x.update(at_390=None),
"not reached": lambda x: x.update(stop_reason="at_390_not_reached"),
"clock": lambda x: x["at_390"]["clock"].update(absolute_minute=391),
"counter type": lambda x: x["at_390"].update(domain_event_counter="300"),
"row differs": lambda x: x["minutes"][28]["operations_observation"].update(guest_auto_count=2),
}, validate_report)
for mutate in (lambda x: x.pop("at_390"), lambda x: x.update(at_390=None)):
w, r = copy.deepcopy(writer), copy.deepcopy(reader)
mutate(w)
mutate(r)
with self.assertRaises((ValueError, KeyError)):
validate_pair(w, r)
different = copy.deepcopy(reader)
different["at_390"]["operations"]["population"] = 3
different["minutes"][28]["operations_observation"]["operations"]["population"] = 3
validate_report(different)
with self.assertRaises(ValueError):
validate_pair(writer, different)
with self.assertRaises((ValueError, KeyError)):
validate_pair(writer, {**reader, "at_390": None})
def test_v2_all_seven_families_restore_verbatim(self):
full = report()
# T4 and T6 are conditional: an earlier SAVE event is the dropped head.
old = io("save", minute=600, count=0)["event"]
row = full["io"][0]
row["before"]["recent_events"][0] = old
row["dropped"] = copy.deepcopy(old)
row["after"] = check.transform(row["before"], row["event"])
public, sidecar = evidence(full)
check.check_report(public, sidecar)
paths = check.payload_paths(public)
for path in ("/report/io/0/signal_payload", "/report/io/0/latest",
"/report/io/0/event/payload", "/report/io/0/before/recent_events/0/payload",
"/report/io/0/after/recent_events/255/payload", "/report/io/0/dropped/payload",
"/report/minutes/0/replacement/payload"):
self.assertEqual(paths[path]["timing_redactions"], [
{"original_key": key, "sidecar_ref": path + "/" + key} for key in check.TIMINGS])
self.assertNotIn("duration_us", paths[path])
self.assertEqual(public["io"][0]["after"]["recent_events"][0],
full["io"][0]["after"]["recent_events"][0])
self.assertEqual(check.check_sidecar(public, sidecar), full)
for kind in ("save", "load", "tamper"):
full_row = io(kind)
check.check_io(full_row, kind)
self.rejects(sidecar, {
"root extra": lambda x: x.update(extra={}),
"performance use": lambda x: x["report"].update(statistics={"average": 1}),
"outside closure": lambda x: x["report"].update(elapsed_ms=1),
"nested timing": lambda x: x["report"]["io"][0]["event"]["payload"].update(nested={"latency_us": 1}),
"missing timing": lambda x: x["report"]["io"][0]["latest"].pop("duration_us"),
"tamper value": lambda x: x["report"]["io"][0]["latest"].update(code="CHANGED"),
"nonSAVE": lambda x: x["report"]["io"][0]["before"]["recent_events"][0].update(event_type="OLD"),
"wrong service": lambda x: x["report"]["io"][0]["before"]["recent_events"][0].update(source_service="other"),
}, lambda x: check.check_sidecar(public, x))
self.rejects(public, {
"leaked key": lambda x: x["io"][0]["signal_payload"].update(duration_us=124),
"hidden payload leak": lambda x: x.update(payload={"hidden_ms": 1}),
"extra marker": lambda x: x["io"][0]["latest"]["timing_redactions"].append(
{"original_key": "other", "sidecar_ref": "/report/other"}),
"missing marker": lambda x: x["io"][0]["latest"].pop("timing_redactions"),
"one marker": lambda x: x["io"][0]["latest"]["timing_redactions"].pop(),
"wrong pointer": lambda x: x["io"][0]["latest"]["timing_redactions"][0].update(
sidecar_ref="/report/io/0/signal_payload/duration_us"),
"unresolved pointer": lambda x: x["io"][0]["latest"]["timing_redactions"][0].update(
sidecar_ref="/report/io/999/latest/duration_us"),
"extra marker field": lambda x: x["io"][0]["latest"]["timing_redactions"][0].update(extra=1),
"nonSAVE marker": lambda x: x["io"][0]["after"]["recent_events"][0]["payload"].update(
timing_redactions=copy.deepcopy(x["io"][0]["latest"]["timing_redactions"])),
"restore differs": lambda x: x.update(pid=999),
}, lambda x: check.check_sidecar(x, sidecar))
with self.assertRaises(ValueError):
check.check_report(public)
# The raw equality check must see differences hidden by public redaction.
tampered = copy.deepcopy(sidecar)
tampered["report"]["io"][0]["latest"]["duration_us"] += 1
self.assertEqual(check.redact_report(tampered["report"]), public)
with self.assertRaises(ValueError):
check.check_report(public, tampered)
def test_v2_at390_full_array_binding(self):
full = report("O-writer")
events = [
{"event_id": "domain_event.%012d" % n, "event_type": "ARRIVAL",
"absolute_minute": 380 + i, "source_service": "operations", "payload": {"count": i + 1}}
for i, n in enumerate((250, 251))]
full["at_390"]["events"] = [summarize(e, full["event_id"]) for e in events]
public, sidecar = evidence(full, events)
check.check_report(public, sidecar)
self.rejects(sidecar, {
"missing array": lambda x: x.pop("at_390_event_verbatim"),
"missing entry": lambda x: x["at_390_event_verbatim"].pop(),
"extra entry": lambda x: x["at_390_event_verbatim"].append(copy.deepcopy(events[0])),
"reordered": lambda x: x["at_390_event_verbatim"].reverse(),
"raw differs": lambda x: x["at_390_event_verbatim"][0]["payload"].update(count=7),
"nonSAVE timing": lambda x: x["at_390_event_verbatim"][0]["payload"].update(duration_us=1),
}, lambda x: check.check_sidecar(public, x))
for field in ("raw_event_sha256", "canonical_sha256"):
changed = copy.deepcopy(full)
changed["at_390"]["events"][0][field] = "f" * 64
pub, sc = evidence(changed, events)
with self.assertRaises(ValueError):
check.check_sidecar(pub, sc)
changed = copy.deepcopy(full)
changed["at_390"]["events"][0]["canonical_sha256"] = check.json_sha(
{"event_id": events[0]["event_id"], "replaced_for_cross_pid_compare": True})
pub, sc = evidence(changed, events)
with self.assertRaises(ValueError):
check.check_sidecar(pub, sc)
# D5 operates on an entire E element, including type and timing differences.
# This exercises the binding independently of the strict > saved_minute filter.
canonical_observations = []
raw_shas = []
for kind in ("save", "load"):
raw_event = io(kind, 361)["event"]
raw_event["payload"]["duration_us"] += 1 if kind == "load" else 0
value = copy.deepcopy(full)
value["at_390"]["events"] = [summarize(raw_event, value["event_id"])]
pub, sc = evidence(value, [raw_event])
check.check_sidecar(pub, sc)
canonical_observations.append(check.canonical_observation(value["at_390"], value["event_id"]))
raw_shas.append(value["at_390"]["events"][0]["raw_event_sha256"])
with self.assertRaises(ValueError):
check.check_report(pub, sc) # E at saved_minute is outside this observation's window.
self.assertNotEqual(raw_shas[0], raw_shas[1])
self.assertEqual(*canonical_observations)
# All other event fields and canonical hashes remain significant cross PID.
reader = report("O-reader", 101)
reader["at_390"]["events"] = copy.deepcopy(full["at_390"]["events"])
rp, rs = evidence(reader, events)
check.check_pair(public, rp, sidecar, rs)
changed_events = copy.deepcopy(events)
changed_events[0]["payload"]["count"] = 9
reader["at_390"]["events"] = [summarize(e, reader["event_id"]) for e in changed_events]
rp, rs = evidence(reader, changed_events)
check.check_report(rp, rs)
with self.assertRaises(ValueError):
check.check_pair(public, rp, sidecar, rs)
def test_v2_receipt_sidecar_binding_rejections(self):
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
out = Path(temporary)
receipt = synthetic_receipt(out)
check.check_receipt(receipt, out)
self.rejects(receipt, {
"unbound": lambda x: x["phases"][3].pop("sidecar"),
"wrong SHA": lambda x: x["phases"][3]["sidecar"].update(sha256="f" * 64),
"missing map": lambda x: x["profiles"][x["phases"][3]["runtime_profile"]].pop(check.SIDECAR),
"wrong path": lambda x: x["phases"][3]["sidecar"].update(path="other.json"),
"coverage omitted": lambda x: x.pop("coverage"),
"false coverage": lambda x: x["coverage"].update(overload_nonzero_backlog="exercised_recorded"),
"persistence claim": lambda x: x["coverage"].update(across_restart_backlog_persistence_claimed=True),
}, lambda x: check.check_receipt(x, out))
path = out / "R-writer-states/report_full.json"
saved = path.read_bytes()
path.write_bytes(b"{}")
with self.assertRaises(ValueError):
check.check_receipt(receipt, out)
path.unlink()
with self.assertRaises(ValueError):
check.check_receipt(receipt, out)
path.write_bytes(saved)
private = Path(receipt["phases"][3]["runtime_profile"]) / check.SIDECAR
private.write_bytes(b"{}")
with self.assertRaises(ValueError):
check.check_receipt(receipt, out)
def test_v3_overload_is_observation_not_persistence(self):
for count, backlog in ((0, 0), (0, 121), (1, 0), (1, 121)):
full = report()
full["overloads"] = [{"minute": 612, "backlog": backlog}] * count
full["paused_idle"]["before"]["backlog"] = backlog
full["paused_idle"]["after"]["backlog"] = backlog
full["overload_case"] = {"exercised": bool(count and backlog > 0),
"overloads": count, "backlog_at_save": backlog}
validate_report(full)
observed = check.coverage([full])
self.assertEqual(observed["overload_nonzero_backlog"],
"exercised_recorded" if count and backlog else "not_exercised")
self.assertFalse(observed["across_restart_backlog_persistence_claimed"])
self.rejects(full, {
"missing disclosure": lambda x: x.pop("overload_case"),
"wrong exercised": lambda x: x["overload_case"].update(exercised=not bool(count and backlog)),
"wrong count": lambda x: x["overload_case"].update(overloads=count + 1),
"wrong backlog": lambda x: x["overload_case"].update(backlog_at_save=backlog + 1),
"consumption": lambda x: x["paused_idle"]["after"].update(backlog=backlog + 1),
"persistence claim": lambda x: x.update(across_restart_backlog_persistence_claimed=True),
"nonzero claim": lambda x: x.update(nonzero_backlog_preserved=True),
}, validate_report)
writer, reader = report(), report("R-reader", 101)
reader["paused_idle"]["before"]["backlog"] = 0
reader["paused_idle"]["after"]["backlog"] = 0
for row in reader["minutes"]:
row.update(backlog_before=0, backlog_after=0)
validate_pair(writer, reader) # No across-restart accumulator persistence requirement.
def test_v4_no_arrival_is_diagnostic_failure(self):
full = report("O-writer")
full.update(boundary=None, boundary_reason="no_arrival_within_cap",
stop_reason="no_arrival_within_cap", next_boundary=None, io=[], minutes=[], actual_k=0)
full["ui_ticks"] = [{"clock": n, "guest_auto_ids": [], "guest_auto_count": 0}
for n in range(361, 481)]
self.assertTrue(check.check_no_arrival_diagnostic(full))
with self.assertRaisesRegex(ValueError, "incomplete probe"):
validate_report(full)
self.rejects(full, {
"missing reason": lambda x: x.pop("boundary_reason"),
"wrong reason": lambda x: x.update(boundary_reason="complete"),
"not null": lambda x: x.update(boundary={}),
"short cap": lambda x: x["ui_ticks"].pop(),
}, check.check_no_arrival_diagnostic)
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
out = Path(temporary)
receipt = synthetic_receipt(out)
row = receipt["phases"][5]
full["pid"] = row["report"]["pid"]
public, sidecar = evidence(full)
row["report"] = public
text = "P28_RESTART_REPORT=" + json.dumps(public) + "\nP28_RESTART_AUDIO_CLOSE=" + json.dumps(audio(full["pid"])) + "\n"
(out / "O-writer/stdout.log").write_text(text)
row["raw"]["stdout.log"] = check.pin(out / "O-writer/stdout.log")
row["process"]["stdout_sha256"] = row["raw"]["stdout.log"]["sha256"]
(out / "O-writer/process.json").write_text(json.dumps(row["process"]))
row["owned_files"]["process.json"] = check.pin(out / "O-writer/process.json")
for path in (out / "O-writer-states/report_full.json",
Path(row["runtime_profile"]) / check.SIDECAR):
path.write_text(json.dumps(sidecar))
binding = check.pin(out / "O-writer-states/report_full.json")
row["sidecar"] = {"path": check.SIDECAR, **binding}
receipt["profiles"][row["runtime_profile"]][check.SIDECAR] = binding
with self.assertRaisesRegex(ValueError, "incomplete probe"):
check.check_receipt(receipt, out)
def test_v5_engine_elapsed_deadline(self):
for elapsed in (0, .25, 37, 1739.5):
full = report()
full["probe_deadline"].update(engine_elapsed_at_begin_seconds=elapsed, timer_seconds=1740-elapsed)
validate_report(full)
value = report()["probe_deadline"]
self.rejects(value, {
"old relative timer": lambda x: x.update(timer_seconds=1740),
"wrong limit": lambda x: x.update(limit_seconds_from_engine_start=1800),
"negative elapsed": lambda x: x.update(engine_elapsed_at_begin_seconds=-1, timer_seconds=1741),
"missing elapsed": lambda x: x.pop("engine_elapsed_at_begin_seconds"),
"expired": lambda x: x.update(engine_elapsed_at_begin_seconds=1740, timer_seconds=0),
"nonfinite": lambda x: x.update(engine_elapsed_at_begin_seconds=float("inf")),
}, check.check_deadline)
check.check_deadline({**value, "engine_elapsed_at_begin_seconds": 1750, "timer_seconds": -10}, complete=False)
text = (check.HERE / "restart_probe.gd").read_text()
for altered in (text + "\nfunc forbidden():\n\tTime.get_ticks_msec()\n",
text.replace("deadline_timer_seconds() ->", "other_watchdog() ->"),
text.replace("GameClock.advance_minutes(1)", "Time.get_ticks_msec()"),
text + "\nfunc forbidden():\n\tTime.get_unix_time_from_system()\n"):
with self.assertRaises(ValueError):
check.check_probe(altered)
if __name__ == "__main__":
unittest.main(verbosity=2)
@@ -243,7 +243,7 @@
"facility_value_contracts_validation.json": "bf490a9ca585c48fc318e76c4a069ef244827d828d46e6415399f7710590dd16",
"performance_audit.json": "0b630b15a392c3e0366f1362bfe4ddacb968f915f54549f82e4d6fa315384762",
"progress_contract.json": "ccbdfce8c8365d5c13f59531955708834cce45acd0e136561c95295dfdb5df77",
"progress_snapshot.json": "40c8b516e053323ec79ed5cba348ff20a628bd541254961eec95fe05c44655c0",
"progress_snapshot.json": "3c9175a894f639fd8fc6795c421a9f38742bab1f18d45c58fec3d65296d80613",
"progress_validator_guard_checks.json": "72ee513fcf1cad85c24bfd0a4b472f425f6acf117928ece0f6b41e29018da627",
"progress_validator_guard_checks.r01.json": "14c26adffa5a1938241db4912e50ea54b660641ee6fee2e412d467dce14d0519",
"requirement_coverage.json": "03b10e4da367579db502d0671a6e0dda36fd385111c6f1c0084acaff7605f593",
@@ -253,6 +253,6 @@
"validate_facility_value_contracts.py": "91640e2a76cd6cc9186f7b85c0bf379b24b6cac0d48962815235ee628e7ae43e",
"validate_plan.py": "4973d3c2797289d266f5c6e7c36f3d2c31931b23a1022eab3d94328267bcc1b4",
"validator_update_checks.json": "f997d0f3de2cea29550840b1d5cb23647d64f81329de46758551e2b6c8fecc27",
"work_packages.json": "7e3213bea7a2d2b3d7b09a9e218c9dfbc2b8bd3489965c9c7785dfa05ae1daa7"
"work_packages.json": "26ae4834d412f88743cd3bcff1d891edc597b1e357244139b3fd8ba9d90fd9f1"
}
}
@@ -1,9 +1,9 @@
{
"schema_version": 1,
"integrated_at_jst": "2026-10-21T03:10:19.441649+09:00",
"integrated_at_jst": "2026-10-21T04:37:36.598744+09:00",
"scope": "原30パッケージ/88成果、正式完了22成果・4パッケージ。部分点なし。現在P28-01は未完、collectorの補助成果は原加算0。全ゲーム/同一Windows版の最終受入は未完。",
"source_head": "464cc26fd301c66ecc10d2167f613f814e36fc47",
"source_authority_note": "台帳更新直前main464cc26。製品1407/collector4不変、full9と正式192/22198は全適用条件一致時再利用。RESTART e524正式21PASS/native Owriter canonicalSHA失敗を保持。実型診断でStringName非文字順を確定し、同Astra repair8 S954528aは正式24PASS。実Desktop Opus257が全raw/diffを読んで新S native7を承認、Rootexec34944で実行中。原22/88・4/30、P28加算0。CLI auth失敗をDesktop成功と混同しない。",
"source_head": "3ac2cedc8dc977778fd5a3ba152197cc6cf00fa2",
"source_authority_note": "台帳更新直前mainQ3ac2ced。RESTART S954528a→Q3ac2ced正式8/8全4通常ゲートPASS。実native7/全raw243/PID/sidecar結合、独立freshDesktop Opus5.5全8PASS/highmedium0/low3を実証。受信900秒失敗は保持し、同じ実結果だけ正確凍結入力で通常reviewへ1回再接続。CLI認証回復とは扱わない。原22/88・4/30、P28-01 whole-unit未完。",
"immutable_history": {
"baseline.json": {
"sha256": "750bb3d313cc5e2ce0d4c79e563a995abd7a78f991dee1dd75c627877b02cd7b",
@@ -5256,8 +5256,24 @@
"title": "現HEADの性能基準",
"state": "in_progress",
"completed": false,
"reusable_evidence": "docs/plans/original-completion-2026-10-02/execution/p28-01/INTEGRATED_FULL9_MEASUREMENT_DB9D613.json",
"remaining": "collector/full9済。現RESTART S954528a正式24PASS、native7実行中。全raw結合/独立all8/通常final/原wholeunitゲート未完。原加算0。",
"reusable_evidence": [
{
"path": "docs/plans/original-completion-2026-10-02/execution/p28-01/RESTART_FORMAL_COMPLETION_3AC2CED.json",
"bytes": 6366,
"sha256": "5c9b82a70f6bdb972d720aaa64f5d27aa54130f27f9d1f7cea1c7b02524f84be"
},
{
"path": "artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/native-restart-954528a-r01/ROOT_RAW_ACCEPTANCE_JOIN.json",
"bytes": 70643,
"sha256": "6dbb3cbb4ac1838b66034323cab22a9c5a968c1da0efe8d34676073b3f980cfb"
},
{
"path": "artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/ROOT_CANDIDATE_3AC2CED_QUALIFICATION.json",
"bytes": 235149,
"sha256": "5bd8030acddc385eb728441286f6a740ec1ee966125474b60ef4b1efe2a2c343"
}
],
"remaining": "collector/full9/RESTART正式完了。残りは原whole-unit証拠ゲート・独立レビュー・通常integration/final・台帳のみ。原加算0。",
"original_completed": 22,
"original_total": 88
},
@@ -9735,8 +9751,8 @@
"formal_count": 22,
"original_delivery_units": 88,
"partial_credit": false,
"selection_status": "P28-01-COLLECTORはQ0f53a67で正式completed9/9・全4ゲートPASS。次は統合版全9本測定、別PIDRESTART、原whole-unit受入。",
"pending_decisions": "本測定の実停止/不足があれば実Opus判断。RESTARTは承認済案をhelperfinal後に通常登録。Windows等の原未達を保持し未確定値を捏造しない。"
"selection_status": "P28-01-COLLECTOR正式9/9、実db9d613全9測定、RESTART Q3ac2ced正式8/8完了。現在は原P28-01 whole-unit証拠ゲートを1件閉じる。",
"pending_decisions": "実Opus266のwhole-unit草案を原条件・証拠と照合し通常登録。G3適用判断は別Opusレビュー。未回答ゲーム仕様は確定しない。"
},
"historical_regression_before_P08_02_formal_closure": {
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p23-02-final-candidate-r32-combined-root-acceptance-r01.json",
@@ -10722,40 +10738,24 @@
"whole_goal_accepted": false
},
"current_workflow_handoff": {
"project": "the-tree-p06-02-audit-astra",
"task": "P06-02-AUDIT-CONTINUE",
"controller_title": "ゲーム開発作業",
"controller_local_session": "local_a7f85421-3eed-4482-8030-c0dca669573a",
"actual_model": "Opus5.5 medium",
"desktop_read_write_roundtrip_verified": true,
"project": "the-tree-p28-01-restart",
"task": "P28-01-RESTART",
"state": "completed",
"submission": "3084add460e0fe0b6b32ae4396c9f698c81e0358",
"candidate": "e53858a55cff5a8035c71fd799c02c7e75c0a5dd",
"original_completed": 17,
"submission": "954528a7c5a0e27e2e50b642373168fa0a550aba",
"candidate": "3ac2cedc8dc977778fd5a3ba152197cc6cf00fa2",
"evidence": {
"path": "docs/plans/original-completion-2026-10-02/execution/p28-01/RESTART_FORMAL_COMPLETION_3AC2CED.json",
"bytes": 6366,
"sha256": "5c9b82a70f6bdb972d720aaa64f5d27aa54130f27f9d1f7cea1c7b02524f84be"
},
"helper_credit": 0,
"original_completed": 22,
"original_total": 88,
"audit_credit": 0,
"controller_title": "The Tree 開発管制",
"controller_local_session": "local_16f7c88b-81d7-4a43-ad0d-b9c00aa6d6a5",
"desktop_read_roundtrip": true,
"desktop_prepare_job": "e447020934ba4bcb89c03f925635a2ae",
"desktop_integrate": "auto mode denied before launch",
"root_integrate_job": "e19be36c0d6247e98e85262300e95a75",
"evidence": [
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-controller-handoff-20261019/9c611769a9b14537b640c7f05edd43cc-validation.json",
"sha256": "74c6cd065997be5aaac9cdb72ce48c1ad417757f0c482a8fecec1278c44143f1"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-controller-handoff-20261019/d4918e5d32d34052b552a6ab21bb2a0b-result.json",
"sha256": "41254556695ad2763d7f596586e51d2d741d3dc05003283928cdd3a163078cda"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-controller-handoff-20261019/2ab8fcedb7cf4467895b62fa14cc62ad-integration.json",
"sha256": "111c4db9f841a5122329f5c48f6391816513bad45619fe87751be221182b35fb"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-controller-handoff-20261019/0ec6d584092f4d6995a8120e0a29c2b0-final.json",
"sha256": "958817589cdba9c145e7c71f1c1230625bcfe6eea3616cdb55963f14281c2f31"
}
],
"remaining": "P06 whole-unit gameplay acceptance, unapproved production mana policy, P14 warp dependency and all recorded cross-cutting conditions remain open",
"next": "Persistent Claude Desktop controller decides next original P06 acceptance batch from completed audit; Root maintains approvals/ledger. No duplicate temporary commander."
"next": "the-tree-p28-01-gate/P28-01-GATE; actual Desktop266 draft; not registered yet"
},
"historical_workflow_before_desktop_handoff_20261019": {
"source_thread": "01a14f6a-b6a1-7fd3-bd45-0f84bbef77be",
@@ -10929,7 +10929,7 @@
"both_budget_passed": false,
"full9_measurement": false
},
"next": "Same actual repair7handle then newS formal/native/independentall8review and normalintegration/final; originalwholeunitgate233 follows only afterwards",
"next": "原P28-01 whole-unitゲートを実Opus草案から照合・登録し、証拠検証→独立レビュー→通常統合final→台帳まで閉じる。",
"same_Windows_verified": false,
"full9_measurement": {
"actual_commit": "db9d6132a8349928560dc4a4a99306d27a81e332",
@@ -10945,6 +10945,48 @@
"GPU_unavailable": true
},
"restart": {
"project": "the-tree-p28-01-restart",
"task": "P28-01-RESTART",
"state": "completed",
"submitted": "954528a7c5a0e27e2e50b642373168fa0a550aba",
"candidate": "3ac2cedc8dc977778fd5a3ba152197cc6cf00fa2",
"main_base": "3086af2ccd970ddee271a184214dad037bd1d6af",
"repairs": 8,
"acceptance_completed": 8,
"acceptance_total": 8,
"all4_normal_gates_passed": true,
"completion_proof": {
"path": "docs/plans/original-completion-2026-10-02/execution/p28-01/RESTART_FORMAL_COMPLETION_3AC2CED.json",
"bytes": 6366,
"sha256": "5c9b82a70f6bdb972d720aaa64f5d27aa54130f27f9d1f7cea1c7b02524f84be"
},
"native_root_join": {
"path": "artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/native-restart-954528a-r01/ROOT_RAW_ACCEPTANCE_JOIN.json",
"bytes": 70643,
"sha256": "6dbb3cbb4ac1838b66034323cab22a9c5a968c1da0efe8d34676073b3f980cfb"
},
"candidate_qualification": {
"path": "artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/ROOT_CANDIDATE_3AC2CED_QUALIFICATION.json",
"bytes": 235149,
"sha256": "5bd8030acddc385eb728441286f6a740ec1ee966125474b60ef4b1efe2a2c343"
},
"independent_reviewer_session": "local_251adf7f-dd2e-4726-9141-fff58a45eb14",
"independent_review_sha256": "b8fff13e8789797a4a50a5e2900f3d84ef20a6682a8f25feca225edc7fe00300",
"high_medium": 0,
"low": 3,
"receiver900_failure_retained": true,
"new_review_inference_on_rejoin": false,
"CLI_auth_recovered": false,
"implementation_model": "gpt-6-astra",
"review_model": "claude-opus-5-5",
"original_credit": 0,
"remaining": [
"原P28-01のwork/acceptance/横断6を保持するwhole-unit証拠ゲート(実Opus266草案を照合中)・独立Opusレビュー・通常prepare/Root委任候補承認/integration/final・台帳。engine/full9/192の重複実行なし。",
"G3の非0backlog未発生とprivate accumulator非保存の適用判断を理由付きで独立レビュー。開示のみで再現証明へ補完しない。",
"予算未達4件はP28-02/03に保持、200客OpsON未検証・GPU null理由・同一Windows・長期操作感・全ゲーム最終受入は未達。"
]
},
"historical_restart_before_formal_3ac2ced": {
"project": "the-tree-p28-01-restart",
"task": "P28-01-RESTART",
"base": "2132bbe3d39a0f1b69a97c731bb09213bf9d7a91",
@@ -11240,5 +11282,41 @@
"Normalprepare/exactQRootdelegatedapproval/integration/final",
"OriginalP28-01wholeunitgate9 sameoriginalconditions/independentreview/final/ledger beforecredit"
]
},
"historical_workflow_handoff_before_P28_01_restart_completion": {
"project": "the-tree-p06-02-audit-astra",
"task": "P06-02-AUDIT-CONTINUE",
"state": "completed",
"submission": "3084add460e0fe0b6b32ae4396c9f698c81e0358",
"candidate": "e53858a55cff5a8035c71fd799c02c7e75c0a5dd",
"original_completed": 17,
"original_total": 88,
"audit_credit": 0,
"controller_title": "The Tree 開発管制",
"controller_local_session": "local_16f7c88b-81d7-4a43-ad0d-b9c00aa6d6a5",
"desktop_read_roundtrip": true,
"desktop_prepare_job": "e447020934ba4bcb89c03f925635a2ae",
"desktop_integrate": "auto mode denied before launch",
"root_integrate_job": "e19be36c0d6247e98e85262300e95a75",
"evidence": [
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-controller-handoff-20261019/9c611769a9b14537b640c7f05edd43cc-validation.json",
"sha256": "74c6cd065997be5aaac9cdb72ce48c1ad417757f0c482a8fecec1278c44143f1"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-controller-handoff-20261019/d4918e5d32d34052b552a6ab21bb2a0b-result.json",
"sha256": "41254556695ad2763d7f596586e51d2d741d3dc05003283928cdd3a163078cda"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-controller-handoff-20261019/2ab8fcedb7cf4467895b62fa14cc62ad-integration.json",
"sha256": "111c4db9f841a5122329f5c48f6391816513bad45619fe87751be221182b35fb"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-controller-handoff-20261019/0ec6d584092f4d6995a8120e0a29c2b0-final.json",
"sha256": "958817589cdba9c145e7c71f1c1230625bcfe6eea3616cdb55963f14281c2f31"
}
],
"remaining": "P06 whole-unit gameplay acceptance, unapproved production mana policy, P14 warp dependency and all recorded cross-cutting conditions remain open",
"next": "Persistent Claude Desktop controller decides next original P06 acceptance batch from completed audit; Root maintains approvals/ledger. No duplicate temporary commander."
}
}
@@ -18066,7 +18066,7 @@
},
"legacy_state": "planned",
"state_scope": "package-level; completed means whole package accepted; partial implementation is not completion",
"current_summary": "P28-01 collector補助9/9は全4正式ゲート完了。実main db9d613の正規全9測定が正常終了し、R/O x1/x3・描画CPU/提出・機種/build/seed/区間/平均P95最大を取得。原条件の保存再開は別PID RESTARTを実装中(Opus判断/Astra、8AC未受入)。原22/88・4/30を維持。代表Rのx1/x3/stall予算、GPU取得、200客OpsON、同一Windows/長期/全ゲーム受入は未達を保持。",
"current_summary": "P28-01 collector補助9/9とRESTART補助8/8が全4通常ゲートで正式完了。実db9d613全9測定とS954528a別PID保存再開の全rawを保持し、Q3ac2cedの製品1407/collector4/probe4への適用を実照合。原P28-01はwork/acceptance/横断6の最終証拠ゲートと独立whole-unitレビュー・通常final・台帳が残るため未完、原22/88・4/30・部分点なし。予算未達/200客OpsON/GPU null/同一Windows/長期は別未達を保持。",
"remaining_deliverables": [
{
"id": "P28-01",
@@ -18167,17 +18167,34 @@
"scope": "S954528a正式24PASS/native7 in progress and exact prior failure diagnosis; no game acceptance",
"linked_at_jst": "2026-10-21T03:59:44.437107+09:00",
"current_game_acceptance_inferred": false
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p28-01/RESTART_FORMAL_COMPLETION_3AC2CED.json",
"bytes": 6366,
"sha256": "5c9b82a70f6bdb972d720aaa64f5d27aa54130f27f9d1f7cea1c7b02524f84be",
"scope": "RESTART補助成果のみ8/8正式完了、原P28-01加算0",
"linked_at_jst": "2026-10-21T04:37:36.598744+09:00"
},
{
"path": "artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/native-restart-954528a-r01/ROOT_RAW_ACCEPTANCE_JOIN.json",
"bytes": 70643,
"sha256": "6dbb3cbb4ac1838b66034323cab22a9c5a968c1da0efe8d34676073b3f980cfb",
"scope": "S954528a実native7全raw243照合、原whole-unitレビュー前"
},
{
"path": "artifacts/original-completion-2026-10-02/p28-01-runner-preflight-r01/ROOT_CANDIDATE_3AC2CED_QUALIFICATION.json",
"bytes": 235149,
"sha256": "5bd8030acddc385eb728441286f6a740ec1ee966125474b60ef4b1efe2a2c343",
"scope": "Q3ac2cedの製品1407/probe4/実nativeとfull9適用範囲照合"
}
],
"updated_at_jst": "2026-10-21T03:59:44.437107+09:00",
"progress_summary": "実db9d613で正規9phase import/parse2/R0/P1/P2/O0/P3/P4完走、全9ownedPID終了・native診断/cleanup0・source1407/collector4/通常player保全。Root160 raw/source/PID/profile結合PASS。R登録20,000マス/200客/50職員/150施設(稼働100施設)、P1はwarm30+測定120、P2は実warm31+測定120。P1 kernel平均479210us対4000、P2 x3P95 5062697us対12000、stall最大4809099/5891466us対50000でfalse。Oは通常開始50マス/客0..2/職員0/施設0の適用範囲だけ。長区間CPU描画を取得(P1平均3.68465ms/P2平均5.36198ms)、GPUはnullと理由。経路/snapshot/保存読込はSHA束縛済r02を限定再利用。独立Opus管制は測定情報充足を実読確認。RESTART旧bc703c9独立H1/M2/L2と5E parse失敗を保全。e524ff2正式21PASS/native Owriter raw/canonicalSHA失敗、実型diagnosticでStringName keys.sort非文字順を確定(数値書式一致)。実Desktop Opus249/253指示で同Astra repair8 S954528aを3ファイル最小修正、正式24test5.429sPASS。実Opus257が全rawと差分を読み、正確Sの登録native7をRootexec34944で開始。全raw/source/PID/sidecar結合、独立all8review、通常integration/final、原wholeunit受入前の加算0。",
"updated_at_jst": "2026-10-21T04:37:36.598744+09:00",
"progress_summary": "P28-01 collector補助9/9とRESTART補助8/8が全4通常ゲートで正式完了。実db9d613全9測定とS954528a別PID保存再開の全rawを保持し、Q3ac2cedの製品1407/collector4/probe4への適用を実照合。原P28-01はwork/acceptance/横断6の最終証拠ゲートと独立whole-unitレビュー・通常final・台帳が残るため未完、原22/88・4/30・部分点なし。予算未達/200客OpsON/GPU null/同一Windows/長期は別未達を保持。 正式24試験を保持、native R/O K30全状態typed一致・改ざん拒否・実arrival390分16件ID9〜24連番。非0backlog未実施/private accumulator非保存は非主張、独立low3保持。旧bc703c9/5E/e524失敗・受信900秒失敗は失敗のまま。",
"historical_progress_summary_before_20261020": "現1273へPath micro軽量化を限定採用。53 whole typed pairs/120同一呼出return比較と全168回帰を確認。最大Runtime混合負荷/Operations enabled/Windows性能は未受入。旧900秒timeout/未測定値を維持。\n【限定採用前の証拠時点の履歴】\n実Runtime最大負荷診断は準備BUILDで900.024秒timeout(-15)。目標実数/保存/別process/計測に未到達。setup span候補を準備し原因特定を継続。 setup区間観測の別実行も900.018秒timeout。429→430分の公開tickは268.723秒、601→602分は未完。内部hotspot・最終target数・保存・性能測定は未確定。 現1237 counter r04もBUILD900.07856秒timeout(-9)、430CONSTRUCTION268.326934秒。inclusive Path累積は重複合算/差引禁止、602LOGISTICS未閉・最終測定null。",
"remaining_gaps": [
"S954528a正式24PASS、native7実行中。完走後Root全raw/source/player/PID/fullsidecar照合、独立Opus全8review、通常integration/final必須。全て同一Sに束縛し、旧失敗を合格へ補完しない。",
"上記5指摘を含め正式UI保存/別PID厳格読込/全状態IO差分限定/K30継続/改ざん原子的拒否/実Ops arrival境界を正確最終Sで受入",
"原P28-01 work/acceptance/横断6条件の証拠ゲート・whole-unit独立レビュー・final・台帳",
"性能予算未達をP28/P28-02に保持:P1 x1mean479.210ms>4ms・stallmax4809.099ms>50ms、P2 x3P955062.697ms>12ms・stallmax5891.466ms>50ms",
"200客Operations ONは未検証(通常Oは客0..2)、GPU時間はnullと理由を保持。同一Windows/長期操作感/バランス/全ゲーム最終受入は未達"
"原P28-01のwork/acceptance/横断6を保持するwhole-unit証拠ゲート(実Opus266草案を照合中)・独立Opusレビュー・通常prepare/Root委任候補承認/integration/final・台帳。engine/full9/192の重複実行なし。",
"G3の非0backlog未発生とprivate accumulator非保存の適用判断を理由付きで独立レビュー。開示のみで再現証明へ補完しない。",
"予算未達4件はP28-02/03に保持、200客OpsON未検証・GPU null理由・同一Windows・長期操作感・全ゲーム最終受入は未達。"
],
"historical_summary_before_integrated_full9_20261021": "r02のheadless/OpsOFF/x1/300分、代表20,000マス/200客/50職員/150施設の既存証拠は対象区間を限定して再利用する(外側advance wall826.6msをKernel4ms予算へ比較しない)。新collectorはS5db97d7を独立Opus全9PASS、高/中0・low3記録、Q0f53a67で通常integration/finalまで完了した。新37合成試験は構造検証、実fresh R0は602→612分/4PID正常終了/Guard・audio・source/player保全を確認し、別31チェックで原rawを照合。実Kernel標本10件からx1平均379427us対4000us、stall最大466395us対50000usでfalseを記録した。これは事前診断で本測定ではない。全R/O・x1/x3・描画/区間/統計と別PID保存再開・原全条件の証拠/独立レビュー/受入まで原成果を完了扱いにしない。"
},
@@ -18513,7 +18530,7 @@
],
"cross_cutting_acceptance_scope": "Completion requirements only, not achieved results. Apply each to relevant slices; non-applicable views require a recorded reason.",
"initial_revision_state": "in_progress",
"updated_at_jst": "2026-10-21T00:28:26.609424+09:00",
"updated_at_jst": "2026-10-21T04:37:36.598744+09:00",
"execution_progress": {
"current1277_checkpoint": {
"source_files": 1273,