Files
TheTree_mock/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/IMPLEMENTATION.md
T

52 KiB
Raw Blame History

P28-02-EQ S4 implementation — retained completion r03

S4 retains the existing driver/verifier and all 134 prior test bodies (including the original 119). The only production-code correction in this completion is to require check_probe(...)["ok"] in driver admission and verifier recompute, with every error included in the rejection. --check and --run share the same admission gate. Unit tests mock the run boundary; no engine is launched.

The call-site check was limited to run_eq.py and verify_eq.py as instructed. Other calls to check_python_imports, check_observation and check_lifecycle raise on rejection and return True on success; check_report already requires ok. DIAG check_imports/bound_raw and collector stage_gate/guard_gate reject by exception. In particular, the collector gates' successful None is not false. No further ignored verdict-dictionary call was found in these two files.

Complete S4 requirement-to-code and test map

The following is the current S4 map. Earlier stage notes below are preserved historical records, including statements of work that was pending at that time. All tests cited here are engine-free, synthetic evidence tests, not native proof.

Retained requirement (S4 must / binding / r01-r03) Code Unit coverage
S1: pin full source map, EQ and allowed dependencies, engine, fixture, admission run_eq.DEPENDENCIES/FROZEN, load_dependencies, actual_pins, frozen_commit; verify_eq.verify repeats actual pins SourcesAndMetrics source closure/pin tests; S4Bundle.test_import_closure_rejections; S4NativeBundleLogic.test_receipt_and_source_rejection_matrix
S2: independently bind lifecycle and audio SHA; reject missing/error even with stdout verify_eq.NAMES, phase_evidence, check_audio; lifecycle inventory excludes only lifecycle/audio S4Bundle.test_missing_private_evidence_and_extra_rejected, test_phase_role_pid_audio_and_guard_rejected, test_rebound_lifecycle_and_scenario_contradictions
S2: retain raw and joined separately with normalization evidence; join before compare phase_evidence calls check.join_report; run writes raw/joined/proofs/checker JSON; seal hashes all; recompute compares joined reports S4Bundle.test_synthetic_phase_all_real_checkers_not_native_proof; S4RemainingBindings.test_nonzero_determinism_rejected_after_real_join; Normalization sidecar rejection tests
S2: full observation bytes/SHA and lifecycle guard/preparation/cleanup phase_evidence calls check_observation for all 31 checkpoints and check_lifecycle(raw, life, guard) S2Format observation/lifecycle tests; S4Bundle positive and contradiction tests
S3a: strict_json, measurement passed, all private files SHA bound verify_eq.read, check.read_report_stdout, phase_evidence exact inventory and check_report(raw, life.measurement, life.e3, life.e3_b1, life.e45) S3a.test_duplicate_JSON_key_rejected; S4Bundle positive, missing evidence and contradictions
S3a: lifecycle.e3/e3_b1, all 18 e3 files, full package evidence and checker outcomes phase_evidence binds each e3 row to lifecycle and raw; package bytes remain inside e3 evidence; copy_profile also retains all package/log/config files S3a package/NA/code/event rejection tests; S4Bundle scenario/b1 rejection matrix
S3b: lifecycle.e45, all 21 e45 files, 39 ordered scenarios, continuous intervals NAMES, phase_evidence count/copy checks; existing check_report/check_e45 continuity checks S4Bundle contradictions; S3b scenario ordering/continuity and ownership tests
S3b: join_facts sidecars/proofs and checker results with raw facts check.join_report/check.join_facts reused unchanged; phase_evidence returns raw/joined/proofs/checker; verify compares their stored copies with recomputation S3b facts/normalization tests; S4Bundle positive; S4NativeBundleLogic.test_synthetic_full_bundle_positive_not_native_evidence
S3b: separate R-A/R-B and O-A/O-B comparisons; zero differences required verify_eq.recompute explicit role loop, requires ok and empty differences S4NativeBundleLogic positive and cross-role rejection; S4RemainingBindings determinism rejection
S3b: preserve existing-defect, aliasing, cached digest facts, never manufacture PASS phase_evidence preserves existing checker outcomes and raw facts S4Bundle positive explicitly asserts existing-defect; S3b.test_aliasing_cannot_be_PASS, test_aliasing_missing_record and digest tests
r01: seven owned phases in exact order, parse --check-only, headless runtime run_eq.plan/run; verify_eq.PHASES/recompute validates commands, phase, role, PID and timestamps S4NativeBundleLogic positive and receipt matrix; S4RemainingBindings owned lifecycle matrix
r01: guard before parent, unique fresh startup/runtime profiles, env/role/fixture bindings wrapper_text, plan, run_private_engine, guard_gate; recompute validates wrapper, 14 distinct profiles and 7 PIDs S4Bundle guard/role/audio matrix; S4NativeBundleLogic startup-name rejection; S4RemainingBindings profile-reuse rejection
r01: gates return None; absent profile empty inventory is not export success run uses gates directly; copy_evidence requires exact existing inventory; copy_profile records exists separately S4NativeBundleLogic.test_gate_none_success_not_boolean; S4Bundle.test_missing_profile_not_export_success
r01: original absolute input destinations, never substitute copied root actual_pins invokes collector.inputs on original readonly and checks nine unique destinations S4NativeBundleLogic.test_copied_manifest_root_and_destination_count_rejected; S4RemainingBindings.test_nine_original_destinations_required
r01: finally cleanup, source/project/default-player preservation; failures retained without seal run finally captures cleanup/errors, profiles, pins and execution; recompute validates preservation/cleanup; seal only on success S4NativeBundleLogic.test_failure_keeps_raw_and_no_bundle_without_starting_engine and cleanup/source matrix
r01: complete copies, exact evidence inventory, final manifest/seal, no overwrite copy_evidence/copy_profile verify before/after copy; inventory/pin; seal writes manifest then seal; write uses x mode S4Bundle seal/missing/changed/extra/existing-output tests; S4NativeBundleLogic full synthetic bundle
r01: verifier reads bundle at BUILD_OUTPUT_DIR/p28-02-eq-evidence, recomputes raw checks and stored results verify_eq.main/verify/check_seal/recompute; no writes in verification S4Bundle missing bundle/seal/manifest tests; S4NativeBundleLogic full verify positive
r02: collector read-only import in closed D1+DIAG+EQ set; never import restart_pair load_dependencies pins all 11 external files, checks loaded module closure and Python imports; copying implemented in EQ S4Bundle.test_import_closure_rejections explicitly rejects restart_pair and other unapproved imports
r02: exact raw3 stdout.log, stderr.log, engine-native.log; exit comes from owned process.json, not raw3 collector.run_private_engine and DIAG.bound_raw reused; recompute checks owned JSON/diagnostics S4NativeBundleLogic receipt matrix missing native log/owned/exit-in-raw; S4RemainingBindings exit/start/end/diagnostic rejection
r02: exact private names and API arguments NAMES = checkpoint 00..30, observation 00..30, e3 00..17, e45 00..20, events/report/lifecycle/audio-close; phase_evidence passes all five check_report args and guard to check_lifecycle S4Bundle positive, missing/extra evidence and scenario matrix
r02: synthetic writes outside checkout; verifier read-only test_eq.synthetic_directory uses BUILD_OUTPUT_DIR or tempfile.gettempdir and rejects checkout descendants; verify outputs only stdout S4Bundle.test_checkout_temp_destination_rejected; full synthetic verify test
r03: enforce false static verdict, include all errors, both driver modes and verifier run_eq.main and verify_eq.recompute require static.ok S4ProbeAdmission four tests; S4RemainingBindings verifier false/true tests
r03: preserve original context bytes and all plans; retain old failures and test bodies S4_SUPPLEMENTARY.json loads Root original JSON unchanged, records five source pins and eight verified plan hashes; retained test prefix reconstructs original SHA Source/plan assertions recorded in supplementary; final unit output and SHA recorded separately
r01-r03: S_eq native is not Q; no acceptance/credit from units; exact submitted/base admission/recompute carry S_eq-native-not-Q, candidate_Q_measured false, formal_acceptance false, original_credit 0 S4NativeBundleLogic Q-label rejection and positive; final worker JSON uses submitted only after full local PASS

