Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe44f55075 | ||
|
|
78f7cba7a9 |
+1
-1
@@ -3740,7 +3740,7 @@
|
||||
"template": "Operations notification: <checks> checks, <failures> failures",
|
||||
"required": true,
|
||||
"fixed_check_count_used": false,
|
||||
"source_sha256_at_schema_audit": "9c26386c529b8c8135639e8d0f0ed390da7139d64ff1e268975b05948cab9147",
|
||||
"source_sha256_at_schema_audit": "50172ab6daa031d221f6a78cac5cdbcb8884f295f8062b54656562e2412faff2",
|
||||
"authority": {
|
||||
"path": "docs/spec/acceptance/P24-02-code-r01.json",
|
||||
"scope": "new local suite source marker; actual execution pending"
|
||||
|
||||
+14
-1
@@ -305,6 +305,18 @@ def check_json(path: str, main_text: str, report: dict) -> None:
|
||||
((base_t, "base"), (main_text, "main"), (p24_t, "p24")))
|
||||
recon = load_json_strict(recon_t, f"{path}@reconciled")
|
||||
expected = expect3(base, main, p24)
|
||||
# Repair5 authority permits exactly this P24 source pin rebind; no schema,
|
||||
# cleanup policy, non-P24 row or ordered structure is changed.
|
||||
test = "tests/ui/test_operations_notification.gd"
|
||||
digest = hashlib.sha256((ROOT / test).read_bytes()).hexdigest()
|
||||
if path.endswith("completion_marker_contracts.json"):
|
||||
rows = [r for r in expected["rows"] if r["test"] == test]
|
||||
if len(rows) != 1:
|
||||
fail("exactly one P24 marker row required")
|
||||
else:
|
||||
rows[0]["source_sha256_at_schema_audit"] = digest
|
||||
elif path.endswith("suite-policy.json"):
|
||||
expected["suite_policies"][test]["source_sha256"] = digest
|
||||
ok = ordered_equal(recon, expected)
|
||||
if not ok:
|
||||
fail(f"{path}: reconciled JSON != main snapshot + P24-only additions (value/order)")
|
||||
@@ -459,7 +471,8 @@ def main() -> int:
|
||||
report["scope"] = ("Static source preservation only. Not Godot/import/native/OS/full-roster proof and "
|
||||
"not acceptance. Root owns current-main composition and all execution.")
|
||||
report["failures"] = failures
|
||||
EVIDENCE.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
if args.write_evidence:
|
||||
EVIDENCE.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
summary = {p: {k: (len(v) if isinstance(v, list) else v) for k, v in r.items()
|
||||
if k in ("missing", "duplicates", "unexpected", "required_count", "reconciled_symbol_count",
|
||||
"equals_main_plus_p24_only_additions_in_order", "body_issues")}
|
||||
|
||||
+3
-5
@@ -33,13 +33,11 @@ class CheckerTests(unittest.TestCase):
|
||||
def validate(self, rows, **counts):
|
||||
data = dict(test_suite='tests/ui/test_operations_notification.gd', failures=0, checks=1,
|
||||
full_roster=dict(results=rows, **counts))
|
||||
previous = Path.cwd()
|
||||
try:
|
||||
os.chdir(self.root)
|
||||
# Repair5 deliberately resolves suite bytes from the verified T view,
|
||||
# never from cwd. This TEST-ONLY adapter supplies that isolated view.
|
||||
with patch.object(checker, 'VERIFIED_ROOT', self.root):
|
||||
return checker._validate_condition_artifact_content(
|
||||
'final_validation_review', data, 'json', self.root, {}, {})
|
||||
finally:
|
||||
os.chdir(previous)
|
||||
|
||||
def test_positive_roster(self):
|
||||
for counts in ({}, dict(total_suites=3, suites_count=3, failures=0)):
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"actual_main": "54cade4181f6c3c4f5701ba54ac5fcbeca695945",
|
||||
"exact4_main_blobs": [
|
||||
{
|
||||
"path": "scenes/main/main.gd",
|
||||
"actual_main_blob": "fff37f082d750bb91c71f2aa54d168c9e2cb8fe7",
|
||||
"equals_already_reconciled_reference_blob": true
|
||||
},
|
||||
{
|
||||
"path": "scenes/main/world_preview.gd",
|
||||
"actual_main_blob": "fa32fe0344d20565b6d542da1256a94e8dee1845",
|
||||
"equals_already_reconciled_reference_blob": true
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json",
|
||||
"actual_main_blob": "2eecb803f5eb6774ff38cd353de1f02847aeb0f9",
|
||||
"equals_already_reconciled_reference_blob": true
|
||||
},
|
||||
{
|
||||
"path": "tools/regression/suite-policy.json",
|
||||
"actual_main_blob": "ad194ae425fb8123fa191ed3635f404c098f692d",
|
||||
"equals_already_reconciled_reference_blob": true
|
||||
}
|
||||
],
|
||||
"reason": "M54 is docs-only after original M51 reference; all four conflict-input blobs are genuinely identical. Future M changing any conflict-input blob needs new reconciliation proof, not automatic old-S overwrite."
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"source": "bd3a13405115fc9bf6c5acec55bcfef7dd15266a",
|
||||
"main": "54cade4181f6c3c4f5701ba54ac5fcbeca695945",
|
||||
"all_files_complete": true,
|
||||
"file_or_byte_cap": null,
|
||||
"reference_only_not_executable_snapshot_imports": true,
|
||||
"files": [
|
||||
{
|
||||
"path": "tools/check_p23_life_observation_evidence.py",
|
||||
"reference_path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/tools/check_p23_life_observation_evidence.py.source.txt",
|
||||
"sha256": "e41479ae51bccdfab3f31bd348794b441c2f341179bbe33222e2aacdf88f987f",
|
||||
"git_blob": "8a62d1e1070688ced445e48d49b831fc7e9cfea3"
|
||||
},
|
||||
{
|
||||
"path": "tools/run_p23_life_observation.py",
|
||||
"reference_path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/tools/run_p23_life_observation.py.source.txt",
|
||||
"sha256": "8dbd90e22f47912b3381b514398fe1fb2c403c97d8e3d0dd675e9c8db5b5d0d1",
|
||||
"git_blob": "0a255140d48e3cf194c1644948a0f1e1dc89a3ca"
|
||||
},
|
||||
{
|
||||
"path": "tools/run_all_tests.py",
|
||||
"reference_path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/tools/run_all_tests.py.source.txt",
|
||||
"sha256": "320ca668732b4ff72fc4449998af2327d4e5c527b06896740806aaf0487282b4",
|
||||
"git_blob": "502ad8c1f6ba371446ecfd8f37f0f9194cdb10ea"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair4-20261017/actual-limited-review/result.json",
|
||||
"reference_path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair4-20261017/actual-limited-review/result.json",
|
||||
"sha256": "ef17de03039bcd2b3d7a2851d26c0abdc163b32fef40048d933a693f1b49114f",
|
||||
"git_blob": "fec14229d322f4cbe9e27f2e02eb08f0e89bef31"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair4-20261017/CURRENT_ACCEPTANCE_AND_NEXT_BATCH.json",
|
||||
"reference_path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair4-20261017/CURRENT_ACCEPTANCE_AND_NEXT_BATCH.json",
|
||||
"sha256": "9c7892ce6ccd26d997e7a609be29ef8a12acb2fb7df75cf4def6f11a8a9157dc",
|
||||
"git_blob": "7a35430785c15b510dfe107c03807bf5c75951ba"
|
||||
}
|
||||
],
|
||||
"instruction": "P23 helper code is reference only; preserve exact generic Git/source provenance where applicable, do not copy P23 marker/acceptance identities as P24 evidence or import missing modules into old-base S."
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
# Root operational facts for repair5
|
||||
|
||||
Actual source bd3a134, actual Main54cade4. The4conflict main blobs equal the original M51 snapshots, verified by Git and recorded in CURRENT_MAIN_RECONCILIATION_APPLICABILITY.json. Bind this reconciliation input provenance: a later M changing any of these4blobs must not silently reuse an old-S resolution and drop new Main code. Docs-only M updates may be applicable by exact relevant blob identity, with fresh genuine Q/M roles; do not relabel oldQ. Additional negative: newQ with currentM as parent but stale conflict S blobs dropping changed M hunk must fail against the reconciled-input binding.
|
||||
|
||||
Spec/source/marker/settings/fixture pins are Git file blobs. The engine executable is external and cannot have a Git blob ID; use a separately verified external engine fingerprint/actual started+ended runtime receipt binding and explicit same engine across actual inputs. Do not invent a path or require an external binary to be a repository blob. Source-only tests may use labelled TEST-ONLY data; no real index or acceptance is created. Actual Root capture will supply real engine path/SHA/version and OS platform. Existing P23 receipts are format references only, never P24 actual execution.
|
||||
|
||||
If adding a native UI test changes tests/ui/test_operations_notification.gd source, update only its own marker/policy source-authority SHA fields to the actual new test source after verifying unchanged marker schema/cleanup semantics. Keep all non-P24 entries and all existing safety rules. Do not leave a stale source pin, and do not lower marker expectations. The original registered scope already allows the two JSON files. Adjust local preservation/input checks for this explicit new-source SHA rebind; never claim unchanged old SHA.
|
||||
|
||||
Do not edit NEXT_CLOSURE.md or other Main progress/shared Root reference files; Main54 changed them and doing so adds unrelated merge conflicts. New status/docs/helpers/tests belong under source-ready-repair5-20261017 or another specifically directed p24-02 owned subdir. Keep renderer world_preview.gd unchanged unless Opus explicitly instructs a necessary fix. The new modal visibility callback is functional correctness, not a visual redesign.
|
||||
|
||||
Root bridge owns prelaunch HEAD/no competing worker/quota checks and exclusive lease. A restricted worker must not ps or search user folders. Task-local TMPPREFIX and PYTHONPYCACHEPREFIX are ordinary environment routing within already writable allocation; both solved real default temp/cache failures in the identical sandbox. No policy, permission, security or billing changes. Root can set these before the actual model process so every shell receives correct defaults. Native/Godot/OS/full executions remain Root-owned and not worker actions.
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"plan_id": "P24-02",
|
||||
"unit_state": "in_progress",
|
||||
"runner_state": "submitted",
|
||||
"submitted_sha": "bd3a13405115fc9bf6c5acec55bcfef7dd15266a",
|
||||
"source_backup_remote_branch": "codex/p24-02-source-bd3a134",
|
||||
"same_existing_task": "the-tree-p24-02-operations/P24-02",
|
||||
"repair_count": 4,
|
||||
"max_repair_attempts": null,
|
||||
"actual_roles": "Opus5.5 commander; existing Antigravity IDE Opus5.5Medium GUI partial4file merge, then verified terminal quota; Opus-authorized Codex6.1-sol same-task nonUI continuation, no duplicateworker/registration/counterreset",
|
||||
"static_readiness": {
|
||||
"actual_compile_pass": true,
|
||||
"actual_preservation_pass": true,
|
||||
"actual_diff_check_pass": true,
|
||||
"meaningful_local_tests": 9,
|
||||
"local_tests_reused_only_with_3_input_hashes_and_actual_raw_exit0": true,
|
||||
"actual_source_and_JSON_move_guards_pass": true
|
||||
},
|
||||
"limited_independent_review": {
|
||||
"actual_Opus_run": "95cffd7b552a4939a4252349b3dfcfbd",
|
||||
"status": "pass",
|
||||
"critical_high_medium": 0,
|
||||
"low": 5,
|
||||
"original_unit_acceptance_ids": [],
|
||||
"scope": "Static source readiness only; not Core whole-unit review evidence."
|
||||
},
|
||||
"prepared_real_composition": {
|
||||
"scope": "Prospective real Git composed source, not a normal integration candidate or runtime evidence. Actual failed merge and stage1/2/3 are preserved; Root resolved only4 known conflicts by taking exact already-reconciled S blobs.",
|
||||
"submitted_sha": "bd3a13405115fc9bf6c5acec55bcfef7dd15266a",
|
||||
"main_context_sha": "51e8657bfbe24856186cc6530358c5459cf909b6",
|
||||
"prepared_tree": "a0667b90d13bd3ae8d8b8bdbc580192c2f90622f",
|
||||
"prepared_commit": "4bf9a1b80e1491d138954d218720b4bf6298d32a",
|
||||
"prepared_worktree": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-root-composed-bd3a134-r01",
|
||||
"actual_parents": [
|
||||
"51e8657bfbe24856186cc6530358c5459cf909b6",
|
||||
"bd3a13405115fc9bf6c5acec55bcfef7dd15266a"
|
||||
],
|
||||
"actual_conflict_resolution_bindings": [
|
||||
{
|
||||
"path": "scenes/main/main.gd",
|
||||
"resolved_actual_sha256": "f71f8c15493d6b51002ee4afb41cc349efe77e860944c1f79a5b24f928ecbd24",
|
||||
"actual_S_blob": "a3bba86dd156437ce6b802bcb49597cb94a45312",
|
||||
"authority": "Exact submitted S content with actual static body/symbol/order preservation proofs; Root resolved index only, no authored source edits"
|
||||
},
|
||||
{
|
||||
"path": "scenes/main/world_preview.gd",
|
||||
"resolved_actual_sha256": "8c2daa9e95d56e6e40bb2071b206693069cb7e4731b4d660d59d41c34cb43dfa",
|
||||
"actual_S_blob": "26dd8d785f37f6c9142c80b7deaf8daecb0cebe6",
|
||||
"authority": "Exact submitted S content with actual static body/symbol/order preservation proofs; Root resolved index only, no authored source edits"
|
||||
},
|
||||
{
|
||||
"path": "tools/regression/suite-policy.json",
|
||||
"resolved_actual_sha256": "adc2fbac2463bfdb047bede0182c66083996b75d2bd542a3b8640672d7ca2400",
|
||||
"actual_S_blob": "de0ab07c83c144a6c469cfdcf52ad8bd6c0bd6fa",
|
||||
"authority": "Exact submitted S content with actual static body/symbol/order preservation proofs; Root resolved index only, no authored source edits"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json",
|
||||
"resolved_actual_sha256": "1063e578eefe6da1b38c24f4c004669bcac67a21884636fb1b9c7e96e4ecf388",
|
||||
"actual_S_blob": "68b8dc8324b7928164bddbcbb1dbb49fbeb25f89",
|
||||
"authority": "Exact submitted S content with actual static body/symbol/order preservation proofs; Root resolved index only, no authored source edits"
|
||||
}
|
||||
],
|
||||
"selected_source_files": 1368,
|
||||
"required_roster_size_NOT_EXECUTED": 180,
|
||||
"all_git_blob_bindings": 4835,
|
||||
"source_maps": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/coordinator-resume-20261017-r01/prepared-bd3a134-source-maps",
|
||||
"historical_EOF_lint": {
|
||||
"exit_code": 2,
|
||||
"output": "docs/plans/original-completion-2026-10-02/execution/p24-02/ROOT_CODE_PHASE_PRELAUNCH_PROOF/original-GUI-copy/scenes/main/main.gd.source.txt:3319: new blank line at EOF.\nscenes/main/main.gd:3319: new blank line at EOF.\nscripts/ui/manual_save_slots_dialog.gd:219: new blank line at EOF.\n",
|
||||
"disposition": "Extra blank EOF lines inherited in actual source and exact preservation copy; retained byte-identically. Recorded source-style observations only, not an invented runtime/spec requirement and not claimed clean lint. Local repair4 actual delta git-diff-check passed. Not product behavior or a conflict marker."
|
||||
},
|
||||
"native_runs": 0,
|
||||
"full_runs": 0,
|
||||
"all8_original_P24_accepted": false,
|
||||
"normal_integration_candidate": false,
|
||||
"production_main_unchanged": true,
|
||||
"original_completed_units": 14,
|
||||
"at_jst": "2026-10-17T14:10:32.615822+09:00"
|
||||
},
|
||||
"first_next_required_batch": [
|
||||
"Implement strict same-root actual Git S/M/T/Q composition/source/input/roster binding, including deterministic4conflict resolution, using existing P23/shared helpers without relabeling tests.",
|
||||
"Replace artifact-ID count proxy with actual condition/provenance/content correspondence; one all-keys JSON plus irrelevant fillers must fail; genuine shared raw traces may be reused only with concrete scope bindings.",
|
||||
"Cover actual staff-panel click equivalent (direct handler call is not OS mapclick), defense modal visibility guard, actual bubble render/state transitions; investigate heart semantics/multiple-link order and per-frame relation scans without inventing gameplay thresholds.",
|
||||
"Treat preservation body-line set weakness and always-written evidence flag as recorded low hardening; do not claim stronger automatic proof than provided and preserve independent manual inspection scope.",
|
||||
"Batch required related fixes then actual import/local/impact, actual normalOS/scale/save evidence, exact final full once, whole8 formal independent review, normalintegration/final/ledger; Windows-specific conditions remain genuine actual-device requirements."
|
||||
],
|
||||
"all8_original_conditions_accepted": false,
|
||||
"new_native_runs": 0,
|
||||
"new_full_roster_runs": 0,
|
||||
"original_denominator": {
|
||||
"packages": 30,
|
||||
"units": 88,
|
||||
"completed": 14,
|
||||
"partial_credit": false
|
||||
},
|
||||
"no_source_code_adoption_on_main": true,
|
||||
"at_jst": "2026-10-17T14:21:51.543429+09:00"
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"task_id": "P24-02",
|
||||
"commit": "bd3a13405115fc9bf6c5acec55bcfef7dd15266a",
|
||||
"status": "pass",
|
||||
"summary": "Limited independent static review of the Q checkout (S=bd3a134 blobs composed onto M=51e8657). I used Read/Grep/Glob only and ran nothing. This is static source-readiness only: none of the 8 original P24 conditions is accepted, no acceptance_ids are added, and nothing here counts as Godot, native, OS, full-roster, Windows or whole-unit review evidence.\n\n(1) Reconciled files. world_preview.gd keeps the P23 LifeOverlay pipeline: _draw_contents/_build_life_observation, the overlay pass/serial report, the actor_drawings rows, aggregation and hidden filtering, and the cabin passengers. The single new adapter, _draw_actor_bubble(row, canvas), only reads state. It skips riding rows, looks up live Staff/Guest through get_staff/get_guest and RelationshipState through get_relationships, and never writes the observation or its rows. _draw_unit_bubble's fitted-row origin at+(-1p,-15p) works out to exactly P24's old center+(-9p, h/2-3wp-32p), so geometry, glyphs and colours are unchanged; only the target canvas is different. The 10 'reexpressed' _draw_actors lines are covered by main's _observe_actors/_draw_actors; staff queue placement survives at world_preview.gd:1433. The P24 additions in main.gd (modal guard, domain-event stream bind/unbind, cut-in, camera controls, click handler) match the GUI-copy bytes. Both JSON files are main's entries plus the P24 row/key appended at the end. No new production values were found.\n\n(2) check_p24_operations_evidence.py. The real HEAD now comes from git, and CANDIDATE_COMMIT/TARGET_HEAD are cross-checks only; git failure or a mismatch gives an empty result. The required suite set is loaded from the shared run_all_tests.roster. Suite sets must match exactly. Unknown or duplicate rows and non-dict rows are rejected, and every row needs a valid SHA that matches the file on disk, failures as an int equal to 0 (bool rejected), and passed=True. Optional counts must match exactly when present. The raw diff shows both old count-bypass `pass` branches removed, and the OS, receipt, PID, condition and Windows guards are untouched. The 9 stdlib tests include real positive controls (roster with and without counts, HEAD in a throwaway git repo) and meaningful negatives (invented replacement, duplicate padding, unknown extra rows, failures/passed type variants, SHA variants, malformed rows and counts, env mismatch, git unavailable).\n\n(3) check_repair4_preservation.py. It compares scope-qualified symbols across base, P24, main and the reconciled file, plus body lines per symbol, flags P24 edits to symbols main removed, and does a strict 3-way JSON comparison by value and order with duplicate-key detection. The METRIC_IDS regex fix correctly reads the assigned array past the Array[StringName] annotation. The bubble schema checks are pinned to M.\n\n(4) Docs. SOURCE_READY/NOTRUN status for all 8 conditions, the earlier failed py_compile and JSON-order runs, the GUI quota stop and the stale 179 run are all recorded honestly. The Root S/M/T/Q composition contract is still listed as an unresolved prerequisite, not as passed.\n\nI found no critical, high or medium defects. The low findings below are hardening items for the later required phases, which all remain mandatory: Root composition contract, import/impact, normal OS, exact final full roster, whole-8 independent review, normal integration and Windows.",
|
||||
"acceptance_ids": [],
|
||||
"findings": [
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "scenes/main/main.gd:985-987 connects world_preview.staff_assignment_clicked to assign_staff_by_click, but nothing in world_preview.gd emits that signal (it is only declared at world_preview.gd:6; _gui_input never emits it). This was already the case in P24 (no P24 _gui_input lines were lost) and is not a repair4 regression. A non-drag alternative already exists through the staff panel's facility_option and apply_button, so this is dead wiring rather than a missing feature. However, tests/ui/test_operations_notification.gd:110 calls assign_staff_by_click directly, so click_alternatives evidence must not treat that direct call as a real map-click path. Either emit the signal from the facility-click branch (respecting modal_input_blocked) or remove the connection."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "main.gd:3259 _update_modal_input_guard includes defense_manager in its dialog list, but _ensure_defense_manager (main.gd:3063-3089) never connects defense_manager.visibility_changed to the guard, unlike the other six dialogs. Opening or closing the defense dialog alone does not update world_preview.modal_input_blocked. AcceptDialog's exclusive default probably masks this, but modal_and_pause_resume runtime evidence should cover it or the connection should be added."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "check_repair4_preservation.py compares function bodies as sets of stripped lines (lines 176-203), so it cannot detect reordered statements or a dropped copy of a repeated line (for example a duplicate return/queue_redraw). REPAIR4_REEXPRESSED_P24_LINES also allows every lost P24 line in the two listed functions, not just specific lines. I checked the 19 enumerated lines by hand and they are legitimately re-expressed, but the guard is weaker than an ordered/multiset body check. Also, --write-evidence is parsed but has no effect: evidence is always written. This is documented in the status file."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "check_p24_operations_evidence.py: get_actual_git_head() resolves the repo from the checker's own location (parents[1]), while the roster, source_hashes and suite SHA checks use the current working directory (Path('.')). If it is run from another checkout, HEAD and source evidence come from different trees. The existing 'distinct artifacts' guard (lines 716-722) only counts IDs: one artifact containing every condition's keys plus 7 hash-valid filler artifacts would pass, because each condition needs only one artifact to validate. Neither problem is new to repair4 or a weakened guard, but both should be closed in the Root S/M/T/Q composition contract before the real index verify-only run."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "Bubble coverage and semantics (already marked NOTRUN, recorded so they are not lost): (a) no local test exercises the new _draw_actor_bubble/_draw_unit_bubble render path; tests only call OperationFeedback.resolve_*_bubble. (b) _staff_relationship/_guest_relationship return the first RelationshipState involving the actor, so with several relationships the heart bubble depends on iteration order. (c) The inherited heart rule 'shield>0 or affection>0 or route-lock pending/locked' needs whole-8 review against 'no invented thresholds'. (d) Each frame scans every relationship for every drawn actor."
|
||||
}
|
||||
]
|
||||
}
|
||||
+2503
File diff suppressed because it is too large
Load Diff
+311
@@ -0,0 +1,311 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Exact standard suites in one private source copy, with owned native evidence.
|
||||
|
||||
Completion schemas and test bodies are unchanged. Import and every script start
|
||||
in a fresh private startup profile before Godot creates logs/recovery locks;
|
||||
the unchanged Guard then selects a separate fresh runtime profile.
|
||||
"""
|
||||
import argparse, hashlib, importlib.util, json, os, re, shutil, subprocess, sys, time, uuid
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
sys.dont_write_bytecode = True
|
||||
HERE = Path(__file__).resolve().parent
|
||||
SUPPORT = HERE / 'regression'
|
||||
MIN_SPACE = 300 * 1024 * 1024
|
||||
|
||||
def module(name, path):
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
value = importlib.util.module_from_spec(spec); spec.loader.exec_module(value); return value
|
||||
def sha(path): return hashlib.sha256(Path(path).read_bytes()).hexdigest()
|
||||
def read(path): return json.loads(Path(path).read_bytes())
|
||||
def require(ok, reason):
|
||||
if not ok: raise AssertionError(reason)
|
||||
def write(path, value):
|
||||
with Path(path).open('x', encoding='utf-8') as stream:
|
||||
stream.write(json.dumps(value, ensure_ascii=False, indent=2) + '\n')
|
||||
def now(): return datetime.now(timezone.utc).isoformat()
|
||||
def roster(root):
|
||||
return ['tests/run_tests.gd'] + sorted(str(p.relative_to(root)) for p in (root/'tests').rglob('test*.gd')
|
||||
if 'export' not in p.relative_to(root).parts and str(p.relative_to(root)) != 'tests/s0/test_kernel_and_save.gd')
|
||||
def inventory(base, stage=False):
|
||||
base = Path(base); result = {}
|
||||
if not base.exists(): return result
|
||||
require(base.is_dir() and not base.is_symlink(), 'ordinary inventory directory')
|
||||
for p in sorted(base.rglob('*')):
|
||||
rel = p.relative_to(base)
|
||||
if stage and '.godot' in rel.parts: continue
|
||||
require(not p.is_symlink(), 'symlink is not an ordinary source/proof/profile')
|
||||
if p.is_file(): result[rel.as_posix()] = {'bytes': p.stat().st_size, 'sha256': sha(p)}
|
||||
return result
|
||||
def source_refs(root):
|
||||
paths = [p for folder in ('autoload','scripts','scenes','data','tests','assets','tools')
|
||||
for p in (root/folder).rglob('*') if p.is_file() and p.name != '.DS_Store' and '__pycache__' not in p.parts]
|
||||
paths += [root/p for p in ('project.godot','export_presets.cfg','Makefile','AGENTS.md')]
|
||||
require(all(not p.is_symlink() for p in paths), 'source aliases refused')
|
||||
return {p.relative_to(root).as_posix(): {'path':str(p),'bytes':p.stat().st_size,'sha256':sha(p)} for p in sorted(paths)}
|
||||
def profile_path(name):
|
||||
require(re.fullmatch(r'TheTree-PCK-tests-[0-9a-f]{32}-[a-z0-9-]+', name) is not None, 'owned profile nonce')
|
||||
if sys.platform == 'darwin': return Path.home()/'Library/Application Support'/name
|
||||
if sys.platform.startswith('linux'): return Path(os.environ.get('XDG_DATA_HOME', str(Path.home()/'.local/share')))/name
|
||||
raise RuntimeError('profile platform requires a reviewed native runner; no Windows acceptance inference')
|
||||
def default_player(root):
|
||||
text = (root/'project.godot').read_text()
|
||||
require('config/name="The Tree"' in text and 'config/use_custom_user_dir=' not in text, 'canonical default profile source')
|
||||
if sys.platform == 'darwin': path = Path.home()/'Library/Application Support/Godot/app_userdata/The Tree'
|
||||
elif sys.platform.startswith('linux'): path = Path(os.environ.get('XDG_DATA_HOME', str(Path.home()/'.local/share')))/'godot/app_userdata/The Tree'
|
||||
else: raise RuntimeError('unreviewed default-profile platform')
|
||||
return {'path':str(path),'existed':path.exists(),'files':inventory(path),'logs_and_locks_included':True}
|
||||
def private_project(public_bytes, name):
|
||||
text = public_bytes.decode('utf-8')
|
||||
require(text.count('[application]\n\n') == 1 and 'config/use_custom_user_dir=' not in text
|
||||
and 'config/custom_user_dir_name=' not in text, 'canonical project has no private execution settings')
|
||||
addition = 'config/use_custom_user_dir=true\nconfig/custom_user_dir_name=' + json.dumps(name) + '\n'
|
||||
altered = text.replace('[application]\n\n', '[application]\n\n' + addition, 1).encode()
|
||||
require(altered.decode().replace(addition, '', 1).encode() == public_bytes, 'two private fields reverse to whole public bytes')
|
||||
return altered
|
||||
def fresh_environment(base): return {k:v for k,v in base.items() if not k.startswith('THE_TREE_')}
|
||||
def phase_policy(test, source, policies):
|
||||
value = policies.get(test, {'ordinary_cleanup_prepared':False,'ordinary_control_labels':[],
|
||||
'old_bounded_teardown':False,'new_audio_QA':False})
|
||||
if test in policies: require(value['source_sha256'] == sha(source), 'suite proof/IO policy source SHA changed')
|
||||
return dict(value, path=test, source_sha256=sha(source), candidate_source_sha256=sha(source))
|
||||
def dependency_paths(test, refs):
|
||||
"""Reviewed literal GDScript dependencies, including relative inherited QA."""
|
||||
pending=[test];seen=set()
|
||||
while pending:
|
||||
name=pending.pop()
|
||||
if name in seen:continue
|
||||
seen.add(name)
|
||||
text=Path(refs[name]['path']).read_text()
|
||||
for quoted in re.findall(r'[\"\']([^\"\']+\.gd)[\"\']',text):
|
||||
target=quoted[6:] if quoted.startswith('res://') else str(Path(name).parent/quoted)
|
||||
if target in refs and target not in seen:pending.append(target)
|
||||
return seen
|
||||
def policy_coverage(paths, refs, policy):
|
||||
for test in paths:
|
||||
dependencies=dependency_paths(test,refs);p=phase_policy(test,Path(refs[test]['path']),policy['suite_policies'])
|
||||
if 'tests/helpers/ui_audio_fixture_cleanup.gd' in dependencies:
|
||||
require(p['ordinary_cleanup_prepared'] and p['ordinary_control_labels'], 'unknown ordinary helper user requires exact reviewed policy '+test)
|
||||
if 'tests/helpers/ui_audio_teardown.gd' in dependencies:
|
||||
require(p['ordinary_cleanup_prepared'] or p['old_bounded_teardown'] or test=='tests/ui/test_ui_audio_feedback.gd', 'unknown bounded teardown user requires reviewed proof policy '+test)
|
||||
def copy_source(source,target):
|
||||
if sys.platform=='darwin':subprocess.run(['/bin/cp','-c',str(source),str(target)],check=True)
|
||||
else:shutil.copyfile(source,target)
|
||||
require(target.stat().st_ino!=Path(source).stat().st_ino or target.stat().st_dev!=Path(source).stat().st_dev,
|
||||
'private source is a separate inode; hardlinks refused')
|
||||
def profile_gate(path, report, name):
|
||||
value = read(report)
|
||||
require(value['verified'] is True and value['conditions'] == [True]*5 and value['conditions_checked'] == 5
|
||||
and value['fresh_before_parent_initialize'] is True and value['profile_writes_before_guard'] == 0
|
||||
and value['actual_user_data_dir'] == str(path) == value['expected_user_data_dir']
|
||||
and value['globalized_probe'] == str(path/'guard-probe') and value['custom_user_dir_name'] == name
|
||||
and value['project_settings_persisted'] is False, 'all five unchanged runtime Guard conditions')
|
||||
return {'report':value,'report_sha256':sha(report),'whole_files':inventory(path)}
|
||||
def process_gate(row, allowed):
|
||||
return (row.get('exit_code') == 0 and row.get('helper_exit_code') == 0 and row.get('timed_out') is False
|
||||
and row.get('error_lines') == allowed and row.get('owned_popen_ended') is True
|
||||
and row.get('old_helper_engine_ended') is True and row.get('start_receipt_written') is True
|
||||
and row.get('end_receipt_written') is True and row.get('lifecycle_error') is None
|
||||
and row.get('external_process_or_group_signals') == 0
|
||||
and row.get('adapter_owned_cleanup',{}).get('engine_ended') is True)
|
||||
def routed_report(directory, route, test, pid, raw, stage, source_sha):
|
||||
file = directory/route['filename']
|
||||
require(set(directory.iterdir()) == {file} and file.is_file() and not file.is_symlink() and file.stat().st_size>0,
|
||||
'exclusive fresh outside report file set')
|
||||
value = read(file); matches = [l[len(route['stdout_prefix']):] for l in raw.splitlines() if l.startswith(route['stdout_prefix'])]
|
||||
require(isinstance(value,dict) and value and len(matches)==1, 'whole report and unique actual stdout JSON')
|
||||
printed = json.loads(matches[0]); require(isinstance(printed,dict) and printed, 'nonempty printed report')
|
||||
require(value==printed if route['stdout_projection']=='full' else all(value.get(k)==v for k,v in printed.items()),
|
||||
'literal original report payload agreement')
|
||||
owner = route.get('inherited_source',test)
|
||||
require(sha(stage/test)==source_sha and sha(stage/owner)==route['report_owner_source_sha256'], 'actual report source provenance')
|
||||
return {'verified':True,'path':str(file),'bytes':file.stat().st_size,'sha256':sha(file),
|
||||
'actual_engine_pid':pid,'producer_test':test,'producer_source_sha256':source_sha,'report_owner_source':owner,
|
||||
'report_owner_source_sha256':sha(stage/owner),'payload_field_deletions':0,'whole_JSON':value}
|
||||
def declared_reports(stage, expected, previous, requested):
|
||||
actual = inventory(stage,stage=True)
|
||||
require(not set(requested)&(set(expected)|set(previous)), 'new reports cannot overwrite source/previous reports')
|
||||
require(set(actual)==set(expected)|set(previous)|set(requested), 'complete source/UID/generated report set')
|
||||
require({n:actual[n] for n in expected}==expected and {n:actual[n] for n in previous}==previous, 'all source and earlier report bytes exact')
|
||||
added = {n:actual[n] for n in requested}
|
||||
for name,pin in added.items():
|
||||
require(pin['bytes']>0, 'nonempty actual generated report')
|
||||
if name.endswith('.json'): read(stage/name)
|
||||
else: (stage/name).read_text()
|
||||
return added
|
||||
def totals(rows, paths):
|
||||
names=[r['test'] for r in rows]; missing=[r['test'] for r in rows if r.get('reported_checks') is None]
|
||||
remaining=[n for n in paths if n not in names]; available=sum(r.get('reported_checks') or 0 for r in rows)
|
||||
return {'actual_suites':len(rows),'missing_marker_paths':missing,'remaining_unexecuted_tests':remaining,
|
||||
'available_marker_checks':available,'actual_all_roster_checks':available if not missing and names==paths else None,
|
||||
'strict_accepted_checks':sum(r['reported_checks'] for r in rows if not r['failed'] and r.get('reported_checks') is not None)}
|
||||
|
||||
def execute_phase(engine, stage, out, phase, test, selected, expected, previous, policy, contracts, paths,
|
||||
public_project, protected_player, root, outer, markers, diagnostics, owners, audio):
|
||||
require(not outer.native.helper['live_engines'](), 'one owned native engine at a time')
|
||||
require(shutil.disk_usage(out).free>=MIN_SPACE, 'fresh phase disk admission')
|
||||
require(source_refs(root)==selected['root_before'] and default_player(root)==protected_player, 'entire current source/default profile unchanged before phase')
|
||||
require(inventory(stage,stage=True)==dict(expected,**previous), 'whole stage source/UID/report inventory before phase')
|
||||
env=fresh_environment(os.environ); startup_name='TheTree-PCK-tests-'+uuid.uuid4().hex+'-standard-startup-'+phase
|
||||
startup=profile_path(startup_name); require(not startup.exists(), 'fresh startup profile before native engine')
|
||||
write(out/(phase+'-startup-profile-before.json'), {'path':str(startup),'existed':False,'files':{},'before_native_spawn':True})
|
||||
private=private_project(public_project,startup_name); (stage/'project.godot').write_bytes(private)
|
||||
folder=out/phase; proof=None; evidence=None; runtime=None; runtime_report=None; script=None
|
||||
row={'phase':phase,'test':test,'passed':False,'failed':True,'validation_error':None,'profile_startup_name':startup_name,
|
||||
'private_project_sha256':hashlib.sha256(private).hexdigest(),'private_project_fields':2,'source_sha256':sha(stage/test) if test else None}
|
||||
try:
|
||||
if phase=='import': argv=[engine,'--headless','--path',str(stage),'--editor','--import','--quit','--verbose']
|
||||
else:
|
||||
name='TheTree-PCK-tests-'+uuid.uuid4().hex+'-standard-runtime-'+phase; runtime=profile_path(name)
|
||||
require(not runtime.exists(), 'fresh runtime profile before Guard')
|
||||
runtime_report=out/(phase+'-profile.json')
|
||||
env.update(THE_TREE_PACK_PROFILE_NAME=name,THE_TREE_PACK_PROFILE_EXPECTED=str(runtime),
|
||||
THE_TREE_PACK_PROFILE_REPORT=str(runtime_report),THE_TREE_FULL_PARSE_PATHS=str(out/'parse-paths.json'))
|
||||
if phase=='parse': script=out/'bootstrap/parse_full_dependencies.gd'
|
||||
else:
|
||||
script=out/'starters'/(phase+'.gd')
|
||||
script.write_text('extends '+json.dumps('res://'+test)+'\nconst Guard := preload('+json.dumps(str(out/'bootstrap/profile_guard.gd'))+')\nfunc _initialize() -> void:\n\tif not Guard.activate():\n\t\tquit(97)\n\t\treturn\n\tsuper._initialize()\n')
|
||||
p=phase_policy(test,stage/test,policy['suite_policies']); row['policy']=p
|
||||
route=policy['outside_routes'].get(test)
|
||||
if route:
|
||||
evidence=out/(phase+'-evidence'); evidence.mkdir(); env[route['env']]=str(evidence)
|
||||
if p['ordinary_cleanup_prepared'] or p['old_bounded_teardown'] or test=='tests/ui/test_ui_audio_feedback.gd':
|
||||
proof=out/(phase+'-teardown'); proof.mkdir()
|
||||
if p['ordinary_cleanup_prepared']:
|
||||
(proof/'owned-audio').mkdir(); env.update(THE_TREE_AUDIO_TEARDOWN_PROOF_DIR=str(proof/'owned-audio'),THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF=str(proof/'control.json'))
|
||||
else: env['THE_TREE_AUDIO_TEARDOWN_PROOF_DIR']=str(proof)
|
||||
if test=='tests/ui/test_ui_audio_feedback.gd':
|
||||
audio_dir=out/(phase+'-audio-proof'); audio_dir.mkdir()
|
||||
env.update(THE_TREE_AUDIO_PROOF_REPORT=str(audio_dir/'actual-ogg-decode-player-state.json'),
|
||||
THE_TREE_AUDIO_COMMAND_PROOF_REPORT=str(audio_dir/'actual-command-result-buffer-proof.json'))
|
||||
argv=[engine,'--headless','--path',str(stage),'--script',str(script),'--verbose']
|
||||
logfile=folder/'engine-native.log'; require(logfile.is_absolute() and not logfile.exists(), 'fresh absolute native log')
|
||||
argv+=['--log-file',str(logfile)]; row.update(command=argv,logical_script='res://'+test if test else None,
|
||||
starter_sha256=sha(script) if script else None,controlled_environment={k:v for k,v in env.items() if k.startswith('THE_TREE_')})
|
||||
result,capture=outer.run_phase(argv,folder,180 if phase=='import' else selected['timeout'],env,
|
||||
now_fn=now,dump_fn=write,sha_fn=sha,live_engines_fn=outer.native.helper['live_engines'])
|
||||
row.update(native_process=result,outer_actual_capture=capture,actual_pid=result.get('pid') if result else None,
|
||||
engine_ended=capture['all_captured_ended'],exit_code=result.get('exit_code') if result else None)
|
||||
stdout=(folder/'stdout.log').read_text(); stderr=(folder/'stderr.log').read_text(); raw=stdout+stderr
|
||||
raw_file=out/(test.replace('/','__')+'.log') if test else folder/'combined-raw.log'; raw_file.write_text(raw)
|
||||
row.update(log=str(raw_file.relative_to(out)),log_sha256=sha(raw_file),raw_native_log={'path':str(logfile),'bytes':logfile.stat().st_size,'sha256':sha(logfile)})
|
||||
if test:
|
||||
parsed=markers.parse_raw(test,raw,contracts,row['source_sha256']); row.update(completion=parsed,
|
||||
reported_checks=parsed['checks'],reported_failures=parsed['failures'],completion_marker=parsed['marker'],collector_errors=parsed['errors'])
|
||||
review=diagnostics.review_streams(outer.native,{'stdout':stdout,'stderr':stderr,'native_file':logfile.read_text()},test,stage/test if test else None)
|
||||
row['finite_original_diagnostic_review']=review
|
||||
require(result and diagnostics.diagnostic_result_gate(result,review) and process_gate(result,review['allowed_e31_error_lines']) and capture['passed'], 'strict native/ownership/logger/finite diagnostics')
|
||||
if script: require(sha(script)==row['starter_sha256'], 'actual starter source remains exact')
|
||||
if runtime: row['actual_private_profile']=profile_gate(runtime,runtime_report,name)
|
||||
if phase=='parse':
|
||||
matches=re.findall(r'(?m)^FULL_DEPENDENCY_PARSE checks=([0-9]+) failures=([0-9]+)\n',raw)
|
||||
require(matches==[(str(len(paths)),'0')], 'unique actual all normal-context dependencies parsed')
|
||||
row['actual_parse_checks']=int(matches[0][0])
|
||||
if test:
|
||||
require(parsed['passed'] and sha(stage/test)==row['source_sha256'], 'exact original suite source/marker schema')
|
||||
if evidence: row['outside_report']=routed_report(evidence,route,test,row['actual_pid'],raw,stage,row['source_sha256'])
|
||||
if p['ordinary_cleanup_prepared']: row['ordinary_owner_pairs']=owners.ordinary_gate(proof,row['actual_pid'],out,p['ordinary_control_labels'])
|
||||
if p['old_bounded_teardown'] or test=='tests/ui/test_ui_audio_feedback.gd': row['old_bounded_proof']=audio.teardown_gate(proof,row['actual_pid'],out)
|
||||
if test=='tests/ui/test_ui_audio_feedback.gd':
|
||||
row['actual_command_evidence']=audio.command_gate(audio_dir/'actual-command-result-buffer-proof.json',audio_dir,row['actual_pid'])
|
||||
row['actual_ogg_evidence']=audio.ogg_gate(audio_dir/'actual-ogg-decode-player-state.json',row['actual_pid'],selected['map'])
|
||||
row['passed']=True; row['failed']=False
|
||||
except BaseException as caught: row['validation_error']=type(caught).__name__+': '+str(caught)
|
||||
finally:
|
||||
# run_phase owns cleanup before any receipts/guards. No discovered PID signals.
|
||||
(stage/'project.godot').write_bytes(public_project)
|
||||
row['whole_startup_profile_after']={'path':str(startup),'files':inventory(startup),'fresh_before_engine':True}
|
||||
if runtime is not None: row['whole_runtime_profile_after']={'path':str(runtime),'files':inventory(runtime)}
|
||||
try:
|
||||
requested=policy['fixed_generated_report_routes'].get(test,[]) if test else []
|
||||
generated=declared_reports(stage,expected,previous,requested); previous.update(generated)
|
||||
for name in generated:
|
||||
if name.endswith('-comparison.json'):
|
||||
value=read(stage/name)
|
||||
require(type(value.get('checks')) is int and value['checks']==row['reported_checks'] and value.get('failures')==0,
|
||||
'actual generated JSON report/marker agreement')
|
||||
row['generated_reports']={n:dict(pin,actual_engine_pid=row.get('actual_pid'),producer_test=test,
|
||||
producer_source_sha256=row['source_sha256'],payload_modified=False)for n,pin in generated.items()}
|
||||
row['source_sha256_end']=sha(stage/test) if test else None
|
||||
row['default_player_entire_profile_unchanged']=default_player(root)==protected_player
|
||||
require(row['default_player_entire_profile_unchanged'] and source_refs(root)==selected['root_before'], 'entire protected source/default player including logs/locks unchanged')
|
||||
except BaseException as caught:
|
||||
row['passed']=False;row['failed']=True;row['guard_error']=type(caught).__name__+': '+str(caught)
|
||||
write(out/(phase+'-receipt.json'),row)
|
||||
return row
|
||||
|
||||
def main(argv=None):
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--project-root',type=Path,default=HERE.parent); parser.add_argument('--output',type=Path)
|
||||
parser.add_argument('--godot',default='godot');parser.add_argument('--timeout',type=int,default=1200)
|
||||
parser.add_argument('--marker-contracts',type=Path);parser.add_argument('--source-input-refs',type=Path)
|
||||
parser.add_argument('--prepare-only',action='store_true');args=parser.parse_args(argv)
|
||||
root=args.project_root.resolve();out=(args.output or root/'artifacts'/('all-tests-'+uuid.uuid4().hex)).resolve();require(args.timeout>0,'positive timeout')
|
||||
root_before=source_refs(root); refs=read(args.source_input_refs) if args.source_input_refs else root_before
|
||||
require(set(refs)>=set(root_before), 'prospective source must retain every canonical source key')
|
||||
for n,pin in refs.items():
|
||||
path=Path(pin['path']);require(not path.is_symlink() and path.is_file() and path.stat().st_size==pin['bytes'] and sha(path)==pin['sha256'], 'exact selected source input '+n)
|
||||
require(refs['tools/run_all_tests.py']['sha256']==sha(Path(__file__)), 'actual public runner selected source exact')
|
||||
for file in SUPPORT.iterdir():
|
||||
if file.is_file(): require(refs['tools/regression/'+file.name]['sha256']==sha(file), 'actual support selected source exact '+file.name)
|
||||
paths=['tests/run_tests.gd']+sorted(n for n in refs if n.startswith('tests/') and n.endswith('.gd') and Path(n).name.startswith('test') and 'export'not in Path(n).parts and n!='tests/s0/test_kernel_and_save.gd')
|
||||
markers=module('standard_exact_markers',HERE/'strict_test_markers.py');contract_path=(args.marker_contracts or root/'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json').resolve()
|
||||
contracts=markers.load_contracts(contract_path);require(len(set(paths))==len(paths) and all(n in contracts for n in paths),'unique reviewed roster/schema')
|
||||
policy=read(SUPPORT/'suite-policy.json')
|
||||
for test in set(policy['suite_policies'])&set(paths): phase_policy(test,Path(refs[test]['path']),policy['suite_policies'])
|
||||
policy_coverage(paths,refs,policy)
|
||||
parse_paths=['res://'+n for n in sorted(refs) if n.endswith('.gd')]
|
||||
if args.prepare_only:
|
||||
print(json.dumps({'source_files':len(refs),'suites':len(paths),'parse_paths':len(parse_paths),'future_native_phases':len(paths)+2,'actual_checks':None,'engines':0,'stages':0}));return 0
|
||||
outer=module('standard_exact_owned_outer',SUPPORT/'owned_outer.py');require(not outer.native.helper['live_engines'](),'another Godot owns CPU')
|
||||
engine=shutil.which(args.godot) if not Path(args.godot).is_absolute() else args.godot;require(engine,'native launcher exists')
|
||||
engine=str(Path(engine).resolve());require(shutil.disk_usage(out.parent).free>=MIN_SPACE,'fresh run disk admission')
|
||||
out.mkdir(parents=True,exist_ok=False);stage=out/'stage';stage.mkdir();(out/'starters').mkdir()
|
||||
(out/'bootstrap').mkdir()
|
||||
for name,pin in read(SUPPORT/'bootstrap-scripts.json').items():
|
||||
data=pin['text'].encode('utf-8');require(hashlib.sha256(data).hexdigest()==pin['sha256'], 'unchanged external bootstrap bytes')
|
||||
(out/'bootstrap'/name).write_bytes(data)
|
||||
protected=default_player(root);expected={n:{'bytes':p['bytes'],'sha256':p['sha256']}for n,p in refs.items()}
|
||||
selected={'root_before':root_before,'map':{n:p['sha256']for n,p in refs.items()},'timeout':args.timeout}
|
||||
for n,pin in refs.items():
|
||||
target=stage/n;target.parent.mkdir(parents=True,exist_ok=True)
|
||||
copy_source(Path(pin['path']),target)
|
||||
require(inventory(stage,stage=True)==expected,'one complete private CoW source copy')
|
||||
public=(stage/'project.godot').read_bytes();write(out/'parse-paths.json',parse_paths)
|
||||
run_id=uuid.uuid4().hex;input_receipt={'protocol':'guarded-standard-v1','run_id':run_id,'owner_runner_pid':os.getpid(),
|
||||
'project_root':str(root),'stage':str(stage),'roster':paths,'selected_source_map':selected['map'],
|
||||
'marker_contract_sha256':sha(contract_path),'runner_sha256':sha(Path(__file__)),'marker_module_sha256':sha(HERE/'strict_test_markers.py'),
|
||||
'engine':engine,'engine_sha256':sha(engine),'default_player_before':protected,'performance_is_not_maximum_scene_acceptance':True}
|
||||
write(out/'runner-input.json',input_receipt);write(out/'source-start.json',root_before)
|
||||
phases=[];rows=[];previous={};error=None;cleanup=[];cleanup_errors=[]
|
||||
diagnostics=module('standard_finite_diagnostics',SUPPORT/'diagnostic_gate.py')
|
||||
owners=module('standard_ordinary_proof_gate',SUPPORT/'ordinary_proof_gate.py');audio=module('standard_audio_proof_gate',SUPPORT/'audio_evidence_gate.py')
|
||||
try:
|
||||
for phase,test in [('import',None),('parse',None)]+[(str(i).zfill(3),n)for i,n in enumerate(paths)]:
|
||||
row=execute_phase(engine,stage,out,phase,test,selected,expected,previous,policy,contracts,parse_paths,
|
||||
public,protected,root,outer,markers,diagnostics,owners,audio);phases.append(row)
|
||||
if test:
|
||||
row['sequence']=len(rows);row['godot']=engine;rows.append(row)
|
||||
(out/'all-tests.json').write_text(json.dumps(rows,ensure_ascii=False,indent=2)+'\n')
|
||||
print(('PASS ' if row['passed'] else 'FAIL ')+test,flush=True)
|
||||
require(row['passed'],'first strict failed phase stops without retry: '+phase)
|
||||
except BaseException as caught: error=type(caught).__name__+': '+str(caught)
|
||||
finally:
|
||||
# Sweep actual factory objects before all fragile final receipt/guard writes.
|
||||
cleanup,cleanup_errors=outer.finish_captured(outer.OWNED)
|
||||
context=totals(rows,paths);guard_errors=[]
|
||||
try:
|
||||
require(source_refs(root)==root_before,'full canonical source unchanged at end')
|
||||
require(default_player(root)==protected,'full default player unchanged at end')
|
||||
require(inventory(stage,stage=True)==dict(expected,**previous),'whole stage/UID/report set at end')
|
||||
except BaseException as caught:guard_errors.append(type(caught).__name__+': '+str(caught))
|
||||
ended=bool(outer.OWNED) and all(r['engine_ended']is True for r in cleanup)
|
||||
passed=error is None and not cleanup_errors and not guard_errors and ended and len(phases)==len(paths)+2 and all(r['passed']for r in phases)
|
||||
write(out/'runner-ended.json',dict(context,protocol='guarded-standard-v1',run_id=run_id,owner_runner_pid=os.getpid(),
|
||||
passed=passed,engine_ended=ended,failed_suites=sum(r['failed']for r in rows),actual_captured_PIDs=[p.pid for p in outer.OWNED],
|
||||
final_owned_cleanup=cleanup,cleanup_errors=cleanup_errors,guard_errors=guard_errors,error=error,
|
||||
all_tests_sha256=sha(out/'all-tests.json') if (out/'all-tests.json').exists() else None,phases=phases,
|
||||
default_player_after=default_player(root),formal_acceptance=False,native_Windows='pending'))
|
||||
print(json.dumps(dict(context,passed=passed,error=error,cleanup_errors=cleanup_errors,guard_errors=guard_errors)),flush=True)
|
||||
return 0 if passed else 1
|
||||
if __name__=='__main__':raise SystemExit(main())
|
||||
+362
@@ -0,0 +1,362 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Root-only native collection. Does not run regression or claim acceptance."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
import re
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
HERE = Path(__file__).resolve().parent
|
||||
CONTRACT = 'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'
|
||||
CONDITIONS = ('room_occupancy_and_operation', 'queues_and_overflow',
|
||||
'elevator_state_and_passengers', 'staff_state_and_jobs',
|
||||
'supplies_and_carried_goods', 'same_demand_route_improvement',
|
||||
'normal_os_and_distinct_pid_resume')
|
||||
OS_CHILD_TIMEOUT_SECONDS = 3600
|
||||
RECORDER = 'tests/fixtures/p23-03/passive_os_recorder.gd'
|
||||
|
||||
def collect_screenshots(out, pair, role):
|
||||
"""Bind every external CUA screenshot to its request and decoded PNG.
|
||||
|
||||
The external receipt supplies screenshots[{path,raw_sha256,tool_call_id}].
|
||||
Paths are relative to the evidence root; raw receipt bytes remain unchanged.
|
||||
"""
|
||||
checker = module('p23_screenshot_binding', HERE/'check_p23_life_observation_evidence.py')
|
||||
bindings = []
|
||||
requests = json.loads((pair/(role+'-requests.json')).read_text())['requests']
|
||||
for ack_name in requests:
|
||||
ack_path = out/ack_name
|
||||
checker.require(ack_path.resolve().is_relative_to(out.resolve()), 'ACK path escape')
|
||||
ack = json.loads(ack_path.read_text())
|
||||
request_path = ack_path.with_name('request.json')
|
||||
request = json.loads(request_path.read_text())
|
||||
receipt_path = out/ack['input_receipt']
|
||||
checker.require(receipt_path.resolve().is_relative_to(out.resolve()), 'CUA receipt path escape')
|
||||
cua = json.loads(receipt_path.read_text())
|
||||
checker.require(ack['request_sha256'] == checker.sha(request_path), 'CUA request hash')
|
||||
checker.require(cua['screenshots'], 'CUA screenshots missing')
|
||||
for number, shot in enumerate(cua['screenshots']):
|
||||
raw = out/shot['path']
|
||||
checker.require(raw.resolve().is_relative_to(out.resolve()) and not raw.is_symlink(), 'screenshot path escape')
|
||||
checker.require(checker.sha(raw) == shot['raw_sha256'] and shot['tool_call_id'], 'raw screenshot CUA binding')
|
||||
kind, _, _ = checker.image_kind(raw.read_bytes())
|
||||
conversion = None
|
||||
if kind == 'jpeg':
|
||||
png = ack_path.with_name('decoded-%02d.png' % number)
|
||||
receipt = ack_path.with_name('conversion-%02d.json' % number)
|
||||
convert_screenshot(raw.resolve(), png.resolve(), shot, receipt.resolve())
|
||||
conversion = str(receipt.relative_to(out))
|
||||
else:
|
||||
png = raw
|
||||
width, height, _ = checker.png_pixels(png.read_bytes())
|
||||
bindings.append(dict(request=str(request_path.relative_to(out)), request_sha256=checker.sha(request_path),
|
||||
sequence=request['sequence'], target_pid=request['target_pid'],
|
||||
input_receipt=ack['input_receipt'], input_receipt_sha256=checker.sha(receipt_path),
|
||||
screenshot_index=number, tool_call_id=shot['tool_call_id'],
|
||||
raw_path=shot['path'], raw_sha256=shot['raw_sha256'], conversion=conversion,
|
||||
png_path=str(png.relative_to(out)), png_sha256=checker.sha(png), width=width, height=height))
|
||||
checker.require(bindings, 'empty screenshot collection')
|
||||
destination = pair/(role+'-screenshots.json')
|
||||
with destination.open('x') as output:
|
||||
json.dump(bindings, output, indent=2)
|
||||
output.write('\n')
|
||||
return str(destination.relative_to(out))
|
||||
|
||||
def convert_screenshot(raw_path, png_path, cua_receipt, receipt_path):
|
||||
"""Root-only conversion; raw CUA bytes are never renamed or rewritten."""
|
||||
checker = module('p23_conversion_checker', HERE/'check_p23_life_observation_evidence.py')
|
||||
raw, png, receipt = map(Path, (raw_path, png_path, receipt_path))
|
||||
checker.require(raw.is_absolute() and png.is_absolute() and receipt.is_absolute(),
|
||||
'absolute conversion paths required')
|
||||
checker.require(raw.is_file() and not raw.is_symlink() and not png.exists()
|
||||
and not receipt.exists() and raw.resolve() != png.resolve(), 'fresh separate conversion output')
|
||||
raw_hash = checker.sha(raw)
|
||||
checker.require(raw_hash == cua_receipt['raw_sha256'] and cua_receipt['tool_call_id'],
|
||||
'CUA conversion input hash/call mismatch')
|
||||
kind, width, height = checker.image_kind(raw.read_bytes())
|
||||
checker.require(kind == 'jpeg', 'conversion requires JPEG input')
|
||||
converter = '/usr/bin/sips'
|
||||
converter_hash = checker.sha(converter)
|
||||
argv = [converter, '-s', 'format', 'png', str(raw), '--out', str(png)]
|
||||
process = subprocess.run(argv, capture_output=True, timeout=900, check=False)
|
||||
rec = dict(raw_path=str(raw), raw_sha256=raw_hash, raw_kind=kind,
|
||||
tool_call_id=cua_receipt['tool_call_id'], converter=converter,
|
||||
converter_sha256=converter_hash, argv=argv, exit_code=process.returncode,
|
||||
stdout_sha256=hashlib.sha256(process.stdout).hexdigest(),
|
||||
stderr_sha256=hashlib.sha256(process.stderr).hexdigest(),
|
||||
png_path=str(png), png_sha256=checker.sha(png) if png.is_file() else None,
|
||||
width=width, height=height)
|
||||
# Preserve failure receipts too. These logs allow independent hash checking.
|
||||
with receipt.open('x') as output:
|
||||
json.dump(rec, output, indent=2)
|
||||
output.write('\n')
|
||||
with Path(str(receipt) + '.stdout').open('xb') as output:
|
||||
output.write(process.stdout)
|
||||
with Path(str(receipt) + '.stderr').open('xb') as output:
|
||||
output.write(process.stderr)
|
||||
checker.require(checker.sha(raw) == raw_hash, 'raw CUA bytes changed during conversion')
|
||||
checker.require(checker.sha(converter) == converter_hash, 'converter changed during conversion')
|
||||
checker.inspect_conversion(rec, cua_receipt, converter_hash)
|
||||
return rec
|
||||
|
||||
def collect_os(r, root, out, stage, engine, commit, refs, protected, outer):
|
||||
"""Adapted P08-03 collect_os protocol, retaining owned-process guards.
|
||||
|
||||
Root supplies CUA ack/receipt files in the requested directories. Neither
|
||||
controller nor passive endpoints generate input or change permissions.
|
||||
"""
|
||||
r.require(not outer.native.helper['live_engines'](), 'external engine present')
|
||||
checker = module('p23_os_pins', HERE/'check_p23_life_observation_evidence.py')
|
||||
before = r.inventory(stage, stage=True)
|
||||
public = (stage/'project.godot').read_bytes()
|
||||
(out/'os-pair').mkdir()
|
||||
phases = []
|
||||
for label in ('A-writer', 'A-reader', 'B-writer', 'B-reader'):
|
||||
layout, role = label.split('-')
|
||||
pair = out/'os-pair'/layout
|
||||
pair.mkdir(exist_ok=role == 'reader')
|
||||
r.require(not outer.native.helper['live_engines'](), 'external engine present')
|
||||
r.require(r.source_refs(root) == refs and r.default_player(root) == protected, 'OS before guards')
|
||||
r.require(r.inventory(stage, stage=True) == before, 'OS stage before guard')
|
||||
r.require(shutil.disk_usage(out).free >= 500*1024*1024, 'OS disk admission')
|
||||
folder = out/'os-runs'/label
|
||||
folder.mkdir(parents=True)
|
||||
name = 'TheTree-PCK-tests-'+uuid.uuid4().hex+'-p23-observation-'+label.lower()
|
||||
profile = r.profile_path(name)
|
||||
r.require(not profile.exists(), 'fresh OS private profile')
|
||||
formal_source = pair/'formal' if role == 'reader' else None
|
||||
formal_before = r.inventory(formal_source) if formal_source else {}
|
||||
if role == 'reader':
|
||||
r.require(set(formal_before) == {'world.bin','manifest.json','thumbnail.png','journal.log'}, 'all formal inputs')
|
||||
formal = profile/'saves/manual_ui'
|
||||
formal.mkdir(parents=True)
|
||||
for member, pin in formal_before.items():
|
||||
r.copy_source(formal_source/member, formal/member)
|
||||
r.require(r.sha(formal/member) == pin['sha256'], 'formal fixture copy SHA')
|
||||
recorder = folder/'passive_os.gd'
|
||||
r.copy_source(root/RECORDER, recorder)
|
||||
proof = folder/'teardown'
|
||||
(proof/'owned-audio').mkdir(parents=True)
|
||||
env = r.fresh_environment(dict(os.environ))
|
||||
env.update(P23_OBSERVATION_ROOT=str(pair), P23_OBSERVATION_ROLE=role, P23_LAYOUT=layout,
|
||||
THE_TREE_AUDIO_TEARDOWN_PROOF_DIR=str(proof/'owned-audio'),
|
||||
THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF=str(proof/'control.json'))
|
||||
command = [engine, '--path', str(stage), '--script', str(recorder)]
|
||||
base = {'protocol':'p23-observation-native-os-v1', 'role':role, 'layout':layout, 'commit':commit,
|
||||
'source_map':{n:v['sha256'] for n,v in refs.items()}, 'stage':str(stage),
|
||||
'stage_before':before, 'profile':str(profile), 'profile_name':name,
|
||||
'profile_before':{'existed':profile.exists(), 'files':r.inventory(profile) if profile.exists() else {}}, 'formal_input':formal_before,
|
||||
'formal_source':str(formal_source) if formal_source else None, 'owner_pid':os.getpid(),
|
||||
'default_before':protected, 'command':command, 'engine_sha256':r.sha(engine),
|
||||
'controller_sha256':r.sha(root/'tools/run_p23_life_observation.py'),
|
||||
'recorder_sha256':r.sha(recorder), 'formal_acceptance':False,
|
||||
'timeout_seconds':OS_CHILD_TIMEOUT_SECONDS,
|
||||
'inputs':checker.input_map(root), 'spec_sha256':checker.SPEC_SHA,
|
||||
'settings_sha256':hashlib.sha256(public).hexdigest(),
|
||||
'environment':{k:v for k,v in env.items() if k.startswith(('P23_', 'THE_TREE_'))},
|
||||
'environment_sha256':hashlib.sha256(json.dumps(env,sort_keys=True).encode()).hexdigest()}
|
||||
r.write(folder/'started.json', base)
|
||||
error = None; children = []; guards = []; exit_code = None; owner_proof = None
|
||||
try:
|
||||
(stage/'project.godot').write_bytes(r.private_project(public, name))
|
||||
with (folder/'engine-native.log').open('x') as log:
|
||||
process = subprocess.Popen(command, cwd=stage, env=env, stdout=log, stderr=subprocess.STDOUT)
|
||||
children.append(process)
|
||||
r.write(folder/'process-started.json', dict(base, actual_pid=process.pid,
|
||||
monotonic_ns=time.monotonic_ns(), state='waiting_for_root_cua_requests'))
|
||||
print(json.dumps({'actual_pid':process.pid, 'request_directory':str(pair),
|
||||
'state':'waiting_for_root_cua', 'role':role}), flush=True)
|
||||
exit_code = process.wait(timeout=base['timeout_seconds'])
|
||||
r.require(exit_code == 0, 'ordinary native OS exit0')
|
||||
raw = (folder/'engine-native.log').read_text()
|
||||
r.require('ERROR:' not in raw and 'SCRIPT ERROR:' not in raw, 'OS native diagnostics')
|
||||
matches = re.findall(r'(?m)^P23 passive OS observation: ([0-9]+) checks, 0 failures$', raw)
|
||||
r.require(len(matches) == 1 and int(matches[0]) > 0, 'passive observer completion')
|
||||
observed = r.read(pair/(role+'-profile.json'))
|
||||
r.require(observed['pid'] == process.pid and Path(observed['user_data_dir']).resolve() == profile.resolve()
|
||||
and observed['display'] != 'headless', 'actual OS private profile/display')
|
||||
collect_screenshots(out, pair, role)
|
||||
owners = r.module('p23_os_owner_gate', r.SUPPORT/'ordinary_proof_gate.py')
|
||||
owner_proof = owners.ordinary_gate(proof, process.pid, folder, ['single'])
|
||||
except BaseException as caught:
|
||||
error = type(caught).__name__+': '+str(caught)
|
||||
finally:
|
||||
try:
|
||||
cleanup, cleanup_errors = outer.finish_captured(children)
|
||||
finally:
|
||||
(stage/'project.godot').write_bytes(public)
|
||||
try:
|
||||
r.require(r.source_refs(root) == refs, 'OS source unchanged')
|
||||
r.require(r.inventory(stage, stage=True) == before, 'OS stage unchanged')
|
||||
r.require(r.default_player(root) == protected, 'OS default player unchanged')
|
||||
if formal_source:
|
||||
r.require(r.inventory(formal_source) == formal_before, 'formal input unchanged')
|
||||
r.require(r.sha(recorder) == base['recorder_sha256'], 'recorder unchanged')
|
||||
except BaseException as caught:
|
||||
guards.append(type(caught).__name__+': '+str(caught))
|
||||
passed = not (error or guards or cleanup_errors) and len(children) == 1 and exit_code == 0
|
||||
r.write(folder/'ended.json', dict(base, actual_pid=children[0].pid if children else None,
|
||||
exit_code=exit_code, engine_ended=bool(cleanup) and all(v['engine_ended'] for v in cleanup),
|
||||
error=error, guard_errors=guards, cleanup_errors=cleanup_errors, owned_cleanup=cleanup,
|
||||
ordinary_owner_proof=owner_proof, stage_after=r.inventory(stage,stage=True),
|
||||
engine_sha256_after=r.sha(engine), inputs_after=checker.input_map(root),
|
||||
settings_sha256_after=hashlib.sha256((stage/'project.godot').read_bytes()).hexdigest(),
|
||||
environment_after={k:v for k,v in env.items() if k.startswith(('P23_', 'THE_TREE_'))},
|
||||
environment_sha256_after=hashlib.sha256(json.dumps(env,sort_keys=True).encode()).hexdigest(),
|
||||
default_after=r.default_player(root), source_after=r.source_refs(root),
|
||||
profile_after=r.inventory(profile), passed=passed))
|
||||
phases.append('os-runs/'+label+'/ended.json')
|
||||
r.require(passed, 'native OS collection failed: '+str(error or guards or cleanup_errors))
|
||||
return phases
|
||||
|
||||
def module(name, path):
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
obj = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(obj)
|
||||
return obj
|
||||
|
||||
def absolute(value):
|
||||
path = Path(value)
|
||||
if not path.is_absolute():
|
||||
raise argparse.ArgumentTypeError('absolute path required')
|
||||
return path.resolve()
|
||||
|
||||
def collect(args):
|
||||
root, out = args.project_root, args.output
|
||||
if out.is_relative_to(root):
|
||||
raise ValueError('evidence output must be outside the frozen source checkout')
|
||||
r = module('p23_standard_runner', root/'tools/run_all_tests.py')
|
||||
commit = subprocess.check_output(['git', '-C', str(root), 'rev-parse', 'HEAD'], text=True).strip()
|
||||
r.require(commit == args.commit, 'actual tested commit Q required')
|
||||
r.require(not subprocess.check_output(['git','-C',str(root),'status','--porcelain'], text=True), 'frozen clean worktree required')
|
||||
r.require(not out.exists(), 'fresh output; never overwrite earlier proof')
|
||||
refs = r.source_refs(root)
|
||||
checker = module('p23_initial_inputs', root/'tools/check_p23_life_observation_evidence.py')
|
||||
inputs_before = checker.input_map(root)
|
||||
root_roles = checker.strict_json(args.root_composition.read_bytes())
|
||||
composition = checker.verify_composition(root, root_roles,
|
||||
{name: pin['sha256'] for name, pin in refs.items()}, inputs_before)
|
||||
outer = r.module('p23_owned_outer', r.SUPPORT/'owned_outer.py')
|
||||
r.require(not outer.native.helper['live_engines'](), 'one native engine')
|
||||
engine = shutil.which(args.godot)
|
||||
r.require(engine is not None, 'native engine exists')
|
||||
engine = str(Path(engine).resolve())
|
||||
out.mkdir(parents=True)
|
||||
stage = out/'stage'; stage.mkdir()
|
||||
(out/'starters').mkdir(); (out/'bootstrap').mkdir()
|
||||
for name, pin in r.read(r.SUPPORT/'bootstrap-scripts.json').items():
|
||||
data = pin['text'].encode()
|
||||
r.require(hashlib.sha256(data).hexdigest() == pin['sha256'], 'bootstrap pin')
|
||||
(out/'bootstrap'/name).write_bytes(data)
|
||||
for name, pin in refs.items():
|
||||
target = stage/name; target.parent.mkdir(parents=True, exist_ok=True)
|
||||
r.copy_source(Path(pin['path']), target)
|
||||
r.require(r.sha(target) == pin['sha256'], 'whole copied source '+name)
|
||||
expected = {n: {'bytes':v['bytes'], 'sha256':v['sha256']} for n,v in refs.items()}
|
||||
selected = {'root_before':refs, 'map':{n:v['sha256'] for n,v in refs.items()}, 'timeout':180}
|
||||
r.require(r.inventory(stage, stage=True) == expected, 'complete private source')
|
||||
protected = r.default_player(root); public = (stage/'project.godot').read_bytes()
|
||||
paths = ['res://'+n for n in sorted(refs) if n.endswith('.gd')]
|
||||
r.write(out/'parse-paths.json', paths)
|
||||
markers = r.module('p23_strict_markers', root/'tools/strict_test_markers.py')
|
||||
contracts = markers.load_contracts(root/CONTRACT)
|
||||
policy = r.read(r.SUPPORT/'suite-policy.json')
|
||||
diagnostics = r.module('p23_diagnostics', r.SUPPORT/'diagnostic_gate.py')
|
||||
owners = r.module('p23_owners', r.SUPPORT/'ordinary_proof_gate.py')
|
||||
audio = r.module('p23_audio', r.SUPPORT/'audio_evidence_gate.py')
|
||||
r.write(out/'runner-input.json', {'protocol':'p23-normal-observation-v1', 'commit':commit,
|
||||
'selected_source_map':selected['map'], 'engine':engine, 'engine_sha256':r.sha(engine),
|
||||
'owner_pid':os.getpid(), 'default_player':protected, 'diagnostic_seed':806042,
|
||||
'inputs':inputs_before, 'provenance':checker.input_provenance(root),
|
||||
'pixel_decoder':{'interpreter':sys.executable,
|
||||
'PIL_available':importlib.util.find_spec('PIL') is not None,
|
||||
'raw_screenshots':'preserve bytes; Root lossless conversion required for JPEG without PIL'}})
|
||||
phases = []; previous = {}; cases = []; error = None; os_proof = None
|
||||
deadline = time.monotonic()+900
|
||||
saved_env = {k:os.environ.get(k) for k in ('P23_LAYOUT','P23_OUTPUT')}
|
||||
def phase(label, test):
|
||||
remaining = int(deadline-time.monotonic())
|
||||
r.require(remaining >= (180 if label == 'import' else 1), '900s collection deadline')
|
||||
selected['timeout'] = min(180, remaining)
|
||||
phase_out = out/'runs'/label
|
||||
phase_out.mkdir(parents=True)
|
||||
(phase_out/'starters').mkdir(); (phase_out/'bootstrap').mkdir()
|
||||
for original in (out/'bootstrap').iterdir():
|
||||
r.copy_source(original,phase_out/'bootstrap'/original.name)
|
||||
r.require(r.sha(original)==r.sha(phase_out/'bootstrap'/original.name),'bootstrap full copy')
|
||||
r.write(phase_out/'parse-paths.json',paths)
|
||||
row = r.execute_phase(engine, stage, phase_out, label, test, selected, expected, previous,
|
||||
policy, contracts, paths, public, protected, root, outer, markers, diagnostics, owners, audio)
|
||||
# Supplement the existing runner receipt; preserve it verbatim.
|
||||
r.write(phase_out/'p23-inputs.json', dict(source_map=selected['map'], source_after=r.source_refs(root),
|
||||
engine_sha256=r.sha(engine), inputs=inputs_before, inputs_after=checker.input_map(root),
|
||||
spec_sha256=checker.SPEC_SHA, settings_sha256=hashlib.sha256(public).hexdigest(),
|
||||
stage_before=expected, stage_after=r.inventory(stage,stage=True),
|
||||
default_before=protected, default_after=r.default_player(root),
|
||||
receipt_sha256=r.sha(phase_out/(label+'-receipt.json'))))
|
||||
phases.append('runs/'+label+'/'+label+'-receipt.json')
|
||||
r.require(not row['failed'], 'strict phase failed: '+label)
|
||||
try:
|
||||
phase('import', None); phase('parse', None)
|
||||
for layout in ('A', 'B'):
|
||||
directory = out/('layout-'+layout)
|
||||
os.environ.update(P23_LAYOUT=layout, P23_OUTPUT=str(directory))
|
||||
phase('layout-'+layout.lower(), 'tests/ui/test_p23_life_observation.gd')
|
||||
cases.append({'directory':directory.name, 'phase':phases[-1], 'files':r.inventory(directory)})
|
||||
for layout in ('A', 'B'):
|
||||
checker.inspect_stream(out/('layout-'+layout), root)
|
||||
if args.input_mode == 'native_os':
|
||||
os_phases = collect_os(r, root, out, stage, engine, commit, refs, protected, outer)
|
||||
checker = module('p23_os_input_map', root/'tools/check_p23_life_observation_evidence.py')
|
||||
os_proof = 'os-proof.json'
|
||||
r.write(out/os_proof, {'source_map':selected['map'], 'inputs':checker.input_map(root),
|
||||
'input_method':'native_os', 'observer_mutations':[], 'phases':os_phases, 'directory':'os-pair'})
|
||||
except BaseException as caught:
|
||||
error = type(caught).__name__+': '+str(caught)
|
||||
finally:
|
||||
cleanup, cleanup_errors = outer.finish_captured(outer.OWNED)
|
||||
for key,value in saved_env.items():
|
||||
if value is None: os.environ.pop(key, None)
|
||||
else: os.environ[key] = value
|
||||
if r.source_refs(root) != refs or r.default_player(root) != protected:
|
||||
error = (error+'; ' if error else '')+'protected root/profile changed'
|
||||
if checker.input_map(root) != inputs_before:
|
||||
error = (error+'; ' if error else '')+'spec/fixture/controller inputs changed'
|
||||
r.write(out/'runner-ended.json', {'error':error, 'cleanup':cleanup, 'cleanup_errors':cleanup_errors,
|
||||
'phases':phases, 'formal_acceptance':False, 'native_Windows':'pending'})
|
||||
checker = module('p23_observation_checker', root/'tools/check_p23_life_observation_evidence.py')
|
||||
r.write(out/'index.json', {'schema':'p23-life-observation-v2', 'commit':commit,
|
||||
'composition':composition,
|
||||
'source_map':selected['map'], 'input_map':inputs_before,
|
||||
'provenance':checker.input_provenance(root),
|
||||
'marker_contract_sha256':r.sha(root/CONTRACT),
|
||||
'spec_sha256':hashlib.sha256((root/'docs/spec/acceptance/P23-03.json').read_text().strip().encode()).hexdigest(),
|
||||
'cases':cases, 'phases':phases, 'conditions':list(CONDITIONS),
|
||||
'artifacts':{str(p.relative_to(out)):r.sha(p)
|
||||
for p in out.rglob('*') if p.is_file() and 'stage' not in p.relative_to(out).parts},
|
||||
'os_proof':os_proof, 'regression':None,
|
||||
'acceptance':'pending', 'collection_error':error})
|
||||
return 1 if error or cleanup_errors else 0
|
||||
|
||||
def main(argv=None):
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--project-root', type=absolute, required=True)
|
||||
parser.add_argument('--output', type=absolute, required=True)
|
||||
parser.add_argument('--commit', required=True)
|
||||
parser.add_argument('--root-composition', type=absolute, required=True,
|
||||
help='Root external S/M/T/Q and complete tested-tree blob bindings')
|
||||
parser.add_argument('--godot', default='godot')
|
||||
parser.add_argument('--input-mode', choices=('handler', 'native_os'), default='handler')
|
||||
parser.add_argument('--collect', action='store_true', required=True)
|
||||
return collect(parser.parse_args(argv))
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"scope": "Prospective actual Git composition, not a normal integration candidate or runtime evidence",
|
||||
"S": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08",
|
||||
"M": "54cade4181f6c3c4f5701ba54ac5fcbeca695945",
|
||||
"Q": "60eadb8bc839bfcb46bff41949db9c59611e3e6f",
|
||||
"T": "5dfac310b6be88b9dc4224e4b8c4b16f585d8b58",
|
||||
"parents": [
|
||||
"54cade4181f6c3c4f5701ba54ac5fcbeca695945",
|
||||
"78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
],
|
||||
"worktree": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-root-composed-78f7cba-r01",
|
||||
"conflict_paths": [
|
||||
"docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json",
|
||||
"scenes/main/main.gd",
|
||||
"scenes/main/world_preview.gd",
|
||||
"tools/regression/suite-policy.json"
|
||||
],
|
||||
"resolution": "Exact actual submitted S blobs in four already-reconciled paths, no Root source edits",
|
||||
"all8_accepted": false,
|
||||
"normal_integration_candidate": false,
|
||||
"formally_closed_units": 14
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"path": "result.json",
|
||||
"sha256": "afec8969aa1a0a2338504566092493313c04c9eabea25412411de60f5e657a3f",
|
||||
"bytes": 9867,
|
||||
"actual_source": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p24-02-operations/runs/f725571e5b46473ea04a90424a404bd5/result.json"
|
||||
},
|
||||
{
|
||||
"path": "stdout.log",
|
||||
"sha256": "73ce2f7b317c6ce9dc2e6d224e5108550e31bc6ea4c459aa9327e3374f8e199f",
|
||||
"bytes": 21102,
|
||||
"actual_source": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p24-02-operations/runs/f725571e5b46473ea04a90424a404bd5/stdout.log"
|
||||
},
|
||||
{
|
||||
"path": "stderr.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"bytes": 0,
|
||||
"actual_source": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p24-02-operations/runs/f725571e5b46473ea04a90424a404bd5/stderr.log"
|
||||
},
|
||||
{
|
||||
"path": "command.json",
|
||||
"sha256": "ceeb13991ce637b6d0cb4f1c2206c4b105934887b2bb82549d3aa5e98222944d",
|
||||
"bytes": 1846,
|
||||
"actual_source": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p24-02-operations/runs/f725571e5b46473ea04a90424a404bd5/command.json"
|
||||
},
|
||||
{
|
||||
"path": "packet.txt",
|
||||
"sha256": "bae2c7759d01ae8db80c923414a865bd81a8c5f668b8a0fb3a9857aa74a7d328",
|
||||
"bytes": 4230,
|
||||
"actual_source": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p24-02-operations/runs/f725571e5b46473ea04a90424a404bd5/packet.txt"
|
||||
},
|
||||
{
|
||||
"path": "sandbox.sb",
|
||||
"sha256": "82aaea232b1c988582f5695263444f00f5c9e39ce05e71496566d731112ae709",
|
||||
"bytes": 2022,
|
||||
"actual_source": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p24-02-operations/runs/f725571e5b46473ea04a90424a404bd5/sandbox.sb"
|
||||
},
|
||||
{
|
||||
"path": "ACTUAL_REPAIR5_PREPARED_COMPOSITION.json",
|
||||
"sha256": "8f168e7a693ad9c9fbcf579abdb7bb89fc47684d15bd6b502e008bcfa1fcda50",
|
||||
"bytes": 976,
|
||||
"actual_source": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/coordinator-resume-20261017-r02/ACTUAL_REPAIR5_PREPARED_COMPOSITION.json"
|
||||
},
|
||||
{
|
||||
"path": "ROOT_REPAIR5_LOCAL_PROOF_REAUDIT.json",
|
||||
"sha256": "80f0a8eea3ca917534a0304c031295d15de639e547fad3753394c8255f7e5e67",
|
||||
"bytes": 21349,
|
||||
"actual_source": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/coordinator-resume-20261017-r02/ROOT_REPAIR5_LOCAL_PROOF_REAUDIT.json"
|
||||
}
|
||||
]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
# Same-task continuation facts
|
||||
|
||||
S=78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08; M=54cade4181f6c3c4f5701ba54ac5fcbeca695945; Q=60eadb8bc839bfcb46bff41949db9c59611e3e6f; T=5dfac310b6be88b9dc4224e4b8c4b16f585d8b58. Source backup codex/p24-02-source-78f7cba pushed. Existing task no new registration/cap. All original8 unaccepted, formally14/88. No new native/OS/full; do not start them while correcting actual2medium findings. Current main remains54cade4.
|
||||
|
||||
Actual independent f725 findings are full result.json in this same directory; raw stdout/command/sandbox and Root source/local proof are here, not inaccessible coordinator paths. Root already checked actual process end. Existing GUI terminal quota remains preserved; continue same-task non-UI Runner.llm via actual recorded Opus run and model, original worker=agy registration unchanged. Root bridge owns ps/no competing/lease preflight. Worker never ps/search home. Task-local TMPPREFIX/PYTHONPYCACHEPREFIX already solved actual transport failure with unchanged sandbox.
|
||||
|
||||
Primary proof21+9 passed only in uncommitted phase at oldHEADbd3a134; do not call preservation comparison reproducible at currentS. Fix pinned pre-repair baseline and verify repeatability at actual submitted S and genuine Q after next normal submit, without rerunning full regression. Root can own true post-submit repeatability.
|
||||
|
||||
Non-OS facts must retain actual producer identity/process/lifecycle/time. Never generate OS timestamps/PID/session for Claude review, roster controller or integration to satisfy the checker. No real acceptance index exists; no false proof should be created. Give the normal validation stage and actual integration/final stage explicit applicability: normal validation before formal review/integration cannot require facts that can only exist after it; actual integration/final must still enforce every applicable original condition and genuine stage evidence. No acceptance/criterion waiver, no JSON boolean substitute, no partial credit. Bind coverage to the SAME validated full-roster rows and source hashes. Retain all OS/IME/save/Windows/runtime and raw-proof guards.
|
||||
|
||||
Only acceptance-required focused fixes; defer unrelated low cleanups. A valid-target positive control strengthens the defense behind-dialog test where needed, not a new interaction. Do not invent gameplay values or production triggers. Leave world_preview unchanged. No NEXT_CLOSURE/Main shared ledger or Root context edits. Complete source/local verification only; do not commit/push or run Godot/OS/full.
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
{
|
||||
"scope": "Root actual source/primary local-output re-audit; not native/OS/full/all8 acceptance",
|
||||
"source_before_normal_submit": "bd3a13405115fc9bf6c5acec55bcfef7dd15266a",
|
||||
"actual_run": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p24-02-operations/runs/150085055a4946bfa897ebfc15192b55",
|
||||
"actual_primary_command_event": {
|
||||
"type": "item.completed",
|
||||
"item": {
|
||||
"id": "item_30",
|
||||
"type": "command_execution",
|
||||
"command": "/bin/zsh -lc 'TMPPREFIX=\"$TMPDIR/p24-zsh\" python3 - <<'\"'PY'\nimport hashlib,json,os,subprocess,sys\nfrom pathlib import Path\nroot=Path.cwd(); here=root/'docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017'\nrepair4=here.parent/'repair4'\ncommands=[\n ('py_compile',[sys.executable,'-m','py_compile','tools/check_p24_operations_evidence.py',str(here/'composition.py'),str(here/'correspondence.py'),str(here/'test_repair5.py'),str(repair4/'check_repair4_preservation.py'),str(repair4/'test_checker_roster_head.py')]),\n ('import',[sys.executable,'-c',\\\"import importlib.util; s=importlib.util.spec_from_file_location('p24','tools/check_p24_operations_evidence.py'); m=importlib.util.module_from_spec(s); s.loader.exec_module(m); print('stdlib checker import OK; ROOT='+str(m.ROOT))\\\"]),\n ('repair5_tests',[sys.executable,str(here/'test_repair5.py')]),\n ('repair4_tests',[sys.executable,str(repair4/'test_checker_roster_head.py')]),\n ('preservation',[sys.executable,str(repair4/'check_repair4_preservation.py')]),\n ('missing_real_evidence',[sys.executable,'tools/check_p24_operations_evidence.py','--verify-only']),\n ('diff_check',['git','diff','--check'])]\nresults=[]\nfor name,argv in commands:\n p=subprocess.run(argv,capture_output=True,cwd=root,env=dict(os.environ,PYTHONPYCACHEPREFIX=os.environ['TMPDIR']+'/p24-phase-pyc'))\n log=p.stdout+b'\\\\n--- STDERR ---\\\\n'+p.stderr\n path=here/(name+'.log');path.write_bytes(log)\n results.append(dict(name=name,argv=argv,exit_code=p.returncode,expected_exit_code=1 if name=='missing_real_evidence' else 0,raw_log=path.relative_to(root).as_posix(),sha256=hashlib.sha256(log).hexdigest()))\n print(name, 'exit_code='+str(p.returncode), 'log_sha256='+results[-1]['sha256'],flush=True)\n(here/'LOCAL_COMMAND_RESULTS.json').write_text(json.dumps({'scope':'SOURCE-ONLY; stdlib/Git, TEST-ONLY synthetic fixtures; no acceptance','commands':results},indent=2)+'\\\\n')\nPY\"",
|
||||
"aggregated_output": "py_compile exit_code=0 log_sha256=169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb\nimport exit_code=0 log_sha256=4a2fe8c27abe4d9c077ca3701b07ee860d4673f93267e4ae4697638a1f2254c9\nrepair5_tests exit_code=0 log_sha256=48a4c44bd1f5f94faa0f78f14afea371f04d4e9652c89fc8dcad91a24e7cf836\nrepair4_tests exit_code=0 log_sha256=d3852846638752b6f8421776da825a037228ead8c67333c6b14e93a2fffb8f7a\npreservation exit_code=0 log_sha256=7e6691b7ae2ae94f956758a8907d3d67db29b9642ed0aecbfbc94421dcbdbace\nmissing_real_evidence exit_code=1 log_sha256=e1f4250f0078f0a88e8fd4ec485386ab67e835d0e966e609def115de00f4c48c\ndiff_check exit_code=0 log_sha256=169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb\n",
|
||||
"exit_code": 0,
|
||||
"status": "completed"
|
||||
}
|
||||
},
|
||||
"verified_file_bindings": [
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json",
|
||||
"bytes": 189076,
|
||||
"sha256": "d3599139e2358c1ac9edb5059a823880f72efe5ff457da2887114c243139f743",
|
||||
"git_blob_sha1": "932e8c4e8e6113aac8b629197d757a73a6f1260e"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py",
|
||||
"bytes": 22108,
|
||||
"sha256": "e7dc30bcd56dcdf3f057131bf5dc9a3a672e357bc9b8e5bf2b818d3302d4c83a",
|
||||
"git_blob_sha1": "a2259ee3ec1d0b981504e446c3fc6e213fde8f9f"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py",
|
||||
"bytes": 5689,
|
||||
"sha256": "5c10efe7a9c6b3d290020f8dfbb2431956b3dafff7abdd4859b8e6d83e1d9365",
|
||||
"git_blob_sha1": "f1a07ecf07b94f1508efa98a8606eeeaa61a7a46"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/LOCAL_COMMAND_RESULTS.json",
|
||||
"bytes": 4909,
|
||||
"sha256": "aacde68f9d6909c1c347197b257fa31a66d3e7519c01e16c79fd45aba6e8d82f",
|
||||
"git_blob_sha1": "8a5e25505d56f5f41e40ef426a69b54900689f92"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/PROTOCOL.md",
|
||||
"bytes": 6620,
|
||||
"sha256": "c07618fd692f911120e70ac13e3de4addf379aa8d29e535867ff93d9bd32e8f6",
|
||||
"git_blob_sha1": "9cf90f38f067c67f09b7540ae475f341f97fa7a9"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/REFERENCE_INTEGRITY.json",
|
||||
"bytes": 1695,
|
||||
"sha256": "be8549f3f6462757c7fb1bc664ccd6c5165f09e2eee4468aec75a8d84e4addf9",
|
||||
"git_blob_sha1": "c109a1ab6c7a954faff4897ca5bb37f3b2fd0fe8"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/STATUS.json",
|
||||
"bytes": 3620,
|
||||
"sha256": "b27c9bf3d75e59544528605413d4253b0c88e91298f6fb6c561a12b3aa0b26bd",
|
||||
"git_blob_sha1": "2fbc3d66cf7de3061da20bf67adc4ba84c1cb5ed"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/composition.py",
|
||||
"bytes": 13130,
|
||||
"sha256": "b2fc058b1589310499917c8c5fad056fd8861ccf6bb32dd3ce205d367f493864",
|
||||
"git_blob_sha1": "85c7157858eae2f0019ca578aaad12af3c09eecd"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py",
|
||||
"bytes": 12934,
|
||||
"sha256": "7a0eda4900bc405569b9a797b1f80446e6210a77a81c3c7967f639364c493821",
|
||||
"git_blob_sha1": "f3bce62d865da58e0bbfd3a1101b20909579d3f3"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/diff_check.log",
|
||||
"bytes": 16,
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb",
|
||||
"git_blob_sha1": "fa146f5e868243f2f30da886ba8857913f7ba42a"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/import.log",
|
||||
"bytes": 137,
|
||||
"sha256": "4a2fe8c27abe4d9c077ca3701b07ee860d4673f93267e4ae4697638a1f2254c9",
|
||||
"git_blob_sha1": "733ed0946b27fc409db84e600a3ec15a8dc25945"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/missing_real_evidence.log",
|
||||
"bytes": 134,
|
||||
"sha256": "e1f4250f0078f0a88e8fd4ec485386ab67e835d0e966e609def115de00f4c48c",
|
||||
"git_blob_sha1": "c40aa5563c4816cfb29faf41da7f53ba1131b07b"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/preservation.log",
|
||||
"bytes": 927,
|
||||
"sha256": "7e6691b7ae2ae94f956758a8907d3d67db29b9642ed0aecbfbc94421dcbdbace",
|
||||
"git_blob_sha1": "ec333d287202ab01d6a9a3df8faf9cc9906ad7a1"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/py_compile.log",
|
||||
"bytes": 16,
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb",
|
||||
"git_blob_sha1": "fa146f5e868243f2f30da886ba8857913f7ba42a"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair4_tests.log",
|
||||
"bytes": 634,
|
||||
"sha256": "d3852846638752b6f8421776da825a037228ead8c67333c6b14e93a2fffb8f7a",
|
||||
"git_blob_sha1": "1731dbb82f16a817c95f69f34ceb2d4da7fad12c"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair5_tests.log",
|
||||
"bytes": 1656,
|
||||
"sha256": "48a4c44bd1f5f94faa0f78f14afea371f04d4e9652c89fc8dcad91a24e7cf836",
|
||||
"git_blob_sha1": "a03710c0d634ad1da8e7ada00f91296c1808cdae"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py",
|
||||
"bytes": 21118,
|
||||
"sha256": "f6e00851b444b018a176588f3077d98ab146c64fc0c1ac1dba98bf4dadc7542d",
|
||||
"git_blob_sha1": "77064fcbac9866b00f73aa062cda26a8d9aa4102"
|
||||
},
|
||||
{
|
||||
"path": "scenes/main/main.gd",
|
||||
"bytes": 146784,
|
||||
"sha256": "35c3cec2d1d13f56c1635010a5811c853d7fb42e13b8d2af6cfe8261832be6c6",
|
||||
"git_blob_sha1": "5d136195c7e28a060cde7473ab76baf46b7949e8"
|
||||
},
|
||||
{
|
||||
"path": "tests/ui/test_operations_notification.gd",
|
||||
"bytes": 18698,
|
||||
"sha256": "50172ab6daa031d221f6a78cac5cdbcb8884f295f8062b54656562e2412faff2",
|
||||
"git_blob_sha1": "15dc9e63b0167a0809a949087c23d79a9189623c"
|
||||
},
|
||||
{
|
||||
"path": "tools/check_p24_operations_evidence.py",
|
||||
"bytes": 38965,
|
||||
"sha256": "0c4699fa032e9961e8e9965000382301cfd55898131ddad463ec8a38024d7818",
|
||||
"git_blob_sha1": "57a1b34e94295a687a05cb0f1af60f62545fee45"
|
||||
},
|
||||
{
|
||||
"path": "tools/regression/suite-policy.json",
|
||||
"bytes": 17581,
|
||||
"sha256": "93178d9f68b15307158f1050993bdc75d8790d65ebe75400a3572978e37ec26a",
|
||||
"git_blob_sha1": "d0bddce72981ae73d11a56e07b0e326d56fe9a46"
|
||||
}
|
||||
],
|
||||
"verified_raw_local_commands": [
|
||||
{
|
||||
"name": "py_compile",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"-m",
|
||||
"py_compile",
|
||||
"tools/check_p24_operations_evidence.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/composition.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/py_compile.log",
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb"
|
||||
},
|
||||
{
|
||||
"name": "import",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"-c",
|
||||
"import importlib.util; s=importlib.util.spec_from_file_location('p24','tools/check_p24_operations_evidence.py'); m=importlib.util.module_from_spec(s); s.loader.exec_module(m); print('stdlib checker import OK; ROOT='+str(m.ROOT))"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/import.log",
|
||||
"sha256": "4a2fe8c27abe4d9c077ca3701b07ee860d4673f93267e4ae4697638a1f2254c9"
|
||||
},
|
||||
{
|
||||
"name": "repair5_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair5_tests.log",
|
||||
"sha256": "48a4c44bd1f5f94faa0f78f14afea371f04d4e9652c89fc8dcad91a24e7cf836"
|
||||
},
|
||||
{
|
||||
"name": "repair4_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair4_tests.log",
|
||||
"sha256": "d3852846638752b6f8421776da825a037228ead8c67333c6b14e93a2fffb8f7a"
|
||||
},
|
||||
{
|
||||
"name": "preservation",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/preservation.log",
|
||||
"sha256": "7e6691b7ae2ae94f956758a8907d3d67db29b9642ed0aecbfbc94421dcbdbace"
|
||||
},
|
||||
{
|
||||
"name": "missing_real_evidence",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"tools/check_p24_operations_evidence.py",
|
||||
"--verify-only"
|
||||
],
|
||||
"exit_code": 1,
|
||||
"expected_exit_code": 1,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/missing_real_evidence.log",
|
||||
"sha256": "e1f4250f0078f0a88e8fd4ec485386ab67e835d0e966e609def115de00f4c48c"
|
||||
},
|
||||
{
|
||||
"name": "diff_check",
|
||||
"argv": [
|
||||
"git",
|
||||
"diff",
|
||||
"--check"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/diff_check.log",
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb"
|
||||
}
|
||||
],
|
||||
"later_commands": [
|
||||
{
|
||||
"id": "item_31",
|
||||
"type": "command_execution",
|
||||
"command": "/bin/zsh -lc 'git status --short; cat docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair5_tests.log; cat docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/missing_real_evidence.log'",
|
||||
"aggregated_output": " M docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json\n M docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py\n M docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py\n M scenes/main/main.gd\n M tests/ui/test_operations_notification.gd\n M tools/check_p24_operations_evidence.py\n M tools/regression/suite-policy.json\n?? docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/\n?? docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/\n\n--- STDERR ---\ntest_altered_conflict_nonconflict_and_main_only (__main__.CompositionTests) ... ok\ntest_bindings_and_source_map (__main__.CompositionTests) ... ok\ntest_docs_only_main_fresh_q (__main__.CompositionTests) ... ok\ntest_fifth_conflict (__main__.CompositionTests) ... ok\ntest_final_mode_clean_exact_parents (__main__.CompositionTests) ... ok\ntest_git_environment_and_crosschecks (__main__.CompositionTests) ... ok\ntest_new_main_old_q_and_stale_source_new_q (__main__.CompositionTests) ... ok\ntest_outside_scope (__main__.CompositionTests) ... ok\ntest_parent_order_extra_and_tree_mismatch (__main__.CompositionTests) ... ok\ntest_positive_normal_and_private_objects (__main__.CompositionTests) ... ok\ntest_root_context_sha_symlink_and_cwd (__main__.CompositionTests) ... ok\ntest_engine_requires_actual_receipt_and_bytes (__main__.CorrespondenceTests) ... ok\ntest_observer_payloads_and_pointer (__main__.CorrespondenceTests) ... ok\ntest_alias_identical_bytes (__main__.CoverageAttackTests) ... ok\ntest_all_true_opaque_and_scaffold (__main__.CoverageAttackTests) ... ok\ntest_cross_process_and_whole_roster_engine (__main__.CoverageAttackTests) ... ok\ntest_missing_meaning_reused_and_relabelled_record (__main__.CoverageAttackTests) ... ok\ntest_old_catchall_plus_seven_fillers (__main__.CoverageAttackTests) ... ok\ntest_one_shared_trace_distinct_records_positive (__main__.CoverageAttackTests) ... ok\ntest_wrong_root_source_and_engine (__main__.CoverageAttackTests) ... ok\ntest_exact_nonp24_and_schema_preservation (__main__.PreservationTests) ... ok\n\n----------------------------------------------------------------------\nRan 21 tests in 10.582s\n\nOK\n\n--- STDERR ---\nERROR: Could not locate p24-operations-evidence index.json.\nEnsure BUILD_OUTPUT_DIR is set or provide --index <path>.\n",
|
||||
"exit_code": 0,
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": "item_32",
|
||||
"type": "command_execution",
|
||||
"command": "/bin/zsh -lc 'TMPPREFIX=\"$TMPDIR/p24-zsh\" python3 - <<'\"'PY'\nimport hashlib,json,subprocess\nfrom pathlib import Path\nroot=Path.cwd(); here=root/'docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017'\nmanifest=json.loads((here.parent/'root-repair5-context-20261017/REFERENCE_MANIFEST.json').read_text())\nrefs=[]\nfor row in manifest['files']:\n digest=hashlib.sha256((root/row['reference_path']).read_bytes()).hexdigest()\n assert digest==row['sha256'],row['reference_path']\n refs.append({'path':row['reference_path'],'sha256':digest,'matches_manifest':True})\n(here/'REFERENCE_INTEGRITY.json').write_text(json.dumps({'reference_only_not_runtime_proof':True,'files':refs},indent=2)+'\\\\n')\nstatus=json.loads((here/'STATUS.json').read_text());status['local_checks']={'py_compile_exit':0,'python_import_exit':0,'repair5_stdlib_git_tests':21,'repair5_exit':0,'preserved_roster_head_tests':9,'repair4_exit':0,'preservation_exit':0,'diff_check_exit':0,'missing_real_evidence_exit':1,'raw_results':'LOCAL_COMMAND_RESULTS.json','source_hashes':'SOURCE_MANIFEST.json'}\n(here/'STATUS.json').write_text(json.dumps(status,ensure_ascii=False,indent=2)+'\\\\n')\ntracked=subprocess.run(['git','diff','--name-only'],capture_output=True,text=True,check=True).stdout.splitlines()\nfiles=sorted(set(tracked)|{p.relative_to(root).as_posix() for p in here.rglob('*') if p.is_file() and p.name\"'!='\"'SOURCE_MANIFEST.json'})\nrows=[]\nfor name in files:\n raw=(root/name).read_bytes()\n rows.append(dict(path=name,bytes=len(raw),sha256=hashlib.sha256(raw).hexdigest(),git_blob_sha1=hashlib.sha1(b'blob %d\\\\0'%len(raw)+raw).hexdigest()))\noutput={'task_id':'P24-02','existing_HEAD':subprocess.run(['git','rev-parse','HEAD'],capture_output=True,text=True,check=True).stdout.strip(),'status':'SOURCE-READY/NOTRUN','note':'Uncommitted source/local phase only. This manifest excludes itself. Supplied Root references are unchanged and excluded from authored files.','files':rows}\n(here/'SOURCE_MANIFEST.json').write_text(json.dumps(output,indent=2)+'\\\\n')\nfor row in rows:\n if row['path'] in tracked or row['path'].endswith(('/composition.py','/correspondence.py','/test_repair5.py')):\n print(row['sha256'],row['path'])\nprint('SOURCE_MANIFEST.json sha256='+hashlib.sha256((here/'SOURCE_MANIFEST.json').read_bytes()).hexdigest())\nPY\"",
|
||||
"aggregated_output": "d3599139e2358c1ac9edb5059a823880f72efe5ff457da2887114c243139f743 docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json\ne7dc30bcd56dcdf3f057131bf5dc9a3a672e357bc9b8e5bf2b818d3302d4c83a docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py\n5c10efe7a9c6b3d290020f8dfbb2431956b3dafff7abdd4859b8e6d83e1d9365 docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py\nb2fc058b1589310499917c8c5fad056fd8861ccf6bb32dd3ce205d367f493864 docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/composition.py\n7a0eda4900bc405569b9a797b1f80446e6210a77a81c3c7967f639364c493821 docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py\nf6e00851b444b018a176588f3077d98ab146c64fc0c1ac1dba98bf4dadc7542d docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py\n35c3cec2d1d13f56c1635010a5811c853d7fb42e13b8d2af6cfe8261832be6c6 scenes/main/main.gd\n50172ab6daa031d221f6a78cac5cdbcb8884f295f8062b54656562e2412faff2 tests/ui/test_operations_notification.gd\n0c4699fa032e9961e8e9965000382301cfd55898131ddad463ec8a38024d7818 tools/check_p24_operations_evidence.py\n93178d9f68b15307158f1050993bdc75d8790d65ebe75400a3572978e37ec26a tools/regression/suite-policy.json\nSOURCE_MANIFEST.json sha256=09f8e61b49c6c590f347928e35074aaef9fb90abdb7ac6e3a930d1ded4fe059e\n",
|
||||
"exit_code": 0,
|
||||
"status": "completed"
|
||||
}
|
||||
],
|
||||
"actual_worker_ended": true,
|
||||
"no_scope_violations": true,
|
||||
"tests_reexecuted_by_Root": false,
|
||||
"all8_accepted": false,
|
||||
"ended": 1792216171.950909
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"argv": [
|
||||
"/Users/korizatou114/.local/bin/claude",
|
||||
"-p",
|
||||
"--safe-mode",
|
||||
"--restricted",
|
||||
"--output-format",
|
||||
"json",
|
||||
"--tools",
|
||||
"Read,Grep,Glob",
|
||||
"--strict-mcp-config",
|
||||
"--mcp-config",
|
||||
"{\"mcpServers\":{}}",
|
||||
"--setting-sources",
|
||||
"",
|
||||
"--no-session-persistence",
|
||||
"--permission-mode",
|
||||
"plan",
|
||||
"--json-schema",
|
||||
"{\"type\": \"object\", \"additionalProperties\": false, \"required\": [\"task_id\", \"commit\", \"status\", \"summary\", \"acceptance_ids\", \"findings\"], \"properties\": {\"task_id\": {\"type\": \"string\", \"enum\": [\"P24-02\"]}, \"commit\": {\"type\": \"string\", \"enum\": [\"78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08\"]}, \"status\": {\"type\": \"string\", \"enum\": [\"pass\", \"changes_requested\"]}, \"summary\": {\"type\": \"string\"}, \"acceptance_ids\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"maxItems\": 0}, \"findings\": {\"type\": \"array\", \"items\": {\"type\": \"object\", \"additionalProperties\": false, \"required\": [\"severity\", \"message\"], \"properties\": {\"severity\": {\"type\": \"string\", \"enum\": [\"critical\", \"high\", \"medium\", \"low\"]}, \"message\": {\"type\": \"string\"}}}}}}",
|
||||
"--model",
|
||||
"claude-opus-5-5"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-root-composed-78f7cba-r01",
|
||||
"env_names": [
|
||||
"AGY_CLI_DISABLE_AUTO_UPDATE",
|
||||
"BROWSER_PROFILE_DIR",
|
||||
"BUILD_OUTPUT_DIR",
|
||||
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC",
|
||||
"CLAUDE_CODE_OAUTH_TOKEN",
|
||||
"GIT_TERMINAL_PROMPT",
|
||||
"HOME",
|
||||
"LANG",
|
||||
"LC_ALL",
|
||||
"LOGNAME",
|
||||
"MAC_CHROMIUM_TMPDIR",
|
||||
"PATH",
|
||||
"PORT",
|
||||
"PYTHONDONTWRITEBYTECODE",
|
||||
"TEMP",
|
||||
"TERM",
|
||||
"TEST_DATABASE_PATH",
|
||||
"TMP",
|
||||
"TMPDIR",
|
||||
"USER"
|
||||
],
|
||||
"execution": "sandbox"
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
Latest owner review-material policy: fixed 500000-byte limits are removed. Do not omit required sources or evidence or perform compression/re-submission merely to satisfy the obsolete cap. Claude commander/reviewer can inspect their source checkout with Read,Grep,Glob; reviewer validation materials are mirrored into .review-material within the frozen checkout. Other services keep their own tool sets. Preserve scope, acceptance, exact-version evidence and independent review. Read relevant dependencies directly and report required context gaps.
|
||||
Actual independent limited static review of completed repair5 source/local batch; NOT formal whole-unit acceptance. Use separate actual Claude Opus5.5 session. Return commit 78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08 acceptance_ids=[]; status pass only if no critical/high/medium source readiness defect. Review actual complete changed source and tests, not implementation claims. You are in genuine Root prospective Q checkout with all Main dependencies. No Godot/native/OS/full has run on this new source; all8 still unaccepted; original30/88, formally14 unchanged. Do not turn explicit missing real evidence/upstream/Windows gates into a claimed new code failure, but identify real checker/UI/test defects precisely. No material cap; Read/Grep/Glob whole relevant dependencies. No execution/tools Bash, no source edits.
|
||||
Actual roles: {"scope": "Prospective actual Git composition, not a normal integration candidate or runtime evidence", "S": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08", "M": "54cade4181f6c3c4f5701ba54ac5fcbeca695945", "Q": "60eadb8bc839bfcb46bff41949db9c59611e3e6f", "T": "5dfac310b6be88b9dc4224e4b8c4b16f585d8b58", "parents": ["54cade4181f6c3c4f5701ba54ac5fcbeca695945", "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"], "worktree": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-root-composed-78f7cba-r01", "conflict_paths": ["docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json", "scenes/main/main.gd", "scenes/main/world_preview.gd", "tools/regression/suite-policy.json"], "resolution": "Exact actual submitted S blobs in four already-reconciled paths, no Root source edits", "all8_accepted": false, "normal_integration_candidate": false, "formally_closed_units": 14}
|
||||
Review: (1) new composition.py checker Git root/env overrides, normalS vs integrationC, exact4 typed conflicts/private objects/index, allowed_scope/Main-only/S-only, verified T/Q/C/parents, source/input/blob completeness, Main reconciliation-input binding including changedM staleS newQ negative; external engine pins actual receipt separate from Git blobs. (2) correspondence.py real condition↔record links in observer/OS formats, shared trace distinct records permitted, alias/filler/catchall/pid-only/opaque/relabel/root/source/engine/crossprocess rejected, no fictitious acceptance format or test-only route in production. (3) defense dialog visibility callback before add_child and meaningful real-model native test, preserves ledger/selection; native execution remains mandatory later. Own P24 marker/policy SHA rebind exact, nonP24/schema/guards preserved. (4) existing9 and new stdlib/Git tests meaningful positive/negative, helper own source/provenance pins; source-ready docs honest all8 gaps. Optional preservation ordered/exact exceptions and write-evidence semantics only if changed. Full raw provider/command/sandbox/result and actual Root proof under .review-material/p24-repair5-static/manifest.json, use exact relative paths there; no opaque summaries or omitted files. Prior independent95cffd7 low5 findings available full. Reuse unchanged prior source scope, but assess all repair5 deltas. Source map/full roster/P23 actual old evidence cannot be relabelled to this tree. Natural upstream production cutins, IME/save/scales, bubble actual rendering, staff-panel actual OS click, exact final full roster, whole8 independent review, normal integration/final and Windows all remain needed. OriginalP18 backend265ce30 is complete ancestor, never restart it. Any remaining issue must distinguish static defect needing this batch correction from future runtime/proof dependency. Root will not bypass these gates.
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"task_id": "P24-02",
|
||||
"commit": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08",
|
||||
"status": "changes_requested",
|
||||
"summary": "Limited independent static review of repair5 (S=78f7cba) in the Root prospective Q checkout (Q=60eadb8, M=54cade4, T=5dfac31). I used only Read, Grep and Glob, and ran nothing. This is not formal acceptance: acceptance_ids=[], all 8 conditions stay unaccepted, and original 30/88 and formally closed 14 are unchanged. Nothing here counts as Godot, native, OS, full-roster or Windows evidence.\n\nI read in full: composition.py, correspondence.py, test_repair5.py, PROTOCOL.md and STATUS.json; tools/check_p24_operations_evidence.py; repair4 check_repair4_preservation.py and test_checker_roster_head.py; the main.gd defense/guard region; the repair5 block in tests/ui/test_operations_notification.gd and its surroundings; the world_preview _gui_input/_can_drop_data/_drop_data code; operations_os_observer.gd; the P24 marker/policy rows; and the Root repair5 context files (CLARIFICATIONS, APPLICABILITY). From the manifest I read the Root result, re-audit and prepared-composition records and the prior 95cffd7 result.\n\n(1) composition.py is sound for its declared scope:\n- Every Git call strips inherited GIT_* variables. An inherited override that changes HEAD is rejected, and CANDIDATE_COMMIT/TARGET_HEAD only cross-check. ROOT is the script root, and cwd must be the same toplevel.\n- normal_validation requires HEAD=S. integration_final requires C=HEAD, exact [M,S] parents, C tree=T and a clean checkout. Q parents must be exactly [M,S] and the Q tree must equal T.\n- merge-tree runs with a private object directory and index (repo objects as alternates). It must return exactly four typed CONTENT conflicts; binary, mode and type conflicts are rejected. Only those four entries are replaced with S blobs, and write-tree must equal T.\n- Checks cover allowed_scope, S-only, Main-only and conflict provenance.\n- The source map must be complete under the run_all_tests filter. The spec, marker, project.godot, policy and both helper SHAs are pinned. blob_bindings must exactly cover the source map plus inputs, verified by SHA1 and SHA256 and against checkout bytes for S-owned paths.\n- The four Main 54cade4 input blobs are pinned, so a changed-M/stale-S new Q is rejected (with a test).\n- The engine fingerprint (path, SHA, version plus a started/ended receipt) is separate from the Git blobs.\n\n(2) correspondence.py does reject aliases, record reuse, relabelled actions, missing meanings, fillers, all-true/opaque fields, scaffold/TEST-ONLY payloads, wrong root/S/T/source/pid/session/engine provenance, a same-PID restart and a different roster engine. A shared trace with distinct records is permitted. However, see the medium finding about the OS-event-only format for the final_validation_review meanings.\n\n(3) UI: defense_manager.visibility_changed is now connected before add_child (main.gd:3088-3089), which fixes the prior low finding. The new test asserts that the guard turns on when the dialog opens and off when it closes, which is a genuine regression check. Its model and selection preservation assertions are weak (low finding). Native execution is still required.\n\n(4) Pins: the P24 marker row and suite-policy SHA are both rebound to 50172ab6…, which is the actual test SHA in SOURCE_MANIFEST. The rest of the marker/policy JSON is unchanged, ignoring only that P24 SHA field (the preservation helper's 3-way ordered check). --write-evidence now behaves as documented. STATUS.json honestly lists every gap for all 8 conditions.\n\nBlocking: PreservationTests in test_repair5.py compares against the moving HEAD, so it fails when re-run at S or Q (medium). The correspondence format forces non-OS final-validation facts into OS-session events (medium).\n\nNot blocking, and not code failures in this batch: natural upstream cut-ins, IME/save/scales, actual bubble rendering, a real OS click on the staff panel, the exact final full roster, whole-8 review, normal integration/final, and Windows. These still need real evidence later.",
|
||||
"acceptance_ids": [],
|
||||
"findings": [
|
||||
{
|
||||
"severity": "medium",
|
||||
"message": "PreservationTests.test_exact_nonp24_and_schema_preservation in test_repair5.py (lines 311-322) uses the moving `HEAD:` as its pre-repair baseline, not the pinned source commit bd3a13405115fc9bf6c5acec55bcfef7dd15266a. It only passed in the worker's uncommitted state, where HEAD was still bd3a134. At the submitted commit S=78f7cba, and at Q=60eadb8, HEAD:scenes/main/main.gd already contains `defense_manager.visibility_changed.connect(_update_modal_input_guard)`. So `main_old.replace('\\t\\tadd_child(defense_manager)', '<connect>\\n\\t\\tadd_child(defense_manager)')` adds the line a second time and the assertEqual fails. For the same reason, `new[:start]+new[end:] == old` fails, because HEAD's test file already contains the inserted block. The world_preview comparison against HEAD is trivially true and proves nothing. The 21/21 pass in repair5_tests.log therefore cannot be reproduced at the exact submitted source, and a later re-run by Root on S, Q or C will report a failure. Fix in this batch: pin these comparisons to bd3a134 (as the JSON half of the test already does), or to a reviewed blob ID."
|
||||
},
|
||||
{
|
||||
"severity": "medium",
|
||||
"message": "correspondence.verify (lines 141-149) requires every coverage meaning to be an OS-trace event: `/events/N` with action==meaning, monotonic_ns inside the single OS receipt's [started, ended] window, and provenance pid/session equal to os_environment. This includes the final_validation_review meanings static_import_local_affected (commands/results), exact_final_full_roster, independent_claude_runtime_review and current_main_integration_final (S/M/Q/T/mode), and doc facts such as held_gestures_deferred and macos_windows_classification. Genuine evidence cannot take this form:\n- A full roster runs many separate engine processes.\n- An independent Claude review happens after the runtime artifacts exist, yet it must reference runtime_artifact_sha256 from inside a trace recorded during that runtime.\n- In normal_validation (HEAD=S) no integration-final record exists yet.\nThe only way to pass is for Root to write these facts into the OS session trace with the OS PID/session and in-window timestamps, which is exactly the relabelling the design is meant to forbid. Separately, the exact_final_full_roster record's `results` only gets verify_engine per row. Its suite set and source SHAs are never compared with the full_roster list that the legacy _validate_condition_artifact_content actually validates; the positive test uses results=[receipt]. So the record linked to the meaning is not the validated roster. Fix in this batch: give non-OS meanings typed record kinds bound to their own actual artifacts and receipts (command logs, roster result rows, review artifact SHA, composition roles), and bind the coverage record to the same roster rows the suite-set check validates."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "composition.py pins only the Main side of the four conflict inputs (MAIN_INPUTS). Conflicts are always resolved to whatever blob S has, and nothing pins the reconciled S blobs. A later S that rewrites a conflict file, for example from the old P24 branch, dropping Main hunks, would still compose against an unchanged Main. That protection currently relies on check_repair4_preservation.py, which the checker does not call and which pins MAIN=51e8657. Consider pinning the reviewed S conflict blobs, or making preservation a checker input or gate."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "correspondence.verify keeps a `test_only=True` keyword route in production code that relaxes the scaffold/TEST-ONLY word filter. It is not reachable from the CLI and it requires fixture_scope=TEST-ONLY, so it is not an acceptance bypass. Still, the review asked for no test-only route in production; moving the adapter into the test module would be cleaner. Also, several malformed-input cases raise AttributeError, which is not in the checker's except tuple: a non-dict receipt (receipt.get), a non-dict before/after, or a non-dict os_environment. They end in an uncaught traceback (still exit 1) instead of a clean rejection."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "The new defense-modal test (tests/ui/test_operations_notification.gd:136-159) proves the visibility-callback fix through the modal_input_blocked true/false assertions. Its model and selection preservation assertions have no positive control, though. The click at (200,200) may not map to a buildable cell, and the drop at Vector2.ZERO probably hits no facility. Both could be no-ops even without the guard. A matching unblocked attempt that does change state, or a check that the targets are a valid cell and facility, would make these assertions meaningful. Native execution is still required."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "Carry-overs from prior review 95cffd7:\n- Still open: world_preview.staff_assignment_clicked is still never emitted (dead wiring; documented, and the direct assign_staff_by_click call is not map-click evidence). check_repair4_preservation still compares bodies as sets of lines; this is documented and optional hardening was not done. Bubble first-relationship order, the heart rule and the O(N²) scan remain whole-8 review items.\n- Fixed: the defense visibility hookup, --write-evidence behaviour, the HEAD root vs cwd split (now root_identity plus a verified T view), and the catch-all-plus-fillers case (now per-meaning coverage plus used==artifacts).\n- Note: check_repair4_preservation.git_show and its ls-tree/grep calls still inherit GIT_* environment variables, unlike composition.clean_env."
|
||||
}
|
||||
]
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
(version 1)
|
||||
(allow default)
|
||||
(deny file-write*)
|
||||
(deny file-read-data (require-all (subpath "/Users/korizatou114") (require-not (literal "/Users/korizatou114")) (require-not (literal "/Users/korizatou114/.claude.json")) (require-not (literal "/Users/korizatou114/.local")) (require-not (literal "/Users/korizatou114/.local/share")) (require-not (literal "/Users/korizatou114/Projects")) (require-not (literal "/Users/korizatou114/Projects/TheTree-managed-worktrees")) (require-not (literal "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations")) (require-not (literal "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime")) (require-not (subpath "/Users/korizatou114/.local/bin")) (require-not (subpath "/Users/korizatou114/.local/share/claude")) (require-not (subpath "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/P24-02")) (require-not (subpath "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-root-composed-78f7cba-r01")) (require-not (subpath "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/.git"))))
|
||||
(allow file-write* (subpath "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/P24-02"))
|
||||
(allow file-write* (literal "/dev/null") (literal "/dev/tty") (literal "/dev/stdout") (literal "/dev/stderr"))
|
||||
(deny file-read* file-write* (subpath "/private/tmp/the-tree-p24-02-control-r02"))
|
||||
(deny file-read* file-write* (subpath "/Users/korizatou114/Library/Application Support/agent-control"))
|
||||
(deny file-read* file-write* (subpath "/Users/korizatou114/.ssh"))
|
||||
(deny file-read* file-write* (subpath "/Users/korizatou114/.aws"))
|
||||
(deny file-read* file-write* (subpath "/Users/korizatou114/.azure"))
|
||||
(deny file-read* file-write* (subpath "/Users/korizatou114/.config/gcloud"))
|
||||
(deny file-read* file-write* (subpath "/Users/korizatou114/Library/Keychains"))
|
||||
(deny file-write* (subpath "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/.git"))
|
||||
+1
File diff suppressed because one or more lines are too long
+92
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"scope": "SOURCE-ONLY; stdlib/Git, TEST-ONLY synthetic fixtures; no acceptance",
|
||||
"commands": [
|
||||
{
|
||||
"name": "py_compile",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"-m",
|
||||
"py_compile",
|
||||
"tools/check_p24_operations_evidence.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/composition.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/py_compile.log",
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb"
|
||||
},
|
||||
{
|
||||
"name": "import",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"-c",
|
||||
"import importlib.util; s=importlib.util.spec_from_file_location('p24','tools/check_p24_operations_evidence.py'); m=importlib.util.module_from_spec(s); s.loader.exec_module(m); print('stdlib checker import OK; ROOT='+str(m.ROOT))"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/import.log",
|
||||
"sha256": "4a2fe8c27abe4d9c077ca3701b07ee860d4673f93267e4ae4697638a1f2254c9"
|
||||
},
|
||||
{
|
||||
"name": "repair5_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair5_tests.log",
|
||||
"sha256": "48a4c44bd1f5f94faa0f78f14afea371f04d4e9652c89fc8dcad91a24e7cf836"
|
||||
},
|
||||
{
|
||||
"name": "repair4_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair4_tests.log",
|
||||
"sha256": "d3852846638752b6f8421776da825a037228ead8c67333c6b14e93a2fffb8f7a"
|
||||
},
|
||||
{
|
||||
"name": "preservation",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/preservation.log",
|
||||
"sha256": "7e6691b7ae2ae94f956758a8907d3d67db29b9642ed0aecbfbc94421dcbdbace"
|
||||
},
|
||||
{
|
||||
"name": "missing_real_evidence",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"tools/check_p24_operations_evidence.py",
|
||||
"--verify-only"
|
||||
],
|
||||
"exit_code": 1,
|
||||
"expected_exit_code": 1,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/missing_real_evidence.log",
|
||||
"sha256": "e1f4250f0078f0a88e8fd4ec485386ab67e835d0e966e609def115de00f4c48c"
|
||||
},
|
||||
{
|
||||
"name": "diff_check",
|
||||
"argv": [
|
||||
"git",
|
||||
"diff",
|
||||
"--check"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"raw_log": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/diff_check.log",
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb"
|
||||
}
|
||||
]
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# Repair5 source/local handoff (not acceptance)
|
||||
|
||||
Historical repair5 protocol. Repair6 supersedes the universal OS-event envelope and stage rules below: see [repair6 protocol](../source-ready-repair6-20261017/PROTOCOL.md). Existing repair5 logs, STATUS and SOURCE_MANIFEST remain old-source historical proof; they do not certify repair6.
|
||||
|
||||
The existing collector_protocol.json and operations_os_observer.gd remain authoritative about scope: the observer's local_unit_fixture_only_not_native_os_input_evidence summaries are never OS acceptance. No actual index is included. No engine executable path has been invented. TEST-ONLY fixtures exercise validators, not the game.
|
||||
|
||||
## Composition and paths
|
||||
|
||||
Run the checker from ROOT or a directory within the same checkout. ROOT is obtained with scrubbed Git from the checker location. Relative sources, suite roster and artifacts never use cwd. The temporary tested view is materialized from verified T blobs within the existing task TMPDIR. The source map is exactly run_all_tests.source_refs' filter on T, including fixed settings and every source/asset/test/tool. The marker JSON (outside that filter) is mandatory in inputs. The checker helpers themselves must also be in inputs, as must the frozen spec, project.godot and suite-policy.json. Root can add other actual Git-file inputs; blob_bindings must equal the union of source_hashes and inputs, without omissions or extras. Bindings are SHA1 blob IDs, and source_hashes/inputs are SHA256 of the bytes.
|
||||
|
||||
The regular, non-symlink evidence-dir/root-composition.json is SHA256-bound by index.root_composition_sha256. Its S, M, Q and T are actual Git object IDs; mode is normal_validation or integration_final. Q parents must be exactly [M,S]. Normal validation runs at HEAD=S; integration_final additionally binds C=HEAD, its exact [M,S] parents, a clean checkout and C tree=T. CANDIDATE_COMMIT/TARGET_HEAD only detect mismatches.
|
||||
|
||||
Composition runs merge-tree M S in a private object directory and index, with repository objects as alternates. It accepts exactly the four content conflicts, replaces precisely those entries with S modes/blobs and compares write-tree with Q/T. Every M-only and nonconflicting merged entry survives. Private objects/index are deleted even on failure. The actual Main54 four input blobs are pinned in composition.py; changing any requires new reconciliation and a reviewed source-pin update. A docs-only M requires fresh Q parents and the actual new deterministic tree, never relabelling an old Q.
|
||||
|
||||
The generic functions re-express P23 reference blob 8a62d1e1070688ced445e48d49b831fc7e9cfea3. P23 identities and runtime receipts are not reused as P24 evidence. No P23 module is imported.
|
||||
|
||||
## External engine and record correspondence
|
||||
|
||||
index.engine is {path, sha256, version}, separate from Git bindings. The actual regular external file is hashed without executing it. The OS receipt must carry the identical engine object, engine_started=true, engine_ended=true and strictly increasing started_monotonic_ns/ended_monotonic_ns. Root supplies the genuine path/version and runner receipt. All artifact/record provenance has root, S, T, source_map_sha256, pid, session_id and engine. source_map_sha256 hashes canonical UTF-8 JSON with sorted keys, compact separators and ensure_ascii=false. The OS receipt and os_environment share pid/session. Cross-process records additionally contain actual producer/consumer runtime receipts with different PIDs and identical manifest/world/source/engine bindings.
|
||||
|
||||
Each condition retains its prior passed/details/artifact_ids and content guards, and adds coverage. The exact meaning vocabulary is MEANINGS in correspondence.py, derived clause by clause from the frozen eight groups. Each coverage value is {artifact_id, pointer}, where pointer is a canonical /events/N JSON pointer into the existing OS format {action, monotonic_ns, ...observations}. The action names identify the individual meaning, never PASS. Observed fields listed in MEANINGS are supplementary collector data; they are not emitted by the old local observer and must be genuinely collected by Root. A flag cannot replace them. Multiple conditions may reference distinct records in one genuine OS trace. All listed artifacts must participate, except the required runtime receipt which is intrinsically used. Same bytes under alias IDs, reused records, relabelled actions, missing meanings, mismatched provenance, out-of-runtime events and fixture/template payloads fail.
|
||||
|
||||
Bubble records carry the actual observer shape {actor_id, kind, source_state, recorded_at}, plus OS render observations bound to the same actor/kind. Cutin records carry {kind, heading, message, recorded_at}, plus a production trigger and domain-event trace. These extra OS observations do not turn local record_bubble/record_cutin calls into production evidence. Final full-roster records retain the exact suite-set/source/results checks and require the same started/ended engine identity on all rows. Existing Japanese/IME, owned save path, pause/restart and Windows-not-accepted guards remain in place.
|
||||
|
||||
The unit-level test_only adapter is inaccessible from the CLI. It requires explicit TEST-ONLY fixture_scope and is used solely for synthetic validator controls. Actual verification rejects those controls. Static validity of the correspondence structure is not authentication of a human review or proof of gameplay: Root's independent review must inspect the actual raw receipts and observations.
|
||||
|
||||
## UI and remaining scope
|
||||
|
||||
DefenseManager now connects visibility_changed before add_child, matching the existing dialogs. The added ordinary-cleanup test opens _show_defense_manager, attempts behind-dialog build/drop input on the real model, compares complete snapshots (including economy ledger) and selections, then closes and checks unblocking. It has not run in Godot.
|
||||
|
||||
The direct assign_staff_by_click test is not OS map-click evidence. Later OS collection must exercise the staff panel facility_option/apply_button route. No new map interaction or signal wiring was added. Bubble render/state transitions remain native/collector work. First-relationship order, the inherited heart rule and the O(N²) relationship scan are pending whole-eight review candidates, not new gameplay values or mandated optimizations.
|
||||
|
||||
The existing repair4 preservation helper now permits exactly the current P24 test SHA rebind. All other marker/policy values/order are preserved. It writes its historical result only with --write-evidence. Its historical set-based body comparison remains limited; optional full sequence hardening was not undertaken. Repair5 tests separately compare the entire main.gd delta to exactly the single callback line, world_preview byte-for-byte, the entire test outside the enumerated inserted block, and both JSON structures after undoing only the P24 pin. This does not re-prove P23.
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"reference_only_not_runtime_proof": true,
|
||||
"files": [
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/tools/check_p23_life_observation_evidence.py.source.txt",
|
||||
"sha256": "e41479ae51bccdfab3f31bd348794b441c2f341179bbe33222e2aacdf88f987f",
|
||||
"matches_manifest": true
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/tools/run_p23_life_observation.py.source.txt",
|
||||
"sha256": "8dbd90e22f47912b3381b514398fe1fb2c403c97d8e3d0dd675e9c8db5b5d0d1",
|
||||
"matches_manifest": true
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/tools/run_all_tests.py.source.txt",
|
||||
"sha256": "320ca668732b4ff72fc4449998af2327d4e5c527b06896740806aaf0487282b4",
|
||||
"matches_manifest": true
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair4-20261017/actual-limited-review/result.json",
|
||||
"sha256": "ef17de03039bcd2b3d7a2851d26c0abdc163b32fef40048d933a693f1b49114f",
|
||||
"matches_manifest": true
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair5-context-20261017/main-reference/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair4-20261017/CURRENT_ACCEPTANCE_AND_NEXT_BATCH.json",
|
||||
"sha256": "9c7892ce6ccd26d997e7a609be29ef8a12acb2fb7df75cf4def6f11a8a9157dc",
|
||||
"matches_manifest": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"task_id": "P24-02",
|
||||
"existing_HEAD": "bd3a13405115fc9bf6c5acec55bcfef7dd15266a",
|
||||
"status": "SOURCE-READY/NOTRUN",
|
||||
"note": "Uncommitted source/local phase only. This manifest excludes itself. Supplied Root references are unchanged and excluded from authored files.",
|
||||
"files": [
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json",
|
||||
"bytes": 189076,
|
||||
"sha256": "d3599139e2358c1ac9edb5059a823880f72efe5ff457da2887114c243139f743",
|
||||
"git_blob_sha1": "932e8c4e8e6113aac8b629197d757a73a6f1260e"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py",
|
||||
"bytes": 22108,
|
||||
"sha256": "e7dc30bcd56dcdf3f057131bf5dc9a3a672e357bc9b8e5bf2b818d3302d4c83a",
|
||||
"git_blob_sha1": "a2259ee3ec1d0b981504e446c3fc6e213fde8f9f"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py",
|
||||
"bytes": 5689,
|
||||
"sha256": "5c10efe7a9c6b3d290020f8dfbb2431956b3dafff7abdd4859b8e6d83e1d9365",
|
||||
"git_blob_sha1": "f1a07ecf07b94f1508efa98a8606eeeaa61a7a46"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/LOCAL_COMMAND_RESULTS.json",
|
||||
"bytes": 4909,
|
||||
"sha256": "aacde68f9d6909c1c347197b257fa31a66d3e7519c01e16c79fd45aba6e8d82f",
|
||||
"git_blob_sha1": "8a5e25505d56f5f41e40ef426a69b54900689f92"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/PROTOCOL.md",
|
||||
"bytes": 6620,
|
||||
"sha256": "c07618fd692f911120e70ac13e3de4addf379aa8d29e535867ff93d9bd32e8f6",
|
||||
"git_blob_sha1": "9cf90f38f067c67f09b7540ae475f341f97fa7a9"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/REFERENCE_INTEGRITY.json",
|
||||
"bytes": 1695,
|
||||
"sha256": "be8549f3f6462757c7fb1bc664ccd6c5165f09e2eee4468aec75a8d84e4addf9",
|
||||
"git_blob_sha1": "c109a1ab6c7a954faff4897ca5bb37f3b2fd0fe8"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/STATUS.json",
|
||||
"bytes": 3620,
|
||||
"sha256": "b27c9bf3d75e59544528605413d4253b0c88e91298f6fb6c561a12b3aa0b26bd",
|
||||
"git_blob_sha1": "2fbc3d66cf7de3061da20bf67adc4ba84c1cb5ed"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/composition.py",
|
||||
"bytes": 13130,
|
||||
"sha256": "b2fc058b1589310499917c8c5fad056fd8861ccf6bb32dd3ce205d367f493864",
|
||||
"git_blob_sha1": "85c7157858eae2f0019ca578aaad12af3c09eecd"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py",
|
||||
"bytes": 12934,
|
||||
"sha256": "7a0eda4900bc405569b9a797b1f80446e6210a77a81c3c7967f639364c493821",
|
||||
"git_blob_sha1": "f3bce62d865da58e0bbfd3a1101b20909579d3f3"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/diff_check.log",
|
||||
"bytes": 16,
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb",
|
||||
"git_blob_sha1": "fa146f5e868243f2f30da886ba8857913f7ba42a"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/import.log",
|
||||
"bytes": 137,
|
||||
"sha256": "4a2fe8c27abe4d9c077ca3701b07ee860d4673f93267e4ae4697638a1f2254c9",
|
||||
"git_blob_sha1": "733ed0946b27fc409db84e600a3ec15a8dc25945"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/missing_real_evidence.log",
|
||||
"bytes": 134,
|
||||
"sha256": "e1f4250f0078f0a88e8fd4ec485386ab67e835d0e966e609def115de00f4c48c",
|
||||
"git_blob_sha1": "c40aa5563c4816cfb29faf41da7f53ba1131b07b"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/preservation.log",
|
||||
"bytes": 927,
|
||||
"sha256": "7e6691b7ae2ae94f956758a8907d3d67db29b9642ed0aecbfbc94421dcbdbace",
|
||||
"git_blob_sha1": "ec333d287202ab01d6a9a3df8faf9cc9906ad7a1"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/py_compile.log",
|
||||
"bytes": 16,
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb",
|
||||
"git_blob_sha1": "fa146f5e868243f2f30da886ba8857913f7ba42a"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair4_tests.log",
|
||||
"bytes": 634,
|
||||
"sha256": "d3852846638752b6f8421776da825a037228ead8c67333c6b14e93a2fffb8f7a",
|
||||
"git_blob_sha1": "1731dbb82f16a817c95f69f34ceb2d4da7fad12c"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair5_tests.log",
|
||||
"bytes": 1656,
|
||||
"sha256": "48a4c44bd1f5f94faa0f78f14afea371f04d4e9652c89fc8dcad91a24e7cf836",
|
||||
"git_blob_sha1": "a03710c0d634ad1da8e7ada00f91296c1808cdae"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py",
|
||||
"bytes": 21118,
|
||||
"sha256": "f6e00851b444b018a176588f3077d98ab146c64fc0c1ac1dba98bf4dadc7542d",
|
||||
"git_blob_sha1": "77064fcbac9866b00f73aa062cda26a8d9aa4102"
|
||||
},
|
||||
{
|
||||
"path": "scenes/main/main.gd",
|
||||
"bytes": 146784,
|
||||
"sha256": "35c3cec2d1d13f56c1635010a5811c853d7fb42e13b8d2af6cfe8261832be6c6",
|
||||
"git_blob_sha1": "5d136195c7e28a060cde7473ab76baf46b7949e8"
|
||||
},
|
||||
{
|
||||
"path": "tests/ui/test_operations_notification.gd",
|
||||
"bytes": 18698,
|
||||
"sha256": "50172ab6daa031d221f6a78cac5cdbcb8884f295f8062b54656562e2412faff2",
|
||||
"git_blob_sha1": "15dc9e63b0167a0809a949087c23d79a9189623c"
|
||||
},
|
||||
{
|
||||
"path": "tools/check_p24_operations_evidence.py",
|
||||
"bytes": 38965,
|
||||
"sha256": "0c4699fa032e9961e8e9965000382301cfd55898131ddad463ec8a38024d7818",
|
||||
"git_blob_sha1": "57a1b34e94295a687a05cb0f1af60f62545fee45"
|
||||
},
|
||||
{
|
||||
"path": "tools/regression/suite-policy.json",
|
||||
"bytes": 17581,
|
||||
"sha256": "93178d9f68b15307158f1050993bdc75d8790d65ebe75400a3572978e37ec26a",
|
||||
"git_blob_sha1": "d0bddce72981ae73d11a56e07b0e326d56fe9a46"
|
||||
}
|
||||
]
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"task_id": "P24-02",
|
||||
"source": "bd3a13405115fc9bf6c5acec55bcfef7dd15266a",
|
||||
"phase": "non-UI source/local repair5",
|
||||
"acceptance_ids": [],
|
||||
"native_runs": 0,
|
||||
"full_roster_runs": 0,
|
||||
"game_completion_credit": 0,
|
||||
"conditions": {
|
||||
"placement_and_invalid_drop": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Native placement/rejection/ledger/selection and actual staff-panel OS click coverage NOTRUN."
|
||||
},
|
||||
"modal_and_pause_resume": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Defense modal test source added; native execution, pending-command/save identity, ordinary pause/resume and actual separate-process save restart NOTRUN."
|
||||
},
|
||||
"unit_bubbles": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Bubble native render/model/state switching and removal NOTRUN. First-relationship order, heart semantics and O(N²) scan remain whole-eight review candidates."
|
||||
},
|
||||
"event_log": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Current exact-source production bounded log/Japanese sequence/amount/time/reason/pause/load evidence NOTRUN; historical evidence is not current acceptance."
|
||||
},
|
||||
"important_warning_cutin": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Natural NTR/duel/defense production triggers require whole P18-01/02, P19, P21 inputs. P18 backend 265ce30 is a completed ancestor and is not restarted. Unknown production initial values remain unresolved; no new values added."
|
||||
},
|
||||
"click_alternatives": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Actual staff-panel facility_option/apply_button OS click and navigation coverage NOTRUN. Direct handler calls are not map-click evidence. P23 held gestures remain deferred."
|
||||
},
|
||||
"japanese_input_and_scale": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "OS IME composition/confirm/cancel, persisted save display, scale/focus/clipping and old-save protection NOTRUN. Same-Windows-release device evidence unavailable and still required."
|
||||
},
|
||||
"final_validation_review": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Root must independently review this source batch, rebuild fresh Q/T on actual current M, run import/impact, normal OS collection, one exact final full roster, whole-eight review and normal integration/final. No actual engine path/receipt/index supplied or fabricated."
|
||||
}
|
||||
},
|
||||
"denominator": {
|
||||
"packages": 30,
|
||||
"units": 88,
|
||||
"completed": 14,
|
||||
"partial_credit": false
|
||||
},
|
||||
"optional4": "Only --write-evidence flag behavior clarified; historical sequence comparison hardening remains deferred.",
|
||||
"root_next_gate": "Independent Claude limited source review; actual new Q/T composition and all actual runtime/evidence gates remain Root-owned.",
|
||||
"local_checks": {
|
||||
"py_compile_exit": 0,
|
||||
"python_import_exit": 0,
|
||||
"repair5_stdlib_git_tests": 21,
|
||||
"repair5_exit": 0,
|
||||
"preserved_roster_head_tests": 9,
|
||||
"repair4_exit": 0,
|
||||
"preservation_exit": 0,
|
||||
"diff_check_exit": 0,
|
||||
"missing_real_evidence_exit": 1,
|
||||
"raw_results": "LOCAL_COMMAND_RESULTS.json",
|
||||
"source_hashes": "SOURCE_MANIFEST.json"
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
+262
@@ -0,0 +1,262 @@
|
||||
"""Stdlib/Git composition primitives; no runtime or acceptance execution.
|
||||
|
||||
Re-expressed from P23 checker blob 8a62d1e1070688ced445e48d49b831fc7e9cfea3,
|
||||
SHA256 e41479ae51bccdfab3f31bd348794b441c2f341179bbe33222e2aacdf88f987f.
|
||||
Source filter matches run_all_tests.source_refs (reference blob
|
||||
502ad8c1f6ba371446ecfd8f37f0f9194cdb10ea); no imports from Main-only modules.
|
||||
"""
|
||||
import contextlib
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
CONTRACT = 'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'
|
||||
SPEC = 'docs/spec/acceptance/P24-02-code-r01.json'
|
||||
RECONCILED_MAIN = '54cade4181f6c3c4f5701ba54ac5fcbeca695945'
|
||||
MAIN_INPUTS = {
|
||||
'scenes/main/main.gd': 'fff37f082d750bb91c71f2aa54d168c9e2cb8fe7',
|
||||
'scenes/main/world_preview.gd': 'fa32fe0344d20565b6d542da1256a94e8dee1845',
|
||||
CONTRACT: '2eecb803f5eb6774ff38cd353de1f02847aeb0f9',
|
||||
'tools/regression/suite-policy.json': 'ad194ae425fb8123fa191ed3635f404c098f692d',
|
||||
}
|
||||
KNOWN_CONFLICTS = set(MAIN_INPUTS)
|
||||
OVERRIDES = {'GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE', 'GIT_OBJECT_DIRECTORY',
|
||||
'GIT_ALTERNATE_OBJECT_DIRECTORIES', 'GIT_COMMON_DIR'}
|
||||
|
||||
|
||||
def require(ok, message):
|
||||
if not ok:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def clean_env():
|
||||
# Config injection can also redirect Git. Do not inherit any Git overrides.
|
||||
return {k: v for k, v in os.environ.items() if not k.startswith('GIT_')}
|
||||
|
||||
|
||||
def git_process(root, *args, private=None, input=None):
|
||||
env = clean_env()
|
||||
if private:
|
||||
env.update(private)
|
||||
return subprocess.run(['git', '-C', str(root), *args], input=input,
|
||||
capture_output=True, env=env, timeout=120)
|
||||
|
||||
|
||||
def git_bytes(root, *args, private=None):
|
||||
p = git_process(root, *args, private=private)
|
||||
require(p.returncode == 0, 'Git failed: ' + ' '.join(args) + ': ' + p.stderr.decode(errors='replace'))
|
||||
return p.stdout
|
||||
|
||||
|
||||
def root_identity(script_root, cwd):
|
||||
root = Path(git_bytes(script_root, 'rev-parse', '--show-toplevel').decode().strip()).resolve()
|
||||
require(Path(git_bytes(cwd, 'rev-parse', '--show-toplevel').decode().strip()).resolve() == root,
|
||||
'cwd differs from ROOT')
|
||||
head = git_bytes(root, 'rev-parse', 'HEAD').strip()
|
||||
if any(k in OVERRIDES or k.startswith('GIT_CEILING') for k in os.environ):
|
||||
inherited = subprocess.run(['git', '-C', str(root), 'rev-parse', 'HEAD'],
|
||||
capture_output=True, timeout=10)
|
||||
require(inherited.returncode == 0 and inherited.stdout.strip() == head,
|
||||
'inherited Git override changes HEAD')
|
||||
for name in ('CANDIDATE_COMMIT', 'TARGET_HEAD'):
|
||||
require(name not in os.environ or os.environ[name].strip().encode() == head,
|
||||
name + ' mismatches HEAD')
|
||||
return root
|
||||
|
||||
|
||||
def strict_json(raw):
|
||||
def pairs(rows):
|
||||
d = {}
|
||||
for k, v in rows:
|
||||
require(k not in d, 'duplicate JSON key: ' + k)
|
||||
d[k] = v
|
||||
return d
|
||||
return json.loads(raw, object_pairs_hook=pairs)
|
||||
|
||||
|
||||
def safe_path(root, name):
|
||||
p = Path(name)
|
||||
require(not p.is_absolute() and '..' not in p.parts and p.as_posix() == name, 'unsafe relative path')
|
||||
target = root / p
|
||||
require(target.resolve().is_relative_to(root.resolve()), 'path escapes root')
|
||||
require(not any((root / Path(*p.parts[:i])).is_symlink() for i in range(1, len(p.parts)+1)),
|
||||
'source/artifact symlink')
|
||||
return target
|
||||
|
||||
|
||||
def root_context(directory, index):
|
||||
path = safe_path(directory, 'root-composition.json')
|
||||
require(path.is_file(), 'missing regular root-composition.json')
|
||||
raw = path.read_bytes()
|
||||
require(hashlib.sha256(raw).hexdigest() == index.get('root_composition_sha256'), 'composition SHA mismatch')
|
||||
return strict_json(raw)
|
||||
|
||||
|
||||
def blob_oid(raw):
|
||||
return hashlib.sha1(b'blob %d\0' % len(raw) + raw).hexdigest()
|
||||
|
||||
|
||||
def git_blob_stream(root, oids):
|
||||
process = subprocess.Popen(['git', '-C', str(root), 'cat-file', '--batch'],
|
||||
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=clean_env())
|
||||
try:
|
||||
for oid in oids:
|
||||
require(re.fullmatch('[0-9a-f]{40}', oid), 'invalid blob OID')
|
||||
process.stdin.write((oid + '\n').encode()); process.stdin.flush()
|
||||
match = re.fullmatch(rb'([0-9a-f]{40}) blob (0|[1-9][0-9]*)\n', process.stdout.readline(128))
|
||||
require(match is not None and match[1].decode() == oid, 'invalid blob header')
|
||||
raw = process.stdout.read(int(match[2]))
|
||||
require(len(raw) == int(match[2]) and process.stdout.read(1) == b'\n', 'truncated blob')
|
||||
require(blob_oid(raw) == oid, 'blob SHA1 mismatch')
|
||||
yield oid, raw
|
||||
process.stdin.close()
|
||||
require(process.stdout.read(1) == b'' and process.wait() == 0, 'extra blob output/Git failure')
|
||||
finally:
|
||||
if process.poll() is None:
|
||||
process.kill()
|
||||
process.wait()
|
||||
process.stdin.close(); process.stdout.close()
|
||||
|
||||
|
||||
def tree(root, revision):
|
||||
result = {}
|
||||
for row in git_bytes(root, 'ls-tree', '-r', '-z', revision).split(b'\0'):
|
||||
if not row:
|
||||
continue
|
||||
meta, path = row.split(b'\t', 1)
|
||||
path = path.decode()
|
||||
mode, kind, oid = meta.decode().split()
|
||||
require(path not in result, 'duplicate tree path')
|
||||
require(not Path(path).is_absolute() and '..' not in Path(path).parts, 'unsafe tree path')
|
||||
result[path] = (mode, kind, oid)
|
||||
return result
|
||||
|
||||
|
||||
def source_paths(manifest):
|
||||
folders = {'autoload', 'scripts', 'scenes', 'data', 'tests', 'assets', 'tools'}
|
||||
fixed = {'project.godot', 'export_presets.cfg', 'Makefile', 'AGENTS.md'}
|
||||
require(fixed <= set(manifest), 'missing fixed source settings')
|
||||
return {p for p in manifest if (Path(p).parts[0] in folders and Path(p).name != '.DS_Store'
|
||||
and '__pycache__' not in Path(p).parts)} | fixed
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def tested_checkout(root, t):
|
||||
# Only a private writable allocation; never fall back to global temp.
|
||||
temporary = os.environ.get('TMPDIR')
|
||||
require(temporary and Path(temporary).is_dir(), 'existing task TMPDIR required')
|
||||
with tempfile.TemporaryDirectory(prefix='p24-view-', dir=temporary) as name:
|
||||
view = Path(name)
|
||||
manifest = tree(root, t)
|
||||
paths = sorted(manifest)
|
||||
for path, (_, raw) in zip(paths, git_blob_stream(root, [manifest[p][2] for p in paths])):
|
||||
require(manifest[path][0] in ('100644', '100755') and manifest[path][1] == 'blob',
|
||||
'non-regular tested source')
|
||||
target = safe_path(view, path)
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_bytes(raw)
|
||||
yield view
|
||||
|
||||
|
||||
def deterministic_tree(root, m, s, main_inputs=MAIN_INPUTS):
|
||||
main, submitted = tree(root, m), tree(root, s)
|
||||
require(set(main_inputs) == KNOWN_CONFLICTS, 'reconciliation must bind all four inputs')
|
||||
for p, oid in main_inputs.items():
|
||||
require(main.get(p, (None, None, None))[2] == oid,
|
||||
'Main conflict input changed; new reconciliation required: ' + p)
|
||||
temporary = os.environ.get('TMPDIR')
|
||||
require(temporary and Path(temporary).is_dir(), 'existing task TMPDIR required')
|
||||
objects = Path(git_bytes(root, 'rev-parse', '--git-path', 'objects').decode().strip())
|
||||
if not objects.is_absolute():
|
||||
objects = root / objects
|
||||
with tempfile.TemporaryDirectory(prefix='p24-compose-', dir=temporary) as name:
|
||||
private = Path(name)
|
||||
(private / 'objects').mkdir()
|
||||
env = {'GIT_OBJECT_DIRECTORY': str(private / 'objects'),
|
||||
'GIT_ALTERNATE_OBJECT_DIRECTORIES': str(objects.resolve()),
|
||||
'GIT_INDEX_FILE': str(private / 'index')}
|
||||
result = git_process(root, 'merge-tree', '--write-tree', '-z', '--name-only', m, s, private=env)
|
||||
require(result.returncode == 1, 'expected exactly four content conflicts')
|
||||
fields = result.stdout.split(b'\0')
|
||||
merged = fields.pop(0).decode()
|
||||
require(re.fullmatch('[0-9a-f]{40}', merged), 'missing merge tree')
|
||||
conflict_paths = []
|
||||
while fields and fields[0]:
|
||||
conflict_paths.append(fields.pop(0).decode())
|
||||
require(fields and fields.pop(0) == b'', 'missing conflict separator')
|
||||
require(len(conflict_paths) == 4 and set(conflict_paths) == KNOWN_CONFLICTS, 'unexpected conflict set')
|
||||
# Structured merge-tree messages: path count, paths, type, message.
|
||||
seen = set()
|
||||
while fields and fields[0]:
|
||||
count = int(fields.pop(0))
|
||||
paths = [fields.pop(0).decode() for _ in range(count)]
|
||||
kind = fields.pop(0).decode()
|
||||
message = fields.pop(0).decode()
|
||||
if kind == 'Auto-merging':
|
||||
continue
|
||||
require(kind == 'CONFLICT (contents)' and count == 1 and paths[0] in KNOWN_CONFLICTS
|
||||
and 'binary' not in message.lower(), 'unsupported conflict type: ' + kind)
|
||||
seen.update(paths)
|
||||
require(seen == KNOWN_CONFLICTS, 'missing content conflict messages')
|
||||
for p in KNOWN_CONFLICTS:
|
||||
require(main[p][0] == submitted[p][0] == '100644'
|
||||
and main[p][1] == submitted[p][1] == 'blob', 'mode/type conflict')
|
||||
git_bytes(root, 'read-tree', merged, private=env)
|
||||
for p in sorted(KNOWN_CONFLICTS):
|
||||
mode, _, oid = submitted[p]
|
||||
git_bytes(root, 'update-index', '--add', '--cacheinfo', mode, oid, p, private=env)
|
||||
return git_bytes(root, 'write-tree', private=env).decode().strip()
|
||||
|
||||
|
||||
def verify_composition(root, roles, source_map, inputs, base, allowed_paths, main_inputs=MAIN_INPUTS):
|
||||
require(isinstance(roles, dict), 'missing composition roles')
|
||||
for k in ('S', 'M', 'Q', 'T'):
|
||||
require(isinstance(roles.get(k), str) and re.fullmatch('[0-9a-f]{40}', roles[k]), 'invalid role ' + k)
|
||||
s, m, q, t = (roles[k] for k in ('S', 'M', 'Q', 'T'))
|
||||
for c in (base, s, m, q):
|
||||
require(git_bytes(root, 'cat-file', '-t', c).strip() == b'commit', 'role is not commit')
|
||||
require(git_bytes(root, 'rev-list', '--parents', '-n', '1', q).decode().split() == [q, m, s],
|
||||
'Q parents must be exactly current [M,S]')
|
||||
require(git_bytes(root, 'rev-parse', q+'^{tree}').decode().strip() == t, 'T differs from Q tree')
|
||||
head = git_bytes(root, 'rev-parse', 'HEAD').decode().strip()
|
||||
if roles.get('mode') == 'normal_validation':
|
||||
require(head == s, 'normal validation HEAD must be S')
|
||||
elif roles.get('mode') == 'integration_final':
|
||||
require(roles.get('C') == head, 'final HEAD must be C')
|
||||
require(git_bytes(root, 'rev-list', '--parents', '-n', '1', head).decode().split() == [head, m, s],
|
||||
'C parents must be exactly [M,S]')
|
||||
require(git_bytes(root, 'rev-parse', head+'^{tree}').decode().strip() == t, 'C tree differs')
|
||||
require(not git_bytes(root, 'status', '--porcelain'), 'final checkout dirty')
|
||||
else:
|
||||
raise ValueError('invalid composition mode')
|
||||
require(deterministic_tree(root, m, s, main_inputs) == t, 'Q/T differs from deterministic composition')
|
||||
b, st, mt, tt = (tree(root, rev) for rev in (base, s, m, t))
|
||||
changed_s = {p for p in b.keys() | st.keys() if b.get(p) != st.get(p)}
|
||||
changed_m = {p for p in b.keys() | mt.keys() if b.get(p) != mt.get(p)}
|
||||
def allowed(p):
|
||||
return any(p.startswith(a[:-2]) if a.endswith('/**') else p == a for a in allowed_paths)
|
||||
require(all(allowed(p) for p in changed_s), 'S changed outside allowed_paths')
|
||||
for paths, authority in ((changed_s-changed_m, st), (changed_m-changed_s, mt), (KNOWN_CONFLICTS, st)):
|
||||
require(all(tt.get(p) == authority.get(p) for p in paths), 'S/M-only or conflict provenance mismatch')
|
||||
require(isinstance(source_map, dict) and set(source_map) == source_paths(tt), 'incomplete source_refs map')
|
||||
require(isinstance(inputs, dict) and {SPEC, CONTRACT, 'project.godot', 'tools/regression/suite-policy.json'} <= set(inputs),
|
||||
'missing settings/spec/marker/policy input pins')
|
||||
required = set(source_map) | set(inputs)
|
||||
bindings = roles.get('blob_bindings')
|
||||
require(isinstance(bindings, dict) and set(bindings) == required, 'missing/extra blob_bindings')
|
||||
paths = sorted(required)
|
||||
for p in paths:
|
||||
require(p in tt and tt[p][0] in ('100644', '100755') and tt[p][1] == 'blob', 'not regular bound blob')
|
||||
require(bindings[p] == tt[p][2], 'changed blob binding: ' + p)
|
||||
for p, (oid, raw) in zip(paths, git_blob_stream(root, [tt[p][2] for p in paths])):
|
||||
digest = hashlib.sha256(raw).hexdigest()
|
||||
require(blob_oid(raw) == bindings[p] == oid, 'SHA1 binding mismatch')
|
||||
for mapping in (source_map, inputs):
|
||||
require(p not in mapping or mapping[p] == digest, 'SHA256 binding mismatch: ' + p)
|
||||
if head != s or p in changed_s-changed_m or p in KNOWN_CONFLICTS:
|
||||
require(safe_path(root, p).read_bytes() == raw, 'checkout bytes mismatch: ' + p)
|
||||
return roles
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
"""Record correspondence, using existing OS events {action, monotonic_ns} and
|
||||
observer bubble_history/modal_records/cutin_records/save_records payloads.
|
||||
No PASS record is evidence. Coverage is an index into raw records, not a result.
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Each frozen clause has its own required meaning. The values are the substantive
|
||||
# observed fields required alongside the existing OS action/timestamp envelope.
|
||||
MEANINGS = {
|
||||
'placement_and_invalid_drop': {
|
||||
'grid_snap': ('pointer_position', 'cell', 'grid_geometry'),
|
||||
'connection_warning': ('connection', 'warning_text'),
|
||||
'valid_commit_once': ('before', 'after', 'command_ids'),
|
||||
'invalid_rejection_with_reason_and_model_ledger_selection_unchanged': ('reason', 'before', 'after'),
|
||||
'click_equivalent': ('control_path', 'before', 'after')},
|
||||
'modal_and_pause_resume': {
|
||||
'modal_open_cancel_confirm_focus': ('dialog_name', 'transitions', 'focus'),
|
||||
'pending_commands_save_identity': ('before', 'after'),
|
||||
'behind_dialog_build_assignment_unchanged': ('before', 'after', 'inputs'),
|
||||
'pause_freezes': ('before', 'after', 'elapsed'),
|
||||
'resume_once': ('before', 'after', 'elapsed'),
|
||||
'cross_process_restart': ('producer', 'consumer', 'manifest_sha256', 'world_sha256')},
|
||||
'unit_bubbles': {
|
||||
'zzz_state_model_render': ('actor_id', 'source_state', 'render'),
|
||||
'anger_state_model_render': ('actor_id', 'source_state', 'render'),
|
||||
'heart_state_model_render': ('actor_id', 'relationship', 'render'),
|
||||
'switching_removal': ('actor_id', 'before', 'after', 'render')},
|
||||
'event_log': {
|
||||
'production_sequence_bounded256': ('domain_events', 'rows', 'recent_limit'),
|
||||
'japanese_amount_time_reason': ('rows', 'render'),
|
||||
'pause_load_no_duplicates': ('before', 'after', 'event_ids')},
|
||||
'important_warning_cutin': {
|
||||
'natural_invasion_start': ('production_trigger', 'domain_event', 'heading', 'message'),
|
||||
'natural_duel_start': ('production_trigger', 'domain_event', 'heading', 'message'),
|
||||
'natural_defense_start': ('production_trigger', 'domain_event', 'heading', 'message'),
|
||||
'dismiss_stop_resume': ('transitions', 'before', 'after')},
|
||||
'click_alternatives': {
|
||||
'navigation_zoom_pan_reset_grid_layer': ('controls', 'before', 'after'),
|
||||
'staff_panel_assignment': ('facility_option', 'apply_button', 'before', 'after'),
|
||||
'presentation_model_unchanged': ('before', 'after'),
|
||||
'held_gestures_deferred': ('remaining_scope', 'source_reference')},
|
||||
'japanese_input_and_scale': {
|
||||
'ime_composition': ('text', 'composition_string', 'cursor_position'),
|
||||
'ime_confirmation': ('text', 'confirmed_text'),
|
||||
'ime_cancellation': ('before', 'after'),
|
||||
'persisted_japanese_display': ('display_name', 'path', 'loaded_display_name'),
|
||||
'invalid_input_feedback': ('input_text', 'reason'),
|
||||
'default_owned_path_old_save_cancel': ('before', 'after', 'path'),
|
||||
'scale_clipping_focus_modal': ('window_size', 'display_scale', 'render', 'focus', 'dialog_name'),
|
||||
'macos_windows_classification': ('platform', 'windows_status')},
|
||||
'final_validation_review': {
|
||||
'static_import_local_affected': ('commands', 'results'),
|
||||
'exact_final_full_roster': ('results', 'source_hashes', 'inputs'),
|
||||
'independent_claude_runtime_review': ('reviewer', 'review', 'runtime_artifact_sha256'),
|
||||
'current_main_integration_final': ('S', 'M', 'Q', 'T', 'mode')},
|
||||
}
|
||||
|
||||
|
||||
def require(ok, reason):
|
||||
if not ok:
|
||||
raise ValueError(reason)
|
||||
|
||||
|
||||
def canonical_sha(value):
|
||||
return hashlib.sha256(json.dumps(value, sort_keys=True, separators=(',', ':'), ensure_ascii=False).encode()).hexdigest()
|
||||
|
||||
|
||||
def pointer(value, path):
|
||||
require(isinstance(path, str) and path.startswith('/') and '~' not in path, 'noncanonical record pointer')
|
||||
for part in path[1:].split('/'):
|
||||
if isinstance(value, list):
|
||||
require(part.isdigit() and str(int(part)) == part, 'noncanonical array pointer')
|
||||
value = value[int(part)]
|
||||
else:
|
||||
value = value[part]
|
||||
require(isinstance(value, dict), 'pointer is not a record')
|
||||
return value
|
||||
|
||||
|
||||
def substantive(value):
|
||||
if isinstance(value, bool) or value is None:
|
||||
return False
|
||||
if isinstance(value, dict):
|
||||
return bool(value) and any(substantive(v) for v in value.values())
|
||||
if isinstance(value, list):
|
||||
return bool(value) and any(substantive(v) for v in value)
|
||||
return isinstance(value, (str, int, float)) and value != ''
|
||||
|
||||
|
||||
def verify_engine(engine, receipt):
|
||||
require(isinstance(engine, dict) and set(engine) == {'path', 'sha256', 'version'}, 'external engine fingerprint')
|
||||
path = Path(engine['path'])
|
||||
require(path.is_absolute() and path.is_file() and not path.is_symlink(), 'actual regular engine path required')
|
||||
require(hashlib.sha256(path.read_bytes()).hexdigest() == engine['sha256'], 'engine bytes mismatch')
|
||||
require(isinstance(engine['version'], str) and bool(engine['version'].strip()), 'engine version required')
|
||||
require(receipt.get('engine') == engine, 'receipt engine mismatch')
|
||||
require(receipt.get('engine_started') is True and receipt.get('engine_ended') is True,
|
||||
'actual started+ended engine receipt required')
|
||||
require(type(receipt.get('started_monotonic_ns')) is int
|
||||
and type(receipt.get('ended_monotonic_ns')) is int
|
||||
and 0 < receipt['started_monotonic_ns'] < receipt['ended_monotonic_ns'], 'runtime interval required')
|
||||
|
||||
|
||||
# These facts have independent producers, never the OS trace's provenance.
|
||||
KINDS = {
|
||||
'static_import_local_affected': 'command_log',
|
||||
'exact_final_full_roster': 'roster_controller',
|
||||
'independent_claude_runtime_review': 'claude_review',
|
||||
'current_main_integration_final': 'composition_result',
|
||||
'held_gestures_deferred': 'held_gestures_document',
|
||||
'macos_windows_classification': 'platform_document',
|
||||
}
|
||||
LATER = {'independent_claude_runtime_review', 'current_main_integration_final'}
|
||||
|
||||
|
||||
def stage_report(mode):
|
||||
require(mode in ('normal_validation', 'integration_final'), 'unknown validation stage')
|
||||
return {'stage': mode, 'complete': False,
|
||||
'source_prerequisites': 'required', 'runtime_os_roster_prerequisites': 'required',
|
||||
'later_gates': {m: ('not-yet-applicable' if mode == 'normal_validation' else 'required')
|
||||
for m in sorted(LATER)}}
|
||||
|
||||
|
||||
def suite_rows(rows):
|
||||
require(isinstance(rows, list) and bool(rows), 'actual roster rows required')
|
||||
result = {}
|
||||
for row in rows:
|
||||
require(isinstance(row, dict), 'roster row object required')
|
||||
suite = row.get('test', row.get('suite', row.get('path')))
|
||||
require(isinstance(suite, str) and suite and suite not in result, 'roster suite identity/duplicate')
|
||||
require(isinstance(row.get('source_sha256'), str) and len(row['source_sha256']) == 64,
|
||||
'roster source SHA required')
|
||||
result[suite] = row
|
||||
return result
|
||||
|
||||
|
||||
def typed_document(doc, common, os_env):
|
||||
require(doc.get('kind') in KINDS.values(), 'unknown typed artifact kind')
|
||||
require(doc.get('provenance') == common, 'non-OS source provenance mismatch')
|
||||
require(not {'pid', 'session_id', 'window_size', 'monotonic_ns', 'engine', 'events'} & doc.keys(),
|
||||
'OS provenance on non-OS artifact')
|
||||
producer = doc.get('producer')
|
||||
require(isinstance(producer, dict) and set(producer) == {
|
||||
'kind', 'identity', 'pid', 'run_id', 'started_unix_ns', 'ended_unix_ns',
|
||||
'lifecycle', 'records_sha256'}, 'typed producer receipt schema')
|
||||
require(producer['kind'] == doc['kind'], 'producer kind relabelling')
|
||||
require(all(isinstance(producer[k], str) and producer[k].strip() for k in ('identity', 'run_id')),
|
||||
'producer identity/run required')
|
||||
require(type(producer['pid']) is int and producer['pid'] > 1
|
||||
and producer['pid'] != os_env['pid'] and producer['run_id'] != os_env['session_id'],
|
||||
'non-OS producer must not borrow OS identity')
|
||||
require(producer['lifecycle'] == ['started', 'ended']
|
||||
and type(producer['started_unix_ns']) is int and type(producer['ended_unix_ns']) is int
|
||||
and 0 < producer['started_unix_ns'] < producer['ended_unix_ns'], 'producer lifecycle/times')
|
||||
require(isinstance(doc.get('records'), list) and doc['records']
|
||||
and producer['records_sha256'] == canonical_sha(doc['records']), 'producer payload binding')
|
||||
return producer
|
||||
|
||||
|
||||
def verify_typed(meaning, record, doc, data, roles, docs, hashes, validated_roster, composition_result):
|
||||
kind = KINDS[meaning]
|
||||
require(doc['kind'] == kind and record.get('kind') == kind and record.get('meaning') == meaning,
|
||||
'wrong kind or meaning relabelling')
|
||||
require(not {'provenance', 'pid', 'session_id', 'window_size', 'monotonic_ns', 'action', 'engine'} & record.keys(),
|
||||
'OS provenance on non-OS record')
|
||||
producer = doc['producer']
|
||||
if kind == 'command_log':
|
||||
commands = record.get('commands')
|
||||
require(isinstance(commands, list) and commands and all(isinstance(r, dict) for r in commands), 'command log required')
|
||||
require(isinstance(record.get('results'), list) and all(type(code) is int for code in record['results'])
|
||||
and record['results'] == [r.get('exit_code') for r in commands], 'command results binding')
|
||||
for command in commands:
|
||||
require(isinstance(command.get('argv'), list) and command['argv']
|
||||
and all(isinstance(a, str) and a for a in command['argv']), 'command argv')
|
||||
require(isinstance(command.get('cwd'), str) and Path(command['cwd']).is_absolute(), 'command cwd')
|
||||
require(type(command.get('pid')) is int and command['pid'] > 1
|
||||
and command['pid'] != data['os_environment']['pid'], 'command process identity')
|
||||
require(type(command.get('exit_code')) is int and command['exit_code'] == 0, 'command failure')
|
||||
for key in ('stdout', 'stderr'):
|
||||
require(isinstance(command.get(key), str)
|
||||
and command.get(key+'_sha256') == hashlib.sha256(command[key].encode()).hexdigest(), 'command stream SHA')
|
||||
require(command.get('source_map_sha256') == canonical_sha(data['source_hashes']), 'command source map')
|
||||
require(type(command.get('started_unix_ns')) is int and type(command.get('ended_unix_ns')) is int
|
||||
and producer['started_unix_ns'] <= command['started_unix_ns'] < command['ended_unix_ns'] <= producer['ended_unix_ns'],
|
||||
'command lifecycle/times')
|
||||
elif kind == 'roster_controller':
|
||||
require(record['source_hashes'] == data['source_hashes'] and record['inputs'] == data['inputs'], 'roster input identity')
|
||||
rows = suite_rows(record['results'])
|
||||
require(canonical_sha(rows) == canonical_sha(suite_rows(validated_roster)),
|
||||
'roster differs from validated full_roster rows/source hashes')
|
||||
processes = set()
|
||||
for suite, row in rows.items():
|
||||
require(row['source_sha256'] == data['source_hashes'].get(suite), 'roster source map mismatch')
|
||||
verify_engine(data['engine'], row)
|
||||
require(type(row.get('pid')) is int and row['pid'] > 1 and row['pid'] != data['os_environment']['pid']
|
||||
and isinstance(row.get('run_id'), str) and row['run_id']
|
||||
and row['run_id'] != data['os_environment']['session_id'], 'suite process identity')
|
||||
require((row['pid'], row['run_id']) not in processes, 'suite process receipt reused')
|
||||
processes.add((row['pid'], row['run_id']))
|
||||
require(type(row.get('started_unix_ns')) is int and type(row.get('ended_unix_ns')) is int
|
||||
and producer['started_unix_ns'] <= row['started_unix_ns'] < row['ended_unix_ns'] <= producer['ended_unix_ns'],
|
||||
'suite lifecycle/times outside controller')
|
||||
elif kind == 'claude_review':
|
||||
require(record.get('reviewer') == producer['identity'] and record.get('reviewer_run_id') == producer['run_id'],
|
||||
'reviewer receipt identity')
|
||||
require(all(producer['run_id'] != item['producer']['run_id']
|
||||
and producer['identity'] != item['producer']['identity']
|
||||
for item in docs.values() if 'kind' in item and item is not doc), 'review must have independent producer')
|
||||
review = record.get('review')
|
||||
require(isinstance(review, dict) and review.get('provider') == 'Claude'
|
||||
and isinstance(review.get('text'), str) and review['text'].strip()
|
||||
and review.get('decision') == 'pass', 'actual independent Claude review artifact')
|
||||
require(record.get('review_sha256') == canonical_sha(review), 'review artifact SHA')
|
||||
runtime = {hashes[aid] for aid, item in docs.items() if 'kind' not in item or item['kind'] == 'roster_controller'}
|
||||
require(isinstance(record.get('runtime_artifact_sha256'), list)
|
||||
and set(record['runtime_artifact_sha256']) == runtime, 'review runtime artifact SHA set')
|
||||
require(review.get('runtime_artifact_sha256') == record['runtime_artifact_sha256'], 'review references runtime SHAs')
|
||||
for aid, item in docs.items():
|
||||
if hashes[aid] in runtime:
|
||||
end = item.get('producer', {}).get('ended_unix_ns') if 'kind' in item else item.get('ended_unix_ns')
|
||||
require(type(end) is int and 0 < end < producer['started_unix_ns'], 'review must follow runtime artifacts')
|
||||
elif kind == 'composition_result':
|
||||
require(composition_result == roles and isinstance(composition_result, dict), 'actual composition.py result required')
|
||||
require(record.get('result') == composition_result, 'composition result receipt mismatch')
|
||||
require(all(record.get(k) == roles.get(k) for k in ('S', 'M', 'Q', 'T', 'mode'))
|
||||
and record['mode'] == 'integration_final', 'integration roles/mode mismatch')
|
||||
else:
|
||||
require(record.get('source_map_sha256') == canonical_sha(data['source_hashes'])
|
||||
and record.get('spec_sha256') == data.get('spec_sha256') and bool(data.get('spec_sha256')),
|
||||
'document source/spec binding')
|
||||
if kind == 'platform_document':
|
||||
require(record['windows_status'] == 'NOTRUN' and record['platform'] == data['os_environment']['platform'],
|
||||
'Windows must remain separate, not accepted')
|
||||
|
||||
|
||||
def verify(data, artifacts, roles, root, *, test_only=False, validated_roster=None, composition_result=None):
|
||||
if test_only:
|
||||
require(data.get("fixture_scope") == "TEST-ONLY", "test adapter requires labelled data")
|
||||
require(set(data['conditions']) == set(MEANINGS), 'whole-eight required')
|
||||
stage = stage_report(roles.get('mode'))
|
||||
os_env = data['os_environment']
|
||||
receipt_id = os_env['receipt_artifact_id']
|
||||
docs = {aid: json.loads(row['file'].read_bytes()) for aid, row in artifacts.items()}
|
||||
receipt = docs[receipt_id]
|
||||
verify_engine(data.get('engine'), receipt)
|
||||
require(receipt.get('session_id') == os_env.get('session_id') and isinstance(receipt.get('session_id'), str)
|
||||
and receipt['session_id'], 'OS session binding missing')
|
||||
expected = {'root': str(root.resolve()), 'S': roles['S'], 'T': roles['T'],
|
||||
'source_map_sha256': canonical_sha(data['source_hashes']),
|
||||
'pid': os_env['pid'], 'session_id': os_env['session_id'], 'engine': data['engine']}
|
||||
hashes = {aid: hashlib.sha256(row['file'].read_bytes()).hexdigest() for aid, row in artifacts.items()}
|
||||
require(len(set(hashes.values())) == len(hashes), 'artifact alias/identical bytes')
|
||||
for aid, doc in docs.items():
|
||||
require(isinstance(doc, dict), 'artifact object required')
|
||||
if 'kind' in doc:
|
||||
typed_document(doc, {k: expected[k] for k in ('root', 'S', 'T', 'source_map_sha256')}, os_env)
|
||||
else:
|
||||
require(doc.get('provenance') == expected, 'artifact root/source/session/engine mismatch: '+aid)
|
||||
raw = json.dumps(doc).lower()
|
||||
require((test_only and doc.get('fixture_scope') == 'TEST-ONLY') or not any(word in raw for word in ('test-only', 'local_unit_fixture_only', 'scaffold', 'pending-template')),
|
||||
'fixture/template is not actual evidence')
|
||||
used = {receipt_id}
|
||||
linked = {link.get('artifact_id') for cond in data['conditions'].values()
|
||||
for link in cond.get('coverage', {}).values() if isinstance(link, dict) and 'artifact_id' in link}
|
||||
require(linked | used == set(artifacts), 'unreferenced filler artifacts')
|
||||
seen_records = set()
|
||||
for condition, meanings in MEANINGS.items():
|
||||
coverage = data['conditions'][condition].get('coverage')
|
||||
require(isinstance(coverage, dict) and set(coverage) == set(meanings), 'missing/extra meaning: '+condition)
|
||||
for meaning, fields in meanings.items():
|
||||
link = coverage[meaning]
|
||||
if roles['mode'] == 'normal_validation' and meaning in LATER:
|
||||
require(link == {'status': 'not-yet-applicable'}, 'later gate must be explicitly not-yet-applicable')
|
||||
continue
|
||||
require(isinstance(link, dict) and set(link) == {'artifact_id', 'pointer'}, 'coverage must point to raw record')
|
||||
aid, ptr = link['artifact_id'], link['pointer']
|
||||
require(aid in docs, 'unknown coverage artifact')
|
||||
record = pointer(docs[aid], ptr)
|
||||
require(aid in data['conditions'][condition]['artifact_ids'], 'coverage artifact absent from condition')
|
||||
require((aid, ptr) not in seen_records, 'record reused for different meanings')
|
||||
seen_records.add((aid, ptr)); used.add(aid)
|
||||
if meaning not in KINDS:
|
||||
require(record.get('action') == meaning, 'OS action does not cover meaning')
|
||||
require(all(k in record and substantive(record[k]) for k in fields), 'opaque/boolean-only evidence: '+meaning)
|
||||
if meaning in KINDS:
|
||||
require(ptr.startswith('/records/') and ptr.count('/') == 2, 'typed record pointer required')
|
||||
verify_typed(meaning, record, docs[aid], data, roles, docs, hashes, validated_roster, composition_result)
|
||||
continue
|
||||
require('kind' not in docs[aid] and 'kind' not in record, 'OS event kind relabelling')
|
||||
require(ptr.startswith('/events/') and ptr.count('/') == 2, 'coverage must point to an OS event')
|
||||
require(record.get('action') == meaning, 'OS action does not cover meaning')
|
||||
require(type(record.get('monotonic_ns')) is int
|
||||
and receipt['started_monotonic_ns'] <= record['monotonic_ns'] <= receipt['ended_monotonic_ns'],
|
||||
'record outside receipt runtime')
|
||||
require(record.get('provenance') == expected, 'record provenance mismatch')
|
||||
if meaning in ('invalid_rejection_with_reason_and_model_ledger_selection_unchanged',
|
||||
'behind_dialog_build_assignment_unchanged', 'pending_commands_save_identity',
|
||||
'presentation_model_unchanged'):
|
||||
keys = ('model', 'ledger', 'selection') if 'unchanged' in meaning else ('pending_commands', 'save_identity')
|
||||
require(all(k in record['before'] and record['before'][k] == record['after'].get(k) for k in keys),
|
||||
'state preservation mismatch')
|
||||
if condition == 'unit_bubbles':
|
||||
observed = record.get('observer_record')
|
||||
require(isinstance(observed, dict) and set(observed) == {'actor_id', 'kind', 'source_state', 'recorded_at'},
|
||||
'actual observer bubble payload required')
|
||||
require(observed['actor_id'] == record['actor_id'] and type(observed['source_state']) is int
|
||||
and type(observed['recorded_at']) is int, 'bubble observer identity/state/timestamp')
|
||||
kinds = {'zzz_state_model_render': 'zzz', 'anger_state_model_render': 'anger',
|
||||
'heart_state_model_render': 'heart', 'switching_removal': ''}
|
||||
require(observed['kind'] == kinds[meaning], 'bubble kind does not cover meaning')
|
||||
require(isinstance(record['render'], dict) and record['render'].get('actor_id') == observed['actor_id']
|
||||
and record['render'].get('kind') == observed['kind'], 'bubble render/model binding')
|
||||
if meaning.startswith('natural_'):
|
||||
observed = record.get('observer_record')
|
||||
kind = meaning.removeprefix('natural_').removesuffix('_start')
|
||||
require(isinstance(observed, dict) and set(observed) == {'kind', 'heading', 'message', 'recorded_at'}
|
||||
and observed['kind'] == kind and observed['heading'] == record['heading']
|
||||
and observed['message'] == record['message'] and type(observed['recorded_at']) is int,
|
||||
'actual cutin observer payload required')
|
||||
require(isinstance(record['production_trigger'], dict) and isinstance(record['domain_event'], dict)
|
||||
and record['domain_event'].get('event_id') and record['domain_event'].get('event_type'),
|
||||
'production trigger/event trace required; injected signals insufficient')
|
||||
if meaning == 'cross_process_restart':
|
||||
producer, consumer = record['producer'], record['consumer']
|
||||
require(isinstance(producer, dict) and isinstance(consumer, dict), 'actual restart receipts required')
|
||||
for child in (producer, consumer):
|
||||
verify_engine(data['engine'], child)
|
||||
require(type(child.get('pid')) is int and child['pid'] > 1, 'restart PID')
|
||||
require(child.get('S') == roles['S'] and child.get('T') == roles['T']
|
||||
and child.get('source_map_sha256') == expected['source_map_sha256'], 'restart source binding')
|
||||
require(all(child.get(k) == record[k] for k in ('manifest_sha256', 'world_sha256')), 'restart save mismatch')
|
||||
require(producer['pid'] != consumer['pid'], 'restart must be a separate process')
|
||||
if meaning == 'valid_commit_once':
|
||||
require(isinstance(record['command_ids'], list) and len(record['command_ids']) == 1,
|
||||
'placement must commit once')
|
||||
require(used == set(artifacts), 'unreferenced filler artifacts')
|
||||
return stage
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
|
||||
--- STDERR ---
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
stdlib checker import OK; ROOT=/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement
|
||||
|
||||
--- STDERR ---
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
|
||||
--- STDERR ---
|
||||
ERROR: Could not locate p24-operations-evidence index.json.
|
||||
Ensure BUILD_OUTPUT_DIR is set or provide --index <path>.
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"files": {
|
||||
"scenes/main/main.gd": {
|
||||
"required_count": 279,
|
||||
"reconciled_symbol_count": 279,
|
||||
"missing": 0,
|
||||
"duplicates": 0,
|
||||
"unexpected": 0,
|
||||
"body_issues": 0
|
||||
},
|
||||
"scenes/main/world_preview.gd": {
|
||||
"required_count": 179,
|
||||
"reconciled_symbol_count": 180,
|
||||
"missing": 0,
|
||||
"duplicates": 0,
|
||||
"unexpected": 0,
|
||||
"body_issues": 0
|
||||
},
|
||||
"docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json": {
|
||||
"missing": 0,
|
||||
"duplicates": 0,
|
||||
"equals_main_plus_p24_only_additions_in_order": true
|
||||
},
|
||||
"tools/regression/suite-policy.json": {
|
||||
"missing": 0,
|
||||
"duplicates": 0,
|
||||
"equals_main_plus_p24_only_additions_in_order": true
|
||||
}
|
||||
},
|
||||
"schema_checks_ok": true,
|
||||
"root_composition_dependencies": 4,
|
||||
"failures": []
|
||||
}
|
||||
|
||||
--- STDERR ---
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
|
||||
--- STDERR ---
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
|
||||
--- STDERR ---
|
||||
test_1_invented_replacement (__main__.CheckerTests) ... ok
|
||||
test_2_duplicate_padding (__main__.CheckerTests) ... ok
|
||||
test_3_unknown_extra (__main__.CheckerTests) ... ok
|
||||
test_4_required_results (__main__.CheckerTests) ... ok
|
||||
test_5_source_hash (__main__.CheckerTests) ... ok
|
||||
test_6_missing_or_malformed_rows (__main__.CheckerTests) ... ok
|
||||
test_7_env_mismatch_and_positive_head (__main__.CheckerTests) ... ok
|
||||
test_8_git_unavailable_env_only (__main__.CheckerTests) ... ok
|
||||
test_positive_roster (__main__.CheckerTests) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 9 tests in 0.473s
|
||||
|
||||
OK
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
|
||||
--- STDERR ---
|
||||
test_altered_conflict_nonconflict_and_main_only (__main__.CompositionTests) ... ok
|
||||
test_bindings_and_source_map (__main__.CompositionTests) ... ok
|
||||
test_docs_only_main_fresh_q (__main__.CompositionTests) ... ok
|
||||
test_fifth_conflict (__main__.CompositionTests) ... ok
|
||||
test_final_mode_clean_exact_parents (__main__.CompositionTests) ... ok
|
||||
test_git_environment_and_crosschecks (__main__.CompositionTests) ... ok
|
||||
test_new_main_old_q_and_stale_source_new_q (__main__.CompositionTests) ... ok
|
||||
test_outside_scope (__main__.CompositionTests) ... ok
|
||||
test_parent_order_extra_and_tree_mismatch (__main__.CompositionTests) ... ok
|
||||
test_positive_normal_and_private_objects (__main__.CompositionTests) ... ok
|
||||
test_root_context_sha_symlink_and_cwd (__main__.CompositionTests) ... ok
|
||||
test_engine_requires_actual_receipt_and_bytes (__main__.CorrespondenceTests) ... ok
|
||||
test_observer_payloads_and_pointer (__main__.CorrespondenceTests) ... ok
|
||||
test_alias_identical_bytes (__main__.CoverageAttackTests) ... ok
|
||||
test_all_true_opaque_and_scaffold (__main__.CoverageAttackTests) ... ok
|
||||
test_cross_process_and_whole_roster_engine (__main__.CoverageAttackTests) ... ok
|
||||
test_missing_meaning_reused_and_relabelled_record (__main__.CoverageAttackTests) ... ok
|
||||
test_old_catchall_plus_seven_fillers (__main__.CoverageAttackTests) ... ok
|
||||
test_one_shared_trace_distinct_records_positive (__main__.CoverageAttackTests) ... ok
|
||||
test_wrong_root_source_and_engine (__main__.CoverageAttackTests) ... ok
|
||||
test_exact_nonp24_and_schema_preservation (__main__.PreservationTests) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 21 tests in 10.582s
|
||||
|
||||
OK
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
"""TEST-ONLY synthetic stdlib/Git controls. Never acceptance/native evidence."""
|
||||
import copy
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
ROOT = HERE.parents[5]
|
||||
|
||||
def module(name, path):
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
result = importlib.util.module_from_spec(spec); spec.loader.exec_module(result)
|
||||
return result
|
||||
|
||||
c = module('composition', HERE/'composition.py')
|
||||
e = module('correspondence', HERE/'correspondence.py')
|
||||
checker = module('checker', ROOT/'tools/check_p24_operations_evidence.py')
|
||||
|
||||
class CompositionTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory(dir=os.environ['TMPDIR'], prefix='TEST-ONLY-p24-')
|
||||
self.addCleanup(self.tmp.cleanup)
|
||||
self.root = Path(self.tmp.name)
|
||||
self.git('init', '-q')
|
||||
self.git('config', 'user.name', 'TEST-ONLY')
|
||||
self.git('config', 'user.email', 'test-only@example.invalid')
|
||||
for p in c.KNOWN_CONFLICTS | {c.SPEC, 'project.godot', 'export_presets.cfg', 'Makefile', 'AGENTS.md', 'scripts/both.txt'}:
|
||||
self.write(p, 'TEST-ONLY base\n')
|
||||
self.base = self.commit('base')
|
||||
for p in c.KNOWN_CONFLICTS:
|
||||
self.write(p, 'TEST-ONLY Main\n')
|
||||
self.write('docs/main-only.txt', 'TEST-ONLY Main-only\n')
|
||||
self.m = self.commit('Main')
|
||||
self.pins = {p: c.tree(self.root, self.m)[p][2] for p in c.KNOWN_CONFLICTS}
|
||||
self.git('checkout', '-q', self.base)
|
||||
for p in c.KNOWN_CONFLICTS:
|
||||
self.write(p, 'TEST-ONLY Source\n')
|
||||
self.write('scripts/source-only.txt', 'TEST-ONLY Source-only\n')
|
||||
self.s = self.commit('Source')
|
||||
# Build Q independently with Git merge-tree/private index, then commit-tree
|
||||
# only in this throwaway TEST-ONLY repository.
|
||||
merge = c.git_process(self.root, 'merge-tree', '--write-tree', '-z', '--name-only', self.m, self.s)
|
||||
self.assertEqual(merge.returncode, 1)
|
||||
self.git('read-tree', merge.stdout.split(b'\0')[0].decode())
|
||||
for p in c.KNOWN_CONFLICTS:
|
||||
entry = c.tree(self.root, self.s)[p]
|
||||
self.git('update-index', '--cacheinfo', entry[0], entry[2], p)
|
||||
self.t = self.git('write-tree')
|
||||
self.q = self.git('commit-tree', self.t, '-p', self.m, '-p', self.s, '-m', 'TEST-ONLY Q')
|
||||
self.git('read-tree', self.s)
|
||||
self.roles = dict(S=self.s, M=self.m, Q=self.q, T=self.t, mode='normal_validation')
|
||||
tt = c.tree(self.root, self.t)
|
||||
self.sources = {p: hashlib.sha256(c.git_bytes(self.root, 'show', self.t+':'+p)).hexdigest() for p in c.source_paths(tt)}
|
||||
self.inputs = {p: hashlib.sha256(c.git_bytes(self.root, 'show', self.t+':'+p)).hexdigest()
|
||||
for p in (c.SPEC, c.CONTRACT, 'project.godot', 'tools/regression/suite-policy.json')}
|
||||
self.roles['blob_bindings'] = {p: tt[p][2] for p in self.sources.keys() | self.inputs.keys()}
|
||||
self.allowed = list(c.KNOWN_CONFLICTS) + ['scripts/source-only.txt']
|
||||
|
||||
def git(self, *args):
|
||||
return c.git_bytes(self.root, *args).decode().strip()
|
||||
|
||||
def write(self, p, text):
|
||||
target = self.root/p; target.parent.mkdir(parents=True, exist_ok=True); target.write_text(text)
|
||||
|
||||
def commit(self, message):
|
||||
self.git('add', '.'); self.git('commit', '-qm', 'TEST-ONLY '+message)
|
||||
return self.git('rev-parse', 'HEAD')
|
||||
|
||||
def verify(self, roles=None, pins=None):
|
||||
return c.verify_composition(self.root, roles or self.roles, self.sources, self.inputs,
|
||||
self.base, self.allowed, pins or self.pins)
|
||||
|
||||
def altered_q(self, path, text):
|
||||
self.git('read-tree', self.t)
|
||||
blob = c.git_process(self.root, 'hash-object', '-w', '--stdin', input=text.encode()).stdout.decode().strip()
|
||||
self.git('update-index', '--cacheinfo', '100644', blob, path)
|
||||
t = self.git('write-tree'); self.git('read-tree', self.s)
|
||||
q = self.git('commit-tree', t, '-p', self.m, '-p', self.s, '-m', 'TEST-ONLY malicious Q')
|
||||
return dict(self.roles, T=t, Q=q)
|
||||
|
||||
def test_positive_normal_and_private_objects(self):
|
||||
before = sorted(p.relative_to(self.root/'.git/objects').as_posix() for p in (self.root/'.git/objects').rglob('*'))
|
||||
self.verify()
|
||||
self.assertEqual(before, sorted(p.relative_to(self.root/'.git/objects').as_posix() for p in (self.root/'.git/objects').rglob('*')))
|
||||
with c.tested_checkout(self.root, self.t) as view:
|
||||
self.assertEqual((view/'docs/main-only.txt').read_text(), 'TEST-ONLY Main-only\n')
|
||||
|
||||
def test_altered_conflict_nonconflict_and_main_only(self):
|
||||
for p in ('scenes/main/main.gd', 'scripts/both.txt', 'docs/main-only.txt'):
|
||||
with self.subTest(path=p), self.assertRaisesRegex(ValueError, 'deterministic'):
|
||||
self.verify(self.altered_q(p, 'TEST-ONLY attacker\n'))
|
||||
self.git('read-tree', self.t)
|
||||
self.git('update-index', '--force-remove', 'docs/main-only.txt')
|
||||
t = self.git('write-tree'); self.git('read-tree', self.s)
|
||||
q = self.git('commit-tree', t, '-p', self.m, '-p', self.s, '-m', 'TEST-ONLY dropped')
|
||||
with self.assertRaises(ValueError): self.verify(dict(self.roles, T=t, Q=q))
|
||||
|
||||
def test_parent_order_extra_and_tree_mismatch(self):
|
||||
for parents in ((self.s, self.m), (self.m, self.s, self.base)):
|
||||
args = sum((['-p', p] for p in parents), [])
|
||||
q = self.git('commit-tree', self.t, *args, '-m', 'TEST-ONLY parents')
|
||||
with self.assertRaisesRegex(ValueError, 'parents'): self.verify(dict(self.roles, Q=q))
|
||||
with self.assertRaisesRegex(ValueError, 'T differs'): self.verify(dict(self.roles, T=self.git('rev-parse', self.s+'^{tree}')))
|
||||
|
||||
def test_bindings_and_source_map(self):
|
||||
for kind in ('missing', 'extra', 'changed'):
|
||||
r = copy.deepcopy(self.roles); b = r['blob_bindings']; p = next(iter(b))
|
||||
if kind == 'missing': del b[p]
|
||||
elif kind == 'extra': b['extra'] = '0'*40
|
||||
else: b[p] = '0'*40
|
||||
with self.subTest(kind=kind), self.assertRaises(ValueError): self.verify(r)
|
||||
self.sources['project.godot'] = '0'*64
|
||||
with self.assertRaisesRegex(ValueError, 'SHA256'): self.verify()
|
||||
|
||||
def test_outside_scope(self):
|
||||
self.allowed.remove('scripts/source-only.txt')
|
||||
with self.assertRaisesRegex(ValueError, 'outside'): self.verify()
|
||||
|
||||
def test_fifth_conflict(self):
|
||||
self.git('checkout', '-q', self.m); self.write('scripts/both.txt', 'TEST-ONLY M change\n'); m = self.commit('new M')
|
||||
self.git('checkout', '-q', self.s); self.write('scripts/both.txt', 'TEST-ONLY S change\n'); s = self.commit('new S')
|
||||
with self.assertRaisesRegex(ValueError, 'conflict set'): c.deterministic_tree(self.root, m, s, self.pins)
|
||||
|
||||
def test_new_main_old_q_and_stale_source_new_q(self):
|
||||
self.git('checkout', '-q', self.m); self.write('scenes/main/main.gd', 'TEST-ONLY changed M hunk\n'); m = self.commit('changed Main')
|
||||
self.git('checkout', '-q', self.s)
|
||||
with self.assertRaisesRegex(ValueError, 'parents'): self.verify(dict(self.roles, M=m))
|
||||
q = self.git('commit-tree', self.t, '-p', m, '-p', self.s, '-m', 'TEST-ONLY fresh parents stale S resolution')
|
||||
with self.assertRaisesRegex(ValueError, 'new reconciliation'): self.verify(dict(self.roles, M=m, Q=q))
|
||||
|
||||
def test_docs_only_main_fresh_q(self):
|
||||
self.git('checkout', '-q', self.m); self.write('docs/main-only.txt', 'TEST-ONLY new docs\n'); m = self.commit('docs Main')
|
||||
self.git('checkout', '-q', self.s)
|
||||
with self.assertRaisesRegex(ValueError, 'parents'): self.verify(dict(self.roles, M=m))
|
||||
# No new reconciliation needed for identical four inputs.
|
||||
self.assertRegex(c.deterministic_tree(self.root, m, self.s, self.pins), '^[0-9a-f]{40}$')
|
||||
|
||||
def test_final_mode_clean_exact_parents(self):
|
||||
self.git('checkout', '-q', self.q)
|
||||
self.verify(dict(self.roles, mode='integration_final', C=self.q))
|
||||
self.write('untracked.txt', 'TEST-ONLY dirty')
|
||||
with self.assertRaisesRegex(ValueError, 'dirty'):
|
||||
self.verify(dict(self.roles, mode='integration_final', C=self.q))
|
||||
|
||||
def test_root_context_sha_symlink_and_cwd(self):
|
||||
p = self.root/'root-composition.json'; p.write_text(json.dumps(self.roles))
|
||||
idx = {'root_composition_sha256': hashlib.sha256(p.read_bytes()).hexdigest()}
|
||||
self.assertEqual(c.root_context(self.root, idx), self.roles)
|
||||
with self.assertRaisesRegex(ValueError, 'SHA'): c.root_context(self.root, {})
|
||||
p.rename(self.root/'other.json'); p.symlink_to('other.json')
|
||||
with self.assertRaisesRegex(ValueError, 'symlink'): c.root_context(self.root, idx)
|
||||
with self.assertRaisesRegex(ValueError, 'cwd'): c.root_identity(self.root, ROOT)
|
||||
|
||||
def test_git_environment_and_crosschecks(self):
|
||||
with patch.dict(os.environ, {'GIT_DIR': str(ROOT/'.git')}):
|
||||
with self.assertRaises(ValueError): c.root_identity(self.root, self.root)
|
||||
# An index override cannot legitimately define HEAD; it must never affect
|
||||
# composition or the clean Git reads even when inherited.
|
||||
with patch.dict(os.environ, {'GIT_INDEX_FILE': str(self.root/'fake-index')}):
|
||||
self.assertEqual(c.root_identity(self.root, self.root), self.root)
|
||||
self.verify()
|
||||
with patch.dict(os.environ, {'TARGET_HEAD': '0'*40}):
|
||||
with self.assertRaises(ValueError): c.root_identity(self.root, self.root)
|
||||
|
||||
class CorrespondenceTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory(dir=os.environ['TMPDIR'], prefix='TEST-ONLY-records-'); self.addCleanup(self.tmp.cleanup)
|
||||
self.root = Path(self.tmp.name)
|
||||
self.roles = {'S': '1'*40, 'T': '2'*40}
|
||||
self.data = {'source_hashes': {'TEST-ONLY': '3'*64}, 'os_environment': {'pid': 1234, 'session_id': 'TEST-ONLY', 'receipt_artifact_id': 'receipt', 'platform': 'macOS'},
|
||||
'engine': {'path': str(self.root/'TEST-ONLY-engine'), 'sha256': '4'*64, 'version': 'TEST-ONLY'}, 'conditions': {}}
|
||||
self.prov = dict(root=str(self.root), S='1'*40, T='2'*40, source_map_sha256=e.canonical_sha(self.data['source_hashes']),
|
||||
pid=1234, session_id='TEST-ONLY', engine=self.data['engine'])
|
||||
|
||||
def test_observer_payloads_and_pointer(self):
|
||||
# Actual observer format, scoped structural controls only. It cannot be
|
||||
# promoted to OS proof: fixture_scope remains explicitly TEST-ONLY.
|
||||
doc = {'fixture_scope': 'TEST-ONLY', 'bubble_history': [dict(actor_id='worker', kind='zzz', source_state=1, recorded_at=10)],
|
||||
'modal_records': [dict(dialog_name='DefenseManager', action='open', details={'focus': 'button'}, recorded_at=11)]}
|
||||
self.assertEqual(e.pointer(doc, '/bubble_history/0')['source_state'], 1)
|
||||
self.assertEqual(e.pointer(doc, '/modal_records/0')['action'], 'open')
|
||||
self.assertFalse(e.substantive({'pass': True, 'all': True}))
|
||||
with self.assertRaises(ValueError): e.pointer(doc, '/bubble_history/00')
|
||||
|
||||
def test_engine_requires_actual_receipt_and_bytes(self):
|
||||
engine_file = self.root/'TEST-ONLY-engine'; engine_file.write_bytes(b'TEST-ONLY not executable')
|
||||
eng = dict(path=str(engine_file), sha256=hashlib.sha256(engine_file.read_bytes()).hexdigest(), version='TEST-ONLY')
|
||||
receipt = dict(engine=eng, engine_started=True, engine_ended=True, started_monotonic_ns=1, ended_monotonic_ns=2)
|
||||
e.verify_engine(eng, receipt) # fingerprint structure only, never execution
|
||||
for key in ('engine_started', 'engine_ended'):
|
||||
with self.assertRaises(ValueError): e.verify_engine(eng, dict(receipt, **{key: False}))
|
||||
with self.assertRaises(ValueError): e.verify_engine(dict(eng, sha256='0'*64), receipt)
|
||||
|
||||
class CoverageAttackTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory(dir=os.environ['TMPDIR'], prefix='TEST-ONLY-coverage-')
|
||||
self.addCleanup(self.tmp.cleanup); self.root = Path(self.tmp.name)
|
||||
engine = self.root/'engine'; engine.write_bytes(b'TEST-ONLY engine fingerprint fixture, never executed')
|
||||
self.engine = dict(path=str(engine), sha256=hashlib.sha256(engine.read_bytes()).hexdigest(), version='TEST-ONLY')
|
||||
self.roles = dict(S='1'*40, T='2'*40)
|
||||
self.data = dict(fixture_scope='TEST-ONLY', source_hashes={'TEST-ONLY': '3'*64}, inputs={'TEST-ONLY': '4'*64},
|
||||
engine=self.engine, os_environment=dict(pid=1234, session_id='TEST-ONLY', receipt_artifact_id='receipt', platform='macOS'), conditions={})
|
||||
self.prov = dict(root=str(self.root), **self.roles, source_map_sha256=e.canonical_sha(self.data['source_hashes']),
|
||||
pid=1234, session_id='TEST-ONLY', engine=self.engine)
|
||||
self.receipt = dict(engine=self.engine, engine_started=True, engine_ended=True, started_monotonic_ns=1, ended_monotonic_ns=1000)
|
||||
self.docs = {'receipt': dict(self.receipt, fixture_scope='TEST-ONLY', provenance=self.prov, session_id='TEST-ONLY'),
|
||||
'trace': dict(fixture_scope='TEST-ONLY', provenance=self.prov, events=[])}
|
||||
events = self.docs['trace']['events']
|
||||
for cond, meanings in e.MEANINGS.items():
|
||||
coverage = {}
|
||||
self.data['conditions'][cond] = dict(artifact_ids=['trace'], coverage=coverage)
|
||||
for meaning, fields in meanings.items():
|
||||
row = {k: 'TEST-ONLY observed '+k for k in fields}
|
||||
row.update(action=meaning, monotonic_ns=len(events)+2, provenance=self.prov)
|
||||
if 'before' in fields:
|
||||
row['before'] = dict(model={'value': 1}, ledger=[1], selection='worker', pending_commands=[1], save_identity='slot')
|
||||
row['after'] = copy.deepcopy(row['before'])
|
||||
if cond == 'unit_bubbles':
|
||||
kind = {'zzz_state_model_render': 'zzz', 'anger_state_model_render': 'anger', 'heart_state_model_render': 'heart', 'switching_removal': ''}[meaning]
|
||||
row['observer_record'] = dict(actor_id=row['actor_id'], kind=kind, source_state=1, recorded_at=2)
|
||||
row['render'] = dict(actor_id=row['actor_id'], kind=kind)
|
||||
if meaning.startswith('natural_'):
|
||||
row['observer_record'] = dict(kind=meaning.removeprefix('natural_').removesuffix('_start'), heading=row['heading'], message=row['message'], recorded_at=2)
|
||||
row['production_trigger'] = {'TEST-ONLY': 'synthetic fixture'}
|
||||
row['domain_event'] = dict(event_id='TEST-ONLY', event_type='TEST-ONLY')
|
||||
if meaning == 'valid_commit_once': row['command_ids'] = ['TEST-ONLY one']
|
||||
if meaning == 'macos_windows_classification': row.update(windows_status='NOTRUN', platform='macOS')
|
||||
if meaning == 'cross_process_restart':
|
||||
for n, pid in [('producer', 1234), ('consumer', 2345)]:
|
||||
row[n] = dict(self.receipt, **self.roles, pid=pid, source_map_sha256=self.prov['source_map_sha256'],
|
||||
manifest_sha256=row['manifest_sha256'], world_sha256=row['world_sha256'])
|
||||
if meaning == 'exact_final_full_roster': row.update(results=[self.receipt], source_hashes=self.data['source_hashes'], inputs=self.data['inputs'])
|
||||
coverage[meaning] = dict(artifact_id='trace', pointer='/events/'+str(len(events)))
|
||||
events.append(row)
|
||||
|
||||
# Typed synthetic producer artifacts. No real OS identity or execution.
|
||||
self.roles.update(M='5'*40, Q='6'*40, mode='integration_final')
|
||||
self.data['spec_sha256'] = '7'*64
|
||||
self.data['source_hashes'] = {'tests/TEST-ONLY.gd': '3'*64}
|
||||
self.prov['source_map_sha256'] = e.canonical_sha(self.data['source_hashes'])
|
||||
for event in events:
|
||||
if event['action'] == 'cross_process_restart':
|
||||
for child in ('producer', 'consumer'):
|
||||
event[child]['source_map_sha256'] = self.prov['source_map_sha256']
|
||||
self.validated_roster = [dict(self.receipt, test='tests/TEST-ONLY.gd', source_sha256='3'*64,
|
||||
failures=0, passed=True, pid=5432, run_id='TEST-ONLY suite',
|
||||
started_unix_ns=210, ended_unix_ns=220)]
|
||||
self.docs['receipt']['ended_unix_ns'] = 100
|
||||
self.docs['trace']['ended_unix_ns'] = 100
|
||||
typed = [row for row in events if row['action'] in e.KINDS]
|
||||
events[:] = [row for row in events if row['action'] not in e.KINDS]
|
||||
for row in typed:
|
||||
meaning = row.pop('action'); kind = e.KINDS[meaning]
|
||||
row.pop('monotonic_ns'); row.pop('provenance')
|
||||
row.update(kind=kind, meaning=meaning)
|
||||
producer = dict(kind=kind, identity='TEST-ONLY '+kind, pid=4321,
|
||||
run_id='TEST-ONLY '+kind, started_unix_ns=200, ended_unix_ns=300,
|
||||
lifecycle=['started', 'ended'])
|
||||
if kind == 'command_log':
|
||||
command = dict(argv=['TEST-ONLY'], cwd=str(self.root), exit_code=0, pid=5433,
|
||||
stdout='', stderr='', stdout_sha256=hashlib.sha256(b'').hexdigest(),
|
||||
stderr_sha256=hashlib.sha256(b'').hexdigest(), started_unix_ns=210, ended_unix_ns=220,
|
||||
source_map_sha256=self.prov['source_map_sha256'])
|
||||
row.update(commands=[command], results=[0])
|
||||
elif kind == 'roster_controller':
|
||||
row.update(results=copy.deepcopy(self.validated_roster), source_hashes=self.data['source_hashes'], inputs=self.data['inputs'])
|
||||
elif kind == 'composition_result':
|
||||
row.update(**self.roles, result=copy.deepcopy(self.roles))
|
||||
elif kind.endswith('_document'):
|
||||
row.update(source_map_sha256=self.prov['source_map_sha256'], spec_sha256=self.data['spec_sha256'])
|
||||
self.docs[kind] = dict(fixture_scope='TEST-ONLY', kind=kind,
|
||||
provenance={k: self.prov[k] for k in ('root', 'S', 'T', 'source_map_sha256')}, producer=producer, records=[row])
|
||||
review_doc = self.docs['claude_review']; review = review_doc['records'][0]
|
||||
runtime = [hashlib.sha256(json.dumps(self.docs[aid]).encode()).hexdigest() for aid in ('receipt', 'trace')]
|
||||
self.seal_typed()
|
||||
runtime.append(hashlib.sha256(json.dumps(self.docs['roster_controller']).encode()).hexdigest())
|
||||
review.update(reviewer=review_doc['producer']['identity'], reviewer_run_id=review_doc['producer']['run_id'],
|
||||
runtime_artifact_sha256=runtime,
|
||||
review=dict(provider='Claude', text='TEST-ONLY synthetic review', decision='pass', runtime_artifact_sha256=runtime))
|
||||
review['review_sha256'] = e.canonical_sha(review['review'])
|
||||
review_doc['producer'].update(started_unix_ns=400, ended_unix_ns=500)
|
||||
self.seal_typed()
|
||||
for cond, meanings in e.MEANINGS.items():
|
||||
coverage = self.data['conditions'][cond]['coverage']
|
||||
for meaning in meanings:
|
||||
if meaning in e.KINDS:
|
||||
coverage[meaning] = dict(artifact_id=e.KINDS[meaning], pointer='/records/0')
|
||||
else:
|
||||
coverage[meaning] = dict(artifact_id='trace', pointer='/events/'+str(next(i for i,r in enumerate(events) if r['action'] == meaning)))
|
||||
self.data['conditions'][cond]['artifact_ids'] = sorted({link['artifact_id'] for link in coverage.values()})
|
||||
|
||||
def seal_typed(self):
|
||||
for doc in self.docs.values():
|
||||
if 'kind' in doc:
|
||||
doc['producer']['records_sha256'] = e.canonical_sha(doc['records'])
|
||||
|
||||
def verify(self, actual=False):
|
||||
artifacts = {}
|
||||
for aid, doc in self.docs.items():
|
||||
path = self.root/(aid+'.json'); path.write_text(json.dumps(doc))
|
||||
artifacts[aid] = dict(file=path)
|
||||
return e.verify(self.data, artifacts, self.roles, self.root, test_only=not actual,
|
||||
validated_roster=self.validated_roster, composition_result=self.roles)
|
||||
|
||||
def test_one_shared_trace_distinct_records_positive(self):
|
||||
self.verify()
|
||||
# TEST-ONLY data is rejected by the actual entry point.
|
||||
with self.assertRaisesRegex(ValueError, 'fixture/template'): self.verify(actual=True)
|
||||
|
||||
def test_old_catchall_plus_seven_fillers(self):
|
||||
for i in range(7): self.docs['filler'+str(i)] = dict(fixture_scope='TEST-ONLY', provenance=self.prov, pid=100+i)
|
||||
with self.assertRaisesRegex(ValueError, 'filler'): self.verify()
|
||||
|
||||
def test_alias_identical_bytes(self):
|
||||
self.docs['alias'] = copy.deepcopy(self.docs['trace'])
|
||||
with self.assertRaisesRegex(ValueError, 'alias'): self.verify()
|
||||
|
||||
def test_missing_meaning_reused_and_relabelled_record(self):
|
||||
coverage = self.data['conditions']['placement_and_invalid_drop']['coverage']
|
||||
removed = coverage.pop('grid_snap')
|
||||
with self.assertRaisesRegex(ValueError, 'meaning'): self.verify()
|
||||
coverage['grid_snap'] = coverage['connection_warning']
|
||||
with self.assertRaisesRegex(ValueError, 'meaning|reused'): self.verify()
|
||||
coverage['grid_snap'] = removed
|
||||
self.docs['trace']['events'][0]['action'] = 'other'
|
||||
with self.assertRaisesRegex(ValueError, 'meaning'): self.verify()
|
||||
|
||||
def test_wrong_root_source_and_engine(self):
|
||||
original = copy.deepcopy(self.prov)
|
||||
for key in ('root', 'S', 'T', 'source_map_sha256', 'pid', 'session_id', 'engine'):
|
||||
self.docs['trace']['provenance'] = dict(original, **{key: 'wrong'})
|
||||
with self.subTest(key=key), self.assertRaisesRegex(ValueError, 'mismatch'): self.verify()
|
||||
self.docs['trace']['provenance'] = original
|
||||
self.docs['trace']['events'][0]['provenance'] = dict(original, S='0'*40)
|
||||
with self.assertRaisesRegex(ValueError, 'record provenance'): self.verify()
|
||||
|
||||
def test_all_true_opaque_and_scaffold(self):
|
||||
row = self.docs['trace']['events'][0]
|
||||
for k in e.MEANINGS['placement_and_invalid_drop']['grid_snap']: row[k] = {'passed': True}
|
||||
with self.assertRaisesRegex(ValueError, 'opaque'): self.verify()
|
||||
self.docs['trace']['fixture_scope'] = 'pending-template'
|
||||
with self.assertRaisesRegex(ValueError, 'fixture/template'): self.verify()
|
||||
|
||||
def test_cross_process_and_whole_roster_engine(self):
|
||||
event = next(r for r in self.docs['trace']['events'] if r['action'] == 'cross_process_restart')
|
||||
event['consumer']['pid'] = event['producer']['pid']
|
||||
with self.assertRaisesRegex(ValueError, 'separate process'): self.verify()
|
||||
event['consumer']['pid'] = 2345
|
||||
event = self.docs['roster_controller']['records'][0]
|
||||
event['results'][0]['engine'] = dict(self.engine, version='other')
|
||||
self.validated_roster = copy.deepcopy(event['results'])
|
||||
self.seal_typed()
|
||||
with self.assertRaisesRegex(ValueError, 'engine mismatch'): self.verify()
|
||||
|
||||
class PreservationTests(unittest.TestCase):
|
||||
def test_inherited_git_overrides_are_scrubbed(self):
|
||||
with patch.dict(os.environ, {'GIT_DIR': '/nonexistent/p24',
|
||||
'GIT_WORK_TREE': '/nonexistent/p24',
|
||||
'GIT_INDEX_FILE': '/nonexistent/p24'}):
|
||||
self.test_exact_nonp24_and_schema_preservation()
|
||||
|
||||
def test_exact_nonp24_and_schema_preservation(self):
|
||||
test = 'tests/ui/test_operations_notification.gd'
|
||||
digest = hashlib.sha256((ROOT/test).read_bytes()).hexdigest()
|
||||
for path, container, field in ((c.CONTRACT, 'rows', 'source_sha256_at_schema_audit'), ('tools/regression/suite-policy.json', 'suite_policies', 'source_sha256')):
|
||||
old = json.loads(c.git_bytes(ROOT, 'show', 'bd3a13405115fc9bf6c5acec55bcfef7dd15266a:'+path))
|
||||
new = json.loads((ROOT/path).read_bytes())
|
||||
rows = new[container]
|
||||
row = next(r for r in rows if r['test'] == test) if isinstance(rows, list) else rows[test]
|
||||
self.assertEqual(row[field], digest)
|
||||
old_rows = old[container]
|
||||
old_row = next(r for r in old_rows if r['test'] == test) if isinstance(old_rows, list) else old_rows[test]
|
||||
row[field] = old_row[field]
|
||||
self.assertEqual(new, old)
|
||||
self.assertEqual((ROOT/'scenes/main/world_preview.gd').read_bytes(), c.git_bytes(ROOT, 'show', 'bd3a13405115fc9bf6c5acec55bcfef7dd15266a:scenes/main/world_preview.gd'))
|
||||
old = c.git_bytes(ROOT, 'show', 'bd3a13405115fc9bf6c5acec55bcfef7dd15266a:'+test).decode()
|
||||
new = (ROOT/test).read_text()
|
||||
self.assertIn('await FixtureCleanup.free_owner_and_wait(self, main)', new)
|
||||
self.assertEqual(old[old.index('\tvar cleanup:'):], new[new.index('\tvar cleanup:'):])
|
||||
start = new.index('\t# Defense dialog uses the ordinary visibility callback')
|
||||
end = new.index('\t# Pause freezes simulation via process_real_delta', start)
|
||||
self.assertEqual(new[:start]+new[end:], old)
|
||||
main_old = c.git_bytes(ROOT, 'show', 'bd3a13405115fc9bf6c5acec55bcfef7dd15266a:scenes/main/main.gd').decode()
|
||||
self.assertEqual((ROOT/'scenes/main/main.gd').read_text(), main_old.replace(
|
||||
'\t\tadd_child(defense_manager)',
|
||||
'\t\tdefense_manager.visibility_changed.connect(_update_modal_input_guard)\n\t\tadd_child(defense_manager)'))
|
||||
for path, oid in c.MAIN_INPUTS.items():
|
||||
self.assertEqual(c.tree(ROOT, c.RECONCILED_MAIN)[path][2], oid)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=2)
|
||||
+343
@@ -0,0 +1,343 @@
|
||||
{
|
||||
"scope": "SOURCE-ONLY actual worker checks; synthetic TEST-ONLY fixtures, no acceptance/runtime proof",
|
||||
"existing_HEAD": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08",
|
||||
"environment": {
|
||||
"TMPDIR": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/P24-02/tmp",
|
||||
"TMPPREFIX": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/P24-02/tmp/p24-zsh",
|
||||
"PYTHONPYCACHEPREFIX": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/P24-02/tmp/p24-phase-pyc"
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"name": "py_compile",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"-m",
|
||||
"py_compile",
|
||||
"tools/check_p24_operations_evidence.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/test_repair6.py"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217070419420000,
|
||||
"ended_unix_ns": 1792217070498310000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/py_compile_final.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/py_compile_final.stderr.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "import",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"-c",
|
||||
"import importlib.util; s=importlib.util.spec_from_file_location('p24','tools/check_p24_operations_evidence.py'); m=importlib.util.module_from_spec(s); s.loader.exec_module(m); print('stdlib checker import OK; ROOT='+str(m.ROOT))"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217070498569000,
|
||||
"ended_unix_ns": 1792217070615361000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/import_final.stdout.log",
|
||||
"sha256": "227e4f4314d035bbceb5c19e6729cbd2a562d41fe4e619fc9b43ef06d585bbd8"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/import_final.stderr.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "repair5_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217070615651000,
|
||||
"ended_unix_ns": 1792217081062430000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair5_tests_final.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair5_tests_final.stderr.log",
|
||||
"sha256": "493a9af9fad2232faff405fe4c980b9f2d16aed498bd3050ee113033c00ebbb6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "repair6_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/test_repair6.py"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217081063000000,
|
||||
"ended_unix_ns": 1792217082071978000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair6_tests_final.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair6_tests_final.stderr.log",
|
||||
"sha256": "caa40f0804691880e2d4a6eb538b39349b0c7c1f8b1ffd675a0166b274057904"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "repair4_roster_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217082072276000,
|
||||
"ended_unix_ns": 1792217082723977000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair4_roster_tests_final.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair4_roster_tests_final.stderr.log",
|
||||
"sha256": "0adb30a92012d8b4619f01e069fc0f56ddc45daacc8c3b212a63fa832cf0b412"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "missing_real_evidence",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"tools/check_p24_operations_evidence.py",
|
||||
"--verify-only"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217082724279000,
|
||||
"ended_unix_ns": 1792217082863893000,
|
||||
"exit_code": 1,
|
||||
"expected_exit_code": 1,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/missing_real_evidence_final.stdout.log",
|
||||
"sha256": "99c1064974aee51d8216bcdf4b06bb23455486d0c33010f83c48b590e00d4269"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/missing_real_evidence_final.stderr.log",
|
||||
"sha256": "7085270e8aa6835668d4bdf5b0cf911151fd73a0de1734e700517d2d99471299"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "diff_check",
|
||||
"argv": [
|
||||
"git",
|
||||
"diff",
|
||||
"--check"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217082864195000,
|
||||
"ended_unix_ns": 1792217082886605000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/diff_check_final.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/diff_check_final.stderr.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"earlier_commands": [
|
||||
{
|
||||
"name": "py_compile",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"-m",
|
||||
"py_compile",
|
||||
"tools/check_p24_operations_evidence.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/test_repair6.py"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217025324921000,
|
||||
"ended_unix_ns": 1792217025409162000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/py_compile.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/py_compile.stderr.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "import",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"-c",
|
||||
"import importlib.util; s=importlib.util.spec_from_file_location('p24','tools/check_p24_operations_evidence.py'); m=importlib.util.module_from_spec(s); s.loader.exec_module(m); print('stdlib checker import OK; ROOT='+str(m.ROOT))"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217025409418000,
|
||||
"ended_unix_ns": 1792217025528235000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/import.stdout.log",
|
||||
"sha256": "227e4f4314d035bbceb5c19e6729cbd2a562d41fe4e619fc9b43ef06d585bbd8"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/import.stderr.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "repair5_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217025528551000,
|
||||
"ended_unix_ns": 1792217036154558000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair5_tests.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair5_tests.stderr.log",
|
||||
"sha256": "024c7b22e820ff22be9d56e5847fc3a5d8de623cf779bb9dd17944876d8339ce"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "repair6_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/test_repair6.py"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217036155059000,
|
||||
"ended_unix_ns": 1792217037444081000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair6_tests.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair6_tests.stderr.log",
|
||||
"sha256": "776bc53636215fefb415624b88a625905ceb46f32685859871e4c0f4bc99671b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "repair4_roster_tests",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement/docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217037444461000,
|
||||
"ended_unix_ns": 1792217038222625000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair4_roster_tests.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair4_roster_tests.stderr.log",
|
||||
"sha256": "3feee74bcfd21a227b7a9927fdda5eef8ae23efb890c97495630705fa07ec3d5"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "missing_real_evidence",
|
||||
"argv": [
|
||||
"/Applications/Xcode.app/Contents/Developer/usr/bin/python3",
|
||||
"tools/check_p24_operations_evidence.py",
|
||||
"--verify-only"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217038222937000,
|
||||
"ended_unix_ns": 1792217038393099000,
|
||||
"exit_code": 1,
|
||||
"expected_exit_code": 1,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/missing_real_evidence.stdout.log",
|
||||
"sha256": "99c1064974aee51d8216bcdf4b06bb23455486d0c33010f83c48b590e00d4269"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/missing_real_evidence.stderr.log",
|
||||
"sha256": "7085270e8aa6835668d4bdf5b0cf911151fd73a0de1734e700517d2d99471299"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "diff_check",
|
||||
"argv": [
|
||||
"git",
|
||||
"diff",
|
||||
"--check"
|
||||
],
|
||||
"cwd": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement",
|
||||
"started_unix_ns": 1792217038393493000,
|
||||
"ended_unix_ns": 1792217038424058000,
|
||||
"exit_code": 0,
|
||||
"expected_exit_code": 0,
|
||||
"logs": {
|
||||
"stdout": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/diff_check.stdout.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/diff_check.stderr.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"tested_source_sha256": {
|
||||
"tools/check_p24_operations_evidence.py": "6d97a687a45f177d0c8b999436afddcf1d1e399e56bcc0ea352e74b17bd92ca3",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py": "19b56e0edf74ffce0e2d62028c4c3c8bf3ed4304fa3a6c64b58ff46f2df45099",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py": "d3c8e8ea95a1b8e1d651a7af0126336e9afdd097d4bc7f298217779ecfc4b409",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/test_repair6.py": "f4e289c8a1056d12c9d5a63c4283e7bc00eb49782a897f82c339ba0b4d9292c3"
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
{
|
||||
"scope": "read-only byte checks, not runtime or acceptance",
|
||||
"HEAD": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08",
|
||||
"changed_tracked_files": [
|
||||
"docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/PROTOCOL.md",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py",
|
||||
"tools/check_p24_operations_evidence.py"
|
||||
],
|
||||
"root_context_manifest_matches": [
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair6-context-20261017/result.json",
|
||||
"sha256": "afec8969aa1a0a2338504566092493313c04c9eabea25412411de60f5e657a3f"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair6-context-20261017/stdout.log",
|
||||
"sha256": "73ce2f7b317c6ce9dc2e6d224e5108550e31bc6ea4c459aa9327e3374f8e199f"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair6-context-20261017/stderr.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair6-context-20261017/command.json",
|
||||
"sha256": "ceeb13991ce637b6d0cb4f1c2206c4b105934887b2bb82549d3aa5e98222944d"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair6-context-20261017/packet.txt",
|
||||
"sha256": "bae2c7759d01ae8db80c923414a865bd81a8c5f668b8a0fb3a9857aa74a7d328"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair6-context-20261017/sandbox.sb",
|
||||
"sha256": "82aaea232b1c988582f5695263444f00f5c9e39ce05e71496566d731112ae709"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair6-context-20261017/ACTUAL_REPAIR5_PREPARED_COMPOSITION.json",
|
||||
"sha256": "8f168e7a693ad9c9fbcf579abdb7bb89fc47684d15bd6b502e008bcfa1fcda50"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-repair6-context-20261017/ROOT_REPAIR5_LOCAL_PROOF_REAUDIT.json",
|
||||
"sha256": "80f0a8eea3ca917534a0304c031295d15de639e547fad3753394c8255f7e5e67"
|
||||
}
|
||||
],
|
||||
"protected_tracked_files": [
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/REPAIR4_CODE_PHASE_STATUS.md",
|
||||
"sha256": "8d18133375c2776a2ba627143c30188b0dd6cf0ce467ae3edd1edac0186f58cb",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/SOURCE_READY_PRESERVATION_RESULT.json",
|
||||
"sha256": "94388558fcb52b98abc27fb8f0ea88dfb395167f69db4e452b1e40ccbf6a6771",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/check_repair4_preservation.py",
|
||||
"sha256": "e7dc30bcd56dcdf3f057131bf5dc9a3a672e357bc9b8e5bf2b818d3302d4c83a",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/repair4/test_checker_roster_head.py",
|
||||
"sha256": "5c10efe7a9c6b3d290020f8dfbb2431956b3dafff7abdd4859b8e6d83e1d9365",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/LOCAL_COMMAND_RESULTS.json",
|
||||
"sha256": "aacde68f9d6909c1c347197b257fa31a66d3e7519c01e16c79fd45aba6e8d82f",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/REFERENCE_INTEGRITY.json",
|
||||
"sha256": "be8549f3f6462757c7fb1bc664ccd6c5165f09e2eee4468aec75a8d84e4addf9",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/SOURCE_MANIFEST.json",
|
||||
"sha256": "09f8e61b49c6c590f347928e35074aaef9fb90abdb7ac6e3a930d1ded4fe059e",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/STATUS.json",
|
||||
"sha256": "b27c9bf3d75e59544528605413d4253b0c88e91298f6fb6c561a12b3aa0b26bd",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/composition.py",
|
||||
"sha256": "b2fc058b1589310499917c8c5fad056fd8861ccf6bb32dd3ce205d367f493864",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/diff_check.log",
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/import.log",
|
||||
"sha256": "4a2fe8c27abe4d9c077ca3701b07ee860d4673f93267e4ae4697638a1f2254c9",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/missing_real_evidence.log",
|
||||
"sha256": "e1f4250f0078f0a88e8fd4ec485386ab67e835d0e966e609def115de00f4c48c",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/preservation.log",
|
||||
"sha256": "7e6691b7ae2ae94f956758a8907d3d67db29b9642ed0aecbfbc94421dcbdbace",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/py_compile.log",
|
||||
"sha256": "169f24774e13a79b6341d6c41c58f159e180701e87e9028aa70afdf8712b6fbb",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair4_tests.log",
|
||||
"sha256": "d3852846638752b6f8421776da825a037228ead8c67333c6b14e93a2fffb8f7a",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/repair5_tests.log",
|
||||
"sha256": "48a4c44bd1f5f94faa0f78f14afea371f04d4e9652c89fc8dcad91a24e7cf836",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "scenes/main/main.gd",
|
||||
"sha256": "35c3cec2d1d13f56c1635010a5811c853d7fb42e13b8d2af6cfe8261832be6c6",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "scenes/main/world_preview.gd",
|
||||
"sha256": "8c2daa9e95d56e6e40bb2071b206693069cb7e4731b4d660d59d41c34cb43dfa",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "tests/ui/test_operations_notification.gd",
|
||||
"sha256": "50172ab6daa031d221f6a78cac5cdbcb8884f295f8062b54656562e2412faff2",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "tools/regression/suite-policy.json",
|
||||
"sha256": "93178d9f68b15307158f1050993bdc75d8790d65ebe75400a3572978e37ec26a",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json",
|
||||
"sha256": "d3599139e2358c1ac9edb5059a823880f72efe5ff457da2887114c243139f743",
|
||||
"identical_to": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08"
|
||||
}
|
||||
],
|
||||
"world_preview_identical_to_pinned_baseline": true
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
# Repair6 source/local protocol — not acceptance
|
||||
|
||||
Scope is only M1 and M2 from actual f725571e5b46473ea04a90424a404bd5. Current worker HEAD is 78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08; edits are uncommitted. No real index is supplied or created. All eight groups remain unaccepted; original 30/88 and formal14 are unchanged. No Godot, native, OS, full-roster or Windows execution occurred. Synthetic TEST-ONLY fixtures never become evidence.
|
||||
|
||||
The repair5 composition.py is byte-identical (SHA256 b2fc058b1589310499917c8c5fad056fd8861ccf6bb32dd3ce205d367f493864). Its original root, S/M/Q/T, mode, deterministic composition, complete source map, helper pins and source/checkout guards still apply. No new composition implementation or alternate result flag exists. Main, world_preview, UI tests, marker and policy are unchanged in repair6. The optional defense-test positive control and unrelated low findings are deferred.
|
||||
|
||||
## Preservation
|
||||
|
||||
All three source comparisons in PreservationTests use bd3a13405115fc9bf6c5acec55bcfef7dd15266a, as do the JSON comparisons. Reads use composition.git_bytes, which strips every inherited GIT_* variable. A negative-environment control supplies invalid GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE and still runs the entire preservation check. world_preview must match baseline bytes; main must contain exactly the existing callback delta; the UI test must contain exactly the existing added block. There is no moving HEAD baseline or trivial baseline==HEAD success path.
|
||||
|
||||
Local checks only describe these uncommitted worker bytes. Root must normally submit, then run test_repair5.py and test_repair6.py at the actual new S and actual prepared Q before heavier tests, followed by the actual independent limited Opus review. This worker does not claim post-submit reproducibility has been observed.
|
||||
|
||||
## Stage applicability
|
||||
|
||||
Mode comes from the verified root-composition.json, never an index waiver. Both modes require all eight condition keys, every applicable runtime/OS meaning, static/import/local commands, full roster, source/config/engine bindings, original content guards, IME/save/restart and Windows classification.
|
||||
|
||||
In normal_validation HEAD must be S. The final_validation_review group has passed=false and status=prerequisites-only. Its static_import_local_affected and exact_final_full_roster coverage links remain mandatory. Its independent_claude_runtime_review and current_main_integration_final coverage values must each be exactly {"status":"not-yet-applicable"}. They are not satisfied or synthesized; later artifacts cannot be slipped into normal validation as fillers. Other groups retain their strict passed=true declaration plus substantive evidence. Successful normal verification reports only source/runtime/OS/roster prerequisites and explicitly P24-02 NOT complete, all eight unaccepted.
|
||||
|
||||
integration_final requires every original group and every meaning, including actual typed independent review and composition records. Every group retains passed=true plus actual evidence checks. A boolean never substitutes for a record. composition.py independently requires C=HEAD, clean checkout, exact parents and T. Successful machine verification still does not confer independent formal acceptance.
|
||||
|
||||
Stage reporting lists source/runtime prerequisites and later gates before checking. After composition it reports source verification; runtime failure remains NOT VERIFIED. If there is no index, no stage or prerequisites are established and completion is explicitly denied.
|
||||
|
||||
## OS versus other producers
|
||||
|
||||
OS/runtime meanings retain /events/N, action==meaning, the existing in-window monotonic_ns, and exact root/S/T/source-map/pid/session/engine provenance. All bubble/cutin/restart/save/IME guards remain. The OS engine receipt and runtime trace also need genuine ended_unix_ns when a later independent review references them. This is their real artifact-end time, not a review event inserted into their monotonic window.
|
||||
|
||||
The six non-OS meanings use separate JSON artifacts, with kind, provenance, producer and records. Their provenance is exactly {root,S,T,source_map_sha256}; no OS pid/session/window/engine fields. Coverage points to /records/N. Each record carries its exact kind and meaning. Wrong-kind relabelling, OS action/time/provenance on a typed record and OS metadata on a typed artifact are rejected. Artifacts still require the outer index's file SHA verification, distinct bytes, meaningful coverage and no fillers. Existing legacy substantive content fields can coexist on the appropriate artifact; the typed coverage does not replace those checks.
|
||||
|
||||
Each producer receipt has exactly kind, identity, pid, run_id, started_unix_ns, ended_unix_ns, lifecycle and records_sha256. kind matches the artifact and record kind. Identity/run are nonempty, pid is a real producer process separate from the OS PID, and run_id must not borrow the OS session. lifecycle is ["started","ended"], times are positive increasing actual Unix nanoseconds, and records_sha256 binds the canonical records array. Canonical SHA means UTF-8 JSON, sorted keys, compact separators, ensure_ascii=false. Root must collect actual producer receipts; these fields do not authenticate themselves and require independent inspection of the real logs. Never invent identities or timestamps to populate this schema.
|
||||
|
||||
- static_import_local_affected → command_log. commands contains actual argv, absolute cwd, child pid, exit_code=0, stdout/stderr text and their UTF-8 SHAs, source_map_sha256 and start/end Unix nanoseconds within the command producer's lifecycle. results equals the command exit-code list. These are the actual completed commands, not OS events.
|
||||
- exact_final_full_roster → roster_controller. The controller receipt binds results, source_hashes and inputs. The checker passes the exact row objects successfully validated by _validate_condition_artifact_content to correspondence. Coverage results must have equal unique suite-id sets, source hashes and complete row contents (order is immaterial), and each suite SHA must equal the source map. Receipt-only results, altered rows, duplicates or different suites fail. Every row additionally passes verify_engine and carries its own pid/run_id and start/end Unix times within the controller interval; process/run pairs cannot be reused. Row engine monotonic intervals are local to that engine, not the OS window.
|
||||
- independent_claude_runtime_review → claude_review. reviewer and reviewer_run_id match the independent producer receipt; its identity/run differ from the other typed producers. review is the actual embedded review artifact with provider=Claude, nonempty text, decision=pass and runtime_artifact_sha256; review_sha256 binds its canonical content. Both the review and coverage record reference exactly the actual SHA set of all runtime artifacts (including OS receipt/trace) and the roster-controller artifact. Review producer start must follow their real artifact end times. No OS timestamp is needed.
|
||||
- current_main_integration_final → composition_result. S/M/Q/T/mode match the verified roles, mode is integration_final, and result equals the actual dictionary returned by composition.verify_composition during this checker execution, including C and blob bindings. The producer receipt binds the archived result to the run. True/false cannot replace this result and no composition rules are duplicated.
|
||||
- held_gestures_deferred → held_gestures_document. Retains remaining_scope and source_reference and binds source_map_sha256 plus the frozen spec_sha256. P23 held gestures remain deferred, not waived.
|
||||
- macos_windows_classification → platform_document. Also binds source/spec; platform matches the actual OS environment and windows_status must stay NOTRUN. Same-release Windows device acceptance remains a later required platform gate.
|
||||
|
||||
## Local proof and handoff
|
||||
|
||||
LOCAL_COMMAND_RESULTS.json and separate stdout/stderr files capture actual source-only worker checks; SOURCE_MANIFEST.json binds the authored files and preserved inputs. These are not a production acceptance index. Prior repair5 raw proofs and STATUS remain unchanged and historical. Tests include positive typed/stage controls, wrong-kind and producer/lifecycle negatives, command stream/source errors, exact validated roster row handoff, review SHA/time/reference errors, composition-result mismatch, document bindings, normal-stage exclusions and final whole-eight enforcement.
|
||||
|
||||
Root owns lease/process checks, normal submit, exact-S/Q reruns, independent limited review, all runtime/native/OS/full-roster collection, whole-eight runtime review and final integration validation. Natural invasion/duel/defense upstream triggers, actual bubble rendering, staff-panel OS click, IME/save/scales, Windows and all other gaps remain as listed in STATUS.json. There is no new acceptance credit or change to task registration, contract or denominator.
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"task_id": "P24-02",
|
||||
"existing_HEAD": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08",
|
||||
"scope": "Uncommitted repair6 source/local files only; not acceptance. Excludes itself and preexisting Root context/cache. Protected inputs are bound in PRESERVATION_AND_CONTEXT.json.",
|
||||
"files": [
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/PROTOCOL.md",
|
||||
"bytes": 6909,
|
||||
"sha256": "5957906580486513ce1569985903396d8c878f3ccb95188292d7ccf10972d14b",
|
||||
"git_blob_sha1": "638b416713b4337ce37e78e4b6b2564360f89e8f"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/correspondence.py",
|
||||
"bytes": 22489,
|
||||
"sha256": "19b56e0edf74ffce0e2d62028c4c3c8bf3ed4304fa3a6c64b58ff46f2df45099",
|
||||
"git_blob_sha1": "62fea34b77926c0fe13703843a73668cc962ceca"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/test_repair5.py",
|
||||
"bytes": 25962,
|
||||
"sha256": "d3c8e8ea95a1b8e1d651a7af0126336e9afdd097d4bc7f298217779ecfc4b409",
|
||||
"git_blob_sha1": "10bee7082c38ae7d337e170f42865f70975147a5"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/LOCAL_COMMAND_RESULTS.json",
|
||||
"bytes": 17465,
|
||||
"sha256": "a0f3a59b641c09a0df71932eb86bb6af6a6011977a3d96eb1a70ad2629869929",
|
||||
"git_blob_sha1": "243ca32d9ae92bea53fd53832e9708acd988ae68"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/PRESERVATION_AND_CONTEXT.json",
|
||||
"bytes": 8077,
|
||||
"sha256": "edd211d6a107e4998caaa879a1426ba40a3b84e0243eeda0ca597d46133d4178",
|
||||
"git_blob_sha1": "90730bd7ef5f8336a6bfa0eaa840e71631bc10ec"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/PROTOCOL.md",
|
||||
"bytes": 8937,
|
||||
"sha256": "6f315d6e73d4526727d26a9d69c29dd222ead2c1499da06e4f6efaa2fef84a56",
|
||||
"git_blob_sha1": "d1f35a0806ce7d633b5db91fa55b232ff016cca3"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/STATUS.json",
|
||||
"bytes": 5364,
|
||||
"sha256": "2f557bb3f965e1957ae87b2003cc75be03f06c4a24d503b85ae8748882948ea4",
|
||||
"git_blob_sha1": "28b7bc851f7476b1a49afdbb95fb922c7c2e5b43"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/diff_check.stderr.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/diff_check.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/diff_check_final.stderr.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/diff_check_final.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/import.stderr.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/import.stdout.log",
|
||||
"bytes": 121,
|
||||
"sha256": "227e4f4314d035bbceb5c19e6729cbd2a562d41fe4e619fc9b43ef06d585bbd8",
|
||||
"git_blob_sha1": "880d13f6b8240144f13f6d72dd9076939cc575a9"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/import_final.stderr.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/import_final.stdout.log",
|
||||
"bytes": 121,
|
||||
"sha256": "227e4f4314d035bbceb5c19e6729cbd2a562d41fe4e619fc9b43ef06d585bbd8",
|
||||
"git_blob_sha1": "880d13f6b8240144f13f6d72dd9076939cc575a9"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/missing_real_evidence.stderr.log",
|
||||
"bytes": 118,
|
||||
"sha256": "7085270e8aa6835668d4bdf5b0cf911151fd73a0de1734e700517d2d99471299",
|
||||
"git_blob_sha1": "4dad6858c0bdc83821363c91e49760f29513596a"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/missing_real_evidence.stdout.log",
|
||||
"bytes": 87,
|
||||
"sha256": "99c1064974aee51d8216bcdf4b06bb23455486d0c33010f83c48b590e00d4269",
|
||||
"git_blob_sha1": "a39487f1ca9b0802793e09b7fd7b450ab31d8920"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/missing_real_evidence_final.stderr.log",
|
||||
"bytes": 118,
|
||||
"sha256": "7085270e8aa6835668d4bdf5b0cf911151fd73a0de1734e700517d2d99471299",
|
||||
"git_blob_sha1": "4dad6858c0bdc83821363c91e49760f29513596a"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/missing_real_evidence_final.stdout.log",
|
||||
"bytes": 87,
|
||||
"sha256": "99c1064974aee51d8216bcdf4b06bb23455486d0c33010f83c48b590e00d4269",
|
||||
"git_blob_sha1": "a39487f1ca9b0802793e09b7fd7b450ab31d8920"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/py_compile.stderr.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/py_compile.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/py_compile_final.stderr.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/py_compile_final.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair4_roster_tests.stderr.log",
|
||||
"bytes": 618,
|
||||
"sha256": "3feee74bcfd21a227b7a9927fdda5eef8ae23efb890c97495630705fa07ec3d5",
|
||||
"git_blob_sha1": "8e6170ce10bcfa9f1c531b30eb678cf2ce371b17"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair4_roster_tests.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair4_roster_tests_final.stderr.log",
|
||||
"bytes": 618,
|
||||
"sha256": "0adb30a92012d8b4619f01e069fc0f56ddc45daacc8c3b212a63fa832cf0b412",
|
||||
"git_blob_sha1": "1cfb9aee720ec6a2339019eb5cb770eb6b52796b"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair4_roster_tests_final.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair5_tests.stderr.log",
|
||||
"bytes": 1718,
|
||||
"sha256": "024c7b22e820ff22be9d56e5847fc3a5d8de623cf779bb9dd17944876d8339ce",
|
||||
"git_blob_sha1": "adb56f4847071456bd9ef6fbe0c3b598bcc0ed97"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair5_tests.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair5_tests_final.stderr.log",
|
||||
"bytes": 1718,
|
||||
"sha256": "493a9af9fad2232faff405fe4c980b9f2d16aed498bd3050ee113033c00ebbb6",
|
||||
"git_blob_sha1": "07c6e7a905be522e3e3b2c8085059f139fefdfa4"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair5_tests_final.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair6_tests.stderr.log",
|
||||
"bytes": 1172,
|
||||
"sha256": "776bc53636215fefb415624b88a625905ceb46f32685859871e4c0f4bc99671b",
|
||||
"git_blob_sha1": "28260c3efb2fe539f96c980317889269e4538336"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair6_tests.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair6_tests_final.stderr.log",
|
||||
"bytes": 1172,
|
||||
"sha256": "caa40f0804691880e2d4a6eb538b39349b0c7c1f8b1ffd675a0166b274057904",
|
||||
"git_blob_sha1": "3c69fbbfd0c42493575cd87f8227dd789595526a"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/repair6_tests_final.stdout.log",
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"git_blob_sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair6-20261017/test_repair6.py",
|
||||
"bytes": 11168,
|
||||
"sha256": "f4e289c8a1056d12c9d5a63c4283e7bc00eb49782a897f82c339ba0b4d9292c3",
|
||||
"git_blob_sha1": "da0840cd0931e185841443dd99c285a2a9e0346d"
|
||||
},
|
||||
{
|
||||
"path": "tools/check_p24_operations_evidence.py",
|
||||
"bytes": 40557,
|
||||
"sha256": "6d97a687a45f177d0c8b999436afddcf1d1e399e56bcc0ea352e74b17bd92ca3",
|
||||
"git_blob_sha1": "a526eda4f58ae4a5cb04aed0b81afa166be6d138"
|
||||
}
|
||||
]
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"task_id": "P24-02",
|
||||
"source": "78f7cba7a9fb5e5dcb144758e1a86fe63b3d7d08",
|
||||
"phase": "non-UI source/local repair6; uncommitted worker bytes",
|
||||
"acceptance_ids": [],
|
||||
"native_runs": 0,
|
||||
"full_roster_runs": 0,
|
||||
"game_completion_credit": 0,
|
||||
"conditions": {
|
||||
"placement_and_invalid_drop": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Native placement/rejection/ledger/selection and actual staff-panel OS click coverage NOTRUN."
|
||||
},
|
||||
"modal_and_pause_resume": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Defense modal test source added; native execution, pending-command/save identity, ordinary pause/resume and actual separate-process save restart NOTRUN."
|
||||
},
|
||||
"unit_bubbles": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Bubble native render/model/state switching and removal NOTRUN. First-relationship order, heart semantics and O(N²) scan remain whole-eight review candidates."
|
||||
},
|
||||
"event_log": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Current exact-source production bounded log/Japanese sequence/amount/time/reason/pause/load evidence NOTRUN; historical evidence is not current acceptance."
|
||||
},
|
||||
"important_warning_cutin": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Natural NTR/duel/defense production triggers require whole P18-01/02, P19, P21 inputs. P18 backend 265ce30 is a completed ancestor and is not restarted. Unknown production initial values remain unresolved; no new values added."
|
||||
},
|
||||
"click_alternatives": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Actual staff-panel facility_option/apply_button OS click and navigation coverage NOTRUN. Direct handler calls are not map-click evidence. P23 held gestures remain deferred."
|
||||
},
|
||||
"japanese_input_and_scale": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "OS IME composition/confirm/cancel, persisted save display, scale/focus/clipping and old-save protection NOTRUN. Same-Windows-release device evidence unavailable and still required."
|
||||
},
|
||||
"final_validation_review": {
|
||||
"source_status": "SOURCE-READY",
|
||||
"runtime_status": "NOTRUN",
|
||||
"accepted": false,
|
||||
"gap": "Only worker stdlib/compile/import checks passed. Actual post-submit S/Q reruns and independent limited source review are NOTRUN. Actual import/affected game tests, native/OS collection, exact-final full roster, whole-eight runtime review, integration/final and Windows remain Root-owned. No real acceptance index exists."
|
||||
}
|
||||
},
|
||||
"denominator": {
|
||||
"packages": 30,
|
||||
"units": 88,
|
||||
"completed": 14,
|
||||
"partial_credit": false
|
||||
},
|
||||
"root_next_gate": "Verify this local proof; normal submit; rerun targeted stdlib tests at actual committed S and actual Q; independent limited Opus review; later import/affected, native/OS, exact-final full roster, independent whole-eight runtime review, normal integration and final validation.",
|
||||
"local_checks": {
|
||||
"py_compile_exit": 0,
|
||||
"python_import_exit": 0,
|
||||
"repair5_stdlib_git_tests": 22,
|
||||
"repair6_stdlib_tests": 12,
|
||||
"preserved_roster_head_tests": 9,
|
||||
"total_tests": 43,
|
||||
"all_test_exits": 0,
|
||||
"diff_check_exit": 0,
|
||||
"missing_real_evidence_exit": 1,
|
||||
"raw_results": "LOCAL_COMMAND_RESULTS.json",
|
||||
"source_hashes": "SOURCE_MANIFEST.json",
|
||||
"preservation_and_root_context": "PRESERVATION_AND_CONTEXT.json",
|
||||
"actual_new_S_rerun": "NOTRUN; Root-owned after normal submit",
|
||||
"actual_new_Q_rerun": "NOTRUN; Root-owned before heavy/native gates"
|
||||
},
|
||||
"status": "SOURCE-READY / runtime NOTRUN",
|
||||
"os_runs": 0,
|
||||
"fixed_findings": {
|
||||
"M1": "Pinned all preservation baseline reads to bd3a134; composition.git_bytes scrubs inherited GIT_*; added override test. Current worker check only.",
|
||||
"M2": "Typed non-OS artifacts and actual producer receipts; canonical full-row equality to the legacy-validated roster objects, exact suite/source hashes and per-row engine/process checks; explicit normal/final applicability and whole-eight guards."
|
||||
},
|
||||
"historical_proof": "Repair5 raw logs, manifests and STATUS are unchanged old-source history; not proof for these repair6 bytes.",
|
||||
"preserved": "composition.py, world_preview, main.gd, UI test, marker/policy and all repair4 files unchanged. No marker/policy rebind was needed.",
|
||||
"deferred_low_findings": "Optional defense positive control and unrelated low cleanup deferred; no new interaction.",
|
||||
"stage_applicability": {
|
||||
"normal_validation": {
|
||||
"source_runtime_os_roster": "required actual prerequisites; not fulfilled by worker unit tests",
|
||||
"independent_claude_runtime_review": "not-yet-applicable",
|
||||
"current_main_integration_final": "not-yet-applicable",
|
||||
"complete": false
|
||||
},
|
||||
"integration_final": "Every original condition and meaning required, including actual typed independent runtime review and composition result. No boolean substitute, waiver or partial credit."
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
stdlib checker import OK; ROOT=/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement
|
||||
+1
@@ -0,0 +1 @@
|
||||
stdlib checker import OK; ROOT=/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/P24-02-implement
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ERROR: Could not locate p24-operations-evidence index.json.
|
||||
Ensure BUILD_OUTPUT_DIR is set or provide --index <path>.
|
||||
+1
@@ -0,0 +1 @@
|
||||
Source/runtime prerequisites NOT VERIFIED; stage not established; P24-02 NOT complete.
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ERROR: Could not locate p24-operations-evidence index.json.
|
||||
Ensure BUILD_OUTPUT_DIR is set or provide --index <path>.
|
||||
+1
@@ -0,0 +1 @@
|
||||
Source/runtime prerequisites NOT VERIFIED; stage not established; P24-02 NOT complete.
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
test_1_invented_replacement (__main__.CheckerTests) ... ok
|
||||
test_2_duplicate_padding (__main__.CheckerTests) ... ok
|
||||
test_3_unknown_extra (__main__.CheckerTests) ... ok
|
||||
test_4_required_results (__main__.CheckerTests) ... ok
|
||||
test_5_source_hash (__main__.CheckerTests) ... ok
|
||||
test_6_missing_or_malformed_rows (__main__.CheckerTests) ... ok
|
||||
test_7_env_mismatch_and_positive_head (__main__.CheckerTests) ... ok
|
||||
test_8_git_unavailable_env_only (__main__.CheckerTests) ... ok
|
||||
test_positive_roster (__main__.CheckerTests) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 9 tests in 0.569s
|
||||
|
||||
OK
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
test_1_invented_replacement (__main__.CheckerTests) ... ok
|
||||
test_2_duplicate_padding (__main__.CheckerTests) ... ok
|
||||
test_3_unknown_extra (__main__.CheckerTests) ... ok
|
||||
test_4_required_results (__main__.CheckerTests) ... ok
|
||||
test_5_source_hash (__main__.CheckerTests) ... ok
|
||||
test_6_missing_or_malformed_rows (__main__.CheckerTests) ... ok
|
||||
test_7_env_mismatch_and_positive_head (__main__.CheckerTests) ... ok
|
||||
test_8_git_unavailable_env_only (__main__.CheckerTests) ... ok
|
||||
test_positive_roster (__main__.CheckerTests) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 9 tests in 0.455s
|
||||
|
||||
OK
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
test_altered_conflict_nonconflict_and_main_only (__main__.CompositionTests) ... ok
|
||||
test_bindings_and_source_map (__main__.CompositionTests) ... ok
|
||||
test_docs_only_main_fresh_q (__main__.CompositionTests) ... ok
|
||||
test_fifth_conflict (__main__.CompositionTests) ... ok
|
||||
test_final_mode_clean_exact_parents (__main__.CompositionTests) ... ok
|
||||
test_git_environment_and_crosschecks (__main__.CompositionTests) ... ok
|
||||
test_new_main_old_q_and_stale_source_new_q (__main__.CompositionTests) ... ok
|
||||
test_outside_scope (__main__.CompositionTests) ... ok
|
||||
test_parent_order_extra_and_tree_mismatch (__main__.CompositionTests) ... ok
|
||||
test_positive_normal_and_private_objects (__main__.CompositionTests) ... ok
|
||||
test_root_context_sha_symlink_and_cwd (__main__.CompositionTests) ... ok
|
||||
test_engine_requires_actual_receipt_and_bytes (__main__.CorrespondenceTests) ... ok
|
||||
test_observer_payloads_and_pointer (__main__.CorrespondenceTests) ... ok
|
||||
test_alias_identical_bytes (__main__.CoverageAttackTests) ... ok
|
||||
test_all_true_opaque_and_scaffold (__main__.CoverageAttackTests) ... ok
|
||||
test_cross_process_and_whole_roster_engine (__main__.CoverageAttackTests) ... ok
|
||||
test_missing_meaning_reused_and_relabelled_record (__main__.CoverageAttackTests) ... ok
|
||||
test_old_catchall_plus_seven_fillers (__main__.CoverageAttackTests) ... ok
|
||||
test_one_shared_trace_distinct_records_positive (__main__.CoverageAttackTests) ... ok
|
||||
test_wrong_root_source_and_engine (__main__.CoverageAttackTests) ... ok
|
||||
test_exact_nonp24_and_schema_preservation (__main__.PreservationTests) ... ok
|
||||
test_inherited_git_overrides_are_scrubbed (__main__.PreservationTests) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 22 tests in 10.413s
|
||||
|
||||
OK
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
test_altered_conflict_nonconflict_and_main_only (__main__.CompositionTests) ... ok
|
||||
test_bindings_and_source_map (__main__.CompositionTests) ... ok
|
||||
test_docs_only_main_fresh_q (__main__.CompositionTests) ... ok
|
||||
test_fifth_conflict (__main__.CompositionTests) ... ok
|
||||
test_final_mode_clean_exact_parents (__main__.CompositionTests) ... ok
|
||||
test_git_environment_and_crosschecks (__main__.CompositionTests) ... ok
|
||||
test_new_main_old_q_and_stale_source_new_q (__main__.CompositionTests) ... ok
|
||||
test_outside_scope (__main__.CompositionTests) ... ok
|
||||
test_parent_order_extra_and_tree_mismatch (__main__.CompositionTests) ... ok
|
||||
test_positive_normal_and_private_objects (__main__.CompositionTests) ... ok
|
||||
test_root_context_sha_symlink_and_cwd (__main__.CompositionTests) ... ok
|
||||
test_engine_requires_actual_receipt_and_bytes (__main__.CorrespondenceTests) ... ok
|
||||
test_observer_payloads_and_pointer (__main__.CorrespondenceTests) ... ok
|
||||
test_alias_identical_bytes (__main__.CoverageAttackTests) ... ok
|
||||
test_all_true_opaque_and_scaffold (__main__.CoverageAttackTests) ... ok
|
||||
test_cross_process_and_whole_roster_engine (__main__.CoverageAttackTests) ... ok
|
||||
test_missing_meaning_reused_and_relabelled_record (__main__.CoverageAttackTests) ... ok
|
||||
test_old_catchall_plus_seven_fillers (__main__.CoverageAttackTests) ... ok
|
||||
test_one_shared_trace_distinct_records_positive (__main__.CoverageAttackTests) ... ok
|
||||
test_wrong_root_source_and_engine (__main__.CoverageAttackTests) ... ok
|
||||
test_exact_nonp24_and_schema_preservation (__main__.PreservationTests) ... ok
|
||||
test_inherited_git_overrides_are_scrubbed (__main__.PreservationTests) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 22 tests in 10.241s
|
||||
|
||||
OK
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
test_checker_stage_declarations_no_boolean_substitute (__main__.TypedProducerTests) ... ok
|
||||
test_command_schema_source_stream_and_result_negatives (__main__.TypedProducerTests) ... ok
|
||||
test_composition_receipt_requires_actual_result (__main__.TypedProducerTests) ... ok
|
||||
test_document_bindings_and_windows_notrun (__main__.TypedProducerTests) ... ok
|
||||
test_each_kind_positive_and_both_stages (__main__.TypedProducerTests) ... ok
|
||||
test_each_kind_rejects_relabelling_and_os_provenance (__main__.TypedProducerTests) ... ok
|
||||
test_final_requires_every_original_condition_and_later_meaning (__main__.TypedProducerTests) ... ok
|
||||
test_normal_cannot_synthesize_later_gates_or_skip_runtime (__main__.TypedProducerTests) ... ok
|
||||
test_review_artifact_references_and_chronology (__main__.TypedProducerTests) ... ok
|
||||
test_roster_process_receipts_cannot_borrow_os_identity_or_window (__main__.TypedProducerTests) ... ok
|
||||
test_roster_receipt_only_differing_rows_and_source_sets (__main__.TypedProducerTests) ... ok
|
||||
test_roster_uses_exact_legacy_validated_objects (__main__.TypedProducerTests) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 12 tests in 1.082s
|
||||
|
||||
OK
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
test_checker_stage_declarations_no_boolean_substitute (__main__.TypedProducerTests) ... ok
|
||||
test_command_schema_source_stream_and_result_negatives (__main__.TypedProducerTests) ... ok
|
||||
test_composition_receipt_requires_actual_result (__main__.TypedProducerTests) ... ok
|
||||
test_document_bindings_and_windows_notrun (__main__.TypedProducerTests) ... ok
|
||||
test_each_kind_positive_and_both_stages (__main__.TypedProducerTests) ... ok
|
||||
test_each_kind_rejects_relabelling_and_os_provenance (__main__.TypedProducerTests) ... ok
|
||||
test_final_requires_every_original_condition_and_later_meaning (__main__.TypedProducerTests) ... ok
|
||||
test_normal_cannot_synthesize_later_gates_or_skip_runtime (__main__.TypedProducerTests) ... ok
|
||||
test_review_artifact_references_and_chronology (__main__.TypedProducerTests) ... ok
|
||||
test_roster_process_receipts_cannot_borrow_os_identity_or_window (__main__.TypedProducerTests) ... ok
|
||||
test_roster_receipt_only_differing_rows_and_source_sets (__main__.TypedProducerTests) ... ok
|
||||
test_roster_uses_exact_legacy_validated_objects (__main__.TypedProducerTests) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 12 tests in 0.804s
|
||||
|
||||
OK
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
"""TEST-ONLY stdlib controls: no real evidence index or runtime execution."""
|
||||
import copy
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
spec = importlib.util.spec_from_file_location('repair5_tests', HERE.parent/'source-ready-repair5-20261017/test_repair5.py')
|
||||
r5 = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(r5)
|
||||
e, checker = r5.e, r5.checker
|
||||
|
||||
|
||||
class TypedProducerTests(unittest.TestCase):
|
||||
def fixture(self, normal=False):
|
||||
f = r5.CoverageAttackTests()
|
||||
f.setUp()
|
||||
self.addCleanup(f.doCleanups)
|
||||
if normal:
|
||||
f.roles['mode'] = 'normal_validation'
|
||||
for meaning in e.LATER:
|
||||
del f.docs[e.KINDS[meaning]]
|
||||
f.data['conditions']['final_validation_review']['coverage'][meaning] = {'status': 'not-yet-applicable'}
|
||||
f.data['conditions']['final_validation_review']['artifact_ids'] = ['command_log', 'roster_controller']
|
||||
return f
|
||||
|
||||
def test_each_kind_positive_and_both_stages(self):
|
||||
f = self.fixture()
|
||||
self.assertEqual(set(e.KINDS.values()), {d['kind'] for d in f.docs.values() if 'kind' in d})
|
||||
self.assertEqual(f.verify()['stage'], 'integration_final')
|
||||
f = self.fixture(normal=True)
|
||||
report = f.verify()
|
||||
self.assertFalse(report['complete'])
|
||||
self.assertEqual(set(report['later_gates'].values()), {'not-yet-applicable'})
|
||||
|
||||
def test_each_kind_rejects_relabelling_and_os_provenance(self):
|
||||
for kind in e.KINDS.values():
|
||||
for attack in ('kind', 'meaning', 'os_record', 'os_doc', 'os_pid', 'os_session', 'receipt_kind', 'receipt_hash', 'lifecycle', 'times', 'identity'):
|
||||
with self.subTest(kind=kind, attack=attack):
|
||||
f = self.fixture(); doc = f.docs[kind]; record = doc['records'][0]
|
||||
if attack == 'kind': record['kind'] = 'os_event'
|
||||
elif attack == 'meaning': record['meaning'] = 'grid_snap'
|
||||
elif attack == 'os_record': record['session_id'] = 'TEST-ONLY'
|
||||
elif attack == 'os_doc': doc['provenance'] = f.prov
|
||||
elif attack == 'os_pid': doc['producer']['pid'] = f.data['os_environment']['pid']
|
||||
elif attack == 'os_session': doc['producer']['run_id'] = f.data['os_environment']['session_id']
|
||||
elif attack == 'receipt_kind': doc['producer']['kind'] = 'other'
|
||||
elif attack == 'lifecycle': doc['producer']['lifecycle'] = ['started']
|
||||
elif attack == 'times': doc['producer']['ended_unix_ns'] = doc['producer']['started_unix_ns']
|
||||
elif attack == 'identity': doc['producer']['identity'] = ''
|
||||
f.seal_typed()
|
||||
if attack == 'receipt_hash': doc['producer']['records_sha256'] = '0'*64
|
||||
with self.assertRaises(ValueError): f.verify()
|
||||
|
||||
def test_command_schema_source_stream_and_result_negatives(self):
|
||||
changes = [('pid', 1234), ('argv', []), ('cwd', 'relative'), ('exit_code', 1), ('exit_code', True),
|
||||
('stdout_sha256', '0'*64), ('stderr', 'unbound output'),
|
||||
('started_unix_ns', 1), ('ended_unix_ns', 10000), ('source_map_sha256', '0'*64)]
|
||||
for key, value in changes:
|
||||
with self.subTest(key=key, value=value):
|
||||
f = self.fixture(normal=True)
|
||||
f.docs['command_log']['records'][0]['commands'][0][key] = value
|
||||
f.seal_typed()
|
||||
with self.assertRaisesRegex(ValueError, 'command'): f.verify()
|
||||
|
||||
def test_roster_receipt_only_differing_rows_and_source_sets(self):
|
||||
for attack in ('receipt_only', 'different', 'duplicate', 'source', 'no_validated_rows', 'boolean_relabel', 'engine'):
|
||||
with self.subTest(attack=attack):
|
||||
f = self.fixture(normal=True); record = f.docs['roster_controller']['records'][0]
|
||||
if attack == 'receipt_only': record['results'] = [f.receipt]
|
||||
elif attack == 'different': record['results'][0]['checks'] = 999
|
||||
elif attack == 'duplicate': record['results'] *= 2
|
||||
elif attack == 'source': record['results'][0]['source_sha256'] = '0'*64
|
||||
elif attack == 'no_validated_rows': f.validated_roster = None
|
||||
elif attack == 'boolean_relabel': record['results'][0]['failures'] = False
|
||||
else:
|
||||
record['results'][0]['engine_ended'] = False
|
||||
f.validated_roster = copy.deepcopy(record['results'])
|
||||
f.seal_typed()
|
||||
with self.assertRaises(ValueError): f.verify()
|
||||
|
||||
def test_roster_uses_exact_legacy_validated_objects(self):
|
||||
f = self.fixture(normal=True)
|
||||
suite = 'tests/TEST-ONLY.gd'; path = f.root/suite
|
||||
path.parent.mkdir(); path.write_text('TEST-ONLY suite bytes')
|
||||
rows = [dict(f.receipt, test=suite, source_sha256=hashlib.sha256(path.read_bytes()).hexdigest(), failures=0, passed=True)]
|
||||
content = dict(test_suite='tests/ui/test_operations_notification.gd', failures=0, checks=1,
|
||||
full_roster={'results': rows})
|
||||
validated = []
|
||||
with patch.object(checker, 'VERIFIED_ROOT', f.root), patch.object(checker, 'get_required_suite_roster', return_value=[suite]):
|
||||
self.assertEqual(checker._validate_condition_artifact_content('final_validation_review', content, 'json', f.root, {}, {}, validated), (True, ''))
|
||||
self.assertIs(validated[0], rows[0])
|
||||
bad = copy.deepcopy(content); bad['full_roster']['results'][0]['source_sha256'] = '0'*64
|
||||
rejected = []
|
||||
self.assertFalse(checker._validate_condition_artifact_content('final_validation_review', bad, 'json', f.root, {}, {}, rejected)[0])
|
||||
self.assertEqual(rejected, [])
|
||||
# The coverage list must be equal to these actual objects, not merely
|
||||
# another engine receipt or a differently hashed suite with a pass flag.
|
||||
with self.assertRaises(ValueError):
|
||||
e.verify_typed('exact_final_full_roster', f.docs['roster_controller']['records'][0],
|
||||
f.docs['roster_controller'], f.data, f.roles, f.docs, {}, validated, f.roles)
|
||||
|
||||
def test_review_artifact_references_and_chronology(self):
|
||||
for attack in ('hash', 'references', 'early', 'run', 'provider', 'decision', 'independence'):
|
||||
with self.subTest(attack=attack):
|
||||
f = self.fixture(); doc = f.docs['claude_review']; record = doc['records'][0]
|
||||
if attack == 'hash': record['review_sha256'] = '0'*64
|
||||
elif attack == 'references': record['runtime_artifact_sha256'] = ['0'*64]
|
||||
elif attack == 'early': doc['producer']['started_unix_ns'] = 50
|
||||
elif attack == 'run': record['reviewer_run_id'] = 'other'
|
||||
elif attack == 'independence': doc['producer']['identity'] = f.docs['roster_controller']['producer']['identity']
|
||||
else:
|
||||
record['review'][attack] = 'wrong'
|
||||
record['review_sha256'] = e.canonical_sha(record['review'])
|
||||
f.seal_typed()
|
||||
with self.assertRaises(ValueError): f.verify()
|
||||
|
||||
def test_composition_receipt_requires_actual_result(self):
|
||||
f = self.fixture(); doc = f.docs['composition_result']; record = doc['records'][0]
|
||||
for result in (None, True, dict(f.roles, T='0'*40)):
|
||||
with self.assertRaisesRegex(ValueError, 'composition.py result'):
|
||||
e.verify_typed('current_main_integration_final', record, doc, f.data, f.roles, f.docs, {}, f.validated_roster, result)
|
||||
record['result'] = dict(f.roles, M='0'*40); f.seal_typed()
|
||||
with self.assertRaisesRegex(ValueError, 'composition result receipt'): f.verify()
|
||||
|
||||
def test_document_bindings_and_windows_notrun(self):
|
||||
for kind in ('held_gestures_document', 'platform_document'):
|
||||
for field in ('source_map_sha256', 'spec_sha256'):
|
||||
f = self.fixture(normal=True); f.docs[kind]['records'][0][field] = '0'*64; f.seal_typed()
|
||||
with self.assertRaisesRegex(ValueError, 'document source/spec'): f.verify()
|
||||
f = self.fixture(normal=True); f.docs['platform_document']['records'][0]['windows_status'] = 'PASS'; f.seal_typed()
|
||||
with self.assertRaisesRegex(ValueError, 'Windows'): f.verify()
|
||||
|
||||
def test_normal_cannot_synthesize_later_gates_or_skip_runtime(self):
|
||||
for meaning in e.LATER:
|
||||
for link in (True, {'passed': True}, {'status': 'satisfied'}):
|
||||
f = self.fixture(normal=True)
|
||||
f.data['conditions']['final_validation_review']['coverage'][meaning] = link
|
||||
with self.assertRaises(ValueError): f.verify()
|
||||
f = self.fixture(normal=True)
|
||||
f.data['conditions']['placement_and_invalid_drop']['coverage']['grid_snap'] = {'status': 'not-yet-applicable'}
|
||||
with self.assertRaises(ValueError): f.verify()
|
||||
f = self.fixture(normal=True); f.roles['mode'] = 'integration_final'
|
||||
with self.assertRaises(ValueError): f.verify()
|
||||
with self.assertRaises(ValueError): e.stage_report('waiver')
|
||||
|
||||
def test_final_requires_every_original_condition_and_later_meaning(self):
|
||||
for condition in e.MEANINGS:
|
||||
f = self.fixture(); del f.data['conditions'][condition]
|
||||
with self.assertRaisesRegex(ValueError, 'whole-eight'): f.verify()
|
||||
for meaning in e.LATER:
|
||||
f = self.fixture()
|
||||
f.data['conditions']['final_validation_review']['coverage'][meaning] = {'status': 'not-yet-applicable'}
|
||||
with self.assertRaises(ValueError): f.verify()
|
||||
|
||||
def test_roster_process_receipts_cannot_borrow_os_identity_or_window(self):
|
||||
for key, value in [('pid', 1234), ('run_id', 'TEST-ONLY'), ('started_unix_ns', 1), ('ended_unix_ns', 10000)]:
|
||||
f = self.fixture(normal=True)
|
||||
row = f.docs['roster_controller']['records'][0]['results'][0]
|
||||
row[key] = value
|
||||
f.validated_roster = copy.deepcopy([row]); f.seal_typed()
|
||||
with self.assertRaisesRegex(ValueError, 'suite'): f.verify()
|
||||
|
||||
def test_checker_stage_declarations_no_boolean_substitute(self):
|
||||
checker.validate_condition_stage('final_validation_review', {'passed': False, 'status': 'prerequisites-only'}, 'normal_validation')
|
||||
for mode in ('normal_validation', 'integration_final'):
|
||||
for cond in checker.REQUIRED_CONDITIONS:
|
||||
if mode == 'normal_validation' and cond == 'final_validation_review':
|
||||
with self.assertRaises(ValueError): checker.validate_condition_stage(cond, {'passed': True}, mode)
|
||||
else:
|
||||
checker.validate_condition_stage(cond, {'passed': True}, mode)
|
||||
for flag in (False, 1, None):
|
||||
with self.assertRaises(ValueError): checker.validate_condition_stage(cond, {'passed': flag}, mode)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=2)
|
||||
@@ -3085,6 +3085,7 @@ func _ensure_defense_manager() -> DefenseManagementPanel:
|
||||
panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
defense_manager.add_child(scroll)
|
||||
scroll.add_child(panel)
|
||||
defense_manager.visibility_changed.connect(_update_modal_input_guard)
|
||||
add_child(defense_manager)
|
||||
return defense_manager.find_child("DefenseManagementPanel", true, false) as DefenseManagementPanel
|
||||
|
||||
|
||||
@@ -133,6 +133,31 @@ func _run() -> void:
|
||||
_expect(not preview.modal_input_blocked, "Modal close unblocks behind-dialog input")
|
||||
_expect(main.manual_save_path == initial_manual_path, "Modal cancellation preserves existing save identity")
|
||||
|
||||
# Defense dialog uses the ordinary visibility callback and real model.
|
||||
main.call(&"_show_defense_manager")
|
||||
await process_frame
|
||||
_expect(preview.modal_input_blocked, "Defense dialog blocks map input on open")
|
||||
preview.set_build_definition(reception_def, 0)
|
||||
var defense_before: Dictionary = runtime.create_snapshot()
|
||||
var defense_selection := [preview.selected_entity_id, staff_panel.selected_staff_id,
|
||||
main.get("_selected_entity_id"), main.get("_selected_entity_kind")]
|
||||
var behind_click := InputEventMouseButton.new()
|
||||
behind_click.button_index = MOUSE_BUTTON_LEFT
|
||||
behind_click.pressed = true
|
||||
behind_click.position = Vector2(200, 200)
|
||||
preview._gui_input(behind_click)
|
||||
preview._drop_data(Vector2.ZERO, drop_payload)
|
||||
_expect(SimulationDigest.compute(defense_before) == SimulationDigest.compute(runtime.create_snapshot()),
|
||||
"Defense modal build/drop attempts preserve complete model including economy ledger")
|
||||
_expect(defense_selection == [preview.selected_entity_id, staff_panel.selected_staff_id,
|
||||
main.get("_selected_entity_id"), main.get("_selected_entity_kind")],
|
||||
"Defense modal build/drop attempts preserve map and staff selections")
|
||||
preview.clear_build_definition()
|
||||
var defense_dialog: AcceptDialog = main.get("defense_manager")
|
||||
defense_dialog.hide()
|
||||
await process_frame
|
||||
_expect(not preview.modal_input_blocked, "Defense dialog close unblocks map input")
|
||||
|
||||
# Pause freezes simulation via process_real_delta/accumulator; ordinary resume continues exactly once
|
||||
var clock_paused_before: bool = bool(clock.get("paused"))
|
||||
clock.set_paused(true)
|
||||
|
||||
@@ -20,8 +20,20 @@ import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
# This helper ships in S; it has only stdlib dependencies (no Main-only imports).
|
||||
_HELPER = Path(__file__).resolve().parents[1] / 'docs/plans/original-completion-2026-10-02/execution/p24-02/source-ready-repair5-20261017/composition.py'
|
||||
_spec = importlib.util.spec_from_file_location('p24_composition', _HELPER)
|
||||
composition = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(composition)
|
||||
_spec = importlib.util.spec_from_file_location('p24_correspondence', _HELPER.with_name('correspondence.py'))
|
||||
correspondence = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(correspondence)
|
||||
ROOT = Path(composition.git_bytes(Path(__file__).resolve().parents[1], 'rev-parse', '--show-toplevel').decode().strip())
|
||||
VERIFIED_ROOT = ROOT
|
||||
|
||||
REQUIRED_CONDITIONS = [
|
||||
"placement_and_invalid_drop",
|
||||
"modal_and_pause_resume",
|
||||
@@ -66,21 +78,12 @@ def compute_sha256(path: Path) -> str:
|
||||
|
||||
|
||||
def get_actual_git_head(root: Path = None) -> str:
|
||||
root = root if root is not None else Path(__file__).resolve().parents[1]
|
||||
root = root if root is not None else ROOT
|
||||
try:
|
||||
import subprocess
|
||||
res = subprocess.run(["git", "rev-parse", "HEAD"], cwd=root, capture_output=True, text=True, timeout=5)
|
||||
if res.returncode == 0:
|
||||
h = res.stdout.strip().lower()
|
||||
if HEX_COMMIT_PATTERN.match(h) and not (set(h) <= {"0"} or set(h) <= {"f"}):
|
||||
for name in ("CANDIDATE_COMMIT", "TARGET_HEAD"):
|
||||
if name in os.environ and os.environ[name].strip().lower() != h:
|
||||
print(f"ERROR: {name} mismatch with real git HEAD {h}", file=sys.stderr)
|
||||
return ""
|
||||
return h
|
||||
composition.root_identity(root, root)
|
||||
return composition.git_bytes(root, 'rev-parse', 'HEAD').decode().strip()
|
||||
except Exception:
|
||||
pass
|
||||
return ""
|
||||
return ""
|
||||
|
||||
|
||||
def get_required_suite_roster(root: Path) -> list[str]:
|
||||
@@ -93,7 +96,7 @@ def get_required_suite_roster(root: Path) -> list[str]:
|
||||
|
||||
def find_index_file(custom_path: str = None) -> Path:
|
||||
if custom_path:
|
||||
p = Path(custom_path)
|
||||
p = Path(custom_path) if Path(custom_path).is_absolute() else ROOT / custom_path
|
||||
if p.is_file():
|
||||
return p.resolve()
|
||||
if p.is_dir():
|
||||
@@ -114,9 +117,9 @@ def find_index_file(custom_path: str = None) -> Path:
|
||||
return candidate2.resolve()
|
||||
|
||||
candidates = [
|
||||
Path(".runtime/P24-02/build/p24-operations-evidence/index.json"),
|
||||
Path("docs/plans/original-completion-2026-10-02/execution/p24-02/evidence/index.json"),
|
||||
Path("artifacts/p24-02-operations/index.json"),
|
||||
ROOT / Path(".runtime/P24-02/build/p24-operations-evidence/index.json"),
|
||||
ROOT / Path("docs/plans/original-completion-2026-10-02/execution/p24-02/evidence/index.json"),
|
||||
ROOT / Path("artifacts/p24-02-operations/index.json"),
|
||||
]
|
||||
for c in candidates:
|
||||
if c.is_file():
|
||||
@@ -143,6 +146,7 @@ def _validate_condition_artifact_content(
|
||||
evidence_dir: Path,
|
||||
root_data: dict,
|
||||
validated_artifacts: dict,
|
||||
validated_roster: list = None,
|
||||
) -> tuple[bool, str]:
|
||||
if not isinstance(art_data, dict):
|
||||
return False, f"Artifact content for condition '{cond}' must be a JSON object"
|
||||
@@ -368,7 +372,7 @@ def _validate_condition_artifact_content(
|
||||
if not full_roster or not isinstance(full_roster, dict):
|
||||
return False, "Missing 'full_roster' summary in final validation review evidence"
|
||||
|
||||
repo_root = Path(".").resolve()
|
||||
repo_root = VERIFIED_ROOT
|
||||
required_suites = get_required_suite_roster(repo_root)
|
||||
total_required = len(required_suites)
|
||||
|
||||
@@ -425,10 +429,24 @@ def _validate_condition_artifact_content(
|
||||
if seen_suites != set(required_suites):
|
||||
return False, f"Full roster execution missing required suites: {sorted(list(missing_from_roster))[:5]}"
|
||||
|
||||
# Hand the exact successfully validated objects to correspondence; never
|
||||
# re-read a different list from the index or a coverage receipt.
|
||||
if validated_roster is not None:
|
||||
validated_roster.extend(suite_entries)
|
||||
|
||||
return True, ""
|
||||
|
||||
|
||||
def verify_evidence(index_path: Path) -> bool:
|
||||
def validate_condition_stage(condition, row, mode):
|
||||
correspondence.stage_report(mode)
|
||||
if condition == 'final_validation_review' and mode == 'normal_validation':
|
||||
correspondence.require(row.get('passed') is False and row.get('status') == 'prerequisites-only',
|
||||
'normal_validation final group must be prerequisites-only, passed=false')
|
||||
else:
|
||||
correspondence.require(row.get('passed') is True, 'condition requires passed=true plus actual evidence: '+condition)
|
||||
|
||||
|
||||
def _verify_evidence(index_path: Path, roles: dict, composition_result: dict) -> bool:
|
||||
print(f"Reading evidence index from: {index_path}")
|
||||
try:
|
||||
data = json.loads(index_path.read_text(encoding="utf-8"))
|
||||
@@ -487,13 +505,13 @@ def verify_evidence(index_path: Path) -> bool:
|
||||
print("ERROR: 'source_hashes' dictionary is required in evidence index", file=sys.stderr)
|
||||
return False
|
||||
|
||||
missing_scope_sources = [f for f in REQUIRED_SCOPE_FILES if f not in sources]
|
||||
missing_scope_sources = [f for f in REQUIRED_SCOPE_FILES if f not in sources and f not in data.get("inputs", {})]
|
||||
if missing_scope_sources:
|
||||
print(f"ERROR: 'source_hashes' omits required scope files: {missing_scope_sources}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
for rel_path, expected_hash in sources.items():
|
||||
p = Path(rel_path)
|
||||
p = composition.safe_path(VERIFIED_ROOT, rel_path)
|
||||
if not p.is_file():
|
||||
print(f"ERROR: Required source file does not exist on disk: {rel_path}", file=sys.stderr)
|
||||
return False
|
||||
@@ -530,9 +548,9 @@ def verify_evidence(index_path: Path) -> bool:
|
||||
print(f"ERROR: Artifact '{art_id}' path traversal or absolute path forbidden: {rel_art_path}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
art_file = evidence_dir / rel_art_path
|
||||
art_file = composition.safe_path(evidence_dir, rel_art_path)
|
||||
if not art_file.is_file():
|
||||
art_file = Path(rel_art_path)
|
||||
art_file = composition.safe_path(ROOT, rel_art_path)
|
||||
if not art_file.is_file():
|
||||
print(f"ERROR: Referenced artifact file missing on disk: {rel_art_path}", file=sys.stderr)
|
||||
return False
|
||||
@@ -651,6 +669,7 @@ def verify_evidence(index_path: Path) -> bool:
|
||||
print(f"ERROR: Unknown invented conditions present in evidence index: {sorted(invented)}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
validated_roster = []
|
||||
condition_to_artifacts = {}
|
||||
for cond in REQUIRED_CONDITIONS:
|
||||
cond_data = conditions[cond]
|
||||
@@ -658,13 +677,10 @@ def verify_evidence(index_path: Path) -> bool:
|
||||
print(f"ERROR: Condition '{cond}' must be a structured JSON object with evidence details, not bare boolean or primitive", file=sys.stderr)
|
||||
return False
|
||||
|
||||
passed_val = cond_data.get("passed")
|
||||
if isinstance(passed_val, bool):
|
||||
if passed_val is not True:
|
||||
print(f"ERROR: Condition '{cond}' explicitly marked not passed", file=sys.stderr)
|
||||
return False
|
||||
else:
|
||||
print(f"ERROR: Condition '{cond}' missing strict boolean 'passed': true (value={passed_val!r})", file=sys.stderr)
|
||||
try:
|
||||
validate_condition_stage(cond, cond_data, roles['mode'])
|
||||
except ValueError as exc:
|
||||
print(f"ERROR: {exc}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
cond_art_ids = cond_data.get("artifact_ids")
|
||||
@@ -701,6 +717,7 @@ def verify_evidence(index_path: Path) -> bool:
|
||||
evidence_dir,
|
||||
data,
|
||||
validated_artifacts,
|
||||
validated_roster,
|
||||
)
|
||||
if ok:
|
||||
content_verified = True
|
||||
@@ -712,29 +729,62 @@ def verify_evidence(index_path: Path) -> bool:
|
||||
print(f"ERROR: Condition '{cond}' artifact content verification failed: {last_err}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
# Reject self-declaration where conditions share a single generic artifact
|
||||
unique_referenced_artifacts = set()
|
||||
for aids in condition_to_artifacts.values():
|
||||
unique_referenced_artifacts.update(aids)
|
||||
|
||||
if len(unique_referenced_artifacts) < len(REQUIRED_CONDITIONS):
|
||||
print(f"ERROR: All 8 conditions require distinct evidence artifacts; found only {len(unique_referenced_artifacts)} unique artifacts across {len(REQUIRED_CONDITIONS)} conditions", file=sys.stderr)
|
||||
try:
|
||||
correspondence.verify(data, validated_artifacts, roles, ROOT,
|
||||
validated_roster=validated_roster, composition_result=composition_result)
|
||||
except (ValueError, KeyError, TypeError, OSError, IndexError) as exc:
|
||||
print(f"ERROR: correspondence: {exc}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
print("SUCCESS: All 8 required conditions, candidate version, scope manifest, and OS execution artifacts strictly verified.")
|
||||
if roles['mode'] == 'normal_validation':
|
||||
print("SUCCESS: Source/runtime/OS/full-roster prerequisites verified. P24-02 NOT complete; independent runtime review and integration-final are not-yet-applicable. All 8 remain unaccepted.")
|
||||
else:
|
||||
print("SUCCESS: All 8 required condition evidence groups including typed review/integration records strictly verified. Independent formal acceptance remains separate.")
|
||||
return True
|
||||
|
||||
|
||||
def verify_evidence(index_path: Path) -> bool:
|
||||
global VERIFIED_ROOT
|
||||
try:
|
||||
composition.root_identity(ROOT, Path.cwd())
|
||||
data = composition.strict_json(index_path.read_bytes())
|
||||
roles = composition.root_context(index_path.parent, data)
|
||||
print(json.dumps(correspondence.stage_report(roles.get('mode')), sort_keys=True))
|
||||
composition.require(data.get('inputs', {}).get(composition.SPEC) == EXPECTED_SPEC_SHA256, 'frozen spec input SHA mismatch')
|
||||
required_helpers = {_HELPER.relative_to(ROOT).as_posix(), _HELPER.with_name('correspondence.py').relative_to(ROOT).as_posix()}
|
||||
composition.require(required_helpers <= set(data['inputs']), 'missing checker helper input pins')
|
||||
composition_result = composition.verify_composition(ROOT, roles, data.get('source_hashes'), data.get('inputs'),
|
||||
EXPECTED_BASE_COMMIT, REQUIRED_SCOPE_FILES + ['docs/plans/original-completion-2026-10-02/execution/p24-02/**'])
|
||||
print("Source/composition prerequisites: verified; runtime/OS/roster prerequisites: verification pending; P24-02 NOT complete.")
|
||||
with composition.tested_checkout(ROOT, roles['T']) as view:
|
||||
VERIFIED_ROOT = view
|
||||
verified = _verify_evidence(index_path, roles, composition_result)
|
||||
if not verified:
|
||||
print("Runtime/OS/roster or applicable later prerequisites: NOT VERIFIED; P24-02 NOT complete.")
|
||||
return verified
|
||||
except (ValueError, KeyError, TypeError, OSError, IndexError) as exc:
|
||||
print(f"ERROR: composition: {exc}", file=sys.stderr)
|
||||
return False
|
||||
finally:
|
||||
VERIFIED_ROOT = ROOT
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Check P24-02 Operations Evidence")
|
||||
parser.add_argument("--verify-only", action="store_true", help="Strict verification of existing evidence index only")
|
||||
parser.add_argument("--index", type=str, help="Path to evidence index.json", default=None)
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
composition.root_identity(ROOT, Path.cwd())
|
||||
except (ValueError, OSError) as exc:
|
||||
print(f"ERROR: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
index_file = find_index_file(args.index)
|
||||
if not index_file:
|
||||
print("ERROR: Could not locate p24-operations-evidence index.json.", file=sys.stderr)
|
||||
print("Ensure BUILD_OUTPUT_DIR is set or provide --index <path>.", file=sys.stderr)
|
||||
print("Source/runtime prerequisites NOT VERIFIED; stage not established; P24-02 NOT complete.")
|
||||
return 1
|
||||
|
||||
if not verify_evidence(index_file):
|
||||
|
||||
@@ -416,7 +416,7 @@
|
||||
"new_audio_QA": false
|
||||
},
|
||||
"tests/ui/test_operations_notification.gd": {
|
||||
"source_sha256": "9c26386c529b8c8135639e8d0f0ed390da7139d64ff1e268975b05948cab9147",
|
||||
"source_sha256": "50172ab6daa031d221f6a78cac5cdbcb8884f295f8062b54656562e2412faff2",
|
||||
"ordinary_cleanup_prepared": true,
|
||||
"ordinary_control_labels": ["single"],
|
||||
"old_bounded_teardown": false,
|
||||
|
||||
Reference in New Issue
Block a user