Merge commit 'd369d1c399f7506bdb8d980b642ad0da216d14f4' into HEAD
This commit is contained in:
@@ -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.
|
||||
+23
@@ -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.
|
||||
+277
@@ -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)
|
||||
+48
@@ -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."
|
||||
}
|
||||
+14
@@ -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
|
||||
}
|
||||
+36
@@ -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."
|
||||
}
|
||||
+124
@@ -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
|
||||
}
|
||||
+38
@@ -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": []
|
||||
}
|
||||
+60
@@ -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."
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
BIN
Binary file not shown.
BIN
Binary file not shown.
+11
@@ -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
|
||||
BIN
Binary file not shown.
+9
@@ -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"
|
||||
}
|
||||
+31
@@ -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."
|
||||
}
|
||||
+976
@@ -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
|
||||
}
|
||||
+5327
File diff suppressed because it is too large
Load Diff
+37
@@ -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"
|
||||
}
|
||||
+5330
File diff suppressed because it is too large
Load Diff
+38
@@ -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"
|
||||
}
|
||||
+6665
File diff suppressed because it is too large
Load Diff
+38
@@ -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"
|
||||
}
|
||||
+37
@@ -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"
|
||||
}
|
||||
+25
@@ -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
|
||||
+6666
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
+89
@@ -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)
|
||||
+6
@@ -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
|
||||
+8
@@ -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)
|
||||
+1
@@ -0,0 +1 @@
|
||||
uid://c08passiver03
|
||||
+8620
File diff suppressed because it is too large
Load Diff
+5
@@ -0,0 +1,5 @@
|
||||
...................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 35 tests in 18.245s
|
||||
|
||||
OK
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
.................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 49 tests in 44.792s
|
||||
|
||||
OK
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
........................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 56 tests in 49.916s
|
||||
|
||||
OK
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
...........................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 75 tests in 66.488s
|
||||
|
||||
OK
|
||||
+19
@@ -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)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
...........................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 75 tests in 65.333s
|
||||
|
||||
OK
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
...................................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 83 tests in 73.589s
|
||||
|
||||
OK
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
...................................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 83 tests in 75.150s
|
||||
|
||||
OK
|
||||
+6670
File diff suppressed because it is too large
Load Diff
+29
@@ -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"
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
...................................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 83 tests in 76.743s
|
||||
|
||||
OK
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
...................................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 83 tests in 74.493s
|
||||
|
||||
OK
|
||||
+6673
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
+29
@@ -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"
|
||||
}
|
||||
+6679
File diff suppressed because it is too large
Load Diff
+32
@@ -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"
|
||||
}
|
||||
+8025
File diff suppressed because it is too large
Load Diff
+34
@@ -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"
|
||||
}
|
||||
+39
@@ -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.
|
||||
+169
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
@@ -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})
|
||||
@@ -0,0 +1 @@
|
||||
uid://b08passivep03
|
||||
Vendored
+460
@@ -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
@@ -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.
@@ -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
@@ -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": {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user