Completion evidence and limits

The original 134-test file can be recovered by removing only the newly appended classes and retaining its original unittest main; its SHA is cb742b252dbc278113b3c11c2431adac35b0c2e201a762a8ea1ac926e4af414b, matching Root's retained record. This also preserves all 119 earlier bodies. S4_SUPPLEMENTARY preserves all eight plans/API notes/clarification references directly from the supplied r09 JSON, plus the exact r03 text and decision. All five source SHA checks and all eight plan SHA checks succeeded.

Attempt 07 exposed a newly added test's overbroad comparator mock: it injected a difference into the report's self-check before the intended cross-PID gate. Only that new test was corrected to retain the real identity self-comparison. Attempt 07 raw/exit/SHA remain a failure. Attempt 08 rechecks the added classes (9 tests, 86.276 seconds, OK, exit 0). Attempt 09 covers the three added S4StoredResultBindings tests (0.025 seconds, OK, exit 0): verify must reject a cached verdict differing from recomputation, missing sidecars, and raw/joined substitution even when the supplied files have a valid seal. These isolate the stored-result equality gate with a recomputation mock; full real recomputation remains covered by the existing and new native-bundle-logic classes. Prior attempt 01 syntax, 02 unit, 04 recompute and supplementary assert failures remain historical failures. Attempt 05's 132 PASS and late attempt 06's 134 OK do not prove this version; the latter has no provider completion/exit receipt. Final full local evidence: attempt 10 ran all 146 tests in 293.277 seconds, OK, exit 0 (outer wall time 293.5742515 seconds). Raw is retained in UNIT_OUTPUT_S4_ATTEMPT_10.txt and UNIT_OUTPUT.txt, SHA-256 ff6fc0065772434f9ca35a1267e24d199057e339869a868942a41829327503bb. This was the single final full run after the targeted fixes and all additions.

An attempted read of Root's external retained test copy returned PermissionError. No permission change was attempted; exact retained-prefix SHA verification provided the same preservation check inside the allowed workspace. A shell heredoc read also failed before execution; subsequent reads used python -c.

Root still must run the exact submitted S in seven native phases, place the bundle, run p28-02-eq-unit and p28-02-eq-native-verify, obtain fresh independent Opus review of all six conditions, and complete qualification/approval/ integration/final before OPT and whole-unit gates. Original credit is zero; 23/88 and 4/30 are unchanged. No native, accepted S, Q or product PASS is claimed.

Retained S1-S3b implementation history

P28-02-EQ S1 implementation

Scope and authority

This run implements only staged plan r02 S1: compare_versions.py, synthetic test_eq.py, progress and unit evidence. No product, SPEC, TASK, references, registration, git, engine, Runner, or other worker operations are performed. S2–S4 and all six formal acceptance gates remain pending. A successful comparison is not a product E3/E5 PASS and does not establish native harness acceptance.

Read-only clarification SHA-256 checks matched the supplied values:

  • r01: 25d323fd562d29e80782b6f075fc7a0e8b49457a6c4fbd7c30e74b31a6b6a126
  • r02: 777accdd652f85db6b9014d85e3c8b3b60ca94b20768e6173b36bc769d360fd9
  • r03: 12b27f984ef5843d98327200ad261dccaf64968402192b08ad55b15ed5454ea2

SPEC file bytes SHA is 3791ccdcb87e8d71fe9205e1e692ebca9e0f974ea3b5fbc4fbb3943882131f1c, matching registration/ROOT_PROPOSAL_BYTE_TRANSFER.json. Removing the final LF gives the supplied contract text SHA cf75af22a803bf492e30f8a04a39f5187ece5b94cd54207aad8ece1683d4bc93. Neither representation was rewritten.

