Merge commit 'd369d1c399f7506bdb8d980b642ad0da216d14f4' into HEAD

This commit is contained in:
Agent Control Runner
2026-10-15 07:33:14 +09:00
75 changed files with 69772 additions and 10 deletions
@@ -3679,6 +3679,28 @@
"path": "docs/spec/acceptance/P08-02.json",
"scope": "new standalone mixed suite; native execution pending"
}
},
{
"test": "tests/ui/test_p08_normal_placement_ops.gd",
"template": "P08 normal placement: <checks> checks, <failures> failures",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "d3c246d34f8fd66f6ed237e42a86df89ebaf481bc9dee143b4de8d654ce0eb2e",
"authority": {
"path": "docs/spec/acceptance/P08-03.json",
"scope": "normal placement; native and OS pending"
}
},
{
"test": "tests/transport/test_runtime_build_preview.gd",
"template": "Runtime build preview: <checks> checks, <failures> failures",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "c881b60bce7276047884303a6823da9abfaaf8c1e85dbc5f2c0ff13f0d742449",
"authority": {
"path": "docs/spec/acceptance/P08-03.json",
"scope": "normal placement; native and OS pending"
}
}
],
"unknown_roster_suite_policy": "refuse, explicitly review its source/schema before accepting",
@@ -0,0 +1,594 @@
# P08-03 condition matrix — implementation submission, not acceptance
## Repair16 current submission
Root finalized deletion of the repair13 fixture omitted by the Runner submission.
No repair13 fixture remains in the net final diff. Repair14 observations below
are historical and superseded; they do not require a native re-run now.
Environment provenance: the P08_/THE_TREE_ subset is reconstructable and checked
by direct equality across started, process-started, ended and the pinned receipt.
The full-env environment_sha256 is opaque and checked only by cross-receipt and
pin equality; the original os.environ cannot be reconstructed. Receipt bytes and
SHA are pinned through the original index and ended receipt. Driver bytes at HEAD
and in the working tree must equal R09_COMMIT. Other applicability gates remain.
Net diff command (executed read-only):
`git diff --name-status --no-renames 31aa7706d28a92e313c432d5a62e35d19503dcc3 HEAD`
HEAD: **to be bound by Runner**. Output:
```text
M docs/plans/original-completion-2026-10-02/execution/p08-03/CONDITION_MATRIX.md
A docs/plans/original-completion-2026-10-02/execution/p08-03/REPAIR12_CONTEXT_GAP.md
A docs/plans/original-completion-2026-10-02/execution/p08-03/ROOT_NATIVE_R09_COLLECTION_PINS.json
A docs/plans/original-completion-2026-10-02/execution/p08-03/ROOT_R09_COLLECTION_AND_PUBLICATION_DIAGNOSIS.json
A docs/plans/original-completion-2026-10-02/execution/p08-03/ROOT_R09_READONLY_IMAGE_DIMENSIONS.json
M docs/plans/original-completion-2026-10-02/execution/p08-03/implementation.json
A docs/plans/original-completion-2026-10-02/execution/p08-03/repair13-local-source-manifest.json
A docs/plans/original-completion-2026-10-02/execution/p08-03/repair13-local-validation.json
M tools/check_p08_normal_placement_evidence.py
M tools/test_p08_normal_placement_evidence.py
```
Only the two validators and scoped docs; no fixture, Godot, controller, recorder
or input changes. Repair16 retains the 107 existing tests and adds eight specific
negative controls and one driver-rule positive.
Repair16 local validation: `python3 tools/test_p08_normal_placement_evidence.py`
ran 116 tests in 80.606s: OK, exit0, no failures or skips. No native/OS/full run.
Current validator SHA-256:
- checker: 3b2aeb4f064e08e774997b4548dd966d994dc6a07a2ffb2e233b4c9d7aab24a4
- tests: 7814ee7a45934ef6929748423c18424478f2634d63dc4979fa056aef3798af4a
Executed native source commit: 31aa7706d28a92e313c432d5a62e35d19503dcc3.
Current candidate commit: **to be bound by Runner**.
Executed source/input/engine hashes are recorded separately in
implementation.json executed_native_binding; current validator_only_changes
never replaces the executed source map. Earlier repair history remains historical.
All five conditions remain: **Root native evidence collected at 31aa;
independent semantic acceptance pending; Root final full175 regression pending;
integration pending**. No acceptance or earlier PASS is inherited.
Strict reuse checks require the R09 ancestor, complete committed and working-tree
whitelists, exact inputs and non-whitelisted sources, R09 validator blobs and
SHA-pinned runner/OS receipts and engine bytes. The committed R09..HEAD diff
contains only validator and scoped documentation changes after Root finalized
the fixture deletion. The prior Repair14 fixture-addition finding is superseded.
No fixture inputs are excluded.
JPEG positives use only actual R09 capture bytes, compared to the SHA-pinned
original index, measurement, and original OS acknowledgements/role receipts.
The structural parser checks referenced DQT/DHT, SOF/SOS component identity,
non-empty entropy and EOI; synthetic JPEG data exists only in negative tests
inside the Python test module.
Open semantic findings: preview/runtime stair difference; coordinator runtime
acceptance=false; Windows same-distribution/device. Required remaining work:
Root R09 positive hash re-check;
Root final full175; independent Opus review of all five conditions;
integration/current final verification/ledger; Windows same-distribution/device
(no Mac substitution). The denominator30/88 and immutable spec are unchanged.
Repair counter14 is historical; repair/inference/material limits remain null.
Historical Repair14 local validation: python3 tools/test_p08_normal_placement_evidence.py:
107 tests in 84.026 seconds, exit0, no failures or skips. Two Python AST
checks and git diff --check passed. Earlier failed helper-renaming attempts
were corrected; no native, Godot, full regression or verify-only run occurred.
Focused final controls: 18 tests passed, including actual original capture
hashes. Root positive re-check remains required.
Historical Repair14 validator-only SHA-256:
- tools/check_p08_normal_placement_evidence.py: 301098ced37bf83bd580af8b0a73e32f776157737ec6a55513c8cb5f63cd10f6
- tools/test_p08_normal_placement_evidence.py: 24a6894d7e944f5819641adc1bf2ce7a2fba5b367f1005bbae83775060498283
## Repair13 historical status (superseded by Repair14)
Checker/test-only repair. Product, Runtime, Godot, collector, same31aa and rawR09
bytes are unchanged. Root supplied the read-only **post-collection** sips
measurement of 138 images; this is not capture-time metadata. All measured
screenshots are 1280×752 JPEG despite their .png names. Window content size
1280×720 is never used as screenshot dimensions.
The checker reads every image, checks SOI/EOI and bounded SOF0/SOF2 frame/scan
structure, and compares its dimensions and recomputed SHA against the Root
measurement and index. This is structural validation, not JPEG pixel decoding.
The measurement's original_index_sha256 binds the recomputed index. Exact
69-request/138-image membership and before/after dimensions are checked;
formal save thumbnails retain their separate existing member checks.
Collection pins bind the original index, runner receipts and both OS receipts;
every indexed original/canonical artifact must be byte-identical. Owner proof
is verified at ORIGINAL_ROOT/os-runs/{writer,reader}/teardown/control.json,
retaining original absolute varbytes pins without rewriting them.
Reuse is restricted to same31aa (`31aa7706d28a92e313c432d5a62e35d19503dcc3`):
all collected source/input hashes still match, except the two explicitly
changed Python validator/test sources and the new synthetic Python image
fixture. The old validator/test pins are checked against same31aa git objects;
product, GDScript fixtures, engine, recorder, controller and marker pins remain
exact. This exception does not confer gameplay or changed-product acceptance.
Current local Python results and final executed hashes are in
`repair13-local-validation.json`, `repair13-local-source-manifest.json` and
`implementation.json`. All 88 previous tests remain; 12 additional controls
cover baseline/progressive parsing, malformed/truncated/non-JPEG bytes,
SOF/measurement disagreement, before/after drift, missing/extra/duplicate
entries, extra indexed screenshots, source SHA, stale index, collection pin
and original/canonical divergence. Synthetic fixtures have no dependency on
operational Root handoff documents.
All five conditions remain unaccepted. R09 local integrity validation is not
the independent R09 re-check. Leave open: stair preview/domain-status
disagreement for independent acceptance, Windows same-distribution/device,
Root final175 after frozen submission, R09 re-check, independent Opus review,
and integration/current verification/ledger. No OS steps were replayed.
Immutable specification: `docs/spec/acceptance/P08-03.json`, normalized SHA-256
`7941da4edbd3c43a636a4a3d834d57c095b56da988fa3a056e55b22d3a5d50e9`.
Base HEAD: `12430ba89970bda349781e51157e72e48a4ac06f`. Worker made no commit.
This is one existing unit in 30 packages / 88 units, with no partial credit.
| Condition | Implemented paths / diagnostic cases | Current evidence state |
|---|---|---|
| support_connection | Normal palette: unsupported standard room; supported/connected reception; supported stair with missing landing; lower/upper stair construction. Real preview and Runtime command results are retained. | Source and synthetic checker controls only; real handler/native/OS pending. |
| invalid_position_reason | Reception footprint crosses the boundary from an in-bounds origin; existing reception overlap. Exact displayed Japanese reason and report codes; whole typed before/after preservation. | Source and semantic corruption controls only; actual refusals pending. |
| demolish_rebuild | Palette demolition toggle, cell selection, confirmation/cancel, Runtime `demolish_facility`, synchronous/queued results. Lower landing refusal, cancellation, reception removal, same-cell reconstruction. Occupancy, operational/construction instances, costs/refund checked. | Implemented; Godot parsing, actual UI, audio ownership, Runtime results pending. |
| pan_zoom_world_identity | Move mode + non-Ctrl wheel; normal wheel zoom, 0.5/4.0 clamps; recomputed local/viewport/screen coordinates and actual selected cell. OS recorder requests CUA only. | Mock bridge/checker controls only; actual OS wheel/screenshot provenance pending. |
| separate_pid_resume | Formal four-member save; separate native writer/reader; normal load menu; whole typed/raw presave/formal identity and source-defined post-operation reconstruction, instance ID, cell and overlap judgement. | R02 diagnosed notification difference; repaired candidate requires fresh native/OS collection. |
## Original-matched diagnostic choices
`BASELINE.txt` §9.3 names reception/checkout in the lobby; current
`data/facilities/reception.tres` is FRONT 4×2, cost read directly from the
definition. §10.1 explicitly gives standard room 2×1 FRONT; current
`standard_room.tres` matches and is used for unsupported-placement rejection.
§8.4 names stairs; current `infrastructure/guest_stairs.tres` and
`tests/transport/test_runtime_stairs.gd` expose ordinary two-floor stair
construction and `STAIR_LANDING_MISSING` / `STAIR_LANDING_IN_USE`.
All three IDs are in Main's existing normal palette and Runtime registry.
These choices establish this diagnostic slice, never all30 acceptance.
The handler fixture computes any diagnostic resource top-up from the four
planned positive construction definitions. It emits an initial formal save
and a budget report explicitly tagged diagnostic. No production costs,
services, balance values or definitions are changed. New art is unnecessary;
the demolition button reuses Main's existing styling and audio.
## r01 fixture repair (retained earlier submission)
The only failure authorities used are `NATIVE_R01_FAILURE_AND_SCOPE.json`
and `native-r01-writer-stderr.log`. The r01 writer failed 13 expectations;
its full SaveService return Dictionaries were not captured and remain absent.
No past Dictionary was reconstructed and no historical raw evidence was edited.
The handler now changes a toggle button's pressed state, emitting the real
production `toggled` connection before `pressed`. Repeated `choose(id)` leaves
an already selected ID active. Production wiring is unchanged.
Initial and normal saves use private `user://saves/p08_initial` and
`user://saves/manual_ui`; separate handler readers SHA-copy the exported input
into their own private profile before normal-menu load. The initial diagnostic
package seeds the normal slot, so the actual normal save creates its backup.
Exports retain all four members, the backup, and verbatim manifest slot
metadata with SHA/byte lengths and actual paths. An absent initial backup is
explicitly recorded. Every observed Runtime save/load result and direct
SaveService diagnostic return is recorded as typed JSON and SHA-pinned raw
Variant, with PID, requested/absolute paths and user-data directory.
The earlier 35 local checker tests remain synthetic controls. Their negative cases
also cover missing backup members, slot metadata SHA, failed actual returns,
and saves outside private profiles. The mock collector supplies a controlled
disk-space input; the production disk-admission gate is unchanged.
Current native/OS/full regression/review/integration remain pending.
## r02 whole-model operation repair (retained earlier submission)
The retained submitted HEAD is `c2b59f04f94dda0a61991ec3bb7f0e946196f995`.
`NATIVE_R02_READER_OPERATION_DELTA.json` and `native-r02-reader-stderr.log`
are supplied historical evidence: reader PID 58430 failed the old whole
postsave/postload equality assertion. Their observed 161/162 counts are
diagnostic observations, never constants in the checker or scenario.
The fixture captures the complete writer model immediately before the normal
save, leaves `writer-checkpoint.var` as the complete postsave snapshot, and
uses `SaveService.inspect_snapshot` to decode the formal world read-only.
Both writer and reader retain inspection returned Dictionaries and complete
typed/raw formal models. The presave and formal models must match in full;
the reader formal model must match the writer formal model in full.
For each role, the expected complete model starts from that formal model.
Only one `source_defined_notification` is constructed using Runtime lines
4680–4720, `StableIdGenerator.next_id`, `SimulationDomainEvent.to_dictionary`
and `DomainEventStream.publish/create_snapshot`. The payload is recomputed
from the actual returned Dictionary, including optional selected/manifest
fields and all timing fields. Event envelope, next ID, counter increment,
sorted published IDs, existing history and the source's recent-event limit
are derived independently. No fields or Runtime effects are removed,
normalized away or copied from the observed notification as an expectation.
The complete typed expectation and raw expected Variant must match the
complete postsave/postload checkpoint. Read-only inspection must also leave
the whole live model unchanged.
Each role exports `*-expected-operation`, `*-operation-actual` and
`*-operation-comparison.json` alongside unchanged-format raw checkpoints,
formal models and returned-result records. On unknown drift, these complete
raw inputs remain and the checker reports the precise typed difference paths.
No new native difference was observed by this worker; fresh native execution
is pending, so the supplied R02 trace is not a PASS for these changed sources.
The current Python suite retains all 35 earlier tests and adds 14 semantic
tests, including every notification payload/envelope field, type drift,
counter/published-ID errors, extra or rewritten history, unrelated/unknown
model drift, read-only formal mismatch and a non-trace-derived count with
the source's history-limit behavior. These are synthetic controls only.
Exact executed source/input SHAs and the current 49-test result are recorded
in `local-validation.json` and `implementation.json`.
## Evidence boundary
`placement.gd` contains the shared finite scenario and handler endpoints.
`passive_placement.gd` overrides **all** input/setup/progression endpoints:
button, reveal, click, wheel, load_menu, complete_build, setup,
diagnostic_budget, save_initial_fixture, archive_formal. Its reachable
scenario neither calls product handlers nor emits their signals, advances
the clock, submits commands, resets Runtime or restores models. It reads
snapshots/reports and archives evidence. Root performs all OS gameplay.
Constructing/freeing the Main scene uses the existing ordinary cleanup helper.
The passive executable has a separate completion line. Only the handler UI
suite adds one entry to the strict marker contract and one source-pinned
ordinary cleanup policy. All previous marker/policy entries are retained.
The native OS collector never routes its process through the headless gate.
Checker controls are synthetic, including fabricated engine, PID, typed-byte
stand-ins, screenshots and weak-reference records. A positive local test
validates the checker, not the game or OS. Controller tests replace Popen,
engine probes, profiles and owner gate with mocks and launch no engine.
See `local-validation.json` and `implementation.json` for the actual final
executed source/input hashes and results.
## Still required from Root / independent review
Freeze a clean exact candidate; collect guarded native handler and real CUA
OS writer/reader evidence; run verify-only against that candidate; perform
impact checks and final full regression after related sources are frozen;
obtain independent Opus review of all five conditions; integrate and verify
the current final source, then update the authoritative ledger.
No reused P08-02 PASS is claimed for changed sources. P08-01 and the whole
P08 package remain open. Windows same-distribution/device evidence remains
open; Mac/Linux results cannot substitute for it. No outside-scope service
defect or required permission change has been demonstrated by this worker.
## r04 initial OS load oracle repair (retained earlier submission)
The supplied OS_R04_INITIAL_LOAD_ORACLE_FINDING.json and
os-r04-writer-engine.log identify the bootstrap-only simple equality failure.
The registered build contains 2153 files; its complete read-only inventory is
recorded in registered-r04-evidence-manifest.json. Historical raw/PASS evidence
is unchanged and no changed-source acceptance is inherited.
Passive setup now uses the existing verify_operation oracle with bootstrap-
prefix. Complete typed JSON and raw Variant formal, checkpoint (postload),
returned Dictionary, expected-operation and operation-actual files, plus a
separate comparison JSON, remain distinct from writer/reader final proofs.
The same source-defined notification logic checks all state, previous events,
next event ID/counter and every payload field; no event masking or omissions.
The checker binds bootstrap formal/returned models to the recorded read-only
inspection and first Runtime return, reconstructs the expectation and checks
whole typed state and raw expected/actual identity.
Static inspection within the allowed fixture/recorder scope found no other
postload-versus-formal simple equality oracle. Remaining exact comparisons
check presave/formal identity or read-only preservation and are intentional.
Seven added semantic controls cover missing/extra notifications, counter,
payload and unknown-field drift, missing raw and overwritten bootstrap raw;
all 49 earlier tests remain. Final actual results and exact source/input
hashes are recorded in local-validation.json and local-source-manifest.json.
Only pure Python validation uses the ordinary 900-second subprocess timeout.
Root native/OS collection for this candidate, final full regression after
freeze, separate Opus review and integration/current final verification remain
open. All five conditions and the 30/88 denominator are unchanged. No Runtime,
UI, SaveService, collector, specification or historical evidence edits.
## R05 consolidated repair (historical submission)
The supplied ROOT_CHECKER_R05_INFRASTRUCTURE_ORACLE.json and
ROOT_OS_R05_GUIDE_INTERCEPTION.json are failure authorities, not acceptance.
The original failed OS request and all supplied raw files remain untouched.
The complete gzipped reader checkpoint is copied byte-for-byte into the fixture
suite with its provenance. Tests verify the decompressed 2120352 bytes and
SHA `304d97de8051d5e74c6e32c4482a3cb183b0172d7671088fdc40469cc3448c0d`.
It is actual native input from candidate 4a17d0e0f589fa76d81f1d4630ec45c63bac21ab,
not proof of acceptance for the changed candidate.
Runtime _on_facility_completed and FacilityInfrastructureProjector define the
split: ordinary construction instances require operational membership; supported
schema proxies require exact infrastructure membership. The checker preserves
completed-job, occupation, demolition and refusal invariants, and now checks
projection identity/cells/definition/fingerprint, managed ROUTE and connector
membership, exact stair connector fields and lower landing, and projected
walkable/path topology. Actual checkpoint corruption tests exercise missing,
extra and incorrect topology, ordinary facility loss and proxy occupation loss.
Whole-checker synthetic controls now represent stairs in the infrastructure
projector and retain every earlier test.
The handler unsupported target is (4,4,0). The passive observer independently
chooses a visible cell with the unchanged UNSUPPORTED predicate outside the
opening guide rectangle after normal palette selection. It reads bounds,
preview and guide geometry; it does not suppress the guide or mutate models.
Cell requests include viewport-to-screen affine mapping derived from existing
Godot transforms and current guide geometry. The engine matrix is separate
from physical stretch and screenshot/window translation (R06 correction). The checker recomputes the mapping and rejects guide interception.
Root must retain actual CUA coordinates, screenshots and raw receipts and check
the mapping against the real window; no OS success is claimed by this worker.
Bootstrap repair, all five facets, product UI and driver progress are preserved.
Python syntax/checker execution and exact source/input manifests are recorded in
local-validation.json and implementation.json. Godot parsing, fresh native and
OS collection, final full regression, independent review, integration/current
verification and Windows device evidence remain pending. No context gap or
outside-scope service defect has been demonstrated in this batch.
## R06 targeted repair (preserved repair)
Only the OS per-child total wait changes from 900 to 2400 seconds, with
truthful start/end receipt provenance. Per-request 300, provider 900, validation
180 and every source/acceptance guard remain unchanged. Product and fixtures
are unchanged. Historical R06 native passes do not establish changed-source PASS.
R06 calibration correction (ROOT_NATIVE_R06_OS_TIMEOUT.json): the engine
viewport_to_screen affine matrix [a,b,c,d,tx,ty] maps viewport (x,y) to
(a*x+c*y+tx, b*x+d*y+ty) in engine coordinates. It reports identity in the
real window and does not include physical stretch or the screenshot titlebar.
Keep 1440x810 virtual coordinates separate from 1280x720 window content and
1280x752 screenshot coordinates. For this measured window, apply scale 8/9
(approximately 0.8889), then add 32 pixels to screenshot y for the titlebar.
For modal controls, first apply the dialog offset reported by Godot, then
physical stretch and titlebar. Desktop CUA coordinates additionally require
the observed screenshot/window origin. Retain actual CUA coordinates, raw
screenshots and window geometry; recalibrate whenever geometry changes.
guide_rect remains in viewport coordinates. Preserve historical failed
evidence: R06 request 33 was unacknowledged after PID 17863 ended and cannot
count as evidence. Fresh guarded native/OS collection, full regression,
independent review and integration remain pending.
Historical R06 local validation: syntax passed; 75 checker tests ran with one failure.
The existing OS mock expects 900 rather than 2400. Blocked pending authority
to update only that mock expectation in tools/test_p08_normal_placement_evidence.py
and rerun local checks. No test was disabled or changed.
## R06 authorized mock synchronization (current submission)
The independent literal expected2400 is asserted against the driver constant,
actual wait argument and actual started/ended receipts for both writer and
reader. The timeout case also checks its writer receipts and preserves owned
child cleanup, project restoration and existing protection controls. All 75
checker tests are retained. Final local syntax/test results and exact source
and input SHAs are recorded in local-validation.json, local-source-manifest.json
and implementation.json. These are mocked Python controls, not native or OS
acceptance. Root native, OS, final full regression, independent review and
integration/current verification remain pending, including Windows device
acceptance. Existing driver2400, calibration and earlier repair work is retained.
## R07 actual-input observer repair (current submission)
Authority: ROOT_OS_R07_SELECTED_CELL_READBACK.json and its supplied raw writer
actions/observations and screenshot. These historical failures remain unchanged:
writer exit1, reader not started, and request64 is not current acceptance proof.
The five condition records and acceptance denominator remain unchanged.
The passive read-only observer captures left-press viewport coordinates in
_input before GUI side effects, inverse local coordinates, the actual converted
world cell, bounds, cell dimensions, map origin, pan/zoom and both affine
transforms. It also records the prior selection/occupant as separate dispatch
fields. The action records the post-input selected entity and cell occupant
separately. Later mouse-getter reads remain diagnostic only. The checker binds
the action to the actual pressed event, independently recomputes its cell and
transforms, and checks camera selection against complete-model occupancy.
Requested center pixels remain distinct from actual event pixels; a press
elsewhere within the same cell is valid.
All old tests remain; new whole-checker semantic controls cover missing dispatch,
wrong actual cell, mismatched event coordinates, transform drift, wrong selected
entity/occupancy and bypassed selection. A positive control demonstrates that
a later diagnostic getter cannot change acceptance. Final syntax, test counts
and source/input hashes are recorded in repair-r07-local-validation.json and
repair-r07-local-source-manifest.json, referenced by implementation.json.
No product changes, Godot/native/OS/full regression, git writes, Runner actions
or integration were performed by this worker. Driver receipt values remain
2400 seconds and all timeout cleanup guards remain. Root must collect actual
native and OS evidence on the final candidate, perform verify-only and final
full regression, then obtain a separate independent review of all five facets.
Any proposed historical reuse requires exact source/input applicability and
independent review; no changed-source PASS is inherited here.
## Repair10 facility-only palette (current submission)
R07 candidate 1f0a2bcd failed test_main_dashboard.gd:132 after 147 suites passed;
this historical run stopped strictly and is not final full-175 acceptance.
ROOT_FULL_R07_* and ROOT_FULL_REGRESSION_R07_* raw proof files remain unchanged.
BuildPalette now contains only the 23 registered facility buttons, with 23
columns. A single HBox is the scroll content; DemolitionButton is its sibling.
The new semantic suite checks every facility membership, scroll/HBox topology,
ordinary opening and scroll reachability. Existing operation/cleanup checks and
the one strict completion marker are retained. No Runtime/domain/assets changes.
Exact current source and input hashes are in repair10-local-source-manifest.json
and implementation.json; actual Python results are in repair10-local-validation.json.
These local controls establish no Godot or OS acceptance. Root must first rerun
test_main_dashboard and test_p08_normal_placement_ops natively, then freeze the
final candidate for native writer/reader, real OS collection, verify-only and
full-175 regression, followed by separate Opus review and integration/current
verification/ledger. All five facets remain pending. Windows device acceptance
remains open. All repair/inference/material caps stay null. No git writes,
Runner operations, agents, integration or engine runs by the worker.
Final repair10 SHA-256 pins (local controls only):
- `scenes/main/main.gd`: `36316f9edc170ba965eb2f595a740ae7fcc8914e4090f0351c0cec181d6a7431`
- `tests/ui/test_p08_normal_placement_ops.gd`: `d3c246d34f8fd66f6ed237e42a86df89ebaf481bc9dee143b4de8d654ce0eb2e`
- `tests/fixtures/p08-03/placement.gd`: `1ebaaa80784905d661954e255bfb8a96a3a963a57b9a38b19e7f91b90fb628b3`
- `docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json`: `9eab2b529e11d00bb00a415f29135b5fe7d8df2a282564ecc37292c8bda64010`
- `tools/regression/suite-policy.json`: `a74dc701155b6207bc23095296d723928f62719fce14fda392b12f9947007fb1`
- Complete source/input manifest: `9f3e7ddb8cecf53d668dd4556f504e4fba26b29fb81dfe4b583ab060c6e6a9c8`
- Final local validation: `ef88dee24a9796600d6d90c6a0ae563c8d06f039231dae6db01d1f96ede2055b` (83 checker tests / 0 failures; four Python syntax checks passed).
## Repair11 nullable RefCounted observer (current submission)
R08 writer PID 75240 failed before the initial manual load; its real palette click and raw failure proof are retained as historical diagnostics only. InputObserver.endpoint now accepts the RefCounted passive recorder and retains its null guard. Modal observers explicitly keep endpoint null, record null_modal_receipts_only in observed.json, queue_free and restore the root observer. No modal cell dispatch or product handler calls were added. Both placement fixtures were reread for typed assignments; no further Node/RefCounted mismatch was found by local inspection. Godot parsing remains pending.
Final source/input pins are in repair11-local-source-manifest.json and implementation.json. Only passive_placement.gd and the Python test source changed since Repair10. The passive fixture input SHA change invalidates native/OS evidence whose input map includes it; recollect the full5 set. R08 palette/UI4 proof is retained and may be reused only after exact actual source/input/engine/marker applicability checks; no blanket inherited PASS.
Root order: actual native startup with initial manual menu load, profile JSON and no SCRIPT ERROR; then full5 native/OS writer and reader with distinct PIDs; then mandatory frozen full175 regression. Separate Opus review, integration/current verification/ledger and Windows platform acceptance remain pending. All five conditions remain unaccepted. No Godot, native, full regression, git writes, Runner operations or agents were performed by this worker. Local Python syntax and checker results are recorded in repair11-local-validation.json.
Repair11 final pins and local results:
- passive_placement.gd: `cdbd9a09b535d00a79aec7e2b7219f4daa4cf235449602b3cd02c6f12d9df88c`
- test_p08_normal_placement_evidence.py: `b8189b2b4bf15933d7e3e760495928b6a5a7ec5b0400a1c5198427d1cb0a3408`
- Complete source/input manifest: `0d33515d9ef33656fe13aab3f417a18a2b602047d6eb013b3f6b896f0330edf6`
- Local validation: `188d61cb4e23211646cc9808bfb924bc56fe66f1fb7ef0534584740dcfcd9561`; 88 tests, 0 failures; four syntax checks passed. These controls establish no gameplay acceptance.
## Repair13 final executed local pins
Final execution: 100 Python tests, 0 failures; 3 syntax checks passed.
Actual R09 --verify-only: integrity pass, acceptance pending.
- tools/check_p08_normal_placement_evidence.py: 73bff1e00c319b8e681953fe64497eefb53ece168d2d18e0b60951e65f66279d
- tools/test_p08_normal_placement_evidence.py: 7e708a4429603166485b6f3267d887561d23bcf25b564d002473094e388476ca
- tests/fixtures/p08-03/repair13_images.py: 248a8d73ece3a60e601421fdd2ad53f8f8e971184fb1328c7155a71b8ed4ca53
- repair13-local-validation.json: f249c76c6d4c044c1a3c33ea09abc99f09a8c0ea6b0ade470d2af205eb4d89af
- repair13-local-source-manifest.json: 7d5a62155b7053398a5bc55879c9a92a07dcb3c5a0603e92d6f38eefba122ca1
## Repair17 revision 2 — submitted, no acceptance claimed
History above and all R09 evidence/pins remain historical and unrewritten.
(1) support_connection is NOT satisfied: blocked pending Root reconciliation and application of runtime-preview-proposal/runtime_preview.patch. See proposal for the additional Main display premise gap.
(2)–(5) are not verified. The earlier reviewer raw-proof read refusal remains historical. The reviewer now has the permitted task build via --add-dir (while --restricted, Read/Grep/Glob and outer sandbox remain); future independent checking with raw-proof access is required.
Native/OS proof for changed demolition status and support display is invalidated. Root must recollect after all product fixes, including the reconciled Runtime proposal, are combined. No applicability or acceptance is claimed.
Limits for repair, inference and material remain null. No 500k compression; low findings (empty cell, audio, idempotency, English Runtime messages) remain deferred. Denominator remains one existing unit among 30 packages / 88 units, no partial credit.
New HEAD: to be bound by Runner. No worker commit or branch change.
Validation: 128 Python tests passed (85.953s, exit0) after one targeted-test correction; py_compile passed with an in-scope cache directory after default-cache PermissionError; JSON load and git apply --check passed. placement.gd and proposed GDScript test are not run. Placement fixture requires Root's complete applied fix.
Pending:
- Root reconciliation and application of Runtime preview patch (including Main display premise gap)
- Root native/OS recollection for changed demolition and support UI after all fixes are combined
- Root final full175
- Independent Opus review of all 5 conditions with raw-proof access
- Integration / current final verification / ledger
- Windows same-distribution/device (no Mac substitution)
Net committed diff, from git diff --name-status --no-renames 31aa7706d28a92e313c432d5a62e35d19503dcc3 HEAD:
```text
M docs/plans/original-completion-2026-10-02/execution/p08-03/CONDITION_MATRIX.md
A docs/plans/original-completion-2026-10-02/execution/p08-03/REPAIR12_CONTEXT_GAP.md
A docs/plans/original-completion-2026-10-02/execution/p08-03/ROOT_NATIVE_R09_COLLECTION_PINS.json
A docs/plans/original-completion-2026-10-02/execution/p08-03/ROOT_R09_COLLECTION_AND_PUBLICATION_DIAGNOSIS.json
A docs/plans/original-completion-2026-10-02/execution/p08-03/ROOT_R09_READONLY_IMAGE_DIMENSIONS.json
M docs/plans/original-completion-2026-10-02/execution/p08-03/implementation.json
A docs/plans/original-completion-2026-10-02/execution/p08-03/repair13-local-source-manifest.json
A docs/plans/original-completion-2026-10-02/execution/p08-03/repair13-local-validation.json
M tools/check_p08_normal_placement_evidence.py
M tools/test_p08_normal_placement_evidence.py
```
Working changes (plus new proposal files):
```text
M docs/plans/original-completion-2026-10-02/execution/p08-03/CONDITION_MATRIX.md
M docs/plans/original-completion-2026-10-02/execution/p08-03/implementation.json
M scenes/main/main.gd
M tests/fixtures/p08-03/checker_fixture.py
M tests/fixtures/p08-03/placement.gd
M tools/check_p08_normal_placement_evidence.py
M tools/test_p08_normal_placement_evidence.py
A docs/plans/original-completion-2026-10-02/execution/p08-03/runtime-preview-proposal/RUNTIME_PREVIEW_PROPOSAL.md
A docs/plans/original-completion-2026-10-02/execution/p08-03/runtime-preview-proposal/runtime_preview.patch
```
Exact validation commands and initial/retry results are recorded in implementation.json repair17.validation. No Godot/native/full execution or recollection was performed.
## Repair19 — submitted, no acceptance
Input M: fd643f55a271e63c554b94681454d357117c0678. Verify-only failure:
8ee0765cdd0a438dbf0ddc0f67ebbc70. New HEAD: **to be bound by Runner**.
The R15 diagnosis was an unverified palette reveal followed by a possibly clipped
button click; deferred quit also allowed requests and secondary failures after
an ACK timeout or identity/hash failure. The Root31 ACK is invalid. R15 earns no
credit. No acceptance or changed-source evidence reuse is claimed.
Repair19 changes only the passive endpoint, additive checker gates, synthetic
positive/negative specimens and these handoff records. Repair18 and all R09 pins
remain history without rewriting. Runtime, product UI, the ACK deadline, spec,
scope and denominator remain unchanged.
### Source-map applicability
The four changed executable/source inputs and their SHA256 at M and in the
worktree are listed in implementation.json `repair19.source_map`. The two changed
handoff documents are also listed there at M; their final byte SHA256 are reported
with submission, outside the documents to avoid a self-referential hash.
Read-only rg and preload/load tracing found these consumers:
- docs recorder `passive_os_placement_recorder.gd:2` preloads passive_placement.gd,
which extends placement.gd. Its `run` drives the writer/reader OS pair.
- `tests/ui/test_p08_normal_placement_ops.gd:2` preloads placement.gd directly.
That parent is unchanged by repair19; it loads main.tscn and the existing codec
and audio cleanup helpers. The passive subclass is not loaded by this UI suite.
- `tools/run_p08_normal_placement.py:145,210,227` loads the checker for initial
input fingerprinting, OS input mapping and final evidence verification. Its
import/parse stages precede handler writer/reader stages using the UI suite,
and its OS stage uses the docs recorder.
- `tools/test_p08_normal_placement_evidence.py:28-30,55-56` loads the checker,
checker_fixture.py and collector, and reads both GDScript fixture sources.
- `tools/run_all_tests.py:roster` discovers the UI suite; `source_refs` includes
tests and tools in the whole-source fingerprint. Import/parse/native and final
regression applicability therefore requires the actual complete fingerprint.
The checker also imports the prior typed codec and standard runner directly.
Every OS/native collection and regression whose inputs include a changed file
is not applicable and must rerun on the final frozen revision: the complete
p08-normal-placement OS/native pair, checker tests, the UI suite when its actual
input fingerprint includes a changed fixture, and exactly one final all-suite
regression on the roster Root derives at the final revision. No roster count is
assumed. A prior native/import stage may be reused only on an exact fingerprint
match; no reuse is claimed where source changed. The UI suite is included in the
fresh pair and final roster regardless of its unchanged direct parent fixture.
Neither completion_marker_contracts.json nor suite-policy.json changed: no pinned
print line, suite source SHA or cleanup policy changed in repair19.
Still pending: Root first inspects normal scrollbar operation in a short disposable
diagnostic, then freezes source and runs a fresh contiguous long OS/native attempt;
exactly one final all-suite regression on the derived roster; independent Opus
review of all five conditions with raw-proof access; integration, current final
verification and ledger. Windows same-distribution/device remains open with no
Mac substitution. Local command outcomes are recorded in implementation.json.
## Repair18 — submitted, no acceptance
7297a4c050f0293df331c2c51bb32def248bcb6b
['4775001', '127f22f']
dbf5cb8 / native source 12f04d6; target/stairs/construction/pointer passes; 8 unchanged state pairs; Opus pass; final-validation pass (historical support trace, no current applicability claimed)
Every path in diff(M..worktree) must be inside allowed_paths; every path outside allowed_paths must equal its blob at 127f22f. Inherited Runtime is read-only.
runtime_preview.patch was superseded by the integrated helper and was not applied; retained as history.
to be bound by Runner
(1) pending Root native/OS; (2)-(5) remain pending
not claimed
['Root freeze then normal OS and native recollection including changed preview and demolition UI', 'exactly one final all-suite regression on roster derived by Root', 'independent Opus review of all 5 conditions with raw-proof access', 'integration, current final verification and ledger', 'Windows same-distribution/device open; no Mac substitution']
R09 history and pins remain unrewritten. Low findings (empty cell, audio, idempotency, English Runtime messages) remain deferred.
Repair18 local validation: python3 -B tools/test_p08_normal_placement_evidence.py ran 131 tests in 88.476s, exit 1: one existing R09 raw-proof read PermissionError; no weakening. py_compile initially failed on default cache permissions, then passed with PYTHONPYCACHEPREFIX inside allowed fixture scratch. JSON load and git diff --check passed. Scope adapter passed including boundary equality. Exact commands and source SHA256 are in implementation.json repair18. Root/Runner raw-proof access remains required.
## Repair20 — submitted candidate
Frozen input f5f85ae08c1c6c9c1ec511f13a7215170d7d8d49; registered validate failure f2d59df6a3c34c0e93b15b1a05cfa533. Historical pins selected the R09 route for fresh proof; the checker now selects from the explicit index commit, retaining R09 applicability and fresh HEAD/source/input checks. Both routes bind screenshot paths to the request; fresh proof uses strict PNG/JPEG magic dispatch and equal positive dimensions. Historical R09 pins, dimensions and runtime_preview.patch remain unchanged.
Root full176 was interrupted after 13 PASS, at phase013, guards 0: an interruption, not a product defect and not acceptance. No OS collection was started. New HEAD: to be bound by Runner. Conditions (1)-(5) remain pending Root native/OS.
Pending: Root exact-final local/native/checker applicability; one complete final full regression on the derived roster; fresh contiguous all-5 normal OS plus native collection; independent Opus review of all five conditions; integration/current final verification/ledger; Windows same-distribution/device, with no Mac substitution.
Local verification: final Python rerun 153 tests / 127.709s, 152 passed, one existing R09 original raw-proof PermissionError (exit 1); all 11 repair20 cases passed. py_compile failed on default external cache permission (exit 1). JSON load, diff whitespace and scope self-check passed. No test skipped or weakened; Root must rerun with required evidence/cache access.
@@ -0,0 +1,50 @@
# Repair12 recorded direction: context gap
Status: blocked; no checker implementation submitted. Inspected checkout HEAD
`31aa7706d28a92e313c432d5a62e35d19503dcc3`. Contract base remains
`12430ba89970bda349781e51157e72e48a4ac06f`.
The instruction requires JPEG SOF dimensions to match recorded before/after
dimensions. The available canonical R09 collection has 69 request.json,
69 ack.json and 69 input-receipt.json files. None contains recorded screenshot
before/after dimensions. The two indexed root-cua-ack-controller Python sources
also write no such dimensions. The concrete example
`os-pair/writer-request-0058/screen-before.png` has JPEG SOF dimensions
1280 x 752; its request.json records window_size 1280 x 720. Window size
therefore cannot substitute for screenshot dimensions. Extracting both sides
of a comparison from the same JPEG would not independently bind dimension drift.
Required context: identify and provide the existing, attributable R09 record
of before/after screenshot dimensions and its relationship to these 138 image
files. Do not invent records or change originalR09. If no such record exists,
the owner must resolve this requirement explicitly; the worker cannot silently
replace it with SOF self-consistency or window dimensions.
Original root access returned `Operation not permitted`:
`/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09`.
The canonical copy was readable at
`/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/.runtime/P08-03/build/p08-normal-placement-evidence`.
Original/canonical byte equality was consequently not established by this worker.
No security settings were changed. Pillow is unavailable in the worker's Python.
Read-only Python inspection established:
- All 753 files listed in the canonical index match their indexed size and
recomputed SHA256. This is an indexed-byte audit, not a complete file-set gate
or acceptance result.
- Every current source_map member and input member matches the R09 index,
including product source, fixtures, controller, recorder, marker contract,
spec and inputs. The engine binary matches runner-input.json's engine SHA256.
- os-proof.json names `os-runs/writer/ended.json` and
`os-runs/reader/ended.json`. Recorded owner control paths use
ORIGINAL_ROOT/os-runs/{writer,reader}/teardown/control.json.
The original absolute varbytes pin must remain enforced.
Only this scoped document was added. Checker, tests, product and evidence bytes
were not edited. No tests, native engine, OS replay, regression, git writes,
Runner operations or agents were run. These inspections are not JPEG validity
checks and are not sufficient for acceptance.
All requested validator repairs and negative tests remain pending. Root's final
full175, R09 re-check, independent Opus review and integration remain required.
Preview/domain-status disagreement and Windows same-distribution remain open.
@@ -0,0 +1,23 @@
{
"unit": "P08-03",
"candidate": "4a17d0e0f589fa76d81f1d4630ec45c63bac21ab",
"registered_validation": "89dfca90b9d64eb780460589144837ee-validation.json",
"actual_deficits": [
"partial demolition/completion"
],
"cause_evidence": {
"checker": "tools/check_p08_normal_placement_evidence.py:173 unconditionally requires construction facility IDs == FacilityService operational IDs",
"raw_snapshot": "pair/reader-checkpoint.json",
"construction_only_ids": [
"facility_00000002",
"facility_00000003"
],
"definitions": [
"guest_stairs",
"guest_stairs"
],
"runtime_source": "autoload/simulation_runtime.gd:10682-10720 separates supported schema proxies into infrastructure projector and ordinary facilities into operational service"
},
"requested_action": "Verify current intended proxy projection contract from source, then make checker faithfully require operational membership for ordinary definitions and exact projected topology for supported infrastructure proxies. Do not simply skip stairs or drop occupancy/loss/demolition invariants. Add real-snapshot and missing/extra/wrong projected topology negative tests. Same targeted fixture repair batch; no product scope expansion.",
"formal_acceptance": false
}
@@ -0,0 +1,145 @@
# Root collection protocol (not executed by worker)
R02 repair requires a fresh exact-source collection. The supplied R02 reader
failure is historical evidence, not a PASS for the repaired candidate.
Keep every raw postsave/postload snapshot and returned Dictionary. In each
handler and OS pair the shared fixture now also emits writer-presave,
writer/reader-formal-model, expected-operation, operation-actual and
operation-comparison artifacts. Formal models come from the read-only normal
`SaveService.inspect_snapshot` API. `writer-checkpoint.var` remains the raw
postsave state; never replace it with the presave/formal model.
The checker reconstructs one source-defined notification from each actual
returned Dictionary and compares the complete expected typed/raw model.
Counts come from the saved model, not the historical 161/162 trace. Preserve
all artifacts on an unknown difference and record the checker difference
paths with the corresponding actual/expected files before another repair.
The collector and Runtime/SaveService/UI remain unchanged in this repair.
Read the fixed spec and condition matrix first. Freeze/commit through the
authorized Root workflow. The worker has not committed or run this procedure.
Use a clean checkout at the exact submitted HEAD, an installed native Godot,
and a new output directory **outside** the source checkout:
```sh
python3 tools/run_p08_normal_placement.py --collect \
--project-root /absolute/frozen/checkout \
--output /absolute/build/p08-normal-placement-evidence \
--commit EXACT_FROZEN_HEAD --godot /absolute/Godot \
--input-mode native_os
BUILD_OUTPUT_DIR=/absolute/build python3 tools/check_p08_normal_placement_evidence.py \
--verify-only --project-root /absolute/frozen/checkout
```
`--input-mode handler` collects only the strict headless pair. Its index has
no OS proof and intentionally cannot pass the whole checker. `native_os`
first collects that same headless pair, then separately starts the passive
nonheadless writer/reader. Import and handler phases use unchanged
`execute_phase` guards, markers, owner/audio proof. OS phases reuse the
P08-02 `collect_native_os.py` / passive recorder protocol, read-only as reuse
sources, with P08-03 arguments and paths; no new OS automation framework.
Before native launch the controller checks live engines, exact HEAD, clean
checkout, copied source inventory, disk admission and default player.
Each OS role gets a UUID private profile. Writer receives the handler's
`pair/initial-formal`; reader receives the OS writer's `os-pair/formal`.
All four formal members are copied and SHA-checked. The staged project gets
only private-profile settings and is restored in finally. Only captured
Popen children are cleaned by `owned_outer.finish_captured`.
The repaired handler also saves only inside its private `user://` profile,
then exports `initial-formal` and `formal` to the evidence directory.
`formal.bak`, `*-slot-metadata.json` (verbatim manifest), and `*-export.json`
retain backup/metadata bytes, source paths and SHA pins. Initial backup absence
is recorded explicitly. Each role's `*-save-results.json` references actual
typed result JSON and SHA-pinned raw Variant files, including failed returns.
Inspect the full returned dictionaries and paths on the next native run.
The r01 dictionaries were never captured; do not reconstruct them or append
new results to the historical r01 raw evidence.
Actual argv is `[engine, --path, stage, --script, passive_os.gd]`, with no
headless flag or headless proof gate. `started.json`, `process-started.json`,
`ended.json`, raw engine log, actual profile/engine report, source/stage/default
player inventories and ordinary owner/audio records remain in the evidence.
Controller and recorder SHA appear in start/end documents. Each OS child
has a 2400-second total wait recorded as timeout_seconds in start/end receipts,
using the same value passed to process.wait. Each acknowledgement retains its
300-second bound; provider 900 and validation 180 remain unchanged.
Timeout/error preserves failure records and cleans only owned children.
## CUA request / read-only acknowledgement bridge
The collector prints `waiting_for_root_cua`; the recorder prints each exact
request filename and writes:
`os-pair/{writer|reader}-request-NNNN/request.json`.
It contains PID, sequence, action, target window, instructions and applicable
expected world cell, transformed viewport/screen coordinate, window/screen
scale. The recorder waits; it never clicks or changes Accessibility settings.
Root uses its existing CUA tool on the indicated PID/window. A request may
ask for normal palette scrolling, a button/cell click, ordinary non-Ctrl
wheel, normal manual load, or normal play/speed/pause until construction
finishes. Modal buttons include their own window ID and screen transform.
If a cell is clipped, the recorder first asks for ordinary zoom-out framing,
then recomputes coordinates. Do not substitute old pixels or injected input.
Capture real CUA screenshots before and after each request. Retain the raw
CUA result and tool-call identity; never manufacture a receipt to advance.
Root writes its own receipt file within the evidence directory. The bridge
envelope references that raw tool call and records:
```json
{
"method": "native_os",
"target_pid": 123,
"timestamp_ns": 123456789,
"collector_pid": 456,
"tool_name": "actual CUA tool name",
"tool_call_id": "actual tool call identity",
"events": [{"type": "actual input event", "raw_receipt": "retained raw CUA result"}]
}
```
After completing the requested operation, Root writes `ack.json` beside
the request. All artifact references are relative to the evidence root:
```json
{
"target_pid": 123,
"sequence": 1,
"request_sha256": "actual request file SHA-256",
"input_receipt": "root-receipts/writer-0001.json",
"screen_before": "root-receipts/writer-0001-before.png",
"screen_after": "root-receipts/writer-0001-after.png"
}
```
These numbers/strings are format examples, never evidence. Recorder and
controller only **read** Root's acknowledgement/receipt files. The recorder
separately retains actual Godot input observations and world selection,
whole typed/Variant snapshots, displayed reasons and Runtime results.
The checker verifies request/ack hash and sequence/PID binding, raw input
presence, PNG structure/CRC, affine coordinate conversions, formal members,
model invariants, distinct processes, native lifecycle and real owner proof.
Independent review must match tool-call identities/raw CUA results and actual
screenshots; an integrity checker is not an OS attestation authority.
Keep final requests (including save/load) as well as row-specific requests.
Do not edit evidence after collection to force a pass. Correct source/input
defects through the fixed repair workflow. GDScript parsing, actual native
and OS success, full regression, review and integration are all pending.
R06 calibration correction (ROOT_NATIVE_R06_OS_TIMEOUT.json): the engine
viewport_to_screen affine matrix [a,b,c,d,tx,ty] maps viewport (x,y) to
(a*x+c*y+tx, b*x+d*y+ty) in engine coordinates. It reports identity in the
real window and does not include physical stretch or the screenshot titlebar.
Keep 1440x810 virtual coordinates separate from 1280x720 window content and
1280x752 screenshot coordinates. For this measured window, apply scale 8/9
(approximately 0.8889), then add 32 pixels to screenshot y for the titlebar.
For modal controls, first apply the dialog offset reported by Godot, then
physical stretch and titlebar. Desktop CUA coordinates additionally require
the observed screenshot/window origin. Retain actual CUA coordinates, raw
screenshots and window geometry; recalibrate whenever geometry changes.
guide_rect remains in viewport coordinates. Preserve historical failed
evidence: R06 request 33 was unacknowledged after PID 17863 ended and cannot
count as evidence. Fresh guarded native/OS collection, full regression,
independent review and integration remain pending.
@@ -0,0 +1,277 @@
{
"phase": "147",
"test": "tests/ui/test_main_dashboard.gd",
"passed": false,
"failed": true,
"validation_error": "AssertionError: native ERROR/FAIL/ObjectDB/resource diagnostics never allowed",
"profile_startup_name": "TheTree-PCK-tests-e5cb56d130e248c3a42d9ee038103767-standard-startup-147",
"private_project_sha256": "c107c8c021eb4d886c580d0e195f8ea4b82d2bef9132c2f40b821174686804f8",
"private_project_fields": 2,
"source_sha256": "fa9ee0c4b9aee00a2be6d05a9dab7c0c3e8b0beb2b944257de1dc308bfc3cc20",
"policy": {
"source_sha256": "fa9ee0c4b9aee00a2be6d05a9dab7c0c3e8b0beb2b944257de1dc308bfc3cc20",
"ordinary_cleanup_prepared": false,
"ordinary_control_labels": [],
"old_bounded_teardown": true,
"new_audio_QA": false,
"path": "tests/ui/test_main_dashboard.gd",
"candidate_source_sha256": "fa9ee0c4b9aee00a2be6d05a9dab7c0c3e8b0beb2b944257de1dc308bfc3cc20"
},
"command": [
"/Applications/Godot.app/Contents/MacOS/Godot",
"--headless",
"--path",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/stage",
"--script",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/starters/147.gd",
"--verbose",
"--log-file",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147/engine-native.log"
],
"logical_script": "res://tests/ui/test_main_dashboard.gd",
"starter_sha256": "d3a7cb6d65c098794b75d54bc3bb572894ba94ebec0746cff4bf0b99b9f332dd",
"controlled_environment": {
"THE_TREE_PACK_PROFILE_NAME": "TheTree-PCK-tests-1e2e00eb89e24067a79af5e3f8fbcc92-standard-runtime-147",
"THE_TREE_PACK_PROFILE_EXPECTED": "/Users/korizatou114/Library/Application Support/TheTree-PCK-tests-1e2e00eb89e24067a79af5e3f8fbcc92-standard-runtime-147",
"THE_TREE_PACK_PROFILE_REPORT": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147-profile.json",
"THE_TREE_FULL_PARSE_PATHS": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/parse-paths.json",
"THE_TREE_AUDIO_TEARDOWN_PROOF_DIR": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147-teardown"
},
"native_process": {
"argv": [
"/Applications/Godot.app/Contents/MacOS/Godot",
"--headless",
"--path",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/stage",
"--script",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/starters/147.gd",
"--verbose",
"--log-file",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147/engine-native.log"
],
"pid": 66967,
"started_utc": "2026-10-13T22:42:29.505015+00:00",
"ended_utc": "2026-10-13T22:42:33.592473+00:00",
"wall_seconds": 4.087419749999981,
"exit_code": 1,
"helper_exit_code": 1,
"timed_out": false,
"stdout_sha256": "aa1c521a68968776506b900e8c4f37fbeb834165ef82ab423eb6403fb29cedb4",
"stderr_sha256": "1f058d97960cd4d1df9f564a65801220987a3dcdd14ea2e6761495be91a23be8",
"error_lines": [
"ERROR: all23 facilities including the cleaning room appear in the build palette",
"ERROR: FAIL: 1 of 169 checks failed"
],
"owned_popen_ended": true,
"old_helper_engine_ended": true,
"start_receipt_written": true,
"end_receipt_written": true,
"lifecycle_error": null,
"old_helper_lifecycle_error": null,
"actual_start_binding": {
"scope": "isolated diagnostic owned child",
"event": "ENGINE_STARTED",
"actual_pid": 66967,
"owner_pid": 55474,
"command": [
"/Applications/Godot.app/Contents/MacOS/Godot",
"--headless",
"--path",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/stage",
"--script",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/starters/147.gd",
"--verbose",
"--log-file",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147/engine-native.log"
],
"monotonic_ns": 1423635909541,
"pid": 66967,
"argv": [
"/Applications/Godot.app/Contents/MacOS/Godot",
"--headless",
"--path",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/stage",
"--script",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/starters/147.gd",
"--verbose",
"--log-file",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147/engine-native.log"
],
"started_utc": "2026-10-13T22:42:29.505015+00:00",
"current_process_identity": {
"pid": 66967,
"ppid": 55474,
"pgid": 66967,
"args": "/Applications/Godot.app/Contents/MacOS/Godot --headless --path /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/stage --script /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/starters/147.gd --verbose --log-file /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147/engine-native.log"
},
"live_identity_exact": true,
"tracked_child_ended_before_initial_probe": false,
"signal_scope": "tracked Popen child only; no external group signal"
},
"actual_end_binding": {
"scope": "isolated diagnostic owned child",
"event": "ENGINE_ENDED",
"actual_pid": 66967,
"owner_pid": 55474,
"command": [
"/Applications/Godot.app/Contents/MacOS/Godot",
"--headless",
"--path",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/stage",
"--script",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/starters/147.gd",
"--verbose",
"--log-file",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147/engine-native.log"
],
"monotonic_ns": 1427715972291,
"exit_code": 1,
"actual_process_exit_code": 1,
"engine_ended": true,
"timed_out": false,
"lifecycle_error": null,
"start_receipt_written": true,
"pid": 66967,
"argv": [
"/Applications/Godot.app/Contents/MacOS/Godot",
"--headless",
"--path",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/stage",
"--script",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/starters/147.gd",
"--verbose",
"--log-file",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147/engine-native.log"
],
"ended_utc": "2026-10-13T22:42:33.587191+00:00",
"signal_scope": "tracked Popen child only; no external group signal"
},
"strict_native_diagnostics": {
"errors": [
"ERROR: all23 facilities including the cleaning room appear in the build palette",
"ERROR: FAIL: 1 of 169 checks failed"
],
"banner_count": 1,
"known_unicode_diagnostic_count": 0,
"unrecognized_unicode_diagnostic_count": 0,
"exit_leak_diagnostic_lines": []
},
"external_process_or_group_signals": 0,
"owned_child_process_helper_sha256": "c007e712c281573254faa1233c2ac92e100ab87393256a6dc096b35283e43037",
"adapter_owned_cleanup": {
"owned_child_created": true,
"engine_ended": true,
"actual_process_exit_code": 1,
"attempts": [
{
"attempt": 1,
"kill_attempted": false,
"wait_timeout_seconds": 5,
"wait_completed": true,
"errors": [],
"poll_before": 1,
"wait_returned_code": 1,
"poll_after": 1
}
],
"errors": []
},
"adapter_error": null,
"old_helper_bytes_preserved": true,
"helper_wait_None_maps_to_actual_timeout_seconds": 5,
"explicit_helper_wait_timeouts_preserved": true,
"additional_cleanup_wait_timeout_seconds": 5,
"additional_cleanup_max_attempts": 3
},
"outer_actual_capture": {
"actual_captured_pids": [
66967
],
"cleanup": [
{
"pid": 66967,
"cleanup": {
"owned_child_created": true,
"engine_ended": true,
"actual_process_exit_code": 1,
"attempts": [
{
"attempt": 1,
"kill_attempted": false,
"wait_timeout_seconds": 5,
"wait_completed": true,
"errors": [],
"poll_before": 1,
"wait_returned_code": 1,
"poll_after": 1
}
],
"errors": []
},
"outer_cleanup_errors": [],
"engine_ended": true,
"outer_maximum_helper_invocations": 3,
"helper_maximum_waits": 3,
"per_wait_timeout_seconds": 5,
"foreign_process_or_group_signals": 0
}
],
"adapter_exception": null,
"all_captured_ended": true,
"outer_cleanup_errors": [],
"foreign_process_or_group_signals": 0,
"all_cleanup_before_outer_receipt": true,
"outer_receipt_written": true,
"outer_receipt_error": null,
"passed": true
},
"actual_pid": 66967,
"engine_ended": true,
"exit_code": 1,
"log": "tests__ui__test_main_dashboard.gd.log",
"log_sha256": "f0c217b36ff566c5445ed98b2c322ae47c07198b7ecf76b31c32652380285e5b",
"raw_native_log": {
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01/147/engine-native.log",
"bytes": 21511,
"sha256": "e6dd83843678b2b0247d38cf4efc0921ff456e3c4349eb9f4548a354fbbe712c"
},
"completion": {
"passed": false,
"checks": null,
"failures": null,
"marker": null,
"errors": [
"missing/duplicate primary completion marker",
"raw diagnostics or FAIL lines"
],
"diagnostic_lines": [
"ERROR: all23 facilities including the cleaning room appear in the build palette",
"ERROR: FAIL: 1 of 169 checks failed"
],
"known_leak_warning_lines": [],
"known_leak_warning_count": 0,
"known_unicode_diagnostic_count": 0,
"unrecognized_unicode_diagnostic_count": 0
},
"reported_checks": null,
"reported_failures": null,
"completion_marker": null,
"collector_errors": [
"missing/duplicate primary completion marker",
"raw diagnostics or FAIL lines"
],
"whole_startup_profile_after": {
"path": "/Users/korizatou114/Library/Application Support/TheTree-PCK-tests-e5cb56d130e248c3a42d9ee038103767-standard-startup-147",
"files": {},
"fresh_before_engine": true
},
"whole_runtime_profile_after": {
"path": "/Users/korizatou114/Library/Application Support/TheTree-PCK-tests-1e2e00eb89e24067a79af5e3f8fbcc92-standard-runtime-147",
"files": {}
},
"generated_reports": {},
"source_sha256_end": "fa9ee0c4b9aee00a2be6d05a9dab7c0c3e8b0beb2b944257de1dc308bfc3cc20",
"default_player_entire_profile_unchanged": true,
"sequence": 147,
"godot": "/Applications/Godot.app/Contents/MacOS/Godot"
}
@@ -0,0 +1,11 @@
ERROR: all23 facilities including the cleaning room appear in the build palette
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] _expect (res://tests/ui/test_main_dashboard.gd:623)
[1] _run (res://tests/ui/test_main_dashboard.gd:132)
[2] _test_defense_notice (res://tests/ui/test_main_dashboard.gd:615)
ERROR: FAIL: 1 of 169 checks failed
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] _run (res://tests/ui/test_main_dashboard.gd:213)
[1] free_owner_and_wait (res://tests/helpers/ui_audio_teardown.gd:58)
@@ -0,0 +1,48 @@
{
"unit": "P08-03",
"candidate": "1f0a2bcd53c3f9fdf057e7916871cf5b42145c55",
"output": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-full-regression-1f0a2bcd-r01",
"suites_passed": 147,
"failed_suite": "tests/ui/test_main_dashboard.gd",
"failed_labels": [
"ERROR: all23 facilities including the cleaning room appear in the build palette",
"ERROR: FAIL: 1 of 169 checks failed"
],
"remaining_unexecuted": [
"tests/ui/test_opening_assignment.gd",
"tests/ui/test_original_build_pointer.gd",
"tests/ui/test_original_facility_controls.gd",
"tests/ui/test_p08_normal_placement_ops.gd",
"tests/ui/test_paired_bgm.gd",
"tests/ui/test_pixel_tower.gd",
"tests/ui/test_rank_pointer.gd",
"tests/ui/test_room_presentation.gd",
"tests/ui/test_selection_autosave.gd",
"tests/ui/test_selection_departure.gd",
"tests/ui/test_selection_lifecycle.gd",
"tests/ui/test_staff_management.gd",
"tests/ui/test_staff_rescue.gd",
"tests/ui/test_staff_rest.gd",
"tests/ui/test_stair_transport_details.gd",
"tests/ui/test_supply_auto_purchase_ui.gd",
"tests/ui/test_supply_management.gd",
"tests/ui/test_ui_audio_feedback.gd",
"tests/ui/test_ui_presentation_audio_contract.gd",
"tests/ui/test_upkeep_closed_ui.gd",
"tests/ui/test_upkeep_inspector.gd",
"tests/ui/test_world_tree_rank.gd",
"tests/world/test_elevator_topology.gd",
"tests/world/test_legacy_stairs.gd",
"tests/world/test_path_transit_density.gd",
"tests/world/test_path_vertical_policy.gd",
"tests/world/test_stair_infrastructure.gd"
],
"error": "AssertionError: first strict failed phase stops without retry: 147",
"cleanup_errors": [],
"guard_errors": [],
"owned_ended": true,
"formal_acceptance": false,
"test_assertion": "palette.get_child_count() == 23 at tests/ui/test_main_dashboard.gd:132",
"observed_product_source": "Main adds DemolitionButton to BuildPalette with grid.columns = MVP_FACILITY_IDS.size()+1; catalog button/icon check23 separately passes",
"candidate_fix_for_Opus_assessment": "Keep 23 facility-only grid membership; normal demolition tool as sibling control within same scroll palette, preserve ordinary access and all modes. No test condition weakening or arbitrary facility count change."
}
@@ -0,0 +1,14 @@
{
"unit": "P08-03",
"candidate": "4f3b42dfeca478d2398407373d75b529eb76fcf0",
"affected_ui4": "pass exact source/engine/marker matched, both stages guarded",
"native4": "import/parse/handler writer/reader passed before OS",
"OS_writer_pid": 75240,
"owned_collector_pid": 73669,
"failure": "SCRIPT ERROR Invalid assignment endpoint RefCounted(passive_placement.gd) on Node(InputObserver), setup:96",
"root_cua": "one genuine palette click; raw proof retained; initial load had not executed so not valid acceptance",
"source": "InputObserver.endpoint is Node; Passive extends placement.gd extends RefCounted",
"collection": "Root exact owned collector SIGINT after native error; no further UI/acks; no source modification",
"output": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r08",
"formal_acceptance": false
}
@@ -0,0 +1,36 @@
{
"unit": "P08-03",
"candidate": "d01286360ee88046e06b80d840fc303a71e0d661",
"local_final_tests": 75,
"native_import_parse_writer_reader": "all_pass",
"OS_acknowledged_requests": 32,
"OS_unacknowledged_request": 33,
"OS_writer_pid": 17863,
"OS_error": "TimeoutExpired: Command '['/Applications/Godot.app/Contents/MacOS/Godot', '--path', '/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r06/stage', '--script', '/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r06/os-runs/writer/passive_os.gd']' timed out after 900 seconds",
"owned_ended": true,
"guards": [],
"cleanup": [],
"formal_acceptance": false,
"deficits": [
"OS total child wait900 exceeded before rebuild/camera/finalsave",
"Godot viewport_to_screen is identity in actual real window; documents cannot claim it already includes canvas stretch/CUA titlebar"
],
"actual_CUA_mapping": {
"viewport_dimensions": [
1440,
810
],
"window_content": [
1280,
720
],
"screenshot_dimensions": [
1280,
752
],
"scale": 0.8888888888888888,
"titlebar_pixels": 32,
"modal_mapping": "apply native-reported dialog translation then physical stretch/titlebar"
},
"requested_fix": "Only OS child total wait to2400 with actual provenance; preserve per-request300, provider900, validation180, acceptance and source guards. Correct calibration docs/metadata to distinguish engine virtual matrix from CUA screenshot/window coordinates. No product/fixture rewrite or duplicated regression. Request33 after screenshot shows project manager because original child already terminal: unacknowledged, not valid evidence."
}
@@ -0,0 +1,124 @@
{
"unit": "P08-03",
"native_candidate": "31aa7706d28a92e313c432d5a62e35d19503dcc3",
"original_root": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09",
"index": {
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09/index.json",
"bytes": 301212,
"sha256": "68c29eb3d333ad0b6fb11664d8b0d18e326449da8b0dcca201343477744947fe"
},
"runner_input": {
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09/runner-input.json",
"bytes": 316087,
"sha256": "ce680cac09e66c6758c7cc4901e154a67ec31e8df217db7c90cd53dd7e6afde9"
},
"runner_ended": {
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09/runner-ended.json",
"bytes": 3196,
"sha256": "23a7602f293d7efb4c665a6d7456bb730c03bfa665ce93ac2a5d3427d4829cd2"
},
"OS": {
"writer": {
"receipt": {
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09/os-runs/writer/ended.json",
"bytes": 1329615,
"sha256": "645821cca51868f84b93ce09735196fdb65b5f3add310e4695db036ba8b26e6a"
},
"actual_pid": 80337,
"passed": true,
"engine_ended": true,
"exit_code": 0,
"error": null,
"guard_errors": [],
"cleanup_errors": []
},
"reader": {
"receipt": {
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09/os-runs/reader/ended.json",
"bytes": 1328376,
"sha256": "9dfb8c1d2f2930f6e48bce55146f0f02956cd7596c88f688442dc6d6ea5c0428"
},
"actual_pid": 92565,
"passed": true,
"engine_ended": true,
"exit_code": 0,
"error": null,
"guard_errors": [],
"cleanup_errors": []
}
},
"requests": {
"writer": 64,
"reader": 5
},
"actual_camera_cell": [
-8,
0,
0
],
"actual_selection": {
"entity_id": "facility_00000004",
"occupant_id": "facility_00000004",
"required": true
},
"camera_dispatch": {
"bounds": {
"max_x": 12,
"max_y": 6,
"min_x": -12,
"min_y": 0
},
"cell_dimensions": [
16.0,
24.0
],
"entity_id_before": "facility_00000001",
"local": [
546.5,
515.5
],
"map_position": [
475.0,
360.0
],
"occupant_id_before": "facility_00000004",
"pan": [
0.28118896484375,
109.441101074219
],
"screen": [
625.5,
580.5
],
"screen_transform": [
1.0,
0.0,
0.0,
1.0,
79.0,
65.0
],
"viewport": [
625.5,
580.5
],
"viewport_transform": [
1.0,
0.0,
0.0,
1.0,
79.0,
65.0
],
"world_cell": [
-8,
0,
0
],
"zoom": 0.5
},
"strict_registered_validation": "failed on mirrored absolute proof path; direct original check then failed PNG-only screenshot gate for actual JPEG",
"full_regression_final_candidate": "pending",
"independent_review": "pending",
"formal_acceptance": false
}
@@ -0,0 +1,38 @@
{
"unit": "P08-03",
"candidate": "4a17d0e0f589fa76d81f1d4630ec45c63bac21ab",
"formal_acceptance": false,
"OS_completed": false,
"successful_requests": [
1,
2,
3,
4
],
"unacknowledged_request": 5,
"required_world_cell": [
-8,
4,
0
],
"viewport": [
242.0,
180.0
],
"actual_coordinate": [
215,
192
],
"canvas_scale": 0.8888888888888888,
"titlebar_pixels": 32,
"observed": "Open-business guide intercepts unsupported target cell click and selects reception; no unsupported placement interaction occurred",
"actual_tool_call": "call_bc7eaed7c8ca4b82b53e15166d6ec0f3",
"screenshots": [
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-handler-r05/os-pair/writer-request-0005/screen-before.png",
"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-handler-r05/os-pair/writer-request-0005/screen-after.png"
],
"requested_fix": "Keep unsupported predicate; choose visible unsupported target outside normal guide. Derive/record stretch-to-window CUA coordinate mapping. No guide suppression/model injection/criteria weakening. Preserve good bootstrap/native code and raw failed attempt.",
"owned_engine_ended": true,
"cleanup_errors": [],
"guard_errors": []
}
@@ -0,0 +1,60 @@
{
"unit": "P08-03",
"candidate": "0c5e0022f2d809e4735804f67582b9c96a1dc025",
"native4_phases": "pass",
"local75": "pass final SHA matched",
"actual_OS_requests": 64,
"OS_writer_pid": 35236,
"OS_timeout_seconds": 2400,
"actual_failures": [
"observed OS selected cell",
"camera world identity"
],
"raw_recorded_selected_cell": [],
"actual_input_viewport": [
625.5,
580.5
],
"preclick_viewport_transform": [
1.0,
0.0,
0.0,
1.0,
79.0,
65.0
],
"local_actual_input": [
546.5,
515.5
],
"map_position": [
475.0,
360.0
],
"cell_dimensions": [
16.0,
24.0
],
"bounds": {
"max_x": 12,
"max_y": 6,
"min_x": -12,
"min_y": 0
},
"derived_actual_input_cell": [
-8,
0,
0
],
"formula_source": "scenes/main/world_preview.gd:391-401",
"UI_after_click": "request0063 screen-after.png shows selected reception at coordinate(-8,0)",
"observer_source": "tests/fixtures/p08-03/passive_placement.gd:156-161 uses view.canvas_to_cell(view.get_local_mouse_position()) after awaiting Root and frames",
"diagnosis_limit": "raw getter value was not recorded; exact reason it returns null remains unproven. Input-event-derived cell and actual selected-entity/UI identity must both be verified, not replaced by requested cell.",
"ordinary_save": "request0064 actual normal save completed and exported formal",
"OS_reader": "not started, writer exit1",
"owned_ended": true,
"guard_errors": [],
"cleanup_errors": [],
"formal_acceptance": false,
"requested_fix": "Capture actual left-press world coordinate from read-only input event before UI side effects; retain matching selected entity ID check and whole-model guards. Add negative wrong-input-cell/entity tests. Never alter raw failed proof or waive native exit/error criteria. Opus should assess narrowly applicable evidence reuse to avoid needless duplicate replay."
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

@@ -0,0 +1,11 @@
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
OpenGL API 4.1 Metal - 90.5 - Compatibility - Using Device: Apple - Apple M4
SCRIPT ERROR: Invalid assignment of property or key 'endpoint' with value of type 'RefCounted (passive_placement.gd)' on a base object of type 'Node (InputObserver)'.
at: setup (res://tests/fixtures/p08-03/passive_placement.gd:96)
GDScript backtrace (most recent call first):
[0] setup (res://tests/fixtures/p08-03/passive_placement.gd:96)
[1] run (res://tests/fixtures/p08-03/placement.gd:279)
[2] run (/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r08/os-runs/writer/passive_os.gd:6)
P08_ROOT_CUA_WAIT /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r08/os-pair/writer-request-0001/request.json
P08_ROOT_CUA_WAIT /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r08/os-pair/writer-request-0002/request.json
@@ -0,0 +1,9 @@
{
"raw_path": "/Users/korizatou114/Projects/\u3068\u308a\u306b\u304f\u5de5\u623f\u30b2\u30fc\u30e0\u5236\u4f5c\u90e8/artifacts/original-completion-2026-10-02/p08-03-native-handler-r05/pair/reader-checkpoint.json",
"raw_sha256": "304d97de8051d5e74c6e32c4482a3cb183b0172d7671088fdc40469cc3448c0d",
"raw_bytes": 2120352,
"compressed_path": "ROOT_R05_READER_CHECKPOINT.json.gz",
"candidate": "4a17d0e0f589fa76d81f1d4630ec45c63bac21ab",
"complete_raw_preserved": true,
"scope": "actual native reader snapshot, not synthetic acceptance proof"
}
@@ -0,0 +1,31 @@
{
"candidate": "31aa7706d28a92e313c432d5a62e35d19503dcc3",
"native_collection": "R09 import/parse/handler writer/reader and actual OS writer80337(64 requests)/reader92565(5 requests) all exit0, all owned ended, guards/cleanup0",
"canonical_copy_error": "ordinary_gate absolute varbytes pin path expects original directory, not cloned build directory. checker.check(W,originalA) passes this gate",
"original_check_next_error": "missing OS screenshot; actual CUA getScreenshot bytes are JPEG although Root named them .png, PNG-only gate rejects",
"screenshot_formats": {
"JPEG": 138
},
"screenshots": 138,
"examples": [
{
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09/os-pair/writer-request-0058/screen-after.png",
"bytes": 169431,
"signature": "JPEG",
"first16": "ffd8ffe000104a464946000101000048",
"sha256": "a13d0a1f5c8420700edbec576be93eceab1a7ea6be82802aa2d42365d17026f4"
},
{
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09/os-pair/writer-request-0058/screen-before.png",
"bytes": 167891,
"signature": "JPEG",
"first16": "ffd8ffe000104a464946000101000048",
"sha256": "ce8959eaad1dc24de5f2d8e89ca77afc7286120647603dbdaa78525e91f07e44"
}
],
"original_root": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09",
"canonical_root": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/.runtime/P08-03/build/p08-normal-placement-evidence",
"original_raw_not_modified": true,
"formal_acceptance": false,
"required_decision": "Safely satisfy strict image proof and provenance with original raw bytes retained; assess content-preserving re-encoding and verified original/canonical path mapping without redoing actual OS steps or relabeling failed validators; no relaxed image/provenance/whole-model or independence criteria."
}
@@ -0,0 +1,976 @@
{
"scope": "post-collection read-only measurement of immutable R09 images; not invented capture-time metadata",
"original_index_sha256": "68c29eb3d333ad0b6fb11664d8b0d18e326449da8b0dcca201343477744947fe",
"measurement_tool": "/usr/bin/sips -g pixelWidth -g pixelHeight",
"tool_stdout_sha256": "03126a9cb750316569fededbc1b7b758806c1e603ba9e7cf3ce67c9cc413211c",
"images": [
{
"file": "os-pair/reader-request-0001/screen-after.png",
"source_sha256": "b54b6f7fa5ee014698ecaa2d5df50e3dfd28f404474d1d722dd09d08fec1636e",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0001/screen-before.png",
"source_sha256": "de219c703de4dfb8e44b1ce4b5c2f26df059931067e00a55b8fc15db53d1d7f9",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0002/screen-after.png",
"source_sha256": "cde7dfdf26c1b08a302441420c7175d08e73854fa17f4d7007403d68f25238fd",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0002/screen-before.png",
"source_sha256": "8d9fd9fe1408162c2032530e5d7e14931a0ab0f4a0a7b9c2afc8e71adb4dce74",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0003/screen-after.png",
"source_sha256": "61f9116fb3ba373de996fd8674da62fce781e4670e5a849ecd51b03309dfec52",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0003/screen-before.png",
"source_sha256": "8c338125bee670059af829b8208831bececf883afbd0cd20a3799d575ca2003f",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0004/screen-after.png",
"source_sha256": "eb97a85ccf570690d0f83f8f6a3a2fea2c5ae7b9af45f6d7433732480a93f2de",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0004/screen-before.png",
"source_sha256": "e39330e00bf85082cef937af1b42cfb7f1ee9ea6ca59ad27310ba2b5ba78cd14",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0005/screen-after.png",
"source_sha256": "8cac36016a2309451269b62b5f8ccc923b6818205260a9dc1c44d09dd8a7d86d",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/reader-request-0005/screen-before.png",
"source_sha256": "5c71fd681ed7b41350f431ed486e32e6df6c6a833a0c9c2d7d3506906eb0c4c1",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0001/screen-after.png",
"source_sha256": "685d672ff0349c317f0e6257512e25c1ce547606ec3d4d331970ae0c1d0ff7d8",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0001/screen-before.png",
"source_sha256": "7378e03e85dd92629883988fbe6420142a2012f4485f023231f3148697ea49b8",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0002/screen-after.png",
"source_sha256": "ef680cf46d904ba830115e833e332221bf6333995b013aa5157df0de92a49220",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0002/screen-before.png",
"source_sha256": "68f63798582a7404fe024afd8ddcc5680ac32d8efeefbb587f5e0be79091c43c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0003/screen-after.png",
"source_sha256": "806c43c47b4da5a19a41ecfb70014120f0fab9cca98c8641ab3f3c791e4e7321",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0003/screen-before.png",
"source_sha256": "91ddeee45a12b1e5c60630cc0bb5e3c9a2cb73b667c782c53d86b4540867ce48",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0004/screen-after.png",
"source_sha256": "c44d0b0d9540e54db5cb507cce9a160c8f746813d9b592c7bfca6f3fc34ace07",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0004/screen-before.png",
"source_sha256": "c3b351565a4f7a63771313f1f62201ba4912465e3a747a16edcdf6812f817f0e",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0005/screen-after.png",
"source_sha256": "9626def46a116578a06e7673bd9c4c52d1e6cc00df8e0f152028021c38206736",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0005/screen-before.png",
"source_sha256": "cce2a6ca77b1878dc3afccb59f11d44d2b12fdb8251ce188866f00b62ee39b21",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0006/screen-after.png",
"source_sha256": "915c9b10978026a1de5fc4efb4c6d49c5841431f0f947031de931289fd51fbbe",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0006/screen-before.png",
"source_sha256": "532d5e4f10549c7dad44cc4e07d161fc84069518f776140ae869b73fbf151ecd",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0007/screen-after.png",
"source_sha256": "4f6257841b5f37bc1e8b4429803216bddbfc8c212954685fdd6b2a12c301ae98",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0007/screen-before.png",
"source_sha256": "970a2a1986c18d9a26b3a7682de38b95cd3ba80fdb5e48e75a5f2af26c939761",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0008/screen-after.png",
"source_sha256": "a9cca8444c00ffcaa4a50a5bafea3204b8e007e0a61e31c9c119ed0d1a0a9f5c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0008/screen-before.png",
"source_sha256": "fb58d85c83c9e5c09f2c869e8171a577b1f53b7b8669f369f7e2e6ff46c01af2",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0009/screen-after.png",
"source_sha256": "bce7ecf4e8b288e05df5d098c7ea9d15918457e9360864923cf0283b13dcfaef",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0009/screen-before.png",
"source_sha256": "27926f876398d59ec12e4263f537997efc0c45a16f99e4e45e5bbd8df2f8b980",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0010/screen-after.png",
"source_sha256": "9109144c9aa892b9602b9b1c9bd76a33a3b77e64bf172e91db0b04b5117d7028",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0010/screen-before.png",
"source_sha256": "4e949455676f2c9b6a2e54a1c4535cdaad5443b2866bdbb1f00bb5bd8fe2d33f",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0011/screen-after.png",
"source_sha256": "9225d1306242056aab728674c0ddc70db352f7b340a2383ff2abfc71bcbd3545",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0011/screen-before.png",
"source_sha256": "484ba517d60755900d4b236591e5662800fe2d8920567589aca36dba51a527c8",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0012/screen-after.png",
"source_sha256": "5be61fbf3b8b97264734fe2485acd4351540e7d5a464acf28c1fc825ad63ad66",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0012/screen-before.png",
"source_sha256": "c405713b49527f218fe9b775398e6d5c5fa634659e9772e1f92f78f8900860e7",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0013/screen-after.png",
"source_sha256": "2d75692d7ca006c2a107dd4a1ec96169b97b74e10a893eccc769fff51f673c77",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0013/screen-before.png",
"source_sha256": "a0ad8e4afb6dfa02220b5b6f43f5db8753ceba9d0263551d1829655ab7b36e1c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0014/screen-after.png",
"source_sha256": "b76e0f4f1d6d241b862c888bb6a4d0f412c3cc128c63cf9431fa4ae909b3da65",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0014/screen-before.png",
"source_sha256": "f6d72f5de7e79bfa316664015e2b733c204eec170586161aa207a57967fe623a",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0015/screen-after.png",
"source_sha256": "122d9e6eadaaa453c6aeb0edb05f783d9d9290be29c89ff80f292728a03b6ac7",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0015/screen-before.png",
"source_sha256": "165d50aa0b26bd3244c311560f3ac95fbfd3e22d7ad9c3740638a060a61371f6",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0016/screen-after.png",
"source_sha256": "9d5db7ab5703d08319233d12d5c1324944692876d24904f27f8231137178c995",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0016/screen-before.png",
"source_sha256": "c58b82369638d39507b9e0ace7a674c2d75dc4be04022de3f8767e23751acc5f",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0017/screen-after.png",
"source_sha256": "e22b06968d21aaf7f4567e6fd0a15785680b54ac6e5285443f0ba6548e6fc4aa",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0017/screen-before.png",
"source_sha256": "9d2d785c6750daca47cfab652ee807697cea59469c8bbe4335766eeb49dbeb05",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0018/screen-after.png",
"source_sha256": "e3d72eea15ed516ce97f43f31b7627e5336467ae7a64a8bbbd72f9733869ea3d",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0018/screen-before.png",
"source_sha256": "57005d30173b51e58531c586dc10712786160d663e100b958f9d487ef09376ae",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0019/screen-after.png",
"source_sha256": "9255d120eb5021c636fc6e6f74c3af72f741aad278ee024eea4901d776a242d5",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0019/screen-before.png",
"source_sha256": "bb72bba570b3c3d97785ef0c2f084a5dd98eef600f95eea2a2163a12a68bd482",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0020/screen-after.png",
"source_sha256": "4a5e8d7d9d78bc670eb1a3775912506bf6bb1106ed9e8d270c977244ee382119",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0020/screen-before.png",
"source_sha256": "9482ff51c1c56dbb595587c9f1f42d73d2cf22eaf4c5cd965f79f34b882aae1c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0021/screen-after.png",
"source_sha256": "be21bf324daf892c34cc1726ff36a84d8312c584199c042cfc853af148d86ace",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0021/screen-before.png",
"source_sha256": "8551975c3ab1be67776b14771dce614b801ca56517740618e4270f4e3466cf22",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0022/screen-after.png",
"source_sha256": "a39a7688a3c5beab968d0a34e5a55791773b934d4158160cc54b6b37fe31550e",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0022/screen-before.png",
"source_sha256": "543cb4a1dc8976af90449297ee734539eea3361a9e4112ccab510f269a7bb94f",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0023/screen-after.png",
"source_sha256": "569715f733c918ec7b6211d953526b0df66b521df855ade7e3554476638509b6",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0023/screen-before.png",
"source_sha256": "cd09b4b43abf503f3b5b4cd397a002e88909dda37084fb090bf2278fe11e6255",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0024/screen-after.png",
"source_sha256": "1878386793d16510a1d8f289131688538542996d5f778118f606bb9f466a1d99",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0024/screen-before.png",
"source_sha256": "cd9a4f8050f06595460ad667307fa62b29b807eb59dd60d628024ca1ef60e345",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0025/screen-after.png",
"source_sha256": "4733c86f40ee9d66b4f2e801b17d46eed30e23979f8602899071de2be117d15c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0025/screen-before.png",
"source_sha256": "72586b2cdeb481c2ff1d956eec6aa9fdf08941e59f67e56c3d8665fc3ef89141",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0026/screen-after.png",
"source_sha256": "a31ed7d43307c05703d183eb6e639366312dfaa5513e0c19db6838505f6c0e50",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0026/screen-before.png",
"source_sha256": "46a6004cf1fffa7a8ebfcc93076267c45bfc4283beac25433aff35ab6d2312ed",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0027/screen-after.png",
"source_sha256": "aa44efd2415d0ef7dca4b46a700adf4d96f073727fee7888a15a2a2ae90270cf",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0027/screen-before.png",
"source_sha256": "cf0b99d7035f636961824c919bab0d93a0c814c97bf27f789a1d909f3160360f",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0028/screen-after.png",
"source_sha256": "87cbcc1b0c444a1073d0cb48a4e4687a88bed87bb0efabcc40d098f98aee4861",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0028/screen-before.png",
"source_sha256": "52dc193175d1a12a41d3bc55f368646e900caae479e8c8ef6c7bf2de4009ce49",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0029/screen-after.png",
"source_sha256": "e38a3a141816b242e8fcdea1a729877daa57a43094853002dec2497368f9211c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0029/screen-before.png",
"source_sha256": "acbe7607ec4a3b0a04c59c8f2b8cee7f79d21cdcd6d7c5a5f7aef0c4ecdb7253",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0030/screen-after.png",
"source_sha256": "0a8f71d79face5b53277171db1d8b7a5bef215972311efed527c2a9153a85d98",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0030/screen-before.png",
"source_sha256": "a0ed46e43d628ab7eab28ff0173634cf9adfd4d78ce0d255caadbf8659d0ff48",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0031/screen-after.png",
"source_sha256": "7081709f6e37d7d47db3592bb9a621f40daff426b27d17941a9a46369d90c4cb",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0031/screen-before.png",
"source_sha256": "3013e92573621d326f8bcc65e8f1d57ac1eefd0f71eb61f605fcabb56d6c44f6",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0032/screen-after.png",
"source_sha256": "add6518c2564fb76e7454151ca7d8f20c897f65e2db6355b460b1c2a86754c71",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0032/screen-before.png",
"source_sha256": "d938c4a4a2c2a0b203a31c123c03bd0f7ef73fb6d267d186edb44c5ef721d56b",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0033/screen-after.png",
"source_sha256": "dc4d8b182e13623560c72501e2abe436aeb118f69d99e4cc9360c8cc18971f1b",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0033/screen-before.png",
"source_sha256": "f331391c69347860d9c9184a7277fda3720cc1c4949b132b9346742c49716c61",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0034/screen-after.png",
"source_sha256": "771b00371fb8c4ef9797b0d62490be11fa48164beedd846f888207bc3c867175",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0034/screen-before.png",
"source_sha256": "81dae87e99555528f0cbb7fe19bb7485983c5a0f29a0692cfbc1b18690a4346f",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0035/screen-after.png",
"source_sha256": "dc6ffea5314485f9270f4f1ea78ade78afd59655b0613898365dc12ea0398b18",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0035/screen-before.png",
"source_sha256": "673c2f0fe3244ecc897b014699ef6491cae80d2bab8fbccdac8fd86f37203b9c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0036/screen-after.png",
"source_sha256": "3695ecb8109c3b1b4810adff8f8a112cc238ec8051fcb0aeec624e7df4be208d",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0036/screen-before.png",
"source_sha256": "d0386b449b9e91e85a0e05122202846e230facea4fa362c8583bfedf0f563c1e",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0037/screen-after.png",
"source_sha256": "99bf2fcc940d6e1351873024af933c30d5bed5e8b085f3f0ba7762097744bf26",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0037/screen-before.png",
"source_sha256": "2b5c953a0e02da363273e72832bbbd14d6aa13955a77ab8b58e8b0babd617b0e",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0038/screen-after.png",
"source_sha256": "ba98f3832f4a0ad8c365d4342c899accfacc2b2910621892adfeef2af2e741cd",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0038/screen-before.png",
"source_sha256": "01c5666579d78a58d49a7e8b11f3273e4bd5cd97d32f8c15bd57ec2982f0067d",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0039/screen-after.png",
"source_sha256": "f7368b2ccaab8fe218465f919fadeb75d18640bb5282fe7fd52a5e589b5e57cc",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0039/screen-before.png",
"source_sha256": "92f15737f3617e860fe288655134e995686401b32de6c561894a470e035a1c00",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0040/screen-after.png",
"source_sha256": "46d3b76b586a7ee3aa2943ed4f659f137933abb6d25f0eed5f60e546455dc0d6",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0040/screen-before.png",
"source_sha256": "ceb54f8d409778c90ac162b244822f718ff5a5e9471f6efde44643d154a3ff17",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0041/screen-after.png",
"source_sha256": "29024b76601c1ec5c5ea3e150eac42019be30aac9ab17d737835afff14fc3ed6",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0041/screen-before.png",
"source_sha256": "6aef1783644c4eb31ddbdd8fc26e4cfc08546d3d982a38a0e65caf1bc6b56d55",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0042/screen-after.png",
"source_sha256": "b7a0d3b23b609f6a66f1aee07f26d145005152627e3018a8975b785fcd365f0e",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0042/screen-before.png",
"source_sha256": "c1b61f3df55a383a24fa545f89a6a9e353ec9ce214ad3e8c3d972fd002aadae6",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0043/screen-after.png",
"source_sha256": "424a5ed967e5430646a09cb79e005a37e57180bc6bc45019c35297b5d1d11bf5",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0043/screen-before.png",
"source_sha256": "cbc3cddd3b2780c61da7ccf4d0685aff2af79652086cf7b4b3c8a0b2e60e3ce6",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0044/screen-after.png",
"source_sha256": "95c8f783cd2758d7c1ae7759e3143d5f6e2d12a6f7f6958982581a292a20e59c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0044/screen-before.png",
"source_sha256": "ea1dea1b2119438db7342ccf07099fce6bbf19306ab7e140ac0aae2bf904ad84",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0045/screen-after.png",
"source_sha256": "8384de8ca62d374c56602e0f02866334fb5952ae1769e772b458c23646046d47",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0045/screen-before.png",
"source_sha256": "747ef5a69382710d17d46d810941c6591763e51ea1c9ab9a06b1e1172348edd0",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0046/screen-after.png",
"source_sha256": "87303f72438035b05946b45e96fcfd5e1635acb6f045bef5882d1f54ab1d9c3e",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0046/screen-before.png",
"source_sha256": "01735714b37386f40b9e185c06ac994fa5d60736b6fcf4f8c653566317db2dff",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0047/screen-after.png",
"source_sha256": "0c22cc8246c5b5eb349147e9c2633ad280d1489d36313f8486a36909a0edf4dc",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0047/screen-before.png",
"source_sha256": "d74da0f11f706ec90d29c85fc61c8410e770fc512e51ffef8fd47cfeb7833314",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0048/screen-after.png",
"source_sha256": "f25c6679a66d53fa0baef6946cb09c6b34b5a3215132f8912176ac07ae4fd178",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0048/screen-before.png",
"source_sha256": "142264548642eeb26e3131199077433280f2abfc8e3c185c0b80b8ac7dc88368",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0049/screen-after.png",
"source_sha256": "f13497c3acf83c3d0d44e9bc55334000e62e830fb043d823d33845b8e0dd3243",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0049/screen-before.png",
"source_sha256": "4d09dd8f26cb9d23dd8be9e0e1ecd57cd0c314c5c0f3a69b8ede9fd21671478c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0050/screen-after.png",
"source_sha256": "16d49100dc19067be96c76e298bdba65912c067af2f25ade8069aaaecfb7f257",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0050/screen-before.png",
"source_sha256": "8b750551b8aedef80bf3e6648ed16ebeda5b78ae2f97f99202d9db1af89e8dea",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0051/screen-after.png",
"source_sha256": "57218dbfdf0d561d761c64e47c36c278bdec43e014431383a4ad2c1e23b1b0e4",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0051/screen-before.png",
"source_sha256": "65e5d9d93f57ebd6af5a88db73e44ac9084162e2c30895431490852b73aae07b",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0052/screen-after.png",
"source_sha256": "5e2f067f3e271c6f380454cd44268ee83203871a50710fbad456b23dfc1e429b",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0052/screen-before.png",
"source_sha256": "c4a945390bd626fff4f3f7af44f9e508c6af6aa97b1c7be356f9949dc6ede205",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0053/screen-after.png",
"source_sha256": "a989599abc63a7418c8b65ff64d65f9251e09a0de6dbf99b83524e066bb26c19",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0053/screen-before.png",
"source_sha256": "cf3fa4764f3d7ab2a2de43b477ad459fd63bf653d62a0e43ec515fc6033b7bf8",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0054/screen-after.png",
"source_sha256": "bde2224c59ec06f948dc889654bf0aa173ab4502d90605b33a501353217685de",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0054/screen-before.png",
"source_sha256": "7c30aec29a115a067e067393c04c1ef930976577456fd41a4583895b0903b94a",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0055/screen-after.png",
"source_sha256": "f330511835fd1d8526b0b9c758a117ed5a051f9bb9dc97eb519732b327fe092d",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0055/screen-before.png",
"source_sha256": "d73e160d1eec129f36ffcf10fd42bce77b7d0e0a794c00c9b7d28e0d8546f979",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0056/screen-after.png",
"source_sha256": "f1d0914ebfec58d8098dbf53c142fb27afe08891162e62244b6a69a335942658",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0056/screen-before.png",
"source_sha256": "06cfb2c3d8a74dd8a33aeb96830ed86e7bbaaa9714ff8423eb7a22098782945f",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0057/screen-after.png",
"source_sha256": "c4182734d4ea40bfe6dee01e2d7809a7e396b367fbde251c44fdebeca7ea832d",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0057/screen-before.png",
"source_sha256": "d5b59f180a124f74dff53fd3c0f7050a8022667ea4405929042ddb4c35fe962c",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0058/screen-after.png",
"source_sha256": "a13d0a1f5c8420700edbec576be93eceab1a7ea6be82802aa2d42365d17026f4",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0058/screen-before.png",
"source_sha256": "ce8959eaad1dc24de5f2d8e89ca77afc7286120647603dbdaa78525e91f07e44",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0059/screen-after.png",
"source_sha256": "5375cfadc79596c8f404d2ef7573fcec522f0f42f2049d6095a887578ef62d45",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0059/screen-before.png",
"source_sha256": "85f25e0e2edb225371e2d66adf4c733aee093d2774b03ea6bc1e2c57aecb41db",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0060/screen-after.png",
"source_sha256": "7782db3ef0a6a2c8f26695ad5aa6978d373c903ada226c987004bbdffdfcb544",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0060/screen-before.png",
"source_sha256": "fe29ed682a21b12f39c2f8329b934992ea14357f0738a5bbdb5918fe2dfcc3d4",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0061/screen-after.png",
"source_sha256": "0f1416c3bb88e58401c2e8a3151eadbd42609b96ce0f47dc1411da00a496fc1f",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0061/screen-before.png",
"source_sha256": "63aa95d1dda03f1a253364dadf9ebb4ce61dc8976482afe26e10a98c7d256290",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0062/screen-after.png",
"source_sha256": "c8dea8222efab5aa0d4a3c0de8387a38f0e8f9e43ff5d6796f160475c1ed06ea",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0062/screen-before.png",
"source_sha256": "78cacff1897f04525b06de0bec81689cdbb5027d8d388b9ea60b69ccb3a91238",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0063/screen-after.png",
"source_sha256": "a654e2584d16a8f6cf70822ad61c03925b13910511843b7bb6e3d8fb3c7044a1",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0063/screen-before.png",
"source_sha256": "ed9127c074512800ebb12e46cc3a4669308e84a2229a963abf2c8aef5e56c631",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0064/screen-after.png",
"source_sha256": "f62e00c37d09e382c04d321a2234f8794b71da88dfdacc86ab4c7b46a965ac27",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
},
{
"file": "os-pair/writer-request-0064/screen-before.png",
"source_sha256": "8751fad9f2fd8820d634889d984abebfb2c79f8af6c515a8e24e443569d7fe57",
"width": 1280,
"height": 752,
"format_by_magic": "JPEG"
}
],
"pairs_have_equal_dimensions": true,
"formal_acceptance": false
}
@@ -0,0 +1,37 @@
{
"task_id": "P08-03",
"started_at": "2026-10-13T19:19:51.362993+00:00",
"ended_at": "2026-10-13T19:20:39.117228+00:00",
"syntax": {
"method": "compile(source, filename, exec); no pyc",
"files": {
"tools/run_p08_normal_placement.py": "191831b4f684bdd7e99b3be6038c15a6830f544d17c941869b1c2a8fbe4a2aa3",
"tools/check_p08_normal_placement_evidence.py": "5baea283760e04f23abefcf576f9a3e8230b96ed30d82569528dcd211a6032cf",
"tools/test_p08_normal_placement_evidence.py": "ebf6c0ef2c32dc8fac61d570a7fea99c1ac2499b92399db32afec26147b9d84c",
"tests/fixtures/p08-03/checker_fixture.py": "0d12e09e5342a016bc9e61c056b07357e761c29f9d82fbf941ce524f51ff131e"
},
"passed": true
},
"checker_tests": {
"argv": [
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
"-B",
"tools/test_p08_normal_placement_evidence.py"
],
"exit_code": 0,
"log": "repair-r02-local-checker-tests.log",
"log_sha256": "0cb0e9deddcd9d90883a9416ecfed346bf1f4337a51247d08a39d49160313129",
"synthetic_only": true,
"test_count": 49,
"retained_previous_tests": 35,
"new_semantic_tests": 14
},
"local_source_manifest": "local-source-manifest.json",
"local_source_manifest_sha256": "25b7492044046b5c8498f968b648392b592d42e266b2ff6fdb4773e52ba3e451",
"source_and_inputs_unchanged_during_tests": true,
"git_diff_check": "pass",
"native_engines_started": 0,
"OS_operations": 0,
"full_regression_executed": false,
"acceptance": "pending"
}
@@ -0,0 +1,38 @@
{
"task_id": "P08-03",
"started_at": "2026-10-13T19:51:22.470024+00:00",
"ended_at": "2026-10-13T19:52:12.939899+00:00",
"syntax": {
"method": "compile in memory; no pyc",
"files": {
"tools/run_p08_normal_placement.py": "191831b4f684bdd7e99b3be6038c15a6830f544d17c941869b1c2a8fbe4a2aa3",
"tools/check_p08_normal_placement_evidence.py": "7fbc115599782b2b7e98f9df855e72b076580b74f6a17aa255d16f2566fe6285",
"tools/test_p08_normal_placement_evidence.py": "3a5fb02b944a9eff808458df897574232f9e5609d828031562e93d9920b9cfbb",
"tests/fixtures/p08-03/checker_fixture.py": "062333148bfb570f2191317f1634e5dd1495cf3602221fc9a054dd9243597669"
},
"passed": true
},
"checker_tests": {
"argv": [
"python3",
"-B",
"tools/test_p08_normal_placement_evidence.py"
],
"timeout_seconds": 900,
"exit_code": 0,
"log": "repair-r04-local-checker-tests.log",
"log_sha256": "e54ecf761ca49aebe01fc1a13367ba01aa0f437ba649b781b1c8feb3a6f8bbc6",
"synthetic_only": true,
"test_count": 56,
"retained_previous_tests": 49,
"new_semantic_tests": 7
},
"source_and_inputs_unchanged_during_tests": true,
"native_engines_started": 0,
"OS_operations": 0,
"full_regression_executed": false,
"acceptance": "pending",
"local_source_manifest": "local-source-manifest.json",
"local_source_manifest_sha256": "533748d30a8fb7b7e78930cf2c08139e980f75341ba772f062780d2056ec2900",
"git_diff_check": "pass"
}
@@ -0,0 +1,38 @@
{
"task_id": "P08-03",
"started_at": "2026-10-13T20:49:58.133267+00:00",
"ended_at": "2026-10-13T20:51:06.466499+00:00",
"syntax": {
"method": "ast.parse in memory; no pyc",
"files": {
"tools/run_p08_normal_placement.py": "191831b4f684bdd7e99b3be6038c15a6830f544d17c941869b1c2a8fbe4a2aa3",
"tools/check_p08_normal_placement_evidence.py": "dfa37ed586240972e57cbb6a962beb856ba289abd58dbfaf83706d3a227a0116",
"tools/test_p08_normal_placement_evidence.py": "d40edc5518e8bfcb59a1da3f55305955581209cfd24a0223c764d6e39c4c361e",
"tests/fixtures/p08-03/checker_fixture.py": "508e8bc0f9ff3dc578a3b34fdfb3354fe31e5e604e2d7731cd25511c4261e93a"
},
"passed": true
},
"checker_tests": {
"argv": [
"python3",
"-B",
"tools/test_p08_normal_placement_evidence.py"
],
"timeout_seconds": 900,
"exit_code": 0,
"log": "repair-r05-local-checker-tests.log",
"log_sha256": "84c71a911af1ea79ad6cb005513ce2d3b245a1cc3577baa014817714dc08d413",
"test_count": 75,
"retained_previous_tests": 56,
"new_tests": 19,
"synthetic_and_actual_snapshot_controls_only": true
},
"source_and_inputs_unchanged_during_tests": true,
"native_engines_started": 0,
"OS_operations": 0,
"full_regression_executed": false,
"acceptance": "pending",
"local_source_manifest": "local-source-manifest.json",
"local_source_manifest_sha256": "f897d2713f64e1b3338e3e24a9e61859db190643a6eadbd202dde91c5bb0df04",
"git_diff_check": "pass"
}
@@ -0,0 +1,37 @@
{
"task_id": "P08-03",
"started_at": "2026-10-13T20:48:14.426031+00:00",
"ended_at": "2026-10-13T20:49:23.475326+00:00",
"syntax": {
"method": "ast.parse in memory; no pyc",
"files": {
"tools/run_p08_normal_placement.py": "191831b4f684bdd7e99b3be6038c15a6830f544d17c941869b1c2a8fbe4a2aa3",
"tools/check_p08_normal_placement_evidence.py": "dfa37ed586240972e57cbb6a962beb856ba289abd58dbfaf83706d3a227a0116",
"tools/test_p08_normal_placement_evidence.py": "de55cb674ef7163ab9c6dfceba4ae42fb0a43bc718df51fa63dc2f271bcbf1b7",
"tests/fixtures/p08-03/checker_fixture.py": "508e8bc0f9ff3dc578a3b34fdfb3354fe31e5e604e2d7731cd25511c4261e93a"
},
"passed": true
},
"checker_tests": {
"argv": [
"python3",
"-B",
"tools/test_p08_normal_placement_evidence.py"
],
"timeout_seconds": 900,
"exit_code": 1,
"log": "repair-r05-local-checker-tests.log",
"log_sha256": "b6f30299c9383c77553e946cff853894e7a53a8a9e88bdd15342dd9ede457242",
"test_count": 75,
"retained_previous_tests": 56,
"new_tests": 19,
"synthetic_and_actual_snapshot_controls_only": true
},
"source_and_inputs_unchanged_during_tests": true,
"native_engines_started": 0,
"OS_operations": 0,
"full_regression_executed": false,
"acceptance": "pending",
"local_source_manifest": "local-source-manifest.json",
"local_source_manifest_sha256": "b3141b695926da4e45a04d576c4f2922dee62e5f316a428798d3c5edf82c7fea"
}
@@ -0,0 +1,25 @@
........................................................FF.................
======================================================================
FAIL: test_whole_checker_missing_stair_projection (__main__.EvidenceTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-implement/tools/test_p08_normal_placement_evidence.py", line 349, in test_whole_checker_missing_stair_projection
self.reject('missing/extra infrastructure projection')
File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-implement/tools/test_p08_normal_placement_evidence.py", line 48, in reject
self.assertIn(text, ' '.join(errors))
AssertionError: 'missing/extra infrastructure projection' not found in "wrong resume model: source-defined operation drift reader [('systems', 'runtime', 'facility_infrastructure', 'projections')]"
======================================================================
FAIL: test_whole_checker_wrong_stair_connector (__main__.EvidenceTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-implement/tools/test_p08_normal_placement_evidence.py", line 353, in test_whole_checker_wrong_stair_connector
self.reject('wrong infrastructure connector topology')
File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-implement/tools/test_p08_normal_placement_evidence.py", line 48, in reject
self.assertIn(text, ' '.join(errors))
AssertionError: 'wrong infrastructure connector topology' not found in "wrong resume model: source-defined operation drift reader [('systems', 'runtime', 'path', 'connectors', '0', 'cost')]"
----------------------------------------------------------------------
Ran 75 tests in 65.677s
FAILED (failures=2)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,5 @@
...................................
----------------------------------------------------------------------
Ran 35 tests in 17.918s
OK
@@ -0,0 +1,31 @@
{
"task_id": "P08-03",
"syntax": {
"method": "ast.parse in memory; no pyc",
"files": {
"tools/run_p08_normal_placement.py": "5cb1f58664a0bec71c8b5e853749d1c3656e0a2a027201e33fbaa6b0c0291fc6",
"tools/check_p08_normal_placement_evidence.py": "dfa37ed586240972e57cbb6a962beb856ba289abd58dbfaf83706d3a227a0116",
"tools/test_p08_normal_placement_evidence.py": "8b98647990e45588e117b6e9ecb87e5a1fcf8d83ddbd6c27da8b0a2edd74da86",
"tests/fixtures/p08-03/checker_fixture.py": "508e8bc0f9ff3dc578a3b34fdfb3354fe31e5e604e2d7731cd25511c4261e93a"
},
"passed": true
},
"checker_tests": {
"argv": [
"python3",
"-B",
"tools/test_p08_normal_placement_evidence.py"
],
"timeout_seconds": 900,
"exit_code": 0,
"log": "repair-r06-mock-sync-local-checker-tests.log",
"log_sha256": "74a86ece9204fadf39c763ec089b46b94ecfb9a04206c4aaeaeadda423879bda",
"test_count": 75,
"failures": 0
},
"native_engines_started": 0,
"OS_operations": 0,
"full_regression_executed": false,
"acceptance": "pending",
"local_source_manifest_sha256": "a8f442062ef4d4c791e07ad00271c7123c80997bf76897f12c78c303d90173a8"
}
@@ -0,0 +1,89 @@
ERROR: P08 placement: diagnostic initial formal save
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] save_initial_fixture (res://tests/fixtures/p08-03/placement.gd:306)
[2] writer (res://tests/fixtures/p08-03/placement.gd:208)
[3] run (res://tests/fixtures/p08-03/placement.gd:261)
[4] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: unsupported preview refusal
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] build (res://tests/fixtures/p08-03/placement.gd:115)
[2] click (res://tests/fixtures/p08-03/placement.gd:94)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: out_of_bounds preview refusal
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] build (res://tests/fixtures/p08-03/placement.gd:115)
[2] click (res://tests/fixtures/p08-03/placement.gd:94)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: supported_connected accepted
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] build (res://tests/fixtures/p08-03/placement.gd:111)
[2] click (res://tests/fixtures/p08-03/placement.gd:94)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: overlap preview refusal
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] build (res://tests/fixtures/p08-03/placement.gd:115)
[2] click (res://tests/fixtures/p08-03/placement.gd:94)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: missing_connection domain refusal
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] build (res://tests/fixtures/p08-03/placement.gd:113)
[2] click (res://tests/fixtures/p08-03/placement.gd:94)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: lower_stair accepted
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] build (res://tests/fixtures/p08-03/placement.gd:111)
[2] click (res://tests/fixtures/p08-03/placement.gd:94)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: upper_stair accepted
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] build (res://tests/fixtures/p08-03/placement.gd:111)
[2] click (res://tests/fixtures/p08-03/placement.gd:94)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: refused_demolition result code
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] demolish (res://tests/fixtures/p08-03/placement.gd:145)
[2] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: refused_demolition result reason
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] demolish (res://tests/fixtures/p08-03/placement.gd:146)
[2] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: demolition result code
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] demolish (res://tests/fixtures/p08-03/placement.gd:145)
[2] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: rebuild accepted
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] build (res://tests/fixtures/p08-03/placement.gd:111)
[2] click (res://tests/fixtures/p08-03/placement.gd:94)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
ERROR: P08 placement: normal save
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:33)
[1] writer (res://tests/fixtures/p08-03/placement.gd:223)
[2] button (res://tests/fixtures/p08-03/placement.gd:73)
[3] frames (res://tests/fixtures/p08-03/placement.gd:65)
@@ -0,0 +1,6 @@
ERROR: P08 placement: whole formal resume model
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:36)
[1] reader (res://tests/fixtures/p08-03/placement.gd:249)
[2] frames (res://tests/fixtures/p08-03/placement.gd:68)
@@ -0,0 +1,15 @@
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
OpenGL API 4.1 Metal - 90.5 - Compatibility - Using Device: Apple - Apple M4
P08_ROOT_CUA_WAIT /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r04/os-pair/writer-request-0001/request.json
ERROR: P08 placement: OS initial formal model exact
at: push_error (core/variant/variant_utility.cpp:1023)
GDScript backtrace (most recent call first):
[0] expect (res://tests/fixtures/p08-03/placement.gd:37)
[1] setup (res://tests/fixtures/p08-03/passive_placement.gd:78)
[2] load_menu (res://tests/fixtures/p08-03/passive_placement.gd:155)
[3] request (res://tests/fixtures/p08-03/passive_placement.gd:51)
[4] frames (res://tests/fixtures/p08-03/placement.gd:71)
P08_ROOT_CUA_WAIT /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r04/os-pair/writer-request-0002/request.json
P08_ROOT_CUA_WAIT /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r04/os-pair/writer-request-0003/request.json
P08_ROOT_CUA_WAIT /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r04/os-pair/writer-request-0004/request.json
@@ -0,0 +1,8 @@
extends SceneTree
const Passive := preload("res://tests/fixtures/p08-03/passive_placement.gd")
func _initialize() -> void:
call_deferred("run")
func run() -> void:
var result: Dictionary = await Passive.new().run(self, OS.get_environment("P08_PLACEMENT_ROOT"), OS.get_environment("P08_PLACEMENT_ROLE"))
print("P08 passive OS placement: %d checks, %d failures" % [result.checks, result.failures])
quit(0 if result.failures == 0 else 1)
@@ -0,0 +1,5 @@
...................................
----------------------------------------------------------------------
Ran 35 tests in 18.245s
OK
@@ -0,0 +1,5 @@
.................................................
----------------------------------------------------------------------
Ran 49 tests in 44.792s
OK
@@ -0,0 +1,5 @@
........................................................
----------------------------------------------------------------------
Ran 56 tests in 49.916s
OK
@@ -0,0 +1,5 @@
...........................................................................
----------------------------------------------------------------------
Ran 75 tests in 66.488s
OK
@@ -0,0 +1,19 @@
..................F........................................................
======================================================================
FAIL: test_mock_native_controller_two_private_pids (__main__.EvidenceTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-implement/tools/test_p08_normal_placement_evidence.py", line 430, in test_mock_native_controller_two_private_pids
self.collector_mock()
File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-implement/tools/test_p08_normal_placement_evidence.py", line 423, in collector_mock
phases = D.collect_os(r,self.root,output,stage,str(Path(self.temp.name)/'synthetic-engine-not-executable'),'1'*40,refs,protected,outer)
File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-implement/tools/run_p08_normal_placement.py", line 120, in collect_os
r.require(passed, 'native OS collection failed: '+str(error or guards or cleanup_errors))
File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-implement/tools/run_all_tests.py", line 22, in require
if not ok: raise AssertionError(reason)
AssertionError: native OS collection failed: AssertionError: 900 != 2400
----------------------------------------------------------------------
Ran 75 tests in 64.918s
FAILED (failures=1)
@@ -0,0 +1,5 @@
...........................................................................
----------------------------------------------------------------------
Ran 75 tests in 65.333s
OK
@@ -0,0 +1,5 @@
...................................................................................
----------------------------------------------------------------------
Ran 83 tests in 73.589s
OK
@@ -0,0 +1,5 @@
...................................................................................
----------------------------------------------------------------------
Ran 83 tests in 75.150s
OK
@@ -0,0 +1,29 @@
{
"task_id": "P08-03",
"syntax": {
"method": "ast.parse in memory; no pyc",
"files": {
"tools/run_p08_normal_placement.py": "5cb1f58664a0bec71c8b5e853749d1c3656e0a2a027201e33fbaa6b0c0291fc6",
"tools/check_p08_normal_placement_evidence.py": "e3fea19be9952cd99be4df003734c43e6f81580b79984addb3622d81c1a2cc4e",
"tools/test_p08_normal_placement_evidence.py": "f75ce5a2aeee080864d252dc4285e32f107ce0b48b7f62dd598665a13ffa5637",
"tests/fixtures/p08-03/checker_fixture.py": "e83a94dfcfd490a99bd44ed71bd6c378de94413750cfce68dea938bfbbbf011f"
},
"passed": true
},
"checker_tests": {
"argv": [
"python3",
"tools/test_p08_normal_placement_evidence.py"
],
"exit_code": 0,
"log": "repair-r07-final-local-checker-tests.log",
"log_sha256": "60c535311af9c32b5f8ce706d88f99ef963217d000c1d12f8bcdd62b2a2ad0c3",
"test_count": 83,
"failures": 0
},
"native_engines_started": 0,
"OS_operations": 0,
"full_regression_executed": false,
"acceptance": "pending",
"local_source_manifest_sha256": "bd23d9f9ce58be85ebd3749112b281d7d71cf4eb9733d4aecf2e57a15f4e8ca7"
}
@@ -0,0 +1,5 @@
...................................................................................
----------------------------------------------------------------------
Ran 83 tests in 76.743s
OK
@@ -0,0 +1,5 @@
...................................................................................
----------------------------------------------------------------------
Ran 83 tests in 74.493s
OK
@@ -0,0 +1,10 @@
{
"method": "ast.parse in memory; no pyc",
"files": {
"tools/run_p08_normal_placement.py": "5cb1f58664a0bec71c8b5e853749d1c3656e0a2a027201e33fbaa6b0c0291fc6",
"tools/check_p08_normal_placement_evidence.py": "e3fea19be9952cd99be4df003734c43e6f81580b79984addb3622d81c1a2cc4e",
"tools/test_p08_normal_placement_evidence.py": "f75ce5a2aeee080864d252dc4285e32f107ce0b48b7f62dd598665a13ffa5637",
"tests/fixtures/p08-03/checker_fixture.py": "e83a94dfcfd490a99bd44ed71bd6c378de94413750cfce68dea938bfbbbf011f"
},
"passed": true
}
@@ -0,0 +1,29 @@
{
"task_id": "P08-03",
"syntax": {
"method": "ast.parse in memory; no pyc",
"files": {
"tools/run_p08_normal_placement.py": "5cb1f58664a0bec71c8b5e853749d1c3656e0a2a027201e33fbaa6b0c0291fc6",
"tools/check_p08_normal_placement_evidence.py": "e3fea19be9952cd99be4df003734c43e6f81580b79984addb3622d81c1a2cc4e",
"tools/test_p08_normal_placement_evidence.py": "f75ce5a2aeee080864d252dc4285e32f107ce0b48b7f62dd598665a13ffa5637",
"tests/fixtures/p08-03/checker_fixture.py": "e83a94dfcfd490a99bd44ed71bd6c378de94413750cfce68dea938bfbbbf011f"
},
"passed": true
},
"checker_tests": {
"argv": [
"python3",
"tools/test_p08_normal_placement_evidence.py"
],
"exit_code": 0,
"log": "repair10-final-local-checker-tests.log",
"log_sha256": "b3d9829ba6d23abf088f52231aef135d29b6d6dc3513a3d850ade9c2217316f9",
"test_count": 83,
"failures": 0
},
"native_engines_started": 0,
"OS_operations": 0,
"full_regression_executed": false,
"acceptance": "pending",
"local_source_manifest_sha256": "9f3e7ddb8cecf53d668dd4556f504e4fba26b29fb81dfe4b583ab060c6e6a9c8"
}
@@ -0,0 +1,32 @@
{
"task_id": "P08-03",
"repair": "Repair11",
"python_syntax": {
"status": "pass",
"method": "ast.parse in memory",
"paths": [
"tools/run_p08_normal_placement.py",
"tools/check_p08_normal_placement_evidence.py",
"tools/test_p08_normal_placement_evidence.py",
"tests/fixtures/p08-03/checker_fixture.py"
]
},
"checker": {
"command": "python3 -B tools/test_p08_normal_placement_evidence.py",
"tests": 88,
"failures": 0,
"exit_code": 0,
"elapsed_seconds": 71.298,
"output": "Ran 88 tests in 71.298s; OK",
"scope": "Python synthetic whole checker, historical checkpoint and static fixture controls only"
},
"not_executed": [
"Godot",
"native/OS",
"full175",
"Runner",
"independent review",
"integration"
],
"source_manifest_sha256": "0d33515d9ef33656fe13aab3f417a18a2b602047d6eb013b3f6b896f0330edf6"
}
@@ -0,0 +1,34 @@
{
"task_id": "P08-03",
"scope": "Repair13 local Python only; no gameplay acceptance",
"executed_sha256": {
"tools/check_p08_normal_placement_evidence.py": "73bff1e00c319b8e681953fe64497eefb53ece168d2d18e0b60951e65f66279d",
"tools/test_p08_normal_placement_evidence.py": "7e708a4429603166485b6f3267d887561d23bcf25b564d002473094e388476ca",
"tests/fixtures/p08-03/repair13_images.py": "248a8d73ece3a60e601421fdd2ad53f8f8e971184fb1328c7155a71b8ed4ca53"
},
"syntax_checks": 3,
"syntax": "pass",
"tests": {
"command": [
"python3",
"-B",
"tools/test_p08_normal_placement_evidence.py"
],
"exit_code": 0,
"stdout": "",
"stderr": "....................................................................................................\n----------------------------------------------------------------------\nRan 100 tests in 81.207s\n\nOK\n"
},
"verify_only": {
"command": [
"python3",
"-B",
"tools/check_p08_normal_placement_evidence.py",
"--verify-only"
],
"BUILD_OUTPUT_DIR": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/.runtime/P08-03/build",
"exit_code": 0,
"stdout": "{\"task_id\": \"P08-03\", \"integrity\": \"pass\", \"deficits\": [], \"acceptance\": \"pending\"}\n",
"stderr": ""
},
"acceptance": "pending"
}
@@ -0,0 +1,39 @@
# OUTSIDE CURRENT TASK SCOPE — NOT APPLIED — Root reconciles against standing full-game implementation authorization after concrete review; no approval inferred.
## Problem and concrete proposal
At HEAD 7e2368f5c453a3900ba1bb038d7138d25f7eb4fb, guest_stairs at (-8,2,0), without a path at (-8,1,0), has preview can_build=true but submit_command(build_facility) returns VALIDATION_FAILED / STAIR_LANDING_MISSING / 「先に階段の一つ下の階に通路を作ってください。」.
WorldPreview uses ConstructionService alone (scenes/main/world_preview.gd:201-218); Runtime performs additional checks (autoload/simulation_runtime.gd:7576-7615).
runtime_preview.patch is a concrete proposal against this HEAD. It is NOT applied. It changes exactly:
- autoload/simulation_runtime.gd
- scenes/main/world_preview.gd
- tests/transport/test_runtime_build_preview.gd (new)
- tests/transport/test_runtime_build_preview.gd.uid (new)
The private _build_facility_precheck(command_id, payload) returns CommandResult or null. Taking the raw payload rather than eagerly parsed parameters preserves the exact original order: operations gate, definition lookup/NOT_FOUND, unsupported vertical, origin parsing/INVALID_PAYLOAD, stair landing, busy elevator, rotation/INVALID_PAYLOAD. The existing prefix is moved unchanged; execution calls it, then reads the already-validated payload and calls start_construction unchanged. There is no copied domain rule in Main, WorldPreview or the checker.
The public read-only preview_build_facility(definition_id: StringName, origin: Vector3i, rotation: int) runs that helper and merges validate_placement(...).to_dictionary(). A failure forces can_build=false and prepends details.reason (or Code key) plus the exact message. Reasons retain PlacementReport's dictionary shape (code/message/cells/details), not strings. WorldPreview uses the guarded Runtime API, otherwise retains its old fallback, and keeps connection-report augmentation.
## Required reconciliation: recorded Main premise is false
The recorded direction says Main needs no change. Direct source inspection contradicts it: scenes/main/main.gd:2123-2131 selects the first error code and returns 「配置不可: <mapped code>」 before inspecting reason messages. STAIR_LANDING_MISSING is not mapped to the Runtime message. Thus the proposed patch fixes can_build but, by itself, cannot satisfy the specified exact displayed-message equality. No build-status hunk is applied or smuggled into this proposal. Root must reconcile this concrete source gap before applying a complete fix. Condition (1) remains blocked. The green UI is not hidden, recoloured or reworded.
## Purity check (current source; not a native execution)
- autoload/simulation_runtime.gd:7988-8002 _operations_construction_investment_gate reads gate/arrears and constructs a new result only; scripts/operations/operations_coordinator.gd:546-562 reads terminal/arrears/quarantine and returns a fresh dictionary.
- autoload/simulation_runtime.gd:1890-1891 and :4020-4027 sum payroll/upkeep; scripts/staff/staff_service.gd:198 builds a fresh obligations projection; scripts/economy/facility_upkeep_settlement.gd:94-98 sums existing debts.
- autoload/simulation_runtime.gd:6687-6688 _staff_assignment_failure only constructs CommandResult. No command queue, journal, ID allocation or event path is invoked.
- autoload/simulation_runtime.gd:12744-12759 _elevator_shaft_busy/_elevator_touches_module read dictionaries and definition fields. scripts/transport/elevator_service.gd:345-360 get_report duplicates shafts and computes local projection rows.
- scripts/world/path_service.gd:1415-1416 has_cell is a dictionary lookup.
- scripts/construction/construction_service.gd:56-111 validate_placement creates a local PlacementReport; :862-973 fill only that report using read-only world calls; :975-993 checks resource sufficiency. :1136-1144 _can_afford invokes the configured resource query. autoload/game_state.gd:44-48 and scripts/economy/ledger_backed_resource_state.gd:42-48 only read resources.
- scripts/world/world_service.gd:305 onward validate_support builds local structural sets/reports; :122 cells_for_footprint and :194 get_occupant are read queries. scripts/construction/placement_report.gd:36-61 modifies only the new report; :73 to_dictionary returns its projection.
These production dependencies contain no event emission, counters, command-log writes, RNG advance or model mutation in the preview call graph. Mutation begins in ConstructionService.start_construction (:114 onward), which the preview never calls. The helper may return a freshly allocated CommandResult without allocating a command ID; preview never calls submit_command. Purity must also be checked natively through byte-identical typed snapshots after Root applies the proposal; source review is not execution proof.
## Test impact and pending targeted checks
Expected unchanged outcomes: tests/transport/test_runtime_stairs.gd; tests/s1/test_construction_service.gd; tests/mvp/test_original_room_zones.gd; tests/ui/test_main_dashboard.gd; tests/ui/test_pixel_tower.gd. Related fixtures tests/fixtures/p08-03/placement.gd and passive_placement.gd require fresh native evidence after the combined product correction.
The new proposed test asserts:
- failing-cell preview false, STAIR_LANDING_MISSING and exact Runtime message;
- var_to_bytes(create_snapshot()) byte identity before/after preview;
- command reason/message equality at the same cell;
- with diagnostic path at (-8,1,0), preview true and command OK (existing initial reception supplies support);
- operations gate and unsupported-vertical precedence over landing (explicit test doubles isolate ordering, existing domain tests retain real values);
- WorldPreview surfaces the Runtime code.
No GDScript test was run. The patch is checked only with git apply --check. It is a proposal, not acceptance or an applied Runtime change.
@@ -0,0 +1,169 @@
diff --git a/autoload/simulation_runtime.gd b/autoload/simulation_runtime.gd
--- a/autoload/simulation_runtime.gd
+++ b/autoload/simulation_runtime.gd
@@ -7573,18 +7573,33 @@
return CommandResult.failed(CommandResult.Code.TRANSACTION_APPLY_FAILED, command.command_id, failure_message)
return CommandResult.succeeded(command.command_id, {&"request_id": request_id, &"reason": &"GUEST_LEFT"})
-func _execute_build_facility(command: SimulationCommand) -> CommandResult:
- var operations_gate := _operations_construction_investment_gate(command.command_id)
+func preview_build_facility(definition_id: StringName, origin: Vector3i, rotation: int) -> Dictionary:
+ var failure := _build_facility_precheck(0, {&"definition_id": definition_id, &"origin": origin, &"rotation": rotation})
+ var definition := definition_registry.get_facility(definition_id)
+ var report: Dictionary = construction_service.validate_placement(definition, origin, rotation).to_dictionary()
+ if failure != null:
+ report[&"can_build"] = false
+ var code := String(failure.details.get(&"reason", CommandResult.Code.keys()[failure.code]))
+ var codes: Array = Array(report.get(&"error_codes", []))
+ var reasons: Array = Array(report.get(&"reasons", []))
+ codes.push_front(code)
+ reasons.push_front({&"code": code, &"message": failure.message, &"cells": [], &"details": failure.details.duplicate(true)})
+ report[&"error_codes"] = codes
+ report[&"reasons"] = reasons
+ return report
+
+func _build_facility_precheck(command_id: int, payload: Dictionary) -> CommandResult:
+ var operations_gate := _operations_construction_investment_gate(command_id)
if operations_gate != null:
return operations_gate
- var definition_id := StringName(command.payload.get(&"definition_id", command.payload.get("definition_id", "")))
+ var definition_id := StringName(payload.get(&"definition_id", payload.get("definition_id", "")))
var definition := definition_registry.get_facility(definition_id)
if definition == null:
- return CommandResult.failed(CommandResult.Code.NOT_FOUND, command.command_id, "Facility definition was not found.")
+ return CommandResult.failed(CommandResult.Code.NOT_FOUND, command_id, "Facility definition was not found.")
if _facility_definition_is_unsupported_vertical_proxy(definition):
return CommandResult.failed(
CommandResult.Code.VALIDATION_FAILED,
- command.command_id,
+ command_id,
"Vertical infrastructure topology is not supported.",
{
&"reason": FacilityInfrastructureProjector.REASON_UNSUPPORTED_VERTICAL_TOPOLOGY,
@@ -7592,18 +7607,28 @@
&"unchanged": true,
}
)
- var origin_value: Variant = _parse_world_cell(command.payload.get(&"origin", command.payload.get("origin", null)))
+ var origin_value: Variant = _parse_world_cell(payload.get(&"origin", payload.get("origin", null)))
if origin_value == null:
- return CommandResult.failed(CommandResult.Code.INVALID_PAYLOAD, command.command_id, "origin must be Vector3i or [x, y, layer].")
+ return CommandResult.failed(CommandResult.Code.INVALID_PAYLOAD, command_id, "origin must be Vector3i or [x, y, layer].")
var origin: Vector3i = origin_value
if definition.id in [&"guest_stairs", &"service_stairs"] and not path_service.has_cell(origin + Vector3i(0, -1, 0)):
- return _staff_assignment_failure(command.command_id, &"STAIR_LANDING_MISSING", "先に階段の一つ下の階に通路を作ってください。")
+ return _staff_assignment_failure(command_id, &"STAIR_LANDING_MISSING", "先に階段の一つ下の階に通路を作ってください。")
for shaft: Dictionary in elevators.get_report()[&"shafts"]:
if _elevator_touches_module(shaft, definition, origin) and _elevator_shaft_busy(shaft):
- return _staff_assignment_failure(command.command_id, &"ELEVATOR_BUSY", "Wait until the shaft is idle before extending it.")
+ return _staff_assignment_failure(command_id, &"ELEVATOR_BUSY", "Wait until the shaft is idle before extending it.")
+ var rotation := int(payload.get(&"rotation", payload.get("rotation", 0)))
+ if rotation not in definition.allowed_rotations:
+ return CommandResult.failed(CommandResult.Code.INVALID_PAYLOAD, command_id, "The selected rotation is not allowed.")
+ return null
+
+func _execute_build_facility(command: SimulationCommand) -> CommandResult:
+ var failure := _build_facility_precheck(command.command_id, command.payload)
+ if failure != null:
+ return failure
+ var definition_id := StringName(command.payload.get(&"definition_id", command.payload.get("definition_id", "")))
+ var definition := definition_registry.get_facility(definition_id)
+ var origin: Vector3i = _parse_world_cell(command.payload.get(&"origin", command.payload.get("origin", null)))
var rotation := int(command.payload.get(&"rotation", command.payload.get("rotation", 0)))
- if rotation not in definition.allowed_rotations:
- return CommandResult.failed(CommandResult.Code.INVALID_PAYLOAD, command.command_id, "The selected rotation is not allowed.")
var result := construction_service.start_construction(
definition,
origin,
diff --git a/scenes/main/world_preview.gd b/scenes/main/world_preview.gd
--- a/scenes/main/world_preview.gd
+++ b/scenes/main/world_preview.gd
@@ -202,6 +202,13 @@
var target: Variant = _hovered_cell if cell == null else cell
if build_definition == null or not target is Vector3i:
return INVALID_PREVIEW.duplicate(true)
+ if _runtime != null and _runtime.has_method(&"preview_build_facility"):
+ var result: Dictionary = _runtime.call(&"preview_build_facility", build_definition.id,
+ Vector3i(target.x, target.y, layer_mode), build_rotation)
+ result[&"connection"] = _build_connection_report(
+ _cells_from_serialized(result.get(&"cells", [])),
+ Vector3i(target.x, target.y, layer_mode))
+ return result
var construction: Variant = _service(&"construction_service")
if construction != null and construction.has_method(&"validate_placement"):
var report: Variant = construction.call(
diff --git a/tests/transport/test_runtime_build_preview.gd b/tests/transport/test_runtime_build_preview.gd
new file mode 100644
--- /dev/null
+++ b/tests/transport/test_runtime_build_preview.gd
@@ -0,0 +1,64 @@
+extends SceneTree
+
+var failures := 0
+
+class GatedRuntime extends SimulationRuntimeService:
+ var block_operations := false
+ var block_vertical := false
+ func _operations_construction_investment_gate(command_id: int) -> CommandResult:
+ if block_operations:
+ return CommandResult.failed(CommandResult.Code.VALIDATION_FAILED, command_id,
+ "Operations currently block construction and investment.", {&"reason": &"ARREARS_REMAIN"})
+ return super._operations_construction_investment_gate(command_id)
+ func _facility_definition_is_unsupported_vertical_proxy(definition: Variant) -> bool:
+ return block_vertical or super._facility_definition_is_unsupported_vertical_proxy(definition)
+
+func _initialize() -> void:
+ call_deferred("_run")
+
+func check(ok: bool, message: String) -> void:
+ if not ok:
+ failures += 1
+ push_error(message)
+
+func _run() -> void:
+ var runtime := GatedRuntime.new()
+ var clock := load("res://autoload/game_clock.gd").new()
+ var state := load("res://autoload/game_state.gd").new()
+ clock.reset(1, 6, 0)
+ state.reset()
+ check(runtime.initialize(clock, state, 90416)[&"valid"], "initialize")
+ runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
+ clock.set_paused(true)
+ var cell := Vector3i(-8, 2, 0)
+ var message := "先に階段の一つ下の階に通路を作ってください。"
+ var before := var_to_bytes(runtime.create_snapshot())
+ var report := runtime.preview_build_facility(&"guest_stairs", cell, 0)
+ check(not report[&"can_build"] and "STAIR_LANDING_MISSING" in report[&"error_codes"], "missing landing preview")
+ check(report[&"reasons"][0][&"message"] == message, "Runtime message")
+ check(before == var_to_bytes(runtime.create_snapshot()), "typed save snapshot byte identity")
+ var view := load("res://scenes/main/world_preview.gd").new()
+ view.set_runtime(runtime)
+ view.set_build_definition(runtime.definition_registry.get_facility(&"guest_stairs"))
+ check("STAIR_LANDING_MISSING" in view.get_build_preview_report(cell)[&"error_codes"], "WorldPreview surfaces Runtime")
+ var refused := runtime.submit_command(&"build_facility", {&"definition_id": &"guest_stairs", &"origin": cell})
+ check(refused.details.get(&"reason") == &"STAIR_LANDING_MISSING" and refused.message == message, "command agrees")
+ # Diagnostic path setup; existing reception supplies structural support.
+ var walkable: Array[Vector3i] = runtime.world_service.get_walkable_cells()
+ walkable.append(Vector3i(-8, 1, 0))
+ check(runtime.path_service.rebuild_graph(walkable), "diagnostic landing path")
+ report = runtime.preview_build_facility(&"guest_stairs", cell, 0)
+ var accepted := runtime.submit_command(&"build_facility", {&"definition_id": &"guest_stairs", &"origin": cell})
+ check(report[&"can_build"] and accepted.is_success(), "landing positive agreement")
+ runtime.block_operations = true
+ runtime.block_vertical = true
+ report = runtime.preview_build_facility(&"guest_stairs", Vector3i(-8, 4, 0), 0)
+ check(report[&"error_codes"][0] == "ARREARS_REMAIN", "operations precedence")
+ runtime.block_operations = false
+ report = runtime.preview_build_facility(&"guest_stairs", Vector3i(-8, 4, 0), 0)
+ check(report[&"error_codes"][0] == String(FacilityInfrastructureProjector.REASON_UNSUPPORTED_VERTICAL_TOPOLOGY), "vertical precedence")
+ view.free()
+ runtime.free()
+ clock.free()
+ state.free()
+ quit(1 if failures else 0)
diff --git a/tests/transport/test_runtime_build_preview.gd.uid b/tests/transport/test_runtime_build_preview.gd.uid
new file mode 100644
--- /dev/null
+++ b/tests/transport/test_runtime_build_preview.gd.uid
@@ -0,0 +1 @@
+uid://cpxbldpreview
+126 -9
View File
@@ -148,6 +148,11 @@ var world_preview: WorldPreview
var front_button: Button
var back_button: Button
var excavation_button: Button
var demolition_button: Button
var demolition_dialog: ConfirmationDialog
var _demolition_mode := false
var _demolition_target: StringName = &""
var _pending_demolition_commands: Dictionary = {}
var pan_button: Button
var pause_button: Button
var speed_buttons: Dictionary = {}
@@ -790,12 +795,20 @@ func _create_bottom_bar() -> Control:
palette_scroll.custom_minimum_size.y = 62
palette_scroll.visible = false
column.add_child(palette_scroll)
var palette_row := HBoxContainer.new()
palette_row.name = "BuildPaletteRow"
palette_row.add_theme_constant_override("separation", 4)
palette_scroll.add_child(palette_row)
var grid := GridContainer.new()
grid.name = "BuildPalette"
grid.columns = MVP_FACILITY_IDS.size()
grid.add_theme_constant_override("h_separation", 4)
grid.add_theme_constant_override("v_separation", 0)
palette_scroll.add_child(grid)
palette_row.add_child(grid)
demolition_button = _button("撤去", _toggle_demolition_mode, 72)
demolition_button.name = "DemolitionButton"
demolition_button.toggle_mode = true
palette_row.add_child(demolition_button)
build_status_label = Label.new()
build_status_label.name = "BuildStatusLabel"
@@ -1241,6 +1254,7 @@ func _select_build_definition(definition_id: StringName) -> void:
if definition == null:
_set_status("選択した施設定義が見つかりません。", false)
return
_set_demolition_mode(false, false)
_set_excavation_mode(false, false)
_set_pan_mode(false)
_selected_definition_id = definition_id
@@ -1267,6 +1281,9 @@ func _clear_build_selection(announce := true) -> void:
func _clear_active_tool() -> void:
if _demolition_mode:
_set_demolition_mode(false)
return
if world_preview.pan_mode:
_set_pan_mode(false)
_set_status("画面移動を解除しました。施設をクリックすると情報を表示します。", true, true)
@@ -1299,6 +1316,7 @@ func _toggle_pan_mode() -> void:
func _set_pan_mode(enabled: bool) -> void:
if enabled:
_set_demolition_mode(false, false)
_clear_build_selection(false)
_set_excavation_mode(false, false)
_set_build_palette_open(false)
@@ -1309,6 +1327,7 @@ func _set_pan_mode(enabled: bool) -> void:
func _set_excavation_mode(enabled: bool, announce := true) -> void:
if enabled:
_set_demolition_mode(false, false)
_set_pan_mode(false)
_excavation_mode = enabled
if excavation_button != null:
@@ -1354,6 +1373,9 @@ func _rotate_build_preview() -> void:
func _on_map_cell_clicked(cell: Vector3i) -> void:
if _audio_feedback != null:
_audio_feedback.request_click()
if _demolition_mode:
_preview_demolition(cell)
return
if _excavation_mode:
_start_excavation(cell)
return
@@ -2102,7 +2124,19 @@ func _preview_failure_message(report: Dictionary) -> String:
var codes_value: Variant = report.get(&"error_codes", [])
if codes_value is Array and not codes_value.is_empty():
var code := String(codes_value[0])
return "配置不可: %s" % PREVIEW_REASON_NAMES.get(code, code)
if PREVIEW_REASON_NAMES.has(code):
return "配置不可: %s" % PREVIEW_REASON_NAMES[code]
var code_reasons: Variant = report.get(&"reasons", [])
if code_reasons is Array and not code_reasons.is_empty():
var reason: Variant = code_reasons[0]
for candidate: Variant in code_reasons:
if candidate is Dictionary and String(candidate.get(&"code", "")) == code:
reason = candidate
break
if reason is Dictionary:
var message := String(reason.get(&"message", ""))
if not message.is_empty():
return "配置不可: %s" % message
var reasons_value: Variant = report.get(&"reasons", [])
if reasons_value is Array and not reasons_value.is_empty() and reasons_value[0] is Dictionary:
return "配置不可: %s" % String(reasons_value[0].get(&"message", "条件を満たしていません"))
@@ -2331,6 +2365,8 @@ func _apply_loaded_interface(result: Dictionary) -> void:
if _audio_feedback != null:
_audio_feedback.begin_loaded_epoch(_current_audio_foreground())
_pending_build_commands.clear()
_pending_demolition_commands.clear()
_set_demolition_mode(false, false)
_pending_excavation_commands.clear()
_pending_hire_commands.clear()
_pending_elevator_commands.clear()
@@ -2570,6 +2606,10 @@ func _on_snapshot_published(_snapshot: Dictionary = {}, _digest: String = "") ->
func _on_command_completed(result: Variant) -> void:
if result == null:
return
if _pending_demolition_commands.has(int(result.command_id)):
_pending_demolition_commands.erase(int(result.command_id))
_show_demolition_result(result)
return
if _pending_related_commands.has(int(result.command_id)):
_pending_related_commands.erase(int(result.command_id))
_set_status("関連施設の設定を反映しました。" if result.is_success() else result.message, result.is_success())
@@ -2753,17 +2793,17 @@ func _phase_name(phase: GameClock.Phase) -> String:
return "夜"
const RESOURCE_TITLES := {&"gold": "所持金", &"mana": "マナ", &"materials": "資材", &"faith": "信仰"}
func _resource_title(resource_name: StringName) -> String:
return String(RESOURCE_TITLES.get(resource_name, String(resource_name)))
func _on_resource_changed(resource_name: StringName, value: int) -> void:
if not resource_labels.has(resource_name):
return
var titles := {
&"gold": "所持金",
&"mana": "マナ",
&"materials": "資材",
&"faith": "信仰",
}
var label := resource_labels[resource_name] as Label
label.text = "%s %d" % [titles[resource_name], value]
label.text = "%s %d" % [_resource_title(resource_name), value]
if resource_name == &"mana":
label.mouse_filter = Control.MOUSE_FILTER_STOP
label.tooltip_text = "残量0で全館停止。接客・調理・搬入・エレベーターと新規入館が停止します。\n残量と配電が回復すると再開します。破壊・摘発による休止は解除されません。"
@@ -3083,3 +3123,80 @@ func _submit_ui_command(
if _audio_feedback != null:
return _audio_feedback.submit_command(command_type, payload, actor_id, target_id, priority, execute_at, idempotency_key)
return _runtime.call(&"submit_command", command_type, payload, actor_id, target_id, priority, execute_at, idempotency_key)
func _toggle_demolition_mode() -> void:
_set_demolition_mode(not _demolition_mode)
func _set_demolition_mode(enabled: bool, announce := true) -> void:
if enabled:
_set_pan_mode(false)
_set_excavation_mode(false, false)
_clear_build_selection(false)
_demolition_mode = enabled
_demolition_target = &""
if demolition_dialog != null:
demolition_dialog.hide()
if demolition_button != null:
demolition_button.set_pressed_no_signal(enabled)
if world_preview != null:
world_preview.set_demolition_mode(enabled)
if announce:
_set_status("撤去する施設のマスを選択してください。確認画面で取り消せます。" if enabled else "撤去モードを解除しました。", true, true)
func _preview_demolition(cell: Vector3i) -> void:
# Selection only; Runtime owns eligibility, occupancy and refunds.
_demolition_target = world_preview.facility_at_canvas(world_preview.cell_to_canvas(cell))
world_preview.selected_entity_id = _demolition_target
if demolition_dialog == null:
demolition_dialog = ConfirmationDialog.new()
demolition_dialog.name = "DemolitionDialog"
demolition_dialog.title = "施設の撤去"
demolition_dialog.ok_button_text = "撤去する"
demolition_dialog.cancel_button_text = "戻る"
demolition_dialog.confirmed.connect(_confirm_demolition)
demolition_dialog.canceled.connect(_cancel_demolition)
add_child(demolition_dialog)
_apply_button_style(demolition_dialog.get_ok_button())
_apply_button_style(demolition_dialog.get_cancel_button())
demolition_dialog.dialog_text = "座標 (%d, %d / %d)\n施設: %s\n\n撤去を指示しますか?" % [cell.x, cell.y, cell.z, String(_demolition_target)]
demolition_dialog.popup_centered(Vector2i(420, 210))
func _cancel_demolition() -> void:
_demolition_target = &""
_set_status("撤去を取り消しました。", true, true)
func _confirm_demolition() -> void:
if not _demolition_mode:
return
if _runtime == null or not _runtime.has_method(&"submit_command"):
_set_status("Simulation Runtimeへ接続できません。", false)
return
var target := _demolition_target
_demolition_target = &""
var result: CommandResult = _runtime.submit_command(&"demolish_facility", {&"instance_id": target})
# Paused play returns execution synchronously; running play returns acceptance.
if result.is_success() and _runtime.command_queue.get_processed_result(result.command_id) == null:
_pending_demolition_commands[result.command_id] = target
_set_status("撤去を受け付けました", true)
return
_show_demolition_result(result)
func _show_demolition_result(result: CommandResult) -> void:
if result.is_success():
var refund: Dictionary = result.details.get(&"refund", {})
var keys: Array = refund.keys()
keys.sort()
var amounts: PackedStringArray = []
for key: Variant in keys:
if int(refund[key]) != 0:
amounts.append("%s %d" % [_resource_title(StringName(key)), int(refund[key])])
_set_status("撤去しました(返金: %s)" % "、".join(amounts) if not amounts.is_empty() else "撤去しました(返金なし)", true)
else:
_set_status("撤去できません: " + result.message, false)
_refresh_selected_entity()
world_preview.queue_redraw()
+19 -1
View File
@@ -51,6 +51,7 @@ var selected_entity_id: StringName = &"":
var build_definition: Variant = null
var build_rotation := 0
var excavation_mode := false
var demolition_mode := false
var visual_theme: VisualThemeProfile = null
var zoom_level := 1.0
@@ -134,6 +135,8 @@ func set_visual_theme(profile: VisualThemeProfile) -> void:
func set_build_definition(definition: Variant, rotation := 0) -> void:
if definition != null:
demolition_mode = false
if definition != null and excavation_mode:
set_excavation_mode(false)
build_definition = definition
@@ -157,6 +160,8 @@ func set_build_rotation(value: int) -> void:
func set_excavation_mode(enabled: bool) -> void:
if enabled:
demolition_mode = false
if excavation_mode == enabled:
_update_excavation_preview()
return
@@ -197,6 +202,12 @@ func get_build_preview_report(cell: Variant = null) -> Dictionary:
var target: Variant = _hovered_cell if cell == null else cell
if build_definition == null or not target is Vector3i:
return INVALID_PREVIEW.duplicate(true)
if _runtime != null and _runtime.has_method(&"preview_build_facility"):
var result: Dictionary = _runtime.call(&"preview_build_facility", build_definition.id, Vector3i(target.x, target.y, layer_mode), build_rotation)
result[&"connection"] = _build_connection_report(
_cells_from_serialized(result.get(&"cells", [])),
Vector3i(target.x, target.y, layer_mode))
return result
var construction: Variant = _service(&"construction_service")
if construction != null and construction.has_method(&"validate_placement"):
var report: Variant = construction.call(
@@ -461,7 +472,7 @@ func _gui_input(event: InputEvent) -> void:
var cell: Variant = canvas_to_cell(event.position)
if not cell is Vector3i:
return
if build_definition != null or excavation_mode:
if build_definition != null or excavation_mode or demolition_mode:
cell_clicked.emit(cell)
accept_event()
return
@@ -1685,3 +1696,10 @@ func _draw_build_connection(report: Dictionary) -> void:
var message := "入口への経路接続済" if status == &"CONNECTED" else "入口への経路未接続" if status == &"DISCONNECTED" else "入口・経路を確認できません"
draw_string(ThemeDB.fallback_font, target+Vector2(8,-12), message,
HORIZONTAL_ALIGNMENT_LEFT, -1, 13, color)
func set_demolition_mode(enabled: bool) -> void:
demolition_mode = enabled
if enabled:
clear_build_definition()
set_excavation_mode(false)
queue_redraw()
+444
View File
@@ -0,0 +1,444 @@
"""Synthetic checker specimens only. No native/OS execution or acceptance claim.
The JSON, Variant stand-ins, executable and lifecycle records here are deliberately
fabricated unit-test data, never collector output. Semantic corruption tests repin
their bytes, so they cannot pass merely by detecting a stale artifact checksum.
"""
import copy
import json
import hashlib
import json
from pathlib import Path
import shutil
import struct
import zlib
import subprocess
def put(path, data):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data, ensure_ascii=False, indent=2)+'\n')
def typed(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(v) for v in value]}
name = 'bool' if isinstance(value, bool) else 'int' if isinstance(value, int) else 'float' if isinstance(value, float) else 'Nil' if value is None else 'String'
return {'type': name, 'text': json.dumps(value, ensure_ascii=False)}
def owner_proof(folder, pid, checker):
"""Fabricated weak-reference records, only for the whole-parser control."""
directory = folder/'teardown'; audio = directory/'owned-audio'
audio.mkdir(parents=True)
before = {'owner_ids':[1], 'owner_meta_present':True, 'closing':False,
'clock_process':True,'clock_physics_process':False,'clock_process_mode':0,
'root_gui_disable_input':False,'auto_accept_quit':False,'original_auto_accept_quit':True}
after = dict(before, owner_ids=[], owner_meta_present=False, auto_accept_quit=True)
control = {'owned_engine_pid':pid,'owner_instance_id':1,'passed':True,
'maximum_wait_us':500000,'whole_Runtime_field_deletions':0,
'before':before,'after':after,'expected_remaining_owner_ids':[]}
for key in ('ordinary_owner_release_verified','clock_process_flags_unchanged',
'root_gui_input_flag_unchanged','audio_teardown_passed'): control[key] = True
for key in ('gameplay_expectations_changed','clock_flags_intentionally_modified','application_close_called',
'SceneTree_quit_overridden','WindowQuit_verified','formal_acceptance'): control[key] = False
put(directory/'control.json', control)
targets = [{'kind':kind,'role':role,'instance_id':i*4+j+1,'alive':True}
for i,kind in enumerate(('stream','packet_sequence')) for j,role in enumerate(('click','success','refusal','notification'))]
proof = {'owned_engine_pid':pid,'owner_instance_id':1,'passed':True,'maximum_wait_us':500000,
'waited_actual_us':100,'deadline_reached':False,'initial_targets':targets,
'final_targets':[dict(t,alive=False) for t in targets], 'full_typed_snapshots':{}}
for key in ('owner_freed','all_owned_targets_released','whole_runtime_unchanged'): proof[key] = True
for key in ('bus_deleted','cues_muted_for_test','actual_human_hearing','WindowQuit_verified','formal_acceptance'): proof[key] = False
for part in ('before','after'):
path = audio/('owner_1-'+part+'.varbytes')
path.write_bytes(b'SYNTHETIC typed bytes; not engine proof')
proof['full_typed_snapshots'][part] = {'path':str(path),'field_deletions':0,'bytes':path.stat().st_size,'sha256':checker.sha(path)}
put(audio/'owner_1.json', proof)
owners = checker.module('synthetic_owner_parser', checker.HERE/'regression/ordinary_proof_gate.py')
return owners.ordinary_gate(directory,pid,folder,['single'])
def make(base, source, checker):
root, out = base/'source', base/'p08-normal-placement-evidence'
for folder in ('autoload', 'scripts', 'scenes', 'data', 'tests', 'assets', 'tools'):
(root/folder).mkdir(parents=True, exist_ok=True)
for name in ('project.godot', 'export_presets.cfg', 'Makefile', 'AGENTS.md', checker.SPEC,
checker.CONTRACT, checker.TEST, checker.RECORDER, checker.RECORDER+".uid",
"tools/run_p08_normal_placement.py",
'docs/plans/original-completion-2026-10-02/IMPLEMENTATION_PLAN.md',
'docs/traceability/original/BASELINE.txt', 'data/facilities/reception.tres',
'data/facilities/standard_room.tres',
'data/facilities/infrastructure/guest_stairs.tres'):
target = root/name
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source/name, target)
(root/'tests/fixtures/p08-03').mkdir(parents=True)
out.mkdir()
engine = base/'synthetic-engine-not-executable'
engine.write_text('SYNTHETIC TEST DATA; NEVER EXECUTE\n')
sha = checker.sha
source_map = {n: v['sha256'] for n, v in checker.runner.source_refs(root).items()}
index = {'schema': 'p08-normal-placement-v1', 'commit': subprocess.check_output(['git','-C',str(source),'rev-parse','HEAD'],text=True).strip(), 'source_map': source_map,
'inputs': checker.input_map(root), 'spec_sha256': checker.SPEC_SHA,
'marker_contract_sha256': sha(root/checker.CONTRACT), 'conditions': checker.CONDITIONS,
'collection_error': None, 'acceptance': 'pending', 'regression': None}
put(out/'runner-input.json', {'selected_source_map': source_map, 'commit': index['commit'],
'engine': str(engine), 'engine_sha256': sha(engine)})
put(out/'runner-ended.json', {'error': None, 'cleanup_errors': [], 'synthetic': True})
def phase(label, pid):
prefix = 'runs/'+label+'/'
command = [str(engine), '--headless', '--path', str(root), '--script', label]
raw = {'actual_pid': pid, 'command': command, 'live_identity_exact': True,
'engine_ended': True, 'exit_code': 0, 'synthetic': True}
for name in ('started.json', 'ended.json'):
put(out/(prefix+label+'/'+name), raw)
put(out/(prefix+label+'/outer-owned-finally.json'), {'actual_captured_pids': [pid],
'all_captured_ended': True, 'outer_cleanup_errors': [], 'foreign_process_or_group_signals': 0})
(out/(prefix+'stdout.log')).write_text('Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org\nP08 normal placement: 100 checks, 0 failures\n')
receipt = {'actual_pid': pid, 'command': command, 'phase': label, 'test': checker.TEST,
'source_sha256': source_map[checker.TEST], 'log': 'stdout.log',
'exit_code': 0, 'engine_ended': True, 'failed': False,
'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': label, 'expected_user_data_dir': label}}}
name = prefix+label+'-receipt.json'
put(out/name, receipt)
return name
pair_phases = [phase('writer', 101), phase('reader', 102)]
os_phases = []
index['cases'] = [{'directory': 'pair', 'phases': pair_phases}]
index['phases'] = pair_phases
index['os_proof'] = 'os.json'
put(out/'os.json', {'source_map': source_map, 'inputs': index['inputs'], 'input_method': 'native_os',
'observer_mutations': [], 'phases': os_phases, 'directory': 'os-pair', 'synthetic': True})
def pair(directory, pids, method):
folder = out/directory
folder.mkdir()
runtime = {k: {} for k in sorted(checker.RUNTIME_KEYS)}
runtime.update(world={'occupancies': [], 'bounds':{'min_x':-10,'max_y':10}}, construction={'facilities': [], 'jobs': []},
id_generator={'version':1,'counters':{'domain_event':7}},
domain_events={'version':1,'published_ids':[],'recent_events':[]},
facilities={'instances': []}, next_command_id=1,
command_queue={'processed': [], 'pending': [], 'in_flight': [], 'accepted': [], 'idempotency': {}})
model = {'schema_version': 1, 'clock': {'absolute_minute': 360, 'paused': True},
'game_state': {'resources': {'gold': 5000, 'materials': 50}}, 'systems': {'runtime': runtime}}
runtime['domain_events']['published_ids'] = ['domain_event.%012d' % n for n in range(1,8)]
runtime['domain_events']['recent_events'] = [
{'event_id':'domain_event.%012d' % n, 'event_type':'SYNTHETIC_HISTORY',
'absolute_minute':360, 'source_service':'synthetic', 'entity_ids':[],
'payload':{'ordinal':n}, 'causation_command_id':0} for n in range(1,8)]
target = [-8, 0, 0]
cost = {'reception': {'gold': 500, 'materials': 8}, 'guest_stairs': {'gold': 40, 'materials': 0}, 'standard_room':{'gold':350,'materials':5}}
rooms = 0
def snap(name):
# Synthetic controls follow the same split as Runtime: stairs are
# construction instances with infrastructure, never operational rooms.
projections = []
entities = []; connectors = []
for f in runtime['construction']['facilities']:
if f['definition_id'] != 'guest_stairs': continue
f.update(rotation=0, layer=0, completed_at=360)
fid = f['instance_id']; origin = f['origin']
p = {k:copy.deepcopy(f[k]) for k in ('instance_id','definition_id','origin','source_job_id','rotation','layer','completed_at')}
p.update(kind='guest_stairs', route_entity_id='infra.route:'+fid,
connector_id='infra.connector:'+fid, cells=f['occupied_cells'], staff_only=False,
pass_through=True, footprint=[1,1], definition_tags=['guest_access','movement','route_subslot','schema_facility_proxy','stairs','vertical_connector'])
canonical = 'projection|'+''.join('%d:%s|' % (len(p[k]),p[k]) for k in ('instance_id','definition_id','kind','route_entity_id','connector_id','source_job_id'))
canonical += 'layer=0|staff=0|pass=1|footprint=1,1|rotation=0|completed=360|'
canonical += 'origin=%d,%d,%d|tags=' % tuple(origin)
canonical += ''.join('%d:%s;' % (len(t),t) for t in p['definition_tags'])+'|cells='
canonical += ''.join('%d,%d,%d;' % tuple(c) for c in p['cells'])
p['record_fingerprint'] = hashlib.sha256(canonical.encode()).hexdigest()
projections.append(p)
entities.append({'entity_id':p['route_entity_id'],'category':'ROUTE','cells':p['cells']})
connectors.append({'id':p['connector_id'],'from':origin,'to':[origin[0],origin[1]-1,origin[2]],
'cost':150,'bidirectional':True,'access_id':'','enabled':True,'movement_type':'CONNECTOR',
'dynamic_cost':0,'operational_state':'OPERATIONAL','cabin_capacity':8,'queue_capacity':256,
'cabin_state':'IDLE','current_floor':origin[1],'travel_minutes_per_floor':1,'request_queue':[]})
runtime['facility_infrastructure'] = {'projections':projections}
runtime['spatial_subslots'] = {'entities':entities}
route_cells = [c for p in projections for c in p['cells']]
walkable = [[4,0,0]]+route_cells
runtime['route_projection'] = {'base_walkable_cells':[[4,0,0]],'projected_route_cells':route_cells,'projected_walkable_cells':walkable}
runtime['path'] = {'connectors':connectors,'vertical_walk_blockers':[], 'cell_traffic':[{'cell':c} for c in walkable]}
put(folder/(name+'.json'), typed(model))
(folder/(name+'.var')).write_bytes(json.dumps(model, sort_keys=True).encode())
return name
def position(cell):
return {'world_cell': cell[:], 'selected_cell': cell[:], 'bounds': {'min_x': -10, 'max_y': 10},
'map_position': [0, 0], 'cell_dimensions': [10, 10],
'local': [(cell[0]+10.5)*10, (10.5-cell[1])*10],
'viewport_transform':[1,0,0,1,0,0], 'screen_transform':[1,0,0,1,0,0],
'screen':[(cell[0]+10.5)*10, (10.5-cell[1])*10],
'viewport': [(cell[0]+10.5)*10, (10.5-cell[1])*10], 'zoom': 1.0, 'pan': [0, 0]}
def result(code, details=None, message=''):
row = {'code': code, 'details': details or {}, 'message': message,
'command_id': runtime['next_command_id'], 'target_id': '', 'is_replay': False, 'resolution_hints': []}
runtime['next_command_id'] += 1
runtime['command_queue']['processed'].append(copy.deepcopy(row))
return row
os_sequences = {}
def os_meta(row, pid):
row['input_method'] = method
if method != 'native_os': return
p = row['position']
p['dispatch'] = {k:copy.deepcopy(v) for k,v in p.items() if k != 'selected_cell'}
occupant = next((o['entity_id'] for o in runtime['world']['occupancies'] if p['world_cell'] in o['cells']), '')
p['selection'] = {'required':row['id'] == 'pan_zoom', 'entity_id':occupant, 'occupant_id':occupant}
p['diagnostics'] = {'getter_cell':[]}
requests = [{'action':'cell', 'world_cell':row['position']['world_cell'],
'viewport':row['position']['viewport'], 'screen':row['position']['screen'],
'viewport_to_screen':[1,0,0,1,0,0], 'guide_visible':False, 'guide_rect':[0,0,0,0]}]
if row['id'] in ('unsupported','resume_overlap'):
requests.append({'action':'load_menu'})
if row['id'] == 'pan_zoom':
requests.append({'action':'button','node':'/root/Main/ManualSaveButton'})
requests += [{'action':'wheel','ctrl':False,'move_mode':True}]
requests += [{'action':'wheel','ctrl':False,'move_mode':False} for _ in range(18)]
if row['id'] == 'supported_connected':
geometry = {'target_rect':[120,0,20,20], 'target_screen_rect':[120,0,20,20],
'palette_rect':[0,0,100,30], 'thumb_rect':[0,20,50,10],
'viewport_to_screen':[1,0,0,1,0,0],
'bar':{'rect':[0,20,100,10], 'visible':True, 'min_value':0,
'max_value':200, 'page':100, 'value':0}}
requests = [dict(geometry, action='reveal_palette', node='/root/Main/Palette/Target',
direction='right', scroll_before=0),
{'action':'button','node':'/root/Main/Palette/Target'}] + requests
row['requests'] = []
for local_sequence, request in enumerate(requests, 1):
sequence = os_sequences.get(pid, 0)+1
os_sequences[pid] = sequence
prefix = directory+'/'+row['id']+'-'+str(local_sequence)+'/'
request.update(target_pid=pid, sequence=sequence)
put(out/(prefix+'request.json'), request)
if request['action'] == 'reveal_palette':
after = copy.deepcopy(geometry)
after.update(target_rect=[60,0,20,20], target_screen_rect=[60,0,20,20],
thumb_rect=[30,20,50,10], scroll_after=60, visible_after=True)
after['bar']['value'] = 60
put(out/(prefix+'reveal.json'), after)
events = [{'synthetic':True}]
if request['action'] == 'cell':
events = [{'synthetic':True, 'button':1, 'pressed':True,
'position':p['dispatch']['viewport'], 'dispatch':copy.deepcopy(p['dispatch'])}]
put(out/(prefix+'observed.json'), {'pid':pid,'sequence':sequence,'events':events})
receipt = directory+'/'+row['id']+'-os.json'
put(out/receipt, {'method':'native_os','target_pid':pid,'timestamp_ns':10000,
'collector_pid':999,'tool_name':'mock CUA','tool_call_id':'synthetic-only',
'events':[{'synthetic':True}]})
put(out/(prefix+'ack.json'), {'target_pid':pid,'sequence':sequence,
'request_sha256':sha(out/(prefix+'request.json')), 'input_receipt':receipt,
'screen_before':prefix+'screen-before.png','screen_after':prefix+'screen-after.png'})
row['requests'].append(prefix+'ack.json')
def chunk(kind, body):
return struct.pack('>I',len(body))+kind+body+struct.pack('>I',zlib.crc32(kind+body))
screenshot = (b'\x89PNG\r\n\x1a\n'+
chunk(b'IHDR',struct.pack('>IIBBBBB',1,1,8,2,0,0,0))+
chunk(b'IDAT',zlib.compress(b'\0\0\0\0'))+chunk(b'IEND',b''))
for ack_name in row['requests']:
for side in ('before', 'after'):
(out/Path(ack_name).parent/('screen-'+side+'.png')).write_bytes(screenshot)
actions = []
for label in checker.WRITER:
cell = [4, 1, 0] if label in ('lower_stair', 'refused_demolition') else [4, 2, 0] if label == 'upper_stair' else target[:]
definition = 'guest_stairs' if label in ('lower_stair', 'upper_stair', 'missing_connection') else 'reception'
if label == 'unsupported': definition = 'standard_room'
row = {'id': label, 'position': position(cell), 'expected': '', 'results': [], 'status': '',
'kind': 'build', 'definition': definition, 'before': snap('writer-'+label+'-before')}
report = {'can_build': True, 'error_codes': [], 'total_cost': cost[definition], 'connection': {'status': 'CONNECTED'}}
row['report'] = report
if label in checker.REASONS:
code, message = checker.REASONS[label]
report.update(can_build=False, error_codes=[code])
row.update(expected=code, status=message)
elif label == 'missing_connection':
row['expected'] = 'STAIR_LANDING_MISSING'
report.update(can_build=False, error_codes=[row['expected']], reasons=[{'code':row['expected'], 'message':'先に階段の一つ下の階に通路を作ってください。', 'cells':[], 'details':{'reason':row['expected']}}])
row['status'] = '配置不可: '+report['reasons'][0]['message']
elif label == 'cancel_demolition':
row.update(kind='cancel', status='撤去を取り消しました。')
elif label in ('demolition', 'refused_demolition'):
fid = 'f1' if label == 'demolition' else 'f2'
row.update(kind='demolish', instance_id=fid)
if label == 'refused_demolition':
row['expected'] = 'STAIR_LANDING_IN_USE'
row['results'] = [result('VALIDATION_FAILED', {'reason': row['expected']}, 'dependent stair')]
else:
row['results'] = [result('OK', {'refund': {'materials': 2}, 'instance_id': fid})]
model['game_state']['resources']['materials'] += 2
runtime['construction']['facilities'] = [v for v in runtime['construction']['facilities'] if v['instance_id'] != fid]
runtime['construction']['jobs'] = [v for v in runtime['construction']['jobs'] if v.get('facility_instance_id') != fid]
runtime['facilities']['instances'] = [v for v in runtime['facilities']['instances'] if v['instance_id'] != fid]
runtime['world']['occupancies'] = [v for v in runtime['world']['occupancies'] if v['entity_id'] != fid]
r = row['results'][0]
row['status'] = '撤去できません: '+r['message'] if row['expected'] else '撤去しました(返金: 資材 2)'
elif label == 'pan_zoom':
row.update(kind='camera', original_local=[1, 2], ctrl_pressed=False,
pan_before=[0,0], pan_after=[0,10],
steps=[0.5]*9+[1, 1.5, 2, 2.5, 3, 3.5, 4, 4, 4])
else:
rooms += 1
fid, jid = 'f'+str(rooms), 'j'+str(rooms)
row['results'] = [result('OK', {'job_id': jid})]
for k, v in cost[definition].items(): model['game_state']['resources'][k] -= v
cells = [[cell[0]+dx,cell[1]+dy,cell[2]] for dx in range(4 if definition == 'reception' else 1) for dy in range(2 if definition == 'reception' else 1)]
job = {'job_id': jid, 'state': 'PLANNED', 'reserved_cells': cells}
runtime['construction']['jobs'].append(job)
runtime['world']['occupancies'].append({'entity_id': jid, 'cells': cells})
row['after'] = snap('writer-'+label+'-after')
job.update(state='COMPLETED', facility_instance_id=fid)
facility = {'instance_id': fid, 'definition_id': definition, 'occupied_cells': cells, 'origin': cell[:], 'source_job_id': jid}
runtime['construction']['facilities'].append(facility)
if definition != 'guest_stairs':
runtime['facilities']['instances'].append(copy.deepcopy(facility))
runtime['world']['occupancies'][-1]['entity_id'] = fid
row['completed'] = snap('writer-'+label+'-completed')
if 'after' not in row: row['after'] = snap('writer-'+label+'-after')
os_meta(row, pids[0])
actions.append(row)
budget = {'setup': 'diagnostic', 'costs': [{'definition': d, 'cost': cost[d]} for d in ('reception', 'reception', 'guest_stairs', 'guest_stairs')],
'needed': {'gold': 1080, 'materials': 16}, 'initial': {'gold': 5000, 'materials': 50}, 'deltas': {}}
put(folder/'writer-actions.json', {'setup': 'diagnostic', 'actions': actions, 'budget': budget})
snap('writer-presave')
snap('writer-formal-model')
snap('reader-formal-model')
formal_model = typed(model)
formal = folder/'formal'
formal.mkdir()
for member in checker.MEMBERS: (formal/member).write_text('synthetic '+member+'\n')
shutil.copytree(formal, folder/'formal.bak')
shutil.copyfile(formal/'manifest.json', folder/'formal-slot-metadata.json')
profile = '/synthetic-private-profile'
absolute = profile+'/saves/manual_ui'
put(folder/'formal-export.json', {'pid':pids[0], 'requested_path':'user://saves/manual_ui',
'absolute_path':absolute, 'user_data_dir':profile,
'packages':{name:{'present':True, 'source_path':absolute+suffix,
'members':{n:{'sha256':sha(folder/name/n),'bytes':(folder/name/n).stat().st_size} for n in checker.MEMBERS}}
for name,suffix in [('formal',''),('formal.bak','.bak')]},
'slot_metadata':{'file':'formal-slot-metadata.json','sha256':sha(formal/'manifest.json')}})
for role,pid,op in [('writer',pids[0],'save'),('reader',pids[1],'recovery')]:
returned = {'ok':True,'operation':op,'save_path':'user://saves/manual_ui',
'code':'OK','message':'synthetic result','duration_us':13,'runtime_duration_us':17,
'manifest':{'save_id':'synthetic-save','absolute_minute':360}}
if role == 'reader':
returned['selected'] = {'id':'formal','kind':'formal','generation':0}
expected = checker.expected_operation(formal_model,returned,
'SAVE_CHECKPOINT_SUCCEEDED' if role == 'writer' else 'SAVE_RECOVERY_LOADED')
for label in ('checkpoint','expected-operation','operation-actual'):
put(folder/(role+'-'+label+'.json'),expected)
(folder/(role+'-'+label+'.var')).write_bytes(json.dumps(expected,sort_keys=True).encode())
count = len(model['systems']['runtime']['domain_events']['recent_events'])
put(folder/(role+'-operation-comparison.json'), {'pid':pid,'delta_kind':'source_defined_notification',
'formal_model':role+'-formal-model','actual_model':role+'-checkpoint',
'expected_model':role+'-expected-operation','returned_result':typed(returned),
'saved_recent_count':count,'expected_recent_count':count+1,'actual_recent_count':count+1,
'whole_raw_equal':True})
stem = role+'-save-result-0001'
(folder/(stem+'.var')).write_bytes(b'synthetic raw Dictionary stand-in')
put(folder/(stem+'.json'), {'pid':pid,'operation':'runtime_operation',
'requested_path':'user://saves/manual_ui','absolute_path':absolute,'user_data_dir':profile,
'result':typed(returned),
'raw_sha256':sha(folder/(stem+'.var'))})
inspect_stem = role+'-save-result-0002'
(folder/(inspect_stem+'.var')).write_bytes(b'synthetic inspection Dictionary stand-in')
put(folder/(inspect_stem+'.json'), {'pid':pid,'operation':'formal_inspect',
'requested_path':'user://saves/manual_ui','absolute_path':absolute,'user_data_dir':profile,
'result':typed({'ok':True,'read_only':True,'snapshot':copy.deepcopy(model)}),
'raw_sha256':sha(folder/(inspect_stem+'.var'))})
put(folder/(role+'-save-results.json'), {'pid':pid,'records':[stem,inspect_stem]})
if method == "native_os":
prefix = "writer-bootstrap-"
returned = {"ok":True,"operation":"recovery","code":"OK","save_path":"user://saves/manual_ui"}
expected = checker.expected_operation(formal_model,returned,"SAVE_RECOVERY_LOADED")
for label,value in [("formal-model",formal_model),("returned-result",typed(returned)),
("checkpoint",expected),("expected-operation",expected),("operation-actual",expected)]:
put(folder/(prefix+label+".json"),value)
(folder/(prefix+label+".var")).write_bytes(json.dumps(value,sort_keys=True).encode())
records = []
for suffix,operation,value in [
("0000-bootstrap","runtime_operation",returned),
("0000-inspect","initial_inspect",{"ok":True,"read_only":True,"snapshot":copy.deepcopy(model)})]:
stem = "writer-save-result-"+suffix
(folder/(stem+".var")).write_bytes(b"synthetic bootstrap Dictionary")
put(folder/(stem+".json"), {"pid":pids[0],"operation":operation,
"requested_path":"user://saves/manual_ui","absolute_path":absolute,"user_data_dir":profile,
"result":typed(value),"raw_sha256":sha(folder/(stem+".var"))})
records.append(stem)
log = json.loads((folder/"writer-save-results.json").read_text())
log["records"] = records+log["records"]
put(folder/"writer-save-results.json",log)
count = len(model["systems"]["runtime"]["domain_events"]["recent_events"])
put(folder/(prefix+"operation-comparison.json"), {
"pid":pids[0],"delta_kind":"source_defined_notification",
"formal_model":prefix+"formal-model","actual_model":prefix+"checkpoint",
"expected_model":prefix+"expected-operation","returned_result":typed(returned),
"saved_recent_count":count,"expected_recent_count":count+1,"actual_recent_count":count+1,
"whole_raw_equal":True})
put(folder/'save.json', {'members': {n: sha(formal/n) for n in checker.MEMBERS},
'pid': pids[0], 'cell': target, 'instance_id': 'f4'})
row = {'id': 'resume_overlap', 'kind': 'build', 'position': position(target),
'definition':'reception',
'before': snap('reader-resume-before'), 'after': snap('reader-resume-after'),
'results': [], 'report': {'can_build': False, 'error_codes': ['OVERLAP']},
'status': checker.REASONS['overlap'][1]}
os_meta(row, pids[1])
put(folder/'reader-actions.json', {'setup': 'diagnostic', 'actions': [row]})
if method == 'native_os':
put(folder/'writer-requests.json', {'pid':pids[0],
'requests':[name for action in actions for name in action['requests']]})
put(folder/'reader-requests.json', {'pid':pids[1],'requests':row['requests']})
for role, pid in zip(('writer', 'reader'), pids):
put(folder/(role+'-process.json'), {'pid': pid, 'engine': {'hash': 'synthetic', 'string': 'synthetic'}, 'checks': 100, 'failures': 0})
pair('pair', [101, 102], 'handler')
pair('os-pair', [201, 202], 'native_os')
shutil.copytree(out/'pair/formal', out/'pair/initial-formal')
initial = copy.deepcopy(json.loads((out/'pair/formal-export.json').read_text()))
initial.update(requested_path='user://saves/p08_initial',absolute_path='/synthetic-private-profile/saves/p08_initial')
initial['packages'] = {'initial-formal':initial['packages']['formal'],
'initial-formal.bak':{'present':False,'source_path':initial['absolute_path']+'.bak','members':{}}}
initial['packages']['initial-formal']['source_path'] = initial['absolute_path']
shutil.copyfile(out/'pair/initial-formal/manifest.json',out/'pair/initial-formal-slot-metadata.json')
initial['slot_metadata']['file'] = 'initial-formal-slot-metadata.json'
put(out/'pair/initial-formal-export.json',initial)
for role, pid in (('writer',201),('reader',202)):
prefix = 'os-runs/'+role+'/'
folder = out/prefix
folder.mkdir(parents=True)
shutil.copyfile(source/checker.RECORDER, folder/'passive_os.gd')
profile = base/('synthetic-profile-'+role)
command = [str(engine),'--path',str(root),'--script',str(folder/'passive_os.gd')]
formal = out/('pair/initial-formal' if role == 'writer' else 'os-pair/formal')
members = {n:{'bytes':(formal/n).stat().st_size,'sha256':sha(formal/n)} for n in checker.MEMBERS}
record = {'protocol':'p08-placement-native-os-v1','role':role,'commit':index['commit'],
'source_map':source_map,'stage':str(root),'profile':str(profile),'command':command,
'engine_sha256':sha(engine),'controller_sha256':source_map['tools/run_p08_normal_placement.py'],
'recorder_sha256':sha(source/checker.RECORDER),'formal_input':members,
'actual_pid':pid,'monotonic_ns':1,'exit_code':0,'engine_ended':True,'passed':True,
'error':None,'guard_errors':[],'cleanup_errors':[],
'owned_cleanup':[{'pid':pid,'engine_ended':True,'outer_cleanup_errors':[],'foreign_process_or_group_signals':0}],
'stage_before':{},'stage_after':{},'default_before':{},'default_after':{},
'source_after':{n:{'sha256':v} for n,v in source_map.items()},
'profile_before':{'existed':False,'files':{}},'ordinary_owner_proof':owner_proof(folder,pid,checker)}
for name in ('started.json','process-started.json','ended.json'): put(folder/name, record)
(folder/'engine-native.log').write_text('P08 passive OS placement: 100 checks, 0 failures\n')
put(out/('os-pair/'+role+'-profile.json'), {'pid':pid,'user_data_dir':str(profile),'display':'synthetic'})
os_phases.append(prefix+'ended.json')
put(out/'os.json', {'source_map':source_map,'inputs':index['inputs'],'input_method':'native_os',
'observer_mutations':[],'phases':os_phases,'directory':'os-pair','synthetic':True})
put(out/'index.json', index)
repin(out)
return root, out
def repin(out):
index = json.loads((out/'index.json').read_text())
index['artifacts'] = {p.relative_to(out).as_posix(): {'bytes': p.stat().st_size,
'sha256': hashlib.sha256(p.read_bytes()).hexdigest()} for p in out.rglob('*') if p.is_file() and p != out/'index.json'}
put(out/'index.json', index)
+309
View File
@@ -0,0 +1,309 @@
extends "res://tests/fixtures/p08-03/placement.gd"
## Passive endpoint implementation. All gameplay/input is performed by Root CUA.
## Shared parent contains the handler endpoints, but every such endpoint below
## is overridden; this class never emits UI signals or invokes product handlers.
var receipts: Array = []
var terminated := false
var terminal_record: Dictionary = {}
var terminal_cause_recorded := false
var reveal_rows: Array = []
var all_requests: Array = []
var input_observer: Node
var last_dispatch: Dictionary = {}
class InputObserver extends Node:
var events: Array = []
var endpoint: RefCounted = null
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton or event is InputEventKey:
var row := {"ticks_usec": Time.get_ticks_usec(), "text": event.as_text(), "pressed": event.is_pressed()}
if event is InputEventMouseButton:
row["button"] = event.button_index
row["position"] = [event.position.x, event.position.y]
row["ctrl"] = event.ctrl_pressed
if endpoint != null and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
row["dispatch"] = endpoint.dispatch_position(event.position)
events.append(row)
func expect(ok: bool, message: String) -> void:
if terminated and ok:
return
if terminated and terminal_cause_recorded:
if not ok:
terminal_record["suppressed_after_terminal"] += 1
json_file(role + "-terminal.json", terminal_record)
return
if terminated and not ok:
terminal_cause_recorded = true
super.expect(ok, message)
func terminate(stem: String, reason: String) -> void:
terminated = true
terminal_record = {"pid": OS.get_process_id(), "role": role, "sequence": serial,
"stem": stem, "reason": reason, "suppressed_after_terminal": 0}
json_file(role + "-terminal.json", terminal_record)
expect(false, reason)
tree.quit(1)
func request(action: Dictionary) -> void:
if terminated:
return
serial += 1
var stem := "%s-request-%04d" % [role, serial]
var folder := directory.path_join(stem)
DirAccess.make_dir_recursive_absolute(folder)
var window: Window = main.get_window()
action.merge({"sequence": serial, "target_pid": OS.get_process_id(), "role": role,
"state": "waiting_for_root_cua", "window_title": window.title,
"window_position": [window.position.x, window.position.y],
"window_size": [window.size.x, window.size.y], "screen_scale": DisplayServer.screen_get_scale(window.current_screen),
"content_scale_factor": window.content_scale_factor, "setup": "diagnostic"})
json_file(stem + "/request.json", action)
var path := folder.path_join("ack.json")
var first_event: int = input_observer.events.size()
var deadline := Time.get_ticks_msec() + 300000
print("P08_ROOT_CUA_WAIT " + folder.path_join("request.json"))
while not FileAccess.file_exists(path) and Time.get_ticks_msec() < deadline:
await tree.process_frame
if not FileAccess.file_exists(path):
terminate(stem, "Root CUA acknowledgement timeout")
return
var ack: Variant = JSON.parse_string(FileAccess.get_file_as_string(path))
if not ack is Dictionary or ack.get("target_pid") != OS.get_process_id() or ack.get("sequence") != serial or ack.get("request_sha256") != FileAccess.get_sha256(folder.path_join("request.json")):
terminate(stem, "Root CUA acknowledgement identity/hash")
return
await frames()
for event: Dictionary in input_observer.events.slice(first_event):
if event.has("dispatch"):
last_dispatch = event["dispatch"]
json_file(stem + "/observed.json", {"pid": OS.get_process_id(), "sequence": serial,
"observer_endpoint": "null_modal_receipts_only" if input_observer.endpoint == null else "passive_read_only_dispatch",
"events": input_observer.events.slice(first_event), "status": main.build_status_label.text})
receipts.append("os-pair/" + stem + "/ack.json")
all_requests.append("os-pair/" + stem + "/ack.json")
func annotate(row: Dictionary) -> void:
row["reveal"] = reveal_rows.duplicate(true)
reveal_rows.clear()
row["input_method"] = "native_os"
row["requests"] = receipts.duplicate()
receipts.clear()
func point(node: Control) -> Dictionary:
var viewport: Vector2 = node.get_global_transform_with_canvas() * (node.size * 0.5)
var screen: Vector2 = node.get_screen_transform() * (node.size * 0.5)
return {"node": String(node.get_path()), "viewport": [viewport.x, viewport.y], "screen": [screen.x, screen.y], "window_id": node.get_window().get_window_id(),
"viewport_to_screen": affine(node.get_screen_transform() * node.get_global_transform_with_canvas().affine_inverse())}
func unsupported_cell() -> Vector3i:
# Read-only selection: retain the production predicate and avoid the guide.
var view: WorldPreview = main.world_preview
var bounds: Dictionary = runtime.world_service.get_bounds()
for y: int in range(4, int(bounds[&"max_y"]) + 1):
for x: int in range(int(bounds[&"max_x"]) - 1, int(bounds[&"min_x"]) - 1, -1):
var cell := Vector3i(x, y, 0)
var local := view.cell_to_canvas(cell)
var viewport := view.get_global_transform_with_canvas() * local
if not Rect2(Vector2.ZERO, view.size).has_point(local):
continue
if main.opening_guide.visible and main.opening_guide.get_global_rect().has_point(viewport):
continue
if "UNSUPPORTED" in view.get_build_preview_report(cell).get("error_codes", []):
return cell
expect(false, "visible unsupported target outside opening guide")
return Vector3i(4, 4, 0)
func setup() -> void:
input_method = "native_os"
expect(DisplayServer.get_name() != "headless", "OS recorder requires a real display")
main = load("res://scenes/main/main.tscn").instantiate()
tree.root.add_child(main)
tree.root.title = "The Tree P08-03 " + role + " PID " + str(OS.get_process_id())
input_observer = InputObserver.new()
input_observer.endpoint = self
tree.root.add_child(input_observer)
await frames()
json_file(role + "-profile.json", {"pid": OS.get_process_id(), "user_data_dir": OS.get_user_data_dir(), "engine": Engine.get_version_info(), "display": DisplayServer.get_name()})
if role == "writer":
await load_menu(main.find_child("SaveLoadMenu", true, false))
var stored: Dictionary = SaveService.inspect_snapshot(ProjectSettings.globalize_path(String(main.manual_save_path)))
record_save_result("initial_inspect", String(main.manual_save_path), stored)
expect(bool(stored.get("ok", false)), "read-only initial formal inspection")
var formal: Dictionary = stored.get("snapshot", {})
capture_model("bootstrap-formal-model", formal)
capture("bootstrap-checkpoint")
expect(not operation_results.is_empty(), "bootstrap returned load Dictionary")
if not operation_results.is_empty():
var returned: Dictionary = operation_results.back()
capture_model("bootstrap-returned-result", returned)
verify_operation(formal, returned, &"SAVE_RECOVERY_LOADED", "bootstrap-")
expect(clock.paused, "diagnostic formal fixture starts paused")
func diagnostic_budget() -> void:
budget = JSON.parse_string(FileAccess.get_file_as_string(directory.path_join("diagnostic-budget.json")))
func save_initial_fixture() -> void:
# The controller copied the handler's SHA-pinned formal diagnostic fixture.
# Root loaded it using the normal menu. No model/setup mutation here.
pass
func rect_values(rect: Rect2) -> Array:
return [rect.position.x, rect.position.y, rect.size.x, rect.size.y]
func control_rect(node: Control, screen: bool = false) -> Rect2:
var transform := node.get_screen_transform() if screen else node.get_global_transform_with_canvas()
return transform * Rect2(Vector2.ZERO, node.size)
func reveal_geometry(node: Control) -> Dictionary:
var bar: HScrollBar = main.palette_scroll.get_h_scroll_bar()
var bar_rect := control_rect(bar)
var span := bar.max_value - bar.min_value
var thumb := bar_rect
if span > 0:
thumb.size.x = bar_rect.size.x * bar.page / span
thumb.position.x += bar_rect.size.x * (bar.value - bar.min_value) / span
return {"target_rect": rect_values(control_rect(node)), "target_screen_rect": rect_values(control_rect(node, true)),
"palette_rect": rect_values(main.palette_scroll.get_global_rect()),
"bar": {"rect": rect_values(bar_rect), "visible": bar.is_visible_in_tree(),
"min_value": bar.min_value, "max_value": bar.max_value, "page": bar.page, "value": bar.value},
"thumb_rect": rect_values(thumb), "viewport_to_screen": point(node)["viewport_to_screen"]}
func reveal(node: Control) -> void:
if terminated:
return
var palette: Rect2 = main.palette_scroll.get_global_rect()
var target_rect := control_rect(node)
if palette.encloses(target_rect):
reveal_rows.append({"node": String(node.get_path()), "direction": "none"})
return
var direction := "right" if target_rect.end.x > palette.end.x else "left"
var before: int = main.palette_scroll.scroll_horizontal
var action := reveal_geometry(node)
action.merge({"action": "reveal_palette", "node": String(node.get_path()), "direction": direction,
"scroll_before": before, "instructions": "Use the normal horizontal scrollbar to reveal this palette button without activating it."})
await request(action)
if terminated:
return
await frames()
var after := reveal_geometry(node)
var visible_after: bool = main.palette_scroll.get_global_rect().encloses(control_rect(node))
after.merge({"scroll_after": main.palette_scroll.scroll_horizontal, "visible_after": visible_after})
var stem := "%s-request-%04d" % [role, serial]
json_file(stem + "/reveal.json", after)
reveal_rows.append(action)
var moved: bool = main.palette_scroll.scroll_horizontal > before if direction == "right" else main.palette_scroll.scroll_horizontal < before
if not visible_after or not moved:
terminate(stem, "palette target not visible after OS reveal")
func button(node: BaseButton) -> void:
if terminated:
return
expect(node != null and not node.disabled, "available production button")
if node == null or node.disabled:
return
# Native modal windows own a separate input viewport.
var old_observer: Node = input_observer
if node.get_window() != main.get_window():
input_observer = InputObserver.new()
input_observer.endpoint = null # Modal receipts only; never dispatch world cells.
node.get_window().add_child(input_observer)
var action := point(node)
action.merge({"action": "button", "instructions": "Click the named button through CUA; capture before/after screenshots."})
await request(action)
if input_observer != old_observer:
input_observer.queue_free()
input_observer = old_observer
func click(cell: Vector3i) -> Dictionary:
if terminated:
return {}
var view: WorldPreview = main.world_preview
for attempt: int in range(8):
if Rect2(Vector2.ZERO, view.size).has_point(view.cell_to_canvas(cell)):
break
var framing := point(view)
framing.merge({"action": "framing", "world_cell": vector(cell), "instructions": "Use ordinary zoom-out at the preview center until the requested world cell is visible; coordinates will be recomputed after ack."})
await request(framing)
if terminated:
return {}
expect(Rect2(Vector2.ZERO, view.size).has_point(view.cell_to_canvas(cell)), "OS target visible after normal framing")
var local := view.cell_to_canvas(cell)
var viewport := view.get_global_transform_with_canvas() * local
var screen := view.get_screen_transform() * local
var mapping := affine(view.get_screen_transform() * view.get_global_transform_with_canvas().affine_inverse())
var guide_rect: Rect2 = main.opening_guide.get_global_rect()
observed_cell = null
last_dispatch = {}
await request({"action": "cell", "world_cell": vector(cell), "viewport": [viewport.x, viewport.y],
"screen": [screen.x, screen.y], "viewport_to_screen": mapping,
"guide_rect": [guide_rect.position.x, guide_rect.position.y, guide_rect.size.x, guide_rect.size.y],
"guide_visible": main.opening_guide.visible,
"instructions": "Click screen coordinates derived from viewport_to_screen (includes canvas stretch and window translation). Retain actual CUA coordinates and screenshots. If clipped or intercepted, recollect; never substitute fixed pixels."})
if terminated:
return {}
var selected: Array = last_dispatch.get("world_cell", [])
expect(selected == vector(cell), "observed OS selected cell")
var occupant: StringName = runtime.world_service.get_occupant(cell)
var selection_required: bool = view.build_definition == null and not view.excavation_mode and not view.demolition_mode and not occupant.is_empty()
if selection_required:
expect(view.selected_entity_id == occupant, "actual OS facility selection")
var getter: Variant = view.canvas_to_cell(view.get_local_mouse_position())
return {"world_cell": vector(cell), "selected_cell": selected,
"dispatch": last_dispatch.duplicate(true),
"selection": {"required": selection_required, "entity_id": String(view.selected_entity_id), "occupant_id": String(occupant)},
"diagnostics": {"getter_cell": vector(getter) if getter is Vector3i else []},
"local": [local.x, local.y], "viewport": [viewport.x, viewport.y],
"viewport_transform": affine(view.get_global_transform_with_canvas()),
"screen": [screen.x, screen.y], "screen_transform": affine(view.get_screen_transform()),
"map_position": [view.get_map_rect().position.x, view.get_map_rect().position.y],
"cell_dimensions": [view.get_cell_rect(cell).size.x, view.get_cell_rect(cell).size.y],
"bounds": runtime.world_service.get_bounds(), "zoom": view.zoom_level,
"pan": [view.pan_offset.x, view.pan_offset.y]}
func dispatch_position(position: Vector2) -> Dictionary:
var view: WorldPreview = main.world_preview
var local := view.get_global_transform_with_canvas().affine_inverse() * position
var cell: Variant = view.canvas_to_cell(local)
return {"world_cell": vector(cell) if cell is Vector3i else [],
"entity_id_before": String(view.selected_entity_id),
"occupant_id_before": String(runtime.world_service.get_occupant(cell)) if cell is Vector3i else "",
"local": [local.x, local.y], "viewport": [position.x, position.y],
"viewport_transform": affine(view.get_global_transform_with_canvas()),
"screen_transform": affine(view.get_screen_transform()),
"screen": vector2(view.get_screen_transform() * local),
"bounds": runtime.world_service.get_bounds(),
"map_position": vector2(view.get_map_rect().position),
"cell_dimensions": vector2(view.get_cell_rect(Vector3i.ZERO).size),
"zoom": view.zoom_level, "pan": vector2(view.pan_offset)}
func vector2(value: Vector2) -> Array:
return [value.x, value.y]
func wheel(event: InputEventMouseButton, move_mode: bool) -> void:
if terminated:
return
var action := point(main.world_preview)
action.merge({"action": "wheel", "direction": "up" if event.button_index == MOUSE_BUTTON_WHEEL_UP else "down",
"ctrl": false, "move_mode": move_mode, "instructions": "Send one ordinary wheel step at the preview center without Ctrl; retain the CUA receipt."})
await request(action)
func complete_build(id: StringName) -> void:
if terminated:
return
await request({"action": "complete_construction", "definition": String(id),
"minutes": runtime.definition_registry.get_facility(id).build_minutes,
"instructions": "Use normal speed/play controls, wait for construction completion, then pause. No injected clock or model changes."})
expect(clock.paused, "Root paused after ordinary construction progression")
func load_menu(menu: MenuButton) -> void:
if terminated:
return
var action := point(menu)
action.merge({"action": "load_menu", "item_id": 0, "instructions": "Open this normal menu and choose manual load (item 0)."})
await request(action)
func archive_formal() -> void:
export_package(String(main.manual_save_path), "formal")
func finish_observations() -> void:
json_file(role + "-requests.json", {"pid": OS.get_process_id(), "requests": all_requests})
+1
View File
@@ -0,0 +1 @@
uid://b08passivep03
+460
View File
@@ -0,0 +1,460 @@
extends RefCounted
## Diagnostic setup, never natural-play or OS-input proof.
const Cleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd")
const Codec := preload("res://tests/fixtures/p08-02/mixed_world.gd")
const MEMBERS := ["world.bin", "manifest.json", "thumbnail.png", "journal.log"]
var checks := 0
var failures := 0
var tree: SceneTree
var runtime: Variant
var clock: Variant
var main: Variant
var directory: String
var role: String
var actions: Array = []
var results: Array = []
var serial := 0
var target := Vector3i(-8, 0, 0)
var budget: Dictionary = {}
var input_method := "handler"
var observed_cell: Variant = null
var save_serial := 0
var save_records: Array = []
var operation_results: Array[Dictionary] = []
const INITIAL_SAVE := "user://saves/p08_initial"
func annotate(row: Dictionary) -> void:
row["input_method"] = input_method
func selected_cell(cell: Vector3i) -> void:
observed_cell = cell
func expect(ok: bool, message: String) -> void:
checks += 1
if not ok:
failures += 1
push_error("P08 placement: " + message)
func json_file(name: String, data: Variant) -> void:
var file := FileAccess.open(directory.path_join(name), FileAccess.WRITE)
expect(file != null, "write " + name)
if file != null:
file.store_string(JSON.stringify(data, "\t") + "\n")
file.close()
func capture(label: String) -> String:
return capture_model(label, runtime.create_snapshot())
func capture_model(label: String, snapshot: Dictionary) -> String:
var name := role + "-" + label
json_file(name + ".json", Codec.new().typed(snapshot))
var file := FileAccess.open(directory.path_join(name + ".var"), FileAccess.WRITE)
if file != null:
file.store_buffer(var_to_bytes(snapshot))
file.close()
else:
expect(false, "raw Variant " + name)
return name
func vector(cell: Vector3i) -> Array:
return [cell.x, cell.y, cell.z]
func affine(value: Transform2D) -> Array:
return [value.x.x, value.x.y, value.y.x, value.y.y, value.origin.x, value.origin.y]
func observe(result: CommandResult) -> void:
results.append(result.to_dictionary())
func frames() -> void:
await tree.process_frame
await tree.process_frame
func button(node: BaseButton) -> void:
# Actual production button signal/connection, explicitly not native OS.
expect(node != null and not node.disabled, "available production button")
if node == null or node.disabled:
return
if node.toggle_mode:
node.button_pressed = not node.button_pressed
node.pressed.emit()
await frames()
func choose(id: StringName) -> void:
if not main.palette_scroll.visible:
await button(main.palette_toggle_button)
var node: Button = main.build_buttons[id]
await reveal(node)
if not node.button_pressed:
await button(node)
expect(node.button_pressed and main._selected_definition_id == id, "chosen production definition")
func click(cell: Vector3i) -> Dictionary:
var view: WorldPreview = main.world_preview
var local := view.cell_to_canvas(cell)
var viewport := view.get_global_transform_with_canvas() * local
var event := InputEventMouseButton.new()
event.button_index = MOUSE_BUTTON_LEFT
event.pressed = true
event.position = local
# This is a handler test through the real WorldPreview, not an OS receipt.
observed_cell = null
view._gui_input(event)
await frames()
return {"world_cell": vector(cell), "selected_cell": vector(observed_cell if observed_cell is Vector3i else view.canvas_to_cell(local)),
"local": [local.x, local.y], "viewport": [viewport.x, viewport.y],
"viewport_transform": affine(view.get_global_transform_with_canvas()),
"map_position": [view.get_map_rect().position.x, view.get_map_rect().position.y],
"cell_dimensions": [view.get_cell_rect(cell).size.x, view.get_cell_rect(cell).size.y],
"bounds": runtime.world_service.get_bounds(), "zoom": view.zoom_level,
"pan": [view.pan_offset.x, view.pan_offset.y]}
func build(id: StringName, cell: Vector3i, label: String, expected: String = "") -> void:
await choose(id)
if label == "unsupported":
cell = unsupported_cell()
var report: Dictionary = main.world_preview.get_build_preview_report(cell)
var before := capture(label + "-before")
results.clear()
var position := await click(cell)
var status: String = main.build_status_label.text
var after := capture(label + "-after")
if expected.is_empty():
expect(not results.is_empty() and results.back().code == "OK", label + " accepted")
elif expected == "STAIR_LANDING_MISSING":
expect(not report.can_build and expected in report.error_codes and results.is_empty(), label + " preview refusal")
expect(status == "配置不可: " + String(report.reasons[0].message), label + " preview refusal status")
else:
expect(expected in report.error_codes and results.is_empty(), label + " preview refusal")
var row := {"id": label, "kind": "build", "definition": String(id), "expected": expected,
"report": report, "before": before, "after": after, "position": position,
"results": results.duplicate(true), "status": status, "input_method": "handler"}
annotate(row)
actions.append(row)
if expected.is_empty():
await complete_build(id)
row["completed"] = capture(label + "-completed")
func unsupported_cell() -> Vector3i:
return Vector3i(4, 4, 0)
func demolish(cell: Vector3i, label: String, cancel := false, expected := "") -> void:
if not main.palette_scroll.visible:
await button(main.palette_toggle_button)
if not main._demolition_mode:
await button(main.demolition_button)
var before := capture(label + "-before")
results.clear()
var position := await click(cell)
var instance_id: String = String(main._demolition_target)
expect(main.demolition_dialog.visible, "normal confirmation visible")
if cancel:
await button(main.demolition_dialog.get_cancel_button())
else:
await button(main.demolition_dialog.get_ok_button())
await frames()
if cancel:
expect(results.is_empty(), "cancel submits no command")
else:
expect(not results.is_empty(), "confirmation submitted Runtime command")
if not results.is_empty():
expect(results.back().code == ("OK" if expected.is_empty() else "VALIDATION_FAILED"), label + " result code")
expect(String(results.back().details.get("reason", "")) == expected, label + " result reason")
var row := {"id": label, "kind": "cancel" if cancel else "demolish", "expected": expected,
"instance_id": instance_id, "position": position, "before": before, "after": capture(label + "-after"),
"results": results.duplicate(true), "status": main.build_status_label.text, "input_method": input_method}
annotate(row)
actions.append(row)
func camera() -> void:
await button(main.pan_button)
var view: WorldPreview = main.world_preview
var before := capture("pan-before")
var original := view.cell_to_canvas(target)
var event := InputEventMouseButton.new()
event.button_index = MOUSE_BUTTON_WHEEL_UP
event.pressed = true
event.factor = 1.0
event.position = view.size * 0.5
event.ctrl_pressed = false
var zoom: float = view.zoom_level
var original_pan: Vector2 = view.pan_offset
await wheel(event, true)
expect(view.zoom_level == zoom, "move-mode wheel pans without Ctrl")
var moved_pan: Vector2 = view.pan_offset
expect(moved_pan != original_pan, "move-mode wheel actually moves the camera")
await button(main.pan_button)
var steps: Array = []
for direction: int in [MOUSE_BUTTON_WHEEL_DOWN, MOUSE_BUTTON_WHEEL_UP]:
for unused: int in range(9):
event.button_index = direction
await wheel(event, false)
steps.append(view.zoom_level)
expect(view.zoom_level == (0.5 if direction == MOUSE_BUTTON_WHEEL_DOWN else 4.0), "existing zoom clamp")
# Use transformed pixels; camera state is not required to survive save/load.
var position := await click(target)
expect(position.world_cell == position.selected_cell, "camera world identity")
expect(view.cell_to_canvas(target) != original, "pixels transform")
var row := {"id": "pan_zoom", "kind": "camera", "before": before, "after": capture("pan-after"),
"position": position, "original_local": [original.x, original.y], "steps": steps,
"pan_before": [original_pan.x, original_pan.y], "pan_after": [moved_pan.x, moved_pan.y],
"ctrl_pressed": false, "input_method": input_method}
annotate(row)
actions.append(row)
func diagnostic_budget() -> void:
var state: Variant = tree.root.get_node("GameState")
var needed := {&"gold": 0, &"materials": 0}
var costs: Array = []
for id: StringName in [&"reception", &"reception", &"guest_stairs", &"guest_stairs"]:
var definition: FacilityDefinition = runtime.definition_registry.get_facility(id)
costs.append({"definition": String(id), "cost": definition.construction_cost.duplicate(true)})
for key: StringName in needed:
needed[key] += int(definition.construction_cost.get(key, 0))
var deltas := {}
for key: StringName in needed:
if needed[key] > state.get_resource(key):
deltas[key] = needed[key] - state.get_resource(key)
budget = {"setup": "diagnostic", "costs": costs, "needed": needed, "initial": state.resources.duplicate(true), "deltas": deltas}
if not deltas.is_empty():
expect(runtime.submit_command(&"change_resources", {&"deltas": deltas}).is_success(), "definition-derived diagnostic budget")
func writer() -> void:
diagnostic_budget()
await save_initial_fixture()
await build(&"standard_room", Vector3i(4, 4, 0), "unsupported", "UNSUPPORTED")
await build(&"reception", Vector3i(runtime.world_service.get_bounds()[&"max_x"], 0, 0), "out_of_bounds", "OUT_OF_BOUNDS")
await build(&"reception", target, "supported_connected")
await build(&"reception", target, "overlap", "OVERLAP")
# Existing reception supports this upper cell, but provides no stair landing.
await build(&"guest_stairs", Vector3i(-8, 2, 0), "missing_connection", "STAIR_LANDING_MISSING")
await build(&"guest_stairs", Vector3i(4, 1, 0), "lower_stair")
await build(&"guest_stairs", Vector3i(4, 2, 0), "upper_stair")
await demolish(Vector3i(4, 1, 0), "refused_demolition", false, "STAIR_LANDING_IN_USE")
await demolish(target, "cancel_demolition", true)
await demolish(target, "demolition")
await build(&"reception", target, "rebuild")
await camera()
capture("presave")
await button(main.find_child("ManualSaveButton", true, false))
expect(main.build_status_label.text == "手動セーブを保存しました。", "normal save")
capture("checkpoint")
await archive_formal()
var formal := inspect_formal()
var presave: Dictionary = bytes_to_var(FileAccess.get_file_as_bytes(directory.path_join("writer-presave.var")))
expect(var_to_bytes(presave) == var_to_bytes(formal), "whole presave formal model")
verify_operation(formal, operation_results.back(), &"SAVE_CHECKPOINT_SUCCEEDED")
var members := {}
for member: String in MEMBERS:
members[member] = FileAccess.get_sha256(directory.path_join("formal/" + member))
json_file("save.json", {"members": members, "instance_id": String(runtime.world_service.get_occupant(target)), "cell": vector(target), "pid": OS.get_process_id()})
func reader(distinct: bool) -> void:
var saved: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(directory.path_join("save.json")))
if distinct:
expect(saved.pid != OS.get_process_id(), "separate actual writer/reader PID")
# Real load menu callback, no direct restore_snapshot or model mutation.
var menu: MenuButton = main.find_child("SaveLoadMenu", true, false)
await load_menu(menu)
await frames()
expect(main.build_status_label.text == "手動セーブを読み込みました。", "normal resume")
capture("checkpoint")
var formal := inspect_formal()
var original := FileAccess.get_file_as_bytes(directory.path_join("writer-formal-model.var"))
expect(original == var_to_bytes(formal), "whole formal resume model")
verify_operation(formal, operation_results.back(), &"SAVE_RECOVERY_LOADED")
expect(String(runtime.world_service.get_occupant(target)) == saved.instance_id, "same resumed instance/cell")
for member: String in MEMBERS:
expect(FileAccess.get_sha256(directory.path_join("formal/" + member)) == saved.members[member], "reader preserves formal member " + member)
await build(&"reception", target, "resume_overlap", "OVERLAP")
func run(p_tree: SceneTree, output: String, requested_role: String) -> Dictionary:
# Handler entry is never an OS evidence route. Passive subclass overrides endpoints.
tree = p_tree
directory = output
role = "reader" if requested_role == "reader" else "writer"
expect(DirAccess.make_dir_recursive_absolute(directory) == OK, "diagnostic directory")
runtime = tree.root.get_node("SimulationRuntime")
clock = tree.root.get_node("GameClock")
runtime.save_operation_completed.connect(record_save_operation)
await setup()
runtime.command_completed.connect(observe)
main.world_preview.cell_clicked.connect(selected_cell)
await frames()
if role == "writer":
await writer()
else:
await reader(true)
json_file(role + "-actions.json", {"setup": "diagnostic", "input_method": input_method, "budget": budget, "actions": actions})
if requested_role == "standalone":
role = "reader"
actions = []
save_records = []
await reader(false)
json_file(role + "-actions.json", {"setup": "diagnostic", "input_method": input_method, "actions": actions})
finish_observations()
runtime.command_completed.disconnect(observe)
runtime.save_operation_completed.disconnect(record_save_operation)
var cleanup: Dictionary = await Cleanup.free_owner_and_wait(tree, main)
expect(cleanup.get(&"passed", false), "ordinary Main/audio cleanup")
json_file(role + "-process.json", {"pid": OS.get_process_id(), "engine": Engine.get_version_info(), "checks": checks, "failures": failures, "role": requested_role, "setup": "diagnostic"})
return {"checks": checks, "failures": failures}
func reveal(node: Control) -> void:
main.palette_scroll.ensure_control_visible(node)
await frames()
func wheel(event: InputEventMouseButton, _move_mode: bool) -> void:
main.world_preview._gui_input(event)
await frames()
func complete_build(id: StringName) -> void:
clock.advance_minutes(runtime.definition_registry.get_facility(id).build_minutes)
await frames()
func load_menu(menu: MenuButton) -> void:
menu.get_popup().id_pressed.emit(0)
func setup() -> void:
clock.reset(1, 6, 0)
tree.root.get_node("GameState").reset()
runtime.initialize(clock, tree.root.get_node("GameState"), 42533)
clock.set_paused(true)
tree.root.size = Vector2i(1440, 810)
main = load("res://scenes/main/main.tscn").instantiate()
main.manual_save_path = "user://saves/manual_ui"
if role == "reader":
import_package(directory.path_join("formal"), String(main.manual_save_path))
tree.root.add_child(main)
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
func save_initial_fixture() -> void:
# Explicit diagnostic input, not an OS action or natural-play save.
var saved: Dictionary = SaveService.save_snapshot(INITIAL_SAVE, runtime.create_snapshot())
record_save_result("initial_save", INITIAL_SAVE, saved)
expect(bool(saved.get("ok", false)), "diagnostic initial formal save")
export_package(INITIAL_SAVE, "initial-formal")
# Seed the private normal slot, so its later normal save produces a backup.
import_package(ProjectSettings.globalize_path(INITIAL_SAVE), String(main.manual_save_path))
json_file("diagnostic-budget.json", budget)
func archive_formal() -> void:
export_package(String(main.manual_save_path), "formal")
func inspect_formal() -> Dictionary:
var stored := SaveService.inspect_snapshot(String(main.manual_save_path))
record_save_result("formal_inspect", String(main.manual_save_path), stored)
expect(bool(stored.get(&"ok", false)), "read-only formal inspection")
var formal: Dictionary = stored.get(&"snapshot", {})
capture_model("formal-model", formal)
return formal
func verify_operation(formal: Dictionary, result: Dictionary, event_type: StringName, prefix: String = "") -> void:
var expected := formal.duplicate(true)
var model: Dictionary = expected[&"systems"][&"runtime"]
var counters: Dictionary = model[&"id_generator"]["counters"]
var next: int = int(counters.get("domain_event", 0)) + 1
counters["domain_event"] = next
var event_id := "domain_event.%012d" % next
var payload := {
&"ok": bool(result.get(&"ok", false)),
&"code": StringName(result.get(&"code", &"UNKNOWN")),
&"message": str(result.get(&"message", "")),
&"operation": StringName(result.get(&"operation", &"unknown")),
&"save_path": str(result.get(&"save_path", result.get(&"path", ""))),
&"reason": StringName(result.get(&"reason", &"")),
&"request_id": int(result.get(&"request_id", 0)),
&"checkpoint_absolute_minute": int(result.get(&"checkpoint_absolute_minute", formal[&"clock"][&"absolute_minute"])),
&"duration_us": int(result.get(&"duration_us", 0)),
&"runtime_duration_us": int(result.get(&"runtime_duration_us", 0)),
}
if result.get(&"selected") is Dictionary:
var selected: Dictionary = result[&"selected"]
payload[&"selected_candidate_id"] = StringName(selected.get(&"id", &""))
payload[&"selected_candidate_kind"] = StringName(selected.get(&"kind", &""))
payload[&"selected_generation"] = int(selected.get(&"generation", -1))
if result.get(&"manifest") is Dictionary:
var manifest: Dictionary = result[&"manifest"]
payload[&"save_id"] = str(manifest.get("save_id", ""))
payload[&"saved_absolute_minute"] = int(manifest.get("absolute_minute", -1))
var stream: Dictionary = model[&"domain_events"]
stream["published_ids"].append(event_id)
stream["published_ids"].sort()
var notification := SimulationDomainEvent.new(StringName(event_id), event_type,
int(formal[&"clock"][&"absolute_minute"]), &"save_service", [], payload, 0)
stream["recent_events"].append(notification.to_dictionary())
if stream["recent_events"].size() > DomainEventStream.RECENT_EVENT_LIMIT:
stream["recent_events"].pop_front()
capture_model(prefix + "expected-operation", expected)
capture(prefix + "operation-actual")
var actual: Dictionary = bytes_to_var(FileAccess.get_file_as_bytes(directory.path_join(role + "-" + prefix + "checkpoint.var")))
json_file(role + "-" + prefix + "operation-comparison.json", {
"pid": OS.get_process_id(), "delta_kind": "source_defined_notification",
"formal_model": role + "-" + prefix + "formal-model", "actual_model": role + "-" + prefix + "checkpoint",
"expected_model": role + "-" + prefix + "expected-operation", "returned_result": Codec.new().typed(result),
"saved_recent_count": formal[&"systems"][&"runtime"][&"domain_events"]["recent_events"].size(),
"expected_recent_count": stream["recent_events"].size(),
"actual_recent_count": actual[&"systems"][&"runtime"][&"domain_events"]["recent_events"].size(),
"whole_raw_equal": var_to_bytes(expected) == var_to_bytes(actual),
})
# Complete raw actual/expected snapshots remain available on unknown drift.
expect(var_to_bytes(expected) == var_to_bytes(actual), "whole source-defined save operation model; see " + role + "-" + prefix + "operation-comparison.json")
expect(var_to_bytes(actual) == var_to_bytes(runtime.create_snapshot()), "read-only inspection preserves live model")
func record_save_operation(result: Dictionary) -> void:
operation_results.append(result.duplicate(true))
record_save_result("runtime_operation", String(main.manual_save_path), result)
func record_save_result(operation: String, path: String, result: Dictionary) -> void:
save_serial += 1
var stem := "%s-save-result-%04d" % [role, save_serial]
var raw := FileAccess.open(directory.path_join(stem + ".var"), FileAccess.WRITE)
expect(raw != null, "raw save result")
if raw != null:
raw.store_buffer(var_to_bytes(result))
raw.close()
json_file(stem + ".json", {"pid": OS.get_process_id(), "operation": operation,
"requested_path": path, "absolute_path": ProjectSettings.globalize_path(path),
"user_data_dir": OS.get_user_data_dir(), "result": Codec.new().typed(result),
"raw_sha256": FileAccess.get_sha256(directory.path_join(stem + ".var"))})
save_records.append(stem)
json_file(role + "-save-results.json", {"pid": OS.get_process_id(), "records": save_records})
func import_package(source: String, destination: String) -> void:
var absolute := ProjectSettings.globalize_path(destination)
expect(DirAccess.make_dir_recursive_absolute(absolute) == OK, "private save directory")
for member: String in MEMBERS:
var origin := source.path_join(member)
var copy := absolute.path_join(member)
expect(DirAccess.copy_absolute(origin, copy) == OK, "private save input " + member)
expect(FileAccess.get_sha256(origin) == FileAccess.get_sha256(copy), "private save input SHA " + member)
func export_package(path: String, name: String) -> void:
var absolute := ProjectSettings.globalize_path(path)
var pins := {}
for suffix: String in ["", ".bak"]:
var source := absolute + suffix
var present := DirAccess.dir_exists_absolute(source)
pins[name + suffix] = {"source_path": source, "present": present, "members": {}}
if not present:
expect(not suffix.is_empty(), "formal package exists")
continue
var destination := directory.path_join(name + suffix)
expect(DirAccess.make_dir_recursive_absolute(destination) == OK, "export directory")
for member: String in MEMBERS:
var origin := source.path_join(member)
var copy := destination.path_join(member)
expect(DirAccess.copy_absolute(origin, copy) == OK, "export " + member)
var digest := FileAccess.get_sha256(origin)
expect(not digest.is_empty() and digest == FileAccess.get_sha256(copy), "export SHA " + member)
pins[name + suffix]["members"][member] = {"sha256": digest, "bytes": FileAccess.get_file_as_bytes(copy).size()}
# Slot metadata lives in the existing manifest; copy it verbatim.
var metadata := absolute.path_join("manifest.json")
var metadata_copy := directory.path_join(name + "-slot-metadata.json")
expect(DirAccess.copy_absolute(metadata, metadata_copy) == OK, "slot metadata export")
json_file(name + "-export.json", {"pid": OS.get_process_id(), "requested_path": path,
"absolute_path": absolute, "user_data_dir": OS.get_user_data_dir(), "packages": pins,
"slot_metadata": {"file": name + "-slot-metadata.json", "sha256": FileAccess.get_sha256(metadata_copy)}})
func finish_observations() -> void:
pass
+1
View File
@@ -0,0 +1 @@
uid://dc83placement
@@ -0,0 +1,9 @@
{
"raw_path": "/Users/korizatou114/Projects/\u3068\u308a\u306b\u304f\u5de5\u623f\u30b2\u30fc\u30e0\u5236\u4f5c\u90e8/artifacts/original-completion-2026-10-02/p08-03-native-handler-r05/pair/reader-checkpoint.json",
"raw_sha256": "304d97de8051d5e74c6e32c4482a3cb183b0172d7671088fdc40469cc3448c0d",
"raw_bytes": 2120352,
"compressed_path": "ROOT_R05_READER_CHECKPOINT.json.gz",
"candidate": "4a17d0e0f589fa76d81f1d4630ec45c63bac21ab",
"complete_raw_preserved": true,
"scope": "actual native reader snapshot, not synthetic acceptance proof"
}
Binary file not shown.
+49
View File
@@ -0,0 +1,49 @@
extends SceneTree
const Placement := preload("res://tests/fixtures/p08-03/placement.gd")
class PalettePlacement extends Placement:
func setup() -> void:
super.setup()
await frames()
var palette := main.find_child("BuildPalette", true, false) as GridContainer
expect(palette != null, "production facility palette exists")
if palette == null:
return
expect(palette.get_child_count() == 23 and palette.columns == 23,
"palette has exactly 23 facility slots")
expect(main.build_buttons.size() == 23, "all 23 registered facility buttons exist")
for child: Node in palette.get_children():
expect(child is Button and main.build_buttons.values().has(child),
"every palette child is a registered facility button")
for id: StringName in main.MVP_FACILITY_IDS:
expect(main.build_buttons.has(id) and main.build_buttons[id].get_parent() == palette,
"each facility remains inside the facility palette")
var row := palette.get_parent()
expect(row is HBoxContainer and row.get_parent() == main.palette_scroll
and main.palette_scroll.get_child_count() == 1,
"one HBox is the normal palette scroll content")
var demolition: Button = main.demolition_button
expect(demolition != null and demolition.get_parent() == row
and demolition.name == "DemolitionButton" and row.get_child_count() == 2,
"normal demolition entry is a sibling of the facility palette")
if demolition == null:
return
await button(main.palette_toggle_button)
expect(main.palette_scroll.visible and demolition.is_visible_in_tree()
and not demolition.disabled and demolition.toggle_mode,
"opening the normal palette exposes the available demolition entry")
await reveal(demolition)
expect(demolition.get_global_rect().intersects(main.palette_scroll.get_global_rect()),
"demolition entry is reachable through normal palette scrolling")
await button(main.palette_toggle_button)
func _initialize() -> void:
call_deferred("run")
func run() -> void:
var directory := OS.get_environment("P08_PLACEMENT_ROOT")
var role := OS.get_environment("P08_PLACEMENT_ROLE")
if directory.is_empty():
directory = ProjectSettings.globalize_path("user://p08-placement-%d" % Time.get_ticks_usec())
role = "standalone"
var result: Dictionary = await PalettePlacement.new().run(self, directory, role)
print("P08 normal placement: %d checks, %d failures" % [result.checks, result.failures])
quit(0 if result.failures == 0 else 1)
@@ -0,0 +1 @@
uid://ca83n0rmalp03
File diff suppressed because it is too large Load Diff
+9
View File
@@ -391,6 +391,15 @@
],
"old_bounded_teardown": false,
"new_audio_QA": false
},
"tests/ui/test_p08_normal_placement_ops.gd": {
"source_sha256": "d3c246d34f8fd66f6ed237e42a86df89ebaf481bc9dee143b4de8d654ce0eb2e",
"ordinary_cleanup_prepared": true,
"ordinary_control_labels": [
"single"
],
"old_bounded_teardown": false,
"new_audio_QA": false
}
},
"outside_routes": {
+250
View File
@@ -0,0 +1,250 @@
#!/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
import uuid
import re
sys.dont_write_bytecode = True
HERE = Path(__file__).resolve().parent
CONTRACT = 'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'
CONDITIONS = ('support_connection', 'invalid_position_reason', 'demolish_rebuild',
'pan_zoom_world_identity', 'separate_pid_resume')
OS_CHILD_TIMEOUT_SECONDS = 2400
RECORDER = 'docs/plans/original-completion-2026-10-02/execution/p08-03/passive_os_placement_recorder.gd'
def collect_os(r, root, out, stage, engine, commit, refs, protected, outer):
"""P08-02 collect_native_os protocol; deliberately not execute_phase/headless.
Root supplies CUA ack/receipt files in the requested directories. Neither
controller nor passive endpoints generate input or change permissions.
"""
r.require(not outer.native.helper['live_engines'](), 'external engine present')
before = r.inventory(stage, stage=True)
public = (stage/'project.godot').read_bytes()
pair = out/'os-pair'
pair.mkdir()
r.copy_source(out/'pair/diagnostic-budget.json', pair/'diagnostic-budget.json')
phases = []
for role in ('writer', 'reader'):
r.require(not outer.native.helper['live_engines'](), 'external engine present')
r.require(r.source_refs(root) == refs and r.default_player(root) == protected, 'OS before guards')
r.require(r.inventory(stage, stage=True) == before, 'OS stage before guard')
r.require(shutil.disk_usage(out).free >= 500*1024*1024, 'OS disk admission')
folder = out/'os-runs'/role
folder.mkdir(parents=True)
name = 'TheTree-PCK-tests-'+uuid.uuid4().hex+'-p08-placement-'+role
profile = r.profile_path(name)
r.require(not profile.exists(), 'fresh OS private profile')
formal_source = out/('pair/initial-formal' if role == 'writer' else 'os-pair/formal')
formal_before = r.inventory(formal_source)
r.require(set(formal_before) == {'world.bin','manifest.json','thumbnail.png','journal.log'}, 'all formal inputs')
formal = profile/'saves/manual_ui'
formal.mkdir(parents=True)
for member, pin in formal_before.items():
r.copy_source(formal_source/member, formal/member)
r.require(r.sha(formal/member) == pin['sha256'], 'formal fixture copy SHA')
recorder = folder/'passive_os.gd'
r.copy_source(root/RECORDER, recorder)
proof = folder/'teardown'
(proof/'owned-audio').mkdir(parents=True)
env = r.fresh_environment(dict(os.environ))
env.update(P08_PLACEMENT_ROOT=str(pair), P08_PLACEMENT_ROLE=role,
THE_TREE_AUDIO_TEARDOWN_PROOF_DIR=str(proof/'owned-audio'),
THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF=str(proof/'control.json'))
command = [engine, '--path', str(stage), '--script', str(recorder)]
base = {'protocol':'p08-placement-native-os-v1', 'role':role, 'commit':commit,
'source_map':{n:v['sha256'] for n,v in refs.items()}, 'stage':str(stage),
'stage_before':before, 'profile':str(profile), 'profile_name':name,
'profile_before':{'existed':False, 'files':{}}, 'formal_input':formal_before,
'formal_source':str(formal_source), 'owner_pid':os.getpid(),
'default_before':protected, 'command':command, 'engine_sha256':r.sha(engine),
'controller_sha256':r.sha(root/'tools/run_p08_normal_placement.py'),
'recorder_sha256':r.sha(recorder), 'formal_acceptance':False,
'timeout_seconds':OS_CHILD_TIMEOUT_SECONDS,
'environment':{k:v for k,v in env.items() if k.startswith(('P08_', 'THE_TREE_'))},
'environment_sha256':hashlib.sha256(json.dumps(env,sort_keys=True).encode()).hexdigest()}
r.write(folder/'started.json', base)
error = None; children = []; guards = []; exit_code = None; owner_proof = None
try:
(stage/'project.godot').write_bytes(r.private_project(public, name))
with (folder/'engine-native.log').open('x') as log:
process = subprocess.Popen(command, cwd=stage, env=env, stdout=log, stderr=subprocess.STDOUT)
children.append(process)
r.write(folder/'process-started.json', dict(base, actual_pid=process.pid,
monotonic_ns=time.monotonic_ns(), state='waiting_for_root_cua_requests'))
print(json.dumps({'actual_pid':process.pid, 'request_directory':str(pair),
'state':'waiting_for_root_cua', 'role':role}), flush=True)
exit_code = process.wait(timeout=base['timeout_seconds'])
r.require(exit_code == 0, 'ordinary native OS exit0')
raw = (folder/'engine-native.log').read_text()
r.require('ERROR:' not in raw and 'SCRIPT ERROR:' not in raw, 'OS native diagnostics')
matches = re.findall(r'(?m)^P08 passive OS placement: ([0-9]+) checks, 0 failures$', raw)
r.require(len(matches) == 1 and int(matches[0]) > 0, 'passive observer completion')
observed = r.read(pair/(role+'-profile.json'))
r.require(observed['pid'] == process.pid and Path(observed['user_data_dir']).resolve() == profile.resolve()
and observed['display'] != 'headless', 'actual OS private profile/display')
owners = r.module('p08_os_owner_gate', r.SUPPORT/'ordinary_proof_gate.py')
owner_proof = owners.ordinary_gate(proof, process.pid, folder, ['single'])
except BaseException as caught:
error = type(caught).__name__+': '+str(caught)
finally:
try:
cleanup, cleanup_errors = outer.finish_captured(children)
finally:
(stage/'project.godot').write_bytes(public)
try:
r.require(r.source_refs(root) == refs, 'OS source unchanged')
r.require(r.inventory(stage, stage=True) == before, 'OS stage unchanged')
r.require(r.default_player(root) == protected, 'OS default player unchanged')
r.require(r.inventory(formal_source) == formal_before, 'formal input unchanged')
r.require(r.sha(recorder) == base['recorder_sha256'], 'recorder unchanged')
except BaseException as caught:
guards.append(type(caught).__name__+': '+str(caught))
passed = not (error or guards or cleanup_errors) and len(children) == 1 and exit_code == 0
r.write(folder/'ended.json', dict(base, actual_pid=children[0].pid if children else None,
exit_code=exit_code, engine_ended=bool(cleanup) and all(v['engine_ended'] for v in cleanup),
error=error, guard_errors=guards, cleanup_errors=cleanup_errors, owned_cleanup=cleanup,
ordinary_owner_proof=owner_proof, stage_after=r.inventory(stage,stage=True),
default_after=r.default_player(root), source_after=r.source_refs(root),
profile_after=r.inventory(profile), passed=passed))
phases.append('os-runs/'+role+'/ended.json')
r.require(passed, 'native OS collection failed: '+str(error or guards or cleanup_errors))
return phases
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
if out.is_relative_to(root):
raise ValueError('evidence output must be outside the frozen source checkout')
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 subprocess.check_output(['git','-C',str(root),'status','--porcelain'], text=True), 'frozen clean worktree required')
r.require(not out.exists(), 'fresh output; never overwrite earlier proof')
refs = r.source_refs(root)
checker = module('p08_initial_inputs', root/'tools/check_p08_normal_placement_evidence.py')
inputs_before = checker.input_map(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)
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-normal-placement-v1', 'commit':commit,
'selected_source_map':selected['map'], 'engine':engine, 'engine_sha256':r.sha(engine),
'owner_pid':os.getpid(), 'default_player':protected, 'diagnostic_seed':42533, 'inputs':inputs_before})
phases = []; previous = {}; cases = []; error = None; os_proof = None
deadline = time.monotonic()+(7200 if args.input_mode == 'native_os' else 900)
saved_env = {k:os.environ.get(k) for k in ('P08_PLACEMENT_ROOT','P08_PLACEMENT_ROLE','P08_PLACEMENT_INPUT')}
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)
pair = out/'pair'
preserved = {}
for role in ('writer', 'reader'):
os.environ.update(P08_PLACEMENT_ROOT=str(pair), P08_PLACEMENT_ROLE=role, P08_PLACEMENT_INPUT='handler')
phase(role, 'tests/ui/test_p08_normal_placement_ops.gd')
actual = r.inventory(pair)
r.require(all(actual.get(n) == pin for n, pin in preserved.items()),
'reader preserved every writer and formal byte')
preserved = actual
cases.append({'directory':'pair', 'phases':phases[-2:], 'files':preserved})
if args.input_mode == 'native_os':
os_phases = collect_os(r, root, out, stage, engine, commit, refs, protected, outer)
checker = module('p08_os_input_map', root/'tools/check_p08_normal_placement_evidence.py')
os_proof = 'os-proof.json'
r.write(out/os_proof, {'source_map':selected['map'], 'inputs':checker.input_map(root),
'input_method':'native_os', 'observer_mutations':[], 'phases':os_phases, 'directory':'os-pair'})
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
if r.source_refs(root) != refs or r.default_player(root) != protected:
error = (error+'; ' if error else '')+'protected root/profile changed'
if checker.input_map(root) != inputs_before:
error = (error+'; ' if error else '')+'spec/fixture/controller inputs changed'
r.write(out/'runner-ended.json', {'error':error, 'cleanup':cleanup, 'cleanup_errors':cleanup_errors,
'phases':phases, 'formal_acceptance':False, 'native_Windows':'pending'})
checker = module('p08_placement_checker', root/'tools/check_p08_normal_placement_evidence.py')
r.write(out/'index.json', {'schema':'p08-normal-placement-v1', 'commit':commit,
'source_map':selected['map'], 'inputs':inputs_before,
'marker_contract_sha256':r.sha(root/CONTRACT),
'spec_sha256':hashlib.sha256((root/'docs/spec/acceptance/P08-03.json').read_text().strip().encode()).hexdigest(),
'cases':cases, 'phases':phases, 'conditions':list(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':os_proof, '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('--input-mode', choices=('handler', 'native_os'), default='handler')
parser.add_argument('--collect', action='store_true', required=True)
return collect(parser.parse_args(argv))
if __name__ == '__main__':
raise SystemExit(main())
File diff suppressed because it is too large Load Diff