Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e25213e91 | ||
|
|
27b18b75c9 | ||
|
|
1b08d6b0fc | ||
|
|
20d0ae5990 |
@@ -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.
|
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 |
|
The checker has partial authority/role corrections; the seven-domain audit uses
|
||||||
| --- | --- | --- |
|
M source. S5 executable probes, fresh-Q collector/wrapper/index plumbing,
|
||||||
| 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. |
|
full-proof joins and independent normal-C qualification remain incomplete.
|
||||||
| 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. |
|
Normal C now fails closed without the authoritative Root/Runner receipt contract.
|
||||||
| Local8 | Root-measured PASS | B/audit-support/p04-root-fb8b-local-r01: bulk, negative, applicability, native, series, encoder, join, roles result/stdio records. |
|
The isolated Git fixtures remain Root-run because `/tmp` creation was denied.
|
||||||
| 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. |
|
See [REPAIR31_STATUS.md](REPAIR31_STATUS.md) for precise remaining work and the
|
||||||
| 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. |
|
corrected Root execution order; [s5/PENDING.md](s5/PENDING.md) records S5 gaps.
|
||||||
| 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. |
|
|
||||||
|
|
||||||
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.
|
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
|
||||||
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.
|
still require exact-version evidence; nativeWindows remains individually
|
||||||
|
pending. Static fixture results confer no original acceptance credit.
|
||||||
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.
|
|
||||||
|
|||||||
+53
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
+4
-3
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"task_id": "P04-01",
|
"task_id": "P04-01",
|
||||||
"revision": "repair29",
|
"revision": "repair29",
|
||||||
"status": "approval candidate only; SOURCE-READY / NOTRUN",
|
"status": "superseded by D05_REMAINING_APPROVAL.json; candidate text below is historical",
|
||||||
"approval": null,
|
"approval": "D05_REMAINING_APPROVAL.json",
|
||||||
"apply_to_product_or_checker": false,
|
"apply_to_product_or_checker": false,
|
||||||
"review_flow": "Root asks owner after review. This document neither requests approval from worker nor records it.",
|
"review_flow": "Root asks owner after review. This document neither requests approval from worker nor records it.",
|
||||||
"proof_legend": {
|
"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.",
|
"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.",
|
"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"
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -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
|
# 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.
|
**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.
|
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`.
|
D05 is **six of six actually approved**; adoption into raw enforcement and
|
||||||
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).
|
verification are pending. Normal-C qualification now rejects matching-parent/tree
|
||||||
Kernel `scripts/core/simulation_kernel.gd` SHA256: `341c0c878c4894adbac628d0db6362ff69fc3347bdd9e61e50936e15dc2d1edb`.
|
commits without the authoritative Root/Runner receipt contract. That contract's
|
||||||
Runtime `autoload/simulation_runtime.gd` SHA256: `7f01b2dcdf28bc965c7588173c2dc70054633faf7204b1ac38ba0f4369331b47`.
|
path, SHA256 and provenance verification remain a concrete context gap.
|
||||||
Root-measured native product `5f6bc11d`; main `9b1a18c1`.
|
|
||||||
|
|
||||||
## 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.
|
See [CURRENT_STATUS.md](CURRENT_STATUS.md) and [REPAIR31_STATUS.md](REPAIR31_STATUS.md) before any Root execution.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|||||||
+9522
File diff suppressed because it is too large
Load Diff
+71
@@ -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.
|
||||||
+94
@@ -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.
|
||||||
+63
@@ -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.
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
{
|
||||||
|
"task_id": "P04-01",
|
||||||
|
"status": "blocked",
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "tools/check_p04_order_evidence.py",
|
||||||
|
"output": "compiled without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_candidate_fixtures.py",
|
||||||
|
"output": "compiled without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_role_fixtures.py",
|
||||||
|
"output": "compiled without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/normal_c_join.py",
|
||||||
|
"output": "compiled without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/normal_c_join_fixtures.py",
|
||||||
|
"output": "compiled without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py",
|
||||||
|
"output": "compiled without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "pure_static_ast",
|
||||||
|
"observation": "normal_c_join.verify parameters",
|
||||||
|
"output": [
|
||||||
|
"database",
|
||||||
|
"approved_database",
|
||||||
|
"candidate",
|
||||||
|
"submission",
|
||||||
|
"hashes"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "pure_static_source",
|
||||||
|
"observation": "checker contains runner_inputs",
|
||||||
|
"output": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fixtures": [
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_applicability_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_approval_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_candidate_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_encoder_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_join_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_negative_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_role_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_series_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/normal_c_join_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s4/engine_identity_negative_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s4/receipt_lifecycle_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engine_runs": 0,
|
||||||
|
"fixture_runs": 0,
|
||||||
|
"condition_credit": 0,
|
||||||
|
"original_completion": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# REPAIR33 — blocked, no implementation or acceptance claim
|
||||||
|
|
||||||
|
P04-01 remains incomplete. Only this status and REPAIR33_STATIC_CHECKS.json
|
||||||
|
were added. Checker, fixtures, wrapper and S5 run documents remain unchanged.
|
||||||
|
No Git writes, Runner operations, fixture execution or engine runs occurred.
|
||||||
|
|
||||||
|
The instruction to return blocked for missing specifications applies to these
|
||||||
|
unresolved input contracts:
|
||||||
|
|
||||||
|
- The Root-supplied Q descriptor has no supplied schema or existing definition
|
||||||
|
in the inspected checker, S5 wrapper or local execution documentation.
|
||||||
|
`verify_roles` requires `product_binding` to contain exactly `tested_product`
|
||||||
|
and `runner_inputs`. Each runner input references an existing native receipt,
|
||||||
|
wrapper and materials; it does not define M/S fields or the wrapper's fresh-Q
|
||||||
|
configuration input. Specify the descriptor fields/types and how M, S, Q,
|
||||||
|
staged product, settings, markers, policy and material bindings are obtained
|
||||||
|
without inventing another input contract. Future hashes are not requested.
|
||||||
|
- The requested combined control includes matching Runner/Root records, but
|
||||||
|
`normal_c_join.verify(database, approved_database, candidate, submission,
|
||||||
|
hashes)` accepts only Runner databases and caller-supplied commit strings.
|
||||||
|
Its CLI has no Root exact-candidate record input or verification. Specify
|
||||||
|
that record's schema and binding, or explicitly confirm that Root performs
|
||||||
|
this join outside this verifier and define the combined control boundary.
|
||||||
|
The verifier was neither weakened nor called from the checker.
|
||||||
|
|
||||||
|
These are contract questions, not requests for permission expansion. Runner
|
||||||
|
core, Owner CLI and the reference core were not read. No dependency on them
|
||||||
|
was introduced. No speculative partial implementation was made.
|
||||||
|
|
||||||
|
Actual verification: six existing Python files compiled with py_compile;
|
||||||
|
generated bytecode was placed under the allowed execution directory and
|
||||||
|
removed. Pure AST inspection confirmed the normal_c_join parameter list;
|
||||||
|
a source assertion confirmed runner_inputs is present. Actual outputs are
|
||||||
|
recorded in REPAIR33_STATIC_CHECKS.json. All twelve discovered fixture files
|
||||||
|
are individually listed there as unexecuted; Root runs them later with its
|
||||||
|
own scratch directory. No test or acceptance result is inferred from syntax.
|
||||||
|
|
||||||
|
An initial shell here-document command failed before Python started with
|
||||||
|
`can't create temp file for here document: operation not permitted`.
|
||||||
|
It produced no verification result. The checks were then run using python3
|
||||||
|
`-c`, without shell temporary-file redirection.
|
||||||
|
|
||||||
|
Explicitly pending: this REPAIR33 implementation; S5 destruction, midnight
|
||||||
|
and exit drivers; fresh-Q plumbing for S1–S4 and the collector; all 184
|
||||||
|
executable suites and the 329 parse verifier; the truthful index; Root's
|
||||||
|
fixed run order, independent review and normal integration/final joins.
|
||||||
|
|
||||||
|
Formal 16/88, original 30/88, seven domains plus EV, all six D05 approvals
|
||||||
|
and P04 credit 0 remain fixed. M remains
|
||||||
|
`c0ea009b28a7649aca6a433a1a24dc0be5e7ab81`. No condition credit, original
|
||||||
|
completion, self-reported acceptance or cap change is claimed.
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"task_id": "P04-01",
|
||||||
|
"status": "submitted",
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "tools/check_p04_order_evidence.py",
|
||||||
|
"output": "tools/check_p04_order_evidence.py: py_compile completed without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_candidate_fixtures.py",
|
||||||
|
"output": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_candidate_fixtures.py: py_compile completed without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_role_fixtures.py",
|
||||||
|
"output": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_role_fixtures.py: py_compile completed without syntax errors",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "ast",
|
||||||
|
"output": "AST: documentation roster is definition-only; qualifier retains identity require and structural return with provenance false; role candidate initialized, assigned and returned; pure control function has no subprocess/Git calls.",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "py_compile",
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_candidate_fixtures.py",
|
||||||
|
"output": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_candidate_fixtures.py: py_compile completed without syntax errors (final literal inputs)",
|
||||||
|
"exit_code": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "ast",
|
||||||
|
"output": "AST: pure candidate controls contain four literal 40-hex inputs.",
|
||||||
|
"exit_code": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fixtures": [
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_applicability_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_approval_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_candidate_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_encoder_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_join_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_native_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_negative_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_role_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/checker_series_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/normal_c_join_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s4/engine_identity_negative_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s4/receipt_lifecycle_fixtures.py",
|
||||||
|
"execution": "unexecuted; Root only"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pure_candidate_controls": "unexecuted; Root may use checker_candidate_fixtures.py --pure-only",
|
||||||
|
"engine_runs": 0,
|
||||||
|
"fixture_runs": 0,
|
||||||
|
"condition_credit": 0,
|
||||||
|
"original_completion": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# REPAIR34 — structural step submitted
|
||||||
|
|
||||||
|
P04-01 remains incomplete. This step changes only the checker structural C
|
||||||
|
qualification and the two local fixture boundaries, plus this status and the
|
||||||
|
static-check record. The checker returns structure_qualified true and
|
||||||
|
provenance_verified_by_checker false with C/S/M/C_tree/Q joins. Prospective
|
||||||
|
roles return candidate_structure null. The provenance roster is documentation
|
||||||
|
only, never consumed. Other parent, tree, checker-blob and binding guards
|
||||||
|
were left unchanged.
|
||||||
|
|
||||||
|
Candidate fixtures now expect honest structural qualification for a manufactured
|
||||||
|
same-tree C. A separate --pure-only path contains three identity negatives and
|
||||||
|
one exact positive with literal 40-hex inputs; it requires no Git or engine.
|
||||||
|
The two role cases expect structural verification and separately record actual
|
||||||
|
downstream --verify-only returncode/stdout/stderr without asserting acceptance.
|
||||||
|
Both boundaries assert stderr has no 'qualification context gap'. Other
|
||||||
|
negative expectations remain unchanged. These fixtures have not been executed;
|
||||||
|
their downstream outcomes are pending Root execution, not inferred here.
|
||||||
|
|
||||||
|
Actual verification is limited to py_compile for the three changed Python
|
||||||
|
files and AST checks recorded with their real output in
|
||||||
|
REPAIR34_STATIC_CHECKS.json. Temporary compilation bytecode was created only
|
||||||
|
inside the allowed execution directory and removed. Every discovered fixture,
|
||||||
|
including the pure candidate controls, is unexecuted. An initial editing
|
||||||
|
command failed with a Python SyntaxError before any file writes; edits were
|
||||||
|
then applied in place. That command was not a validation check.
|
||||||
|
|
||||||
|
Explicitly pending in this same unit:
|
||||||
|
|
||||||
|
- normal_c_join and its fixtures: unchanged and unexecuted here; post-final
|
||||||
|
Root SQL candidate/M/S/approval/validation/review/integration/final joins
|
||||||
|
remain mandatory before original credit.
|
||||||
|
- Wrapper/descriptor: separate pre-run configuration with Root-derived M/S/Q
|
||||||
|
and pinned source/material references, not after-run binding.runner_inputs
|
||||||
|
receipts. Root JSON and exact-candidate qualification remain pending.
|
||||||
|
- S5 destruction, midnight and exit drivers; S1–S4 and collector fresh Q.
|
||||||
|
- All 184 executable suites / 329 parse verification; truthful index.
|
||||||
|
- Root run order, independent review, integration/final and provenance joins.
|
||||||
|
|
||||||
|
scratch_fixture_adapter.py routing is unchanged. No Git commands or writes,
|
||||||
|
engine runs, fixture runs, Runner operations, permissions or cap changes were
|
||||||
|
performed. Runner core and Owner CLI were not read; this step does not depend
|
||||||
|
on them. External provenance remains a required pending context, not a reason
|
||||||
|
to block the authorized structural step.
|
||||||
|
|
||||||
|
All seven domains plus EV, all six D05 approvals, formal 16/88, original 30/88
|
||||||
|
and P04 credit 0 remain fixed. Frozen M is
|
||||||
|
c0ea009b28a7649aca6a433a1a24dc0be5e7ab81. No condition credit, self-reported
|
||||||
|
acceptance, original completion or new counted unit is claimed.
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"validation": "py_compile and ast only",
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"file": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py",
|
||||||
|
"py_compile": "passed",
|
||||||
|
"ast.parse": "passed",
|
||||||
|
"ast.required_functions": "passed",
|
||||||
|
"ast.no_fixed_counts": "passed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_wrapper_fixtures.py",
|
||||||
|
"py_compile": "passed",
|
||||||
|
"ast.parse": "passed"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fixtures": [
|
||||||
|
{
|
||||||
|
"name": "partial-triple",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "non-hex",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "short",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mixed-modes",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "historical-native",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "no-flags",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fresh-q",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "historical-check-only",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "git-dirty-file",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "git-untracked-file",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "git-wrong-head-tree",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "git-wrong-submission",
|
||||||
|
"status": "unexecuted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "git-wrong-main",
|
||||||
|
"status": "unexecuted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# REPAIR35 — submitted preparation, no acceptance credit
|
||||||
|
|
||||||
|
Scope is the S5 wrapper fresh-Q mode, pure mode-selection fixtures and status
|
||||||
|
documents only. The wrapper now binds M/S/Q_tree, the clean checkout carrier,
|
||||||
|
selection authority, selected source bytes and Q marker contracts. Fixed-input
|
||||||
|
rechecks require identical provenance. Cache comparisons remove only checker
|
||||||
|
and TEST from both maps and otherwise compare keys and hashes. R17 is explicitly
|
||||||
|
check-only/read-only. Fresh-Q counts are derived; historical material is listed
|
||||||
|
as historical_not_inputs rather than pinned as fresh-Q input.
|
||||||
|
|
||||||
|
R34 structural C, Root normal_c_join, probe, adapter, ownership/PID/cleanup,
|
||||||
|
Writer/Reader, formal mirror and inventory remain unchanged. Product, Clock,
|
||||||
|
values, tests/, Runner, core and Owner CLI were read-only. No Git commands,
|
||||||
|
engines, Runner operations or fixture execution were performed. No /tmp or
|
||||||
|
permission additions were used. A shell heredoc could not be created by the
|
||||||
|
environment; that edit attempt exited before running Python or changing files.
|
||||||
|
Edits were then applied directly in place.
|
||||||
|
|
||||||
|
Only py_compile and AST static validation are recorded in
|
||||||
|
REPAIR35_STATIC_CHECKS.json. Pure fixtures (partial triple, non-hex, short,
|
||||||
|
mixed modes, historical native, no flags, full triple, historical check-only)
|
||||||
|
and all five Root Git negatives are **unexecuted**. No functional pass is claimed.
|
||||||
|
|
||||||
|
Pending: S5 destruction/midnight/exit drivers; fresh Q for S1–S4 and collector;
|
||||||
|
184 suites / 329 parse; truthful index; Root run order; Root exact-candidate
|
||||||
|
qualification. Root next builds Qt and parentless X, stages under its own B,
|
||||||
|
then runs check-only, pure fixtures and Git negatives as described in
|
||||||
|
s5/S5_ROOT_RUN.md. No native/batch admission until the pending prerequisites
|
||||||
|
are ready.
|
||||||
|
|
||||||
|
All 7 domains + EV, formal 16/88, original 30/88, P04 credit 0, all six D05
|
||||||
|
approvals, frozen M c0ea009b28a7649aca6a433a1a24dc0be5e7ab81 and allowed_paths
|
||||||
|
remain fixed. This is an internal step of P04-01, no new counted unit and no
|
||||||
|
completion claim. Unchanged support gates including owned_outer.py were not
|
||||||
|
read or executed; their qualification remains with Root, as recorded in the
|
||||||
|
direction. Source commit identity was not independently checked because Git
|
||||||
|
commands are prohibited for this worker.
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"py_compile_ast": [
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py",
|
||||||
|
"sha256": "e96b2793d7352ac52e16505c9c4cde3d151497763be3cb47926338df070b05e5",
|
||||||
|
"py_compile": "passed",
|
||||||
|
"ast": "passed",
|
||||||
|
"top_level_functions": [
|
||||||
|
"r17_relocation_guard",
|
||||||
|
"probe_guard",
|
||||||
|
"module",
|
||||||
|
"pin",
|
||||||
|
"load_uid_helper",
|
||||||
|
"make_uid_policy",
|
||||||
|
"engine_pin",
|
||||||
|
"select_mode",
|
||||||
|
"fresh_q_guard",
|
||||||
|
"main"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_uid_controls.py",
|
||||||
|
"sha256": "17069b87b98c385e1298152c9c5c2f23c8710b79eb19aef073c64ce215f6c902",
|
||||||
|
"py_compile": "passed",
|
||||||
|
"ast": "passed",
|
||||||
|
"top_level_functions": [
|
||||||
|
"module",
|
||||||
|
"main"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_wrapper_fixtures.py",
|
||||||
|
"sha256": "1a4daebf46051e975a9cc740660c4672371ea6a9e6cb04cbc1d458ece5f0151d",
|
||||||
|
"py_compile": "passed",
|
||||||
|
"ast": "passed",
|
||||||
|
"top_level_functions": [
|
||||||
|
"main"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# REPAIR36 — bounded preparation submitted, no acceptance credit
|
||||||
|
|
||||||
|
Changes are limited to the S5 wrapper, new pure UID controls and these documents.
|
||||||
|
Actual-Q AST helper loading, finite derived UID planning, import sealing,
|
||||||
|
private-globals phase instrumentation, phase receipts and cleanup rechecks
|
||||||
|
supplement the existing expected inventory. Historical selection, existing
|
||||||
|
require gates, ownership/PID, engine, cache and formal mirror rules remain.
|
||||||
|
The helper is loaded from real Q before controls construct synthetic refs.
|
||||||
|
|
||||||
|
Only py_compile and AST checks are executed and recorded in
|
||||||
|
REPAIR36_STATIC_CHECKS.json. Wrapper fixtures, UID controls, check-only plans,
|
||||||
|
Git negatives and every native diagnostic are unexecuted. No functional pass,
|
||||||
|
full regression, 15+EV batch, original credit or completion is claimed.
|
||||||
|
No Git, engine, Runner or other agent operations were performed. A shell
|
||||||
|
heredoc edit failed before Python execution; edits then used apply_patch.
|
||||||
|
|
||||||
|
Context gap: Q runner API was read from
|
||||||
|
build/owner-handoff/p04-after-p26-closure-r01/q35-uid-diagnostic/run_all_tests.py.reference;
|
||||||
|
Root must confirm the actual Q runner matches that mirror (320ca668…)
|
||||||
|
at runtime. Helper implementation was read from the adjacent P13 reference;
|
||||||
|
runtime loading uses only the actual pinned Q, never either mirror.
|
||||||
|
|
||||||
|
Pending: S5 destruction/midnight/exit drivers; S1–S4/collector fresh Q;
|
||||||
|
derived 184 suites / 329 parse; truthful index; Root exact-candidate qualification.
|
||||||
|
Root order is py_compile → wrapper fixtures → UID controls with explicit scratch
|
||||||
|
→ fresh check-only plan → exactly one new-name diagnostic. The failed r35
|
||||||
|
diagnostic is preserved. All 7 domains + EV, formal 16/88, original 30/88,
|
||||||
|
P04 credit 0, all six D05 approvals pending, M c0ea009 and allowed_paths stay fixed.
|
||||||
@@ -35,8 +35,8 @@ def payload(build, gate=None):
|
|||||||
native = build / 'audit-support/native-first-current'
|
native = build / 'audit-support/native-first-current'
|
||||||
c = gate.verify_native(native)
|
c = gate.verify_native(native)
|
||||||
raw = gate.combine_native_series(build, c)
|
raw = gate.combine_native_series(build, c)
|
||||||
source = gate.product_manifest(gate.tree_entries(gate.TESTED_PRODUCT))
|
tested = c['production_commit']
|
||||||
gate.require(len(source) == 1338, 'complete native source required')
|
source = gate.selected_manifest(gate.tree_entries(tested))
|
||||||
source_map = {p: v['sha256'] for p, v in source.items()}
|
source_map = {p: v['sha256'] for p, v in source.items()}
|
||||||
# Resolve content from supplied roots only; never open original provenance
|
# Resolve content from supplied roots only; never open original provenance
|
||||||
# paths, never omit required source/config/input/environment material.
|
# 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')
|
relocation = gate.load(build / 'audit-support/p04-r17-full-inputs-r01/MANIFEST.json')
|
||||||
authorities = {}
|
authorities = {}
|
||||||
for ref in sorted({r for _, refs, _ in gate.REQUIRED.values() for r in refs}):
|
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/traceability/original/BASELINE.txt' if ref.startswith('BASELINE:') else
|
||||||
'docs/DESIGN_DECISIONS.md' if ref == 'D-034' 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')
|
'docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/ORDER_CONTRACT_DRAFT.md')
|
||||||
path = gate.safe(gate.ROOT, relative)
|
path = gate.safe(gate.ROOT, relative)
|
||||||
if ref.startswith('D05-P04-'):
|
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),
|
authorities[ref] = {'source': relative, 'sha256': gate.sha(path),
|
||||||
'status': 'approved' if not ref.startswith('BASELINE:') else 'original'}
|
'status': 'approved' if not ref.startswith('BASELINE:') else 'original'}
|
||||||
conditions = {cid: {'case_id': cid, 'authority_refs': list(refs), 'nativeWindows': 'pending',
|
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():
|
for name, rows in gate.REACH_REFS.items():
|
||||||
refs = []
|
refs = []
|
||||||
for path, function, digest, lines in rows:
|
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,
|
refs.append({'path': path, 'sha256': source_map[path], 'function': function,
|
||||||
'anchor_sha256': digest, 'line_count': lines})
|
'anchor_sha256': digest, 'line_count': lines})
|
||||||
reachability[name] = {'reach': name == 'EV', 'case_id': 'EV' if name == 'EV' else None, 'source_refs': refs,
|
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}
|
'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,
|
index = {'schema_version': 2, 'task_id': 'P04-01', 'formal_acceptance': False,
|
||||||
'versions': {'registered': gate.REGISTERED_COMMIT, 'execution_origin': gate.EXECUTION_ORIGIN,
|
'versions': {'registered': gate.REGISTERED_COMMIT, 'execution_origin': gate.EXECUTION_ORIGIN,
|
||||||
'tested': gate.TESTED_PRODUCT},
|
'tested': tested},
|
||||||
'product_binding': {'tested_product': gate.TESTED_PRODUCT, 'runner_inputs': runners},
|
'product_binding': {'tested_product': tested, 'runner_inputs': runners},
|
||||||
'source_map': source_map, 'registered_pins': gate.load(gate.SPEC)['current_source_pins'],
|
'source_map': source_map, 'registered_pins': gate.load(gate.SPEC)['current_source_pins'],
|
||||||
'applicability_delta': delta,
|
'applicability_delta': delta,
|
||||||
'delta_cases': {r['path'] + ':' + r['function']: {cid: cid for cid in
|
'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'),
|
'native_bundle': descriptor(native / 'OWNERSHIP_RAW_PROVENANCE.json'),
|
||||||
'original_audit': {'sha256': gate.sha(gate.ROOT / gate.DOC_SCOPE / 'order-audit.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')},
|
'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',
|
'safety_outcomes': ['no charging while legitimately stopped',
|
||||||
'no double midnight settlement', 'no orphan reservations']}
|
'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
|
return index
|
||||||
|
|
||||||
|
|
||||||
@@ -140,13 +140,14 @@ def main():
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
gate = checker()
|
gate = checker()
|
||||||
os.environ['BUILD_OUTPUT_DIR'] = str(args.build.resolve(strict=True))
|
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()
|
output = args.output.absolute()
|
||||||
gate.require(not output.exists() and not output.is_symlink(), 'output must be fresh')
|
gate.require(not output.exists() and not output.is_symlink(), 'output must be fresh')
|
||||||
for path in output.parents:
|
for path in output.parents:
|
||||||
gate.require(not path.is_symlink(), 'output parent symlink')
|
gate.require(not path.is_symlink(), 'output parent symlink')
|
||||||
index = payload(args.build, gate)
|
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():
|
with gate.isolated_objects():
|
||||||
_, role = gate.verify_roles(index, args.build.resolve())
|
_, role = gate.verify_roles(index, args.build.resolve())
|
||||||
# The historical invocation is separate from the reusable evidence index.
|
# The historical invocation is separate from the reusable evidence index.
|
||||||
|
|||||||
+3
-2
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/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 importlib.util
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
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')
|
spec = importlib.util.spec_from_file_location('bulk_gate', ROOT / 'tools/check_p04_order_evidence.py')
|
||||||
gate = importlib.util.module_from_spec(spec)
|
gate = importlib.util.module_from_spec(spec)
|
||||||
spec.loader.exec_module(gate)
|
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)
|
base = Path(temporary)
|
||||||
|
assert not base.resolve().is_relative_to(ROOT.resolve())
|
||||||
repo = base / 'repo'
|
repo = base / 'repo'
|
||||||
repo.mkdir()
|
repo.mkdir()
|
||||||
gate.ROOT = repo
|
gate.ROOT = repo
|
||||||
|
|||||||
+1
-1
@@ -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')
|
spec = importlib.util.spec_from_file_location('p04_gate', ROOT / 'tools/check_p04_order_evidence.py')
|
||||||
gate = importlib.util.module_from_spec(spec)
|
gate = importlib.util.module_from_spec(spec)
|
||||||
spec.loader.exec_module(gate)
|
spec.loader.exec_module(gate)
|
||||||
PRODUCTION = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1'
|
PRODUCTION = gate.MAIN_ANCHOR
|
||||||
|
|
||||||
|
|
||||||
def run(native_bundle=None):
|
def run(native_bundle=None):
|
||||||
|
|||||||
+57
@@ -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))
|
||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Candidate structure controls; no provenance or whole-role/native credit."""
|
||||||
|
import argparse
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
sys.dont_write_bytecode = True
|
||||||
|
ROOT = Path(__file__).resolve().parents[5]
|
||||||
|
|
||||||
|
|
||||||
|
def load_gate():
|
||||||
|
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)
|
||||||
|
return gate
|
||||||
|
|
||||||
|
|
||||||
|
def expected_candidate(commit, tree, main, submitted, composed):
|
||||||
|
return {'structure_qualified': True, 'provenance_verified_by_checker': False,
|
||||||
|
'provenance_owner': 'actual Runner.prepare_integration/integrate and Root normal_c_join AFTER final before original credit',
|
||||||
|
'join': {'C': commit, 'S': submitted, 'M': main, 'C_tree': tree, 'Q': composed}}
|
||||||
|
|
||||||
|
|
||||||
|
def run_pure():
|
||||||
|
"""Three identity negatives and one exact positive; no Git or engine."""
|
||||||
|
gate = load_gate()
|
||||||
|
commit = '1111111111111111111111111111111111111111'
|
||||||
|
tree = '2222222222222222222222222222222222222222'
|
||||||
|
submitted = '3333333333333333333333333333333333333333'
|
||||||
|
other = '4444444444444444444444444444444444444444'
|
||||||
|
for args in ((commit, other, gate.MAIN_ANCHOR, submitted, tree),
|
||||||
|
(commit, tree, other, submitted, tree),
|
||||||
|
(submitted, tree, gate.MAIN_ANCHOR, submitted, tree)):
|
||||||
|
try:
|
||||||
|
gate.qualify_normal_candidate(*args)
|
||||||
|
except ValueError as exc:
|
||||||
|
assert str(exc) == 'normal candidate identity mismatch', str(exc)
|
||||||
|
else:
|
||||||
|
raise AssertionError('invalid candidate structure qualified')
|
||||||
|
args = (commit, tree, gate.MAIN_ANCHOR, submitted, tree)
|
||||||
|
assert gate.qualify_normal_candidate(*args) == expected_candidate(*args)
|
||||||
|
return {'scope': 'pure structure only', 'negative_controls': 3,
|
||||||
|
'exact_positive_controls': 1, 'formal_acceptance': False}
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
gate = load_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
|
||||||
|
result = gate.qualify_normal_candidate(synthetic, tree, main, submission, tree)
|
||||||
|
assert result == expected_candidate(synthetic, tree, main, submission, tree)
|
||||||
|
return {'scope': 'isolated candidate structure only; provenance remains external',
|
||||||
|
'synthetic_equal_parents_and_tree': result, 'formal_acceptance': False}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('--pure-only', action='store_true', help='no Git, engine or scratch directory')
|
||||||
|
args = parser.parse_args()
|
||||||
|
print(json.dumps(run_pure() if args.pure_only else run(), indent=2))
|
||||||
+4
-1
@@ -48,10 +48,13 @@ def run():
|
|||||||
add('decisions', (ROOT / 'docs/DESIGN_DECISIONS.md').read_bytes(), 'authority')
|
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('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('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=(
|
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'))
|
else 'decisions' if ref == 'D-034' else 'a01'))
|
||||||
for _, refs, _ in gate.REQUIRED.values() for ref in refs}
|
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('stdout', b'SYNTHETIC fixture log', 'stdout')
|
||||||
add('native_log', b'SYNTHETIC fixture log', 'native_log')
|
add('native_log', b'SYNTHETIC fixture log', 'native_log')
|
||||||
domains = {d: dict(source_refs=[dict(path='autoload/simulation_runtime.gd', function='_advance_facilities',
|
domains = {d: dict(source_refs=[dict(path='autoload/simulation_runtime.gd', function='_advance_facilities',
|
||||||
|
|||||||
+31
-8
@@ -23,8 +23,11 @@ def run(build, evidence):
|
|||||||
for name in ('GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE', 'GIT_OBJECT_DIRECTORY',
|
for name in ('GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE', 'GIT_OBJECT_DIRECTORY',
|
||||||
'GIT_ALTERNATE_OBJECT_DIRECTORIES'):
|
'GIT_ALTERNATE_OBJECT_DIRECTORIES'):
|
||||||
env.pop(name, None)
|
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)
|
base = Path(temp)
|
||||||
|
assert not base.resolve().is_relative_to(ROOT.resolve())
|
||||||
checkout = base / 'checkout'
|
checkout = base / 'checkout'
|
||||||
subprocess.run(['git', 'clone', '--shared', '--no-checkout', str(ROOT), str(checkout)],
|
subprocess.run(['git', 'clone', '--shared', '--no-checkout', str(ROOT), str(checkout)],
|
||||||
env=env, check=True, capture_output=True)
|
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()
|
return subprocess.check_output(['git', '-c', 'core.hooksPath=/dev/null', *args], cwd=checkout, env=env).decode().strip()
|
||||||
|
|
||||||
actual = git('rev-parse', 'HEAD')
|
actual = git('rev-parse', 'HEAD')
|
||||||
anchor = '9b1a18c1eb25ca1300dcd59da78423c0dda2f498'
|
anchor = 'c0ea009b28a7649aca6a433a1a24dc0be5e7ab81'
|
||||||
ancestry = subprocess.run(['git', 'merge-base', '--is-ancestor', anchor, actual], cwd=checkout, env=env)
|
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
|
submission = git('show', '-s', '--format=%P', actual).split()[1] if ancestry.returncode == 0 else actual
|
||||||
git('checkout', '--detach', submission)
|
git('checkout', '--detach', submission)
|
||||||
@@ -49,7 +52,7 @@ def run(build, evidence):
|
|||||||
' g.verify_roles(json.loads(Path(sys.argv[1]).read_text()),Path(sys.argv[2]))\n')
|
' g.verify_roles(json.loads(Path(sys.argv[1]).read_text()),Path(sys.argv[2]))\n')
|
||||||
index_path = base / 'index.json'
|
index_path = base / 'index.json'
|
||||||
|
|
||||||
def check(name, index=None, positive=False, full=False):
|
def check(name, index=None, positive=False, full=False, no_context_gap=False):
|
||||||
index_path.write_text(json.dumps(original if index is None else index))
|
index_path.write_text(json.dumps(original if index is None else index))
|
||||||
if full:
|
if full:
|
||||||
directory = base / name
|
directory = base / name
|
||||||
@@ -61,8 +64,12 @@ def run(build, evidence):
|
|||||||
command = [sys.executable, str(probe), str(index_path), str(build)]
|
command = [sys.executable, str(probe), str(index_path), str(build)]
|
||||||
process_env = env
|
process_env = env
|
||||||
process = subprocess.run(command, cwd=checkout, env=process_env, capture_output=True, text=True)
|
process = subprocess.run(command, cwd=checkout, env=process_env, capture_output=True, text=True)
|
||||||
assert (process.returncode == 0) == positive, (name, process.stdout, process.stderr)
|
if no_context_gap:
|
||||||
results.append({'case': name, 'result': 'accepted' if positive else 'rejected',
|
assert 'qualification context gap' not in process.stderr, (name, process.stderr)
|
||||||
|
if positive is not None:
|
||||||
|
assert (process.returncode == 0) == positive, (name, process.stdout, process.stderr)
|
||||||
|
results.append({'case': name, 'result': 'command_completed' if process.returncode == 0 else 'command_rejected',
|
||||||
|
'returncode': process.returncode, 'formal_acceptance': False,
|
||||||
'stdout': process.stdout, 'stderr': process.stderr})
|
'stdout': process.stdout, 'stderr': process.stderr})
|
||||||
|
|
||||||
check('real_submission_positive', positive=True)
|
check('real_submission_positive', positive=True)
|
||||||
@@ -101,8 +108,23 @@ def run(build, evidence):
|
|||||||
git('checkout', '--detach', anchor)
|
git('checkout', '--detach', anchor)
|
||||||
git('merge', '--no-ff', '--no-edit', submission)
|
git('merge', '--no-ff', '--no-edit', submission)
|
||||||
merged = git('rev-parse', 'HEAD')
|
merged = git('rev-parse', 'HEAD')
|
||||||
check('real_integration_positive', positive=True)
|
# A normal commit C cannot be relabelled as tested non-production Q.
|
||||||
check('real_final_positive', positive=True)
|
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.
|
||||||
|
# Structure qualifies; provenance and credit remain external.
|
||||||
|
check('unqualified_merge_structure', positive=True, no_context_gap=True)
|
||||||
|
check('unqualified_merge_downstream', positive=None, full=True, no_context_gap=True)
|
||||||
|
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_structure', positive=True, no_context_gap=True)
|
||||||
|
check('synthetic_identical_parents_tree_downstream', positive=None, full=True, no_context_gap=True)
|
||||||
|
git('checkout', '--detach', merged)
|
||||||
game.unlink()
|
game.unlink()
|
||||||
git('add', '-u')
|
git('add', '-u')
|
||||||
git('commit', '--amend', '--no-edit')
|
git('commit', '--amend', '--no-edit')
|
||||||
@@ -113,7 +135,8 @@ def run(build, evidence):
|
|||||||
changed = copy.deepcopy(original)
|
changed = copy.deepcopy(original)
|
||||||
changed['conditions']['power_stop']['required_measurements']['charges'] = 9
|
changed['conditions']['power_stop']['required_measurements']['charges'] = 9
|
||||||
check('forged_index', changed, full=True)
|
check('forged_index', changed, full=True)
|
||||||
return {'scope': 'fixture controls only', 'results': results}
|
return {'scope': 'fixture controls only', 'formal_acceptance': False,
|
||||||
|
'condition_credit': 0, 'results': results}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -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",
|
"revision": "repair30",
|
||||||
"status": "SOURCE-READY / NOTRUN; Root measurements separately recorded",
|
"status": "BLOCKED: partial implementation; no native admission",
|
||||||
"task_id": "P04-01",
|
"task_id": "P04-01",
|
||||||
"current_table": true,
|
"current_table": true,
|
||||||
"scope": {
|
"scope": {
|
||||||
@@ -14,166 +14,296 @@
|
|||||||
],
|
],
|
||||||
"packages": 30,
|
"packages": 30,
|
||||||
"deliveries": 88,
|
"deliveries": 88,
|
||||||
"original_credit": "13/88 unchanged; P04 receives zero credit",
|
"original_credit": "16/88 formal; P04 receives zero credit",
|
||||||
"CurrentAlphaScope": "unchanged",
|
"CurrentAlphaScope": "unchanged",
|
||||||
"main_9b": "frozen; nothing integrated"
|
"frozen_main": "c0ea009b28a7649aca6a433a1a24dc0be5e7ab81"
|
||||||
},
|
},
|
||||||
"domains": [
|
"domains": [
|
||||||
{
|
{
|
||||||
"domain": "閉店",
|
"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": [
|
"current_source": [
|
||||||
"Runtime _process_tick_commands:5743",
|
{
|
||||||
"FacilityService _prepare_service_for_tick:853",
|
"path": "autoload/simulation_runtime.gd",
|
||||||
"Runtime _release_closed_business_queues:12624"
|
"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": [
|
"approved_authority": [
|
||||||
"D-034",
|
"D-034",
|
||||||
"D05-P04-DEPENDENCY"
|
"D05-P04-DEPENDENCY",
|
||||||
],
|
"D05-P04-PAUSE-REASON"
|
||||||
"pending_D05": [
|
|
||||||
"D05(a) simultaneous reason selection"
|
|
||||||
],
|
],
|
||||||
|
"pending_D05": [],
|
||||||
"phase": "APPLY_COMMANDS / FACILITY_COMPLETION / FACILITY_QUEUES",
|
"phase": "APPLY_COMMANDS / FACILITY_COMPLETION / FACILITY_QUEUES",
|
||||||
"relative_priority": "Command closure before completion; dependency hold during preparation; closed queue release after completion.",
|
"relative_priority": "Command closure before completion; dependency hold during preparation; closed queue release after completion.",
|
||||||
"status": "approved",
|
"status": "approved policy; fresh Q evidence pending",
|
||||||
"observation_status": "observed-current"
|
"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": "停電",
|
"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": [
|
"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": [
|
"approved_authority": [
|
||||||
"BASELINE:183",
|
"BASELINE:183",
|
||||||
"P04-01 safety acceptance"
|
"P04-01 safety acceptance",
|
||||||
],
|
"D05-P04-PAUSE-REASON"
|
||||||
"pending_D05": [
|
|
||||||
"D05(a)"
|
|
||||||
],
|
],
|
||||||
|
"pending_D05": [],
|
||||||
"phase": "MANA → FACILITY_COMPLETION",
|
"phase": "MANA → FACILITY_COMPLETION",
|
||||||
"relative_priority": "Projection before completion; RELATED chosen before NO_POWER.",
|
"relative_priority": "Projection before completion; RELATED chosen before NO_POWER.",
|
||||||
"status": "observed-current",
|
"status": "approved policy; fresh Q evidence pending",
|
||||||
"observation_status": "observed-current",
|
"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."
|
"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": "破壊",
|
"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": [
|
"current_source": [
|
||||||
"Runtime _process_tick_commands:5743",
|
{
|
||||||
"_advance_defense:8577",
|
"path": "autoload/simulation_runtime.gd",
|
||||||
"_apply_defense_outcome_boundary:9804",
|
"function": "_process_tick_commands",
|
||||||
"FacilityService _prepare_service_for_tick:853"
|
"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": [
|
"approved_authority": [
|
||||||
"P04-01 safety acceptance (original); explicit destruction rule pending D05"
|
"D05-P04-DESTRUCTION"
|
||||||
],
|
|
||||||
"pending_D05": [
|
|
||||||
"D05(b); BASELINE:183 is mana depletion, not destruction authority; destruction_stop registry correction only after approval"
|
|
||||||
],
|
],
|
||||||
|
"pending_D05": [],
|
||||||
"phase": "APPLY_COMMANDS vs INCIDENTS_AND_EVENTS",
|
"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.",
|
"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",
|
"status": "approved policy; fresh Q evidence pending",
|
||||||
"observation_status": "observed-current"
|
"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": "退出",
|
"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": [
|
"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": [
|
"approved_authority": [
|
||||||
"D-034",
|
"D-034",
|
||||||
"P04-01 safety acceptance"
|
"P04-01 safety acceptance",
|
||||||
],
|
"D05-P04-EXIT"
|
||||||
"pending_D05": [
|
|
||||||
"D05(c)"
|
|
||||||
],
|
],
|
||||||
|
"pending_D05": [],
|
||||||
"phase": "APPLY_COMMANDS vs AI_DECISIONS",
|
"phase": "APPLY_COMMANDS vs AI_DECISIONS",
|
||||||
"relative_priority": "Command exit before completion/charging; AI PLANNED_EXIT after them; despawn later.",
|
"relative_priority": "Command exit before completion/charging; AI PLANNED_EXIT after them; despawn later.",
|
||||||
"status": "pending D05",
|
"status": "approved policy; fresh Q evidence pending",
|
||||||
"observation_status": "observed-current"
|
"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": "課金",
|
"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": [
|
"current_source": [
|
||||||
"Runtime _advance_facility_upkeep:1855",
|
{
|
||||||
"_complete_service_transaction:11769",
|
"path": "autoload/simulation_runtime.gd",
|
||||||
"_apply_service_transaction:11785",
|
"function": "_advance_facility_upkeep",
|
||||||
"coordinator _process_daily_close:1125"
|
"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": [
|
"approved_authority": [
|
||||||
"P04-01 safety acceptance",
|
"P04-01 safety acceptance",
|
||||||
"D05-P04-DEPENDENCY",
|
"D05-P04-DEPENDENCY",
|
||||||
"D05-P04-SHIFT-1800"
|
"D05-P04-SHIFT-1800",
|
||||||
],
|
"D05-P04-MIDNIGHT-DAY"
|
||||||
"pending_D05": [
|
|
||||||
"D05(d), beyond approved A01 and18:00; timing/attribution mandatory P04, numeric math D04/P05 separate"
|
|
||||||
],
|
],
|
||||||
|
"pending_D05": [],
|
||||||
"phase": "TIME_BOUNDARIES → FACILITY_COMPLETION",
|
"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.",
|
"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",
|
"status": "approved policy; fresh Q evidence pending",
|
||||||
"observation_status": "observed-current"
|
"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": "シフト交代",
|
"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": [
|
"current_source": [
|
||||||
"Runtime _advance_facilities:8482",
|
{
|
||||||
"_advance_staff_ai:8658",
|
"path": "autoload/simulation_runtime.gd",
|
||||||
"StaffService advance_one_minute:700"
|
"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": [
|
"approved_authority": [
|
||||||
"BASELINE:64",
|
"BASELINE:64",
|
||||||
"BASELINE:67",
|
"BASELINE:67",
|
||||||
"D05-P04-SHIFT-1800"
|
"D05-P04-SHIFT-1800"
|
||||||
],
|
],
|
||||||
"pending_D05": [
|
"pending_D05": [],
|
||||||
"Already approved; do not re-ask"
|
|
||||||
],
|
|
||||||
"phase": "FACILITY_COMPLETION → AI_DECISIONS",
|
"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).",
|
"relative_priority": "18:00 completion/payment before shift handover; day staff [17:59,18:00), night [18:00,18:01).",
|
||||||
"status": "approved",
|
"status": "approved policy; fresh Q evidence pending",
|
||||||
"observation_status": "observed-current"
|
"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決算",
|
"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": [
|
"current_source": [
|
||||||
"Kernel _handle_time_boundaries:254",
|
{
|
||||||
"Runtime _advance_operations_time:1898",
|
"path": "scripts/core/simulation_kernel.gd",
|
||||||
"coordinator _process_minute_boundaries:882",
|
"function": "_handle_time_boundaries",
|
||||||
"_process_daily_close:1125"
|
"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": [
|
"approved_authority": [
|
||||||
"BASELINE:71",
|
"BASELINE:71",
|
||||||
"BASELINE:72",
|
"BASELINE:72",
|
||||||
"A01",
|
"A01",
|
||||||
"D05-P04-DEPENDENCY"
|
"D05-P04-DEPENDENCY",
|
||||||
],
|
"D05-P04-MIDNIGHT-DAY"
|
||||||
"pending_D05": [
|
|
||||||
"A01 approved ownership-based midnight upkeep not reopened; extra attribution D05(d)"
|
|
||||||
],
|
],
|
||||||
|
"pending_D05": [],
|
||||||
"phase": "pre-TIME_BOUNDARIES signals → TIME_BOUNDARIES → FACILITY_COMPLETION",
|
"phase": "pre-TIME_BOUNDARIES signals → TIME_BOUNDARIES → FACILITY_COMPLETION",
|
||||||
"relative_priority": "Midnight signals, then upkeep/close, then completion.",
|
"relative_priority": "Midnight signals, then upkeep/close, then completion.",
|
||||||
"status": "approved",
|
"status": "approved policy; fresh Q evidence pending",
|
||||||
"observation_status": "observed-current"
|
"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",
|
"source_facts": "REPAIR30_SOURCE_FACTS.json",
|
||||||
"authority": "D05_OWNER_APPROVAL.json approves dependency and shift only; original BASELINE/D-034/A01 retain their scope",
|
"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": [
|
"historical_superseded": [
|
||||||
"REPAIR17_STATUS.md",
|
"REPAIR17_STATUS.md",
|
||||||
"REPAIR18_STATUS.md",
|
"REPAIR18_STATUS.md",
|
||||||
@@ -184,18 +314,16 @@
|
|||||||
"REPAIR21_STATUS.md",
|
"REPAIR21_STATUS.md",
|
||||||
"REPAIR22–28 creation-time status and runbooks"
|
"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.",
|
"history_policy": "Historical source/proof pins retain their original revisions; CURRENT_STATUS.md is canonical. New approvals are not new native evidence.",
|
||||||
"evidence_policy": "Root-measured S4r28 4/4 PASS, controls, local8, r22 collection, schema2 index, registered validation PASS28s; worker SOURCE-READY / NOTRUN.",
|
"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": [
|
"pending": [
|
||||||
"Owner D05 a–d approval or explicit non-mandatory ruling; unknown mandatory rules stay pending",
|
"Complete current-Q collector/wrapper/index binding and S5 drivers; see REPAIR30_STATUS.md",
|
||||||
"Post-approval normal checker/registry repair (a61 unchanged here)",
|
"Fresh native S1-S5 on final Q, then full184/329 on the same Q including checker",
|
||||||
"support53cb normal registered rebind",
|
"Truthful index, formal registered validation on S --verify-only, whole-unit independent review, normal C integration",
|
||||||
"final full1339 against final checker; none exists against a61",
|
"nativeWindows individually pending for every condition"
|
||||||
"independent review and integration: P04 first, support on main9b afterward",
|
|
||||||
"nativeWindows obligations individually if required"
|
|
||||||
],
|
],
|
||||||
"priority_candidates_if_required": "D05_REMAINING_ORDER_CANDIDATE.json",
|
"priority_candidates_if_required": "D05_REMAINING_ORDER_CANDIDATE.json (superseded history)",
|
||||||
"collection_plan": "s4/S4_ROOT_RUN.md",
|
"collection_plan": "REPAIR30_STATUS.md",
|
||||||
"formal_acceptance": false,
|
"formal_acceptance": false,
|
||||||
"original_unit_complete": false,
|
"original_unit_complete": false,
|
||||||
"phase_order": [
|
"phase_order": [
|
||||||
@@ -436,5 +564,24 @@
|
|||||||
],
|
],
|
||||||
"observed-current": "All phase and source behavior observations; not approval"
|
"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,88 @@
|
|||||||
|
# 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. REPAIR35
|
||||||
|
adds fresh-Q input binding and separates historical R17 relocation checks from
|
||||||
|
the unchanged probe checks. All source and parse counts are derived. Historical
|
||||||
|
R17 requires `--historical-r17 --check-only` and is read-only. Only historical
|
||||||
|
mode defaults `--project-root` to PRODUCT. Fresh-Q requires an explicit root and
|
||||||
|
all three full lowercase HEX40 inputs. R17 MANIFEST and repair22 power-functions
|
||||||
|
JSON are historical_not_inputs in fresh-Q plans, never fresh-Q fixed pins.
|
||||||
|
No old S1–S4 record is renamed or reused as fresh proof.
|
||||||
|
|
||||||
|
REPAIR36 supplies a bounded UID diagnostic, not native/batch admission. Full admission still awaits S5
|
||||||
|
destruction/midnight/exit, S1–S4/collector fresh Q, 184 suites / 329 parse and the
|
||||||
|
truthful index are ready. Root run order and exact-candidate qualification also
|
||||||
|
remain pending. The native implementation is retained for later Root admission;
|
||||||
|
this change and a check-only plan give no admission or acceptance credit.
|
||||||
|
|
||||||
|
After the final submission, Root alone prepares Q using these steps (not performed by the worker):
|
||||||
|
|
||||||
|
1. Set S to the final submission and M to
|
||||||
|
`c0ea009b28a7649aca6a433a1a24dc0be5e7ab81`; derive Qt with
|
||||||
|
`git merge-tree --write-tree "$M" "$S"`.
|
||||||
|
2. Create X with `git commit-tree "$Qt" -m 'nonproduction Q checkout'` with
|
||||||
|
**no parents**, then create a clean worktree at X. X is a nonproduction
|
||||||
|
checkout carrier of Q, never normal Runner C. R34 and Root normal_c_join
|
||||||
|
remain unchanged.
|
||||||
|
3. Stage the s5 directory under Root's own B, the registered BUILD directory.
|
||||||
|
4. Follow the REPAIR36 order below, with fresh output and plan paths:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
BUILD_OUTPUT_DIR="$B" python3 "$B/.../run_s5_native.py" \
|
||||||
|
--project-root "$wt" --main "$M" --submission "$S" --tested-tree "$Qt" \
|
||||||
|
--check-only --plan "$B/p04-s5-plan-r36.json" --output "$B/p04-s5-DIAG-r36"
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Pure fixtures and controls follow the order below. Their JSON has accepted=false.
|
||||||
|
6. In separate controlled check-only cases, require rejection for: a dirty file;
|
||||||
|
an untracked file; HEAD tree unequal to --tested-tree; wrong --submission;
|
||||||
|
--main unequal to the frozen anchor. Preserve each actual rejection receipt
|
||||||
|
and restore a clean carrier between cases. These Git negatives and all pure
|
||||||
|
fixtures are unexecuted in this worker submission. No engine runs.
|
||||||
|
|
||||||
|
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. All 7 domains + EV and original 30/88 remain fixed. Root alone
|
||||||
|
performs later qualification; no engine is authorized for this worker.
|
||||||
|
|
||||||
|
## REPAIR36 UID diagnostic protocol and Root order
|
||||||
|
|
||||||
|
Protocol `p04-s5-fresh-q-uid-diagnostic-v1` is a diagnostic composite with
|
||||||
|
standard_execute_phase_context=false, native_admissible=false and
|
||||||
|
fresh_q_evidence=false. The wrapper extracts only uid_plan and uid_snapshot
|
||||||
|
from the actual pinned Q helper using AST, binding shared to the actual Q
|
||||||
|
runner. It does not execute the helper module. Plans derive finite UID owners
|
||||||
|
from staged refs; import alone seals exact UID bytes. Private function globals
|
||||||
|
replace declared_reports while preserving the execute_phase code object.
|
||||||
|
All four phase UID receipts and the post-cleanup seal are required.
|
||||||
|
Historical mode has no UID instrumentation and remains read-only.
|
||||||
|
|
||||||
|
Root order, all unexecuted by this worker:
|
||||||
|
|
||||||
|
1. py_compile the wrapper and both pure control files.
|
||||||
|
2. Run s5_wrapper_fixtures.py.
|
||||||
|
3. Run `python3 "$B/.../s5_uid_controls.py" --project-root "$wt" --scratch "$B/p04-s5-uid-controls-r36"`.
|
||||||
|
Scratch must be absolute, absent, outside Q, with an existing parent in BUILD.
|
||||||
|
4. Produce a fresh check-only plan with the command above.
|
||||||
|
5. Perform exactly one fresh diagnostic with the identical command and paths,
|
||||||
|
removing only --check-only. Use a new output name; preserve
|
||||||
|
`p04-s5-DIAG-r35` as FAILED. This is a bounded diagnostic, not full admission.
|
||||||
|
|
||||||
|
Root must confirm the actual Q run_all_tests.py matches the supplied reference
|
||||||
|
(sha256 prefix 320ca668); the worker read only the mirror for Q API context.
|
||||||
|
Runtime helper fingerprints and source/provenance guards bind the actual Q.
|
||||||
|
No full regression, 15+EV batch or original credit is claimed. The S5
|
||||||
|
destruction/midnight/exit drivers, S1–S4/collector fresh Q, derived 184 suites /
|
||||||
|
329 parse, truthful index and Root exact-candidate qualification remain pending.
|
||||||
@@ -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,596 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""S5-only native entry. --check-only never loads ownership helpers or starts Godot."""
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
import ast
|
||||||
|
import builtins
|
||||||
|
import inspect
|
||||||
|
import types
|
||||||
|
import copy
|
||||||
|
import hashlib
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
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 r17_relocation_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)
|
||||||
|
|
||||||
|
def probe_guard(root):
|
||||||
|
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 load_uid_helper(root, r, refs):
|
||||||
|
hp = root / "tools/run_p13_reference_tests.py"
|
||||||
|
descriptor = pin(hp)
|
||||||
|
r.require(all(descriptor[k] == refs["tools/run_p13_reference_tests.py"][k]
|
||||||
|
for k in ("bytes", "sha256")), "actual Q UID helper pin")
|
||||||
|
src = hp.read_bytes()
|
||||||
|
r.require(len(src) == descriptor["bytes"] and
|
||||||
|
hashlib.sha256(src).hexdigest() == descriptor["sha256"], "stable helper read")
|
||||||
|
tree = ast.parse(src, filename=str(hp))
|
||||||
|
nodes = []
|
||||||
|
for name in ("uid_plan", "uid_snapshot"):
|
||||||
|
matches = [n for n in tree.body if isinstance(n, ast.FunctionDef) and n.name == name]
|
||||||
|
r.require(len(matches) == 1, "exactly one UID helper: " + name)
|
||||||
|
nodes.append(matches[0])
|
||||||
|
ns = {"__builtins__": builtins, "shared": r, "re": re, "stat": stat}
|
||||||
|
exec(compile(ast.Module(body=nodes, type_ignores=[]), str(hp), "exec"), ns)
|
||||||
|
binding = dict(helper_path="tools/run_p13_reference_tests.py",
|
||||||
|
helper_sha256=descriptor["sha256"], helper_bytes=descriptor["bytes"],
|
||||||
|
functions={n.name: hashlib.sha256(ast.get_source_segment(src.decode(), n).encode()).hexdigest()
|
||||||
|
for n in nodes}, shared_module="tools/run_all_tests.py",
|
||||||
|
shared_sha256=r.sha(root / "tools/run_all_tests.py"))
|
||||||
|
return ns["uid_plan"], ns["uid_snapshot"], binding
|
||||||
|
|
||||||
|
|
||||||
|
def make_uid_policy(r, uid_snapshot, source, plan, out):
|
||||||
|
state = dict(source=source, plan=plan, accepted=None, phase=None)
|
||||||
|
|
||||||
|
def reports(stage, exp, previous, requested):
|
||||||
|
r.require(not previous and not requested, "S5 has no generated reports")
|
||||||
|
snap = uid_snapshot(stage, source, plan)
|
||||||
|
if state["accepted"] is None:
|
||||||
|
r.require(state["phase"] == "import", "UID generation only during import")
|
||||||
|
state["accepted"] = snap
|
||||||
|
exp.update({n: {k: p[k] for k in ("bytes", "sha256")} for n, p in snap.items()})
|
||||||
|
r.write(out / "accepted-uids.json", snap)
|
||||||
|
r.require(snap == state["accepted"], "sealed UID bytes unchanged")
|
||||||
|
return r.declared_reports(stage, exp, previous, requested)
|
||||||
|
|
||||||
|
execute = types.FunctionType(r.execute_phase.__code__, dict(vars(r), declared_reports=reports),
|
||||||
|
"execute_phase", r.execute_phase.__defaults__, r.execute_phase.__closure__)
|
||||||
|
r.require(execute.__code__ is r.execute_phase.__code__, "unchanged execute_phase code object")
|
||||||
|
|
||||||
|
def phase_call(*args):
|
||||||
|
stage, phase_out, phase = args[1:4]
|
||||||
|
r.require(phase_out == out, "UID receipt output binding")
|
||||||
|
state["phase"] = phase
|
||||||
|
before, after = None, None
|
||||||
|
try:
|
||||||
|
if phase == "import":
|
||||||
|
r.require(state["accepted"] is None and not (out / "uid-plan.json").exists(), "single UID import")
|
||||||
|
r.require(r.inventory(stage, stage=True) == source, "original stage before import")
|
||||||
|
before = {}
|
||||||
|
r.write(out / "uid-plan.json", plan)
|
||||||
|
else:
|
||||||
|
before = uid_snapshot(stage, source, plan)
|
||||||
|
r.require(before == state["accepted"], "UID set before phase unchanged")
|
||||||
|
row = execute(*args)
|
||||||
|
if row["passed"]:
|
||||||
|
snap = uid_snapshot(stage, source, plan)
|
||||||
|
r.require(snap == state["accepted"], "UID set after phase unchanged")
|
||||||
|
after = snap
|
||||||
|
return row
|
||||||
|
finally:
|
||||||
|
r.write(out / (phase + "-uids.json"), dict(before=before, after=after))
|
||||||
|
|
||||||
|
return reports, phase_call, state
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
C_REL = "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json"
|
||||||
|
|
||||||
|
|
||||||
|
def select_mode(args):
|
||||||
|
"""Pure CLI mode selection; no filesystem or Git access."""
|
||||||
|
triple = (args.main, args.submission, args.tested_tree)
|
||||||
|
if any(value is not None for value in triple):
|
||||||
|
if (not all(isinstance(value, str) and re.fullmatch(r"[0-9a-f]{40}", value)
|
||||||
|
for value in triple) or args.historical_r17):
|
||||||
|
raise ValueError("fresh-q requires a full HEX40 triple without --historical-r17")
|
||||||
|
return "fresh-q"
|
||||||
|
if args.historical_r17 and args.check_only:
|
||||||
|
return "historical-r17-readonly"
|
||||||
|
raise ValueError("historical R17 is read-only; require --historical-r17 --check-only")
|
||||||
|
|
||||||
|
|
||||||
|
def fresh_q_guard(root, M, S, Qt):
|
||||||
|
gate = module("s5_gate", root / "tools/check_p04_order_evidence.py")
|
||||||
|
gate.require(Path(gate.__file__).resolve() == root / gate.CHECKER_PATH
|
||||||
|
and not root.is_symlink(), "fresh-q checker/root location")
|
||||||
|
gate.require(M == gate.MAIN_ANCHOR, "fresh-q main anchor")
|
||||||
|
commit, tree, entries = gate.actual_checkout()
|
||||||
|
gate.require(tree == Qt and commit != S and commit != M, "fresh-q checkout carrier")
|
||||||
|
gate.require(Path(os.environ["BUILD_OUTPUT_DIR"]).resolve() == BUILD.resolve(),
|
||||||
|
"fresh-q own BUILD_OUTPUT_DIR")
|
||||||
|
with gate.isolated_objects():
|
||||||
|
for value in (M, S):
|
||||||
|
gate.require(gate.git_bytes("cat-file", "-t", value) == b"commit\n", "commit input")
|
||||||
|
gate.submission_role(S)
|
||||||
|
composed = gate.git_bytes("-c", "rerere.enabled=false", "merge-tree", "--write-tree", M, S).decode().strip()
|
||||||
|
gate.require(re.fullmatch(r"[0-9a-f]{40}", composed) is not None and composed == Qt,
|
||||||
|
"fresh-q recomputed tree")
|
||||||
|
gate.require(hashlib.sha256(gate.git_bytes("show", M + ":tools/run_all_tests.py")).hexdigest()
|
||||||
|
== gate.SELECTION_SHA, "selection authority")
|
||||||
|
gate.require(gate.product_manifest(gate.tree_entries(M)) == gate.product_manifest(entries),
|
||||||
|
"fresh-q product unchanged")
|
||||||
|
sel = gate.selected_manifest(entries, require_checker=True)
|
||||||
|
r = module("s5_guard_runner", root / "tools/run_all_tests.py")
|
||||||
|
source_before = r.source_refs(root)
|
||||||
|
gate.require(source_before.keys() == sel.keys() and TEST in sel,
|
||||||
|
"fresh-q selected source keys")
|
||||||
|
gate.require({name: {key: value[key] for key in ("bytes", "sha256")}
|
||||||
|
for name, value in source_before.items()} == sel, "fresh-q selected bytes")
|
||||||
|
gate.require(C_REL in entries, "fresh-q contracts entry")
|
||||||
|
blob = gate.git_bytes("cat-file", "blob", entries[C_REL][1])
|
||||||
|
contract_pin = pin(root / C_REL)
|
||||||
|
gate.require(contract_pin["bytes"] == len(blob)
|
||||||
|
and contract_pin["sha256"] == hashlib.sha256(blob).hexdigest(),
|
||||||
|
"fresh-q contracts pin")
|
||||||
|
build = BUILD.resolve()
|
||||||
|
gate.require(HERE.is_relative_to(build), "fresh-q staged HERE inside BUILD")
|
||||||
|
for staged in [HERE, *HERE.rglob("*")]:
|
||||||
|
current = build
|
||||||
|
for part in staged.relative_to(build).parts:
|
||||||
|
current = current / part
|
||||||
|
gate.require(not current.is_symlink(), "fresh-q staged symlink")
|
||||||
|
gate.require(staged.is_dir() or stat.S_ISREG(staged.stat().st_mode),
|
||||||
|
"fresh-q staged regular file")
|
||||||
|
return dict(M=M, S=S, Q_tree=Qt, recomputed_Q=composed, checkout_commit=commit,
|
||||||
|
checkout_role="nonproduction Root checkout carrier of tree Q; NOT normal Runner C",
|
||||||
|
selected_manifest_sha256=gate.manifest_digest(sel), selected_file_count=len(sel),
|
||||||
|
product_file_count=len(sel)-1, selection_authority_sha256=gate.SELECTION_SHA)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("--project-root", type=Path, default=None)
|
||||||
|
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")
|
||||||
|
parser.add_argument("--main")
|
||||||
|
parser.add_argument("--submission")
|
||||||
|
parser.add_argument("--tested-tree")
|
||||||
|
parser.add_argument("--historical-r17", action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
mode = select_mode(args)
|
||||||
|
if mode == "fresh-q" and args.project_root is None:
|
||||||
|
raise ValueError("fresh-q requires explicit --project-root")
|
||||||
|
project_root = args.project_root if args.project_root is not None else PRODUCT
|
||||||
|
if project_root.is_symlink():
|
||||||
|
raise ValueError("project root symlink")
|
||||||
|
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 = 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)
|
||||||
|
provenance = None
|
||||||
|
if mode == "fresh-q":
|
||||||
|
provenance = fresh_q_guard(root, args.main, args.submission, args.tested_tree)
|
||||||
|
else:
|
||||||
|
r17_relocation_guard(root)
|
||||||
|
probe_guard(root)
|
||||||
|
expected = {n: dict(bytes=p["bytes"], sha256=p["sha256"]) for n, p in refs.items()}
|
||||||
|
uid_source = copy.deepcopy(expected)
|
||||||
|
contracts_path = root / C_REL if mode == "fresh-q" else CONTRACTS
|
||||||
|
fixed = [pin(p) for p in ([] if mode == "fresh-q" else MATERIALS) + [
|
||||||
|
QA, Path(__file__), HERE / "S5_ROOT_RUN.md",
|
||||||
|
root / "tests/transport/test_runtime_transport.gd",
|
||||||
|
root / "tests/staff/test_rescue_elevator.gd",
|
||||||
|
contracts_path,
|
||||||
|
]]
|
||||||
|
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-fresh-q-v1" if mode == "fresh-q" else "p04-s5-historical-r17-readonly-v1"),
|
||||||
|
mode=mode, provenance=provenance, historical_r17=mode != "fresh-q",
|
||||||
|
native_admissible=False, fresh_q_evidence=False,
|
||||||
|
historical_not_inputs=[str(p) for p in MATERIALS] if mode == "fresh-q" else [],
|
||||||
|
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)
|
||||||
|
if mode == "fresh-q":
|
||||||
|
uid_plan, uid_snapshot, binding = load_uid_helper(root, r, source_before)
|
||||||
|
uid_plan_map = uid_plan(refs)
|
||||||
|
r.require(len(uid_plan_map) > 0, "nonempty derived UID plan")
|
||||||
|
r.require(all(p["owner"] in refs and p["owner_sha256"] == refs[p["owner"]]["sha256"]
|
||||||
|
for p in uid_plan_map.values()), "UID plan owner bindings")
|
||||||
|
plan.update(protocol="p04-s5-fresh-q-uid-diagnostic-v1", diagnostic_composite=True,
|
||||||
|
standard_execute_phase_context=False, uid_plan=uid_plan_map,
|
||||||
|
uid_plan_count=len(uid_plan_map), instrumentation=dict(
|
||||||
|
wrapper_sha256=r.sha(__file__),
|
||||||
|
execute_phase_source_sha256=hashlib.sha256(inspect.getsource(r.execute_phase).encode()).hexdigest(),
|
||||||
|
declared_reports_source_sha256=hashlib.sha256(inspect.getsource(r.declared_reports).encode()).hexdigest(),
|
||||||
|
callback="private-globals declared_reports + phase wrapper", uid_helper=binding))
|
||||||
|
# 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
|
||||||
|
if mode != "fresh-q":
|
||||||
|
raise ValueError("historical R17 is read-only")
|
||||||
|
r.require(len(source_before) == provenance["selected_file_count"], "fresh-q selected count")
|
||||||
|
r.require(args.plan.is_file() and r.read(args.plan) == plan, "run exact check-only plan first")
|
||||||
|
reports, phase_call, uid_state = make_uid_policy(r, uid_snapshot, uid_source, plan["uid_plan"], out)
|
||||||
|
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")
|
||||||
|
r.require(fresh_q_guard(root, args.main, args.submission, args.tested_tree) == provenance,
|
||||||
|
"fresh-q provenance changed")
|
||||||
|
probe_guard(root)
|
||||||
|
hp = pin(root / binding["helper_path"])
|
||||||
|
r.require(hp["bytes"] == binding["helper_bytes"] and hp["sha256"] == binding["helper_sha256"],
|
||||||
|
"UID helper unchanged")
|
||||||
|
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()}
|
||||||
|
excluded = {"tools/check_p04_order_evidence.py", TEST}
|
||||||
|
r.require({k: v for k, v in old_map.items() if k not in excluded}
|
||||||
|
== {k: v for k, v in current_map.items() if k not in excluded},
|
||||||
|
"immutable cache selected inputs except checker and QA override")
|
||||||
|
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) == sum(name.endswith(".gd") for name in refs), "complete derived parse roster")
|
||||||
|
r.write(out / "parse-paths.json", paths)
|
||||||
|
markers = module("s5_markers", root / "tools/strict_test_markers.py")
|
||||||
|
contracts = markers.load_contracts(contracts_path)
|
||||||
|
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,
|
||||||
|
uid_helper=binding, uid_plan=plan["uid_plan"], uid_source_count=len(uid_source),
|
||||||
|
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 = phase_call(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()
|
||||||
|
if uid_state["accepted"] is not None:
|
||||||
|
r.require(uid_snapshot(stage, uid_source, plan["uid_plan"]) == uid_state["accepted"],
|
||||||
|
"UID seal after cleanup")
|
||||||
|
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)
|
||||||
|
and uid_state["accepted"] is not None
|
||||||
|
and set(uid_state["accepted"]) == set(plan["uid_plan"])
|
||||||
|
and all((out / (phase + "-uids.json")).is_file() for phase in plan["phases"]))
|
||||||
|
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,119 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Pure Root-only UID controls; no engine or environment access."""
|
||||||
|
import argparse
|
||||||
|
import copy
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.dont_write_bytecode = True
|
||||||
|
|
||||||
|
|
||||||
|
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 main():
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('--project-root', required=True, type=Path)
|
||||||
|
parser.add_argument('--scratch', required=True, type=Path)
|
||||||
|
args = parser.parse_args()
|
||||||
|
root = args.project_root.resolve(strict=True)
|
||||||
|
r = module('s5_uid_q_runner', root / 'tools/run_all_tests.py')
|
||||||
|
w = module('s5_uid_wrapper', Path(__file__).with_name('run_s5_native.py'))
|
||||||
|
# Actual Q pins precede all synthetic data. No synthetic refs enter the loader.
|
||||||
|
uid_plan, uid_snapshot, binding = w.load_uid_helper(root, r, r.source_refs(root))
|
||||||
|
scratch = args.scratch
|
||||||
|
r.require(scratch.is_absolute() and not scratch.exists() and not scratch.is_symlink(),
|
||||||
|
'absolute fresh scratch')
|
||||||
|
parent = scratch.parent.resolve(strict=True)
|
||||||
|
r.require(parent.is_dir() and parent.is_relative_to(w.BUILD.resolve())
|
||||||
|
and not (parent / scratch.name).is_relative_to(root), 'scratch parent inside BUILD outside Q')
|
||||||
|
scratch = parent / scratch.name
|
||||||
|
scratch.mkdir()
|
||||||
|
results = []
|
||||||
|
|
||||||
|
def fixture(label):
|
||||||
|
stage = scratch / label
|
||||||
|
stage.mkdir()
|
||||||
|
files = {'project.godot': b'config_version=5\n',
|
||||||
|
'scripts/special/peeping_room_service.gd': b'extends Node\n',
|
||||||
|
'tests/special/test_a.gd': b'extends SceneTree\n',
|
||||||
|
'scripts/other.gd': b'extends RefCounted\n',
|
||||||
|
'scripts/other.gd.uid': b'uid://existing\n'}
|
||||||
|
for name, data in files.items():
|
||||||
|
path = stage / name
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_bytes(data)
|
||||||
|
source = r.inventory(stage, stage=True)
|
||||||
|
refs = {n: dict(p, path=str(stage / n)) for n, p in source.items()}
|
||||||
|
plan = uid_plan(refs)
|
||||||
|
r.require(bool(plan) and all(p['owner_sha256'] == refs[p['owner']]['sha256']
|
||||||
|
for p in plan.values()), 'derived synthetic plan')
|
||||||
|
for i, name in enumerate(plan):
|
||||||
|
(stage / name).write_bytes(('uid://generated' + str(i) + '\n').encode())
|
||||||
|
return stage, source, plan
|
||||||
|
|
||||||
|
stage, source, plan = fixture('positive')
|
||||||
|
snap = uid_snapshot(stage, source, plan)
|
||||||
|
r.require(set(snap) == set(plan), 'exact positive planned UID set')
|
||||||
|
results.append('positive')
|
||||||
|
|
||||||
|
def negative(label, mutate):
|
||||||
|
stage, source, plan = fixture(label)
|
||||||
|
names = list(plan)
|
||||||
|
mutate(stage, source, plan, names)
|
||||||
|
try:
|
||||||
|
uid_snapshot(stage, source, plan)
|
||||||
|
except AssertionError:
|
||||||
|
results.append(label)
|
||||||
|
else:
|
||||||
|
raise AssertionError('control did not reject: ' + label)
|
||||||
|
|
||||||
|
negative('extra', lambda s, a, p, n: (s / 'extra.uid').write_bytes(b'uid://extra\n'))
|
||||||
|
negative('original', lambda s, a, p, n: (s / 'project.godot').write_bytes(b'changed\n'))
|
||||||
|
negative('owner', lambda s, a, p, n: (s / p[n[0]]['owner']).write_bytes(b'changed\n'))
|
||||||
|
negative('existing-collision', lambda s, a, p, n: (s / n[0]).write_bytes(b'uid://existing\n'))
|
||||||
|
negative('generated-collision', lambda s, a, p, n: (s / n[0]).write_bytes((s / n[1]).read_bytes()))
|
||||||
|
for label, raw in [('no-newline', b'uid://abc'), ('crlf', b'uid://abc\r\n'),
|
||||||
|
('uppercase', b'uid://ABC\n'), ('too-long', b'uid://abcdefghijklmn\n')]:
|
||||||
|
negative(label, lambda s, a, p, n, raw=raw: (s / n[0]).write_bytes(raw))
|
||||||
|
|
||||||
|
def hardlink(stage, source, plan, names):
|
||||||
|
os.link(stage / names[0], scratch / 'hardlink-peer')
|
||||||
|
|
||||||
|
def symlink(stage, source, plan, names):
|
||||||
|
path = stage / names[0]
|
||||||
|
path.unlink()
|
||||||
|
path.symlink_to(stage / names[1])
|
||||||
|
|
||||||
|
negative('hardlink', hardlink)
|
||||||
|
negative('symlink', symlink)
|
||||||
|
negative('missing', lambda s, a, p, n: (s / n[0]).unlink())
|
||||||
|
stage, source, plan = fixture('post-seal')
|
||||||
|
out = scratch / 'policy-receipts'
|
||||||
|
out.mkdir()
|
||||||
|
reports, phase_call, state = w.make_uid_policy(r, uid_snapshot, source, plan, out)
|
||||||
|
expected = copy.deepcopy(source)
|
||||||
|
state['phase'] = 'import'
|
||||||
|
reports(stage, expected, {}, [])
|
||||||
|
r.require(state['accepted'] == uid_snapshot(stage, source, plan), 'import sealed')
|
||||||
|
state['phase'] = 'parse'
|
||||||
|
(stage / next(iter(plan))).write_bytes(b'uid://mutated\n')
|
||||||
|
try:
|
||||||
|
reports(stage, expected, {}, [])
|
||||||
|
except AssertionError:
|
||||||
|
results.append('post-seal-reports')
|
||||||
|
else:
|
||||||
|
raise AssertionError('post-seal mutation accepted')
|
||||||
|
print(json.dumps({'accepted': False, 'Root-only': True, 'controls': results,
|
||||||
|
'uid_helper': binding, 'scratch': str(scratch)}))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Pure select_mode fixtures; no Git, engine, temporary files or environment access."""
|
||||||
|
import argparse
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.dont_write_bytecode = True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
path = Path(__file__).parent / "run_s5_native.py"
|
||||||
|
spec = importlib.util.spec_from_file_location("s5_wrapper_fixture_target", path)
|
||||||
|
wrapper = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(wrapper)
|
||||||
|
cases = [
|
||||||
|
("partial-triple", argparse.Namespace(main="a" * 40, submission=None, tested_tree=None,
|
||||||
|
historical_r17=False, check_only=True), None),
|
||||||
|
("non-hex", argparse.Namespace(main="z" * 40, submission="b" * 40, tested_tree="c" * 40,
|
||||||
|
historical_r17=False, check_only=True), None),
|
||||||
|
("short", argparse.Namespace(main="a" * 39, submission="b" * 40, tested_tree="c" * 40,
|
||||||
|
historical_r17=False, check_only=True), None),
|
||||||
|
("mixed-modes", argparse.Namespace(main="a" * 40, submission="b" * 40, tested_tree="c" * 40,
|
||||||
|
historical_r17=True, check_only=True), None),
|
||||||
|
("historical-native", argparse.Namespace(main=None, submission=None, tested_tree=None,
|
||||||
|
historical_r17=True, check_only=False), None),
|
||||||
|
("no-flags", argparse.Namespace(main=None, submission=None, tested_tree=None,
|
||||||
|
historical_r17=False, check_only=False), None),
|
||||||
|
("fresh-q", argparse.Namespace(main="a" * 40, submission="b" * 40, tested_tree="c" * 40,
|
||||||
|
historical_r17=False, check_only=True), "fresh-q"),
|
||||||
|
("historical-check-only", argparse.Namespace(main=None, submission=None, tested_tree=None,
|
||||||
|
historical_r17=True, check_only=True),
|
||||||
|
"historical-r17-readonly"),
|
||||||
|
]
|
||||||
|
results = []
|
||||||
|
for name, args, expected in cases:
|
||||||
|
try:
|
||||||
|
actual = wrapper.select_mode(args)
|
||||||
|
passed = expected is not None and actual == expected
|
||||||
|
except ValueError:
|
||||||
|
actual = "ValueError"
|
||||||
|
passed = expected is None
|
||||||
|
results.append(dict(name=name, result=actual, passed=passed))
|
||||||
|
print(json.dumps(dict(accepted=False, fixtures=results, passed=all(r["passed"] for r in results))))
|
||||||
|
return 0 if all(r["passed"] for r in results) else 1
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
||||||
@@ -20,13 +20,29 @@ ROOT = Path(__file__).resolve().parents[1]
|
|||||||
SPEC = ROOT / 'docs/spec/acceptance/P04-01.json'
|
SPEC = ROOT / 'docs/spec/acceptance/P04-01.json'
|
||||||
SPEC_HASH = '9ec722e7dfb0bee178d291624a026420c08412574e238bba1fde012c7a6f7881'
|
SPEC_HASH = '9ec722e7dfb0bee178d291624a026420c08412574e238bba1fde012c7a6f7881'
|
||||||
DOMAINS = {'閉店', '停電', '破壊', '退出', '課金', 'シフト交代', '00:00決算'}
|
DOMAINS = {'閉店', '停電', '破壊', '退出', '課金', 'シフト交代', '00:00決算'}
|
||||||
OWNER_HASH = '4583ee9aad45c4db183d72df4420df48aa8e0897e3b5efda13016f0b5cdbd68e'
|
|
||||||
REGISTERED_COMMIT = 'deb1bcb2374eb378b840ca345db952bd8572cb6e'
|
REGISTERED_COMMIT = 'deb1bcb2374eb378b840ca345db952bd8572cb6e'
|
||||||
EXECUTION_ORIGIN = '9767b0a28ca8d252520307dbbac60a1d8cfb87ab'
|
EXECUTION_ORIGIN = '9767b0a28ca8d252520307dbbac60a1d8cfb87ab'
|
||||||
CHECKER_PATH = 'tools/check_p04_order_evidence.py'
|
CHECKER_PATH = 'tools/check_p04_order_evidence.py'
|
||||||
DOC_SCOPE = 'docs/plans/original-completion-2026-10-02/execution/p04-01/'
|
DOC_SCOPE = 'docs/plans/original-completion-2026-10-02/execution/p04-01/'
|
||||||
MAIN_ANCHOR = '9b1a18c1eb25ca1300dcd59da78423c0dda2f498'
|
OWNER_BINDINGS = {
|
||||||
TESTED_PRODUCT = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1'
|
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'
|
||||||
|
# Documentation only: external Runner prepare_integration/integrate and Root
|
||||||
|
# normal_c_join joins after final. The checker never consumes this roster.
|
||||||
|
NORMAL_C_PROVENANCE_JOIN = 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'
|
SELECTION_SHA = '320ca668732b4ff72fc4449998af2327d4e5c527b06896740806aaf0487282b4'
|
||||||
_GIT_ENV = None
|
_GIT_ENV = None
|
||||||
# Fixed membership, never supplied by the evidence index.
|
# Fixed membership, never supplied by the evidence index.
|
||||||
@@ -43,19 +59,20 @@ ORDER_FUNCTIONS = {
|
|||||||
'scripts/operations/operations_coordinator.gd': ('_process_minute_boundaries',),
|
'scripts/operations/operations_coordinator.gd': ('_process_minute_boundaries',),
|
||||||
}
|
}
|
||||||
# Condition -> (domain, authority refs, required engine measurements).
|
# 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 = {
|
REQUIRED = {
|
||||||
'power_stop': ('停電', ('BASELINE:183',), {'charges': 0}),
|
'power_stop': ('停電', ('BASELINE:183', 'D05-P04-PAUSE-REASON'), {'charges': 0}),
|
||||||
'destruction_stop': ('破壊', ('BASELINE:183',), {'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}),
|
'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}),
|
'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}),
|
'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}),
|
'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}),
|
'closure_release': ('閉店', ('D-034',), {'orphan_reservations': 0, 'released_once': True, 'started_service_continues': True}),
|
||||||
'exit_release': ('退出', ('D-034',), {'orphan_reservations': 0, 'released_once': True}),
|
'exit_release': ('退出', ('D-034', 'D05-P04-EXIT'), {'orphan_reservations': 0, 'released_once': True}),
|
||||||
'patience_release': ('退出', ('D-034',), {'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'), {'orphan_reservations': 0, 'crossed_midnight_while_paused': True, 'stopped_charges': 0, 'completions': 1, 'charges': 1}),
|
'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'), {'settlements': 1, 'sales_payments': 1, 'payroll_payments': 1, 'upkeep_payments': 1, 'duty_payments': 1, 'nonzero_payroll': True}),
|
'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}),
|
'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}),
|
'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}),
|
'night_staff_absent': ('シフト交代', ('BASELINE:67', 'D05-P04-SHIFT-1800'), {'minute': 1081, 'state': 'WAITING_FOR_STAFF', 'night_staff_count': 0}),
|
||||||
@@ -244,6 +261,16 @@ def product_manifest(entries):
|
|||||||
return result
|
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):
|
def manifest_digest(manifest):
|
||||||
return hashlib.sha256(json.dumps(manifest, sort_keys=True, separators=(',', ':')).encode()).hexdigest()
|
return hashlib.sha256(json.dumps(manifest, sort_keys=True, separators=(',', ':')).encode()).hexdigest()
|
||||||
|
|
||||||
@@ -266,91 +293,6 @@ def supplied_file(directory, descriptor):
|
|||||||
return path
|
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):
|
def ancestor(older, newer):
|
||||||
# merge-base's nonzero status is data only for the ordinary non-ancestor case.
|
# merge-base's nonzero status is data only for the ordinary non-ancestor case.
|
||||||
try:
|
try:
|
||||||
@@ -398,6 +340,7 @@ def verify_roles(index, directory):
|
|||||||
"""Infer roles from Git, never from an index or a caller's stage label."""
|
"""Infer roles from Git, never from an index or a caller's stage label."""
|
||||||
require(not ({'candidate_commit', 'candidate_tree', 'code_only', 'candidate', 'phase'} & index.keys()),
|
require(not ({'candidate_commit', 'candidate_tree', 'code_only', 'candidate', 'phase'} & index.keys()),
|
||||||
'candidate/code-only/phase declarations are not evidence')
|
'candidate/code-only/phase declarations are not evidence')
|
||||||
|
candidate = None
|
||||||
commit, actual_tree, actual = actual_checkout()
|
commit, actual_tree, actual = actual_checkout()
|
||||||
require(_GIT_ENV is not None, 'isolated object store required')
|
require(_GIT_ENV is not None, 'isolated object store required')
|
||||||
if not ancestor(MAIN_ANCHOR, commit):
|
if not ancestor(MAIN_ANCHOR, commit):
|
||||||
@@ -407,7 +350,7 @@ def verify_roles(index, directory):
|
|||||||
parents = git_bytes('show', '-s', '--format=%P', commit).decode().split()
|
parents = git_bytes('show', '-s', '--format=%P', commit).decode().split()
|
||||||
require(len(parents) == 2, 'integration/final requires a two-parent no-ff merge')
|
require(len(parents) == 2, 'integration/final requires a two-parent no-ff merge')
|
||||||
main, submitted = parents
|
main, submitted = parents
|
||||||
require(ancestor(MAIN_ANCHOR, main), 'merge main ancestry')
|
require(main == MAIN_ANCHOR, 'integration main is not frozen M')
|
||||||
submission_role(submitted)
|
submission_role(submitted)
|
||||||
role = 'integration/final'
|
role = 'integration/final'
|
||||||
composed = git_bytes('-c', 'rerere.enabled=false', 'merge-tree', '--write-tree',
|
composed = git_bytes('-c', 'rerere.enabled=false', 'merge-tree', '--write-tree',
|
||||||
@@ -425,6 +368,7 @@ def verify_roles(index, directory):
|
|||||||
'unknown source hidden as metadata: ' + path)
|
'unknown source hidden as metadata: ' + path)
|
||||||
if role == 'integration/final':
|
if role == 'integration/final':
|
||||||
require(actual_tree == composed and actual == target, 'actual merge differs from composition')
|
require(actual_tree == composed and actual == target, 'actual merge differs from composition')
|
||||||
|
candidate = qualify_normal_candidate(commit, actual_tree, main, submitted, composed)
|
||||||
require(target[CHECKER_PATH] == patch[CHECKER_PATH] == actual[CHECKER_PATH],
|
require(target[CHECKER_PATH] == patch[CHECKER_PATH] == actual[CHECKER_PATH],
|
||||||
'checker blob differs from submission')
|
'checker blob differs from submission')
|
||||||
for path in patch:
|
for path in patch:
|
||||||
@@ -432,16 +376,22 @@ def verify_roles(index, directory):
|
|||||||
require(target.get(path) == patch[path], 'reviewed patch differs in merge: ' + path)
|
require(target.get(path) == patch[path], 'reviewed patch differs in merge: ' + path)
|
||||||
binding = index['product_binding']
|
binding = index['product_binding']
|
||||||
require(set(binding) == {'tested_product', 'runner_inputs'}, 'unknown product role/metadata declaration')
|
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)
|
product = product_manifest(target)
|
||||||
tested_entries = tree_entries(TESTED_PRODUCT)
|
tested_entries = tree_entries(tested)
|
||||||
expected = product_manifest(tested_entries)
|
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,
|
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),
|
require(all(target[p][0] == main_entries[p][0] == tested_entries[p][0] for p in product),
|
||||||
'native product mode mismatch')
|
'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()
|
runner_paths = set()
|
||||||
for descriptor in binding['runner_inputs']:
|
for descriptor in binding['runner_inputs']:
|
||||||
path = supplied_file(directory, descriptor)
|
path = supplied_file(directory, descriptor)
|
||||||
@@ -449,14 +399,14 @@ def verify_roles(index, directory):
|
|||||||
runner_paths.add(path)
|
runner_paths.add(path)
|
||||||
native = load(path)
|
native = load(path)
|
||||||
before = native['source_before']
|
before = native['source_before']
|
||||||
require(set(before) == set(product) and all(
|
require(set(before) == set(selected_product) and all(
|
||||||
{'bytes': v['bytes'], 'sha256': v['sha256']} == product[p] for p, v in before.items()),
|
{'bytes': v['bytes'], 'sha256': v['sha256']} == selected_product[p] for p, v in before.items()),
|
||||||
'runner complete source map mismatch')
|
'runner complete source map mismatch')
|
||||||
require(native['runner_sha256'] == product['tools/run_all_tests.py']['sha256'], 'runner source pin')
|
require(native['runner_sha256'] == product['tools/run_all_tests.py']['sha256'], 'runner source pin')
|
||||||
overrides = native['QA_overrides']
|
overrides = native['QA_overrides']
|
||||||
require(len(overrides) == 1 and overrides[0].startswith('tests/') and overrides[0] in product,
|
require(len(overrides) == 1 and overrides[0].startswith('tests/') and overrides[0] in product,
|
||||||
'QA override membership')
|
'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']
|
selected[overrides[0]] = native['QA']['sha256']
|
||||||
require(native['selected_source_map'] == selected, 'selected QA source map')
|
require(native['selected_source_map'] == selected, 'selected QA source map')
|
||||||
needed = native.get('fixed_input_pins', []) + [native['QA']]
|
needed = native.get('fixed_input_pins', []) + [native['QA']]
|
||||||
@@ -467,11 +417,24 @@ def verify_roles(index, directory):
|
|||||||
require(sha(supplied_file(directory, descriptor['wrapper'])) == native['wrapper_sha256'], 'wrapper bytes')
|
require(sha(supplied_file(directory, descriptor['wrapper'])) == native['wrapper_sha256'], 'wrapper bytes')
|
||||||
require(runner_paths, 'runner inputs missing')
|
require(runner_paths, 'runner inputs missing')
|
||||||
require(index['versions'] == {'registered': REGISTERED_COMMIT, 'execution_origin': EXECUTION_ORIGIN,
|
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,
|
return composed, {'candidate_structure': candidate, 'role': role, 'actual_head': commit, 'actual_tree': actual_tree,
|
||||||
'submission': submitted, 'main': main, 'existing_metadata': metadata,
|
'submission': submitted, 'main': main, 'existing_metadata': metadata,
|
||||||
'manifest_sha256': manifest_digest(product), 'runner_paths': runner_paths,
|
'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):
|
||||||
|
"""Qualify structure only; Runner and Root verify provenance externally.
|
||||||
|
|
||||||
|
The documentation roster is never consumed. Structure grants no provenance
|
||||||
|
verification or original credit.
|
||||||
|
"""
|
||||||
|
require(tree == composed and main == MAIN_ANCHOR and commit != submitted,
|
||||||
|
'normal candidate identity mismatch')
|
||||||
|
return {'structure_qualified': True, 'provenance_verified_by_checker': False,
|
||||||
|
'provenance_owner': 'actual Runner.prepare_integration/integrate and Root normal_c_join AFTER final before original credit',
|
||||||
|
'join': {'C': commit, 'S': submitted, 'M': main, 'C_tree': tree, 'Q': composed}}
|
||||||
|
|
||||||
|
|
||||||
def function_bytes(data):
|
def function_bytes(data):
|
||||||
@@ -572,6 +535,19 @@ def applicability(index, spec, source, head):
|
|||||||
require(case_id == declaration.get('case_id'), 'boundary delta engine case: ' + key)
|
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):
|
def coverage(index, raw, source, product_tree):
|
||||||
authority = index['authority']
|
authority = index['authority']
|
||||||
for ref in {r for _, refs, _ in REQUIRED.values() for r in refs}:
|
for ref in {r for _, refs, _ in REQUIRED.values() for r in refs}:
|
||||||
@@ -580,11 +556,7 @@ def coverage(index, raw, source, product_tree):
|
|||||||
aid = entry.get('artifact_id')
|
aid = entry.get('artifact_id')
|
||||||
require(aid in raw and index['artifacts'][aid]['type'] == 'authority', 'raw authority: ' + ref)
|
require(aid in raw and index['artifacts'][aid]['type'] == 'authority', 'raw authority: ' + ref)
|
||||||
if ref.startswith('D05-P04-'):
|
if ref.startswith('D05-P04-'):
|
||||||
require(sha(raw[aid]) == OWNER_HASH, 'owner approval hash mismatch')
|
owner_authority(ref, entry, raw[aid])
|
||||||
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')
|
|
||||||
else:
|
else:
|
||||||
path = ('docs/traceability/original/BASELINE.txt' if ref.startswith('BASELINE:') else
|
path = ('docs/traceability/original/BASELINE.txt' if ref.startswith('BASELINE:') else
|
||||||
'docs/DESIGN_DECISIONS.md' if ref == 'D-034' else
|
'docs/DESIGN_DECISIONS.md' if ref == 'D-034' else
|
||||||
@@ -983,14 +955,13 @@ def verify_shift_completion(base):
|
|||||||
"""C's first 18:00 transaction, never the paid-midnight 1442 sale."""
|
"""C's first 18:00 transaction, never the paid-midnight 1442 sale."""
|
||||||
for row in load(safe(base, 'SOURCE_MANIFEST.json'))['files']:
|
for row in load(safe(base, 'SOURCE_MANIFEST.json'))['files']:
|
||||||
native_file(base, row['copy'], row)
|
native_file(base, row['copy'], row)
|
||||||
require(native_applicability(base) == TESTED_PRODUCT, 'shift tested revision')
|
tested = native_applicability(base)
|
||||||
pids = native_ownership(base)
|
pids = native_ownership(base)
|
||||||
shift_pids = [pids['actual-native/' + phase] for phase in NATIVE_RUNS['actual-native']]
|
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')
|
require(len(shift_pids) == len(set(shift_pids)) == 3, 'shift ended PID identity')
|
||||||
inputs = load(safe(base, 'actual-native/runner-input.json'))
|
inputs = load(safe(base, 'actual-native/runner-input.json'))
|
||||||
expected = product_manifest(tree_entries(TESTED_PRODUCT))
|
expected = selected_manifest(tree_entries(tested), require_checker=False)
|
||||||
require(len(inputs['source_before']) == 1338 and
|
require({p: {'bytes': v['bytes'], 'sha256': v['sha256']} for p, v in inputs['source_before'].items()}
|
||||||
{p: {'bytes': v['bytes'], 'sha256': v['sha256']} for p, v in inputs['source_before'].items()}
|
|
||||||
== expected, 'shift complete native source')
|
== expected, 'shift complete native source')
|
||||||
prefix = 'actual-native/order-evidence/'
|
prefix = 'actual-native/order-evidence/'
|
||||||
observations = load(safe(base, prefix + 'observations.json'))
|
observations = load(safe(base, prefix + 'observations.json'))
|
||||||
|
|||||||
Reference in New Issue
Block a user