Internal transport choices for S2

  • Standard-library-only Python; no product or unapproved dependency imports.
  • Nodes follow plan r02 A1. Scalars retain their Variant codes. Float payloads are 16 lowercase hex digits for little-endian f64, including signed zero and NaN bit patterns. Strings are never coerced to StringName. NodePath uses type 22 with its string payload. RID/Object/Callable/Signal are rejected.
  • Composite math types use flat scalar components (AABB: 6, Basis: 9, Transform3D: 12, Projection: 16). Packed arrays retain their type code.
  • Array typed_info is null or [builtin_int_node, class_StringName_node, script_null_node]. Dictionary metadata is null or [key_info, value_info] using that same triple. Object/script-bearing values are not transported.
  • A path is a list of ["key", key_node] or ["index", integer] segments. Dictionary keys retain types and insertion order; indexes address Arrays. Empty path addresses the root. Mutations operate on deep copies, validate bounds and duplicate keys, and reject unknown operation fields.
  • array_splice uses nodes for the inserted list; dict_insert uses index, key_node, value_node. Other operation names/fields follow A3.
  • A transport record has exactly tree or diff, tree_sha, raw_bytes_sha, roundtrip_ok. Checkpoint S diffs apply to the previous S; latest diffs apply to current S. latest may instead have same_as_S: true and the three proof fields, with matching S raw-byte SHA.
  • tree_sha is SHA-256 of compact, insertion-order UTF-8 JSON, no ASCII escaping, no whitespace, no terminal newline. S2 must produce this representation and prove Godot byte roundtrip. Python never claims it can independently recreate Godot's var_to_bytes from a reported SHA or boolean.
  • There is no application depth cutoff or depth-4 hash summary. Entire trees are reconstructed and checked at each checkpoint. Resource/JSON parser limits remain ordinary process limits; malformed evidence is not a PASS.
  • Exact tree equality comes first. Text-key dictionary fallback preserves every key's type, every typed-info value, and array order, records all changed dictionary orders, and rejects duplicate textual keys. Scalar key spellings use their string/integer/bool/null text; float and compound keys use lossless compact typed JSON spelling, without decimal conversion. Original key nodes are always compared as well, so this sorting cannot erase key type or bits.

F1–F3 and restoration

The required four functions return/consume (normalized, sidecar) with precisely entries, violations, profile_root as sidecar keys. profile_root input is {"root": <simplified absolute user root>, "actual_user_data_dir": <guard value>}. The sidecar adds matches_guard: true inside this object after checking equality.

Only top-level E2 event payloads, or elements of snapshot systems.runtime.domain_events.recent_events, qualify. Nested event-shaped payload data and lookalike events elsewhere do not qualify. The nine event types and save_service source are closed. Both timing fields must exist and be nonnegative ints. Their markers are typed Dictionary nodes representing the r02 marker, not numeric substitutes. F3 preserves the whole original String node and root, and replaces every exact root-plus-slash occurrence. A preexisting reserved token is rejected to avoid ambiguous inversion.

Entries retain event index (null for snapshot trees), typed path, key and original node; F3 also retains root. Tree paths preserve event position, while comparison separately checks the actual event_id without remapping. Unknown timing/profile values remain unchanged and recorded as violations. Violation presence alone is not failure. Their actual differences are ordinary full-tree differences.

Restoration re-applies the closed normalization policy to reject missing, duplicate, forged or unauthorized entries. The independent original tree SHA must also match after restoration: changing a timing value in a sidecar to another valid timing cannot be detected from the marker alone. The comparator performs this SHA check against retained raw transport trees; unit tests include this forgery. A sidecar is not an independent authority for its own integrity.

validate_scenario_paths accepts only fixed user://p28_eq/{r,o}/ names: good, tampered_world, missing_key, wrong_type, out_of_range, duplicate_id. S3 must use these names and deterministic metadata/tamper rules.

Joined comparison report interface

Report keys are closed: schema (p28-02-eq/typed-v1), role (R/O), profile_root, checkpoints, events, event_start, event_end, signal_order, scenarios. No missing value is defaulted to zero. Manifest/package records belong to the bundle, not the S comparison report.

  • Main checkpoints: 31 records, consecutive minutes. Each contains minute, S and latest transports, latest_digest, computed_latest_digest, harness_normalized_digest, K, C, and observation.
  • Observation has before/after, each with complete S/K/C bytes SHA values. Equality is mandatory before environment normalization. S2 must obtain these from the complete raw layers, including telemetry and instance IDs.
  • Digest self-consistency is mandatory in each PID. If latest has F1–F3 entries, compare the explicitly labeled harness normalized digest and preserve both product digests with an exclusion reason. Otherwise compare product digests. Full S and latest comparison is mandatory in either case.
  • K uses the SPEC names, _accumulator as f64 hex, _phase_handlers as phase string to handler-ID list (compared as sets), and performance_budget with _sample_counts, _samples, _totals. Unknown/missing fields are rejected.
  • C has _mvp_manifest_cache_generation, catalog_is_current, _mvp_manifest_cache_bytes (complete base64 var_to_bytes), catalog_instance_id, current_catalog_instance_id.
  • Each excluded telemetry/instance-ID field retains a reason and both raw values.
  • event_start has counter and published_ids_count. A mismatch invalidates correspondence. Event rows have sequence (zero-based receive order), transport, and original_field_types. All original types and all tree fields are compared; no cap is applied. S2's checker must enforce the exact product event shape and required original type observations. event_end and signal order also compare.
  • Scenarios have id, operation, result, checkpoints and events (raw typed event trees). Result retains actual codes, ownership results, changed paths/values, boundaries and event counts defined by S3. State checkpoints use the same full-state machinery. Matching existing product failures remain matching failures, never rewritten as PASS. S3's checker must enforce scenario coverage, allowed operations and absolute product acceptance separately.

