Merge commit 'bf559632ddd938085702529d9dd6b7c878f4ebc7' into HEAD

This commit is contained in:
Agent Control Runner
2026-10-14 00:26:35 +09:00
19 changed files with 2220 additions and 0 deletions
@@ -3668,6 +3668,17 @@
"text": "\tprint(\"TOMARI_FLOOR_TROUBLE checks=%d failures=%d\" % [checks,failures])"
}
]
},
{
"test": "tests/s1/test_p08_combined_migration.gd",
"template": "P08 combined migration: <checks> checks, <failures> failures",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "9284a8cfb478b4c8d69f6d8166eec6c41107e3902029289b3c0e9ba48c370855",
"authority": {
"path": "docs/spec/acceptance/P08-02.json",
"scope": "new standalone mixed suite; native execution pending"
}
}
],
"unknown_roster_suite_policy": "refuse, explicitly review its source/schema before accepting",
@@ -0,0 +1,44 @@
# P08-02 retained implementation condition matrix
Status: submitted for Root verification; original P08-02 acceptance remains pending.
Frozen spec: `docs/spec/acceptance/P08-02.json`, stripped UTF-8 SHA-256
`19f02bb7912a4d7354e565186f02366fc1d4dd698468d26142e8204fd14ebfb0`.
The raw file has a trailing newline. The six rows are facets of one existing unit, not six units.
All rows use `tests/fixtures/p08-02/mixed_world.gd` through `writer.gd` and
`reader.gd`, and the standalone `tests/s1/test_p08_combined_migration.gd`.
Driver phases are `off-positive`, `off-refusal`, `on-positive`, `on-refusal`,
each with `-writer` then `-reader`; import/parse precede them.
| Required condition | Retained fixture/test coverage | Driver phase | Checker rule (`tools/check_p08_migration_evidence.py`) | Negative mutation (`tools/test_p08_migration_evidence.py`) | Pending evidence |
|---|---|---|---|---|---|
| mixed_construction | `setup`: paid zero-progress old-size premium job, progressing premium job, completed dorm in the same save; `run`: full progress/payment/reservation/completion fields | All four pairs; positive applies batch, refusal continues old shape | `semantics` checks starting/progressing paid jobs, completed dorm and diagnostic budget; `case_gate` permits only explicit typed geometry deltas and requires four-cell positive jobs | `missing_start_stage`, `resource_delta_mismatch`, `partial_batch`; unapproved typed changes are compared without dropping fields | Native runtime/save and distinct-PID continuation; normal OS flow; Root final verification pending |
| occupancy_change | `invariant`: restore validation of ownership/support; migrated occupied/reserved cells captured in whole snapshots | All four pairs | `semantics`: disjoint cells, exact construction/world ownership and operational facility cells; `GEOMETRY` finite allowlist | `orphan_occupancy` | Native added/released cells and support validation; OS model/formal records; Root review pending |
| actual_actor_positions | Mid-route walker, fractional credit, real staff/rescue/cargo and EV positions; no route changes approved | All four pairs, checkpoint and minutes 001–160 | `typed_differences` forbids actor/credit/route/money deltas; full typed and raw Variant writer/reader equality | `duplicate_actor`, `unequal_cross_pid` | Native actual positions/credit/routes and cross-PID equality; OS state captures; Root review pending |
| combined_rescue_logistics_ev | `setup`: actual in-flight rescue, purchased carried food with original requests, four EV boarded plus one waiting; `run`: patient treated, original cargo completed, each EV arrival once | All four pairs and uncapped events | `semantics`: IDs, endpoints, reservations and EV actors; `case_gate`: final patient health, original cargo completion and exactly one arrival per original EV request | `lost_patient`, `lost_cargo`, `lost_ev` | Native coherent same-save mixed state and continuation; OS save/model attribution; Root review pending |
| no_overlap_orphan_loss | Whole typed snapshots/raw Variant files and uncapped events; runtime/cargo invariants | ON and OFF positive/refusal pairs | Ordered four-case roster, actual mode, distinct lifecycle PIDs, strict markers, all 162 labels compared, semantic ownership/reference checks | `duplicate_actor`, `orphan_occupancy`, `unequal_cross_pid`, `missing_on`, `missing_phase`, `duplicate_pid`, `wrong_source`, `stale_source` | Native ON/OFF and separate writer/reader PIDs; normal-menu OS proof; final regression and Root verification pending |
| unsolvable_preservation | Real pre-existing migration backup, late maintenance obstruction at dorm, independently migratable first job; refusal rollback and unchanged live/formal/backup | `off-refusal`, `on-refusal` writer/reader | Live equality; original equals refusal checkpoint; before/after member hash maps equal; raw four-member original/result/backup hashes bound | `partial_batch`, `overwritten_original`, `overwritten_backup` | Native late refusal and separate-PID original continuation; OS cancel/changed-source preservation; Root review pending |
The standalone suite executes both roles in one process and does not establish distinct-PID proof.
Only the Root collector launches separate phases through existing `execute_phase`/owned-outer
and fresh guarded profiles. Exactly one public suite marker exists:
`P08 combined migration: <checks> checks, <failures> failures`.
The driver privately owns the writer/reader marker templates; no second public entry is added.
Local Python tests are synthetic checker fixtures, including synthetic lifecycle/OS/regression
records; their success establishes checker reachability and rejection tests only.
Native Godot/OS execution, normal production menu preview/cancel/confirm/changed-source rejection,
final full regression, final submitted reviewer-packet measurement, applicable Windows coverage,
independent Opus review, integration/current verification and ledger closure remain Root conditions.
Controlled old-save setup must be labelled controlled, never natural production.
Checker integrity success cannot close the original unit. No production defect or product fix
was demonstrated by the authorized local checks; retained code and marker contract are reused.
Repair r04: seed 42588; existing definition-derived construction total gold 7110 /
materials 88, signing 150, food eight units 24. Initial gold 5000 / materials 50
and previous added resources zero leave a deficit of gold 2284 / materials 38.
The controlled fixture records and supplies only this derived deficit.
Historical full metadata is now referenced by
`implementation-historical-6c7c724.json`: both fixed Git versions were SHA-verified
before replacement. Root's verified gzip roundtrip SHA is provenance only;
no external archive is a checker/runtime dependency. Historical failure logs remain preserved.
@@ -0,0 +1,101 @@
{
"classification": "Root coordinator supplied repair input, not worker implementation or acceptance proof",
"measured_UIDs": {
"tests/fixtures/p08-02/mixed_world.gd.uid": {
"text": "uid://dg5n4yme6rk4p\n",
"raw_sha256": "d7549f933b74f5e807cd2d3b3adcdd083af4a3bd331614314ff7bfd7b0903f31"
},
"tests/fixtures/p08-02/reader.gd.uid": {
"text": "uid://741t47oxl3ct\n",
"raw_sha256": "3e68ce192d5770e3823df9699c5c99ebb618fe0a480b4d56913624941900b08a"
},
"tests/fixtures/p08-02/writer.gd.uid": {
"text": "uid://csw2850g6gjct\n",
"raw_sha256": "8f150654767de0c66329d7d9e84d306c4fa5a65c918e04fb520b626b39f68334"
}
},
"replacement_example": {
"classification": "Synthetic machine-readable complete index from retained Proof; diagnostic ONLY, never native/OS/regression acceptance evidence.",
"construction": "tools/test_p08_migration_evidence.py Proof creates all linked bytes and reachable whole-check positive. Embedded documents illustrate receipts/lifecycle/OS/regression/typed records. Digests belong to the disposable synthetic fixture, not delivered acceptance artifacts; reproduce with Proof in a worktree-local disposable directory.",
"complete_example_generator": {
"source": "tools/test_p08_migration_evidence.py",
"source_raw_sha256": "9924f4cb4f55b15caf9f9733d91f5095553abcf2861e4b335755531480b534a9",
"class": "Proof",
"constructor": "Proof(Path(fresh_temporary_directory))",
"project_root_binding": "module ROOT resolved from unchanged generator inside this exact candidate source tree",
"generated_full_index": "proof.index",
"generated_representative_documents": "{path: json.loads((proof.path / path).read_text()) for path in representative_artifact_document_paths}",
"native_or_os_runs": 0
},
"index_top_level_fields": [
"schema",
"commit",
"source_map",
"spec_sha256",
"marker_contract_sha256",
"inputs",
"cases",
"conditions",
"artifacts",
"acceptance",
"collection_error",
"phases",
"os_proof",
"regression"
],
"representative_artifact_document_paths": [
"runs/off-positive-writer/off-positive-writer-receipt.json",
"runs/off-positive-reader/off-positive-reader-receipt.json",
"runs/off-positive-writer/off-positive-writer/started.json",
"runs/off-positive-writer/off-positive-writer/ended.json",
"runs/off-positive-writer/off-positive-writer/outer-owned-finally.json",
"os.json",
"os/preview/input.json",
"regression.json",
"regression/input.json",
"regression/ended.json",
"pairs/off-positive/identity.json",
"pairs/off-positive/writer-process.json",
"pairs/off-positive/before-members.json"
],
"fixture_config_inputs": {
"fixture_sources": {
"tests/s1/test_p08_combined_migration.gd": "9284a8cfb478b4c8d69f6d8166eec6c41107e3902029289b3c0e9ba48c370855",
"tests/s1/test_p08_combined_migration.gd.uid": "8c3a70d0ce619b8cb98dc003eb6c53a31f167a686179a3ffc105f7cd4d856da5",
"tests/fixtures/p08-02/README.md": "bc76975e49e7761c2a3540a1e907ab2215ec315653a1d87df6919d1cebd779e0",
"tests/fixtures/p08-02/mixed_world.gd": "889bc895888b8c6ad50659a3b23a3ee45e9edf8dde9168f5560792c292070d26",
"tests/fixtures/p08-02/reader.gd": "a760d0e45979d747dbd1f8710033bdce13287b00eb879d947d8378ff920ed1be",
"tests/fixtures/p08-02/writer.gd": "1a918b5509773b4b07a27d47ee44583b0eb5288138f7bf896088a7913773c260",
"tools/run_p08_mixed_migration.py": "7e86737e6354a4734726ba8d3171ad5f58d6c0380aba5a0fa3c57879d580e579",
"tools/check_p08_migration_evidence.py": "8d697c8e9a606bcff6a0a8c6ec55e0e9c434ca9682b7ce6915b5bcb1ea4ff3fd",
"tools/test_p08_migration_evidence.py": "9924f4cb4f55b15caf9f9733d91f5095553abcf2861e4b335755531480b534a9"
},
"native_runner_input_shape": {
"protocol": "p08-mixed-v1",
"commit": "<actual final commit>",
"selected_source_map": "<exact source map>",
"engine": "<actual executable>",
"engine_sha256": "<raw SHA>",
"owner_pid": "<actual collector PID>",
"default_player": "<protected profile record>",
"diagnostic_seed": 42588
},
"case_environment": {
"P08_PAIR_ROOT": "<absolute guarded pair output>",
"P08_OPERATIONS": "off|on",
"P08_CASE": "positive|refusal"
},
"timeouts": "unchanged: collection 900s, phase maximum 180s",
"formal_validation": "Root copies actual evidence into allocated build directory; --verify-only reads BUILD_OUTPUT_DIR/p08-evidence/index.json"
},
"exact_reconstruction_verification": {
"entire_index_equal": true,
"entire_representative_documents_equal": true,
"index_canonical_sha256": "456c67833dc6d6d905a1c0543f7a3e6b1ead715b8e88a5fe816dbcb77072efc0",
"representative_canonical_sha256": "5727797a0ec11363d1463406be4f1979e279a9c77fff02c284ff7fff60bc32e6",
"canonical_encoding": "json.dumps(value,sort_keys=True,ensure_ascii=False).encode()"
},
"purpose": "Lossless complete synthetic example regeneration from retained code, not a real native/OS acceptance index. Explicit index_schema above remains authoritative. Root proved equality of all original fields before this proposal. Full prior implementation preserved in commit6c7c7244 and byte-verified gzip evidence."
},
"instructions": "Read this compact input first. Do not cat the entire 1MB old example into model context. Parse implementation.json with stdlib, replace example field, keep all other fields/schema/source logic. Add exact supplied UIDs; update outputs; after source map changes recompute current synthetic example digests with unchanged Proof class. Historical exact old reconstruction remains tied to6c. This input is within allowed scope, not an external path."
}
@@ -0,0 +1,306 @@
{
"purpose": "Same retained candidate; diagnose checker against real native outputs. Original native bytes and candidate preserved; not game acceptance.",
"actual_candidate": "592809bfdaf6a1bbc5ec9cbaeff71a7bb072add9",
"all8_native_phases_pass": true,
"defects": [
"actual Vector3i constructor scalar format rejected by decoder",
"logistics lazy destination inventory treated as orphan although canonical live facility exists",
"RESERVED queued request has no assigned carrier by domain contract",
"support revision is global world revision epoch, not independent +1 counter; actual changed142→150 alongside world144→150 after occupancy rewrites"
],
"actual_readonly_diagnostics": {
"ACTUAL_NATIVE_CHECKER.json": {
"candidate": "592809bfdaf6a1bbc5ec9cbaeff71a7bb072add9",
"elapsed_seconds": 16.212463750038296,
"actual_readonly_checker_deficits": [
"OS proof: unsafe artifact path",
"case off-positive: invalid literal for int() with base 10: 'Vector3i(0'",
"case off-refusal: invalid literal for int() with base 10: 'Vector3i(0'",
"case on-positive: invalid literal for int() with base 10: 'Vector3i(6'",
"case on-refusal: invalid literal for int() with base 10: 'Vector3i(-12'",
"final regression: unsafe artifact path"
],
"full_game_acceptance": false,
"original_unit_completed": false,
"index": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-02-native-mixed-r05/index.json"
},
"VECTOR_DECODER_READONLY_DIAGNOSTIC.json": {
"candidate": "592809bfdaf6a1bbc5ec9cbaeff71a7bb072add9",
"scope": "Root readonly decoder prototype diagnostic; no candidate code or actual evidence altered; no acceptance",
"observations": [
{
"case": "off-positive",
"jobs": [
{
"id": "construction_00000015",
"state": "BUILDING",
"progress": 1266
},
{
"id": "construction_00000016",
"state": "PLANNED",
"progress": 0
}
],
"starting_job": "construction_00000016"
},
{
"case": "off-refusal",
"jobs": [
{
"id": "construction_00000015",
"state": "BUILDING",
"progress": 1266
},
{
"id": "construction_00000016",
"state": "PLANNED",
"progress": 0
}
],
"starting_job": "construction_00000016"
},
{
"case": "on-positive",
"jobs": [
{
"id": "construction_00000015",
"state": "BUILDING",
"progress": 1266
},
{
"id": "construction_00000016",
"state": "PLANNED",
"progress": 0
}
],
"starting_job": "construction_00000016"
},
{
"case": "on-refusal",
"jobs": [
{
"id": "construction_00000015",
"state": "BUILDING",
"progress": 1266
},
{
"id": "construction_00000016",
"state": "PLANNED",
"progress": 0
}
],
"starting_job": "construction_00000016"
}
],
"remaining_deficits": [
"OS proof: unsafe artifact path",
"case off-positive: orphan cargo endpoint",
"case off-refusal: orphan cargo endpoint",
"case on-positive: orphan cargo endpoint",
"case on-refusal: orphan cargo endpoint",
"final regression: unsafe artifact path"
],
"elapsed_seconds": 16.21374141704291
},
"CARGO_ENDPOINT_READONLY_DIAGNOSTIC.json": [
{
"first_label": "original",
"original_requests": [
"supply.logistics_request.000000000001",
"supply.logistics_request.000000000002"
],
"active_inventory_ids": [
"cargo:staff_gina",
"facility.inventory:facility_00000005"
],
"requests": [
{
"request_id": "supply.logistics_request.000000000001",
"source_inventory_id": "facility.inventory:facility_00000005",
"destination_inventory_id": "facility.inventory:facility_00000006",
"item_requirements": {
"ingredient/raw_food": 4
},
"priority": 50,
"created_at": 728,
"deadline": -1,
"total_weight": 4,
"reserved_stack_ids": [
"stack_00000001"
],
"reservation_ids": [
"reservation_00000001"
],
"assigned_carrier_id": "staff_gina",
"state": "DELIVERING",
"retry_count": 0,
"state_reason": "",
"state_changed_at": 735
},
{
"request_id": "supply.logistics_request.000000000002",
"source_inventory_id": "facility.inventory:facility_00000005",
"destination_inventory_id": "facility.inventory:facility_00000006",
"item_requirements": {
"ingredient/raw_food": 4
},
"priority": 50,
"created_at": 729,
"deadline": -1,
"total_weight": 4,
"reserved_stack_ids": [
"stack_00000001"
],
"reservation_ids": [
"reservation_00000002"
],
"assigned_carrier_id": "",
"state": "RESERVED",
"retry_count": 0,
"state_reason": "NO_AVAILABLE_PORTER_OR_ROUTE",
"state_changed_at": 729
}
]
}
],
"CARGO_RULE_READONLY_DIAGNOSTIC.json": {
"candidate": "592809bfdaf6a1bbc5ec9cbaeff71a7bb072add9",
"scope": "Root readonly prototype only. Candidate/checker/evidence files unchanged, no formal acceptance.",
"basis": "Authoritative SupplyLogisticsBridge.validate_crosslinks lines508-554 resolves facility inventory endpoints by facility ownership and allows unassigned RESERVED request with valid reservation; destination inventory materializes upon delivery.",
"remaining_deficits": [
"OS proof: unsafe artifact path",
"final regression: unsafe artifact path",
"unapproved typed migration delta off-positive/systems/runtime/world/revisions/support",
"unapproved typed migration delta on-positive/systems/runtime/world/revisions/support"
],
"elapsed_seconds": 78.40071395831183
},
"ACTUAL_WORLD_REVISION_DELTAS.json": [
{
"case": "off-positive",
"original_world_revisions": {
"world": 144,
"occupancy": 144,
"walkability": 99,
"excavation": 0,
"support": 142
},
"checkpoint_world_revisions": {
"world": 150,
"occupancy": 150,
"walkability": 99,
"excavation": 0,
"support": 150
}
},
{
"case": "on-positive",
"original_world_revisions": {
"world": 144,
"occupancy": 144,
"walkability": 99,
"excavation": 0,
"support": 142
},
"checkpoint_world_revisions": {
"world": 150,
"occupancy": 150,
"walkability": 99,
"excavation": 0,
"support": 150
}
},
{
"case": "off-refusal",
"original_world_revisions": {
"world": 144,
"occupancy": 144,
"walkability": 99,
"excavation": 0,
"support": 142
},
"checkpoint_world_revisions": {
"world": 144,
"occupancy": 144,
"walkability": 99,
"excavation": 0,
"support": 142
}
},
{
"case": "on-refusal",
"original_world_revisions": {
"world": 144,
"occupancy": 144,
"walkability": 99,
"excavation": 0,
"support": 142
},
"checkpoint_world_revisions": {
"world": 144,
"occupancy": 144,
"walkability": 99,
"excavation": 0,
"support": 142
}
}
]
},
"source_basis": {
"scripts/supply/supply_logistics_bridge.gd:508": [
"static func validate_crosslinks(requests: Dictionary, staff: StaffService, inventory: InventoryService, facilities: FacilityService) -> bool:",
"\tvar carrier_owners: Dictionary = {}",
"\tvar active_task_ids: Dictionary = {}",
"\tfor id: StringName in _request_ids(requests):",
"\t\tvar request: LogisticsRequest = requests[id]",
"\t\tvar source := _facility_for_inventory(facilities, request.source_inventory_id)",
"\t\tvar destination := _facility_for_inventory(facilities, request.destination_inventory_id)",
"\t\tif not String(request.source_inventory_id).begins_with(\"facility.inventory:\") or not String(request.destination_inventory_id).begins_with(\"facility.inventory:\"):",
"\t\t\treturn false",
"\t\tif not request.is_terminal() and (source == null or destination == null):",
"\t\t\treturn false",
"\t\tvar task := _active_task(staff, id)",
"\t\tif request.state in [LogisticsRequest.State.RESERVED, LogisticsRequest.State.BLOCKED] or request.is_terminal():",
"\t\t\tif task != null:",
"\t\t\t\treturn false",
"\t\t\tif request.state == LogisticsRequest.State.RESERVED and not _reservation_quantities_valid(request, inventory, true):",
"\t\t\t\treturn false",
"\t\t\tcontinue",
"\t\tif request.state not in [LogisticsRequest.State.ASSIGNED, LogisticsRequest.State.PICKING_UP, LogisticsRequest.State.DELIVERING]:",
"\t\t\treturn false",
"\t\tvar worker := staff.get_staff(request.assigned_carrier_id)",
"\t\tif worker == null or worker.role_id != &\"porter\" or carrier_owners.has(worker.staff_id) \\",
"\t\t\tor task == null or task.assigned_staff_id != worker.staff_id or worker.current_task_id != task.task_id \\"
],
"scripts/world/world_service.gd:652": [
"func _mark_dirty(",
"\tcells: Array,",
"\toccupancy_changed: bool,",
"\twalkability_changed: bool,",
"\texcavation_changed: bool,",
"\tsupport_changed: bool",
") -> void:",
"\trevision += 1",
"\tif occupancy_changed:",
"\t\toccupancy_revision = revision",
"\tif walkability_changed:",
"\t\twalkability_revision = revision",
"\tif excavation_changed:",
"\t\texcavation_revision = revision",
"\tif support_changed:",
"\t\tsupport_revision = revision",
"\tfor cell: Variant in cells:",
"\t\tif cell is Vector3i and is_in_bounds(cell):",
"\t\t\t_dirty_cells[cell] = true"
]
},
"instructions": [
"Read only this compact file first; no broad history or full evidence dump.",
"Do not modify fixture/runtime/collector/native semantics already passed. Fix checker decoding/crosslink/counter checks, realistic targeted tests and metadata together. Original6conditions and30/88 unchanged.",
"Native bytes must stay immutable. Decide whether tested runtime inputs exactly match final after tooling-only changes; do not silently re-label old tested SHA. If final validator requires exact full source-map, execute final native once after all tooling fixes consolidated.",
"Freeze all source edits before running checker tests; prior README mutation during tests caused preventable stale proof retry.",
"Root external native collector should check first-writer actual scalar/crosslink semantics before running all other phases to avoid repeated whole collection.",
"Independent review and OS/final regression remain mandatory."
]
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,16 @@
{
"classification": "Historical full record preserved; compact provenance reference",
"original_raw_sha256": "ab1fcf46ef73f2157f16f69394b4039a562c031fae8d407adca013a452226e2f",
"original_raw_bytes": 1082602,
"git_reference": {
"commit": "6c7c724410c350afe3d49fa8ec52defe20e78041",
"path": "docs/plans/original-completion-2026-10-02/execution/p08-02/implementation.json"
},
"second_full_copy_git_reference": {
"commit": "e59206b9b2578ddb4a1ec023f836d413a7a8fbfb",
"path": "docs/plans/original-completion-2026-10-02/execution/p08-02/implementation-historical-6c7c724.json"
},
"root_lossless_archive": "artifacts/original-completion-2026-10-02/p08-02-preserved-r01/full-submitted-implementation.json.gz",
"raw_archive_roundtrip_verified": true,
"current_acceptance_claimed": false
}
@@ -0,0 +1,330 @@
{
"task_id": "P08-02",
"status": "submitted",
"acceptance": "pending",
"base_commit": "e196578c1a4ad2fdf84642565bd102e524be386f",
"spec_sha256_stripped_utf8": "19f02bb7912a4d7354e565186f02366fc1d4dd698468d26142e8204fd14ebfb0",
"spec_sha256_raw": "01b3600e8815b514ffd5c4d341d77a6a3e8341064796c1dae706062b746ba6aa",
"scope": "Metadata-only synchronization against Git 1545bd42; no code, fixture, runtime, marker or acceptance changes.",
"outputs": [
{
"path": "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json",
"sha256": "c4c6dbea08a92682c692a280dbc90702ccbe63702a4f2624519b18d42930e18f",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/s1/test_p08_combined_migration.gd",
"sha256": "9284a8cfb478b4c8d69f6d8166eec6c41107e3902029289b3c0e9ba48c370855",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/s1/test_p08_combined_migration.gd.uid",
"sha256": "8c3a70d0ce619b8cb98dc003eb6c53a31f167a686179a3ffc105f7cd4d856da5",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/fixtures/p08-02/README.md",
"sha256": "e88ca33fdb4e96602d1fb108d71a9c35b6fa054619ecf6f1396e9a6c5e0ebd98",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/fixtures/p08-02/mixed_world.gd",
"sha256": "a23f8a686be1d77e4874b9956eef89be4756f6e5eb01cc62454c3845acc62c25",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/fixtures/p08-02/reader.gd",
"sha256": "a760d0e45979d747dbd1f8710033bdce13287b00eb879d947d8378ff920ed1be",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/fixtures/p08-02/writer.gd",
"sha256": "1a918b5509773b4b07a27d47ee44583b0eb5288138f7bf896088a7913773c260",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tools/run_p08_mixed_migration.py",
"sha256": "7e86737e6354a4734726ba8d3171ad5f58d6c0380aba5a0fa3c57879d580e579",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tools/check_p08_migration_evidence.py",
"sha256": "928353233bf85436a5aaf8c4f77f3f82472d94b8ad2646cb1b030baf92b3b5dc",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tools/test_p08_migration_evidence.py",
"sha256": "fd9ef7ec63f53dfd5e04e261606c9303d01a2e6590e22a35fef2e35df1429280",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p08-02/CONDITION_MATRIX.md",
"sha256": "6673051df9ae10f2df9b1812828e71ad9f5f24c433572defeef4e0978962a4e8",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p08-02/implementation.json",
"sha256": "fee85e6f4bb2824fc64bdfa275302f503a3234d83ab6c473c5e3ae6fdf91a3a6",
"hash_scope": "canonical normalized self record: replace this sha256 with null, UTF-8 json.dumps(ensure_ascii=False,sort_keys=True,separators=(comma,colon)), no newline",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/fixtures/p08-02/mixed_world.gd.uid",
"sha256": "d7549f933b74f5e807cd2d3b3adcdd083af4a3bd331614314ff7bfd7b0903f31",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/fixtures/p08-02/reader.gd.uid",
"sha256": "3e68ce192d5770e3823df9699c5c99ebb618fe0a480b4d56913624941900b08a",
"hash_scope": "raw bytes",
"disposition": "r04 current source; retained paths and UID/marker entries"
},
{
"path": "tests/fixtures/p08-02/writer.gd.uid",
"sha256": "8f150654767de0c66329d7d9e84d306c4fa5a65c918e04fb520b626b39f68334",
"hash_scope": "raw bytes",
"disposition": "retained unchanged UID"
}
],
"self_hash_note": "A raw self-containing SHA cannot be embedded in itself. This explicit normalized hash covers implementation.json; Root must separately measure its raw SHA and the final full packet on actual submitted SHA. No final packet measurement claimed.",
"commands_actually_run": [
{
"command": "python3 -B AST parse of three P08 Python tools",
"exit_code": 0,
"result": "3 parses passed"
},
{
"command": "python3 -B tools/test_p08_migration_evidence.py (first run)",
"exit_code": 1,
"result": "2 tests; positive stale source map because worker changed README during test"
},
{
"command": "python3 -B tools/test_p08_migration_evidence.py (stable-source rerun)",
"exit_code": 0,
"result": "2 tests in 33.523s, OK; synthetic only",
"classification": "Historical worker run; superseded as current local-check metadata, preserved without relabeling."
},
{
"command": "python3 -B tools/test_p08_migration_evidence.py (Repair 7, final frozen sources)",
"exit_code": 0,
"result": "4 tests in 55.197s, OK; synthetic only"
}
],
"local_checks": {
"ast_parse": "passed, three Python sources",
"checker_tests": {
"command": "python3 -B tools/test_p08_migration_evidence.py",
"tests_run": 4,
"elapsed_seconds": 55.197,
"result": "OK",
"exit_code": 0,
"scope": "Synthetic local checker tests only; source edits frozen before this single run. Not native, OS, full regression or acceptance evidence.",
"final_raw_sha256": {
"tools/test_p08_migration_evidence.py": "fd9ef7ec63f53dfd5e04e261606c9303d01a2e6590e22a35fef2e35df1429280",
"tools/check_p08_migration_evidence.py": "928353233bf85436a5aaf8c4f77f3f82472d94b8ad2646cb1b030baf92b3b5dc",
"docs/plans/original-completion-2026-10-02/execution/p08-02/ROOT_REPAIR_INPUT-r04.json": "23ef44a0775ca53f1f67d6d64fcc96cd33eae935478768e9ce9431796eaa12ef"
}
},
"native_or_full_regression_run": false,
"evidence_reuse_pending": "Reuse of earlier native 8, OS and final 174 regression evidence is pending Root confirmation of exact source_map, input, config and environment matches. If restored r04 is in the selected source map, Root must decide whether to re-collect. Independent review and integration remain pending; no unconfirmed evidence counts asserted."
},
"pending_root_conditions": [
"mixed_construction",
"occupancy_change",
"actual_actor_positions",
"combined_rescue_logistics_ev",
"no_overlap_orphan_loss",
"unsolvable_preservation",
"native_Godot_and_OS_execution",
"separate_PID_writer_reader",
"normal_menu_OS_proof",
"final_full_regression",
"final_submitted_packet_measurement",
"applicable_Windows_coverage",
"independent_Opus_review",
"main_integration_current_final_verification",
"ledger_reflection_and_original_unit_closure"
],
"product_fix_proposal": null,
"index_schema": {
"name": "p08-evidence-v1",
"location": "BUILD_OUTPUT_DIR/p08-evidence/index.json",
"authority": "tools/check_p08_migration_evidence.py check() and tools/run_p08_mixed_migration.py collect()",
"top_level": {
"schema": "literal p08-evidence-v1",
"commit": "40 lowercase hex actual submitted commit; collector checks HEAD",
"source_map": "exact runner.source_refs(root) path -> raw SHA-256 including fixture/suite/tool sources",
"inputs": "exact frozen docs/spec/inputs/p08-02 immediate file path -> raw SHA-256",
"spec_sha256": "stripped UTF-8 frozen spec SHA",
"marker_contract_sha256": "raw marker contract SHA",
"cases": "ordered off-positive, off-refusal, on-positive, on-refusal",
"phases": "collector import/parse and case receipt paths",
"conditions": "all six IDs -> all four cases, except unsolvable_preservation -> both refusal cases",
"artifacts": "relative path -> {bytes: integer, sha256: raw digest}; no absolute/traversal/symlink; index itself excluded",
"os_proof": "relative OS proof JSON path; initially null in collector",
"regression": "relative final regression proof JSON path; initially null in collector",
"acceptance": "literal pending, including after integrity verification",
"collection_error": "null for integrity gate"
},
"case": {
"id": "operations-kind",
"operations": "off|on",
"kind": "positive|refusal",
"directory": "relative pair directory",
"phases": "writer then reader receipt paths (two)",
"files": "collector inventory path -> bytes/sha256; checker artifacts is content authority"
},
"phase_receipt": "actual_pid unique positive integer; phase, command argv, test, source_sha256, log relative to receipt parent; exit_code=0, engine_ended=true; native_process exit_code/helper_exit_code=0,timed_out=false,lifecycle_error=null; actual_private_profile.report fresh_before_parent_initialize=true,profile_writes_before_guard=0,actual_user_data_dir=expected_user_data_dir",
"raw_native_lifecycle": "receipt parent/phase/{started.json,ended.json,outer-owned-finally.json}. Start/end actual_pid and command match receipt. Start live_identity_exact or tracked_child_ended_before_initial_probe. End exit_code=0,engine_ended=true. Outer actual_captured_pids=[actual_pid],all_captured_ended=true,no cleanup errors or foreign signals. Raw version/argv/lifecycle must be actual Root capture.",
"strict_logs": "receipt parent/log: native version banner and exact role completion template, current source_sha256; full regression checks existing strict contracts for every current roster suite",
"typed_state": "Every .var raw Variant has .json typed tree: Dictionary entries=[typed key,typed value], Array items plus element_type/element_class, scalar type and exact var_to_str text. Required identity,original,after-live,before-members,after-members,writer/reader-process,writer/reader-checkpoint,writer/reader-minute-001 through 160,writer/reader-events. Preserve all fields and uncapped events. Driver also retains first-candidate,preview,migration diagnostics.",
"formal_members": "original/result/backup formal/{world.bin,manifest.json,thumbnail.png,journal.log}; raw artifact hashes bound to before/after typed member maps. Refusal preserves full original and pre-existing backup.",
"normal_OS_proof": "commit and exact source_map; input_method=native_os,setup=controlled_old_save; ordered preview,cancel,confirm,changed_source_rejection. Each action links input_receipt (method=native_os,event_type mouse|keyboard,target_pid positive int,timestamp_ns positive),screen_before/after,model_before/after,formal_before/after. Non-confirm formal JSON maps equal. Root independently assesses actual OS input/screens/state; signal-emitted UI is handler evidence only.",
"final_regression": "commit,directory,input,ended artifact paths. Input selected_source_map exact and roster runner.roster(root). Ended error null,cleanup_errors/guard_errors empty,ordered phases full roster each strict raw log,exit_code=0,engine_ended=true.",
"limits": "This documents implemented gates, not an acceptance reducer. Import/parse and config/environment runner-input are retained and hashed by driver; checker explicitly gates case phases. Root independently checks native version/config/environment, normal OS behavior and original conditions. Synthetic metadata cannot prove actual execution."
},
"example": {
"classification": "Synthetic machine-readable complete index from retained Proof; diagnostic ONLY, never native/OS/regression acceptance evidence.",
"construction": "tools/test_p08_migration_evidence.py Proof creates all linked bytes and reachable whole-check positive. Embedded documents illustrate receipts/lifecycle/OS/regression/typed records. Digests belong to the disposable synthetic fixture, not delivered acceptance artifacts; reproduce with Proof in a worktree-local disposable directory.",
"complete_example_generator": {
"source": "tools/test_p08_migration_evidence.py",
"source_raw_sha256": "fd9ef7ec63f53dfd5e04e261606c9303d01a2e6590e22a35fef2e35df1429280",
"class": "Proof",
"constructor": "Proof(Path(fresh_temporary_directory))",
"project_root_binding": "module ROOT resolved from unchanged generator inside this exact candidate source tree",
"generated_full_index": "proof.index",
"generated_representative_documents": "{path: json.loads((proof.path / path).read_text()) for path in representative_artifact_document_paths}",
"native_or_os_runs": 0
},
"index_top_level_fields": [
"schema",
"commit",
"source_map",
"spec_sha256",
"marker_contract_sha256",
"inputs",
"cases",
"conditions",
"artifacts",
"acceptance",
"collection_error",
"phases",
"os_proof",
"regression"
],
"representative_artifact_document_paths": [
"runs/off-positive-writer/off-positive-writer-receipt.json",
"runs/off-positive-reader/off-positive-reader-receipt.json",
"runs/off-positive-writer/off-positive-writer/started.json",
"runs/off-positive-writer/off-positive-writer/ended.json",
"runs/off-positive-writer/off-positive-writer/outer-owned-finally.json",
"os.json",
"os/preview/input.json",
"regression.json",
"regression/input.json",
"regression/ended.json",
"pairs/off-positive/identity.json",
"pairs/off-positive/writer-process.json",
"pairs/off-positive/before-members.json"
],
"fixture_config_inputs": {
"fixture_sources": {
"tests/s1/test_p08_combined_migration.gd": "9284a8cfb478b4c8d69f6d8166eec6c41107e3902029289b3c0e9ba48c370855",
"tests/s1/test_p08_combined_migration.gd.uid": "8c3a70d0ce619b8cb98dc003eb6c53a31f167a686179a3ffc105f7cd4d856da5",
"tests/fixtures/p08-02/README.md": "e88ca33fdb4e96602d1fb108d71a9c35b6fa054619ecf6f1396e9a6c5e0ebd98",
"tests/fixtures/p08-02/mixed_world.gd": "a23f8a686be1d77e4874b9956eef89be4756f6e5eb01cc62454c3845acc62c25",
"tests/fixtures/p08-02/reader.gd": "a760d0e45979d747dbd1f8710033bdce13287b00eb879d947d8378ff920ed1be",
"tests/fixtures/p08-02/writer.gd": "1a918b5509773b4b07a27d47ee44583b0eb5288138f7bf896088a7913773c260",
"tools/run_p08_mixed_migration.py": "7e86737e6354a4734726ba8d3171ad5f58d6c0380aba5a0fa3c57879d580e579",
"tools/check_p08_migration_evidence.py": "928353233bf85436a5aaf8c4f77f3f82472d94b8ad2646cb1b030baf92b3b5dc",
"tools/test_p08_migration_evidence.py": "fd9ef7ec63f53dfd5e04e261606c9303d01a2e6590e22a35fef2e35df1429280"
},
"native_runner_input_shape": {
"protocol": "p08-mixed-v1",
"commit": "<actual final commit>",
"selected_source_map": "<exact source map>",
"engine": "<actual executable>",
"engine_sha256": "<raw SHA>",
"owner_pid": "<actual collector PID>",
"default_player": "<protected profile record>",
"diagnostic_seed": 42588
},
"case_environment": {
"P08_PAIR_ROOT": "<absolute guarded pair output>",
"P08_OPERATIONS": "off|on",
"P08_CASE": "positive|refusal"
},
"timeouts": "unchanged: collection 900s, phase maximum 180s",
"formal_validation": "Root copies actual evidence into allocated build directory; --verify-only reads BUILD_OUTPUT_DIR/p08-evidence/index.json"
},
"purpose": "Synthetic Proof generator documents current schema. Historical reconstruction measurements are preserved in Git, not asserted for changed fixture.",
"previous_full_inline_record": {
"commit": "1545bd42d689a9a6382e2b003ee0550fa197f6e4",
"path": "docs/plans/original-completion-2026-10-02/execution/p08-02/implementation.json",
"sha256": "ae4a9f11c4e10a2be31d8fc6429577ff5f14f6097fae4f2d5a6a321937fefdac",
"bytes": 16946,
"hash_scope": "Git raw bytes",
"preservation": "Full previous metadata/example remains byte-preserved in Git; historical links and SHA values unchanged."
}
},
"historical_record": {
"path": "docs/plans/original-completion-2026-10-02/execution/p08-02/implementation-historical-6c7c724.json",
"sha256": "94321c2e924ef509738c8c4302c9e68854b9ce305830352d2dbb51d43f9ff34c",
"original_full_raw_sha256": "ab1fcf46ef73f2157f16f69394b4039a562c031fae8d407adca013a452226e2f",
"classification": "Reference to byte-preserved original full historical record in fixed Git commits and Root archive; not current canonical evidence"
},
"repair_r04": {
"seed": 42588,
"construction_cost": {
"gold": 7110,
"materials": 88
},
"signing_gold": 150,
"food_quantity": 8,
"food_gold": 24,
"initial": {
"gold": 5000,
"materials": 50
},
"previous_change_resources": {},
"derived_delta": {
"gold": 2284,
"materials": 38
},
"mismatch": "Previous zero added resources insufficient; no acceptance narrowed.",
"git_history_verification": "Both fixed Git references raw SHA matched ab1fcf46ef73f2157f16f69394b4039a562c031fae8d407adca013a452226e2f, 1082602 bytes",
"archive_verification": "Reuse Root supplied roundtrip evidence; archive not opened or executed."
},
"landing_repair": {
"input": "ROOT_REPAIR_INPUT-r04.json",
"ground": "initialized world paths within rank 1 bounds",
"upper": "complete each stair pair before ordering next floor, using maximum registered build_minutes",
"nearby_preflight": "rank bounds, registered stair definitions and existing completed logistics endpoints checked locally",
"acceptance_sources": "all 18 retained; no omissions",
"packet_limit_bytes": null,
"packet_measurement": "Final actual submitted Runner packet measurement remains Root responsibility; obsolete byte cap removed; no source omission or compression.",
"collection_timeout_seconds": 900
},
"metadata_sync": {
"source_commit": "1545bd42d689a9a6382e2b003ee0550fa197f6e4",
"current_tool_raw_sha256": {
"tools/check_p08_migration_evidence.py": "928353233bf85436a5aaf8c4f77f3f82472d94b8ad2646cb1b030baf92b3b5dc",
"tools/test_p08_migration_evidence.py": "fd9ef7ec63f53dfd5e04e261606c9303d01a2e6590e22a35fef2e35df1429280"
},
"source_map": "run_all_tests.py source_refs enumerates autoload/scripts/scenes/data/tests/assets/tools plus project.godot/export_presets.cfg/Makefile/AGENTS.md, excluding docs. Only docs changed, so source refs unchanged.",
"worker_validation": "JSON parse, Git raw SHA equality, generator Proof reference existence; no checker/native/Godot/full regression execution.",
"review_material_context_gap": "No .review-material or explicit complete 18-source Runner packet manifest provided in this checkout. Exact packet bytes cannot be claimed without Runner operation (prohibited); Root must measure complete actual submitted packet. No required source was removed."
}
}
+23
View File
@@ -0,0 +1,23 @@
# P08-02 diagnostic fixture
Controlled fixture inputs are diagnostic, not production balance values.
Native collection and acceptance remain pending.
Seed: 42588. Registered construction costs for the 16 planned builds total
gold 7110 / materials 88; Gina signing costs 150 and eight raw food units cost
24. Initial resources are gold 5000 / materials 50. The previous fixture had
no change_resources delta (zero), short by gold 2284 / materials 38.
The fixture derives and records this deficit from the actual registry/catalogs
in identity.diagnostic_budget before using the existing change_resources command.
No price or production coefficient is changed.
Stair preparation proceeds from floor 1 through floor 3. Each pair finishes
using the maximum registered stair build_minutes before the next floor is
ordered. Ground landings use initialized world paths; upper landings are
created by completed stairs through build_facility, with a local path check
before each pair. Failed commands include kind, payload and result details.
The first legacy premium job progresses while the six actor/transport facets
are prepared. The second is paid and reserved immediately before saving, with
zero progress; the dormitory is already complete. All three stages share the
same migration batch and whole-state writer/reader comparisons.
+241
View File
@@ -0,0 +1,241 @@
extends RefCounted
## All seeds, actor IDs, positions, food quantities and schedules are diagnostic inputs.
var checks := 0
var failures := 0
var runtime: Variant
var clock: Variant
var state: Variant
var directory: String
var mode: String
var slot: String
var serial := 0
var events: Array = []
var identity: Dictionary = {}
const MEMBERS := [SaveService.WORLD_FILE, SaveService.MANIFEST_FILE, SaveService.THUMBNAIL_FILE, SaveService.JOURNAL_FILE]
func expect(ok: bool, label: String) -> bool:
checks += 1
if not ok:
failures += 1
push_error("P08 mixed: " + label)
return ok
func command(kind: StringName, payload: Dictionary) -> bool:
serial += 1
var result: CommandResult = runtime.submit_command(kind, payload, &"player", &"", 0, -1, StringName("p08.%d" % serial))
var label := String(kind) + ": " + result.message
if not result.is_success(): label += " payload=" + var_to_str(payload) + " details=" + var_to_str(result.details)
return expect(result.is_success(), label)
func registry(old: bool) -> void:
var paths: Array[String] = FacilityCatalog.FACILITY_PATHS + FacilityCatalog.INFRASTRUCTURE_FACILITY_PATHS + FacilityCatalog.RESCUE_FACILITY_PATHS
paths.append_array(["res://tests/fixtures/legacy_premium_room.tres", "res://tests/fixtures/legacy_staff_dormitory.tres"] if old else ["res://data/facilities/expansion/premium_room.tres", "res://data/facilities/expansion/staff_dormitory.tres"])
expect(runtime.definition_registry.rebuild_from_paths(paths)[&"valid"], "definition registry")
func build(id: StringName, cell: Vector3i, complete := true) -> bool:
if not command(&"build_facility", {&"definition_id":id, &"origin":cell}): return false
if complete: clock.advance_minutes(runtime.definition_registry.get_facility(id).build_minutes)
return true
func instance(id: StringName) -> FacilityInstance:
for room: FacilityInstance in runtime.facility_service.get_instances():
if room.definition_id == id: return room
return null
## Scalar text avoids loss of integer precision; raw Variant bytes accompany JSON.
func typed(value: Variant) -> Dictionary:
var result := {"type":type_string(typeof(value))}
if value is Dictionary:
result["entries"] = []
for key: Variant in value: result["entries"].append([typed(key),typed(value[key])])
elif value is Array:
result["element_type"] = value.get_typed_builtin()
result["element_class"] = String(value.get_typed_class_name())
result["items"] = []
for item: Variant in value: result["items"].append(typed(item))
else: result["text"] = var_to_str(value)
return result
func put(name: String, value: Variant) -> void:
var path := directory.path_join(name)
if not expect(not FileAccess.file_exists(path+".var") and not FileAccess.file_exists(path+".json"), "fresh proof "+name): return
var file := FileAccess.open(path+".var",FileAccess.WRITE)
if not expect(file != null,"Variant output"): return
file.store_buffer(var_to_bytes(value)); file.close()
file = FileAccess.open(path+".json",FileAccess.WRITE)
if not expect(file != null,"typed output"): return
file.store_string(JSON.stringify(typed(value))); file.close()
func get_proof(name: String) -> Variant:
return bytes_to_var(FileAccess.get_file_as_bytes(directory.path_join(name+".var")))
func capture(name: String, value: Variant) -> void:
put(mode+"-"+name,value)
if mode == "reader": expect(var_to_bytes(value) == var_to_bytes(get_proof("writer-"+name)),"whole cross-PID "+name)
func copy_package(source: String, destination: String) -> void:
expect(DirAccess.make_dir_recursive_absolute(destination) == OK,"package directory")
for member: String in MEMBERS:
var data := FileAccess.get_file_as_bytes(source.path_join(member))
if not expect(not data.is_empty() and not FileAccess.file_exists(destination.path_join(member)),"fresh complete member "+member): continue
var file := FileAccess.open(destination.path_join(member),FileAccess.WRITE)
if not expect(file != null,"member writable"): continue
file.store_buffer(data); file.close()
expect(data == FileAccess.get_file_as_bytes(destination.path_join(member)),"whole member copy verified")
func packages() -> Dictionary:
var hashes := {}
for suffix: String in ["",SaveService.MIGRATION_BACKUP_SUFFIX]:
for member: String in MEMBERS: hashes[suffix+"/"+member] = FileAccess.get_sha256(ProjectSettings.globalize_path(slot+suffix).path_join(member))
return hashes
func observe(event: SimulationDomainEvent) -> void: events.append(event.to_dictionary())
## Controlled diagnostic input; costs come only from registered domain definitions.
func prepare_diagnostic_budget() -> bool:
var planned: Array[StringName] = [&"warehouse",&"kitchen",&"infirmary",&"staff_door",&"reception",&"reception",&"guest_elevator",&"staff_dormitory",&"premium_room",&"premium_room",&"service_stairs",&"service_stairs",&"service_stairs",&"guest_stairs",&"guest_stairs",&"guest_stairs"]
var needed := {&"gold":0,&"materials":0}
var costs: Array = []
for id: StringName in planned:
var definition: FacilityDefinition = runtime.definition_registry.get_facility(id)
if not expect(definition != null,"budget definition "+String(id)): return false
costs.append({&"definition_id":id,&"cost":definition.construction_cost.duplicate(true)})
for resource: StringName in needed: needed[resource] += int(definition.construction_cost.get(resource,0))
var signing := int(runtime.mvp_content_catalog.staff_hire_payload(&"staff_gina").get(&"signing_cost",0))
var food := 8 * int(SupplyCatalog.get_item(SupplyCatalog.RAW_FOOD)[&"unit_price"])
needed[&"gold"] += signing + food
var deltas := {}
for resource: StringName in needed:
var deficit: int = maxi(0,int(needed[resource])-state.get_resource(resource))
if deficit > 0: deltas[resource] = deficit
identity[&"diagnostic_budget"] = {&"seed":42588,&"costs":costs,&"signing":signing,&"food_quantity":8,&"food_cost":food,&"needed":needed,&"initial":state.resources.duplicate(true),&"previous_change_resources":{},&"deltas":deltas}
return deltas.is_empty() or command(&"change_resources",{&"deltas":deltas})
func setup(operations: bool) -> bool:
registry(true)
if not prepare_diagnostic_budget(): return false
if operations and not expect(runtime.enable_production_operations().get(&"ok",false),"Operations enabled at Day 1 06:00"): return false
for row: Array in [[&"warehouse",Vector3i(-8,0,1)],[&"kitchen",Vector3i(2,0,1)],[&"infirmary",Vector3i(6,0,1)],[&"staff_door",Vector3i(0,0,1)],[&"reception",Vector3i(-6,0,0)],[&"reception",Vector3i(5,0,0)],[&"guest_elevator",Vector3i.ZERO]]:
if not build(row[0],row[1],false): return false
clock.advance_minutes(180)
# Completed stairs supply the next floor's landing through the domain projector.
# Ground-floor landings come from the initialized world; never inject path cells.
var stair_minutes: int = maxi(runtime.definition_registry.get_facility(&"service_stairs").build_minutes,runtime.definition_registry.get_facility(&"guest_stairs").build_minutes)
for y: int in [1,2,3]:
if not expect(runtime.path_service.has_cell(Vector3i(-9,y-1,1)) and runtime.path_service.has_cell(Vector3i(4,y-1,0)),"completed lower stair landings for floor %d" % y): return false
if not build(&"service_stairs",Vector3i(-9,y,1),false) or not build(&"guest_stairs",Vector3i(4,y,0),false): return false
clock.advance_minutes(stair_minutes)
if not build(&"staff_dormitory",Vector3i(-8,2,1)): return false
identity[&"dorm"] = instance(&"staff_dormitory").instance_id
if not build(&"premium_room",Vector3i(-6,2,0),false): return false
clock.advance_minutes(7)
identity[&"jobs"] = []
for job: ConstructionJob in runtime.construction_service.get_jobs():
if not job.is_terminal(): identity[&"jobs"].append(job.job_id)
if not expect(identity[&"jobs"].size() == 1,"one paid progressing job"): return false
var warehouse := instance(&"warehouse")
var kitchen := instance(&"kitchen")
if not expect(warehouse != null and kitchen != null,"completed logistics endpoints"): return false
if not command(&"hire_staff_candidate",{&"candidate_id":&"staff_gina"}): return false
if not command(&"set_staff_work_assignment",{&"staff_id":&"staff_gina",&"facility_id":warehouse.instance_id,&"template_id":&"DAY"}): return false
if not command(&"purchase_supplies",{&"warehouse_id":warehouse.instance_id,&"item_id":SupplyCatalog.RAW_FOOD,&"quantity":8}): return false
if not command(&"set_kitchen_production",{&"facility_id":kitchen.instance_id,&"enabled":true,&"target_stock":4}): return false
var cargo_ready := false
for minute: int in range(60):
clock.advance_minutes(1)
if not runtime.staff_service.get_staff(&"staff_gina").carried_inventory_id.is_empty(): cargo_ready = true; break
if not expect(cargo_ready,"real purchased cargo picked up"): return false
for id: StringName in [&"patient",&"carrier"]:
if not command(&"register_staff",{&"staff_id":id,&"role_id":&"porter",&"options":{&"current_cell":Vector3i(-3,0,1) if id == &"patient" else Vector3i(-1,0,1),&"health":0 if id == &"patient" else 100,&"state":StaffRuntime.State.AVAILABLE,&"role_tags":[&"medic"],&"permitted_task_tags":[&"rescue"]}}): return false
var carrying := false
for minute: int in range(6):
clock.advance_minutes(1)
for task: StaffTask in runtime.staff_service.get_tasks():
if task.task_type == &"rescue_transport" and task.state == StaffTask.State.MOVING:
carrying = true; identity[&"rescue_task"] = task.task_id
if carrying: break
if not expect(carrying,"actual rescue transport"): return false
for index: int in range(5):
if not command(&"spawn_guest",{&"guest_id":StringName("p08.passenger.%d" % index),&"guest_type_id":&"traveler",&"gold":100,&"options":{&"current_cell":Vector3i.ZERO,&"state":GuestRuntime.State.MOVING,&"state_entered_at":clock.absolute_minute-1,&"planned_exit_at":clock.absolute_minute+2000,&"path_handle":{&"target_cell":Vector3i(0,1,0)}}}): return false
clock.advance_minutes(1)
if not command(&"spawn_guest",{&"guest_id":&"p08.walker",&"guest_type_id":&"traveler",&"gold":100,&"options":{&"current_cell":Vector3i(4,0,0),&"state":GuestRuntime.State.MOVING,&"state_entered_at":clock.absolute_minute-1,&"planned_exit_at":clock.absolute_minute+2000,&"path_handle":{&"target_cell":Vector3i(4,3,0)}}}): return false
clock.advance_minutes(1)
identity[&"ev_requests"] = []
for trip: Dictionary in runtime.elevators.get_report()[&"trips"]: identity[&"ev_requests"].append(trip[&"request_id"])
identity[&"logistics_requests"] = []
for request: LogisticsRequest in runtime.logistics_requests.values():
if not request.is_terminal(): identity[&"logistics_requests"].append(request.request_id)
expect(not runtime.staff_service.get_staff(&"staff_gina").carried_inventory_id.is_empty(),"cargo in SAME save as patient and EV")
expect(runtime.staff_service.get_staff(&"patient").health == 0,"patient remains untreated")
var car: Dictionary = runtime.elevators.get_report()[&"shafts"][0]
expect(car[&"passenger_count"] == 4 and car[&"waiting_count"] == 1,"passengers and queue coexist")
expect(runtime.create_snapshot()[&"systems"][&"runtime"][&"movement_credits"].size() > 0,"fractional movement credit")
if not build(&"premium_room",Vector3i(5,2,0),false): return false
for candidate: ConstructionJob in runtime.construction_service.get_jobs():
if not candidate.is_terminal() and not identity[&"jobs"].has(candidate.job_id): identity[&"jobs"].append(candidate.job_id)
if not expect(identity[&"jobs"].size() == 2,"two paid active jobs"): return false
identity[&"starting_job"] = identity[&"jobs"][1]
for id: StringName in identity[&"jobs"]:
var job: ConstructionJob = runtime.construction_service.get_job(id)
expect(not job.is_terminal() and (job.progress == 0 if id == identity[&"starting_job"] else job.progress > 0) and not job.construction_cost.is_empty() and job.reserved_cells.size() == 6,"old-size paid starting/progressing jobs remain active")
return failures == 0
func invariant() -> void:
expect(runtime.staff_service.validate_invariants()[&"ok"],"staff ownership")
expect(SupplyLogisticsBridge.validate_crosslinks(runtime.logistics_requests,runtime.staff_service,runtime.inventory_service,runtime.facility_service),"cargo crosslinks")
var snap: Dictionary = runtime.create_snapshot()
expect(runtime.restore_snapshot(snap),"whole Runtime ownership/support/transport validation")
expect(var_to_bytes(snap) == var_to_bytes(runtime.create_snapshot()),"whole canonical typed state")
func run(tree: SceneTree, output: String, role: String, operations: bool, refusal: bool) -> Dictionary:
directory = output; mode = role
slot = "user://p08-%d/formal" % Time.get_ticks_usec()
tree.root.get_node("GameClock").set_paused(true); tree.root.get_node("GameClock").set_process(false)
tree.root.get_node("SimulationRuntime").configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false})
runtime = load("res://autoload/simulation_runtime.gd").new()
clock = load("res://autoload/game_clock.gd").new(); state = load("res://autoload/game_state.gd").new()
clock.reset(1,6,0); state.reset(); expect(runtime.initialize(clock,state,42588)[&"valid"],"current initialization")
clock.set_paused(true); runtime.configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false,&"auto_migrate":false})
if mode == "writer":
expect(DirAccess.make_dir_recursive_absolute(directory) == OK,"proof directory")
if not setup(operations): return finish()
registry(false)
var baseline: Dictionary = runtime.create_snapshot()
expect(SaveService.save_snapshot(slot,baseline)[&"ok"],"formal original saved")
if refusal:
var initial: Dictionary = runtime.migrate_facility_dimensions_at_path(slot)
expect(initial.get(&"ok",false) and initial.get(&"backup_created",false),"real prior migration backup")
expect(runtime.staff_service.create_task(&"maintenance",10,clock.absolute_minute,{&"target_entity_id":identity[&"dorm"],&"target_cell":Vector3i(-9,3,1),&"estimated_minutes":30},&"p08.late").is_success(),"later old entrance task")
if not command(&"register_staff",{&"staff_id":&"maintainer",&"role_id":&"porter",&"options":{&"current_cell":Vector3i(-9,1,1),&"state":StaffRuntime.State.AVAILABLE}}): return finish()
expect(runtime.staff_service.assign_task_to_staff(&"p08.late",&"maintainer",clock.absolute_minute).is_success(),"real task ownership")
expect(SaveService.save_snapshot(slot,runtime.create_snapshot())[&"ok"],"obstructed source saved")
put("identity",identity); put("original",runtime.create_snapshot())
copy_package(ProjectSettings.globalize_path(slot),directory.path_join("original/formal"))
var live: Dictionary = runtime.create_snapshot()
var before := packages(); put("before-members",before)
var first: Dictionary = runtime.prepare_facility_dimension_snapshot(identity[&"jobs"][0])
expect(first.get(&"ok",false),"earlier candidate independently migratable")
put("first-candidate",first)
var preview: Dictionary = runtime.preview_facility_dimensions_at_path(slot); put("preview",preview)
var result: Dictionary = runtime.migrate_facility_dimensions_at_path(slot,&"",String(preview.get(&"source_digest",""))); put("migration",result)
expect(var_to_bytes(live) == var_to_bytes(runtime.create_snapshot()),"live unchanged")
put("after-live",runtime.create_snapshot())
if refusal:
expect(not result.get(&"ok",true) and result.get(&"details",{}).get(&"rolled_back",false) and result.get(&"details",{}).get(&"facility_id",&"") == identity[&"dorm"],"later refusal rolls back earlier candidates")
expect(before == packages(),"original and existing backup unchanged")
else: expect(preview.get(&"ok",false) and result.get(&"ok",false) and result.get(&"backup_created",false),"positive whole batch")
put("after-members",packages())
copy_package(ProjectSettings.globalize_path(slot),directory.path_join("result/formal"))
copy_package(ProjectSettings.globalize_path(slot+SaveService.MIGRATION_BACKUP_SUFFIX),directory.path_join("backup/formal"))
else:
registry(false); identity = get_proof("identity")
copy_package(directory.path_join("result/formal"),ProjectSettings.globalize_path(slot))
copy_package(directory.path_join("backup/formal"),ProjectSettings.globalize_path(slot+SaveService.MIGRATION_BACKUP_SUFFIX))
var loaded := SaveService.load_snapshot(slot)
expect(loaded.get(&"ok",false) and runtime.restore_snapshot(loaded.get(&"snapshot",{})),"formal continuation restore")
expect(runtime.get_operations_report().get(&"enabled",false) == operations,"actual Operations mode")
invariant(); capture("checkpoint",runtime.create_snapshot())
expect(runtime.domain_events.subscribe(&"*",&"p08.uncapped",Callable(self,"observe")),"uncapped events")
for minute: int in range(160):
clock.advance_minutes(1); capture("minute-%03d" % (minute+1),runtime.create_snapshot())
capture("events",events)
for id: StringName in identity[&"jobs"]:
var job: ConstructionJob = runtime.construction_service.get_job(id)
expect(job.state == ConstructionJob.State.COMPLETED and runtime.facility_service.get_instance(job.facility_instance_id).occupied_cells.size() == (6 if refusal else 4),"paid job completes once with expected shape")
expect(runtime.staff_service.get_staff(&"patient").health == 100,"patient treated")
for id: StringName in identity[&"logistics_requests"]: expect(runtime.logistics_requests[id].state == LogisticsRequest.State.COMPLETED,"original cargo delivered")
for id: StringName in identity[&"ev_requests"]:
var count := 0
for event: Dictionary in events:
if event["event_type"] == "ELEVATOR_ARRIVED" and event["payload"].get(&"request_id",&"") == id: count += 1
expect(count == 1,"original EV request completes exactly once")
invariant()
put(mode+"-process",{&"pid":OS.get_process_id(),&"operations":operations,&"refusal":refusal,&"checks":checks,&"failures":failures})
return finish()
func finish() -> Dictionary:
runtime.free(); clock.free(); state.free()
return {"checks":checks,"failures":failures}
+1
View File
@@ -0,0 +1 @@
uid://dg5n4yme6rk4p
+7
View File
@@ -0,0 +1,7 @@
extends SceneTree
func _initialize() -> void: call_deferred("run")
func run() -> void:
var fixture := preload("res://tests/fixtures/p08-02/mixed_world.gd").new()
var result: Dictionary = fixture.run(self,OS.get_environment("P08_PAIR_ROOT"),"reader",OS.get_environment("P08_OPERATIONS") == "on",OS.get_environment("P08_CASE") == "refusal")
print("P08 mixed reader: %d checks, %d failures" % [result.checks,result.failures])
quit(0 if result.failures == 0 else 1)
+1
View File
@@ -0,0 +1 @@
uid://741t47oxl3ct
+7
View File
@@ -0,0 +1,7 @@
extends SceneTree
func _initialize() -> void: call_deferred("run")
func run() -> void:
var fixture := preload("res://tests/fixtures/p08-02/mixed_world.gd").new()
var result: Dictionary = fixture.run(self,OS.get_environment("P08_PAIR_ROOT"),"writer",OS.get_environment("P08_OPERATIONS") == "on",OS.get_environment("P08_CASE") == "refusal")
print("P08 mixed writer: %d checks, %d failures" % [result.checks,result.failures])
quit(0 if result.failures == 0 else 1)
+1
View File
@@ -0,0 +1 @@
uid://csw2850g6gjct
+15
View File
@@ -0,0 +1,15 @@
extends SceneTree
func _initialize() -> void: call_deferred("run")
func run() -> void:
var checks := 0
var failures := 0
for operations: bool in [false,true]:
for refusal: bool in [false,true]:
var output := ProjectSettings.globalize_path("user://p08-suite-%d-%s-%s" % [Time.get_ticks_usec(),operations,refusal])
for role: String in ["writer","reader"]:
var fixture := preload("res://tests/fixtures/p08-02/mixed_world.gd").new()
var result: Dictionary = fixture.run(self,output,role,operations,refusal)
checks += result.checks; failures += result.failures
if result.failures > 0: break
print("P08 combined migration: %d checks, %d failures" % [checks,failures])
quit(0 if failures == 0 else 1)
@@ -0,0 +1 @@
uid://bq08mixed02wld
+369
View File
@@ -0,0 +1,369 @@
#!/usr/bin/env python3
"""Read-only artifact integrity gate. Success NEVER accepts original P08-02."""
import argparse
import hashlib
import importlib.util
import json
import math
import os
from pathlib import Path
import re
import sys
sys.dont_write_bytecode = True
HERE = Path(__file__).resolve().parent
CONTRACT = 'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'
SPEC_SHA = '19f02bb7912a4d7354e565186f02366fc1d4dd698468d26142e8204fd14ebfb0'
CONDITIONS = ('mixed_construction','occupancy_change','actual_actor_positions',
'combined_rescue_logistics_ev','no_overlap_orphan_loss','unsolvable_preservation')
MEMBERS = ('world.bin','manifest.json','thumbnail.png','journal.log')
CASES = ('off-positive','off-refusal','on-positive','on-refusal')
LABELS = ['checkpoint'] + ['minute-%03d' % n for n in range(1,161)] + ['events']
def sha(path): return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def load(path): return json.loads(Path(path).read_bytes())
def module(name, path):
spec = importlib.util.spec_from_file_location(name,path)
obj = importlib.util.module_from_spec(spec); spec.loader.exec_module(obj); return obj
def decode(node):
"""Only decode for semantic checks; whole typed nodes remain comparison authority."""
t = node['type']
if t == 'Dictionary':
pairs = [(decode(k),decode(v)) for k,v in node['entries']]
keys = [json.dumps(k,sort_keys=True) for k,v in pairs]
if len(keys) != len(set(keys)): raise ValueError('duplicate typed dictionary key')
return {k:v for k,v in pairs}
if t == 'Array': return [decode(n) for n in node['items']]
text = node['text']
if t in ('String','StringName'): return json.loads(text.removeprefix('&'))
if t == 'int': return int(text)
if t == 'float': return float(text)
if t == 'bool':
if text not in ('true','false'): raise ValueError('invalid bool')
return text == 'true'
if t == 'Nil': return None
if t in ('Vector2i','Vector3i','Vector2','Vector3'):
match = re.fullmatch(re.escape(t)+r'\(([^()]*)\)',text)
parts = match.group(1).split(',') if match else []
integer = t.endswith('i')
number = r'[+-]?[0-9]+' if integer else r'[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?'
if len(parts) != int(t[6]) or any(not re.fullmatch(number,x.strip()) for x in parts):
raise ValueError('invalid typed vector '+t)
values = [(int if integer else float)(x.strip()) for x in parts]
if not integer and not all(math.isfinite(x) for x in values):
raise ValueError('invalid typed vector '+t)
return values
# Preserve unfamiliar scalar types verbatim; never silently drop them.
return (t,text)
def indexed(rows, key):
result = {row[key]:row for row in rows}
if len(result) != len(rows): raise ValueError('duplicate '+key)
return result
def semantics(snapshot, identity, initial=False):
"""Independent ID/cell/reference checks on actual serialized Runtime state."""
r = snapshot['systems']['runtime']
guests = indexed(r['guests']['guests'],'guest_id')
staff = indexed(r['staff']['staff'],'staff_id')
if set(guests) & set(staff): raise ValueError('duplicate actor across domains')
jobs = indexed(r['construction']['jobs'],'job_id')
facilities = indexed(r['construction']['facilities'],'instance_id')
operational = indexed(r['facilities']['instances'],'instance_id')
owners = {k:v['occupied_cells'] for k,v in facilities.items()}
owners.update({k:v['reserved_cells'] for k,v in jobs.items() if v['state'] not in ('COMPLETED','CANCELLED')})
occupied = indexed(r['world']['occupancies'],'entity_id')
cells = set()
for owner,row in occupied.items():
actual = {tuple(c) for c in row['cells']}
if len(actual) != len(row['cells']) or cells & actual: raise ValueError('overlap occupancy')
cells |= actual
if owner not in owners or actual != {tuple(c) for c in owners[owner]}: raise ValueError('orphan occupancy/ownership')
if set(owners) != set(occupied): raise ValueError('lost occupancy owner')
for fid,facility in operational.items():
if fid not in facilities or facility['occupied_cells'] != facilities[fid]['occupied_cells']:
raise ValueError('operational/construction ownership mismatch')
for jid in identity['jobs']:
if jid not in jobs: raise ValueError('lost paid job')
starting = jid == identity['starting_job']
stage_ok = (jobs[jid]['progress'] == 0 and jobs[jid]['state'] == 'PLANNED') if starting else (jobs[jid]['progress'] > 0 and jobs[jid]['state'] == 'BUILDING')
if initial and (not stage_ok or not jobs[jid]['construction_cost'] or len(jobs[jid]['reserved_cells']) != 6):
raise ValueError('missing paid old-size progress/reservation')
if identity['starting_job'] not in identity['jobs']: raise ValueError('missing starting stage')
budget = identity['diagnostic_budget']
total = {key:sum(row['cost'].get(key,0) for row in budget['costs']) for key in ('gold','materials')}
total['gold'] += budget['signing'] + budget['food_cost']
deficit = {key:max(0,value-budget['initial'][key]) for key,value in total.items() if value > budget['initial'][key]}
if budget['seed'] != 42588 or budget['food_quantity'] != 8 or total != budget['needed'] or deficit != budget['deltas']:
raise ValueError('diagnostic resource derivation mismatch')
if len(identity['jobs']) < 2 or identity['dorm'] not in facilities: raise ValueError('mixed jobs/completed facility missing')
tasks = indexed(r['staff']['tasks'],'task_id')
if 'patient' not in staff or 'carrier' not in staff: raise ValueError('lost patient/carrier')
rescue = tasks[identity['rescue_task']]
if rescue['target_entity_id'] != 'patient' or rescue['rescue_facility_id'] not in facilities:
raise ValueError('rescue patient/destination reference')
if initial and (rescue['state'] != 'MOVING' or rescue['assigned_staff_id'] != 'carrier' or staff['patient']['health'] != 0):
raise ValueError('rescue is not actually in flight')
inventories = indexed(r['inventory']['inventories'],'owner_inventory_id')
requests = indexed(r['logistics_requests'],'request_id')
reservations = indexed(r['inventory']['reservations'],'reservation_id')
if not identity['logistics_requests']: raise ValueError('missing original food request')
for rid in identity['logistics_requests']:
req = requests[rid]
for endpoint in ('source_inventory_id','destination_inventory_id'):
value = req[endpoint]
if not value.startswith('facility.inventory:') or value.removeprefix('facility.inventory:') not in operational:
raise ValueError('orphan cargo endpoint')
state = req['state']
carrier_id = req['assigned_carrier_id']
if state == 'RESERVED' and carrier_id:
raise ValueError('RESERVED carrier contradiction')
if state in ('RESERVED','DELIVERING'):
ids = req['reservation_ids']
if not ids or len(ids) != len(set(ids)) or any(x not in reservations for x in ids):
raise ValueError(state+' missing/duplicate reservation')
totals = {}
for reservation_id in ids:
row = reservations[reservation_id]
if (row['requester_id'] != rid or row['owner_inventory_id'] != req['source_inventory_id']
or row['stack_id'] not in req['reserved_stack_ids']
or row['state'] != ('ACTIVE' if state == 'RESERVED' else 'CONSUMED')
or type(row['quantity']) is not int or row['quantity'] <= 0):
raise ValueError(state+' reservation crosslink mismatch')
totals[row['item_id']] = totals.get(row['item_id'],0)+row['quantity']
if totals != req['item_requirements'] or set(req['reserved_stack_ids']) != {reservations[x]['stack_id'] for x in ids}:
raise ValueError(state+' reservation quantity mismatch')
if state == 'RESERVED':
source_stacks = indexed(inventories.get(req['source_inventory_id'],{}).get('stacks',[]),'stack_id')
for reservation_id in ids:
row = reservations[reservation_id]; stack = source_stacks.get(row['stack_id'],{})
if (stack.get('item_id') != row['item_id'] or stack.get('quantity',0) < row['quantity']
or stack.get('reserved_quantity',0) < row['quantity']):
raise ValueError('RESERVED cargo/reservation mismatch')
else:
carrier = staff.get(carrier_id,{})
cargo = inventories.get(carrier.get('carried_inventory_id'),{})
cargo_totals = {}
for stack in cargo.get('stacks',[]):
cargo_totals[stack['item_id']] = cargo_totals.get(stack['item_id'],0)+stack['quantity']
if not carrier or cargo_totals != totals:
raise ValueError('DELIVERING carrier/cargo mismatch')
trips = indexed(r['elevators']['trips'],'request_id')
actors = set(guests) | set(staff)
for trip in trips.values():
actor = trip['actor_id']
if actor not in actors and actor.removeprefix('guest:').removeprefix('staff:') not in actors:
raise ValueError('orphan EV actor')
if initial:
if len(identity['ev_requests']) != 5 or not set(identity['ev_requests']) <= set(trips): raise ValueError('lost EV request')
if sum(len(c['boarded']) for c in r['elevators']['shafts']) != 4: raise ValueError('EV passengers/queue absent')
if 'p08.walker' not in guests or not r['movement_credits']: raise ValueError('mid-route guest/credit absent')
return r
def typed_differences(a, b, path=()):
if a == b: return []
if a.get('type') != b.get('type'): return [path]
if a['type'] == 'Dictionary':
aa = {str(decode(k)):(k,v) for k,v in a['entries']}; bb = {str(decode(k)):(k,v) for k,v in b['entries']}
if aa.keys() != bb.keys(): return [path]
differences = []
for k in aa:
if aa[k][0] != bb[k][0]: differences.append(path+(k,'@key-type'))
differences += typed_differences(aa[k][1],bb[k][1],path+(k,))
return differences
if a['type'] == 'Array' and a.get('element_type') == b.get('element_type') and a.get('element_class') == b.get('element_class'):
if len(a['items']) != len(b['items']): return [path]
return [p for i,(x,y) in enumerate(zip(a['items'],b['items'])) for p in typed_differences(x,y,path+(str(i),))]
return [path]
def migration_revisions(before, after, refusal):
"""WorldService._mark_dirty assigns domain counters the global epoch.
r04: (world, occupancy, support) (144,144,142) -> (150,150,150).
Only an actual occupancy rewrite can justify the support epoch delta.
Whole typed comparison still rejects every other unapproved field.
"""
old, new = before['world']['revisions'], after['world']['revisions']
keys = ('world','occupancy','support')
if any(type(row[k]) is not int or row[k] < 0 for row in (old,new) for k in keys):
raise ValueError('invalid revision epoch')
if refusal:
if any(old[k] != new[k] for k in keys):
raise ValueError('refusal revision changed')
return
changed = before['world']['occupancies'] != after['world']['occupancies']
if (not changed or not old['support'] <= old['world'] or not old['occupancy'] <= old['world']
or new['world'] <= old['world'] or new['occupancy'] != new['world']
or new['support'] != new['world'] or new['support'] < old['support']):
raise ValueError('support epoch/occupancy mismatch')
# Explicit geometry changes only. No actor, economy, request, event or route wildcard.
# This fixture deliberately places actors away from removed cells: NO route changes approved.
GEOMETRY = [
r'systems/runtime/world/occupancies/\d+/cells(?:/.*)?',
r'systems/runtime/world/dirty_cells(?:/.*)?',
r'systems/runtime/world/revisions/(world|occupancy)',
r'systems/runtime/construction/jobs/\d+/reserved_cells(?:/.*)?',
r'systems/runtime/construction/facilities/\d+/occupied_cells(?:/.*)?',
r'systems/runtime/facilities/instances/\d+/occupied_cells(?:/.*)?',
]
def check(project_root, evidence_dir):
root, evidence = Path(project_root).resolve(), Path(evidence_dir).resolve()
deficits = []
def need(ok, reason):
if not ok: deficits.append(reason)
def guarded(label, fn):
try: return fn()
except (KeyError,ValueError,TypeError,OSError,IndexError,AttributeError) as exc:
deficits.append(label+': '+str(exc)); return None
index = guarded('index',lambda:load(evidence/'index.json'))
if not isinstance(index,dict): return deficits or ['index is not an object']
def artifact(name):
if not isinstance(name,str) or Path(name).is_absolute() or '..' in Path(name).parts: raise ValueError('unsafe artifact path')
path = evidence/name
if not path.is_file() or any(p.is_symlink() for p in [path,*path.parents] if p != evidence.parent): raise ValueError('missing/aliased artifact '+name)
pin = index['artifacts'][name]
if pin != {'bytes':path.stat().st_size,'sha256':sha(path)}: raise ValueError('artifact hash '+name)
return path
def document(name): return load(artifact(name))
need(index.get('schema') == 'p08-evidence-v1','schema')
need(index.get('acceptance') == 'pending','integrity is not unit acceptance')
need(index.get('collection_error') is None,'collection failure')
def source_gate():
runner = module('p08_readonly_source',root/'tools/run_all_tests.py')
actual = {n:p['sha256'] for n,p in runner.source_refs(root).items()}
need(index['source_map'] == actual,'wrong/stale/incomplete final source map')
spec = load(root/'docs/spec/acceptance/P08-02.json')
need(index['spec_sha256'] == SPEC_SHA == hashlib.sha256((root/'docs/spec/acceptance/P08-02.json').read_text().strip().encode()).hexdigest(),'frozen spec SHA')
for name,pin in spec['current_source_pins'].items(): need(actual.get(name) == pin,'frozen production source '+name)
inputs = {str(p.relative_to(root)):sha(p) for p in (root/'docs/spec/inputs/p08-02').iterdir() if p.is_file()}
need(index['inputs'] == inputs,'frozen input map')
need(index['marker_contract_sha256'] == sha(root/CONTRACT),'marker contract source')
need(re.fullmatch('[0-9a-f]{40}',index['commit']) is not None,'submitted commit identity')
guarded('source',source_gate)
for name in index.get('artifacts',{}): guarded('artifact '+name,lambda name=name:artifact(name))
markers = module('p08_evidence_markers',root/'tools/strict_test_markers.py')
contracts = markers.load_contracts(root/CONTRACT)
pids = set()
def phase(name, role):
receipt = document(name); pid = receipt['actual_pid']
need(type(pid) is int and pid > 0 and pid not in pids,'distinct native PID '+name); pids.add(pid)
parent = str(Path(name).parent)
prefix = '' if parent == '.' else parent+'/'
folder = prefix+receipt['phase']+'/'
start,end,outer = [document(folder+n) for n in ('started.json','ended.json','outer-owned-finally.json')]
for row in (start,end):
need(row['actual_pid'] == pid and row['command'] == receipt['command'],'raw lifecycle PID/argv '+name)
need(end.get('exit_code') == 0 and end.get('engine_ended') is True,'ended exit '+name)
need(start.get('live_identity_exact') is True or start.get('tracked_child_ended_before_initial_probe') is True,'native Popen identity '+name)
need(outer['actual_captured_pids'] == [pid] and outer['all_captured_ended'] is True and not outer['outer_cleanup_errors'] and outer['foreign_process_or_group_signals'] == 0,'owned cleanup '+name)
native = receipt['native_process']
need(native['exit_code'] == 0 and native['helper_exit_code'] == 0 and native['timed_out'] is False and native['lifecycle_error'] is None,'native exit/errors '+name)
need(receipt['exit_code'] == 0 and receipt['engine_ended'] is True,'phase ended '+name)
if role:
test = 'tests/fixtures/p08-02/'+role+'.gd'
need(receipt['test'] == test and receipt['source_sha256'] == index['source_map'][test],'phase source '+name)
raw = artifact(prefix+receipt['log']).read_text()
parsed = markers.parse_raw(test,raw,{test:{'template':'P08 mixed '+role+': <checks> checks, <failures> failures'}},receipt['source_sha256'])
need(not parsed['errors'],'strict completion '+name+': '+str(parsed['errors']))
profile = receipt['actual_private_profile']['report']
need(profile['fresh_before_parent_initialize'] is True and profile['profile_writes_before_guard'] == 0 and profile['actual_user_data_dir'] == profile['expected_user_data_dir'],'guarded fresh profile '+name)
return receipt
def case_gate(case):
name = case['id']; prefix = case['directory']+'/'
need(name == case['operations']+'-'+case['kind'],'case identity '+name)
need(len(case['phases']) == 2,'writer and reader phases '+name)
receipts = [phase(n,r) for n,r in zip(case['phases'],('writer','reader'))]
def typed(name):
artifact(prefix+name+'.var')
return document(prefix+name+'.json')
identity = decode(typed('identity'))
original = typed('original'); after_live = typed('after-live')
need(original == after_live,'live partial batch '+name)
before_members,after_members = [decode(typed(n)) for n in ('before-members','after-members')]
for package in ('original','result','backup'):
for member in MEMBERS: artifact(prefix+package+'/formal/'+member)
for member in MEMBERS:
need(before_members['/'+member] == sha(artifact(prefix+'original/formal/'+member)),'original overwritten '+name+'/'+member)
need(after_members['/'+member] == sha(artifact(prefix+'result/formal/'+member)),'result member '+name+'/'+member)
need(after_members['.pre_migration.bak/'+member] == sha(artifact(prefix+'backup/formal/'+member)),'backup overwritten '+name+'/'+member)
refusal = case['kind'] == 'refusal'
if refusal: need(before_members == after_members,'refusal original/backup overwritten '+name)
source = semantics(decode(original),identity,True)
need(source['operations']['enabled'] == (case['operations']=='on'),'missing actual Operations mode '+name)
for role,receipt in zip(('writer','reader'),receipts):
proc = decode(typed(role+'-process'))
need(proc['pid'] == receipt['actual_pid'] and proc['failures'] == 0 and proc['operations'] == (case['operations']=='on') and proc['refusal'] == refusal,'fixture/native binding '+name+'/'+role)
checkpoint = typed('writer-checkpoint')
migrated = decode(checkpoint)['systems']['runtime']
migration_revisions(source,migrated,refusal)
if refusal: need(original == checkpoint,'partial earlier candidate '+name)
else:
for path in typed_differences(original,checkpoint):
support_epoch = path == ('systems','runtime','world','revisions','support')
need(support_epoch or any(re.fullmatch(pattern,'/'.join(path)) for pattern in GEOMETRY),'unapproved typed migration delta '+name+'/'+ '/'.join(path))
migrated = decode(checkpoint)['systems']['runtime']
jobs = indexed(migrated['construction']['jobs'],'job_id')
need(all(len(jobs[j]['reserved_cells']) == 4 for j in identity['jobs']),'positive batch not applied '+name)
for label in LABELS:
writer,reader = typed('writer-'+label),typed('reader-'+label)
need(writer == reader,'cross-PID full typed state/events '+name+'/'+label)
need(sha(artifact(prefix+'writer-'+label+'.var')) == sha(artifact(prefix+'reader-'+label+'.var')),'cross-PID raw Variant '+name+'/'+label)
if label != 'events': semantics(decode(writer),identity)
final = decode(typed('writer-minute-160'))['systems']['runtime']
need(indexed(final['staff']['staff'],'staff_id')['patient']['health'] == 100,'patient lost/untreated '+name)
final_requests = indexed(final['logistics_requests'],'request_id')
need(all(final_requests[i]['state']=='COMPLETED' for i in identity['logistics_requests']),'original cargo completion '+name)
events = decode(typed('writer-events'))
for rid in identity['ev_requests']:
need(sum(e['event_type']=='ELEVATOR_ARRIVED' and e['payload'].get('request_id')==rid for e in events)==1,'EV original request exactly once '+name+'/'+rid)
cases = index.get('cases',[])
need([c.get('id') for c in cases] == list(CASES),'missing/duplicate ON/OFF positive/refusal case')
for case in cases: guarded('case '+str(case.get('id')),lambda case=case:case_gate(case))
for condition in CONDITIONS:
expected = [c for c in CASES if condition != 'unsolvable_preservation' or c.endswith('refusal')]
need(index.get('conditions',{}).get(condition) == expected,'condition mapping '+condition)
def os_gate():
proof = document(index['os_proof'])
need(proof['commit'] == index['commit'] and proof['source_map'] == index['source_map'],'OS current candidate')
need(proof['input_method'] == 'native_os' and proof['setup'] == 'controlled_old_save','OS input provenance/setup')
actions = proof['actions']
need([a['action'] for a in actions] == ['preview','cancel','confirm','changed_source_rejection'],'OS actions missing')
for action in actions:
raw = document(action['input_receipt'])
need(raw['method'] == 'native_os' and raw['event_type'] in ('mouse','keyboard') and type(raw['target_pid']) is int and raw['target_pid'] > 0 and raw['timestamp_ns'] > 0,'fake OS signal')
for key in ('screen_before','screen_after','model_before','model_after','formal_before','formal_after'): artifact(action[key])
if action['action'] in ('preview','cancel','changed_source_rejection'):
need(document(action['formal_before']) == document(action['formal_after']),'OS formal preservation '+action['action'])
guarded('OS proof',os_gate)
def regression_gate():
proof = document(index['regression']); run_input = document(proof['input']); ended = document(proof['ended'])
need(run_input['selected_source_map'] == index['source_map'],'final regression source map')
need(proof['commit'] == index['commit'],'final regression commit')
need(not ended['error'] and not ended['cleanup_errors'] and not ended['guard_errors'],'regression failure')
runner = module('p08_regression_roster',root/'tools/run_all_tests.py')
roster = runner.roster(root)
need(run_input['roster'] == roster,'full final roster')
rows = [x for x in ended['phases'] if x.get('test')]
need([x['test'] for x in rows] == roster,'full final regression receipt')
for row in rows:
raw = artifact(proof['directory']+'/'+row['log']).read_text()
need(not markers.parse_raw(row['test'],raw,contracts,index['source_map'][row['test']])['errors'],'regression strict '+row['test'])
need(row['exit_code'] == 0 and row['engine_ended'] is True,'regression native exit '+row['test'])
guarded('final regression',regression_gate)
return sorted(set(deficits))
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--verify-only',action='store_true',required=True)
parser.add_argument('--project-root',type=Path,default=HERE.parent)
args = parser.parse_args(argv)
build = os.environ.get('BUILD_OUTPUT_DIR')
deficits = ['BUILD_OUTPUT_DIR missing'] if not build else check(args.project_root,Path(build)/'p08-evidence')
print(json.dumps({'integrity':'deficient' if deficits else 'verified','deficits':deficits,
'acceptance':'pending','conditions':{c:'pending' for c in CONDITIONS}},ensure_ascii=False,indent=2))
return 1 if deficits else 0
if __name__ == '__main__': raise SystemExit(main())
+141
View File
@@ -0,0 +1,141 @@
#!/usr/bin/env python3
"""Root-only native collection. Does not run regression or claim acceptance."""
import argparse
import hashlib
import importlib.util
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import time
sys.dont_write_bytecode = True
HERE = Path(__file__).resolve().parent
CONTRACT = 'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'
CONDITIONS = ('mixed_construction', 'occupancy_change', 'actual_actor_positions',
'combined_rescue_logistics_ev', 'no_overlap_orphan_loss', 'unsolvable_preservation')
def module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
obj = importlib.util.module_from_spec(spec)
spec.loader.exec_module(obj)
return obj
def absolute(value):
path = Path(value)
if not path.is_absolute():
raise argparse.ArgumentTypeError('absolute path required')
return path.resolve()
def collect(args):
root, out = args.project_root, args.output
r = module('p08_standard_runner', root/'tools/run_all_tests.py')
commit = subprocess.check_output(['git', '-C', str(root), 'rev-parse', 'HEAD'], text=True).strip()
r.require(commit == args.commit, 'actual final submitted commit required')
r.require(not out.exists(), 'fresh output; never overwrite earlier proof')
refs = r.source_refs(root)
outer = r.module('p08_owned_outer', r.SUPPORT/'owned_outer.py')
r.require(not outer.native.helper['live_engines'](), 'one native engine')
engine = shutil.which(args.godot)
r.require(engine is not None, 'native engine exists')
engine = str(Path(engine).resolve())
out.mkdir(parents=True)
stage = out/'stage'; stage.mkdir()
(out/'starters').mkdir(); (out/'bootstrap').mkdir()
for name, pin in r.read(r.SUPPORT/'bootstrap-scripts.json').items():
data = pin['text'].encode()
r.require(hashlib.sha256(data).hexdigest() == pin['sha256'], 'bootstrap pin')
(out/'bootstrap'/name).write_bytes(data)
for name, pin in refs.items():
target = stage/name; target.parent.mkdir(parents=True, exist_ok=True)
r.copy_source(Path(pin['path']), target)
r.require(r.sha(target) == pin['sha256'], 'whole copied source '+name)
expected = {n: {'bytes':v['bytes'], 'sha256':v['sha256']} for n,v in refs.items()}
selected = {'root_before':refs, 'map':{n:v['sha256'] for n,v in refs.items()}, 'timeout':180}
r.require(r.inventory(stage, stage=True) == expected, 'complete private source')
protected = r.default_player(root); public = (stage/'project.godot').read_bytes()
paths = ['res://'+n for n in sorted(refs) if n.endswith('.gd')]
r.write(out/'parse-paths.json', paths)
markers = r.module('p08_strict_markers', root/'tools/strict_test_markers.py')
contracts = markers.load_contracts(root/CONTRACT)
for role in ('writer','reader'):
name = 'tests/fixtures/p08-02/'+role+'.gd'
contracts[name] = {'test':name, 'template':'P08 mixed '+role+': <checks> checks, <failures> failures', 'required':True}
policy = r.read(r.SUPPORT/'suite-policy.json')
diagnostics = r.module('p08_diagnostics', r.SUPPORT/'diagnostic_gate.py')
owners = r.module('p08_owners', r.SUPPORT/'ordinary_proof_gate.py')
audio = r.module('p08_audio', r.SUPPORT/'audio_evidence_gate.py')
r.write(out/'runner-input.json', {'protocol':'p08-mixed-v1', 'commit':commit,
'selected_source_map':selected['map'], 'engine':engine, 'engine_sha256':r.sha(engine),
'owner_pid':os.getpid(), 'default_player':protected, 'diagnostic_seed':42588})
phases = []; previous = {}; cases = []; error = None
deadline = time.monotonic()+900
saved_env = {k:os.environ.get(k) for k in ('P08_PAIR_ROOT','P08_OPERATIONS','P08_CASE')}
def phase(label, test):
remaining = int(deadline-time.monotonic())
r.require(remaining >= (180 if label == 'import' else 1), '900s collection deadline')
selected['timeout'] = min(180,remaining)
phase_out = out/'runs'/label
phase_out.mkdir(parents=True)
(phase_out/'starters').mkdir(); (phase_out/'bootstrap').mkdir()
for original in (out/'bootstrap').iterdir():
r.copy_source(original,phase_out/'bootstrap'/original.name)
r.require(r.sha(original)==r.sha(phase_out/'bootstrap'/original.name),'bootstrap full copy')
r.write(phase_out/'parse-paths.json',paths)
row = r.execute_phase(engine, stage, phase_out, label, test, selected, expected, previous,
policy, contracts, paths, public, protected, root, outer, markers, diagnostics, owners, audio)
phases.append('runs/'+label+'/'+label+'-receipt.json')
r.require(not row['failed'], 'strict phase failed: '+label)
try:
phase('import', None); phase('parse', None)
for operations in ('off','on'):
for case in ('positive','refusal'):
name = operations+'-'+case; pair = out/'pairs'/name
os.environ.update(P08_PAIR_ROOT=str(pair), P08_OPERATIONS=operations, P08_CASE=case)
case_phases = []
preserved = {}
for role in ('writer','reader'):
label = name+'-'+role
test = 'tests/fixtures/p08-02/'+role+'.gd'
phase(label, test)
actual = r.inventory(pair)
r.require(all(actual.get(n) == pin for n,pin in preserved.items()), 'reader preserved every writer byte')
preserved = actual
case_phases.append(phases[-1])
cases.append({'id':name, 'operations':operations, 'kind':case,
'directory':'pairs/'+name, 'phases':case_phases, 'files':preserved})
except BaseException as caught:
error = type(caught).__name__+': '+str(caught)
finally:
cleanup, cleanup_errors = outer.finish_captured(outer.OWNED)
for key,value in saved_env.items():
if value is None: os.environ.pop(key, None)
else: os.environ[key] = value
r.require(r.source_refs(root) == refs and r.default_player(root) == protected, 'protected root/profile unchanged')
r.write(out/'runner-ended.json', {'error':error, 'cleanup':cleanup, 'cleanup_errors':cleanup_errors,
'phases':phases, 'formal_acceptance':False, 'native_Windows':'pending'})
inputs = {str(p.relative_to(root)):r.sha(p) for p in (root/'docs/spec/inputs/p08-02').iterdir() if p.is_file()}
# The collector is intentionally incomplete until Root supplies OS and regression artifacts.
r.write(out/'index.json', {'schema':'p08-evidence-v1', 'commit':commit,
'source_map':selected['map'], 'inputs':inputs, 'marker_contract_sha256':r.sha(root/CONTRACT),
'spec_sha256':hashlib.sha256((root/'docs/spec/acceptance/P08-02.json').read_text().strip().encode()).hexdigest(),
'cases':cases, 'phases':phases, 'conditions':{c:[x['id'] for x in cases if c != 'unsolvable_preservation' or x['kind']=='refusal'] for c in CONDITIONS},
'artifacts':{str(p.relative_to(out)):{'bytes':p.stat().st_size,'sha256':r.sha(p)}
for p in out.rglob('*') if p.is_file() and 'stage' not in p.relative_to(out).parts},
'os_proof':None, 'regression':None,
'acceptance':'pending', 'collection_error':error})
return 1 if error or cleanup_errors else 0
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--project-root', type=absolute, required=True)
parser.add_argument('--output', type=absolute, required=True)
parser.add_argument('--commit', required=True)
parser.add_argument('--godot', default='godot')
parser.add_argument('--collect', action='store_true', required=True)
return collect(parser.parse_args(argv))
if __name__ == '__main__':
raise SystemExit(main())
+264
View File
@@ -0,0 +1,264 @@
#!/usr/bin/env python3
"""Synthetic evidence ONLY: disposable end-to-end check() positives and corruptions.
No Godot/OS execution, no actual acceptance proof. Mutations update hashes so the
semantic gate, not merely a stale digest, must reject invalid state.
"""
import copy
import hashlib
import json
from pathlib import Path
import tempfile
import unittest
import check_p08_migration_evidence as c
ROOT = Path(__file__).resolve().parent.parent
BANNER = 'Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org\n'
R04 = json.loads((ROOT/'docs/plans/original-completion-2026-10-02/execution/p08-02/ROOT_REPAIR_INPUT-r04.json').read_text())
ACTUAL = R04['actual_readonly_diagnostics']
REQUESTS = ACTUAL['CARGO_ENDPOINT_READONLY_DIAGNOSTIC.json'][0]['requests']
REVISIONS = ACTUAL['ACTUAL_WORLD_REVISION_DELTAS.json'][0]
def typed(value):
if isinstance(value,tuple): return {'type':'Vector3i','text':'Vector3i('+', '.join(map(str,value))+')'}
if isinstance(value,dict): return {'type':'Dictionary','entries':[[typed(k),typed(v)] for k,v in value.items()]}
if isinstance(value,list): return {'type':'Array','element_type':0,'element_class':'','items':[typed(x) for x in value]}
kind = 'Nil' if value is None else 'bool' if type(value) is bool else 'int' if type(value) is int else 'String'
return {'type':kind,'text':json.dumps(value)}
class Proof:
def __init__(self, path):
self.path = path
runner = c.module('p08_synthetic_source',ROOT/'tools/run_all_tests.py')
self.runner = runner
source = {n:p['sha256'] for n,p in runner.source_refs(ROOT).items()}
self.index = {'schema':'p08-evidence-v1','commit':'e196578c1a4ad2fdf84642565bd102e524be386f',
'source_map':source,'spec_sha256':c.SPEC_SHA,'marker_contract_sha256':c.sha(ROOT/c.CONTRACT),
'inputs':{str(p.relative_to(ROOT)):c.sha(p) for p in (ROOT/'docs/spec/inputs/p08-02').iterdir() if p.is_file()},
'cases':[],'conditions':{k:[x for x in c.CASES if k!='unsolvable_preservation' or x.endswith('refusal')] for k in c.CONDITIONS},
'artifacts':{},'acceptance':'pending','collection_error':None,'phases':[],
'os_proof':'os.json','regression':'regression.json'}
for number,name in enumerate(c.CASES): self.case(name,number)
self.os(); self.regression(); self.save()
def put(self,name,value):
path = self.path/name; path.parent.mkdir(parents=True,exist_ok=True)
path.write_bytes(value if isinstance(value,bytes) else json.dumps(value).encode())
self.index['artifacts'][name] = {'bytes':path.stat().st_size,'sha256':c.sha(path)}
def variant(self,prefix,name,value):
node = typed(value)
self.put(prefix+name+'.json',node)
# Deliberately not a native Variant: this is an isolated Python proof fixture.
self.put(prefix+name+'.var',json.dumps(node).encode())
def save(self): (self.path/'index.json').write_text(json.dumps(self.index))
def state(self,operations):
jobs = [{'job_id':j,'state':'PLANNED' if j=='j2' else 'BUILDING','progress':0 if j=='j2' else 1266,'reserved_cells':[(x,2,0) for x in range(offset,offset+6)],'construction_cost':{'gold':1}}
for j,offset in [('j1',0),('j2',10)]]
facilities = [{'instance_id':'dorm','occupied_cells':[[30,0,1]]},{'instance_id':'clinic','occupied_cells':[[31,0,1]]}]
facilities += [{'instance_id':'facility_00000005','occupied_cells':[(32,0,1)]},
{'instance_id':'facility_00000006','occupied_cells':[(33,0,1)]}]
guests = [{'guest_id':g} for g in ['p08.walker']+['g'+str(n) for n in range(5)]]
staff = [{'staff_id':'patient','health':0},{'staff_id':'carrier'},{'staff_id':'staff_gina','carried_inventory_id':'cargo:staff_gina'}]
r = {'operations':{'enabled':operations},'guests':{'guests':guests},'staff':{'staff':staff,'tasks':[
{'task_id':'rescue','target_entity_id':'patient','rescue_facility_id':'clinic','state':'MOVING','assigned_staff_id':'carrier'}]},
'construction':{'jobs':jobs,'facilities':facilities},'facilities':{'instances':copy.deepcopy(facilities)},
'world':{'revisions':copy.deepcopy(REVISIONS['original_world_revisions']),'occupancies':[{'entity_id':j['job_id'],'cells':copy.deepcopy(j['reserved_cells'])} for j in jobs]+
[{'entity_id':f['instance_id'],'cells':copy.deepcopy(f['occupied_cells'])} for f in facilities]},
'inventory':{'inventories':[{'owner_inventory_id':owner,'stacks':[{'stack_id':stack,'item_id':'ingredient/raw_food','quantity':4,'reserved_quantity':reserved}]} for owner,stack,reserved in
[('facility.inventory:facility_00000005','stack_00000001',4),('cargo:staff_gina','stack_00000002',0)]],
'reservations':[{'reservation_id':req['reservation_ids'][0],'requester_id':req['request_id'],
'owner_inventory_id':req['source_inventory_id'],'stack_id':'stack_00000001','item_id':'ingredient/raw_food',
'quantity':4,'state':'CONSUMED' if req['state']=='DELIVERING' else 'ACTIVE'} for req in REQUESTS]},
'logistics_requests':copy.deepcopy(REQUESTS),
'movement_credits':[{'credit':1000}],
'elevators':{'trips':[{'request_id':'ev'+str(n),'actor_id':'g'+str(n)} for n in range(5)],'shafts':[{'boarded':['g0','g1','g2','g3']}]}}
return {'systems':{'runtime':r}}
def phase(self,name,role,pid):
folder = 'runs/'+name+'/'; test = 'tests/fixtures/p08-02/'+role+'.gd'
command = ['synthetic-native','--script',test]
start = {'actual_pid':pid,'command':command,'live_identity_exact':True,'event':'ENGINE_STARTED','owner_pid':1,'monotonic_ns':1}
end = dict(start,event='ENGINE_ENDED',monotonic_ns=2,exit_code=0,engine_ended=True)
self.put(folder+name+'/started.json',start); self.put(folder+name+'/ended.json',end)
self.put(folder+name+'/outer-owned-finally.json',{'actual_captured_pids':[pid],'all_captured_ended':True,'outer_cleanup_errors':[],'foreign_process_or_group_signals':0})
self.put(folder+'raw.log',(BANNER+'P08 mixed '+role+': 1 checks, 0 failures\n').encode())
receipt = {'phase':name,'actual_pid':pid,'command':command,'exit_code':0,'engine_ended':True,'test':test,
'source_sha256':self.index['source_map'][test],'log':'raw.log',
'native_process':{'exit_code':0,'helper_exit_code':0,'timed_out':False,'lifecycle_error':None},
'actual_private_profile':{'report':{'fresh_before_parent_initialize':True,'profile_writes_before_guard':0,'actual_user_data_dir':'diagnostic-private-'+name,'expected_user_data_dir':'diagnostic-private-'+name}}}
self.put(folder+name+'-receipt.json',receipt)
return folder+name+'-receipt.json'
def case(self,name,number):
operations = name.startswith('on-'); refusal = name.endswith('refusal'); prefix = 'pairs/'+name+'/'
phases = [self.phase(name+'-'+role,role,100+2*number+i) for i,role in enumerate(('writer','reader'))]
self.index['cases'].append({'id':name,'operations':'on' if operations else 'off','kind':'refusal' if refusal else 'positive','directory':prefix[:-1],'phases':phases})
self.index['phases'] += phases
identity = {'starting_job':'j2','diagnostic_budget':{'seed':42588,'food_quantity':8,'food_cost':24,'signing':1,'costs':[{'cost':{'gold':2,'materials':1}}],'initial':{'gold':0,'materials':0},'needed':{'gold':27,'materials':1},'deltas':{'gold':27,'materials':1}},'jobs':['j1','j2'],'dorm':'dorm','rescue_task':'rescue','logistics_requests':['food'],'ev_requests':['ev'+str(n) for n in range(5)]}
identity['logistics_requests'] = [req['request_id'] for req in REQUESTS]
original = self.state(operations)
self.variant(prefix,'identity',identity); self.variant(prefix,'original',original); self.variant(prefix,'after-live',original)
before = {}; after = {}
for member in c.MEMBERS:
raw = ('synthetic '+member).encode()
for package in ('original','result','backup'): self.put(prefix+package+'/formal/'+member,raw)
before['/'+member] = after['/'+member] = hashlib.sha256(raw).hexdigest()
before['.pre_migration.bak/'+member] = after['.pre_migration.bak/'+member] = hashlib.sha256(raw).hexdigest()
self.variant(prefix,'before-members',before); self.variant(prefix,'after-members',after)
checkpoint = copy.deepcopy(original)
if not refusal:
r = checkpoint['systems']['runtime']
r['world']['revisions'] = copy.deepcopy(REVISIONS['checkpoint_world_revisions'])
for job in r['construction']['jobs']: job['reserved_cells'] = job['reserved_cells'][:4]
for row in r['world']['occupancies'][:2]: row['cells'] = row['cells'][:4]
events = [{'event_type':'ELEVATOR_ARRIVED','payload':{'request_id':rid}} for rid in identity['ev_requests']]
for i,role in enumerate(('writer','reader')):
self.variant(prefix,role+'-process',{'pid':100+2*number+i,'failures':0,'checks':1,'operations':operations,'refusal':refusal})
for label in c.LABELS:
state = copy.deepcopy(checkpoint)
if label == 'minute-160':
state['systems']['runtime']['staff']['staff'][0]['health'] = 100
for req in state['systems']['runtime']['logistics_requests']: req['state'] = 'COMPLETED'
self.variant(prefix,role+'-'+label,events if label=='events' else state)
def os(self):
proof = {'commit':self.index['commit'],'source_map':self.index['source_map'],'input_method':'native_os','setup':'controlled_old_save','actions':[]}
for name in ('preview','cancel','confirm','changed_source_rejection'):
row = {'action':name,'input_receipt':'os/'+name+'/input.json'}
self.put(row['input_receipt'],{'method':'native_os','event_type':'mouse','target_pid':500,'timestamp_ns':1})
for field in ('screen_before','screen_after','model_before','model_after','formal_before','formal_after'):
row[field] = 'os/'+name+'/'+field+'.json'; self.put(row[field],{'synthetic':'diagnostic'})
proof['actions'].append(row)
self.put('os.json',proof)
def regression(self):
contracts = c.module('p08_synthetic_markers',ROOT/'tools/strict_test_markers.py').load_contracts(ROOT/c.CONTRACT)
roster = self.runner.roster(ROOT); rows = []
for i,test in enumerate(roster):
contract = contracts[test]
def marker(template):
for key in ('checks','passed'): template = template.replace('<'+key+'>','1')
for key in ('failures','failed','skipped'): template = template.replace('<'+key+'>','0')
return template+'\n'
raw = BANNER+marker(contract['template'])
for auxiliary in contract.get('auxiliary',[]): raw += marker(auxiliary['template'])
if contract.get('json_report'):
raw += contract['json_report']['prefix']+json.dumps({'check_summary':{'total':1,'passed':1,'failed':0,'skipped':0},'status':'PASS','runtime_errors':[],'unmet_fixture_fields':[]})+'\n'
log = str(i)+'.log'; self.put('regression/'+log,raw.encode())
rows.append({'test':test,'log':log,'exit_code':0,'engine_ended':True})
self.put('regression/input.json',{'selected_source_map':self.index['source_map'],'roster':roster})
self.put('regression/ended.json',{'error':None,'cleanup_errors':[],'guard_errors':[],'phases':rows})
self.put('regression.json',{'commit':self.index['commit'],'directory':'regression','input':'regression/input.json','ended':'regression/ended.json'})
class EvidenceTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.temp = tempfile.TemporaryDirectory(prefix='p08-checker-')
cls.proof = Proof(Path(cls.temp.name))
cls.baseline = copy.deepcopy(cls.proof.index)
@classmethod
def tearDownClass(cls): cls.temp.cleanup()
def test_positive_reaches_whole_check(self):
self.assertEqual(c.check(ROOT,self.proof.path),[])
def test_strict_native_vectors(self):
for kind,good,expected in (
('Vector3i','Vector3i(0, -12, 6)',[0,-12,6]),
('Vector2i','Vector2i(-2, 3)',[-2,3]),
('Vector3','Vector3(1.5, -2e1, .25)',[1.5,-20,.25]),
('Vector2','Vector2(0, 1e-3)',[0,.001])):
with self.subTest(kind=kind):
self.assertEqual(c.decode({'type':kind,'text':good}),expected)
invalid = [good.replace(kind,'WrongVector'),good+'tail',good.replace(',',',,',1),
good[:good.rfind(',')]+')',good.replace(')',', 4)')]
if kind.endswith('i'): invalid += [good.replace('(', '(1.0,',1), kind+'(1.0, '+', '.join(['2']*(len(expected)-1))+')']
for text in invalid:
with self.subTest(text=text), self.assertRaisesRegex(ValueError,'invalid typed vector'):
c.decode({'type':kind,'text':text})
def test_r04_local_deficits_through_whole_check(self):
p = self.proof
def mutate_state(node, change):
state = c.decode(node); change(state['systems']['runtime']); return typed(state)
def bad_vector(node):
if node['type'] == 'Vector3i':
node['text'] = 'Vector3i(0, , 1)'; return True
children = ([n for pair in node['entries'] for n in pair] if node['type']=='Dictionary'
else node.get('items',[]))
return any(bad_vector(child) for child in children)
corruptions = [
('original','invalid typed vector',None),
('original','orphan cargo endpoint',lambda r:r['logistics_requests'][0].update(destination_inventory_id='facility.inventory:absent')),
('original','RESERVED missing/duplicate reservation',lambda r:r['inventory']['reservations'].pop()),
('original','DELIVERING carrier/cargo mismatch',lambda r:r['logistics_requests'][0].update(assigned_carrier_id='patient')),
('original','RESERVED carrier contradiction',lambda r:r['logistics_requests'][1].update(assigned_carrier_id='staff_gina')),
('original','DELIVERING reservation quantity mismatch',lambda r:r['inventory']['reservations'][0].update(quantity=3)),
('writer-checkpoint','support epoch/occupancy mismatch',lambda r:r['world']['revisions'].update(support=143)),
]
for label,message,change in corruptions:
path = 'pairs/off-positive/'+label+'.json'
original = (p.path/path).read_bytes()
try:
node = json.loads(original)
if change: node = mutate_state(node,change)
else: self.assertTrue(bad_vector(node))
p.put(path,node); p.save()
with self.subTest(message=message):
self.assertTrue(any(message in deficit for deficit in c.check(ROOT,p.path)),message)
finally:
p.put(path,original); p.index = copy.deepcopy(self.baseline); p.save()
for key in ('world','occupancy','support'):
path = 'pairs/off-refusal/writer-checkpoint.json'
original = (p.path/path).read_bytes()
try:
node = c.decode(json.loads(original)); revisions = node['systems']['runtime']['world']['revisions']
revisions[key] += 1
p.put(path,typed(node)); p.save()
with self.subTest(refusal_revision=key):
self.assertTrue(any('refusal revision changed' in deficit for deficit in c.check(ROOT,p.path)))
finally:
p.put(path,original); p.index = copy.deepcopy(self.baseline); p.save()
def test_corruptions_cannot_be_accepted(self):
p = self.proof
mutations = {
'duplicate_actor':lambda r:r['guests']['guests'].append(copy.deepcopy(r['guests']['guests'][0])),
'orphan_occupancy':lambda r:r['world']['occupancies'][0].update(entity_id='orphan'),
'lost_patient':lambda r:r['staff']['staff'].pop(0),
'lost_cargo':lambda r:r['inventory']['inventories'].pop(),
'lost_ev':lambda r:r['elevators']['trips'].pop(),
'missing_start_stage':lambda r:r['construction']['jobs'][1].update(state='BUILDING',progress=1),
}
path = 'pairs/off-positive/original.json'
original = (p.path/path).read_bytes()
for label,mutate in mutations.items():
with self.subTest(label=label):
node = c.decode(json.loads(original)); mutate(node['systems']['runtime'])
p.put(path,typed(node)); p.save()
self.assertTrue(c.check(ROOT,p.path),label)
p.put(path,original); p.index = copy.deepcopy(self.baseline); p.save()
path = 'pairs/off-positive/identity.json'
original = (p.path/path).read_bytes()
node = c.decode(json.loads(original)); node['diagnostic_budget']['deltas']['gold'] += 1
p.put(path,typed(node)); p.save()
self.assertTrue(c.check(ROOT,p.path),'resource_delta_mismatch')
p.put(path,original); p.index = copy.deepcopy(self.baseline); p.save()
paths = [('partial_batch','pairs/off-refusal/after-live.json'),('unequal_cross_pid','pairs/on-positive/reader-checkpoint.json'),
('overwritten_original','pairs/off-refusal/original/formal/world.bin'),('overwritten_backup','pairs/off-refusal/backup/formal/world.bin')]
for label,path in paths:
with self.subTest(label=label):
original = (p.path/path).read_bytes()
p.put(path,b'{}'); p.save(); self.assertTrue(c.check(ROOT,p.path),label)
p.put(path,original); p.index = copy.deepcopy(self.baseline); p.save()
for label in ('missing_on','wrong_source','stale_source','fake_os_signal','missing_phase','duplicate_pid'):
with self.subTest(label=label):
changed = None
if label=='missing_on': p.index['cases'] = p.index['cases'][:2]
elif label=='wrong_source': p.index['source_map']['autoload/simulation_runtime.gd'] = '0'*64
elif label=='stale_source': del p.index['source_map']['tools/check_p08_migration_evidence.py']
elif label=='missing_phase': p.index['cases'][0]['phases'].pop()
elif label=='fake_os_signal':
changed = 'os/preview/input.json'; original = (p.path/changed).read_bytes()
row = json.loads(original); row['method'] = 'signal_emitted'; p.put(changed,row)
else:
changed = p.index['cases'][0]['phases'][1]; original = (p.path/changed).read_bytes()
row = json.loads(original); row['actual_pid'] = 100; p.put(changed,row)
p.save(); self.assertTrue(c.check(ROOT,p.path),label)
if changed: p.put(changed,original)
p.index = copy.deepcopy(self.baseline); p.save()
if __name__ == '__main__': unittest.main()