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

This commit is contained in:
Agent Control Runner
2026-10-18 10:58:54 +09:00
parent 2dde7596a8
commit 20d0ae5990
32 changed files with 11890 additions and 314 deletions
@@ -1,4 +1,12 @@
# Current checker protocol — repair29
# Checker protocol — historical repair29 description
Repair30 is a partial, blocked implementation. CURRENT_STATUS.md and
REPAIR30_STATUS.md supersede the current-role, authority and execution claims
below. M is c0ea009; product manifests exclude checker, selected native/full
SourceRefs include it. Q is the actual recomputed merge-tree; C requires separate
normal-integration qualification. All four remaining D05 policies are approved.
Do not run the old collection/index recipe as fresh-Q evidence. No 500000-byte
limit applies. The historical protocol text below is retained for provenance.
Worker **SOURCE-READY / NOTRUN**. [CURRENT_STATUS.md](CURRENT_STATUS.md) is canonical for execution facts; creation-time NOT RUN in REPAIR22–28 and runbooks is historical. [ORDER_AUDIT.md](ORDER_AUDIT.md) and order-audit.json give the eleven-phase/seven-domain audit. [D05_REMAINING_ORDER_CANDIDATE.md](D05_REMAINING_ORDER_CANDIDATE.md) is approval material only.
@@ -1,31 +1,29 @@
# P04-01 current status — repair29
# P04-01 current status — repair31
Worker checks: SOURCE-READY / NOTRUN. No probes or tests were run by this worker.
**BLOCKED: partial implementation; do not start the once-only native/full run.**
Formal completed status is **16/88**, with **zero P04 credit**.
This canonical table overrides creation-time NOT RUN / pending-execution entries in REPAIR22–28, their status/validation records, and the runbooks (including S4_ROOT_RUN.md). Those files are historical and remain untouched. It does not relabel an old run as execution of repair29.
D05 is six of six actually approved; adoption and exact-Q verification are pending.
All four later D05 policies were approved by the actual human on 2026-10-18.
D05_REMAINING_APPROVAL.json preserves exact answers and binds both supplied
records by path/SHA256. Dependency hold, 18:00 and A01 upkeep remain approved.
The old candidates are superseded, not deleted.
`B` = `/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build`.
Frozen M is c0ea009b28a7649aca6a433a1a24dc0be5e7ab81. Actual tree enumeration
found 1368 product files excluding the checker and 3644 metadata paths.
Native/full selected SourceRefs must additionally include the checker.
Final S, genuine non-production Q and later normal C are not supplied by this
worker. No Git writes, engine execution, Runner operations or delegation.
| Item | Canonical status | Exact-version evidence |
| --- | --- | --- |
| Current native product / main | Root-measured `5f6bc11d` / `9b1a18c1` | Product1338 at B/audit-support/p04-r17-full-inputs-r01/product; current SHA256 inventory in REPAIR29_STATIC_SOURCE.json. Old deb11300 is not current. |
| S4 r28 | Root-measured 4/4 PASS; import/parse/Writer/Reader PIDs49940,50044,50078,50105 all ended; guards0; cleanup0 | B/p04-s4-native-r28; B/audit-support/p04-root-fb8b-s4-r01/native.result.json. Full controls in that same support directory. |
| Local8 | Root-measured PASS | B/audit-support/p04-root-fb8b-local-r01: bulk, negative, applicability, native, series, encoder, join, roles result/stdio records. |
| Collection | Root-measured r22 collected, no native re-run claimed | B/audit-support/p04-raw-collect-r22/MANIFEST.json and s1/s2a/s2b/s3/s4.json. |
| Index | Root-measured schema2, missing_conditions=[], all15 conditions + EV mechanically verified | B/p04-evidence/index.json and generation-invocation.json; local-r01 index/checker output. This is not D05 approval. |
| Registered validation on fb8b7919 | Root-measured PASS,28.095s | B/audit-support/p04-root-fb8b-local-r01/registered-validation.result.json and stdout log. Does not establish final repair29 validation or acceptance. |
| Full178 | Root-measured178 suites /21615 checks PASS used checker f5, **not a61** | B/audit-support/p18-regression-support-final-r01/native-full178/runner-ended.json and source-start.json; exact receipt remains preserved. Checker f5 SHA256 `f5b44827958f2ae352fe5c4bc3a1ffd4211ec7a41fc4c0759c8b954891662324`. |
| Full1339 against a61 | **No such full run exists** | a61 SHA256 `a61c5b496e656f60c66898e42500bc9a2d45f947690ce8f5f19a03984ebbc850`. Local8 and registered validation are separate evidence. |
| Worker repair29 | SOURCE-READY / NOTRUN | Static source/line/registration/SHA256 inspection only. No tests, probes, Git, engine, Runner or agents. |
| Owner D05 | Pending a–d, candidate only | D05_REMAINING_ORDER_CANDIDATE.md/json; A01, dependency hold and18:00 remain approved. |
| Original unit | **Incomplete;13/88 unchanged** | Mechanical PASS does not approve unknown mandatory priorities, replace independent review, or integrate the unit. |
The checker has partial authority/role corrections; the seven-domain audit uses
M source. S5 executable probes, fresh-Q collector/wrapper/index plumbing,
full-proof joins and independent normal-C qualification remain incomplete.
Normal C now fails closed without the authoritative Root/Runner receipt contract.
The isolated Git fixtures remain Root-run because `/tmp` creation was denied.
See [REPAIR31_STATUS.md](REPAIR31_STATUS.md) for precise remaining work and the
corrected Root execution order; [s5/PENDING.md](s5/PENDING.md) records S5 gaps.
Proof hashes for the exact collection/index/full receipt/validation and current source are in [REPAIR29_STATIC_SOURCE.json](REPAIR29_STATIC_SOURCE.json). Applicable source/config/input/environment joins stay in the immutable schema2 index and raw collection; no raw is normalized, spliced, regenerated or relabelled here.
Product reuse requires exact applicability: the178 suites do not execute the Python checker and the316-file GDScript parse roster excludes it. Static comparison with the preserved full178 selected_source_map found one test-source difference, tests/business/test_required_kitchen.gd (full178 3a9c92f8…, current product5dcc86d6…), and no game-source difference. Preserve the Runner applicability binding for this test; do not claim all1338 selected product hashes match that full178 receipt or byte-identical full1339 validation against a61. Preserve the f5 full178 receipt and all historical partial/full outputs separately.
Remaining Runner steps: independent review of these documents, then Root obtains owner decisions (or explicit non-mandatory rulings) for D05 a–d. Unknown mandatory rules stay pending. Any destruction authority pin/registry or other approved implementation change follows a normal repair. The support53cb normal registered rebind, final full run on the final source/checker, final source/config/input/environment binding, formal independent review and integration remain Runner work. Integration order is **P04 first, then support on main9b (`9b1a18c1`)**. NativeWindows obligations remain individually pending if required. No criterion is waived and no extra original unit is counted.
Known authority/scope gaps: destruction_stop binds BASELINE:183 (mana depletion, not destruction); explicit D05 destruction rule required before normal pin repair. S4 NO_POWER was induced by direct disconnect_nodes; global depletion appears only in B1 combined diagnostic. Preserve these distinctions even though the mechanical index passes.
Changed files in repair29 (all under this directory): ORDER_AUDIT.md; order-audit.json; D05_REMAINING_ORDER_CANDIDATE.md; D05_REMAINING_ORDER_CANDIDATE.json; CHECKER_PROTOCOL.md; EVIDENCE_COLLECTION.md; P04_ORDER_EVIDENCE_PROTOCOL.json; CURRENT_STATUS.md; REPAIR29_STATIC_SOURCE.json. Product/checker/registry, native footprint, staged inputs, raw and historical runbooks are unchanged.
Historical S1–S4/r22, old registered validation and f5 full178 retain their
original identities. They are not fresh Q evidence. All 15 conditions plus EV
still require exact-version evidence; nativeWindows remains individually
pending. Static fixture results confer no original acceptance credit.
@@ -0,0 +1,53 @@
{
"task_id": "P04-01",
"origin": "direct_user_reply",
"formal_acceptance": false,
"source_bindings": [
{
"path": "build/owner-handoff/p04-after-p26-closure-r01/D05_ACTUAL_HUMAN_APPROVAL.json",
"sha256": "cd365ded1b777a0327d090709f0a4161f5005562819183455d9f2e106fba3e96"
},
{
"commit": "c0ea009b28a7649aca6a433a1a24dc0be5e7ab81",
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01-owner-approval-20261018/D05_ACTUAL_HUMAN_APPROVAL.json",
"sha256": "cd365ded1b777a0327d090709f0a4161f5005562819183455d9f2e106fba3e96"
}
],
"approved_choices": [
{
"id": "D05-P04-DESTRUCTION",
"source_id": "destruction_completion_order",
"answer_exact": "現行順序を承認する(Opus推奨)",
"approved_question_policy": "コマンド破壊をサービス完了前に処理。事故・襲撃による破壊は完了・課金後に処理してその分の売上を有効とし、次の分で失敗処理と予約解放。"
},
{
"id": "D05-P04-MIDNIGHT-DAY",
"source_id": "midnight_revenue_day",
"answer_exact": "新しい日に計上し、前日決算・維持費を完了より先に確定する(Opus推奨・現状維持)",
"approved_question_policy": "00:00完了のサービス売上は新しい日に計上。前日決算・維持費は完了より先に確定。既承認の維持費規則と18:00交代順序を維持。"
},
{
"id": "D05-P04-PAUSE-REASON",
"source_id": "pause_reason_priority",
"answer_exact": "2点とも現行動作を確定する(Opus推奨)",
"approved_question_policy": "停電と依存先休業が同時なら休業を理由表示の優先とする。どちらも進捗・課金停止、予約保持。"
},
{
"id": "D05-P04-EXIT",
"source_id": "exit_command_ai_order",
"answer_exact": "2点とも現行動作を確定する(Opus推奨)",
"approved_question_policy": "退出コマンドは完了前、AIの予定退出は判断中の客だけを対象として完了後に処理。"
}
],
"prior_approved_rules_preserved": [
"依存先休業中は進捗・課金停止、予約保持、復帰後1回だけ完了",
"17:59→18:00昼番作業を先に確定し完了・課金後に交代",
"既承認維持費規則"
],
"supersedes": [
"D05_REMAINING_ORDER_CANDIDATE.md",
"D05_REMAINING_ORDER_CANDIDATE.json"
],
"original_unit_complete": false
}
@@ -1,8 +1,8 @@
{
"task_id": "P04-01",
"revision": "repair29",
"status": "approval candidate only; SOURCE-READY / NOTRUN",
"approval": null,
"status": "superseded by D05_REMAINING_APPROVAL.json; candidate text below is historical",
"approval": "D05_REMAINING_APPROVAL.json",
"apply_to_product_or_checker": false,
"review_flow": "Root asks owner after review. This document neither requests approval from worker nor records it.",
"proof_legend": {
@@ -126,5 +126,6 @@
},
"authority_gap": "destruction_stop currently binds BASELINE:183, which is mana depletion, not destruction authority. Explicit D05 destruction rule required. Pin/registry repair only after approval through normal repair.",
"power_scope": "S4 NO_POWER uses direct disconnect_nodes; not proof of global depletion, which exists only in B1 combined diagnostic.",
"original_unit_complete": false
"original_unit_complete": false,
"superseded_by": "D05_REMAINING_APPROVAL.json"
}
@@ -1,3 +1,5 @@
> Superseded: D05_REMAINING_APPROVAL.json records the actual human approval of all four policies. The candidate text below is retained as history.
# D05 remaining order candidate — repair29
**Approval candidate only. SOURCE-READY / NOTRUN.** Root asks the owner after review. Nothing is applied to product, checker or registry; observation is not approval. A01 midnight ownership upkeep, dependency hold and18:00 are already approved and are not re-asked.
@@ -1,4 +1,9 @@
# Evidence collection status — repair29
# Evidence collection — historical repair29 description
Repair30 supersedes current-use claims below: existing S1–S4/r22/full178 records
remain historical. New Q evidence is required, with checker explicitly selected.
The fresh-Q collection path and S5 drivers are not ready in this partial repair.
See REPAIR30_STATUS.md; do not start native/full or formal acceptance yet.
Worker **SOURCE-READY / NOTRUN** (static Read/SHA256 only). No probes, tests, engine or Runner execution in this repair. [CURRENT_STATUS.md](CURRENT_STATUS.md) overrides historical creation-time NOT RUN entries in REPAIR22–28 and runbooks, which remain untouched. Do not repeat their completed execution steps merely because their original prose says pending.
@@ -0,0 +1,33 @@
# Concrete32 external Runner-record boundary
The supplied normal-gate reference was read directly: verify, has_evidence,
prepare_integration, approve and integrate (893–1092), and the SQL schema
(474–483). P26 normal-candidate-example files are format samples only.
`normal_c_join.py` uses read-only SQLite transactions over actual Root-selected
Runner records. It joins submitted S, candidate C, frozen main_base M, approval,
validation/review on S and integration/final on C. It checks the exact validation
roster, raw review result and referenced validation logs, and hashes evidence
inputs and the logical record snapshot. Root must establish that both databases
are actual Runner records: arbitrary SQLite files cannot authenticate themselves.
Runner integrate deletes approvals after final verification. Root retains an
actual consistent Runner snapshot after approve, supplied as
`--approved-runner-db`; `--runner-db` supplies later final evidence. These are
read-only inputs, not a new Runner API. The worker creates neither snapshot.
Missing records fail. No Git, Runner or engine is invoked. Outputs confer no
acceptance or Git/Q/source/settings/markers/policy/engine/input qualification.
All partial31 files, including the existing checker, remain unchanged as directed.
Its NORMAL_C_RECEIPT_CONTRACT fail-closed path therefore still blocks formal C
qualification. This new join is not wired into that gate and cannot bypass it.
Integration of the boundary remains an implementation gap. No actual Q/C or
ordinary-gate proof was produced. This is not a new human D05 policy question.
Root runs `normal_c_join_fixtures.py --scratch DIR`: synthetic positive, wrong
C/M, missing kind, failed check, extra/missing validation ID, task mismatch,
medium review, missing artifact, wrong approval and missing final. Unexecuted.
`scratch_fixture_adapter.py --scratch DIR --fixture NAME -- ...` routes preserved
fixture TemporaryDirectory calls to explicit external scratch and clears inherited
GIT_* routing. Existing assertions are unchanged; candidate/role fixtures still
exercise partial31 semantics. No fixture output belongs in source.
@@ -1,61 +1,28 @@
# P04-01 order audit — repair29
# P04-01 order audit — repair31
Worker **SOURCE-READY / NOTRUN**: static Read and SHA256 only. No original completion. [CURRENT_STATUS.md](CURRENT_STATUS.md) is canonical for execution status. [order-audit.json](order-audit.json) is the matching structured audit.
Formal status is **16/88, P04 credit 0**. Policy approvals are recorded; implementation and exact-Q evidence remain incomplete. No original-unit completion is claimed.
B = `/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build`.
P = `B/audit-support/p04-r17-full-inputs-r01/product`. Source references below are relative to P, not old deb11300. All1338 product file SHA256 values, function lines and16 handler registrations are recomputed in [REPAIR29_STATIC_SOURCE.json](REPAIR29_STATIC_SOURCE.json).
Kernel `scripts/core/simulation_kernel.gd` SHA256: `341c0c878c4894adbac628d0db6362ff69fc3347bdd9e61e50936e15dc2d1edb`.
Runtime `autoload/simulation_runtime.gd` SHA256: `7f01b2dcdf28bc965c7588173c2dc70054633faf7204b1ac38ba0f4369331b47`.
Root-measured native product `5f6bc11d`; main `9b1a18c1`.
D05 is **six of six actually approved**; adoption into raw enforcement and
verification are pending. Normal-C qualification now rejects matching-parent/tree
commits without the authoritative Root/Runner receipt contract. That contract's
path, SHA256 and provenance verification remain a concrete context gap.
## Actual eleven phases — observed-current
M is `c0ea009b28a7649aca6a433a1a24dc0be5e7ab81`. Source hashes, full product inventory, metadata membership and function line numbers were read from its actual Git tree in [REPAIR30_SOURCE_FACTS.json](REPAIR30_SOURCE_FACTS.json). Product manifest excludes the checker; native/full selected SourceRefs must include it. Q and C do not yet exist for this worker revision.
Kernel advance_one_minute:122 defines the order; _run_phase:236 string-sorts handler IDs. Registrations below are Runtime lines366–435 plus operations:1766. Every literal ID begins `simulation_runtime.`. Observations do not approve D05.
The four actual human answers are preserved verbatim in [D05_REMAINING_APPROVAL.json](D05_REMAINING_APPROVAL.json), bound to both supplied copies by path and SHA256. Existing dependency, 18:00 and A01 approvals remain unchanged. The candidate documents are superseded history.
1. **APPLY_COMMANDS** — simulation_runtime.commands → _process_tick_commands (registration:369). Previous minute: commands → _process_tick_commands:5743. Operations gate requests current tick abort and returns before Clock changes; otherwise commands apply for minute+1.
| Domain | Approved rule | Current M source | Evidence |
| --- | --- | --- | --- |
| 閉店 | D-034 preserves started services on direct closure and releases waiting requests. Dependency closure stops progress and charging, retains reservations/service identity, and completes once after recovery. RELATED_FACILITY_INACTIVE wins over NO_POWER when both apply. | autoload/simulation_runtime.gd:5765 _process_tick_commands; scripts/facility/facility_service.gd:853 _prepare_service_for_tick; autoload/simulation_runtime.gd:12672 _release_closed_business_queues | Fresh Q pending; nativeWindows pending |
| 停電 | BASELINE:183 covers real mana depletion. Legitimately stopped service has no progress or charge and preserves reservations. D05-P04-PAUSE-REASON makes dependency closure the displayed reason when dependency closure and power loss coincide. | autoload/simulation_runtime.gd:10716 _advance_mana; scripts/facility/facility_service.gd:853 _prepare_service_for_tick | Fresh Q pending; nativeWindows pending |
| 破壊 | Command destruction precedes completion. Accident/raid destruction follows completion and charging in minute N; that sale remains valid. Failure and reservation release for affected unfinished service occurs in N+1. D05-P04-DESTRUCTION is the authority, not BASELINE:183. | autoload/simulation_runtime.gd:5765 _process_tick_commands; autoload/simulation_runtime.gd:8599 _advance_defense; autoload/simulation_runtime.gd:9826 _apply_defense_outcome_boundary; scripts/facility/facility_service.gd:853 _prepare_service_for_tick | Fresh Q pending; nativeWindows pending |
| 退出 | D-034 release safety remains. Command exit precedes completion; AI planned exit follows completion and only applies to a deciding guest. Later despawn is distinct. | autoload/simulation_runtime.gd:7575 _execute_leave_facility_queue; autoload/simulation_runtime.gd:8760 _advance_guest_ai_decisions | Fresh Q pending; nativeWindows pending |
| 課金 | Charge only completed service, once per idempotency key; retain original price snapshot and reservation/ledger joins. At 00:00 prior-day settlement and upkeep precede completion; the sale belongs to the new day. | autoload/simulation_runtime.gd:1876 _advance_facility_upkeep; autoload/simulation_runtime.gd:11817 _complete_service_transaction; autoload/simulation_runtime.gd:11833 _apply_service_transaction; scripts/operations/operations_coordinator.gd:1125 _process_daily_close | Fresh Q pending; nativeWindows pending |
| シフト交代 | Approved 18:00 order remains: completion and payment before handover. No renewal of prior approval. | autoload/simulation_runtime.gd:8504 _advance_facilities; autoload/simulation_runtime.gd:8680 _advance_staff_ai | Fresh Q pending; nativeWindows pending |
| 00:00決算 | A01 ownership-based upkeep is unchanged. Prior-day settlement/upkeep precede 00:00 service completion; its sale belongs to the new day. Replay/restore must not duplicate settlement. | scripts/core/simulation_kernel.gd:254 _handle_time_boundaries; autoload/simulation_runtime.gd:1919 _advance_operations_time; scripts/operations/operations_coordinator.gd:882 _process_minute_boundaries; scripts/operations/operations_coordinator.gd:1125 _process_daily_close | Fresh Q pending; nativeWindows pending |
2. **TIME_BOUNDARIES** — simulation_runtime.0_weather → _advance_weather (registration:366); simulation_runtime.a_upkeep → _advance_facility_upkeep (registration:368); simulation_runtime.operations → _advance_operations_time (registration:1766). After APPLY: absolute_minute += 1, _sync_calendar_fields, _handle_time_boundaries:254 emits settlement_requested(completed_day) then day_started at00:00, before TIME_BOUNDARIES handlers. Handler order: weather, upkeep, operations. Runtime upkeep:1855; operations:1898 → coordinator _process_minute_boundaries:882: 00:00 upkeep, daily close, 06:00 morning, demand, arrivals (conditional boundaries and early returns).
The preserved S1–S4, r22 index, old registered validation and f5 full178 run retain their historical identities. Current runtime deltas conservatively require fresh proof for all 15 conditions plus EV. A test count, approval record or byte-equal ordering function alone does not establish original acceptance. No thresholds or original unknown values are changed.
3. **MANA** — simulation_runtime.mana → _advance_mana (registration:379). Runtime _advance_mana:10694: proxy preflight → mana_network advance → mana_power_projection.apply → MANA_STATE_CHANGED events.
The eleven phases remain APPLY_COMMANDS, TIME_BOUNDARIES, MANA, CONSTRUCTION, LOGISTICS, FACILITY_COMPLETION, VITALS_AND_ENVIRONMENT, INCIDENTS_AND_EVENTS, FACILITY_QUEUES, AI_DECISIONS, PUBLISH_SNAPSHOT. See the structured audit for preserved phase analysis and the new source manifest for exact M references.
4. **CONSTRUCTION** — simulation_runtime.construction → _advance_construction (registration:384). Construction:8064 follows power and precedes logistics.
5. **LOGISTICS** — simulation_runtime.logistics → _advance_inventory_and_logistics (registration:389). Logistics:8472 precedes completion.
6. **FACILITY_COMPLETION** — simulation_runtime.facilities → _advance_facilities (registration:394). Runtime _advance_facilities:8482: facility_service.advance_one_minute then kitchen. FacilityService _prepare_service_for_tick:853 checks BROKEN, related_facility_operating (RELATED_FACILITY_INACTIVE), power_available (NO_POWER), staff grace. Only ACTIVE services advance (:569). _complete_service:895 → Runtime _complete_service_transaction:11769 → _apply_service_transaction:11785 posts SERVICE_SALE / SERVICE_CASH_SWEEP at the post-increment minute (:11826–11838).
7. **VITALS_AND_ENVIRONMENT** — simulation_runtime.guest_vitals → _advance_guest_vitals (registration:399). Guest vitals:8488 follows completion.
8. **INCIDENTS_AND_EVENTS** — simulation_runtime.authority_incidents → _advance_authority_incidents (registration:409); simulation_runtime.defense → _advance_defense (registration:414); simulation_runtime.relationship_events → _advance_relationship_events (registration:419). String-sorted authority_incidents:8551 → defense:8577 → relationship_events:8615; after completion/charging.
9. **FACILITY_QUEUES** — simulation_runtime.guest_queues → _advance_guest_queues (registration:404). _advance_guest_queues:8502 releases closed queues first (_release_closed_business_queues:12624); closed queues spend no patience (:8516–8517).
10. **AI_DECISIONS** — simulation_runtime.staff_ai → _advance_staff_ai (registration:424). _advance_staff_ai:8658: prune elevator waits, elevators, rescue, staff_service, prune waits, staff_commute (shift handover), staffing sync, cleaning, fatigue, rescue and staffing sync again, then _advance_guest_ai_decisions:8738. DECIDING PLANNED_EXIT → LEAVING; despawn occurs only on later minute (:8760–8762).
11. **PUBLISH_SNAPSHOT** — simulation_runtime.snapshot → _publish_snapshot (registration:374); simulation_runtime.zz_save_checkpoints → _process_save_checkpoints (registration:431). snapshot:12476 then zz_save_checkpoints:4514; persistence follows publication.
## Seven domains
Proofs below are **Root-measured**. R = B/audit-support/p04-raw-collect-r22; I = B/p04-evidence/index.json (schema2). I native_bundle/raw_references/versions/source_map/environment preserve exact C and series bindings. R/MANIFEST.json pins series bytes/SHA256 and relocation; each series retains raw provenance. REPAIR29_STATIC_SOURCE.json also pins R files and I. Source function paths/lines/hashes are in that static manifest.
| Domain | Status / authority | Phase and source function+line | Relative priority | Exact-version proof | Pending |
| --- | --- | --- | --- | --- | --- |
| 閉店 | approved; D-034, D05-P04-DEPENDENCY | APPLY_COMMANDS / FACILITY_COMPLETION / FACILITY_QUEUES: Runtime _process_tick_commands:5743; FacilityService _prepare_service_for_tick:853; Runtime _release_closed_business_queues:12624 | Command closure before completion; dependency hold during preparation; closed queue release after completion. | I native_bundle C; R/s2a.json; R/s3.json B1 | D05(a) simultaneous reason selection |
| 停電 | observed-current; BASELINE:183, P04-01 safety acceptance | MANA → FACILITY_COMPLETION: Runtime _advance_mana:10694; FacilityService _prepare_service_for_tick:853 | Projection before completion; RELATED chosen before NO_POWER. | R/s4.json; B/p04-s4-native-r28; R/s3.json B1 combined diagnostic | D05(a) |
| 破壊 | pending D05; P04-01 safety acceptance (original); explicit destruction rule pending D05 | APPLY_COMMANDS vs INCIDENTS_AND_EVENTS: Runtime _process_tick_commands:5743; _advance_defense:8577; _apply_defense_outcome_boundary:9804; FacilityService _prepare_service_for_tick:853 | Command destruction before completion; incident destruction after completion: B4a charges25G then destroys in same tick; B4b next-tick failure/release. | R/s3.json B4a/B4b | D05(b); BASELINE:183 is mana depletion, not destruction authority; destruction_stop registry correction only after approval |
| 退出 | pending D05; D-034, P04-01 safety acceptance | APPLY_COMMANDS vs AI_DECISIONS: Runtime _execute_leave_facility_queue:7553; _advance_guest_ai_decisions:8738 | Command exit before completion/charging; AI PLANNED_EXIT after them; despawn later. | R/s3.json B2a/B2b/B3 and B1 departure history | D05(c) |
| 課金 | pending D05; P04-01 safety acceptance, D05-P04-DEPENDENCY, D05-P04-SHIFT-1800 | TIME_BOUNDARIES → FACILITY_COMPLETION: Runtime _advance_facility_upkeep:1855; _complete_service_transaction:11769; _apply_service_transaction:11785; coordinator _process_daily_close:1125 | Upkeep/daily close before sale; post-increment sale timestamp, exclusive close period_end;00:00 sale belongs to new day. | I native_bundle C; R/s2a.json; R/s4.json | D05(d), beyond approved A01 and18:00; timing/attribution mandatory P04, numeric math D04/P05 separate |
| シフト交代 | approved; BASELINE:64, BASELINE:67, D05-P04-SHIFT-1800 | FACILITY_COMPLETION → AI_DECISIONS: Runtime _advance_facilities:8482; _advance_staff_ai:8658; StaffService advance_one_minute:700 | 18:00 completion/payment before shift handover; day staff [17:59,18:00), night [18:00,18:01). | I C first1080 sale joins; R/s2b.json no-night1081/overtime | Already approved; do not re-ask |
| 00:00決算 | approved; BASELINE:71, BASELINE:72, A01, D05-P04-DEPENDENCY | pre-TIME_BOUNDARIES signals → TIME_BOUNDARIES → FACILITY_COMPLETION: Kernel _handle_time_boundaries:254; Runtime _advance_operations_time:1898; coordinator _process_minute_boundaries:882; _process_daily_close:1125 | Midnight signals, then upkeep/close, then completion. | I C paused/formal; R/s2a.json nonzero payroll/upkeep, replay and typed restore | A01 approved ownership-based midnight upkeep not reopened; extra attribution D05(d) |
S4 proves isolated NO_POWER caused by the probe calling disconnect_nodes directly, not global mana depletion. Global depletion appears only in B1 combined diagnostic; B1 does not prove isolated power or approve priority. BASELINE:183 is mana depletion, not destruction authority. Current destruction_stop binding is therefore a known authority gap. Checker a61 and registry stay unchanged until approval and normal repair.
## Cross-cutting safety
- **No charge while paused NO_POWER or RELATED** — original; FACILITY_COMPLETION; FacilityService _prepare_service_for_tick:853, ACTIVE-only gate:569, _complete_service:895. Preparation before advance/completion/payment. Root-measured proof: R/s4.json isolated power; I C and R/s2a.json dependency hold.
- **Double-settlement idempotency** — original; TIME_BOUNDARIES; coordinator _process_daily_close:1125; _day_summaries replay:1127–1130; daily-close:N:1137. Before facility completion. Root-measured proof: I C; R/s2a.json same-boundary replay and separate-PID restore, unchanged accounting.
- **Orphan reservation release** — original; APPLY_COMMANDS / FACILITY_QUEUES; Runtime _execute_leave_facility_queue:7553 (release keys:7565–7569); _leave_guest_queue_boundary:9178; _release_closed_business_queues:12624; _release_closed_business_request:12642. Command release before completion; closed-queue release afterward; closed patience not spent. Root-measured proof: R/s3.json B2a/B2b/B3/B4b; I C; R/s2a.json reservation/service identity and restore.
A01 midnight ownership upkeep, dependency hold and18:00 are already approved; do not re-ask. Authority pins are in I/authority; D05_OWNER_APPROVAL.json approves only the two named D05 choices. Remaining candidate choices and their side effects are in [D05_REMAINING_ORDER_CANDIDATE.md](D05_REMAINING_ORDER_CANDIDATE.md). P04 timing/attribution remains mandatory and separate from D04/P05 numeric cost math. Unknown mandatory rules remain pending.
Original credit **13/88 unchanged**,15 conditions + EV, seven domains, three safety outcomes and30/88 denominator unchanged. P04 remains incomplete. Root execution history and remaining Runner steps are in CURRENT_STATUS.md.
See [CURRENT_STATUS.md](CURRENT_STATUS.md) and [REPAIR31_STATUS.md](REPAIR31_STATUS.md) before any Root execution.
@@ -0,0 +1,71 @@
{
"task_id": "P04-01",
"scope": "Worker static controls only; no engine/registered validation/acceptance",
"formal_acceptance": false,
"original_credit": 0,
"results": [
{
"check": "checker_approval_fixtures",
"status": "pass",
"positive": 6,
"negative": 24,
"scope": "path/hash/status + literal human answers"
},
{
"check": "checker_negative_fixtures",
"status": "pass"
},
{
"check": "checker_applicability_fixtures",
"status": "pass",
"M": "c0ea009b28a7649aca6a433a1a24dc0be5e7ab81",
"changed_function_units": 58
},
{
"check": "checker_native_fixtures",
"status": "pass",
"scope": "mutations of historical supplied raw; not a native engine run"
},
{
"check": "checker_series_fixtures",
"status": "pass",
"scope": "historical/synthetic controls"
},
{
"check": "checker_encoder_fixtures",
"status": "pass"
},
{
"check": "checker_join_fixtures",
"status": "pass",
"scope": "historical/synthetic controls"
},
{
"check": "bulk_reader_equivalence",
"status": "not_run",
"reason": "Contains git init/hash-object -w and isolated-object writes; worker Git writes prohibited"
},
{
"check": "checker_role_fixtures",
"status": "not_run",
"reason": "Contains clone/checkout/add/commit/merge/reset; worker Git writes prohibited; fresh Q index is also not available"
},
{
"check": "Python AST / top-level execution JSON",
"status": "pass"
},
{
"check": "git diff --check",
"status": "pass"
}
],
"exclusions": [
"No fresh-Q positive fixture claimed",
"No fake-normal-C qualification claimed",
"No S5 native execution",
"No full184/329",
"No p04-acceptance on current S"
],
"note": "Recorded fixture outcomes are not exact-version native proofs. Final comment/document edits do not alter executed fixture semantics. Final source is unqualified for native admission; see REPAIR30_STATUS.md."
}
@@ -0,0 +1,67 @@
# Repair 30 — BLOCKED / partial implementation
This revision is **not ready for Root native admission**. Formal status remains
**16/88, P04=0**. Outstanding items include unfinished implementation, not merely
the fresh evidence Root is expected to produce after submission.
Implemented within allowed_paths:
- Four actual human approvals, exact answer/policy text, both source paths and
SHA256 bindings; candidate documents marked superseded.
- Per-ID path/hash authority binding for six D05 IDs; required authority refs
corrected without changing the 15-condition + EV roster or thresholds.
- Frozen M is c0ea009b28a7649aca6a433a1a24dc0be5e7ab81. Counts/membership derive
from Git objects: 1368 product files excluding checker, 3644 metadata paths.
Ordering functions retain registered byte equality; applicability has 58
changed function units. Full details are in REPAIR30_SOURCE_FACTS.json.
- Q must equal the recomputed merge-tree object. A commit cannot impersonate Q.
C must have frozen M as first parent, legal S as second parent and the same
entire tree as Q. Selected native sources explicitly include the checker;
product equality continues to exclude it.
- Seven-domain audit refreshed with actual M hashes/function lines. All
condition-specific nativeWindows obligations remain pending.
Implementation/context gaps blocking readiness:
1. S5's four executable drivers and raw semantic adapters are **not written**.
s5/PENDING.md records concrete source constraints. Additional approved
destruction/day/pause-reason/exit measurements are not enforced from S5 raw
bytes yet. REQUIRED retains the existing safety metrics.
2. p04_native_series.py, collect_p04_native.py, S1–S4 wrappers and parts of the
schema2 builder still bind historical run names/manifests/raw pins. Connect
fresh Q material without replacing historical records or inventing future
hashes. The builder now reads tested revision from native provenance and
includes the checker, so the old bundle cannot satisfy the new role check.
3. Full184/329 runner-input has no source_before or QA_overrides, unlike native
QA inputs. It needs its own exact source/settings/markers/policy/engine/input
and ended-receipt join. The native input loop is not a full-proof verifier.
4. Parent/tree equality alone cannot establish normal prepare-integration
provenance: a synthetic commit can have identical parents/tree. The supplied
plan does not define the concrete normal-candidate qualification receipt,
path and hash contract. Independent qualification remains pending; no
invented Runner API or authority has been added.
5. Bulk and role fixtures perform Git writes, including temporary objects,
commits and merges. They were not run under the worker Git-write prohibition.
Updated role negatives are unexecuted; genuine fresh-Q positive and
fake-normal-C rejection remain unqualified.
Static results are in REPAIR30_STATIC_CHECKS.json. Historical/synthetic fixture
success is not new game evidence. No engine, formal registered gate, Runner
operation, Git write or other agent was invoked. Product/test-tree/Clock/values
remain unchanged.
Required Root order after remaining implementation is repaired:
1. All eight static controls plus role/applicability/approval negatives.
2. Genuine Q from final S and frozen M; fresh real native S1–S5 once.
3. Inspect free disk and verified CoW, then full184/329 once on the same final Q
including final checker; bind test_required_kitchen separately.
4. Truthful index from exact raw material.
5. Registered p04-acceptance on S with --verify-only.
6. Independent whole-unit review.
7. Normal prepare-integration/final on independently qualified C, equal to Q for
source/settings/markers/policy/engine/inputs.
Keep live Root records under .runtime while M is frozen. Old S1–S4/r22 and f5
full178 remain historical. No known-fail formal gate is a progress check.
No sources/evidence are removed for the obsolete 500000-byte cap.
@@ -0,0 +1,94 @@
{
"task_id": "P04-01",
"scope": "Worker static controls only; no native run or formal gate",
"formal_acceptance": false,
"original_credit": 0,
"results": [
{
"check": "checker_approval_fixtures",
"status": "pass",
"exit_code": 0,
"scope": "six positive and 24 negative authority controls"
},
{
"check": "checker_negative_fixtures",
"status": "pass",
"exit_code": 0,
"scope": "historical/synthetic control only; no fresh Q proof"
},
{
"check": "checker_applicability_fixtures",
"status": "pass",
"exit_code": 0,
"scope": "historical/synthetic control only; no fresh Q proof"
},
{
"check": "checker_native_fixtures",
"status": "pass",
"exit_code": 0,
"scope": "historical/synthetic control only; no fresh Q proof"
},
{
"check": "checker_series_fixtures",
"status": "pass",
"exit_code": 0,
"scope": "historical/synthetic control only; no fresh Q proof"
},
{
"check": "checker_encoder_fixtures",
"status": "pass",
"exit_code": 0,
"scope": "historical/synthetic control only; no fresh Q proof"
},
{
"check": "checker_join_fixtures",
"status": "pass",
"exit_code": 0,
"scope": "historical/synthetic control only; no fresh Q proof"
},
{
"check": "Python AST / execution JSON",
"status": "pass",
"python_files": 22,
"json_files": 17
},
{
"check": "git diff --check",
"status": "pass"
},
{
"check": "normal C fail-closed in-memory controls",
"status": "pass",
"cases": [
"missing authority contract rejected",
"caller-forged authority contract rejected"
],
"scope": "not a Git role fixture"
},
{
"check": "bulk_reader_equivalence",
"status": "blocked",
"exit_code": 1,
"reason": "/tmp directory creation raised PermissionError (Operation not permitted), before any Git invocation",
"execution": "fixture body unexecuted; Root-run"
},
{
"check": "checker_role_fixtures",
"status": "unexecuted",
"reason": "isolated temporary directory unavailable; fresh-Q evidence also unavailable; Root-run"
},
{
"check": "checker_candidate_fixtures",
"status": "unexecuted",
"reason": "isolated temporary directory unavailable; Root-run"
}
],
"exclusions": [
"S5 drivers and adapters not implemented",
"fresh-Q pipeline not implemented",
"full184/329 verifier not implemented",
"normal-C authoritative receipt path/hash/provenance contract not supplied",
"no genuine-Q or qualified-C positive claimed"
],
"note": "Existing REPAIR30_SOURCE_FACTS and REPAIR30_STATIC_CHECKS were reused without modification. Counts here describe static file parsing, not acceptance or runtime source membership."
}
@@ -0,0 +1,59 @@
# Repair 31 — BLOCKED / incomplete implementation
Formal status remains **16/88, P04 credit 0**. **Do not admit the once-only
native/full batch.** This revision does not finish BF35.
D05 is **six of six actually approved**. There is no policy question for the
human. Adoption into enforced raw evidence and exact-Q verification are pending.
A01 remains approved. The per-ID path/SHA256 bindings in the checker and the
superseded candidate documents are preserved. The authority fixtures exercise
positive, missing, wrong-hash, pending-status and wrong-path cases for every ID.
Repair30's SOURCE_FACTS and STATIC_CHECKS remain historical, unchanged inputs.
This repair adds a fail-closed normal-C qualification boundary and records the
receipt content requirements in `NORMAL_C_RECEIPT_FIELDS`. Even a commit with
the correct two parents and Q tree is insufficient. The authoritative Root/Runner
receipt path, digest and provenance verification contract have not been supplied;
`NORMAL_C_RECEIPT_CONTRACT` remains unset. No Runner API or authority is inferred.
An index-provided receipt cannot resolve this gap. This blocks every C, including
a legitimate C, until that concrete contract and its verifier are supplied.
The schema2 builder's undefined `tested` reference is fixed by checking the CLI
reference against the constructed payload's tested version. This does not make
its historical pipeline usable for fresh Q.
Bulk and role fixtures now allocate under `/tmp`, outside the source repository,
with inherited Git routing removed. Role fixtures reject unqualified no-ff merges
and synthetic commits with identical parents/tree. The additional candidate
fixture constructs such a commit only in a temporary bare clone. These Git
fixtures are **Root-run / unexecuted**: the worker's bulk attempt failed on
temporary directory creation with `PermissionError: Operation not permitted`,
before any Git invocation. They were not redirected into the worktree.
Remaining implementation, separate from the genuine authority context gap:
1. Four executable S5 drivers and their raw semantic adapters are still missing.
`s5/PENDING.md` remains accurate. All approved destruction/day/reason/exit
policies must be enforced alongside the existing safety conditions.
2. Fresh-Q run identity/provenance plumbing in native series, collector, S1–S4
wrappers and schema2 builder is unfinished. Historical names, pins and source
manifests have not been relabeled.
3. The separate full184/329 verifier and its exact source/settings/markers/policy/
engine/input/ended-receipt joins, including separate test_required_kitchen
binding, are unfinished. The native input loop is not a substitute.
4. Normal-C positive qualification needs the actual authoritative receipt contract
described above; matching Git structure alone is deliberately rejected.
5. Genuine-Q positive and fake-Q/full-role fixtures remain unexecuted. The new
synthetic-C Git fixture also remains unexecuted; static parsing is not proof
that it ran.
See REPAIR31_STATIC_CHECKS.json for actual worker results. No engine, formal gate,
Runner operation, repository Git write, integration or other agent was invoked.
Product code, Clock, values, tests, spec, denominator, thresholds and permissions
are unchanged. No material was removed for the obsolete byte cap.
After the missing implementation and context are resolved, Root retains the
recorded order: static controls; genuine Q and fresh S1–S5 once; disk/verified CoW
then full184/329 once on final Q with final checker; truthful index; verify-only
on S; independent whole-unit review; prepare-integration/final on qualified C.
Live records stay under `.runtime`. No known-failing gate is a progress check.
@@ -0,0 +1,63 @@
{
"task_id": "P04-01",
"scope": "new concrete32 static preparation only",
"results": [
{
"path": "normal_c_join.py",
"check": "AST and in-memory compile",
"exit_code": 0,
"status": "pass",
"sha256": "3156e1df928ae15ab311b61eb27e21ef27cf123cb7097646a81a3f836c30ba33"
},
{
"path": "normal_c_join_fixtures.py",
"check": "AST and in-memory compile",
"exit_code": 0,
"status": "pass",
"sha256": "fba1634aafbb5c6030bec073b75b609a20d10d5ca6a6f0eddc270a12023830a3"
},
{
"path": "scratch_fixture_adapter.py",
"check": "AST and in-memory compile",
"exit_code": 0,
"status": "pass",
"sha256": "4994101754c38568007f2d7e1e0c8a2221d26216f464c496a7258ff89c601994"
},
{
"path": "s5/run_s5_native.py",
"check": "AST and in-memory compile",
"exit_code": 0,
"status": "pass",
"sha256": "928409e17984330498b2637e33957740bcdd91d427df5ee60d21a86671646fa2"
},
{
"path": "s5/s5_power_adapter.py",
"check": "AST and in-memory compile",
"exit_code": 0,
"status": "pass",
"sha256": "6b77e1ac7f1bdfd031321f106d8a6fcf465a3c1dd30e697d2b1e7c7285139f15"
},
{
"path": "s5/p04_s5_power_probe.gd",
"check": "text-only forbidden operation and declaration controls",
"exit_code": 0,
"status": "pass",
"godot_parse": "unexecuted",
"sha256": "248da3f1dbca644e2fd62fcf283a4e499e0631ff23f8dc44dc77b872ef1be5ba"
},
{
"check": "normal-gate reference supplied index SHA256",
"status": "pass",
"exit_code": 0,
"sha256": "4c6067bbd57034764873a468ff161a6882d232503043d5640fc83dea0b455856"
}
],
"fixtures": "unexecuted",
"formal_validation": "unexecuted",
"engines_launched": 0,
"git_commands": 0,
"runner_operations": 0,
"whole_goal_accepted": false,
"original_credit": 0,
"existing_partial31_files_edited": 0
}
@@ -0,0 +1,44 @@
# Repair 32 — partial implementation submitted; no acceptance claim
Only new concrete32 files were added. Existing partial31 files, including the
checker and s5/PENDING.md, were not edited. No condition credit is claimed:
formal 16/88, original 30/88, P04 credit 0, all 15 conditions plus EV, frozen
Mc0 and all six approved D05 items remain unchanged.
Implemented, unexecuted:
- S5 power driver pair and S4-derived wrapper: public bath pure depletion and
cafeteria/kitchen reason-priority depletion; public spend/recovery commands;
observed completion; same-key replay; full typed/JSON phase points; formal
save/independent Reader load/replay. No disconnect or direct resource mutation.
- Hashed raw semantic adapter for existing power_stop, dependency_stop and
recovery_completion measurement keys. It does not qualify native provenance.
- Read-only normal_c_join over actual Runner task/candidate/main_base, approval,
validation/review and integration/final records. No future C hash is frozen.
Root must retain an actual approved Runner snapshot before integrate deletes
approval; later final records come from the current Runner database.
- Root-run synthetic normal join controls and explicit-scratch adapter for
preserved Git fixtures. No fixtures were executed.
- S5_ROOT_RUN.md and NORMAL_C_BOUNDARY32.md explain boundaries and limitations.
Actual verification: Python AST/compile for five new Python files and textual
probe controls passed. No pycache, engine, Godot parse, Git command, Runner
operation, fixture, formal validation, independent review or integration ran.
The shell rejected a here-document temporary-file allocation; subsequent commands
used python -c. An attempted documentation addition at the repository root was
rejected and no file was created there; the document was added within allowed_paths.
Remaining implementation limitations:
1. The old checker still deliberately rejects normal C: preserving partial31
means this standalone Runner-record join is not connected to its role output.
It does not assert Git structure/Q equivalence and cannot bypass that gate.
2. The S5 wrapper retains historical S4 template identity/count bindings. Fresh-Q
plumbing is outside this step and remains pending; this is not batch admission.
3. S5 destruction/midnight/exit, fresh-Q/full184/329, truthful collection/index,
exact-version applicability, independent review and ordinary gates remain
pending. None was attempted together or counted as a new unit.
4. Scratch adapters preserve the old fixtures' assertions; positive normal-C
structure fixtures under the eventual integrated boundary are still pending.
Runner/Root must run the permitted static fixtures in external scratch, review
the added source, and resolve boundary integration before the established
once-only genuine-Q/native/full sequence. No evidence or completion is invented.
@@ -35,8 +35,8 @@ def payload(build, gate=None):
native = build / 'audit-support/native-first-current'
c = gate.verify_native(native)
raw = gate.combine_native_series(build, c)
source = gate.product_manifest(gate.tree_entries(gate.TESTED_PRODUCT))
gate.require(len(source) == 1338, 'complete native source required')
tested = c['production_commit']
source = gate.selected_manifest(gate.tree_entries(tested))
source_map = {p: v['sha256'] for p, v in source.items()}
# Resolve content from supplied roots only; never open original provenance
# paths, never omit required source/config/input/environment material.
@@ -80,13 +80,13 @@ def payload(build, gate=None):
relocation = gate.load(build / 'audit-support/p04-r17-full-inputs-r01/MANIFEST.json')
authorities = {}
for ref in sorted({r for _, refs, _ in gate.REQUIRED.values() for r in refs}):
relative = (gate.DOC_SCOPE + 'D05_OWNER_APPROVAL.json' if ref.startswith('D05-P04-') else
relative = (gate.OWNER_BINDINGS[ref][0] if ref.startswith('D05-P04-') else
'docs/traceability/original/BASELINE.txt' if ref.startswith('BASELINE:') else
'docs/DESIGN_DECISIONS.md' if ref == 'D-034' else
'docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/ORDER_CONTRACT_DRAFT.md')
path = gate.safe(gate.ROOT, relative)
if ref.startswith('D05-P04-'):
gate.require(gate.sha(path) == gate.OWNER_HASH, 'owner approval hash')
gate.owner_authority(ref, {'source': relative, 'status': 'approved'}, path)
authorities[ref] = {'source': relative, 'sha256': gate.sha(path),
'status': 'approved' if not ref.startswith('BASELINE:') else 'original'}
conditions = {cid: {'case_id': cid, 'authority_refs': list(refs), 'nativeWindows': 'pending',
@@ -103,16 +103,16 @@ def payload(build, gate=None):
for name, rows in gate.REACH_REFS.items():
refs = []
for path, function, digest, lines in rows:
gate.resolve_anchor(gate.git_bytes('show', gate.TESTED_PRODUCT + ':' + path), function, digest, lines)
gate.resolve_anchor(gate.git_bytes('show', tested + ':' + path), function, digest, lines)
refs.append({'path': path, 'sha256': source_map[path], 'function': function,
'anchor_sha256': digest, 'line_count': lines})
reachability[name] = {'reach': name == 'EV', 'case_id': 'EV' if name == 'EV' else None, 'source_refs': refs,
'raw_verified': 'EV' in raw['verified_conditions'] if name == 'EV' else None}
delta = gate.source_delta(gate.REGISTERED_COMMIT, gate.TESTED_PRODUCT)
delta = gate.source_delta(gate.REGISTERED_COMMIT, tested)
index = {'schema_version': 2, 'task_id': 'P04-01', 'formal_acceptance': False,
'versions': {'registered': gate.REGISTERED_COMMIT, 'execution_origin': gate.EXECUTION_ORIGIN,
'tested': gate.TESTED_PRODUCT},
'product_binding': {'tested_product': gate.TESTED_PRODUCT, 'runner_inputs': runners},
'tested': tested},
'product_binding': {'tested_product': tested, 'runner_inputs': runners},
'source_map': source_map, 'registered_pins': gate.load(gate.SPEC)['current_source_pins'],
'applicability_delta': delta,
'delta_cases': {r['path'] + ':' + r['function']: {cid: cid for cid in
@@ -123,10 +123,10 @@ def payload(build, gate=None):
'native_bundle': descriptor(native / 'OWNERSHIP_RAW_PROVENANCE.json'),
'original_audit': {'sha256': gate.sha(gate.ROOT / gate.DOC_SCOPE / 'order-audit.json'),
'content': gate.load(gate.ROOT / gate.DOC_SCOPE / 'order-audit.json')},
'review_status': 'pending_review', 'original_credit': '13/88',
'review_status': 'pending_review', 'original_credit': '16/88; P04=0',
'safety_outcomes': ['no charging while legitimately stopped',
'no double midnight settlement', 'no orphan reservations']}
gate.applicability(index, gate.load(gate.SPEC), source_map, gate.TESTED_PRODUCT)
gate.applicability(index, gate.load(gate.SPEC), source_map, tested)
return index
@@ -140,13 +140,14 @@ def main():
args = parser.parse_args()
gate = checker()
os.environ['BUILD_OUTPUT_DIR'] = str(args.build.resolve(strict=True))
gate.require(args.registered_ref == gate.REGISTERED_COMMIT and args.tested_ref == gate.TESTED_PRODUCT,
'source refs differ from immutable evidence roles')
output = args.output.absolute()
gate.require(not output.exists() and not output.is_symlink(), 'output must be fresh')
for path in output.parents:
gate.require(not path.is_symlink(), 'output parent symlink')
index = payload(args.build, gate)
gate.require(args.registered_ref == gate.REGISTERED_COMMIT and
args.tested_ref == index['versions']['tested'],
'source refs differ from immutable evidence roles')
with gate.isolated_objects():
_, role = gate.verify_roles(index, args.build.resolve())
# The historical invocation is separate from the reusable evidence index.
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Root-only disposable repository controls; never original acceptance evidence."""
"""Isolated disposable repository controls; never original acceptance evidence."""
import importlib.util
import os
from pathlib import Path
@@ -24,8 +24,9 @@ def run():
spec = importlib.util.spec_from_file_location('bulk_gate', ROOT / 'tools/check_p04_order_evidence.py')
gate = importlib.util.module_from_spec(spec)
spec.loader.exec_module(gate)
with tempfile.TemporaryDirectory(prefix='p04-bulk-fixture-') as temporary:
with tempfile.TemporaryDirectory(prefix='p04-bulk-fixture-', dir='/tmp') as temporary:
base = Path(temporary)
assert not base.resolve().is_relative_to(ROOT.resolve())
repo = base / 'repo'
repo.mkdir()
gate.ROOT = repo
@@ -14,7 +14,7 @@ ROOT = Path(__file__).resolve().parents[5]
spec = importlib.util.spec_from_file_location('p04_gate', ROOT / 'tools/check_p04_order_evidence.py')
gate = importlib.util.module_from_spec(spec)
spec.loader.exec_module(gate)
PRODUCTION = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1'
PRODUCTION = gate.MAIN_ANCHOR
def run(native_bundle=None):
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""Read-only authority controls; no Git writes, engine or acceptance execution."""
import copy
import importlib.util
import json
from pathlib import Path
import sys
from unittest.mock import patch
sys.dont_write_bytecode = True
ROOT = Path(__file__).resolve().parents[5]
spec = importlib.util.spec_from_file_location('p04_authority', ROOT / 'tools/check_p04_order_evidence.py')
gate = importlib.util.module_from_spec(spec)
spec.loader.exec_module(gate)
def run():
results = []
original = gate.load(ROOT / gate.DOC_SCOPE / 'D05_REMAINING_APPROVAL.json')
source = gate.git_bytes('show', 'c0ea009b28a7649aca6a433a1a24dc0be5e7ab81:' +
'docs/plans/original-completion-2026-10-02/execution/' +
'p04-01-owner-approval-20261018/D05_ACTUAL_HUMAN_APPROVAL.json')
import hashlib
assert all(row['sha256'] == hashlib.sha256(source).hexdigest()
for row in original['source_bindings'])
human = {row['id']: row for row in json.loads(source)['approved']}
for choice in original['approved_choices']:
assert all(choice[k] == human[choice['source_id']][k]
for k in ('answer_exact', 'approved_question_policy'))
for ref, (relative, digest) in gate.OWNER_BINDINGS.items():
entry = {'source': relative, 'status': 'approved'}
path = ROOT / relative
gate.owner_authority(ref, entry, path)
results.append({'id': ref, 'case': 'positive', 'result': 'accepted'})
for label in ('missing', 'wrong_hash', 'pending', 'wrong_path'):
changed = copy.deepcopy(entry)
if label == 'missing':
changed = {}
elif label == 'pending':
changed['status'] = 'pending'
elif label == 'wrong_path':
changed['source'] = gate.DOC_SCOPE + 'D05_REMAINING_ORDER_CANDIDATE.json'
try:
if label == 'wrong_hash':
with patch.object(gate, 'sha', return_value='0' * 64):
gate.owner_authority(ref, changed, path)
else:
gate.owner_authority(ref, changed, path)
except ValueError as exc:
results.append({'id': ref, 'case': label, 'result': 'rejected', 'error': str(exc)})
else:
raise AssertionError('negative accepted: ' + ref + ':' + label)
return {'scope': 'authority fixtures only; no native or acceptance proof', 'results': results}
if __name__ == '__main__':
print(json.dumps(run(), ensure_ascii=False, indent=2))
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""Isolated candidate qualification negative; no whole-role/native credit."""
import importlib.util
import json
from pathlib import Path
import subprocess
import sys
import tempfile
sys.dont_write_bytecode = True
ROOT = Path(__file__).resolve().parents[5]
def run():
spec = importlib.util.spec_from_file_location('candidate_gate', ROOT / 'tools/check_p04_order_evidence.py')
gate = importlib.util.module_from_spec(spec)
spec.loader.exec_module(gate)
env = gate.git_environment()
env.update(GIT_AUTHOR_NAME='P04 isolated fixture', GIT_AUTHOR_EMAIL='fixture@invalid',
GIT_COMMITTER_NAME='P04 isolated fixture', GIT_COMMITTER_EMAIL='fixture@invalid')
with tempfile.TemporaryDirectory(prefix='p04-candidate-fixture-', dir='/tmp') as temp:
repo = Path(temp) / 'objects.git'
assert not repo.resolve().is_relative_to(ROOT.resolve())
subprocess.run(['git', '-c', 'core.hooksPath=/dev/null', 'clone', '--bare', '--shared',
str(ROOT), str(repo)], env=env, check=True, capture_output=True)
def git(*args):
return subprocess.check_output(['git', '-c', 'core.hooksPath=/dev/null', *args],
cwd=repo, env=env, text=True).strip()
submission = git('rev-parse', 'HEAD')
main = gate.MAIN_ANCHOR
tree = git('merge-tree', '--write-tree', main, submission)
synthetic = git('commit-tree', tree, '-p', main, '-p', submission,
'-m', 'synthetic C; no Root qualification')
assert git('show', '-s', '--format=%P', synthetic).split() == [main, submission]
assert git('rev-parse', synthetic + '^{tree}') == tree
try:
gate.qualify_normal_candidate(synthetic, tree, main, submission, tree)
except ValueError as exc:
assert 'qualification context gap' in str(exc), str(exc)
else:
raise AssertionError('synthetic C accepted')
return {'scope': 'isolated candidate qualification only; full role fixtures remain Root-run',
'synthetic_equal_parents_and_tree': 'rejected', 'formal_acceptance': False,
'normal_C_positive': 'unexecuted: authoritative receipt contract unavailable'}
if __name__ == '__main__':
print(json.dumps(run(), indent=2))
@@ -48,10 +48,13 @@ def run():
add('decisions', (ROOT / 'docs/DESIGN_DECISIONS.md').read_bytes(), 'authority')
add('a01', (ROOT / 'docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/ORDER_CONTRACT_DRAFT.md').read_bytes(), 'authority')
add('owner', (ROOT / 'docs/plans/original-completion-2026-10-02/execution/p04-01/D05_OWNER_APPROVAL.json').read_bytes(), 'authority')
add('remaining_owner', (ROOT / gate.DOC_SCOPE / 'D05_REMAINING_APPROVAL.json').read_bytes(), 'authority')
authority = {ref: dict(status='approved', artifact_id=(
'owner' if ref.startswith('D05-P04-') else 'baseline' if ref.startswith('BASELINE:')
('owner' if gate.OWNER_BINDINGS[ref][0].endswith('/D05_OWNER_APPROVAL.json') else 'remaining_owner') if ref.startswith('D05-P04-') else 'baseline' if ref.startswith('BASELINE:')
else 'decisions' if ref == 'D-034' else 'a01'))
for _, refs, _ in gate.REQUIRED.values() for ref in refs}
for ref, (relative, digest) in gate.OWNER_BINDINGS.items():
authority[ref]['source'] = relative
add('stdout', b'SYNTHETIC fixture log', 'stdout')
add('native_log', b'SYNTHETIC fixture log', 'native_log')
domains = {d: dict(source_refs=[dict(path='autoload/simulation_runtime.gd', function='_advance_facilities',
@@ -23,8 +23,11 @@ def run(build, evidence):
for name in ('GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE', 'GIT_OBJECT_DIRECTORY',
'GIT_ALTERNATE_OBJECT_DIRECTORIES'):
env.pop(name, None)
with tempfile.TemporaryDirectory(prefix='p04-role-fixtures-', dir=build) as temp:
# Never let a task build path put Git objects inside the source repository.
# /tmp is explicit so an inherited TMPDIR cannot redirect writes into it.
with tempfile.TemporaryDirectory(prefix='p04-role-fixtures-', dir='/tmp') as temp:
base = Path(temp)
assert not base.resolve().is_relative_to(ROOT.resolve())
checkout = base / 'checkout'
subprocess.run(['git', 'clone', '--shared', '--no-checkout', str(ROOT), str(checkout)],
env=env, check=True, capture_output=True)
@@ -33,7 +36,7 @@ def run(build, evidence):
return subprocess.check_output(['git', '-c', 'core.hooksPath=/dev/null', *args], cwd=checkout, env=env).decode().strip()
actual = git('rev-parse', 'HEAD')
anchor = '9b1a18c1eb25ca1300dcd59da78423c0dda2f498'
anchor = 'c0ea009b28a7649aca6a433a1a24dc0be5e7ab81'
ancestry = subprocess.run(['git', 'merge-base', '--is-ancestor', anchor, actual], cwd=checkout, env=env)
submission = git('show', '-s', '--format=%P', actual).split()[1] if ancestry.returncode == 0 else actual
git('checkout', '--detach', submission)
@@ -101,8 +104,21 @@ def run(build, evidence):
git('checkout', '--detach', anchor)
git('merge', '--no-ff', '--no-edit', submission)
merged = git('rev-parse', 'HEAD')
check('real_integration_positive', positive=True)
check('real_final_positive', positive=True)
# A normal commit C cannot be relabelled as tested non-production Q.
changed = copy.deepcopy(original)
changed['product_binding']['tested_product'] = merged
check('normal_C_cannot_impersonate_Q', changed)
changed = copy.deepcopy(original)
changed['product_binding']['tested_product'] = git('rev-parse', anchor + '^{tree}')
check('main_tree_cannot_impersonate_Q', changed)
# A merge made by this fixture has no independent normal-C provenance.
# Equal parents/tree are insufficient, even for git merge --no-ff.
check('unqualified_merge_rejected')
synthetic = git('commit-tree', git('rev-parse', merged + '^{tree}'),
'-p', anchor, '-p', submission, '-m', 'synthetic normal C')
git('checkout', '--detach', synthetic)
check('synthetic_identical_parents_tree_rejected')
git('checkout', '--detach', merged)
game.unlink()
git('add', '-u')
git('commit', '--amend', '--no-edit')
@@ -0,0 +1,132 @@
#!/usr/bin/env python3
"""Root-only, read-only join of actual Runner records; never grants acceptance.
Root must select the real Runner state.sqlite, not a hand-written export. This
checks consistency, not authenticity of an arbitrary caller-supplied database.
No Git, engine, Runner API, SQL mutation or temporary file is used.
Root retains a read-only Runner snapshot taken after approve; integrate deletes
the live approval. Final evidence is read separately from the current database.
"""
import argparse
import hashlib
import json
from pathlib import Path
import re
import sqlite3
MAIN = "c0ea009b28a7649aca6a433a1a24dc0be5e7ab81"
SPEC = "9ec722e7dfb0bee178d291624a026420c08412574e238bba1fde012c7a6f7881"
def require(value, message):
if not value:
raise ValueError(message)
def unique(pairs):
out = {}
for key, value in pairs:
require(key not in out, "duplicate JSON key")
out[key] = value
return out
def read(path, hashes):
path = Path(path)
require(path.is_file() and not path.is_symlink(), "ordinary record required: " + str(path))
require("normal-candidate-example" not in path.parts, "format samples are not authority")
data = path.read_bytes()
hashes[str(path)] = hashlib.sha256(data).hexdigest()
result = json.loads(data, object_pairs_hook=unique)
require(isinstance(result, dict) and not result.get("example_only_not_P04_authority"), "actual record required")
return result
def verify(database, approved_database, candidate, submission, hashes):
for sha in (candidate, submission):
require(re.fullmatch(r"[0-9a-f]{40}", sha), "full commit SHA required")
database = database.resolve(strict=True)
require(database.is_file(), "Runner database required")
# mode=ro deliberately reads live WAL consistently; immutable=1 would hide it.
with sqlite3.connect(database.as_uri() + "?mode=ro", uri=True) as db:
db.row_factory = sqlite3.Row
db.execute("PRAGMA query_only=ON")
db.execute("BEGIN")
task = db.execute("SELECT * FROM tasks WHERE id=?", ("P04-01",)).fetchone()
require(task is not None, "Runner task missing")
require(task["submitted"] == submission and task["candidate"] == candidate
and task["main_base"] == MAIN and candidate != submission,
"Runner candidate/submission/main_base mismatch")
require(task["state"] in ("approved", "completed"), "Runner approval state required")
contract = json.loads(task["contract"], object_pairs_hook=unique)
require(contract["id"] == "P04-01" and contract["spec_sha256"] == SPEC
and contract["validation_ids"] == ["p04-acceptance"]
and contract["acceptance_ids"] == ["P04-01"], "immutable contract mismatch")
approved_database = approved_database.resolve(strict=True)
with sqlite3.connect(approved_database.as_uri() + "?mode=ro", uri=True) as approved:
approved.row_factory = sqlite3.Row
approved.execute("PRAGMA query_only=ON")
approved.execute("BEGIN")
approved_task = approved.execute("SELECT * FROM tasks WHERE id=?", ("P04-01",)).fetchone()
require(approved_task is not None and approved_task["state"] == "approved"
and all(approved_task[k] == task[k] for k in ("submitted", "candidate", "main_base", "contract")),
"Root-retained actual approved Runner snapshot mismatch")
approval = approved.execute("SELECT * FROM approvals WHERE task_id=?", ("P04-01",)).fetchone()
require(approval is not None and approval["candidate"] == candidate
and approval["main_base"] == MAIN and approval["owner"].strip(), "exact Runner approval required")
rows = []
for kind, sha in (("validation", submission), ("review", submission),
("integration", candidate), ("final", candidate)):
records = db.execute("SELECT * FROM evidence WHERE task_id=? AND kind=? AND commit_sha=? AND passed=1",
("P04-01", kind, sha)).fetchall()
require(records, "Runner evidence missing: " + kind)
for record in records:
value = read(record["artifact"], hashes)
require(value.get("task_id") == "P04-01" and value.get("commit") == sha, "evidence identity mismatch")
if kind == "review":
require(value.get("status") == "pass" and value.get("acceptance_ids") == ["P04-01"], "independent review failed")
require(isinstance(value.get("findings"), list) and all(
f.get("severity") == "low" for f in value["findings"]), "review finding blocks join")
else:
require(value.get("kind") == kind and value.get("passed") is True, "verification kind/result mismatch")
checks = value.get("checks")
require(isinstance(checks, list) and len(checks) == 1, "exact validation roster required")
check = checks[0]
require(check.get("id") == "p04-acceptance" and type(check.get("exit_code")) is int
and check["exit_code"] == 0 and check.get("passed") is True, "failed validation check")
artifact = Path(check["artifact"])
require(artifact.is_dir(), "registered validation artifact directory missing")
for name in ("command.json", "stdout.log", "stderr.log"):
path = artifact / name
require(path.is_file() and not path.is_symlink(), "registered validation log missing")
hashes[str(path)] = hashlib.sha256(path.read_bytes()).hexdigest()
rows.append(dict(record))
# Hash the logical transaction snapshot, not mutable SQLite/WAL bytes.
snapshot = dict(task=dict(task), approval=dict(approval), evidence=rows)
digest = hashlib.sha256(json.dumps(snapshot, sort_keys=True, separators=(",", ":")).encode()).hexdigest()
return dict(protocol="p04-normal-c-runner-join-v1", runner_database=str(database),
approved_runner_database=str(approved_database),
runner_records_sha256=digest, join={"C": candidate, "S": submission, "M": MAIN},
runner_records_consistent=True, structure_verified=False,
source_Q_applicability_verified=False, input_sha256=hashes,
whole_goal_accepted=False, unit_accepted=False)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--runner-db", type=Path, required=True)
parser.add_argument("--approved-runner-db", type=Path, required=True,
help="Root-retained actual Runner snapshot after approve, before integrate deletes approval")
parser.add_argument("--candidate", required=True)
parser.add_argument("--submission", required=True)
args = parser.parse_args()
try:
print(json.dumps(verify(args.runner_db, args.approved_runner_db, args.candidate, args.submission, {}), sort_keys=True))
except (OSError, ValueError, KeyError, TypeError, sqlite3.Error) as error:
print(json.dumps({"runner_records_consistent": False, "error": str(error), "whole_goal_accepted": False}))
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""Root-run synthetic boundary fixtures. Never P04 authority; no default scratch."""
import argparse
import importlib.util
import json
from pathlib import Path
import sqlite3
import sys
sys.dont_write_bytecode = True
HERE = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location("normal_c_join", HERE / "normal_c_join.py")
join = importlib.util.module_from_spec(spec)
spec.loader.exec_module(join)
def fixture(root, change):
root.mkdir()
submission, candidate = "1" * 40, "2" * 40
contract = dict(id="P04-01", spec_sha256=join.SPEC,
validation_ids=["p04-acceptance"], acceptance_ids=["P04-01"])
db_path = root / "runner.sqlite"
with sqlite3.connect(db_path) as db:
db.executescript("CREATE TABLE tasks(id,contract,state,submitted,candidate,main_base);"
"CREATE TABLE approvals(task_id,candidate,main_base,owner,created);"
"CREATE TABLE evidence(id,task_id,kind,commit_sha,artifact,passed);")
db.execute("INSERT INTO tasks VALUES(?,?,?,?,?,?)",
("P04-01", json.dumps(contract), "approved", submission, candidate, join.MAIN))
db.execute("INSERT INTO approvals VALUES(?,?,?,?,?)", ("P04-01", candidate, join.MAIN, "fixture-only", 1.0))
for number, kind in enumerate(("validation", "review", "integration", "final")):
sha = submission if kind in ("validation", "review") else candidate
value = dict(task_id="P04-01", commit=sha)
if kind == "review":
value.update(status="pass", acceptance_ids=["P04-01"], findings=[])
if change == "medium":
value["findings"] = [{"severity": "medium", "message": "synthetic"}]
else:
logs = root / (kind + "-logs")
logs.mkdir()
for name in ("command.json", "stdout.log", "stderr.log"):
(logs / name).write_text("{}" if name.endswith("json") else "synthetic fixture only\n")
check = dict(id="p04-acceptance", exit_code=0, artifact=str(logs), passed=True)
value.update(kind=kind, passed=True, checks=[check])
if kind == "final":
if change == "wrong_C": value["commit"] = "3" * 40
if change == "kind_missing": del value["kind"]
if change == "failed_check": check["exit_code"] = 1
if change == "extra_id": value["checks"].append(dict(check, id="extra"))
if change == "missing_id": value["checks"] = []
if change == "task_mismatch": value["task_id"] = "P26-01"
if change == "missing_artifact": check["artifact"] = str(root / "missing")
artifact = root / (kind + ".json")
artifact.write_text(json.dumps(value))
db.execute("INSERT INTO evidence VALUES(?,?,?,?,?,?)", (number, "P04-01", kind, sha, str(artifact), 1))
if change == "wrong_M": db.execute("UPDATE tasks SET main_base=?", ("3" * 40,))
if change == "wrong_approval": db.execute("UPDATE approvals SET candidate=?", ("3" * 40,))
if change == "no_final": db.execute("DELETE FROM evidence WHERE kind='final'")
return db_path, submission, candidate
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--scratch", type=Path, required=True)
args = parser.parse_args()
root = args.scratch.resolve()
if root.exists() or root.is_relative_to(HERE.parents[4]) or root == Path("/tmp").resolve() or Path("/tmp").resolve() in root.parents:
raise ValueError("fresh external scratch required; /tmp and repository are prohibited")
root.mkdir(parents=True)
results = []
for name in ("positive", "wrong_C", "wrong_M", "kind_missing", "failed_check", "extra_id",
"missing_id", "task_mismatch", "medium", "missing_artifact", "wrong_approval", "no_final"):
path, submission, candidate = fixture(root / name, name)
try:
result = join.verify(path, path, candidate, submission, {})
if name != "positive" or result["whole_goal_accepted"] is not False:
raise AssertionError("unexpected qualification: " + name)
except ValueError:
if name == "positive": raise
results.append(name)
print(json.dumps(dict(synthetic_controls=results, whole_goal_accepted=False)))
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -1,6 +1,6 @@
{
"revision": "repair29",
"status": "SOURCE-READY / NOTRUN; Root measurements separately recorded",
"revision": "repair30",
"status": "BLOCKED: partial implementation; no native admission",
"task_id": "P04-01",
"current_table": true,
"scope": {
@@ -14,166 +14,296 @@
],
"packages": 30,
"deliveries": 88,
"original_credit": "13/88 unchanged; P04 receives zero credit",
"original_credit": "16/88 formal; P04 receives zero credit",
"CurrentAlphaScope": "unchanged",
"main_9b": "frozen; nothing integrated"
"frozen_main": "c0ea009b28a7649aca6a433a1a24dc0be5e7ab81"
},
"domains": [
{
"domain": "閉店",
"normative_rule": "D-034: direct closure releases waiting requests and continues started service. Approved dependency closure holds progress/payment and preserves reservation/service ID until one completion.",
"normative_rule": "D-034 preserves started services on direct closure and releases waiting requests. Dependency closure stops progress and charging, retains reservations/service identity, and completes once after recovery. RELATED_FACILITY_INACTIVE wins over NO_POWER when both apply.",
"current_source": [
"Runtime _process_tick_commands:5743",
"FacilityService _prepare_service_for_tick:853",
"Runtime _release_closed_business_queues:12624"
{
"path": "autoload/simulation_runtime.gd",
"function": "_process_tick_commands",
"line": 5765,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "9de66a4bb84b12304300d49085f44546412319bd4aee91e67b61becf97e50294"
},
{
"path": "scripts/facility/facility_service.gd",
"function": "_prepare_service_for_tick",
"line": 853,
"sha256": "ceb4a3e9224587423f273cdb2b56e6843ab176ac1fc4fe79dd498b5ed5c33b77",
"function_sha256": "b35c2c0fb23a04258b71995dd7c3b6dfacbbcdf36106e2e3348acef0e18d21cc"
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_release_closed_business_queues",
"line": 12672,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "3a05fbe94877eeb750fb0d692501954555ab6a8005448ab3b6023dab9bad816b"
}
],
"evidence": "I native_bundle C; R/s2a.json; R/s3.json B1",
"approved_authority": [
"D-034",
"D05-P04-DEPENDENCY"
],
"pending_D05": [
"D05(a) simultaneous reason selection"
"D05-P04-DEPENDENCY",
"D05-P04-PAUSE-REASON"
],
"pending_D05": [],
"phase": "APPLY_COMMANDS / FACILITY_COMPLETION / FACILITY_QUEUES",
"relative_priority": "Command closure before completion; dependency hold during preparation; closed queue release after completion.",
"status": "approved",
"observation_status": "observed-current"
"status": "approved policy; fresh Q evidence pending",
"observation_status": "historical observations; current M source inspected",
"historical_evidence": "I native_bundle C; R/s2a.json; R/s3.json B1",
"evidence": "Fresh exact-Q native proof pending; no old raw reused as Q",
"nativeWindows": "pending"
},
{
"domain": "停電",
"normative_rule": "BASELINE:183 mana depletion stops facilities. A legitimately power-stopped service must not progress/charge; retain reservation identity and complete once after recovery. This does not approve a simultaneous-cause priority.",
"normative_rule": "BASELINE:183 covers real mana depletion. Legitimately stopped service has no progress or charge and preserves reservations. D05-P04-PAUSE-REASON makes dependency closure the displayed reason when dependency closure and power loss coincide.",
"current_source": [
"Runtime _advance_mana:10694",
"FacilityService _prepare_service_for_tick:853"
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_mana",
"line": 10716,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "05c54626ce6e355acd92994ab80aaf2177c5cf194885e66934552139e087599e"
},
{
"path": "scripts/facility/facility_service.gd",
"function": "_prepare_service_for_tick",
"line": 853,
"sha256": "ceb4a3e9224587423f273cdb2b56e6843ab176ac1fc4fe79dd498b5ed5c33b77",
"function_sha256": "b35c2c0fb23a04258b71995dd7c3b6dfacbbcdf36106e2e3348acef0e18d21cc"
}
],
"evidence": "R/s4.json; B/p04-s4-native-r28; R/s3.json B1 combined diagnostic",
"approved_authority": [
"BASELINE:183",
"P04-01 safety acceptance"
],
"pending_D05": [
"D05(a)"
"P04-01 safety acceptance",
"D05-P04-PAUSE-REASON"
],
"pending_D05": [],
"phase": "MANA → FACILITY_COMPLETION",
"relative_priority": "Projection before completion; RELATED chosen before NO_POWER.",
"status": "observed-current",
"observation_status": "observed-current",
"evidence_scope": "S4 probe calls disconnect_nodes directly: isolated NO_POWER, not global depletion. Global depletion appears only in S3 B1 combined diagnostic. S1 covers separate staff/EV safety."
"status": "approved policy; fresh Q evidence pending",
"observation_status": "historical observations; current M source inspected",
"evidence_scope": "S4 probe calls disconnect_nodes directly: isolated NO_POWER, not global depletion. Global depletion appears only in S3 B1 combined diagnostic. S1 covers separate staff/EV safety.",
"historical_evidence": "R/s4.json; B/p04-s4-native-r28; R/s3.json B1 combined diagnostic",
"evidence": "Fresh exact-Q native proof pending; no old raw reused as Q",
"nativeWindows": "pending"
},
{
"domain": "破壊",
"normative_rule": "No charge while legitimately failed/stopped and no orphan reservation. Distinguish command destruction before facility processing from late INCIDENTS event destruction after completion; observation is not normative priority approval.",
"normative_rule": "Command destruction precedes completion. Accident/raid destruction follows completion and charging in minute N; that sale remains valid. Failure and reservation release for affected unfinished service occurs in N+1. D05-P04-DESTRUCTION is the authority, not BASELINE:183.",
"current_source": [
"Runtime _process_tick_commands:5743",
"_advance_defense:8577",
"_apply_defense_outcome_boundary:9804",
"FacilityService _prepare_service_for_tick:853"
{
"path": "autoload/simulation_runtime.gd",
"function": "_process_tick_commands",
"line": 5765,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "9de66a4bb84b12304300d49085f44546412319bd4aee91e67b61becf97e50294"
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_defense",
"line": 8599,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "db38b51531276d2620999d57eed7a6219b73f8b8d9ff3706cf569f4797918527"
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_apply_defense_outcome_boundary",
"line": 9826,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "182c48282d96c6ccd1e5f636751db9de8cef2770ad433b291db89111c5fb5043"
},
{
"path": "scripts/facility/facility_service.gd",
"function": "_prepare_service_for_tick",
"line": 853,
"sha256": "ceb4a3e9224587423f273cdb2b56e6843ab176ac1fc4fe79dd498b5ed5c33b77",
"function_sha256": "b35c2c0fb23a04258b71995dd7c3b6dfacbbcdf36106e2e3348acef0e18d21cc"
}
],
"evidence": "R/s3.json B4a/B4b",
"approved_authority": [
"P04-01 safety acceptance (original); explicit destruction rule pending D05"
],
"pending_D05": [
"D05(b); BASELINE:183 is mana depletion, not destruction authority; destruction_stop registry correction only after approval"
"D05-P04-DESTRUCTION"
],
"pending_D05": [],
"phase": "APPLY_COMMANDS vs INCIDENTS_AND_EVENTS",
"relative_priority": "Command destruction before completion; incident destruction after completion: B4a charges25G then destroys in same tick; B4b next-tick failure/release.",
"status": "pending D05",
"observation_status": "observed-current"
"status": "approved policy; fresh Q evidence pending",
"observation_status": "historical observations; current M source inspected",
"historical_evidence": "R/s3.json B4a/B4b",
"evidence": "Fresh exact-Q native proof pending; no old raw reused as Q",
"nativeWindows": "pending"
},
{
"domain": "退出",
"normative_rule": "Leave/abandon releases the owned reservation once; no orphan or duplicate charge. Preserve D-034. Completion, queue release and later normal despawn are distinct observations.",
"normative_rule": "D-034 release safety remains. Command exit precedes completion; AI planned exit follows completion and only applies to a deciding guest. Later despawn is distinct.",
"current_source": [
"Runtime _execute_leave_facility_queue:7553",
"_advance_guest_ai_decisions:8738"
{
"path": "autoload/simulation_runtime.gd",
"function": "_execute_leave_facility_queue",
"line": 7575,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "04733da2c6f9627e6d831f8bb6b620018d63305fe43bb927abf21a969288d90d"
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_guest_ai_decisions",
"line": 8760,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "e33b41294e88dba840affd5cc0a5c58fe5d46f5d98a80a8d5f4e907a3b9a7b93"
}
],
"evidence": "R/s3.json B2a/B2b/B3 and B1 departure history",
"approved_authority": [
"D-034",
"P04-01 safety acceptance"
],
"pending_D05": [
"D05(c)"
"P04-01 safety acceptance",
"D05-P04-EXIT"
],
"pending_D05": [],
"phase": "APPLY_COMMANDS vs AI_DECISIONS",
"relative_priority": "Command exit before completion/charging; AI PLANNED_EXIT after them; despawn later.",
"status": "pending D05",
"observation_status": "observed-current"
"status": "approved policy; fresh Q evidence pending",
"observation_status": "historical observations; current M source inspected",
"historical_evidence": "R/s3.json B2a/B2b/B3 and B1 departure history",
"evidence": "Fresh exact-Q native proof pending; no old raw reused as Q",
"nativeWindows": "pending"
},
{
"domain": "課金",
"normative_rule": "No stopped charge; one sale per completed service and idempotent resend. Reservation consumption, actual sale and payment key must join by service ID and original priceSnapshot.",
"normative_rule": "Charge only completed service, once per idempotency key; retain original price snapshot and reservation/ledger joins. At 00:00 prior-day settlement and upkeep precede completion; the sale belongs to the new day.",
"current_source": [
"Runtime _advance_facility_upkeep:1855",
"_complete_service_transaction:11769",
"_apply_service_transaction:11785",
"coordinator _process_daily_close:1125"
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_facility_upkeep",
"line": 1876,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "33a969a14d1a15296059cecadc4bf7e5a35c9eb61d82cb9e2d6d9bbcf5c32c68"
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_complete_service_transaction",
"line": 11817,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "f2b6e96a8eeef3dd3f8419b4d9d5ef4e1d13241600ce970bdd78a924428cac6c"
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_apply_service_transaction",
"line": 11833,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "950474ff3ca8a867ee025c2b7635586d79f2385f79586fc66107191ceb329a9a"
},
{
"path": "scripts/operations/operations_coordinator.gd",
"function": "_process_daily_close",
"line": 1125,
"sha256": "871a248ee101b6df543fd5cf0440b5d4b0f02c21fa145a99f0687888c1bc6f90",
"function_sha256": "665ac0ac4d4c220e68e98810da063fd2ad7ae7dc9e1997944a1e7bea7a3c30e6"
}
],
"evidence": "I native_bundle C; R/s2a.json; R/s4.json",
"approved_authority": [
"P04-01 safety acceptance",
"D05-P04-DEPENDENCY",
"D05-P04-SHIFT-1800"
],
"pending_D05": [
"D05(d), beyond approved A01 and18:00; timing/attribution mandatory P04, numeric math D04/P05 separate"
"D05-P04-SHIFT-1800",
"D05-P04-MIDNIGHT-DAY"
],
"pending_D05": [],
"phase": "TIME_BOUNDARIES → FACILITY_COMPLETION",
"relative_priority": "Upkeep/daily close before sale; post-increment sale timestamp, exclusive close period_end;00:00 sale belongs to new day.",
"status": "pending D05",
"observation_status": "observed-current"
"status": "approved policy; fresh Q evidence pending",
"observation_status": "historical observations; current M source inspected",
"historical_evidence": "I native_bundle C; R/s2a.json; R/s4.json",
"evidence": "Fresh exact-Q native proof pending; no old raw reused as Q",
"nativeWindows": "pending"
},
{
"domain": "シフト交代",
"normative_rule": "Approved [17:59,18:00) work belongs to day staff: complete/pay once at18:00 then switch; night work starts [18:00,18:01).",
"normative_rule": "Approved 18:00 order remains: completion and payment before handover. No renewal of prior approval.",
"current_source": [
"Runtime _advance_facilities:8482",
"_advance_staff_ai:8658",
"StaffService advance_one_minute:700"
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_facilities",
"line": 8504,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "f1efd0c23bdd60d1ef19a21879640b53b8b4d88844c0c881fe7cd724387ec274"
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_staff_ai",
"line": 8680,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "0e222987f7c5e25583dbaba8fe63784aa563715067396e8d31d10bd191e7179b"
}
],
"evidence": "I C first1080 sale joins; R/s2b.json no-night1081/overtime",
"approved_authority": [
"BASELINE:64",
"BASELINE:67",
"D05-P04-SHIFT-1800"
],
"pending_D05": [
"Already approved; do not re-ask"
],
"pending_D05": [],
"phase": "FACILITY_COMPLETION → AI_DECISIONS",
"relative_priority": "18:00 completion/payment before shift handover; day staff [17:59,18:00), night [18:00,18:01).",
"status": "approved",
"observation_status": "observed-current"
"status": "approved policy; fresh Q evidence pending",
"observation_status": "historical observations; current M source inspected",
"historical_evidence": "I C first1080 sale joins; R/s2b.json no-night1081/overtime",
"evidence": "Fresh exact-Q native proof pending; no old raw reused as Q",
"nativeWindows": "pending"
},
{
"domain": "00:00決算",
"normative_rule": "A01 approved ownership-prorated upkeep at midnight is retained. One daily close/payroll/upkeep, no duplicate replay/reload; distinguish prior [0,1440) accounting and sale at1440.",
"normative_rule": "A01 ownership-based upkeep is unchanged. Prior-day settlement/upkeep precede 00:00 service completion; its sale belongs to the new day. Replay/restore must not duplicate settlement.",
"current_source": [
"Kernel _handle_time_boundaries:254",
"Runtime _advance_operations_time:1898",
"coordinator _process_minute_boundaries:882",
"_process_daily_close:1125"
{
"path": "scripts/core/simulation_kernel.gd",
"function": "_handle_time_boundaries",
"line": 254,
"sha256": "341c0c878c4894adbac628d0db6362ff69fc3347bdd9e61e50936e15dc2d1edb",
"function_sha256": "2ced47a2911b36def9d89de82a43afc69148ead44d19db6a2a6c7bce5a910ae9"
},
{
"path": "autoload/simulation_runtime.gd",
"function": "_advance_operations_time",
"line": 1919,
"sha256": "45514aea9367ff678f4dc05166bb9b58121f240d4b5565edeb7ab258e3ded8e0",
"function_sha256": "511580d1fac3d2785072e94c2981065fa47ba18b1c97122922645dac5c0d94ab"
},
{
"path": "scripts/operations/operations_coordinator.gd",
"function": "_process_minute_boundaries",
"line": 882,
"sha256": "871a248ee101b6df543fd5cf0440b5d4b0f02c21fa145a99f0687888c1bc6f90",
"function_sha256": "1312166dc17aee0ef470069a73ff3fe6b86d11d04ca7de76f3d04f1d2d14674e"
},
{
"path": "scripts/operations/operations_coordinator.gd",
"function": "_process_daily_close",
"line": 1125,
"sha256": "871a248ee101b6df543fd5cf0440b5d4b0f02c21fa145a99f0687888c1bc6f90",
"function_sha256": "665ac0ac4d4c220e68e98810da063fd2ad7ae7dc9e1997944a1e7bea7a3c30e6"
}
],
"evidence": "I C paused/formal; R/s2a.json nonzero payroll/upkeep, replay and typed restore",
"approved_authority": [
"BASELINE:71",
"BASELINE:72",
"A01",
"D05-P04-DEPENDENCY"
],
"pending_D05": [
"A01 approved ownership-based midnight upkeep not reopened; extra attribution D05(d)"
"D05-P04-DEPENDENCY",
"D05-P04-MIDNIGHT-DAY"
],
"pending_D05": [],
"phase": "pre-TIME_BOUNDARIES signals → TIME_BOUNDARIES → FACILITY_COMPLETION",
"relative_priority": "Midnight signals, then upkeep/close, then completion.",
"status": "approved",
"observation_status": "observed-current"
"status": "approved policy; fresh Q evidence pending",
"observation_status": "historical observations; current M source inspected",
"historical_evidence": "I C paused/formal; R/s2a.json nonzero payroll/upkeep, replay and typed restore",
"evidence": "Fresh exact-Q native proof pending; no old raw reused as Q",
"nativeWindows": "pending"
}
],
"source_facts": "REPAIR29_STATIC_SOURCE.json",
"authority": "D05_OWNER_APPROVAL.json approves dependency and shift only; original BASELINE/D-034/A01 retain their scope",
"source_facts": "REPAIR30_SOURCE_FACTS.json",
"authority": "D05_OWNER_APPROVAL.json preserves dependency/18:00; D05_REMAINING_APPROVAL.json binds all four actual 2026-10-18 answers; BASELINE/D-034/A01 unchanged.",
"historical_superseded": [
"REPAIR17_STATUS.md",
"REPAIR18_STATUS.md",
@@ -184,18 +314,16 @@
"REPAIR21_STATUS.md",
"REPAIR22–28 creation-time status and runbooks"
],
"history_policy": "Creation-time NOT RUN in REPAIR22–28 and runbooks is historical; CURRENT_STATUS.md canonical table overrides execution status. Historical files unchanged.",
"evidence_policy": "Root-measured S4r28 4/4 PASS, controls, local8, r22 collection, schema2 index, registered validation PASS28s; worker SOURCE-READY / NOTRUN.",
"history_policy": "Historical source/proof pins retain their original revisions; CURRENT_STATUS.md is canonical. New approvals are not new native evidence.",
"evidence_policy": "All old S1-S4/r22/native/full178 records are historical. None is relabelled as Q. Fresh native S1-S5 and full184/329 on final Q remain NOT RUN.",
"pending": [
"Owner D05 a–d approval or explicit non-mandatory ruling; unknown mandatory rules stay pending",
"Post-approval normal checker/registry repair (a61 unchanged here)",
"support53cb normal registered rebind",
"final full1339 against final checker; none exists against a61",
"independent review and integration: P04 first, support on main9b afterward",
"nativeWindows obligations individually if required"
"Complete current-Q collector/wrapper/index binding and S5 drivers; see REPAIR30_STATUS.md",
"Fresh native S1-S5 on final Q, then full184/329 on the same Q including checker",
"Truthful index, formal registered validation on S --verify-only, whole-unit independent review, normal C integration",
"nativeWindows individually pending for every condition"
],
"priority_candidates_if_required": "D05_REMAINING_ORDER_CANDIDATE.json",
"collection_plan": "s4/S4_ROOT_RUN.md",
"priority_candidates_if_required": "D05_REMAINING_ORDER_CANDIDATE.json (superseded history)",
"collection_plan": "REPAIR30_STATUS.md",
"formal_acceptance": false,
"original_unit_complete": false,
"phase_order": [
@@ -436,5 +564,24 @@
],
"observed-current": "All phase and source behavior observations; not approval"
},
"full178_applicability_context": "REPAIR29_STATIC_SOURCE.json full_source_static_comparison: full178 selected1339 includes f5; one test-source mismatch (test_required_kitchen.gd), no game-source mismatch; preserve Runner applicability binding, no blanket1338 identity or a61 full proof."
"full178_applicability_context": "REPAIR29_STATIC_SOURCE.json full_source_static_comparison: full178 selected1339 includes f5; one test-source mismatch (test_required_kitchen.gd), no game-source mismatch; preserve Runner applicability binding, no blanket1338 identity or a61 full proof.",
"current_source_commit": "c0ea009b28a7649aca6a433a1a24dc0be5e7ab81",
"nativeWindows": {
"EV": "pending",
"closure_release": "pending",
"dependency_stop": "pending",
"destruction_stop": "pending",
"exit_release": "pending",
"midnight_replay": "pending",
"midnight_settlement": "pending",
"night_staff_absent": "pending",
"overtime_task": "pending",
"patience_release": "pending",
"paused_midnight": "pending",
"power_stop": "pending",
"recovery_completion": "pending",
"same_minute_replay": "pending",
"save_restore": "pending",
"shift_completion": "pending"
}
}
@@ -0,0 +1,31 @@
# S5 — pending implementation, not a native run plan
No S5 executable driver or native receipt is supplied by this partial repair.
Do not start the once-only Q native/full batch from this directory.
The four required cases remain unchanged:
1. Real mana depletion, NO_POWER, no charge/progress, reservation retained,
recovery and one completion. S4's `disconnect_nodes` is not depletion.
The existing cafeteria fixture has an operating kitchen prerequisite;
global depletion can select RELATED_FACILITY_INACTIVE first. A driver must
observe that distinction rather than relabel the reason or mutate power
availability directly. A separate combined-cause case must prove the
approved RELATED-before-NO_POWER reason priority.
2. Actual accident or raid destruction during completion: valid minute-N
sale; next-minute failure/release for unfinished affected work; compare
command destruction before completion. S3 B4a/B4b use a registered event
with SET_FACILITY_STATE and must not simply be renamed an actual raid.
3. 00:00 completion: retain the S2a paid-midnight setup and full typed
snapshots, add phase observations proving prior-day settlement/upkeep
precede the sale, and independently join the sale to the new accounting
day. Retain replay/no-double-settlement proof.
4. Command exit versus AI planned exit at completion: retain actual public
commands and guest/service/reservation/ledger joins. Observe the AI
DECIDING predicate after completion, without forcing guest state or
treating a due exit time as universal active-service cancellation.
All prices, durations, resource rules and thresholds come from the selected
Q definitions and current public runtime. No new original values or rules
are supplied here. These notes identify implementation work; they are not
engine evidence and confer no condition credit.
@@ -0,0 +1,22 @@
# Concrete32 power pair — unexecuted, not batch admission
`p04_s5_power_probe.gd` supplies S5A_PURE (paid public bath, genuine mana
depletion) and S5B_DEPENDENCY (cafeteria plus kitchen, RELATED-before-NO_POWER).
Both use public resource commands, observed recovery, formal packages, independent
Reader replay, phase raw and resource-command replay receipts. The bath has no
item reservation; the dependent case retains and consumes the actual meal ID.
`run_s5_native.py` retains the S4 ownership/engine/cleanup safeguards and historical
template bindings. It is not fresh-Q plumbing. Do not run it against Q or start
the once-only native/full batch until the separately pending identity work is
finished. No old S1–S4 record is renamed or reused as fresh proof.
Root later stages the wrapper, probe and this document in its own build area.
The adapter takes `--raw-root`, `--writer-sha256`, `--reader-sha256` from verified
native records. It verifies referenced typed/JSON hashes and derives existing
measurement keys. It does not qualify source, engine, settings or full evidence.
S5 destruction, midnight and exit cases remain unimplemented. The preserved
`PENDING.md` is historical partial31 text; this document records only the added,
unexecuted power pair. D05 six approvals, A01, frozen M, 16/88 and P04 credit 0
are unchanged. Root alone runs engines and scratch fixtures.
@@ -0,0 +1,466 @@
extends "res://tests/s3/test_runtime_actor_hardening.gd"
const CASES: Array[String] = ["S5A_PURE", "S5B_DEPENDENCY"]
const SEEDS: Dictionary = {"S5A_PURE": 420550, "S5B_DEPENDENCY": 420551}
const GUEST: StringName = &"p04.s5.guest.a"
const REQUEST: StringName = &"p04.s5.request.a"
const QUEUED_GUEST: StringName = &"p04.s5.guest.b"
const QUEUED_REQUEST: StringName = &"p04.s5.request.b"
const SERVERS: Array[StringName] = [&"p04.order.server.a", &"p04.order.server.b"]
const SNAPSHOT_SERVERS: Array[String] = ["p04.order.server.a", "p04.order.server.b"]
var _evidence_dir: String = ""
var _mode: String = ""
var _case: String = ""
var _serial: int = 0
var _facility_id: StringName = &""
var _service_id: StringName = &""
var _boundary: int = 960
var _price: int = 0
var _duration: int = 0
var _patience: int = 0
var _reserve: int = 0
var _recovery: Dictionary = {}
var _commands: Array = []
var _results: Array = []
var _receipts: Array = []
var _phases: Array = []
var _points: Dictionary = {}
var _branches: Dictionary = {}
var _slots: Dictionary = {}
var _replay_reference: Dictionary = {}
func _run() -> void:
_evidence_dir = OS.get_environment("THE_TREE_S5_EVIDENCE")
_mode = OS.get_environment("THE_TREE_S5_MODE")
if _evidence_dir.is_empty() or _mode not in ["writer", "reader"]:
quit(2)
return
_expect(DirAccess.make_dir_recursive_absolute(_evidence_dir) == OK, "external evidence directory")
if _mode == "writer":
for branch: String in CASES:
_case = branch
_writer_case()
else:
_reader()
_write(_mode, {&"pid": OS.get_process_id(), &"profile": OS.get_user_data_dir(), &"slots": _slots,
&"branches": _branches, &"checks": _checks, &"failures": _failures,
&"whole_goal_accepted": false, &"unit_accepted": false}, true)
_cleanup()
print("S5 power: %d checks, %d failures" % [_checks, _failures])
quit(1 if _failures else 0)
func _fresh() -> void:
_serial = 0
_facility_id = &""
_service_id = &""
_boundary = 960
_price = 0
_duration = 0
_patience = 0
_reserve = 0
_recovery = {}
_replay_reference = {}
_commands = []
_results = []
_receipts = []
_phases = []
_points = {}
_reset_runtime(SEEDS[_case])
_runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
_runtime.command_completed.connect(func(result: CommandResult) -> void:
_results.append({&"minute": _clock.absolute_minute, &"result": result.to_dictionary()})
_expect(result.is_success(), "actual public command completion " + str(result.command_id))
)
func _cmd(kind: StringName, payload: Dictionary, at: int = -1) -> CommandResult:
_serial += 1
var key: StringName = StringName("p04.s5.%s.command.%d" % [_case, _serial])
var result: CommandResult = _runtime.submit_command(kind, payload, &"player", &"", 10, at, key)
_commands.append({&"serial": _serial, &"kind": kind, &"payload": payload.duplicate(true),
&"at": at, &"issued_at": _clock.absolute_minute, &"idempotency_key": key, &"result": result.to_dictionary()})
_expect(result.is_success(), "public command " + String(kind))
return result
func _queue(guest_id: StringName, request_id: StringName, exit_at: int) -> void:
_cmd(&"spawn_guest", {&"guest_id": guest_id, &"guest_type_id": &"traveler", &"gold": _price * 2,
&"options": {&"state": GuestRuntime.State.DECIDING, &"current_cell": Vector3i.ZERO, &"planned_exit_at": exit_at}})
_cmd(&"create_service_request", {&"facility_id": _facility_id, &"request_id": request_id, &"guest_ids": [guest_id]})
var guest: GuestRuntime = _runtime.guest_service.get_guest(guest_id)
var request: ServiceRequest = _runtime.facility_service.get_request(request_id)
_expect(guest != null and request != null, "actual Guest and request exist")
if guest == null or request == null: return
_expect(guest.state == GuestRuntime.State.QUEUING and guest.queue_request_id == request_id, "actual queued ownership before advancing clock")
_expect(request.quoted_price == _price and request.service_minutes == _duration and request.reserved_inventory_ids.size() == (1 if _case == "S5B_DEPENDENCY" else 0), "definition price/duration and one meal reservation")
for id: StringName in request.reserved_inventory_ids:
var reservation: InventoryReservation = _runtime.inventory_service.get_reservation(id)
_expect(reservation != null and reservation.is_active() and reservation.requester_id == request_id, "public queue actually reserves meal")
func _prepare() -> bool:
_fresh()
var facility: FacilityInstance
if _case == "S5B_DEPENDENCY":
facility = _build_cafeteria(true)
else:
var bath: FacilityDefinition = _runtime.definition_registry.get_facility(&"public_bath")
_expect(bath != null and bath.build_minutes > 0, "registered public bath definition")
if bath == null: return false
var build: CommandResult = _cmd(&"build_facility", {&"definition_id": &"public_bath", &"origin": Vector3i(-5, 0, WorldService.LAYER_FRONT)})
if not build.is_success(): return false
var began: int = _clock.absolute_minute
while _runtime.construction_service.get_facilities().is_empty() and _clock.absolute_minute <= began + bath.build_minutes:
_clock.advance_one_minute()
var built: Array[Dictionary] = _runtime.construction_service.get_facilities()
_expect(built.size() == 1 and _clock.absolute_minute - began == bath.build_minutes, "definition build duration and one constructed bath")
if built.size() != 1: return false
facility = _runtime.facility_service.get_instance(StringName(built[0][&"instance_id"]))
if facility == null: return false
_facility_id = facility.instance_id
var definition: FacilityDefinition = _runtime.definition_registry.get_facility(facility.definition_id)
_price = definition.base_price
_duration = definition.base_service_minutes
_patience = _runtime.guest_service.get_definition(&"traveler").base_patience
_expect(_price > 0 and _duration > 1, "paid natural service definition")
var staff_ids: Array[StringName] = []
for index: int in range(definition.staff_min):
var id: StringName = StringName("p04.s5.staff.%d" % index)
staff_ids.append(id)
_cmd(&"register_staff", {&"staff_id": id, &"role_id": &"server" if _case == "S5B_DEPENDENCY" else &"attendant", &"options": {&"state": StaffRuntime.State.OFF_DUTY, &"current_cell": Vector3i.ZERO}})
_cmd(&"set_staff_work_assignment", {&"staff_id": id, &"template_id": &"DAY", &"facility_id": _facility_id})
_expect(_clock.absolute_minute < _boundary - _duration - 1, "setup before fixed boundary")
if _clock.absolute_minute >= _boundary - _duration - 1: return false
_clock.advance_minutes(_boundary - _duration - 1 - _clock.absolute_minute)
_expect(facility.active_staff_ids == staff_ids, "public staff attendance")
if _case == "S5B_DEPENDENCY":
_expect(_stock(facility.local_inventory_id, &"ingredient/basic_meal", 1, &"p04.s5.stock"), "one actual meal")
_queue(GUEST, REQUEST, _boundary + _duration + 1)
_clock.advance_one_minute()
var active: Array = _runtime.facility_service.get_active_services(_facility_id)
_expect(active.size() == 1, "one actual started service")
if active.size() != 1: return false
var service: ServiceInstance = active[0]
_service_id = service.service_id
_expect(service.started_at + _duration == _boundary, "natural completion boundary")
_clock.advance_minutes(_boundary - 1 - _clock.absolute_minute)
_reserve = _state.get_resource(&"mana")
_recovery = {&"staff_ids": staff_ids, &"resume_minute": -1}
_expect(_reserve > 0 and service.elapsed_minutes == _duration - 1, "positive reserve and duration-1 progress")
return _clock.absolute_minute == _boundary - 1
func _connect_observations() -> void:
_runtime.economy_service.transaction_posted.connect(func(id: StringName, entries: Array) -> void:
var rows: Array = []
for entry: LedgerEntry in entries: rows.append(entry.to_dictionary())
_receipts.append({&"id": id, &"minute": _clock.absolute_minute, &"entries": rows})
)
_clock.tick_phase_started.connect(func(phase: int, minute: int) -> void:
var label: String = "phase-%d-%s" % [minute, SimulationKernel.TickPhase.keys()[phase]]
var row: Dictionary = _capture()
row[&"phase"] = SimulationKernel.TickPhase.keys()[phase]
_assert_phase(row)
_phases.append(_write(label, row))
)
func _assert_phase(point: Dictionary) -> void:
_expect(point.has(&"snapshot") and point.has(&"mana"), "complete raw phase observation")
func _capture() -> Dictionary:
var snapshot: Dictionary = _runtime.create_snapshot()
var operations: Dictionary = snapshot[&"systems"][&"runtime"][&"operations"]
var facility: FacilityInstance = _runtime.facility_service.get_instance(_facility_id)
var service: ServiceInstance = _runtime.facility_service.get_service(_service_id)
var event: EventInstance = _runtime.event_service.get_instance(&"p04.destroy.instance")
var kitchen: FacilityInstance = _runtime.facility_service.get_instance(facility.related_facility_id)
var actors: Dictionary = {}
var requests: Dictionary = {}
var wallets: Dictionary = {}
for id: StringName in [GUEST, QUEUED_GUEST]:
var guest: GuestRuntime = _runtime.guest_service.get_guest(id)
actors[String(id)] = guest.create_snapshot() if guest != null else {}
wallets[String(id)] = _runtime.economy_service.get_balance(StringName("GUEST_WALLET:" + String(id)))
for id: StringName in [REQUEST, QUEUED_REQUEST]:
var request: ServiceRequest = _runtime.facility_service.get_request(id)
requests[String(id)] = request.create_snapshot() if request != null else {}
var reservations: Array = []
for reservation: InventoryReservation in _runtime.inventory_service.get_reservations(false): reservations.append(reservation.create_snapshot())
var ledger: Array = []
for entry: LedgerEntry in _runtime.economy_service.get_entries(): ledger.append(entry.to_dictionary())
return {&"snapshot": snapshot, &"minute": _clock.absolute_minute,
&"inputs": {&"case": _case, &"seed": SEEDS[_case], &"serial": _serial, &"facility_id": _facility_id, &"service_id": _service_id,
&"boundary": _boundary, &"price": _price, &"duration": _duration, &"patience": _patience, &"reserve": _reserve, &"recovery": _recovery.duplicate(true),
&"kitchen_premise": "ActorHardening physical FLEX fixture; not natural hire/unlock"},
&"related_facility_operating": facility.related_facility_operating, &"mana": _state.get_resource(&"mana"), &"kitchen": kitchen.create_snapshot() if kitchen != null else {}, &"graph_invariants": _runtime.mana_network_service.validate_invariants(),
&"facility": facility.create_snapshot(), &"service": service.create_snapshot() if service != null else {},
&"event": event.create_snapshot() if event != null else {}, &"guests": actors, &"requests": requests, &"wallets": wallets,
&"reservations": reservations, &"ledger": ledger, &"receipts": _receipts.duplicate(true),
&"player_cash": _runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT),
&"available_meals": _runtime.inventory_service.available_quantity(facility.local_inventory_id, &"ingredient/basic_meal"),
&"active_services": _runtime.facility_service.get_active_services(_facility_id).size(),
&"operations_enabled": operations[&"enabled"], &"saved_coordinator": operations[&"coordinator"],
&"actual_coordinator_absent": _runtime.operations_coordinator == null, &"unrelated_getters_called": false}
func _labels() -> Array[String]:
return ["boundary", "held", "recovered"]
func _advance(label: String) -> void:
if label == "boundary":
_cmd(&"spend_resources", {&"cost": {&"mana": _reserve}})
_clock.advance_one_minute()
elif label == "recovered":
_expect(_clock.absolute_minute == _boundary + 1, "recover only after held")
_cmd(&"change_resources", {&"deltas": {&"mana": _reserve}})
_recovery[&"key"] = _commands.back()[&"idempotency_key"]
while _clock.absolute_minute < _boundary + _duration:
_clock.advance_one_minute()
var point: Dictionary = _capture()
if point[&"service"][&"state"] == "COMPLETED":
_recovery[&"resume_minute"] = _clock.absolute_minute
break
_assert_stopped(point)
_expect(_recovery[&"resume_minute"] > 0, "bounded observed recovery completion")
elif label == "duplicate_guard":
var before_replay: Dictionary = _runtime.create_snapshot()
var replay: CommandResult = _runtime.submit_command(&"change_resources", {&"deltas": {&"mana": _reserve}}, &"player", &"", 10, -1, _recovery[&"key"])
var after_replay: Dictionary = _runtime.create_snapshot()
_expect(replay.is_success() and replay.is_replay and var_to_bytes(before_replay) == var_to_bytes(after_replay), "same key replay changes no Runtime field")
_replay_reference = _write("resource-replay", {&"before": before_replay, &"after": after_replay, &"result": replay.to_dictionary()})
_clock.advance_one_minute()
else:
_clock.advance_one_minute()
func _writer_case() -> void:
if not _prepare(): return
var before: Dictionary = _capture()
_assert_before(before)
_points["before"] = _write("before", before)
_connect_observations()
for label: String in _labels():
_advance(label)
var actual: Dictionary = _capture()
_assert_outcome(before, actual)
_save_point(label, actual)
_advance("duplicate_guard")
var guard: Dictionary = _capture()
_assert_outcome(before, guard)
_points["duplicate_guard"] = _write("duplicate_guard", guard)
_branches[_case] = _write("case", {&"resource_replay": _replay_reference, &"points": _points.duplicate(true), &"phases": _phases.duplicate(true),
&"commands": _write("commands", {&"submitted": _commands, &"completed_including_fixture": _results})})
func _assert_before(point: Dictionary) -> void:
_assert_unconfounded(point)
_expect(point[&"mana"] > 0 and point[&"facility"][&"power_available"] and point[&"related_facility_operating"], "initial power and dependency")
_expect(point[&"service"][&"state"] == "ACTIVE" and point[&"service"][&"elapsed_minutes"] == _duration - 1, "natural pre-completion point")
func _assert_unconfounded(point: Dictionary) -> void:
_expect(not point[&"operations_enabled"] and point[&"actual_coordinator_absent"], "isolated fixture")
_expect(point[&"facility"][&"operator_open"] and point[&"facility"][&"durability"] > 0 and point[&"event"].is_empty(), "no closure or destruction")
_expect(point[&"facility"][&"active_staff_ids"] == _recovery[&"staff_ids"], "no shift confound")
_expect(point[&"graph_invariants"][&"valid"], "graph invariants")
if point[&"service"][&"state"] != "COMPLETED":
_expect(point[&"guests"][String(GUEST)][&"state"] == "RECEIVING_SERVICE" and point[&"guests"][String(GUEST)][&"planned_exit_at"] > point[&"minute"], "guest ownership and no exit")
func _assert_stopped(point: Dictionary) -> void:
_assert_unconfounded(point)
var expected_reason: String = "RELATED_FACILITY_INACTIVE" if _case == "S5B_DEPENDENCY" and not point[&"related_facility_operating"] else "NO_POWER"
_expect(point[&"service"][&"state"] == "PAUSED" and point[&"service"][&"interruption_reason"] == expected_reason, "approved actual reason priority")
_expect(point[&"service"][&"elapsed_minutes"] == _duration - 1 and point[&"receipts"].is_empty(), "stopped progress and no payment")
if point[&"minute"] <= _boundary + 1:
_expect(point[&"mana"] == 0 and not point[&"facility"][&"power_available"], "real depleted reserve projects no power")
if _case == "S5B_DEPENDENCY":
_expect(point[&"kitchen"][&"state"] == "NO_POWER" and not point[&"related_facility_operating"], "kitchen NO_POWER before dependent reason")
else:
_expect(point[&"related_facility_operating"], "pure no dependency")
func _assert_reservation(before: Dictionary, point: Dictionary, request_id: StringName, state: String, terminal: int) -> void:
var prior: Array = []
var current: Array = []
for row: Dictionary in before[&"reservations"]:
if row[&"requester_id"] == String(request_id): prior.append(row)
for row: Dictionary in point[&"reservations"]:
if row[&"requester_id"] == String(request_id): current.append(row)
_expect(prior.size() == 1 and current.size() == 1, "one original reservation per request")
if prior.size() != 1 or current.size() != 1: return
_expect(prior[0][&"reservation_id"] == current[0][&"reservation_id"] and current[0][&"state"] == state and current[0][&"terminal_at"] == terminal, "same reservation ID/state/terminal time; no second release")
if state == "ACTIVE":
_expect(var_to_bytes(prior[0]) == var_to_bytes(current[0]), "entire held reservation unchanged")
var request: Dictionary = point[&"requests"][String(request_id)]
_expect(not request.is_empty() and request[&"reserved_inventory_ids"].has(current[0][&"reservation_id"]), "active reservation has live request owner")
else:
_expect(point[&"requests"][String(request_id)].is_empty(), "terminal reservation has no orphan request")
if state == "RELEASED":
var release_count: int = 0
var inventory: Dictionary = point[&"snapshot"][&"systems"][&"runtime"][&"inventory"]
for operation: Dictionary in inventory[&"idempotency_results"]:
var result: Dictionary = operation[&"result"]
if operation[&"action"] == "release" and String(result.get(&"reservation_id", "")) == current[0][&"reservation_id"]:
release_count += 1
_expect(bool(result.get(&"ok", false)) and result.get(&"quantity", 0) == current[0][&"quantity"], "release returned actual reserved quantity, not an orphan repair/retry")
_expect(release_count == 1, "one raw inventory release operation for original reservation")
func _assert_outcome(before: Dictionary, point: Dictionary) -> void:
_assert_unconfounded(point)
var service: Dictionary = point[&"service"]
_expect(service[&"service_id"] == before[&"service"][&"service_id"], "same service ID")
var paid: bool = service[&"state"] == "COMPLETED"
if not paid:
_assert_stopped(point)
_expect(var_to_bytes(point[&"ledger"]) == var_to_bytes(before[&"ledger"]), "entire stopped ledger unchanged")
_expect(var_to_bytes(point[&"requests"][String(REQUEST)]) == var_to_bytes(before[&"requests"][String(REQUEST)]), "same live request and ownership")
else:
_expect(point[&"facility"][&"power_available"] and service[&"elapsed_minutes"] == _duration and point[&"active_services"] == 0, "one recovered completion")
_expect(point[&"receipts"].size() == 1, "exactly one receipt")
var expected: Array = before[&"ledger"].duplicate(true)
for receipt: Dictionary in point[&"receipts"]: expected.append_array(receipt[&"entries"])
_expect(var_to_bytes(expected) == var_to_bytes(point[&"ledger"]), "ledger exactly one receipt")
if _case == "S5B_DEPENDENCY":
_assert_reservation(before, point, REQUEST, "CONSUMED" if paid else "ACTIVE", service[&"completed_at"] if paid else -1)
else:
_expect(point[&"reservations"].is_empty(), "bath has no item inputs; ownership proven through request, service and guest")
_expect(point[&"wallets"][String(GUEST)] == _price * (1 if paid else 2) and point[&"player_cash"] == before[&"player_cash"] + (_price if paid else 0), "one price or zero")
func _save_point(label: String, point: Dictionary) -> void:
_points[label] = _write(label, point)
var path: String = "user://saves/p04_s5/" + _case + "-" + label
var saved: Dictionary = SaveService.save_snapshot(path, point[&"snapshot"])
var inspected: Dictionary = SaveService.inspect_snapshot(path)
_expect(bool(saved.get(&"ok", false)) and bool(inspected.get(&"ok", false)) and bool(inspected.get(&"read_only", false)), "public formal save/inspect")
_expect(var_to_bytes(inspected.get(&"snapshot", {})) == var_to_bytes(point[&"snapshot"]), "all typed fields preserved by formal package")
_expect(var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(point[&"snapshot"]), "formal saving leaves Runtime unchanged")
_slots[_case + "-" + label] = ProjectSettings.globalize_path(path)
# Snapshot bytes exist once in point raw and once in the required formal
# package; indexes do not embed inspection/load copies of those bytes.
func _write(label: String, value: Variant, global_name: bool = false) -> Dictionary:
var name: String = label if global_name else _mode + "-" + _case + "-" + label
var reference: Dictionary = {}
for extension: String in ["var", "json"]:
var path: String = _evidence_dir.path_join(name + "." + extension)
_expect(not FileAccess.file_exists(path), "raw point written exactly once " + name)
var file: FileAccess = FileAccess.open(path, FileAccess.WRITE)
_expect(file != null, "raw file " + name)
if file == null: continue
if extension == "var": file.store_buffer(var_to_bytes(value))
else: file.store_string(JSON.stringify(value, "\t"))
file.flush()
file.close()
reference[extension] = {&"path": path, &"sha256": FileAccess.get_sha256(path)}
return reference
func _read(reference: Dictionary) -> Dictionary:
var item: Dictionary = reference["var"]
var path: String = item["path"]
_expect(FileAccess.get_sha256(path) == item["sha256"], "raw typed SHA")
var json_ref: Dictionary = reference["json"]
_expect(FileAccess.get_sha256(json_ref["path"]) == json_ref["sha256"], "raw JSON SHA")
var file: FileAccess = FileAccess.open(path, FileAccess.READ)
_expect(file != null, "typed input readable")
if file == null: return {}
var value: Variant = bytes_to_var(file.get_buffer(file.get_length()))
file.close()
_expect(value is Dictionary, "typed input dictionary")
return value if value is Dictionary else {}
func _restore_inputs(point: Dictionary) -> void:
var inputs: Dictionary = point[&"inputs"]
_expect(_serial == 0, "Reader starts with serial zero before importing external inputs")
_serial = inputs[&"serial"]
_facility_id = inputs[&"facility_id"]
_service_id = inputs[&"service_id"]
_boundary = inputs[&"boundary"]
_price = inputs[&"price"]
_duration = inputs[&"duration"]
_patience = inputs[&"patience"]
_reserve = inputs[&"reserve"]
_recovery = inputs[&"recovery"].duplicate(true)
func _load_point(path: String, expected: Dictionary) -> bool:
_fresh()
_restore_inputs(expected)
var loaded: Dictionary = SaveService.load_snapshot(path)
_expect(bool(loaded.get(&"ok", false)), "public formal load")
if not bool(loaded.get(&"ok", false)): return false
_expect(var_to_bytes(loaded[&"snapshot"]) == var_to_bytes(expected[&"snapshot"]), "all saved typed fields equal Writer")
var restored: bool = _runtime.restore_snapshot(loaded[&"snapshot"])
_expect(restored, "public Runtime restore")
_expect(var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(expected[&"snapshot"]), "all restored typed fields equal Writer")
return restored
func _is_replayed_phase(row: Dictionary) -> bool:
return int(row[&"minute"]) > _boundary or (int(row[&"minute"]) == _boundary and row[&"phase"] == SimulationKernel.TickPhase.keys()[SimulationKernel.TickPhase.APPLY_COMMANDS])
func _assert_expected_phase_roster(references: Array) -> void:
var expected_pairs: Array = []
var end: int = int(_recovery[&"resume_minute"]) + 1
for minute: int in range(_boundary, end):
for phase: int in range(SimulationKernel.TickPhase.size()):
expected_pairs.append([minute if phase == SimulationKernel.TickPhase.APPLY_COMMANDS else minute + 1, SimulationKernel.TickPhase.keys()[phase]])
var actual_pairs: Array = []
for reference: Dictionary in references:
var row: Dictionary = _read(reference)
actual_pairs.append([int(row[&"minute"]), row[&"phase"]])
_expect(actual_pairs == expected_pairs, "complete dynamic replay phase roster with no omissions")
func _reader() -> void:
var file: FileAccess = FileAccess.open(_evidence_dir.path_join("writer.json"), FileAccess.READ)
_expect(file != null, "Writer receipt")
if file == null: return
var writer: Dictionary = JSON.parse_string(file.get_as_text())
file.close()
_expect(int(writer["pid"]) != OS.get_process_id() and writer["profile"] != OS.get_user_data_dir(), "independent Reader PID/profile")
for branch: String in CASES:
_case = branch
var writer_case: Dictionary = _read(writer["branches"][branch])
var hashes: Dictionary = {}
var restored_refs: Dictionary = {}
for label: String in _labels():
var key: String = branch + "-" + label
var original: String = writer["slots"][key]
var target: String = ProjectSettings.globalize_path("user://saves/p04_s5/" + key)
_expect(DirAccess.make_dir_recursive_absolute(target) == OK, "private Reader formal slot")
var directory: DirAccess = DirAccess.open(original)
_expect(directory != null, "Writer formal slot readable")
if directory == null: return
var members: PackedStringArray = directory.get_files()
members.sort()
_expect(directory.get_directories().is_empty() and members == PackedStringArray(["journal.log", "manifest.json", "thumbnail.png", "world.bin"]), "all formal members enumerated")
var member_hashes: Dictionary = {}
for member: String in members:
var sha: String = FileAccess.get_sha256(original.path_join(member))
_expect(DirAccess.copy_absolute(original.path_join(member), target.path_join(member)) == OK, "copy every formal member")
var copied_sha: String = FileAccess.get_sha256(target.path_join(member))
_expect(not sha.is_empty() and sha == copied_sha, "original/copy member SHA equality")
member_hashes[member] = {&"original_before": sha, &"copy_before": copied_sha}
hashes[key] = {&"original": original, &"copy": target, &"members": member_hashes}
_slots[key] = target
var expected: Dictionary = _read(writer_case[&"points"][label])
if not _load_point(target, expected): return
restored_refs[label] = _write(label + "-restored", _capture())
var before: Dictionary = _read(writer_case[&"points"]["before"])
var boundary: Dictionary = _read(writer_case[&"points"]["boundary"])
if not _load_point(_slots[branch + "-boundary"], boundary): return
_assert_stopped(_capture())
_connect_observations()
var replay_refs: Dictionary = {}
for label: String in ["held", "recovered", "duplicate_guard"]:
_advance(label)
var actual: Dictionary = _capture()
var expected: Dictionary = _read(writer_case[&"points"][label])
_expect(var_to_bytes(actual) == var_to_bytes(expected), "replay complete typed point including Runtime, inputs, receipts " + label)
_assert_outcome(before, actual)
replay_refs[label] = _write(label + "-replay", actual)
var expected_phases: Array = []
for reference: Dictionary in writer_case[&"phases"]:
if _is_replayed_phase(_read(reference)): expected_phases.append(reference)
_assert_expected_phase_roster(expected_phases)
_expect(_phases.size() == expected_phases.size(), "complete phase count")
if _phases.size() == expected_phases.size():
for index: int in range(_phases.size()):
_expect(var_to_bytes(_read(_phases[index])) == var_to_bytes(_read(expected_phases[index])), "same phase order and all typed phase state")
for key: String in hashes:
var row: Dictionary = hashes[key]
for member: String in row[&"members"]:
var item: Dictionary = row[&"members"][member]
item[&"original_after"] = FileAccess.get_sha256(String(row[&"original"]).path_join(member))
item[&"copy_after"] = FileAccess.get_sha256(String(row[&"copy"]).path_join(member))
_expect(item[&"original_before"] == item[&"original_after"] and item[&"copy_before"] == item[&"copy_after"], "original/copy unchanged after all loads and replay")
_branches[branch] = _write("case", {&"resource_replay": _replay_reference, &"restored": restored_refs, &"replay": replay_refs, &"phases": _phases,
&"member_hashes": hashes, &"recovery_commands": _commands, &"replay_completed_commands": _results})
@@ -0,0 +1,405 @@
#!/usr/bin/env python3
"""S5-only native entry. --check-only never loads ownership helpers or starts Godot."""
from pathlib import Path
import argparse
import copy
import hashlib
import importlib.util
import json
import os
import shutil
import subprocess
import stat
import sys
sys.dont_write_bytecode = True
HERE = Path(__file__).resolve().parent
BUILD = Path("/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build")
PRODUCT = BUILD / "audit-support/p04-r17-full-inputs-r01/product"
CACHE_RUN = BUILD / "p04-final-product-full-r01"
TEST = "tests/s3/test_runtime_staff_assignment.gd"
QA = HERE / "p04_s5_power_probe.gd"
ENGINE = Path("/Applications/Godot.app/Contents/MacOS/Godot")
ENGINE_SHA256 = "c7cccbf8fb143e34e02fd6521e09be2c2b974f0d5db080b19071c9c570718ccf"
MANIFEST = BUILD / "audit-support/p04-r17-full-inputs-r01/MANIFEST.json"
MANIFEST_SHA = "a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c8a8"
CONTRACTS = BUILD / "audit-support/p04-r17-full-inputs-r01/fixed/6ce6b28c5985e8a4f13b78bfeb1f1e09f6216d874fb01e0656ec1633bfa01cd7/completion_marker_contracts.json"
CASES = ["S5A_PURE", "S5B_DEPENDENCY"]
LABELS = {case: ["boundary", "held", "recovered"] for case in CASES}
SLOTS = sorted(case + "-" + label for case in CASES for label in LABELS[case])
MATERIALS = [MANIFEST, BUILD / "audit-support/p04-review-repair22-r01/ACTUAL_CURRENT_PUBLIC_POWER_FUNCTIONS.json"]
def template_guard(root):
if root != PRODUCT.resolve() or not HERE.is_relative_to(BUILD.resolve()):
raise ValueError("Root must stage this exact QA/wrapper/plan inside own B")
if pin(MANIFEST)["sha256"] != MANIFEST_SHA:
raise ValueError("immutable full R17 relocation manifest")
manifest = json.loads(MANIFEST.read_text())
for name, source in manifest["product_source"].items():
# Old absolute paths are lookup keys only. Never open them.
row = manifest["original_to_relocated"][source["path"]]
actual = pin(root / name)
if Path(row["relocated"]).resolve() != root / name or any(
actual[k] != source[k] or actual[k] != row[k] for k in ("bytes", "sha256")):
raise ValueError("relocated product differs: " + name)
probe = QA.read_text()
import re
if ":=" in probe or re.search(r"\bvar\s+\w+\s*=", probe) or re.search(r"\bfor\s+\w+\s+in\b", probe):
raise ValueError("explicit typed declarations/loops required")
if re.search(r"\.(?:patience_remaining|elapsed_minutes|power_available|capacity|hold_until)\s*=(?!=)", probe):
raise ValueError("forbidden direct state mutation")
for forbidden in ["evaluate_now(", "configure_operations(", "._update_shift_states(", ".record_duty_minute("]:
if forbidden in probe:
raise ValueError("forbidden bypass: " + forbidden)
# Constants and public bodies are read from the actual selected source, not a memo.
mana = (root / "scripts/mana/mana_network_service.gd").read_text()
for key in ("EVALUATION_INTERVAL_MINUTES", "MINIMUM_OFF_HOLD_MINUTES"):
if not re.search(r"const " + key + r" := 10\b", mana):
raise ValueError("source timing changed: " + key)
def module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
value = importlib.util.module_from_spec(spec)
spec.loader.exec_module(value)
return value
def pin(path):
path = Path(path)
if path.is_symlink() or not path.is_file():
raise ValueError("missing exact input: " + str(path))
data = path.read_bytes()
return dict(path=str(path), bytes=len(data), sha256=hashlib.sha256(data).hexdigest())
def engine_pin(path, expected=None):
path = Path(path)
if path != ENGINE or any(p.is_symlink() for p in (path, *path.parents)):
raise ValueError("exact installed engine required; no symlink or relocated input")
if path.resolve(strict=True) != ENGINE:
raise ValueError("installed engine resolved path changed")
before = path.stat()
if not stat.S_ISREG(before.st_mode):
raise ValueError("installed engine must be regular")
digest = hashlib.sha256(path.read_bytes()).hexdigest()
after = path.stat()
fields = ("st_dev", "st_ino", "st_size", "st_mtime_ns", "st_ctime_ns", "st_mode")
if any(getattr(before, k) != getattr(after, k) for k in fields):
raise ValueError("engine changed while hashing")
if any(p.is_symlink() for p in (path, *path.parents)) or path.resolve(strict=True) != ENGINE:
raise ValueError("engine path changed while hashing")
value = dict(path=str(path), resolved_path=str(path.resolve(strict=True)),
bytes=after.st_size, mtime_ns=after.st_mtime_ns, mode=after.st_mode,
device=after.st_dev, inode=after.st_ino, ctime_ns=after.st_ctime_ns, sha256=digest)
if digest != ENGINE_SHA256:
raise ValueError("engine differs from installed engine constant")
if expected is not None and value != expected:
raise ValueError("engine identity changed")
return value
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--project-root", type=Path, default=PRODUCT)
parser.add_argument("--output", type=Path, default=BUILD / "p04-s5-native-r32")
parser.add_argument("--plan", type=Path, default=BUILD / "p04-s5-plan-r32.json")
parser.add_argument("--cache-run", type=Path, default=None,
help="optional passed registered cache; default is fresh, without cache access")
parser.add_argument("--godot", type=Path, default=ENGINE)
parser.add_argument("--check-only", action="store_true")
args = parser.parse_args()
engine_descriptor = engine_pin(args.godot)
if args.cache_run is not None and args.cache_run.resolve() != CACHE_RUN.resolve():
raise ValueError("only registered own-B full-run cache")
root = args.project_root.resolve()
out = args.output.resolve()
if not out.is_relative_to(BUILD.resolve()) or not args.plan.resolve().is_relative_to(BUILD.resolve()):
raise ValueError("plan/output must stay in task build")
if out.exists() or out.is_symlink():
raise ValueError("fresh output required")
if args.check_only and (args.plan.exists() or args.plan.is_symlink()):
raise ValueError("fresh plan required")
r = module("s5_standard_runner", root / "tools/run_all_tests.py")
# Preserve the reviewed source_refs -> exactly one QA override order.
source_before = r.source_refs(root)
refs = dict(source_before)
refs[TEST] = pin(QA)
template_guard(root)
expected = {n: dict(bytes=p["bytes"], sha256=p["sha256"]) for n, p in refs.items()}
fixed = [pin(p) for p in MATERIALS + [
QA, Path(__file__), HERE / "S5_ROOT_RUN.md",
root / "tests/transport/test_runtime_transport.gd",
root / "tests/staff/test_rescue_elevator.gd",
CONTRACTS,
]]
selected = dict(root_before=source_before, map={n: p["sha256"] for n, p in refs.items()}, timeout=1200)
cache_note = None
cache_receipts = []
if args.cache_run is not None:
# Reject failed caches before reading their inputs or cache contents.
r.require(r.read(args.cache_run / "runner-ended.json")["passed"] is True,
"failed cache is ineligible")
for leaf in (["runner-ended.json", "runner-input.json"] if args.cache_run is not None else []):
path = args.cache_run / leaf
try:
cache_receipts.append(pin(path))
except OSError as caught:
cache_note = dict(path=str(path), error=type(caught).__name__ + ": " + str(caught),
required_before_native=True)
break
plan = dict(protocol="p04-s5-preparation-v1", project_root=str(root), output=str(out), engine_path=str(args.godot.resolve()),
source_before=source_before, selected_source_map=selected["map"],
QA_overrides=[TEST], fixed_input_pins=fixed,
cache_run=str(args.cache_run) if args.cache_run is not None else None,
import_mode="cache" if args.cache_run is not None else "fresh",
engine_sha256=ENGINE_SHA256, engine=engine_descriptor,
cache_receipts=cache_receipts, cache_access=cache_note,
phases=["import", "parse", "writer", "reader"],
native_engine_launches=0, whole_goal_accepted=False, unit_accepted=False)
# Check-only only reads source/materials and writes the plan in task build.
# Reads engine identity; never launches Godot or inspects players/processes.
if args.check_only:
args.plan.parent.mkdir(parents=True, exist_ok=True)
r.write(args.plan, plan)
print(json.dumps(dict(check_only=True, engines=0, source_files=len(source_before),
QA_overrides=[TEST], fixed_pins=len(fixed), plan=str(args.plan),
plan_sha256=r.sha(args.plan), cache_access=cache_note), ensure_ascii=False))
return 0
r.require(root == PRODUCT.resolve() and len(source_before) == 1338, "Root native requires product 1338; worker plan is not native evidence")
r.require(args.plan.is_file() and r.read(args.plan) == plan, "run exact check-only plan first")
engine_observations = []
engine_identity = dict(before=engine_descriptor, during=[], after=None)
def repin(label):
try:
value = engine_pin(args.godot, engine_descriptor)
engine_observations.append(dict(stage=label, descriptor=value))
if label == "after-cleanup":
engine_identity["after"] = value
else:
engine_identity["during"].append(value)
except BaseException as caught:
engine_observations.append(dict(stage=label, error=str(caught)))
raise
def fixed_guard():
repin("cleanup-fixed-guard")
template_guard(root)
for value in fixed + cache_receipts:
r.require(pin(value["path"]) == value, "fixed input changed: " + value["path"])
fixed_guard()
old = args.cache_run
if old is not None:
# Native cache admission remains Root-only and fails closed.
r.require(cache_note is None, "Root must read exact cache receipts: " + str(cache_note))
r.require(r.read(old / "runner-ended.json")["passed"], "ended cache run must have passed")
cache_input = r.read(old / "runner-input.json")
r.require(cache_input["engine_sha256"] == ENGINE_SHA256, "cache engine identity")
old_map = cache_input["selected_source_map"]
current_map = {n: p["sha256"] for n, p in source_before.items()}
r.require({k: v for k, v in old_map.items() if k != "tools/check_p04_order_evidence.py"} == current_map and len(old_map) == 1339, "immutable full cache: all 1338 product inputs equal; checker is not parsed/executed by product suites")
protected = r.default_player(root)
outer = module("s5_owned_outer", r.SUPPORT / "owned_outer.py")
r.require(not outer.native.helper["live_engines"](), "another Godot owns CPU")
engine = ENGINE
repin("native-admission")
r.require(shutil.disk_usage(out.parent).free >= 1024**3 + engine.stat().st_size + 136*1024**2,
"reviewed native disk admission")
r.require(not out.exists(), "fresh output required; preserve previous attempts")
out.mkdir()
stage = out / "stage"
stage.mkdir()
(out / "starters").mkdir()
(out / "bootstrap").mkdir()
phases = []
previous = {}
error = None
guards = []
cleanup = []
cleanup_errors = []
cache_before = None
formal_before = None
formal_after = None
original_phase = outer.run_phase
def run_phase(argv, folder, timeout, env, **kwargs):
env = dict(env)
if folder.name in ["writer", "reader"]:
env.update(THE_TREE_S5_EVIDENCE=str(out / "raw"), THE_TREE_S5_MODE=folder.name)
return original_phase(argv, folder, timeout, env, **kwargs)
outer.run_phase = run_phase
try:
r.write(out / "runner-started.json", dict(started=r.now(), owner_runner_pid=os.getpid(),
plan=pin(args.plan), engines_launched=0))
r.write(out / "source_before.json", source_before)
r.write(out / "selected-source-map.json", refs)
# Private source stage first, then literal reviewed bootstrap.
for name, value in refs.items():
target = stage / name
target.parent.mkdir(parents=True, exist_ok=True)
r.copy_source(Path(value["path"]), target)
r.require(r.inventory(stage, stage=True) == expected, "whole private source")
for name, value in r.read(r.SUPPORT / "bootstrap-scripts.json").items():
data = value["text"].encode()
r.require(hashlib.sha256(data).hexdigest() == value["sha256"], "bootstrap pin")
(out / "bootstrap" / name).write_bytes(data)
if old is not None:
cache = old / "stage/.godot"
cache_before = r.inventory(cache)
r.require(bool(cache_before), "nonempty ended cache")
for name in cache_before:
src = cache / name
dst = stage / ".godot" / name
dst.parent.mkdir(parents=True, exist_ok=True)
subprocess.run(["/bin/cp", "-c", str(src), str(dst)], check=True)
r.require((src.stat().st_dev, src.stat().st_ino) != (dst.stat().st_dev, dst.stat().st_ino),
"cache clone is a separate inode")
r.require(r.inventory(stage / ".godot") == cache_before, "whole cache clone hashes")
r.write(out / "cache-reuse.json", dict(ended_run=str(old), receipts=cache_receipts,
whole_cache=cache_before, independent_inode=True,
ordinary_import_required=True, ordinary_parse_required=True))
paths = ["res://" + n for n in sorted(refs) if n.endswith(".gd")]
r.require(len(paths) == 316, "complete 316-script parse roster")
r.write(out / "parse-paths.json", paths)
markers = module("s5_markers", root / "tools/strict_test_markers.py")
contracts = markers.load_contracts(CONTRACTS)
contracts[TEST] = dict(test=TEST, template="S5 power: <checks> checks, <failures> failures", required=True)
policy = r.read(r.SUPPORT / "suite-policy.json")
r.require(TEST not in policy["suite_policies"], "no normal suite watchdog/policy override")
r.write(out / "contracts.json", contracts)
r.write(out / "runner-input.json", dict(plan, owner_runner_pid=os.getpid(),
wrapper_sha256=r.sha(__file__), QA=pin(QA), engine=engine_descriptor,
engine_identity_before=engine_descriptor, engine_identity_initial=copy.deepcopy(engine_identity),
runner_sha256=r.sha(root / "tools/run_all_tests.py"),
default_player_before=protected, fixed_input_pins=fixed,
functional_watchdog_seconds=1200, source_adoption=False))
diagnostics = module("s5_diagnostics", r.SUPPORT / "diagnostic_gate.py")
owners = module("s5_owners", r.SUPPORT / "ordinary_proof_gate.py")
audio = module("s5_audio", r.SUPPORT / "audio_evidence_gate.py")
public = (stage / "project.godot").read_bytes()
for phase, test in [("import", None), ("parse", None), ("writer", TEST), ("reader", TEST)]:
if phase == "reader":
writer = r.read(out / "raw/writer.json")
formal_before = {n: r.inventory(Path(p)) for n, p in writer["slots"].items()}
r.require(sorted(formal_before) == SLOTS, "exact three formal points for isolated power case")
if phase == "import" and old is None:
r.require(not (stage / ".godot").exists() and not (stage / ".godot").is_symlink(),
"fresh private .godot absent at actual import")
repin("before-" + phase)
r.write(out / ("engine-identity-before-" + phase + ".json"),
dict(engine_observations[-1], observation_index=len(engine_observations)-1))
row = r.execute_phase(str(engine), stage, out, phase, test, selected, expected,
previous, policy, contracts, paths, public, protected, root,
outer, markers, diagnostics, owners, audio)
phases.append(row)
# execute_phase writer/reader share out/<test>.log via write_text.
# Keep binary per-phase copies under these existing unique names.
# The shared runner log is not write-once; see S5_ROOT_RUN.md.
if test and row.get("log"):
(out / (phase + "-combined-raw.log")).write_bytes((out / row["log"]).read_bytes())
row["strict_runner_log_path"] = row["log"]
row["log"] = phase + "-combined-raw.log"
r.write(out / (phase + "-actual-phase.json"), row)
print(json.dumps(dict(phase=phase, passed=row["passed"], error=row.get("validation_error"))), flush=True)
r.require(row["passed"], "first strict phase failure: " + phase)
if phase in ["writer", "reader"]:
receipt = r.read(out / ("raw/" + phase + ".json"))
r.require(receipt["checks"] > 0 and receipt["failures"] == 0,
"S5 actual outcome receipt")
r.require(sorted(receipt["branches"]) == CASES,
"exact one independent Writer/Reader case")
r.require(sorted(receipt["slots"]) == SLOTS, "all formal point slots")
r.require(receipt["pid"] == row["actual_pid"], "actual native PID/receipt")
repin("after-collection")
writer = r.read(out / "raw/writer.json")
reader = r.read(out / "raw/reader.json")
r.require(writer["pid"] != reader["pid"] and writer["profile"] != reader["profile"], "distinct formal processes")
formal_after = {n: r.inventory(Path(p)) for n, p in writer["slots"].items()}
r.require(formal_before == formal_after, "Reader leaves Writer packages unchanged")
except BaseException as caught:
error = type(caught).__name__ + ": " + str(caught)
finally:
try:
cleanup, cleanup_errors = outer.finish_captured(outer.OWNED)
except BaseException as caught:
cleanup_errors.append(str(caught))
try:
r.write(out / "outer-owned-finally.json", dict(cleanup=cleanup, errors=cleanup_errors))
except BaseException as caught:
guards.append("finally receipt: " + type(caught).__name__ + ": " + str(caught))
# Explicit re-pin after cleanup is independent of other fixed-input guards.
try:
repin("after-cleanup")
except BaseException as caught:
guards.append(type(caught).__name__ + ": " + str(caught))
# Fixed guard always follows ownership cleanup, even if setup or an engine failed.
try:
fixed_guard()
after = r.source_refs(root)
r.write(out / "source_after.json", after)
r.require(after == source_before, "whole product source unchanged")
r.require(r.default_player(root) == protected, "default player unchanged")
if (stage / "project.godot").exists():
r.require(r.inventory(stage, stage=True) == dict(expected, **previous), "whole private source unchanged")
if cache_before is not None:
r.require(r.inventory(old / "stage/.godot") == cache_before, "original cache unchanged")
if formal_before is not None:
writer = r.read(out / "raw/writer.json")
formal_after = {n: r.inventory(Path(p)) for n, p in writer["slots"].items()}
r.require(formal_before == formal_after, "Writer formal packages unchanged after Reader, including failure")
except BaseException as caught:
guards.append(type(caught).__name__ + ": " + str(caught))
pids = [p.pid for p in outer.OWNED]
passed = (error is None and not guards and not cleanup_errors and len(phases) == 4
and all(p["passed"] for p in phases) and len(pids) == len(set(pids)) == 4
and all(p["engine_ended"] for p in cleanup))
execution = dict(passed=passed, error=error, guard_errors=guards, phases=phases,
actual_captured_PIDs=pids, cleanup=cleanup, cleanup_errors=cleanup_errors,
formal_before=formal_before, formal_after=formal_after,
whole_goal_accepted=False, unit_accepted=False)
# IO1 has already copied all four members into a separate Reader profile.
# Mirror those exact complete directories to own B for read-only R verification.
# Original profile paths are provenance after this step, never verifier inputs.
try:
if passed:
relocated = {}
for role in ("writer", "reader"):
receipt = r.read(out / ("raw/" + role + ".json"))
relocated[role] = {}
for slot, original in receipt["slots"].items():
target = out / "formal" / role / slot
target.mkdir(parents=True)
members = r.inventory(Path(original))
r.require(set(members) == {"journal.log", "manifest.json", "thumbnail.png", "world.bin"}, "all formal members")
for member in members:
shutil.copyfile(Path(original) / member, target / member)
r.require(r.inventory(target) == members == formal_before[slot], "whole formal mirror")
relocated[role][slot] = dict(provenance=original, relative=str(target.relative_to(out)), members=members)
r.write(out / "formal-relocation.json", relocated)
r.write(out / "raw-inventory.json", r.inventory(out / "raw"))
r.write(out / "PID-set.json", dict(owner_runner_pid=os.getpid(), engine_PIDs=pids))
except BaseException as caught:
guards.append("output collection: " + type(caught).__name__ + ": " + str(caught))
passed = False
execution["passed"] = False
try:
repin("after-output-collection")
except BaseException as caught:
guards.append(str(caught))
passed = False
execution["passed"] = False
try:
r.write(out / "engine-identity.json",
dict(observations=engine_observations, identity=engine_identity))
except BaseException as caught:
guards.append("engine identity receipt: " + type(caught).__name__ + ": " + str(caught))
passed = False
execution["passed"] = False
execution["engine_observations"] = engine_observations
execution["engine_identity"] = engine_identity
r.write(out / "execution.json", execution)
r.write(out / "runner-ended.json", dict(execution, ended=r.now()))
print(json.dumps(dict(passed=passed, error=error, guard_errors=guards, output=str(out))))
return 0 if passed else 1
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as caught:
print(type(caught).__name__ + ": " + str(caught), file=sys.stderr)
raise SystemExit(2)
@@ -0,0 +1,145 @@
#!/usr/bin/env python3
"""Derive S5 power measurements from hashed writer/reader raw, not test counts.
This semantic adapter does not verify engine provenance, Q or full-suite joins.
Its output is preparation only and cannot replace the registered evidence gate.
"""
import argparse
import hashlib
import json
from pathlib import Path
CASES = ("S5A_PURE", "S5B_DEPENDENCY")
GUEST = "p04.s5.guest.a"
REQUEST = "p04.s5.request.a"
def require(value, message):
if not value:
raise ValueError(message)
def unique(pairs):
result = {}
for key, value in pairs:
require(key not in result, "duplicate raw key")
result[key] = value
return result
class Raw:
def __init__(self, root):
self.root = root.resolve(strict=True)
self.hashes = {}
def pin(self, path, expected):
path = Path(path)
require(path.is_file() and not path.is_symlink() and path.resolve().is_relative_to(self.root), "raw reference outside root/missing")
data = path.read_bytes()
digest = hashlib.sha256(data).hexdigest()
require(digest == expected, "raw reference SHA mismatch")
self.hashes[str(path)] = digest
return data
def reference(self, reference):
require(set(reference) == {"var", "json"}, "typed and JSON raw references required")
self.pin(reference["var"]["path"], reference["var"]["sha256"])
return json.loads(self.pin(reference["json"]["path"], reference["json"]["sha256"]), object_pairs_hook=unique)
def derive(root, writer_sha, reader_sha):
raw = Raw(root)
writer = json.loads(raw.pin(root / "writer.json", writer_sha), object_pairs_hook=unique)
reader = json.loads(raw.pin(root / "reader.json", reader_sha), object_pairs_hook=unique)
require(writer["pid"] != reader["pid"] and writer["profile"] != reader["profile"], "independent reader required")
require(set(writer["branches"]) == set(reader["branches"]) == set(CASES), "exact case pair")
output = {}
for case in CASES:
branch = raw.reference(writer["branches"][case])
replay = raw.reference(reader["branches"][case])
raw.reference(branch["commands"])
for role in (branch, replay):
guard = raw.reference(role["resource_replay"])
require(guard["result"]["is_replay"] is True and guard["result"]["code"] == "OK"
and guard["before"] == guard["after"], "resource replay changes no Runtime field")
points = {name: raw.reference(ref) for name, ref in branch["points"].items()}
require(set(points) == {"before", "boundary", "held", "recovered", "duplicate_guard"}, "full point roster")
before = points["before"]
price, duration = before["inputs"]["price"], before["inputs"]["duration"]
require(price > 0 and duration > 1 and before["mana"] > 0, "paid natural service")
service_id = before["service"]["service_id"]
require(before["service"]["state"] == "ACTIVE" and before["service"]["elapsed_minutes"] == duration - 1, "pre-boundary progress")
reservations = before["requests"][REQUEST]["reserved_inventory_ids"]
require(len(reservations) == (1 if case == "S5B_DEPENDENCY" else 0), "item premise")
for label in ("boundary", "held"):
point = points[label]
service = point["service"]
require(point["minute"] == before["inputs"]["boundary"] + (label == "held"), "boundary minute")
require(point["mana"] == 0 and point["facility"]["power_available"] is False, "real depletion projection")
reason = "RELATED_FACILITY_INACTIVE" if case == "S5B_DEPENDENCY" else "NO_POWER"
require(service["state"] == "PAUSED" and service["interruption_reason"] == reason
and service["elapsed_minutes"] == duration - 1 and service["service_id"] == service_id, "stopped reason/progress/service")
require(point["receipts"] == [] and point["ledger"] == before["ledger"]
and point["wallets"][GUEST] == price * 2 and point["player_cash"] == before["player_cash"], "zero stopped charge")
require(point["requests"][REQUEST] == before["requests"][REQUEST]
and point["guests"][GUEST]["state"] == "RECEIVING_SERVICE", "live request/guest ownership")
require(point["reservations"] == before["reservations"], "entire reservation retained")
if case == "S5B_DEPENDENCY":
require(point["kitchen"]["state"] == "NO_POWER" and point["related_facility_operating"] is False, "RELATED-before-NO_POWER")
require(all(r["state"] == "ACTIVE" and r["requester_id"] == REQUEST for r in point["reservations"]), "active item owner")
else:
require(point["related_facility_operating"] is True, "pure power premise")
recovered = points["recovered"]
resume = recovered["inputs"]["recovery"]["resume_minute"]
require(recovered["minute"] == resume and resume <= before["inputs"]["boundary"] + duration, "bounded observed resume")
for label in ("recovered", "duplicate_guard"):
point = points[label]
service = point["service"]
require(service["service_id"] == service_id and service["state"] == "COMPLETED"
and service["elapsed_minutes"] == duration and point["active_services"] == 0, "one completed service")
require(len(point["receipts"]) == 1 and point["ledger"] == before["ledger"] + point["receipts"][0]["entries"], "whole ledger single receipt")
require(point["wallets"][GUEST] == price and point["player_cash"] == before["player_cash"] + price, "single price")
require(point["receipts"] == recovered["receipts"] and point["ledger"] == recovered["ledger"], "no duplicate sale")
if reservations:
require(len(point["reservations"]) == 1, "same item count")
r = point["reservations"][0]
require(r["reservation_id"] == reservations[0] and r["state"] == "CONSUMED"
and r["terminal_at"] == service["completed_at"] and point["requests"][REQUEST] == {}, "consumed without orphan")
for label in ("held", "recovered", "duplicate_guard"):
require(raw.reference(replay["replay"][label]) == points[label], "reader full raw replay mismatch")
for label in ("boundary", "held", "recovered"):
require(raw.reference(replay["restored"][label])["snapshot"] == points[label]["snapshot"], "formal restore snapshot mismatch")
phases = [raw.reference(ref) for ref in branch["phases"]]
expected_replay = [p for p in phases if p["minute"] > before["inputs"]["boundary"] or
(p["minute"] == before["inputs"]["boundary"] and p["phase"] == "APPLY_COMMANDS")]
require([raw.reference(ref) for ref in replay["phases"]] == expected_replay, "all reader phase raw mismatch")
reasons = []
for p in phases:
reason = p["service"].get("interruption_reason", "")
if not reasons or reasons[-1] != reason:
reasons.append(reason)
output[case] = dict(measurements={
**({"power_stop": {"charges": 0}} if case == "S5A_PURE" else
{"dependency_stop": {"charges": 0, "progress_delta": 0, "reservation_ids_preserved": True, "service_id_preserved": True}}),
"recovery_completion": {"completions": 1, "charges": 1}},
reason_sequence=reasons, resume_minute=resume)
return dict(cases=output, raw_sha256=raw.hashes, native_provenance_verified=False,
whole_goal_accepted=False, unit_accepted=False)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--raw-root", type=Path, required=True)
parser.add_argument("--writer-sha256", required=True)
parser.add_argument("--reader-sha256", required=True)
args = parser.parse_args()
try:
print(json.dumps(derive(args.raw_root, args.writer_sha256, args.reader_sha256), sort_keys=True))
except (OSError, ValueError, KeyError, TypeError) as error:
print(json.dumps({"error": str(error), "whole_goal_accepted": False}))
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
"""Root-only scratch routing for preserved partial31 fixture sources.
Only TemporaryDirectory allocation is redirected. Fixture assertions and checker
semantics remain unchanged. No fixture is run by importing this adapter.
"""
import argparse
import os
from pathlib import Path
import runpy
import sys
import tempfile
sys.dont_write_bytecode = True
HERE = Path(__file__).resolve().parent
FIXTURES = {"bulk_reader_equivalence", "checker_role_fixtures", "checker_candidate_fixtures",
"checker_approval_fixtures", "checker_negative_fixtures", "checker_applicability_fixtures"}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--scratch", type=Path, required=True)
parser.add_argument("--fixture", choices=sorted(FIXTURES), required=True)
parser.add_argument("arguments", nargs=argparse.REMAINDER)
args = parser.parse_args()
scratch = args.scratch.resolve()
repository = HERE.parents[4]
if scratch.exists() or scratch.is_relative_to(repository) or scratch == Path("/tmp").resolve() or Path("/tmp").resolve() in scratch.parents:
raise ValueError("fresh external scratch required; no repository or /tmp writes")
scratch.mkdir(parents=True)
old_env, old_argv = dict(os.environ), sys.argv[:]
original = tempfile.TemporaryDirectory
def directory(suffix=None, prefix=None, dir=None, **kwargs):
# Explicit dir in old source is intentionally superseded only here.
return original(suffix=suffix, prefix=prefix, dir=scratch, **kwargs)
try:
for name in list(os.environ):
if name.startswith("GIT_"):
del os.environ[name]
os.environ["TMPDIR"] = str(scratch)
tempfile.TemporaryDirectory = directory
forwarded = args.arguments[1:] if args.arguments[:1] == ["--"] else args.arguments
source = HERE / (args.fixture + ".py")
sys.argv = [str(source), *forwarded]
runpy.run_path(str(source), run_name="__main__")
finally:
tempfile.TemporaryDirectory = original
sys.argv = old_argv
os.environ.clear()
os.environ.update(old_env)
if __name__ == "__main__":
main()
+89 -115
View File
@@ -20,13 +20,31 @@ ROOT = Path(__file__).resolve().parents[1]
SPEC = ROOT / 'docs/spec/acceptance/P04-01.json'
SPEC_HASH = '9ec722e7dfb0bee178d291624a026420c08412574e238bba1fde012c7a6f7881'
DOMAINS = {'閉店', '停電', '破壊', '退出', '課金', 'シフト交代', '00:00決算'}
OWNER_HASH = '4583ee9aad45c4db183d72df4420df48aa8e0897e3b5efda13016f0b5cdbd68e'
REGISTERED_COMMIT = 'deb1bcb2374eb378b840ca345db952bd8572cb6e'
EXECUTION_ORIGIN = '9767b0a28ca8d252520307dbbac60a1d8cfb87ab'
CHECKER_PATH = 'tools/check_p04_order_evidence.py'
DOC_SCOPE = 'docs/plans/original-completion-2026-10-02/execution/p04-01/'
MAIN_ANCHOR = '9b1a18c1eb25ca1300dcd59da78423c0dda2f498'
TESTED_PRODUCT = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1'
OWNER_BINDINGS = {
ref: (DOC_SCOPE + leaf, digest)
for refs, leaf, digest in (
(('D05-P04-DEPENDENCY', 'D05-P04-SHIFT-1800'), 'D05_OWNER_APPROVAL.json',
'4583ee9aad45c4db183d72df4420df48aa8e0897e3b5efda13016f0b5cdbd68e'),
(('D05-P04-DESTRUCTION', 'D05-P04-MIDNIGHT-DAY', 'D05-P04-PAUSE-REASON',
'D05-P04-EXIT'), 'D05_REMAINING_APPROVAL.json',
'09b5092124574c3ccbf3b55169729a7529d9dde9b9a115d5e944fce4b960f5e4'),
) for ref in refs
}
MAIN_ANCHOR = 'c0ea009b28a7649aca6a433a1a24dc0be5e7ab81'
# Required evidence content, not an invented Runner API. Root must supply the
# independently authoritative receipt path/hash contract before C can qualify.
# Neither an index nor a commit with matching parents/tree can supply authority.
NORMAL_C_RECEIPT_CONTRACT = None
NORMAL_C_RECEIPT_FIELDS = frozenset({
'candidate_commit', 'candidate_tree', 'first_parent', 'second_parent',
'tested_tree', 'prepare_integration_receipt', 'independent_review_receipt',
'validation_receipt', 'source_manifest_sha256', 'settings_sha256',
'markers_sha256', 'policy_sha256', 'engine_sha256', 'inputs_sha256',
})
SELECTION_SHA = '320ca668732b4ff72fc4449998af2327d4e5c527b06896740806aaf0487282b4'
_GIT_ENV = None
# Fixed membership, never supplied by the evidence index.
@@ -43,19 +61,20 @@ ORDER_FUNCTIONS = {
'scripts/operations/operations_coordinator.gd': ('_process_minute_boundaries',),
}
# Condition -> (domain, authority refs, required engine measurements).
# Measurements describe safety/counts, not the still-pending attribution policy.
# Existing safety/count thresholds are retained. Repair30's additional approved
# order measurements still need the S5 raw adapter (see REPAIR30_STATUS.md).
REQUIRED = {
'power_stop': ('停電', ('BASELINE:183',), {'charges': 0}),
'destruction_stop': ('破壊', ('BASELINE:183',), {'charges': 0}),
'power_stop': ('停電', ('BASELINE:183', 'D05-P04-PAUSE-REASON'), {'charges': 0}),
'destruction_stop': ('破壊', ('D05-P04-DESTRUCTION',), {'charges': 0}),
'dependency_stop': ('閉店', ('D05-P04-DEPENDENCY',), {'charges': 0, 'progress_delta': 0, 'reservation_ids_preserved': True, 'service_id_preserved': True}),
'shift_completion': ('シフト交代', ('BASELINE:64', 'BASELINE:67', 'D05-P04-SHIFT-1800'), {'minute': 1080, 'completions': 1, 'charges': 1, 'completion_before_shift': True}),
'recovery_completion': ('課金', ('D05-P04-DEPENDENCY',), {'completions': 1, 'charges': 1}),
'same_minute_replay': ('課金', ('D05-P04-DEPENDENCY', 'D05-P04-SHIFT-1800'), {'completions': 1, 'charges': 1, 'duplicate_generations': 0, 'same_minute_replayed': True}),
'closure_release': ('閉店', ('D-034',), {'orphan_reservations': 0, 'released_once': True, 'started_service_continues': True}),
'exit_release': ('退出', ('D-034',), {'orphan_reservations': 0, 'released_once': True}),
'patience_release': ('退出', ('D-034',), {'orphan_reservations': 0, 'released_once': True}),
'paused_midnight': ('00:00決算', ('D05-P04-DEPENDENCY', 'BASELINE:71', 'BASELINE:72'), {'orphan_reservations': 0, 'crossed_midnight_while_paused': True, 'stopped_charges': 0, 'completions': 1, 'charges': 1}),
'midnight_settlement': ('00:00決算', ('BASELINE:71', 'BASELINE:72', 'A01'), {'settlements': 1, 'sales_payments': 1, 'payroll_payments': 1, 'upkeep_payments': 1, 'duty_payments': 1, 'nonzero_payroll': True}),
'exit_release': ('退出', ('D-034', 'D05-P04-EXIT'), {'orphan_reservations': 0, 'released_once': True}),
'patience_release': ('退出', ('D-034', 'D05-P04-EXIT'), {'orphan_reservations': 0, 'released_once': True}),
'paused_midnight': ('00:00決算', ('D05-P04-DEPENDENCY', 'BASELINE:71', 'BASELINE:72', 'D05-P04-MIDNIGHT-DAY'), {'orphan_reservations': 0, 'crossed_midnight_while_paused': True, 'stopped_charges': 0, 'completions': 1, 'charges': 1}),
'midnight_settlement': ('00:00決算', ('BASELINE:71', 'BASELINE:72', 'A01', 'D05-P04-MIDNIGHT-DAY'), {'settlements': 1, 'sales_payments': 1, 'payroll_payments': 1, 'upkeep_payments': 1, 'duty_payments': 1, 'nonzero_payroll': True}),
'midnight_replay': ('00:00決算', ('BASELINE:71', 'BASELINE:72', 'A01'), {'settlements': 1, 'same_minute_replayed': True, 'duplicate_payments': 0}),
'save_restore': ('00:00決算', ('BASELINE:71', 'BASELINE:72', 'A01'), {'settlements': 1, 'duplicate_payments': 0, 'formal_save_restored': True}),
'night_staff_absent': ('シフト交代', ('BASELINE:67', 'D05-P04-SHIFT-1800'), {'minute': 1081, 'state': 'WAITING_FOR_STAFF', 'night_staff_count': 0}),
@@ -244,6 +263,16 @@ def product_manifest(entries):
return result
def selected_manifest(entries, require_checker=True):
result = product_manifest(entries)
if require_checker:
require(CHECKER_PATH in entries, 'selected source missing checker')
if CHECKER_PATH in entries:
data = git_bytes('cat-file', 'blob', entries[CHECKER_PATH][1])
result[CHECKER_PATH] = {'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest()}
return result
def manifest_digest(manifest):
return hashlib.sha256(json.dumps(manifest, sort_keys=True, separators=(',', ':')).encode()).hexdigest()
@@ -266,91 +295,6 @@ def supplied_file(directory, descriptor):
return path
def verify_product_target(index, directory, checker_commit):
"""Four actual roles, complete source selection, and candidate equality.
This does not establish any native boundary condition. Runner input files
are checked against Git blobs, never against a Root-reported digest alone.
"""
binding = index['product_binding']
target = binding['product_target']
require(set(target) == {'main_anchor', 'submitted', 'composed_tree'}, 'product target shape')
require(target['main_anchor'] == MAIN_ANCHOR, 'main anchor changed')
for key in target:
require(re.fullmatch('[0-9a-f]{40}', target[key]) is not None, 'full product target OID')
for commit in (REGISTERED_COMMIT, EXECUTION_ORIGIN, target['main_anchor'], target['submitted'], checker_commit):
require(git_bytes('cat-file', '-t', commit).strip() == b'commit', 'role is not a commit')
require(_GIT_ENV is not None, 'merge-tree needs isolated object store')
composed = git_bytes('-c', 'rerere.enabled=false', 'merge-tree', '--write-tree',
target['main_anchor'], target['submitted']).decode().strip()
require(composed == target['composed_tree'], 'recomputed composed tree mismatch')
anchor, submission, tree = [tree_entries(t) for t in (MAIN_ANCHOR, target['submitted'], composed)]
selection = git_bytes('show', MAIN_ANCHOR + ':tools/run_all_tests.py')
require(hashlib.sha256(selection).hexdigest() == SELECTION_SHA, 'source selection authority')
changed = git_bytes('diff', '--no-ext-diff', '--no-renames', '--name-only', '-z',
REGISTERED_COMMIT, target['submitted']).split(b'\0')
require(all(allowed_path(p.decode()) for p in changed if p), 'submission outside registered scope')
for path in anchor.keys() | tree.keys():
if anchor.get(path) != tree.get(path):
require(allowed_path(path), 'new/changed path outside scope: ' + path)
baseline = product_manifest(anchor)
product = product_manifest(tree)
require(len(baseline) == 1338 and product == baseline, 'complete selected product mismatch')
metadata = sorted(p for p in anchor if not selected_path(p) and anchor[p] == tree.get(p))
require(len(metadata) == 3139, 'unchanged existing metadata membership changed')
require(set(p for p in tree if selected_path(p)) == set(product) | {CHECKER_PATH},
'unknown selected source cannot be metadata')
own = Path(__file__).read_bytes()
for role, entries in (('submitted', submission), ('composed', tree),
('checker', tree_entries(checker_commit))):
require(CHECKER_PATH in entries and git_bytes('cat-file', 'blob', entries[CHECKER_PATH][1]) == own,
'checker self blob not verified: ' + role)
tested = binding['tested_product']
require(git_bytes('cat-file', '-t', tested).strip() == b'commit'
and product_manifest(tree_entries(tested)) == product, 'tested product manifest mismatch')
candidate = tree_entries(index['candidate_tree'])
require(candidate == tree, 'candidate product/QA/collector/tree bytes differ from target')
runners = binding['runner_inputs']
require(isinstance(runners, list) and runners, 'actual runner inputs missing')
runner_paths = set()
for descriptor in runners:
runner_path = supplied_file(directory, descriptor)
require(runner_path not in runner_paths, 'duplicate runner input')
runner_paths.add(runner_path)
native = load(runner_path)
before = native['source_before']
require(set(before) == set(product) and all(
{'bytes': v['bytes'], 'sha256': v['sha256']} == product[p] for p, v in before.items()),
'runner source_before differs from complete product')
require(native['runner_sha256'] == product['tools/run_all_tests.py']['sha256'], 'runner source pin')
overrides = native['QA_overrides']
require(isinstance(overrides, list) and len(overrides) == 1
and overrides[0].startswith('tests/') and overrides[0] in product, 'one declared QA override')
selected = {p: v['sha256'] for p, v in product.items()}
selected[overrides[0]] = native['QA']['sha256']
require(native['selected_source_map'] == selected, 'selected source/QA override mismatch')
# A relocation is explicit and hash-bound; never open the original path.
materials = descriptor['materials']
fixed = native.get('fixed_input_pins', [])
require(isinstance(fixed, list), 'native fixed input pin list')
needed = fixed + [native['QA']]
require(set(materials) == {p['path'] for p in needed}, 'runner input/config material membership')
for pin in needed:
real = supplied_file(directory, materials[pin['path']])
require(real.stat().st_size == pin['bytes'] and sha(real) == pin['sha256'], 'native input/QA bytes')
wrapper = supplied_file(directory, descriptor['wrapper'])
require(sha(wrapper) == native['wrapper_sha256'], 'native wrapper bytes')
digest = manifest_digest(product)
require(index['versions'] == {
'registered': REGISTERED_COMMIT, 'execution_origin': EXECUTION_ORIGIN,
'checker': {'commit': checker_commit, 'sha256': hashlib.sha256(own).hexdigest()},
'tested': {'product_target': target, 'manifest_sha256': digest}}, 'four version roles')
require(index['source_map'] == {p: v['sha256'] for p, v in product.items()}, 'product source map')
return composed, {'manifest_sha256': digest, 'existing_metadata': metadata,
'runner_paths': runner_paths,
'tested_product': tested, 'product_target': target}
def ancestor(older, newer):
# merge-base's nonzero status is data only for the ordinary non-ancestor case.
try:
@@ -407,7 +351,7 @@ def verify_roles(index, directory):
parents = git_bytes('show', '-s', '--format=%P', commit).decode().split()
require(len(parents) == 2, 'integration/final requires a two-parent no-ff merge')
main, submitted = parents
require(ancestor(MAIN_ANCHOR, main), 'merge main ancestry')
require(main == MAIN_ANCHOR, 'integration main is not frozen M')
submission_role(submitted)
role = 'integration/final'
composed = git_bytes('-c', 'rerere.enabled=false', 'merge-tree', '--write-tree',
@@ -425,6 +369,7 @@ def verify_roles(index, directory):
'unknown source hidden as metadata: ' + path)
if role == 'integration/final':
require(actual_tree == composed and actual == target, 'actual merge differs from composition')
qualify_normal_candidate(commit, actual_tree, main, submitted, composed)
require(target[CHECKER_PATH] == patch[CHECKER_PATH] == actual[CHECKER_PATH],
'checker blob differs from submission')
for path in patch:
@@ -432,16 +377,22 @@ def verify_roles(index, directory):
require(target.get(path) == patch[path], 'reviewed patch differs in merge: ' + path)
binding = index['product_binding']
require(set(binding) == {'tested_product', 'runner_inputs'}, 'unknown product role/metadata declaration')
require(binding['tested_product'] == TESTED_PRODUCT, 'wrong tested revision')
tested = binding['tested_product']
require(tested == composed and git_bytes('cat-file', '-t', tested).strip() == b'tree',
'tested Q is not the genuine recomputed merge-tree')
selection = git_bytes('show', MAIN_ANCHOR + ':tools/run_all_tests.py')
require(hashlib.sha256(selection).hexdigest() == SELECTION_SHA, 'source selection authority')
product = product_manifest(target)
tested_entries = tree_entries(TESTED_PRODUCT)
tested_entries = tree_entries(tested)
expected = product_manifest(tested_entries)
require(len(product) == 1338 and product == expected and
require(product == expected and
product_manifest(main_entries) == expected and product_manifest(anchor_entries) == expected,
'complete 1338-file native product mismatch')
'complete selected native product mismatch')
require(all(target[p][0] == main_entries[p][0] == tested_entries[p][0] for p in product),
'native product mode mismatch')
require(index['source_map'] == {p: v['sha256'] for p, v in product.items()}, 'stale pin: source map')
selected_product = selected_manifest(target)
require(set(selected_product) == set(product) | {CHECKER_PATH}, 'checker must be explicitly selected')
require(index['source_map'] == {p: v['sha256'] for p, v in selected_product.items()}, 'stale pin: source map')
runner_paths = set()
for descriptor in binding['runner_inputs']:
path = supplied_file(directory, descriptor)
@@ -449,14 +400,14 @@ def verify_roles(index, directory):
runner_paths.add(path)
native = load(path)
before = native['source_before']
require(set(before) == set(product) and all(
{'bytes': v['bytes'], 'sha256': v['sha256']} == product[p] for p, v in before.items()),
require(set(before) == set(selected_product) and all(
{'bytes': v['bytes'], 'sha256': v['sha256']} == selected_product[p] for p, v in before.items()),
'runner complete source map mismatch')
require(native['runner_sha256'] == product['tools/run_all_tests.py']['sha256'], 'runner source pin')
overrides = native['QA_overrides']
require(len(overrides) == 1 and overrides[0].startswith('tests/') and overrides[0] in product,
'QA override membership')
selected = {p: v['sha256'] for p, v in product.items()}
selected = {p: v['sha256'] for p, v in selected_product.items()}
selected[overrides[0]] = native['QA']['sha256']
require(native['selected_source_map'] == selected, 'selected QA source map')
needed = native.get('fixed_input_pins', []) + [native['QA']]
@@ -467,11 +418,26 @@ def verify_roles(index, directory):
require(sha(supplied_file(directory, descriptor['wrapper'])) == native['wrapper_sha256'], 'wrapper bytes')
require(runner_paths, 'runner inputs missing')
require(index['versions'] == {'registered': REGISTERED_COMMIT, 'execution_origin': EXECUTION_ORIGIN,
'tested': TESTED_PRODUCT}, 'evidence version roles')
'tested': tested}, 'evidence version roles')
return composed, {'role': role, 'actual_head': commit, 'actual_tree': actual_tree,
'submission': submitted, 'main': main, 'existing_metadata': metadata,
'manifest_sha256': manifest_digest(product), 'runner_paths': runner_paths,
'tested_product': TESTED_PRODUCT}
'tested_product': tested, 'product_file_count': len(product), 'selected_file_count': len(selected_product)}
def qualify_normal_candidate(commit, tree, main, submitted, composed):
"""Fail closed until the actual Root/Runner authority contract is supplied.
The field roster above records the required joins. It intentionally is not
a self-issued attestation format that a synthetic commit can satisfy.
"""
require(tree == composed and main == MAIN_ANCHOR and commit != submitted,
'normal candidate identity mismatch')
require(NORMAL_C_RECEIPT_CONTRACT is not None,
'normal C qualification context gap: authoritative Root/Runner receipt '
'path, SHA256 and provenance verification contract are not supplied')
# No authority implementation is inferred from a caller-supplied object.
raise ValueError('normal C receipt authority verifier is not implemented')
def function_bytes(data):
@@ -572,6 +538,19 @@ def applicability(index, spec, source, head):
require(case_id == declaration.get('case_id'), 'boundary delta engine case: ' + key)
def owner_authority(ref, entry, path):
"""Each decision is bound to its own immutable, path-qualified record."""
require(ref in OWNER_BINDINGS, 'unknown owner authority: ' + ref)
relative, digest = OWNER_BINDINGS[ref]
require(entry.get('status') == 'approved', 'pending/missing authority: ' + ref)
require(entry.get('source') == relative, 'owner approval path mismatch: ' + ref)
require(sha(path) == digest, 'owner approval hash mismatch: ' + ref)
owner = load(path)
require(owner.get('origin') == 'direct_user_reply' and owner.get('formal_acceptance') is False,
'owner approval scope')
require(ref in {v['id'] for v in owner['approved_choices']}, 'owner approval condition')
def coverage(index, raw, source, product_tree):
authority = index['authority']
for ref in {r for _, refs, _ in REQUIRED.values() for r in refs}:
@@ -580,11 +559,7 @@ def coverage(index, raw, source, product_tree):
aid = entry.get('artifact_id')
require(aid in raw and index['artifacts'][aid]['type'] == 'authority', 'raw authority: ' + ref)
if ref.startswith('D05-P04-'):
require(sha(raw[aid]) == OWNER_HASH, 'owner approval hash mismatch')
owner = load(raw[aid])
require(owner.get('origin') == 'direct_user_reply' and owner.get('formal_acceptance') is False,
'owner approval scope')
require(ref in {v['id'] for v in owner['approved_choices']}, 'owner approval condition')
owner_authority(ref, entry, raw[aid])
else:
path = ('docs/traceability/original/BASELINE.txt' if ref.startswith('BASELINE:') else
'docs/DESIGN_DECISIONS.md' if ref == 'D-034' else
@@ -983,14 +958,13 @@ def verify_shift_completion(base):
"""C's first 18:00 transaction, never the paid-midnight 1442 sale."""
for row in load(safe(base, 'SOURCE_MANIFEST.json'))['files']:
native_file(base, row['copy'], row)
require(native_applicability(base) == TESTED_PRODUCT, 'shift tested revision')
tested = native_applicability(base)
pids = native_ownership(base)
shift_pids = [pids['actual-native/' + phase] for phase in NATIVE_RUNS['actual-native']]
require(len(shift_pids) == len(set(shift_pids)) == 3, 'shift ended PID identity')
inputs = load(safe(base, 'actual-native/runner-input.json'))
expected = product_manifest(tree_entries(TESTED_PRODUCT))
require(len(inputs['source_before']) == 1338 and
{p: {'bytes': v['bytes'], 'sha256': v['sha256']} for p, v in inputs['source_before'].items()}
expected = selected_manifest(tree_entries(tested), require_checker=False)
require({p: {'bytes': v['bytes'], 'sha256': v['sha256']} for p, v in inputs['source_before'].items()}
== expected, 'shift complete native source')
prefix = 'actual-native/order-evidence/'
observations = load(safe(base, prefix + 'observations.json'))