compare_reports reports differences with both actual values, dictionary-order paths, exclusions, violations and digest mode. Evidence errors yield ok: false. It does not replace check_eq or native/source admission: empty synthetic scenario lists can be compared in S1 tests; they cannot satisfy S3 acceptance.

Source closure and performance

check_source_closure hard-pins the collector's sorted compact JSON map digest 651f703621c8ed06a724709f75d8bc05b1eef2988c3b3d5d3466096a3f759bf0 and 1407 entries. Each row is bytes plus SHA-256. Added/missing paths fail. The exact changed set must equal the supplied registered set, which must be a subset of the six OPT paths. The caller cannot replace the before pin. S4 must separately pin all EQ/DIAG/RESTART/collector bytes, engine, fixture and admission metadata.

Source closure unit tests inject a synthetic map pin only within unittest mock to exercise positive closure mechanics; a separate test proves the real function rejects that synthetic map with the production pin. No product hooks are replaced.

classify_improvement implements SPEC §4 strict disjoint ranges of three finite, nonnegative measurements; markers and absent samples are rejected. Actual metric collection and the combined OPT adoption decision remain later native work.

Validation and preservation

Only python3 test_eq.py is executed, with synthetic inputs and bytecode disabled. The first run's missing-F3-sidecar failure is preserved unchanged in UNIT_OUTPUT_ATTEMPT_01.txt with SHA. The implementation now rejects the leftover reserved token after restoration. The intermediate successful run is also kept. UNIT_OUTPUT.txt is the latest complete raw output, with a separate SHA file. These are local unit results, not Runner/native validation or Q measurements.

S2 implementation (repair 4)

S2 only is complete. S1 compare_versions.py is byte-identical to its supplied 058f3fef... pin. The original 43 test bodies are retained; S2 adds 29 tests. E3/E4/E5 execution and S4 driver/verification are deliberately not implemented by this run. All six formal acceptance conditions remain pending.

Probe and evidence

  • eq_probe.gd follows the six DIAG lifecycle stages: public paused preparation; main with two deferred frames; 30 warm steps; 30 observed steps; outside-tick observations; observer teardown and close_requested.emit(). R uses the pinned fixture and starts B0 at 602/B1 at 632. O keeps the new 360-minute state, lets main enable Ops, and uses the same warm sequence (B1 390). The actual Ops result and all preparation/frame/B0/B1 values are retained, never substituted.
  • THE_TREE_EQ_ROLE is R or O. THE_TREE_P28_FIXTURE supplies R. The fixture SHA is pinned in the probe. The existing guard wrapper supplies THE_TREE_PACK_PROFILE_REPORT. No separate profile root from environment is trusted: bind_profile reads the receipt, reads the live globalized user root, checks OS.get_user_data_dir too, and records the receipt and SHA.
  • Every supported Variant is encoded using the S1 A1 representation. All math components, packed arrays, StringName/NodePath and typed container metadata retain their types. Unsupported object-bearing nodes append an error and fail transport/proof; they are not silently stringified. Full bytes roundtrip is performed by encode -> decode -> var_to_bytes in Godot. Python's synthetic tests do not establish that Godot execution succeeded.
  • Diff production uses exact recursive set operations and array_splice. Changed Dictionary key lists/order/metadata replace the whole affected subtree using set; unchanged key lists recurse into every value. This is a valid subset of A3 operations and has no depth limit. The emitted operations are replayed in Godot and checked before export, then replayed independently by the existing Python comparator. No S1 diff interface changes.
  • evidence/checkpoint-00.json holds the full B1 S tree; checkpoint-01..30.json hold S diffs from the previous checkpoint. Latest uses same_as_S only for equal bytes; otherwise it holds a diff from that checkpoint's S.
  • evidence/observation-00..30.json retain complete before/after S/K/C bytes (base64) plus hashes, K/C actual values. K includes all telemetry and C includes actual instance IDs. Reading a state witness also checks that create_snapshot did not change K or C. Cache filling is an explicit recorded preparation.
  • Domain events are captured through wildcard subscription after B1 and through the last tick/frame, without a cap. to_dictionary() transport includes its own byte roundtrip proof and receive-order sequence. original_field_types observes all seven object fields; entity_ids and payload include typed_info.
  • evidence/events.json, report.json, lifecycle.json and audio-close.json retain the run data. lifecycle has preparation, Ops/save policy, raw baseline/frame values, warm signals, guard binding, observer inventories, error list, and file hashes. File writes refuse overwrites. The lifecycle inventory excludes its own hash and the later audio receipt; S4 must bind both independently. S4 must reject missing lifecycle/audio or errors even if a stdout report exists.
  • stdout emits exactly one P28_02_EQ_REPORT= line with the unchanged S1 closed schema. Report also contains full transports; private files are independently bound copies, not substitutes for raw output.

Python joining and checking

  • S1 calls this a joined comparison report. The raw probe leaves harness_normalized_digest null because F1-F3 has one implementation, in Python. check_eq.join_report(raw) reconstructs all trees, checks their proof hashes, normalizes/restores using S1, and returns a copy plus complete sidecars. It fills that existing field with a harness-only typed canonical SHA, not a product SimulationDigest. Only Dictionary enumeration order is canonicalized; key node types, scalar bits, metadata and Array order remain exact. This avoids turning an allowed Dictionary-order fallback into a spurious digest failure. normalized_tree_sha remains insertion-order sensitive for transport binding. S4 must preserve and hash raw and joined outputs separately, call this join before compare_reports, and retain normalization evidence. Product latest_digest and computed_latest_digest always remain the actual Godot values.
  • check_report is explicitly an S2 format/contradiction check with formal_acceptance=false. It enforces 31 checkpoints, minute/counter coherence, full S/latest/K/C, observation proof, actual event field types, unaltered event IDs, and event coverage against endpoint published_ids. Empty or unknown transport fields do not pass as a digest-only comparison.
  • check_observation binds full raw bytes to SHA witnesses. check_lifecycle binds the separately collected guard receipt and checks actual preparation/teardown evidence. These functions must be called by S4 when copied evidence is joined.
  • check_probe is a conservative static screen, not a Godot parser or proof of arbitrary GDScript safety. It rejects inferred declarations, static autoload references/imports, live writes, unlisted/dynamic live dispatch, mutation calls outside preparation/stepping, nontextual sort, event truncation, and missing full-state/roundtrip/guard operations. Native parse-base/parse-wrapper and independent source review remain mandatory.
  • E3/E4/E5 scenarios are absent and check_report explicitly rejects nonempty scenario lists at this stage. S3 must extend coverage/absolute product-outcome checking and static allowed scenario boundaries without weakening S2 checks.

