Merge commit 'bf559632ddd938085702529d9dd6b7c878f4ebc7' into HEAD
This commit is contained in:
@@ -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.
|
||||
+101
@@ -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."
|
||||
}
|
||||
+306
@@ -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."
|
||||
]
|
||||
}
|
||||
+341
File diff suppressed because one or more lines are too long
+16
@@ -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."
|
||||
}
|
||||
}
|
||||
Vendored
+23
@@ -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.
|
||||
Vendored
+241
@@ -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
@@ -0,0 +1 @@
|
||||
uid://dg5n4yme6rk4p
|
||||
Vendored
+7
@@ -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)
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
uid://741t47oxl3ct
|
||||
Vendored
+7
@@ -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)
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
uid://csw2850g6gjct
|
||||
@@ -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
|
||||
@@ -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())
|
||||
@@ -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())
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user