From 6f75c9a0513aafe5bd6ae7ed46b0ffda6386ac50 Mon Sep 17 00:00:00 2001 From: Agent Control Runner Date: Wed, 21 Oct 2026 10:10:39 +0900 Subject: [PATCH] =?UTF-8?q?P28-02-EQ:=20=E6=84=8F=E5=91=B3=E3=82=92?= =?UTF-8?q?=E4=BF=9D=E3=81=A4=E8=BB=BD=E9=87=8F=E5=8C=96=EF=BC=9A=E5=90=8C?= =?UTF-8?q?=E7=AD=89=E6=80=A7=E3=81=AE=E5=85=88=E8=A1=8C=E5=9B=BA=E5=AE=9A?= =?UTF-8?q?=EF=BC=88harness=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../execution/p28-02/eq/IMPLEMENTATION.md | 579 ++++++ .../execution/p28-02/eq/PROGRESS.md | 236 +++ .../execution/p28-02/eq/S2_SUPPLEMENTARY.json | 33 + .../p28-02/eq/S3A_SUPPLEMENTARY.json | 41 + .../p28-02/eq/S3B_SUPPLEMENTARY.json | 49 + .../execution/p28-02/eq/S4_SUPPLEMENTARY.json | 549 ++++++ .../execution/p28-02/eq/UNIT_OUTPUT.sha256 | 1 + .../execution/p28-02/eq/UNIT_OUTPUT.txt | 154 ++ .../p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.txt | 48 + .../p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.txt | 46 + .../p28-02/eq/UNIT_OUTPUT_S1_FINAL.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S1_FINAL.txt | 48 + .../eq/UNIT_OUTPUT_S2_ATTEMPT_01.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.txt | 73 + .../eq/UNIT_OUTPUT_S2_ATTEMPT_02.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.txt | 76 + .../eq/UNIT_OUTPUT_S2_ATTEMPT_03.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.txt | 77 + .../eq/UNIT_OUTPUT_S3A_ATTEMPT_01.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.txt | 77 + .../eq/UNIT_OUTPUT_S3A_ATTEMPT_02.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.txt | 90 + .../eq/UNIT_OUTPUT_S3A_ATTEMPT_03.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.txt | 96 + .../eq/UNIT_OUTPUT_S3A_ATTEMPT_04.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.txt | 96 + .../eq/UNIT_OUTPUT_S3B_ATTEMPT_01.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.txt | 96 + .../eq/UNIT_OUTPUT_S3B_ATTEMPT_02.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.txt | 4 + .../eq/UNIT_OUTPUT_S3B_ATTEMPT_03.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.txt | 127 ++ .../eq/UNIT_OUTPUT_S3B_ATTEMPT_04.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.txt | 119 ++ .../eq/UNIT_OUTPUT_S3B_ATTEMPT_05.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.txt | 119 ++ .../eq/UNIT_OUTPUT_S3B_ATTEMPT_06.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.txt | 123 ++ .../eq/UNIT_OUTPUT_S3B_ATTEMPT_07.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.txt | 14 + .../eq/UNIT_OUTPUT_S3B_ATTEMPT_08.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.txt | 132 ++ .../eq/UNIT_OUTPUT_S3B_ATTEMPT_09.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.txt | 124 ++ .../eq/UNIT_OUTPUT_S4_ATTEMPT_01.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.txt | 10 + .../eq/UNIT_OUTPUT_S4_ATTEMPT_02.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.txt | 328 ++++ .../eq/UNIT_OUTPUT_S4_ATTEMPT_03.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.txt | 14 + .../eq/UNIT_OUTPUT_S4_ATTEMPT_04.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.txt | 21 + .../eq/UNIT_OUTPUT_S4_ATTEMPT_05.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.txt | 137 ++ .../eq/UNIT_OUTPUT_S4_ATTEMPT_06.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.txt | 139 ++ .../eq/UNIT_OUTPUT_S4_ATTEMPT_07.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.txt | 28 + .../eq/UNIT_OUTPUT_S4_ATTEMPT_08.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.txt | 17 + .../eq/UNIT_OUTPUT_S4_ATTEMPT_09.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.txt | 11 + .../eq/UNIT_OUTPUT_S4_ATTEMPT_10.sha256 | 1 + .../p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.txt | 154 ++ .../execution/p28-02/eq/check_eq.py | 873 +++++++++ .../execution/p28-02/eq/compare_versions.py | 651 +++++++ .../execution/p28-02/eq/eq_probe.gd | 808 ++++++++ .../execution/p28-02/eq/run_eq.py | 273 +++ .../execution/p28-02/eq/test_eq.py | 1702 +++++++++++++++++ .../execution/p28-02/eq/verify_eq.py | 254 +++ 72 files changed, 8676 insertions(+) create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/IMPLEMENTATION.md create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/PROGRESS.md create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S2_SUPPLEMENTARY.json create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3A_SUPPLEMENTARY.json create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3B_SUPPLEMENTARY.json create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S4_SUPPLEMENTARY.json create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.sha256 create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.txt create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/check_eq.py create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/eq_probe.gd create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/run_eq.py create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py create mode 100644 docs/plans/original-completion-2026-10-02/execution/p28-02/eq/verify_eq.py diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/IMPLEMENTATION.md b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/IMPLEMENTATION.md new file mode 100644 index 0000000..a46d108 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/IMPLEMENTATION.md @@ -0,0 +1,579 @@ +# 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": , "actual_user_data_dir": }`. +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. diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/PROGRESS.md b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/PROGRESS.md new file mode 100644 index 0000000..2e0d117 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/PROGRESS.md @@ -0,0 +1,236 @@ +# P28-02-EQ progress — S4 retained completion r03 + +S4 の保持済み実装に対する残作業を完了し、局所unitの証拠として提出する。 +正式受入は保留、原本加算0。 +以下の旧段階の記録は履歴であり、現在の提出状態を表すものではない。 + +- run_eq.main と verify_eq.recompute の check_probe 戻り値を検査し、 + ok:false を全 errors 付きで拒否する。driver の両モードで共通。 + 両ファイル内の他の checker 呼出しも戻り値契約を確認済み。 +- 既存134件(元119件を含む)の試験本体を変更せず、12件を追加。 + driver/verifier の false/true、owned start/end/exit/diagnostic、profile、 + nine destinations、join 後の決定性不一致、保存済み結果・sidecar・ + raw/joined 入替えの拒否を対象とする。engine は全て不使用。 +- 対象クラス attempt 07: 8件中1件失敗。追加試験の模擬不一致が自己比較にも + 作用したため、試験だけを修正。失敗の raw/exit/SHA を保存。 +- attempt 08: 9件、86.276秒、OK、exit 0。 +- attempt 09: 保存済み結果の結合試験3件、0.025秒、OK、exit 0。 +- 最後の全件試験 attempt 10: `python3 -B test_eq.py`、146件、 + 293.277秒、OK、exit 0(外側の所要時間293.5742515秒)。 + 生出力は UNIT_OUTPUT_S4_ATTEMPT_10.txt と UNIT_OUTPUT.txt に保存。 + SHA-256: ff6fc0065772434f9ca35a1267e24d199057e339869a868942a41829327503bb。 + 開始は01:05:07 UTCまで、期限まで300秒以上を確保した。全件実行は今回1回。 +- S4_SUPPLEMENTARY.json は Root の r09 JSON を直接読み、内容を変えず + actual_commander_context に保存。追加 r03 と判断も提供ファイルから読む。 + 5資料、過去8計画、API notes の SHA を照合済み。 + 134件の元ファイル再構成SHAは cb742b252dbc278113b3c11c2431adac35b0c2e201a762a8ea1ac926e4af414b。 +- IMPLEMENTATION.md 冒頭に、全 S4 must、S4 binding、r01/r02/r03 の + 要件・コード・試験の対応表を記録した。旧文書と全失敗履歴は保持。 +- 外部 retained copy の読取りは PermissionError となったため、権限を変えず、 + W 内の保持prefixと元mainから元ファイルSHAを再現して確認した。 + 読取り用heredocも実行前に失敗し、その後は python -c を使用した。 + +過去のS4 attempt 01/02/04と補足生成assertは失敗のまま保持。 +attempt 05 の132件PASSはその版だけの事実。遅着した attempt 06 は +134件/206.531秒/OKだが、provider exit124・完了通知/exit受領なし・未提出の +事実は変更しない。今回の全件結果とは区別する。 + +提出後は Root の正確な S の native 7 phase → bundle 配置 → +p28-02-eq-unit と p28-02-eq-native-verify → fresh 独立 Opus の全6条件レビュー → +通常の資格確認・承認・統合・final → OPT/whole-unit。23/88、4/30は不変。 +worker は engine、正式validation、Runner、git書込み、他agent、製品変更、 +全回帰を実行していない。局所unitをnative、受入済みS、Q測定、製品PASSとは呼ばない。 + +## Retained prior progress (unchanged) + +# P28-02-EQ progress — current S3b (repair 7) + +stage S3b complete (not a failure; next is S4) + +段階 S3b 完了(失敗ではない。次は S4)。指定に従い正式 status は blocked。 +S_eq は未提出。全6受入条件の正式判定は保留、原本加算0。 + +- E4: 両 role に共通の5経路を実装。E4-1 はその PID の + definition_registry.get_facility_ids() を使い、登録順/文字順/件数、 + 公開 bounds、全候補の preview、最初の配置可能候補、submit/処理結果を保持。 + 空 registry、誤った列挙元、欠落した試行、false NA は拒否する。 +- E5: 4対象×dict/array×2方向の16組。handler 外で操作し、 + 完全な前後 S/K/C、返却値、digest、全イベント、別区間の signal を保持。 + aliasing は changed path/value 付きの existing-defect として出力し、PASS にしない。 +- checker: 39 scenario(既存E3の18 + E4の5 + E5の16)の結合、 + 区間連続、全イベント、restore 0/load 1、X(P,event)、所有権を検査。 + caller の PASS や、publish 時点だけによる cache_stale 判定は拒否する。 +- 比較器の局所修正は、追加試験の失敗で確認した2点だけ: + E5外から内の直後の cached digest 不整合を既存不具合として保持すること、 + 返却値の typed facts にも辞書順だけの fallback を適用すること。 +- 既存91件の試験ソースを元の構成に再結合した SHA は + f81185e506954964bb96b31a569233202a1a7e7c78b2121aba6ab3f2e24d7e1e と一致。 + E3本体、過去の進捗と全試験履歴は保持した。 +- 最終局所 unit: python3 -B test_eq.py、119 tests、OK、終了コード0。 + 既存91 + S3b追加28。Godot/native・正式validationは未実行。 + 生出力は UNIT_OUTPUT_S3B_ATTEMPT_09.txt と UNIT_OUTPUT.txt、対応SHAを保存。 +- S3b試行履歴(すべて生出力/SHAを保存): + 01=91件PASS、02=追加試験の構文エラー、 + 03=114件中digest既存不具合の比較試験1件失敗、 + 04/05=114件PASS、06=118件PASS、 + 07=辞書順fallbackの単独試験1件失敗、 + 08=119件中そのfixtureのcheckpoint欠落で1件失敗、 + 09=119件PASS。失敗を成功で上書きしていない。 +- S3B_SUPPLEMENTARY.json の単一 actual_commander_context key に + 両S3b計画、両S3計画、両段階計画、今回のRUN判断全文を保持。 + 計画6件のSHA、SPEC/TASK、references/registration、読取専用補足、 + S2/S3a補足、既存出力のSHAを照合した。 + +次はS4(driver・verify・bundleと提出)。IMPLEMENTATION.md末尾に、 +lifecycle.e45、e45-NN、raw/joined facts、sidecar、既存不具合の結合を追記。 +その後にRootの凍結Sで7 native phase、両validation、独立Opusレビュー、 +通常の資格確認・承認・統合・final。S3bのunit結果をnative/Qの結果とは呼ばない。 + +engine、Runner、git書込み、他agent、製品変更、全回帰は実行していない。 + +## Retained prior S3b-blocked/S3a/S2/S1 history (unchanged) + +Final S3b unit SHA-256: 8360a2065b303099d5c546b3e4aecc0cc0ab0c2c1e5120b8034b6a1a64317030 + +# P28-02-EQ progress — S3b blocked before implementation + +S3b is not complete. S_eq is not submitted. All six acceptance gates remain +pending; original credit remains 0. The retained S3a history follows unchanged. + +## Specification/API mismatch affecting E4-1 coverage + +EQ_S3B_STAGE_PLAN.txt E4-1 explicitly chooses the facility definition list from +`mvp_content_catalog`. The product's `scripts/data/mvp_content_catalog.gd:26-31` +DEFAULT_PATHS contains only guest_classes, species, staff_candidates and +unique_characters. Its get_ids(content_type) at :217-223 returns an empty list +for an absent content type. It supplies no facility definition enumeration. + +Facility definitions instead belong to `definition_registry`: +`scripts/core/definition_registry.gd:64-75` exposes get_facility, +get_facility_ids and get_all_facilities. Runtime initializes this registry from +FacilityCatalog paths at `autoload/simulation_runtime.gd:446-447`, and the +public preview_build_facility at :7660-7668 looks up that registry. + +Using an absent catalog type and reporting NA would not prove that no facility +is placeable. Replacing the explicitly fixed enumeration source with the +registry changes the candidates used by the required E4-1 acceptance scenario. +Per the instruction not to supplement missing specifications, this needs an +explicit correction of E4-1 to authorize the actual definition source. Proposed +correction: enumerate runtime.definition_registry.get_facility_ids() in textual +ID order, retaining the specified cell scan and public placement check. This is +a proposal only, not an implemented or approved change. + +Only this progress note changed. No implementation or tests were changed or +removed. The supplied SHA values for IMPLEMENTATION.md, eq_probe.gd, check_eq.py, +compare_versions.py, test_eq.py and UNIT_OUTPUT.txt matched before this note. +The 91-test result below is retained S3a evidence, not a test execution in this +run. No new unit test, engine, Runner, git write, agent, or product operation ran. +The first progress-note write attempt failed before writing because zsh could +not create a heredoc temporary file; this note was then written by apply_patch. +S3b E4/E5 and then S4 remain pending. Do not label this run S3b complete. + +## Retained S3a/S2/S1 progress (unchanged historical text) + +# P28-02-EQ progress — current S3a + +stage S3a complete (not a failure; next is S3b) + +段階 S3a 完了(失敗ではない。次は S3b)。計画に従い正式 status は blocked。 +S_eq は未提出。6受入条件はすべて保留、原本加算0。 + +- checker: phase key は正確に0..10。重複JSON keyも拒否。 + 30分各checkpointにsnapshot_published → state_updatedがちょうど1組必要。 + 測定開始の接続一覧にprobe自身の接続がなければ失敗。 +- probe/checker: E3の3 API × 6分類を、適用/NAの18行で記録・検査。 + B1の固定変異、実際のAPI戻り値、package全bytes/SHA、完全S/K/C、 + 全イベント差、scenario signal、区間の連続性、X(B, ev_fail)を保持。 + codeを創作せず、期待外の製品結果は既存不具合候補として残す。 +- S1 comparatorは元のSHAのまま。S1/S2の試験本体を保持 + (指定checker修正に必要なS2 fixture/呼出しの変更のみ)。 +- 最終局所試験: python3 -B test_eq.py、**91 tests, OK**、終了コード0。 + S3a追加19件。Godot/native/正式validationは未実行。 +- 生出力: UNIT_OUTPUT.txt と UNIT_OUTPUT_S3A_ATTEMPT_04.txt。 + SHA-256: 02221ae41e5dd40ecdac0ec0d7ffc657f265d3194c3817583c2b88ad375f132b。 + S3aの01/02/03/04試行(72/85/91/91件、全件PASS)を個別に保存。 + 既存のS1失敗出力・S2出力とSHAは変更せず保持。 +- S3A_SUPPLEMENTARY.json: 単一actual_commander_context keyに + 両S3計画・両段階計画・今回のRUN判断全文を保存。4計画のSHA一致。 +- SPEC/TASK/references/registration、read-only補足3件、S2補足、 + S1 comparatorと全ての既存UNIT_OUTPUT履歴のSHA一致を確認。 + +次はS3b(E4/E5)だけ。その後S4(driver/bundleと提出)、 +Rootの7 native phase、両validation、新しい独立Opusレビュー、 +通常の承認・統合・final。S4でlifecycle.measurement/e3/e3_b1と +private evidenceを結合する必要がある。詳細はIMPLEMENTATION.md末尾。 + +engine、Runner、git書込み、他agent、製品変更、全回帰は実行していない。 + +## Retained S2/S1 progress (unchanged historical text) + +# P28-02-EQ progress — current S2 + +stage S2 complete (not a failure; next is S3) + +段階 S2 完了(失敗ではない。次は S3)。計画 G4 に従い status は blocked。 +正式提出はしていない。6受入条件はすべて保留、原本加算0。 + +- eq_probe.gd: DIAG の6段階起動、A1 encode/decode、A2 bytes roundtrip、 + A3 全 B1/毎 tick 差分、31 checkpoint、B の全イベント記録、 + guard 実値照合、private evidence、単一 report 行、close_requested を実装。 +- check_eq.py: S1 schema の形式/矛盾、正規化の結合、raw 観測/起動証跡、 + 静的禁止の検査を追加。S3 の scenario は未着手。 +- test_eq.py: S1 43件を保持し、S2 29件を追加。最終 **72 tests, OK**。 + 実行は python3 -B test_eq.py のみ。native・正式 validation は未実行。 +- 生出力: UNIT_OUTPUT.txt。SHA-256: 9d323abda9bfffa02faf3a9d5cb56aa87e647017c991eb55b4807cf734386698。 + S2 の3試行も UNIT_OUTPUT_S2_ATTEMPT_01/02/03.txt と SHA に保存。 + S1 の最終出力は UNIT_OUTPUT_S1_FINAL.txt に保存。下記の失敗履歴と + UNIT_OUTPUT_ATTEMPT_01/02 は変更せず保持。 +- S2_SUPPLEMENTARY.json: 単一 actual_commander_context key に両計画全文、 + RUN判断全文、read-only 補足の path/SHA を保持。両計画の SHA 一致を確認。 + +次は S3 の E3/E4/E5 操作・結果・検査。その後 S4 の driver/bundle を実装し、 +Root/Runner の7 native phase、両 validation、新しい独立レビュー、承認・統合・final。 +engine、Runner、git 書込み、他 agent、製品変更、全回帰は実行していない。 + +## Retained S1 progress (unchanged historical text) + +# P28-02-EQ progress + +## Current stage + +stage S1 complete (not a failure; next is S2) + +段階 S1 完了(失敗ではない。次は S2)。正式な返却 status は計画 G4 に従い blocked。 +S_eq の提出、受入の自己確定、原本への加算はしていない。 + +## Completed + +- compare_versions.py: typed tree 比較、F1–F3 の4つの normalize/restore 関数、 + 全 checkpoint の差分再構成と tree SHA 再計算、report の S/latest/K/C/E2/ + scenario 比較、source map 1407件の固定と許可された変更集合の完全一致検査。 +- test_eq.py: 合成入力のみの43試験。型・挿入順・深い tree・可逆性・guard・ + violations・sidecar 改ざん・全イベント・比較除外・source 閉包の正常/拒否を検査。 +- IMPLEMENTATION.md: S2 向けの内部データ形式と、後続 checker/native の責任を記録。 + +## Unit evidence + +実行: `python3 test_eq.py`(engine 不使用)。最新結果: **43 tests, OK**、終了コード0。 +生出力: `UNIT_OUTPUT.txt`。 +SHA-256: `cdca0cdd551ce76c6100c4dd90e04559551f9d88c054a19a2bc6a77e6572ae15`。 + +初回の36試験中1失敗(F3 sidecar の欠落を見逃した)は +`UNIT_OUTPUT_ATTEMPT_01.txt` と `.sha256` にそのまま保持した。 +予約 token の復元漏れを拒否する修正後、41試験 PASS の中間出力も +`UNIT_OUTPUT_ATTEMPT_02.txt` と `.sha256` に保持した。 +失敗を成功に書き換えていない。作成したファイルは削除していない。 + +## Remaining stages and gates + +- S2: eq_probe.gd の6段階起動、Godot encode/decode と bytes roundtrip、31 checkpoint + と E2 の evidence 書出し、check_eq.py の形式/静的検査、対応 unit。 +- S3: E3/E4/E5 専用区間、全ての場面/入力の実行と実値の保存、絶対条件の checker。 +- S4: run_eq.py と verify_eq.py、全依存 SHA の固定、bundle 結合/拒否試験、正式提出。 +- Root/Runner: 凍結した S_eq で7 native phase、両正式 validation、独立レビュー、 + 通常の承認・統合・final。6受入条件は全て保留。 + +engine、Runner、git 書込み、他 agent、製品変更、全回帰は実行していない。 diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S2_SUPPLEMENTARY.json b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S2_SUPPLEMENTARY.json new file mode 100644 index 0000000..f62a4d1 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S2_SUPPLEMENTARY.json @@ -0,0 +1,33 @@ +{ + "actual_commander_context": { + "actual_run_decision": { + "action": "run", + "task_id": "P28-02-EQ", + "reason": "Use only after Root verifies through the normal gates: repair_ready, repairs 4, no S submitted, no active run, and the S1 files still present unchanged in the W. Run repair 4 of P28-02-EQ once on the same W from base 2549cf7d6992560b850bbd11934e3c14b39a1988 with the single worker codex gpt-6-astra, doing only stage S2 of EQ_STAGED_IMPLEMENTATION_PLAN r01 and r02. Start by reading eq/PROGRESS.md and eq/IMPLEMENTATION.md, and reuse the internal types, paths, record schema and API recorded there and in compare_versions.py without redesign. Do not delete or rewrite S1 code, except for fixes a failing test requires. Keep the S1 unit failure history in PROGRESS.md and UNIT_OUTPUT. S2 scope: (1) eq_probe.gd startup per the six-stage lifecycle reused from DIAG; (2) the r02 A1 typed tree encode/decode; (3) the A2 Godot roundtrip proof recording raw_bytes_sha, tree_sha and roundtrip_ok per checkpoint; (4) A3 export of the full B1 tree and exact per-tick diff operations for S and latest_snapshot to private user:// evidence/; (5) the B event record, with to_dictionary trees, original_field_types, start counter and published_ids count; (6) binding of the profile root to the guard actual_user_data_dir, with the value read live and never assumed; and (7) the single-line P28_02_EQ_REPORT plus close_requested.emit(), with the report fields matching what compare_versions.compare_reports already consumes. Also add the check_eq.py format, contradiction and static probe checks: no autoload class_name reference, no state-changing call outside the allowed preparation and stepping, no := inference from a Variant, textual StringName ordering, no SimulationDigest-only judgment. Add synthetic tests for these to test_eq.py. The E3/E4/E5 scenarios are S3 and must not be started now. Run the engine-free python3 test_eq.py until every existing test passes, save the raw output, update PROGRESS.md, and end S2 with formal status blocked and the finding 'stage S2 complete (not a failure; next is S3)'. Do not submit. Deliver as the one supplementary key the full texts of both plans and this decision; clarifications r01, r02 and r03 stay read-only in build/eq-staged-readonly-r04 with path and SHA. No engine, no git write or commit, no product change, no full regression; SPEC, TASK, eq/references and eq/registration stay unchanged. Ordinary implementation choices are recorded without stopping; block only for undecided matters affecting original product spec, values, permissions, billing or original acceptance. After S3 and S4, Root runs native on the frozen S_eq in 7 phases and builds the bundle; then both validations are mandatory, followed by a fresh independent Opus review of all 6 conditions and the normal integration and final. No original credit (23/88, 4/30). Quota fallback only on structured provider quota, once, same role, Antigravity claude-opus-5-5-high; any other failure is blocked. Decided by Claude Opus 5.5 in the Desktop control session (message 324); not a CLI commander result." + }, + "actual_full_plans": { + "EQ_STAGED_IMPLEMENTATION_PLAN.txt": { + "sha256": "eb7b4831e2164c6fc983fa6f9825e7f3e2993b4c0ebf2f90aac8ad10662666d2", + "full_unedited": "EQ_STAGED_IMPLEMENTATION_PLAN(P28-02-EQ repair 3 以降。base 2549cf7d6992560b850bbd11934e3c14b39a1988。SPEC、TASK、6条件、eq/references、eq/registration、EQ_S_TIMING_CLARIFICATION r01/r02、EQ_ENVIRONMENT_FIELDS_CLARIFICATION r03 は全てそのまま有効。変えるのは、工程と、成果物の内部の設計の固定だけ)\n\n前回までの事実\n- repair 2(run 84ca0ff8…)は、IMPLEMENTATION.md と compare_versions.py などを作った後、item_30 で全てを削除し、「6ファイルと unit の PASS を提供できない」として、自分から終了した。仕様の不足の指摘ではない。packet は 94 KB あった。\n- この失敗は失敗のまま保持する。削除したことを成功として扱わない。\n\n工程の変更(必須)\n- G1: **作ったファイルは、削除しない**。完成していなくても、W の eq/ に残す。各 run の最後に、eq/PROGRESS.md に、終わった段階・残りの作業・現在の試験の結果を書く。\n- G2: 1回の run では、下の**1つの段階だけ**を行う。始める前に eq/PROGRESS.md を読み、次の段階から再開する。前の段階のコードは作り直さない。\n- G3: 各段階の終わりに、engine を使わない python3 test_eq.py を実行する。その時点で存在する試験が、全件 PASS になるまで直す。生出力を eq/UNIT_OUTPUT.txt に保存する。\n- G4: 段階1〜3の終わりには、正式な JSON の status を blocked にし、findings に「段階 Sx 完了(失敗ではない。次は Sx+1)」と PROGRESS.md の要点を書いて返す。段階4の終わりにだけ、提出する(status を submitted 相当の正式な提出にする)。\n- G5: 通常の実装上の判断(関数の分け方、名前、試験データ、記録の書式)は、IMPLEMENTATION.md に記録して進める。blocked にしてよいのは、原本の仕様・値・権限・課金・受入に影響する未確定事項がある場合だけ。\n- G6: engine の起動、git への書込み、製品の変更、全回帰はしない。SPEC、TASK、eq/references、eq/registration は変更しない。\n\n固定するインターフェース(6ファイル。SPEC §2)\n\n1. compare_versions.py(Python のみ。engine を使わない)\n - normalize_events(events, profile_root) -> (normalized, sidecar):\n - r03 の F1〜F3 を、JSON の event の一覧に適用する。\n - 閉じた一覧の外の *_us / *_ms / profile_root を含む文字列は、正規化せず、violations として返す。\n - restore_events(normalized, sidecar, profile_root) -> events: 逆の復元(完全一致の確認に使う)。\n - compare_reports(a, b) -> dict: 2つの report(同じ版の別 PID、または前後の版)を比べる。\n - 毎分の checkpoint の S_norm_sha と latest_norm_sha の一致\n - digest の規則(r02 の T3)\n - K と C の、SPEC §3.2 に列挙した欄\n - E2 の正規化した全イベント(開始の counter の一致が前提)\n - E3/E4/E5 の scenario の結果の一致\n - 比べない欄は、理由と両側の値を記録する\n - 差は path ごとに返す\n - check_source_closure(before_map, after_map, allowed_changed) -> dict: SPEC §2 と OPT r02 §2。追加・欠落・登録されていない差分を拒否する。\n2. eq_probe.gd(GDScript):\n - 起動の6段階は、DIAG の diag_probe.gd の構成をそのまま参考にする。\n - 役割は R と O(env の THE_TREE_EQ_ROLE)。\n - 観測の checkpoint は B1 と、30分の各 tick の最後(31個)。各 checkpoint に、次のものを置く:\n - minute\n - S_raw_sha、S_norm_sha(GDScript の中で F1〜F3 の typed の marker を使って正規化した後の var_to_bytes の SHA)\n - 正規化した S の path の hash の表(depth ≤ 4)\n - latest_norm_sha\n - digest の情報\n - K と C の全体\n - sidecar\n - E2 は subscribe('*') で、全イベントの JSON(正規化の前)を記録する。正規化は compare_versions.py で行う(GDScript と Python で、同じ規則の二重実装をしない)。\n - E3/E4/E5 の scenario は、SPEC §3.3 の専用の区間で行う。各区間について、開始と終了、操作、code、前後の S/K/C、件数(r02 の T4)を記録する。\n - stdout には、P28_02_EQ_REPORT= をちょうど1行出す。終了は close_requested.emit()。\n3. check_eq.py: report 1つを検査する。\n - 形式、必須の欄、矛盾\n - 閉じた一覧の外の差\n - probe の静的な禁止(autoload の class_name の参照、状態を変える呼出しの区間の外での使用、Variant からの := の推論)\n - SimulationDigest だけでの判定\n4. run_eq.py: Root が実行する driver。\n - diag_p28_02.py の構成をそのまま参考にする(--check / --run、依存の SHA、1407 の source、凍結した S の照合、owned phase、guard、private profile、cleanup)。\n - phase は import、parse-base、parse-wrapper、R-A、R-B、O-A、O-B。\n - 成功したら、execution.json と bundle.json を作る。\n5. verify_eq.py: --project-root . で、$BUILD_OUTPUT_DIR/p28-02-eq-evidence の bundle を結合する。bundle が無ければ失敗する。\n - 各 report に check_eq を行う。\n - R-A と R-B、O-A と O-B に compare_reports を行い、差が0であること(harness の正しさ)。\n - E3/E5 の、前の版での製品の失敗は、「既存の不具合」の一覧として出力する。harness の不合格とは区別する。\n - SPEC、TASK、eq/references、eq/registration の SHA を固定して照合する。\n6. test_eq.py: 合成した入力だけで動く。各段階で、その段階の試験を足していく。\n\n段階(1回の run で1つ)\n- S1: compare_versions.py の全体と、その試験(F1〜F3 の正常と拒否、可逆性、比較、source の閉包)。PROGRESS.md と IMPLEMENTATION.md を作る。\n- S2: eq_probe.gd の、起動・観測の checkpoint・E2 の記録・報告。check_eq.py の静的な検査と形式の検査、それぞれの試験。\n- S3: eq_probe.gd の E3/E4/E5 の scenario、check_eq.py のそれに対する検査、試験。\n- S4: run_eq.py と verify_eq.py、bundle の試験。全件 PASS を確かめて、正式に提出する。\n\nRoot への依頼(packet を小さくするため)\n- actual_commander_context の key には、この計画の全文と RUN の判断だけを入れる。r01・r02・r03 の全文は、build/ に読取専用で置き、その path と SHA だけを渡す。eq/references は W の中にあるので、path だけで足りる。\n" + }, + "EQ_STAGED_IMPLEMENTATION_PLAN_R02.txt": { + "sha256": "128f42f18e168e9299995296ac7ad119f47d1647799d472663282e47e8ac9fdd", + "full_unedited": "EQ_STAGED_IMPLEMENTATION_PLAN r02(P28-02-EQ repair 3 以降。EQ_STAGED_IMPLEMENTATION_PLAN(r01)の工程 G1〜G6、段階 S1〜S4、Root への依頼は、そのまま有効。この r02 は、固定インターフェースのうち、状態とイベントの運搬の表現と、normalize_events の返り値を置き換えて確定する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03 は変更しない)\n\nA. 型を保つ運搬の表現(typed tree。JSON は運び方であって、型の情報は落とさない)\n\nA1 node の形式(JSON の配列)\n- 各値は [type_code, payload]。type_code は Godot の typeof() の値。\n - null: [0]\n - bool: [1, 0|1]\n - int: [2, 整数]\n - float: [3, \"<8 byte little-endian IEEE754 の hex>\"](10進の文字列にしない)\n - String: [4, \"文字列\"]\n - StringName: [21, \"文字列\"]\n - Vector2/Vector2i/Vector3/Vector3i/Rect2/Rect2i/Color など: [type_code, [各成分の node]](成分は int か float の node)\n - Dictionary: [27, [[key_node, value_node], …], typed_info]。**元の挿入の順序のまま**並べる。typed_info は、型つきの Dictionary なら key と value の builtin 型・class 名・script、それ以外は null。\n - Array: [28, [element_node, …], typed_info]。typed_info は get_typed_builtin()・get_typed_class_name()・get_typed_script() の値、型の無い Array なら null。\n - PackedByteArray: [29, \"\"]。他の Packed*Array も、要素ごとの node の列にする(float は hex)。\n- Object、Callable、Signal、RID が現れたら、運搬せずに失敗にする(snapshot と event の dict には、本来現れないもの)。\n\nA2 無損失の証明(Godot の中で行う。probe の必須の処理)\n- tree = encode(value) を作った後、decode(tree) で Variant を作り直す。var_to_bytes(decode(tree)) == var_to_bytes(value) であることを確かめる。一致しなければ失敗にする。\n- report には、checkpoint ごとに、次の3つを記録する。\n - raw_bytes_sha = sha256(var_to_bytes(value))\n - tree_sha = sha256(tree を key の順序を変えずに JSON.stringify した UTF-8)\n - roundtrip_ok\n- Python は、受け取った tree から tree_sha を計算し直して結合する。これで、Python で比べる tree が、Godot の元の bytes と無損失に対応することが保証される。\n\nA3 保存の場所と大きさ(深さの制限は設けない。全体を再構成できるようにする)\n- 各 PID は、checkpoint の列(B1 と、30分の各 tick の最後)について、S 層と latest_snapshot を、次の形で、private user:// の evidence/ に書き出す。driver は、それを RESTART の copy_states と同じ方式で out へ複製し、SHA を結合する。\n - checkpoint 0(B1): tree の全体(JSON、zstd で圧縮してよい。圧縮した場合は、圧縮の前後の SHA を両方記録する)。\n - checkpoint k(k≥1): checkpoint k−1 の tree に対する、path を指定した差分の操作の列。操作は set(path, node)、dict_insert(path, index, key_node, value_node)、dict_remove(path, key_node)、array_splice(path, start, delete_count, [node…])。順序つきで、再構成すると、checkpoint k の tree と完全一致すること。\n - latest_snapshot は、各 checkpoint で、var_to_bytes が S 層と同じなら same_as_S=true とし、違えば、その tree(または S に対する差分)を保存する。\n- Python は、checkpoint 0 から差分を順に適用して、全ての checkpoint を再構成する。checkpoint ごとに tree_sha と一致することを確かめる。\n\nA4 比較(compare_versions.py。全て tree の上で行い、深さの制限は無い)\n- 第一の比較は、tree の完全一致(型、key、順序、値。全ての node)。\n- 一致しない場合に限り、正規化した比較を行う。dict の key を文字で並べ(同じ文字の key が2つあれば拒否)、それ以外の型・値・配列の順序を保ったまま比べる。それで一致すれば「dict の列挙の順序だけの差」として、その全ての path を記録する。それ以外の差は、全ての path と両側の node を記録して、不一致にする。\n- F1〜F3(r03)の正規化は、tree の node の上で行う。sidecar から、元の tree へ完全に戻せること(tree_sha が一致すること)を確かめる。\n\nB. E2 のイベントの運搬\n- 各 event について、event.to_dictionary()(製品の直列化。scripts/core/domain_event.gd:47-59)の tree を記録する。あわせて、元の object の欄の型(event_id と event_type が StringName であるか、entity_ids の型、payload の dict の typed_info)を、original_field_types として記録する。\n- 受け取りの順序で番号をつけ、開始の時点の counter と、published_ids の数を記録する。\n- イベントの列は、A3 と同じく evidence/ に書き出し(tree の列。圧縮してよい)、SHA を結合する。Godot の中で、各 event について A2 の roundtrip を確かめる。\n- compare_reports は、この tree の列を受け取り、全ての欄と event_id を**そのまま**比べる(ID の付け替えはしない)。F1〜F3 は、payload の該当する node にだけ適用する。\n\nC. normalize_events とその仲間の返り値(固定)\n- normalize_events(events, profile_root) -> (normalized, sidecar)。返り値は2つの要素のまま。\n - normalized: tree の列。閉じた一覧(r03)の node だけを marker に置き換えたもの。\n - sidecar: dict で、key は次の3つに固定。\n - \"entries\": [{\"event_index\", \"path\", \"key\", \"original_node\"}…]。F1〜F3 で置き換えた全ての node の元の値。F3 の場合は original_node に元の message の文字列を入れ、\"root\" に、置き換えた root を入れる。\n - \"violations\": [{\"event_index\", \"path\", \"kind\", \"node\"}…]。閉じた一覧の外にあった、*_us / *_ms の key、profile_root を含む文字列など。**存在しただけでは不合格にしない**。正規化はせずに、そのまま保持して記録する。\n - \"profile_root\": 使った root の文字列と、guard の actual_user_data_dir との一致の結果。\n- restore_events(normalized, sidecar, profile_root) -> events: entries から元に戻す。violations の node は、もともと変えていないので、そのまま。\n- 状態の tree にも、同じ形の normalize_tree(tree, profile_root) -> (normalized, sidecar) と restore_tree を用意する。\n- r03 の規則は、そのまま。violations にあるものを正規化しようとしたら拒否する。violations にあるものが、比べる2つの側で実際に異なれば、その差は不一致(失敗)として、path と両側の値を記録する。\n\nD. 段階への影響\n- S1(今回): compare_versions.py に、A4 の比較、C の4つの関数、A3 の差分の再構成、tree_sha の再計算、check_source_closure を実装する。試験は合成の tree で行い、次のものを確かめる。\n - 型の違い(int と float、String と StringName、型つきの配列)を区別すること\n - dict の順序だけの差の path\n - 差分の再構成の完全一致\n - sidecar からの逆の復元\n - violations の扱い(存在だけでは不合格にしない、正規化しようとしたら拒否、差があれば不一致)\n- S2: eq_probe.gd に、A1 の encode と decode、A2 の roundtrip、A3 の書き出し、B の記録を実装する。\n- S3 と S4 は、r01 のとおり。\n" + } + }, + "read_only_clarifications": { + "EQ_S_TIMING_CLARIFICATION.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_S_TIMING_CLARIFICATION.txt", + "sha256": "25d323fd562d29e80782b6f075fc7a0e8b49457a6c4fbd7c30e74b31a6b6a126" + }, + "EQ_S_TIMING_CLARIFICATION_R02.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_S_TIMING_CLARIFICATION_R02.txt", + "sha256": "777accdd652f85db6b9014d85e3c8b3b60ca94b20768e6173b36bc769d360fd9" + }, + "EQ_ENVIRONMENT_FIELDS_CLARIFICATION_R03.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_ENVIRONMENT_FIELDS_CLARIFICATION_R03.txt", + "sha256": "12b27f984ef5843d98327200ad261dccaf64968402192b08ad55b15ed5454ea2" + } + } + } +} diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3A_SUPPLEMENTARY.json b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3A_SUPPLEMENTARY.json new file mode 100644 index 0000000..05faf50 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3A_SUPPLEMENTARY.json @@ -0,0 +1,41 @@ +{ + "actual_commander_context": { + "actual_run_decision": { + "action": "run", + "task_id": "P28-02-EQ", + "reason": "Supersedes DESKTOP_EQ_S3A_RUN_DECISION.json, which is kept unchanged as history. DESKTOP_EQ_S3A_REPAIR_DECISION.json stays valid as written: its facts (S2 checkpoint, the two checker defects, the S3a/S3b split) are unchanged by this correction. Use only after Root verifies through the normal gates: repair_ready, repairs 5, no S submitted, no active run, and the S1 and S2 files still present unchanged in the W. Run repair 5 of P28-02-EQ once on the same W from base 2549cf7d6992560b850bbd11934e3c14b39a1988 with the single worker codex gpt-6-astra, doing only stage S3a as defined in EQ_S3_STAGE_PLAN.txt and replaced in part by EQ_S3_STAGE_PLAN_R02.txt, under EQ_STAGED_IMPLEMENTATION_PLAN r01 and r02. Start by reading eq/PROGRESS.md and eq/IMPLEMENTATION.md and reuse the S1/S2 types, paths, schema, API and notes without redesign. Do not delete or rewrite S1/S2 code or test bodies, except for the two checker fixes and fixes a failing test requires. Keep the failure history. S3a scope: (1) check_eq.py:109 must require the exact phase-key set {0..10}. (2) check_eq.py:147-150 must require exactly one snapshot_published then state_updated pair for each of the 30 measured minutes, bound to the checkpoint minute and to a recorded connection inventory that contains the probe's own snapshot_published connection. A missing probe connection fails; it is never downgraded to a state-only expectation. The product's unconnected case is out of this interval's scope, and scenario signals are kept separate. (3) E3 uses the source-backed table. restore_snapshot returns its bool with code null and reason 'API returns bool only'. validate returns its full {ok, errors} with code null and reason 'API returns ok/errors only'. load_from_path returns a real code, and a missing code there is a failure. Missing key, wrong type and out-of-range are applied to all three APIs by fixed rules (clock removal, string absolute_minute and speed 9 for the Dictionary APIs; checksum_world removal, string format_version and an unsupported format_version for the package). Duplicate published_ids is applied to restore and, if SaveService.save_snapshot accepts it, to load; it is NA for envelope validate. Duplicate facility is applied in R and is NA in O when B1 actually has 0 facilities, recorded with the count and with no construction, no R substitution and no invented values. world.bin tamper is load only, by r03 D3. Record full before/after S/K/C, the event difference and count (0 for restore and validate; exactly 1 SAVE_LOAD_FAILED equal to X(B, ev_fail) for failed loads), and the applied/NA table. Mismatches are kept as existing-defect candidates; envelope validate accepting an internal duplicate is not called a product defect. Add the listed checker rules and negative tests. State-changing calls are allowed only inside the listed scenario interval. Run the engine-free python3 test_eq.py until every existing test passes, save the raw output, update PROGRESS.md, and end S3a with formal status blocked and the finding 'stage S3a complete (not a failure; next is S3b)'. Do not submit. Deliver as the one supplementary key both S3 plans, both staged plans and this decision; clarifications r01, r02 and r03 stay read-only in build/eq-staged-readonly-r04. No engine, no git write or commit, no product change, no full regression; SPEC, TASK, eq/references and eq/registration stay unchanged. Ordinary implementation choices are recorded without stopping; block only for undecided matters affecting original product spec, values, permissions, billing or original acceptance. The remaining order is S3b, then S4 and submission, then Root native in 7 phases, then both validations, then a fresh independent Opus review of all 6 conditions, then the normal integration and final. No original credit (23/88, 4/30); the 900-second timeout is unchanged. Quota fallback only on structured provider quota, once, same role, Antigravity claude-opus-5-5-high; any other failure is blocked. Decided by Claude Opus 5.5 in the Desktop control session (message 330); not a CLI commander result." + }, + "actual_full_plans": { + "EQ_STAGED_IMPLEMENTATION_PLAN.txt": { + "sha256": "eb7b4831e2164c6fc983fa6f9825e7f3e2993b4c0ebf2f90aac8ad10662666d2", + "full_unedited": "EQ_STAGED_IMPLEMENTATION_PLAN(P28-02-EQ repair 3 以降。base 2549cf7d6992560b850bbd11934e3c14b39a1988。SPEC、TASK、6条件、eq/references、eq/registration、EQ_S_TIMING_CLARIFICATION r01/r02、EQ_ENVIRONMENT_FIELDS_CLARIFICATION r03 は全てそのまま有効。変えるのは、工程と、成果物の内部の設計の固定だけ)\n\n前回までの事実\n- repair 2(run 84ca0ff8…)は、IMPLEMENTATION.md と compare_versions.py などを作った後、item_30 で全てを削除し、「6ファイルと unit の PASS を提供できない」として、自分から終了した。仕様の不足の指摘ではない。packet は 94 KB あった。\n- この失敗は失敗のまま保持する。削除したことを成功として扱わない。\n\n工程の変更(必須)\n- G1: **作ったファイルは、削除しない**。完成していなくても、W の eq/ に残す。各 run の最後に、eq/PROGRESS.md に、終わった段階・残りの作業・現在の試験の結果を書く。\n- G2: 1回の run では、下の**1つの段階だけ**を行う。始める前に eq/PROGRESS.md を読み、次の段階から再開する。前の段階のコードは作り直さない。\n- G3: 各段階の終わりに、engine を使わない python3 test_eq.py を実行する。その時点で存在する試験が、全件 PASS になるまで直す。生出力を eq/UNIT_OUTPUT.txt に保存する。\n- G4: 段階1〜3の終わりには、正式な JSON の status を blocked にし、findings に「段階 Sx 完了(失敗ではない。次は Sx+1)」と PROGRESS.md の要点を書いて返す。段階4の終わりにだけ、提出する(status を submitted 相当の正式な提出にする)。\n- G5: 通常の実装上の判断(関数の分け方、名前、試験データ、記録の書式)は、IMPLEMENTATION.md に記録して進める。blocked にしてよいのは、原本の仕様・値・権限・課金・受入に影響する未確定事項がある場合だけ。\n- G6: engine の起動、git への書込み、製品の変更、全回帰はしない。SPEC、TASK、eq/references、eq/registration は変更しない。\n\n固定するインターフェース(6ファイル。SPEC §2)\n\n1. compare_versions.py(Python のみ。engine を使わない)\n - normalize_events(events, profile_root) -> (normalized, sidecar):\n - r03 の F1〜F3 を、JSON の event の一覧に適用する。\n - 閉じた一覧の外の *_us / *_ms / profile_root を含む文字列は、正規化せず、violations として返す。\n - restore_events(normalized, sidecar, profile_root) -> events: 逆の復元(完全一致の確認に使う)。\n - compare_reports(a, b) -> dict: 2つの report(同じ版の別 PID、または前後の版)を比べる。\n - 毎分の checkpoint の S_norm_sha と latest_norm_sha の一致\n - digest の規則(r02 の T3)\n - K と C の、SPEC §3.2 に列挙した欄\n - E2 の正規化した全イベント(開始の counter の一致が前提)\n - E3/E4/E5 の scenario の結果の一致\n - 比べない欄は、理由と両側の値を記録する\n - 差は path ごとに返す\n - check_source_closure(before_map, after_map, allowed_changed) -> dict: SPEC §2 と OPT r02 §2。追加・欠落・登録されていない差分を拒否する。\n2. eq_probe.gd(GDScript):\n - 起動の6段階は、DIAG の diag_probe.gd の構成をそのまま参考にする。\n - 役割は R と O(env の THE_TREE_EQ_ROLE)。\n - 観測の checkpoint は B1 と、30分の各 tick の最後(31個)。各 checkpoint に、次のものを置く:\n - minute\n - S_raw_sha、S_norm_sha(GDScript の中で F1〜F3 の typed の marker を使って正規化した後の var_to_bytes の SHA)\n - 正規化した S の path の hash の表(depth ≤ 4)\n - latest_norm_sha\n - digest の情報\n - K と C の全体\n - sidecar\n - E2 は subscribe('*') で、全イベントの JSON(正規化の前)を記録する。正規化は compare_versions.py で行う(GDScript と Python で、同じ規則の二重実装をしない)。\n - E3/E4/E5 の scenario は、SPEC §3.3 の専用の区間で行う。各区間について、開始と終了、操作、code、前後の S/K/C、件数(r02 の T4)を記録する。\n - stdout には、P28_02_EQ_REPORT= をちょうど1行出す。終了は close_requested.emit()。\n3. check_eq.py: report 1つを検査する。\n - 形式、必須の欄、矛盾\n - 閉じた一覧の外の差\n - probe の静的な禁止(autoload の class_name の参照、状態を変える呼出しの区間の外での使用、Variant からの := の推論)\n - SimulationDigest だけでの判定\n4. run_eq.py: Root が実行する driver。\n - diag_p28_02.py の構成をそのまま参考にする(--check / --run、依存の SHA、1407 の source、凍結した S の照合、owned phase、guard、private profile、cleanup)。\n - phase は import、parse-base、parse-wrapper、R-A、R-B、O-A、O-B。\n - 成功したら、execution.json と bundle.json を作る。\n5. verify_eq.py: --project-root . で、$BUILD_OUTPUT_DIR/p28-02-eq-evidence の bundle を結合する。bundle が無ければ失敗する。\n - 各 report に check_eq を行う。\n - R-A と R-B、O-A と O-B に compare_reports を行い、差が0であること(harness の正しさ)。\n - E3/E5 の、前の版での製品の失敗は、「既存の不具合」の一覧として出力する。harness の不合格とは区別する。\n - SPEC、TASK、eq/references、eq/registration の SHA を固定して照合する。\n6. test_eq.py: 合成した入力だけで動く。各段階で、その段階の試験を足していく。\n\n段階(1回の run で1つ)\n- S1: compare_versions.py の全体と、その試験(F1〜F3 の正常と拒否、可逆性、比較、source の閉包)。PROGRESS.md と IMPLEMENTATION.md を作る。\n- S2: eq_probe.gd の、起動・観測の checkpoint・E2 の記録・報告。check_eq.py の静的な検査と形式の検査、それぞれの試験。\n- S3: eq_probe.gd の E3/E4/E5 の scenario、check_eq.py のそれに対する検査、試験。\n- S4: run_eq.py と verify_eq.py、bundle の試験。全件 PASS を確かめて、正式に提出する。\n\nRoot への依頼(packet を小さくするため)\n- actual_commander_context の key には、この計画の全文と RUN の判断だけを入れる。r01・r02・r03 の全文は、build/ に読取専用で置き、その path と SHA だけを渡す。eq/references は W の中にあるので、path だけで足りる。\n" + }, + "EQ_STAGED_IMPLEMENTATION_PLAN_R02.txt": { + "sha256": "128f42f18e168e9299995296ac7ad119f47d1647799d472663282e47e8ac9fdd", + "full_unedited": "EQ_STAGED_IMPLEMENTATION_PLAN r02(P28-02-EQ repair 3 以降。EQ_STAGED_IMPLEMENTATION_PLAN(r01)の工程 G1〜G6、段階 S1〜S4、Root への依頼は、そのまま有効。この r02 は、固定インターフェースのうち、状態とイベントの運搬の表現と、normalize_events の返り値を置き換えて確定する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03 は変更しない)\n\nA. 型を保つ運搬の表現(typed tree。JSON は運び方であって、型の情報は落とさない)\n\nA1 node の形式(JSON の配列)\n- 各値は [type_code, payload]。type_code は Godot の typeof() の値。\n - null: [0]\n - bool: [1, 0|1]\n - int: [2, 整数]\n - float: [3, \"<8 byte little-endian IEEE754 の hex>\"](10進の文字列にしない)\n - String: [4, \"文字列\"]\n - StringName: [21, \"文字列\"]\n - Vector2/Vector2i/Vector3/Vector3i/Rect2/Rect2i/Color など: [type_code, [各成分の node]](成分は int か float の node)\n - Dictionary: [27, [[key_node, value_node], …], typed_info]。**元の挿入の順序のまま**並べる。typed_info は、型つきの Dictionary なら key と value の builtin 型・class 名・script、それ以外は null。\n - Array: [28, [element_node, …], typed_info]。typed_info は get_typed_builtin()・get_typed_class_name()・get_typed_script() の値、型の無い Array なら null。\n - PackedByteArray: [29, \"\"]。他の Packed*Array も、要素ごとの node の列にする(float は hex)。\n- Object、Callable、Signal、RID が現れたら、運搬せずに失敗にする(snapshot と event の dict には、本来現れないもの)。\n\nA2 無損失の証明(Godot の中で行う。probe の必須の処理)\n- tree = encode(value) を作った後、decode(tree) で Variant を作り直す。var_to_bytes(decode(tree)) == var_to_bytes(value) であることを確かめる。一致しなければ失敗にする。\n- report には、checkpoint ごとに、次の3つを記録する。\n - raw_bytes_sha = sha256(var_to_bytes(value))\n - tree_sha = sha256(tree を key の順序を変えずに JSON.stringify した UTF-8)\n - roundtrip_ok\n- Python は、受け取った tree から tree_sha を計算し直して結合する。これで、Python で比べる tree が、Godot の元の bytes と無損失に対応することが保証される。\n\nA3 保存の場所と大きさ(深さの制限は設けない。全体を再構成できるようにする)\n- 各 PID は、checkpoint の列(B1 と、30分の各 tick の最後)について、S 層と latest_snapshot を、次の形で、private user:// の evidence/ に書き出す。driver は、それを RESTART の copy_states と同じ方式で out へ複製し、SHA を結合する。\n - checkpoint 0(B1): tree の全体(JSON、zstd で圧縮してよい。圧縮した場合は、圧縮の前後の SHA を両方記録する)。\n - checkpoint k(k≥1): checkpoint k−1 の tree に対する、path を指定した差分の操作の列。操作は set(path, node)、dict_insert(path, index, key_node, value_node)、dict_remove(path, key_node)、array_splice(path, start, delete_count, [node…])。順序つきで、再構成すると、checkpoint k の tree と完全一致すること。\n - latest_snapshot は、各 checkpoint で、var_to_bytes が S 層と同じなら same_as_S=true とし、違えば、その tree(または S に対する差分)を保存する。\n- Python は、checkpoint 0 から差分を順に適用して、全ての checkpoint を再構成する。checkpoint ごとに tree_sha と一致することを確かめる。\n\nA4 比較(compare_versions.py。全て tree の上で行い、深さの制限は無い)\n- 第一の比較は、tree の完全一致(型、key、順序、値。全ての node)。\n- 一致しない場合に限り、正規化した比較を行う。dict の key を文字で並べ(同じ文字の key が2つあれば拒否)、それ以外の型・値・配列の順序を保ったまま比べる。それで一致すれば「dict の列挙の順序だけの差」として、その全ての path を記録する。それ以外の差は、全ての path と両側の node を記録して、不一致にする。\n- F1〜F3(r03)の正規化は、tree の node の上で行う。sidecar から、元の tree へ完全に戻せること(tree_sha が一致すること)を確かめる。\n\nB. E2 のイベントの運搬\n- 各 event について、event.to_dictionary()(製品の直列化。scripts/core/domain_event.gd:47-59)の tree を記録する。あわせて、元の object の欄の型(event_id と event_type が StringName であるか、entity_ids の型、payload の dict の typed_info)を、original_field_types として記録する。\n- 受け取りの順序で番号をつけ、開始の時点の counter と、published_ids の数を記録する。\n- イベントの列は、A3 と同じく evidence/ に書き出し(tree の列。圧縮してよい)、SHA を結合する。Godot の中で、各 event について A2 の roundtrip を確かめる。\n- compare_reports は、この tree の列を受け取り、全ての欄と event_id を**そのまま**比べる(ID の付け替えはしない)。F1〜F3 は、payload の該当する node にだけ適用する。\n\nC. normalize_events とその仲間の返り値(固定)\n- normalize_events(events, profile_root) -> (normalized, sidecar)。返り値は2つの要素のまま。\n - normalized: tree の列。閉じた一覧(r03)の node だけを marker に置き換えたもの。\n - sidecar: dict で、key は次の3つに固定。\n - \"entries\": [{\"event_index\", \"path\", \"key\", \"original_node\"}…]。F1〜F3 で置き換えた全ての node の元の値。F3 の場合は original_node に元の message の文字列を入れ、\"root\" に、置き換えた root を入れる。\n - \"violations\": [{\"event_index\", \"path\", \"kind\", \"node\"}…]。閉じた一覧の外にあった、*_us / *_ms の key、profile_root を含む文字列など。**存在しただけでは不合格にしない**。正規化はせずに、そのまま保持して記録する。\n - \"profile_root\": 使った root の文字列と、guard の actual_user_data_dir との一致の結果。\n- restore_events(normalized, sidecar, profile_root) -> events: entries から元に戻す。violations の node は、もともと変えていないので、そのまま。\n- 状態の tree にも、同じ形の normalize_tree(tree, profile_root) -> (normalized, sidecar) と restore_tree を用意する。\n- r03 の規則は、そのまま。violations にあるものを正規化しようとしたら拒否する。violations にあるものが、比べる2つの側で実際に異なれば、その差は不一致(失敗)として、path と両側の値を記録する。\n\nD. 段階への影響\n- S1(今回): compare_versions.py に、A4 の比較、C の4つの関数、A3 の差分の再構成、tree_sha の再計算、check_source_closure を実装する。試験は合成の tree で行い、次のものを確かめる。\n - 型の違い(int と float、String と StringName、型つきの配列)を区別すること\n - dict の順序だけの差の path\n - 差分の再構成の完全一致\n - sidecar からの逆の復元\n - violations の扱い(存在だけでは不合格にしない、正規化しようとしたら拒否、差があれば不一致)\n- S2: eq_probe.gd に、A1 の encode と decode、A2 の roundtrip、A3 の書き出し、B の記録を実装する。\n- S3 と S4 は、r01 のとおり。\n" + }, + "EQ_S3_STAGE_PLAN.txt": { + "sha256": "ecbfb00691017fbd35027df8fa9ca6f82c761a5a3389568fe44b1babcfca308a", + "full_unedited": "EQ_S3_STAGE_PLAN(P28-02-EQ。EQ_STAGED_IMPLEMENTATION_PLAN r01/r02 の段階 S3 を、S3a と S3b に分ける。理由: S2 は 846.159 秒で、Runner の900秒の上限に近かったため。要求の範囲は変えない。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03 は変更しない)\n\n共通\n- 最初に eq/PROGRESS.md と eq/IMPLEMENTATION.md を読み、S1/S2 の型・path・record schema・API・notes を再利用する。再設計しない。\n- S1/S2 のコードと試験の本体を消さない。書き直さない(S3 で直すと決めた checker の2点と、失敗した試験が求める修正を除く)。\n- 失敗の履歴は、PROGRESS.md と UNIT_OUTPUT に残す。各段階の終わりに、engine を使わない python3 test_eq.py の全件 PASS まで直し、生出力を保存する。\n- 状態を変える呼出しは、SPEC §3.3 (b) の、列挙した scenario の専用の区間の中でだけ許可する。check_eq.py の静的な許可も、その区間と列挙した操作に限る。\n- engine の起動、git への書込み、製品の変更、全回帰はしない。SPEC、TASK、eq/references、eq/registration は変更しない。\n\nS3a(次の run)\n1. checker の修正 1(eq/check_eq.py:109)\n - 各 checkpoint の immutable snapshot の phase の key の集合が、正確に {0,…,10} であることを要求する(空の dict や、一部の欠落を拒否する)。\n - 負の試験を加える: 空、1つの欠落、範囲外の key、重複した key の表現。\n2. checker の修正 2(eq/check_eq.py:147-150)\n - 測定の区間の30 tick の各分について、製品の _publish_snapshot(autoload/simulation_runtime.gd:12616-12621)が出す snapshot_published → state_updated を、実際の回数と順序で記録したものを、その分の checkpoint と結びつけて検査する。\n - 各分に、ちょうど1組であること(snapshot_published に接続した受け手が無い場合は、製品の条件 :12619 のとおり state_updated だけになるので、probe の側で接続を記録し、期待値をその実際の接続の状態から決める)。\n - 順序は snapshot_published が先。\n - 分の番号は、checkpoint の minute と一致すること。\n - scenario の区間で出た追加の signal は、別の区間の記録に入れる。測定の区間の記録には混ぜない。\n - 負の試験を加える: 欠落、一部の分だけ、重複、順序の改ざん、分のずれ、scenario の signal の混入。\n3. E3 失敗時の拒否(専用の scenario の区間。R と O の両方)\n - restore_snapshot、SimulationSnapshot.validate、load_from_path の3つの API に、次の不正な入力を、それぞれ1件以上与える:\n - 欠けた key\n - 違う型\n - 範囲外の値\n - 重複した ID(published_ids、facility の ID)\n - world.bin の改ざん(r03 の D3 の固定の規則)\n - 不正な入力は、B1 の snapshot の deep copy から、固定の規則で作る。乱数や時刻を使わない。\n - 記録すること:\n - 戻り値と code\n - 前後の S/K/C 層(同じ PID の中で完全に比べる)\n - 全イベントの差分と、その件数(r02 の T4: 直接の restore は0件、load の失敗は SAVE_LOAD_FAILED がちょうど1件で、X(B, ev_fail) と r03 の正規化の後で完全一致すること)\n - check_eq.py: E3 の記録の形式と矛盾の検査を加える。製品の失敗(不正な入力が受理された、状態が変わった、など)は、「既存の不具合」として記録する。PASS で補わない。\n - 試験を加える: E3 の正常の記録と、拒否の場合(code の欠落、件数の不一致、拒否の前後の状態の変化を見逃すこと)。\n4. 終わり: PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3a 完了(失敗ではない。次は S3b)」とする。\n\nS3b(S3a の後の run)\n1. E4 キャッシュの古さ(専用の区間。R と O)\n - 場面: 状態を変えるコマンド(建設のコマンドを1件、通常の command queue を通す)、tick(advance_minutes(1))、restore_snapshot、load_from_path、状態を変えないコマンド。\n - 各場面の直後の create_snapshot() と latest_snapshot を、完全な typed tree(r02 の A)で記録する。版の間の比較は compare_versions.py で行う。\n - 件数: 直接の restore は SAVE_* が0件、load の成功は SAVE_LOADED がちょうど1件(X(P, ev_load))。\n2. E5 所有権(専用の区間)\n - 対象: create_snapshot() の戻り値、latest_snapshot、snapshot_published と state_updated の引数。\n - 外から内: 入れ子の dict と配列を変更した後に、内部の状態、次の create_snapshot()、latest_digest が変わっていないかを、完全な typed tree で確かめる。\n - 内から外: 次の tick の後に、既に返した値が変わっていないかを確かめる。\n - 予想される aliasing(latest_snapshot と signal の引数が同じ object であること)による live の変化は、「既存の不具合」として、変わった path と値を全て記録する。その後の検査は、新しい baseline から始める。harness による無断の変更とは区別する。\n3. check_eq.py と試験: E4/E5 の記録の検査と、正常と拒否の試験を加える。\n4. 終わり: PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3b 完了(失敗ではない。次は S4)」とする。\n\nその後\n- S4: run_eq.py と verify_eq.py、bundle の試験、全件 PASS の後に正式に提出する。\n- その後に、Root の native(7 phase)→ 両方の validation → 別の新しい Opus による全6条件のレビュー → 通常の統合と final、の順序で進める。\n" + }, + "EQ_S3_STAGE_PLAN_R02.txt": { + "sha256": "566e3ad98f9d47136ff4d4932f81c0a7f9fc96321a6f08ba944a9f1e736e6caa", + "full_unedited": "EQ_S3_STAGE_PLAN r02(P28-02-EQ。EQ_S3_STAGE_PLAN(r01)の分け方(S3a = checker の2点の修正 + E3、S3b = E4/E5)、共通の規則、S3b、その後の順序は、そのまま有効。この r02 は、実際の API に合わせて、S3a の「checker の修正 2」と「E3」を置き換えて確定する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02 は変更しない)\n\n1. checker の修正 1(eq/check_eq.py:109): r01 のとおり(phase の key の集合が正確に {0..10}、負の試験)。\n\n2. checker の修正 2(eq/check_eq.py:147-150。r01 を置き換える)\n- probe は、自分の observer を snapshot_published に接続している。そのため、製品の _publish_snapshot(autoload/simulation_runtime.gd:12616-12621)は、毎 tick、snapshot_published を出してから state_updated を出す(:12619 の条件が真になる)。\n- 測定の区間の30 tick の各分について、**ちょうど1組の snapshot_published → state_updated** を要求し、その分の checkpoint の minute と結びつける。\n- 測定の開始の時点で、snapshot_published と state_updated の接続の一覧(get_connections() の、接続先の object と method)を記録し、その中に probe 自身の接続があることを要求する。probe の接続が無い場合は、期待を「state_updated だけ」に下げることはせず、失敗にする。\n- 製品で受け手が接続されていない場合の動作(state_updated だけ)は、この区間の対象の外とする。試験もしない。\n- scenario の区間で出た signal は、別の区間の記録に入れ、測定の区間には混ぜない。\n- 負の試験を加える:\n - 欠落、一部の分だけ、重複、順序の改ざん、分のずれ\n - scenario の signal の混入\n - probe の接続が一覧に無いのに合格にすること\n - 期待を state_updated だけに下げること\n\n3. E3 失敗時の拒否(専用の scenario の区間。r01 を置き換える)\n\n3.1 各 API の実際の戻り値(架空の code は作らない)\n- SimulationRuntime.restore_snapshot(Dictionary) -> bool(:587): 戻り値の bool を、そのまま記録する。code は null とし、理由を \"API returns bool only\" とする。\n- SimulationSnapshot.validate(Dictionary) -> {ok, errors}(scripts/core/simulation_snapshot.gd:16-43): 返った dict の全体(ok と、errors の全件)を、そのまま記録する。code は null とし、理由を \"API returns ok/errors only\" とする。\n- load_from_path(String) -> Dictionary(:4223): 実際の code を記録する。この API で code が欠けていれば、それは失敗として拒否する(上の2つの「API に code が無い」とは区別する)。\n\n3.2 不正の分類と、それを適用する API(source に基づく表。適用しないものは、理由つきの NA として記録し、PASS に補わない)\n\n| 分類 | restore_snapshot(Dictionary) | validate(Dictionary。envelope の外形だけを検査) | load_from_path(package) |\n|---|---|---|---|\n| 欠けた key | 適用: B1 の deep copy から clock を削除 → false を期待 | 適用: clock を削除 → errors に missing_clock を期待 | 適用: package の manifest.json から checksum_world を削除 → INVALID_MANIFEST を期待 |\n| 違う型 | 適用: clock.absolute_minute を文字列 \"x\" に → false | 適用: 同じ → errors に invalid_absolute_minute | 適用: manifest.json の format_version を文字列に → INVALID_MANIFEST |\n| 範囲外の値 | 適用: clock.speed を 9 に → false | 適用: 同じ → errors に invalid_speed | 適用: manifest.json の format_version を、対応していない大きな整数に → UNSUPPORTED_FORMAT(自動の migration を試みた場合は、その実際の code と、migration_attempted を記録) |\n| 重複した ID(published_ids) | 適用: systems.runtime.domain_events.published_ids に、既存の ID を1つ追加 → false(DomainEventStream.restore_snapshot、scripts/core/domain_event_stream.gd:113-140 が拒否) | NA: validate は envelope の外形だけで、runtime の内部を検査しない(:16-43)。実際の戻り値(ok:true を予想)は記録するが、不具合とはしない | 適用(公開の API で作れる場合): 重複を入れた snapshot を SaveService.save_snapshot で、固定の user:// の path に保存し、load_from_path で読む。save が拒否した場合は、その実際の code を記録し、load の側は理由つきの NA にする |\n| 重複した ID(facility) | R で適用: 施設の instance の配列で、最初の entry を複製 → false(FacilityService.restore_snapshot、scripts/facility/facility_service.gd:701-703 が拒否)。O で NA: B1 の施設の件数が実際に0のとき、複製する既存の entry が無いため(件数を記録する)。施設を建設すること、R の B1 で代用すること、製品の値を作ることはしない | NA: 上と同じ理由 | R で、published_ids と同じ方法で適用。O で NA(理由は同じ) |\n| world.bin の改ざん | NA: Dictionary の API は package を読まない | NA: 同じ | 適用: r03 の D3 の固定の規則 → CHECKSUM_MISMATCH を期待 |\n\n- 不正な入力は、B1 の deep copy と、固定の user:// の相対 path と、固定の規則だけで作る。乱数・時刻・PID を使わない(r03 の D1〜D3)。\n- 期待の結果は、上の source に基づくものとして記録する。実際の結果が期待と違う場合(たとえば、不正な入力が受理された)は、「既存の不具合の候補」として、全ての記録とともに残す。ただし、envelope の validate が runtime の内部の重複を受理することは、その API の範囲の外なので、不具合とは断定しない。\n\n3.3 各操作で記録し、検査すること\n- 前後の S/K/C 層(同じ PID の中で、完全に比べる)。拒否された場合は、変化が無いこと。\n- 全イベントの差分と、その件数。restore_snapshot と validate は0件。load_from_path の失敗は SAVE_LOAD_FAILED がちょうど1件で、X(B, ev_fail) と、r03 の正規化の後で完全一致すること。\n- 適用と NA の表を、そのまま report に入れる。fresh の whole-unit レビューが、適用の条件を判定できるようにする。\n\n3.4 試験(test_eq.py)\n- 正常の記録。\n- 拒否の場合:\n - restore と validate の架空の code\n - load の code の欠落を合格にすること\n - NA を PASS として数えること\n - O の施設の重複を、件数が0なのに適用したと記録すること\n - 拒否の前後の状態の変化を見逃すこと\n - 件数の不一致\n - envelope の validate が重複を受理したことを、製品の不具合と断定すること\n\n4. 終わり: r01 のとおり(PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3a 完了(失敗ではない。次は S3b)」とする)。\n" + } + }, + "read_only_clarifications": { + "EQ_S_TIMING_CLARIFICATION.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_S_TIMING_CLARIFICATION.txt", + "sha256": "25d323fd562d29e80782b6f075fc7a0e8b49457a6c4fbd7c30e74b31a6b6a126" + }, + "EQ_S_TIMING_CLARIFICATION_R02.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_S_TIMING_CLARIFICATION_R02.txt", + "sha256": "777accdd652f85db6b9014d85e3c8b3b60ca94b20768e6173b36bc769d360fd9" + }, + "EQ_ENVIRONMENT_FIELDS_CLARIFICATION_R03.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_ENVIRONMENT_FIELDS_CLARIFICATION_R03.txt", + "sha256": "12b27f984ef5843d98327200ad261dccaf64968402192b08ad55b15ed5454ea2" + } + } + } +} diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3B_SUPPLEMENTARY.json b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3B_SUPPLEMENTARY.json new file mode 100644 index 0000000..4b7803c --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3B_SUPPLEMENTARY.json @@ -0,0 +1,49 @@ +{ + "actual_commander_context": { + "actual_run_decision": { + "action": "run", + "task_id": "P28-02-EQ", + "reason": "Supersedes DESKTOP_EQ_S3B_RUN_DECISION.json, which is kept unchanged as history. Use only after Root verifies through the normal gates: repair_ready, repairs 7, no S submitted, no active run, and the S1, S2 and S3a files still present unchanged in the W. Run repair 7 of P28-02-EQ once on the same W from base 2549cf7d6992560b850bbd11934e3c14b39a1988 with the single worker codex gpt-6-astra, doing only stage S3b as defined in EQ_S3B_STAGE_PLAN.txt and corrected in E4-1 only by EQ_S3B_STAGE_PLAN_R02.txt. Deliver both S3b plans in full as part of the one supplementary key, together with both S3 plans, both staged plans and this decision; clarifications r01, r02 and r03 stay read-only in build/eq-staged-readonly-r04. Start by reading eq/PROGRESS.md, including the run 7da027a entry, and eq/IMPLEMENTATION.md, including the S4 binding requirements, and reuse the S1/S2/S3a types, paths, schema, API and code without redesign. E4-1 correction: in both R and O, take candidates from that PID's runtime.definition_registry.get_facility_ids(), sorted by text ID, scan cells in (x, y, z) lexical order with rotation 0, judge each pair only with the public preview_build_facility, and submit the first placeable pair through submit_command(&\"build_facility\", {definition_id, origin, rotation}). Save the raw enumerated list and count, the sorted list and rule, the cell range rule, every tried candidate with its full preview result, the chosen candidate with its submit and command result, and any non-application reason. NA is allowed only when the real list is non-empty and every pair is not placeable; an empty list is a failure, and a false NA from an empty or wrong source is forbidden. NA is never PASS, no facility values are invented, and nothing is built outside this path. Everything else in S3b is unchanged: E4 paths 2 to 5, E5 over all 4 targets by 2 locations by 2 directions, full typed state and event records, the latest_snapshot aliasing (:12617-12621) recorded as an existing defect and never as PASS, the listed check_eq.py rules and negative tests plus the r02 E4-1 rejections, and keeping E3, the 91 existing test bodies and the failure history except for fixes a failing test requires. Run the engine-free python3 test_eq.py until every test passes, save the raw output, update PROGRESS.md, and end S3b with formal status blocked and the finding 'stage S3b complete (not a failure; next is S4)'. Do not submit. No engine, no git write or commit, no product change, no full regression; SPEC, TASK, eq/references and eq/registration stay unchanged. Ordinary implementation choices are recorded without stopping; block only for undecided matters affecting original product spec, values, permissions, billing or original acceptance. The remaining order is S4 (driver and verify) and submission, then Root native on the exact S in 7 phases, then both validations, then a fresh independent Opus review of all 6 conditions, then the normal prepare, candidate qualification, approval, integration and final; the OPT whole-unit gate follows later. No original credit (23/88, 4/30); the 900-second timeout is unchanged. Quota fallback only on structured provider quota, once, same role, Antigravity claude-opus-5-5-high; any other failure is blocked. Decided by Claude Opus 5.5 in the Desktop control session (message 336); not a CLI commander result." + }, + "actual_full_plans": { + "EQ_STAGED_IMPLEMENTATION_PLAN.txt": { + "sha256": "eb7b4831e2164c6fc983fa6f9825e7f3e2993b4c0ebf2f90aac8ad10662666d2", + "full_unedited": "EQ_STAGED_IMPLEMENTATION_PLAN(P28-02-EQ repair 3 以降。base 2549cf7d6992560b850bbd11934e3c14b39a1988。SPEC、TASK、6条件、eq/references、eq/registration、EQ_S_TIMING_CLARIFICATION r01/r02、EQ_ENVIRONMENT_FIELDS_CLARIFICATION r03 は全てそのまま有効。変えるのは、工程と、成果物の内部の設計の固定だけ)\n\n前回までの事実\n- repair 2(run 84ca0ff8…)は、IMPLEMENTATION.md と compare_versions.py などを作った後、item_30 で全てを削除し、「6ファイルと unit の PASS を提供できない」として、自分から終了した。仕様の不足の指摘ではない。packet は 94 KB あった。\n- この失敗は失敗のまま保持する。削除したことを成功として扱わない。\n\n工程の変更(必須)\n- G1: **作ったファイルは、削除しない**。完成していなくても、W の eq/ に残す。各 run の最後に、eq/PROGRESS.md に、終わった段階・残りの作業・現在の試験の結果を書く。\n- G2: 1回の run では、下の**1つの段階だけ**を行う。始める前に eq/PROGRESS.md を読み、次の段階から再開する。前の段階のコードは作り直さない。\n- G3: 各段階の終わりに、engine を使わない python3 test_eq.py を実行する。その時点で存在する試験が、全件 PASS になるまで直す。生出力を eq/UNIT_OUTPUT.txt に保存する。\n- G4: 段階1〜3の終わりには、正式な JSON の status を blocked にし、findings に「段階 Sx 完了(失敗ではない。次は Sx+1)」と PROGRESS.md の要点を書いて返す。段階4の終わりにだけ、提出する(status を submitted 相当の正式な提出にする)。\n- G5: 通常の実装上の判断(関数の分け方、名前、試験データ、記録の書式)は、IMPLEMENTATION.md に記録して進める。blocked にしてよいのは、原本の仕様・値・権限・課金・受入に影響する未確定事項がある場合だけ。\n- G6: engine の起動、git への書込み、製品の変更、全回帰はしない。SPEC、TASK、eq/references、eq/registration は変更しない。\n\n固定するインターフェース(6ファイル。SPEC §2)\n\n1. compare_versions.py(Python のみ。engine を使わない)\n - normalize_events(events, profile_root) -> (normalized, sidecar):\n - r03 の F1〜F3 を、JSON の event の一覧に適用する。\n - 閉じた一覧の外の *_us / *_ms / profile_root を含む文字列は、正規化せず、violations として返す。\n - restore_events(normalized, sidecar, profile_root) -> events: 逆の復元(完全一致の確認に使う)。\n - compare_reports(a, b) -> dict: 2つの report(同じ版の別 PID、または前後の版)を比べる。\n - 毎分の checkpoint の S_norm_sha と latest_norm_sha の一致\n - digest の規則(r02 の T3)\n - K と C の、SPEC §3.2 に列挙した欄\n - E2 の正規化した全イベント(開始の counter の一致が前提)\n - E3/E4/E5 の scenario の結果の一致\n - 比べない欄は、理由と両側の値を記録する\n - 差は path ごとに返す\n - check_source_closure(before_map, after_map, allowed_changed) -> dict: SPEC §2 と OPT r02 §2。追加・欠落・登録されていない差分を拒否する。\n2. eq_probe.gd(GDScript):\n - 起動の6段階は、DIAG の diag_probe.gd の構成をそのまま参考にする。\n - 役割は R と O(env の THE_TREE_EQ_ROLE)。\n - 観測の checkpoint は B1 と、30分の各 tick の最後(31個)。各 checkpoint に、次のものを置く:\n - minute\n - S_raw_sha、S_norm_sha(GDScript の中で F1〜F3 の typed の marker を使って正規化した後の var_to_bytes の SHA)\n - 正規化した S の path の hash の表(depth ≤ 4)\n - latest_norm_sha\n - digest の情報\n - K と C の全体\n - sidecar\n - E2 は subscribe('*') で、全イベントの JSON(正規化の前)を記録する。正規化は compare_versions.py で行う(GDScript と Python で、同じ規則の二重実装をしない)。\n - E3/E4/E5 の scenario は、SPEC §3.3 の専用の区間で行う。各区間について、開始と終了、操作、code、前後の S/K/C、件数(r02 の T4)を記録する。\n - stdout には、P28_02_EQ_REPORT= をちょうど1行出す。終了は close_requested.emit()。\n3. check_eq.py: report 1つを検査する。\n - 形式、必須の欄、矛盾\n - 閉じた一覧の外の差\n - probe の静的な禁止(autoload の class_name の参照、状態を変える呼出しの区間の外での使用、Variant からの := の推論)\n - SimulationDigest だけでの判定\n4. run_eq.py: Root が実行する driver。\n - diag_p28_02.py の構成をそのまま参考にする(--check / --run、依存の SHA、1407 の source、凍結した S の照合、owned phase、guard、private profile、cleanup)。\n - phase は import、parse-base、parse-wrapper、R-A、R-B、O-A、O-B。\n - 成功したら、execution.json と bundle.json を作る。\n5. verify_eq.py: --project-root . で、$BUILD_OUTPUT_DIR/p28-02-eq-evidence の bundle を結合する。bundle が無ければ失敗する。\n - 各 report に check_eq を行う。\n - R-A と R-B、O-A と O-B に compare_reports を行い、差が0であること(harness の正しさ)。\n - E3/E5 の、前の版での製品の失敗は、「既存の不具合」の一覧として出力する。harness の不合格とは区別する。\n - SPEC、TASK、eq/references、eq/registration の SHA を固定して照合する。\n6. test_eq.py: 合成した入力だけで動く。各段階で、その段階の試験を足していく。\n\n段階(1回の run で1つ)\n- S1: compare_versions.py の全体と、その試験(F1〜F3 の正常と拒否、可逆性、比較、source の閉包)。PROGRESS.md と IMPLEMENTATION.md を作る。\n- S2: eq_probe.gd の、起動・観測の checkpoint・E2 の記録・報告。check_eq.py の静的な検査と形式の検査、それぞれの試験。\n- S3: eq_probe.gd の E3/E4/E5 の scenario、check_eq.py のそれに対する検査、試験。\n- S4: run_eq.py と verify_eq.py、bundle の試験。全件 PASS を確かめて、正式に提出する。\n\nRoot への依頼(packet を小さくするため)\n- actual_commander_context の key には、この計画の全文と RUN の判断だけを入れる。r01・r02・r03 の全文は、build/ に読取専用で置き、その path と SHA だけを渡す。eq/references は W の中にあるので、path だけで足りる。\n" + }, + "EQ_STAGED_IMPLEMENTATION_PLAN_R02.txt": { + "sha256": "128f42f18e168e9299995296ac7ad119f47d1647799d472663282e47e8ac9fdd", + "full_unedited": "EQ_STAGED_IMPLEMENTATION_PLAN r02(P28-02-EQ repair 3 以降。EQ_STAGED_IMPLEMENTATION_PLAN(r01)の工程 G1〜G6、段階 S1〜S4、Root への依頼は、そのまま有効。この r02 は、固定インターフェースのうち、状態とイベントの運搬の表現と、normalize_events の返り値を置き換えて確定する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03 は変更しない)\n\nA. 型を保つ運搬の表現(typed tree。JSON は運び方であって、型の情報は落とさない)\n\nA1 node の形式(JSON の配列)\n- 各値は [type_code, payload]。type_code は Godot の typeof() の値。\n - null: [0]\n - bool: [1, 0|1]\n - int: [2, 整数]\n - float: [3, \"<8 byte little-endian IEEE754 の hex>\"](10進の文字列にしない)\n - String: [4, \"文字列\"]\n - StringName: [21, \"文字列\"]\n - Vector2/Vector2i/Vector3/Vector3i/Rect2/Rect2i/Color など: [type_code, [各成分の node]](成分は int か float の node)\n - Dictionary: [27, [[key_node, value_node], …], typed_info]。**元の挿入の順序のまま**並べる。typed_info は、型つきの Dictionary なら key と value の builtin 型・class 名・script、それ以外は null。\n - Array: [28, [element_node, …], typed_info]。typed_info は get_typed_builtin()・get_typed_class_name()・get_typed_script() の値、型の無い Array なら null。\n - PackedByteArray: [29, \"\"]。他の Packed*Array も、要素ごとの node の列にする(float は hex)。\n- Object、Callable、Signal、RID が現れたら、運搬せずに失敗にする(snapshot と event の dict には、本来現れないもの)。\n\nA2 無損失の証明(Godot の中で行う。probe の必須の処理)\n- tree = encode(value) を作った後、decode(tree) で Variant を作り直す。var_to_bytes(decode(tree)) == var_to_bytes(value) であることを確かめる。一致しなければ失敗にする。\n- report には、checkpoint ごとに、次の3つを記録する。\n - raw_bytes_sha = sha256(var_to_bytes(value))\n - tree_sha = sha256(tree を key の順序を変えずに JSON.stringify した UTF-8)\n - roundtrip_ok\n- Python は、受け取った tree から tree_sha を計算し直して結合する。これで、Python で比べる tree が、Godot の元の bytes と無損失に対応することが保証される。\n\nA3 保存の場所と大きさ(深さの制限は設けない。全体を再構成できるようにする)\n- 各 PID は、checkpoint の列(B1 と、30分の各 tick の最後)について、S 層と latest_snapshot を、次の形で、private user:// の evidence/ に書き出す。driver は、それを RESTART の copy_states と同じ方式で out へ複製し、SHA を結合する。\n - checkpoint 0(B1): tree の全体(JSON、zstd で圧縮してよい。圧縮した場合は、圧縮の前後の SHA を両方記録する)。\n - checkpoint k(k≥1): checkpoint k−1 の tree に対する、path を指定した差分の操作の列。操作は set(path, node)、dict_insert(path, index, key_node, value_node)、dict_remove(path, key_node)、array_splice(path, start, delete_count, [node…])。順序つきで、再構成すると、checkpoint k の tree と完全一致すること。\n - latest_snapshot は、各 checkpoint で、var_to_bytes が S 層と同じなら same_as_S=true とし、違えば、その tree(または S に対する差分)を保存する。\n- Python は、checkpoint 0 から差分を順に適用して、全ての checkpoint を再構成する。checkpoint ごとに tree_sha と一致することを確かめる。\n\nA4 比較(compare_versions.py。全て tree の上で行い、深さの制限は無い)\n- 第一の比較は、tree の完全一致(型、key、順序、値。全ての node)。\n- 一致しない場合に限り、正規化した比較を行う。dict の key を文字で並べ(同じ文字の key が2つあれば拒否)、それ以外の型・値・配列の順序を保ったまま比べる。それで一致すれば「dict の列挙の順序だけの差」として、その全ての path を記録する。それ以外の差は、全ての path と両側の node を記録して、不一致にする。\n- F1〜F3(r03)の正規化は、tree の node の上で行う。sidecar から、元の tree へ完全に戻せること(tree_sha が一致すること)を確かめる。\n\nB. E2 のイベントの運搬\n- 各 event について、event.to_dictionary()(製品の直列化。scripts/core/domain_event.gd:47-59)の tree を記録する。あわせて、元の object の欄の型(event_id と event_type が StringName であるか、entity_ids の型、payload の dict の typed_info)を、original_field_types として記録する。\n- 受け取りの順序で番号をつけ、開始の時点の counter と、published_ids の数を記録する。\n- イベントの列は、A3 と同じく evidence/ に書き出し(tree の列。圧縮してよい)、SHA を結合する。Godot の中で、各 event について A2 の roundtrip を確かめる。\n- compare_reports は、この tree の列を受け取り、全ての欄と event_id を**そのまま**比べる(ID の付け替えはしない)。F1〜F3 は、payload の該当する node にだけ適用する。\n\nC. normalize_events とその仲間の返り値(固定)\n- normalize_events(events, profile_root) -> (normalized, sidecar)。返り値は2つの要素のまま。\n - normalized: tree の列。閉じた一覧(r03)の node だけを marker に置き換えたもの。\n - sidecar: dict で、key は次の3つに固定。\n - \"entries\": [{\"event_index\", \"path\", \"key\", \"original_node\"}…]。F1〜F3 で置き換えた全ての node の元の値。F3 の場合は original_node に元の message の文字列を入れ、\"root\" に、置き換えた root を入れる。\n - \"violations\": [{\"event_index\", \"path\", \"kind\", \"node\"}…]。閉じた一覧の外にあった、*_us / *_ms の key、profile_root を含む文字列など。**存在しただけでは不合格にしない**。正規化はせずに、そのまま保持して記録する。\n - \"profile_root\": 使った root の文字列と、guard の actual_user_data_dir との一致の結果。\n- restore_events(normalized, sidecar, profile_root) -> events: entries から元に戻す。violations の node は、もともと変えていないので、そのまま。\n- 状態の tree にも、同じ形の normalize_tree(tree, profile_root) -> (normalized, sidecar) と restore_tree を用意する。\n- r03 の規則は、そのまま。violations にあるものを正規化しようとしたら拒否する。violations にあるものが、比べる2つの側で実際に異なれば、その差は不一致(失敗)として、path と両側の値を記録する。\n\nD. 段階への影響\n- S1(今回): compare_versions.py に、A4 の比較、C の4つの関数、A3 の差分の再構成、tree_sha の再計算、check_source_closure を実装する。試験は合成の tree で行い、次のものを確かめる。\n - 型の違い(int と float、String と StringName、型つきの配列)を区別すること\n - dict の順序だけの差の path\n - 差分の再構成の完全一致\n - sidecar からの逆の復元\n - violations の扱い(存在だけでは不合格にしない、正規化しようとしたら拒否、差があれば不一致)\n- S2: eq_probe.gd に、A1 の encode と decode、A2 の roundtrip、A3 の書き出し、B の記録を実装する。\n- S3 と S4 は、r01 のとおり。\n" + }, + "EQ_S3_STAGE_PLAN.txt": { + "sha256": "ecbfb00691017fbd35027df8fa9ca6f82c761a5a3389568fe44b1babcfca308a", + "full_unedited": "EQ_S3_STAGE_PLAN(P28-02-EQ。EQ_STAGED_IMPLEMENTATION_PLAN r01/r02 の段階 S3 を、S3a と S3b に分ける。理由: S2 は 846.159 秒で、Runner の900秒の上限に近かったため。要求の範囲は変えない。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03 は変更しない)\n\n共通\n- 最初に eq/PROGRESS.md と eq/IMPLEMENTATION.md を読み、S1/S2 の型・path・record schema・API・notes を再利用する。再設計しない。\n- S1/S2 のコードと試験の本体を消さない。書き直さない(S3 で直すと決めた checker の2点と、失敗した試験が求める修正を除く)。\n- 失敗の履歴は、PROGRESS.md と UNIT_OUTPUT に残す。各段階の終わりに、engine を使わない python3 test_eq.py の全件 PASS まで直し、生出力を保存する。\n- 状態を変える呼出しは、SPEC §3.3 (b) の、列挙した scenario の専用の区間の中でだけ許可する。check_eq.py の静的な許可も、その区間と列挙した操作に限る。\n- engine の起動、git への書込み、製品の変更、全回帰はしない。SPEC、TASK、eq/references、eq/registration は変更しない。\n\nS3a(次の run)\n1. checker の修正 1(eq/check_eq.py:109)\n - 各 checkpoint の immutable snapshot の phase の key の集合が、正確に {0,…,10} であることを要求する(空の dict や、一部の欠落を拒否する)。\n - 負の試験を加える: 空、1つの欠落、範囲外の key、重複した key の表現。\n2. checker の修正 2(eq/check_eq.py:147-150)\n - 測定の区間の30 tick の各分について、製品の _publish_snapshot(autoload/simulation_runtime.gd:12616-12621)が出す snapshot_published → state_updated を、実際の回数と順序で記録したものを、その分の checkpoint と結びつけて検査する。\n - 各分に、ちょうど1組であること(snapshot_published に接続した受け手が無い場合は、製品の条件 :12619 のとおり state_updated だけになるので、probe の側で接続を記録し、期待値をその実際の接続の状態から決める)。\n - 順序は snapshot_published が先。\n - 分の番号は、checkpoint の minute と一致すること。\n - scenario の区間で出た追加の signal は、別の区間の記録に入れる。測定の区間の記録には混ぜない。\n - 負の試験を加える: 欠落、一部の分だけ、重複、順序の改ざん、分のずれ、scenario の signal の混入。\n3. E3 失敗時の拒否(専用の scenario の区間。R と O の両方)\n - restore_snapshot、SimulationSnapshot.validate、load_from_path の3つの API に、次の不正な入力を、それぞれ1件以上与える:\n - 欠けた key\n - 違う型\n - 範囲外の値\n - 重複した ID(published_ids、facility の ID)\n - world.bin の改ざん(r03 の D3 の固定の規則)\n - 不正な入力は、B1 の snapshot の deep copy から、固定の規則で作る。乱数や時刻を使わない。\n - 記録すること:\n - 戻り値と code\n - 前後の S/K/C 層(同じ PID の中で完全に比べる)\n - 全イベントの差分と、その件数(r02 の T4: 直接の restore は0件、load の失敗は SAVE_LOAD_FAILED がちょうど1件で、X(B, ev_fail) と r03 の正規化の後で完全一致すること)\n - check_eq.py: E3 の記録の形式と矛盾の検査を加える。製品の失敗(不正な入力が受理された、状態が変わった、など)は、「既存の不具合」として記録する。PASS で補わない。\n - 試験を加える: E3 の正常の記録と、拒否の場合(code の欠落、件数の不一致、拒否の前後の状態の変化を見逃すこと)。\n4. 終わり: PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3a 完了(失敗ではない。次は S3b)」とする。\n\nS3b(S3a の後の run)\n1. E4 キャッシュの古さ(専用の区間。R と O)\n - 場面: 状態を変えるコマンド(建設のコマンドを1件、通常の command queue を通す)、tick(advance_minutes(1))、restore_snapshot、load_from_path、状態を変えないコマンド。\n - 各場面の直後の create_snapshot() と latest_snapshot を、完全な typed tree(r02 の A)で記録する。版の間の比較は compare_versions.py で行う。\n - 件数: 直接の restore は SAVE_* が0件、load の成功は SAVE_LOADED がちょうど1件(X(P, ev_load))。\n2. E5 所有権(専用の区間)\n - 対象: create_snapshot() の戻り値、latest_snapshot、snapshot_published と state_updated の引数。\n - 外から内: 入れ子の dict と配列を変更した後に、内部の状態、次の create_snapshot()、latest_digest が変わっていないかを、完全な typed tree で確かめる。\n - 内から外: 次の tick の後に、既に返した値が変わっていないかを確かめる。\n - 予想される aliasing(latest_snapshot と signal の引数が同じ object であること)による live の変化は、「既存の不具合」として、変わった path と値を全て記録する。その後の検査は、新しい baseline から始める。harness による無断の変更とは区別する。\n3. check_eq.py と試験: E4/E5 の記録の検査と、正常と拒否の試験を加える。\n4. 終わり: PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3b 完了(失敗ではない。次は S4)」とする。\n\nその後\n- S4: run_eq.py と verify_eq.py、bundle の試験、全件 PASS の後に正式に提出する。\n- その後に、Root の native(7 phase)→ 両方の validation → 別の新しい Opus による全6条件のレビュー → 通常の統合と final、の順序で進める。\n" + }, + "EQ_S3_STAGE_PLAN_R02.txt": { + "sha256": "566e3ad98f9d47136ff4d4932f81c0a7f9fc96321a6f08ba944a9f1e736e6caa", + "full_unedited": "EQ_S3_STAGE_PLAN r02(P28-02-EQ。EQ_S3_STAGE_PLAN(r01)の分け方(S3a = checker の2点の修正 + E3、S3b = E4/E5)、共通の規則、S3b、その後の順序は、そのまま有効。この r02 は、実際の API に合わせて、S3a の「checker の修正 2」と「E3」を置き換えて確定する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02 は変更しない)\n\n1. checker の修正 1(eq/check_eq.py:109): r01 のとおり(phase の key の集合が正確に {0..10}、負の試験)。\n\n2. checker の修正 2(eq/check_eq.py:147-150。r01 を置き換える)\n- probe は、自分の observer を snapshot_published に接続している。そのため、製品の _publish_snapshot(autoload/simulation_runtime.gd:12616-12621)は、毎 tick、snapshot_published を出してから state_updated を出す(:12619 の条件が真になる)。\n- 測定の区間の30 tick の各分について、**ちょうど1組の snapshot_published → state_updated** を要求し、その分の checkpoint の minute と結びつける。\n- 測定の開始の時点で、snapshot_published と state_updated の接続の一覧(get_connections() の、接続先の object と method)を記録し、その中に probe 自身の接続があることを要求する。probe の接続が無い場合は、期待を「state_updated だけ」に下げることはせず、失敗にする。\n- 製品で受け手が接続されていない場合の動作(state_updated だけ)は、この区間の対象の外とする。試験もしない。\n- scenario の区間で出た signal は、別の区間の記録に入れ、測定の区間には混ぜない。\n- 負の試験を加える:\n - 欠落、一部の分だけ、重複、順序の改ざん、分のずれ\n - scenario の signal の混入\n - probe の接続が一覧に無いのに合格にすること\n - 期待を state_updated だけに下げること\n\n3. E3 失敗時の拒否(専用の scenario の区間。r01 を置き換える)\n\n3.1 各 API の実際の戻り値(架空の code は作らない)\n- SimulationRuntime.restore_snapshot(Dictionary) -> bool(:587): 戻り値の bool を、そのまま記録する。code は null とし、理由を \"API returns bool only\" とする。\n- SimulationSnapshot.validate(Dictionary) -> {ok, errors}(scripts/core/simulation_snapshot.gd:16-43): 返った dict の全体(ok と、errors の全件)を、そのまま記録する。code は null とし、理由を \"API returns ok/errors only\" とする。\n- load_from_path(String) -> Dictionary(:4223): 実際の code を記録する。この API で code が欠けていれば、それは失敗として拒否する(上の2つの「API に code が無い」とは区別する)。\n\n3.2 不正の分類と、それを適用する API(source に基づく表。適用しないものは、理由つきの NA として記録し、PASS に補わない)\n\n| 分類 | restore_snapshot(Dictionary) | validate(Dictionary。envelope の外形だけを検査) | load_from_path(package) |\n|---|---|---|---|\n| 欠けた key | 適用: B1 の deep copy から clock を削除 → false を期待 | 適用: clock を削除 → errors に missing_clock を期待 | 適用: package の manifest.json から checksum_world を削除 → INVALID_MANIFEST を期待 |\n| 違う型 | 適用: clock.absolute_minute を文字列 \"x\" に → false | 適用: 同じ → errors に invalid_absolute_minute | 適用: manifest.json の format_version を文字列に → INVALID_MANIFEST |\n| 範囲外の値 | 適用: clock.speed を 9 に → false | 適用: 同じ → errors に invalid_speed | 適用: manifest.json の format_version を、対応していない大きな整数に → UNSUPPORTED_FORMAT(自動の migration を試みた場合は、その実際の code と、migration_attempted を記録) |\n| 重複した ID(published_ids) | 適用: systems.runtime.domain_events.published_ids に、既存の ID を1つ追加 → false(DomainEventStream.restore_snapshot、scripts/core/domain_event_stream.gd:113-140 が拒否) | NA: validate は envelope の外形だけで、runtime の内部を検査しない(:16-43)。実際の戻り値(ok:true を予想)は記録するが、不具合とはしない | 適用(公開の API で作れる場合): 重複を入れた snapshot を SaveService.save_snapshot で、固定の user:// の path に保存し、load_from_path で読む。save が拒否した場合は、その実際の code を記録し、load の側は理由つきの NA にする |\n| 重複した ID(facility) | R で適用: 施設の instance の配列で、最初の entry を複製 → false(FacilityService.restore_snapshot、scripts/facility/facility_service.gd:701-703 が拒否)。O で NA: B1 の施設の件数が実際に0のとき、複製する既存の entry が無いため(件数を記録する)。施設を建設すること、R の B1 で代用すること、製品の値を作ることはしない | NA: 上と同じ理由 | R で、published_ids と同じ方法で適用。O で NA(理由は同じ) |\n| world.bin の改ざん | NA: Dictionary の API は package を読まない | NA: 同じ | 適用: r03 の D3 の固定の規則 → CHECKSUM_MISMATCH を期待 |\n\n- 不正な入力は、B1 の deep copy と、固定の user:// の相対 path と、固定の規則だけで作る。乱数・時刻・PID を使わない(r03 の D1〜D3)。\n- 期待の結果は、上の source に基づくものとして記録する。実際の結果が期待と違う場合(たとえば、不正な入力が受理された)は、「既存の不具合の候補」として、全ての記録とともに残す。ただし、envelope の validate が runtime の内部の重複を受理することは、その API の範囲の外なので、不具合とは断定しない。\n\n3.3 各操作で記録し、検査すること\n- 前後の S/K/C 層(同じ PID の中で、完全に比べる)。拒否された場合は、変化が無いこと。\n- 全イベントの差分と、その件数。restore_snapshot と validate は0件。load_from_path の失敗は SAVE_LOAD_FAILED がちょうど1件で、X(B, ev_fail) と、r03 の正規化の後で完全一致すること。\n- 適用と NA の表を、そのまま report に入れる。fresh の whole-unit レビューが、適用の条件を判定できるようにする。\n\n3.4 試験(test_eq.py)\n- 正常の記録。\n- 拒否の場合:\n - restore と validate の架空の code\n - load の code の欠落を合格にすること\n - NA を PASS として数えること\n - O の施設の重複を、件数が0なのに適用したと記録すること\n - 拒否の前後の状態の変化を見逃すこと\n - 件数の不一致\n - envelope の validate が重複を受理したことを、製品の不具合と断定すること\n\n4. 終わり: r01 のとおり(PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3a 完了(失敗ではない。次は S3b)」とする)。\n" + }, + "EQ_S3B_STAGE_PLAN.txt": { + "sha256": "d14fe474ae4626719d8ff9be6cef1423f076bff0829060ded77b1520ac7bd88d", + "full_unedited": "EQ_S3B_STAGE_PLAN(P28-02-EQ 段階 S3b。EQ_S3_STAGE_PLAN r01/r02 の S3b を、実際の API に合わせて具体化する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02 は変更しない)\n\n共通\n- 最初に eq/PROGRESS.md と eq/IMPLEMENTATION.md(末尾の S4 の結合の要件を含む)を読み、S1/S2/S3a の型・path・record schema・API・notes を再利用する。再設計しない。\n- E3、既存の91件の試験の本体、失敗の履歴は、消さない。書き直さない(失敗した試験が求める修正を除く)。\n- E4/E5 の操作は、SPEC §3.3 (b) の専用の scenario の区間でだけ行う。各区間には開始と終了の記録を付ける。check_eq.py の静的な許可は、この区間と、下に列挙した操作に限る。\n- 状態は全て r02 の A の typed tree で記録する(深さの制限なし、可逆)。正規化は r03 の閉じた一覧だけを使う。\n- 各操作について、前後の S/K/C 層の tree と、全イベントの差分と件数と、scenario の中で出た signal(測定の区間とは別の記録)を記録する。\n\nE4 キャッシュの古さ(R と O。5つの経路を、この順序で行う。各経路の後の状態を、次の経路の開始の状態として記録する)\n1. 状態を変えるコマンド(通常の command queue を通す)\n - SimulationRuntime.submit_command(&\"build_facility\", {definition_id, origin, rotation})(autoload/simulation_runtime.gd:476、:305、:7717-7720)。\n - 引数は固定の規則で選ぶ。定義の一覧(mvp_content_catalog)を ID の文字の順序で、cell を (x, y, z) の辞書順で走査し、製品の公開の配置の判定で、最初に配置できる組を選ぶ。選んだ規則と結果を記録する。施設の値を作らない。配置できる組が無い場合(たとえば O の小さな世界)は、理由つきの NA にする。\n - 記録の時点: submit の直後(queue の状態、command の ID の counter)と、advance_minutes(1) を1回行った後(APPLY_COMMANDS で実行された後)。両方で、create_snapshot() と latest_snapshot の tree を記録する。\n2. tick: advance_minutes(1) を1回。直後の create_snapshot() と latest_snapshot を記録する。\n3. 直接の restore_snapshot(P)。P は、この経路の開始の時点の create_snapshot() の deep copy。\n - 直後の S が、P を規則どおりに復元したものと、正規化の後で完全一致すること。\n - SAVE_* の event は0件。\n4. load_from_path の成功\n - この経路の開始の時点の snapshot を、SaveService.save_snapshot で、固定の user:// の path(例: user://p28_eq//e4_good)に、固定の metadata で保存する。save は静的な API で、Runtime の event を出さない。\n - その path を、Runtime の load_from_path で読む。\n - 直後の状態が X(P, ev_load) と、正規化の後で完全一致すること。SAVE_LOADED はちょうど1件。\n5. 状態を変えないコマンド(製品が検証の段階で拒否するコマンド)\n - submit_command(&\"build_facility\", {definition_id: \"\"}) を submit して、advance_minutes(1) を1回行う。\n - 戻り値と、command の結果(拒否の code)を記録する。\n - 製品の状態の変化が、command の記帳(次の command の ID、処理済みの結果の記録)と tick の進行の分に限られることを、全ての path の差分で記録する。それ以外の変化があれば、事実として記録する。\n- 各経路の後に、create_snapshot() と latest_snapshot を記録する。latest_snapshot は publish(tick)の時にだけ更新される製品の仕様なので、tick を含まない経路の直後に latest_snapshot が以前の値のままであっても、それは記録する事実であって、cache の古さとは呼ばない。古さの判定は、OPT の後の版との、同じ場面での比較(compare_versions.py)で行う。\n- この段階での検査: 同じ版の2 PID の間で、5つの経路の記録が、正規化の後で一致すること(harness の決定性)。\n\nE5 所有権(R と O。4つの対象 × 入れ子の dict と配列 × 2つの向き)\n- 対象:\n - (1) create_snapshot() の戻り値\n - (2) SimulationRuntime.latest_snapshot\n - (3) snapshot_published の引数\n - (4) state_updated の引数\n - (3) と (4) は、probe の既存の接続で受け取った参照を、handler の外で保持して使う。handler の中で変更しない(他の受け手への影響を避けるため)。\n- 変更の場所(固定。R と O の両方に存在するもの):\n - 入れ子の dict: systems.runtime.id_generator.counters に、key \"__p28_eq_probe\" と値 1 を追加する。\n - 入れ子の配列: systems.runtime.domain_events.published_ids に、文字列 \"__p28_eq_probe\" を追加する。\n- 外から内:\n - 変更の直前に、内部の create_snapshot() の tree と、latest_snapshot の tree と、latest_digest の文字列を記録する。latest_digest は遅延して計算されるので、変更の前に一度読んで確定させ、その事実を記録する。\n - 変更の直後に、同じ3つを取り直して比べる。\n - 変化があれば、変わった path と値を全て記録する。\n- 内から外:\n - 返された値の deep copy を保持する。advance_minutes(1) を1回行った後に、返された値そのものが、保持した deep copy と同じであることを確かめる。\n- 予想される既存の不具合:\n - latest_snapshot と、signal の引数 (3)(4) は同じ object である(:12617-12621)。そのため、(2)〜(4) の外から内の変更は、latest_snapshot を変え、まだ計算していない digest にも影響しうる。\n - これは「既存の不具合」として、対象・向き・変わった path・値・digest への影響を全て記録する。PASS で補わない。harness による無断の変更とは区別する(どの scenario の、どの操作かを結びつける)。\n - その後の検査は、advance_minutes(1) を1回行って新しい latest_snapshot が publish された後の状態を、新しい baseline として始める。\n- (1) が deep copy であれば、影響が無いことを予想する。影響があれば、同じく事実として記録する。\n\ncheck_eq.py と試験\n- E4 と E5 の記録の形式・必須の欄・矛盾の検査を加える:\n - 経路の順序\n - 区間の連続\n - 件数(restore は0、load の成功は1)\n - X(P, ev_load)\n - 4×2×2 の全ての組の存在\n - NA の理由\n- 拒否の試験を加える:\n - 経路の欠落\n - 件数の不一致\n - 既存の aliasing を PASS として扱うこと\n - aliasing の記録の欠落\n - handler の中での変更\n - 区間の外での状態の変更\n - tick を含まない経路の latest_snapshot の据え置きを cache の古さと誤判定すること\n - NA を PASS として数えること\n\n終わり\n- engine を使わない python3 test_eq.py の全件 PASS まで直し、生出力を保存する。PROGRESS.md を更新する。正式な JSON の status を blocked にし、findings を「段階 S3b 完了(失敗ではない。次は S4)」とする。提出しない。\n- engine の起動、git への書込み、製品の変更、全回帰はしない。通常の実装上の判断は、記録して進める。\n" + }, + "EQ_S3B_STAGE_PLAN_R02.txt": { + "sha256": "9a26f47012e51ed23eb03e539fc5c4734e4d41c09ce37a21a18b4ac8a77a5f4c", + "full_unedited": "EQ_S3B_STAGE_PLAN r02(P28-02-EQ 段階 S3b。EQ_S3B_STAGE_PLAN(r01)は、そのまま有効。この r02 は、r01 の E4 の経路 1 の「引数の選び方」(施設の定義の列挙元)だけを置き換える。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02、S3 の計画 r01/r02 は変更しない)\n\n0. 訂正の理由(計画の参照の誤り。製品・仕様の変更ではない)\n- r01 は、施設の定義の一覧を mvp_content_catalog から取るとしていた。しかし scripts/data/mvp_content_catalog.gd:26-31 の DEFAULT_PATHS は人物の4種だけで、施設を含まない。そこから列挙すると一覧が空になり、「配置できる組が無い」という NA が誤って成立してしまう。\n- 施設の定義は、autoload/simulation_runtime.gd:446-447 で、FacilityCatalog の FACILITY_PATHS、INFRASTRUCTURE_FACILITY_PATHS、RESCUE_FACILITY_PATHS、ORIGINAL_FACILITY_PATHS、TRANSPORT_FACILITY_PATHS から runtime.definition_registry に登録される。preview_build_facility(:7660)も、同じ definition_registry.get_facility を使う。\n- run 7da027a85548460bb008b562a79a52ae の worker は、この誤りを指摘し、空の一覧を NA にせず blocked で返した。これは正しい判断であり、失敗ではない。\n\n1. E4 の経路 1 の引数の選び方(r01 の該当の箇条を置き換える)\n- 列挙元: R と O のそれぞれで、その PID の runtime の definition_registry.get_facility_ids()(scripts/core/definition_registry.gd:68-69。Array[StringName])。R と O の両方とも、元の実際の施設の registry から候補を取る。別の catalog、固定の ID の一覧、R の結果での O の代用は使わない。\n- 順序: 取得した ID を、文字列としての ID の順序(String(id) の昇順。Python 側の記録は Unicode の code point の順序)に並べる。registry の登録の順序は、取得した生の一覧として別に記録する。\n- cell の走査: r01 のとおり、(x, y, z) の辞書順。走査の範囲は、その版の世界の公開の寸法から、固定の規則で決め、その規則と範囲を記録する。rotation は 0 に固定する(他の値は試さない)。\n- 判定: 製品の公開の SimulationRuntime.preview_build_facility(definition_id, origin, rotation) だけを使う。ID の順序の外側のループ、cell の順序の内側のループで、最初に配置できると返った組を選ぶ。\n- 実行: 選んだ組で submit_command(&\"build_facility\", {definition_id, origin, rotation})(:476、:305、:7717-7720)を submit する。記録の時点(submit の直後と、advance_minutes(1) の後)は r01 のとおり。\n\n2. 保存する記録(R と O のそれぞれ)\n- get_facility_ids() の生の一覧(登録の順序)と、その件数。\n- 並べた後の一覧と、並べ方の規則。\n- cell の走査の規則と範囲。\n- 試した各候補(definition_id、origin、rotation)と、preview_build_facility の戻り値の全体(typed tree)。試行の件数が多い場合も、全件を記録する(省略しない)。\n- 選んだ候補と、その submit の戻り値と、command の結果。\n- 適用しなかった場合の理由。\n\n3. NA の条件\n- NA にしてよいのは、get_facility_ids() の実際の一覧が空でなく、走査の範囲の全ての組で preview_build_facility が配置できないと返した場合だけ。そのときは、上の 2 の全ての記録とともに、理由つきの NA とする。\n- 一覧が空の場合は NA にせず、registry の取得の誤りとして失敗にし、その事実を記録する。間違った列挙元や空の一覧からの NA(false NA)は禁止する。\n- NA を PASS として数えない。施設の値を作らない。この経路の外で建設しない。\n- check_eq.py に、次の拒否を加える: 列挙元が definition_registry.get_facility_ids() 以外であること、空の一覧での NA、preview の記録が無い候補の選択、試行の記録の欠落、並べ方の規則の違反、R と O で列挙元が違うこと。\n\n4. 変更しないこと\n- E4 の経路 2〜5、E5 の 4×2×2、全ての状態とイベントの typed tree での記録、既存の aliasing の不具合としての記録、S1/S2/S3a の型・path・schema・API・code の再利用、E3 と既存の91件の試験の本体と失敗の履歴(失敗した試験が求める修正を除く)、engine を使わない python3 test_eq.py の全件 PASS と生出力の保存、PROGRESS.md の更新、正式な JSON の status を blocked にし findings を「段階 S3b 完了(失敗ではない。次は S4)」とすること、提出しないこと、engine・git の書込み・製品の変更・全回帰をしないこと。いずれも r01 のとおり。\n- 通常の実装上の判断は、記録して進める。\n" + } + }, + "read_only_clarifications": { + "EQ_S_TIMING_CLARIFICATION.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_S_TIMING_CLARIFICATION.txt", + "sha256": "25d323fd562d29e80782b6f075fc7a0e8b49457a6c4fbd7c30e74b31a6b6a126" + }, + "EQ_S_TIMING_CLARIFICATION_R02.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_S_TIMING_CLARIFICATION_R02.txt", + "sha256": "777accdd652f85db6b9014d85e3c8b3b60ca94b20768e6173b36bc769d360fd9" + }, + "EQ_ENVIRONMENT_FIELDS_CLARIFICATION_R03.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_ENVIRONMENT_FIELDS_CLARIFICATION_R03.txt", + "sha256": "12b27f984ef5843d98327200ad261dccaf64968402192b08ad55b15ed5454ea2" + } + } + } +} diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S4_SUPPLEMENTARY.json b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S4_SUPPLEMENTARY.json new file mode 100644 index 0000000..cc437f1 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S4_SUPPLEMENTARY.json @@ -0,0 +1,549 @@ +{ + "actual_commander_context": { + "actual_run_decision": { + "action": "run", + "task_id": "P28-02-EQ", + "reason": "Supersedes DESKTOP_EQ_S4_RUN_DECISION.json, which was never dispatched and is kept unchanged as history. DESKTOP_EQ_S4_REPAIR_DECISION.json stays valid and usable as written: its facts (the S3b r02 checkpoint, the retained evidence and the S4 continuation) are unchanged by this correction. Use only after Root verifies through the normal gates: repair_ready, repairs 8, no S submitted, no active run, and all 58 current S1 to S3b files still present unchanged in the W. Run repair 8 of P28-02-EQ once on the same W from base 2549cf7d6992560b850bbd11934e3c14b39a1988 with the single worker codex gpt-6-astra, doing the whole final stage S4 as defined in EQ_S4_STAGE_PLAN.txt and corrected by EQ_S4_STAGE_PLAN_R02.txt: run_eq.py, verify_eq.py, bundle normal and rejection unit tests, full local PASS and the formal submission, in this one run, with no reduction to a smaller deliverable. Deliver both S4 plans in full as part of the one supplementary key, together with both S3b plans, both S3 plans, both staged plans, S4_FROZEN_DEPENDENCY_API_NOTES_R01.json and this decision; clarifications r01, r02 and r03 stay read-only in build/eq-staged-readonly-r04. The r02 corrections are as follows. Import the collector read-only inside the frozen SPEC §1 closure only; restart_pair.py belongs to the RESTART task, is not imported, and copy_states is read as reference only. EQ implements its own evidence copy and inventory in eq/ and rejects out-of-closure imports. raw3 is the collector's actual stdout.log, stderr.log and engine-native.log (collect_p28_01.py:217,225). The exit code is read from the owned receipts (for example process.json), never from raw3, and engine-native.log is required. Call check_report(raw, measurement, e3_evidence, b1_record, e45_evidence) with lifecycle.measurement, e3, e3_b1 and e45, and call check_lifecycle(raw, lifecycle, guard). The exact evidence names are checkpoint-00..30, observation-00..30, e3-00..17, e45-00..20, events, report, lifecycle and audio-close, all .json, plus the existing package evidence. The final worker JSON status must be exactly 'submitted' (core.py:1015), not pass or blocked, with commit set to the base. The worker writes no git, and Runner.submit commits normally. Formal validation runs with a read-only checkout (core.py:1064 writable=()) and BUILD_OUTPUT_DIR assigned to the runtime build area (core.py:827), so bundle-synthesis unit tests write only under that BUILD_OUTPUT_DIR or tempfile.gettempdir(), and verify_eq.py only reads. Nothing writes into the source tree, and environment and permissions are unchanged. Everything else in S4 r01 is unchanged: all S4 bindings, raw recomputation in verify, the 7 phases, pins and the 1407-file source map, seal only on success, the S_eq-native-not-Q label, all 119 test bodies and the full failure history, raw outputs with SHAs, and PROGRESS and IMPLEMENTATION updates. No engine, no run_eq.py --run, no trial formal validation, no git write, no product change, no full regression; SPEC, TASK, eq/references and eq/registration stay unchanged. Ordinary implementation choices are recorded without stopping; block only for undecided matters affecting original product spec, values, permissions, billing or original acceptance. After submission: Root native on the exact S in 7 phases, the bundle placed at $BUILD_OUTPUT_DIR/p28-02-eq-evidence, both validations, a fresh independent Opus review of all 6 conditions, then the normal prepare, candidate qualification, approval, integration and final, then the OPT and whole-unit gates. No original credit (23/88, 4/30); the 900-second timeout is unchanged. Quota fallback only on structured provider quota, once, same role, Antigravity claude-opus-5-5-high; any other failure is blocked. Decided by Claude Opus 5.5 in the Desktop control session (message 342); not a CLI commander result." + }, + "actual_Opus_session": "local_a7f85421-3eed-4482-8030-c0dca669573a", + "actual_Opus_model": "claude-opus-5-5", + "stage": "S4 only: run_eq.py, verify_eq.py, synthetic bundle positive/negative units, final local fullPASS and worker JSON status submitted with commit equal to base; Runner commits normally. Read PROGRESS/IMPLEMENTATION and map every S4 binding first. Preserve all119 prior test bodies and every failed raw. No worker engine/git/product/fullregression; exact S native7, both validations, fresh independent Opus all6 and normal final remain pending", + "retained_S1_to_S3b_files": { + "IMPLEMENTATION.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/IMPLEMENTATION.md", + "bytes": 30148, + "sha256": "4b023cb03fd86bc2afb4dc1c2d9808e716ea3d1714cdda875c0050bcb8fff93f" + }, + "PROGRESS.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/PROGRESS.md", + "bytes": 11587, + "sha256": "de05c86683daceca83f11205049035da25bbe874bac5da35843755e7f1a6e658" + }, + "S2_SUPPLEMENTARY.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S2_SUPPLEMENTARY.json", + "bytes": 19208, + "sha256": "26f23bd8650a2495fd93f4364cbb17cc34f9eb1568758d406bec12ae2dab83a7" + }, + "S3A_SUPPLEMENTARY.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3A_SUPPLEMENTARY.json", + "bytes": 33965, + "sha256": "9e9d420b01a0030919d2e49245e975a81bf3f561a7fa9fdf7cdc1efb8f02560e" + }, + "S3B_SUPPLEMENTARY.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/S3B_SUPPLEMENTARY.json", + "bytes": 46293, + "sha256": "ec89b263b3a94ee3d4c2e6946c1f781138bbab822bbdd77f84f84b250064fc9b" + }, + "SPEC.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/SPEC.md", + "bytes": 10693, + "sha256": "3791ccdcb87e8d71fe9205e1e692ebca9e0f974ea3b5fbc4fbb3943882131f1c" + }, + "TASK_INSTRUCTIONS.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/TASK_INSTRUCTIONS.md", + "bytes": 2961, + "sha256": "f9937c3c7dff5a25ada453365d26c87fecf009d29518724f0c1e67d2b18afff3" + }, + "UNIT_OUTPUT.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.sha256", + "bytes": 82, + "sha256": "a26c3765d7e4d3471c55d741c76170fa82834453ad0d59ff245867e643d42ee7" + }, + "UNIT_OUTPUT.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.txt", + "bytes": 7291, + "sha256": "8360a2065b303099d5c546b3e4aecc0cc0ab0c2c1e5120b8034b6a1a64317030" + }, + "UNIT_OUTPUT_ATTEMPT_01.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.sha256", + "bytes": 93, + "sha256": "eed78af7775a79838e65ea3cb07e9fe09822d2d7a23007f294cbf0a0c98d1c7c" + }, + "UNIT_OUTPUT_ATTEMPT_01.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.txt", + "bytes": 3368, + "sha256": "307486177b76602cbe68acae24c9560d501b3b866136d8e69802ec24c28e8be8" + }, + "UNIT_OUTPUT_ATTEMPT_02.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.sha256", + "bytes": 93, + "sha256": "1de0c0052e66cc60668690bf43e29eb01808afd023525e517ba94beaab0db669" + }, + "UNIT_OUTPUT_ATTEMPT_02.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.txt", + "bytes": 2699, + "sha256": "07144a7f1941162227f54fefd1961ed0f209e97282432723bbda534079582e4e" + }, + "UNIT_OUTPUT_S1_FINAL.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.sha256", + "bytes": 91, + "sha256": "91d9d408ed8d012f38ff892fa6712d129f4849d0ce0b579eaeb7cb1a3f84b704" + }, + "UNIT_OUTPUT_S1_FINAL.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.txt", + "bytes": 2839, + "sha256": "cdca0cdd551ce76c6100c4dd90e04559551f9d88c054a19a2bc6a77e6572ae15" + }, + "UNIT_OUTPUT_S2_ATTEMPT_01.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.sha256", + "bytes": 96, + "sha256": "579254585137adf932f5e4a0eaa2b0ecd67d275ece6c7199bdafbee4b48f4f5d" + }, + "UNIT_OUTPUT_S2_ATTEMPT_01.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.txt", + "bytes": 4395, + "sha256": "25953dfc5f8bc3759ae66f6403b162100fb0217c4476f308616b8ab78a2cc67e" + }, + "UNIT_OUTPUT_S2_ATTEMPT_02.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.sha256", + "bytes": 96, + "sha256": "f4094cc3a8924b79316f473b8b4027a4743036d9d9cf8b2ad0c492ff7b581756" + }, + "UNIT_OUTPUT_S2_ATTEMPT_02.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.txt", + "bytes": 4617, + "sha256": "e26c986dda41b83143723e4c1c5b2ff1051a36b9a947b319341a2239cc3188de" + }, + "UNIT_OUTPUT_S2_ATTEMPT_03.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.sha256", + "bytes": 96, + "sha256": "d8f8f7a9be6b2fb1618a1ff03f9af5aa0e397373c5e8f9716dc47befa6e3bb83" + }, + "UNIT_OUTPUT_S2_ATTEMPT_03.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.txt", + "bytes": 4693, + "sha256": "9d323abda9bfffa02faf3a9d5cb56aa87e647017c991eb55b4807cf734386698" + }, + "UNIT_OUTPUT_S3A_ATTEMPT_01.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.sha256", + "bytes": 97, + "sha256": "303396536b67929fca0fcb4617578bc546c4f65a674e5dcd2b485bb27c060082" + }, + "UNIT_OUTPUT_S3A_ATTEMPT_01.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.txt", + "bytes": 4693, + "sha256": "5cf84b792b5f87cd4183f41cf3a846962a53dc0aa33049c3c55f290356584641" + }, + "UNIT_OUTPUT_S3A_ATTEMPT_02.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.sha256", + "bytes": 97, + "sha256": "76d72513d22720cb0c6fd2bb43ac5000b80144a680a64f635276de8fca47ca97" + }, + "UNIT_OUTPUT_S3A_ATTEMPT_02.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.txt", + "bytes": 5457, + "sha256": "000152e51d23db3d4397583b3f4540f5ed0ae469010c993fa1d122fd51537431" + }, + "UNIT_OUTPUT_S3A_ATTEMPT_03.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.sha256", + "bytes": 97, + "sha256": "9625ff44edb36f93ffac168208b148f7f49b247bc4f641d2b35e7c03f4f10ce0" + }, + "UNIT_OUTPUT_S3A_ATTEMPT_03.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.txt", + "bytes": 5810, + "sha256": "7c14e8ecf4540e412467408cad267d53358940c86f87a0c8e519b305153f3cb8" + }, + "UNIT_OUTPUT_S3A_ATTEMPT_04.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.sha256", + "bytes": 97, + "sha256": "caab1a3e97878fd0c273e818bc3cf481f0f5f5d3def557da2c5c51981b6dbd0f" + }, + "UNIT_OUTPUT_S3A_ATTEMPT_04.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.txt", + "bytes": 5810, + "sha256": "02221ae41e5dd40ecdac0ec0d7ffc657f265d3194c3817583c2b88ad375f132b" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_01.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.sha256", + "bytes": 97, + "sha256": "3af8110cac13104df8e85851491d781d3edff527bb168a626c9c0d3285fcc093" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_01.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.txt", + "bytes": 5810, + "sha256": "c89f4f1ca1ea9b985079cd236ffff4193fa5c76d9bfa28fa65ac08cfc93b569c" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_02.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.sha256", + "bytes": 97, + "sha256": "8f5edcdb522ab51606374403d6bcec508029aa32260430ac715a4b5bbb610da2" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_02.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.txt", + "bytes": 375, + "sha256": "7bd19a6a3c84385f754261d51779f05b6e39c116459086d5aad3a83afa7225c0" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_03.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.sha256", + "bytes": 97, + "sha256": "a9f4348d6fdbe4bcbed3f19831a88131fb365107411d452a2237f14038e88e6b" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_03.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.txt", + "bytes": 30717, + "sha256": "0872061bbc2c1403d2cd04877b8456f3fead35236be008b1a07f02ae5d85b11a" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_04.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.sha256", + "bytes": 97, + "sha256": "950e32a41ebfd325c86eb6810148d726316a1a455203e5c806692dcce82e017a" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_04.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.txt", + "bytes": 6983, + "sha256": "63204c3415c9b1719fa6aa596b714077a57f530896f979d12b89a15eb2d827e9" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_05.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.sha256", + "bytes": 97, + "sha256": "4293e250807be76a74c0b743b6ed550f5038d50a34ac5f9e743c68b8c15e5564" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_05.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.txt", + "bytes": 6983, + "sha256": "bfcb263bf6d7f284fb2b20ee229d96b7c4a9bd7cd5e7b513df1d3ea32580ed6e" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_06.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.sha256", + "bytes": 97, + "sha256": "e0b6b770ded4ead6f785d64f4f866916b3a8392ba5d330ed5820755e3c6497f0" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_06.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.txt", + "bytes": 7223, + "sha256": "7d9bf9c602a93aca06d03eb06025beeea35603d453e293c07e7a6f81ca9ca000" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_07.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.sha256", + "bytes": 97, + "sha256": "d38c2f6c05976e05a553b80917d4bede994425a76cbcaaba274fd36836101a64" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_07.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.txt", + "bytes": 963, + "sha256": "f7c7c045ea98a366810b7c309fc1a87a77ccc5d8e823750eebaa742c9529e2ca" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_08.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.sha256", + "bytes": 97, + "sha256": "7b252056637268e05f3eaa28a6f75f64c9345e4e95031bdba93c33048e8807a6" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_08.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.txt", + "bytes": 7879, + "sha256": "19c3f115d6a73bf91413877878f5d5f9d78a3e253dae3ddba7dfec9b5d46eaba" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_09.sha256": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.sha256", + "bytes": 97, + "sha256": "f603c6d559184e68909e2409114659a263af5d18a684be332cebffaf816b6bd0" + }, + "UNIT_OUTPUT_S3B_ATTEMPT_09.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.txt", + "bytes": 7291, + "sha256": "8360a2065b303099d5c546b3e4aecc0cc0ab0c2c1e5120b8034b6a1a64317030" + }, + "check_eq.py": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/check_eq.py", + "bytes": 57523, + "sha256": "e22602c5961d53ce98247fb014bbd91549b5cc0cf34a370102d3acf575a8d498" + }, + "compare_versions.py": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", + "bytes": 34690, + "sha256": "1324e9e689a2885bd85f58a54f974d8a198e09fd3542123c6f597442e1437263" + }, + "eq_probe.gd": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/eq_probe.gd", + "bytes": 41542, + "sha256": "f933cad2a7ad4905fec15228ceb75ecb0ed100c64200a41feb80ba9702cf88fb" + }, + "references/OPT_CONTRACT_T1.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPT_CONTRACT_T1.md", + "bytes": 13952, + "sha256": "ad9f3d76f3500b39263fb898d7c64588b4b47c9e11b456f938195261fd054d16" + }, + "references/OPUS_D2_SCOPE_CLARIFICATION.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPUS_D2_SCOPE_CLARIFICATION.txt", + "bytes": 5598, + "sha256": "5775e7b512d9e90dbcfbcb181f5b64dc0fa8207e0947c0a4a6a5c9195565f9bd" + }, + "references/OPUS_STARTUP_LIFECYCLE_CLARIFICATION.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPUS_STARTUP_LIFECYCLE_CLARIFICATION.txt", + "bytes": 5996, + "sha256": "967aebf27ff412f7a16ce771ef7d68abf8cfde0bb76ed19cf6dbf2817ca7acc6" + }, + "registration/ACCEPTANCE_BASELINE.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/registration/ACCEPTANCE_BASELINE.json", + "bytes": 2981, + "sha256": "84628bc21205387f8a7143031bdc50c9f68a767d350e6c34b32e0ba1c7059337" + }, + "registration/CONFIG_PROPOSAL.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/registration/CONFIG_PROPOSAL.json", + "bytes": 821, + "sha256": "775fbbb97cda8b4d4991defdf7871b0fc79f489f4dea34c1733d4830426cf1df" + }, + "registration/REGISTRATION_PROPOSAL.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/registration/REGISTRATION_PROPOSAL.json", + "bytes": 4733, + "sha256": "9590fc853a4df8d50cc0d269d23bd9c844dc6931590ff6f24ebf95bb54a8d135" + }, + "registration/ROOT_PROPOSAL_BYTE_TRANSFER.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/registration/ROOT_PROPOSAL_BYTE_TRANSFER.json", + "bytes": 4778, + "sha256": "63197f650849084f769e487a76458361886a37090042f1e351851c75b0384da2" + }, + "test_eq.py": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", + "bytes": 67839, + "sha256": "7f65b1dec6f68800cba4415b9afa3c11f0a0e58fd970f5582268cfd2123f9c19" + } + }, + "actual_full_plans": { + "EQ_STAGED_IMPLEMENTATION_PLAN.txt": { + "sha256": "eb7b4831e2164c6fc983fa6f9825e7f3e2993b4c0ebf2f90aac8ad10662666d2", + "full_unedited": "EQ_STAGED_IMPLEMENTATION_PLAN(P28-02-EQ repair 3 以降。base 2549cf7d6992560b850bbd11934e3c14b39a1988。SPEC、TASK、6条件、eq/references、eq/registration、EQ_S_TIMING_CLARIFICATION r01/r02、EQ_ENVIRONMENT_FIELDS_CLARIFICATION r03 は全てそのまま有効。変えるのは、工程と、成果物の内部の設計の固定だけ)\n\n前回までの事実\n- repair 2(run 84ca0ff8…)は、IMPLEMENTATION.md と compare_versions.py などを作った後、item_30 で全てを削除し、「6ファイルと unit の PASS を提供できない」として、自分から終了した。仕様の不足の指摘ではない。packet は 94 KB あった。\n- この失敗は失敗のまま保持する。削除したことを成功として扱わない。\n\n工程の変更(必須)\n- G1: **作ったファイルは、削除しない**。完成していなくても、W の eq/ に残す。各 run の最後に、eq/PROGRESS.md に、終わった段階・残りの作業・現在の試験の結果を書く。\n- G2: 1回の run では、下の**1つの段階だけ**を行う。始める前に eq/PROGRESS.md を読み、次の段階から再開する。前の段階のコードは作り直さない。\n- G3: 各段階の終わりに、engine を使わない python3 test_eq.py を実行する。その時点で存在する試験が、全件 PASS になるまで直す。生出力を eq/UNIT_OUTPUT.txt に保存する。\n- G4: 段階1〜3の終わりには、正式な JSON の status を blocked にし、findings に「段階 Sx 完了(失敗ではない。次は Sx+1)」と PROGRESS.md の要点を書いて返す。段階4の終わりにだけ、提出する(status を submitted 相当の正式な提出にする)。\n- G5: 通常の実装上の判断(関数の分け方、名前、試験データ、記録の書式)は、IMPLEMENTATION.md に記録して進める。blocked にしてよいのは、原本の仕様・値・権限・課金・受入に影響する未確定事項がある場合だけ。\n- G6: engine の起動、git への書込み、製品の変更、全回帰はしない。SPEC、TASK、eq/references、eq/registration は変更しない。\n\n固定するインターフェース(6ファイル。SPEC §2)\n\n1. compare_versions.py(Python のみ。engine を使わない)\n - normalize_events(events, profile_root) -> (normalized, sidecar):\n - r03 の F1〜F3 を、JSON の event の一覧に適用する。\n - 閉じた一覧の外の *_us / *_ms / profile_root を含む文字列は、正規化せず、violations として返す。\n - restore_events(normalized, sidecar, profile_root) -> events: 逆の復元(完全一致の確認に使う)。\n - compare_reports(a, b) -> dict: 2つの report(同じ版の別 PID、または前後の版)を比べる。\n - 毎分の checkpoint の S_norm_sha と latest_norm_sha の一致\n - digest の規則(r02 の T3)\n - K と C の、SPEC §3.2 に列挙した欄\n - E2 の正規化した全イベント(開始の counter の一致が前提)\n - E3/E4/E5 の scenario の結果の一致\n - 比べない欄は、理由と両側の値を記録する\n - 差は path ごとに返す\n - check_source_closure(before_map, after_map, allowed_changed) -> dict: SPEC §2 と OPT r02 §2。追加・欠落・登録されていない差分を拒否する。\n2. eq_probe.gd(GDScript):\n - 起動の6段階は、DIAG の diag_probe.gd の構成をそのまま参考にする。\n - 役割は R と O(env の THE_TREE_EQ_ROLE)。\n - 観測の checkpoint は B1 と、30分の各 tick の最後(31個)。各 checkpoint に、次のものを置く:\n - minute\n - S_raw_sha、S_norm_sha(GDScript の中で F1〜F3 の typed の marker を使って正規化した後の var_to_bytes の SHA)\n - 正規化した S の path の hash の表(depth ≤ 4)\n - latest_norm_sha\n - digest の情報\n - K と C の全体\n - sidecar\n - E2 は subscribe('*') で、全イベントの JSON(正規化の前)を記録する。正規化は compare_versions.py で行う(GDScript と Python で、同じ規則の二重実装をしない)。\n - E3/E4/E5 の scenario は、SPEC §3.3 の専用の区間で行う。各区間について、開始と終了、操作、code、前後の S/K/C、件数(r02 の T4)を記録する。\n - stdout には、P28_02_EQ_REPORT= をちょうど1行出す。終了は close_requested.emit()。\n3. check_eq.py: report 1つを検査する。\n - 形式、必須の欄、矛盾\n - 閉じた一覧の外の差\n - probe の静的な禁止(autoload の class_name の参照、状態を変える呼出しの区間の外での使用、Variant からの := の推論)\n - SimulationDigest だけでの判定\n4. run_eq.py: Root が実行する driver。\n - diag_p28_02.py の構成をそのまま参考にする(--check / --run、依存の SHA、1407 の source、凍結した S の照合、owned phase、guard、private profile、cleanup)。\n - phase は import、parse-base、parse-wrapper、R-A、R-B、O-A、O-B。\n - 成功したら、execution.json と bundle.json を作る。\n5. verify_eq.py: --project-root . で、$BUILD_OUTPUT_DIR/p28-02-eq-evidence の bundle を結合する。bundle が無ければ失敗する。\n - 各 report に check_eq を行う。\n - R-A と R-B、O-A と O-B に compare_reports を行い、差が0であること(harness の正しさ)。\n - E3/E5 の、前の版での製品の失敗は、「既存の不具合」の一覧として出力する。harness の不合格とは区別する。\n - SPEC、TASK、eq/references、eq/registration の SHA を固定して照合する。\n6. test_eq.py: 合成した入力だけで動く。各段階で、その段階の試験を足していく。\n\n段階(1回の run で1つ)\n- S1: compare_versions.py の全体と、その試験(F1〜F3 の正常と拒否、可逆性、比較、source の閉包)。PROGRESS.md と IMPLEMENTATION.md を作る。\n- S2: eq_probe.gd の、起動・観測の checkpoint・E2 の記録・報告。check_eq.py の静的な検査と形式の検査、それぞれの試験。\n- S3: eq_probe.gd の E3/E4/E5 の scenario、check_eq.py のそれに対する検査、試験。\n- S4: run_eq.py と verify_eq.py、bundle の試験。全件 PASS を確かめて、正式に提出する。\n\nRoot への依頼(packet を小さくするため)\n- actual_commander_context の key には、この計画の全文と RUN の判断だけを入れる。r01・r02・r03 の全文は、build/ に読取専用で置き、その path と SHA だけを渡す。eq/references は W の中にあるので、path だけで足りる。\n" + }, + "EQ_STAGED_IMPLEMENTATION_PLAN_R02.txt": { + "sha256": "128f42f18e168e9299995296ac7ad119f47d1647799d472663282e47e8ac9fdd", + "full_unedited": "EQ_STAGED_IMPLEMENTATION_PLAN r02(P28-02-EQ repair 3 以降。EQ_STAGED_IMPLEMENTATION_PLAN(r01)の工程 G1〜G6、段階 S1〜S4、Root への依頼は、そのまま有効。この r02 は、固定インターフェースのうち、状態とイベントの運搬の表現と、normalize_events の返り値を置き換えて確定する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03 は変更しない)\n\nA. 型を保つ運搬の表現(typed tree。JSON は運び方であって、型の情報は落とさない)\n\nA1 node の形式(JSON の配列)\n- 各値は [type_code, payload]。type_code は Godot の typeof() の値。\n - null: [0]\n - bool: [1, 0|1]\n - int: [2, 整数]\n - float: [3, \"<8 byte little-endian IEEE754 の hex>\"](10進の文字列にしない)\n - String: [4, \"文字列\"]\n - StringName: [21, \"文字列\"]\n - Vector2/Vector2i/Vector3/Vector3i/Rect2/Rect2i/Color など: [type_code, [各成分の node]](成分は int か float の node)\n - Dictionary: [27, [[key_node, value_node], …], typed_info]。**元の挿入の順序のまま**並べる。typed_info は、型つきの Dictionary なら key と value の builtin 型・class 名・script、それ以外は null。\n - Array: [28, [element_node, …], typed_info]。typed_info は get_typed_builtin()・get_typed_class_name()・get_typed_script() の値、型の無い Array なら null。\n - PackedByteArray: [29, \"\"]。他の Packed*Array も、要素ごとの node の列にする(float は hex)。\n- Object、Callable、Signal、RID が現れたら、運搬せずに失敗にする(snapshot と event の dict には、本来現れないもの)。\n\nA2 無損失の証明(Godot の中で行う。probe の必須の処理)\n- tree = encode(value) を作った後、decode(tree) で Variant を作り直す。var_to_bytes(decode(tree)) == var_to_bytes(value) であることを確かめる。一致しなければ失敗にする。\n- report には、checkpoint ごとに、次の3つを記録する。\n - raw_bytes_sha = sha256(var_to_bytes(value))\n - tree_sha = sha256(tree を key の順序を変えずに JSON.stringify した UTF-8)\n - roundtrip_ok\n- Python は、受け取った tree から tree_sha を計算し直して結合する。これで、Python で比べる tree が、Godot の元の bytes と無損失に対応することが保証される。\n\nA3 保存の場所と大きさ(深さの制限は設けない。全体を再構成できるようにする)\n- 各 PID は、checkpoint の列(B1 と、30分の各 tick の最後)について、S 層と latest_snapshot を、次の形で、private user:// の evidence/ に書き出す。driver は、それを RESTART の copy_states と同じ方式で out へ複製し、SHA を結合する。\n - checkpoint 0(B1): tree の全体(JSON、zstd で圧縮してよい。圧縮した場合は、圧縮の前後の SHA を両方記録する)。\n - checkpoint k(k≥1): checkpoint k−1 の tree に対する、path を指定した差分の操作の列。操作は set(path, node)、dict_insert(path, index, key_node, value_node)、dict_remove(path, key_node)、array_splice(path, start, delete_count, [node…])。順序つきで、再構成すると、checkpoint k の tree と完全一致すること。\n - latest_snapshot は、各 checkpoint で、var_to_bytes が S 層と同じなら same_as_S=true とし、違えば、その tree(または S に対する差分)を保存する。\n- Python は、checkpoint 0 から差分を順に適用して、全ての checkpoint を再構成する。checkpoint ごとに tree_sha と一致することを確かめる。\n\nA4 比較(compare_versions.py。全て tree の上で行い、深さの制限は無い)\n- 第一の比較は、tree の完全一致(型、key、順序、値。全ての node)。\n- 一致しない場合に限り、正規化した比較を行う。dict の key を文字で並べ(同じ文字の key が2つあれば拒否)、それ以外の型・値・配列の順序を保ったまま比べる。それで一致すれば「dict の列挙の順序だけの差」として、その全ての path を記録する。それ以外の差は、全ての path と両側の node を記録して、不一致にする。\n- F1〜F3(r03)の正規化は、tree の node の上で行う。sidecar から、元の tree へ完全に戻せること(tree_sha が一致すること)を確かめる。\n\nB. E2 のイベントの運搬\n- 各 event について、event.to_dictionary()(製品の直列化。scripts/core/domain_event.gd:47-59)の tree を記録する。あわせて、元の object の欄の型(event_id と event_type が StringName であるか、entity_ids の型、payload の dict の typed_info)を、original_field_types として記録する。\n- 受け取りの順序で番号をつけ、開始の時点の counter と、published_ids の数を記録する。\n- イベントの列は、A3 と同じく evidence/ に書き出し(tree の列。圧縮してよい)、SHA を結合する。Godot の中で、各 event について A2 の roundtrip を確かめる。\n- compare_reports は、この tree の列を受け取り、全ての欄と event_id を**そのまま**比べる(ID の付け替えはしない)。F1〜F3 は、payload の該当する node にだけ適用する。\n\nC. normalize_events とその仲間の返り値(固定)\n- normalize_events(events, profile_root) -> (normalized, sidecar)。返り値は2つの要素のまま。\n - normalized: tree の列。閉じた一覧(r03)の node だけを marker に置き換えたもの。\n - sidecar: dict で、key は次の3つに固定。\n - \"entries\": [{\"event_index\", \"path\", \"key\", \"original_node\"}…]。F1〜F3 で置き換えた全ての node の元の値。F3 の場合は original_node に元の message の文字列を入れ、\"root\" に、置き換えた root を入れる。\n - \"violations\": [{\"event_index\", \"path\", \"kind\", \"node\"}…]。閉じた一覧の外にあった、*_us / *_ms の key、profile_root を含む文字列など。**存在しただけでは不合格にしない**。正規化はせずに、そのまま保持して記録する。\n - \"profile_root\": 使った root の文字列と、guard の actual_user_data_dir との一致の結果。\n- restore_events(normalized, sidecar, profile_root) -> events: entries から元に戻す。violations の node は、もともと変えていないので、そのまま。\n- 状態の tree にも、同じ形の normalize_tree(tree, profile_root) -> (normalized, sidecar) と restore_tree を用意する。\n- r03 の規則は、そのまま。violations にあるものを正規化しようとしたら拒否する。violations にあるものが、比べる2つの側で実際に異なれば、その差は不一致(失敗)として、path と両側の値を記録する。\n\nD. 段階への影響\n- S1(今回): compare_versions.py に、A4 の比較、C の4つの関数、A3 の差分の再構成、tree_sha の再計算、check_source_closure を実装する。試験は合成の tree で行い、次のものを確かめる。\n - 型の違い(int と float、String と StringName、型つきの配列)を区別すること\n - dict の順序だけの差の path\n - 差分の再構成の完全一致\n - sidecar からの逆の復元\n - violations の扱い(存在だけでは不合格にしない、正規化しようとしたら拒否、差があれば不一致)\n- S2: eq_probe.gd に、A1 の encode と decode、A2 の roundtrip、A3 の書き出し、B の記録を実装する。\n- S3 と S4 は、r01 のとおり。\n" + }, + "EQ_S3_STAGE_PLAN.txt": { + "sha256": "ecbfb00691017fbd35027df8fa9ca6f82c761a5a3389568fe44b1babcfca308a", + "full_unedited": "EQ_S3_STAGE_PLAN(P28-02-EQ。EQ_STAGED_IMPLEMENTATION_PLAN r01/r02 の段階 S3 を、S3a と S3b に分ける。理由: S2 は 846.159 秒で、Runner の900秒の上限に近かったため。要求の範囲は変えない。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03 は変更しない)\n\n共通\n- 最初に eq/PROGRESS.md と eq/IMPLEMENTATION.md を読み、S1/S2 の型・path・record schema・API・notes を再利用する。再設計しない。\n- S1/S2 のコードと試験の本体を消さない。書き直さない(S3 で直すと決めた checker の2点と、失敗した試験が求める修正を除く)。\n- 失敗の履歴は、PROGRESS.md と UNIT_OUTPUT に残す。各段階の終わりに、engine を使わない python3 test_eq.py の全件 PASS まで直し、生出力を保存する。\n- 状態を変える呼出しは、SPEC §3.3 (b) の、列挙した scenario の専用の区間の中でだけ許可する。check_eq.py の静的な許可も、その区間と列挙した操作に限る。\n- engine の起動、git への書込み、製品の変更、全回帰はしない。SPEC、TASK、eq/references、eq/registration は変更しない。\n\nS3a(次の run)\n1. checker の修正 1(eq/check_eq.py:109)\n - 各 checkpoint の immutable snapshot の phase の key の集合が、正確に {0,…,10} であることを要求する(空の dict や、一部の欠落を拒否する)。\n - 負の試験を加える: 空、1つの欠落、範囲外の key、重複した key の表現。\n2. checker の修正 2(eq/check_eq.py:147-150)\n - 測定の区間の30 tick の各分について、製品の _publish_snapshot(autoload/simulation_runtime.gd:12616-12621)が出す snapshot_published → state_updated を、実際の回数と順序で記録したものを、その分の checkpoint と結びつけて検査する。\n - 各分に、ちょうど1組であること(snapshot_published に接続した受け手が無い場合は、製品の条件 :12619 のとおり state_updated だけになるので、probe の側で接続を記録し、期待値をその実際の接続の状態から決める)。\n - 順序は snapshot_published が先。\n - 分の番号は、checkpoint の minute と一致すること。\n - scenario の区間で出た追加の signal は、別の区間の記録に入れる。測定の区間の記録には混ぜない。\n - 負の試験を加える: 欠落、一部の分だけ、重複、順序の改ざん、分のずれ、scenario の signal の混入。\n3. E3 失敗時の拒否(専用の scenario の区間。R と O の両方)\n - restore_snapshot、SimulationSnapshot.validate、load_from_path の3つの API に、次の不正な入力を、それぞれ1件以上与える:\n - 欠けた key\n - 違う型\n - 範囲外の値\n - 重複した ID(published_ids、facility の ID)\n - world.bin の改ざん(r03 の D3 の固定の規則)\n - 不正な入力は、B1 の snapshot の deep copy から、固定の規則で作る。乱数や時刻を使わない。\n - 記録すること:\n - 戻り値と code\n - 前後の S/K/C 層(同じ PID の中で完全に比べる)\n - 全イベントの差分と、その件数(r02 の T4: 直接の restore は0件、load の失敗は SAVE_LOAD_FAILED がちょうど1件で、X(B, ev_fail) と r03 の正規化の後で完全一致すること)\n - check_eq.py: E3 の記録の形式と矛盾の検査を加える。製品の失敗(不正な入力が受理された、状態が変わった、など)は、「既存の不具合」として記録する。PASS で補わない。\n - 試験を加える: E3 の正常の記録と、拒否の場合(code の欠落、件数の不一致、拒否の前後の状態の変化を見逃すこと)。\n4. 終わり: PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3a 完了(失敗ではない。次は S3b)」とする。\n\nS3b(S3a の後の run)\n1. E4 キャッシュの古さ(専用の区間。R と O)\n - 場面: 状態を変えるコマンド(建設のコマンドを1件、通常の command queue を通す)、tick(advance_minutes(1))、restore_snapshot、load_from_path、状態を変えないコマンド。\n - 各場面の直後の create_snapshot() と latest_snapshot を、完全な typed tree(r02 の A)で記録する。版の間の比較は compare_versions.py で行う。\n - 件数: 直接の restore は SAVE_* が0件、load の成功は SAVE_LOADED がちょうど1件(X(P, ev_load))。\n2. E5 所有権(専用の区間)\n - 対象: create_snapshot() の戻り値、latest_snapshot、snapshot_published と state_updated の引数。\n - 外から内: 入れ子の dict と配列を変更した後に、内部の状態、次の create_snapshot()、latest_digest が変わっていないかを、完全な typed tree で確かめる。\n - 内から外: 次の tick の後に、既に返した値が変わっていないかを確かめる。\n - 予想される aliasing(latest_snapshot と signal の引数が同じ object であること)による live の変化は、「既存の不具合」として、変わった path と値を全て記録する。その後の検査は、新しい baseline から始める。harness による無断の変更とは区別する。\n3. check_eq.py と試験: E4/E5 の記録の検査と、正常と拒否の試験を加える。\n4. 終わり: PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3b 完了(失敗ではない。次は S4)」とする。\n\nその後\n- S4: run_eq.py と verify_eq.py、bundle の試験、全件 PASS の後に正式に提出する。\n- その後に、Root の native(7 phase)→ 両方の validation → 別の新しい Opus による全6条件のレビュー → 通常の統合と final、の順序で進める。\n" + }, + "EQ_S3_STAGE_PLAN_R02.txt": { + "sha256": "566e3ad98f9d47136ff4d4932f81c0a7f9fc96321a6f08ba944a9f1e736e6caa", + "full_unedited": "EQ_S3_STAGE_PLAN r02(P28-02-EQ。EQ_S3_STAGE_PLAN(r01)の分け方(S3a = checker の2点の修正 + E3、S3b = E4/E5)、共通の規則、S3b、その後の順序は、そのまま有効。この r02 は、実際の API に合わせて、S3a の「checker の修正 2」と「E3」を置き換えて確定する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02 は変更しない)\n\n1. checker の修正 1(eq/check_eq.py:109): r01 のとおり(phase の key の集合が正確に {0..10}、負の試験)。\n\n2. checker の修正 2(eq/check_eq.py:147-150。r01 を置き換える)\n- probe は、自分の observer を snapshot_published に接続している。そのため、製品の _publish_snapshot(autoload/simulation_runtime.gd:12616-12621)は、毎 tick、snapshot_published を出してから state_updated を出す(:12619 の条件が真になる)。\n- 測定の区間の30 tick の各分について、**ちょうど1組の snapshot_published → state_updated** を要求し、その分の checkpoint の minute と結びつける。\n- 測定の開始の時点で、snapshot_published と state_updated の接続の一覧(get_connections() の、接続先の object と method)を記録し、その中に probe 自身の接続があることを要求する。probe の接続が無い場合は、期待を「state_updated だけ」に下げることはせず、失敗にする。\n- 製品で受け手が接続されていない場合の動作(state_updated だけ)は、この区間の対象の外とする。試験もしない。\n- scenario の区間で出た signal は、別の区間の記録に入れ、測定の区間には混ぜない。\n- 負の試験を加える:\n - 欠落、一部の分だけ、重複、順序の改ざん、分のずれ\n - scenario の signal の混入\n - probe の接続が一覧に無いのに合格にすること\n - 期待を state_updated だけに下げること\n\n3. E3 失敗時の拒否(専用の scenario の区間。r01 を置き換える)\n\n3.1 各 API の実際の戻り値(架空の code は作らない)\n- SimulationRuntime.restore_snapshot(Dictionary) -> bool(:587): 戻り値の bool を、そのまま記録する。code は null とし、理由を \"API returns bool only\" とする。\n- SimulationSnapshot.validate(Dictionary) -> {ok, errors}(scripts/core/simulation_snapshot.gd:16-43): 返った dict の全体(ok と、errors の全件)を、そのまま記録する。code は null とし、理由を \"API returns ok/errors only\" とする。\n- load_from_path(String) -> Dictionary(:4223): 実際の code を記録する。この API で code が欠けていれば、それは失敗として拒否する(上の2つの「API に code が無い」とは区別する)。\n\n3.2 不正の分類と、それを適用する API(source に基づく表。適用しないものは、理由つきの NA として記録し、PASS に補わない)\n\n| 分類 | restore_snapshot(Dictionary) | validate(Dictionary。envelope の外形だけを検査) | load_from_path(package) |\n|---|---|---|---|\n| 欠けた key | 適用: B1 の deep copy から clock を削除 → false を期待 | 適用: clock を削除 → errors に missing_clock を期待 | 適用: package の manifest.json から checksum_world を削除 → INVALID_MANIFEST を期待 |\n| 違う型 | 適用: clock.absolute_minute を文字列 \"x\" に → false | 適用: 同じ → errors に invalid_absolute_minute | 適用: manifest.json の format_version を文字列に → INVALID_MANIFEST |\n| 範囲外の値 | 適用: clock.speed を 9 に → false | 適用: 同じ → errors に invalid_speed | 適用: manifest.json の format_version を、対応していない大きな整数に → UNSUPPORTED_FORMAT(自動の migration を試みた場合は、その実際の code と、migration_attempted を記録) |\n| 重複した ID(published_ids) | 適用: systems.runtime.domain_events.published_ids に、既存の ID を1つ追加 → false(DomainEventStream.restore_snapshot、scripts/core/domain_event_stream.gd:113-140 が拒否) | NA: validate は envelope の外形だけで、runtime の内部を検査しない(:16-43)。実際の戻り値(ok:true を予想)は記録するが、不具合とはしない | 適用(公開の API で作れる場合): 重複を入れた snapshot を SaveService.save_snapshot で、固定の user:// の path に保存し、load_from_path で読む。save が拒否した場合は、その実際の code を記録し、load の側は理由つきの NA にする |\n| 重複した ID(facility) | R で適用: 施設の instance の配列で、最初の entry を複製 → false(FacilityService.restore_snapshot、scripts/facility/facility_service.gd:701-703 が拒否)。O で NA: B1 の施設の件数が実際に0のとき、複製する既存の entry が無いため(件数を記録する)。施設を建設すること、R の B1 で代用すること、製品の値を作ることはしない | NA: 上と同じ理由 | R で、published_ids と同じ方法で適用。O で NA(理由は同じ) |\n| world.bin の改ざん | NA: Dictionary の API は package を読まない | NA: 同じ | 適用: r03 の D3 の固定の規則 → CHECKSUM_MISMATCH を期待 |\n\n- 不正な入力は、B1 の deep copy と、固定の user:// の相対 path と、固定の規則だけで作る。乱数・時刻・PID を使わない(r03 の D1〜D3)。\n- 期待の結果は、上の source に基づくものとして記録する。実際の結果が期待と違う場合(たとえば、不正な入力が受理された)は、「既存の不具合の候補」として、全ての記録とともに残す。ただし、envelope の validate が runtime の内部の重複を受理することは、その API の範囲の外なので、不具合とは断定しない。\n\n3.3 各操作で記録し、検査すること\n- 前後の S/K/C 層(同じ PID の中で、完全に比べる)。拒否された場合は、変化が無いこと。\n- 全イベントの差分と、その件数。restore_snapshot と validate は0件。load_from_path の失敗は SAVE_LOAD_FAILED がちょうど1件で、X(B, ev_fail) と、r03 の正規化の後で完全一致すること。\n- 適用と NA の表を、そのまま report に入れる。fresh の whole-unit レビューが、適用の条件を判定できるようにする。\n\n3.4 試験(test_eq.py)\n- 正常の記録。\n- 拒否の場合:\n - restore と validate の架空の code\n - load の code の欠落を合格にすること\n - NA を PASS として数えること\n - O の施設の重複を、件数が0なのに適用したと記録すること\n - 拒否の前後の状態の変化を見逃すこと\n - 件数の不一致\n - envelope の validate が重複を受理したことを、製品の不具合と断定すること\n\n4. 終わり: r01 のとおり(PROGRESS.md を更新し、正式な JSON の status を blocked にし、findings を「段階 S3a 完了(失敗ではない。次は S3b)」とする)。\n" + }, + "EQ_S3B_STAGE_PLAN.txt": { + "sha256": "d14fe474ae4626719d8ff9be6cef1423f076bff0829060ded77b1520ac7bd88d", + "full_unedited": "EQ_S3B_STAGE_PLAN(P28-02-EQ 段階 S3b。EQ_S3_STAGE_PLAN r01/r02 の S3b を、実際の API に合わせて具体化する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02 は変更しない)\n\n共通\n- 最初に eq/PROGRESS.md と eq/IMPLEMENTATION.md(末尾の S4 の結合の要件を含む)を読み、S1/S2/S3a の型・path・record schema・API・notes を再利用する。再設計しない。\n- E3、既存の91件の試験の本体、失敗の履歴は、消さない。書き直さない(失敗した試験が求める修正を除く)。\n- E4/E5 の操作は、SPEC §3.3 (b) の専用の scenario の区間でだけ行う。各区間には開始と終了の記録を付ける。check_eq.py の静的な許可は、この区間と、下に列挙した操作に限る。\n- 状態は全て r02 の A の typed tree で記録する(深さの制限なし、可逆)。正規化は r03 の閉じた一覧だけを使う。\n- 各操作について、前後の S/K/C 層の tree と、全イベントの差分と件数と、scenario の中で出た signal(測定の区間とは別の記録)を記録する。\n\nE4 キャッシュの古さ(R と O。5つの経路を、この順序で行う。各経路の後の状態を、次の経路の開始の状態として記録する)\n1. 状態を変えるコマンド(通常の command queue を通す)\n - SimulationRuntime.submit_command(&\"build_facility\", {definition_id, origin, rotation})(autoload/simulation_runtime.gd:476、:305、:7717-7720)。\n - 引数は固定の規則で選ぶ。定義の一覧(mvp_content_catalog)を ID の文字の順序で、cell を (x, y, z) の辞書順で走査し、製品の公開の配置の判定で、最初に配置できる組を選ぶ。選んだ規則と結果を記録する。施設の値を作らない。配置できる組が無い場合(たとえば O の小さな世界)は、理由つきの NA にする。\n - 記録の時点: submit の直後(queue の状態、command の ID の counter)と、advance_minutes(1) を1回行った後(APPLY_COMMANDS で実行された後)。両方で、create_snapshot() と latest_snapshot の tree を記録する。\n2. tick: advance_minutes(1) を1回。直後の create_snapshot() と latest_snapshot を記録する。\n3. 直接の restore_snapshot(P)。P は、この経路の開始の時点の create_snapshot() の deep copy。\n - 直後の S が、P を規則どおりに復元したものと、正規化の後で完全一致すること。\n - SAVE_* の event は0件。\n4. load_from_path の成功\n - この経路の開始の時点の snapshot を、SaveService.save_snapshot で、固定の user:// の path(例: user://p28_eq//e4_good)に、固定の metadata で保存する。save は静的な API で、Runtime の event を出さない。\n - その path を、Runtime の load_from_path で読む。\n - 直後の状態が X(P, ev_load) と、正規化の後で完全一致すること。SAVE_LOADED はちょうど1件。\n5. 状態を変えないコマンド(製品が検証の段階で拒否するコマンド)\n - submit_command(&\"build_facility\", {definition_id: \"\"}) を submit して、advance_minutes(1) を1回行う。\n - 戻り値と、command の結果(拒否の code)を記録する。\n - 製品の状態の変化が、command の記帳(次の command の ID、処理済みの結果の記録)と tick の進行の分に限られることを、全ての path の差分で記録する。それ以外の変化があれば、事実として記録する。\n- 各経路の後に、create_snapshot() と latest_snapshot を記録する。latest_snapshot は publish(tick)の時にだけ更新される製品の仕様なので、tick を含まない経路の直後に latest_snapshot が以前の値のままであっても、それは記録する事実であって、cache の古さとは呼ばない。古さの判定は、OPT の後の版との、同じ場面での比較(compare_versions.py)で行う。\n- この段階での検査: 同じ版の2 PID の間で、5つの経路の記録が、正規化の後で一致すること(harness の決定性)。\n\nE5 所有権(R と O。4つの対象 × 入れ子の dict と配列 × 2つの向き)\n- 対象:\n - (1) create_snapshot() の戻り値\n - (2) SimulationRuntime.latest_snapshot\n - (3) snapshot_published の引数\n - (4) state_updated の引数\n - (3) と (4) は、probe の既存の接続で受け取った参照を、handler の外で保持して使う。handler の中で変更しない(他の受け手への影響を避けるため)。\n- 変更の場所(固定。R と O の両方に存在するもの):\n - 入れ子の dict: systems.runtime.id_generator.counters に、key \"__p28_eq_probe\" と値 1 を追加する。\n - 入れ子の配列: systems.runtime.domain_events.published_ids に、文字列 \"__p28_eq_probe\" を追加する。\n- 外から内:\n - 変更の直前に、内部の create_snapshot() の tree と、latest_snapshot の tree と、latest_digest の文字列を記録する。latest_digest は遅延して計算されるので、変更の前に一度読んで確定させ、その事実を記録する。\n - 変更の直後に、同じ3つを取り直して比べる。\n - 変化があれば、変わった path と値を全て記録する。\n- 内から外:\n - 返された値の deep copy を保持する。advance_minutes(1) を1回行った後に、返された値そのものが、保持した deep copy と同じであることを確かめる。\n- 予想される既存の不具合:\n - latest_snapshot と、signal の引数 (3)(4) は同じ object である(:12617-12621)。そのため、(2)〜(4) の外から内の変更は、latest_snapshot を変え、まだ計算していない digest にも影響しうる。\n - これは「既存の不具合」として、対象・向き・変わった path・値・digest への影響を全て記録する。PASS で補わない。harness による無断の変更とは区別する(どの scenario の、どの操作かを結びつける)。\n - その後の検査は、advance_minutes(1) を1回行って新しい latest_snapshot が publish された後の状態を、新しい baseline として始める。\n- (1) が deep copy であれば、影響が無いことを予想する。影響があれば、同じく事実として記録する。\n\ncheck_eq.py と試験\n- E4 と E5 の記録の形式・必須の欄・矛盾の検査を加える:\n - 経路の順序\n - 区間の連続\n - 件数(restore は0、load の成功は1)\n - X(P, ev_load)\n - 4×2×2 の全ての組の存在\n - NA の理由\n- 拒否の試験を加える:\n - 経路の欠落\n - 件数の不一致\n - 既存の aliasing を PASS として扱うこと\n - aliasing の記録の欠落\n - handler の中での変更\n - 区間の外での状態の変更\n - tick を含まない経路の latest_snapshot の据え置きを cache の古さと誤判定すること\n - NA を PASS として数えること\n\n終わり\n- engine を使わない python3 test_eq.py の全件 PASS まで直し、生出力を保存する。PROGRESS.md を更新する。正式な JSON の status を blocked にし、findings を「段階 S3b 完了(失敗ではない。次は S4)」とする。提出しない。\n- engine の起動、git への書込み、製品の変更、全回帰はしない。通常の実装上の判断は、記録して進める。\n" + }, + "EQ_S3B_STAGE_PLAN_R02.txt": { + "sha256": "9a26f47012e51ed23eb03e539fc5c4734e4d41c09ce37a21a18b4ac8a77a5f4c", + "full_unedited": "EQ_S3B_STAGE_PLAN r02(P28-02-EQ 段階 S3b。EQ_S3B_STAGE_PLAN(r01)は、そのまま有効。この r02 は、r01 の E4 の経路 1 の「引数の選び方」(施設の定義の列挙元)だけを置き換える。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02、S3 の計画 r01/r02 は変更しない)\n\n0. 訂正の理由(計画の参照の誤り。製品・仕様の変更ではない)\n- r01 は、施設の定義の一覧を mvp_content_catalog から取るとしていた。しかし scripts/data/mvp_content_catalog.gd:26-31 の DEFAULT_PATHS は人物の4種だけで、施設を含まない。そこから列挙すると一覧が空になり、「配置できる組が無い」という NA が誤って成立してしまう。\n- 施設の定義は、autoload/simulation_runtime.gd:446-447 で、FacilityCatalog の FACILITY_PATHS、INFRASTRUCTURE_FACILITY_PATHS、RESCUE_FACILITY_PATHS、ORIGINAL_FACILITY_PATHS、TRANSPORT_FACILITY_PATHS から runtime.definition_registry に登録される。preview_build_facility(:7660)も、同じ definition_registry.get_facility を使う。\n- run 7da027a85548460bb008b562a79a52ae の worker は、この誤りを指摘し、空の一覧を NA にせず blocked で返した。これは正しい判断であり、失敗ではない。\n\n1. E4 の経路 1 の引数の選び方(r01 の該当の箇条を置き換える)\n- 列挙元: R と O のそれぞれで、その PID の runtime の definition_registry.get_facility_ids()(scripts/core/definition_registry.gd:68-69。Array[StringName])。R と O の両方とも、元の実際の施設の registry から候補を取る。別の catalog、固定の ID の一覧、R の結果での O の代用は使わない。\n- 順序: 取得した ID を、文字列としての ID の順序(String(id) の昇順。Python 側の記録は Unicode の code point の順序)に並べる。registry の登録の順序は、取得した生の一覧として別に記録する。\n- cell の走査: r01 のとおり、(x, y, z) の辞書順。走査の範囲は、その版の世界の公開の寸法から、固定の規則で決め、その規則と範囲を記録する。rotation は 0 に固定する(他の値は試さない)。\n- 判定: 製品の公開の SimulationRuntime.preview_build_facility(definition_id, origin, rotation) だけを使う。ID の順序の外側のループ、cell の順序の内側のループで、最初に配置できると返った組を選ぶ。\n- 実行: 選んだ組で submit_command(&\"build_facility\", {definition_id, origin, rotation})(:476、:305、:7717-7720)を submit する。記録の時点(submit の直後と、advance_minutes(1) の後)は r01 のとおり。\n\n2. 保存する記録(R と O のそれぞれ)\n- get_facility_ids() の生の一覧(登録の順序)と、その件数。\n- 並べた後の一覧と、並べ方の規則。\n- cell の走査の規則と範囲。\n- 試した各候補(definition_id、origin、rotation)と、preview_build_facility の戻り値の全体(typed tree)。試行の件数が多い場合も、全件を記録する(省略しない)。\n- 選んだ候補と、その submit の戻り値と、command の結果。\n- 適用しなかった場合の理由。\n\n3. NA の条件\n- NA にしてよいのは、get_facility_ids() の実際の一覧が空でなく、走査の範囲の全ての組で preview_build_facility が配置できないと返した場合だけ。そのときは、上の 2 の全ての記録とともに、理由つきの NA とする。\n- 一覧が空の場合は NA にせず、registry の取得の誤りとして失敗にし、その事実を記録する。間違った列挙元や空の一覧からの NA(false NA)は禁止する。\n- NA を PASS として数えない。施設の値を作らない。この経路の外で建設しない。\n- check_eq.py に、次の拒否を加える: 列挙元が definition_registry.get_facility_ids() 以外であること、空の一覧での NA、preview の記録が無い候補の選択、試行の記録の欠落、並べ方の規則の違反、R と O で列挙元が違うこと。\n\n4. 変更しないこと\n- E4 の経路 2〜5、E5 の 4×2×2、全ての状態とイベントの typed tree での記録、既存の aliasing の不具合としての記録、S1/S2/S3a の型・path・schema・API・code の再利用、E3 と既存の91件の試験の本体と失敗の履歴(失敗した試験が求める修正を除く)、engine を使わない python3 test_eq.py の全件 PASS と生出力の保存、PROGRESS.md の更新、正式な JSON の status を blocked にし findings を「段階 S3b 完了(失敗ではない。次は S4)」とすること、提出しないこと、engine・git の書込み・製品の変更・全回帰をしないこと。いずれも r01 のとおり。\n- 通常の実装上の判断は、記録して進める。\n" + }, + "EQ_S4_STAGE_PLAN.txt": { + "sha256": "4448602b1542f003282c9572765c71046800a1e2a92e1755792f0ba39caa56d5", + "full_unedited": "EQ_S4_STAGE_PLAN(P28-02-EQ 段階 S4。最後の段階。EQ_STAGED_IMPLEMENTATION_PLAN r01/r02 の S4 を、実際の API と S1〜S3b の結合の要件に合わせて具体化する。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02、S3 の計画 r01/r02、S3b の計画 r01/r02 は変更しない)\n\n0. 共通\n- 最初に eq/PROGRESS.md と eq/IMPLEMENTATION.md を読む。特に、S2 と S3a の「S4 must ...」の全ての箇条と、末尾の「S4 binding requirements」を、S4 の要件の一覧として最初に書き出し、各要件をどのコードと試験で満たしたかを IMPLEMENTATION.md に対応表で記録する。\n- S1〜S3b の型・path・record schema・API・コード(check_eq.join_report、check_report、check_observation、check_lifecycle、strict_json、compare_versions.compare_reports など)を、そのまま使う。再設計しない。S4 が新しく作るのは eq/run_eq.py と eq/verify_eq.py と、その試験。\n- 既存の119件の試験の本体、全ての失敗の履歴(S3b の attempt 02/03/07/08 を含む)、旧 run 7da027a の指示の誤りの記録は、消さない。書き直さない(失敗した試験が求める修正を除く)。\n- 凍結した依存の API は、RootB/S4_FROZEN_DEPENDENCY_API_NOTES_R01.json(SHA 682a0d9a04978411691e9a8291b46a9ddc6eeb621d38c0f699a756e47be0084b)の要約に従う。collector(execution/p28-01/collector/collect_p28_01.py、SHA a43e1f96…)と restart_pair.py(SHA 538302ee…)は、読取専用で import して使う。複製や書き換えはしない。\n\n1. eq/run_eq.py(Root が実行する driver。SPEC §2 の argv のまま)\n1.1 --check(engine を起動しない)\n- 引数と pin を検証して、実行の計画(7つの phase の argv、環境変数、出力の path、profile の名前)を JSON で出す。process は起動しない。\n- 検証する pin: fixture の SHA(eb4f7700…)、engine の SHA(c7cccbf8…)、製品の source map の SHA(651f7036…、1407件の全ての相対 path・bytes・SHA を source_map(standard, root) で取る。件数だけにしない)、machine、EQ のファイル(6つ)の SHA、project.godot の元の bytes の SHA、設定・marker・policy の SHA。\n- inputs(readonly) で、元の manifest の SHA と、元の絶対の destination の9件を検証する。複製した manifest の root で代用しない。\n- --output の dir が既に存在すれば拒否する(上書きしない)。\n\n1.2 --run の phase(この順序で、それぞれ1回)\n- import: argv_for(engine, stage, wrapper, importing=True)。stage_gate(before, after, importing=True)。\n- parse-base、parse-wrapper: parse_argv(engine, stage, target) の --check-only。stage_gate(before, after)。\n- R-A、R-B、O-A、O-B: S1〜S3b で決まった R と O の起動の規則で、測定の wrapper を headless で起動する。\n- 各 phase は run_private_engine(standard, outer, command, folder, environment, stage, public, name) で行う。public は project.godot の元の bytes、name は startup の profile の名前、folder は未作成の新しい dir。戻り値の owned row の全体を記録する。\n- guard: parent の initialize の前に有効になること。startup と runtime の profile は、phase ごとに新しく一意の名前にする。環境変数 THE_TREE_PACK_PROFILE_NAME / EXPECTED / REPORT と、role(R/O)、fixture の path と SHA を結びつける。guard_gate(value, runtime: Path, name) の name は runtime の profile の名前。\n- stage_gate と guard_gate は、成功で None、失敗で例外。戻り値を bool として扱わない(試験で拒否する)。\n- profile_files(directory) は、存在しない dir で空の dict を返すが、それを fresh であることや、証拠の保存の成功の証明にしない。fresh であることは guard の受領で、保存の成功は下の 1.3 の複製と inventory で証明する。\n- 各 phase で、collector の raw3(stdout、stderr、exit)と owned5 の受領、実際の PID と開始・終了の時刻、strict diagnostic(collector の規則のまま)を保存する。\n- report の role(R/O)と、native の phase(R-A など)と、実際の PID を、driver が明示的に結びつけて記録する(role を phase 名から推測しない)。\n- finally: 既定の player の設定・source・project.godot・guard・PID の後始末を、collector の既存の処理のまま保持し、後始末の結果(残った process 0、残った profile の扱い)を記録する。\n\n1.3 証拠の複製と結合(owned の process の終了の後)\n- R-A〜O-B の各 phase で、private profile の全ての証拠を複製し、全件の bytes と SHA を記録する: report(stdout の P28_02_EQ_REPORT= の1行)、lifecycle.json(measurement、e3、e3_b1、e45 を含む)、audio-close.json、events.json、observation、全ての e3-NN.json(00〜17)、全ての e45-NN.json(00〜20)、package の証拠。restart.copy_states は参考とし、EQ 自身の正確な名前の inventory で結びつける。欠けた・余分な・変わったファイルは拒否する。\n- lifecycle の inventory が自分の hash と audio の受領を含まないことに従い、lifecycle.json と audio-close.json の SHA を、それぞれ独立に結びつける。lifecycle か audio が欠けている、または error を含む場合は、stdout の report があっても失敗にする。\n- raw の JSON は strict_json で読む。各 phase で:\n - check_observation(raw の全 bytes と SHA の witness)\n - check_lifecycle(guard の受領、準備と後始末、S3a と S3b の分)\n - check_report(raw, measurement=lifecycle.measurement, e3_evidence=…, b1_record=…) に lifecycle.e45 を渡す\n - report.scenarios が E3 の18件 + E4/E5 の21件(E4 の5件 + E5 の16件)= 39件で、順序と区間の連続が正しいこと\n- check_eq.join_report で raw を結合してから、compare_versions.compare_reports を呼ぶ。raw と、結合した出力と、join_facts の sidecar と proof と、checker の結果を、別々のファイルとして、それぞれの SHA とともに保持する。\n- 同じ版の決定性: R-A と R-B、O-A と O-B を、それぞれ別に比べ、SPEC §3.2 の版の間の比較の差が0であることを確かめる。R と O を互いに比べない。\n- 既存の不具合(latest_snapshot の aliasing、cached_digest_aliasing を含む)は、その結果のまま bundle に入れる。PASS に補わない。\n- 全ての複製と結合の後に、bundle の manifest(全ファイルの相対 path・bytes・SHA)を書き、最後に seal(manifest の SHA)を書く。seal の後に書き込みをしない。\n\n1.4 bundle の配置と失敗\n- 7つの phase と 1.3 の全ての検査が成功した場合だけ、bundle を --output の下に作る。Root がそれを $BUILD_OUTPUT_DIR/p28-02-eq-evidence に、bytes をそのまま置く(verify_eq.py は場所を変えない)。\n- 失敗した場合は、bundle を作らず、raw と失敗の記録(どの phase の、どの検査か)を --output に残し、0 以外の終了コードで終わる。失敗を成功に書き換えない。\n- 表記: この記録は「S_eq の native」であって、Q で測ったものではない。source・設定・入力・marker・policy・engine・環境・EQ の同一性が証明された場合だけ、Q_eq での再利用ができる(SPEC §5)。bundle にこの区別を書く。\n\n2. eq/verify_eq.py(正式の validation p28-02-eq-native-verify)\n- --project-root . で、$BUILD_OUTPUT_DIR/p28-02-eq-evidence の bundle を読む。BUILD_OUTPUT_DIR が無い、bundle が無い、seal が無い場合は失敗にする。\n- seal と manifest を検証し、欠けた・余分な・変わったファイルを拒否する。\n- 結合した出力を信用せず、raw から 1.3 の全ての検査(strict_json、check_observation、check_lifecycle、check_report、join_report、compare_reports、39件、R と O の別々の決定性、既存の不具合の保持)をやり直し、bundle の記録と一致することを確かめる。\n- pin(fixture、engine、source map 1407 の全件、machine、EQ のファイルの SHA、project・設定・marker・policy)が、--project-root の実際のファイルと一致することを確かめる。EQ のファイルの SHA は、検証の時点の W の実際のファイルと比べる。\n- 7つの phase の全てで、raw3、owned5、PID の開始と終了、strict diagnostic、guard、後始末(残り0)がそろっていることを確かめる。\n- 結果を1つの JSON で出し、成功だけ終了コード 0。\n\n3. 試験(test_eq.py に追加。engine を使わない)\n- bundle の正常(合成の bytes で作った bundle が verify の論理で通ること。これは native の証明ではないと試験の名前と出力に書く)。\n- 拒否:\n - bundle・seal・manifest の欠落、余分なファイル、変わったファイル、seal の後の書込み\n - lifecycle・audio・e3-NN・e45-NN の欠落、error を含む lifecycle\n - 39件でない scenario、順序の違い、E4/E5 の21件の欠落\n - guard_gate・stage_gate の戻り値の bool としての扱い\n - 存在しない profile の空の dict を fresh や保存の成功とすること\n - 複製した manifest の root での代用、destination の9件の不一致\n - startup と runtime の profile の名前の取り違え、profile の再利用\n - role と phase と PID の結びつきの欠落や矛盾\n - raw3・owned5・PID の開始と終了の欠落、strict diagnostic の違反、後始末の残り\n - R と O の交差の比較、決定性の差が0でないのに合格にすること\n - join の前の compare、raw と結合した出力の混同、sidecar の欠落\n - 既存の不具合を PASS にすること、aliasing の記録の欠落\n - source map の件数だけの検査、1407件の1つの不一致、pin の不一致\n - Q で測ったという表記\n - --output の既存の dir への上書き、失敗の時の bundle の作成\n- 既存の119件を含めて、python3 -B test_eq.py の全件 PASS まで直し、生出力と SHA を保存する。失敗した試行の生出力も残す。\n\n4. 終わり(正式な提出)\n- PROGRESS.md と IMPLEMENTATION.md(S4 の要件の対応表を含む)を更新する。\n- 局所の全件 PASS を確かめた後、正式な JSON で提出する(status は blocked にしない)。提出は局所の unit の証拠であり、native の実行・受け入れた S・Q での測定・製品の PASS とは表記しない。6条件は、Root の native と両方の validation と fresh の独立した Opus のレビューまで保留のまま。\n- worker は、engine の起動、run_eq.py --run の実行、git への書込み、製品の変更、全回帰をしない。正式の validation(bundle の無い状態の verify_eq.py を含む)を、試しに実行して失敗させない。commit と gate は Runner が通常どおり行う。\n- 通常の実装上の判断は、記録して進める。\n\n5. 提出の後の順序(Root と Runner。worker の範囲の外)\n- Root が、凍結した S で native の7つの phase(import、parse-base、parse-wrapper、R-A、R-B、O-A、O-B)を run_eq.py --run で1回行い、成功した bundle を $BUILD_OUTPUT_DIR/p28-02-eq-evidence に置く。\n- 両方の validation(p28-02-eq-unit、p28-02-eq-native-verify)。\n- fresh の、別の Opus のセッションによる、6条件の全てのレビュー。\n- 通常の prepare、候補の資格の確認、承認、integration、final。その後に OPT と whole-unit の gate。\n- 原本の 23/88・4/30、原本の条件、課金、権限、900秒は変えない。\n" + }, + "EQ_S4_STAGE_PLAN_R02.txt": { + "sha256": "f736fb819c8d0ee6e94822896aa995e448a203ba8395743838f1cbf2a6c72660", + "full_unedited": "EQ_S4_STAGE_PLAN r02(P28-02-EQ 段階 S4。EQ_S4_STAGE_PLAN(r01)は、ここで置き換える箇所を除いて、そのまま有効。この r02 は、r01 の §0 の import の範囲、§1.2 の raw3 の名前、実際の API の引数、正式な提出の status、validation の書込みの場所だけを、実際の source に合わせて訂正し、具体化する。S4 の範囲(run_eq.py、verify_eq.py、bundle の正常と拒否の unit、局所の全件 PASS、正式な提出)は小さくしない。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、段階の計画 r01/r02、S3 の計画 r01/r02、S3b の計画 r01/r02 は変更しない)\n\n1. import の範囲(r01 §0 の4つ目の箇条を置き換える)\n- 凍結した EQ SPEC §1 の読取の閉包(RESTART D1 の6つ + DIAG の5つ + EQ 自身)の中のものだけを使う。閉包と権限は広げない。\n- collector(execution/p28-01/collector/collect_p28_01.py、SHA a43e1f963ef8505ddd5acf8bf747d9bfac22a028cbb805c0b964ee11b9b40a14)は、閉包の中で、読取専用で import する。\n- restart_pair.py(SHA 538302ee…)は RESTART の task の所有物で、EQ の閉包に入らない。import しない。copy_states は、読んで参考にするだけとする。証拠の複製と inventory は、EQ が自分のコードとして eq/ の中に実装する(r01 §1.3 の正確な名前の一覧で)。\n- check_eq.py の静的な検査と試験に、restart_pair の import と、閉包の外の import を拒否するものを加える。\n\n2. raw3 の名前(r01 §1.2 の「raw3(stdout、stderr、exit)」を置き換える)\n- raw3 は、collector の run_engine(collect_p28_01.py:217、:225)が実際に作る3つのファイル: stdout.log、stderr.log、engine-native.log。engine-native.log(--log-file、--verbose)を落とさない。\n- 終了コードは raw3 ではない。owned の受領(process.json など、owned5 の中)にある実際の値を、そこから読んで記録し、結びつける。\n- 各 phase で、raw3 の3つのファイルの存在・bytes・SHA と、owned5 の5つの受領を、全て要求する。どれかが欠ければ失敗にする。試験で、engine-native.log の欠落と、終了コードを raw3 から読もうとすることを拒否する。\n\n3. 実際の API の引数(r01 §1.3 と §2 を具体化する)\n- check_report(raw, measurement=None, e3_evidence=None, b1_record=None, e45_evidence=None): measurement に lifecycle.measurement、e3_evidence に lifecycle.e3、b1_record に lifecycle.e3_b1、e45_evidence に lifecycle.e45 を渡す。どれかを None のまま呼ばない。\n- check_lifecycle(raw, lifecycle, guard): guard は、その phase の guard の受領。\n- 各 R/O の phase の private profile の証拠の正確な名前の一覧: checkpoint-00.json〜checkpoint-30.json(31件)、observation-00.json〜observation-30.json(31件)、e3-00.json〜e3-17.json(18件)、e45-00.json〜e45-20.json(21件)、events.json、report.json、lifecycle.json、audio-close.json。これに package の証拠を加える(S3a/S3b で決まった名前のまま)。この一覧と比べて、欠けた・余分な・変わったファイルを拒否する。\n\n4. 正式な提出の status(r01 §4 を具体化する)\n- Runner は、worker の JSON の status が \"submitted\" であることを要求する(core.py:1015)。schema には \"pass\" もあるが、実装の run では submitted でないと止まる。S4 の最後の JSON の status は、ちょうど \"submitted\" にする。\"pass\" や \"blocked\" にしない。\n- commit の欄は、base の 2549cf7d6992560b850bbd11934e3c14b39a1988 とする。worker は git に書き込まない。通常の git commit は Runner.submit が行う。\n\n5. validation の書込みの場所(r01 §2 と §3 を具体化する)\n- 正式の validation は、checkout を読取専用にして実行される(core.py:1064 の writable=())。BUILD_OUTPUT_DIR は、Runner が runtime の build の領域に割り当てる(core.py:827)。\n- test_eq.py(p28-02-eq-unit)の bundle の合成の試験は、一時の生成物を、その割り当てられた BUILD_OUTPUT_DIR の下(無い場合は tempfile.gettempdir() の下)の新しい dir にだけ作る。source の tree(eq/ を含む)に書き込む設計にしない。\n- verify_eq.py は、bundle を読むだけで、checkout に書き込まない。結果は stdout の JSON で出す。\n- 試験で、checkout の中への書込みを検出して拒否する(たとえば、合成の bundle の dir が source の tree の中にあること)。\n- 環境・権限・writable の設定は変えない。\n\n6. 変更しないこと\n- r01 のそれ以外の全て: 既存の「S4 must」の要件の対応表、7つの phase、guard と profile の規則、gate の None/例外、profile_files の扱い、全証拠の複製と SHA、strict_json と check_observation と check_lifecycle と check_report、39件の scenario、join_report の後の compare_reports、raw と結合した出力と sidecar の分離、R-A/R-B と O-A/O-B の別々の決定性、既存の不具合の保持、source map 1407 と全ての pin、finally の後始末、成功の時だけの seal、「S_eq の native であって Q の測定ではない」の表記、失敗の時の bundle の不作成、verify_eq.py の raw からの再計算、bundle の正常と拒否の試験、119件の本体と全ての失敗の履歴の保持、局所の全件 PASS と生出力の保存。\n- worker は、engine の起動、run_eq.py --run の実行、正式の validation の試しの実行、git への書込み、製品の変更、全回帰をしない。\n- 提出の後の順序(Root の正確な S の native の7つの phase、bundle の配置、両方の validation、fresh の別の Opus による6条件の全てのレビュー、通常の prepare・資格・承認・integration・final、その後の OPT と whole-unit)と、原本の 23/88・4/30・原本の条件・課金・権限・900秒は変えない。\n- 通常の実装上の判断は、記録して進める。\n" + } + }, + "effective_S4_correction": "EQ_S4_STAGE_PLAN_R02.txt replaces S4 import/raw3/argument/protocol/validation-writable details only. restart_pair is read-only reference, never imported; raw3 stdout/stderr/engine-native; worker status submitted and commit base. All S4 r01 other requirements and prior retained stages remain effective", + "actual_Opus_response_origin": "Desktop response344 to request343; the unmodified actual decision reason labels previous message342", + "actual_frozen_dependency_API_notes": { + "sha256": "682a0d9a04978411691e9a8291b46a9ddc6eeb621d38c0f699a756e47be0084b", + "full_unedited": "{\n \"at_jst\": \"2026-10-21T09:22:58.012059+09:00\",\n \"scope\": \"Read-only frozen dependency API preparation for actual Opus S4 plan; no live worker inspection, tests, engine, edits, or acceptance credit\",\n \"sources\": [\n {\n \"path\": \"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/docs/plans/original-completion-2026-10-02/execution/p28-01/collector/collect_p28_01.py\",\n \"bytes\": 23306,\n \"sha256\": \"a43e1f963ef8505ddd5acf8bf747d9bfac22a028cbb805c0b964ee11b9b40a14\"\n },\n {\n \"path\": \"/Users/korizatou114/Projects/とりにく工房ゲーム制作部/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/restart_pair.py\",\n \"bytes\": 17486,\n \"sha256\": \"538302eea55b033157446363c0787ea2dda5fbd31d4181ea5e39824609560d31\"\n },\n {\n \"path\": \"/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-01-perf-baseline/.runtime/P28-01-COLLECTOR/build/p28-01-readonly/run-r02/profile_guard.gd\",\n \"bytes\": 2276,\n \"sha256\": \"597696c705cc8f0e79a35265ca3ef8df55f7fc3c4e0e5a2ce9a4e20e29e29a6f\"\n }\n ],\n \"APIs\": {\n \"inputs(readonly)\": \"Verifies fixed manifest SHA and original absolute destinations, returns manifest_sha256/files. Do not substitute a copied manifest root.\",\n \"source_map(standard,root)\": \"Full relative path to bytes/sha256 map, not count-only.\",\n \"argv_for(engine,stage,wrapper,importing=True)\": \"Import argv; parse_argv(engine,stage,target) gives check-only argv. Measured EQ wrapper argv is explicitly headless.\",\n \"run_private_engine(standard,outer,command,folder,environment,stage,public,name)\": \"Returns owned row dict. public is original project.godot bytes; name is startup profile name. Folder must not yet exist; startup evidence is written beside it. finally restores project bytes.\",\n \"stage_gate(before,after,importing=False)\": \"Raises on failure, returns None on success; import allows only corresponding new gd.uid/import support files.\",\n \"guard_gate(value,runtime,name)\": \"Raises on failure, returns None on success. runtime is Path, name is runtime profile name, not startup profile name; binds exact actual user dir/fresh/5 conditions.\",\n \"profile_files(directory)\": \"Complete relative file SHA/byte inventory, rejects symlinks. Nonexistent gives empty dict but is not proof of freshness or successful evidence export.\",\n \"restart.copy_states(out,row)\": \"Reference for copying private typed evidence after owned process end; EQ must bind its own exact evidence names/inventory.\"\n },\n \"binding_requirements\": [\n \"Seven phases import,parse-base,parse-wrapper,R-A,R-B,O-A,O-B; report role R/O is distinct from native phase and actual PID; bind explicitly.\",\n \"Preserve raw3 and owned5 receipts, actual captured PID lifecycle, strict diagnostics, original project/source/default-player preservation and finally cleanup.\",\n \"Guard activates before parent initialize. Each startup and runtime profile is fresh and unique. Bind env THE_TREE_PACK_PROFILE_NAME/EXPECTED/REPORT plus role/fixture path/SHA.\",\n \"After owned end copy all profile evidence and bind checkpoint/observation/event/scenario/lifecycle/audio to raw report SHA. Seal after copy; reject missing,extra,changed evidence.\",\n \"Only actual successful bundle goes to BUILD_OUTPUT_DIR/p28-02-eq-evidence before both registered unit and native-verify. Exact-S native is not Q measurement unless source/settings/input/marker/policy/engine/environment/EQ identity proves reuse.\",\n \"All original conditions and fresh independent Opus all6 review and normal integration/final remain.\"\n ],\n \"original_credit\": 0\n}\n" + }, + "read_only_clarifications": { + "EQ_S_TIMING_CLARIFICATION.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_S_TIMING_CLARIFICATION.txt", + "bytes": 5792, + "sha256": "25d323fd562d29e80782b6f075fc7a0e8b49457a6c4fbd7c30e74b31a6b6a126" + }, + "EQ_S_TIMING_CLARIFICATION_R02.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_S_TIMING_CLARIFICATION_R02.txt", + "bytes": 7347, + "sha256": "777accdd652f85db6b9014d85e3c8b3b60ca94b20768e6173b36bc769d360fd9" + }, + "EQ_ENVIRONMENT_FIELDS_CLARIFICATION_R03.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-staged-readonly-r04/EQ_ENVIRONMENT_FIELDS_CLARIFICATION_R03.txt", + "bytes": 7637, + "sha256": "12b27f984ef5843d98327200ad261dccaf64968402192b08ad55b15ed5454ea2" + } + }, + "full_frozen_references_in_W": { + "docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPUS_D2_SCOPE_CLARIFICATION.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPUS_D2_SCOPE_CLARIFICATION.txt", + "bytes": 5598, + "sha256": "5775e7b512d9e90dbcfbcb181f5b64dc0fa8207e0947c0a4a6a5c9195565f9bd" + }, + "docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPUS_STARTUP_LIFECYCLE_CLARIFICATION.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPUS_STARTUP_LIFECYCLE_CLARIFICATION.txt", + "bytes": 5996, + "sha256": "967aebf27ff412f7a16ce771ef7d68abf8cfde0bb76ed19cf6dbf2817ca7acc6" + }, + "docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPT_CONTRACT_T1.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/references/OPT_CONTRACT_T1.md", + "bytes": 13952, + "sha256": "ad9f3d76f3500b39263fb898d7c64588b4b47c9e11b456f938195261fd054d16" + }, + "docs/plans/original-completion-2026-10-02/execution/p28-02/eq/TASK_INSTRUCTIONS.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/TASK_INSTRUCTIONS.md", + "bytes": 2961, + "sha256": "f9937c3c7dff5a25ada453365d26c87fecf009d29518724f0c1e67d2b18afff3" + }, + "docs/plans/original-completion-2026-10-02/execution/p28-01/restart/SPEC_CLARIFICATION_01.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/SPEC_CLARIFICATION_01.md", + "bytes": 3613, + "sha256": "4aa50206f662e2939824aa8da2e9e330956d64061f6244e0c3e0244452978920" + }, + "docs/plans/original-completion-2026-10-02/execution/p28-01/restart/SPEC_CLARIFICATION_02.md": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/SPEC_CLARIFICATION_02.md", + "bytes": 12278, + "sha256": "b4ab43445a818fd01068a6c948beffff6d9dee15f8276f5a20aabaf0a3c0640a" + } + }, + "original_credit": 0, + "original_denominator": [ + 30, + 88 + ] + }, + "current_stage_plan_r03": { + "full_unedited": "EQ_S4_STAGE_PLAN r03(P28-02-EQ 段階 S4 の完了。EQ_S4_STAGE_PLAN r01 と r02 は、全てそのまま有効。この r03 は、run 20dc4135cc3041dbb82fcc2b2a6b0cbe(900秒の期限で exit 124)で保持された実装を引き継いで、正式な submitted まで閉じるための残りの作業だけを決める。S4 の範囲は小さくしない。SPEC、TASK、6条件、eq/references、eq/registration、補足 r01/r02/r03、全ての段階の計画は変更しない)\n\n0. 引き継ぐもの(再実装しない、再監査しない)\n- W の中の現在の70件のファイル(RootB/retained-s4-20dc413-r01、RETURN の SHA a2c0d5ffd42b67ef340d5624dd299e294b867168bd1270933aec458a9cde1dc5 と一致するもの)。実装済みの run_eq.py と verify_eq.py、現在の134件の試験。\n- 既存の119件の試験の本体と、全ての unit の生出力(S4 の attempt 01 の構文、02 の追加の unit、04 の recompute の不一致の失敗、S4_SUPPLEMENTARY の作成の assert の失敗を含む)。消さない、書き直さない。\n- attempt 05 の 132件の PASS(194.460秒、embedded exit 0)は、その版だけの事実。その後に2件が加わり、attempt 06 は出力なしで期限に達した。現在の134件の PASS は、まだ証明されていない。134件が通ったとは書かない。\n\n1. medium の修正(必須)\n- eq/run_eq.py:257 と eq/verify_eq.py:144 は、check.check_probe(...) の戻り値を捨てている。check_probe は例外ではなく {ok, errors} を返す(eq/check_eq.py:384)。\n- 両方の箇所を、static = check.check_probe(...) にして、require(static['ok'], ) で拒否するように直す。戻り値を使わない他の check の呼出しが無いかを、run_eq.py と verify_eq.py の中だけで確かめ、同じ形のものがあれば同じく直して記録する。\n- 拒否の試験を加える: check_probe が {ok: false, errors: [...]} を返すとき、run_eq.py の driver(--check と、--run の probe の検査の段階)と verify_eq.py の両方が拒否すること。ok: true のときに通ること。\n\n2. 残りの文書と context\n- PROGRESS.md と IMPLEMENTATION.md を S4 の内容に更新する(今は S3b の記述のまま)。r01 §0 の「S4 must」の要件と、末尾の S4 binding requirements の全ての項目について、満たしたコードと試験の対応表を書く。r02 の訂正(collector だけの読取専用の import、restart_pair を import しない、raw3 の正確な名前、exit を owned の受領から読む、check_report と check_lifecycle の引数、証拠の名前の一覧、validation の書込みの場所)を、どのコードで満たしたかも書く。\n- S4_SUPPLEMENTARY.json: plan の全文を手で再構築しない。Root が同じ W の runtime に、元の bytes の読取専用の JSON として置いた r09 の ACTUAL_OPUS_TASK_CONTEXT.json(RootB/eq-staged-s4-owner-run-input-r09/ACTUAL_OPUS_TASK_CONTEXT.json と同じ bytes。W の中の path は Root の packet が示す)を読み込み、その内容を変えずに、1つの key actual_commander_context として保存する。元のファイルの SHA と、各 plan の SHA が一致することを確かめて記録する。この r03 と RUN r03 は、Root がその後に追加で配置するものを、同じ方法で保存する。\n- 以前の手での再構築の assert の失敗は、失敗の記録として残す。\n\n3. 時間の配分(900秒の期限は変えない)\n- 全件の unit は約200秒かかる(attempt 05 で 194.460秒)。修正の確認は、関係する試験の class だけを指定した部分の実行(python3 -B test_eq.py ...)で行い、その生出力も保存する。\n- 全件の実行は、全ての修正と追加の後に、最後に1回だけ行う。開始は、期限まで少なくとも300秒が残っている時点までとする。不具合の修正が必要になった場合は、記録して、関係する部分の再確認と、もう1回の全件の実行を行ってよい。\n- 時間が足りない場合は、それまでの成果と生出力を残して、通常の blocked で返す。全件の PASS を推定で書かない。\n\n4. 最終の確認と提出\n- 最後の全件の実行は、134件 + この r03 で加えた試験の全て。全件 PASS の生出力と SHA と件数と時間を、UNIT_OUTPUT.txt と、新しい attempt のファイルに保存する。\n- 正式な JSON: status はちょうど \"submitted\"、commit は 2549cf7d6992560b850bbd11934e3c14b39a1988。局所の unit の証拠であり、native の実行・受け入れた S・Q での測定・製品の PASS とは表記しない。\n- worker は、engine の起動、run_eq.py --run の実行、正式の validation の試しの実行、git への書込み、製品の変更、全回帰をしない。API の fallback は使わない(設定のまま)。\n- 通常の実装上の判断は、記録して進める。\n\n5. 提出の後(worker の範囲の外。変更しない)\n- Root の正確な S の native の7つの phase → bundle の配置 → 両方の validation → fresh の独立した Opus による6条件の全てのレビュー → 通常の資格・承認・integration・final → OPT と whole-unit。\n- 原本の 23/88・4/30 への加算は0。原本の条件・課金・権限・900秒は変えない。\n", + "sha256": "6c1ca5dbed18ddb355b285fa85e0d80fd83d7f56e2a79aac3d07664456bd7a63" + }, + "current_run_decision_r03": { + "action": "run", + "task_id": "P28-02-EQ", + "reason": "Use only after Root verifies through the normal gates: repair_ready, repairs 9, no S submitted, no active run, all 70 retained files present unchanged in the W (RETURN SHA a2c0d5ffd42b67ef340d5624dd299e294b867168bd1270933aec458a9cde1dc5), and the r09 ACTUAL_OPUS_TASK_CONTEXT.json placed read-only with its original bytes. Run repair 9 of P28-02-EQ once on the same W from base 2549cf7d6992560b850bbd11934e3c14b39a1988 with the single worker codex gpt-6-astra, finishing stage S4 on the retained implementation as defined in EQ_S4_STAGE_PLAN_R03.txt, with EQ_S4_STAGE_PLAN.txt and EQ_S4_STAGE_PLAN_R02.txt still in force. Do not reimplement, re-audit or reduce S4 to a smaller deliverable. Remaining work, all in this one run: (1) fix the medium false PASS at run_eq.py:257 and verify_eq.py:144 to static = check.check_probe(...) and require(static['ok'], message with all errors), fix any other ignored check return in those two files the same way, and add rejection tests proving that both the driver and the verifier reject ok:false and accept ok:true; (2) add any remaining S4 tests; (3) update PROGRESS.md and IMPLEMENTATION.md to S4, with the requirement-to-code table covering every 'S4 must' item, the S4 binding requirements and the r02 corrections; (4) write S4_SUPPLEMENTARY.json by loading Root's read-only r09 ACTUAL_OPUS_TASK_CONTEXT.json, plus this r03 plan and decision as Root places them, without hand reconstruction, recording and checking the source and per-plan SHAs, and keep the earlier assert failure; (5) check fixes with targeted class runs, saving their raw, then run the full python3 -B test_eq.py once at the end over all 134 tests plus every test added in r03, starting with at least 300 seconds left. Attempt 05's 132 PASS covers that version only, so the final full PASS must include every later test. A further fix with related rechecks and one more full run is allowed if recorded. If time runs short, return a normal blocked status with all raw kept, and never claim an unproven PASS. (6) Submit the formal JSON with status exactly 'submitted' and commit 2549cf7d6992560b850bbd11934e3c14b39a1988, as local unit evidence only, not native, accepted S, Q measurement or product PASS. Keep the 119 earlier test bodies, all raw outputs and failures, every S4 r01 and r02 binding and raw recomputation, the 6 conditions and both validations. No engine, no run_eq.py --run, no trial formal validation, no git write, no product change, no full regression, and no API fallback. SPEC, TASK, eq/references and eq/registration stay unchanged. Ordinary implementation choices are recorded without stopping; block only for undecided matters affecting original product spec, values, permissions, billing or original acceptance. After submission: Root native on the exact S in 7 phases, the bundle at $BUILD_OUTPUT_DIR/p28-02-eq-evidence, both validations, a fresh independent Opus review of all 6 conditions, then the normal qualification, approval, integration and final, then the OPT and whole-unit gates. No original credit (23/88, 4/30); the 900-second timeout and permissions are unchanged. Quota fallback only on structured provider quota, once, same role, Antigravity claude-opus-5-5-high; any other failure is blocked. Decided by Claude Opus 5.5 in the Desktop control session (message 346); not a CLI commander result." + }, + "source_pins": { + "PRIOR_ACTUAL_OPUS_CONTEXT_R09.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-s4-retained-r10/PRIOR_ACTUAL_OPUS_CONTEXT_R09.json", + "bytes": 92871, + "sha256": "c3beadcc6e9e4b144bd1449d082a335948833dbf37351f9f3e0b0e7de5425c1e" + }, + "RETAINED_S4_RETURN.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-s4-retained-r10/RETAINED_S4_RETURN.json", + "bytes": 60561, + "sha256": "a2c0d5ffd42b67ef340d5624dd299e294b867168bd1270933aec458a9cde1dc5" + }, + "ROOT_S4_TIMEOUT_JOIN.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-s4-retained-r10/ROOT_S4_TIMEOUT_JOIN.json", + "bytes": 9703, + "sha256": "945fec6bcfa431d794ac74513219cce8eab8dccade517c6a6faeb391f86e05d7" + }, + "EQ_S4_STAGE_PLAN_R03.txt": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-s4-retained-r10/EQ_S4_STAGE_PLAN_R03.txt", + "bytes": 5501, + "sha256": "6c1ca5dbed18ddb355b285fa85e0d80fd83d7f56e2a79aac3d07664456bd7a63" + }, + "DESKTOP_EQ_S4_RUN_DECISION_R03.json": { + "path": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/.runtime/P28-02-EQ/build/eq-s4-retained-r10/DESKTOP_EQ_S4_RUN_DECISION_R03.json", + "bytes": 3398, + "sha256": "c854a9b0f232ecce9985bcf1988caba886e4b6b484631e00db1bc4d51a28098c" + } + }, + "verified_prior_plan_sha256": { + "EQ_STAGED_IMPLEMENTATION_PLAN.txt": "eb7b4831e2164c6fc983fa6f9825e7f3e2993b4c0ebf2f90aac8ad10662666d2", + "EQ_STAGED_IMPLEMENTATION_PLAN_R02.txt": "128f42f18e168e9299995296ac7ad119f47d1647799d472663282e47e8ac9fdd", + "EQ_S3_STAGE_PLAN.txt": "ecbfb00691017fbd35027df8fa9ca6f82c761a5a3389568fe44b1babcfca308a", + "EQ_S3_STAGE_PLAN_R02.txt": "566e3ad98f9d47136ff4d4932f81c0a7f9fc96321a6f08ba944a9f1e736e6caa", + "EQ_S3B_STAGE_PLAN.txt": "d14fe474ae4626719d8ff9be6cef1423f076bff0829060ded77b1520ac7bd88d", + "EQ_S3B_STAGE_PLAN_R02.txt": "9a26f47012e51ed23eb03e539fc5c4734e4d41c09ce37a21a18b4ac8a77a5f4c", + "EQ_S4_STAGE_PLAN.txt": "4448602b1542f003282c9572765c71046800a1e2a92e1755792f0ba39caa56d5", + "EQ_S4_STAGE_PLAN_R02.txt": "f736fb819c8d0ee6e94822896aa995e448a203ba8395743838f1cbf2a6c72660" + }, + "verified_api_notes_sha256": "682a0d9a04978411691e9a8291b46a9ddc6eeb621d38c0f699a756e47be0084b", + "retained_unchanged_sha256": { + "S2_SUPPLEMENTARY.json": "26f23bd8650a2495fd93f4364cbb17cc34f9eb1568758d406bec12ae2dab83a7", + "S3A_SUPPLEMENTARY.json": "9e9d420b01a0030919d2e49245e975a81bf3f561a7fa9fdf7cdc1efb8f02560e", + "S3B_SUPPLEMENTARY.json": "ec89b263b3a94ee3d4c2e6946c1f781138bbab822bbdd77f84f84b250064fc9b", + "SPEC.md": "3791ccdcb87e8d71fe9205e1e692ebca9e0f974ea3b5fbc4fbb3943882131f1c", + "TASK_INSTRUCTIONS.md": "f9937c3c7dff5a25ada453365d26c87fecf009d29518724f0c1e67d2b18afff3", + "UNIT_OUTPUT_ATTEMPT_01.sha256": "eed78af7775a79838e65ea3cb07e9fe09822d2d7a23007f294cbf0a0c98d1c7c", + "UNIT_OUTPUT_ATTEMPT_01.txt": "307486177b76602cbe68acae24c9560d501b3b866136d8e69802ec24c28e8be8", + "UNIT_OUTPUT_ATTEMPT_02.sha256": "1de0c0052e66cc60668690bf43e29eb01808afd023525e517ba94beaab0db669", + "UNIT_OUTPUT_ATTEMPT_02.txt": "07144a7f1941162227f54fefd1961ed0f209e97282432723bbda534079582e4e", + "UNIT_OUTPUT_S1_FINAL.sha256": "91d9d408ed8d012f38ff892fa6712d129f4849d0ce0b579eaeb7cb1a3f84b704", + "UNIT_OUTPUT_S1_FINAL.txt": "cdca0cdd551ce76c6100c4dd90e04559551f9d88c054a19a2bc6a77e6572ae15", + "UNIT_OUTPUT_S2_ATTEMPT_01.sha256": "579254585137adf932f5e4a0eaa2b0ecd67d275ece6c7199bdafbee4b48f4f5d", + "UNIT_OUTPUT_S2_ATTEMPT_01.txt": "25953dfc5f8bc3759ae66f6403b162100fb0217c4476f308616b8ab78a2cc67e", + "UNIT_OUTPUT_S2_ATTEMPT_02.sha256": "f4094cc3a8924b79316f473b8b4027a4743036d9d9cf8b2ad0c492ff7b581756", + "UNIT_OUTPUT_S2_ATTEMPT_02.txt": "e26c986dda41b83143723e4c1c5b2ff1051a36b9a947b319341a2239cc3188de", + "UNIT_OUTPUT_S2_ATTEMPT_03.sha256": "d8f8f7a9be6b2fb1618a1ff03f9af5aa0e397373c5e8f9716dc47befa6e3bb83", + "UNIT_OUTPUT_S2_ATTEMPT_03.txt": "9d323abda9bfffa02faf3a9d5cb56aa87e647017c991eb55b4807cf734386698", + "UNIT_OUTPUT_S3A_ATTEMPT_01.sha256": "303396536b67929fca0fcb4617578bc546c4f65a674e5dcd2b485bb27c060082", + "UNIT_OUTPUT_S3A_ATTEMPT_01.txt": "5cf84b792b5f87cd4183f41cf3a846962a53dc0aa33049c3c55f290356584641", + "UNIT_OUTPUT_S3A_ATTEMPT_02.sha256": "76d72513d22720cb0c6fd2bb43ac5000b80144a680a64f635276de8fca47ca97", + "UNIT_OUTPUT_S3A_ATTEMPT_02.txt": "000152e51d23db3d4397583b3f4540f5ed0ae469010c993fa1d122fd51537431", + "UNIT_OUTPUT_S3A_ATTEMPT_03.sha256": "9625ff44edb36f93ffac168208b148f7f49b247bc4f641d2b35e7c03f4f10ce0", + "UNIT_OUTPUT_S3A_ATTEMPT_03.txt": "7c14e8ecf4540e412467408cad267d53358940c86f87a0c8e519b305153f3cb8", + "UNIT_OUTPUT_S3A_ATTEMPT_04.sha256": "caab1a3e97878fd0c273e818bc3cf481f0f5f5d3def557da2c5c51981b6dbd0f", + "UNIT_OUTPUT_S3A_ATTEMPT_04.txt": "02221ae41e5dd40ecdac0ec0d7ffc657f265d3194c3817583c2b88ad375f132b", + "UNIT_OUTPUT_S3B_ATTEMPT_01.sha256": "3af8110cac13104df8e85851491d781d3edff527bb168a626c9c0d3285fcc093", + "UNIT_OUTPUT_S3B_ATTEMPT_01.txt": "c89f4f1ca1ea9b985079cd236ffff4193fa5c76d9bfa28fa65ac08cfc93b569c", + "UNIT_OUTPUT_S3B_ATTEMPT_02.sha256": "8f5edcdb522ab51606374403d6bcec508029aa32260430ac715a4b5bbb610da2", + "UNIT_OUTPUT_S3B_ATTEMPT_02.txt": "7bd19a6a3c84385f754261d51779f05b6e39c116459086d5aad3a83afa7225c0", + "UNIT_OUTPUT_S3B_ATTEMPT_03.sha256": "a9f4348d6fdbe4bcbed3f19831a88131fb365107411d452a2237f14038e88e6b", + "UNIT_OUTPUT_S3B_ATTEMPT_03.txt": "0872061bbc2c1403d2cd04877b8456f3fead35236be008b1a07f02ae5d85b11a", + "UNIT_OUTPUT_S3B_ATTEMPT_04.sha256": "950e32a41ebfd325c86eb6810148d726316a1a455203e5c806692dcce82e017a", + "UNIT_OUTPUT_S3B_ATTEMPT_04.txt": "63204c3415c9b1719fa6aa596b714077a57f530896f979d12b89a15eb2d827e9", + "UNIT_OUTPUT_S3B_ATTEMPT_05.sha256": "4293e250807be76a74c0b743b6ed550f5038d50a34ac5f9e743c68b8c15e5564", + "UNIT_OUTPUT_S3B_ATTEMPT_05.txt": "bfcb263bf6d7f284fb2b20ee229d96b7c4a9bd7cd5e7b513df1d3ea32580ed6e", + "UNIT_OUTPUT_S3B_ATTEMPT_06.sha256": "e0b6b770ded4ead6f785d64f4f866916b3a8392ba5d330ed5820755e3c6497f0", + "UNIT_OUTPUT_S3B_ATTEMPT_06.txt": "7d9bf9c602a93aca06d03eb06025beeea35603d453e293c07e7a6f81ca9ca000", + "UNIT_OUTPUT_S3B_ATTEMPT_07.sha256": "d38c2f6c05976e05a553b80917d4bede994425a76cbcaaba274fd36836101a64", + "UNIT_OUTPUT_S3B_ATTEMPT_07.txt": "f7c7c045ea98a366810b7c309fc1a87a77ccc5d8e823750eebaa742c9529e2ca", + "UNIT_OUTPUT_S3B_ATTEMPT_08.sha256": "7b252056637268e05f3eaa28a6f75f64c9345e4e95031bdba93c33048e8807a6", + "UNIT_OUTPUT_S3B_ATTEMPT_08.txt": "19c3f115d6a73bf91413877878f5d5f9d78a3e253dae3ddba7dfec9b5d46eaba", + "UNIT_OUTPUT_S3B_ATTEMPT_09.sha256": "f603c6d559184e68909e2409114659a263af5d18a684be332cebffaf816b6bd0", + "UNIT_OUTPUT_S3B_ATTEMPT_09.txt": "8360a2065b303099d5c546b3e4aecc0cc0ab0c2c1e5120b8034b6a1a64317030", + "UNIT_OUTPUT_S4_ATTEMPT_01.sha256": "59f15ed56cd9e56efbd40fd22b2d76ba53b86fc890cc0f094a8913ab5471b854", + "UNIT_OUTPUT_S4_ATTEMPT_01.txt": "ff9620ce295f2f2edc25e9b0014ac4db221e1b26e8ba1b0f20c20e7e5d045ce9", + "UNIT_OUTPUT_S4_ATTEMPT_02.sha256": "be7112d1386315b7a86c570122c21972e4650c7cf0f84c69ab647b25649a5172", + "UNIT_OUTPUT_S4_ATTEMPT_02.txt": "140d2c270f7c15297bed638c23dd38295381eebacc123fccdc112d32162dcefe", + "UNIT_OUTPUT_S4_ATTEMPT_03.sha256": "9debd9e5bea0735ca49935e5b3e410ba8546248ab64e93941cdfcfe23ee39aa0", + "UNIT_OUTPUT_S4_ATTEMPT_03.txt": "9f27f201325809a590375b7842101ef6b7d08c7de0aa4e66b4de2b7f7fd673d1", + "UNIT_OUTPUT_S4_ATTEMPT_04.sha256": "831b0269c0e99cb380be82f66bf262885fee1059a2ac130a0d5f764516d6fe29", + "UNIT_OUTPUT_S4_ATTEMPT_04.txt": "76738bb4138955e5fec02a93358c55446183492e99fd4d4360ac7fad58caacf9", + "UNIT_OUTPUT_S4_ATTEMPT_05.sha256": "923da4ffe041c211522a495f1f3b8493034e50fa728e9193af53f0323acef7cd", + "UNIT_OUTPUT_S4_ATTEMPT_05.txt": "aa13731a56337065e1a74acbfb640d56655cb4f774c9780dc265c40cf097101e", + "check_eq.py": "30682d2b462fd09de470bff52198303b7e86bb25c92e372103bcade11c3a7418", + "compare_versions.py": "1324e9e689a2885bd85f58a54f974d8a198e09fd3542123c6f597442e1437263", + "eq_probe.gd": "f933cad2a7ad4905fec15228ceb75ecb0ed100c64200a41feb80ba9702cf88fb", + "references/OPT_CONTRACT_T1.md": "ad9f3d76f3500b39263fb898d7c64588b4b47c9e11b456f938195261fd054d16", + "references/OPUS_D2_SCOPE_CLARIFICATION.txt": "5775e7b512d9e90dbcfbcb181f5b64dc0fa8207e0947c0a4a6a5c9195565f9bd", + "references/OPUS_STARTUP_LIFECYCLE_CLARIFICATION.txt": "967aebf27ff412f7a16ce771ef7d68abf8cfde0bb76ed19cf6dbf2817ca7acc6", + "registration/ACCEPTANCE_BASELINE.json": "84628bc21205387f8a7143031bdc50c9f68a767d350e6c34b32e0ba1c7059337", + "registration/CONFIG_PROPOSAL.json": "775fbbb97cda8b4d4991defdf7871b0fc79f489f4dea34c1733d4830426cf1df", + "registration/REGISTRATION_PROPOSAL.json": "9590fc853a4df8d50cc0d269d23bd9c844dc6931590ff6f24ebf95bb54a8d135", + "registration/ROOT_PROPOSAL_BYTE_TRANSFER.json": "63197f650849084f769e487a76458361886a37090042f1e351851c75b0384da2" + }, + "retained_test_bodies": { + "count": 134, + "all_AST_unchanged": true, + "original_file_sha256": "cb742b252dbc278113b3c11c2431adac35b0c2e201a762a8ea1ac926e4af414b", + "method": "Retained prefix plus original unittest main reproduces exact original file SHA; no external retained tree access needed." + }, + "history": { + "prior_provider_exit": 124, + "prior_run_submitted": false, + "supplementary_assert_failure": "Retained in original raw stdout referenced by RETAINED_S4_RETURN.json; not relabeled successful.", + "late_unit06": "134 tests, 206.531 seconds, OK; no process exit receipt; final after-fix full run still required.", + "current_read_failure": "PermissionError reading external retained test file; no file changed. Replaced verification with exact prefix reconstruction checked against Root original SHA." + }, + "original_credit": 0, + "formal_acceptance": false, + "completion_evidence": { + "scope": "local unit only; no native, accepted S, Q measurement or product PASS", + "tests": 146, + "retained_tests": 134, + "added_tests": 12, + "command": "python3 -B test_eq.py", + "raw": "UNIT_OUTPUT_S4_ATTEMPT_10.txt", + "sha256": "ff6fc0065772434f9ca35a1267e24d199057e339869a868942a41829327503bb", + "unittest_seconds": 293.277, + "wall_seconds": 293.5742515, + "exit_code": 0, + "full_runs_after_changes": 1, + "targeted_attempts": { + "07": "8 tests; one new mock failure, retained unchanged", + "08": "9 tests, OK, exit 0", + "09": "3 tests, OK, exit 0" + }, + "late_unit06_hashes_preserved": true, + "formal_validations_pending": [ + "p28-02-eq-unit", + "p28-02-eq-native-verify" + ], + "all_six_acceptance_conditions_pending": true + } +} diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.sha256 new file mode 100644 index 0000000..5f5577b --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.sha256 @@ -0,0 +1 @@ +ff6fc0065772434f9ca35a1267e24d199057e339869a868942a41829327503bb UNIT_OUTPUT.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.txt new file mode 100644 index 0000000..ee7919a --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT.txt @@ -0,0 +1,154 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_defect_other_checkpoint_still_rejected (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_joined_s3b_self_comparison (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_preview_observation (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_ownership_fact_dictionary_order_fallback (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_signal_facts_cannot_be_dropped (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_checkout_temp_destination_rejected (__main__.S4Bundle) ... ok +test_existing_output_never_overwritten (__main__.S4Bundle) ... ok +test_import_closure_rejections (__main__.S4Bundle) ... ok +test_missing_bundle_manifest_seal_and_changed_bytes (__main__.S4Bundle) ... ok +test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) ... ok +test_missing_profile_not_export_success (__main__.S4Bundle) ... ok +test_phase_role_pid_audio_and_guard_rejected (__main__.S4Bundle) ... ok +test_rebound_lifecycle_and_scenario_contradictions (__main__.S4Bundle) ... ok +test_seal_normal_and_changes_not_native_proof (__main__.S4Bundle) ... ok +test_synthetic_phase_all_real_checkers_not_native_proof (__main__.S4Bundle) ... ok +test_copied_manifest_root_and_destination_count_rejected (__main__.S4NativeBundleLogic) ... ok +test_failure_keeps_raw_and_no_bundle_without_starting_engine (__main__.S4NativeBundleLogic) ... ok +test_gate_none_success_not_boolean (__main__.S4NativeBundleLogic) ... ok +test_receipt_and_source_rejection_matrix (__main__.S4NativeBundleLogic) ... ok +test_synthetic_full_bundle_positive_not_native_evidence (__main__.S4NativeBundleLogic) ... ok +test_check_accepts_true (__main__.S4ProbeAdmission) ... ok +test_check_rejects_false_all_errors (__main__.S4ProbeAdmission) ... ok +test_run_admission_accepts_true_mock_launch_only (__main__.S4ProbeAdmission) ... ok +test_run_admission_rejects_false_without_engine (__main__.S4ProbeAdmission) ... ok +test_nine_original_destinations_required (__main__.S4RemainingBindings) ... ok +test_nonzero_determinism_rejected_after_real_join (__main__.S4RemainingBindings) ... ok +test_owned_lifecycle_exit_diagnostic_and_profile_rejections (__main__.S4RemainingBindings) ... ok +test_verifier_accepts_true_recomputes_raw (__main__.S4RemainingBindings) ... ok +test_verifier_rejects_false_with_every_error (__main__.S4RemainingBindings) ... ok +test_cached_verdict_not_trusted (__main__.S4StoredResultBindings) ... ok +test_missing_sidecar_rejected_after_seal (__main__.S4StoredResultBindings) ... ok +test_raw_joined_substitution_rejected_after_seal (__main__.S4StoredResultBindings) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 146 tests in 293.277s + +OK + +exit_code=0 +wall_seconds=293.5742515 diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.sha256 new file mode 100644 index 0000000..2f0dce4 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.sha256 @@ -0,0 +1 @@ +307486177b76602cbe68acae24c9560d501b3b866136d8e69802ec24c28e8be8 UNIT_OUTPUT_ATTEMPT_01.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.txt new file mode 100644 index 0000000..84d2586 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_01.txt @@ -0,0 +1,48 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +====================================================================== +FAIL: test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) (bad={'entries': [{'event_index': 0, 'path': [['key', [4, 'payload']], ['key', [4, 'duration_us']]], 'key': 'duration_us', 'original_node': [2, 7]}, {'event_index': 0, 'path': [['key', [4, 'payload']], ['key', [4, 'runtime_duration_us']]], 'key': 'runtime_duration_us', 'original_node': [2, 8]}], 'violations': [], 'profile_root': {'root': '/private/a', 'actual_user_data_dir': '/private/a', 'matches_guard': True}}) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 218, in test_sidecar_missing_duplicate_and_forged_paths + eq.restore_events(n, bad, profile()) +AssertionError: EvidenceError not raised + +---------------------------------------------------------------------- +Ran 36 tests in 0.847s + +FAILED (failures=1) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.sha256 new file mode 100644 index 0000000..537ecd1 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.sha256 @@ -0,0 +1 @@ +07144a7f1941162227f54fefd1961ed0f209e97282432723bbda534079582e4e UNIT_OUTPUT_ATTEMPT_02.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.txt new file mode 100644 index 0000000..f3f8f1e --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_ATTEMPT_02.txt @@ -0,0 +1,46 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 41 tests in 1.382s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.sha256 new file mode 100644 index 0000000..4c0d38a --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.sha256 @@ -0,0 +1 @@ +cdca0cdd551ce76c6100c4dd90e04559551f9d88c054a19a2bc6a77e6572ae15 UNIT_OUTPUT_S1_FINAL.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.txt new file mode 100644 index 0000000..b66df1a --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S1_FINAL.txt @@ -0,0 +1,48 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 43 tests in 1.432s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.sha256 new file mode 100644 index 0000000..9f36d0d --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.sha256 @@ -0,0 +1 @@ +25953dfc5f8bc3759ae66f6403b162100fb0217c4476f308616b8ab78a2cc67e UNIT_OUTPUT_S2_ATTEMPT_01.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.txt new file mode 100644 index 0000000..5a727e7 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_01.txt @@ -0,0 +1,73 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 68 tests in 4.042s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.sha256 new file mode 100644 index 0000000..72de66f --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.sha256 @@ -0,0 +1 @@ +e26c986dda41b83143723e4c1c5b2ff1051a36b9a947b319341a2239cc3188de UNIT_OUTPUT_S2_ATTEMPT_02.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.txt new file mode 100644 index 0000000..58f25c9 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_02.txt @@ -0,0 +1,76 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 71 tests in 4.371s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.sha256 new file mode 100644 index 0000000..b794fcd --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.sha256 @@ -0,0 +1 @@ +9d323abda9bfffa02faf3a9d5cb56aa87e647017c991eb55b4807cf734386698 UNIT_OUTPUT_S2_ATTEMPT_03.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.txt new file mode 100644 index 0000000..6ae46c1 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S2_ATTEMPT_03.txt @@ -0,0 +1,77 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 72 tests in 4.753s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.sha256 new file mode 100644 index 0000000..44251a7 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.sha256 @@ -0,0 +1 @@ +5cf84b792b5f87cd4183f41cf3a846962a53dc0aa33049c3c55f290356584641 UNIT_OUTPUT_S3A_ATTEMPT_01.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.txt new file mode 100644 index 0000000..fc55009 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_01.txt @@ -0,0 +1,77 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 72 tests in 4.846s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.sha256 new file mode 100644 index 0000000..85fa1cd --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.sha256 @@ -0,0 +1 @@ +000152e51d23db3d4397583b3f4540f5ed0ae469010c993fa1d122fd51537431 UNIT_OUTPUT_S3A_ATTEMPT_02.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.txt new file mode 100644 index 0000000..2f58f57 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_02.txt @@ -0,0 +1,90 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 85 tests in 15.941s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.sha256 new file mode 100644 index 0000000..0b1c557 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.sha256 @@ -0,0 +1 @@ +7c14e8ecf4540e412467408cad267d53358940c86f87a0c8e519b305153f3cb8 UNIT_OUTPUT_S3A_ATTEMPT_03.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.txt new file mode 100644 index 0000000..270ef31 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_03.txt @@ -0,0 +1,96 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 91 tests in 18.225s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.sha256 new file mode 100644 index 0000000..961b119 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.sha256 @@ -0,0 +1 @@ +02221ae41e5dd40ecdac0ec0d7ffc657f265d3194c3817583c2b88ad375f132b UNIT_OUTPUT_S3A_ATTEMPT_04.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.txt new file mode 100644 index 0000000..04bcab5 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3A_ATTEMPT_04.txt @@ -0,0 +1,96 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 91 tests in 18.329s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.sha256 new file mode 100644 index 0000000..d924846 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.sha256 @@ -0,0 +1 @@ +c89f4f1ca1ea9b985079cd236ffff4193fa5c76d9bfa28fa65ac08cfc93b569c UNIT_OUTPUT_S3B_ATTEMPT_01.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.txt new file mode 100644 index 0000000..8a2e138 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_01.txt @@ -0,0 +1,96 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 91 tests in 18.303s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.sha256 new file mode 100644 index 0000000..33c049e --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.sha256 @@ -0,0 +1 @@ +7bd19a6a3c84385f754261d51779f05b6e39c116459086d5aad3a83afa7225c0 UNIT_OUTPUT_S3B_ATTEMPT_02.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.txt new file mode 100644 index 0000000..10125dc --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_02.txt @@ -0,0 +1,4 @@ + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1108 + self.reject(lambda r, e, p: e[3]['detail'].update(input=transport(snapshot())))) + ^ +SyntaxError: unmatched ')' diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.sha256 new file mode 100644 index 0000000..86bd0d5 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.sha256 @@ -0,0 +1 @@ +0872061bbc2c1403d2cd04877b8456f3fead35236be008b1a07f02ae5d85b11a UNIT_OUTPUT_S3B_ATTEMPT_03.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.txt new file mode 100644 index 0000000..b01023c --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_03.txt @@ -0,0 +1,127 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... FAIL +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +====================================================================== +FAIL: test_E5_cached_digest_defect_is_comparable (__main__.S3b) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1193, in test_E5_cached_digest_defect_is_comparable + self.assertTrue(checked['ok'], checked) +AssertionError: False is not true : {'ok': False, 'differences': [], 'dict_order_paths': [], 'excluded': [{'path': ['checkpoints', 0, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 0, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 0, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 0, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 1, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 1, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 1, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 1, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 2, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 2, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 2, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 2, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 3, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 3, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 3, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 3, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 4, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 4, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 4, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 4, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 5, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 5, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 5, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 5, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 6, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 6, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 6, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 6, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 7, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 7, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 7, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 7, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 8, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 8, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 8, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 8, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 9, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 9, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 9, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 9, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 10, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 10, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 10, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 10, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 11, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 11, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 11, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 11, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 12, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 12, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 12, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 12, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 13, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 13, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 13, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 13, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 14, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 14, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 14, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 14, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 15, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 15, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 15, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 15, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 16, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 16, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 16, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 16, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 17, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 17, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 17, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 17, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 18, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 18, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 18, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 18, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 19, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 19, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 19, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 19, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 20, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 20, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 20, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 20, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 21, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 21, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 21, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 21, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 22, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 22, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 22, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 22, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 23, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 23, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 23, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 23, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 24, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 24, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 24, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 24, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 25, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 25, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 25, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 25, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 26, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 26, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 26, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 26, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 27, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 27, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 27, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 27, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 28, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 28, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 28, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 28, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 29, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 29, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 29, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 29, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 30, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['checkpoints', 30, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['checkpoints', 30, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['checkpoints', 30, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['scenarios', 0, 'checkpoints', 0, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['scenarios', 0, 'checkpoints', 0, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['scenarios', 0, 'checkpoints', 0, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['scenarios', 0, 'checkpoints', 0, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['scenarios', 0, 'checkpoints', 1, 'K', 'performance_budget', '_samples'], 'reason': 'wall-clock telemetry', 'a': {'x': [1]}, 'b': {'x': [1]}}, {'path': ['scenarios', 0, 'checkpoints', 1, 'K', 'performance_budget', '_totals'], 'reason': 'wall-clock telemetry', 'a': {'x': 1}, 'b': {'x': 1}}, {'path': ['scenarios', 0, 'checkpoints', 1, 'C', 'catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}, {'path': ['scenarios', 0, 'checkpoints', 1, 'C', 'current_catalog_instance_id'], 'reason': 'process-local instance ID', 'a': 123, 'b': 123}], 'violations': [{'path': ['checkpoints', 0, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 0, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 1, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 1, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 2, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 2, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 3, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 3, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 4, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 4, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 5, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 5, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 6, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 6, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 7, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 7, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 8, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 8, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 9, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 9, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 10, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 10, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 11, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 11, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 12, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 12, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 13, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 13, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 14, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 14, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 15, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 15, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 16, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 16, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 17, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 17, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 18, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 18, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 19, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 19, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 20, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 20, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 21, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 21, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 22, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 22, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 23, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 23, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 24, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 24, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 25, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 25, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 26, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 26, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 27, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 27, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 28, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 28, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 29, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 29, 'latest'], 'a': [], 'b': []}, {'path': ['checkpoints', 30, 'S'], 'a': [], 'b': []}, {'path': ['checkpoints', 30, 'latest'], 'a': [], 'b': []}, {'path': ['events'], 'a': [], 'b': []}, {'path': ['scenarios', 0, 'checkpoints', 0, 'S'], 'a': [], 'b': []}, {'path': ['scenarios', 0, 'checkpoints', 0, 'latest'], 'a': [], 'b': []}, {'path': ['scenarios', 0, 'checkpoints', 1, 'S'], 'a': [], 'b': []}, {'path': ['scenarios', 0, 'checkpoints', 1, 'latest'], 'a': [], 'b': []}], 'digest_modes': [{'path': ['checkpoints', 0], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 1], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 2], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 3], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 4], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 5], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 6], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 7], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 8], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 9], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 10], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 11], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 12], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 13], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 14], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 15], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 16], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 17], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 18], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 19], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 20], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 21], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 22], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 23], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 24], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 25], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 26], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 27], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 28], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 29], 'mode': 'product latest_digest'}, {'path': ['checkpoints', 30], 'mode': 'product latest_digest'}, {'path': ['scenarios', 0, 'checkpoints', 0], 'mode': 'product latest_digest'}, {'path': ['scenarios', 0, 'checkpoints', 1], 'mode': 'product latest_digest'}], 'errors': ['product digest self-consistency']} + +---------------------------------------------------------------------- +Ran 114 tests in 26.564s + +FAILED (failures=1) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.sha256 new file mode 100644 index 0000000..376be76 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.sha256 @@ -0,0 +1 @@ +63204c3415c9b1719fa6aa596b714077a57f530896f979d12b89a15eb2d827e9 UNIT_OUTPUT_S3B_ATTEMPT_04.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.txt new file mode 100644 index 0000000..a05a087 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_04.txt @@ -0,0 +1,119 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 114 tests in 26.408s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.sha256 new file mode 100644 index 0000000..cd2d881 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.sha256 @@ -0,0 +1 @@ +bfcb263bf6d7f284fb2b20ee229d96b7c4a9bd7cd5e7b513df1d3ea32580ed6e UNIT_OUTPUT_S3B_ATTEMPT_05.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.txt new file mode 100644 index 0000000..258e106 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_05.txt @@ -0,0 +1,119 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 114 tests in 26.528s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.sha256 new file mode 100644 index 0000000..0e0afae --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.sha256 @@ -0,0 +1 @@ +7d9bf9c602a93aca06d03eb06025beeea35603d453e293c07e7a6f81ca9ca000 UNIT_OUTPUT_S3B_ATTEMPT_06.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.txt new file mode 100644 index 0000000..7ad54c3 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_06.txt @@ -0,0 +1,123 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_defect_other_checkpoint_still_rejected (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_joined_s3b_self_comparison (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_preview_observation (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_signal_facts_cannot_be_dropped (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 118 tests in 31.744s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.sha256 new file mode 100644 index 0000000..68e3e3e --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.sha256 @@ -0,0 +1 @@ +f7c7c045ea98a366810b7c309fc1a87a77ccc5d8e823750eebaa742c9529e2ca UNIT_OUTPUT_S3B_ATTEMPT_07.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.txt new file mode 100644 index 0000000..ed83d4f --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_07.txt @@ -0,0 +1,14 @@ +test_ownership_fact_dictionary_order_fallback (__main__.S3b) ... FAIL + +====================================================================== +FAIL: test_ownership_fact_dictionary_order_fallback (__main__.S3b) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1233, in test_ownership_fact_dictionary_order_fallback + self.assertTrue(result['ok'], result['differences']) +AssertionError: False is not true : [{'path': ['scenarios', 0, 'result'], 'a': {'facts': {'held_before': [27, [[[4, 'a'], [2, 1]], [[4, 'b'], [2, 2]]], None]}}, 'b': {'facts': {'held_before': [27, [[[4, 'b'], [2, 2]], [[4, 'a'], [2, 1]]], None]}}}] + +---------------------------------------------------------------------- +Ran 1 test in 0.036s + +FAILED (failures=1) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.sha256 new file mode 100644 index 0000000..96aeb35 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.sha256 @@ -0,0 +1 @@ +19c3f115d6a73bf91413877878f5d5f9d78a3e253dae3ddba7dfec9b5d46eaba UNIT_OUTPUT_S3B_ATTEMPT_08.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.txt new file mode 100644 index 0000000..4783bfd --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_08.txt @@ -0,0 +1,132 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_defect_other_checkpoint_still_rejected (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_joined_s3b_self_comparison (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_preview_observation (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_ownership_fact_dictionary_order_fallback (__main__.S3b) ... FAIL +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_signal_facts_cannot_be_dropped (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +====================================================================== +FAIL: test_ownership_fact_dictionary_order_fallback (__main__.S3b) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1233, in test_ownership_fact_dictionary_order_fallback + self.assertTrue(result['ok'], result['differences']) +AssertionError: False is not true : [] + +---------------------------------------------------------------------- +Ran 119 tests in 31.877s + +FAILED (failures=1) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.sha256 new file mode 100644 index 0000000..540c2dd --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.sha256 @@ -0,0 +1 @@ +8360a2065b303099d5c546b3e4aecc0cc0ab0c2c1e5120b8034b6a1a64317030 UNIT_OUTPUT_S3B_ATTEMPT_09.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.txt new file mode 100644 index 0000000..69b6013 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S3B_ATTEMPT_09.txt @@ -0,0 +1,124 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_defect_other_checkpoint_still_rejected (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_joined_s3b_self_comparison (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_preview_observation (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_ownership_fact_dictionary_order_fallback (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_signal_facts_cannot_be_dropped (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 119 tests in 32.034s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.sha256 new file mode 100644 index 0000000..e777270 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.sha256 @@ -0,0 +1 @@ +ff9620ce295f2f2edc25e9b0014ac4db221e1b26e8ba1b0f20c20e7e5d045ce9 UNIT_OUTPUT_S4_ATTEMPT_01.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.txt new file mode 100644 index 0000000..509fc91 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_01.txt @@ -0,0 +1,10 @@ +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1241, in + import run_eq as driver + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/run_eq.py", line 16, in + import verify_eq as verify + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/verify_eq.py", line 18, in + NAMES = {f'{prefix}-{i:02d}.json' for prefix, count in + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/verify_eq.py", line 18, in + NAMES = {f'{prefix}-{i:02d}.json' for prefix, count in +NameError: name 'i' is not defined diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.sha256 new file mode 100644 index 0000000..e62cf93 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.sha256 @@ -0,0 +1 @@ +140d2c270f7c15297bed638c23dd38295381eebacc123fccdc112d32162dcefe UNIT_OUTPUT_S4_ATTEMPT_02.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.txt new file mode 100644 index 0000000..dd3afc6 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_02.txt @@ -0,0 +1,328 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_defect_other_checkpoint_still_rejected (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_joined_s3b_self_comparison (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_preview_observation (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_ownership_fact_dictionary_order_fallback (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_signal_facts_cannot_be_dropped (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_checkout_temp_destination_rejected (__main__.S4Bundle) ... ok +test_existing_output_never_overwritten (__main__.S4Bundle) ... ok +test_import_closure_rejections (__main__.S4Bundle) ... ok +test_missing_bundle_manifest_seal_and_changed_bytes (__main__.S4Bundle) ... ok +test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) ... test_missing_profile_not_export_success (__main__.S4Bundle) ... ok +test_phase_role_pid_audio_and_guard_rejected (__main__.S4Bundle) ... ERROR +test_seal_normal_and_changes_not_native_proof (__main__.S4Bundle) ... ok +test_synthetic_phase_all_real_checkers_not_native_proof (__main__.S4Bundle) ... ERROR +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +====================================================================== +ERROR: test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) (filename='lifecycle.json') +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1365, in test_missing_private_evidence_and_extra_rejected + directory = Path(name); row = s4_phase_fixture(directory) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1285, in s4_phase_fixture + raw, e3, b1, e45 = s4_report_fixture(role) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1270, in s4_report_fixture + add_world(e3raw); add_world(e3); add_world(b1) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1269, in add_world + for child in value: add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1266, in add_world + value['tree_sha'] = eq.tree_sha(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 109, in tree_sha + validate_tree(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 70, in validate_tree + require(key not in seen, 'duplicate dictionary key') + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 29, in require + raise EvidenceError(message) +compare_versions.EvidenceError: duplicate dictionary key + +====================================================================== +ERROR: test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) (filename='audio-close.json') +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1365, in test_missing_private_evidence_and_extra_rejected + directory = Path(name); row = s4_phase_fixture(directory) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1285, in s4_phase_fixture + raw, e3, b1, e45 = s4_report_fixture(role) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1270, in s4_report_fixture + add_world(e3raw); add_world(e3); add_world(b1) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1269, in add_world + for child in value: add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1266, in add_world + value['tree_sha'] = eq.tree_sha(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 109, in tree_sha + validate_tree(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 70, in validate_tree + require(key not in seen, 'duplicate dictionary key') + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 29, in require + raise EvidenceError(message) +compare_versions.EvidenceError: duplicate dictionary key + +====================================================================== +ERROR: test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) (filename='e3-17.json') +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1365, in test_missing_private_evidence_and_extra_rejected + directory = Path(name); row = s4_phase_fixture(directory) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1285, in s4_phase_fixture + raw, e3, b1, e45 = s4_report_fixture(role) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1270, in s4_report_fixture + add_world(e3raw); add_world(e3); add_world(b1) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1269, in add_world + for child in value: add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1266, in add_world + value['tree_sha'] = eq.tree_sha(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 109, in tree_sha + validate_tree(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 70, in validate_tree + require(key not in seen, 'duplicate dictionary key') + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 29, in require + raise EvidenceError(message) +compare_versions.EvidenceError: duplicate dictionary key + +====================================================================== +ERROR: test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) (filename='e45-20.json') +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1365, in test_missing_private_evidence_and_extra_rejected + directory = Path(name); row = s4_phase_fixture(directory) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1285, in s4_phase_fixture + raw, e3, b1, e45 = s4_report_fixture(role) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1270, in s4_report_fixture + add_world(e3raw); add_world(e3); add_world(b1) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1269, in add_world + for child in value: add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1266, in add_world + value['tree_sha'] = eq.tree_sha(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 109, in tree_sha + validate_tree(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 70, in validate_tree + require(key not in seen, 'duplicate dictionary key') + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 29, in require + raise EvidenceError(message) +compare_versions.EvidenceError: duplicate dictionary key + +====================================================================== +ERROR: test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) (filename='extra.json') +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1365, in test_missing_private_evidence_and_extra_rejected + directory = Path(name); row = s4_phase_fixture(directory) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1285, in s4_phase_fixture + raw, e3, b1, e45 = s4_report_fixture(role) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1270, in s4_report_fixture + add_world(e3raw); add_world(e3); add_world(b1) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1269, in add_world + for child in value: add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1266, in add_world + value['tree_sha'] = eq.tree_sha(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 109, in tree_sha + validate_tree(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 70, in validate_tree + require(key not in seen, 'duplicate dictionary key') + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 29, in require + raise EvidenceError(message) +compare_versions.EvidenceError: duplicate dictionary key + +====================================================================== +ERROR: test_phase_role_pid_audio_and_guard_rejected (__main__.S4Bundle) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1373, in test_phase_role_pid_audio_and_guard_rejected + directory = Path(name); row = s4_phase_fixture(directory) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1285, in s4_phase_fixture + raw, e3, b1, e45 = s4_report_fixture(role) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1270, in s4_report_fixture + add_world(e3raw); add_world(e3); add_world(b1) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1269, in add_world + for child in value: add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1266, in add_world + value['tree_sha'] = eq.tree_sha(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 109, in tree_sha + validate_tree(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 70, in validate_tree + require(key not in seen, 'duplicate dictionary key') + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 29, in require + raise EvidenceError(message) +compare_versions.EvidenceError: duplicate dictionary key + +====================================================================== +ERROR: test_synthetic_phase_all_real_checkers_not_native_proof (__main__.S4Bundle) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1336, in test_synthetic_phase_all_real_checkers_not_native_proof + row = s4_phase_fixture(directory) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1285, in s4_phase_fixture + raw, e3, b1, e45 = s4_report_fixture(role) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1270, in s4_report_fixture + add_world(e3raw); add_world(e3); add_world(b1) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1269, in add_world + for child in value: add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1267, in add_world + for child in value.values(): add_world(child) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1266, in add_world + value['tree_sha'] = eq.tree_sha(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 109, in tree_sha + validate_tree(tree) + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 70, in validate_tree + require(key not in seen, 'duplicate dictionary key') + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 29, in require + raise EvidenceError(message) +compare_versions.EvidenceError: duplicate dictionary key + +---------------------------------------------------------------------- +Ran 128 tests in 34.518s + +FAILED (errors=7) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.sha256 new file mode 100644 index 0000000..ccd78c0 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.sha256 @@ -0,0 +1 @@ +9f27f201325809a590375b7842101ef6b7d08c7de0aa4e66b4de2b7f7fd673d1 UNIT_OUTPUT_S4_ATTEMPT_03.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.txt new file mode 100644 index 0000000..42ebf1f --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_03.txt @@ -0,0 +1,14 @@ +test_checkout_temp_destination_rejected (__main__.S4Bundle) ... ok +test_existing_output_never_overwritten (__main__.S4Bundle) ... ok +test_import_closure_rejections (__main__.S4Bundle) ... ok +test_missing_bundle_manifest_seal_and_changed_bytes (__main__.S4Bundle) ... ok +test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) ... ok +test_missing_profile_not_export_success (__main__.S4Bundle) ... ok +test_phase_role_pid_audio_and_guard_rejected (__main__.S4Bundle) ... ok +test_seal_normal_and_changes_not_native_proof (__main__.S4Bundle) ... ok +test_synthetic_phase_all_real_checkers_not_native_proof (__main__.S4Bundle) ... ok + +---------------------------------------------------------------------- +Ran 9 tests in 19.447s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.sha256 new file mode 100644 index 0000000..111afef --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.sha256 @@ -0,0 +1 @@ +76738bb4138955e5fec02a93358c55446183492e99fd4d4360ac7fad58caacf9 UNIT_OUTPUT_S4_ATTEMPT_04.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.txt new file mode 100644 index 0000000..02a3989 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_04.txt @@ -0,0 +1,21 @@ +test_copied_manifest_root_and_destination_count_rejected (__main__.S4NativeBundleLogic) ... ok +test_gate_none_success_not_boolean (__main__.S4NativeBundleLogic) ... ok +test_receipt_and_source_rejection_matrix (__main__.S4NativeBundleLogic) ... ok +test_synthetic_full_bundle_positive_not_native_evidence (__main__.S4NativeBundleLogic) ... ERROR + +====================================================================== +ERROR: test_synthetic_full_bundle_positive_not_native_evidence (__main__.S4NativeBundleLogic) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1506, in test_synthetic_full_bundle_positive_not_native_evidence + patch.object(driver, 'load_dependencies', return_value=(self.collector, self.standard, self.outer, self.diag)): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/verify_eq.py", line 217, in verify + from run_eq import load_dependencies, actual_pins + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py", line 29, in require + raise EvidenceError(message) +compare_versions.EvidenceError: recomputed results differ + +---------------------------------------------------------------------- +Ran 4 tests in 124.325s + +FAILED (errors=1) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.sha256 new file mode 100644 index 0000000..7706bd3 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.sha256 @@ -0,0 +1 @@ +aa13731a56337065e1a74acbfb640d56655cb4f774c9780dc265c40cf097101e UNIT_OUTPUT_S4_ATTEMPT_05.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.txt new file mode 100644 index 0000000..d8804e7 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_05.txt @@ -0,0 +1,137 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_defect_other_checkpoint_still_rejected (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_joined_s3b_self_comparison (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_preview_observation (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_ownership_fact_dictionary_order_fallback (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_signal_facts_cannot_be_dropped (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_checkout_temp_destination_rejected (__main__.S4Bundle) ... ok +test_existing_output_never_overwritten (__main__.S4Bundle) ... ok +test_import_closure_rejections (__main__.S4Bundle) ... ok +test_missing_bundle_manifest_seal_and_changed_bytes (__main__.S4Bundle) ... ok +test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) ... ok +test_missing_profile_not_export_success (__main__.S4Bundle) ... ok +test_phase_role_pid_audio_and_guard_rejected (__main__.S4Bundle) ... ok +test_seal_normal_and_changes_not_native_proof (__main__.S4Bundle) ... ok +test_synthetic_phase_all_real_checkers_not_native_proof (__main__.S4Bundle) ... ok +test_copied_manifest_root_and_destination_count_rejected (__main__.S4NativeBundleLogic) ... ok +test_gate_none_success_not_boolean (__main__.S4NativeBundleLogic) ... ok +test_receipt_and_source_rejection_matrix (__main__.S4NativeBundleLogic) ... ok +test_synthetic_full_bundle_positive_not_native_evidence (__main__.S4NativeBundleLogic) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 132 tests in 194.460s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.sha256 new file mode 100644 index 0000000..f1a198d --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.sha256 @@ -0,0 +1 @@ +3c41e4442e2c21315e484fd2c8cdb9de70272af115a618083fca2d2e6428d187 UNIT_OUTPUT_S4_ATTEMPT_06.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.txt new file mode 100644 index 0000000..89a3657 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_06.txt @@ -0,0 +1,139 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_defect_other_checkpoint_still_rejected (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_joined_s3b_self_comparison (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_preview_observation (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_ownership_fact_dictionary_order_fallback (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_signal_facts_cannot_be_dropped (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_checkout_temp_destination_rejected (__main__.S4Bundle) ... ok +test_existing_output_never_overwritten (__main__.S4Bundle) ... ok +test_import_closure_rejections (__main__.S4Bundle) ... ok +test_missing_bundle_manifest_seal_and_changed_bytes (__main__.S4Bundle) ... ok +test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) ... ok +test_missing_profile_not_export_success (__main__.S4Bundle) ... ok +test_phase_role_pid_audio_and_guard_rejected (__main__.S4Bundle) ... ok +test_rebound_lifecycle_and_scenario_contradictions (__main__.S4Bundle) ... ok +test_seal_normal_and_changes_not_native_proof (__main__.S4Bundle) ... ok +test_synthetic_phase_all_real_checkers_not_native_proof (__main__.S4Bundle) ... ok +test_copied_manifest_root_and_destination_count_rejected (__main__.S4NativeBundleLogic) ... ok +test_failure_keeps_raw_and_no_bundle_without_starting_engine (__main__.S4NativeBundleLogic) ... ok +test_gate_none_success_not_boolean (__main__.S4NativeBundleLogic) ... ok +test_receipt_and_source_rejection_matrix (__main__.S4NativeBundleLogic) ... ok +test_synthetic_full_bundle_positive_not_native_evidence (__main__.S4NativeBundleLogic) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 134 tests in 206.531s + +OK diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.sha256 new file mode 100644 index 0000000..b406f89 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.sha256 @@ -0,0 +1 @@ +29d1a5dec792ae865725220ec4d11c11bb62d08cba9a614ad7bf2d120948ab97 UNIT_OUTPUT_S4_ATTEMPT_07.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.txt new file mode 100644 index 0000000..de96a5e --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_07.txt @@ -0,0 +1,28 @@ +test_check_accepts_true (__main__.S4ProbeAdmission) ... ok +test_check_rejects_false_all_errors (__main__.S4ProbeAdmission) ... ok +test_run_admission_accepts_true_mock_launch_only (__main__.S4ProbeAdmission) ... ok +test_run_admission_rejects_false_without_engine (__main__.S4ProbeAdmission) ... ok +test_nonzero_determinism_rejected_after_real_join (__main__.S4RemainingBindings) ... FAIL +test_owned_lifecycle_exit_diagnostic_and_profile_rejections (__main__.S4RemainingBindings) ... ok +test_verifier_accepts_true_recomputes_raw (__main__.S4RemainingBindings) ... ok +test_verifier_rejects_false_with_every_error (__main__.S4RemainingBindings) ... ok + +====================================================================== +FAIL: test_nonzero_determinism_rejected_after_real_join (__main__.S4RemainingBindings) +---------------------------------------------------------------------- +compare_versions.EvidenceError: report checker: ['report self-check: []'] + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-02-eq/P28-02-EQ-implement/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py", line 1647, in test_nonzero_determinism_rejected_after_real_join + self.recompute(self.execution) +AssertionError: "same-role determinism failed" does not match "report checker: ['report self-check: []']" + +---------------------------------------------------------------------- +Ran 8 tests in 54.265s + +FAILED (failures=1) + +exit_code=1 +wall_seconds=54.554559917 diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.sha256 new file mode 100644 index 0000000..dc00023 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.sha256 @@ -0,0 +1 @@ +d470e6ee7a07a3b6d4ad2182b545e8708ae735b0d106c0800a813eb73f7353ce UNIT_OUTPUT_S4_ATTEMPT_08.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.txt new file mode 100644 index 0000000..4ff1fa5 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_08.txt @@ -0,0 +1,17 @@ +test_check_accepts_true (__main__.S4ProbeAdmission) ... ok +test_check_rejects_false_all_errors (__main__.S4ProbeAdmission) ... ok +test_run_admission_accepts_true_mock_launch_only (__main__.S4ProbeAdmission) ... ok +test_run_admission_rejects_false_without_engine (__main__.S4ProbeAdmission) ... ok +test_nine_original_destinations_required (__main__.S4RemainingBindings) ... ok +test_nonzero_determinism_rejected_after_real_join (__main__.S4RemainingBindings) ... ok +test_owned_lifecycle_exit_diagnostic_and_profile_rejections (__main__.S4RemainingBindings) ... ok +test_verifier_accepts_true_recomputes_raw (__main__.S4RemainingBindings) ... ok +test_verifier_rejects_false_with_every_error (__main__.S4RemainingBindings) ... ok + +---------------------------------------------------------------------- +Ran 9 tests in 86.276s + +OK + +exit_code=0 +wall_seconds=86.551909958 diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.sha256 new file mode 100644 index 0000000..9da19e3 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.sha256 @@ -0,0 +1 @@ +3f33b134a48cfabd8794329bec69ed0678ad71f06052f4e34a78c5955475c450 UNIT_OUTPUT_S4_ATTEMPT_09.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.txt new file mode 100644 index 0000000..8b99a67 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_09.txt @@ -0,0 +1,11 @@ +test_cached_verdict_not_trusted (__main__.S4StoredResultBindings) ... ok +test_missing_sidecar_rejected_after_seal (__main__.S4StoredResultBindings) ... ok +test_raw_joined_substitution_rejected_after_seal (__main__.S4StoredResultBindings) ... ok + +---------------------------------------------------------------------- +Ran 3 tests in 0.025s + +OK + +exit_code=0 +wall_seconds=0.2951165 diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.sha256 b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.sha256 new file mode 100644 index 0000000..222645f --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.sha256 @@ -0,0 +1 @@ +ff6fc0065772434f9ca35a1267e24d199057e339869a868942a41829327503bb UNIT_OUTPUT_S4_ATTEMPT_10.txt diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.txt b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.txt new file mode 100644 index 0000000..ee7919a --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/UNIT_OUTPUT_S4_ATTEMPT_10.txt @@ -0,0 +1,154 @@ +test_all_operations (__main__.Diffs) ... ok +test_invalid_operations (__main__.Diffs) ... ok +test_reconstruction_and_proofs (__main__.Diffs) ... ok +test_attempt_to_normalize_violation_rejected (__main__.Normalization) ... ok +test_environment_values_differ_but_normal_form_equal (__main__.Normalization) ... ok +test_every_save_event_reversible (__main__.Normalization) ... ok +test_f3_keeps_relative_paths_and_words (__main__.Normalization) ... ok +test_guard_mismatch (__main__.Normalization) ... ok +test_nested_lookalike_is_not_eligible (__main__.Normalization) ... ok +test_original_transport_sha_detects_forged_timing (__main__.Normalization) ... ok +test_partial_timing_payload_rejected (__main__.Normalization) ... ok +test_prefix_boundary_and_reserved_token (__main__.Normalization) ... ok +test_sidecar_missing_duplicate_and_forged_paths (__main__.Normalization) ... ok +test_snapshot_and_latest_reversible (__main__.Normalization) ... ok +test_snapshot_event_outside_recent_is_not_eligible (__main__.Normalization) ... ok +test_wrong_event_and_source_are_preserved (__main__.Normalization) ... ok +test_wrong_timing_type_and_negative (__main__.Normalization) ... ok +test_all_events_beyond_recent_window (__main__.Reports) ... ok +test_all_semantic_layers_compared (__main__.Reports) ... ok +test_digest_alone_is_not_enough (__main__.Reports) ... ok +test_event_original_types_and_order (__main__.Reports) ... ok +test_event_start_and_ids (__main__.Reports) ... ok +test_exclusions_keep_actual_values (__main__.Reports) ... ok +test_handler_sets_and_counts (__main__.Reports) ... ok +test_observation_full_layers (__main__.Reports) ... ok +test_product_digest_self_consistency (__main__.Reports) ... ok +test_same_report (__main__.Reports) ... ok +test_scenario_existing_failures_preserved (__main__.Reports) ... ok +test_timing_digest_rule (__main__.Reports) ... ok +test_unknown_or_missing_fields_rejected (__main__.Reports) ... ok +test_violation_presence_and_difference (__main__.Reports) ... ok +test_O_cadence (__main__.S2Format) ... ok +test_counter_and_published_ids_binding (__main__.S2Format) ... ok +test_diff_and_same_as_S_transport (__main__.S2Format) ... ok +test_digest_and_scenario_contradiction (__main__.S2Format) ... ok +test_event_no_drop_duplicate_remap (__main__.S2Format) ... ok +test_event_original_field_types_mandatory (__main__.S2Format) ... ok +test_guard_actual_not_assumed (__main__.S2Format) ... ok +test_harness_digest_allows_only_dictionary_order (__main__.S2Format) ... ok +test_join_is_copy_and_retains_normalization_proof (__main__.S2Format) ... ok +test_kernel_cache_contradictions (__main__.S2Format) ... ok +test_lifecycle_guard_errors_and_boundaries (__main__.S2Format) ... ok +test_missing_full_state_not_digest_only (__main__.S2Format) ... ok +test_normalized_digest_and_raw_tree_are_both_bound (__main__.S2Format) ... ok +test_product_event_shape_and_typed_array (__main__.S2Format) ... ok +test_raw_observation_binding (__main__.S2Format) ... ok +test_roundtrip_tree_sha_and_raw_sha (__main__.S2Format) ... ok +test_s2_valid_and_not_formal_acceptance (__main__.S2Format) ... ok +test_state_witness_and_observation_mutation (__main__.S2Format) ... ok +test_stdout_exactly_one_line (__main__.S2Format) ... ok +test_autoload_class_and_script_import (__main__.S2Static) ... ok +test_comment_does_not_supply_proof (__main__.S2Static) ... ok +test_current_probe (__main__.S2Static) ... ok +test_full_state_and_godot_roundtrip_required (__main__.S2Static) ... ok +test_no_changes_outside_preparation_or_step (__main__.S2Static) ... ok +test_no_event_cap_or_duplicate_report (__main__.S2Static) ... ok +test_pause_and_step_arguments (__main__.S2Static) ... ok +test_textual_stringname_ordering (__main__.S2Static) ... ok +test_unlisted_live_method_and_late_preparation (__main__.S2Static) ... ok +test_variant_inference (__main__.S2Static) ... ok +test_X_recent_limit_and_counter (__main__.S3a) ... ok +test_duplicate_JSON_key_rejected (__main__.S3a) ... ok +test_e3_NA_cannot_be_PASS_or_applied (__main__.S3a) ... ok +test_e3_coverage_input_and_event_count_binding (__main__.S3a) ... ok +test_e3_invented_codes_and_missing_load_code (__main__.S3a) ... ok +test_e3_valid_R_and_O_records (__main__.S3a) ... ok +test_envelope_duplicates_not_defect (__main__.S3a) ... ok +test_event_count_defect_not_silently_accepted (__main__.S3a) ... ok +test_exact_phase_keys (__main__.S3a) ... ok +test_interval_gap_rejected (__main__.S3a) ... ok +test_invalid_input_accepted_is_not_PASS (__main__.S3a) ... ok +test_load_payload_and_pause_outcome (__main__.S3a) ... ok +test_operation_moved_outside_scenario_rejected (__main__.S3a) ... ok +test_package_fixed_mutations_and_hashes (__main__.S3a) ... ok +test_probe_connection_required (__main__.S3a) ... ok +test_rejection_mutation_retained_as_defect (__main__.S3a) ... ok +test_save_refusal_makes_load_NA (__main__.S3a) ... ok +test_scenario_mutation_static_boundary (__main__.S3a) ... ok +test_signals_all_minutes_and_order (__main__.S3a) ... ok +test_E5_cached_digest_defect_is_comparable (__main__.S3b) ... ok +test_NA_not_PASS (__main__.S3b) ... ok +test_aliasing_cannot_be_PASS (__main__.S3b) ... ok +test_aliasing_missing_record (__main__.S3b) ... ok +test_all_paths_and_ownership_R_O (__main__.S3b) ... ok +test_digest_defect_other_checkpoint_still_rejected (__main__.S3b) ... ok +test_digest_materialization_required (__main__.S3b) ... ok +test_empty_registry_not_NA (__main__.S3b) ... ok +test_event_count_mismatch (__main__.S3b) ... ok +test_facts_normalization_is_reversible (__main__.S3b) ... ok +test_first_placeable_choice (__main__.S3b) ... ok +test_interval_gap (__main__.S3b) ... ok +test_joined_s3b_self_comparison (__main__.S3b) ... ok +test_load_X_not_digest_only (__main__.S3b) ... ok +test_load_extra_event (__main__.S3b) ... ok +test_missing_path_and_combination (__main__.S3b) ... ok +test_missing_preview_observation (__main__.S3b) ... ok +test_missing_trial (__main__.S3b) ... ok +test_nested_mutation_required (__main__.S3b) ... ok +test_no_staleness_assertion_for_non_tick (__main__.S3b) ... ok +test_ownership_fact_dictionary_order_fallback (__main__.S3b) ... ok +test_path_order (__main__.S3b) ... ok +test_restore_extra_event (__main__.S3b) ... ok +test_signal_facts_cannot_be_dropped (__main__.S3b) ... ok +test_sort_rule_rejected (__main__.S3b) ... ok +test_static_handler_and_outside_mutations (__main__.S3b) ... ok +test_unpreviewed_choice (__main__.S3b) ... ok +test_wrong_registry_in_either_role (__main__.S3b) ... ok +test_checkout_temp_destination_rejected (__main__.S4Bundle) ... ok +test_existing_output_never_overwritten (__main__.S4Bundle) ... ok +test_import_closure_rejections (__main__.S4Bundle) ... ok +test_missing_bundle_manifest_seal_and_changed_bytes (__main__.S4Bundle) ... ok +test_missing_private_evidence_and_extra_rejected (__main__.S4Bundle) ... ok +test_missing_profile_not_export_success (__main__.S4Bundle) ... ok +test_phase_role_pid_audio_and_guard_rejected (__main__.S4Bundle) ... ok +test_rebound_lifecycle_and_scenario_contradictions (__main__.S4Bundle) ... ok +test_seal_normal_and_changes_not_native_proof (__main__.S4Bundle) ... ok +test_synthetic_phase_all_real_checkers_not_native_proof (__main__.S4Bundle) ... ok +test_copied_manifest_root_and_destination_count_rejected (__main__.S4NativeBundleLogic) ... ok +test_failure_keeps_raw_and_no_bundle_without_starting_engine (__main__.S4NativeBundleLogic) ... ok +test_gate_none_success_not_boolean (__main__.S4NativeBundleLogic) ... ok +test_receipt_and_source_rejection_matrix (__main__.S4NativeBundleLogic) ... ok +test_synthetic_full_bundle_positive_not_native_evidence (__main__.S4NativeBundleLogic) ... ok +test_check_accepts_true (__main__.S4ProbeAdmission) ... ok +test_check_rejects_false_all_errors (__main__.S4ProbeAdmission) ... ok +test_run_admission_accepts_true_mock_launch_only (__main__.S4ProbeAdmission) ... ok +test_run_admission_rejects_false_without_engine (__main__.S4ProbeAdmission) ... ok +test_nine_original_destinations_required (__main__.S4RemainingBindings) ... ok +test_nonzero_determinism_rejected_after_real_join (__main__.S4RemainingBindings) ... ok +test_owned_lifecycle_exit_diagnostic_and_profile_rejections (__main__.S4RemainingBindings) ... ok +test_verifier_accepts_true_recomputes_raw (__main__.S4RemainingBindings) ... ok +test_verifier_rejects_false_with_every_error (__main__.S4RemainingBindings) ... ok +test_cached_verdict_not_trusted (__main__.S4StoredResultBindings) ... ok +test_missing_sidecar_rejected_after_seal (__main__.S4StoredResultBindings) ... ok +test_raw_joined_substitution_rejected_after_seal (__main__.S4StoredResultBindings) ... ok +test_fixed_scenario_paths (__main__.SourcesAndMetrics) ... ok +test_metric_ranges (__main__.SourcesAndMetrics) ... ok +test_source_closure_synthetic_registered_map (__main__.SourcesAndMetrics) ... ok +test_source_pin_is_not_caller_controlled (__main__.SourcesAndMetrics) ... ok +test_array_order_and_all_differences (__main__.TypedTrees) ... ok +test_components_and_sha (__main__.TypedTrees) ... ok +test_deep_state_not_truncated (__main__.TypedTrees) ... ok +test_duplicate_textual_keys_rejected (__main__.TypedTrees) ... ok +test_exact_and_types (__main__.TypedTrees) ... ok +test_nested_order_all_paths (__main__.TypedTrees) ... ok +test_nonstring_keys_keep_types_and_values (__main__.TypedTrees) ... ok +test_unsupported_and_malformed (__main__.TypedTrees) ... ok + +---------------------------------------------------------------------- +Ran 146 tests in 293.277s + +OK + +exit_code=0 +wall_seconds=293.5742515 diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/check_eq.py b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/check_eq.py new file mode 100644 index 0000000..cbf535d --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/check_eq.py @@ -0,0 +1,873 @@ +"""S3a format/static and E3 evidence checks. Not native admission or acceptance. + +Raw records remain immutable. join_report derives normalized digests/sidecars on +copies using S1's sole F1-F3 implementation; it does not manufacture Godot proof. +""" +import base64 +import ast +import copy +import hashlib +import json +from pathlib import Path +import re +import sys + +sys.dont_write_bytecode = True +import compare_versions as eq + + +def check_python_imports(text): + """Closed EQ/stdlib import screen; dynamic file loading is separately pinned by run_eq.""" + allowed = {'argparse', 'ast', 'base64', 'copy', 'hashlib', 'importlib', 'json', 'math', + 'os', 'pathlib', 're', 'shutil', 'struct', 'subprocess', 'sys', 'tempfile', + 'unittest', 'uuid', 'check_eq', 'compare_versions', 'run_eq', 'verify_eq'} + tree = ast.parse(text) + for node in ast.walk(tree): + if isinstance(node, (ast.Import, ast.ImportFrom)): + names = [node.module] if isinstance(node, ast.ImportFrom) else [a.name for a in node.names] + eq.require(all(n and n.split('.')[0] in allowed for n in names), 'import outside EQ closure') + eq.require(not isinstance(node, ast.ImportFrom) or node.level == 0, 'relative import outside closure') + if isinstance(node, ast.Call): + name = getattr(node.func, 'id', getattr(node.func, 'attr', '')) + eq.require(name not in ('eval', 'exec', '__import__', 'import_module'), 'unapproved dynamic import/code') + if name == 'spec_from_file_location': + expected = ast.parse('importlib.util.spec_from_file_location(module_name, root / relative)').body[0].value + eq.require(ast.dump(node) == ast.dump(expected) and + "require(relative in DEPENDENCIES and relative.endswith('.py'), 'import outside closure')" in text, + 'unapproved dynamic file loader') + for value in ast.walk(node): + if isinstance(value, ast.Constant) and isinstance(value.value, str): + eq.require(not value.value.endswith('.py'), 'unapproved literal file loader') + return True + + +def sha(value): + return hashlib.sha256(value).hexdigest() + + +def hex_sha(value): + return type(value) is str and re.fullmatch('[0-9a-f]{64}', value) is not None + + +def integer(value): + return type(value) is int and value >= 0 + + +def fields(tree): + eq.require(tree[0] == 27, 'dictionary required') + result = {} + for key, value in tree[1]: + eq.require(key[0] in (4, 21) and key[1] not in result, 'text key collision/type') + result[key[1]] = value + return result + + +def counts(tree): + runtime = fields(fields(fields(tree)['systems'])['runtime']) + counters = fields(fields(runtime['id_generator'])['counters']) + # Product get_counter has an explicit zero default for an absent prefix. + # At B1 the prefix must exist, so absent evidence is never defaulted here. + counter = counters['domain_event'] + ids = fields(runtime['domain_events'])['published_ids'] + eq.require(counter[0] == 2 and integer(counter[1]), 'domain counter type') + eq.require(ids[0] == 28, 'published IDs array') + eq.require(all(n[0] == 4 for n in ids[1]), 'published ID types') + names = [n[1] for n in ids[1]] + eq.require(names == sorted(set(names)), 'published ID order/duplicates') + return {'counter': counter[1], 'published_ids_count': len(names)}, names + + +def normalized_digest(tree): + """Harness-only typed canonical digest; never claim this is a product digest. + + Key nodes remain exact. Only Dictionary enumeration order is canonicalized, + matching S1 fallback; floats, metadata and Array order remain untouched. + """ + def canonical(node): + result = copy.deepcopy(node) + if node[0] == 27: + names = [eq._key_text(k) for k, _ in node[1]] + eq.require(len(set(names)) == len(names), 'digest textual key collision') + result[1] = [[copy.deepcopy(k), canonical(v)] for k, v in sorted(node[1], key=lambda p: eq._key_text(p[0]))] + elif node[0] == 28 or 5 <= node[0] <= 20 or 30 <= node[0] <= 38: + result[1] = [canonical(v) for v in node[1]] + return result + eq.validate_tree(tree) + return eq.tree_sha(canonical(tree)) + + +def join_report(raw): + """Return (joined report, reversible normalization evidence), never edit raw.""" + joined = copy.deepcopy(raw) + proofs = [] + trees = eq.reconstruct_checkpoints(raw['checkpoints']) + for cp, (s, latest) in zip(joined['checkpoints'], trees): + row = {} + for name, tree in (('S', s), ('latest', latest)): + normalized, side = eq.normalize_tree(tree, raw['profile_root']) + restored = eq.restore_tree(normalized, side, raw['profile_root']) + eq.require(eq.tree_sha(restored) == eq.tree_sha(tree), 'normalization restore SHA') + row[name] = {'normalized_tree_sha': eq.tree_sha(normalized), 'normalized_digest': normalized_digest(normalized), 'sidecar': side, + 'restored_tree_sha': eq.tree_sha(restored)} + expected = row['latest']['normalized_digest'] + eq.require(cp['harness_normalized_digest'] in (None, expected), 'forged normalized digest') + cp['harness_normalized_digest'] = expected + proofs.append(row) + for i, scenario in enumerate(raw.get('scenarios', [])): + derived, scenario_proofs = join_report({'profile_root': raw['profile_root'], 'checkpoints': scenario['checkpoints']}) + joined['scenarios'][i]['checkpoints'] = derived['checkpoints'] + proofs.append({'scenario': scenario['id'], 'checkpoints': scenario_proofs}) + if scenario['id'].startswith(('E4/', 'E5/')): + joined['scenarios'][i]['result']['facts'], fact_proofs = join_facts(scenario['result']['facts'], raw['profile_root']) + proofs.append({'scenario': scenario['id'], 'facts': fact_proofs}) + return joined, proofs + + +def check_measurement(raw, measurement): + eq.require(type(measurement) is dict, 'measurement connection inventory missing') + eq.require(set(measurement) == {'probe_object', 'connections', 'start_minute'}, 'measurement inventory fields') + eq.require(measurement['start_minute'] == raw['checkpoints'][0]['minute'], 'inventory B1 minute') + probe = measurement['probe_object'] + eq.require(type(probe) is str and re.fullmatch('[1-9][0-9]*', probe), 'probe object identity') + for signal, method in (('snapshot_published', 'observe_snapshot'), ('state_updated', 'observe_state')): + rows = measurement['connections'][signal] + eq.require(type(rows) is list, 'connection list') + for row in rows: + eq.require(set(row) == {'object', 'method', 'flags'}, 'connection fields') + eq.require(sum(r['object'] == probe and r['method'] == method for r in rows) == 1, + 'missing/duplicate probe connection: ' + signal) + expected = [{'signal': signal, 'minute': cp['minute']} for cp in raw['checkpoints'][1:] + for signal in ('snapshot_published', 'state_updated')] + eq.require(eq.exact(raw['signal_order'], expected), 'exact measured signal pairs/checkpoint minutes required') + + +def check_report(raw, measurement=None, e3_evidence=None, b1_record=None, e45_evidence=None): + out = {'ok': False, 'stage': 'S2', 'formal_acceptance': False, 'errors': []} + try: + report, proofs = join_report(raw) + compared = eq.compare_reports(report, report) + eq.require(compared['ok'], 'report self-check: ' + repr(compared['errors'])) + if raw['scenarios'] or e3_evidence is not None: + eq.require(e3_evidence is not None and b1_record is not None, 'E3 raw evidence missing') + e3_raw = dict(raw, scenarios=raw['scenarios'][:18]) if e45_evidence is not None else raw + out['e3'] = check_e3(e3_raw, e3_evidence, b1_record) + out['stage'] = 'S3a' + if e45_evidence is not None: + out['e45'] = check_e45(raw, e45_evidence, e3_evidence[-1]['end']) + out['stage'] = 'S3b' + cps = raw['checkpoints'] + start_minute = 632 if raw['role'] == 'R' else 390 + eq.require(cps[0]['minute'] == start_minute, 'B1 minute') + for cp in cps: + eq.require(type(cp['minute']) is int, 'minute type') + k, c = cp['K'], cp['C'] + for key in ('absolute_minute', 'speed', 'snapshot_version', '_pause_request_serial'): + eq.require(integer(k[key]), 'K integer: ' + key) + for key in ('paused', '_skip_next_process', '_abort_current_tick_requested', '_last_tick_advanced'): + eq.require(type(k[key]) is bool, 'K boolean: ' + key) + eq.require(k['paused'] and k['absolute_minute'] == cp['minute'], 'clock contradiction') + eq.require(type(k['_phase_handlers']) is dict and set(k['_phase_handlers']) == {str(i) for i in range(11)}, 'exact phase key set 0..10') + for key in ('latest_digest', 'computed_latest_digest'): + eq.require(hex_sha(cp[key]), 'digest format') + eq.require(cp['observation']['before']['S'] == cp['S']['raw_bytes_sha'], 'S witness/transport contradiction') + eq.require(type(c['_mvp_manifest_cache_generation']) is int, 'cache generation') + eq.require(c['catalog_is_current'] is True, 'unfilled checkpoint cache') + ids = [c['catalog_instance_id'], c['current_catalog_instance_id']] + eq.require(all(type(v) is str and re.fullmatch('[1-9][0-9]*', v) for v in ids), 'cache instance IDs') + eq.require(ids[0] == ids[1], 'cache identity contradiction') + eq.validate_tree([29, c['_mvp_manifest_cache_bytes']]) + trees = eq.reconstruct_checkpoints(cps) + begin, begin_ids = counts(trees[0][0]) + end, end_ids = counts(trees[-1][0]) + eq.require(eq.exact(raw['event_start'], begin) and eq.exact(raw['event_end'], end), 'event counter/state contradiction') + event_ids = [] + for row in raw['events']: + tree = eq._transport(row['transport'], None) + data = fields(tree) + expected_keys = {'event_id', 'event_type', 'absolute_minute', 'source_service', 'entity_ids', 'payload', 'causation_command_id'} + eq.require(set(data) == expected_keys and tree[2] is None, 'event to_dictionary shape') + for name in ('event_id', 'event_type', 'source_service'): + eq.require(data[name][0] == 4 and bool(data[name][1]), 'serialized event String: ' + name) + for name in ('absolute_minute', 'causation_command_id'): + eq.require(data[name][0] == 2 and integer(data[name][1]), 'serialized event int: ' + name) + eq.require(start_minute <= data['absolute_minute'][1] <= start_minute + 30, 'event outside measurement') + ids = data['entity_ids'] + eq.require(ids[0] == 28 and ids[2] == [[2, 4], [21, ''], [0]] and all(v[0] == 4 for v in ids[1]), 'serialized entity_ids Array[String]') + eq.require(data['payload'][0] == 27, 'event payload Dictionary') + original = {'event_id': 21, 'event_type': 21, 'absolute_minute': 2, 'source_service': 21, + 'entity_ids': {'type': 28, 'typed_info': [[2, 21], [21, ''], [0]]}, + 'payload': {'type': 27, 'typed_info': data['payload'][2]}, 'causation_command_id': 2} + eq.require(eq.exact(row['original_field_types'], original), 'original event field types') + event_ids.append(data['event_id'][1]) + eq.require(len(set(event_ids)) == len(event_ids) and not set(event_ids).intersection(begin_ids), 'duplicate/reused event ID') + eq.require(set(end_ids) == set(begin_ids) | set(event_ids), 'missing/extra E2 events') + eq.require(end['counter'] - begin['counter'] == len(event_ids), 'event counter delta') + for row in raw['signal_order']: + eq.require(set(row) == {'signal', 'minute'} and row['signal'] in ('snapshot_published', 'state_updated'), 'signal record') + eq.require(type(row['minute']) is int and start_minute <= row['minute'] <= start_minute+30, 'signal minute') + check_measurement(raw, measurement) + out.update(ok=True, normalization=proofs, comparison=compared) + except (eq.EvidenceError, KeyError, TypeError, ValueError, IndexError) as exc: + out['errors'].append(str(exc)) + return out + + +def check_observation(cp, evidence): + """Bind retained full bytes to report SHA, not merely asserted equality.""" + eq.require(set(evidence) == {'before', 'after'}, 'observation evidence fields') + for side in ('before', 'after'): + row = evidence[side] + eq.require(set(row) == {'sha', 'S', 'K', 'C', 'kernel', 'cache'}, 'raw layer fields') + eq.require(eq.exact(row['kernel'], cp['K']) and eq.exact(row['cache'], cp['C']), 'raw layer value contradiction') + for layer in ('S', 'K', 'C'): + eq.validate_tree([29, row[layer]]) + actual = sha(base64.b64decode(row[layer], validate=True)) + eq.require(actual == row['sha'][layer] == cp['observation'][side][layer], 'raw layer SHA mismatch') + eq.require(all(evidence['before'][k] == evidence['after'][k] for k in ('S', 'K', 'C')), 'raw observation bytes differ') + return True + + +def read_report_stdout(stdout): + lines = [line[len('P28_02_EQ_REPORT='):] for line in stdout.splitlines() if line.startswith('P28_02_EQ_REPORT=')] + eq.require(len(lines) == 1, 'exactly one report line required') + return strict_json(lines[0]) + + +def strict_json(text): + def unique(pairs): + result = {} + for key, value in pairs: + eq.require(key not in result, 'duplicate JSON key: ' + key) + result[key] = value + return result + return json.loads(text, object_pairs_hook=unique) + + +def check_lifecycle(raw, lifecycle, guard): + """S2 startup proof; S4 must supply the separately SHA-bound guard receipt.""" + eq.require(lifecycle['stage'] in ('S2', 'S3a', 'S3b') and lifecycle['errors'] == [], 'probe errors/stage') + eq.require(lifecycle['stop_reason'] == {'S2': 'S2_complete_S3_pending', 'S3a': 'S3a_complete_S3b_pending', 'S3b': 'S3b_complete_S4_pending'}[lifecycle['stage']], 'probe did not finish stage') + if lifecycle['stage'] in ('S3a', 'S3b'): + check_measurement(raw, lifecycle['measurement']) + check_e3(dict(raw, scenarios=raw['scenarios'][:18]), lifecycle['e3'], lifecycle['e3_b1']) + if lifecycle['stage'] == 'S3b': + check_e45(raw, lifecycle['e45'], lifecycle['e3'][-1]['end']) + binding = lifecycle['guard'] + eq.require(guard['verified'] is True and eq.exact(binding['receipt'], guard), 'independent guard differs') + root = eq._profile(raw['profile_root']) + eq.require(root == binding['live_root'] == guard['actual_user_data_dir'], 'live/guard profile contradiction') + eq.require(hex_sha(binding['sha256']), 'guard SHA missing') + eq.require(eq.exact(lifecycle['observer_before'], lifecycle['observer_disconnected']), 'observers not restored') + eq.require(not eq.exact(lifecycle['observer_before'], lifecycle['observer_connected']), 'observers never connected') + b0 = 602 if raw['role'] == 'R' else 360 + for label, minute in (('B0', b0), ('B1', b0+30), ('outside', b0+60)): + row = lifecycle[label] + eq.require(row['kernel']['paused'] is True and row['kernel']['absolute_minute'] == minute, 'lifecycle minute: '+label) + for layer in ('S', 'K', 'C'): + eq.validate_tree([29, row[layer]]) + eq.require(sha(base64.b64decode(row[layer], validate=True)) == row['sha'][layer], 'lifecycle raw SHA') + for label in ('before_main', 'after_main', 'frame1', 'frame2'): + eq.require(type(lifecycle[label]) is dict and lifecycle[label]['kernel']['paused'] is True, 'startup frame evidence') + ops = lifecycle['ops'] + eq.require(ops['code'] == 'INVALID_START_TIME' if raw['role'] == 'R' else ops['ok'] is True, 'startup Ops outcome') + if raw['role'] == 'R': + restores = [r for r in lifecycle['preparation'] if r['operation'] == 'fixture_restore'] + eq.require(len(restores) == 1 and restores[0]['ok'] is True and restores[0]['input_sha256'] == + 'eb4f770071eb07cd7e136fe54c3f78768cc8de7a4264e62a9af1f06a8f90f9bd', 'fixture preparation') + return True + + +def _code(text): + # Mask strings/comments while retaining line positions. Tests exercise decoys. + return re.sub(r'"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\'|#[^\n]*', + lambda m: ' ' * len(m.group()), text) + + +def check_probe(text): + """Conservative S2 static policy, not a replacement for Godot parse/review.""" + errors = [] + code = _code(text) + if ':=' in code: + errors.append('inferred declarations forbidden; explicitly type Variant reads') + if re.search(r'\b(?:SimulationRuntimeService|GameClock|GameState|SimulationRuntime|EventBus)\s*\.', code): + errors.append('autoload static reference') + if re.search(r'\b(?:preload|load)\s*\(\s*["\']res://autoload/', text): + errors.append('autoload script import') + if re.search(r'\.(?:set_script|set|call|callv|call_deferred|set_deferred)\s*\(', code): + errors.append('dynamic product mutation/hook dispatch') + if re.search(r'\b(?:runtime|clock|main)\s*(?:\.[A-Za-z_]\w*|\[[^\n]*?\])+\s*(?:[+*/-]?=(?!=))', code): + errors.append('direct live assignment') + if re.search(r'\.(?:sort|sort_custom)\(', code): + for line in code.splitlines(): + if '.sort(' in line or ('.sort_custom(' in line and 'str(a) < str(b)' not in line and 'json_text(a) < json_text(b)' not in line): + errors.append('ordering must compare textual keys') + function = None + functions = {} + for line in text.splitlines(): + match = re.match(r'func (\w+)\(', line) + if match: + function = match[1] + functions[function] = [] + if function: functions[function].append(line) + clean = _code(line) + allowed_live = { + 'runtime': {'get', 'create_snapshot', 'restore_snapshot', 'load_from_path', 'get_save_policy', 'get_counter', 'subscribe', 'unsubscribe', 'connect', 'disconnect', 'get_facility_ids', 'get_bounds', 'preview_build_facility', 'submit_command', 'get_processed_result'}, + 'clock': {'get', 'set_paused', 'advance_minutes'}, + 'main': {'get', 'connect'}, + } + for receiver, method in re.findall(r'\b(runtime|clock|main)\s*(?:\.\w+)*\.(\w+)\s*\(', clean): + if method not in allowed_live[receiver]: errors.append('unlisted live method: '+receiver+'.'+method) + for method in re.findall(r'\.(\w+)\s*\(', clean): + if method in ('set_paused', 'restore_snapshot', 'advance_minutes', 'add_child', 'instantiate'): + required = 'step' if method == 'advance_minutes' else 'begin' + if function != required and not (method == 'restore_snapshot' and function in ('run_e3', 'run_e4')) and not (method == 'advance_minutes' and function in ('run_e4', 'run_e5')): errors.append('state-changing call outside preparation/stepping: ' + method) + if method in ('load_from_path', 'save_to_path', 'save_snapshot', 'load_snapshot', 'validate', 'enqueue', 'submit_command', 'enable_production_operations', 'initialize', 'reset', 'publish', 'publish_batch', '_set_speed', '_toggle_pause'): + if not ((method in ('load_from_path', 'validate') and function == 'run_e3') or (method == 'save_snapshot' and function == 'e3_prepare_package') or (method in ('load_from_path', 'save_snapshot', 'submit_command') and function == 'run_e4')): + errors.append('S3/unlisted state-changing call: ' + method) + if '.set_paused(' in clean and not re.search(r'\.set_paused\(true\)', clean): errors.append('only pause true allowed') + if '.advance_minutes(' in clean and not re.search(r'\.advance_minutes\(1\)', clean): errors.append('only one-minute stepping allowed') + # A digest alone, stub proof, or truncated checkpoint producer is not admitted. + required = { + 'transport': ('var_to_bytes(value)', 'var_to_bytes(decode(tree))', 'raw == rebuilt', 'encode(value)', 'hashed(json_text(tree).to_utf8_buffer())'), + 'checkpoint': ('layers()', 'transport(runtime.create_snapshot())', 'transport(latest_value)', 'before.s_bytes == after.s_bytes', 'before.k_bytes == after.k_bytes', 'before.c_bytes == after.c_bytes', 'diff_record(', 'write_evidence('), + 'bind_profile': ('ProjectSettings.globalize_path("user://").simplify_path()', 'receipt.get("actual_user_data_dir")', 'actual == live_root'), + 'observe_event': ('event.to_dictionary()', 'transport(value)', 'typeof(event.event_id)', 'typed_info(event.payload)', 'report.events.append('), + 'begin': ('runtime.domain_events.subscribe(&"*"', 'report.event_start = event_counts()', 'await step()', 'checkpoint()'), + 'finish': ('root.close_requested.emit()', 'runtime.domain_events.unsubscribe(', 'write_evidence("events.json"', 'write_evidence("lifecycle.json"'), + } + for name, snippets in required.items(): + body = '\n'.join(functions.get(name, [])) + # Comments cannot supply a required proof operation. + body = '\n'.join(line for line in body.splitlines() if not line.lstrip().startswith('#')) + for snippet in snippets: + if snippet not in body: errors.append('missing full-state/proof operation: ' + name + ': ' + snippet) + begin = '\n'.join(functions.get('begin', [])) + preparation, separator, rest = begin.partition('initial_inventory = inventory()') + if not separator or re.search(r'\.(?:restore_snapshot|set_paused|instantiate|add_child)\(', _code(rest)): + errors.append('preparation mutation after B0 boundary') + if code.count('.advance_minutes(') != 7 or code.count('.restore_snapshot(') != 3 or code.count('.set_paused(') != 2: + errors.append('unexpected mutation call count') + for name, snippets in { + 'run_e3': ('scenario_active = true', 'scenario_active = false', 'e3_observation()', 'runtime.restore_snapshot(input)', 'SimulationSnapshot.validate(input)', 'runtime.load_from_path(path)'), + 'e3_prepare_package': ('demand(scenario_active,', 'SaveService.save_snapshot(path, input, {})'), + }.items(): + body = '\n'.join(functions.get(name, [])) + for snippet in snippets: + if snippet not in body: errors.append('missing E3 boundary/call: '+name+': '+snippet) + if code.count('run_e3()') != 2 or code.count('e3_prepare_package(') != 2: + errors.append('unexpected scenario dispatch') + scenario_body = '\n'.join(functions.get('run_e3', [])) + prefix, opened, remaining = scenario_body.partition('scenario_active = true') + active, closed, suffix = remaining.partition('scenario_active = false') + if not opened or not closed or re.search(r'(?:restore_snapshot|load_from_path|validate|e3_prepare_package)\(', _code(prefix + suffix)): + errors.append('E3 operation outside active interval') + if text.count('print("P28_02_EQ_REPORT="') != 1: errors.append('single report emission required') + for name in ('run_e4', 'run_e5'): + body = '\n'.join(functions.get(name, [])) + prefix, opened, rest = body.partition('scenario_active = true') + active, closed, suffix = rest.partition('scenario_active = false') + if not opened or not closed or re.search(r'(?:advance_minutes|submit_command|restore_snapshot|load_from_path|save_snapshot|e4_candidates)\(|\breturned\s*\[', _code(prefix + suffix)): + errors.append('E4/E5 operation outside active interval') + if code.count(name+'()') != 2: errors.append('unexpected E4/E5 dispatch') + for name, body in functions.items(): + clean = _code('\n'.join(body)) + if name != 'run_e5' and re.search(r'\breturned\s*\[|__p28_eq_probe', '\n'.join(body)): + errors.append('ownership mutation outside E5') + if name in ('observe_snapshot', 'observe_state') and re.search(r'\[[^\n]*\]\s*=|\.(?:append|erase|clear|merge)\(', clean): + errors.append('signal handler mutation') + if name != 'run_e4' and 'e4_candidates()' in clean and name != 'e4_candidates': errors.append('candidate dispatch outside E4') + if code.count('e4_candidates()') != 2 or code.count('.submit_command(') != 2: errors.append('unexpected E4 command/search dispatch') + candidate_body = '\n'.join(functions.get('e4_candidates', [])) + for snippet in ('runtime.definition_registry.get_facility_ids()', 'runtime.world_service.get_bounds()', 'runtime.preview_build_facility(definition_id, origin, 0)', 'demand(scenario_active,', 'selection.trials.append('): + if snippet not in candidate_body: errors.append('missing E4 selection proof: '+snippet) + if re.search(r'report\.events\.(?:resize|pop_front|pop_back|erase|clear)', code): errors.append('event cap/removal forbidden') + return {'ok': not errors, 'stage': 'S3a', 'errors': errors} + + +# S3a source-backed E3 table; E4/E5 admission remains S3b. +E3_KINDS = ('missing_key', 'wrong_type', 'out_of_range', 'duplicate_published_ids', 'duplicate_facility', 'tampered_world') +E3_APIS = ('restore_snapshot', 'validate', 'load_from_path') + + +def node_at(tree, *names): + for name in names: + tree = fields(tree)[name] + return tree + + +def e3_expected_input(b1, kind): + value = copy.deepcopy(b1) + if kind == 'missing_key': + value[1] = [pair for pair in value[1] if pair[0][1] != 'clock'] + elif kind in ('wrong_type', 'out_of_range'): + node_at(value, 'clock', 'absolute_minute' if kind == 'wrong_type' else 'speed')[:] = ( + [4, 'x'] if kind == 'wrong_type' else [2, 9]) + elif kind in ('duplicate_published_ids', 'duplicate_facility'): + nodes = (node_at(value, 'systems', 'runtime', 'domain_events', 'published_ids') if kind == 'duplicate_published_ids' + else node_at(value, 'systems', 'runtime', 'facilities', 'instances')) + if nodes[1]: + nodes[1].append(copy.deepcopy(nodes[1][0])) + else: + eq.require(kind == 'duplicate_facility', 'no B1 published ID to duplicate') + return value + + +def e3_x(before, event): + value = copy.deepcopy(before) + counter = node_at(value, 'systems', 'runtime', 'id_generator', 'counters', 'domain_event') + counter[1] += 1 + domain = node_at(value, 'systems', 'runtime', 'domain_events') + ids = fields(domain)['published_ids'] + ids[1].append(copy.deepcopy(fields(event)['event_id'])) + ids[1].sort(key=lambda n: n[1]) + recent = fields(domain)['recent_events'] + dropped = copy.deepcopy(recent[1][0]) if len(recent[1]) == 256 else None + recent[1].append(copy.deepcopy(event)) + if len(recent[1]) > 256: + del recent[1][0] + return value, dropped + + +def e3_raw_observation(row): + cp = row['checkpoint'] + check_observation(cp, row['raw']) + s = eq._transport(cp['S'], None) + eq.require(cp['S']['raw_bytes_sha'] == row['raw']['before']['sha']['S'], 'E3 S transport/raw') + for layer in ('K', 'C'): + proof = row[layer+'_tree'] + eq._transport(proof, None) + eq.require(proof['raw_bytes_sha'] == row['raw']['before']['sha'][layer], 'E3 layer transport/raw') + return s + + +def e3_package_check(package, kind): + def files(rows): + eq.require(set(rows) == {'manifest.json', 'world.bin', 'thumbnail.png', 'journal.log'}, 'package inventory') + out = {} + for name, item in rows.items(): + if item is None: + out[name] = None + continue + eq.require(set(item) == {'bytes', 'sha256'}, 'package file fields') + content = base64.b64decode(item['bytes'], validate=True) + eq.require(sha(content) == item['sha256'], 'package file SHA') + out[name] = content + return out + saved = fields(eq._transport(package['save_return'], None)) + eq.require('ok' in saved and 'code' in saved, 'save preparation return') + original, modified = files(package['original']), files(package['modified']) + files(package['after_operation']) + if saved['ok'] == [1, 0]: + eq.require(kind.startswith('duplicate_'), 'required package save refused') + return False + eq.require(saved['ok'] == [1, 1], 'save preparation bool') + eq.require(all(original[n] == modified[n] for n in ('thumbnail.png', 'journal.log')), 'unlisted package mutation') + if kind == 'tampered_world': + expected = bytearray(original['world.bin']) + eq.require(len(expected) > 0, 'empty tamper world') + offset = len(expected)//2 + old = expected[offset] + expected[offset] ^= 1 + eq.require(modified['world.bin'] == bytes(expected) and original['manifest.json'] == modified['manifest.json'], 'D3 tamper rule') + eq.require(package['tamper'] == {'offset': offset, 'before': old, 'after': old ^ 1}, 'tamper evidence') + elif kind in ('missing_key', 'wrong_type', 'out_of_range'): + before, after = json.loads(original['manifest.json']), json.loads(modified['manifest.json']) + expected = copy.deepcopy(before) + if kind == 'missing_key': del expected['checksum_world'] + else: expected['format_version'] = 'x' if kind == 'wrong_type' else 2147483647 + eq.require(eq.exact(after, expected) and original['world.bin'] == modified['world.bin'], 'manifest mutation rule') + else: + eq.require(original == modified, 'duplicate package changed after save') + return True + + +def check_e3(raw, evidence, b1_record): + """Separate malformed evidence from observed existing-defect candidates. + + Returns all actual typed differences. Never promote NA or a defect to PASS. + """ + b1 = eq._transport(b1_record, None) + first = eq.reconstruct_checkpoints(raw['checkpoints'])[0][0] + eq.require(eq.exact(b1, first), 'E3 input is not measured B1') + facilities = node_at(b1, 'systems', 'runtime', 'facilities', 'instances') + count = len(facilities[1]) + eq.require(raw['role'] != 'R' or count > 0, 'R B1 has no facility') + expected_ids = ['E3/'+api+'/'+kind for api in E3_APIS for kind in E3_KINDS] + eq.require([s['id'] for s in raw['scenarios']] == expected_ids, 'complete ordered E3 applied/NA table') + eq.require([e['id'] for e in evidence] == expected_ids, 'E3 raw evidence coverage') + results = [] + previous_sha = raw['checkpoints'][-1]['observation']['after'] + for scenario, ev in zip(raw['scenarios'], evidence): + api, kind = scenario['operation'], scenario['result']['category'] + result = scenario['result'] + eq.require(set(result) == {'category', 'applicability', 'reason', 'invoked', 'facility_count', 'ok', 'errors', 'code', + 'code_reason', 'migration_attempted', 'event_count', 'path'}, 'E3 result fields') + eq.require(scenario['id'] == 'E3/'+api+'/'+kind, 'E3 API/category binding') + eq.require(result['facility_count'] == count, 'B1 facility count') + eq.require(ev['boundaries'] == ['begin', 'operation', 'end'], 'E3 interval boundaries') + expected_input = e3_expected_input(b1, kind) + eq.require(eq.exact(eq._transport(ev['input'], None), expected_input), 'fixed B1 mutation rule') + before, after = e3_raw_observation(ev['begin']), e3_raw_observation(ev['end']) + eq.require(eq.exact(previous_sha, ev['begin']['raw']['before']['sha']), 'unrecorded change between E3 intervals') + previous_sha = ev['end']['raw']['after']['sha'] + e3_raw_observation(ev['invocation_before']) + eq.require(eq.exact(scenario['checkpoints'], [ev['begin']['checkpoint'], ev['end']['checkpoint']]), 'E3 boundary binding') + events = [eq._transport(item, None) for item in ev['events']] + eq.require(eq.exact(events, scenario['events']) and type(result['event_count']) is int and result['event_count'] == len(events), 'E3 event count/evidence binding') + applied, reason, invoked = True, None, True + if kind == 'tampered_world' and api != 'load_from_path': + applied, reason, invoked = False, 'Dictionary API does not read packages', False + elif kind == 'duplicate_facility' and count == 0: + eq.require(raw['role'] == 'O', 'facility NA only for O') + applied, reason, invoked = False, 'B1 has zero facilities', False + elif kind.startswith('duplicate_') and api == 'validate': + applied, reason = False, 'Envelope validation does not inspect runtime internals' + if api == 'load_from_path': + eq.require(result['path'] == 'user://p28_eq/'+raw['role'].lower()+'/'+('duplicate_id' if kind.startswith('duplicate_') else kind), 'fixed scenario path') + if applied: + package_input = expected_input if kind.startswith('duplicate_') else b1 + eq.require(eq.exact(eq._transport(ev['package']['input'], None), package_input), 'package save input not fixed B1 copy') + if not e3_package_check(ev['package'], kind): + applied, reason, invoked = False, 'SaveService.save_snapshot refused duplicate input', False + else: + eq.require(ev['package'] is None, 'NA package unexpectedly prepared') + else: + eq.require(result['path'] is None and ev['package'] is None, 'Dictionary API package') + eq.require(result['applicability'] == ('applied' if applied else 'NA') and result['reason'] == reason and result['invoked'] is invoked, 'E3 applied/NA table contradiction') + actual = eq._transport(ev['return'], None) + eq.require(type(result['migration_attempted']) is bool, 'migration flag type') + if api != 'validate': + eq.require(result['errors'] is None, 'invented validation errors') + if api == 'restore_snapshot': + eq.require(result['code'] is None and result['code_reason'] == 'API returns bool only', 'restore invented code') + eq.require(actual == ([1, int(result['ok'])] if invoked and type(result['ok']) is bool else [0]), 'restore actual bool') + eq.require(not invoked or type(result['ok']) is bool, 'restore bool missing') + elif api == 'validate': + eq.require(result['code'] is None and result['code_reason'] == 'API returns ok/errors only', 'validate invented code') + if invoked: + data = fields(actual) + eq.require(set(data) == {'ok', 'errors'} and data['ok'] == [1, int(result['ok'])] and type(result['ok']) is bool, 'validate full return') + eq.require(data['errors'][0] == 28 and [v[1] for v in data['errors'][1]] == result['errors'] and all(v[0] == 4 for v in data['errors'][1]), 'validate errors full list') + elif invoked: + data = fields(actual) + eq.require('code' in data and data['code'][0] in (4, 21) and bool(data['code'][1]), 'load code missing') + eq.require(result['code'] == data['code'][1] and result['code_reason'] is None, 'load code binding') + eq.require(type(result['ok']) is bool and data['ok'] == [1, int(result['ok'])], 'load actual ok') + eq.require(result['migration_attempted'] is (data.get('migration_attempted', [1, 0]) == [1, 1]), 'migration fact') + if not invoked: + eq.require(actual == [0] and result['ok'] is None and result['code'] is None, 'NA has invented outcome') + defects = [] + expected_code, expected_error = None, None + if applied: + if result['ok'] is not False: defects.append({'kind': 'invalid_input_accepted', 'actual': actual}) + if api == 'validate': + expected_error = {'missing_key': 'missing_clock', 'wrong_type': 'invalid_absolute_minute', 'out_of_range': 'invalid_speed'}[kind] + if expected_error not in result['errors']: defects.append({'kind': 'expected_error_missing', 'expected': expected_error, 'actual': actual}) + if api == 'load_from_path': + expected_code = {'missing_key': 'INVALID_MANIFEST', 'wrong_type': 'INVALID_MANIFEST', 'out_of_range': 'UNSUPPORTED_FORMAT', + 'duplicate_published_ids': 'RESTORE_FAILED', 'duplicate_facility': 'RESTORE_FAILED', 'tampered_world': 'CHECKSUM_MISMATCH'}[kind] + if result['code'] != expected_code and not (kind == 'out_of_range' and result['migration_attempted']): + defects.append({'kind': 'unexpected_code', 'expected': expected_code, 'actual': result['code']}) + expected_count = 1 if api == 'load_from_path' and invoked else 0 + if len(events) != expected_count: + defects.append({'kind': 'event_count', 'expected': expected_count, 'actual': len(events)}) + expected_state, dropped = before, None + if expected_count == 1 and len(events) == 1: + event_data = fields(events[0]) + if event_data['event_type'] != [4, 'SAVE_LOAD_FAILED'] or event_data['source_service'] != [4, 'save_service'] or event_data['entity_ids'][1] != []: + defects.append({'kind': 'failure_event_shape', 'actual': events[0]}) + latest = eq._transport(ev['latest_save_operation_result'], None) + if not eq.exact(latest, event_data['payload']): + defects.append({'kind': 'failure_payload_latest_mismatch', 'latest': latest, 'payload': event_data['payload']}) + data = fields(actual) + payload = fields(event_data['payload']) + for name in ('ok', 'code'): + if not eq.exact(data[name], payload[name]): + defects.append({'kind': 'return_payload_mismatch', 'field': name, 'return': data[name], 'payload': payload[name]}) + for name in ('duration_us', 'runtime_duration_us', 'message', 'save_path'): + if name in data and not eq.exact(data[name], payload[name]): + defects.append({'kind': 'return_payload_mismatch', 'field': name, 'return': data[name], 'payload': payload[name]}) + if data.get('preload_pause_restored') != [1, 1] or data.get('loaded_clock_paused') != [1, int(ev['begin']['checkpoint']['K']['paused'])]: + defects.append({'kind': 'load_pause_outcome', 'actual': actual}) + if 'recovery_report' in data and fields(data['recovery_report']).get('restore_committed') != [1, 0]: + defects.append({'kind': 'load_restore_committed', 'actual': data['recovery_report']}) + expected_state, dropped = e3_x(before, events[0]) + normalized_expected, expected_side = eq.normalize_tree(expected_state, raw['profile_root']) + normalized_after, actual_side = eq.normalize_tree(after, raw['profile_root']) + delta = eq.compare_trees(normalized_expected, normalized_after) + if not delta['equal']: defects.append({'kind': 'S_changes', 'comparison': delta}) + for layer in ('K', 'C'): + left, right = ev['begin']['raw']['before'], ev['end']['raw']['after'] + if left[layer] != right[layer]: + defects.append({'kind': layer+'_changes', 'before': left[layer], 'after': right[layer], + 'comparison': eq.compare_trees(ev['begin'][layer+'_tree']['tree'], ev['end'][layer+'_tree']['tree'])}) + # Dictionary APIs require byte identity, not normalization/order fallback. + if expected_count == 0 and ev['begin']['raw']['before']['S'] != ev['end']['raw']['after']['S']: + defects.append({'kind': 'S_bytes_changed', 'before': ev['begin']['raw']['before']['S'], 'after': ev['end']['raw']['after']['S']}) + results.append({'id': scenario['id'], 'applicability': result['applicability'], 'reason': reason, + 'expected': {'ok': False if applied else None, 'code': expected_code, 'error': expected_error, 'event_count': expected_count}, + 'actual': copy.deepcopy(result), + 'status': 'existing-defect-candidate' if defects else ('recorded' if applied else 'NA'), + 'defects': defects, 'dropped_recent_event': dropped, 'expected_state': expected_state, + 'state_comparison': delta, 'expected_sidecar': expected_side, 'actual_sidecar': actual_side}) + results[-1]['exclusions'] = [{'reason': 'SaveService static diagnostic budget outside S/K/C; wall time', + 'before': eq._transport(ev['save_budget_before'], None), 'after': eq._transport(ev['save_budget_after'], None)}, + {'reason': 'Package manifest/file evidence outside S/E2; includes real timestamps', 'actual': ev['package']}] + return results + + + +# S3b additions. Raw evidence is authoritative; outcome labels are derived. +E4_PATHS = ('build_facility', 'tick', 'restore_snapshot', 'load_from_path', 'rejected_command') +E5_TARGETS = ('create_snapshot', 'latest_snapshot', 'snapshot_published', 'state_updated') +SORT_RULE = 'String(id) ascending Unicode code point' +CELL_RULE = 'inclusive x/y public bounds; z FRONT=0 through BACK=1; x,y,z lexical; ID outer; rotation=0' + + +def join_facts(value, profile_root): + """Normalize only snapshot transports; retain all raw facts in raw report.""" + proofs = [] + def walk(item, path): + if isinstance(item, dict) and {'tree', 'tree_sha', 'raw_bytes_sha', 'roundtrip_ok'} == set(item): + tree = eq._transport(item, None) + if path and path[-1] in ('held_before', 'held_after', 'input'): + normal, side = eq.normalize_tree(tree, profile_root) + eq.require(eq.exact(eq.restore_tree(normal, side, profile_root), tree), 'fact normalization roundtrip') + proofs.append({'path': path, 'sidecar': side, 'raw': item}) + return normal + return tree + if isinstance(item, dict): + return {k: walk(v, path+[k]) for k, v in item.items()} + if isinstance(item, list): + return [walk(v, path+[i]) for i, v in enumerate(item)] + return item + return walk(value, []), proofs + + +def e45_facts(detail): + facts = copy.deepcopy(detail) + for key in ('package_before', 'package_after', 'save_return', 'return', 'save_budget_before', 'save_budget_after', 'latest_save_operation_result', 'observation_before', 'observation_after'): + facts.pop(key, None) + if 'return' in detail: + actual = eq._transport(detail['return'], None) + facts['return_fact'] = ({k: fields(actual)[k][1] if fields(actual)[k][0] != 1 else bool(fields(actual)[k][1]) + for k in ('ok', 'code')} if actual[0] == 27 else bool(actual[1])) + for trial in facts.get('trials', []): + trial.pop('before', None); trial.pop('after', None) + return facts + + +def check_selection(detail, begin): + for key in ('observation_before', 'observation_after'): + eq.require(eq.exact(e3_raw_observation(detail[key]), begin), 'preview search S baseline') + eq.require(eq.exact(detail['observation_before']['raw'], detail['observation_after']['raw']), 'preview search changed full S/K/C') + eq.require(detail['source'] == 'definition_registry.get_facility_ids()', 'E4 registry source') + raw = eq._transport(detail['raw_ids'], None) + ordered = eq._transport(detail['sorted_ids'], None) + eq.require(raw[0] == ordered[0] == 28 and all(n[0] == 21 for n in raw[1]), 'facility ID types') + ids = [n[1] for n in raw[1]] + eq.require(type(detail['count']) is int and detail['count'] == len(ids) and len(ids) > 0 and len(set(ids)) == len(ids), 'empty/invalid facility registry') + eq.require(ordered[2] == raw[2] and ordered[1] == sorted(raw[1], key=lambda n: n[1]) and detail['sort_rule'] == SORT_RULE, 'facility sort rule') + eq.require(detail['cell_rule'] == CELL_RULE, 'cell scan rule') + bounds = eq._transport(detail['bounds'], None) + eq.require(eq.exact(bounds, node_at(begin, 'systems', 'runtime', 'world', 'bounds')), 'public bounds/state binding') + b = fields(bounds) + eq.require(set(b) == {'min_x', 'max_x', 'min_y', 'max_y'} and all(n[0] == 2 for n in b.values()), 'bounds shape') + eq.require(b['min_x'][1] <= b['max_x'][1] and b['min_y'][1] <= b['max_y'][1], 'empty scan bounds') + def candidates(): + for ident in sorted(ids): + for x in range(b['min_x'][1], b['max_x'][1]+1): + for y in range(b['min_y'][1], b['max_y'][1]+1): + for z in (0, 1): + yield ident, x, y, z + expected = candidates() + chosen = None + for trial in detail['trials']: + eq.require(chosen is None, 'trials after first placeable candidate') + wanted = next(expected, None) + eq.require(wanted is not None, 'extra candidate trial') + c = fields(eq._transport(trial['candidate'], None)) + eq.require(set(c) == {'definition_id', 'origin', 'rotation'} and c['definition_id'] == [21, wanted[0]] + and c['origin'] == [10, [[2, v] for v in wanted[1:]]] and c['rotation'] == [2, 0], 'missing/reordered candidate trial') + preview = fields(eq._transport(trial['preview'], None)) + eq.require(preview.get('can_build') in ([1, 0], [1, 1]), 'full preview result required') + eq.require(set(trial) == {'candidate', 'preview'}, 'preview trial fields') + if preview['can_build'] == [1, 1]: chosen = trial['candidate'] + if chosen is None: + eq.require(next(expected, None) is None, 'missing candidate trials') + eq.require(detail['chosen'] is None and detail['applicability'] == 'NA' and detail['reason'] == 'all registry/cell pairs rejected by public preview', 'false NA/reason') + eq.require('submit' not in detail and 'command_result' not in detail, 'NA executed command') + else: + eq.require(eq.exact(detail['chosen'], chosen) and detail['applicability'] == 'applied' and detail['reason'] is None, 'chosen without matching preview') + check_command(detail) + return chosen is not None + + +def check_command(detail): + submitted = fields(eq._transport(detail['submit'], None)) + completed = fields(eq._transport(detail['command_result'], None)) + eq.require(all(k in submitted and k in completed for k in ('command_id', 'code')), 'command result absent') + eq.require(submitted['command_id'] == completed['command_id'] and submitted['command_id'][0] == 2, 'command ID binding') + eq.require(submitted['code'][0] == completed['code'][0] == 4, 'actual command code required') + return completed + + +def check_e45(raw, evidence, previous): + ids = ['E4/'+p for p in E4_PATHS] + ['E5/'+t+'/'+l+'/'+d for t in E5_TARGETS + for l in ('dict', 'array') for d in ('outside_in', 'inside_out')] + scenarios = raw['scenarios'][18:] + eq.require([s['id'] for s in scenarios] == ids and [e['id'] for e in evidence] == ids, 'complete ordered E4/E5 coverage') + outcomes = [] + previous_sha = previous['raw']['after']['sha'] + for scenario, ev in zip(scenarios, evidence): + eq.require(set(ev) == {'id', 'boundaries', 'observations', 'events', 'signals', 'detail'}, 'E4/E5 evidence fields') + eq.require(ev['boundaries'] == ['begin', 'operation', 'end'], 'E4/E5 boundaries') + obs, detail = ev['observations'], ev['detail'] + eq.require(eq.exact(detail['signals'], ev['signals']), 'scenario signals/facts binding') + if scenario['id'].startswith('E5/'): + eq.require(set(detail) == {'target', 'location', 'direction', 'digest_materialized_before', 'held_before', 'held_after', 'signals'}, 'E5 detail fields') + else: + common = {'save_budget_before', 'save_budget_after', 'signals'} + specific = { + 'build_facility': {'source', 'raw_ids', 'count', 'sorted_ids', 'sort_rule', 'bounds', 'cell_rule', 'trials', 'chosen', 'applicability', 'reason', 'observation_before', 'observation_after'}, + 'tick': set(), 'restore_snapshot': {'input', 'return'}, + 'load_from_path': {'input', 'path', 'save_return', 'package_before', 'package_after', 'return', 'latest_save_operation_result'}, + 'rejected_command': {'submit', 'command_result'}, + }[scenario['operation']] + if scenario['operation'] == 'build_facility' and detail.get('chosen') is not None: specific |= {'submit', 'command_result'} + eq.require(set(detail) == common | specific, 'E4 detail fields; no invented staleness verdict') + eq.require(len(obs) >= 2, 'E4/E5 missing observations') + trees = [e3_raw_observation(o) for o in obs] + eq.require(eq.exact(previous_sha, obs[0]['raw']['before']['sha']), 'E4/E5 interval gap') + previous_sha = obs[-1]['raw']['after']['sha'] + eq.require(eq.exact(scenario['checkpoints'], [o['checkpoint'] for o in obs]), 'E4/E5 observation binding') + events = [eq._transport(e, None) for e in ev['events']] + result = scenario['result'] + eq.require(set(result) == {'event_count', 'applicability', 'reason', 'facts'}, 'E4/E5 result fields; caller PASS forbidden') + eq.require(type(result['event_count']) is int and result['event_count'] == len(events) + and eq.exact(events, scenario['events']), 'E4/E5 event count binding') + eq.require(result['applicability'] == detail.get('applicability', 'applied') and result['reason'] == detail.get('reason'), 'E4/E5 applicability binding') + eq.require(eq.exact(result['facts'], e45_facts(detail)), 'E4/E5 facts binding/aliasing record missing') + for signal in ev['signals']: + eq.require(set(signal) == {'signal', 'minute'} and signal['signal'] in ('snapshot_published', 'state_updated') + and obs[0]['checkpoint']['minute'] <= signal['minute'] <= obs[-1]['checkpoint']['minute'], 'scenario signal interval') + eq.require(len(ev['signals']) % 2 == 0, 'scenario signal pair missing') + for i in range(0, len(ev['signals']), 2): + a, b = ev['signals'][i:i+2] + eq.require(a['signal'] == 'snapshot_published' and b == {'signal': 'state_updated', 'minute': a['minute']}, 'scenario signal order') + defects = [] + differences = {} + for name in ('S', 'latest'): + a, b = [eq._transport(o['checkpoint'][name], None) for o in (obs[0], obs[-1])] + differences[name] = eq.compare_trees(a, b) + for name in ('K', 'C'): + differences[name] = eq.compare_trees(obs[0][name+'_tree']['tree'], obs[-1][name+'_tree']['tree']) + op = scenario['operation'] + begin_count, begin_ids = counts(trees[0]) + end_count, end_ids = counts(trees[-1]) + event_ids = [fields(event)['event_id'][1] for event in events] + eq.require(len(set(event_ids)) == len(event_ids) and not set(event_ids).intersection(begin_ids) + and set(end_ids) == set(begin_ids) | set(event_ids) + and end_count['counter'] - begin_count['counter'] == len(events), 'E4/E5 full event coverage') + if scenario['id'].startswith('E4/'): + eq.require(scenario['id'] == 'E4/'+op, 'E4 operation') + for key in ('save_budget_before', 'save_budget_after'): + eq.require(set(fields(eq._transport(detail[key], None))) == {'_samples', '_totals', '_sample_counts'}, 'save diagnostic budget missing') + applied = True + if op == 'build_facility': applied = check_selection(detail, trees[0]) + else: eq.require(result['applicability'] == 'applied' and result['reason'] is None, 'unlisted E4 NA') + count = 3 if op == 'rejected_command' or (op == 'build_facility' and applied) else 2 + eq.require(len(obs) == count, 'submit/immediate E4 checkpoint missing') + tick = op in ('tick', 'rejected_command') or (op == 'build_facility' and applied) + eq.require(obs[-1]['checkpoint']['minute'] == obs[0]['checkpoint']['minute'] + int(tick), 'E4 tick count') + if len(obs) == 3: eq.require(obs[1]['checkpoint']['minute'] == obs[0]['checkpoint']['minute'], 'submit checkpoint delayed') + if op in ('restore_snapshot', 'load_from_path'): + p = eq._transport(detail['input'], None) + eq.require(eq.exact(p, trees[0]), 'E4 input not current deep copy') + actual = eq._transport(detail['return'], None) + expected = p + if op == 'restore_snapshot': + eq.require(actual == [1, 1], 'E4 restore did not succeed') + eq.require(len(events) == 0, 'restore must emit zero events') + else: + eq.require(fields(actual).get('ok') == [1, 1] and 'code' in fields(actual), 'E4 load did not succeed') + eq.require(detail['path'] == 'user://p28_eq/'+raw['role'].lower()+'/good', 'fixed E4 path') + eq.require(len(events) == 1 and fields(events[0])['event_type'] == [4, 'SAVE_LOADED'], 'load must emit one SAVE_LOADED') + eq.require(fields(events[0])['source_service'] == [4, 'save_service'], 'load event source') + eq.require(eq.exact(eq._transport(detail['latest_save_operation_result'], None), fields(events[0])['payload']), 'load payload/latest result mismatch') + expected, dropped = e3_x(p, events[0]) + package = {'save_return': detail['save_return'], 'original': detail['package_before'], + 'modified': detail['package_before'], 'after_operation': detail['package_after']} + e3_package_check(package, 'good') + left, left_side = eq.normalize_tree(expected, raw['profile_root']) + right, right_side = eq.normalize_tree(trees[-1], raw['profile_root']) + delta = eq.compare_trees(left, right) + eq.require(delta['equal'], 'E4 restore/load X(P,event) mismatch') + differences['expected_state'] = {'comparison': delta, 'expected': expected, 'sidecars': [left_side, right_side]} + if op == 'rejected_command': + command = check_command(detail) + eq.require(command['code'] != [4, 'OK'], 'nonchanging command not rejected') + # All paths retained, including tick effects; do not assert equivalence from digest. + differences['submit'] = eq.compare_trees(trees[0], trees[1]) + differences['tick'] = eq.compare_trees(trees[1], trees[2]) + else: + _, target, location, direction = scenario['id'].split('/') + eq.require(op == direction and all(detail[k] == v for k, v in [('target', target), ('location', location), ('direction', direction)]), 'E5 target/direction') + eq.require(result['applicability'] == 'applied' and result['reason'] is None and len(obs) == 4, 'E5 coverage/NA') + eq.require(detail['digest_materialized_before'] is True, 'E5 digest not materialized') + minutes = [o['checkpoint']['minute'] for o in obs] + eq.require(minutes == [minutes[0], minutes[0]+1, minutes[0]+1+int(direction == 'inside_out'), minutes[0]+2+int(direction == 'inside_out')], 'E5 preparation/operation/reset tick sequence') + held = eq._transport(detail['held_before'], None) + after_held = eq._transport(detail['held_after'], None) + baseline = obs[1]['checkpoint'] + expected_held = eq._transport(baseline['S' if target == 'create_snapshot' else 'latest'], None) + eq.require(eq.exact(held, expected_held), 'E5 returned target binding') + if direction == 'outside_in': + expected = copy.deepcopy(held) + if location == 'dict': + n = node_at(expected, 'systems', 'runtime', 'id_generator', 'counters') + eq.require('__p28_eq_probe' not in fields(n), 'E5 marker already present') + n[1].append([[4, '__p28_eq_probe'], [2, 1]]) + else: + node_at(expected, 'systems', 'runtime', 'domain_events', 'published_ids')[1].append([4, '__p28_eq_probe']) + eq.require(eq.exact(expected, after_held), 'E5 fixed nested mutation absent/extra') + for layer in ('S', 'latest'): + delta = eq.compare_trees(eq._transport(obs[1]['checkpoint'][layer], None), eq._transport(obs[2]['checkpoint'][layer], None)) + differences['ownership_'+layer] = delta + if not delta['equal']: defects.append({'kind': 'external_mutation_'+layer, 'comparison': delta}) + old, new = obs[1]['checkpoint'], obs[2]['checkpoint'] + for field in ('latest_digest', 'computed_latest_digest'): + differences[field] = {'before': old[field], 'after': new[field]} + if old[field] != new[field]: defects.append({'kind': field+'_changed', 'before': old[field], 'after': new[field]}) + if new['latest_digest'] != new['computed_latest_digest']: + defects.append({'kind': 'cached_digest_aliasing', 'actual': new['latest_digest'], 'computed': new['computed_latest_digest']}) + else: + delta = eq.compare_trees(held, after_held) + differences['held'] = delta + if not delta['equal']: defects.append({'kind': 'internal_mutation_of_returned_value', 'comparison': delta}) + for layer in ('K', 'C'): + differences['ownership_'+layer] = eq.compare_trees(obs[1][layer+'_tree']['tree'], obs[2][layer+'_tree']['tree']) + eq.require(len(events) == counts(trees[-1])[0]['counter']-counts(trees[0])[0]['counter'], 'E5 uncapped event counter delta') + outcomes.append({'id': scenario['id'], 'status': 'existing-defect' if defects else ('NA' if result['applicability'] == 'NA' else 'recorded'), + 'defects': defects, 'differences': differences, 'signals': ev['signals'], + 'latest_policy': 'record actual value; publication timing is not cache staleness', + 'exclusions': [{'reason': 'Save package wall time and raw API timing; state/event normalization remains closed F1-F3', + 'actual': {k: detail[k] for k in ('save_return', 'return', 'package_before', 'package_after', 'save_budget_before', 'save_budget_after', 'latest_save_operation_result') if k in detail}}]}) + return outcomes + + +def main(): + import argparse + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--report', type=Path, required=True) + parser.add_argument('--lifecycle', type=Path, required=True) + parser.add_argument('--probe', type=Path, default=Path(__file__).with_name('eq_probe.gd')) + args = parser.parse_args() + life = strict_json(args.lifecycle.read_text()) + result = {'format': check_report(strict_json(args.report.read_text()), life['measurement'], life['e3'], life['e3_b1'], life.get('e45')), 'static': check_probe(args.probe.read_text())} + print(json.dumps(result, ensure_ascii=False)) + return 0 if all(item['ok'] for item in result.values()) else 1 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py new file mode 100644 index 0000000..656558c --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/compare_versions.py @@ -0,0 +1,651 @@ +"""S1 pure-Python typed transport/comparison. No engine or product imports. + +Paths are lists of ['key', key_node] / ['index', integer] segments. +Transport validation is distinct from product acceptance (see IMPLEMENTATION.md). +""" +import base64 +import copy +import hashlib +import json +import re + + +class EvidenceError(ValueError): + """Malformed, incomplete, or unauthorized evidence transformation.""" + + +SAVE_EVENTS = frozenset('SAVE_CHECKPOINT_SUCCEEDED SAVE_CHECKPOINT_FAILED SAVE_LOADED ' + 'SAVE_LOAD_FAILED SAVE_MIGRATION_SUCCEEDED SAVE_MIGRATION_FAILED SAVE_RECOVERY_LOADED ' + 'SAVE_RECOVERY_CANDIDATE_LOADED SAVE_RECOVERY_FAILED'.split()) +OPT_PATHS = frozenset(('autoload/simulation_runtime.gd', 'scripts/core/simulation_snapshot.gd', + 'scripts/world/world_service.gd', 'scripts/world/route_subslot_path_adapter.gd', + 'scripts/world/path_service.gd', 'scripts/core/command_queue.gd')) +SOURCE_SHA = '651f703621c8ed06a724709f75d8bc05b1eef2988c3b3d5d3466096a3f759bf0' +TOKEN = '{PRIVATE_USER_ROOT}/' + + +def require(ok, message): + if not ok: + raise EvidenceError(message) + + +def json_bytes(value): + return json.dumps(value, ensure_ascii=False, separators=(',', ':'), allow_nan=False).encode('utf-8') + + +def exact(a, b): + return json_bytes(a) == json_bytes(b) + + +def validate_tree(node): + """Validate all nodes; no application depth cutoff or value coercion.""" + pending = [node] + while pending: + n = pending.pop() + require(type(n) is list and n and type(n[0]) is int, 'invalid typed node') + t = n[0] + require(t not in (23, 24, 25, 26) and 0 <= t <= 38, 'unsupported Variant type') + require(len(n) == (1 if t == 0 else 3 if t in (27, 28) else 2), 'node arity') + if t == 0: + continue + p = n[1] + if t in (1, 2): + require(type(p) is int and (p in (0, 1) if t == 1 else -(2**63) <= p < 2**63), 'integer payload') + elif t == 3: + require(type(p) is str and re.fullmatch('[0-9a-f]{16}', p), 'float must be f64 LE hex') + elif t in (4, 21, 22): + require(type(p) is str, 'string payload') + elif t == 29: + require(type(p) is str, 'byte array payload') + try: + require(base64.b64encode(base64.b64decode(p, validate=True)).decode() == p, 'noncanonical base64') + except (ValueError, TypeError) as exc: + raise EvidenceError('invalid base64') from exc + elif t == 27: + require(type(p) is list, 'dictionary entries') + seen = set() + for pair in p: + require(type(pair) is list and len(pair) == 2, 'dictionary pair') + key = json_bytes(pair[0]) + require(key not in seen, 'duplicate dictionary key') + seen.add(key) + pending.extend(pair) + _typed_info(n[2], dictionary=True) + elif t == 28: + require(type(p) is list, 'array elements') + _typed_info(n[2], dictionary=False) + pending.extend(p) + else: + require(type(p) is list, 'component nodes') + sizes = {5: 2, 6: 2, 7: 4, 8: 4, 9: 3, 10: 3, 11: 6, + 12: 4, 13: 4, 14: 4, 15: 4, 16: 6, 17: 9, 18: 12, 19: 16, 20: 4} + if t in sizes: + require(len(p) == sizes[t], 'component count') + integer = t in (6, 8, 10, 13) + require(all(x and x[0] == (2 if integer else 3) for x in p), 'component type') + elif t in (30, 31, 32, 33, 34): + expected = {30: 2, 31: 2, 32: 3, 33: 3, 34: 4}[t] + require(all(x and x[0] == expected for x in p), 'packed element type') + else: + require(all(x and x[0] == {35: 5, 36: 9, 37: 20, 38: 12}[t] for x in p), 'packed vector type') + pending.extend(p) + return node + + +def _typed_info(info, dictionary): + # Metadata uses nodes too: builtin int, class StringName, script null. + if info is None: + return + require(type(info) is list and len(info) == (2 if dictionary else 3), 'typed metadata') + rows = info if dictionary else [info] + for row in rows: + require(type(row) is list and len(row) == 3, 'typed metadata row') + for n in row: + validate_tree(n) + require(row[0][0] == 2 and row[1][0] == 21 and row[2] == [0], 'unsupported typed script metadata') + + +def tree_sha(tree): + validate_tree(tree) + return hashlib.sha256(json_bytes(tree)).hexdigest() + + +def _key_segment(key): + return ['key', copy.deepcopy(key)] + + +def _field(node, name): + if node[0] != 27: + return None + found = [v for k, v in node[1] if k[0] in (4, 21) and k[1] == name] + require(len(found) <= 1, 'ambiguous textual key: ' + name) + return found[0] if found else None + + +def _text(node): + return node[1] if node and node[0] in (4, 21) else None + + +def _at(tree, path): + n = tree + for segment in path: + require(type(segment) is list and len(segment) == 2, 'path segment') + kind, value = segment + if kind == 'key': + require(n[0] == 27, 'key path through non-dictionary') + matches = [v for k, v in n[1] if exact(k, value)] + require(len(matches) == 1, 'missing/ambiguous key path') + n = matches[0] + else: + require(kind == 'index' and n[0] == 28 and type(value) is int and 0 <= value < len(n[1]), 'array path') + n = n[1][value] + return n + + +def _put(tree, path, value): + target = _at(tree, path) + target[:] = copy.deepcopy(value) + + +def apply_diff(tree, operations): + result = copy.deepcopy(validate_tree(tree)) + require(type(operations) is list, 'diff operations') + for op in operations: + require(type(op) is dict and 'op' in op and type(op.get('path')) is list, 'diff operation') + target = _at(result, op['path']) + kind = op['op'] + if kind == 'set': + require(set(op) == {'op', 'path', 'node'}, 'set fields') + _put(result, op['path'], validate_tree(op['node'])) + elif kind == 'dict_insert': + require(set(op) == {'op', 'path', 'index', 'key_node', 'value_node'}, 'insert fields') + require(target[0] == 27 and type(op['index']) is int and 0 <= op['index'] <= len(target[1]), 'insert index') + validate_tree(op['key_node']); validate_tree(op['value_node']) + require(not any(exact(k, op['key_node']) for k, _ in target[1]), 'insert duplicate') + target[1].insert(op['index'], copy.deepcopy([op['key_node'], op['value_node']])) + elif kind == 'dict_remove': + require(set(op) == {'op', 'path', 'key_node'} and target[0] == 27, 'remove fields') + indexes = [i for i, (k, _) in enumerate(target[1]) if exact(k, op['key_node'])] + require(len(indexes) == 1, 'remove missing key') + target[1].pop(indexes[0]) + elif kind == 'array_splice': + require(set(op) == {'op', 'path', 'start', 'delete_count', 'nodes'} and target[0] == 28, 'splice fields') + start, count = op['start'], op['delete_count'] + require(type(start) is int and type(count) is int and 0 <= start <= len(target[1]) and 0 <= count <= len(target[1])-start, 'splice bounds') + require(type(op['nodes']) is list, 'splice nodes') + for n in op['nodes']: + validate_tree(n) + target[1][start:start+count] = copy.deepcopy(op['nodes']) + else: + raise EvidenceError('unknown diff operation') + validate_tree(result) + return result + + +def reconstruct_checkpoints(checkpoints): + """Each checkpoint has S and latest transport records; verify before use.""" + require(type(checkpoints) is list and checkpoints, 'missing checkpoints') + result, previous = [], None + for cp in checkpoints: + s = _transport(cp['S'], previous) + latest = cp['latest'] + if latest.get('same_as_S') is True: + require(set(latest) == {'same_as_S', 'tree_sha', 'raw_bytes_sha', 'roundtrip_ok'}, 'same_as_S fields') + _proof(latest, s) + require(latest['raw_bytes_sha'] == cp['S']['raw_bytes_sha'], 'same_as_S byte mismatch') + l = copy.deepcopy(s) + else: + l = _transport(latest, s) + result.append((s, l)) + previous = s + return result + + +def _proof(record, tree): + require(record.get('roundtrip_ok') is True, 'Godot roundtrip missing/failed') + require(type(record.get('raw_bytes_sha')) is str and re.fullmatch('[0-9a-f]{64}', record['raw_bytes_sha']), 'raw bytes SHA') + require(record.get('tree_sha') == tree_sha(tree), 'tree SHA mismatch') + + +def _transport(record, baseline): + require(('tree' in record) != ('diff' in record), 'tree/diff exclusive') + require(set(record) == {'tree' if 'tree' in record else 'diff', 'tree_sha', 'raw_bytes_sha', 'roundtrip_ok'}, 'transport fields') + if 'tree' in record: + tree = copy.deepcopy(record['tree']) + else: + require(baseline is not None, 'diff without baseline') + tree = apply_diff(baseline, record['diff']) + _proof(record, tree) + return tree + + +def compare_trees(a, b): + validate_tree(a); validate_tree(b) + differences, orders = [], [] + def diff(path, x, y): + differences.append({'path': copy.deepcopy(path), 'a': copy.deepcopy(x), 'b': copy.deepcopy(y)}) + def walk(x, y, path): + if exact(x, y): + return + if x[0] != y[0] or len(x) != len(y): + diff(path, x, y); return + t = x[0] + if t in (27, 28) and not exact(x[2], y[2]): + diff(path + [['metadata', 0]], x[2], y[2]) + if t == 27: + def keyed(n): + d = {} + for k, v in n[1]: + text = _key_text(k) + require(text not in d, 'duplicate textual dictionary key') + d[text] = (k, v) + return d + dx, dy = keyed(x), keyed(y) + if set(dx) == set(dy) and [_key_text(k) for k, _ in x[1]] != [_key_text(k) for k, _ in y[1]]: + orders.append(copy.deepcopy(path)) + for key in sorted(set(dx) | set(dy)): + if key not in dx or key not in dy: + diff(path + [['key', [4, key]]], dx.get(key), dy.get(key)); continue + kx, vx = dx[key]; ky, vy = dy[key] + p = path + [_key_segment(kx)] + if not exact(kx, ky): + diff(p + [['key_type', 0]], kx, ky) + walk(vx, vy, p) + elif t == 28 or t in range(5, 21) or t in range(30, 39): + for i in range(max(len(x[1]), len(y[1]))): + if i >= len(x[1]) or i >= len(y[1]): + diff(path + [['index', i]], x[1][i] if i < len(x[1]) else None, y[1][i] if i < len(y[1]) else None) + else: + walk(x[1][i], y[1][i], path + [['index', i]]) + else: + diff(path, x, y) + walk(a, b, []) + return {'equal': not differences, 'exact': exact(a, b), 'differences': differences, 'dict_order_paths': orders} + + +def _key_text(key): + """Textual ordering never erases the original key node/type. + + Non-string keys use a lossless textual transport spelling, avoiding any + conversion of float bits or compound values to approximate decimal text. + """ + if key[0] in (4, 21, 22): + return key[1] + if key[0] == 2: + return str(key[1]) + if key[0] == 1: + return 'true' if key[1] else 'false' + if key[0] == 0: + return '' + return json_bytes(key).decode('utf-8') + + +def _profile(profile_root): + require(type(profile_root) is dict and set(profile_root) == {'root', 'actual_user_data_dir'}, 'guard-bound profile required') + root = profile_root['root'] + require(type(root) is str and root.startswith('/') and root != '/' and not root.endswith('/') and '/..' not in root and '/./' not in root, 'profile root must be simplified absolute path') + require(root == profile_root['actual_user_data_dir'], 'profile root/guard mismatch') + return root + + +def _marker(key, node): + require(node[0] == 2 and node[1] >= 0, 'timing must be nonnegative int') + return [27, [[[4, 'redacted_timing'], [4, key]], [[4, 'typeof'], [2, node[0]]]], None] + + +def _normalize(trees, profile_root, events): + root = _profile(profile_root) + result = copy.deepcopy(trees) + side = {'entries': [], 'violations': [], 'profile_root': {**profile_root, 'matches_guard': True}} + def visit(n, path, event_index, permitted_payload=False, event_root=False): + if n[0] == 27: + if permitted_payload: + require(_field(n, 'duration_us') is not None and _field(n, 'runtime_duration_us') is not None, 'save payload requires both timing fields') + event_ok = (event_root and _text(_field(n, 'source_service')) == 'save_service' and _text(_field(n, 'event_type')) in SAVE_EVENTS) + for k, v in n[1]: + name = _text(k) + p = path + [_key_segment(k)] + if permitted_payload and name in ('duration_us', 'runtime_duration_us'): + old = copy.deepcopy(v) + v[:] = _marker(name, v) + side['entries'].append({'event_index': event_index, 'path': p, 'key': name, 'original_node': old}) + elif permitted_payload and name == 'message' and v[0] == 4 and root + '/' in v[1]: + require(TOKEN not in v[1], 'ambiguous preexisting root token') + old = copy.deepcopy(v) + v[1] = v[1].replace(root + '/', TOKEN) + side['entries'].append({'event_index': event_index, 'path': p, 'key': name, 'original_node': old, 'root': root}) + else: + if name and (name.endswith('_us') or name.endswith('_ms')): + side['violations'].append({'event_index': event_index, 'path': p, 'kind': 'outside_timing', 'node': copy.deepcopy(v)}) + visit(v, p, event_index, event_ok and name == 'payload') + # Keys are values too; they are never eligible for F1-F3. + if k[0] in (4, 21) and root in k[1]: + side['violations'].append({'event_index': event_index, 'path': p, 'kind': 'profile_in_key', 'node': copy.deepcopy(k)}) + elif n[0] == 28: + for i, child in enumerate(n[1]): + visit(child, path + [['index', i]], event_index) + elif n[0] in (4, 21) and root in n[1]: + side['violations'].append({'event_index': event_index, 'path': path, 'kind': 'outside_profile', 'node': copy.deepcopy(n)}) + for i, t in enumerate(result): + validate_tree(t) + pending = [t] + while pending: + node = pending.pop() + if node[0] in (4, 21, 22): + require(TOKEN not in node[1], 'reserved normalization token in raw/restored tree') + elif node[0] == 27: + for pair in node[1]: + pending.extend(pair) + elif node[0] == 28 or 5 <= node[0] <= 20 or 30 <= node[0] <= 38: + pending.extend(node[1]) + if events: + require(t[0] == 27, 'event dictionary required') + visit(t, [], i, event_root=True) + else: + # Only the product recent_events location is eligible in snapshots. + # Traverse everything for violations, enabling events solely there. + _visit_snapshot(t, root, side, visit) + return result, side + + +def _visit_snapshot(tree, root, side, visit): + permitted = ['systems', 'runtime', 'domain_events', 'recent_events'] + def walk(n, path, names): + if names == permitted: + require(n[0] == 28, 'recent_events array required') + for i, event in enumerate(n[1]): + visit(event, path + [['index', i]], None, event_root=True) + return + if n[0] == 27: + for k, v in n[1]: + name = _text(k) + p = path + [_key_segment(k)] + if name and (name.endswith('_us') or name.endswith('_ms')): + side['violations'].append({'event_index': None, 'path': p, 'kind': 'outside_timing', 'node': copy.deepcopy(v)}) + walk(v, p, names + [name]) + elif n[0] == 28: + for i, child in enumerate(n[1]): + walk(child, path + [['index', i]], names + [i]) + elif n[0] in (4, 21) and root in n[1]: + side['violations'].append({'event_index': None, 'path': path, 'kind': 'outside_profile', 'node': copy.deepcopy(n)}) + walk(tree, [], []) + + +def normalize_events(events, profile_root): + require(type(events) is list, 'event list required') + return _normalize(events, profile_root, True) + + +def normalize_tree(tree, profile_root): + normalized, side = _normalize([tree], profile_root, False) + return normalized[0], side + + +def _restore(normalized, sidecar, profile_root, events): + root = _profile(profile_root) + require(type(sidecar) is dict and set(sidecar) == {'entries', 'violations', 'profile_root'}, 'sidecar fields') + require(sidecar['profile_root'] == {**profile_root, 'matches_guard': True}, 'sidecar profile') + require(type(sidecar['entries']) is list and type(sidecar['violations']) is list, 'sidecar lists') + result = copy.deepcopy(normalized) + seen = set() + for entry in sidecar['entries']: + require(set(entry) == {'event_index', 'path', 'key', 'original_node'} | ({'root'} if entry.get('key') == 'message' else set()), 'entry fields') + index = entry['event_index'] + require((type(index) is int and 0 <= index < len(result)) if events else index is None, 'entry event index') + identity = json_bytes([index, entry['path']]) + require(identity not in seen, 'duplicate sidecar entry') + seen.add(identity) + target = result[index] if events else result + original = validate_tree(entry['original_node']) + if entry['key'] == 'message': + require(entry['root'] == root and original[0] == 4 and root+'/' in original[1] and TOKEN not in original[1], 'message sidecar') + expected = [4, original[1].replace(root+'/', TOKEN)] + else: + require(entry['key'] in ('duration_us', 'runtime_duration_us'), 'outside closed list') + expected = _marker(entry['key'], original) + require(exact(_at(target, entry['path']), expected), 'sidecar does not match normalized node') + _put(target, entry['path'], original) + # Re-running the closed policy rejects missing entries and forged paths, + # including attempts to normalize a violation. Raw tree SHA is also checked + # by the caller against the independently retained transport proof. + normal2, side2 = normalize_events(result, profile_root) if events else normalize_tree(result, profile_root) + require(exact(normal2, normalized) and exact(side2, sidecar), 'non-reversible/unauthorized sidecar') + return result + + +def restore_events(normalized, sidecar, profile_root): + return _restore(normalized, sidecar, profile_root, True) + + +def restore_tree(normalized, sidecar, profile_root): + return _restore(normalized, sidecar, profile_root, False) + + +def check_source_closure(before_map, after_map, allowed_changed): + require(type(before_map) is dict and type(after_map) is dict, 'source maps required') + require(type(allowed_changed) in (list, set, frozenset, tuple), 'registered change set required') + allowed = set(allowed_changed) + errors = [] + for mapping in (before_map, after_map): + for name, row in mapping.items(): + require(type(name) is str and type(row) is dict and set(row) == {'bytes', 'sha256'}, 'source row fields') + require(type(row['bytes']) is int and row['bytes'] >= 0 and type(row['sha256']) is str and re.fullmatch('[0-9a-f]{64}', row['sha256']), 'source row values') + digest = hashlib.sha256(json.dumps(before_map, sort_keys=True, separators=(',', ':')).encode()).hexdigest() + if len(before_map) != 1407 or digest != SOURCE_SHA: + errors.append('before map is not the frozen 1407-source map') + if len(allowed) != len(allowed_changed) or not allowed <= OPT_PATHS: + errors.append('unregistered allowed change set') + added, missing = sorted(after_map.keys()-before_map.keys()), sorted(before_map.keys()-after_map.keys()) + changed = sorted(k for k in before_map.keys() & after_map.keys() if not exact(before_map[k], after_map[k])) + if added or missing or set(changed) != allowed: + errors.append('source closure mismatch') + return {'ok': not errors, 'errors': errors, 'before_sha256': digest, 'added': added, 'missing': missing, 'changed': changed, 'allowed_changed': sorted(allowed)} + + +K_COMPARE = frozenset(('absolute_minute', 'speed', 'paused', 'snapshot_version', + '_accumulator', '_skip_next_process', '_pause_request_serial', + '_abort_current_tick_requested', '_last_tick_advanced', '_phase_handlers')) +C_COMPARE = frozenset(('_mvp_manifest_cache_generation', 'catalog_is_current', '_mvp_manifest_cache_bytes')) + + +def compare_reports(a, b): + """Compare joined reports. Missing evidence fails, never defaults to zero. + + Native admission/source closure is a separate mandatory S4 gate. This + function compares report content, including all scenario outcomes, without + converting an existing product failure into a harness failure or a PASS. + """ + out = {'ok': False, 'differences': [], 'dict_order_paths': [], 'excluded': [], + 'violations': [], 'digest_modes': [], 'errors': []} + + def record(path, x, y): + if not exact(x, y): + out['differences'].append({'path': path, 'a': copy.deepcopy(x), 'b': copy.deepcopy(y)}) + + def excluded(path, reason, x, y): + out['excluded'].append({'path': path, 'reason': reason, 'a': copy.deepcopy(x), 'b': copy.deepcopy(y)}) + + def trees(path, x, y, profiles): + nx, sx = normalize_tree(x, profiles[0]); ny, sy = normalize_tree(y, profiles[1]) + require(tree_sha(restore_tree(nx, sx, profiles[0])) == tree_sha(x), 'a restore SHA') + require(tree_sha(restore_tree(ny, sy, profiles[1])) == tree_sha(y), 'b restore SHA') + sidecars(path, sx, sy) + comparison(path, nx, ny) + return sx, sy + + def comparison(path, x, y): + c = compare_trees(x, y) + for row in c['differences']: + out['differences'].append({**row, 'path': path + row['path']}) + out['dict_order_paths'].extend(path + p for p in c['dict_order_paths']) + + def sidecars(path, x, y): + # Compare semantic paths, not insertion indexes, including event IDs + # in the separately compared event tree. Entry values are never metrics. + identity = lambda e: json_bytes([e['event_index'], e['path'], e['key']]) + mx, my = {identity(e): e for e in x['entries']}, {identity(e): e for e in y['entries']} + record(path + ['normalized_paths'], sorted(k.decode() for k in mx), sorted(k.decode() for k in my)) + for key in sorted(mx.keys() | my.keys()): + ex, ey = mx.get(key), my.get(key) + name = (ex or ey)['key'] + excluded(path + ['sidecar', key.decode()], 'private profile root' if name == 'message' else 'wall-clock timing', ex, ey) + out['violations'].append({'path': path, 'a': x['violations'], 'b': y['violations']}) + + def layers(path, x, y): + for n in (x['K'], y['K']): + require(set(n) == K_COMPARE | {'performance_budget'}, 'K fields missing/unknown') + require(set(n['performance_budget']) == {'_samples', '_totals', '_sample_counts'}, 'budget fields') + require(type(n['_accumulator']) is str and re.fullmatch('[0-9a-f]{16}', n['_accumulator']), 'accumulator f64') + counts = n['performance_budget']['_sample_counts'] + require(type(counts) is dict and all(type(v) is int and v >= 0 for v in counts.values()), 'metric sample counts') + for field in sorted(K_COMPARE): + vx, vy = x['K'][field], y['K'][field] + if field == '_phase_handlers': + require(type(vx) is dict and type(vy) is dict, 'phase handlers') + def handlers(value): + for ids in value.values(): + require(type(ids) is list and all(type(i) is str for i in ids) and len(set(ids)) == len(ids), 'handler IDs') + return {p: sorted(ids) for p, ids in value.items()} + vx, vy = handlers(vx), handlers(vy) + # JSON object order is not semantic; typed state retains its order. + if field == '_phase_handlers': + vx, vy = sorted(vx.items()), sorted(vy.items()) + record(path + ['K', field], vx, vy) + bx, by = x['K']['performance_budget'], y['K']['performance_budget'] + record(path + ['K', 'performance_budget', '_sample_counts'], sorted(bx['_sample_counts'].items()), sorted(by['_sample_counts'].items())) + for field in ('_samples', '_totals'): + excluded(path + ['K', 'performance_budget', field], 'wall-clock telemetry', bx[field], by[field]) + for n in (x['C'], y['C']): + require(set(n) == C_COMPARE | {'catalog_instance_id', 'current_catalog_instance_id'}, 'C fields missing/unknown') + require(type(n['catalog_is_current']) is bool, 'catalog identity flag') + for field in sorted(C_COMPARE): + record(path + ['C', field], x['C'][field], y['C'][field]) + for field in ('catalog_instance_id', 'current_catalog_instance_id'): + excluded(path + ['C', field], 'process-local instance ID', x['C'][field], y['C'][field]) + + def scenario_facts(path, x, y): + # Joined S3b facts carry lossless typed trees as well as JSON metadata. + # Apply the same dictionary-order-only fallback to returned values. + if isinstance(x, list) and isinstance(y, list) and x and y and type(x[0]) is int and type(y[0]) is int: + validate_tree(x); validate_tree(y) + comparison(path, x, y) + elif isinstance(x, dict) and isinstance(y, dict): + record(path + ['keys'], sorted(x), sorted(y)) + for key in sorted(set(x) & set(y)): + scenario_facts(path + [key], x[key], y[key]) + elif isinstance(x, list) and isinstance(y, list): + record(path + ['count'], len(x), len(y)) + for i, (left, right) in enumerate(zip(x, y)): + scenario_facts(path + [i], left, right) + else: + record(path, x, y) + + def checkpoints(path, xs, ys, profiles, main=False, ownership=False): + if main: + require(len(xs) == len(ys) == 31, 'B1 plus 30 ticks required') + record(path + ['count'], len(xs), len(ys)) + tx, ty = reconstruct_checkpoints(xs), reconstruct_checkpoints(ys) + for i, (x, y) in enumerate(zip(xs, ys)): + p = path + [i] + expected = {'minute', 'S', 'latest', 'latest_digest', 'computed_latest_digest', 'harness_normalized_digest', 'K', 'C', 'observation'} + require(set(x) == expected and set(y) == expected, 'checkpoint fields') + for cp in (x, y): + require(type(cp['latest_digest']) is str and type(cp['computed_latest_digest']) is str, 'product digest type') + # Only the immediately observed, intentional external E5 mutation + # may expose cached-digest aliasing. Preserve it as a product fact. + if not (ownership and i == 2): + require(cp['latest_digest'] == cp['computed_latest_digest'], 'product digest self-consistency') + obs = cp['observation'] + require(set(obs) == {'before', 'after'} and set(obs['before']) == set(obs['after']) == {'S', 'K', 'C'}, 'complete observation proof') + require(all(type(v) is str and re.fullmatch('[0-9a-f]{64}', v) for v in list(obs['before'].values())+list(obs['after'].values())), 'observation bytes SHA') + require(exact(obs['before'], obs['after']), 'observation mutated S/K/C') + record(p + ['minute'], x['minute'], y['minute']) + if main: + require(x['minute'] == xs[0]['minute']+i and y['minute'] == ys[0]['minute']+i, 'checkpoint cadence') + trees(p + ['S'], tx[i][0], ty[i][0], profiles) + sx, sy = trees(p + ['latest'], tx[i][1], ty[i][1], profiles) + if ownership and i == 2: + record(p + ['digest_self_consistent'], x['latest_digest'] == x['computed_latest_digest'], y['latest_digest'] == y['computed_latest_digest']) + if sx['entries'] or sy['entries']: + excluded(p + ['computed_latest_digest'], 'E5 latest contains F1-F3; full normalized latest is compared', x['computed_latest_digest'], y['computed_latest_digest']) + else: + record(p + ['computed_latest_digest'], x['computed_latest_digest'], y['computed_latest_digest']) + if sx['entries'] or sy['entries']: + require(type(x['harness_normalized_digest']) is str and type(y['harness_normalized_digest']) is str, 'missing harness normalized digest') + record(p + ['harness_normalized_digest'], x['harness_normalized_digest'], y['harness_normalized_digest']) + excluded(p + ['latest_digest'], 'latest snapshot contains F1-F3 environment values', x['latest_digest'], y['latest_digest']) + out['digest_modes'].append({'path': p, 'mode': 'harness normalized digest'}) + else: + record(p + ['latest_digest'], x['latest_digest'], y['latest_digest']) + out['digest_modes'].append({'path': p, 'mode': 'product latest_digest'}) + layers(p, x, y) + + try: + fields = {'schema', 'role', 'profile_root', 'checkpoints', 'events', 'event_start', 'event_end', 'signal_order', 'scenarios'} + require(type(a) is dict and type(b) is dict and set(a) == fields and set(b) == fields, 'report fields missing/unknown') + require(a['schema'] == b['schema'] == 'p28-02-eq/typed-v1', 'report schema') + require(a['role'] in ('R', 'O') and b['role'] in ('R', 'O'), 'report role') + record(['role'], a['role'], b['role']) + profiles = (a['profile_root'], b['profile_root']) + for profile in profiles: + _profile(profile) + for r in (a, b): + require(set(r['event_start']) == {'counter', 'published_ids_count'}, 'event start fields') + require(all(type(n) is int and n >= 0 for n in r['event_start'].values()), 'event counters') + require(exact(a['event_start'], b['event_start']), 'event start counter/published_ids mismatch: correspondence invalid') + record(['event_end'], a['event_end'], b['event_end']) + record(['signal_order'], a['signal_order'], b['signal_order']) + checkpoints(['checkpoints'], a['checkpoints'], b['checkpoints'], profiles, main=True) + event_trees = [] + for r in (a, b): + ts = [] + for i, e in enumerate(r['events']): + require(set(e) == {'sequence', 'transport', 'original_field_types'} and e['sequence'] == i, 'event sequence/fields') + ts.append(_transport(e['transport'], None)) + event_trees.append(ts) + na, sa = normalize_events(event_trees[0], profiles[0]); nb, sb = normalize_events(event_trees[1], profiles[1]) + require(exact(restore_events(na, sa, profiles[0]), event_trees[0]) and exact(restore_events(nb, sb, profiles[1]), event_trees[1]), 'event restore proof') + sidecars(['events'], sa, sb) + record(['events', 'count'], len(na), len(nb)) + for i, (x, y) in enumerate(zip(na, nb)): + comparison(['events', i], x, y) + record(['events', i, 'original_field_types'], a['events'][i]['original_field_types'], b['events'][i]['original_field_types']) + record(['scenarios', 'count'], len(a['scenarios']), len(b['scenarios'])) + for i, (x, y) in enumerate(zip(a['scenarios'], b['scenarios'])): + require(set(x) == set(y) == {'id', 'operation', 'result', 'checkpoints', 'events'}, 'scenario fields') + for key in ('id', 'operation', 'result', 'events'): + # result preserves failures/path/value/ownership outcomes. + # Scenario events use the same typed normalization below. + if key != 'events': + if key == 'result' and x['id'].startswith(('E4/', 'E5/')) and y['id'].startswith(('E4/', 'E5/')): + scenario_facts(['scenarios', i, key], x[key], y[key]) + else: + record(['scenarios', i, key], x[key], y[key]) + ownership_ids = {'E5/'+t+'/'+loc+'/outside_in' for t in ('create_snapshot', 'latest_snapshot', 'snapshot_published', 'state_updated') for loc in ('dict', 'array')} + ownership = x['id'] == y['id'] and x['id'] in ownership_ids and x['operation'] == y['operation'] == 'outside_in' and len(x['checkpoints']) == len(y['checkpoints']) == 4 + checkpoints(['scenarios', i, 'checkpoints'], x['checkpoints'], y['checkpoints'], profiles, ownership=ownership) + ex, sx = normalize_events(x['events'], profiles[0]); ey, sy = normalize_events(y['events'], profiles[1]) + sidecars(['scenarios', i, 'events'], sx, sy) + record(['scenarios', i, 'events', 'count'], len(ex), len(ey)) + for j, (vx, vy) in enumerate(zip(ex, ey)): + comparison(['scenarios', i, 'events', j], vx, vy) + out['ok'] = not out['differences'] + except (EvidenceError, KeyError, TypeError, IndexError, ValueError) as exc: + out['errors'].append(str(exc)) + return out + + +def classify_improvement(before, after): + """SPEC §4: three actual run/PID values, no substituted markers.""" + import math + require(len(before) == len(after) == 3, 'three values per version required') + require(all(type(v) in (int, float) and math.isfinite(v) and v >= 0 for v in before+after), 'invalid measurement') + return '改善' if max(after) < min(before) else '悪化' if min(after) > max(before) else '差は確認できない' + + +def validate_scenario_paths(paths): + """D1: exact fixed relative names; no UUID/PID/time-generated paths.""" + allowed = {'user://p28_eq/'+role+'/'+name for role in ('r', 'o') + for name in ('good', 'tampered_world', 'missing_key', 'wrong_type', 'out_of_range', 'duplicate_id')} + require(type(paths) is list and all(type(p) is str and p in allowed for p in paths), 'non-fixed scenario path') + return True diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/eq_probe.gd b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/eq_probe.gd new file mode 100644 index 0000000..0fac954 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/eq_probe.gd @@ -0,0 +1,808 @@ +extends SceneTree +## S3b external guarded probe. Native admission remains S4/Root. +const FIXTURE_SHA: String = "eb4f770071eb07cd7e136fe54c3f78768cc8de7a4264e62a9af1f06a8f90f9bd" +const K_FIELDS: Array = ["absolute_minute", "speed", "paused", "snapshot_version", "_skip_next_process", "_pause_request_serial", "_abort_current_tick_requested", "_last_tick_advanced"] +var clock: Variant +var runtime: Variant +var main: Variant +var role: String +var report: Dictionary = {} +var lifecycle: Dictionary = {"stage": "S3b", "errors": [], "preparation": [], "files": []} +var previous_tree: Array = [] +var finished: bool = false +var bound: bool = false +var recording: bool = false +var connected: bool = false +var initial_inventory: Dictionary = {} +var warm_signals: Array = [] +var scenario_active: bool = false +var scenario_events: Array = [] +var scenario_signals: Array = [] +var b1_snapshot: Dictionary = {} +var snapshot_reference: Dictionary = {} +var state_reference: Dictionary = {} + +func _initialize() -> void: + call_deferred("begin") + +func demand(ok: bool, message: String) -> bool: + if not ok: lifecycle.errors.append(message) + return ok + +func hashed(bytes: PackedByteArray) -> String: + var context: HashingContext = HashingContext.new() + context.start(HashingContext.HASH_SHA256) + context.update(bytes) + return context.finish().hex_encode() + +func json_text(value: Variant) -> String: + return JSON.stringify(value, "", false, true) + +func f64(value: float) -> String: + var bytes: PackedByteArray = PackedByteArray() + bytes.resize(8) + bytes.encode_double(0, value) + return bytes.hex_encode() + +func typed_info(value: Variant) -> Variant: + if typeof(value) == TYPE_ARRAY and value.is_typed(): + return [encode(value.get_typed_builtin()), encode(value.get_typed_class_name()), encode(value.get_typed_script())] + if typeof(value) == TYPE_DICTIONARY and value.is_typed(): + return [[encode(value.get_typed_key_builtin()), encode(value.get_typed_key_class_name()), encode(value.get_typed_key_script())], [encode(value.get_typed_value_builtin()), encode(value.get_typed_value_class_name()), encode(value.get_typed_value_script())]] + return null + +func encode(value: Variant) -> Array: + var t: int = typeof(value) + match t: + TYPE_NIL: return [0] + TYPE_BOOL: return [1, 1 if value else 0] + TYPE_INT: return [2, value] + TYPE_FLOAT: return [3, f64(value)] + TYPE_STRING, TYPE_STRING_NAME, TYPE_NODE_PATH: return [t, str(value)] + TYPE_RID, TYPE_OBJECT, TYPE_CALLABLE, TYPE_SIGNAL: + demand(false, "unsupported Variant in transport: " + str(t)) + return [] + TYPE_DICTIONARY: + var pairs: Array = [] + for key: Variant in value: pairs.append([encode(key), encode(value[key])]) + return [27, pairs, typed_info(value)] + TYPE_ARRAY: + var children: Array = [] + for child: Variant in value: children.append(encode(child)) + return [28, children, typed_info(value)] + TYPE_PACKED_BYTE_ARRAY: return [29, Marshalls.raw_to_base64(value)] + var parts: Array = [] + match t: + TYPE_VECTOR2, TYPE_VECTOR2I: parts = [value.x, value.y] + TYPE_RECT2, TYPE_RECT2I: parts = [value.position.x, value.position.y, value.size.x, value.size.y] + TYPE_VECTOR3, TYPE_VECTOR3I: parts = [value.x, value.y, value.z] + TYPE_TRANSFORM2D: parts = [value.x.x, value.x.y, value.y.x, value.y.y, value.origin.x, value.origin.y] + TYPE_VECTOR4, TYPE_VECTOR4I: parts = [value.x, value.y, value.z, value.w] + TYPE_PLANE: parts = [value.normal.x, value.normal.y, value.normal.z, value.d] + TYPE_QUATERNION: parts = [value.x, value.y, value.z, value.w] + TYPE_AABB: parts = [value.position.x, value.position.y, value.position.z, value.size.x, value.size.y, value.size.z] + TYPE_BASIS: parts = basis_parts(value) + TYPE_TRANSFORM3D: parts = basis_parts(value.basis) + [value.origin.x, value.origin.y, value.origin.z] + TYPE_PROJECTION: + for column: int in range(4): + for row: int in range(4): parts.append(value[column][row]) + TYPE_COLOR: parts = [value.r, value.g, value.b, value.a] + _: + if t >= TYPE_PACKED_INT32_ARRAY and t <= TYPE_PACKED_VECTOR4_ARRAY: + for child: Variant in value: parts.append(child) + else: demand(false, "unknown Variant type: " + str(t)) + var nodes: Array = [] + for part: Variant in parts: nodes.append(encode(part)) + return [t, nodes] + +func basis_parts(value: Basis) -> Array: + return [value.x.x, value.x.y, value.x.z, value.y.x, value.y.y, value.y.z, value.z.x, value.z.y, value.z.z] + +func decode(node: Array) -> Variant: + if node.is_empty(): + demand(false, "empty typed node") + return null + var t: int = node[0] + if t == TYPE_NIL: return null + var p: Variant = node[1] + match t: + TYPE_BOOL: return p == 1 + TYPE_INT: return int(p) + TYPE_FLOAT: return String(p).hex_decode().decode_double(0) + TYPE_STRING: return String(p) + TYPE_STRING_NAME: return StringName(p) + TYPE_NODE_PATH: return NodePath(p) + TYPE_PACKED_BYTE_ARRAY: return Marshalls.base64_to_raw(p) + TYPE_DICTIONARY: + var result: Dictionary = {} + if node[2] != null: + var ki: Array = node[2][0] + var vi: Array = node[2][1] + result = Dictionary({}, decode(ki[0]), decode(ki[1]), decode(ki[2]), decode(vi[0]), decode(vi[1]), decode(vi[2])) + for pair: Array in p: result[decode(pair[0])] = decode(pair[1]) + return result + var values: Array = [] + for child: Array in p: values.append(decode(child)) + if t == TYPE_ARRAY: + if node[2] != null: + var info: Array = node[2] + return Array(values, decode(info[0]), decode(info[1]), decode(info[2])) + return values + match t: + TYPE_VECTOR2: return Vector2(values[0], values[1]) + TYPE_VECTOR2I: return Vector2i(values[0], values[1]) + TYPE_RECT2: return Rect2(values[0], values[1], values[2], values[3]) + TYPE_RECT2I: return Rect2i(values[0], values[1], values[2], values[3]) + TYPE_VECTOR3: return Vector3(values[0], values[1], values[2]) + TYPE_VECTOR3I: return Vector3i(values[0], values[1], values[2]) + TYPE_TRANSFORM2D: return Transform2D(Vector2(values[0], values[1]), Vector2(values[2], values[3]), Vector2(values[4], values[5])) + TYPE_VECTOR4: return Vector4(values[0], values[1], values[2], values[3]) + TYPE_VECTOR4I: return Vector4i(values[0], values[1], values[2], values[3]) + TYPE_PLANE: return Plane(Vector3(values[0], values[1], values[2]), values[3]) + TYPE_QUATERNION: return Quaternion(values[0], values[1], values[2], values[3]) + TYPE_AABB: return AABB(Vector3(values[0], values[1], values[2]), Vector3(values[3], values[4], values[5])) + TYPE_BASIS: return decoded_basis(values) + TYPE_TRANSFORM3D: return Transform3D(decoded_basis(values), Vector3(values[9], values[10], values[11])) + TYPE_PROJECTION: return Projection(Vector4(values[0], values[1], values[2], values[3]), Vector4(values[4], values[5], values[6], values[7]), Vector4(values[8], values[9], values[10], values[11]), Vector4(values[12], values[13], values[14], values[15])) + TYPE_COLOR: return Color(values[0], values[1], values[2], values[3]) + TYPE_PACKED_INT32_ARRAY: return PackedInt32Array(values) + TYPE_PACKED_INT64_ARRAY: return PackedInt64Array(values) + TYPE_PACKED_FLOAT32_ARRAY: return PackedFloat32Array(values) + TYPE_PACKED_FLOAT64_ARRAY: return PackedFloat64Array(values) + TYPE_PACKED_STRING_ARRAY: return PackedStringArray(values) + TYPE_PACKED_VECTOR2_ARRAY: return PackedVector2Array(values) + TYPE_PACKED_VECTOR3_ARRAY: return PackedVector3Array(values) + TYPE_PACKED_COLOR_ARRAY: return PackedColorArray(values) + TYPE_PACKED_VECTOR4_ARRAY: return PackedVector4Array(values) + demand(false, "unsupported decode type: " + str(t)) + return null + +func decoded_basis(v: Array) -> Basis: + return Basis(Vector3(v[0], v[1], v[2]), Vector3(v[3], v[4], v[5]), Vector3(v[6], v[7], v[8])) + +func transport(value: Variant) -> Dictionary: + var tree: Array = encode(value) + var raw: PackedByteArray = var_to_bytes(value) + var rebuilt: PackedByteArray = var_to_bytes(decode(tree)) + var ok: bool = raw == rebuilt + demand(ok, "Godot typed tree byte roundtrip failed") + return {"tree": tree, "tree_sha": hashed(json_text(tree).to_utf8_buffer()), "raw_bytes_sha": hashed(raw), "roundtrip_ok": ok} + +func tree_diff(before: Array, after: Array, path: Array = []) -> Array: + if json_text(before) == json_text(after): return [] + # Exact subtree replacement also preserves changes of insertion order and metadata. + if before[0] != after[0] or before[0] not in [TYPE_DICTIONARY, TYPE_ARRAY] or json_text(before[2]) != json_text(after[2]): + return [{"op": "set", "path": path, "node": after}] + var changes: Array = [] + if before[0] == TYPE_DICTIONARY: + var old_keys: Array = [] + var new_keys: Array = [] + for pair: Array in before[1]: old_keys.append(pair[0]) + for pair: Array in after[1]: new_keys.append(pair[0]) + if json_text(old_keys) != json_text(new_keys): return [{"op": "set", "path": path, "node": after}] + for i: int in range(before[1].size()): + changes.append_array(tree_diff(before[1][i][1], after[1][i][1], path + [["key", after[1][i][0]]])) + else: + if before[1].size() != after[1].size(): + return [{"op": "array_splice", "path": path, "start": 0, "delete_count": before[1].size(), "nodes": after[1]}] + for i: int in range(before[1].size()): changes.append_array(tree_diff(before[1][i], after[1][i], path + [["index", i]])) + return changes + +func tree_at(tree: Array, path: Array) -> Array: + var node: Array = tree + for segment: Array in path: + if segment[0] == "index": node = node[1][segment[1]] + else: + var found: bool = false + for pair: Array in node[1]: + if json_text(pair[0]) == json_text(segment[1]): + node = pair[1] + found = true + break + demand(found, "diff path missing") + return node + +func diff_record(record: Dictionary, baseline: Array) -> Dictionary: + var operations: Array = tree_diff(baseline, record.tree) + var replay: Array = baseline.duplicate(true) + for op: Dictionary in operations: + var target: Array = tree_at(replay, op.path) + if op.op == "set": + target.clear() + target.append_array(op.node.duplicate(true)) + elif op.op == "array_splice": + for unused: int in range(op.delete_count): target[1].remove_at(op.start) + for i: int in range(op.nodes.size()): target[1].insert(op.start + i, op.nodes[i].duplicate(true)) + demand(json_text(replay) == json_text(record.tree), "diff roundtrip mismatch") + return {"diff": operations, "tree_sha": record.tree_sha, "raw_bytes_sha": record.raw_bytes_sha, "roundtrip_ok": record.roundtrip_ok} + +func kernel_state() -> Dictionary: + var result: Dictionary = {} + for key: String in K_FIELDS: result[key] = clock.get(key) + result["_accumulator"] = f64(clock.get("_accumulator")) + var ids: Dictionary = {} + var handlers: Dictionary = clock.get("_phase_handlers") + for phase: Variant in handlers: + var names: Array = [] + for key: Variant in handlers[phase]: names.append(str(key)) + names.sort_custom(func(a: Variant, b: Variant) -> bool: return str(a) < str(b)) + ids[str(phase)] = names + result["_phase_handlers"] = ids + var budget: Variant = clock.get("performance_budget") + var metrics: Dictionary = {} + for key: String in ["_samples", "_totals", "_sample_counts"]: metrics[key] = budget.get(key).duplicate(true) + result["performance_budget"] = metrics + return result + +func cache_state() -> Dictionary: + var catalog: Variant = runtime.get("_mvp_manifest_cache_catalog") + var current: Variant = runtime.get("mvp_content_catalog") + return {"_mvp_manifest_cache_generation": runtime.get("_mvp_manifest_cache_generation"), "catalog_is_current": catalog == current, + "_mvp_manifest_cache_bytes": Marshalls.raw_to_base64(var_to_bytes(runtime.get("_mvp_manifest_cache"))), + "catalog_instance_id": str(catalog.get_instance_id()) if catalog != null else null, "current_catalog_instance_id": str(current.get_instance_id())} + +func cache_filled() -> bool: + var current: Variant = runtime.get("mvp_content_catalog") + return runtime.get("_mvp_manifest_cache_catalog") == current and runtime.get("_mvp_manifest_cache_generation") == current.get_manifest_generation() + +func prepare_cache(label: String) -> void: + var before: Dictionary = cache_state() + var filled: bool = cache_filled() + if not filled: runtime.create_snapshot() + lifecycle.preparation.append({"operation": "cache", "label": label, "before": before, "after": cache_state(), "filled_outside_observation": not filled}) + demand(cache_filled(), "cache preparation failed") + +func layers() -> Dictionary: + var k: Dictionary = kernel_state() + var c: Dictionary = cache_state() + var s: Dictionary = runtime.create_snapshot() + var kb: PackedByteArray = var_to_bytes(k) + var cb: PackedByteArray = var_to_bytes(c) + demand(kb == var_to_bytes(kernel_state()), "state witness changed full K") + demand(cb == var_to_bytes(cache_state()), "state witness changed full C") + return {"snapshot": s, "K": k, "C": c, "s_bytes": var_to_bytes(s), "k_bytes": kb, "c_bytes": cb} + +func witness(value: Dictionary) -> Dictionary: + return {"S": hashed(value.s_bytes), "K": hashed(value.k_bytes), "C": hashed(value.c_bytes)} + +func raw_layers(value: Dictionary) -> Dictionary: + return {"sha": witness(value), "S": Marshalls.raw_to_base64(value.s_bytes), "K": Marshalls.raw_to_base64(value.k_bytes), "C": Marshalls.raw_to_base64(value.c_bytes), "kernel": value.K, "cache": value.C} + +func checkpoint() -> void: + var before: Dictionary = layers() + var s: Dictionary = transport(runtime.create_snapshot()) + var latest_value: Dictionary = runtime.get("latest_snapshot") + var latest: Dictionary = transport(latest_value) + var latest_bytes: PackedByteArray = var_to_bytes(latest_value) + var digest: String = runtime.get("latest_digest") + var computed: String = SimulationDigest.compute(latest_value) + var current_tree: Array = s.tree + if not previous_tree.is_empty(): s = diff_record(s, previous_tree) + if latest_bytes == before.s_bytes: + latest = {"same_as_S": true, "tree_sha": latest.tree_sha, "raw_bytes_sha": latest.raw_bytes_sha, "roundtrip_ok": latest.roundtrip_ok} + else: latest = diff_record(latest, current_tree) + var after: Dictionary = layers() + demand(before.s_bytes == after.s_bytes and before.k_bytes == after.k_bytes and before.c_bytes == after.c_bytes, "observation changed full S/K/C") + demand(digest == computed, "latest digest self-consistency") + var cp: Dictionary = {"minute": clock.absolute_minute, "S": s, "latest": latest, "latest_digest": digest, "computed_latest_digest": computed, + "harness_normalized_digest": null, "K": before.K, "C": before.C, "observation": {"before": witness(before), "after": witness(after)}} + # Python joins F1-F3 and the labelled normalized tree digest, retaining this raw record. + var index: int = report.checkpoints.size() + write_evidence("checkpoint-%02d.json" % index, cp) + write_evidence("observation-%02d.json" % index, {"before": raw_layers(before), "after": raw_layers(after)}) + report.checkpoints.append(cp) + previous_tree = current_tree + +func event_counts() -> Dictionary: + return {"counter": runtime.id_generator.get_counter(&"domain_event"), "published_ids_count": runtime.domain_events.get("_published_ids").size()} + +func observe_event(event: Variant) -> void: + if scenario_active: + scenario_events.append(transport(event.to_dictionary())) + return + if not recording: return + var value: Dictionary = event.to_dictionary() + report.events.append({"sequence": report.events.size(), "transport": transport(value), "original_field_types": { + "event_id": typeof(event.event_id), "event_type": typeof(event.event_type), "absolute_minute": typeof(event.absolute_minute), "source_service": typeof(event.source_service), + "entity_ids": {"type": typeof(event.entity_ids), "typed_info": typed_info(event.entity_ids)}, + "payload": {"type": typeof(event.payload), "typed_info": typed_info(event.payload)}, "causation_command_id": typeof(event.causation_command_id)}}) + +func observe_snapshot(_snapshot: Dictionary, _digest: String) -> void: + snapshot_reference = _snapshot + record_signal("snapshot_published") + +func observe_state(_snapshot: Dictionary) -> void: + state_reference = _snapshot + record_signal("state_updated") + +func record_signal(name: String) -> void: + var row: Dictionary = {"signal": name, "minute": clock.absolute_minute} + if scenario_active: scenario_signals.append(row) + elif recording: report.signal_order.append(row) + else: warm_signals.append(row) + +func inventory() -> Dictionary: + var result: Dictionary = {} + for sig: Signal in [runtime.snapshot_published, runtime.state_updated]: + var rows: Array = [] + for connection: Dictionary in sig.get_connections(): + var callback: Callable = connection.callable + rows.append({"object": str(callback.get_object_id()), "method": str(callback.get_method()), "flags": connection.flags}) + rows.sort_custom(func(a: Dictionary, b: Dictionary) -> bool: return json_text(a) < json_text(b)) + result[str(sig.get_name())] = rows + var subscribers: Array = [] + var all_subscribers: Dictionary = runtime.domain_events.get("_subscribers") + for event_type: Variant in all_subscribers: + for id: Variant in all_subscribers[event_type]: + var callback: Callable = all_subscribers[event_type][id] + subscribers.append({"event_type": str(event_type), "id": str(id), "object": str(callback.get_object_id()), "method": str(callback.get_method())}) + subscribers.sort_custom(func(a: Dictionary, b: Dictionary) -> bool: return json_text(a) < json_text(b)) + result["subscribers"] = subscribers + return result + +func step() -> void: + var before: int = clock.absolute_minute + demand(clock.paused, "clock resumed") + clock.advance_minutes(1) + demand(clock.absolute_minute == before + 1 and clock.paused, "manual step failed") + await process_frame + demand(clock.absolute_minute == before + 1 and clock.paused, "inter-tick frame advanced clock") + +func bind_profile() -> bool: + var path: String = OS.get_environment("THE_TREE_PACK_PROFILE_REPORT") + var file: FileAccess = FileAccess.open(path, FileAccess.READ) + if not demand(file != null, "guard receipt missing"): return false + var receipt: Variant = JSON.parse_string(file.get_as_text()) + file.close() + if not demand(receipt is Dictionary and receipt.get("verified") == true, "guard receipt unverified"): return false + var actual: Variant = receipt.get("actual_user_data_dir") + var live_root: String = ProjectSettings.globalize_path("user://").simplify_path() + if not demand(actual is String and actual == live_root and OS.get_user_data_dir() == actual, "live profile differs from guard actual_user_data_dir"): return false + report["profile_root"] = {"root": live_root, "actual_user_data_dir": actual} + lifecycle["guard"] = {"path": path, "sha256": FileAccess.get_sha256(path), "receipt": receipt, "live_root": live_root} + bound = true + return true + +func write_evidence(name: String, value: Variant) -> void: + if not demand(bound, "evidence write before guard binding"): return + var directory: String = "user://evidence" + var mkdir: int = DirAccess.make_dir_recursive_absolute(directory) + if not demand(mkdir == OK, "evidence mkdir failed"): return + var path: String = directory.path_join(name) + if not demand(not FileAccess.file_exists(path), "refuse evidence overwrite: " + name): return + var file: FileAccess = FileAccess.open(path, FileAccess.WRITE) + if not demand(file != null, "evidence open failed: " + name): return + var bytes: PackedByteArray = json_text(value).to_utf8_buffer() + file.store_buffer(bytes) + file.flush() + var error: int = file.get_error() + file.close() + demand(error == OK, "evidence write failed: " + name) + lifecycle.files.append({"path": "evidence/" + name, "bytes": bytes.size(), "sha256": hashed(bytes)}) + +func begin() -> void: + clock = root.get_node("GameClock") + runtime = root.get_node("SimulationRuntime") + role = OS.get_environment("THE_TREE_EQ_ROLE") + report = {"schema": "p28-02-eq/typed-v1", "role": role, "profile_root": null, "checkpoints": [], "events": [], "event_start": null, "event_end": null, "signal_order": [], "scenarios": []} + if not demand(role in ["R", "O"], "unknown EQ role") or not bind_profile(): + finish() + return + # Stage 1: public preparation only. O retains the fresh 360-minute state. + var k0: Dictionary = kernel_state() + clock.set_paused(true) + lifecycle.preparation.append({"operation": "initial_pause", "before": k0, "after": kernel_state()}) + if role == "R": + var path: String = OS.get_environment("THE_TREE_P28_FIXTURE") + if not demand(FileAccess.get_sha256(path) == FIXTURE_SHA, "fixture SHA mismatch"): + finish() + return + var file: FileAccess = FileAccess.open(path, FileAccess.READ) + if not demand(file != null, "fixture open failed"): + finish() + return + var fixture: Variant = file.get_var(false) + file.close() + if not demand(fixture is Dictionary, "fixture is not Dictionary"): + finish() + return + var restored: bool = runtime.restore_snapshot(fixture) + lifecycle.preparation.append({"operation": "fixture_restore", "ok": restored, "input_sha256": FIXTURE_SHA, "K": kernel_state(), "C": cache_state()}) + demand(restored, "fixture restore failed") + prepare_cache("restored") + lifecycle["restored"] = raw_layers(layers()) + k0 = kernel_state() + clock.set_paused(true) + lifecycle.preparation.append({"operation": "restored_pause", "before": k0, "after": kernel_state()}) + prepare_cache("before_main") + # Stage 2: same main and two deferred frames as DIAG, without controls/hooks. + lifecycle["before_main"] = raw_layers(layers()) + main = load("res://scenes/main/main.tscn").instantiate() + root.add_child(main) + lifecycle["after_main"] = raw_layers(layers()) + await process_frame + lifecycle["frame1"] = raw_layers(layers()) + await process_frame + lifecycle["frame2"] = raw_layers(layers()) + var ops: Dictionary = main.get("_operations_start_report").duplicate(true) + lifecycle["ops"] = ops + lifecycle["save_policy"] = runtime.get_save_policy() + demand(ops.get("code") == "INVALID_START_TIME" if role == "R" else ops.get("ok") == true, "unexpected main Ops result") + demand(clock.paused and clock.absolute_minute == (602 if role == "R" else 360), "B0 clock") + lifecycle["B0"] = raw_layers(layers()) + initial_inventory = inventory() + runtime.snapshot_published.connect(observe_snapshot) + runtime.state_updated.connect(observe_state) + demand(runtime.domain_events.subscribe(&"*", &"p28_eq_observer", observe_event), "wildcard subscription failed") + connected = true + lifecycle["observer_before"] = initial_inventory + lifecycle["observer_connected"] = inventory() + # Stage 3: warm, excluded from E2; warm signal order is retained separately. + for unused: int in range(30): + if not lifecycle.errors.is_empty(): break + await step() + prepare_cache("B1") + lifecycle["B1"] = raw_layers(layers()) + demand(clock.absolute_minute == (632 if role == "R" else 390), "B1 clock") + lifecycle["measurement"] = {"probe_object": str(get_instance_id()), "connections": inventory(), "start_minute": clock.absolute_minute} + report.event_start = event_counts() + recording = true + checkpoint() + b1_snapshot = decode(report.checkpoints[0].S.tree).duplicate(true) + # Stage 4: B1 and 30 exact checkpoints, uncapped events through the last frame. + for unused: int in range(30): + if not lifecycle.errors.is_empty(): break + await step() + checkpoint() + report.event_end = event_counts() + recording = false + # Stage 5: E3 dedicated intervals, after measured event/signal closure. + lifecycle["outside"] = raw_layers(layers()) + run_e3() + run_e4() + run_e5() + finish() + +func finish() -> void: + if finished: return + finished = true + # Stage 6: restore observers, preserve every error. + if connected: + runtime.snapshot_published.disconnect(observe_snapshot) + runtime.state_updated.disconnect(observe_state) + runtime.domain_events.unsubscribe(&"*", &"p28_eq_observer") + lifecycle["observer_disconnected"] = inventory() + demand(json_text(initial_inventory) == json_text(lifecycle.observer_disconnected), "observer inventory not restored") + lifecycle["warm_signals"] = warm_signals + lifecycle["stop_reason"] = "S3b_complete_S4_pending" if lifecycle.errors.is_empty() else "failed" + if bound: + write_evidence("events.json", report.events) + write_evidence("report.json", report) + write_evidence("lifecycle.json", lifecycle.duplicate(true)) + print("P28_02_EQ_REPORT=" + json_text(report)) + if is_instance_valid(main): main.ui_audio_window_close_drained.connect(audio_close, CONNECT_ONE_SHOT) + root.close_requested.emit() + +func audio_close(result: Dictionary) -> void: + write_evidence("audio-close.json", result) + +func e3_observation() -> Dictionary: + var before: Dictionary = layers() + var s: Dictionary = transport(runtime.create_snapshot()) + var latest_value: Dictionary = runtime.get("latest_snapshot") + var latest: Dictionary = transport(latest_value) + var digest: String = runtime.get("latest_digest") + var computed: String = SimulationDigest.compute(latest_value) + var after: Dictionary = layers() + demand(before.s_bytes == after.s_bytes and before.k_bytes == after.k_bytes and before.c_bytes == after.c_bytes, "E3 observation changed full S/K/C") + var cp: Dictionary = {"minute": clock.absolute_minute, "S": s, "latest": latest, "latest_digest": digest, "computed_latest_digest": computed, + "harness_normalized_digest": null, "K": before.K, "C": before.C, "observation": {"before": witness(before), "after": witness(after)}} + return {"checkpoint": cp, "raw": {"before": raw_layers(before), "after": raw_layers(after)}, + "K_tree": transport(before.K), "C_tree": transport(before.C)} + +func e3_input(kind: String) -> Dictionary: + var value: Dictionary = b1_snapshot.duplicate(true) + match kind: + "missing_key": value.erase(&"clock") + "wrong_type": value[&"clock"][&"absolute_minute"] = "x" + "out_of_range": value[&"clock"][&"speed"] = 9 + "duplicate_published_ids": + var ids: Array = value[&"systems"][&"runtime"][&"domain_events"]["published_ids"] + if demand(not ids.is_empty(), "B1 has no published ID to duplicate"): ids.append(ids[0]) + "duplicate_facility": + var instances: Array = value[&"systems"][&"runtime"][&"facilities"][&"instances"] + if not instances.is_empty(): instances.append(instances[0].duplicate(true)) + return value + +func e3_package(path: String) -> Dictionary: + var files: Dictionary = {} + for name: String in ["manifest.json", "world.bin", "thumbnail.png", "journal.log"]: + var target: String = path.path_join(name) + if not FileAccess.file_exists(target): + files[name] = null + continue + var file: FileAccess = FileAccess.open(target, FileAccess.READ) + if not demand(file != null, "package evidence open"): continue + var bytes: PackedByteArray = file.get_buffer(file.get_length()) + file.close() + files[name] = {"bytes": Marshalls.raw_to_base64(bytes), "sha256": hashed(bytes)} + return files + +func e3_prepare_package(path: String, input: Dictionary, kind: String) -> Dictionary: + # This helper is called only within run_e3's explicitly opened interval. + demand(scenario_active, "package preparation outside E3") + var budget_before: Dictionary = {} + for key: String in ["_samples", "_totals", "_sample_counts"]: + budget_before[key] = SaveService._performance_budget.get(key).duplicate(true) + var saved: Dictionary = SaveService.save_snapshot(path, input, {}) + var info: Dictionary = {"input": transport(input), "save_return": transport(saved), "original": e3_package(path), "budget_before": transport(budget_before)} + if saved.get(&"ok") == true: + if kind in ["missing_key", "wrong_type", "out_of_range"]: + var manifest_path: String = path.path_join("manifest.json") + var file: FileAccess = FileAccess.open(manifest_path, FileAccess.READ) + if not demand(file != null, "manifest read"): return info + var manifest: Dictionary = JSON.parse_string(file.get_as_text()) + file.close() + match kind: + "missing_key": manifest.erase("checksum_world") + "wrong_type": manifest["format_version"] = "x" + "out_of_range": manifest["format_version"] = 2147483647 + file = FileAccess.open(manifest_path, FileAccess.WRITE) + if not demand(file != null, "manifest write"): return info + file.store_string(json_text(manifest)) + file.close() + elif kind == "tampered_world": + var world_path: String = path.path_join("world.bin") + var file: FileAccess = FileAccess.open(world_path, FileAccess.READ_WRITE) + if not demand(file != null and file.get_length() > 0, "world tamper input"): return info + var offset: int = file.get_length() / 2 + file.seek(offset) + var old: int = file.get_8() + file.seek(offset) + file.store_8(old ^ 0x01) + file.close() + info["tamper"] = {"offset": offset, "before": old, "after": old ^ 0x01} + info["modified"] = e3_package(path) + return info + +func run_e3() -> void: + var facility_count: int = b1_snapshot[&"systems"][&"runtime"][&"facilities"][&"instances"].size() + var kinds: Array = ["missing_key", "wrong_type", "out_of_range", "duplicate_published_ids", "duplicate_facility", "tampered_world"] + lifecycle["e3"] = [] + lifecycle["e3_b1"] = transport(b1_snapshot) + for api: String in ["restore_snapshot", "validate", "load_from_path"]: + for kind: String in kinds: + var id: String = "E3/" + api + "/" + kind + var input: Dictionary = e3_input(kind) + var applicable: bool = true + var reason: Variant = null + if kind == "tampered_world" and api != "load_from_path": + applicable = false + reason = "Dictionary API does not read packages" + elif kind == "duplicate_facility" and facility_count == 0: + demand(role == "O", "R B1 must contain a facility") + applicable = false + reason = "B1 has zero facilities" + elif kind in ["duplicate_published_ids", "duplicate_facility"] and api == "validate": + applicable = false + reason = "Envelope validation does not inspect runtime internals" + var relative: String = "duplicate_id" if kind.begins_with("duplicate_") else kind + var path: String = "user://p28_eq/" + role.to_lower() + "/" + relative + var before: Dictionary = e3_observation() + var budget_before: Dictionary = {} + for key: String in ["_samples", "_totals", "_sample_counts"]: + budget_before[key] = SaveService._performance_budget.get(key).duplicate(true) + scenario_events = [] + scenario_signals = [] + scenario_active = true + var package: Variant = null + var actual: Variant = null + var invoked: bool = applicable or (api == "validate" and reason == "Envelope validation does not inspect runtime internals") + var invocation_before: Dictionary = before + if api == "load_from_path" and applicable: + var package_input: Dictionary = input if kind.begins_with("duplicate_") else b1_snapshot.duplicate(true) + package = e3_prepare_package(path, package_input, kind) + var saved: Dictionary = decode(package.save_return.tree) + if saved.get(&"ok") != true: + demand(kind.begins_with("duplicate_"), "required package preparation refused") + applicable = false + invoked = false + reason = "SaveService.save_snapshot refused duplicate input" + invocation_before = e3_observation() + # These are the only live E3 calls. No reset/repair of product state. + if invoked: + match api: + "restore_snapshot": actual = runtime.restore_snapshot(input) + "validate": actual = SimulationSnapshot.validate(input) + "load_from_path": actual = runtime.load_from_path(path) + if package != null: package["after_operation"] = e3_package(path) + var after: Dictionary = e3_observation() + scenario_active = false + var code: Variant = null + var code_reason: Variant = null + var actual_ok: Variant = null + var errors: Variant = null + var migration: bool = false + if api == "restore_snapshot": + code_reason = "API returns bool only" + actual_ok = actual + elif api == "validate": + code_reason = "API returns ok/errors only" + if invoked: + actual_ok = actual.get(&"ok") + errors = actual.get(&"errors") + elif invoked: + code = actual.get(&"code") + actual_ok = actual.get(&"ok") + migration = actual.get(&"migration_attempted", false) + demand(code != null, "load_from_path missing code") + var event_trees: Array = [] + for event_record: Dictionary in scenario_events: event_trees.append(event_record.tree) + var result: Dictionary = {"category": kind, "applicability": "applied" if applicable else "NA", + "reason": reason, "invoked": invoked, "facility_count": facility_count, "ok": actual_ok, "errors": errors, + "code": str(code) if code != null else null, "code_reason": code_reason, "migration_attempted": migration, + "event_count": scenario_events.size(), "path": path if api == "load_from_path" else null} + var scenario: Dictionary = {"id": id, "operation": api, "result": result, + "checkpoints": [before.checkpoint, after.checkpoint], "events": event_trees} + var budget_after: Dictionary = {} + for key: String in ["_samples", "_totals", "_sample_counts"]: + budget_after[key] = SaveService._performance_budget.get(key).duplicate(true) + var evidence: Dictionary = {"id": id, "begin": before, "invocation_before": invocation_before, "end": after, + "input": transport(input), "return": transport(actual), "package": package, "events": scenario_events, + "signals": scenario_signals.duplicate(true), "latest_save_operation_result": transport(runtime.get("latest_save_operation_result")), + "save_budget_before": transport(budget_before), "save_budget_after": transport(budget_after), "boundaries": ["begin", "operation", "end"]} + report.scenarios.append(scenario) + lifecycle.e3.append(evidence) + write_evidence("e3-%02d.json" % (report.scenarios.size() - 1), evidence) + +# S3b shares S3a's complete observation and transport; no state repair. +func e45_emit(id: String, operation: String, observations: Array, detail: Dictionary) -> void: + detail["signals"] = scenario_signals.duplicate(true) + var cps: Array = [] + for observation: Dictionary in observations: cps.append(observation.checkpoint) + var events: Array = [] + for event: Dictionary in scenario_events: events.append(event.tree) + var result: Dictionary = {"event_count": events.size(), "applicability": detail.get("applicability", "applied"), "reason": detail.get("reason")} + var facts: Dictionary = detail.duplicate(true) + for key: String in ["package_before", "package_after", "save_return", "return", "save_budget_before", "save_budget_after", "latest_save_operation_result", "observation_before", "observation_after"]: facts.erase(key) + if detail.has("return"): + var actual: Variant = decode(detail["return"].tree) + facts["return_fact"] = {"ok": actual.get(&"ok"), "code": actual.get(&"code")} if actual is Dictionary else actual + if facts.has("trials"): + for trial: Dictionary in facts.trials: + trial.erase("before") + trial.erase("after") + result["facts"] = facts + var evidence: Dictionary = {"id": id, "boundaries": ["begin", "operation", "end"], "observations": observations, + "events": scenario_events.duplicate(true), "signals": scenario_signals.duplicate(true), "detail": detail} + report.scenarios.append({"id": id, "operation": operation, "result": result, "checkpoints": cps, "events": events}) + lifecycle.e45.append(evidence) + write_evidence("e45-%02d.json" % (lifecycle.e45.size() - 1), evidence) + +func e4_candidates() -> Dictionary: + demand(scenario_active, "candidate search outside E4") + var before: Dictionary = e3_observation() + var raw_ids: Array = runtime.definition_registry.get_facility_ids() + var ids: Array = raw_ids.duplicate() + ids.sort_custom(func(a: Variant, b: Variant) -> bool: return str(a) < str(b)) + var bounds: Dictionary = runtime.world_service.get_bounds() + var selection: Dictionary = {"source": "definition_registry.get_facility_ids()", "raw_ids": transport(raw_ids), "count": raw_ids.size(), + "sorted_ids": transport(ids), "sort_rule": "String(id) ascending Unicode code point", "bounds": transport(bounds), + "cell_rule": "inclusive x/y public bounds; z FRONT=0 through BACK=1; x,y,z lexical; ID outer; rotation=0", + "trials": [], "chosen": null, "applicability": "applied", "reason": null, "observation_before": before} + if not demand(not ids.is_empty(), "empty facility registry"): + selection.applicability = "failure" + selection.reason = "empty facility registry" + selection["observation_after"] = e3_observation() + return selection + for definition_id: StringName in ids: + for x: int in range(bounds[&"min_x"], bounds[&"max_x"] + 1): + for y: int in range(bounds[&"min_y"], bounds[&"max_y"] + 1): + for z: int in range(0, 2): + var origin: Vector3i = Vector3i(x, y, z) + var preview: Dictionary = runtime.preview_build_facility(definition_id, origin, 0) + var candidate: Dictionary = {"definition_id": definition_id, "origin": origin, "rotation": 0} + selection.trials.append({"candidate": transport(candidate), "preview": transport(preview)}) + if preview.get(&"can_build") == true: + selection.chosen = transport(candidate) + selection["observation_after"] = e3_observation() + demand(json_text(before.raw) == json_text(selection.observation_after.raw), "preview search mutated S/K/C") + return selection + selection.applicability = "NA" + selection.reason = "all registry/cell pairs rejected by public preview" + selection["observation_after"] = e3_observation() + demand(json_text(before.raw) == json_text(selection.observation_after.raw), "preview search mutated S/K/C") + return selection + +func run_e4() -> void: + lifecycle["e45"] = [] + for operation: String in ["build_facility", "tick", "restore_snapshot", "load_from_path", "rejected_command"]: + var observations: Array = [e3_observation()] + var detail: Dictionary = {} + var save_budget_before: Dictionary = e45_save_budget() + scenario_events = [] + scenario_signals = [] + scenario_active = true + if operation == "build_facility": + detail = e4_candidates() + if detail.chosen != null: + var payload: Dictionary = decode(detail.chosen.tree) + var submitted: Variant = runtime.submit_command(&"build_facility", payload) + detail["submit"] = transport(submitted.to_dictionary()) + observations.append(e3_observation()) + clock.advance_minutes(1) + var completed: Variant = runtime.command_queue.get_processed_result(submitted.command_id) + detail["command_result"] = transport(completed.to_dictionary() if completed != null else null) + elif operation == "tick": + clock.advance_minutes(1) + elif operation == "restore_snapshot": + var input: Dictionary = runtime.create_snapshot().duplicate(true) + detail["input"] = transport(input) + detail["return"] = transport(runtime.restore_snapshot(input)) + elif operation == "load_from_path": + var input: Dictionary = runtime.create_snapshot().duplicate(true) + var path: String = "user://p28_eq/" + role.to_lower() + "/good" + detail["input"] = transport(input) + detail["path"] = path + var saved: Dictionary = SaveService.save_snapshot(path, input, {}) + detail["save_return"] = transport(saved) + detail["package_before"] = e3_package(path) + demand(saved.get(&"ok") == true, "E4 good package save failed") + detail["return"] = transport(runtime.load_from_path(path)) + detail["latest_save_operation_result"] = transport(runtime.get("latest_save_operation_result")) + detail["package_after"] = e3_package(path) + elif operation == "rejected_command": + var submitted: Variant = runtime.submit_command(&"build_facility", {&"definition_id": ""}) + detail["submit"] = transport(submitted.to_dictionary()) + observations.append(e3_observation()) + clock.advance_minutes(1) + var completed: Variant = runtime.command_queue.get_processed_result(submitted.command_id) + detail["command_result"] = transport(completed.to_dictionary() if completed != null else null) + detail["save_budget_before"] = save_budget_before + detail["save_budget_after"] = e45_save_budget() + observations.append(e3_observation()) + scenario_active = false + e45_emit("E4/" + operation, operation, observations, detail) + +func e45_save_budget() -> Dictionary: + var budget: Dictionary = {} + for key: String in ["_samples", "_totals", "_sample_counts"]: + budget[key] = SaveService._performance_budget.get(key).duplicate(true) + return transport(budget) + +func run_e5() -> void: + for target: String in ["create_snapshot", "latest_snapshot", "snapshot_published", "state_updated"]: + for location: String in ["dict", "array"]: + for direction: String in ["outside_in", "inside_out"]: + var observations: Array = [e3_observation()] + scenario_events = [] + scenario_signals = [] + scenario_active = true + # Explicit preparation tick refreshes signal references and starts a new baseline. + clock.advance_minutes(1) + var baseline: Dictionary = e3_observation() + observations.append(baseline) + var returned: Dictionary = {} + match target: + "create_snapshot": returned = runtime.create_snapshot() + "latest_snapshot": returned = runtime.get("latest_snapshot") + "snapshot_published": returned = snapshot_reference + "state_updated": returned = state_reference + var held_copy: Dictionary = returned.duplicate(true) + var detail: Dictionary = {"target": target, "location": location, "direction": direction, + "digest_materialized_before": true, "held_before": transport(held_copy)} + if direction == "outside_in": + if location == "dict": + returned[&"systems"][&"runtime"][&"id_generator"][&"counters"]["__p28_eq_probe"] = 1 + else: + returned[&"systems"][&"runtime"][&"domain_events"]["published_ids"].append("__p28_eq_probe") + else: + clock.advance_minutes(1) + observations.append(e3_observation()) + detail["held_after"] = transport(returned) + # Reset only through the authorized next tick, retaining the post-mutation state. + clock.advance_minutes(1) + observations.append(e3_observation()) + scenario_active = false + e45_emit("E5/" + target + "/" + location + "/" + direction, direction, observations, detail) + diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/run_eq.py b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/run_eq.py new file mode 100644 index 0000000..cfb7836 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/run_eq.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python3 +"""Root-only EQ driver. --check neither writes nor starts processes other than read-only host/Git queries.""" +import argparse +import importlib.util +import json +import os +from pathlib import Path +import shutil +import subprocess +import sys +import uuid + +sys.dont_write_bytecode = True +import check_eq as check +import compare_versions as eq +import verify_eq as verify + +HERE, ROOT = verify.HERE, verify.ROOT +BASE = 'docs/plans/original-completion-2026-10-02/execution/' +COLLECTOR = BASE + 'p28-01/collector/collect_p28_01.py' +DEPENDENCIES = { + 'tools/run_all_tests.py': '320ca668732b4ff72fc4449998af2327d4e5c527b06896740806aaf0487282b4', + 'tools/regression/owned_outer.py': 'c2e3483b76db1a3ff940f23f88ea0083fc78736e874ebcdb385d766dde8866e7', + 'tools/regression/owned_diagnostic_process.py': 'e31e93c6e2c5ea46a7d954ef8bc0b4caec1c08b86b8aef19e93b52ef24993087', + 'tools/regression/p09_owned_engine_process.py': 'c007e712c281573254faa1233c2ac92e100ab87393256a6dc096b35283e43037', + COLLECTOR: 'a43e1f963ef8505ddd5acf8bf747d9bfac22a028cbb805c0b964ee11b9b40a14', + BASE + 'p28-01/collector/check_p28_01_report.py': '6c0851d498ca80bdc120fad047b072255f48713f63114521f3d4dfc902b2512b', + BASE + 'p28-02/diag/diag_probe.gd': '4124067d4b193693f696d2b1a1e6eb56731948cfefd5a6e420b5c9a14fb2b11e', + BASE + 'p28-02/diag/verify_diag.py': '829354804f0ebb152a8092486ccadbc6b36143a5c9187dac75c15f90b70d1fb9', + BASE + 'p28-02/diag/test_diag.py': '744b779f4b2452e0c1660c6fd1aa009d26e7315e8a0fddd669a2ac3e261c61b4', + BASE + 'p28-02/diag/diag_p28_02.py': '6b47d08b490ba742ce00e8835a09011c5966d0a8fc7b578498bfc80bc03f14ed', + BASE + 'p28-02/diag/check_diag.py': '96dd9bef220339d6a973215d8db9a73c1bfa44f9e151bcf897641882e831b5ba', +} +FROZEN = { + 'SPEC.md': '3791ccdcb87e8d71fe9205e1e692ebca9e0f974ea3b5fbc4fbb3943882131f1c', + 'TASK_INSTRUCTIONS.md': 'f9937c3c7dff5a25ada453365d26c87fecf009d29518724f0c1e67d2b18afff3', + 'references/OPT_CONTRACT_T1.md': 'ad9f3d76f3500b39263fb898d7c64588b4b47c9e11b456f938195261fd054d16', + 'references/OPUS_D2_SCOPE_CLARIFICATION.txt': '5775e7b512d9e90dbcfbcb181f5b64dc0fa8207e0947c0a4a6a5c9195565f9bd', + 'references/OPUS_STARTUP_LIFECYCLE_CLARIFICATION.txt': '967aebf27ff412f7a16ce771ef7d68abf8cfde0bb76ed19cf6dbf2817ca7acc6', + 'registration/ACCEPTANCE_BASELINE.json': '84628bc21205387f8a7143031bdc50c9f68a767d350e6c34b32e0ba1c7059337', + 'registration/CONFIG_PROPOSAL.json': '775fbbb97cda8b4d4991defdf7871b0fc79f489f4dea34c1733d4830426cf1df', + 'registration/REGISTRATION_PROPOSAL.json': '9590fc853a4df8d50cc0d269d23bd9c844dc6931590ff6f24ebf95bb54a8d135', + 'registration/ROOT_PROPOSAL_BYTE_TRANSFER.json': '63197f650849084f769e487a76458361886a37090042f1e351851c75b0384da2', +} +require, sha, pin, write = verify.require, verify.sha, verify.pin, verify.write + + +def load_dependencies(root=ROOT): + root = Path(root).resolve() + for name, expected in DEPENDENCIES.items(): + require(sha(root / name) == expected, 'dependency pin: ' + name) + local = root / HERE.relative_to(ROOT) + for name in verify.LOCAL_NAMES - {'eq_probe.gd'}: + check.check_python_imports((local / name).read_text()) + def load(relative, module_name): + require(relative in DEPENDENCIES and relative.endswith('.py'), 'import outside closure') + spec = importlib.util.spec_from_file_location(module_name, root / relative) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + # Import sibling dependencies under their real names before the collector. + load(BASE + 'p28-01/collector/check_p28_01_report.py', 'check_p28_01_report') + collector = load(COLLECTOR, 'eq_collector') + diag = load(BASE + 'p28-02/diag/check_diag.py', 'eq_diag_check') + for name in diag.DEPENDENCIES: + diag.check_imports((root / name).read_text(), external=name) + standard = collector.load_tool(collector.EXTERNAL_IMPORTS[0]) + outer = collector.load_tool(collector.EXTERNAL_IMPORTS[1]) + require(Path(outer.native.helper['__file__']).resolve() == root / 'tools/regression/p09_owned_engine_process.py', 'helper closure') + for module in [collector, standard, outer, outer.native, *list(sys.modules.values())]: + name = getattr(module, '__file__', None) + if name: + path = Path(name).resolve() + if path.is_relative_to(root): + require(path.relative_to(root).as_posix() in DEPENDENCIES or path.is_relative_to(local), 'loaded module outside closure') + return collector, standard, outer, diag + + +def actual_pins(root, readonly, fixture, engine, collector, standard): + local = root / HERE.relative_to(ROOT) + dependencies = {n: sha(root / n) for n in DEPENDENCIES} + require(dependencies == DEPENDENCIES, 'dependencies changed') + frozen = {n: sha(local / n) for n in FROZEN} + require(frozen == FROZEN, 'frozen specification changed') + source = collector.source_map(standard, root) + require(len(source) == 1407 and collector.digest(source) == eq.SOURCE_SHA, 'full 1407 source pin') + require(sha(fixture) == collector.FIXTURE_SHA and sha(engine) == collector.ENGINE_SHA, 'fixture/engine pin') + inputs = collector.inputs(readonly) + require(len(inputs['files']) == 9, 'nine original destinations required') + manifest = verify.read(readonly / 'ROOT_INPUT_MANIFEST.json') + require(len(manifest['files']) == 9 and len({r['destination'] for r in manifest['files']}) == 9, 'nine unique destinations') + require(sys.platform == 'darwin', 'native platform') + machine = subprocess.check_output(['sysctl', '-n', 'hw.model'], text=True).strip() + require(machine == 'Mac16,10', 'machine pin') + return {'source': source, 'source_sha256': collector.digest(source), 'dependencies': dependencies, + 'frozen': frozen, 'worker': {n: sha(local / n) for n in sorted(verify.LOCAL_NAMES)}, + 'fixture': pin(fixture), 'engine': pin(engine), 'engine_version': collector.VERSION, + 'project': source['project.godot'], 'readonly': inputs, 'original_manifest': manifest, + 'machine': machine, 'platform': sys.platform} + + +def frozen_commit(source): + commit = subprocess.check_output(['git', '-C', str(ROOT), 'rev-parse', 'HEAD'], text=True).strip() + for name in list(source) + [str((HERE / n).relative_to(ROOT)) for n in verify.LOCAL_NAMES]: + data = subprocess.check_output(['git', '-C', str(ROOT), 'show', commit + ':' + name]) + require(data == (ROOT / name).read_bytes(), 'not frozen S: ' + name) + return commit + + +def wrapper_text(out): + return ('extends ' + json.dumps(str(out / 'eq_probe.gd')) + '\nconst Guard = preload(' + + json.dumps(str(out / 'profile_guard.gd')) + ')\nfunc _initialize() -> void:\n' + '\tif not Guard.activate():\n\t\tquit(97)\n\t\treturn\n\tsuper._initialize()\n') + + +def plan(collector, standard, engine, fixture, out): + stage, wrapper = out / 'stage', out / 'guarded.gd' + commands = [collector.argv_for(engine, stage, wrapper, importing=True), + collector.parse_argv(engine, stage, out / 'eq_probe.gd'), + collector.parse_argv(engine, stage, wrapper)] + [ + [str(engine), '--headless', '--path', str(stage), '--script', str(wrapper)] for _ in range(4)] + rows = [] + for phase, command in zip(verify.PHASES, commands): + startup_name = 'TheTree-PCK-tests-' + uuid.uuid4().hex + '-eq-startup' + runtime_name = 'TheTree-PCK-tests-' + uuid.uuid4().hex + '-eq-runtime' + startup, runtime = standard.profile_path(startup_name), standard.profile_path(runtime_name) + require(not startup.exists() and not runtime.exists(), 'fresh profiles required') + role = verify.ROLES.get(phase) + env = {'THE_TREE_PACK_PROFILE_NAME': runtime_name, 'THE_TREE_PACK_PROFILE_EXPECTED': str(runtime), + 'THE_TREE_PACK_PROFILE_REPORT': str(out / (phase + '-guard.json')), + 'THE_TREE_EQ_ROLE': role or '', 'THE_TREE_P28_FIXTURE': str(fixture), + 'THE_TREE_P28_FIXTURE_SHA': collector.FIXTURE_SHA} + rows.append({'phase': phase, 'role': role, 'argv': command, 'environment': env, + 'startup_name': startup_name, 'startup_profile': str(startup), + 'runtime_name': runtime_name, 'runtime_profile': str(runtime), 'folder': str(out / phase)}) + return rows + + +def copy_evidence(runtime, destination): + source = runtime / 'evidence' + before = verify.inventory(source, seals=True) + require(set(before) == verify.NAMES, 'private evidence missing/extra') + destination.mkdir() + for name in sorted(before): + shutil.copyfile(source / name, destination / name) + require(verify.inventory(source, seals=True) == before == verify.inventory(destination, seals=True), 'evidence changed during copy') + return before + + +def copy_profile(source, destination, collector): + """Keep complete private package/log/config bytes, including non-evidence files.""" + exists = source.is_dir() + before = collector.profile_files(source) + if exists: + destination.mkdir() + for name in before: + target = destination / name + target.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(source / name, target) + require(verify.inventory(destination, seals=True) == before, 'profile copy mismatch') + require(collector.profile_files(source) == before, 'profile changed during copy') + return {'exists': exists, 'files': before} + + +def run(admission, out, collector, standard, outer, diag): + require(not out.exists(), 'new output required') + collector.no_live_engine() + out.mkdir(parents=True) + write(out / 'admission.json', admission) + rows, profiles, error = [], [], None + source = admission['source_map'] + player = standard.default_player(ROOT) + public = (ROOT / 'project.godot').read_bytes() + stage = out / 'stage' + try: + stage.mkdir() + for name in source: + target = stage / name + target.parent.mkdir(parents=True, exist_ok=True) + standard.copy_source(ROOT / name, target) + expected = standard.inventory(stage, stage=True) + require(expected == source, 'stage source differs') + (out / 'eq_probe.gd').write_bytes((HERE / 'eq_probe.gd').read_bytes()) + (out / 'profile_guard.gd').write_bytes((Path(admission['readonly_path']) / 'run-r02/profile_guard.gd').read_bytes()) + (out / 'guarded.gd').write_text(wrapper_text(out)) + (out / 'root-input-manifest.json').write_bytes((Path(admission['readonly_path']) / 'ROOT_INPUT_MANIFEST.json').read_bytes()) + for item in admission['plan']: + phase = item['phase'] + require(standard.inventory(stage, stage=True) == expected, 'stage changed before phase') + require(collector.source_map(standard, ROOT) == source and standard.default_player(ROOT) == player, 'source/player changed') + for name, expected_sha in admission['pins']['worker'].items(): + require(sha(HERE / name) == expected_sha, 'EQ changed during execution') + profiles.extend([Path(item['startup_profile']), Path(item['runtime_profile'])]) + require(all(not p.exists() for p in profiles[-2:]), 'profile reuse') + row = collector.run_private_engine(standard, outer, item['argv'], out / phase, + item['environment'], stage, public, item['startup_name']) + row.update(phase=phase, role=item['role'], environment=item['environment'], pid=row['process']['pid']) + rows.append(row) + require(row['passed'] is True, 'owned phase failure: ' + phase) + after = standard.inventory(stage, stage=True) + collector.stage_gate(expected, after, importing=phase == 'import') + expected = after + row.update(stage_inventory=after, source_preserved=collector.source_map(standard, ROOT) == source, + player_preserved=standard.default_player(ROOT) == player) + if phase in verify.ROLES: + guard_path = out / (phase + '-guard.json') + guard = verify.read(guard_path) + collector.guard_gate(guard, Path(item['runtime_profile']), item['runtime_name']) + row.update(runtime_profile=item['runtime_profile'], runtime_name=item['runtime_name'], + guard=guard, guard_sha256=sha(guard_path)) + row['evidence_files'] = copy_evidence(Path(item['runtime_profile']), out / phase / 'evidence') + verify.phase_evidence(out, row) + row['profile_copies'] = { + 'startup': copy_profile(Path(item['startup_profile']), out / phase / 'startup-profile', collector), + 'runtime': copy_profile(Path(item['runtime_profile']), out / phase / 'runtime-profile', collector)} + diag.bound_raw(out / phase, row) + except BaseException as caught: + error = repr(caught) + finally: + cleanup, cleanup_errors = outer.finish_captured(outer.OWNED) + execution = {'admission': admission, 'phases': rows, 'passed': error is None, 'error': error, + 'cleanup': cleanup, 'cleanup_errors': cleanup_errors, 'source_after': collector.source_map(standard, ROOT), + 'player_before': player, 'player_after': standard.default_player(ROOT), + 'profiles_retained': {str(p): collector.profile_files(p) for p in profiles}} + try: + execution['pins_after'] = actual_pins(ROOT, Path(admission['readonly_path']), Path(admission['fixture']), + Path(admission['engine']), collector, standard) + require((ROOT / 'project.godot').read_bytes() == public and (stage / 'project.godot').read_bytes() == public, 'project restoration') + if error is None: + result = verify.recompute(out, execution, collector, standard, diag) + write(out / 'results.json', result) + for phase, values in result['phases'].items(): + for name, value in values.items(): + write(out / phase / (name + '.json'), value) + except BaseException as caught: + execution.update(passed=False, error=repr(caught)) + write(out / 'execution.json', execution) + if execution['passed']: + verify.seal(out) + return 0 if execution['passed'] else 1 + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + mode = parser.add_mutually_exclusive_group(required=True) + mode.add_argument('--check', action='store_true') + mode.add_argument('--run', action='store_true') + for name in ('readonly', 'fixture', 'engine', 'output'): + parser.add_argument('--' + name, type=Path, required=True) + args = parser.parse_args() + try: + readonly, fixture, engine, out = [p.resolve() for p in (args.readonly, args.fixture, args.engine, args.output)] + require(not out.exists(), 'new output required') + collector, standard, outer, diag = load_dependencies() + pins = actual_pins(ROOT, readonly, fixture, engine, collector, standard) + static = check.check_probe((HERE / 'eq_probe.gd').read_text()) + require(static['ok'], 'probe checker: ' + repr(static['errors'])) + admission = {'measured_source': 'S_eq-native-not-Q', 'candidate_Q_measured': False, + 'commit': frozen_commit(pins['source']), 'source_map': pins['source'], 'pins': pins, + 'readonly_path': str(readonly), 'fixture': str(fixture), 'engine': str(engine), + 'phases': verify.PHASES, 'plan': plan(collector, standard, engine, fixture, out)} + if args.check: + print(json.dumps(admission, ensure_ascii=False, indent=2)) + return 0 + return run(admission, out, collector, standard, outer, diag) + except (ValueError, OSError, KeyError, TypeError, subprocess.CalledProcessError) as error: + print(json.dumps({'status': 'failed', 'error': str(error)})) + return 1 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py new file mode 100644 index 0000000..9c1fbf4 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/test_eq.py @@ -0,0 +1,1702 @@ +"""Engine-free S1 tests; synthetic typed trees only.""" +import copy +import hashlib +import json +import sys +import unittest +from unittest.mock import patch + +sys.dont_write_bytecode = True +import compare_versions as eq + + +def d(**fields): + return [27, [[[4, k], v] for k, v in fields.items()], None] + + +def arr(*values): + return [28, list(values), None] + + +def profile(root='/private/a'): + return {'root': root, 'actual_user_data_dir': root} + + +def event(root='/private/a', duration=7, kind='SAVE_LOADED', source='save_service'): + return d(event_id=[4, 'event_1'], event_type=[4, kind], source_service=[4, source], + absolute_minute=[2, 1], entity_ids=arr(), causation_command_id=[4, ''], + payload=d(duration_us=[2, duration], runtime_duration_us=[2, duration+1], + message=[4, root+'/p28_eq/r/good: '+root+'/world.bin'], code=[4, 'OK'])) + + +def snapshot(e=None): + return d(systems=d(runtime=d(domain_events=d(recent_events=arr(*(e or []))))), value=arr([2, 1])) + + +def transport(t): + return {'tree': copy.deepcopy(t), 'tree_sha': eq.tree_sha(t), 'raw_bytes_sha': 'a'*64, 'roundtrip_ok': True} + + +def checkpoint(t=None, minute=0): + t = snapshot() if t is None else t + k = {key: 0 for key in eq.K_COMPARE} + k.update(_accumulator='0000000000000000', _phase_handlers={'0': ['h1', 'h2']}, + performance_budget={'_samples': {'x': [1]}, '_totals': {'x': 1}, '_sample_counts': {'x': 1}}) + c = {'_mvp_manifest_cache_generation': 1, 'catalog_is_current': True, + '_mvp_manifest_cache_bytes': 'AA==', 'catalog_instance_id': 123, 'current_catalog_instance_id': 123} + return {'minute': minute, 'S': transport(t), 'latest': transport(t), + 'latest_digest': 'digest', 'computed_latest_digest': 'digest', 'harness_normalized_digest': 'norm', + 'K': k, 'C': c, 'observation': {side: {layer: 'a'*64 for layer in ('S', 'K', 'C')} for side in ('before', 'after')}} + + +def report(t=None): + return {'schema': 'p28-02-eq/typed-v1', 'role': 'R', 'profile_root': profile(), + 'checkpoints': [checkpoint(t, i) for i in range(31)], 'events': [], + 'event_start': {'counter': 3, 'published_ids_count': 3}, 'event_end': 3, + 'signal_order': [], 'scenarios': []} + + +class TypedTrees(unittest.TestCase): + def test_exact_and_types(self): + for a, b in (([2, 1], [3, '000000000000f03f']), ([4, 'x'], [21, 'x']), + (arr([2, 1]), [28, [[2, 1]], [[2, 2], [21, ''], [0]]])): + self.assertFalse(eq.compare_trees(a, b)['equal']) + self.assertTrue(eq.compare_trees(snapshot(), snapshot())['exact']) + + def test_nested_order_all_paths(self): + a = d(a=d(x=[2, 1], y=[2, 2]), b=d(c=[2, 3], d=[2, 4])) + b = copy.deepcopy(a) + b[1].reverse() + for _, n in b[1]: + n[1].reverse() + result = eq.compare_trees(a, b) + self.assertTrue(result['equal']) + self.assertEqual(len(result['dict_order_paths']), 3) + self.assertFalse(result['exact']) + + def test_duplicate_textual_keys_rejected(self): + a = [27, [[[4, 'x'], [2, 1]], [[21, 'x'], [2, 2]]], None] + b = copy.deepcopy(a); b[1].reverse() + with self.assertRaises(eq.EvidenceError): + eq.compare_trees(a, b) + + def test_array_order_and_all_differences(self): + result = eq.compare_trees(arr([2, 1], [2, 2]), arr([2, 2], [2, 1])) + self.assertEqual(len(result['differences']), 2) + + def test_nonstring_keys_keep_types_and_values(self): + a = [27, [[[2, 1], [4, 'one']], [[2, 2], [4, 'two']]], None] + b = copy.deepcopy(a); b[1].reverse() + self.assertTrue(eq.compare_trees(a, b)['equal']) + b[1][0][1] = [4, 'changed'] + self.assertFalse(eq.compare_trees(a, b)['equal']) + a = [27, [[[2, 1], [0]], [[4, '1'], [0]]], None] + b = copy.deepcopy(a); b[1].reverse() + with self.assertRaises(eq.EvidenceError): + eq.compare_trees(a, b) + + def test_deep_state_not_truncated(self): + a, b = [2, 1], [2, 2] + for _ in range(40): + a, b = d(child=a), d(child=b) + self.assertEqual(len(eq.compare_trees(a, b)['differences'][0]['path']), 40) + + def test_unsupported_and_malformed(self): + for n in ([23, 0], [24, 0], [25, 0], [26, 0], [3, '1.0'], [2, True], + [1, 2], [2, 2**63], [27, [], {}], [29, '%%%'], [28, [], [[2, 2], [21, ''], [24, 0]]]): + with self.subTest(n=n), self.assertRaises(eq.EvidenceError): + eq.validate_tree(n) + + def test_components_and_sha(self): + zero = [3, '0000000000000000'] + eq.validate_tree([20, [zero]*4]) + eq.validate_tree([37, [[20, [zero]*4]]]) + eq.validate_tree([29, 'AAEC']) + tree = d(text=[4, '日本語/é\n']) + expected = hashlib.sha256(json.dumps(tree, ensure_ascii=False, separators=(',', ':')).encode()).hexdigest() + self.assertEqual(eq.tree_sha(tree), expected) + self.assertNotEqual(eq.tree_sha([3, '0000000000000000']), eq.tree_sha([3, '0000000000000080'])) + + +class Diffs(unittest.TestCase): + def test_all_operations(self): + a = d(items=arr([2, 1], [2, 2]), gone=[4, 'old']) + path = [['key', [4, 'items']]] + ops = [{'op': 'array_splice', 'path': path, 'start': 1, 'delete_count': 1, 'nodes': [[2, 3], [2, 4]]}, + {'op': 'set', 'path': path+[['index', 0]], 'node': [2, 9]}, + {'op': 'dict_remove', 'path': [], 'key_node': [4, 'gone']}, + {'op': 'dict_insert', 'path': [], 'index': 0, 'key_node': [4, 'new'], 'value_node': [1, 1]}] + result = eq.apply_diff(a, ops) + self.assertEqual(result, d(new=[1, 1], items=arr([2, 9], [2, 3], [2, 4]))) + self.assertEqual(a, d(items=arr([2, 1], [2, 2]), gone=[4, 'old'])) + + def test_invalid_operations(self): + for op in ({'op': 'dict_remove', 'path': [], 'key_node': [4, 'absent']}, + {'op': 'dict_insert', 'path': [], 'index': 0, 'key_node': [4, 'x'], 'value_node': [0]}, + {'op': 'set', 'path': [['key', [4, 'absent']]], 'node': [0]}, + {'op': 'unknown', 'path': []}): + with self.subTest(op=op), self.assertRaises(eq.EvidenceError): + eq.apply_diff(d(x=[2, 1]), [op]) + with self.assertRaises(eq.EvidenceError): + eq.apply_diff(arr(), [{'op': 'array_splice', 'path': [], 'start': -1, 'delete_count': 0, 'nodes': []}]) + + def test_reconstruction_and_proofs(self): + a, b = d(x=[2, 1]), d(x=[2, 2]) + b_record = transport(b) + del b_record['tree'] + b_record['diff'] = [{'op': 'set', 'path': [['key', [4, 'x']]], 'node': [2, 2]}] + same = {k: v for k, v in transport(a).items() if k != 'tree'} + same['same_as_S'] = True + cps = [{'S': transport(a), 'latest': same}, {'S': b_record, 'latest': transport(a)}] + self.assertEqual(eq.reconstruct_checkpoints(cps), [(a, a), (b, a)]) + for key, bad in (('tree_sha', 'b'*64), ('roundtrip_ok', False), ('raw_bytes_sha', 'missing')): + corrupt = copy.deepcopy(cps); corrupt[1]['S'][key] = bad + with self.subTest(key=key), self.assertRaises(eq.EvidenceError): + eq.reconstruct_checkpoints(corrupt) + + +class Normalization(unittest.TestCase): + def test_every_save_event_reversible(self): + for kind in eq.SAVE_EVENTS: + events = [event(kind=kind)] + original = copy.deepcopy(events) + n, side = eq.normalize_events(events, profile()) + self.assertEqual(set(side), {'entries', 'violations', 'profile_root'}) + self.assertEqual(len(side['entries']), 3) + self.assertEqual(eq.restore_events(n, side, profile()), original) + self.assertEqual(events, original) + self.assertIn(eq.TOKEN, json.dumps(n)) + + def test_snapshot_and_latest_reversible(self): + t = snapshot([event()]) + n, side = eq.normalize_tree(t, profile()) + self.assertEqual(len(side['entries']), 3) + self.assertEqual(eq.tree_sha(eq.restore_tree(n, side, profile())), eq.tree_sha(t)) + + def test_environment_values_differ_but_normal_form_equal(self): + a, b = event(), event('/private/b', 999) + x, sx = eq.normalize_events([a], profile()) + y, sy = eq.normalize_events([b], profile('/private/b')) + self.assertEqual(x, y) + self.assertNotEqual(sx, sy) + + def test_guard_mismatch(self): + with self.assertRaises(eq.EvidenceError): + eq.normalize_events([event()], {'root': '/private/a', 'actual_user_data_dir': '/private/b'}) + with self.assertRaises(eq.EvidenceError): + eq.normalize_events([event()], '/private/a') + + def test_wrong_event_and_source_are_preserved(self): + for kwargs in ({'kind': 'UNKNOWN'}, {'source': 'not_save_service'}): + original = [event(**kwargs)] + n, side = eq.normalize_events(original, profile()) + self.assertEqual(n, original) + self.assertEqual(side['entries'], []) + self.assertTrue(side['violations']) + self.assertEqual(eq.restore_events(n, side, profile()), original) + + def test_nested_lookalike_is_not_eligible(self): + e = event() + eq._field(e, 'payload')[1].append([[4, 'nested'], event()]) + n, side = eq.normalize_events([e], profile()) + self.assertEqual(len(side['entries']), 3) + self.assertEqual(eq._field(eq._field(n[0], 'payload'), 'nested'), event()) + + def test_snapshot_event_outside_recent_is_not_eligible(self): + s = d(unrelated=event()) + n, side = eq.normalize_tree(s, profile()) + self.assertEqual(n, s) + self.assertFalse(side['entries']) + self.assertTrue(side['violations']) + + def test_wrong_timing_type_and_negative(self): + for value in ([2, -1], [3, '000000000000f03f'], [4, '7']): + e = event(); eq._field(eq._field(e, 'payload'), 'duration_us')[:] = value + with self.assertRaises(eq.EvidenceError): + eq.normalize_events([e], profile()) + + def test_partial_timing_payload_rejected(self): + e = event() + payload = eq._field(e, 'payload') + payload[1] = [pair for pair in payload[1] if pair[0][1] != 'runtime_duration_us'] + with self.assertRaises(eq.EvidenceError): + eq.normalize_events([e], profile()) + + def test_sidecar_missing_duplicate_and_forged_paths(self): + n, side = eq.normalize_events([event()], profile()) + cases = [] + bad = copy.deepcopy(side); bad['entries'].pop(); cases.append(bad) + bad = copy.deepcopy(side); bad['entries'].append(bad['entries'][0]); cases.append(bad) + bad = copy.deepcopy(side); bad['entries'][0]['key'] = 'other_us'; cases.append(bad) + bad = copy.deepcopy(side); bad['entries'][0]['path'] = [['key', [4, 'event_id']]]; cases.append(bad) + bad = copy.deepcopy(side); bad['entries'][-1]['original_node'][1] += 'changed'; cases.append(bad) + bad = copy.deepcopy(side); bad['entries'][-1]['root'] = '/elsewhere'; cases.append(bad) + for bad in cases: + with self.subTest(bad=bad), self.assertRaises(eq.EvidenceError): + eq.restore_events(n, bad, profile()) + + def test_attempt_to_normalize_violation_rejected(self): + e = event(kind='OTHER') + n, side = eq.normalize_events([e], profile()) + path = [['key', [4, 'payload']], ['key', [4, 'duration_us']]] + eq._put(n[0], path, eq._marker('duration_us', [2, 7])) + side['entries'].append({'event_index': 0, 'path': path, 'key': 'duration_us', 'original_node': [2, 7]}) + with self.assertRaises(eq.EvidenceError): + eq.restore_events(n, side, profile()) + + def test_original_transport_sha_detects_forged_timing(self): + original = snapshot([event()]) + n, side = eq.normalize_tree(original, profile()) + side['entries'][0]['original_node'][1] += 1 + restored = eq.restore_tree(n, side, profile()) + self.assertNotEqual(eq.tree_sha(restored), eq.tree_sha(original)) + + def test_f3_keeps_relative_paths_and_words(self): + a, b = event(), event('/private/b') + eq._field(eq._field(b, 'payload'), 'message')[1] += ' different error' + na, _ = eq.normalize_events([a], profile()) + nb, _ = eq.normalize_events([b], profile('/private/b')) + self.assertFalse(eq.compare_trees(na[0], nb[0])['equal']) + + def test_prefix_boundary_and_reserved_token(self): + e = event() + eq._field(eq._field(e, 'payload'), 'message')[1] = '/private/another/world.bin' + n, side = eq.normalize_events([e], profile()) + self.assertEqual(eq._field(eq._field(n[0], 'payload'), 'message'), [4, '/private/another/world.bin']) + self.assertEqual(len(side['entries']), 2) + eq._field(eq._field(e, 'payload'), 'message')[1] = eq.TOKEN+'world.bin' + with self.assertRaises(eq.EvidenceError): + eq.normalize_events([e], profile()) + + +class Reports(unittest.TestCase): + def test_same_report(self): + a = report() + self.assertTrue(eq.compare_reports(a, copy.deepcopy(a))['ok']) + + def test_exclusions_keep_actual_values(self): + a, b = report(), report() + b['checkpoints'][0]['K']['performance_budget']['_samples'] = {'x': [9]} + b['checkpoints'][0]['C']['catalog_instance_id'] = 456 + result = eq.compare_reports(a, b) + self.assertTrue(result['ok'], result) + self.assertTrue(any(x['a'] != x['b'] for x in result['excluded'])) + + def test_all_semantic_layers_compared(self): + for layer, key, value in (('K', 'speed', 3), ('K', '_accumulator', '000000000000f03f'), + ('C', '_mvp_manifest_cache_generation', 2), ('C', '_mvp_manifest_cache_bytes', 'AQ==')): + a, b = report(), report() + b['checkpoints'][0][layer][key] = value + with self.subTest(key=key): + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_unknown_or_missing_fields_rejected(self): + for mutation in ('unknown', 'missing', 'manifest'): + a, b = report(), report() + if mutation == 'unknown': b['checkpoints'][0]['K']['unlisted'] = 1 + if mutation == 'missing': del b['checkpoints'][0]['K']['speed'] + if mutation == 'manifest': b['manifest'] = {'created_at_real': 'now'} + with self.subTest(mutation=mutation): + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_digest_alone_is_not_enough(self): + a, b = report(d(value=[2, 1])), report(d(value=[2, 2])) + self.assertFalse(eq.compare_reports(a, b)['ok']) + self.assertFalse(eq.compare_reports({'latest_digest': 'x'}, {'latest_digest': 'x'})['ok']) + + def test_timing_digest_rule(self): + a, b = report(snapshot([event()])), report(snapshot([event('/private/b', 19)])) + b['profile_root'] = profile('/private/b') + for cp in b['checkpoints']: + cp['latest_digest'] = cp['computed_latest_digest'] = 'other raw digest' + result = eq.compare_reports(a, b) + self.assertTrue(result['ok'], result) + self.assertTrue(all(m['mode'] == 'harness normalized digest' for m in result['digest_modes'])) + b['checkpoints'][0]['harness_normalized_digest'] = 'different' + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_product_digest_self_consistency(self): + a, b = report(), report() + b['checkpoints'][0]['computed_latest_digest'] = 'bad' + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_observation_full_layers(self): + for layer in ('S', 'K', 'C'): + a, b = report(), report() + b['checkpoints'][0]['observation']['after'][layer] = 'b'*64 + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_event_start_and_ids(self): + a, b = report(), report() + b['event_start']['counter'] += 1 + self.assertFalse(eq.compare_reports(a, b)['ok']) + b = report(); b['event_start']['published_ids_count'] += 1 + self.assertFalse(eq.compare_reports(a, b)['ok']) + b = report() + ea, eb = event(), event() + eq._field(eb, 'event_id')[1] = 'event_2' + for r, e in ((a, ea), (b, eb)): + r['events'] = [{'sequence': 0, 'transport': transport(e), 'original_field_types': {'event_id': 21}}] + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_violation_presence_and_difference(self): + a = report(d(unknown_ms=[2, 7])) + self.assertTrue(eq.compare_reports(a, copy.deepcopy(a))['ok']) + b = report(d(unknown_ms=[2, 8])) + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_scenario_existing_failures_preserved(self): + a, b = report(), report() + scenario = {'id': 'E5/latest', 'operation': 'mutate_nested', 'result': {'ownership_ok': False, 'changed_paths': ['x']}, + 'checkpoints': [checkpoint(), checkpoint()], 'events': []} + a['scenarios'] = [copy.deepcopy(scenario)]; b['scenarios'] = [copy.deepcopy(scenario)] + self.assertTrue(eq.compare_reports(a, b)['ok']) + b['scenarios'][0]['result']['ownership_ok'] = True + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_handler_sets_and_counts(self): + a, b = report(), report() + b['checkpoints'][0]['K']['_phase_handlers']['0'].reverse() + self.assertTrue(eq.compare_reports(a, b)['ok']) + b['checkpoints'][0]['K']['performance_budget']['_sample_counts']['x'] += 1 + self.assertFalse(eq.compare_reports(a, b)['ok']) + + def test_all_events_beyond_recent_window(self): + a, b = report(), report() + for i in range(300): + e = event(); eq._field(e, 'event_id')[1] = 'event_'+str(i) + a['events'].append({'sequence': i, 'transport': transport(e), 'original_field_types': {'event_id': 21}}) + b['events'] = copy.deepcopy(a['events']) + e = copy.deepcopy(b['events'][-1]['transport']['tree']) + eq._field(e, 'causation_command_id')[1] = 'changed' + b['events'][-1]['transport'] = transport(e) + result = eq.compare_reports(a, b) + self.assertFalse(result['ok']) + self.assertTrue(any(row['path'][:2] == ['events', 299] for row in result['differences'])) + + def test_event_original_types_and_order(self): + a, b = report(), report() + a['events'] = [{'sequence': 0, 'transport': transport(event()), 'original_field_types': {'event_id': 21}}] + b['events'] = copy.deepcopy(a['events']) + b['events'][0]['original_field_types']['event_id'] = 4 + self.assertFalse(eq.compare_reports(a, b)['ok']) + b['events'][0]['sequence'] = 1 + self.assertFalse(eq.compare_reports(a, b)['ok']) + + +class SourcesAndMetrics(unittest.TestCase): + def test_fixed_scenario_paths(self): + self.assertTrue(eq.validate_scenario_paths(['user://p28_eq/r/good', 'user://p28_eq/o/tampered_world'])) + for suffix in ('2026-10-21', '550e8400-e29b-41d4-a716-446655440000', 'pid123', '../good'): + with self.assertRaises(eq.EvidenceError): + eq.validate_scenario_paths(['user://p28_eq/r/'+suffix]) + + def test_source_pin_is_not_caller_controlled(self): + fake = {str(i): {'bytes': 1, 'sha256': 'a'*64} for i in range(1407)} + self.assertFalse(eq.check_source_closure(fake, fake, [])['ok']) + + def test_source_closure_synthetic_registered_map(self): + # Isolate closure logic with a synthetic pin; production constant remains + # fixed and its rejection is separately tested above. + paths = sorted(eq.OPT_PATHS) + ['synthetic/'+str(i) for i in range(1401)] + before = {p: {'bytes': 1, 'sha256': 'a'*64} for p in paths} + digest = hashlib.sha256(json.dumps(before, sort_keys=True, separators=(',', ':')).encode()).hexdigest() + with patch.object(eq, 'SOURCE_SHA', digest): + self.assertTrue(eq.check_source_closure(before, before, [])['ok']) + after = copy.deepcopy(before); after[paths[0]]['sha256'] = 'b'*64 + self.assertTrue(eq.check_source_closure(before, after, [paths[0]])['ok']) + self.assertFalse(eq.check_source_closure(before, after, [])['ok']) + self.assertFalse(eq.check_source_closure(before, before, [paths[0]])['ok']) + self.assertFalse(eq.check_source_closure(before, after, ['not_allowed'])['ok']) + after['added'] = {'bytes': 1, 'sha256': 'c'*64} + self.assertFalse(eq.check_source_closure(before, after, [paths[0]])['ok']) + after = copy.deepcopy(before); del after[paths[0]] + self.assertFalse(eq.check_source_closure(before, after, [])['ok']) + + def test_metric_ranges(self): + self.assertEqual(eq.classify_improvement([10, 11, 12], [1, 2, 3]), '改善') + self.assertEqual(eq.classify_improvement([1, 2, 3], [10, 11, 12]), '悪化') + self.assertEqual(eq.classify_improvement([1, 2, 3], [3, 4, 5]), '差は確認できない') + for bad in ([1, 2], [1, 2, float('nan')], [1, 2, {'redacted_timing': 'duration_us'}]): + with self.assertRaises(eq.EvidenceError): + eq.classify_improvement([1, 2, 3], bad) + + +import check_eq as checker +from pathlib import Path + + +def s2_report(): + value = report() + value['event_end'] = copy.deepcopy(value['event_start']) + state = snapshot() + runtime = eq._field(eq._field(state, 'systems'), 'runtime') + runtime[1].append([[4, 'id_generator'], d(counters=d(domain_event=[2, 3]))]) + events = eq._field(runtime, 'domain_events') + events[1].append([[4, 'published_ids'], arr(*([4, 'domain_event.%012d' % i] for i in range(1, 4)))]) + value['checkpoints'] = [checkpoint(state, 632+i) for i in range(31)] + for cp in value['checkpoints']: + cp['K'].update(absolute_minute=cp['minute'], paused=True, _skip_next_process=False, + _abort_current_tick_requested=False, _last_tick_advanced=True) + cp['K']['_phase_handlers'] = {str(i): [] for i in range(11)} + cp['C'].update(catalog_instance_id='123', current_catalog_instance_id='123') + cp.update(latest_digest='b'*64, computed_latest_digest='b'*64, harness_normalized_digest=None) + value['signal_order'] = [{'signal': sig, 'minute': cp['minute']} for cp in value['checkpoints'][1:] for sig in ('snapshot_published', 'state_updated')] + return value + + +def s2_event_report(): + value = s2_report() + tree = d(event_id=[4, 'domain_event.000000000004'], event_type=[4, 'TICK'], + absolute_minute=[2, 633], source_service=[4, 'world'], + entity_ids=[28, [[4, 'entity']], [[2, 4], [21, ''], [0]]], + payload=d(nested=arr(d(value=[3, '000000000000f03f']))), causation_command_id=[2, 0]) + value['events'] = [{'sequence': 0, 'transport': transport(tree), 'original_field_types': { + 'event_id': 21, 'event_type': 21, 'absolute_minute': 2, 'source_service': 21, + 'entity_ids': {'type': 28, 'typed_info': [[2, 21], [21, ''], [0]]}, + 'payload': {'type': 27, 'typed_info': None}, 'causation_command_id': 2}}] + value['event_end'] = {'counter': 4, 'published_ids_count': 4} + for cp in value['checkpoints'][1:]: + state = cp['S']['tree'] + runtime = eq._field(eq._field(state, 'systems'), 'runtime') + eq._field(eq._field(eq._field(runtime, 'id_generator'), 'counters'), 'domain_event')[1] = 4 + eq._field(eq._field(runtime, 'domain_events'), 'published_ids')[1].append([4, 'domain_event.000000000004']) + cp['S'] = transport(state) + cp['latest'] = transport(state) + return value + + +def measurement(value): + return {'probe_object': '777', 'start_minute': value['checkpoints'][0]['minute'], + 'connections': {sig: [{'object': '777', 'method': method, 'flags': 0}] + for sig, method in (('snapshot_published', 'observe_snapshot'), ('state_updated', 'observe_state'))}} + + +class S2Format(unittest.TestCase): + def valid(self, value): + result = checker.check_report(value, measurement(value)) + self.assertTrue(result['ok'], result['errors']) + self.assertFalse(result['formal_acceptance']) + + def reject(self, value): + self.assertFalse(checker.check_report(value, measurement(value))['ok']) + + def test_s2_valid_and_not_formal_acceptance(self): + self.valid(s2_report()) + self.valid(s2_event_report()) + + def test_O_cadence(self): + value = s2_report(); value['role'] = 'O' + for cp in value['checkpoints']: + cp['minute'] -= 242; cp['K']['absolute_minute'] -= 242 + for row in value['signal_order']: row['minute'] -= 242 + self.valid(value) + + def test_missing_full_state_not_digest_only(self): + for name in ('S', 'latest', 'K', 'C', 'observation'): + value = s2_report(); del value['checkpoints'][4][name] + with self.subTest(name=name): self.reject(value) + + def test_roundtrip_tree_sha_and_raw_sha(self): + for field, bad in (('roundtrip_ok', False), ('tree_sha', 'c'*64), ('raw_bytes_sha', 'bad')): + value = s2_report(); value['checkpoints'][4]['S'][field] = bad + with self.subTest(field=field): self.reject(value) + + def test_state_witness_and_observation_mutation(self): + value = s2_report(); value['checkpoints'][0]['S']['raw_bytes_sha'] = 'c'*64 + self.reject(value) + value = s2_report(); value['checkpoints'][0]['observation']['after']['K'] = 'c'*64 + self.reject(value) + + def test_guard_actual_not_assumed(self): + value = s2_report(); value['profile_root']['actual_user_data_dir'] = '/different' + self.reject(value) + + def test_counter_and_published_ids_binding(self): + for boundary in ('event_start', 'event_end'): + for key in ('counter', 'published_ids_count'): + value = s2_event_report(); value[boundary][key] += 1 + with self.subTest(boundary=boundary, key=key): self.reject(value) + + def test_event_original_field_types_mandatory(self): + for key in ('event_id', 'event_type', 'entity_ids', 'payload'): + value = s2_event_report(); del value['events'][0]['original_field_types'][key] + with self.subTest(key=key): self.reject(value) + value = s2_event_report(); value['events'][0]['original_field_types']['event_id'] = 4 + self.reject(value) + + def test_event_no_drop_duplicate_remap(self): + value = s2_event_report(); value['events'] = []; self.reject(value) + value = s2_event_report(); value['events'].append(copy.deepcopy(value['events'][0])); self.reject(value) + value = s2_event_report(); tree = value['events'][0]['transport']['tree'] + eq._field(tree, 'event_id')[1] = 'renamed' + value['events'][0]['transport'] = transport(tree); self.reject(value) + + def test_product_event_shape_and_typed_array(self): + for key, bad in (('causation_command_id', [4, '']), ('entity_ids', arr()), ('payload', arr())): + value = s2_event_report(); tree = value['events'][0]['transport']['tree'] + eq._field(tree, key)[:] = bad + value['events'][0]['transport'] = transport(tree) + with self.subTest(key=key): self.reject(value) + + def test_kernel_cache_contradictions(self): + for layer, key, bad in (('K', 'paused', 1), ('K', 'absolute_minute', 999), + ('C', 'catalog_instance_id', '456'), ('C', '_mvp_manifest_cache_bytes', '%%%')): + value = s2_report(); value['checkpoints'][0][layer][key] = bad + with self.subTest(key=key): self.reject(value) + + def test_digest_and_scenario_contradiction(self): + value = s2_report(); value['checkpoints'][0]['computed_latest_digest'] = 'c'*64; self.reject(value) + value = s2_report(); value['checkpoints'][0]['harness_normalized_digest'] = 'forged'; self.reject(value) + value = s2_report(); value['scenarios'] = [{'id': 'pretend'}]; self.reject(value) + + def test_join_is_copy_and_retains_normalization_proof(self): + value = s2_report(); original = copy.deepcopy(value) + joined, proof = checker.join_report(value) + self.assertEqual(value, original) + self.assertEqual(joined['checkpoints'][0]['harness_normalized_digest'], proof[0]['latest']['normalized_digest']) + self.assertEqual(set(proof[0]['S']['sidecar']), {'entries', 'violations', 'profile_root'}) + + def test_diff_and_same_as_S_transport(self): + value = s2_report() + for i, cp in enumerate(value['checkpoints']): + cp['latest'] = {key: v for key, v in cp['S'].items() if key != 'tree'} + cp['latest']['same_as_S'] = True + if i: + del cp['S']['tree']; cp['S']['diff'] = [] + self.valid(value) + value['checkpoints'][1]['S']['diff'] = [{'op': 'set', 'path': [], 'node': d(missing=[0])}] + self.reject(value) + + def test_raw_observation_binding(self): + import base64 + cp = s2_report()['checkpoints'][0] + row = {'kernel': cp['K'], 'cache': cp['C'], 'sha': {}} + for layer in ('S', 'K', 'C'): + row[layer] = base64.b64encode(layer.encode()).decode() + row['sha'][layer] = checker.sha(layer.encode()) + cp['observation'] = {side: copy.deepcopy(row['sha']) for side in ('before', 'after')} + evidence = {side: copy.deepcopy(row) for side in ('before', 'after')} + self.assertTrue(checker.check_observation(cp, evidence)) + evidence['after']['K'] = 'WA==' + with self.assertRaises(eq.EvidenceError): checker.check_observation(cp, evidence) + + def test_stdout_exactly_one_line(self): + text = 'guard log\nP28_02_EQ_REPORT='+json.dumps(s2_report())+'\n' + self.assertEqual(checker.read_report_stdout(text), s2_report()) + for bad in ('', text+text, 'P28_02_EQ_REPORT={\n}\n'): + with self.subTest(bad=bad[:25]), self.assertRaises((eq.EvidenceError, ValueError)): + checker.read_report_stdout(bad) + + def test_lifecycle_guard_errors_and_boundaries(self): + import base64 + value = s2_report() + guard = {'verified': True, 'actual_user_data_dir': '/private/a'} + life = {'stage': 'S2', 'errors': [], 'stop_reason': 'S2_complete_S3_pending', + 'guard': {'receipt': guard, 'live_root': '/private/a', 'sha256': 'a'*64}, + 'observer_before': {'signal': []}, 'observer_connected': {'signal': ['observer']}, + 'observer_disconnected': {'signal': []}, 'ops': {'code': 'INVALID_START_TIME'}, + 'preparation': [{'operation': 'fixture_restore', 'ok': True, 'input_sha256': + 'eb4f770071eb07cd7e136fe54c3f78768cc8de7a4264e62a9af1f06a8f90f9bd'}]} + for label, minute in (('B0', 602), ('B1', 632), ('outside', 662), ('before_main', 602), + ('after_main', 602), ('frame1', 602), ('frame2', 602)): + life[label] = {'kernel': {'paused': True, 'absolute_minute': minute}, 'sha': {}} + for layer in ('S', 'K', 'C'): + life[label][layer] = base64.b64encode(layer.encode()).decode() + life[label]['sha'][layer] = checker.sha(layer.encode()) + self.assertTrue(checker.check_lifecycle(value, life, guard)) + for key, bad in (('errors', ['roundtrip failed']), ('stop_reason', 'failed'), + ('observer_disconnected', {}), ('observer_connected', {'signal': []})): + altered = copy.deepcopy(life); altered[key] = bad + with self.subTest(key=key), self.assertRaises(eq.EvidenceError): checker.check_lifecycle(value, altered, guard) + with self.assertRaises(eq.EvidenceError): checker.check_lifecycle(value, life, {'verified': True, 'actual_user_data_dir': '/wrong'}) + + def test_normalized_digest_and_raw_tree_are_both_bound(self): + value = s2_report() + for cp in value['checkpoints']: + tree = cp['S']['tree'] + runtime = eq._field(eq._field(tree, 'systems'), 'runtime') + eq._field(eq._field(runtime, 'domain_events'), 'recent_events')[1].append(event()) + cp['S'] = transport(tree); cp['latest'] = transport(tree) + joined, proofs = checker.join_report(value) + self.assertEqual(len(proofs[0]['latest']['sidecar']['entries']), 3) + self.assertTrue(eq.compare_reports(joined, joined)['ok']) + self.assertIsNone(value['checkpoints'][0]['harness_normalized_digest']) + joined['checkpoints'][0]['harness_normalized_digest'] = 'b'*64 + with self.assertRaises(eq.EvidenceError): checker.join_report(joined) + + def test_harness_digest_allows_only_dictionary_order(self): + a = d(z=arr([3, '000000000000f03f']), a=d(x=[4, 'name'], y=[21, 'name'])) + b = copy.deepcopy(a); b[1].reverse(); b[1][0][1][1].reverse() + self.assertNotEqual(eq.tree_sha(a), eq.tree_sha(b)) + self.assertEqual(checker.normalized_digest(a), checker.normalized_digest(b)) + eq._field(eq._field(b, 'a'), 'x')[0] = 21 + self.assertNotEqual(checker.normalized_digest(a), checker.normalized_digest(b)) + with self.assertRaises(eq.EvidenceError): checker.normalized_digest([27, [[[4, 'x'], [0]], [[21, 'x'], [0]]], None]) + + +class S2Static(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.probe = Path(__file__).with_name('eq_probe.gd').read_text() + + def reject(self, text): + result = checker.check_probe(text) + self.assertFalse(result['ok'], result) + + def test_current_probe(self): + result = checker.check_probe(self.probe) + self.assertTrue(result['ok'], result['errors']) + + def test_autoload_class_and_script_import(self): + for code in ('SimulationRuntimeService.new()', 'GameClock.set_paused(true)', 'preload("res://autoload/game_state.gd")'): + with self.subTest(code=code): self.reject(self.probe+'\nfunc bad() -> void:\n\t'+code+'\n') + + def test_variant_inference(self): + self.reject(self.probe+'\nfunc bad() -> void:\n\tvar inferred := runtime.get("value")\n') + + def test_no_changes_outside_preparation_or_step(self): + for call in ('clock.set_paused(true)', 'runtime.restore_snapshot({})', 'clock.advance_minutes(1)', 'runtime.load_from_path("x")', 'runtime.reset()', 'runtime.set_script(null)', 'runtime.call("reset")', 'runtime.latest_snapshot = {}'): + with self.subTest(call=call): self.reject(self.probe+'\nfunc bad() -> void:\n\t'+call+'\n') + + def test_pause_and_step_arguments(self): + self.reject(self.probe.replace('clock.set_paused(true)', 'clock.set_paused(false)')) + self.reject(self.probe.replace('clock.advance_minutes(1)', 'clock.advance_minutes(2)')) + + def test_unlisted_live_method_and_late_preparation(self): + self.reject(self.probe+'\nfunc bad() -> void:\n\truntime.configure_something()\n') + self.reject(self.probe.replace('initial_inventory = inventory()', 'initial_inventory = inventory()\n\tclock.set_paused(true)')) + + def test_textual_stringname_ordering(self): + self.reject(self.probe.replace('names.sort_custom(func(a: Variant, b: Variant) -> bool: return str(a) < str(b))', 'names.sort()')) + self.reject(self.probe.replace('return str(a) < str(b)', 'return a < b')) + + def test_full_state_and_godot_roundtrip_required(self): + for required in ('var_to_bytes(decode(tree))', 'transport(runtime.create_snapshot())', 'before.k_bytes == after.k_bytes', 'event.to_dictionary()', 'receipt.get("actual_user_data_dir")'): + with self.subTest(required=required): self.reject(self.probe.replace(required, 'null')) + + def test_no_event_cap_or_duplicate_report(self): + self.reject(self.probe+'\nfunc bad() -> void:\n\treport.events.pop_front()\n') + self.reject(self.probe+'\nfunc bad() -> void:\n\tprint("P28_02_EQ_REPORT=" + "{}")\n') + + def test_comment_does_not_supply_proof(self): + self.reject(self.probe.replace('var rebuilt: PackedByteArray = var_to_bytes(decode(tree))', '# var rebuilt: PackedByteArray = var_to_bytes(decode(tree))')) + self.assertTrue(checker.check_probe(self.probe+'\n# GameClock.reset(); var x := 1\n')['ok']) + + +def e3_observed(tree, template): + import base64 + cp = copy.deepcopy(template) + cp['S'] = transport(tree) + cp['latest'] = transport(tree) + row = {'kernel': cp['K'], 'cache': cp['C'], 'sha': {}} + layer_trees = {'S': tree, 'K': d(value=[4, json.dumps(cp['K'], sort_keys=True)]), + 'C': d(value=[4, json.dumps(cp['C'], sort_keys=True)])} + for layer, value in layer_trees.items(): + content = eq.json_bytes(value) # Synthetic proof bytes; never Godot evidence. + row[layer] = base64.b64encode(content).decode() + row['sha'][layer] = checker.sha(content) + cp['S']['raw_bytes_sha'] = cp['latest']['raw_bytes_sha'] = row['sha']['S'] + cp['observation'] = {side: copy.deepcopy(row['sha']) for side in ('before', 'after')} + result = {'checkpoint': cp, 'raw': {side: copy.deepcopy(row) for side in ('before', 'after')}} + for layer in ('K', 'C'): + result[layer+'_tree'] = transport(layer_trees[layer]) + result[layer+'_tree']['raw_bytes_sha'] = row['sha'][layer] + return result + + +def e3_package_fixture(kind, save_ok=True): + import base64 + def file(content): + return {'bytes': base64.b64encode(content).decode(), 'sha256': checker.sha(content)} + before = {'format_version': 1, 'checksum_world': 'retained'} + after = copy.deepcopy(before) + world = b'world' + new_world = world + if kind == 'missing_key': del after['checksum_world'] + elif kind == 'wrong_type': after['format_version'] = 'x' + elif kind == 'out_of_range': after['format_version'] = 2147483647 + elif kind == 'tampered_world': new_world = world[:2]+bytes([world[2] ^ 1])+world[3:] + original = {'manifest.json': file(eq.json_bytes(before)), 'world.bin': file(world), 'thumbnail.png': None, 'journal.log': None} + modified = {'manifest.json': file(eq.json_bytes(after)), 'world.bin': file(new_world), 'thumbnail.png': None, 'journal.log': None} + result = {'save_return': transport(d(ok=[1, int(save_ok)], code=[21, 'OK' if save_ok else 'INVALID_SNAPSHOT'])), + 'original': original, 'modified': modified, 'after_operation': copy.deepcopy(modified)} + if kind == 'tampered_world': result['tamper'] = {'offset': 2, 'before': world[2], 'after': world[2] ^ 1} + return result + + +def e3_fixture(role='R'): + value = s2_report() + if role == 'O': + value['role'] = 'O' + for cp in value['checkpoints']: + cp['minute'] -= 242 + cp['K']['absolute_minute'] -= 242 + for row in value['signal_order']: row['minute'] -= 242 + b1 = copy.deepcopy(value['checkpoints'][0]['S']['tree']) + b1[1].append([[4, 'clock'], d(absolute_minute=[2, value['checkpoints'][0]['minute']], speed=[2, 1])]) + runtime = checker.node_at(b1, 'systems', 'runtime') + runtime[1].append([[4, 'facilities'], d(instances=arr(d(id=[4, 'f1'])) if role == 'R' else arr())]) + for cp in value['checkpoints']: + cp['S'] = transport(b1); cp['latest'] = transport(b1) + value['checkpoints'][-1] = e3_observed(b1, value['checkpoints'][-1])['checkpoint'] + current = copy.deepcopy(b1) + evidence = [] + for api in checker.E3_APIS: + for kind in checker.E3_KINDS: + applicable, reason, invoked = True, None, True + if kind == 'tampered_world' and api != 'load_from_path': + applicable, reason, invoked = False, 'Dictionary API does not read packages', False + elif kind == 'duplicate_facility' and role == 'O': + applicable, reason, invoked = False, 'B1 has zero facilities', False + elif kind.startswith('duplicate_') and api == 'validate': + applicable, reason = False, 'Envelope validation does not inspect runtime internals' + begin = e3_observed(current, value['checkpoints'][-1]) + actual, code, code_reason, errors, ok = [0], None, None, None, None + events, event_records, package = [], [], None + latest = d() + if api == 'restore_snapshot': + code_reason = 'API returns bool only' + if invoked: actual, ok = [1, 0], False + elif api == 'validate': + code_reason = 'API returns ok/errors only' + if invoked: + ok = not applicable + errors = [] if ok else [{'missing_key': 'missing_clock', 'wrong_type': 'invalid_absolute_minute', 'out_of_range': 'invalid_speed'}[kind]] + actual = d(ok=[1, int(ok)], errors=arr(*([4, e] for e in errors))) + elif invoked: + code = {'missing_key': 'INVALID_MANIFEST', 'wrong_type': 'INVALID_MANIFEST', 'out_of_range': 'UNSUPPORTED_FORMAT', + 'duplicate_published_ids': 'RESTORE_FAILED', 'duplicate_facility': 'RESTORE_FAILED', 'tampered_world': 'CHECKSUM_MISMATCH'}[kind] + ok = False + actual = d(ok=[1, 0], code=[21, code], preload_pause_restored=[1, 1], loaded_clock_paused=[1, 1]) + package = e3_package_fixture(kind) + package['input'] = transport(checker.e3_expected_input(b1, kind) if kind.startswith('duplicate_') else b1) + counter = checker.node_at(current, 'systems', 'runtime', 'id_generator', 'counters', 'domain_event')[1] + path = 'user://p28_eq/'+role.lower()+'/'+('duplicate_id' if kind.startswith('duplicate_') else kind) + latest = d(ok=[1, 0], code=[21, code], duration_us=[2, 1], runtime_duration_us=[2, 2], + message=[4, 'failure'], save_path=[4, path]) + event_tree = d(event_id=[4, 'domain_event.%012d' % (counter+1)], event_type=[4, 'SAVE_LOAD_FAILED'], + source_service=[4, 'save_service'], entity_ids=arr(), absolute_minute=[2, begin['checkpoint']['minute']], + payload=latest, causation_command_id=[2, 0]) + events = [event_tree]; event_records = [transport(event_tree)] + current, _ = checker.e3_x(current, event_tree) + end = e3_observed(current, value['checkpoints'][-1]) + result = {'category': kind, 'applicability': 'applied' if applicable else 'NA', 'reason': reason, 'invoked': invoked, + 'facility_count': 1 if role == 'R' else 0, 'ok': ok, 'errors': errors, 'code': code, 'code_reason': code_reason, + 'migration_attempted': False, 'event_count': len(events), + 'path': 'user://p28_eq/'+role.lower()+'/'+('duplicate_id' if kind.startswith('duplicate_') else kind) if api == 'load_from_path' else None} + id_ = 'E3/'+api+'/'+kind + value['scenarios'].append({'id': id_, 'operation': api, 'result': result, 'checkpoints': [begin['checkpoint'], end['checkpoint']], 'events': events}) + evidence.append({'id': id_, 'begin': begin, 'invocation_before': copy.deepcopy(begin), 'end': end, + 'boundaries': ['begin', 'operation', 'end'], 'input': transport(checker.e3_expected_input(b1, kind)), + 'return': transport(actual), 'package': package, 'events': event_records, 'signals': [], + 'latest_save_operation_result': transport(latest), 'save_budget_before': transport(d()), 'save_budget_after': transport(d())}) + return value, evidence, transport(b1) + + +class S3a(unittest.TestCase): + def check(self, value, evidence, b1): + return checker.check_report(value, measurement(value), evidence, b1) + + def test_exact_phase_keys(self): + for bad in ({}, {str(i): [] for i in range(10)}, {str(i): [] for i in range(12)}, + {'00': [], **{str(i): [] for i in range(11)}}, [['0', []], ['0', []]]): + value = s2_report(); value['checkpoints'][2]['K']['_phase_handlers'] = bad + with self.subTest(bad=bad): + self.assertFalse(checker.check_report(value, measurement(value))['ok']) + + def test_signals_all_minutes_and_order(self): + for mutation in ('missing', 'partial', 'duplicate', 'order', 'minute', 'scenario', 'state_only'): + value = s2_report() + rows = value['signal_order'] + if mutation == 'missing': rows.pop() + elif mutation == 'partial': del rows[2:] + elif mutation == 'duplicate': rows.extend(copy.deepcopy(rows[:2])) + elif mutation == 'order': rows[0], rows[1] = rows[1], rows[0] + elif mutation == 'minute': rows[2]['minute'] += 1 + elif mutation == 'scenario': rows.append({'signal': 'state_updated', 'minute': 662, 'scenario': 'E3'}) + else: value['signal_order'] = [r for r in rows if r['signal'] == 'state_updated'] + with self.subTest(mutation=mutation): + self.assertFalse(checker.check_report(value, measurement(value))['ok']) + + def test_probe_connection_required(self): + value = s2_report() + self.assertFalse(checker.check_report(value)['ok']) + for sig in ('snapshot_published', 'state_updated'): + inventory = measurement(value); inventory['connections'][sig] = [] + self.assertFalse(checker.check_report(value, inventory)['ok']) + inventory = measurement(value); inventory['probe_object'] = '999' + self.assertFalse(checker.check_report(value, inventory)['ok']) + + def test_e3_valid_R_and_O_records(self): + for role in ('R', 'O'): + args = e3_fixture(role) + checked = self.check(*args) + self.assertTrue(checked['ok'], checked['errors']) + self.assertEqual(len(checked['e3']), 18) + self.assertTrue(all(not row['defects'] for row in checked['e3']), checked['e3']) + self.assertFalse(checked['formal_acceptance']) + + def test_e3_invented_codes_and_missing_load_code(self): + for index in (0, 6, 12): + value, evidence, b1 = e3_fixture() + value['scenarios'][index]['result']['code'] = 'INVENTED' if index < 12 else None + self.assertFalse(self.check(value, evidence, b1)['ok']) + value, evidence, b1 = e3_fixture() + actual = evidence[12]['return']['tree'] + actual[1] = [pair for pair in actual[1] if pair[0][1] != 'code'] + evidence[12]['return'] = transport(actual) + self.assertFalse(self.check(value, evidence, b1)['ok']) + + def test_e3_NA_cannot_be_PASS_or_applied(self): + for index in (5, 9, 10): + value, evidence, b1 = e3_fixture() + value['scenarios'][index]['result']['applicability'] = 'PASS' + self.assertFalse(self.check(value, evidence, b1)['ok']) + value, evidence, b1 = e3_fixture('O') + value['scenarios'][4]['result'].update(applicability='applied', invoked=True, reason=None) + self.assertFalse(self.check(value, evidence, b1)['ok']) + + def test_envelope_duplicates_not_defect(self): + args = e3_fixture() + checked = self.check(*args) + self.assertTrue(checked['ok'], checked['errors']) + for index in (9, 10): + self.assertEqual(checked['e3'][index]['status'], 'NA') + self.assertEqual(checked['e3'][index]['defects'], []) + + def test_e3_coverage_input_and_event_count_binding(self): + value, evidence, b1 = e3_fixture() + value['scenarios'].pop() + self.assertFalse(self.check(value, evidence, b1)['ok']) + value, evidence, b1 = e3_fixture() + evidence[0]['input'] = copy.deepcopy(b1) + self.assertFalse(self.check(value, evidence, b1)['ok']) + value, evidence, b1 = e3_fixture() + value['scenarios'][12]['result']['event_count'] = 0 + self.assertFalse(self.check(value, evidence, b1)['ok']) + + def test_rejection_mutation_retained_as_defect(self): + value, evidence, b1 = e3_fixture() + changed = copy.deepcopy(evidence[0]['end']['checkpoint']['S']['tree']) + checker.node_at(changed, 'value')[1].append([4, 'unauthorized']) + end = e3_observed(changed, value['checkpoints'][-1]) + evidence[0]['end'] = end + value['scenarios'][0]['checkpoints'][1] = end['checkpoint'] + evidence[1]['begin'] = copy.deepcopy(end) + value['scenarios'][1]['checkpoints'][0] = copy.deepcopy(end['checkpoint']) + checked = self.check(value, evidence, b1) + self.assertTrue(checked['ok'], checked['errors']) + self.assertEqual(checked['e3'][0]['status'], 'existing-defect-candidate') + self.assertIn('S_changes', [d['kind'] for d in checked['e3'][0]['defects']]) + + def test_invalid_input_accepted_is_not_PASS(self): + value, evidence, b1 = e3_fixture() + value['scenarios'][0]['result']['ok'] = True + evidence[0]['return'] = transport([1, 1]) + checked = self.check(value, evidence, b1) + self.assertTrue(checked['ok'], checked['errors']) + self.assertEqual(checked['e3'][0]['defects'][0]['kind'], 'invalid_input_accepted') + + def test_package_fixed_mutations_and_hashes(self): + for kind in checker.E3_KINDS: + package = e3_package_fixture(kind) + self.assertTrue(checker.e3_package_check(package, kind)) + package['modified']['world.bin']['sha256'] = '0'*64 + with self.assertRaises(eq.EvidenceError): checker.e3_package_check(package, kind) + package = e3_package_fixture('tampered_world'); package['tamper']['offset'] = 0 + with self.assertRaises(eq.EvidenceError): checker.e3_package_check(package, 'tampered_world') + + def test_X_recent_limit_and_counter(self): + value, evidence, b1 = e3_fixture() + before = copy.deepcopy(b1['tree']) + ev = value['scenarios'][12]['events'][0] + recent = checker.node_at(before, 'systems', 'runtime', 'domain_events', 'recent_events') + recent[1] = [copy.deepcopy(ev) for _ in range(256)] + after, dropped = checker.e3_x(before, ev) + self.assertEqual(dropped, ev) + self.assertEqual(len(checker.node_at(after, 'systems', 'runtime', 'domain_events', 'recent_events')[1]), 256) + self.assertEqual(checker.node_at(after, 'systems', 'runtime', 'id_generator', 'counters', 'domain_event'), [2, 4]) + + def test_scenario_mutation_static_boundary(self): + text = Path(__file__).with_name('eq_probe.gd').read_text() + for call in ('SimulationSnapshot.validate({})', 'SaveService.save_snapshot("x", {})', 'run_e3()', 'e3_prepare_package("x", {}, "x")'): + self.assertFalse(checker.check_probe(text+'\nfunc illegal() -> void:\n\t'+call+'\n')['ok']) + + + def test_duplicate_JSON_key_rejected(self): + with self.assertRaises(eq.EvidenceError): + checker.read_report_stdout('P28_02_EQ_REPORT={"_phase_handlers":{"0":[],"0":[]}}') + with self.assertRaises(eq.EvidenceError): + checker.strict_json('{"x":1,"x":2}') + + def test_operation_moved_outside_scenario_rejected(self): + text = Path(__file__).with_name('eq_probe.gd').read_text() + text = text.replace('scenario_active = true', 'scenario_active = false').replace('scenario_active = false\n\t\t\tvar code', 'scenario_active = true\n\t\t\tvar code') + self.assertFalse(checker.check_probe(text)['ok']) + + def test_event_count_defect_not_silently_accepted(self): + value, evidence, b1 = e3_fixture() + scenario = value['scenarios'][12] + scenario['events'] = []; scenario['result']['event_count'] = 0 + evidence[12]['events'] = [] + checked = self.check(value, evidence, b1) + self.assertTrue(checked['ok'], checked['errors']) + self.assertIn('event_count', [d['kind'] for d in checked['e3'][12]['defects']]) + + def test_save_refusal_makes_load_NA(self): + value, evidence, b1 = e3_fixture() + i = 15 + before = copy.deepcopy(evidence[i]['begin']) + result = value['scenarios'][i]['result'] + result.update(applicability='NA', reason='SaveService.save_snapshot refused duplicate input', + invoked=False, ok=None, code=None, event_count=0) + value['scenarios'][i]['events'] = [] + value['scenarios'][i]['checkpoints'][1] = copy.deepcopy(before['checkpoint']) + evidence[i].update(end=copy.deepcopy(before), events=[], **{'return': transport([0])}) + evidence[i]['package'] = e3_package_fixture('duplicate_published_ids', save_ok=False) + evidence[i]['package']['input'] = transport(checker.e3_expected_input(b1['tree'], 'duplicate_published_ids')) + # Keep next baseline explicit; subsequent actual changes remain candidates. + evidence[i+1]['begin'] = copy.deepcopy(before) + value['scenarios'][i+1]['checkpoints'][0] = copy.deepcopy(before['checkpoint']) + checked = self.check(value, evidence, b1) + self.assertTrue(checked['ok'], checked['errors']) + self.assertEqual(checked['e3'][i]['status'], 'NA') + + def test_load_payload_and_pause_outcome(self): + value, evidence, b1 = e3_fixture() + actual = evidence[12]['return']['tree'] + checker.node_at(actual, 'preload_pause_restored')[1] = 0 + evidence[12]['return'] = transport(actual) + checked = self.check(value, evidence, b1) + self.assertTrue(checked['ok'], checked['errors']) + self.assertIn('load_pause_outcome', [d['kind'] for d in checked['e3'][12]['defects']]) + + def test_interval_gap_rejected(self): + value, evidence, b1 = e3_fixture() + evidence[1]['begin'] = copy.deepcopy(evidence[12]['end']) + value['scenarios'][1]['checkpoints'][0] = evidence[1]['begin']['checkpoint'] + self.assertFalse(self.check(value, evidence, b1)['ok']) + + +def e45_fixture(role='R'): + raw, e3, b1 = e3_fixture(role) + tree = copy.deepcopy(e3[-1]['end']['checkpoint']['S']['tree']) + runtime = checker.node_at(tree, 'systems', 'runtime') + runtime[1].append([[4, 'world'], d(bounds=d(min_x=[2, 0], max_x=[2, 0], min_y=[2, 0], max_y=[2, 0]))]) + template = copy.deepcopy(e3[-1]['end']['checkpoint']) + def observed(t, minute): + cp = copy.deepcopy(template) + cp['minute'] = minute; cp['K']['absolute_minute'] = minute + return e3_observed(t, cp) + previous = observed(tree, template['minute']) + current = copy.deepcopy(previous) + evidence = [] + def emit(ident, op, obs, detail, events=()): + detail['signals'] = [] + result = {'event_count': len(events), 'applicability': detail.get('applicability', 'applied'), + 'reason': detail.get('reason'), 'facts': checker.e45_facts(detail)} + raw['scenarios'].append({'id': ident, 'operation': op, 'result': result, + 'checkpoints': [o['checkpoint'] for o in obs], 'events': list(events)}) + evidence.append({'id': ident, 'boundaries': ['begin', 'operation', 'end'], 'observations': obs, + 'detail': detail, 'events': [transport(e) for e in events], 'signals': []}) + for op in checker.E4_PATHS: + begin = copy.deepcopy(current); minute = begin['checkpoint']['minute'] + detail = {}; obs = [begin]; events = [] + if op == 'build_facility': + ids = [28, [[21, 'a']], [[2, 21], [21, ''], [0]]] + detail = {'source': 'definition_registry.get_facility_ids()', 'raw_ids': transport(ids), 'count': 1, + 'sorted_ids': transport(ids), 'sort_rule': checker.SORT_RULE, 'cell_rule': checker.CELL_RULE, + 'bounds': transport(checker.node_at(tree, 'systems', 'runtime', 'world', 'bounds')), + 'chosen': None, 'trials': [], 'applicability': 'NA', + 'reason': 'all registry/cell pairs rejected by public preview', + 'observation_before': copy.deepcopy(begin), 'observation_after': copy.deepcopy(begin)} + for z in (0, 1): + detail['trials'].append({'candidate': transport(d(definition_id=[21, 'a'], origin=[10, [[2, 0], [2, 0], [2, z]]], rotation=[2, 0])), + 'preview': transport(d(can_build=[1, 0], error_codes=arr([4, 'blocked'])))}) + elif op == 'tick': + minute += 1 + elif op == 'restore_snapshot': + detail = {'input': transport(tree), 'return': transport([1, 1])} + elif op == 'load_from_path': + ev = event(raw['profile_root']['root']) + # Match the next identity required by X(P,event). + counter = checker.counts(tree)[0]['counter'] + checker.node_at(ev, 'event_id')[1] = 'event_'+str(counter+1) + detail = {'input': transport(tree), 'return': transport(d(ok=[1, 1], code=[4, 'OK'])), + 'path': 'user://p28_eq/'+role.lower()+'/good'} + package = e3_package_fixture('duplicate_published_ids') + detail.update(save_return=package['save_return'], package_before=package['original'], package_after=package['original'], latest_save_operation_result=transport(checker.node_at(ev, 'payload'))) + tree, _ = checker.e3_x(tree, ev) + events = [ev] + else: + detail = {'submit': transport(d(command_id=[2, 1], code=[4, 'NOT_FOUND'])), + 'command_result': transport(d(command_id=[2, 1], code=[4, 'NOT_FOUND']))} + obs.append(copy.deepcopy(begin)); minute += 1 + detail.update(save_budget_before=transport(d(_samples=d(), _totals=d(), _sample_counts=d())), + save_budget_after=transport(d(_samples=d(), _totals=d(), _sample_counts=d()))) + current = observed(tree, minute); obs.append(copy.deepcopy(current)) + emit('E4/'+op, op, obs, detail, events) + for target in checker.E5_TARGETS: + for location in ('dict', 'array'): + for direction in ('outside_in', 'inside_out'): + begin = copy.deepcopy(current); minute = begin['checkpoint']['minute']+1 + baseline = observed(tree, minute) + held = copy.deepcopy(tree); after_held = copy.deepcopy(held) + if direction == 'outside_in': + if location == 'dict': + checker.node_at(after_held, 'systems', 'runtime', 'id_generator', 'counters')[1].append([[4, '__p28_eq_probe'], [2, 1]]) + else: + checker.node_at(after_held, 'systems', 'runtime', 'domain_events', 'published_ids')[1].append([4, '__p28_eq_probe']) + else: + minute += 1 + post = observed(tree, minute) + if direction == 'outside_in' and target != 'create_snapshot': + post['checkpoint']['latest'] = transport(after_held) + post['checkpoint']['computed_latest_digest'] = 'c'*64 + current = observed(tree, minute+1) + detail = {'target': target, 'location': location, 'direction': direction, 'digest_materialized_before': True, + 'held_before': transport(held), 'held_after': transport(after_held)} + emit('E5/'+target+'/'+location+'/'+direction, direction, [begin, baseline, post, copy.deepcopy(current)], detail) + return raw, evidence, previous + + +class S3b(unittest.TestCase): + def checked(self, value=None): + raw, evidence, previous = e45_fixture() if value is None else value + return checker.check_e45(raw, evidence, previous) + + def reject(self, mutate): + value = e45_fixture() + mutate(*value) + with self.assertRaises((eq.EvidenceError, KeyError, ValueError, TypeError)): + self.checked(value) + + def test_all_paths_and_ownership_R_O(self): + for role in ('R', 'O'): + outcomes = self.checked(e45_fixture(role)) + self.assertEqual(len(outcomes), 21) + self.assertEqual(sum(o['status'] == 'existing-defect' for o in outcomes), 6) + self.assertEqual(outcomes[0]['status'], 'NA') + self.assertNotIn('PASS', str(outcomes)) + + def test_missing_path_and_combination(self): + for i in (0, 4, 5, 20): + self.reject(lambda r, e, p: e.pop(i)) + + def test_path_order(self): + self.reject(lambda r, e, p: e.reverse()) + + def test_interval_gap(self): + self.reject(lambda r, e, p: e[1]['observations'][0]['raw']['before']['sha'].update(S='0'*64)) + + def test_event_count_mismatch(self): + self.reject(lambda r, e, p: r['scenarios'][21]['result'].update(event_count=0)) + + def test_load_extra_event(self): + def mutate(r, e, p): + e[3]['events'].append(copy.deepcopy(e[3]['events'][0])) + r['scenarios'][21]['events'].append(copy.deepcopy(r['scenarios'][21]['events'][0])) + r['scenarios'][21]['result']['event_count'] = 2 + self.reject(mutate) + + def test_restore_extra_event(self): + def mutate(r, e, p): + e[2]['events'] = copy.deepcopy(e[3]['events']) + r['scenarios'][20]['events'] = [e[2]['events'][0]['tree']] + r['scenarios'][20]['result']['event_count'] = 1 + self.reject(mutate) + + def test_load_X_not_digest_only(self): + self.reject(lambda r, e, p: e[3]['detail'].update(input=transport(snapshot()))) + + def test_aliasing_cannot_be_PASS(self): + self.reject(lambda r, e, p: r['scenarios'][27]['result'].update(status='PASS')) + + def test_aliasing_missing_record(self): + self.reject(lambda r, e, p: e[9]['detail'].pop('held_after')) + + def test_nested_mutation_required(self): + self.reject(lambda r, e, p: e[5]['detail'].update(held_after=e[5]['detail']['held_before'])) + + def test_digest_materialization_required(self): + self.reject(lambda r, e, p: e[5]['detail'].update(digest_materialized_before=False)) + + def test_NA_not_PASS(self): + self.reject(lambda r, e, p: r['scenarios'][18]['result'].update(applicability='PASS')) + + def test_wrong_registry_in_either_role(self): + for role in ('R', 'O'): + r, e, p = e45_fixture(role) + e[0]['detail']['source'] = 'mvp_content_catalog' + with self.assertRaises(eq.EvidenceError): + checker.check_selection(e[0]['detail'], p['checkpoint']['S']['tree']) + + def test_empty_registry_not_NA(self): + r, e, p = e45_fixture() + detail = e[0]['detail'] + detail.update(raw_ids=transport(arr()), sorted_ids=transport(arr()), count=0, trials=[]) + with self.assertRaises(eq.EvidenceError): + checker.check_selection(detail, p['checkpoint']['S']['tree']) + + def test_missing_trial(self): + r, e, p = e45_fixture() + e[0]['detail']['trials'].pop() + with self.assertRaises(eq.EvidenceError): + checker.check_selection(e[0]['detail'], p['checkpoint']['S']['tree']) + + def test_sort_rule_rejected(self): + r, e, p = e45_fixture() + e[0]['detail']['sort_rule'] = 'registration order' + with self.assertRaises(eq.EvidenceError): + checker.check_selection(e[0]['detail'], p['checkpoint']['S']['tree']) + + def test_unpreviewed_choice(self): + r, e, p = e45_fixture() + e[0]['detail'].update(chosen=e[0]['detail']['trials'][0]['candidate'], applicability='applied', reason=None) + with self.assertRaises(eq.EvidenceError): + checker.check_selection(e[0]['detail'], p['checkpoint']['S']['tree']) + + def test_first_placeable_choice(self): + r, e, p = e45_fixture() + detail = e[0]['detail']; trial = detail['trials'][0] + trial['preview'] = transport(d(can_build=[1, 1])) + detail.update(trials=[trial], chosen=trial['candidate'], applicability='applied', reason=None, + submit=transport(d(command_id=[2, 1], code=[4, 'OK'])), + command_result=transport(d(command_id=[2, 1], code=[4, 'OK']))) + self.assertTrue(checker.check_selection(detail, p['checkpoint']['S']['tree'])) + + def test_no_staleness_assertion_for_non_tick(self): + out = self.checked() + self.assertIn('publication timing is not cache staleness', out[2]['latest_policy']) + self.reject(lambda r, e, p: e[2]['detail'].update(cache_stale=True)) + + def test_static_handler_and_outside_mutations(self): + text = Path(__file__).with_name('eq_probe.gd').read_text() + for changed in (text.replace('record_signal("state_updated")', '_snapshot["bad"] = 1\n\trecord_signal("state_updated")'), + text+'\nfunc bad() -> void:\n\truntime.submit_command(&"build_facility", {})\n', + text+'\nfunc bad() -> void:\n\te4_candidates()\n', + text.replace('scenario_active = true\n\t\tif operation', 'scenario_active = false\n\t\tif operation')): + self.assertFalse(checker.check_probe(changed)['ok']) + + def test_facts_normalization_is_reversible(self): + r, e, p = e45_fixture() + facts = r['scenarios'][-1]['result']['facts'] + normal, proofs = checker.join_facts(facts, r['profile_root']) + self.assertTrue(proofs) + self.assertEqual(checker.join_facts(copy.deepcopy(facts), r['profile_root'])[0], normal) + self.assertIn('tree_sha', facts['held_before']) + + def test_E5_cached_digest_defect_is_comparable(self): + value = report() + cps = [checkpoint(minute=i) for i in range(4)] + cps[2]['computed_latest_digest'] = 'post-alias' + value['scenarios'] = [{'id': 'E5/latest_snapshot/dict/outside_in', 'operation': 'outside_in', + 'result': {}, 'checkpoints': cps, 'events': []}] + checked = eq.compare_reports(value, copy.deepcopy(value)) + self.assertTrue(checked['ok'], checked) + value['scenarios'][0]['id'] = 'E4/tick' + self.assertFalse(eq.compare_reports(value, value)['ok']) + + + + def test_joined_s3b_self_comparison(self): + raw, evidence, previous = e45_fixture() + joined, proofs = checker.join_report(raw) + result = eq.compare_reports(joined, copy.deepcopy(joined)) + self.assertTrue(result['ok'], result['errors']) + self.assertTrue(any('facts' in p for p in proofs)) + + def test_missing_preview_observation(self): + self.reject(lambda r, e, p: e[0]['detail'].pop('observation_after')) + + def test_signal_facts_cannot_be_dropped(self): + self.reject(lambda r, e, p: e[1]['signals'].append({'signal': 'snapshot_published', 'minute': e[1]['observations'][0]['checkpoint']['minute']})) + + def test_digest_defect_other_checkpoint_still_rejected(self): + value = report() + cps = [checkpoint(minute=i) for i in range(4)] + cps[1]['computed_latest_digest'] = 'bad' + value['scenarios'] = [{'id': 'E5/latest_snapshot/dict/outside_in', 'operation': 'outside_in', + 'result': {}, 'checkpoints': cps, 'events': []}] + self.assertFalse(eq.compare_reports(value, value)['ok']) + + + def test_ownership_fact_dictionary_order_fallback(self): + a = report() + a['scenarios'] = [{'id': 'E5/latest_snapshot/dict/inside_out', 'operation': 'inside_out', + 'result': {'facts': {'held_before': d(a=[2, 1], b=[2, 2])}}, + 'checkpoints': [checkpoint()], 'events': []}] + b = copy.deepcopy(a) + b['scenarios'][0]['result']['facts']['held_before'][1].reverse() + result = eq.compare_reports(a, b) + self.assertTrue(result['ok'], result['differences']) + self.assertTrue(result['dict_order_paths']) + b['scenarios'][0]['result']['facts']['held_before'][1][0][1] = [2, 99] + self.assertFalse(eq.compare_reports(a, b)['ok']) + +import os +import tempfile +import base64 +import run_eq as driver +import verify_eq as verifier + + +def synthetic_directory(): + base = Path(os.environ.get('BUILD_OUTPUT_DIR', tempfile.gettempdir())).resolve() + eq.require(not base.is_relative_to(verifier.ROOT), 'synthetic bundle must be outside checkout') + return tempfile.TemporaryDirectory(prefix='eq-synthetic-not-native-', dir=base) + + +def s4_report_fixture(role): + """Join historical synthetic fixtures, preserving all 119 historical test bodies.""" + raw, e45, previous = e45_fixture(role) + e3raw, e3, b1 = e3_fixture(role) + world = copy.deepcopy(checker.node_at(previous['checkpoint']['S']['tree'], 'systems', 'runtime', 'world')) + def add_world(value): + if isinstance(value, dict): + if 'tree' in value and isinstance(value['tree'], list): + tree = value['tree'] + try: + runtime = checker.node_at(tree, 'systems', 'runtime') + except (eq.EvidenceError, KeyError): + runtime = None + if runtime is not None: + if 'world' not in checker.fields(runtime): + runtime[1].append([[4, 'world'], copy.deepcopy(world)]) + value['tree_sha'] = eq.tree_sha(tree) + for child in value.values(): add_world(child) + elif isinstance(value, list): + for child in value: add_world(child) + add_world(e3raw); add_world(e3); add_world(b1) + for i, cp in enumerate(e3raw['checkpoints']): + e3raw['checkpoints'][i] = e3_observed(cp['S']['tree'], cp)['checkpoint'] + for i, ev in enumerate(e3): + for key in ('begin', 'invocation_before', 'end'): + cp = ev[key]['checkpoint'] + ev[key] = e3_observed(cp['S']['tree'], cp) + e3raw['scenarios'][i]['checkpoints'] = [ev['begin']['checkpoint'], ev['end']['checkpoint']] + raw['checkpoints'] = e3raw['checkpoints'] + raw['scenarios'][:18] = e3raw['scenarios'] + return raw, e3, b1, e45 + + +def s4_phase_fixture(directory, phase='R-A', pid=101): + role = verifier.ROLES[phase] + raw, e3, b1, e45 = s4_report_fixture(role) + runtime_name = phase+'-runtime' + root = '/private/'+runtime_name + raw['profile_root'] = profile(root) + guard = {'verified': True, 'conditions': [True]*5, 'conditions_checked': 5, + 'actual_user_data_dir': root, 'expected_user_data_dir': root, + 'globalized_probe': root+'/guard-probe', 'custom_user_dir_name': runtime_name, + 'fresh_before_parent_initialize': True, 'profile_writes_before_guard': 0, + 'project_settings_persisted': False} + guard_path = directory/(phase+'-guard.json') + verifier.write(guard_path, guard) + life = {'stage': 'S3b', 'errors': [], 'stop_reason': 'S3b_complete_S4_pending', + 'guard': {'receipt': guard, 'live_root': root, 'sha256': verifier.sha(guard_path), 'path': str(guard_path)}, + 'observer_before': {}, 'observer_connected': {'probe': True}, 'observer_disconnected': {}, + 'ops': {'code': 'INVALID_START_TIME'} if role == 'R' else {'ok': True}, + 'preparation': [{'operation': 'fixture_restore', 'ok': True, 'input_sha256': + 'eb4f770071eb07cd7e136fe54c3f78768cc8de7a4264e62a9af1f06a8f90f9bd'}], + 'measurement': measurement(raw), 'e3': e3, 'e3_b1': b1, 'e45': e45} + start = 602 if role == 'R' else 360 + for label, minute in [('B0', start), ('B1', start+30), ('outside', start+60), + ('before_main', start), ('after_main', start), ('frame1', start), ('frame2', start)]: + life[label] = {'kernel': {'paused': True, 'absolute_minute': minute}, 'sha': {}} + for layer in ('S', 'K', 'C'): + life[label][layer] = base64.b64encode(layer.encode()).decode() + life[label]['sha'][layer] = checker.sha(layer.encode()) + folder = directory/phase + folder.mkdir() + evidence = folder/'evidence'; evidence.mkdir() + (folder/'stdout.log').write_text('P28_02_EQ_REPORT='+json.dumps(raw)+'\n') + verifier.write(evidence/'report.json', raw) + verifier.write(evidence/'events.json', raw['events']) + for i, cp in enumerate(raw['checkpoints']): + verifier.write(evidence/f'checkpoint-{i:02d}.json', cp) + verifier.write(evidence/f'observation-{i:02d}.json', e3_observed(cp['S']['tree'], cp)['raw']) + for prefix, values in [('e3', e3), ('e45', e45)]: + for i, value in enumerate(values): verifier.write(evidence/f'{prefix}-{i:02d}.json', value) + life['files'] = [dict(path='evidence/'+n, **p) for n, p in verifier.inventory(evidence).items()] + verifier.write(evidence/'lifecycle.json', life) + audio = {'coordinator': True, 'passed': True, 'owned_engine_pid': pid, 'all_owned_targets_released': True, + 'deadline_reached': False, 'clock_process_held_stopped': True, 'window_input_held_disabled': True, + 'restored_before_quit': False, 'shared_bus_deleted': False, 'settings_mutated': False} + verifier.write(evidence/'audio-close.json', audio) + return {'phase': phase, 'role': role, 'pid': pid, 'runtime_profile': root, 'runtime_name': runtime_name, + 'guard': guard, 'guard_sha256': verifier.sha(guard_path), + 'environment': {'THE_TREE_PACK_PROFILE_REPORT': str(guard_path)}, + 'evidence_files': verifier.inventory(evidence)} + + +def s4_owned_fixture(directory, item, pid): + phase = item['phase']; folder = directory/phase + folder.mkdir(exist_ok=True) + for name in ('stdout.log', 'stderr.log', 'engine-native.log'): + if not (folder/name).exists(): (folder/name).write_text('') + raw = {n: verifier.pin(folder/n) for n in ('stdout.log', 'stderr.log', 'engine-native.log')} + argv = item['argv']+['--log-file', str(folder/'engine-native.log'), '--verbose'] + binding = {'pid': pid, 'actual_pid': pid, 'argv': argv, 'command': argv, 'owner_pid': 10, 'monotonic_ns': 1} + start, end = dict(binding, event='ENGINE_STARTED'), dict(binding, event='ENGINE_ENDED', monotonic_ns=2) + cleanup = {'engine_ended': True, 'errors': []} + process = {'pid': pid, 'argv': argv, 'exit_code': 0, 'helper_exit_code': 0, 'timed_out': False, + 'error_lines': [], 'lifecycle_error': None, 'external_process_or_group_signals': 0, + 'owned_popen_ended': True, 'old_helper_engine_ended': True, 'start_receipt_written': True, + 'end_receipt_written': True, 'actual_start_binding': start, 'actual_end_binding': end, + 'adapter_owned_cleanup': cleanup, 'stdout_sha256': raw['stdout.log']['sha256'], + 'stderr_sha256': raw['stderr.log']['sha256']} + capture = {'passed': True, 'all_captured_ended': True, 'outer_cleanup_errors': [], 'adapter_exception': None, + 'foreign_process_or_group_signals': 0, 'all_cleanup_before_outer_receipt': True, + 'outer_receipt_written': True, 'outer_receipt_error': None, 'actual_captured_pids': [pid]} + for name, value in [('process.json', process), ('started.json', start), ('ended.json', end), + ('adapter-owned-cleanup.json', cleanup), ('outer-owned-finally.json', + {k: v for k, v in capture.items() if k not in ('passed', 'outer_receipt_written', 'outer_receipt_error')})]: + verifier.write(folder/name, value) + return {'passed': True, 'process': process, 'capture': capture, 'raw': raw, 'argv': argv, + 'timeout_seconds': 1800, 'diagnostics': [], 'owned_files': {n: verifier.pin(folder/n) for n in + ('process.json', 'started.json', 'ended.json', 'adapter-owned-cleanup.json', 'outer-owned-finally.json')}} + + +def s4_bundle_fixture(directory, collector, standard): + """Synthetic receipts only. Production validators are real; no Godot claim.""" + source = collector.source_map(standard, verifier.ROOT) + for name in ('eq_probe.gd',): (directory/name).write_bytes((verifier.HERE/name).read_bytes()) + (directory/'profile_guard.gd').write_text('synthetic guard bytes') + (directory/'guarded.gd').write_text(driver.wrapper_text(directory)) + verifier.write(directory/'root-input-manifest.json', {'synthetic_not_native': True}) + pins = {'worker': {'eq_probe.gd': verifier.sha(directory/'eq_probe.gd')}, + 'readonly': {'files': {'run-r02/profile_guard.gd': verifier.sha(directory/'profile_guard.gd')}, + 'manifest_sha256': verifier.sha(directory/'root-input-manifest.json')}} + commands = [collector.argv_for(Path('/synthetic/Godot'), directory/'stage', directory/'guarded.gd', True), + collector.parse_argv(Path('/synthetic/Godot'), directory/'stage', directory/'eq_probe.gd'), + collector.parse_argv(Path('/synthetic/Godot'), directory/'stage', directory/'guarded.gd')] + [ + ['/synthetic/Godot', '--headless', '--path', str(directory/'stage'), '--script', str(directory/'guarded.gd')] + for _ in range(4)] + plan, rows, retained, cleanup = [], [], {}, [] + for i, phase in enumerate(verifier.PHASES): + pid = 100+i; role = verifier.ROLES.get(phase) + item = {'phase': phase, 'role': role, 'argv': commands[i], 'folder': str(directory/phase), + 'startup_name': phase+'-startup', 'startup_profile': '/private/'+phase+'-startup', + 'runtime_name': phase+'-runtime', 'runtime_profile': '/private/'+phase+'-runtime'} + env = {'THE_TREE_PACK_PROFILE_NAME': item['runtime_name'], 'THE_TREE_PACK_PROFILE_EXPECTED': item['runtime_profile'], + 'THE_TREE_PACK_PROFILE_REPORT': str(directory/(phase+'-guard.json')), 'THE_TREE_EQ_ROLE': role or '', + 'THE_TREE_P28_FIXTURE': '/synthetic/fixture', 'THE_TREE_P28_FIXTURE_SHA': collector.FIXTURE_SHA} + item['environment'] = env; plan.append(item) + row = s4_phase_fixture(directory, phase, pid) if role else {'phase': phase, 'role': None, 'pid': pid} + row.update(s4_owned_fixture(directory, item, pid), environment=env, stage_inventory=source, + source_preserved=True, player_preserved=True) + startup = directory/(phase+'-startup-project.godot') + startup.write_bytes(standard.private_project((verifier.ROOT/'project.godot').read_bytes(), item['startup_name'])) + row['startup_project'] = {'name': item['startup_name'], 'profile': item['startup_profile'], 'fresh_before': True, + 'sha256': verifier.sha(startup), 'restored_sha256': source['project.godot']['sha256']} + row['profile_copies'] = {'startup': {'exists': False, 'files': {}}, 'runtime': {'exists': False, 'files': {}}} + if role: + import shutil + target = directory/phase/'runtime-profile'; target.mkdir() + shutil.copytree(directory/phase/'evidence', target/'evidence') + row['profile_copies']['runtime'] = {'exists': True, 'files': verifier.inventory(target)} + for kind in ('startup', 'runtime'): retained[item[kind+'_profile']] = row['profile_copies'][kind]['files'] + rows.append(row) + cleanup.append({'pid': pid, 'engine_ended': True, 'outer_cleanup_errors': [], 'foreign_process_or_group_signals': 0}) + admission = {'source_map': source, 'phases': verifier.PHASES, 'plan': plan, 'pins': pins, + 'measured_source': 'S_eq-native-not-Q', 'candidate_Q_measured': False, + 'readonly_path': '/synthetic/readonly', 'fixture': '/synthetic/fixture', 'engine': '/synthetic/Godot'} + verifier.write(directory/'admission.json', admission) + return {'passed': True, 'error': None, 'cleanup_errors': [], 'cleanup': cleanup, 'admission': admission, + 'source_after': source, 'player_before': {}, 'player_after': {}, 'pins_after': pins, + 'phases': rows, 'profiles_retained': retained} + + +class S4Bundle(unittest.TestCase): + def test_synthetic_phase_all_real_checkers_not_native_proof(self): + with synthetic_directory() as name: + directory = Path(name) + row = s4_phase_fixture(directory) + result = verifier.phase_evidence(directory, row) + self.assertTrue(result['checker']['ok']) + self.assertNotEqual(result['raw'], result['joined']) + self.assertTrue(result['proofs']) + self.assertTrue(any(o['status'] == 'existing-defect' for o in result['checker']['e45'])) + + def test_seal_normal_and_changes_not_native_proof(self): + with synthetic_directory() as name: + directory = Path(name) + verifier.write(directory/'raw.json', {'synthetic_not_native': True}) + verifier.seal(directory); verifier.check_seal(directory) + with self.assertRaises(eq.EvidenceError): verifier.seal(directory) + (directory/'extra').write_text('after seal') + with self.assertRaises(eq.EvidenceError): verifier.check_seal(directory) + + def test_missing_bundle_manifest_seal_and_changed_bytes(self): + for kind in ('bundle.json', 'seal.json', 'raw.json', 'changed'): + with self.subTest(kind=kind), synthetic_directory() as name: + directory = Path(name) + verifier.write(directory/'raw.json', {}) + verifier.seal(directory) + if kind == 'changed': (directory/'raw.json').write_text('changed') + else: (directory/kind).unlink() + with self.assertRaises((OSError, eq.EvidenceError)): verifier.check_seal(directory) + + def test_missing_private_evidence_and_extra_rejected(self): + for filename in ('lifecycle.json', 'audio-close.json', 'e3-17.json', 'e45-20.json', 'extra.json'): + with self.subTest(filename=filename), synthetic_directory() as name: + directory = Path(name); row = s4_phase_fixture(directory) + file = directory/'R-A'/'evidence'/filename + if filename == 'extra.json': file.write_text('{}') + else: file.unlink() + with self.assertRaises(eq.EvidenceError): verifier.phase_evidence(directory, row) + + def test_phase_role_pid_audio_and_guard_rejected(self): + with synthetic_directory() as name: + directory = Path(name); row = s4_phase_fixture(directory) + for key, bad in [('role', 'O'), ('pid', 999), ('runtime_profile', '/wrong'), ('guard_sha256', 'f'*64)]: + altered = copy.deepcopy(row); altered[key] = bad + with self.subTest(key=key), self.assertRaises(eq.EvidenceError): verifier.phase_evidence(directory, altered) + + def test_missing_profile_not_export_success(self): + with synthetic_directory() as name: + with self.assertRaises(eq.EvidenceError): driver.copy_evidence(Path(name)/'absent', Path(name)/'copied') + + def test_existing_output_never_overwritten(self): + with synthetic_directory() as name: + with self.assertRaises(eq.EvidenceError): driver.run({}, Path(name), None, None, None, None) + + def test_checkout_temp_destination_rejected(self): + with patch.dict(os.environ, {'BUILD_OUTPUT_DIR': str(verifier.HERE)}): + with self.assertRaises(eq.EvidenceError): synthetic_directory() + + def test_import_closure_rejections(self): + for text in ('import restart_pair', 'from restart_pair import copy_states', 'import product', + 'importlib.util.spec_from_file_location("bad", "outside.py")', '__import__("outside")'): + with self.subTest(text=text), self.assertRaises(eq.EvidenceError): checker.check_python_imports(text) + for name in verifier.LOCAL_NAMES-{'eq_probe.gd'}: + self.assertTrue(checker.check_python_imports((verifier.HERE/name).read_text())) + + def test_rebound_lifecycle_and_scenario_contradictions(self): + for kind in ('errors', 'scenario_count', 'scenario_order', 'e45_missing', 'b1_missing', 'invented_PASS'): + with self.subTest(kind=kind), synthetic_directory() as name: + directory = Path(name); row = s4_phase_fixture(directory) + folder = directory/'R-A'; evidence = folder/'evidence' + raw = verifier.read(evidence/'report.json'); life = verifier.read(evidence/'lifecycle.json') + if kind == 'errors': life['errors'].append('observed failure') + elif kind == 'scenario_count': raw['scenarios'].pop() + elif kind == 'scenario_order': raw['scenarios'].reverse() + elif kind == 'e45_missing': life['e45'].pop() + elif kind == 'b1_missing': del life['e3_b1'] + else: raw['scenarios'][-1]['result']['status'] = 'PASS' + (evidence/'report.json').write_text(json.dumps(raw)) + (folder/'stdout.log').write_text('P28_02_EQ_REPORT='+json.dumps(raw)+'\n') + life['files'] = [dict(path='evidence/'+n, **p) for n, p in verifier.inventory(evidence).items() + if n not in ('lifecycle.json', 'audio-close.json')] + (evidence/'lifecycle.json').write_text(json.dumps(life)) + row['evidence_files'] = verifier.inventory(evidence) + with self.assertRaises((eq.EvidenceError, KeyError)): verifier.phase_evidence(directory, row) + + +class S4NativeBundleLogic(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.temp = synthetic_directory(); cls.directory = Path(cls.temp.name) + cls.collector, cls.standard, cls.outer, cls.diag = driver.load_dependencies() + cls.execution = s4_bundle_fixture(cls.directory, cls.collector, cls.standard) + + @classmethod + def tearDownClass(cls): + cls.temp.cleanup() + + def recompute(self, value): + with patch.object(self.standard, 'profile_path', side_effect=lambda name: Path('/private')/name): + return verifier.recompute(self.directory, value, self.collector, self.standard, self.diag) + + def test_synthetic_full_bundle_positive_not_native_evidence(self): + result = self.recompute(self.execution) + self.assertEqual(set(result['comparisons']), {'R', 'O'}) + self.assertFalse(result['formal_acceptance']) + verifier.write(self.directory/'execution.json', self.execution) + verifier.write(self.directory/'results.json', result) + for phase, values in result['phases'].items(): + for name, value in values.items(): verifier.write(self.directory/phase/(name+'.json'), value) + verifier.seal(self.directory) + # Only external admission is synthetic. All bundle, owned, lifecycle, + # observation, scenario, joining and comparison logic executes unchanged. + with patch.object(driver, 'actual_pins', return_value=self.execution['admission']['pins']), \ + patch.object(self.standard, 'profile_path', side_effect=lambda name: Path('/private')/name), \ + patch.object(driver, 'load_dependencies', return_value=(self.collector, self.standard, self.outer, self.diag)): + self.assertEqual(verifier.verify(verifier.ROOT, self.directory), result) + + def test_receipt_and_source_rejection_matrix(self): + mutations = [ + ('Q label', lambda x: x['admission'].update(candidate_Q_measured=True)), + ('source entry', lambda x: x['source_after']['project.godot'].update(bytes=0)), + ('source count only', lambda x: x['admission'].update(source_map={'count': 1407})), + ('pin mismatch', lambda x: x.update(pins_after={})), + ('cleanup remaining', lambda x: x['cleanup'][0].update(engine_ended=False)), + ('phase missing', lambda x: x['phases'].pop()), + ('cross role', lambda x: x['phases'][3].update(role='O')), + ('PID binding', lambda x: x['phases'][0].update(pid=999)), + ('raw native missing', lambda x: x['phases'][0]['raw'].pop('engine-native.log')), + ('owned missing', lambda x: x['phases'][0]['owned_files'].pop('ended.json')), + ('exit in raw', lambda x: x['phases'][0]['raw'].update(exit_code=0)), + ('runtime startup mix', lambda x: x['phases'][0]['startup_project'].update(name='R-A-runtime')), + ] + for name, mutate in mutations: + value = copy.deepcopy(self.execution); mutate(value) + with self.subTest(name=name), self.assertRaises((eq.EvidenceError, ValueError)): self.recompute(value) + + def test_gate_none_success_not_boolean(self): + self.assertIsNone(self.collector.stage_gate({}, {})) + guard = self.execution['phases'][3]['guard'] + self.assertIsNone(self.collector.guard_gate(guard, Path(guard['actual_user_data_dir']), guard['custom_user_dir_name'])) + with self.assertRaises(ValueError): self.collector.stage_gate({'x': 1}, {}) + with self.assertRaises(ValueError): self.collector.guard_gate(guard, Path('/wrong'), guard['custom_user_dir_name']) + + def test_copied_manifest_root_and_destination_count_rejected(self): + with self.assertRaises((OSError, ValueError)): self.collector.inputs(self.directory) + + def test_failure_keeps_raw_and_no_bundle_without_starting_engine(self): + with synthetic_directory() as name: + out = Path(name)/'failure' + admission = {'source_map': {'project.godot': verifier.pin(verifier.ROOT/'project.godot')}, + 'readonly_path': '/synthetic', 'fixture': '/synthetic', 'engine': '/synthetic'} + with patch.object(self.collector, 'no_live_engine'), \ + patch.object(self.standard, 'default_player', return_value={}), \ + patch.object(self.standard, 'copy_source', side_effect=OSError('synthetic copy failure')), \ + patch.object(self.collector, 'source_map', return_value=admission['source_map']), \ + patch.object(self.outer, 'finish_captured', return_value=([], [])), \ + patch.object(driver, 'actual_pins', return_value={}), \ + patch.object(self.collector, 'run_private_engine') as launch: + self.assertEqual(driver.run(admission, out, self.collector, self.standard, self.outer, self.diag), 1) + launch.assert_not_called() + self.assertFalse(verifier.read(out/'execution.json')['passed']) + self.assertFalse((out/'bundle.json').exists()) + self.assertFalse((out/'seal.json').exists()) + + +class S4ProbeAdmission(unittest.TestCase): + def driver_probe(self, mode, ok): + with synthetic_directory() as name: + argv = ['run_eq.py', mode, '--readonly', name, '--fixture', name, + '--engine', name, '--output', str(Path(name)/'new-output')] + errors = [] if ok else ['first static violation', 'second static violation'] + with patch.object(sys, 'argv', argv), \ + patch.object(driver, 'load_dependencies', return_value=(None, None, None, None)), \ + patch.object(driver, 'actual_pins', return_value={'source': {}}), \ + patch.object(checker, 'check_probe', return_value={'ok': ok, 'errors': errors}) as probe, \ + patch.object(driver, 'frozen_commit', return_value='synthetic'), \ + patch.object(driver, 'plan', return_value=[]), \ + patch.object(driver, 'run', return_value=0) as launch, \ + patch('builtins.print') as output: + self.assertEqual(driver.main(), 0 if ok else 1) + probe.assert_called_once() + if ok and mode == '--run': launch.assert_called_once() + else: launch.assert_not_called() + if not ok: + failure = json.loads(output.call_args.args[0]) + for error in errors: self.assertIn(error, failure['error']) + + def test_check_rejects_false_all_errors(self): self.driver_probe('--check', False) + def test_run_admission_rejects_false_without_engine(self): self.driver_probe('--run', False) + def test_check_accepts_true(self): self.driver_probe('--check', True) + def test_run_admission_accepts_true_mock_launch_only(self): self.driver_probe('--run', True) + + +class S4RemainingBindings(unittest.TestCase): + setUpClass = classmethod(S4NativeBundleLogic.setUpClass.__func__) + tearDownClass = classmethod(S4NativeBundleLogic.tearDownClass.__func__) + recompute = S4NativeBundleLogic.recompute + + def test_verifier_rejects_false_with_every_error(self): + errors = ['first static violation', 'second static violation'] + with patch.object(checker, 'check_probe', return_value={'ok': False, 'errors': errors}): + with self.assertRaises(eq.EvidenceError) as caught: self.recompute(self.execution) + for error in errors: self.assertIn(error, str(caught.exception)) + + def test_verifier_accepts_true_recomputes_raw(self): + with patch.object(checker, 'check_probe', return_value={'ok': True, 'errors': []}) as probe: + result = self.recompute(self.execution) + probe.assert_called_once() + self.assertEqual(set(result['comparisons']), {'R', 'O'}) + self.assertTrue(all(r['ok'] for r in result['comparisons'].values())) + + def test_owned_lifecycle_exit_diagnostic_and_profile_rejections(self): + mutations = [ + ('start missing', lambda x: x['phases'][0]['process'].pop('actual_start_binding')), + ('end missing', lambda x: x['phases'][0]['process'].pop('actual_end_binding')), + ('exit failure', lambda x: x['phases'][0]['process'].update(exit_code=3)), + ('diagnostic', lambda x: x['phases'][0].update(diagnostics=['ERROR: synthetic'])), + ('profile reuse', lambda x: x['admission']['plan'][1].update( + runtime_name=x['admission']['plan'][0]['runtime_name'])), + ] + for name, mutate in mutations: + value = copy.deepcopy(self.execution); mutate(value) + with self.subTest(name=name), self.assertRaises((eq.EvidenceError, ValueError, KeyError)): + self.recompute(value) + + def test_nonzero_determinism_rejected_after_real_join(self): + original = eq.compare_reports + def differing(left, right): + if left is right: + return original(left, right) + self.assertIsNotNone(left['checkpoints'][0]['harness_normalized_digest']) + self.assertIsNotNone(right['checkpoints'][0]['harness_normalized_digest']) + result = original(left, right) + result.update(ok=False, differences=[{'synthetic_difference': True}]) + return result + with patch.object(eq, 'compare_reports', side_effect=differing): + with self.assertRaisesRegex(eq.EvidenceError, 'same-role determinism failed'): + self.recompute(self.execution) + + def test_nine_original_destinations_required(self): + original_sha = driver.sha + def synthetic_sha(path): + if Path(path) == Path('/synthetic/fixture'): return self.collector.FIXTURE_SHA + if Path(path) == Path('/synthetic/Godot'): return self.collector.ENGINE_SHA + return original_sha(path) + with synthetic_directory() as name: + root = Path(name) + manifest = root/'ROOT_INPUT_MANIFEST.json' + for count, destinations in ((8, list(range(9))), (9, list(range(8))), (9, [0]*9)): + manifest.write_text(json.dumps({'files': [{'destination': str(n)} for n in destinations]})) + with self.subTest(count=count, destinations=destinations), \ + patch.object(driver, 'sha', side_effect=synthetic_sha), \ + patch.object(self.collector, 'inputs', return_value={'files': {str(n): 'sha' for n in range(count)}}): + with self.assertRaisesRegex(eq.EvidenceError, 'nine'): + driver.actual_pins(verifier.ROOT, root, Path('/synthetic/fixture'), + Path('/synthetic/Godot'), self.collector, self.standard) + + +class S4StoredResultBindings(unittest.TestCase): + def reject_stored_change(self, kind): + # Isolate verify's stored-result binding. The full raw recomputation is + # exercised without a mock by S4NativeBundleLogic and S4RemainingBindings. + with synthetic_directory() as name: + directory = Path(name) + admission = dict(readonly_path=name, fixture=name, engine=name, pins={}) + verifier.write(directory/'execution.json', {'admission': admission}) + result = {'phases': {'R-A': {'raw': {'kind': 'raw'}, 'joined': {'kind': 'joined'}, + 'proofs': [{'sidecar': 'required'}], 'checker': {'ok': True}}}} + stored = copy.deepcopy(result) + if kind == 'cached': stored['phases']['R-A']['checker']['ok'] = False + verifier.write(directory/'results.json', stored) + (directory/'R-A').mkdir() + for key, value in result['phases']['R-A'].items(): + if kind == 'proofs' and key == 'proofs': value = [] + if kind == 'raw_joined' and key == 'raw': value = result['phases']['R-A']['joined'] + verifier.write(directory/'R-A'/(key+'.json'), value) + verifier.seal(directory) + with patch.object(driver, 'load_dependencies', return_value=(None, None, None, None)), \ + patch.object(driver, 'actual_pins', return_value={}), \ + patch.object(verifier, 'recompute', return_value=result) as recompute: + with self.assertRaisesRegex(eq.EvidenceError, 'recomputed results differ|copy differs'): + verifier.verify(verifier.ROOT, directory) + recompute.assert_called_once() + + def test_cached_verdict_not_trusted(self): self.reject_stored_change('cached') + def test_missing_sidecar_rejected_after_seal(self): self.reject_stored_change('proofs') + def test_raw_joined_substitution_rejected_after_seal(self): self.reject_stored_change('raw_joined') + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/verify_eq.py b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/verify_eq.py new file mode 100644 index 0000000..240eee1 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-02/eq/verify_eq.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 +"""Read-only verification of the exact S_eq native evidence; never launches Godot.""" +import argparse +import hashlib +import json +import os +from pathlib import Path +import sys + +sys.dont_write_bytecode = True +import check_eq as check +import compare_versions as eq + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[5] +PHASES = ['import', 'parse-base', 'parse-wrapper', 'R-A', 'R-B', 'O-A', 'O-B'] +ROLES = {'R-A': 'R', 'R-B': 'R', 'O-A': 'O', 'O-B': 'O'} +NAMES = {f'{prefix}-{i:02d}.json' for prefix, count in + [('checkpoint', 31), ('observation', 31), ('e3', 18), ('e45', 21)] for i in range(count)} | { + 'events.json', 'report.json', 'lifecycle.json', 'audio-close.json'} +LOCAL_NAMES = {'run_eq.py', 'verify_eq.py', 'check_eq.py', 'compare_versions.py', 'eq_probe.gd', 'test_eq.py'} +require = eq.require + + +def sha(path): + return hashlib.sha256(Path(path).read_bytes()).hexdigest() + + +def pin(path): + path = Path(path) + require(path.is_file() and not path.is_symlink(), 'missing/symlink: ' + str(path)) + return {'bytes': path.stat().st_size, 'sha256': sha(path)} + + +def read(path): + return check.strict_json(Path(path).read_text(encoding='utf-8')) + + +def write(path, value): + with Path(path).open('x', encoding='utf-8') as stream: + json.dump(value, stream, ensure_ascii=False, allow_nan=False, indent=2) + stream.write('\n') + + +def wire(value): + """Checker diagnostics may contain tuples; bind their exact JSON representation.""" + return check.strict_json(json.dumps(value, ensure_ascii=False, allow_nan=False)) + + +def inventory(directory, seals=False): + directory = Path(directory) + require(directory.is_dir() and not directory.is_symlink(), 'evidence directory missing/symlink') + result = {} + for path in sorted(directory.rglob('*')): + require(not path.is_symlink(), 'evidence symlink') + name = path.relative_to(directory).as_posix() + if path.is_file() and (seals or name not in ('bundle.json', 'seal.json')): + result[name] = pin(path) + return result + + +def seal(directory): + directory = Path(directory) + require(not (directory / 'bundle.json').exists() and not (directory / 'seal.json').exists(), 'already sealed') + write(directory / 'bundle.json', {'schema': 'p28-02-eq-bundle-v1', 'files': inventory(directory)}) + write(directory / 'seal.json', {'bundle': pin(directory / 'bundle.json')}) + + +def check_seal(directory): + directory = Path(directory) + manifest, sealed = read(directory / 'bundle.json'), read(directory / 'seal.json') + require(sealed == {'bundle': pin(directory / 'bundle.json')}, 'seal mismatch') + require(manifest == {'schema': 'p28-02-eq-bundle-v1', 'files': inventory(directory)}, 'manifest/file mismatch') + + +def check_audio(audio, pid): + expected = {'coordinator': True, 'passed': True, 'owned_engine_pid': pid, + 'all_owned_targets_released': True, 'deadline_reached': False, + 'clock_process_held_stopped': True, 'window_input_held_disabled': True, + 'restored_before_quit': False, 'shared_bus_deleted': False, 'settings_mutated': False} + require(all(type(audio.get(k)) is type(v) and audio[k] == v for k, v in expected.items()), 'audio close/PID') + + +def phase_evidence(directory, row): + """Recompute all S1-S3b checks from copied native bytes, with no cached verdicts.""" + directory = Path(directory) + phase, role = row['phase'], row['role'] + require(ROLES.get(phase) == role, 'phase/role binding') + folder = directory / phase + evidence = folder / 'evidence' + files = inventory(evidence, seals=True) + require(set(files) == NAMES and files == row['evidence_files'], 'exact private evidence inventory') + raw = check.read_report_stdout((folder / 'stdout.log').read_text()) + require(raw == read(evidence / 'report.json') and raw['role'] == role, 'raw report/role copy') + require(len(raw['scenarios']) == 39, '39 scenarios required') + life = read(evidence / 'lifecycle.json') + require(life['stage'] == 'S3b', 'S3b lifecycle required') + require(len(life['e3']) == 18 and len(life['e45']) == 21, 'scenario evidence coverage') + declared = {r['path']: {'bytes': r['bytes'], 'sha256': r['sha256']} for r in life['files']} + require(len(declared) == len(life['files']), 'duplicate lifecycle inventory') + expected = {'evidence/' + n: v for n, v in files.items() if n not in ('lifecycle.json', 'audio-close.json')} + require(declared == expected, 'lifecycle inventory differs') + guard_path = directory / (phase + '-guard.json') + guard = read(guard_path) + require(guard == row['guard'] and sha(guard_path) == row['guard_sha256'] == life['guard']['sha256'], 'guard SHA') + require(life['guard']['path'] == row['environment']['THE_TREE_PACK_PROFILE_REPORT'], 'guard path binding') + require(raw['profile_root']['root'] == row['runtime_profile'], 'report profile binding') + check.check_lifecycle(raw, life, guard) + check_audio(read(evidence / 'audio-close.json'), row['pid']) + require(read(evidence / 'events.json') == raw['events'], 'events copy') + for i, cp in enumerate(raw['checkpoints']): + require(read(evidence / f'checkpoint-{i:02d}.json') == cp, 'checkpoint copy') + check.check_observation(cp, read(evidence / f'observation-{i:02d}.json')) + for prefix in ('e3', 'e45'): + for i, value in enumerate(life[prefix]): + require(read(evidence / f'{prefix}-{i:02d}.json') == value, 'scenario copy') + checked = check.check_report(raw, life['measurement'], life['e3'], life['e3_b1'], life['e45']) + require(checked['ok'], 'report checker: ' + repr(checked['errors'])) + joined, proofs = check.join_report(raw) + return wire({'raw': raw, 'joined': joined, 'proofs': proofs, 'checker': checked}) + + +def recompute(directory, execution, collector, standard, diag): + """Validate owned receipts and recompute every comparison from raw evidence.""" + directory = Path(directory) + require(execution['passed'] is True and execution['error'] is None and execution['cleanup_errors'] == [], 'execution failed') + admission = execution['admission'] + require(read(directory / 'admission.json') == admission, 'admission copy') + require(admission['measured_source'] == 'S_eq-native-not-Q' and admission['candidate_Q_measured'] is False, 'Q measurement forbidden') + require(admission['phases'] == PHASES, 'phase plan') + from run_eq import wrapper_text + original_out = Path(admission['plan'][0]['folder']).parent + engine = Path(admission['engine']) + expected_commands = [collector.argv_for(engine, original_out / 'stage', original_out / 'guarded.gd', importing=True), + collector.parse_argv(engine, original_out / 'stage', original_out / 'eq_probe.gd'), + collector.parse_argv(engine, original_out / 'stage', original_out / 'guarded.gd')] + [ + [str(engine), '--headless', '--path', str(original_out / 'stage'), '--script', str(original_out / 'guarded.gd')] + for _ in range(4)] + require([p['argv'] for p in admission['plan']] == expected_commands, 'actual seven-phase command plan') + require((directory / 'guarded.gd').read_text() == wrapper_text(original_out), 'guard before parent wrapper') + require(sha(directory / 'eq_probe.gd') == admission['pins']['worker']['eq_probe.gd'], 'frozen probe') + require(sha(directory / 'profile_guard.gd') == admission['pins']['readonly']['files']['run-r02/profile_guard.gd'], 'guard pin') + require(sha(directory / 'root-input-manifest.json') == admission['pins']['readonly']['manifest_sha256'], 'original manifest copy') + static = check.check_probe((directory / 'eq_probe.gd').read_text()) + require(static['ok'], 'probe checker: ' + repr(static['errors'])) + source = admission['source_map'] + require(len(source) == 1407 and collector.digest(source) == eq.SOURCE_SHA, 'full source map pin') + require(execution['source_after'] == source and execution['player_before'] == execution['player_after'], 'source/player preservation') + require(execution['pins_after'] == admission['pins'], 'pin preservation') + rows = execution['phases'] + require([r['phase'] for r in rows] == PHASES, 'seven phases in order') + pids, profiles, joined, results = [], [], {}, {} + previous = source + for i, row in enumerate(rows): + phase = row['phase'] + # DIAG's shared owned/raw checks return before its DIAG-specific report branch + # for the EQ phase names. Its dependency is frozen; no function is replaced. + diag.bound_raw(directory / phase, row) + for name in row['raw']: + require(not collector.diagnostics((directory / phase / name).read_text()), 'strict diagnostic') + for name in row['owned_files']: + read(directory / phase / name) # reject duplicate JSON keys before any admission + pid = row['process']['pid'] + require(type(pid) is int and pid > 0 and row['pid'] == pid, 'phase PID binding') + pids.append(pid) + start, end = row['process']['actual_start_binding'], row['process']['actual_end_binding'] + require(type(start['monotonic_ns']) is int and end['monotonic_ns'] >= start['monotonic_ns'], 'PID start/end time') + command = admission['plan'][i] + require(command['phase'] == phase and command['role'] == ROLES.get(phase), 'planned role') + environment = {'THE_TREE_PACK_PROFILE_NAME': command['runtime_name'], + 'THE_TREE_PACK_PROFILE_EXPECTED': command['runtime_profile'], + 'THE_TREE_PACK_PROFILE_REPORT': str(original_out / (phase + '-guard.json')), + 'THE_TREE_EQ_ROLE': ROLES.get(phase, ''), 'THE_TREE_P28_FIXTURE': admission['fixture'], + 'THE_TREE_P28_FIXTURE_SHA': collector.FIXTURE_SHA} + require(command['environment'] == environment, 'guard/role/fixture environment') + require(command['startup_profile'] == str(standard.profile_path(command['startup_name'])) and + command['runtime_profile'] == str(standard.profile_path(command['runtime_name'])), 'profile name/path') + require(row['argv'][:-3] == command['argv'] and row['argv'][-3] == '--log-file' and + row['argv'][-1] == '--verbose' and '--headless' in row['argv'], 'phase argv') + require(row['environment'] == command['environment'], 'phase environment') + collector.stage_gate(previous, row['stage_inventory'], importing=phase == 'import') + previous = row['stage_inventory'] + require(row['source_preserved'] is True and row['player_preserved'] is True, 'phase preservation') + startup = row['startup_project'] + require(startup['name'] == command['startup_name'] and startup['profile'] == command['startup_profile'] and + startup['fresh_before'] is True and startup['restored_sha256'] == source['project.godot']['sha256'], 'startup profile') + require(sha(directory / (phase + '-startup-project.godot')) == startup['sha256'], 'startup project bytes') + require((directory / (phase + '-startup-project.godot')).read_bytes() == + standard.private_project((ROOT / 'project.godot').read_bytes(), command['startup_name']), 'private project policy') + profiles.extend([startup['profile'], command['runtime_profile']]) + for kind in ('startup', 'runtime'): + copied = row['profile_copies'][kind] + target = directory / phase / (kind + '-profile') + require(type(copied['exists']) is bool and copied['exists'] == target.is_dir(), 'profile existence/copy') + require((inventory(target, seals=True) if target.is_dir() else {}) == copied['files'], 'complete profile copy') + require(execution['profiles_retained'][command[kind + '_profile']] == copied['files'], 'retained profile changed') + if phase in ROLES: + require(row['profile_copies']['runtime']['exists'] is True, 'missing runtime profile') + require({n[len('evidence/'):]: p for n, p in row['profile_copies']['runtime']['files'].items() + if n.startswith('evidence/')} == row['evidence_files'], 'profile/evidence copy binding') + require(row['role'] == ROLES[phase] and row['runtime_profile'] == command['runtime_profile'] and + row['runtime_name'] == command['runtime_name'], 'runtime/role binding') + collector.guard_gate(row['guard'], Path(row['runtime_profile']), row['runtime_name']) + results[phase] = phase_evidence(directory, row) + joined[phase] = results[phase]['joined'] + else: + require(row['role'] is None, 'parse/import role') + require('P28_02_EQ_REPORT=' not in (directory / phase / 'stdout.log').read_text(), 'parse/import report') + require(len(set(pids)) == 7 and len(set(profiles)) == 14, 'PID/profile reuse') + require({r['pid'] for r in execution['cleanup']} == set(pids) and all( + r['engine_ended'] is True and r['outer_cleanup_errors'] == [] and + r['foreign_process_or_group_signals'] == 0 for r in execution['cleanup']), 'cleanup incomplete') + comparisons = {} + for role in ('R', 'O'): + result = eq.compare_reports(joined[role + '-A'], joined[role + '-B']) + require(result['ok'] and result['differences'] == [], 'same-role determinism failed: ' + role) + comparisons[role] = result + return wire({'phases': results, 'comparisons': comparisons, 'measured_source': 'S_eq-native-not-Q', + 'candidate_Q_measured': False, 'original_credit': 0, 'formal_acceptance': False}) + + +def verify(project_root, directory): + from run_eq import load_dependencies, actual_pins + project_root, directory = Path(project_root).resolve(), Path(directory).resolve() + check_seal(directory) + execution = read(directory / 'execution.json') + collector, standard, outer, diag = load_dependencies(project_root) + admission = execution['admission'] + require(actual_pins(project_root, Path(admission['readonly_path']), Path(admission['fixture']), + Path(admission['engine']), collector, standard) == admission['pins'], 'actual input/source/EQ pins differ') + result = recompute(directory, execution, collector, standard, diag) + require(result == read(directory / 'results.json'), 'recomputed results differ') + for phase, values in result['phases'].items(): + for name, value in values.items(): + require(read(directory / phase / (name + '.json')) == value, 'raw/joined/proof/checker copy differs') + return result + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--project-root', type=Path, required=True) + args = parser.parse_args() + try: + require(os.environ.get('BUILD_OUTPUT_DIR'), 'BUILD_OUTPUT_DIR required') + result = verify(args.project_root, Path(os.environ['BUILD_OUTPUT_DIR']) / 'p28-02-eq-evidence') + print(json.dumps({'status': 'verified', 'result': result}, ensure_ascii=False, allow_nan=False)) + return 0 + except (ValueError, OSError, KeyError, TypeError, IndexError) as error: + print(json.dumps({'status': 'failed', 'error': str(error), 'formal_acceptance': False})) + return 1 + + +if __name__ == '__main__': + raise SystemExit(main())