Local validation and preserved history

Engine-free command: python3 -B test_eq.py. S2 attempts 01/02/03 passed 68/71/72 tests respectively. Each complete raw output and SHA is retained. The final 72 include all 43 S1 tests and 29 S2 tests. UNIT_OUTPUT.txt is the final raw output; UNIT_OUTPUT_S1_FINAL.txt preserves the previous 43-test final output. Original UNIT_OUTPUT_ATTEMPT_01 (failure) and ATTEMPT_02 remain unchanged with their hashes. No failure was rewritten.

The first attempted shell heredoc was refused by the environment before it wrote a file (temporary-file creation denied). apply_patch and direct Python writes inside eq/ succeeded; no engine or Runner operation was attempted.

S2_SUPPLEMENTARY.json contains one actual_commander_context key with the full unedited r01/r02 plans, the full supplied RUN decision, and the read-only clarification paths/SHA. Both full plan texts reproduce their supplied hashes. This is a preserved instruction packet, not a new commander decision.

S3a implementation (repair 5)

Only the two specified S2 checker fixes and E3 are implemented. S3b (E4/E5), S4, all native phases, both formal validations and all six acceptance conditions remain pending. No product/engine/Runner/git-write/other-agent operation occurred. The S1 comparator is unchanged (058f3fef57c2ebe6951a48d85d570a110b982e08a13c805c244fec7d5e9a0fe8). Existing test bodies remain, except the S2 format helpers now provide the required measurement inventory and full 30-minute pairs; S1 fixtures are unchanged.

Measurement binding

check_report(raw, measurement=None, e3_evidence=None, b1_record=None) requires the separately retained lifecycle.measurement. This keeps process object IDs out of the unchanged joined-report schema and of cross-PID comparisons. The inventory contains probe_object (actual instance ID), start_minute and the full get_connections inventory. Both observer methods must belong to that probe object exactly once. Every measured checkpoint after B1 must have exactly snapshot_published then state_updated. Missing inventory never downgrades the expectation. The exact string phase keys are 0 through 10; aliases such as 00 fail. strict_json rejects duplicate object keys before they can be discarded. S4 must use strict_json for raw JSON, pass measurement to check_report, and bind lifecycle and all private files by SHA. The CLI now requires --lifecycle.

E3 intervals and raw evidence

The measured stream closes before run_e3. There are 18 ordered entries: restore_snapshot, validate, load_from_path, each with missing_key, wrong_type, out_of_range, duplicate_published_ids, duplicate_facility, tampered_world. Every entry retains applied/NA, its reason, invocation fact, actual B1 facility count, code/null and API reason, bool/errors, migration fact and actual event count. Dictionary-only world cases are NA. Envelope duplicate checks are invoked and their whole return is retained, but remain NA, never an acceptance or defect claim. O's zero-facility cases do not construct, substitute R or invent instances.

B1 is decoded from its already observed lossless transport. Inputs are deep copies with the specified fixed mutations. The unsupported manifest format is the fixed integer 2147483647. Save metadata is empty. Duplicate packages share the allowed fixed duplicate_id path sequentially; each original, modified and post-operation package file is copied into that interval's evidence before any later overwrite. The four-file inventory retains complete base64 bytes and SHA, including absent files as null. world.bin uses offset len//2 XOR 1. Package preparation uses SaveService.save_snapshot only inside the active E3 interval; its actual return and exact input are retained. A refused duplicate save makes load NA; a refused mandatory nonduplicate preparation fails the harness.

Each scenario retains two full S/latest/K/C checkpoints in the existing S1 schema. lifecycle.e3 and evidence/e3-NN.json additionally bind full raw layer bytes, layer typed transports, observation witnesses, invocation boundary, whole typed API return, all scenario event transports, separate signal records, latest_save_operation_result and SaveService diagnostic budgets before/after. check_e3 checks full byte witnesses, binds report to raw evidence and requires continuity between intervals (starting at the last measured checkpoint). No scenario reset or state repair is performed: later intervals use the actual new baseline, including any unexpected product changes.

join_report now derives the existing normalized digest field for scenario checkpoints as well as measured checkpoints, using the unchanged S1 policy. E3 report result summaries contain deterministic API facts; whole returns and package diagnostics remain in SHA-bound raw evidence, not silently discarded. Package timestamps and SaveService static diagnostic budgets have explicit exclusion reasons and actual values in checker output. S1 continues to compare the full normalized scenario state/events and deterministic results.

Product outcomes versus malformed evidence

check_e3 derives source-backed expectations and outputs actual results, expected event counts, typed path/value differences, dropped recent event, normalization sidecars and existing-defect-candidate entries. It does not accept a caller's PASS/defect label. Wrong counts, accepted invalid inputs or changed state are recorded product candidates; a forged count versus the retained event list is malformed harness evidence and fails admission. Missing load code, invented restore/validate code, false NA/applicability, missing raw evidence or unrecorded interval gaps also fail admission.

For failed loads, X(B, ev_fail) increments the counter, sort-inserts the actual unchanged ID and appends the event, retaining the dropped head at the 256 limit. The full normalized state must match this expected tree. The checker also binds payload to latest_save_operation_result and return facts, checks pause/restore outcomes, and retains full K/C differences. Such differences are not suppressed even when caused by the product's load accounting. Envelope duplicate acceptance alone is explicitly not a defect.

Handoff and validation boundary

The static screen admits the listed calls only in run_e3's active interval and the sole package-preparation helper; it remains a conservative screen, not a Godot parser. S3b extends scenario dispatch/coverage and the static count policy for its own authorized operations. S4 must bind lifecycle.e3/e3_b1/measurement, all e3-NN files, package evidence, raw/joined outputs and checker outcomes, and call check_report and check_lifecycle. The current S2 synthetic empty-scenario fixture remains useful for historical format tests; a S3a lifecycle requires the complete 18-entry table and cannot pass with an empty scenario list.

S3A_SUPPLEMENTARY.json has the single actual_commander_context key, containing both unmodified staged plans, both S3 plans and the full effective RUN decision. All four plan hashes match the supplied pins; read-only r01/r02/r03 paths remain in eq-staged-readonly-r04. This is preserved authority, not a new decision.

The local tests use synthetic bytes for Godot proof fields. Their PASS does not prove native parsing, Godot roundtrip, fixture behavior or product acceptance. Native execution is deliberately left to Root after S4, followed by Runner validation and the fresh independent review.

S3b implementation (repair 7; E4-1 r02)

S3b reuses the S1 transport/comparison, S2 measurement, and S3a observations. E3's implementation and the original 91 test bodies remain unchanged. Rebuilding the original test file from its retained prefix plus its original unittest main reproduces f81185e506954964bb96b31a569233202a1a7e7c78b2121aba6ab3f2e24d7e1e. The previous run 7da027a85548460bb008b562a79a52ae remains historical evidence: its blocked enumeration question was resolved by the supplied S3b r02, not retroactively labeled an implementation success.

Native scenario producer and raw binding

  • E4 runs after all 18 E3 intervals: build_facility, tick, restore_snapshot, load_from_path, rejected_command. The next interval starts from the actual previous end. All observations reuse e3_observation's complete immutable S/K/C, bytes, typed proof, latest and both digest values.
  • Registry IDs come from that PID's definition_registry.get_facility_ids(). Both registered order and textual sorted order retain Array[StringName]. Bounds come from world_service.get_bounds(); x and y are inclusive. WorldService's public FRONT/BACK layers are 0 and 1. ID is the outer loop, then x/y/z lexical order, rotation 0. Every tried candidate and complete public preview dictionary is transported without truncation. The whole read-only search has complete before/after observations; it does not repeat large snapshots per candidate. Empty registry is a harness error; NA requires exhausting a nonempty registry's entire nonempty world range.
  • Chosen payload is passed to the ordinary submit_command API. Product source :505-515 processes ready commands immediately when paused, and may publish there. The harness records this actual submit boundary, then exactly one advance_minutes(1), then the processed command result. It does not force delayed command execution, unpause, or replace any executor.
  • E4 load uses the already allowed fixed user://p28_eq/{r,o}/good path and empty metadata. Complete package bytes/SHA, whole returns, static SaveService diagnostic budgets and latest_save_operation_result are retained. Restore requires zero events; load requires one SAVE_LOADED and the existing e3_x implementation of X(P,event). Payload is bound to latest_save_operation_result.
  • E4 rejected command records the full submit and tick deltas separately: bookkeeping, clock and any other actual changed path/value remain visible. No current-run cache-staleness verdict is invented from publication timing.
  • E5 covers all four targets, both fixed nested locations and both directions. Signal handlers only retain references and record signals. Mutations occur after the handler has returned. Each interval has start, preparation-tick baseline, immediate operation result, and reset-tick end observations. Deep copies and original returned values have complete transport proofs. Each next baseline follows a recorded publication, with no direct repair.
  • lifecycle.e45 and evidence/e45-00..20.json bind these 21 intervals. report.scenarios contains the original 18 E3 rows followed by these 21 rows. Scenario events are uncapped typed transports. All scenario signals remain separate from measured signals, and are also bound into comparison facts.

Checker, comparison and existing defects

check_report retains its original first four parameters and adds optional e45_evidence. S3a-only callers continue to work; S3b lifecycle admission requires all 39 scenarios and all raw evidence. check_e3 itself is unchanged; its caller passes exactly the retained first 18 rows for S3b.

check_e45 rejects missing/reordered paths/combinations, interval gaps, false NA, wrong registry/order/bounds/rotation, missing trials/previews, unmatched chosen candidates, event count/identity coverage gaps, malformed signals, missing ownership mutation/proof, and caller-supplied PASS or cache-staleness verdicts. Outcome status is derived: recorded, NA, or existing-defect. Actual full typed differences and both digest values are retained per scenario.

Raw result.facts is bound exactly to detail before joining. join_facts transports all deterministic selection/command/signal facts and normalizes only snapshot transports (input/held_before/held_after) using S1's unchanged closed F1-F3 policy. Full inverse proofs and raw facts are retained. Package/API diagnostics remain in raw evidence with explicit exclusion reasons/values, never discarded. Search raw S/K/C stays in lifecycle evidence; its immutability is checked, and the enclosing scenario checkpoints retain cross-PID K/C comparison.

Two failing added tests justified narrow S1 comparator extensions:

  1. Only checkpoint index 2 of one of the eight named E5 outside_in intervals (four checkpoints, matching operation) can record a cached/computed digest mismatch as a product fact. Other checkpoint/self-consistency checks remain. Both sides' consistency outcomes compare, and digest exclusions follow the same F1-F3 rule. check_e45 reports cached_digest_aliasing as an existing defect.
  2. Joined S3b result facts contain typed trees; they use the existing full compare_trees dictionary-order-only fallback, preserving type/value/array differences and recording every dictionary-order path. Neither exception turns product ownership failures into PASS.

The static checker extends only the listed E4/E5 operations and active intervals, checks selection-source proof snippets, forbids handler mutation and extra dispatches, and retains all previous checks. It remains a conservative screen; native parse and independent source review are still required.

S4 binding requirements (additional to the retained S3a requirements)

S4 must copy/hash lifecycle.e45 and every e45-NN.json, bind them to the stdout/raw report, call check_report with lifecycle.e45, and call check_lifecycle for S3b. Join raw reports before compare_reports; retain join_facts sidecars/proofs and checker outcomes with the raw values. Compare R-A/R-B and O-A/O-B separately. Preserve existing-defect outcomes, including aliasing, in the final bundle. Do not call unit evidence a native run, accepted S, Q measurement, or product PASS.

S3B_SUPPLEMENTARY.json has one actual_commander_context key with all six full plans, the full effective RUN decision, and read-only clarification references. All six plan content hashes match the user-provided pins. SPEC, TASK, references, registration and prior supplementary files are unchanged. No engine, Runner, git write, other agent, product edit or full regression has run.

Final S3b local validation: python3 -B test_eq.py, 119 tests, OK, exit 0. Raw: UNIT_OUTPUT_S3B_ATTEMPT_09.txt and UNIT_OUTPUT.txt. SHA-256: 8360a2065b303099d5c546b3e4aecc0cc0ab0c2c1e5120b8034b6a1a64317030. Attempts 02/03/07/08 retain the syntax, digest, dictionary-order and fixture failures respectively; all earlier evidence remains unchanged.

S4 binding map (implementation in progress)

Retained requirement Implementation / additional unit coverage
Full raw observations and checkpoint SHA verify_eq: evidence inventory, check_observation, altered/missing witness rejection
Lifecycle and audio independently bound verify_eq: exact evidence names, lifecycle.files, audio/PID checks
Measurement, E3, B1, E45 supplied explicitly verify_eq: check_report with all five arguments; 39 scenarios and raw file equality
Guard before parent and fresh profiles run_eq: collector guard_gate and run_private_engine; distinct startup/runtime bindings
Raw versus joined state, join_facts proofs verify_eq: recompute join_report, preserve separate joined/proof/checker files
Same-role determinism and existing defects verify_eq: R-A/R-B and O-A/O-B only, preserve checker outcomes
Seven owned phases and complete raw3/owned5 run_eq/verify_eq: ordered phases, collector receipts, strict diagnostic recheck
Closure, source 1407, frozen S and pins run_eq: checked dependency import and full inventories; verifier repeats actual-file checks
Original absolute input destinations run_eq: collector.inputs on original readonly; no copied-root substitution
Finally cleanup and failure preservation run_eq: collector owned cleanup, failure receipt, seal only after successful checks
Manifest/seal and read-only verification verify_eq: full relative inventory and final seal; synthetic units outside checkout

This table records the required implementation targets, not completed validation. No native or formal validation is authorized for this worker.

S5 implementation (repair 10; EQ_S5_SCALE_PLAN r01/r02)

Implemented by Claude Opus 5.5 in the Desktop control session after the user moved implementation from Codex to Opus. The exact-S native of 6f75c9a failed in R-A and stays a failure; this stage fixes the harness defects that only the real engine exposed and makes the full R scope (E1-E5, 39 scenarios) fit the unchanged limits. All earlier text below and above this section is retained history.

Defects found only by the real engine (scratchpad diagnostics, not formal evidence)

  • write_evidence created user://evidence with the user:// path. Under the guard's runtime user-dir switch this fails; the directory is now created from the globalized path, as the RESTART helpers do.
  • typed_info encoded get_typed_script(), a null Object for unscripted typed containers, as an unsupported Variant 24. It is now transported as NIL ([0], which the Python side already required); a scripted element type still fails.
  • Package manifest mutation re-serialized a JSON-parsed manifest. Godot parses every JSON number as float, so untouched integers became 390.0, 1.0 and so on. Only the one key line is now edited as text; the Python rule already rejects any other change (new negative test).
  • The guard receipt was recorded after JSON parsing, with the same float problem. The exact receipt text is now kept beside it; Python parses that text strictly, compares it with the independently saved guard file and binds its SHA.
  • Godot instance IDs are signed 64-bit and RefCounted IDs are negative. The cache identity check accepts the sign. Raw values stay in raw; only the SPEC 3.2 exclusion (process-local instance ID) is applied across PIDs, with both values and the reason recorded.
  • A large E4 return is a blob; its ok/code facts are taken from the live return value.
  • After the first harness error, later scenarios are no longer run (the run already failed).

Product behavior recorded as an existing defect, separate from harness capture

autoload/simulation_runtime.gd:788 and :1346: a successful restore replaces domain_events with a new DomainEventStream and does not carry subscribers. The probe's wildcard subscription stayed on the old stream after E4 restore, so SAVE_LOADED and all later events were not delivered. follow_event_stream() runs after every E3 call and after E4 restore and load. When the stream changed it records the new stream's subscriber IDs (no instance IDs), recovers the unobserved events from recent_events() in publication order, and subscribes to the live stream again. check_e3/check_e45 record event_stream_replaced_subscribers_not_carried as an existing defect (never PASS). Completeness is still proven only by the counter delta, the published_ids delta and the actual event IDs; an event outside the 256-entry recent_events window would remain missing and fail. lifecycle.event_stream_replacements must equal the per-scenario facts. No event is renumbered, no product file or hook is changed.

Evidence representation (complete and reversible)

  • Trees larger than 64 KiB, raw S/K/C bytes and package files are written once as evidence/blobs/.gz, named by the SHA-256 of the uncompressed bytes; records hold {"blob": sha}. Small trees stay inline. lifecycle.blobs lists every blob with its size, compressed size and compressed SHA; verify_eq binds that list to the files exactly and decompresses every blob to check name and size.
  • Godot's JSON text of a tree equals json_bytes(tree) (checked on the R fixture tree), so a blob name is the tree SHA. var_to_bytes distinguishes typed metadata, String/StringName, int/float and key order (checked in the engine), so transport reuses the proof for equal bytes. Every checkpoint carries a complete tree; the diff chain is gone (tree_diff took 5.4 s per R checkpoint). Report and lifecycle hold references only, which removes the memory and swap growth seen in the failed native.

Python: same results, less work

  • A blob is accepted only when its uncompressed bytes hash to its name, and its tree is used only after the full validate_tree (types, arity, metadata, keys) has passed on first use; only then is its SHA recorded as valid. A failed blob is never recorded and fails again. A matching SHA is never taken as proof of types (Root's repro of [2, true] / [24, 0] in a correctly named blob is a regression test). Valid blob trees are shared, never mutated; checkpoints are loaded one at a time. Equal SHA means equal; otherwise Python == decides, which is exact JSON equality for validated trees (INT/BOOL payloads are int, floats are 16-hex strings).
  • Normalization runs the original closed policy unchanged on a skeleton holding only systems.runtime.domain_events.recent_events, read directly from the tree text. The rest of the text is proven free of the profile root, the reserved token, _us/_ms names and save_service; otherwise the original full walk runs. Restore runs the original reversible check on the skeleton.
  • normalized_digest builds the same canonical JSON without per-node copies and is memoized by SHA (17.4 s to about 1.2 s on an R tree, identical value).
  • Expected inputs, X(B, event) and the E5 expectation copy only the dictionaries on the changed path. Large derived trees are recorded by SHA descriptor in joined facts and checker results; compare_reports rebuilds them from the blobs when SHAs differ.
  • test_eq.S5 proves equivalence against the retained S1-S4 algorithms (compare_trees, canonical digest, deepcopy builders, original normalization including violations, tokens and non-array recent_events), that every one of 31 blob checkpoints is verified alone exactly as inline trees, and the new static requirements (full snapshot transport, blob write, gzip roundtrip, overwrite refusal, stream following).

Snapshot signal rule corrected (EQ_S5_SCALE_PLAN r03)

The S3a rule "exactly one snapshot_published/state_updated pair per measured minute" was a harness assumption. Paused submits publish once each after their command events (simulation_runtime.gd:486-493, :508-512, :5768-5793), besides the tick-end publish (:1745-1749) and a successful restore (:1473); R minute 648 had 50 commands and 51 pairs (the r2 check failure on the old rule is retained). The probe now stores, per signal, the domain_event counter and _next_command_id at emission (read only). check_publishes orders signals and events together and requires: complete pairs with equal counters; a command publish after exactly one submit whose command is in its trailing batch; no submit before any other publish and none left unpublished; every command event covered; and the remaining tick/restore publishes equal to the operations performed (one per measured minute; E3 successful restores; E4 1/1/1/1/1 with build only when applied; E5 2 or 3). Missing, extra and reordered pairs, including a missing publish between adjacent commands, fail. Actual counts stay raw and signal_order is compared exactly across versions.

Python speed, measured on retained R raw (r3, scratchpad diagnostic, not formal)

One R phase checked in the phase_evidence order (lifecycle, observations, check_report, join), with full stdout/stderr and Python's own exit kept for every run: 1270.3 s (first S5 code, with concurrent profiling) -> 552.9 s (memo of identical inputs, copy-free builders) -> 301.8 s (labelled digest, parse-free restore, copy-free diffs) -> 259.7 s (facts derived at first parse) -> 58.3 s (cyclic GC off inside memo_scope; before the blob validation fix, so not used as a result). With full blob validation, r3 + r4 checked in one process took 136.5 + 132.0 s and their comparison 4.2 s with 0 differences; with the validate_tree rewrite (same checks, messages and order; 4000-case differential test against the S1 version) four phase checks in parallel processes took 131 s wall (R 111.9 / 112.1 s, O 5.9 / 6.2 s), all ok. verify_eq therefore runs the four phase checks in parallel worker processes of the same verification and does the same-role comparisons in the parent with the workers' validated SHAs and normalization facts; the result equals the sequential mode, which remains the fallback and the mode used by unit tests. The unchanged 300 s native-verify limit is kept; the Runner configuration is not changed.

  • memo_scope: inside one verification call, identical check inputs (SHA of the exact JSON) are checked once; check_lifecycle and check_report shared E3/E45/measurement work. It also turns cyclic GC off for its duration; typed trees are acyclic lists, results do not depend on GC, and GC is restored on exit.
  • The joined harness digest is labelled normalized-sha256: (SHA of the exact normalized JSON, computed by splicing the normalized events into the blob text). compare_reports compares labelled digests exactly and, only when two differ, compares the canonical (dictionary-order-insensitive) digests; equal canonical digests are reported as dictionary-order-only, otherwise the difference is recorded. checker.normalized_digest remains the canonical digest (same values as S1).
  • Normalization facts, counters and next_command_id are derived when a blob tree is first parsed and memoized by SHA; restore uses the memoized skeleton, so join and comparison do not parse again. compare_trees records nodes shared with the immutable trees instead of deep copies; keys use inline text.

Self-contained bundle for the sandboxed native-verify (repair 11)

The formal p28-02-eq-native-verify runs under the Runner seatbelt, which denies reading data under the home directory except the validation checkout and the task runtime (the bundle is in the runtime's BUILD_OUTPUT_DIR). The first S5 validation failed on the fixture for this reason. run_eq now copies the fixture to inputs/fixture/ and the read-only manifest with its nine destinations to inputs/readonly/ before any phase, and checks the copies against the admission pins (bundle_inputs); the seal covers them. verify_eq passes those copies to actual_pins (bundled_inputs applies collector.inputs' rule: each manifest destination lies in the original read-only directory and its copy has the recorded bytes and SHA). The engine (/Applications) and the machine model stay read live. Everything else verify_eq recomputes from the bundle and the checkout as before.