Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Progress Log

This chapter records user-facing progress updates from the assistant, with the concrete action or result behind each update. It complements clean_room_executable_notes.md: the evidence log records commands, observations, offsets, and corrections, while this chapter preserves the narrative trail of what was reported while the work was happening.

Exact progress-update logging starts with the synthetic picture fuzzing work below. Earlier project work is documented in detail in Clean-Room Executable Notes, but the exact wording of every earlier transient assistant update is not fully available in the current thread context, so this log does not invent those verbatim messages.

Prior Work Summary

Before this progress log was created, the project had already:

  • Established the mdBook documentation layout under docs/.
  • Built clean-room notes for the loader, executable, logic interpreter, resource formats, graphics/object pipeline, and symbolic labels.
  • Set up a bootable DOS 6.22 QEMU hard disk image at build/dos622/dos622.img.
  • Added local graphics/rendering helpers under tools/.
  • Built QEMU fixture support for custom LOGIC.0 scripts.
  • Validated original-engine output against local Python rendering for:
    • picture 45;
    • picture 1 with view 11/group 0/frame 0;
    • picture 1 with view 0/group 1/frame 0, including the bit-0x80 row-orientation rewrite.

The detailed command evidence for those milestones is in docs/src/clean_room_executable_notes.md.

Synthetic Picture Fuzzing Framework

User request:

Write a fuzz testing framework that generates a large set of synthetic picture resources, including some with invalid commands/data, and use that to compare the behaviour of the original engine with the python code you’ve written. I want to capture edge cases so we can model the semantics with a high degree of accuracy

Progress updates and outcomes:

  1. Reported: “I’ll build this as a reusable harness, not a one-off pile of samples: synthetic picture payload generation, fixture construction that swaps in a custom picture resource, Python rendering with error capture, and QEMU capture/compare hooks. I’ll start by reading the current fixture/rendering tools so the new code plugs into the existing path cleanly.”

    Action/result: Read tools/qemu_fixture.py, tools/compare_picture_capture.py, tools/agi_graphics.py, and the current test list.

  2. Reported: “I’ve got the shape now. The important design point is to patch PICDIR and LOGDIR together inside a copied fixture, with VOL.3 holding both the custom LOGIC.0 and the synthetic picture payload. That lets the original engine run synthetic pictures without touching the real SQ2 files.”

    Action/result: Read tests/test_qemu_fixture.py, AGENTS.md, and docs/src/SUMMARY.md to align the fixture changes with existing tests and docs.

  3. Reported: “I’m going to extend the fixture builder first: one generic directory-entry patcher, then a synthetic-picture fixture that writes LOGIC.0 and the fuzzed picture into the same VOL.3. That keeps the fuzz runner small and makes the patching testable.”

    Action/result: Updated tools/qemu_fixture.py with patch_dir_entry(), build_synthetic_picture_fixture(), and a synthetic-picture CLI command.

  4. Reported: “The synthetic fixture builder is in place. Next I’m adding the fuzz corpus tool: it will generate deterministic valid and invalid picture payloads, render each with the Python model, write manifests/PPMs, build QEMU fixtures, and compare captures back to a selected fuzz case.”

    Action/result: Added tools/picture_fuzz.py with deterministic base cases, random case generation, corpus manifests, Python render hashing, fixture building, QEMU execution, and capture comparison.

  5. Reported: “The corpus tool is added. I’m adding tests around the new pieces now: directory entry patching, synthetic fixture layout, deterministic corpus generation, and a synthetic scaled-capture comparison path that doesn’t need QEMU.”

    Action/result: Expanded tests/test_qemu_fixture.py for generic directory patching and synthetic fixture layout.

  6. Reported: “The fixture tests are patched. I’m adding a dedicated fuzz-tool test file next, including a scaled fake QEMU screenshot so the compare logic is exercised without booting DOS during unit tests.”

    Action/result: Added tests/test_picture_fuzz.py.

  7. Reported: “Tests are in place. I’m running them now; if the generator exposes any rough edges, I’ll tighten it before doing the QEMU sample run.”

    Action/result: Ran python3 -B -m unittest discover -s tests, which passed 33 tests. Generated an initial 79-case corpus from 15 curated cases plus 64 random cases.

  8. Reported: “The unit tests pass, and a 79-case corpus is generated from 15 curated cases plus 64 deterministic random ones. I’m going to use the new QEMU runner on a tiny visual-point case first, because that validates the end-to-end plumbing without risking an unsafe malformed-resource hang.”

    Action/result: Ran the new QEMU runner on base_003_visual_point; QEMU exited early with a broken pipe because the harness hid the emulator output.

  9. Reported: “The first automated QEMU run exited early, and the runner had hidden QEMU’s output too aggressively. I’m adjusting it to surface early-exit diagnostics so failures are evidence instead of a mystery.”

    Action/result: Updated tools/picture_fuzz.py to detect early QEMU exit before monitor input and to retain QEMU output on nonzero exit.

  10. Reported: “The runner now checks for early QEMU exit before each monitor keystroke and preserves monitor output on nonzero exit. I’m rerunning the same smoke case.”

    Action/result: The rerun still failed early and revealed that another diagnostic path was needed.

  11. Reported: “QEMU is exiting with status 1 before DOS input. I still need the actual QEMU message, so I’m adding one more diagnostic path to read the monitor output when the early-exit check trips.”

    Action/result: Added exception wrapping that includes QEMU monitor output.

  12. Reported: “One more smoke run; now if QEMU bails, the runner should show why.”

    Action/result: QEMU reported Failed to bind socket: Operation not permitted, showing that Python-launched QEMU needed escalation for the VNC socket.

  13. Reported: “The runner is fine; the sandbox blocked QEMU’s VNC bind when launched from Python. I’m rerunning that same framework command with escalation so the harness can actually start the emulator.”

    Action/result: With escalation, base_003_visual_point matched the original engine with 0 mismatches out of 26,880 logical pixels.

  14. Reported: “The first original-engine fuzz comparison matched. I’m going to expand the corpus to a genuinely large deterministic set now, then run a small representative QEMU slice across scanner, line, fill, pattern, and invalid-but-safe cases.”

    Action/result: Generated a 1,039-case corpus from curated cases plus 1,024 deterministic random cases. The generator marked 1,037 cases safe for QEMU.

  15. Reported: “The corpus now has 1,039 synthetic picture resources, including 1,037 marked safe for automated QEMU. I’m running five more original-engine comparisons against curated edge cases.”

    Action/result: Ran QEMU for base_002_unknown_commands; it matched with 0 mismatches.

  16. Reported: “Unknown commands 0xfb..0xfe matched the current Python behavior for that fixture: no visible changes before 0xff. Continuing through the line/clamp and fill/pattern cases.”

    Action/result: Ran QEMU for base_004_clamped_absolute; it produced 312 mismatches, the first fuzz-discovered semantics gap in this pass.

  17. Reported: “Good, the clamped-coordinate case found a real mismatch: 312 logical pixels. That’s exactly the kind of edge this harness is meant to expose, so I’m keeping that as evidence and continuing the sample sweep before drilling in.”

    Action/result: Ran QEMU for the visual/control seed-fill case; it matched with 0 mismatches.

  18. Reported: “The combined visual/control fill case matched, which reinforces the seed-fill channel-priority model. Next I’m checking pseudo-random pattern plotting and the truncated coordinate pair case.”

    Action/result: Ran QEMU for the pseudo-random pattern case and the truncated coordinate-pair case; both matched with 0 mismatches.

  19. Reported: “The pattern and truncated-pair cases matched; the only mismatch in the curated slice is the clamp edge case using coordinate byte 0xef. I’m adding mismatch bounding boxes and sample pixels to the comparison output so we can immediately see what kind of semantic gap a fuzz case found.”

    Action/result: Extended CaptureComparison in tools/picture_fuzz.py with mismatch_bbox and sample mismatch tuples.

  20. Reported: “The comparison output now includes a compact mismatch bbox and sample pixel tuples. I’m rerunning the comparison against the already captured clamp case, no new QEMU boot needed.”

    Action/result: The captured clamp case reported mismatch bbox (0, 0, 149, 155) and sample pixels showing displaced diagonal-line output.

  21. Reported: “The mismatch samples show this is probably not just ‘coordinate clamp’; it is a steep diagonal line edge. The original is drawing a visible line displaced from the Python line for a (159,167) -> (0,0) style segment, so I’m going back to the line helper with this new targeted case.”

    Action/result: Re-disassembled around code.picture.draw_line (0x66e1) and compared captured versus expected colored point sets. Both had 168 colored points ending at (159,167), but the original began near (25,0) while Python began at (0,0).

  22. Reported: “The mismatch is very specific: both outputs draw 168 colored pixels ending at (159,167), but the original starts the top of the line around (25,0) while Python starts at (0,0). I’m checking the fixture bytes to make sure this is a real semantic signal and not a stale DOS-copy issue.”

    Action/result: Inspected VOL.3, PICDIR, and the corpus case metadata. The fixture correctly contained payload f0 02 f6 ef ef 00 00 ff and patched PICDIR[0] to the synthetic picture in VOL.3.

Gold Rush / SQ2 Shared Delta Source Pass

User request:

Update PROGRESS.md to include these items, then proceed.

Progress updates and outcomes:

  1. Reported: “Picking this back up at the documentation point. I’ve already got the source-level findings for the first input/text cluster, so I’m going to fold those into PROGRESS.md, the version notes, symbolic labels, and the clean-room log before moving to the next cluster.”

    Action/result: Re-read PROGRESS.md, docs/src/versions.md, docs/src/symbolic_labels.md, and docs/src/progress_log.md.

  2. Reported: “I’m going to keep this pass source-first as requested. The plan is to use the changed opcode entry addresses as anchors, inspect the corresponding disassembly in both interpreters, and only mark behavior as done when it is backed by those snippets rather than a black-box run.”

    Action/result: Re-read tools/compare_gr_sq2_static.py, the end of docs/src/clean_room_executable_notes.md, and the current GR/SQ2 docs references for changed actions.

  3. Reported: “Tiny tooling snag: importing the logic disassembler directly needs the tools/ path on PYTHONPATH. I’m rerunning with that local path added; no project behavior involved.”

    Action/result: Retried a local table-print helper with tools/ added to sys.path.

  4. Reported: “That script has import-time argument handling, so I’m leaving it alone rather than leaning on it as a library. I’ll print the table addresses without importing it.”

    Action/result: Printed SQ2 and GR action-table entries for the changed shared opcodes using tools.compare_gr_sq2_static.load_table.

  5. Reported: “For the event/key/menu cluster, 0xad, 0xb1, and 0xb5 already have a good source pass in the notes; the missing piece is mostly 0x79, where the static report says the table capacity changed. I’m reading both key-map handlers and their consumers now.”

    Action/result: Compared SQ2 0x4c3d and GR 0x4e98, confirming that GR scans 0x31 key-map slots where SQ2 scans 0x27.

  6. Reported: “0x79 is now clear: the write logic is otherwise the same, but GR scans more four-byte key-map slots before giving up. I’m moving to the room/inventory/save/restart/object-state cluster, where the deltas are small entry-path changes but touch bigger subsystems.”

    Action/result: Began reading handlers for 0x12, 0x7c, 0x7d, 0x80, and 0x84.

  7. Reported: “The first room-switch read landed in a neighboring helper, so I’m tightening the address search around 0x175c/0x19d4 and the remaining changed handlers. The disassembly is linear, so exact address anchors matter here.”

    Action/result: Switched from nearby sed ranges to exact-offset local disassembly for action handlers.

  8. Reported: “One caveat surfaced: linear ndisasm sometimes swallows handler-entry bytes as prior inline data. For those entries I’m switching to exact-offset disassembly, which is the safer way to read handlers that sit beside tables.”

    Action/result: Exact-offset disassembly recovered the correct SQ2 0x12 handler at image 0x175c.

  9. Reported: “There’s a genuinely version-specific Gold Rush quirk in 0x12: its entry calls a tiny local helper that remaps immediate room bytes 0x7e..0x80 to 0x49 before entering the normal room-switch path. I’m checking whether the local GR scripts actually use that range before I describe the risk level.”

    Action/result: Disassembled local GR logic resources and found switch_room_like(#126), #127, and #128, proving the remap is live in this data set.

  10. Reported: “The room remap is not just dead code: the decoded local GR scripts do contain switch_room_like(#126), #127, and #128, and the GR handler redirects those immediates to room #73. I’ll record that as an observed v3/GR-specific compatibility detail rather than a portable rule.”

    Action/result: Added the remap to the version/evidence notes.

  11. Reported: “For inventory/save/restart, most differences are relocated state addresses plus a couple of extra guard/cleanup writes. The save action has an extra XOR pass over the inventory/object chunk before and after the file writes; I’m tracking that separately because it can matter for v3 save-file compatibility.”

    Action/result: Read GR helper 0x07bc, documenting its repeating-key XOR behavior over a caller-supplied byte range.

  12. Reported: “The object/motion deltas are nicely bounded: GR gates part of direction-to-loop selection on flag 0x14, treats exactly-four-loop views differently from SQ2, and lets motion mode 4 fall into the same target-direction path as mode 3. Those are now concrete enough to document as source-backed v3 deltas.”

    Action/result: Read frame-timer and motion-dispatch routines and decoded the GR motion-mode jump table.

  13. Reported: “I have enough source evidence for the planned queue now. I’m switching into documentation/tooling updates: the version ledger gets the portable summary, the evidence log gets the offsets and commands, and the static report notes get sharper names for the same deltas.”

    Action/result: Updated tools/compare_gr_sq2_static.py changed-action notes.

  14. Reported: “The progress tracker is the next file: I’m changing the queue from ‘do these four passes’ to ‘source pass complete; remaining work is targeted behavioral fixtures and more version samples.’”

    Action/result: Started updating PROGRESS.md.

  15. Reported: “The patch missed on a line wrap; nothing changed there yet. I’m applying the tracker update in smaller chunks so it lands cleanly.”

    Action/result: Successfully updated the logic-action comparison, object-runtime comparison, and highest-value remaining-work sections in PROGRESS.md.

  16. Reported: “PROGRESS.md now reflects the planned items and the source pass status. I’m adding the same findings to the Versions chapter so the differences are visible in the mdBook, not only in the tracker.”

    Action/result: Added shared-action and object/motion delta tables to docs/src/versions.md.

  17. Reported: “The logic bytecode chapter gets a compact cross-version note next. This keeps the opcode catalog portable: SQ2 behavior remains the baseline rows, and GR differences are called out as version associations.”

    Action/result: Added a shared-opcode GR/SQ2 note to docs/src/logic_bytecode.md.

  18. Reported: “I’m also touching the runtime model briefly so a future implementer sees the GR motion-mode caveat next to the generic motion lifecycle, not only in the version ledger.”

    Action/result: Added a GR-specific motion note to docs/src/runtime_model.md.

  19. Reported: “Now the symbolic label map: I’m adding GR address associations for the handlers I just used, and tightening the existing object/motion notes so later version comparisons can match by label instead of address.”

    Action/result: Added GR input/text, room, inventory, save, restart, and data-global associations to docs/src/symbolic_labels.md.

  20. Reported: “Next is the evidence log. I’m appending the exact source pass: commands, handler addresses, and the conclusions, with uncertainty separated from observed behavior.”

    Action/result: Added a new clean-room evidence section to docs/src/clean_room_executable_notes.md.

  21. Reported: “The evidence log is updated. I’m adding the user-facing progress updates to the progress log now, since the project instructions explicitly keep that historical trail.”

    Action/result: Added this progress-log section.

  22. Reported: “To isolate whether this is the line algorithm or the coordinate clamp, I’m adding an exact-boundary version of the same test using (0x9f,0xa7) -> (0,0). If that matches, the gap is in out-of-range coordinate handling; if it mismatches the same way, the diagonal line model needs correction.”

    Action/result: Added a new curated base case for exact-edge absolute-line drawing and renumbered subsequent curated base cases.

  23. User requested: “keep a log of every intermediate step that you’re reporting to me. it’s super interesting and i want to keep track of it for historical record” and “including everything you’ve done so far”.

    Action/result: Created this progress log and updated the project rules so future progress updates are logged as part of the clean-room history.

  24. Reported: “The progress log now contains the current fuzzing session from the first update through the exact-edge test I was adding when you asked. I’m wiring it into the book and adding a standing instruction so I keep appending to it as I go.”

    Action/result: Added progress_log.md to docs/src/SUMMARY.md, linked it from docs/src/README.md, and updated AGENTS.md with an instruction to preserve user-facing progress updates.

  25. Reported: “I’ll keep that log live from here on. Next I’m regenerating the corpus after the new exact-edge case and running the exact-edge QEMU comparison to separate coordinate clamping from diagonal line drawing.”

    Action/result: Regenerated the corpus after adding the exact-edge case. The corpus now has 1,040 cases, with 1,038 marked safe for QEMU. The local unit suite still passed with 33 tests, and mdbook build docs succeeded.

  26. Reported: “The regenerated corpus has 1,040 cases now, with 1,038 marked safe for QEMU; tests and mdBook still build cleanly. I’m running the exact-edge fixture through the original engine now.”

    Action/result: QEMU comparison for base_005_exact_edge_absolute produced the same 312 mismatches and mismatch bbox (0, 0, 149, 155) as base_004_clamped_absolute.

  27. Reported: “The exact-boundary case mismatched identically, so the gap is in the diagonal line helper, not out-of-range coordinate clamping. I’m updating the log, then I’ll correct the Python line algorithm against the disassembly and rerun the two line fuzz cases.”

    Action/result: Began revisiting the disassembled line helper at 0x66e1.

  28. Reported: “The likely bug is subtle but promising: the executable keeps the line accumulators in 8-bit registers, so long steep diagonals can wrap before the compare. My Python model used unbounded integers, which is fine for short lines but wrong at the screen-scale edge.”

    Action/result: Simulated the disassembled algorithm with 8-bit accumulator wrap. The wrapped model reproduced the QEMU edge-case shape: at y=0 the exact-edge line lands at x=25, not x=0.

  29. Reported: “A quick simulation of the disassembled 8-bit accumulator reproduces the original-engine edge case exactly: at y=0 the line lands at x=25, not x=0. I’m applying that change to the renderer and adding a regression test so this edge stays pinned.”

    Action/result: Updated PictureRenderer.draw_line() to wrap diagonal line accumulators to 8 bits after addition and subtraction.

  30. Reported: “The renderer now uses byte-width accumulator arithmetic for diagonal lines. I’m adding the focused test before rerunning the corpus and QEMU comparisons.”

    Action/result: Located the existing split absolute-line and relative-line tests in tests/test_graphics_rendering.py.

  31. Reported: “The existing line tests were split into separate absolute and relative cases, so I’m inserting the long-edge regression beside those instead of replacing anything.”

    Action/result: Added test_long_diagonal_uses_byte_width_line_accumulators to tests/test_graphics_rendering.py.

  32. Reported: “The long-edge regression is in. I’m running the unit suite now; if hashes changed in real SQ2 pictures, I’ll treat that as a signal and verify against the existing QEMU captures before updating expected values.”

    Action/result: The local unit suite passed with 34 tests.

  33. Reported: “The unit suite passes with 34 tests, so no existing SQ2 picture hash moved. I’m regenerating the corpus with the corrected renderer metadata and then comparing the two edge-line captures again.”

    Action/result: Regenerated the corpus. The corrected renderer matched the previously captured base_004_clamped_absolute QEMU output with 0 mismatches. The exact-edge recompare failed because the regenerated corpus did not contain the expected base_005_exact_edge_absolute metadata path, so the base-case list needed inspection.

  34. Reported: “The corrected renderer now matches the previous clamped-edge QEMU capture with zero mismatches. The exact-edge recompare failed because regenerating the corpus wiped the captured fixture metadata path before that case existed in the manifest, so I’m checking the base-case list and will rebuild/rerun that exact-edge capture cleanly.”

    Action/result: Verified that base_005_exact_edge_absolute is present in the base-case list and regenerated corpus. The failed compare was caused by running corpus regeneration and capture comparison in parallel.

  35. Reported: “The exact-edge case is present; the failed compare was a race from running corpus regeneration and comparison in parallel. I’m rerunning the exact-edge QEMU comparison now, sequentially.”

    Action/result: Reran base_005_exact_edge_absolute through QEMU. It matched the corrected renderer with 0 mismatches.

  36. Reported: “The exact-edge QEMU case now matches too. I’m rerunning the representative fuzz slice under the corrected renderer using the new case IDs, then I’ll document the framework, the line-accumulator correction, and the current fuzz results.”

    Action/result: Attempted to run three QEMU fuzz cases in parallel. This was rejected as a bad probe: QEMU’s VNC socket was blocked without escalation, and concurrent mtools/QEMU fixture copying caused a DOS-image directory-copy failure for one case.

  37. Reported: “That parallel QEMU slice was the wrong move: QEMU needs the VNC socket and the DOS image copy steps should be serialized. I’m recording that as a failed probe, then I’ll run the remaining cases one at a time with the harness command approved/escalated as needed.”

    Action/result: Updated copy_fixture_to_dos() to surface mmd failures unless the directory already exists.

  38. Reported: “The harness now surfaces mmd failures unless they’re the harmless ‘already exists’ case. I’m running the remaining representative QEMU cases sequentially now.”

    Action/result: The user interrupted the run and then granted full access. No QEMU or fuzz harness process was left running. Inspection showed that FZFILL2 already existed in the DOS image and that mmd returned a nonzero status with no diagnostic text for an existing directory. A probe directory FZNEW99 was created while checking mtools behavior.

  39. Reported: “Full access received. I’ll pick up from the aborted QEMU run, first checking whether any emulator process or partial DOS-image copy was left behind, then I’ll fix the mtools error reporting and continue the serialized fuzz comparisons.”

    Action/result: Verified no QEMU process was running and identified the quiet mmd existing-directory case.

  40. Reported: “No QEMU process is left behind. The interrupted run stopped before launching QEMU; the remaining issue is mtools returning a nonzero mmd status with no useful message, likely because the DOS directory already exists. I’m checking the DOS root and then I’ll make the copy step robust by verifying the directory exists when mmd is quiet.”

    Action/result: Confirmed FZFILL2 already existed and mmd returned status 1 with no output for that directory.

  41. Reported: “Confirmed: FZFILL2 already exists and mmd reports that with an empty error stream. I also created FZNEW99 as a harmless root-directory probe while checking mtools behavior. I’m patching the harness to validate existing directories explicitly instead of trusting the error text.”

    Action/result: Updated copy_fixture_to_dos() so a quiet mmd failure is accepted only if mdir can read the requested directory.

  42. Reported: “The harness now treats a quiet mmd failure as okay only if mdir can read the target directory. I’m logging that, then I’ll run the remaining QEMU cases sequentially with fresh directory names to keep the DOS image tidy-ish.”

    Action/result: Ran base_010_visual_control_fill through QEMU in DOS directory FZFIL3; it matched with 0 mismatches.

  43. Reported: “The visual/control fill fuzz case still matches under the corrected renderer. I’m moving on to the pseudo-random pattern case, also serialized.”

    Action/result: Ran base_012_pattern_random through QEMU in DOS directory FZPAT3; it matched with 0 mismatches.

  44. Reported: “The pseudo-random pattern case matches too. I’m running the safe truncated-coordinate case now; this one checks that an incomplete pair terminates the command without visible garbage.”

    Action/result: Ran base_014_truncated_pair through QEMU in DOS directory FZTRN3; it matched with 0 mismatches.

  45. Reported: “The representative fuzz slice is green now after the line-accumulator fix. I’m updating the spec/docs with the fuzz framework, the QEMU results, and the 8-bit accumulator correction, then I’ll run final verification.”

    Action/result: Updated graphics_object_pipeline.md, compatibility_testing.md, clean_room_executable_notes.md, and AGENTS.md. The docs now describe the fuzz framework, the representative QEMU pass, the failed probes, and the 8-bit line accumulator correction.

  46. Reported: “The evidence log now has the fuzz pass with command-level detail and the failed probes. I’m adding a short AGENTS.md note so future agents know how to use the fuzz harness and why QEMU fuzz runs should stay serialized.”

    Action/result: Added fuzz-harness command notes to AGENTS.md.

  47. Reported: “Docs and AGENTS are updated. I’m running the full local verification now: tests, mdBook build, whitespace check, and a final compare on the edge-line captures.”

    Action/result: python3 -B -m unittest discover -s tests passed with 34 tests; mdbook build docs succeeded; git diff --check succeeded; and base_004_clamped_absolute compared with 0 mismatches.

  48. Reported: “Verification is clean so far. I’m also checking the exact-edge capture and the three representative post-fix cases from their saved outputs, then I’ll summarize the final state.”

    Action/result: Saved captures for base_005_exact_edge_absolute, base_010_visual_control_fill, base_012_pattern_random, and base_014_truncated_pair all compared with 0 mismatches.

  49. Reported: “All saved fuzz captures compare cleanly now. I’m doing one last status/diff overview and updating the progress log entry from “pending” to the actual verification results.”

    Action/result: git status --short showed the expected modified tracked docs plus untracked generated/tool/test files. The saved fuzz captures present under build/picture-fuzz/fixtures/ include the representative scanner, line, fill, pattern, and truncated-data cases.

  50. Reported: “The diff overview only shows tracked-file deltas, so the new fuzz/test/tool files are still listed as untracked in git status; that matches the repo’s current uncommitted state. I’m closing the progress log with the final verification results now.”

    Action/result: This entry completes the current fuzzing pass log.

  51. Reported: “That boundary is important, and I’m going to write it down in the project docs so the fuzz harness treats ‘malformed but bounded’ differently from ‘malformed enough to make the interpreter run off into unrelated memory.’ The former can teach us parser edge cases; the latter belongs in a security notes bucket, not the compatibility spec.”

    Action/result: Updated compatibility_testing.md, clean_room_executable_notes.md, and AGENTS.md to define safe_for_qemu: false cases as out of scope for the behavioral model. Updated tools/picture_fuzz.py run-qemu to refuse those cases before launching QEMU, and added a regression test for that guard. Verified with python3 -B -m unittest tests.test_picture_fuzz, mdbook build docs, and git diff --check; a follow-up full run of python3 -B -m unittest discover -s tests passed with 35 tests.

  52. Reported: “I’ll commit the source, tests, and docs changes, while leaving generated build outputs and installer/disk-image artifacts out of the commit unless the repo is already tracking them. First I’m checking the ignore rules and the exact file list so the commit stays tidy.”

    Action/result: git status --short --untracked-files=all showed a large untracked generated set under build/ plus DOS installer images under 002962_ms_dos_622/. AGENTS.md already documents build/ as disposable generated output, so these artifacts were not staged.

  53. Reported: “The noisy untracked set is almost entirely generated: DOS installer images, the DOS hard disk image, screenshots, rendered PPM/PNG files, and copied SQ2 fixture directories. I’m staging only the project files that define the tooling, tests, and documentation, then I’ll review the staged diff before committing.”

    Action/result: Staged 18 source, documentation, and test files. The staged diff stat reported 3,571 insertions and 11 deletions, with no generated build/ or 002962_ms_dos_622/ artifacts included.

  54. Reported: “The progress log now records what I staged and why. I’m staging that log addition too, then running the same verification set before the commit.”

    Action/result: git diff --cached --check passed, python3 -B -m unittest discover -s tests passed with 35 tests, and mdbook build docs succeeded.

  55. Reported: “Everything staged looks right: 18 files, with generated artifacts still untracked. I’m creating the commit now.”

    Action/result: Created commit 6d55b73 with message Document graphics decoding and fuzz tests.

  56. Reported: “I’ll take the first step from that list: make the picture fuzz harness capable of running a bounded serial batch through QEMU, with machine-readable results and enough summary data to drive the next semantics fixes. I’m going to inspect the current harness shape, then I’ll add the batch path and document the workflow.”

    Action/result: Inspected tools/picture_fuzz.py, tests/test_picture_fuzz.py, the current compatibility-testing docs, and the working tree state. The only untracked directories before this pass were generated local artifacts under build/ and 002962_ms_dos_622/.

  57. Reported: “I’ve got the shape now: batch-qemu will select only safe_for_qemu cases from the manifest, optionally filter by case id/category/max count, run them one at a time, and write a JSON report with each case’s DOS directory, capture path, status, mismatch summary, and elapsed time. That should make QEMU a repeatable oracle instead of a one-case-at-a-time ritual.”

    Action/result: Added the batch-qemu command, batch selection helpers, stable DOS directory naming, JSON report writing, and unit tests with a mocked QEMU run.

  58. Reported: “Got it. I’ll keep pushing through the full sequence rather than stopping after the batch harness: first verify and run the batch oracle, then use whatever it exposes to refine picture semantics, and then move the same QEMU-validation pattern toward view/cel drawing and object behavior.”

    Action/result: python3 -B -m unittest tests.test_picture_fuzz passed with 8 tests. Regenerated a smaller working corpus with python3 -B tools/picture_fuzz.py generate --count 64 --seed 4097 --output build/picture-fuzz/corpus --clean, producing 80 cases, 78 marked safe for QEMU. git diff --check passed.

  59. Reported: “I’ve logged the verification and corpus regeneration. The next command may take a couple of minutes because it boots QEMU once per case and deliberately runs serially.”

    Action/result: Ran a 14-case curated safe QEMU batch covering scanner, line, corner, fill, pattern, and bounded invalid cases. The batch wrote build/picture-fuzz/batches/base_curated_001.json and reported 14 matches, 0 mismatches, and 0 errors.

  60. Reported: “The base report is strong: all 14 curated safe cases matched, including scanner, absolute and relative lines, both corner path modes, control-only fill, visual-plus-control fill, both pattern modes, and a bounded truncated pair. I’ve selected the first 16 safe random cases from the regenerated corpus and am running them as the next batch.”

    Action/result: Selected rand_00000 through rand_00015 from build/picture-fuzz/corpus/manifest.json for a random safe QEMU batch.

  61. Reported: “The random QEMU batch is underway. If it comes back green, that gives us confidence in the current picture renderer across mixed command streams; if not, the report should point directly at the next disassembly target.”

    Action/result: Ran python3 -B tools/picture_fuzz.py batch-qemu --case rand_00000 ... --case rand_00015 --dos-prefix FR --output build/picture-fuzz/batches/random_00000_00015.json --boot-wait 5 --draw-wait 8. The report showed 16 matches, 0 mismatches, and 0 errors.

  62. Reported: “The random report confirms matches across line, corner, pattern, fill, and scanner categories. I’m patching the runner to print per-case progress during long batches, and I’m adding targeted base cases for bounded fill barriers and pattern edge placement so the next QEMU pass is less accidental.”

    Action/result: Added per-case progress printing for batch-qemu and added new curated base cases for visual fill inside/outside a box, pattern lower-right edge clamping, rectangular pattern masks, and multiple pseudo-random pattern seeds.

  63. Reported: “The new cases are in and the batch command will now report progress as it runs. I’m regenerating the corpus, running the focused tests, and then I’ll send the new targeted cases through QEMU.”

    Action/result: python3 -B -m unittest tests.test_picture_fuzz passed with 8 tests. Regenerated the working corpus; it now has 85 cases, 83 marked safe for QEMU. git diff --check passed.

  64. Reported: “The streaming status is already paying off: the first targeted fill-box case matched. The batch is now on the outside-box fill case.”

    Action/result: The targeted batch continued; both fill cases matched.

  65. Reported: “Good, the two bounded fill cases matched. The circular pattern edge case produced a small 5-pixel mismatch, so after the batch finishes I’ll drill into that report and the pattern positioning logic.”

    Action/result: The targeted batch finished with 3 matches, 2 mismatches, and 0 errors. base_018_pattern_edge_circle mismatched by 5 pixels and base_019_pattern_edge_rectangle mismatched by 14 pixels; both mismatches appeared at X 0 on lower screen rows.

  66. Reported: “The mismatch is very precise: the original engine plots column 160 from a lower-right pattern mask as the first pixel of the next scanline, while the Python renderer clipped it away. This is a pattern-specific edge behavior, not a general line-coordinate issue, so I’m going to model it in the pattern plot path and lock it with a test.”

    Action/result: Inspected the targeted batch report and confirmed the out-of-bounds pattern column wraps through the linear picture buffer. Added write_cell() for linear buffer writes, changed pattern plotting to call it directly, added a regression test for lower-right rectangular pattern wrap, and documented the behavior in graphics_object_pipeline.md.

  67. Reported: “The pattern-edge fix is in place and documented. I’m running the rendering tests and regenerating the corpus so the Python hashes reflect the corrected pattern behavior before rerunning the targeted QEMU batch.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering tests.test_picture_fuzz passed with 32 tests. Regenerated the working corpus; it remained at 85 cases, 83 safe for QEMU. git diff --check passed.

  68. Reported: “The targeted rerun is underway with the corrected renderer. The first fill case still matches, and the run is progressing case by case with the new live output.”

    Action/result: The rerun showed base_016, base_017, and the corrected base_018_pattern_edge_circle all matching. The later cases failed with DOS-image Disk full errors rather than renderer mismatches.

  69. Reported: “Host disk space is fine; the ‘Disk full’ is inside the small DOS hard disk image. I also found the cause: rerunning a fixture copied its old qemu_capture.ppm back into DOS, wasting image space. I’m patching the copy step to exclude generated host captures, then I’ll clear old fuzz directories from the DOS image.”

    Action/result: Updated copy_fixture_to_dos() to skip generated .ppm files when copying a fixture into the DOS image.

  70. Reported: “The DOS image is literally at 0 bytes free, and the root is full of generated fuzz directories (FZ*, FB*, FR*, FT*, FU*). I’m removing those disposable directories from the DOS image, leaving the base DOS install and original SQ2/validation fixture directories alone.”

    Action/result: Removed generated fuzz directories from build/dos622/dos622.img. The DOS image root then showed about 56 MB free.

  71. Reported: “The storage cleanup worked; the rerun is progressing normally and the first targeted case still matches. I’m waiting for the pattern edge cases now.”

    Action/result: Reran the targeted fill/pattern batch as targeted_fill_pattern_003.json. All five cases matched with 0 mismatches and 0 errors.

  72. Reported: “The targeted rerun is green: all five fill/pattern cases now match the original engine. I’m updating the docs with the batch harness, the DOS-image storage lesson, and the newly observed pattern linear-wrap behavior before moving on to view/cel validation.”

    Action/result: Updated AGENTS.md, compatibility_testing.md, clean_room_executable_notes.md, and graphics_object_pipeline.md with batch-QEMU usage, current fuzz coverage, DOS-image cleanup notes, and the pattern X-160 linear-write behavior.

  73. Reported: “The current capture comparator can already compose a rendered view over a picture, but it only reports a mismatch count. I’m going to upgrade it to report bounding boxes/samples and add a view_batch.py tool that builds picture-view fixtures, runs them through QEMU serially, and emits JSON reports like the picture fuzz runner.”

    Action/result: Extended picture-capture comparison results with mismatch boxes and samples. Added tools/view_batch.py with base view/object cases, fixture generation, serial QEMU execution, and JSON report writing.

  74. Reported: “The view batch tool is in place. I’m adding a small unit test around its case loading/report path before running it against QEMU, so the batch machinery itself has coverage independent of the emulator.”

    Action/result: Added tests/test_view_batch.py covering base case coverage, JSON case loading, DOS directory naming, and report summary generation.

  75. Reported: “The view-batch unit tests are added. I’m running the full local suite and mdBook now before using QEMU again.”

    Action/result: python3 -B -m unittest discover -s tests passed with 43 tests, mdbook build docs succeeded, and git diff --check passed.

  76. Reported: “The verification result is logged. Starting the six-case view batch now: normal cel, mirrored cel, left/top clipping, and a low-priority object case.”

    Action/result: Ran python3 -B tools/view_batch.py --dos-prefix VB --output build/view-batch/batches/view_base_001.json --boot-wait 5 --draw-wait 8. Five cases matched; view_011_top_clip mismatched in rows 0 through 4.

  77. Reported: “The cached search found an exact match: the original output equals drawing the cel at left=18, baseline_y=4 when the fixture requested left=20, baseline_y=2. In other words, when the computed top is -2, the overlay path shifts left by that negative top and clamps the top to row 0. I’m encoding that as a provisional add_to_pic/overlay placement rule and will rerun the view batch.”

    Action/result: Updated object-frame composition to adjust left and baseline_y when the computed top is negative. Added a regression test and documented the QEMU-observed top-edge adjustment.

  78. Reported: “The top-edge adjustment is modeled and tested locally. I’m running the relevant tests, then I’ll rerun the view batch to verify the QEMU mismatch is gone.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering tests.test_view_batch passed with 29 tests, and git diff --check passed.

  79. Reported: “The test result is logged. Starting the QEMU rerun for the view batch with the corrected top-edge model.”

    Action/result: Reran tools/view_batch.py as build/view-batch/batches/view_base_002.json. All six cases matched with 0 mismatches and 0 errors.

  80. Reported: “The corrected view batch is fully green: all six cases match, including the top-edge placement case. I’m documenting the view-batch harness and the observed object top-edge rule, then I’ll do the full verification pass.”

    Action/result: Updated compatibility_testing.md and clean_room_executable_notes.md with view-batch commands, coverage, results, and the top-edge object placement rule.

  81. Reported: “That’s a great optimization target. I’m going to pause the broader reverse-engineering loop and investigate QEMU host-directory options for DOS specifically; the likely candidate is QEMU’s virtual FAT block device, which should appear to DOS as another drive. If that works, the next harness shape is ‘boot once, run many prebuilt fixture directories from a shared drive.’”

    Action/result: Checked local QEMU version (11.0.2) and help output. DOS cannot use QEMU 9p/virtfs directly without a guest driver, so the practical candidate is a QEMU FAT-backed block device exposed as a secondary DOS disk.

  82. Reported: “QEMU accepts the FAT-backed secondary drive syntax. Now I’m booting DOS with that share attached and sending a DIR D:\ command, then I’ll capture the VGA screen to confirm DOS can actually see the host file.”

    Action/result: Booted QEMU with -drive file=fat:rw:build/qemu-share,format=raw,if=ide,index=1,media=disk. DOS saw the host directory as drive D: with volume label QEMU VVFAT and listed HOST.TXT.

  83. Reported: “The screenshot confirms it: DOS sees the host directory as D: with volume label QEMU VVFAT, and HOST.TXT is visible. Next I’m testing the part that matters for our harness: running an AGI fixture directly from that shared D: drive without copying it into the DOS image.”

    Action/result: Built build/qemu-share/PIC001 and ran it from D:\PIC001 in QEMU. The capture build/qemu-share/from_share_pic001.ppm compared against picture 1 with 0 mismatches.

  84. Reported: “Running from the shared drive works: the AGI fixture on D:\PIC001 produced a capture with 0 mismatches against the local renderer. The remaining question for ‘boot once’ is whether the generated fixture returns to DOS after drawing; I’m testing that by sending another DOS command after the draw and capturing the screen.”

    Action/result: Sending DIR after running SIERRA left the game screen visible. The generated fixture does not return to DOS, so multi-case no-boot runs need loadvm/reset or a different fixture script.

  85. Reported: “A QEMU internal snapshot with fat:rw: fails because writable vvfat does not support live migration/snapshotting. That’s not fatal: for test inputs we only need the host share read-only inside DOS, and we can put the boot disk on a qcow2 overlay that stores VM snapshots. I’m testing that combination next.”

    Action/result: Created build/dos622/dos622-test.qcow2 as a qcow2 overlay over the raw DOS disk. Read-only vvfat as an IDE disk still failed, but read-only vvfat as an IDE CD-ROM allowed savevm.

  86. Reported: “Useful result: fat:... as a read-only IDE disk still fails, but exposing it as a read-only IDE CD-ROM allows QEMU savevm. Now I’m checking whether this DOS install can actually see that CD-ROM-style drive as D:; if not, we can still use snapshots with another share mechanism, but not this one directly.”

    Action/result: DOS reported Invalid drive specification for the CD-ROM-style share because the current image has MSCDEX but no IDE/ATAPI CD-ROM driver configured.

  87. Reported: “There’s MSCDEX, but no IDE/ATAPI CD-ROM driver in the DOS image. A better idea for a read-only, snapshot-compatible host directory is to expose the QEMU FAT share as a floppy, because DOS can see floppy drives without MSCDEX; I’m testing whether QEMU’s vvfat floppy is large enough and visible.”

    Action/result: Plain if=floppy produced invalid media. fat:floppy: was accepted only when the host directory fit FAT12 capacity. A nested full fixture directory appeared empty, and a root-level fixture exposed only a subset of files, making this path unsuitable for full AGI fixtures.

  88. Reported: “The root-level floppy share is visible but not usable for full AGI fixtures: DOS only sees a small subset of the files. So the clean result is: host directory mounting works well as a secondary D: hard disk with fat:rw:...; snapshot-based no-reboot runs need either a DOS CD-ROM driver for read-only vvfat CD-ROM, or a generated qcow2/FAT test disk instead of a live host directory. I’m documenting the exact working and non-working combinations now.”

    Action/result: Updated AGENTS.md and this evidence log with the working fat:rw: command, the successful run from D:, and the limitations around QEMU snapshots, CD-ROM drivers, and floppy-sized vvfat shares.

  89. Reported: “I’ll commit the source, tests, and docs from this pass, leaving the generated QEMU shares, captures, qcow overlay, build/, installer images, and __pycache__ out of the commit. I’m checking the exact staged set first so the commit doesn’t accidentally pick up emulator artifacts.”

    Action/result: git status --short --untracked-files=all showed the expected generated artifacts under build/, the DOS installer images under 002962_ms_dos_622/, and Python cache files. git diff --check passed.

  90. Reported: “The staged set is exactly 12 source/docs/test files; generated artifacts remain untracked. I’m running the full tests, mdBook, and cached diff whitespace check before committing.”

    Action/result: python3 -B -m unittest discover -s tests passed with 44 tests, mdbook build docs succeeded, and git diff --cached --check passed.

  91. Reported: “The final staged diff is clean. I’m committing it with a message that covers the two main pieces: QEMU validation batches and host-share investigation.”

    Action/result: Created a commit with message Add QEMU validation batches; it was then amended to include this progress log entry.

  92. Reported: “I’ll build and test the qcow2 fixture-disk path end to end: create a normal FAT disk image with prebuilt AGI fixture directories, attach it as D:, verify DOS can see and run from it, then test savevm/loadvm around repeated fixture runs. If it works, I’ll fold that into the harness/docs so we can stop paying the full boot cost per case.”

    Action/result: Confirmed mformat, mcopy, mdir, mmd, mdel, mrd, qemu-img, and qemu-system-i386 are installed. The working tree only had generated artifacts under build/, 002962_ms_dos_622/, and tools/__pycache__/ before this pass.

  93. Reported: “DOS doesn’t accept a partitionless FAT image as a hard disk, so we do need an MBR-style partition. I’m creating a raw disk with a simple FAT16 partition starting at sector 63, formatting that partition with mtools, then converting it to qcow2.”

    Action/result: A partitioned secondary qcow2 fixture disk could be read by mtools, but DOS either treated sector 0 as a garbage FAT boot sector or reported Not ready reading drive D, even with DOS-like partition metadata and forced IDE CHS.

  94. Reported: “Forcing IDE geometry didn’t fix the second-disk case. I’m switching to the more robust variant: create a disposable qcow2 clone of the DOS boot disk with fixture directories preloaded onto C: itself. That still gives us the important property: one boot, savevm at the DOS prompt, then loadvm between fixture runs.”

    Action/result: Copied build/dos622/dos622.img to a disposable raw image, copied PIC001 and VIEW11 fixture directories into its DOS partition, converted it to qcow2, booted once, saved VM state at the DOS prompt, ran PIC001, loaded the saved VM, ran VIEW11, and compared both captures. Both matched with 0 mismatches.

  95. Reported: “The implementation pivot is clear: a generic helper will create a disposable qcow2 clone of the boot disk, preload DOS fixture directories with mtools, boot once, savevm ready, and loadvm ready between cases. Then view_batch.py --snapshot can use it without changing the comparison logic.”

    Action/result: Added tools/qemu_snapshot.py for disposable boot-disk cloning, mtools fixture preloading, and one-boot snapshot QEMU execution. Added tools/view_batch.py --snapshot plus local unit coverage for the snapshot helper’s fixture filtering, mtools image syntax, and monitor key names.

  96. Reported: “The view/object snapshot smoke passed: all six cases matched with zero errors. I’m going to extend the same one-boot mode to the picture fuzz batch command too, because that is where the boot cost really hurts.”

    Action/result: Ran python3 -B tools/view_batch.py --snapshot --dos-prefix VS --output build/view-batch/batches/view_snapshot_smoke.json --boot-wait 5 --draw-wait 8. QEMU booted once from the generated snapshot qcow2, restored the DOS prompt between the six built-in view/object cases, and all captures matched. Extended tools/picture_fuzz.py batch-qemu with --snapshot, using the shared qcow2 boot-disk snapshot helper. Added a mocked unit test proving snapshot-mode fuzz reports are compared and recorded through the existing batch-result path.

  97. Reported: “The real fuzz snapshot smoke passed too: both synthetic picture cases matched the original engine with zero mismatches from one QEMU boot. I’m recording that result now and then I’ll do one final status/check pass.”

    Action/result: Ran python3 -B tools/picture_fuzz.py batch-qemu --snapshot --case base_016_visual_fill_box --case base_019_pattern_edge_rectangle --dos-prefix FS --output build/picture-fuzz/batches/snapshot_smoke.json --boot-wait 5 --draw-wait 8. QEMU booted once from the generated snapshot qcow2, restored the DOS prompt between the two cases, and both captures compared with 0 mismatches.

  98. Reported: “I found a useful next lever: the fixture builder can currently combine a real SQ2 picture with a view, or a synthetic picture alone, but not a synthetic picture plus a view. Adding that combined fixture will let us create tiny controlled priority/control backgrounds and compare object overlay behavior against the original engine.”

    Action/result: Began adding a synthetic-picture-plus-view fixture path and targeted object overlay probes so priority/control behavior can be tested against QEMU with controlled picture backgrounds.

  99. Reported: “The first four priority threshold probes matched exactly, which is a strong signal that the basic existing_priority <= object_priority rule is right. I’m adding one more pair that targets the stranger part of the routine: when the destination cell has a low control nibble, it scans downward to find a real priority barrier.”

    Action/result: Ran python3 -B tools/object_overlay_probe.py --dos-prefix OP --output build/object-overlay-probes/batches/base_priority.json --boot-wait 5 --draw-wait 8. The default-control priority 3/4 pair and full-screen-control-6 priority 5/6 pair all matched QEMU with 0 mismatches. Added two scan-down cases that place control 2 at the object’s top row and control 6 one row below.

  100. Reported: “The QEMU result confirms both branches of the priority gate we cared about: direct high-priority comparison and low-control downward scanning. I’m folding that into the docs now as confirmed compatibility evidence rather than just a code hypothesis.”

    Action/result: Ran python3 -B tools/object_overlay_probe.py --dos-prefix OQ --output build/object-overlay-probes/batches/priority_scan_down.json --boot-wait 5 --draw-wait 8. All six object overlay probes matched QEMU with 0 mismatches, including the two low-control scan-down cases. Updated the graphics/object pipeline, compatibility testing notes, clean-room executable notes, and AGENTS tool instructions.

  101. Reported: “The 0x7a path stages two nibbles into object byte +0x24: the sixth operand as the low nibble and the seventh as the high nibble. I’m adding two mismatch probes now to confirm which nibble controls visible overlay priority, because that matters for the spec.”

    Action/result: Added two object overlay probes with intentionally different operand-6 and operand-7 values: priority 3/control 6 on a default control-4 background, and priority 6/control 3 on a control-6-filled background.

  102. Reported: “The nibble-discriminator cases matched too. That confirms visible object priority comes from the low nibble staged by operand 6; the high nibble from operand 7 does not control whether the cel pixels draw in these probes.”

    Action/result: Ran python3 -B tools/object_overlay_probe.py --dos-prefix OR --output build/object-overlay-probes/batches/priority_nibbles.json --boot-wait 5 --draw-wait 8. All eight object overlay probes matched QEMU with 0 mismatches. Updated the graphics/object pipeline, compatibility notes, and clean-room executable notes to describe the low-nibble visible-priority result.

  103. Reported: “Two useful surprises came out. The right-edge case shows placement clamps the object’s left coordinate to 160 - width rather than just clipping pixels. The persistent 0x36 priority-byte case suggests the high nibble can affect persistent placement/control acceptance even though transient visible drawing uses the low nibble, so I’m tightening those models and adding one confirmation case.”

    Action/result: The expanded object overlay run matched 16 of 18 cases. Added right-edge placement clamping to the local overlay model, changed the persistent 0x36 case to expect rejection under control 6, and added a 0x66 persistent priority-byte confirmation case.

  104. Reported: “The right-edge behavior is not a simple clamp: the actual cel lands around x=140, baseline_y=67, so placement search adjusts both axes. The persistent 0x66 case is hidden too, which makes the safer current conclusion: persistent fixed priority bytes with a nonzero high nibble are not valid visible-priority inputs in these probes. I’m encoding those as observed expectations rather than pretending the simple model covers them generally.”

    Action/result: Added per-case expected placement overrides for the right-edge probe and changed the persistent 0x66 probe to expect a hidden object under the controlled priority-6 picture.

  105. Reported: “The full 19-case QEMU batch is clean: clipping, transparent variants, priority-table-derived priority, and persistent-object setup all matched. I’m updating the spec now, including the important caveat that right-edge placement is observed as a placement-search result, not a general formula yet.”

    Action/result: Ran python3 -B tools/object_overlay_probe.py --dos-prefix OG --output build/object-overlay-probes/batches/expanded_all5_final.json --boot-wait 5 --draw-wait 8. All 19 cases matched QEMU with 0 mismatches. Updated compatibility notes, clean-room executable notes, and graphics/object pipeline documentation.

  106. Reported: “I’m picking up from the movement-probe branch of the work. The first QEMU run showed the object stayed exactly at its activation coordinates, which is a useful failure: the current fixture loops inside one logic invocation, so I’m going to switch it to a once-only setup guarded by an engine flag and let the interpreter return to its per-cycle machinery.”

    Action/result: Re-read tools/qemu_fixture.py, tools/object_movement_probe.py, the condition parser in tools/disassemble_logic.py, and the existing logic-bytecode docs.

  107. Reported: “The local notes already have the important conditional-block semantics, but I’m checking them against the disassembler implementation before encoding fixtures by hand. This is one of those tiny-byte-layout spots where one wrong offset can make the engine do a completely different thing while still looking valid.”

    Action/result: Confirmed the condition-list terminator carries a little-endian false delta after the 0xff condition-list end byte.

  108. Reported: “The real scripts make this simpler than the prose sounded: the condition-list terminator’s two-byte delta skips the following then-body directly. I’m adding a tiny bytecode builder for run this setup once unless flag X is already set, then the logic ends normally each tick so the engine can advance motion.”

    Action/result: Added reusable fixture helpers for logic-resource wrapping, end, set_flag, not flag_set, conditional blocks, and once-only logic.

  109. Reported: “I found SQ2’s own startup logic clearing broad high flag ranges, so I’m choosing an explicit fixture init flag and making it configurable per movement case. The generated logic will now look like: if not flag_set(init_flag) { load picture, set up object, start move, set init_flag } end.”

    Action/result: Added persistent_object_once_logic_payload() and optional init_flag support to persistent object fixtures.

  110. Reported: “The unit tests now cover the new byte sequences directly. I’m running the suite and a quick generated-logic disassembly check next; if those pass, I’ll send the two movement cases through QEMU again and compare against the Python renderer.”

    Action/result: Ran python3 -B -m unittest discover -s tests; 72 tests passed.

  111. Reported: “QEMU ran cleanly, but both cases still mismatch. That’s not a dead end; it means we now have captures from a better fixture, and I’m going to locate the object in those captures rather than assuming the target semantics.”

    Action/result: Ran python3 -B tools/object_movement_probe.py --dos-prefix MV --output build/object-movement-probes/batches/base_movement_once.json --boot-wait 5 --draw-wait 8. Both one-shot movement cases mismatched.

  112. Reported: “The new captures show the object moved, just not to the target I expected. The mismatch boxes are shifted far beyond the requested target, so I’m waiting on a brute-force position match to identify the actual final coordinates.”

    Action/result: Best-position scan found exact matches at (140,80) for the horizontal one-shot case and (20,167) for the vertical one-shot case.

  113. Reported: “The captures match perfectly at (140,80) for the horizontal case and (20,167) for the vertical case. That strongly suggests move_object_to is not treating the target X/Y operands as immediates in this action variant, so I’m going back to the action table metadata and real script usage before updating the model.”

    Action/result: Rechecked 0x51/0x52 docs, action-table metadata, and local SQ2 script uses. The immediate-target interpretation remained consistent with the static handler analysis.

  114. Reported: “The static handler docs still say immediate targets, so the mismatch is probably in the per-cycle movement semantics, not bytecode operands. The object appears to keep the initial direction until it hits a screen boundary, which means we need to verify where and when the arrived at target check runs.”

    Action/result: Re-read movement-pass docs and concluded that scripts need to reissue move_object_to on later cycles so helper 0x1672 can observe that the current object position has reached the target.

  115. Reported: “This clarifies the right fixture shape: setup should be once-only, but move_object_to itself has to be reissued on later cycles until its completion flag becomes set. I’m changing the movement fixture from start movement once to initialize once, then call movement each tick while completion flag is clear.”

    Action/result: Added optional guarded per-cycle action blocks to persistent_object_once_logic_payload() and moved the probe’s 0x51 action into that block.

  116. Reported: “The suite is green at 73 tests and the diff has no whitespace issues. I’m running the revised QEMU probe now; this one should tell us whether repeated action issuance is the missing semantic.”

    Action/result: Ran tests and git diff --check; both passed.

  117. Reported: “That did it: both reissued-action movement probes match the Python expectation exactly. I’m going to fold this into the docs now, then expand the batch a bit with explicit boundary-style movement cases and add better mismatch observability so future failures tell us where did the object end up automatically.”

    Action/result: Ran python3 -B tools/object_movement_probe.py --dos-prefix MV --output build/object-movement-probes/batches/base_movement_reissued.json --boot-wait 5 --draw-wait 8. Both target-arrival cases matched QEMU with 0 mismatches.

  118. Reported: “I’m adding two screen-edge probes to the same harness and teaching mismatch reports to include a best-fit object position. That turns future failures from pixels differ into the engine placed the object at X/Y, which is much more useful for reverse engineering.”

    Action/result: Added right-edge and bottom-edge movement cases plus MovementComparison.best_position.

  119. Reported: “The mismatch-position test found an equivalent drawn placement at the very top edge, which is a nice reminder that clipped cels can alias. I’m moving the synthetic mismatch away from clipping so the inferred coordinate is unambiguous.”

    Action/result: Adjusted the unit test to use an unclipped synthetic mismatch capture.

  120. Reported: “The suite is green at 74 tests. I’m launching the four-case QEMU batch now: two target arrivals plus right and bottom edge completion cases.”

    Action/result: Ran tests and launched python3 -B tools/object_movement_probe.py --dos-prefix MV --output build/object-movement-probes/batches/base_movement_edges.json --boot-wait 5 --draw-wait 8.

  121. Reported: “All four QEMU movement cases matched, including the screen-edge stops. I’m documenting the clean-room evidence now: the important semantic is that scripts reissue targeted movement until the completion flag trips; a one-shot start keeps moving until boundary completion.”

    Action/result: The four-case movement batch matched QEMU with 0 mismatches.

  122. Reported: “I’m updating four doc surfaces: the running progress log, the compatibility test recipe, the object/movement model, and the clean-room evidence notes. Keeping these in sync is a bit clerical, but it is what makes the later implementation work grounded instead of folkloric.”

    Action/result: Updated docs/src/compatibility_testing.md, docs/src/graphics_object_pipeline.md, docs/src/logic_bytecode.md, and docs/src/clean_room_executable_notes.md with the targeted movement findings.

  123. Reported: “I’m going to add one control-buffer acceptance case before wrapping: a synthetic picture whose control channel is filled with zero. The hypothesis from 0x56b8 is that proposed movement should be rejected, leaving the object at its start position even though the movement action keeps reissuing.”

    Action/result: Added a fifth movement case using picture payload f2 00 f8 00 00 ff and an initial expectation that the object would remain at (20,80).

  124. Reported: “The control-zero hypothesis did not match, which is useful evidence. I’m inspecting the report’s inferred position now; if it moved normally, control zero is not a simple blanket movement rejection in this setup.”

    Action/result: Ran python3 -B tools/object_movement_probe.py --dos-prefix MV --output build/object-movement-probes/batches/base_movement_control.json --boot-wait 5 --draw-wait 8. The first four cases matched, but the control-zero case mismatched. best_position showed an exact match at (50,80), meaning the object reached the target.

  125. Reported: “The inferred position is exact at (50,80): the object reached the target on a control-zero-filled synthetic picture. I’m changing that case from a rejected-move hypothesis into a confirmed acceptance probe, then I’ll rerun the batch so the saved report is green.”

    Action/result: Renamed the case to move_allowed_on_control_zero and changed its expected final position to (50,80).

  126. Reported: “The corrected five-case batch is green. I’m updating the docs one more time so they mention the control-zero acceptance result instead of only the four movement cases.”

    Action/result: Ran python3 -B tools/object_movement_probe.py --dos-prefix MV --output build/object-movement-probes/batches/base_movement_control_final.json --boot-wait 5 --draw-wait 8. All five cases matched QEMU with 0 mismatches.

  127. Reported: “I’ve got the source-backed movement model pinned down now, so I’m going to encode more edge cases around 0x16ed: left/up, diagonal, non-divisible distances, zero step override, and already/near-target completion. Then I’ll run them through QEMU and update the docs with what actually matches.”

    Action/result: Added seven movement cases to tools/object_movement_probe.py.

  128. Reported: “The movement corpus now has twelve cases, including the direction and tolerance cases I wanted. I’m updating the tests to lock in that expanded coverage before running QEMU.”

    Action/result: Updated tests/test_object_movement_probe.py; local tests passed.

  129. Reported: “The movement model matched 11 of 12; the only miss is the zero step override. I’m inspecting the report now, because that should tell us the existing default step size the engine actually used.”

    Action/result: Ran python3 -B tools/object_movement_probe.py --dos-prefix MX --output build/object-movement-probes/batches/expanded_movement_edges.json --boot-wait 5 --draw-wait 8. The zero-step case’s best_position was (20,80), proving operand 3 value zero preserved the object’s current zero step in this generated fixture.

  130. Reported: “The zero-step case is illuminating: in this generated object, the existing step byte is zero, so operand 0 preserves zero and the object never moves. I’m changing that case to record zero preserves current step, with the current synthetic default being stationary.”

    Action/result: Updated the zero-step expected final position to (20,80). The rerun python3 -B tools/object_movement_probe.py --dos-prefix MX --output build/object-movement-probes/batches/expanded_movement_edges_final.json --boot-wait 5 --draw-wait 8 matched all 12 cases with 0 mismatches.

  131. Reported: “For object-object collision, the available clean fixture path is less direct than movement: object grouping is not exposed by a simple script action. I’m disassembling 0x4719 closely now so any QEMU probe we add is designed around what the helper really tests, not just a guess about overlap.”

    Action/result: Disassembled 0x4719; confirmed moving-object bit 0x0200, candidate flags, grouping byte +0x02, horizontal overlap, and Y equality/crossing predicates.

  132. Reported: “Good, the startup code initializes object byte +0x02 to the object index, so object 0 and object 1 naturally have different collision groups. I’m adding two-object movement fixtures: one where object 0 is blocked by object 1, and one where setting bit 0x0200 on object 0 skips the collision and allows it through.”

    Action/result: Added set_object_bit_0200_action() to tools/qemu_fixture.py and optional obstacle-object support to tools/object_movement_probe.py.

  133. Reported: “QEMU is now running 14 cases, including the two-object collision checks. I expect the first 12 to stay green; the useful signal will be cases 13 and 14.”

    Action/result: Ran python3 -B tools/object_movement_probe.py --dos-prefix MC --output build/object-movement-probes/batches/movement_collision.json --boot-wait 5 --draw-wait 8. All 14 cases matched with 0 mismatches. The blocked collision case stopped object 0 at (25,80) before touching object 1 at (50,80), and the collision-skip bit case reached (80,80).

  134. Reported: “Before wrapping, I’m checking the autonomous modes (0x53/0x54) call sites so the docs can distinguish what we validated in QEMU from what remains source-only.”

    Action/result: Scanned near call sites and disassembled helper 0x0563. Documented the source-derived cycle ordering: 0x0563 calls dispatcher 0x067a for active objects with countdown byte +0x01 == 1; 0x067a dispatches mode +0x22 value 1 to 0x3f5a, value 2 to 0x0b36, and value 3 to 0x1672, before 0x0563 calls movement pass 0x150a.

  135. Reported: “One thing I’m catching before I wrap this: the current batch finished the targeted movement and collision parts cleanly, but the full steps brief also includes the other motion modes and broader suite shape. I’m going to inspect the existing fixture/probe helpers so I can extend that work instead of calling it done too early.”

    Action/result: Reviewed tools/qemu_fixture.py, tools/object_movement_probe.py, and the existing docs for autonomous modes 0x53 and 0x54.

  136. Reported: “For mode 2, I can make the test deterministic: object 1 approaches object 0, and the visual comparison includes both objects. I’m going to add it with an expected position, run QEMU, and if the real engine lands at a different near-band coordinate I’ll correct the expectation and document that as evidence.”

    Action/result: Added reusable fixture encoders for assignn, set_object_field_1e_var, set_object_field_01_var, approach_first_object_until_near, start_random_motion, and stop_motion_mode. Added one autonomous mode-2 probe case to tools/object_movement_probe.py.

  137. Reported: “The fast suite is green with 78 tests. Now I’m sending the full movement batch through QEMU, including the new autonomous approach case; this is the slower but more interesting part.”

    Action/result: Ran python3 -B tools/object_movement_probe.py --dos-prefix MA --output build/object-movement-probes/batches/autonomous_modes_001.json --boot-wait 5 --draw-wait 8. The first 14 cases matched. The new threshold-25 approach case mismatched; its best captured moving-object position was (60,75), showing the probe had entered collision/stuck-recovery behavior near object 0 rather than cleanly isolating direct approach completion.

  138. Reported: “The mismatch is informative: with a threshold of 25, the object appears to hit the collision/stuck-recovery path near the target instead of cleanly completing. I’m widening the near threshold so this probe isolates mode-2 completion rather than object-object collision recovery.”

    Action/result: Changed the approach threshold to 35 and first expected boundary position to (45,80). The rerun python3 -B tools/object_movement_probe.py --dos-prefix MB --output build/object-movement-probes/batches/autonomous_modes_002.json --boot-wait 5 --draw-wait 8 still mismatched, with best position (50,80).

  139. Reported: “The second report gives a clearer source-derived correction: mode 2 completed at X 50, not 45. That suggests the near test is strict at the threshold boundary; I’m updating the expected result to the real-engine coordinate and rerunning once more for a clean green report.”

    Action/result: Updated the expected approach position to (50,80). The final run python3 -B tools/object_movement_probe.py --dos-prefix MD --output build/object-movement-probes/batches/autonomous_modes_003.json --boot-wait 5 --draw-wait 8 matched all 15 cases with 0 mismatches.

  140. Reported: “Great, the final QEMU batch is green: 15/15 exact matches, including autonomous approach mode. I’m updating the docs and progress log with the failed-threshold observation and the corrected passing run, because that intermediate result is useful clean-room evidence.”

    Action/result: Updated the compatibility docs, object pipeline docs, and clean-room executable notes with the mode-2 QEMU evidence.

  141. Reported: “I’ll take these as an implementation batch: extend the QEMU probes, reverse the stuck/recovery path enough to document it, add object-field notes where source-backed, and start turning view/cycle behavior into the same compatibility harness style.”

    Action/result: Reviewed the existing movement, fixture, overlay, and graphics docs before editing.

  142. Reported: “The current harness can be extended without splitting tools: exact-position checks still work for deterministic modes, and I can add a property-based comparison for random motion where the engine is allowed to choose any final position as long as the object is rendered exactly somewhere valid.”

    Action/result: Added comparison_kind="any_position" support to tools/object_movement_probe.py, plus move_to_once_countdown_gated_completion and random_motion_visible_somewhere cases.

  143. Reported: “The movement harness now has the two new mode cases. I’m adding extra overlay cases for cel and group selection on view 11, which will exercise different frame dimensions and offsets through the real object drawing path.”

    Action/result: Added view 11 group 0 frame 1, group 1 frame 0, and group 1 frame 1 cases to tools/object_overlay_probe.py.

  144. Reported: “Fast tests are clean. I’m going to run the expanded movement QEMU batch first; this will tell us whether countdown-gated mode 3 completes as expected and whether the random-motion property check is robust.”

    Action/result: Ran python3 -B tools/object_movement_probe.py --dos-prefix ME --output build/object-movement-probes/batches/motion_modes_004.json --boot-wait 5 --draw-wait 8. All 17 cases matched with 0 mismatches. The countdown-gated one-shot 0x51 case completed at (50,80), and the random-motion property case matched exactly at final position (140,112).

  145. Reported: “The overlay batch is fully green, including all three new view 11 cel/group selections. I’m going to update the docs now with the QEMU results, the mode-3 clarification, the random-motion property result, and the source-backed stuck-recovery details from 0x0b36.”

    Action/result: Ran python3 -B tools/object_overlay_probe.py --dos-prefix OE --output build/object-overlay-probes/batches/view_cel_selection_002.json --boot-wait 5 --draw-wait 8. All 22 cases matched with 0 mismatches.

  146. Reported: “The label table now includes the mode dispatcher, which will help when we compare later interpreter versions with shifted addresses. I’m appending the new command log/results to the clean-room notes.”

    Action/result: Added symbolic label code.motion.dispatch_mode_step for image offset 0x067a; updated compatibility, logic bytecode, graphics/object pipeline, and clean-room notes with the new QEMU and disassembly evidence.

  147. Reported: “One sanity check before I wrap: I covered cel/group selection, but cycling deserves at least a source-backed pass too. I’m checking the +0x23 handlers/call sites now so I don’t overstate that part.”

    Action/result: Disassembled handlers 0x6b82..0x6c17 for actions 0x48..0x4b. The handlers set object byte +0x23, object flag bits, and optional completion flag byte +0x27; this records the setup side only. Automatic frame-cycling runtime consumers remain a follow-up target.

Logic interpreter opcode coverage and QEMU probes

  1. Reported: “I’ll pick this back up from the current workspace state: first I’m going to re-read the local instructions and inspect the new probe/doc changes, then I’ll run the fast checks before putting QEMU back in the loop.”

    Action/result: Re-read AGENTS.md, inspected the working tree, reviewed tools/logic_interpreter_probe.py, and checked the handoff chapter docs/src/current_status.md.

  2. Reported: “The handoff page and AGENTS notes are consistent: the immediate gap is full logic opcode coverage plus executable-backed probes. I’ve also confirmed there’s already a new QEMU logic probe in progress, so I’m going to stabilize that rather than starting a parallel harness.”

    Action/result: Reviewed the rest of tools/logic_interpreter_probe.py, its unit tests, and the current logic_bytecode.md opcode entries.

  3. Reported: “The docs already use paragraph-style opcode entries and the condition range is documented. One concrete audit miss remains from the earlier pass: action 0x00 is explained structurally but not yet represented as a normal action entry, and I’ll fold that in while covering the rest.”

    Action/result: Ran python3 -B -m unittest discover -s tests; all 84 tests passed before the new edits.

  4. Reported: “The Python suite is still green after the self-loop change. I’m starting the QEMU snapshot batch now; this is the meaningful check for whether the synthetic logic resources are exposing interpreter behavior cleanly.”

    Action/result: Started python3 -B tools/logic_interpreter_probe.py --dos-prefix LJ --output build/logic-interpreter-probes/batches/control_flow_002.json --boot-wait 5 --draw-wait 8.

  5. Reported: “QEMU has built the four fixture directories and is running them from the snapshot disk. While it runs, the specific uncertainty I’m testing is whether a one-shot transient draw has to be held in a live interpreter loop to be visible at screenshot time.”

    Action/result: The QEMU batch completed with 4 matches, 0 mismatches, and 0 errors. The passing cases were jump_skips_first_draw, if_false_skips_then_draw, not_condition_runs_then_draw, and or_group_true_runs_then_draw.

  6. Reported: “Good, the QEMU batch now matches 4/4. That means the interpreter-control fixtures are viable, and the earlier failures were fixture lifetime artifacts rather than evidence against the jump/NOT/OR interpretation. Next I’m auditing every opcode label against the docs so the ‘all opcodes’ pass is explicit rather than vibes in a trench coat.”

    Action/result: Ran an opcode-label audit comparing tools/disassemble_logic.py against docs/src/logic_bytecode.md.

  7. Reported: “The existing logic_bytecode.md is already much further along than the handoff note implied: it has labels and observed behavior for the whole action range through 0xaf, with only the structural 0x00 missing from the normal entry list. I’m going to make that coverage machine-checkable enough to trust.”

    Action/result: Confirmed the action-name map has 176 entries and no range gaps from 0x00..0xaf; the condition-name map has 19 entries and no gaps from 0x00..0x12.

  8. Reported: “The audit came back clean except for exactly one missing normal entry: 0x00 (end). The action label map covers every byte from 0x00 through 0xaf; the condition label map covers every valid-looking condition entry from 0x00 through 0x12.”

    Action/result: Prepared documentation and unit-test edits to add the missing 0x00 entry and lock the coverage audit into the test suite.

  9. Reported: “I’m going to make three small documentation/test edits now: add the missing 0x00 action entry, add a regression test that fails if any opcode label drops out of the docs, and record the QEMU control-flow probe plus the self-loop correction in the evidence/progress chapters.”

    Action/result: Added the 0x00 (end) action entry and coverage audit to logic_bytecode.md, added tests/test_logic_doc_coverage.py, and documented the logic-interpreter QEMU probe in the compatibility/current status/progress chapters.

  10. Reported: “One nuance I want to make explicit before calling this done: ‘all opcodes’ should include the invalid/structural byte ranges too, not just the named action table. I’m adding a short dispatch-range note so future readers know what happens to bytes outside the valid action/condition catalogs.”

    Action/result: Added dispatch-range paragraphs to logic_bytecode.md for action bytes 0x00, 0x01..0xaf, 0xb0..0xfb, 0xfc, 0xfd, 0xfe, and 0xff, plus condition bytes 0x00..0x12, 0x13..0x25, 0x26..0xfb, and structural markers 0xfc..0xff.

  11. Reported: “That range note is in place now: valid actions, invalid action bytes, structural bytes, valid condition predicates, reserved condition bytes, and condition markers are all spelled out separately. I’m adding that last update to the progress record and rerunning verification.”

    Action/result: Verification rerun follows this documentation update.

  12. Reported: “I’ll take this as an implementation pass, not a proposal: expand the logic probe harness, add deterministic opcode-family cases, attach each case to docs/evidence levels, then verify with unit tests, mdBook, and QEMU where practical. First I’m reading the current harness and helper patterns so the new cases fit the existing machinery cleanly.”

    Action/result: Reviewed tools/logic_interpreter_probe.py, tools/qemu_fixture.py, tests/test_logic_interpreter_probe.py, and the logic-bytecode/compatibility status docs.

  13. Reported: “The probe design is promising: most arithmetic/flag/condition opcodes can be validated by doing the operation, then drawing the object only if a condition observes the expected state. If the interpreter disagrees, the screenshot stays blank and the comparison fails loudly.”

    Action/result: Designed the expanded logic probe cases around guarded transient drawing through condition blocks.

  14. Reported: “One wrinkle with self-looped fixtures: mutating opcodes like inc would keep changing state every cycle. I’m making each arithmetic case reset its inputs before the tested action, so the condition remains true on every interpreter pass and the transient draw is stable at capture time.”

    Action/result: Added reset-before-test bytecode patterns for mutable variable, flag, and object-field probes.

  15. Reported: “I’m editing the logic probe now: adding bytecode builders for variable, flag, comparison, and simple object-field checks, then folding those into the default QEMU batch so they run with the existing control-flow cases.”

    Action/result: Expanded tools/logic_interpreter_probe.py to 27 default cases covering control flow, variable arithmetic, indirect variables, flags, comparison predicates, and selected object-field getters/setters.

  16. Reported: “The default logic batch now includes control flow plus arithmetic, indirect-variable, flag, comparison, and three simple object-field probes. I’m running the fast unit tests first; then I’ll send the expanded batch through QEMU and correct anything the original engine disagrees with.”

    Action/result: Ran the logic probe unit tests successfully and confirmed the expanded default batch contains 27 unique cases.

  17. Reported: “The expanded batch has 27 cases and the local probe tests pass. I’m launching QEMU now; the object-field cases are the most likely to teach us something because they touch engine object records without drawing persistent objects.”

    Action/result: Started python3 -B tools/logic_interpreter_probe.py --dos-prefix LK --output build/logic-interpreter-probes/batches/opcode_families_001.json --boot-wait 5 --draw-wait 8 --stop-on-failure.

  18. Reported: “QEMU has all 27 fixture directories loaded into the snapshot disk and is stepping through them. I used --stop-on-failure for this first pass, so if one case is wrong we get the earliest useful failure instead of a pile of downstream noise.”

    Action/result: QEMU continued executing the one-boot snapshot batch.

  19. Reported: “The expanded QEMU run is green: 27/27 exact visual matches. That gives us executable evidence for the core arithmetic opcodes, indirect variable forms, flag opcodes, comparison predicates, and a few simple object-field getter/setter pairs. Next I’m turning that into an evidence matrix so the docs distinguish ‘QEMU validated’ from ‘source-backed only.’”

    Action/result: Saved the matching report at build/logic-interpreter-probes/batches/opcode_families_001.json.

  20. Reported: “I’m adding a small generator for the evidence matrix rather than hand-maintaining a 176-row table. The generator uses only the local dispatch table and our local opcode-label map, then annotates rows with the QEMU probes we have actually run.”

    Action/result: Added tools/logic_opcode_evidence.py, linked the generated chapter from SUMMARY.md, and added a unit test that checks the generated evidence matrix is current.

  21. Reported: “The generator is in place and linked into the book. I’m generating the evidence chapter now, then I’ll wire the run result into the compatibility/evidence notes.”

    Action/result: Generated docs/src/logic_opcode_evidence.md and verified it with python3 -B tools/logic_opcode_evidence.py --check.

  22. Reported: “The generated matrix now covers every action row 0x00..0xaf, all known condition rows 0x00..0x12, and the invalid/structural byte ranges. I’m tightening the tests around the new probe cases so the expanded default batch doesn’t accidentally shrink later.”

    Action/result: Expanded tests/test_logic_interpreter_probe.py to assert representative variable, flag, comparison, arithmetic, control-flow, and object-field cases remain in the default batch.

  23. Reported: “I’m updating the documentation trail with the exact QEMU batch name and the new evidence chapter. This is the clean-room receipt: what ran, what matched, and what remains source-backed rather than emulator-backed.”

    Action/result: Updated compatibility, current-status, logic-bytecode, and progress docs with the expanded logic probe and evidence matrix.

  24. Reported: “I’ll do these in order and keep the artifacts testable: first multi-logic call/resume fixtures, then variable-backed resource/object variants, then object predicates, then strings/messages, then inventory/table predicates. I’m going to inspect the current fixture builder and logic resource format first so the new probes extend the existing QEMU harness instead of becoming a separate one-off.”

    Action/result: Reviewed the logic interpreter probe, QEMU fixture helper, tests, opcode evidence generator, and local logic resource documentation.

  25. Reported: “The existing logic_resource() helper emits a minimal no-message resource, which is fine for the first three steps. For the string/message step I need to construct a real custom message table, so I’m checking the locally documented message format and existing logic parser before editing.”

    Action/result: Re-read docs/src/logic_resources.md, confirming code_length, message_count, table offsets relative to table base, and XOR-encrypted text using the Avis Durgan key.

  26. Reported: “I’m going to extend the single logic probe harness rather than create five tools. The key change is letting a case patch multiple logic resources into VOL.3 and optionally give logic 0 a custom message table, which unlocks call/load and string/message probes cleanly.”

    Action/result: Updated tools/qemu_fixture.py so logic_resource() can encode custom message tables.

  27. Reported: “The fixture helper now supports encrypted custom logic messages using the locally documented XOR key and offset-table layout. Next I’m adding the multi-logic/resource patching and the new probe cases in sequence.”

    Action/result: Added extra-logic metadata, message metadata, multi-logic VOL.3 packing, and new logic probe cases for the five requested groups.

  28. Reported: “I’ve got the new cases drafted; I spotted two fixture-shape issues before running them: a persistent-object var-resource case should not use the conditional transient-draw wrapper, and the NOT-always-false probe needs the marker before the condition byte. I’m tightening those now and then I’ll run the local tests.”

    Action/result: Corrected the persistent object case and the NOT marker ordering.

  29. Reported: “Multi-resource fixture patching is in. I’m running the focused tests now; if they pass, I’ll inspect a generated fixture byte layout before letting QEMU at the larger batch.”

    Action/result: Ran focused logic probe and fixture tests; 28 tests passed. The default logic probe batch now contains 47 cases.

  30. Reported: “The focused tests pass and the default batch is now 47 cases. I’m starting QEMU with stop-on-failure; this will validate the steps in sequence and stop at the first semantic mismatch so I can correct the model before continuing.”

    Action/result: Started the all-case QEMU run five_steps_001.json.

  31. Reported: “Because the batch is ordered, the first failing case will tell us which requested step needs attention. Cases 28-31 are call/load/resume, then the variable-backed object/resource cases, then object predicates, strings/messages, and inventory/table markers.”

    Action/result: The all-case QEMU run did not reach execution. The snapshot disk filled while copying fixture directories, so the failure was a harness capacity limit rather than an interpreter mismatch.

  32. Reported: “The first QEMU attempt did not reach execution: the snapshot boot disk filled up while copying 47 full SQ2 fixture directories. That’s a harness capacity issue, not an interpreter mismatch. I’ll run the new five-step cases as a smaller batch and add a case filter so future runs don’t have to copy the entire corpus.”

    Action/result: Added repeated --case filtering to tools/logic_interpreter_probe.py.

  33. Reported: “The harness can now run named subsets with repeated --case flags. I’m going to validate the five requested steps in chunks: call/load /resume first, then variable-backed resources, then predicates, strings/messages, and inventory/table markers.”

    Action/result: Started filtered QEMU validation.

  34. Reported: “Starting step 1 now: call_logic, load_logic plus call_logic, call_logic_var, and the resume-action smoke probe.”

    Action/result: Step 1 matched QEMU with 4 matches, 0 mismatches, and 0 errors.

  35. Reported: “Step 1 is green: all four call/load/resume probes matched. I’m moving to step 2, the variable-backed object/resource variants, including var-based transient drawing and immediate-completion move_object_to_var.”

    Action/result: Step 2 matched QEMU with 4 matches, 0 mismatches, and 0 errors.

  36. Reported: “Step 2 is green too. The persistent object selected through variable-backed resource/group/frame actions matched view 11 group 1 frame 1, and 0x7b matched the same cel through all-variable operands. Next is object rectangle predicates.”

    Action/result: Step 3 matched QEMU with 4 matches, 0 mismatches, and 0 errors.

  37. Reported: “Step 3 is green: all four object rectangle predicates matched. I’m moving to strings/messages now; this is the new custom-message-table path, so if anything breaks it will most likely be message encoding or parser state rather than drawing.”

    Action/result: Step 4 matched QEMU with 2 matches, 0 mismatches, and 0 errors.

  38. Reported: “Step 4 is green. The custom message resource was accepted by the original loader, 0x72 copied message text into string slots, 0x0f normalized and compared it, and 0x75 plus 0x0e recognized look. Now I’m validating the inventory/object-table marker actions and predicates.”

    Action/result: Started the inventory/table marker QEMU batch.

  39. Reported: “The inventory/table step covers both predicates (0x09, 0x0a) and the marker actions 0x5c..0x61. I’m running them together because they’re small and all use the same table entry.”

    Action/result: Step 5 matched QEMU with 6 matches, 0 mismatches, and 0 errors.

  40. Reported: “QEMU is executing the six inventory/table cases now. If these match, all five requested steps will have QEMU-backed evidence, with the larger all-cases run split only because the DOS snapshot disk filled up.”

    Action/result: Confirmed the six inventory/table cases matched.

  41. Reported: “Step 5 is green. I’m updating tests and the evidence matrix annotations now so the new QEMU-backed opcodes show up as validated rather than source-only.”

    Action/result: Updated regression tests and regenerated the opcode evidence matrix.

  42. Reported: “The evidence matrix is regenerated with the newly validated opcodes. I’m documenting both the successful step runs and the one failed ‘all 47 at once’ attempt, because the failure tells future us about snapshot disk capacity rather than AGI behavior.”

    Action/result: Updated compatibility, current-status, clean-room notes, and progress docs.

  43. Reported: “Checkpoint is bbda90f; only generated/local artifacts remain untracked. I’m starting the next pass by checking the existing object/view action notes and local view metadata so the new probes use expected values that are already derived from local evidence.”

    Action/result: Reviewed object/view getter and bitfield notes in logic_bytecode.md, inspected view 11 with tools/inspect_view.py, and checked the current evidence matrix rows.

  44. Reported: “For this pass I’m splitting the target actions into two evidence types: value probes where a getter/condition observes the expected state, and smoke probes for bitfield actions whose direct bit value is not exposed by an existing script predicate. That keeps the docs honest: ‘this opcode executed and consumed operands under QEMU’ is useful, but different from proving every downstream semantic.”

    Action/result: Added value probes for object/view metadata getters, variable-backed field +0x24, inactive object-distance behavior, and 0x4d clearing direction byte +0x21; added one dispatch smoke case for selected bitfield/helper actions.

  45. Reported: “The new object/view cases are in: metadata getters, variable-backed field +0x24, inactive distance behavior, 0x4d clearing direction, and a dispatch smoke case for the bitfield/helper actions with no direct script-visible getter. I’m running the focused tests now.”

    Action/result: Ran python3 -B -m unittest tests.test_logic_interpreter_probe; 6 tests passed, and the default logic probe set now contains 52 cases.

  46. Reported: “The local tests pass and the default set is now 52 cases. I’m running just the five new object/view cases through QEMU so the snapshot disk stays small.”

    Action/result: The first QEMU attempt under sandbox failed before execution because the VNC socket bind was not permitted.

  47. Reported: “QEMU was blocked by the sandbox when binding the local VNC socket. I’m rerunning the same filtered batch with approval so the emulator can start; this is the same kind of local QEMU validation we’ve been using.”

    Action/result: Reran the filtered object/view batch with approved escalation.

  48. Reported: “QEMU is running the five filtered cases now. The first four are value probes; the fifth is intentionally a dispatch smoke probe for bitfield/helper actions that don’t expose a simple script-visible bit readback.”

    Action/result: The QEMU batch matched with 5 matches, 0 mismatches, and 0 errors.

  49. Reported: “The QEMU batch is green: five matches, zero mismatches. I’m updating the evidence matrix now, marking direct value probes as QEMU-validated and the remaining bitfield/helper actions as QEMU dispatch-smoke rather than overstating their full semantics.”

    Action/result: Updated tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  50. Reported: “The generated matrix now has a separate QEMU dispatch-smoke evidence level. I’m documenting the new object/view batch and the distinction between value probes and smoke probes in the project notes.”

    Action/result: Updated compatibility, current-status, clean-room notes, and progress docs with the object/view follow-up batch.

  51. Reported: “I’ve got the shape of it now: mdBook is using its default narrow content column, and there’s no project CSS override yet. I’m going to add a small theme stylesheet so wide reference tables can use more horizontal room and scroll inside themselves when they still overflow.”

    Action/result: Inspected docs/book.toml, the generated mdBook CSS, and the current worktree state before adding the table-layout override.

  52. Reported: “I found the progress log tail and confirmed the worktree is clean apart from the usual generated/untracked artifacts. Next I’m checking mdBook’s generated selector names so the override lands on the actual content container instead of guessing.”

    Action/result: Confirmed mdBook wraps generated tables in .table-wrapper and applies the page width through --content-max-width.

  53. Reported: “The generated mdBook CSS confirms the hard cap is --content-max-width: 750px, applied to .content main. I can override that variable cleanly from an additional-css file and then give tables their own horizontal overflow behavior.”

    Action/result: Added docs/theme/wide-tables.css to widen the content column and make wide tables scroll horizontally while preserving readable wrapping in the final detail column.

  54. Reported: “mdBook already wraps tables in .table-wrapper, but only adds overflow; the table itself can still be squeezed by the 750px main column. I’m adding a source-controlled CSS file that widens the content column and keeps table columns readable before falling back to horizontal scrolling.”

    Action/result: Updated docs/book.toml to load the new stylesheet via additional-css.

  55. Reported: “I’ll rework the logic bytecode chapter now that the book can handle wider tables. First I’m going to inspect the chapter structure and the current markdown patterns so the table conversion is deliberate rather than a blind format pass.”

    Action/result: Read docs/src/logic_bytecode.md, checked the progress log tail, and confirmed the worktree state before editing.

  56. Reported: “The chapter has several paragraph lists that are really reference tables: runtime metadata examples, main-stream byte ranges, the condition table/ranges/predicates, action entry examples, and decoded action families. I’m reading the rest of the file now so I don’t miss another block that should be restored to table form.”

    Action/result: Reviewed the remaining logic bytecode chapter sections and identified compact opcode catalogs versus longer semantic explanations.

  57. Reported: “There are also long explanatory opcode entries where paragraphs are still the better shape, especially for movement, parsing, save/restore, and display behavior. I’m going to table the compact catalog-like material and leave the multi-paragraph semantic notes as prose.”

    Action/result: Chose a mixed layout: tables for opcode facts and prose for state-machine or helper-flow details.

  58. Reported: “The densest restored tables will be in the front half of the chapter and the local scan summary. For the long decoded action families section, I’m going section by section: compact opcode rows become tables, while explanatory helper blocks stay as explanatory blocks.”

    Action/result: Collected line-numbered context for the runtime, condition, action, and scan-summary sections.

  59. Reported: “I’ve separated catalog data from semantic explanation. The first patch is the high-value cleanup: dispatch/condition catalogs and the short arithmetic/flag/action summary rows go back into tables.”

    Action/result: Converted metadata examples, main-stream byte ranges, condition entries/ranges/predicates, action examples, variable actions, and flag actions to Markdown tables.

  60. Reported: “The first conversion is in. I’m moving through the action families next; these are especially useful as tables because implementers will scan by opcode, label, handler, and effect.”

    Action/result: Inspected the object/view, resource-control, object-state, message/UI, and remaining-entry sections for table conversion.

  61. Reported: “The remaining opcode blocks are large, but most are structurally regular. I’m going to table the resource/object/UI families now and keep the detailed movement subsections as prose where they explain per-cycle behavior.”

    Action/result: Converted the object/view action and resource/interpreter control catalogs to Opcode, Label, Handler, and Observed action tables.

  62. Reported: “I’m making the action-family tables broad but shallow: Opcode, Label, Handler, Observed action. The final action column can now wrap inside the wider mdBook layout, which is exactly what that CSS change was for.”

    Action/result: Kept long behavior descriptions in the final table column so rows remain scan-friendly without losing evidence detail.

  63. Reported: “The object/view and resource-control catalogs are tabled now. Next I’m doing the object-state, message/UI, and misc sections, then I’ll build the book to catch Markdown table mistakes.”

    Action/result: Converted additional object-state, post-movement, dirty position, and object-field-24 action summaries to tables.

  64. Reported: “Object state is now much easier to scan. I’m converting the remaining compact UI/resource/session listings the same way; after that I’ll make sure no Count: opcode paragraphs remain in the scan summary.”

    Action/result: Converted message-display, menu/list, and text/input action catalogs to tables.

  65. Reported: “Most of the chapter’s UI/action catalogs are back in table form. I’m doing the final resource/session/misc groups now, plus the local SQ2 frequency lists at the end.”

    Action/result: Converted resource/table actions, session-control actions, miscellaneous actions, remaining table entries, and frequency summaries to tables.

  66. Reported: “The conversion pass is complete. I’m checking for leftover paragraph-style opcode summaries and then I’ll build the book; Markdown table syntax is fussy enough that I want mdBook to be the judge.”

    Action/result: Initial leftover scan found only movement-mode opcode paragraphs; mdbook build docs succeeded.

  67. Reported: “The only opcode paragraphs I expect to remain are the movement entries where the surrounding explanation matters. I’m rerunning the leftover scan with safer shell quoting and then building the mdBook.”

    Action/result: Confirmed the remaining paragraph-style opcode summaries were 0x51..0x54 movement actions and the book still built successfully.

  68. Reported: “The leftover scan found exactly the movement opcodes I intentionally left in prose. I’m going to improve those too by adding a compact movement-mode table, while keeping the multi-paragraph per-cycle details underneath.”

    Action/result: Added a movement-mode entry-point table for opcodes 0x51..0x54 and rewrote the surrounding prose to avoid duplicate paragraph-style opcode summaries.

  69. Reported: “That takes care of the movement outliers: they now have a table for the entry-point facts, with the state-machine details kept beneath it. I’m doing the final validation pass now.”

    Action/result: Verified no paragraph-style opcode summary patterns remain, mdbook build docs succeeds, and git diff --check is clean.

  70. Reported: “The book builds cleanly and git diff --check is clean. I’m adding the progress-log entries for this documentation pass, then I’ll check the final status.”

    Action/result: Recorded the logic-bytecode table conversion pass in this progress log.

  71. Reported: “I’ll pick the thread back up at the logic-interpreter probe expansion. I’m going to inspect the current probe harness, evidence matrix, and source-backed-only opcode rows so the next batch targets behaviors that can actually be observed in QEMU.”

    Action/result: Inspected the current probe harness, evidence matrix, and documentation targets for additional runtime-visible opcodes.

  72. Reported: “The current harness already has 52 default cases and a separate smoke level in the evidence matrix. The obvious next useful target is to turn some smoke/source-backed object field helpers into value probes where we can observe the effect through existing getters or visible drawing.”

    Action/result: Identified object-state, random, and no-op action entries suitable for direct QEMU probes.

  73. Reported: “I’m going to add a small batch of value/smoke probes that are low-risk and visible: object position variants 0x28, 0x93, 0x94, deactivation/clear-all effects 0x24 and 0x22, deterministic random 0x82 with equal bounds, and no-op/runtime-skip entries 0x7f, 0x9b, 0xaf.”

    Action/result: Added nine candidate cases to tools/logic_interpreter_probe.py.

  74. Reported: “I’m picking up from the just-added probe batch. First I’ll run the harness tests so we know whether the new cases are structurally sound before spending QEMU time on them.”

    Action/result: Ran python3 -B -m unittest tests.test_logic_interpreter_probe; all six tests passed.

  75. Reported: “The local probe tests pass, so the new cases are well-formed. I’m going to run them against the original engine now; this is the part that tells us which hypotheses deserve to graduate from static/source-backed notes into runtime evidence.”

    Action/result: Started the nine-case QEMU probe batch; the sandbox blocked the initial VNC socket bind.

  76. Reported: “As expected, the sandbox blocked QEMU’s local VNC socket. I’ll rerun the same batch with approval so the emulator can bind its display port.”

    Action/result: Reran the nine-case batch with elevated QEMU permission.

  77. Reported: “The QEMU batch is running from a snapshot now. While it works through the fixtures, I’ll prep the evidence-matrix and docs context so the runtime results can be recorded cleanly once they land.”

    Action/result: Reviewed tools/logic_opcode_evidence.py and relevant docs while QEMU was running.

  78. Reported: “The docs context confirms these opcodes were previously mostly source-backed or smoke-only. If the batch passes, I’ll promote the specific ones with observable outcomes into the generated evidence matrix instead of leaving them as ‘we saw it in disassembly.’”

    Action/result: Confirmed target opcodes were suitable for evidence-level promotion pending QEMU results.

  79. Reported: “Still waiting on QEMU; snapshot batches can be quiet until the report is written. I’m letting it finish rather than interrupting, because partial emulator runs are much less useful as evidence.”

    Action/result: Continued waiting for the snapshot-backed QEMU batch.

  80. Reported: “First two probes matched: 0x28 adds the variable deltas as expected, and 0x82 with equal bounds stores that bound. The no-op and object activation cases are next in the batch.”

    Action/result: Observed the first two QEMU matches from the running batch.

  81. Reported: “Good batch, with one interesting wrinkle: eight passed and clear_all_object_bits_removes_persistent_draw did not. I’m going to inspect that mismatch rather than paper over it; 0x22 may be clearing active/update bits but not removing an already-linked draw entry in the way my first fixture assumed.”

    Action/result: Inspected the report build/logic-interpreter-probes/batches/object_state_misc_001.json; eight cases matched and the 0x22 fixture mismatched.

  82. Reported: “The mismatch is exactly at the first object’s footprint, so the original engine still draws the previously activated object after 0x22 in this same logic pass. I’m reading the harness shape now and will turn this into a positive probe for the behavior we actually observed: ‘clear bits does not immediately unlink the already-active draw entry.’”

    Action/result: Confirmed the mismatch bounding box was the previously activated object’s visible footprint.

  83. Reported: “I’m going to make the probe harness a bit more expressive so a case can expect two rendered objects. That lets the 0x22 probe encode the observed behavior directly, instead of pretending the only valid outcome is a single sprite.”

    Action/result: Began extending LogicInterpreterCase with optional additional expected sprites.

  84. Reported: “The first patch missed because the constructor is still using positional arguments. I’ve got the exact spot now and will apply the narrower edit.”

    Action/result: Added the optional expected_extra_sprites field and constructor plumbing.

  85. Reported: “Now I’m changing the 0x22 case itself from a negative expectation into a positive one: expect the old persistent object plus the new transient draw. That will give us a sharper note for the spec.”

    Action/result: Renamed the case to clear_all_object_bits_keeps_current_draw_entry and gave it two expected sprites.

  86. Reported: “One more harness edit: comparison needs to render any extra expected sprites before it overlays the primary expected sprite. After that I’ll rerun just the corrected 0x22 case.”

    Action/result: Updated compare_capture() to compose extra expected sprites.

  87. Reported: “I’ll also update the unit-test coverage list so the newly promoted cases are tracked by name. Small bookkeeping, but it helps prevent accidental loss of these probes later.”

    Action/result: Added explicit test coverage for the nine new probe case ids and raised the minimum case-count assertion.

  88. Reported: “The probe catalog now names all nine new cases explicitly. I’m running the local tests and a quick capture comparison path check before asking QEMU to revalidate the corrected 0x22 fixture.”

    Action/result: python3 -B -m unittest tests.test_logic_interpreter_probe passed again.

  89. Reported: “Local tests are green. I’ll rerun only the corrected 0x22 fixture now, which should be fast relative to the full nine-case sweep.”

    Action/result: The sandbox again blocked the first QEMU VNC bind attempt.

  90. Reported: “Same socket restriction on the single rerun; I’ll rerun it with approval.”

    Action/result: Reran the corrected 0x22 fixture with elevated QEMU permission.

  91. Reported: “The corrected 0x22 probe matches. I’m going to promote the QEMU-backed opcodes in the evidence generator now, including the nuance that 0x22 clears bits without immediately removing the current draw entry.”

    Action/result: Added QEMU evidence entries for 0x22, 0x24, 0x28, 0x7f, 0x82, 0x93, 0x94, 0x9b, and 0xaf.

  92. Reported: “The evidence map is updated. Next I’ll regenerate the mdBook evidence chapter and run its consistency check, then I’ll update the narrative notes with the exact commands and outcomes.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md and ran python3 -B tools/logic_opcode_evidence.py --check successfully.

  93. Reported: “The generated evidence chapter and its check both pass. I’m now recording the reverse-engineering trail: the failed first hypothesis for 0x22, the corrected fixture, and which opcodes moved to runtime-backed evidence.”

    Action/result: Updated clean-room notes, compatibility testing docs, and current status with the new probe evidence.

  94. Reported: “Documentation is updated. I’m running the normal validation pass now: full Python tests, evidence check, mdBook build, and whitespace diff check.”

    Action/result: The first full test run exposed that the documentation coverage test still recognized only the older paragraph-style opcode entries.

  95. Reported: “The book, evidence check, and whitespace check passed, but the full test suite exposed a doc-coverage parser regression: it no longer recognizes the tabled opcode entries in logic_bytecode.md. I’m going to adjust that test to understand the current table format rather than weakening coverage.”

    Action/result: Updated the coverage test to accept documented opcode rows in the current Markdown table format.

  96. Reported: “The coverage test was still looking for the older bold paragraph heading pattern only. I’m updating it to accept both that historical format and the current Markdown table rows, while still requiring every opcode label to appear.”

    Action/result: tests/test_logic_doc_coverage.py now accepts both paragraph headings and table rows.

  97. Reported: “The coverage test now recognizes table rows as documented opcode entries. I’m rerunning the full validation pass to make sure that was the only failure.”

    Action/result: python3 -B -m unittest discover -s tests passed 91 tests; mdbook build docs and git diff --check also passed.

  98. Reported: “Everything now validates: 91 Python tests, mdBook build, and diff check are clean. I’m doing a final status/diff pass so the wrap-up is precise and doesn’t hide generated debris.”

    Action/result: Confirmed the modified tracked files and removed tools/__pycache__/.

  99. Reported: “I’ll continue from the freshly committed logic-probe work. I’m going to scan the evidence matrix for still source-backed opcodes and pick another cluster that can be validated through visible state or script-observable getters.”

    Action/result: Confirmed the worktree only had the known generated/input directories and that the opcode evidence matrix was current.

  100. Reported: “The worktree is clean except the known generated/input directories, and the evidence matrix is current. My first grep had shell quoting trouble around backticks, so I’m switching to a small local parse of the generated matrix.”

    Action/result: Replaced the failing backtick-sensitive scan with simpler source-backed and dispatch-smoke matrix scans.

  101. Reported: “The current harness already has good coverage for variables, strings, inventory markers, object positions, and several draw paths. I’m checking the remaining source-backed rows now with simpler shell quoting; likely next targets are object bitfield helpers or small global/object field actions that can be observed indirectly.”

    Action/result: Identified 0x1f and the object field +0x23 family 0x48..0x4b as practical next targets.

  102. Reported: “The best near-term candidates are object/state opcodes, not UI/save/sound paths. I’m going to focus on opcodes around 0x2d..0x50 where disassembly says they change object bits or fields; some can be made visible via drawing, getters, or movement side effects.”

    Action/result: Reviewed object-state docs and movement harness context for observable probe options.

  103. Reported: “A useful small batch is emerging: variable-backed load_view (0x1f) can be validated by drawing the loaded view, while 0x49 and 0x4b can at least be value-probed for their documented flag-clearing operand. I’ll add those, plus dispatch-smoke cases for 0x48 and 0x4a so the whole +0x23 setup family has runtime coverage.”

    Action/result: Chose a five-case follow-up batch covering 0x1f and 0x48..0x4b.

  104. Reported: “I’m going to add a small bit of flexibility to the logic probe harness first: most cases preload view 11, but the load_view_var probe must start without that preload or it wouldn’t prove anything. Then I’ll add the five cases.”

    Action/result: Added the optional preload_view_no hook to tools/logic_interpreter_probe.py.

  105. Reported: “The preload hook is in. I’m adding a tiny local condition helper for ‘flag is not set,’ then the new runtime cases in the existing case catalog.”

    Action/result: Added not_flag_set_condition().

  106. Reported: “Now I’m inserting the cases themselves: one load_view_var value probe, two +0x23 mode actions that clear a flag as documented, and two dispatch-smoke cases for the no-flag mode variants.”

    Action/result: Added load_view_var_allows_following_draw, object_field_23_mode0_dispatch_smoke, object_field_23_mode1_clears_flag, object_field_23_mode3_dispatch_smoke, and object_field_23_mode2_clears_flag.

  107. Reported: “The new cases are in. I’m updating the unit test’s named coverage list so these probes stay pinned in the default catalog.”

    Action/result: Updated tests/test_logic_interpreter_probe.py to require the five new case ids.

  108. Reported: “I’ll run the local harness tests before QEMU. If any of these bytecode snippets are malformed, it’s cheaper to catch it here.”

    Action/result: python3 -B -m unittest tests.test_logic_interpreter_probe passed.

  109. Reported: “Local tests pass. I’ll run the five new cases against the original engine now; if the VNC bind hits the sandbox again I’ll rerun with approval.”

    Action/result: The first QEMU run was blocked by the sandbox VNC bind restriction.

  110. Reported: “The sandbox blocked the VNC socket as expected. I’ll rerun the same batch with QEMU permission.”

    Action/result: Reran the five-case batch with elevated QEMU permission.

  111. Reported: “The QEMU snapshot batch is running. While it does that, I’ll prepare the evidence-map changes so they’re ready if the cases match.”

    Action/result: Reviewed the evidence generator and existing docs while the QEMU batch ran.

  112. Reported: “The docs already have source notes for 0x1f and 0x48..0x4b; this batch is specifically trying to convert part of that into observed engine behavior. I’m checking the QEMU run now.”

    Action/result: The batch build/logic-interpreter-probes/batches/load_view_field23_001.json matched all five cases with 0 mismatches and 0 errors.

  113. Reported: “All five matched. I’ll promote 0x1f, 0x49, and 0x4b to QEMU-validated evidence, and mark 0x48/0x4a as dispatch-smoke since those cases prove runtime execution and operand consumption but not the hidden +0x23 byte value directly.”

    Action/result: Updated tools/logic_opcode_evidence.py accordingly.

  114. Reported: “The evidence generator is updated. I’m regenerating the matrix and checking it, then I’ll record the commands and results in the clean-room docs.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md and checked it successfully.

  115. Reported: “The matrix regenerated cleanly. I’m updating the narrative docs now: compatibility commands, chronological clean-room notes, current status, and the progress log for the updates from this run.”

    Action/result: Updated the clean-room notes, compatibility testing page, and current status.

  116. Reported: “I’m appending a short dated evidence section and compatibility snippet for this batch. The key distinction in the docs will be ‘value-backed’ for 0x1f, 0x49, 0x4b versus ‘dispatch-smoke’ for 0x48, 0x4a.”

    Action/result: Added the dated evidence section and compatibility command.

  117. Reported: “The compatibility docs now have the replay command. I’m updating current status so the next session won’t repeat this cluster.”

    Action/result: Current status now mentions the 0x1f and 0x48..0x4b follow-up batch.

  118. Reported: “I’m also adding a couple of concise notes in the opcode chapter itself, so readers of the spec see what was runtime-confirmed without having to jump to the evidence matrix.”

    Action/result: Added concise QEMU evidence notes to docs/src/logic_bytecode.md.

  119. Reported: “Docs are updated. I’m running the validation pass now: full tests, evidence consistency, mdBook build, and diff whitespace checks.”

    Action/result: python3 -B -m unittest discover -s tests passed 91 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check also passed.

  120. Reported: “Everything validates: 91 tests, evidence check, mdBook, and whitespace checks are clean. I’m doing final status and diff review, then I’ll wrap this pass.”

    Action/result: Confirmed the diff is limited to logic-probe source, evidence generation, tests, and documentation; generated/input directories remain untracked.

  121. Reported: “I’ll continue with the object bit/control path I recommended: first I’m checking the current uncommitted pass so I can build on it cleanly rather than trampling the latest probe work.”

    Action/result: Confirmed the previous variable-view/object-field probe pass was still uncommitted and read AGENTS.md for the project rules.

  122. Reported: “The previous pass is still uncommitted, and I’m going to extend it rather than split the thread artificially. The most promising value probe is 0x44: set the collision-skip bit with 0x43, clear it with 0x44, then prove collision blocking returns during movement.”

    Action/result: Inspected the object movement harness and existing collision-skip evidence.

  123. Reported: “The movement harness has exactly the shape we need, but it only has a ‘set skip bit’ helper. I’m adding the companion 0x44 encoder plus a filtered movement case that sets then clears the bit and should collide again.”

    Action/result: Added clear_object_bit_0200_action() to tools/qemu_fixture.py.

  124. Reported: “The raw encoder is in. Now I’m threading a clear-skip option through the movement case model and adding the concrete collision-restored case.”

    Action/result: Added moving_clear_skip_collision, filtered --case support, and case move_collision_clear_skip_bit_blocks_again to tools/object_movement_probe.py.

  125. Reported: “The tests now cover the new encoder, filtered movement case loading, and the new collision-restored case. I’ll run the focused tests, then the single QEMU case.”

    Action/result: Updated tests/test_qemu_fixture.py and tests/test_object_movement_probe.py; focused tests passed.

  126. Reported: “Focused local tests pass. I’m running just the new movement probe in QEMU now; the new --case filter avoids rerunning the whole movement suite.”

    Action/result: The first QEMU run was blocked by the sandbox VNC bind restriction.

  127. Reported: “The QEMU VNC bind hit the sandbox restriction. I’ll rerun the same single-case probe with permission.”

    Action/result: Reran the single-case movement probe with elevated QEMU permission.

  128. Reported: “The 0x44 probe matched: after setting and then clearing the collision-skip bit, the object is blocked by the obstacle again. I’m promoting 0x44 from dispatch-smoke to QEMU-validated evidence.”

    Action/result: QEMU batch build/object-movement-probes/batches/clear_skip_bit_001.json matched with 1 match, 0 mismatches, and 0 errors.

  129. Reported: “Evidence metadata is updated. I’ll regenerate the generated matrix, then update the docs with the movement batch command and result.”

    Action/result: Added 0x44 to QEMU-validated evidence and removed it from dispatch-smoke evidence.

  130. Reported: “The matrix now treats 0x44 as QEMU-validated. I’m adding the clean-room evidence trail and a short spec note explaining what the new collision-restored probe proves.”

    Action/result: Regenerated and checked docs/src/logic_opcode_evidence.md.

  131. Reported: “I’m patching the docs in the same evidence-first style: one dated note in the clean-room log, one compatibility command, and one concise semantics sentence in the object/graphics model.”

    Action/result: Updated docs/src/graphics_object_pipeline.md and docs/src/logic_bytecode.md with the 0x44 observation.

  132. Reported: “The spec now records the behavior. I’m adding the reproducible QEMU command to the compatibility chapter next.”

    Action/result: Added the clear_skip_bit_001.json QEMU command to docs/src/compatibility_testing.md.

  133. Reported: “Compatibility has the new command. I’m updating current status and the clean-room notes with the exact batch result.”

    Action/result: Updated docs/src/current_status.md.

  134. Reported: “I’m adding a dated clean-room entry rather than folding this into the older movement section, because it’s a new QEMU observation made in this pass.”

    Action/result: Added the dated 0x44 clean-room section to docs/src/clean_room_executable_notes.md.

  135. Reported: “The clean-room notes now include the exact 0x44 batch and result. I’m adding progress-log entries for this continuation before the final validation run.”

    Action/result: Appended progress-log entries for the 0x44 probe pass.

  136. Reported: “Progress log is updated. I’m running the full validation sweep now, including the movement tests touched by this pass.”

    Action/result: python3 -B -m unittest discover -s tests passed 93 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check also passed.

  137. Reported: “Validation passed: 93 tests now, evidence check, mdBook build, and whitespace check are all clean. I’m doing a final status/diff pass and adding the validation note to the progress log.”

    Action/result: Reviewed the final status and diff summary for the combined variable-view/object-field and 0x44 probe pass.

  138. Reported: “I’ll keep going in the same object-control lane. Since there’s already a validated uncommitted batch, I’m going to look for one more nearby bit action that can be promoted from dispatch-smoke to value-backed evidence without dragging us into UI or save/restore behavior.”

    Action/result: Reviewed remaining object/control bit documentation and the current uncommitted worktree.

  139. Reported: “The next likely value-backed target is the horizon-exempt bit 0x0008: docs say 0x3d sets it and 0x3e clears it, and the placement helper clamps objects against the horizon when the bit is clear. I’m going to add two small visible placement probes around that.”

    Action/result: Chose horizon-like placement probes targeting 0x3d, 0x3e, and 0x3f.

  140. Reported: “I’m adding three horizon placement cases: default bit-clear clamping proves the horizon global is active, 0x3d keeps the object above the horizon, and 0x3e restores the clamp after the bit was set. If these pass, they give us clean value evidence for 0x3d, 0x3e, and 0x3f.”

    Action/result: Added horizon_clamps_object_when_bit_clear, horizon_exempt_bit_keeps_object_above_horizon, and horizon_clear_exempt_bit_restores_clamp.

  141. Reported: “The horizon cases are in the probe catalog. I’ll pin them in the local test list and run the focused harness tests before QEMU.”

    Action/result: Updated tests/test_logic_interpreter_probe.py to require the three new case ids.

  142. Reported: “I’ll run the focused logic probe unit tests now. If those pass, the bytecode is at least structurally sane.”

    Action/result: python3 -B -m unittest tests.test_logic_interpreter_probe passed.

  143. Reported: “The focused unit tests pass. I’ll run these three horizon cases in QEMU now; if the baseline expectation is wrong, the capture comparison should give us the actual position.”

    Action/result: The first QEMU run was blocked by the sandbox VNC bind restriction.

  144. Reported: “The usual QEMU VNC bind was blocked by the sandbox. I’ll rerun the same three-case batch with permission.”

    Action/result: Reran the horizon-bit batch with elevated QEMU permission.

  145. Reported: “The horizon-bit batch is running from a snapshot. I’ll let it complete and then either promote the opcodes or adjust the expected baseline if QEMU tells us the clamp differs.”

    Action/result: Waited for the snapshot-backed QEMU run to complete.

  146. Reported: “All three horizon probes matched. That gives us QEMU-backed behavior for 0x3f setting the horizon, 0x3d exempting the object from the clamp, and 0x3e restoring the clamp. I’m updating the evidence matrix now.”

    Action/result: QEMU batch build/logic-interpreter-probes/batches/horizon_bits_001.json matched with 3 matches, 0 mismatches, and 0 errors.

  147. Reported: “Evidence metadata now promotes 0x3d, 0x3e, and 0x3f. I’ll regenerate the matrix and then patch the docs with the exact QEMU batch and behavior.”

    Action/result: Updated tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  148. Reported: “The generated evidence matrix is current. I’m adding the horizon-bit observations to the prose docs now: the object pipeline, opcode chapter, compatibility command, current status, and the chronological clean-room notes.”

    Action/result: Began documenting the horizon-bit QEMU observations.

  149. Reported: “The placement text has slightly different wording than I expected. I’ve got the exact paragraph now and will insert the horizon QEMU note there.”

    Action/result: Added the horizon clamp note to docs/src/graphics_object_pipeline.md.

  150. Reported: “I’m adding the same observation to the opcode chapter beside the object-bit table, keeping it short and tied to the generated probe names.”

    Action/result: Added the 0x3d/0x3e/0x3f QEMU note to docs/src/logic_bytecode.md.

  151. Reported: “Next I’m adding the exact horizon batch command to the compatibility chapter so the result can be replayed later.”

    Action/result: Added the horizon-bit batch command to docs/src/compatibility_testing.md.

  152. Reported: “Compatibility docs have the replay command. I’m updating current status so the horizon-bit evidence is visible in the ‘where are we now’ page.”

    Action/result: Added the horizon-bit finding to docs/src/current_status.md.

  153. Reported: “I’m adding the dated clean-room note for the horizon probes with the exact commands and observed match count.”

    Action/result: Added the horizon-bit placement section to docs/src/clean_room_executable_notes.md.

  154. Reported: “Progress log is updated for the horizon pass. I’m running the full suite and documentation checks now.”

    Action/result: python3 -B -m unittest discover -s tests passed 93 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check also passed.

  155. Reported: “Everything validates again: 93 tests, evidence check, mdBook, and diff whitespace. I’m adding the final validation entry and doing one last status review.”

    Action/result: Recorded the validation result for the horizon-bit pass.

  156. Reported: “I’ll keep going on the nearby object/control bits, using the same pattern as the horizon probes: make the object state visible in a tiny generated fixture, run it through QEMU, then promote only the behavior that actually matches.”

    Action/result: Selected action 0x38 (clear_object_bit_0004) as the next target because its visible effect can be tested through priority derivation during object placement.

  157. Reported: “The overlay tests give us a nice pattern for this one: put a control-6 background under a fixed-priority object, clear the fixed-priority bit, and see whether the original engine goes back to the Y-derived priority.”

    Action/result: Planned a fixture that fixes object priority/control to 5, clears bit 0x0004, places the object at baseline 80, and expects the Y-derived priority 7.

  158. Reported: “The harness now accepts custom picture payloads and expected priority values, which makes this fixed-priority probe small instead of needing a separate one-off tool.”

    Action/result: Extended tools/logic_interpreter_probe.py to allow custom picture payloads and expected priority values in generated cases.

  159. Reported: “The 0x38 probe is in. I’m running the focused unit test first so any fixture-building mistake shows up before we spend a QEMU run on it.”

    Action/result: Added the clear_fixed_priority_bit_uses_derived_priority case and the matching unit-test expectation.

  160. Reported: “The focused test passes. I’m moving to the original-engine run now; if QEMU agrees, 0x38 can move out of dispatch-smoke status.”

    Action/result: Began the QEMU validation attempt for the one-case fixed-priority batch.

  161. Reported: “I’ll pick up from the fixed-priority probe that was interrupted by the sandboxed VNC bind. First I’m going to verify the current file state, then I’ll rerun that one QEMU case with the needed permission and fold the result back into the docs.”

    Action/result: Verified the working tree and confirmed 0x38 was still listed as dispatch-smoke evidence.

  162. Reported: “The working tree matches the handoff summary, and the fixed-priority probe is already wired in but still listed only as dispatch-smoke evidence. I’m rerunning that single case now through QEMU so we can see whether 0x38 deserves promotion.”

    Action/result: Reran the fixed-priority QEMU batch with elevated QEMU permission after the sandbox rejected the VNC bind.

  163. Reported: “That matched cleanly: one QEMU case, zero mismatches. I’m going to promote 0x38 from ‘dispatch returned’ to ‘behavior validated’, then regenerate the evidence table and document exactly what the probe proved.”

    Action/result: QEMU report build/logic-interpreter-probes/batches/fixed_priority_bit_001.json matched with 1 match, 0 mismatches, and 0 errors.

  164. Reported: “Evidence metadata is patched. I’m regenerating the generated opcode evidence chapter next, then I’ll make the prose changes around the same observation.”

    Action/result: Promoted 0x38 in tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  165. Reported: “The generated evidence file is refreshed. I’m reading the exact local paragraphs now so the new fixed-priority note lands with the related object-bit and compatibility material instead of becoming a stray footnote.”

    Action/result: Located the relevant sections in the opcode, object pipeline, compatibility, clean-room notes, and current status chapters.

  166. Reported: “I found the doc anchors. The new note is intentionally narrow: 0x38 clears the fixed-priority bit, and the original engine then derives priority from Y, enough to draw over a control-6 synthetic background at baseline 80.”

    Action/result: Updated docs/src/logic_bytecode.md with the QEMU-validated visible effect of 0x38.

  167. Reported: “Opcode prose is updated. I’m now tying the same behavior into the object pipeline chapter and the compatibility replay chapter.”

    Action/result: Added the fixed-priority clear-bit note to docs/src/graphics_object_pipeline.md.

  168. Reported: “The object pipeline now records the visible 0x38 effect next to the flag-bit map. I’m adding the exact one-case QEMU command to the compatibility chapter so it can be replayed later.”

    Action/result: Added the fixed-priority batch command and summary to docs/src/compatibility_testing.md.

  169. Reported: “The replay command is in. I’m adding the chronological clean-room note next, including the initial sandbox failure and the successful elevated QEMU run because both are part of the evidence trail.”

    Action/result: Added the fixed-priority clear-bit QEMU section to docs/src/clean_room_executable_notes.md.

  170. Reported: “The clean-room log now has the fixed-priority probe as a dated section. I’m updating the handoff status page so the latest confirmed object-bit behavior is visible at a glance.”

    Action/result: Added the fixed-priority finding to docs/src/current_status.md.

  171. Reported: “The progress log is caught up through the docs edits. I’m running the compatibility/unit checks, the generated evidence check, mdBook build, and whitespace check now.”

    Action/result: python3 -B -m unittest discover -s tests passed 93 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check also passed.

  172. Reported: “All checks passed: 93 unit tests, evidence check, mdBook, and diff whitespace. I’m recording that validation in the progress log, then I’ll do a final status/diff review.”

    Action/result: Recorded the validation result for the fixed-priority clear-bit pass.

  173. Reported: “I’ll keep advancing the object-state opcode evidence, staying close to the current uncommitted work. The next useful pocket is the remaining bitfield actions that are still only dispatch-smoke: I’ll inspect the harness support and pick ones whose effects can be made visible without inventing too much scaffolding.”

    Action/result: Reviewed the current working tree, logic-interpreter probe cases, evidence metadata, and existing docs for the remaining dispatch-smoke object opcodes.

  174. Reported: “The remaining smoke list splits into two kinds: bits that affect drawing/update-list behavior, and fields/modes that can be observed through existing getters or movement outcomes. I’m narrowing on the low-risk ones first: 0x4c/0x4e and the bit toggles that have a visible movement or placement consequence.”

    Action/result: Inspected existing logic and movement probe support to find observable paths for object-state opcodes.

  175. Reported: “There are already getters for some fields, so we can convert several smoke cases into ordinary logic probes without touching the renderer. I’m going to add focused cases for 0x4c and 0x4e, and then look for a clean way to make 0x40..0x42 or 0x58..0x59 observable.”

    Action/result: Confirmed that 0x4e can be observed through motion behavior, while 0x4c still lacks a direct visible assertion.

  176. Reported: “0x4e has a natural visible test: start an autonomous mode, immediately clear mode byte +0x22, and confirm the object stays put during the later update cycles. I’m also reading the acceptance-test docs because bits 0x0100, 0x0800, and 0x0002 appear to influence movement against control pixels.”

    Action/result: Read the movement pipeline and control/priority acceptance sections to confirm that 0x4e can be validated with a focused movement fixture.

  177. Reported: “The movement docs confirm a few of the remaining bits are not just hidden state; they sit inside the movement acceptance predicate. For this pass I’m going to add one focused 0x4e movement case first, since it is straightforward and should either match or give us a precise correction.”

    Action/result: Chose a one-case QEMU movement probe for 0x4e.

  178. Reported: “I’m going to make a small fixture addition rather than hand-assembling bytes in the movement harness. That keeps the evidence trail readable: clear_object_field_22_and_global_action() will map directly to opcode 0x4e.”

    Action/result: Added clear_object_field_22_and_global_action() to tools/qemu_fixture.py.

  179. Reported: “The opcode helper is in place. Next I’m adding the movement case that starts random motion on object 0 and immediately applies 0x4e, expecting the later QEMU capture to remain at the starting position.”

    Action/result: Added movement case clear_field_22_after_random_motion_stops_motion and a new random_motion_then_clear_4e path in tools/object_movement_probe.py.

  180. Reported: “The movement harness now has a random_motion_then_clear_4e path. I’m updating the tests so the new case and byte helper are pinned before I run QEMU.”

    Action/result: Added the new case id to tests/test_object_movement_probe.py.

  181. Reported: “The case list test is updated. I’m adding the direct byte-level fixture test for the new 0x4e helper too, so the generated logic is self-checking.”

    Action/result: Imported and tested clear_object_field_22_and_global_action() in tests/test_qemu_fixture.py.

  182. Reported: “The helper test area already has the autonomous-motion byte encodings. I’m adding 0x4e there beside the related motion-control opcodes.”

    Action/result: Added the expected byte sequence 4e 02 to the autonomous motion fixture test.

  183. Reported: “The fixture tests now pin the new action byte sequence. I’ll run the focused unit tests before spending a QEMU run.”

    Action/result: python3 -B -m unittest tests.test_object_movement_probe tests.test_qemu_fixture passed 33 tests, and python3 -B -m unittest tests.test_logic_interpreter_probe passed 6 tests.

  184. Reported: “The focused tests pass. I’m running the single original-engine movement case now; if QEMU agrees, 0x4e can move from dispatch-smoke to behavior validated for clearing the active motion mode.”

    Action/result: Ran the focused 0x4e movement probe through QEMU with elevated VNC permission.

  185. Reported: “QEMU matched: the object stayed at its start after 0x4e cleared the just-started random-motion mode. I’m promoting 0x4e in the evidence matrix and then documenting the exact replay command and interpretation.”

    Action/result: QEMU report build/object-movement-probes/batches/clear_field_22_001.json matched with 1 match, 0 mismatches, and 0 errors.

  186. Reported: “0x4e is now marked as a QEMU-backed action in the evidence metadata. I’m regenerating the generated evidence chapter.”

    Action/result: Promoted 0x4e in tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  187. Reported: “The generated matrix is refreshed. I’m patching the prose docs now: opcode row note, movement pipeline note, compatibility replay command, clean-room chronology, and current status.”

    Action/result: Began documenting the 0x4e QEMU result in prose docs.

  188. Reported: “The documentation shape is clear. I’m adding the 0x4e result as ‘motion-mode clearing is visible’, while keeping the global side effect sourced to static analysis until we build a direct flag/global probe.”

    Action/result: Updated docs/src/logic_bytecode.md with the QEMU-validated visible 0x4e effect.

  189. Reported: “The opcode row now names the exact QEMU-visible part of 0x4e. I’m adding the same observation to the movement chapter near the mode-control description.”

    Action/result: Began updating docs/src/graphics_object_pipeline.md.

  190. Reported: “The random-motion section wording is a little different than the snippet I had in mind, so I’ve got the exact paragraph now and will insert the 0x4e note there.”

    Action/result: Added the 0x4e random-motion stop note to docs/src/graphics_object_pipeline.md.

  191. Reported: “The movement chapter now records the 0x4e stop behavior. I’m adding the replay command to the compatibility chapter beside the existing single-case movement batches.”

    Action/result: Located the single-case movement-batch section in docs/src/compatibility_testing.md.

  192. Reported: “The compatibility chapter has a good slot right after the 0x44 single-case movement batch. I’m adding the 0x4e replay command there.”

    Action/result: Added the 0x4e movement replay command and match summary to docs/src/compatibility_testing.md.

  193. Reported: “The replay command is documented. I’m adding the chronological clean-room section for the new helper, harness case, QEMU run, and evidence promotion.”

    Action/result: Added the 0x4e clean-room evidence section to docs/src/clean_room_executable_notes.md.

  194. Reported: “The dated evidence note is in. I’m updating the status page with the new confirmed motion-control behavior.”

    Action/result: Added the 0x4e finding to docs/src/current_status.md.

  195. Reported: “The status page is current. I’m catching the progress log up for this continuation, including the QEMU result and evidence promotion, then I’ll run the full validation suite.”

    Action/result: Began appending the progress-log entries for this continuation.

  196. Reported: “The progress log is up to date through the 0x4e work. I’m running the full test suite, evidence check, mdBook build, and whitespace check now.”

    Action/result: python3 -B -m unittest discover -s tests passed 93 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check also passed.

  197. Reported: “All four checks passed. I’m adding that validation note to the progress log, then I’ll do the quick mdBook/whitespace rerun because the log itself changed.”

    Action/result: Recorded the validation result for the 0x4e motion-mode clearing pass.

  198. Reported: “Got it: I’ll keep going through the whole sequence and leave the commit for you.”

    Action/result: Continued the movement/object-bit reverse-engineering pass without committing.

  199. Reported: “The existing renderer gives us a direct way to make control classes visible. I’m going to target 0x58/0x59 first because the disassembly suggests they gate special control acceptance, then use QEMU only to confirm the visible result.”

    Action/result: Chose synthetic control-screen movement probes for the object-bit handlers.

  200. Reported: “I’m going to add explicit fixture helpers for the object-bit opcodes instead of hand-assembling bytes in the probe cases.”

    Action/result: Added reusable logic-action helpers for 0x58, 0x59, 0x40, 0x41, 0x42, and rectangle bounds 0x5a.

  201. Reported: “The 0x58/0x59 byte helpers are in, and I’m wiring the first movement cases around a synthetic control-screen fill.”

    Action/result: Added initial object-movement probe cases for control-class acceptance.

  202. Reported: “The movement cases are wired; I’m adding focused tests so the generated fixture bytes and case registry stay pinned down.”

    Action/result: Added unit-test coverage for the new movement cases.

  203. Reported: “Imports are updated. I’m adding assertions for the exact helper encodings before running the focused tests.”

    Action/result: Added fixture-helper byte-encoding assertions.

  204. Reported: “The tests now cover the helper bytes and the new case ids. I’m running those focused tests before touching QEMU.”

    Action/result: Ran the focused helper/probe tests successfully.

  205. Reported: “Focused tests pass. I’m running the three control-1 acceptance cases through QEMU now.”

    Action/result: Began a targeted QEMU batch for the first control-class movement cases.

  206. Reported: “The QEMU mismatch shows the full-screen control-1 fill is not the right oracle: the engine accepts the move when our expectation said it should block. I’m switching to the rectangle-boundary path the disassembly also points at for 0x58/0x59.”

    Action/result: Reclassified the initial result as a bad probe design and added rectangle-boundary cases.

  207. Reported: “I added a helper for 0x5a rectangle bounds and am replacing the weak control-fill assertions with boundary-crossing movement cases.”

    Action/result: Added 0x5a fixture support and rectangle-boundary movement fixtures.

  208. Reported: “The movement harness now has both the corrected control-1 observations and the rectangle-boundary cases. I’m pinning those names in tests.”

    Action/result: Updated movement-probe tests for the revised case set.

  209. Reported: “Tests are patched. I’m rerunning the focused unit tests before launching the corrected QEMU batch.”

    Action/result: Re-ran the focused unit tests successfully.

  210. Reported: “Focused tests pass. I’m rerunning QEMU with the corrected control-1 observations and the new rectangle-boundary cases.”

    Action/result: Ran the revised QEMU batch.

  211. Reported: “The corrected control-1 cases all matched, but the rectangle case still reached the target. I’m going back to static inspection of the boundary branch before trying another fixture tweak.”

    Action/result: Paused the failed rectangle hypothesis and inspected the movement/boundary code path.

  212. Reported: “Interesting: rectangle-boundary also reached the target, which means the bit probably gates a specific movement mode or countdown path rather than all object motion. I’m dumping the surrounding branch now.”

    Action/result: Disassembled the surrounding movement branch.

  213. Reported: “The static dump shows the boundary check is behind the pre-movement mode dispatcher and only for objects with direction active, active/update bits, and clear 0x0002. I’ll adapt the probe to that path.”

    Action/result: Identified the gating conditions for the rectangle-boundary helper.

  214. Reported: “Before moving on, I’m inspecting the actual branch target so the next fixture is based on code shape instead of another guess.”

    Action/result: Continued static inspection of the rectangle-boundary target and object-field tests.

  215. Reported: “Aha, the bit 0x0002 branch lives in the pre-movement mode dispatcher. I’m changing the rectangle-boundary cases to use the countdown-gated autonomous path that reaches that branch.”

    Action/result: Reworked rectangle-boundary probes to drive the relevant update path.

  216. Reported: “For the rectangle cases I’ll reuse the existing one-shot autonomous mode machinery, because that already gives the object an active direction across cycles.”

    Action/result: Connected the rectangle-boundary cases to the autonomous movement machinery.

  217. Reported: “The rectangle cases now use countdown-gated motion and compare the final object position. I’m running the focused tests again.”

    Action/result: Re-ran focused unit tests after the rectangle-case rewrite.

  218. Reported: “Focused tests pass. I’m running the three rectangle-boundary cases through QEMU.”

    Action/result: Ran the corrected rectangle-boundary QEMU batch.

  219. Reported: “That worked: all three rectangle-boundary cases matched. I’m recording that as the positive evidence for 0x58/0x59, then moving to the control-class bits 0x40/0x41/0x42.”

    Action/result: Promoted the rectangle-boundary result as QEMU evidence for 0x58/0x59.

  220. Reported: “The acceptance helper is clear enough now: control class 2 checks bit 0x0100, class 3 checks bit 0x0800, and 0x42 clears both. I’m adding QEMU cases that follow that exact branch.”

    Action/result: Added class-2/class-3 object-control cases for 0x40, 0x41, and 0x42.

  221. Reported: “The 0x40/0x41/0x42 helpers are in. I’m adding case coverage for control classes 2 and 3 with priority 14 so the scan actually runs.”

    Action/result: Added fixture helpers and movement-probe cases for the control-class bits.

  222. Reported: “The control-class cases are added; I’m expanding the tests to pin the helper encodings and case ids.”

    Action/result: Updated unit tests for the control-class probes.

  223. Reported: “Tests now include the new control-class cases. I’m running the focused suite before QEMU.”

    Action/result: Ran the focused unit tests.

  224. Reported: “Focused tests pass. I’m running the four control-class QEMU cases for 0x40/0x41/0x42.”

    Action/result: Started the control-class QEMU batch.

  225. Reported: “The first 0x0100 case did not block, so I’m inspecting the acceptance path again instead of forcing the expected output.”

    Action/result: Returned to static inspection after the QEMU mismatch.

  226. Reported: “Found the missing piece: I used priority 15, and the code skips the control scan at that priority. I’m lowering these probes to priority 14 and expecting rejection to leave the object visible but stationary.”

    Action/result: Corrected the control-class probes to avoid the priority-15 bypass.

  227. Reported: “The control-class expectations are now tied to the priority-14 scan path. I’m rerunning the focused tests before another QEMU pass.”

    Action/result: Re-ran the focused unit tests.

  228. Reported: “Focused tests pass again. I’m running the combined control/rectangle QEMU batch.”

    Action/result: Ran a larger QEMU batch for control and rectangle behavior.

  229. Reported: “The control-1 rejection now matches, but setting bit 0x0002 did not make the object visible or moving there. I’m going to document 0x58 via the rectangle-boundary evidence and keep the control-1 branch as a separate observed behavior.”

    Action/result: Split the 0x58 positive evidence from the class-1 control-screen observations.

  230. Reported: “The 0x58 case also has no visible object under full control-1 fill, so I’m renaming those cases to describe what they actually prove rather than what I hoped they would prove.”

    Action/result: Renamed the control-1 cases to reflect observed hidden/no movement behavior.

  231. Reported: “Names and expectations now reflect the real class-1 observation. I’m running a clean batch with the renamed cases and the control-class bits.”

    Action/result: Prepared the corrected acceptance batch.

  232. Reported: “The corrected acceptance batch is running. If it matches, I’ll promote the class-2/class-3 results as evidence for 0x40/0x41/0x42.”

    Action/result: Ran the corrected control acceptance batch.

  233. Reported: “Great: control-1 and rectangle matched; 0x0100 differs only because I expected a plain picture while the rejected object remains visible at the start point. I’m updating the oracle to the actual static branch result.”

    Action/result: Corrected the class-2/class-3 rejection oracle to visible, stationary objects.

  234. Reported: “For control class 2, 0x0100 blocks movement but leaves the object visible at its starting location. I’m mirroring that expectation for class 3 and rerunning the four-bit batch.”

    Action/result: Updated both class-2 and class-3 blocked expectations.

  235. Reported: “The class-2 and class-3 rejection cases now expect a stationary visible object. Focused tests pass, and I’m rerunning just those four QEMU cases.”

    Action/result: Re-ran the focused unit tests and the four-case QEMU batch.

  236. Reported: “The 0x40/0x41/0x42 batch matched exactly. I’m running the clean control-1 batch too so that observation has its own compact report.”

    Action/result: Captured matching QEMU evidence for the class-2/class-3 control-bit behavior.

  237. Reported: “The control-class-1 clean report matched too. I’m promoting the QEMU evidence metadata for 0x40, 0x41, 0x42, 0x58, and 0x59 now.”

    Action/result: Promoted the matching movement-probe batches in tools/logic_opcode_evidence.py.

  238. Reported: “The opcode table is regenerated with those five opcodes marked as QEMU-backed. I’m patching the prose docs with the static branch and the matching batch names.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md and began prose documentation updates.

  239. Reported: “I’m going to document the control-screen acceptance helper, rectangle-boundary branch, and corrected probe results together so the earlier false starts are preserved as corrections.”

    Action/result: Updated the opcode, movement pipeline, compatibility, and clean-room notes with the corrected evidence.

  240. Reported: “I found exact doc locations. I’m applying the labels first, then the prose can refer to stable names rather than raw addresses.”

    Action/result: Added symbolic labels for the control-acceptance and rectangle-boundary routines.

  241. Reported: “Symbolic labels are updated. I’m patching the opcode chapter next with the verified summaries and evidence names.”

    Action/result: Updated the logic-bytecode chapter rows for 0x40, 0x41, 0x42, 0x58, and 0x59.

  242. Reported: “The opcode rows now include the bit semantics and matching QEMU evidence. I’m updating the object pipeline chapter with the actual branch-level explanation.”

    Action/result: Added the branch-level explanation to docs/src/graphics_object_pipeline.md.

  243. Reported: “The object pipeline now describes priority-15 bypass, control-class bits, and rectangle-boundary gating. I’m adding replay commands to the compatibility chapter.”

    Action/result: Added replay commands for the matched QEMU batches.

  244. Reported: “Compatibility docs now have the three replay batches. I’m adding the chronological clean-room note with the false starts and corrections.”

    Action/result: Added the detailed chronology to docs/src/clean_room_executable_notes.md.

  245. Reported: “The clean-room notes now preserve the failed assumptions, the corrected static reading, and the matching batches. I’m updating the status page, then I’ll continue to the remaining object animation/update opcodes.”

    Action/result: Updated docs/src/current_status.md with the new control/priority finding.

  246. Reported: “That batch is documented. I’m moving on to 0x46-0x4c, starting from the handler offsets and the update loop before making any new QEMU cases.”

    Action/result: Began static inspection of the object animation/update handlers.

  247. Reported: “The handler offset mismatch is a useful warning: the table is image-relative, while the file has an MZ header. I’m normalizing that before trusting any handler disassembly.”

    Action/result: Started checking the executable image/file-offset mapping.

  248. Reported: “I found a compact visible probe for 0x46/0x47/0x49/0x4c, but before running it I’m checking the code path that decrements frame counters and chooses the next cel.”

    Action/result: Added draft animation probe cases but deferred QEMU pending static confirmation.

  249. Reported: “You’re right. The QEMU probes are valuable, but I let them become the search strategy instead of the cross-check. I’ll course-correct: first inspect and label the disassembled routines, derive the behavior from those code paths, and use QEMU only for small validation probes after the static story is clear.”

    Action/result: Changed the active methodology back to disassembly-first analysis at the user’s direction.

  250. Reported: “First I’m sorting out the offset convention so every handler label lands on the right bytes. Then I’ll walk the 0x46-0x4c handlers and the per-cycle update callback directly from the executable.”

    Action/result: Began verifying MZ header/image-offset conventions before continuing handler disassembly.

  251. Reported: “The progress log is caught up through the correction. I’m now normalizing the executable offsets: the opcode table gives loaded-image offsets, while ndisasm -e needs the MZ header included in the file offset.”

    Action/result: Confirmed that handler table addresses are image-relative and map to file offsets by adding the MZ header size.

  252. Reported: “The offset mapping checks out: handlers from AGIDATA.OVL are loaded-image addresses, and in the MZ file the bytes are at image_offset + 0x200. I’ve confirmed that on the 0x5a, 0x58, and animation-control handlers.”

    Action/result: Used focused ndisasm slices to verify the image/file mapping and handler starts.

  253. Reported: “The static path is now much clearer. The per-cycle object updater at image 0x0563 scans active objects, decrements byte +0x20 when bit 0x0020 is set, calls the frame-mode helper at 0x48b3 when that countdown reaches zero, then reloads +0x20 from +0x1f.”

    Action/result: Identified the frame-timer scan and its reload behavior from disassembly.

  254. Reported: “The frame-mode helper at image 0x48b3 is the missing high-level piece: mode 0 loops frames forward, mode 1 advances forward and stops/sets a flag at the last frame, mode 2 steps backward and stops/sets a flag, and mode 3 loops backward. This gives us a spec-level model for 0x46-0x4c before any emulator check.”

    Action/result: Derived the frame-mode state machine from static disassembly.

  255. Reported: “One important detail from the static path: actions 0x49 and 0x4b set bit 0x1000, and code.object.advance_frame_by_mode consumes that bit by clearing it and returning before the first frame change. So those modes have a one-callback startup delay; the docs need to say that explicitly.”

    Action/result: Added the bit-0x1000 startup-delay behavior to the static model.

  256. Reported: “I’ve added stable labels for the frame timer scan and frame-mode dispatcher, so the rest of the prose can now talk about those routines symbolically rather than as loose addresses.”

    Action/result: Added code.object.frame_timer_update and code.object.advance_frame_by_mode to docs/src/symbolic_labels.md.

  257. Reported: “The opcode chapter now corrects 0x4c: it does not clear +0x20; it copies the variable value into both +0x1f and +0x20. That was exactly the kind of thing the disassembly-first pass was meant to catch.”

    Action/result: Corrected the 0x4c opcode documentation and expanded the frame-timer explanation.

  258. Reported: “I’m adding the static evidence trail now: table offsets, MZ offset convention, focused disassembly slices, and the corrected 0x4c interpretation. Then I’ll let the small QEMU probes validate the derived model rather than discover it.”

    Action/result: Added the static frame-timer/frame-mode analysis section to docs/src/clean_room_executable_notes.md.

  259. Reported: “The clean-room notes now include the course correction and the exact static evidence. I’m tightening the fixture tests for the new helper bytes before running the targeted animation validations.”

    Action/result: Added helper-byte assertions for actions 0x46, 0x47, 0x49, and 0x4c.

  260. Reported: “The helper-byte tests now cover 0x46, 0x47, 0x49, and 0x4c. I’m running the focused Python tests before I ask QEMU to validate the visible frame behavior.”

    Action/result: Ran focused unit tests and the opcode evidence check; both passed.

  261. Reported: “Focused tests passed. Now I’m running only the three frame-timer QEMU cases that follow from the static model: normal mode-1 advance, 0x46 disabling the timer, and 0x47 restoring it.”

    Action/result: Started the frame_timer_001 QEMU validation batch.

  262. Reported: “As expected, the sandbox blocked QEMU’s local VNC bind. I’m rerunning the same narrow validation outside the sandbox so the emulator can open its monitor/display sockets.”

    Action/result: Reran the same QEMU command with approved elevated permission for the object-movement probe.

  263. Reported: “QEMU is running the snapshot batch now. While it works, I’m not adding more guesses; the next edits depend on whether those three cases match the disassembly-derived expectations.”

    Action/result: Waited for the QEMU snapshot batch to complete.

  264. Reported: “The frame-timer QEMU batch matched all three cases. That validates the static model’s visible pieces: 0x4c seeds the countdown, 0x46 suppresses the advance by clearing bit 0x0020, and 0x47 restores it.”

    Action/result: Recorded frame_timer_001 as a matched QEMU batch.

  265. Reported: “I’m promoting only the opcodes directly covered by that batch: 0x46, 0x47, and 0x4c. 0x49 already had QEMU flag-clearing evidence, and this batch will be cited as additional frame-mode evidence in prose rather than overloading the metadata.”

    Action/result: Updated tools/logic_opcode_evidence.py to promote 0x46, 0x47, and 0x4c to QEMU behavior evidence.

  266. Reported: “The evidence metadata now marks 0x46, 0x47, and 0x4c as behavior-validated by frame_timer_001 instead of dispatch-smoke. I’m regenerating the evidence chapter and then I’ll document the QEMU result in prose.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  267. Reported: “The generated evidence chapter is refreshed. I’m adding the replay command and result summary to the compatibility and clean-room docs so the validation trail is reproducible.”

    Action/result: Began documenting the frame-timer QEMU batch in prose docs.

  268. Reported: “I found the compatibility section next to the movement batches. I’m placing frame_timer_001 there and linking it to the exact opcodes it validates.”

    Action/result: Added the frame_timer_001 replay command to docs/src/compatibility_testing.md.

  269. Reported: “The opcode and graphics chapters now include the QEMU-backed frame-timer result. I’m appending the exact batch command/result to the clean-room chronology next.”

    Action/result: Added the frame_timer_001 result to the logic-bytecode, graphics-object-pipeline, and clean-room notes.

  270. Reported: “The clean-room chronology has the frame-timer validation and the sandbox failure/rerun recorded. I’m updating the current status so the ‘next step’ no longer says this is unvalidated.”

    Action/result: Updated docs/src/current_status.md to mark the frame timer model as QEMU-validated for visible mode-1 behavior.

  271. Reported: “Current status is updated. I’m catching the progress log up through the static analysis, the QEMU validation, and the evidence promotion before running the full validation suite.”

    Action/result: Appended progress-log entries for the frame-timer analysis and validation pass.

  272. Reported: “The progress log is current. I’m running the full local compatibility suite, evidence check, mdBook build, and whitespace check now.”

    Action/result: python3 -B -m unittest discover -s tests passed 97 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check also passed.

  273. Reported: “All four checks passed: 97 Python tests, evidence check, mdBook build, and git diff --check. I’m adding that validation note to the progress log, then I’ll do the tiny final mdBook/whitespace rerun because the log changed.”

    Action/result: Recorded the successful validation suite result.

  274. Reported: “I’ll proceed with the disassembly-first next slice: the object frame-mode family around 0x48, 0x4a, and 0x4b. I’ll use QEMU only after the static path says exactly what should happen.”

    Action/result: Started a static-first pass over the frame-mode setup actions and the frame advance helper.

  275. Reported: “I’ve refreshed the repo instructions and current notes. Next I’m reading the movement fixture code so any validation case mirrors the disassembled behavior instead of guessing from screenshots.”

    Action/result: Re-read local harness files and AGENTS/project guidance.

  276. Reported: “Before touching harness code, I’m re-reading the exact action handlers and the frame dispatcher bytes. The goal is to nail down where mode 2 actually completes, since that’s the one most likely to hide an off-by-one misunderstanding.”

    Action/result: Cut and disassembled focused executable slices around image offsets 0x48b3 and 0x6b82.

  277. Reported: “The static read turned up one correction: mode 2 doesn’t just decrement once and stop. It keeps stepping backward and completes when it reaches frame 0, with an immediate-complete shortcut if it starts at frame 0.”

    Action/result: Corrected the frame-mode model before adding runtime probes.

  278. Reported: “For looping modes, I don’t want a flaky ‘capture at just the right cycle’ test. I’m going to make the logic fixture stop the timer after it observes the expected frame, using the already decoded 0x32 object frame read plus 0x46 to clear the timer bit.”

    Action/result: Chose deterministic loop-stopping bytecode for mode 0 and mode 3 validation cases.

  279. Reported: “I’m going to add tiny byte helpers for the exact opcodes the fixture needs, then keep the QEMU cases narrow: mode 0 wraps forward, mode 2 reaches frame 0 and stops, mode 3 wraps backward.”

    Action/result: Planned scoped fixture helper additions for actions 0x48, 0x4a, 0x4b, and 0x32.

  280. Reported: “The fixture helpers are in. I’m wiring them into the movement probe as explicit animation modes rather than making a one-off custom fixture, so future frame-mode cases can reuse the same path.”

    Action/result: Added helper encoders to tools/qemu_fixture.py and threaded animation mode selection through tools/object_movement_probe.py.

  281. Reported: “The movement probe now has three new frame-mode cases. I’m adding unit coverage for the helper encodings and registry entries before I put the original engine through it.”

    Action/result: Added tests for the new helper bytes and movement case IDs.

  282. Reported: “The tests now cover the new byte helpers and all three cases. I’m running the focused Python tests first; if those pass, I’ll run the QEMU batch against the original interpreter.”

    Action/result: Ran focused unit tests for fixture helpers and movement probes.

  283. Reported: “Focused tests passed. I’m running the QEMU validation batch now with the three frame-mode cases against the original engine.”

    Action/result: Started frame_timer_modes_002 through tools/object_movement_probe.py.

  284. Reported: “QEMU has built the snapshot disk and is stepping through the cases now. So far the harness is using the same one-boot snapshot pattern as the earlier movement batches.”

    Action/result: QEMU validation proceeded through the snapshot fixture harness.

  285. Reported: “All three frame-mode cases matched QEMU: mode 0 forward wrap, mode 2 backward completion at frame 0, and mode 3 backward wrap. I’m promoting the opcode evidence and then I’ll record the correction and replay command in the docs.”

    Action/result: Confirmed frame_timer_modes_002 with 3 matches, 0 mismatches, and 0 errors.

  286. Reported: “The evidence metadata is updated: 0x48 and 0x4a are now behavior-backed instead of dispatch-smoke, and 0x4b has both its flag side effect and visible mode-2 completion covered.”

    Action/result: Updated tools/logic_opcode_evidence.py.

  287. Reported: “The generated chapter is refreshed. I’m finding every place where the old ‘mode 2 decrements once’ wording survived so the docs don’t carry a stale hypothesis.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md and searched the docs for old frame-mode wording.

  288. Reported: “I found the places where the older mode-2 wording lives. I’m correcting those and adding the exact QEMU command/result to the compatibility and clean-room notes.”

    Action/result: Began patching prose docs for the corrected mode-2 behavior and frame_timer_modes_002.

  289. Reported: “I’ll pick this back up at the doc-integration step: the code and QEMU probe are in place, so I’m going to finish recording the evidence trail and then run the book/tests checks.”

    Action/result: Resumed after context compaction and continued from the documentation integration step.

  290. Reported: “The scan shows the new code and two doc chapters already changed, with the older mode-2 wording still present in the clean-room chronology and the compatibility/current-status pages not yet caught up. I’m going to patch those together so the evidence trail stays coherent.”

    Action/result: Located remaining docs needing updates.

  291. Reported: “I’m making the doc edits now: correcting the static mode-2 note, adding the exact new QEMU replay command/result, and updating the status page so 0x48/0x4a are no longer described as smoke-only.”

    Action/result: Updated compatibility testing, current status, clean-room notes, and logic-bytecode prose.

  292. Reported: “The main docs are patched. I’m appending the progress-log entries next, including the short updates from this resumed turn so the historical record remains continuous.”

    Action/result: Appended this progress-log block.

  293. Reported: “All core checks passed: 97 tests, evidence check, mdBook build, and whitespace check. One search command tripped over shell backticks in the pattern, so I’m rerunning that search safely and then adding the validation note to the log.”

    Action/result: python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check passed. The corrected safe search found only the historical progress-log mention of the old wording and the corrected clean-room sentence.

  294. Reported: “The safe search only finds the historical progress note and the corrected sentence, so the stale wording is gone from the actual spec prose. I’m logging the validation result and then doing the small final doc/whitespace rerun because the log changed.”

    Action/result: Added the validation result to this progress log.

  295. Reported: “I’ll continue from the post-frame-mode checkpoint. I’m going to re-open the current status and evidence matrix, pick the highest-value source-backed opcode cluster that is still weakly documented, and keep the progress log moving before substantial new work.”

    Action/result: Reviewed current status, git state, recent progress, and evidence gaps after commit a27928a.

  296. Reported: “The evidence scan also caught a stale sentence in logic_bytecode.md that still calls 0x48/0x4a dispatch-smoke. I’ll fix that as part of this pass, then dig into the next weak cluster: the object bitfield/refresh opcodes 0x3a..0x3c, which currently have only smoke evidence.”

    Action/result: Selected the 0x3a..0x3c object bitfield/refresh action cluster for the next source-first investigation.

  297. Reported: “The existing docs already know the direct field writes, but the high-value gap is semantics: bit 0x0010 partitions active objects between update-list roots. I’m reading the surrounding wrappers/list helpers now so the opcode names can graduate from ‘bit twiddles’ toward actual engine behavior.”

    Action/result: Re-read the 0x3a..0x3c, 0x6a54, 0x6a8e, 0x6aab, 0x0307, 0x0358, 0x045e, and 0x0488 source paths.

  298. Reported: “The source read shows 0x3c is broader than its old label implies: it computes the object address from the operand, but then runs the all-list flush, rebuild/draw, and dirty-rectangle refresh path. I’m checking whether that label is baked into tests before renaming it to something more accurate.”

    Action/result: Found no test dependency on refresh_object_helper.

  299. Reported: “There are no tests pinning the old 0x3c label, so I can safely tighten the terminology. I’m going to treat 0x3a/0x3b as list-membership partition toggles and 0x3c as an all-object-list refresh/repaint action, then regenerate the evidence table from the local opcode names.”

    Action/result: Planned the label change to refresh_object_lists.

  300. Reported: “I’m going to edit the label and prose now, not the runtime behavior. The evidence level will stay as QEMU dispatch-smoke until we build a visible fixture, but the specification text can still record the static source semantics precisely.”

    Action/result: Updated tools/disassemble_logic.py, logic_bytecode.md, and graphics_object_pipeline.md with refresh_object_lists semantics.

  301. Reported: “Before editing, I checked the evidence generator: it derives summaries from the opcode labels, so a better 0x3c label will automatically make the table less misleading. I’m applying that targeted terminology update plus the stale 0x48/0x4a sentence fix.”

    Action/result: Removed the stale 0x48/0x4a smoke-only wording from logic_bytecode.md.

  302. Reported: “The label/prose update is in. I’m regenerating the opcode evidence chapter now so the generated matrix uses refresh_object_lists consistently.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  303. Reported: “The regenerated matrix has the new label. One search command again interpreted backticks, but the useful result confirms the generated evidence row changed; I’ll rerun searches with safe quoting when checking cleanup. Next I’m checking the symbolic label map so the update-list helpers have stable names for later interpreter-version comparisons.”

    Action/result: Reviewed docs/src/symbolic_labels.md and confirmed the update-list wrapper helpers were not yet named there.

  304. Reported: “The symbolic map does not yet name the update-list wrappers or the 0x0010 toggle helpers, even though those are exactly the kind of cross-version anchors you asked us to preserve. I’m adding stable labels for them and then I’ll see whether there’s a clean visible QEMU validation for the root-order effect.”

    Action/result: Added symbolic labels for update-list builders, flush, rebuild, refresh, and bit-0x0010 membership helpers.

  305. Reported: “The symbolic labels are in. I’m reading the fixture builders now to find the least invasive way to validate the predicted draw-order effect from bit 0x0010, preferably with two overlapping objects and a stable pixel/sample comparison.”

    Action/result: Reviewed logic and object overlay probe fixture builders.

  306. Reported: “A clean QEMU validation looks feasible: activate two overlapping objects, clear bit 0x0010 on one, then use the source-derived root order to predict which object draws on top. I’m checking the fixture helper defaults and view frames so the expected image is stable and distinguishable.”

    Action/result: Confirmed view 11/group 0 frames 0 and 1 have overlapping nontransparent pixels with different colors.

  307. Reported: “The probe framework can already compare multiple sprites by compositing extras first and the primary sprite last, which fits the predicted root-order test. I hit a small local attribute-name mismatch while checking frame transparency; I’m inspecting the rendered frame structure and then I’ll add the case.”

    Action/result: Confirmed frame transparency is frame.control & 0x0f.

  308. Reported: “The frame renderer uses control & 0x0f as transparency; view 11 frames 0 and 1 differ enough to reveal order. I’m adding one source-derived behavior case to the logic probe: object 11 is moved to the 0x1703 partition with 0x3a, object 10 stays in 0x16ff, and the expected composite has object 10 on top.”

    Action/result: Prepared a visible root-order probe design.

  309. Reported: “I can cover both toggles with two cases rather than overloading one: one where 0x3a moves frame-1 behind a still-0x16ff frame-0 object, and one where 0x3b moves frame-1 back over a 0x1703 frame-0 object. I’ll include 0x3c after the partitioning in both cases to validate that the global refresh preserves the predicted order.”

    Action/result: Added two root-partition cases to tools/logic_interpreter_probe.py.

  310. Reported: “The two behavior cases are in the probe list. I’m adding unit coverage for their registration before trying them under QEMU, so a typo in the case IDs or expected sprites gets caught locally first.”

    Action/result: Added the new case IDs to tests/test_logic_interpreter_probe.py.

  311. Reported: “I’m making the test registration check explicit for the two new root-partition cases. That keeps the probe catalogue honest as it grows.”

    Action/result: Updated the base-case registration test.

  312. Reported: “The catalogue test is updated. I’m running the focused logic-probe tests now, then I’ll run the two new cases through QEMU if local composition passes.”

    Action/result: python3 -B -m unittest tests.test_logic_interpreter_probe tests.test_logic_doc_coverage passed.

  313. Reported: “Focused tests passed. I’m running the two new root-partition cases against the original engine now; this one needs QEMU/VNC access, so I’ll request the same kind of permission as prior batches.”

    Action/result: Ran object_root_partition_001; the first case mismatched.

  314. Reported: “The first QEMU case mismatched, which is useful evidence rather than a dead end: my source-derived draw-order prediction is missing another ordering detail. I’m opening the report and capture samples now, then I’ll go back to the list builder/sort code before adjusting the model.”

    Action/result: Inspected mismatch samples and re-read the list builder and node traversal.

  315. Reported: “The mismatch is not just ‘opposite top sprite’; there are white pixels where the local expectation has object colors, so another object-state detail is in play. I’m comparing the capture against a few source-plausible composites before changing the probe, then I’ll inspect the activation/list code around that detail.”

    Action/result: Determined that activation-time placement/collision was affecting the first fixture design.

  316. Reported: “The capture points to placement, not root order: activating two objects at exactly the same position lets the placement helper nudge one to avoid collision. I’m revising the fixtures to activate the second object elsewhere, then use the already decoded dirty position setter 0x93 to overlap it after activation, so the test isolates the 0x0010 partition effect.”

    Action/result: Updated the fixture to activate object 11 at X 90, then move it to X 50 with 0x93.

  317. Reported: “The fixtures now avoid activation-time collision adjustment. I’m rerunning focused tests and then the same QEMU batch.”

    Action/result: Focused tests passed, but object_root_partition_002 mismatched.

  318. Reported: “The revised case still mismatched, so the remaining issue is likely not placement. I’m going back to the render/list order carefully: the list builder inserts nodes at the head, and the processor walks from the tail, so I need to model that actual traversal instead of assuming root order alone determines topmost pixels.”

    Action/result: Rechecked the source traversal and mismatch report.

  319. Reported: “The second mismatch is identical, so 0x93 did not isolate the object from the placement/update behavior the way I hoped. I’m going to inspect the 0x93 handler before touching the fixture again; if it calls placement or refreshes through the same collision path, I’ll avoid it for this validation.”

    Action/result: Static read confirmed 0x93 calls placement helper 0x593a.

  320. Reported: “Confirmed: 0x93 calls placement helper 0x593a, so it was still letting collision adjustment move the object. I’m switching the isolation step to 0x25, which static docs say writes current and saved position fields directly without placement, then the explicit 0x3c refresh will make the final overlap visible.”

    Action/result: Replaced 0x93 with 0x25 in the root-partition fixtures.

  321. Reported: “The fixture now uses 0x25 for direct overlap, with 0x3c doing the refresh. I’m rerunning the focused unit test and QEMU batch again.”

    Action/result: Focused tests passed, but object_root_partition_003 mismatched.

  322. Reported: “Still mismatching. At this point the fixture is no longer a quick validation, so I’m going to stop iterating by trial and inspect the actual captured shape and relevant draw code before deciding whether this is worth continuing now. The source trail matters more than forcing a probe.”

    Action/result: The capture showed object 11 drawn at both X 50 and X 90.

  323. Reported: “The capture reveals object 11 is still at its activation X (90), so the direct 0x25 write after activation is not enough to move the already-listed persistent object in this path. I’m disassembling the generated fixture and the 0x25/activation code paths to understand why before deciding whether to keep or drop this QEMU case.”

    Action/result: Confirmed the generated fixture contained 0x25 0b 32 50 and that 0x25 rewrites both current and saved coordinates.

  324. Reported: “Now the behavior is clear: 0x25 updates the saved position too, so the restore pass no longer knows to erase the old object at X 90. The result is a deliberate ghost plus the new overlap. I’m checking whether modeling that ghost makes the QEMU capture match; if it does, this becomes a useful combined observation about 0x25 plus the list refresh.”

    Action/result: Local comparison matched exactly when the stale X-90 drawing was included in the expected image.

  325. Reported: “That matches exactly when I include the stale X-90 image left by 0x25. I’m updating the expected composites to include that ghost explicitly, then I’ll rerun both cases; the root-order part still cleanly validates at the overlapping X-50 pixels.”

    Action/result: Updated the two root-partition cases to include the activation-position ghost sprite in expected output.

  326. Reported: “The expected composites now include the observed stale image from the direct position rewrite. I’m rerunning focused tests and then the two-case QEMU batch.”

    Action/result: Focused tests passed.

  327. Reported: “Focused tests pass. I’m running the corrected QEMU batch; this should now distinguish the documented ghost from any actual root-order mismatch.”

    Action/result: QEMU batch object_root_partition_004 matched with 2 matches, 0 mismatches, and 0 errors.

  328. Reported: “Great, both root-partition cases matched the original engine. I’m promoting 0x3a, 0x3b, and 0x3c from smoke to behavior evidence, then I’ll document the source correction, the failed fixture attempts, and the final passing QEMU batch.”

    Action/result: Promoted 0x3a, 0x3b, and 0x3c in tools/logic_opcode_evidence.py.

  329. Reported: “The evidence generator now treats the root-partition opcodes as behavior-validated. I’m regenerating the matrix and then I’ll patch the prose docs around the exact command and result.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  330. Reported: “The matrix now shows 0x3a, 0x3b, and 0x3c as QEMU-validated. I’m updating the prose docs next, including the important caveat that the fixture initially failed until we accounted for 0x25 preserving the stale saved rectangle.”

    Action/result: Began updating compatibility, status, graphics, and opcode prose docs.

  331. Reported: “I found two stale spots: the older view-load/field23 compatibility paragraph still says 0x48/0x4a are smoke-only, and current status still mentions generic bitfield smoke coverage. I’m patching those along with the new object_root_partition_004 replay command.”

    Action/result: Patched compatibility, current status, graphics pipeline, and logic bytecode prose.

  332. Reported: “The compatibility, status, graphics, and opcode chapters are patched. I’m adding the chronological clean-room record now, including the mismatch sequence and why the final fixture needed to model the 0x25 stale image.”

    Action/result: Added the object update-list partition section to docs/src/clean_room_executable_notes.md.

  333. Reported: “The clean-room chronology now has the source commands, the three failed fixture variants, and the final passing QEMU evidence. I’m adding a compact current-status bullet so future resumption sees 0x0010 as confirmed behavior, not just next-work detail.”

    Action/result: Added the root-partition summary to current status.

  334. Reported: “Current status is updated. I’m appending the work log now so the intermediate false starts and the eventual source correction are preserved for the historical record.”

    Action/result: Appended this progress-log block.

  335. Reported: “The progress log is caught up. I’m running the full validation suite now: all Python tests, evidence check, mdBook build, whitespace check, and a stale-wording search.”

    Action/result: python3 -B -m unittest discover -s tests passed 97 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check passed. The stale-wording search found only historical command/log references plus an older chronology sentence.

  336. Reported: “The validation suite passed. The stale search only found historical command/log references plus one old ‘Current smoke rows’ sentence from an earlier chronology section; I’m changing that sentence to make clear it was the state at the time, not the current evidence status.”

    Action/result: Reworded the older clean-room chronology sentence to describe the smoke rows as historical.

  337. Reported: “That historical sentence is corrected. I’m recording the validation result in the progress log, then doing a final mdBook and whitespace rerun because documentation changed after the checks.”

    Action/result: Added this final validation note.

  338. Reported: “I’ll keep going from the uncommitted root-partition work. I’m going to scan the current evidence gaps and pick the next source-backed opcode cluster that can be upgraded without muddying the model.”

    Action/result: Reviewed git status and the opcode evidence matrix after the root-partition pass.

  339. Reported: “The evidence matrix has no remaining dispatch-smoke rows; the next good target is a source-backed-but-not-behavior-validated object bit. I’m going after 0x2d/0x2e and bit 0x2000, because it appears in the per-cycle frame/group selection path and should be possible to validate visibly.”

    Action/result: Selected actions 0x2d and 0x2e for the next source-first investigation.

  340. Reported: “I’ll pick up from the 0x2000 object flag mismatch and start by reading the generated batch report/captures, then I’ll go back to the disassembly before changing the model. The useful thing here is to separate ‘our expected sprite is wrong’ from ‘the flag means something subtler than the static read suggested.’”

    Action/result: Inspected object_bit_2000_001.json; the mismatch was confined to the object pixels.

  341. Reported: “The mismatch is tight: all differing pixels are exactly where the object is drawn, not a random screen-state problem. The captured colors look like a different cel/group than expected, so I’m going to inspect the fixture and renderer expectations before touching the opcode description.”

    Action/result: Listed the fixture and inspected the capture metadata.

  342. Reported: “The probe itself is doing what I intended: object 10 is initialized to view 11 group 0, direction 6, tick divider 1, then either clears or sets bit 0x2000. Next I’m checking whether the engine picked a different group/frame or whether the group-selection pass is gated by another field I missed.”

    Action/result: Re-read the probe setup code and the 0x0563 static frame-update slice.

  343. Reported: “The static slice confirms the bit gate exactly at 0x0593: if 0x2000 is set, it skips the direction-to-group lookup; if clear, it can call the group selector. I’m correcting a local import path for the comparison helper now so I can identify which cel the original engine actually drew.”

    Action/result: Corrected the local helper invocation and tested alternate expected group/frame combinations.

  344. Reported: “The miniature render dump is useful: group 0 cels are 20x5, group 1 cels are 13x7. The capture’s mismatch bbox height spans seven rows, so the original engine likely selected group 1 but mirrored or used the opposite group-1 frame from my expectation.”

    Action/result: Rendered compact view-11 cel dumps; this hypothesis was corrected by the subsequent exact-frame comparison.

  345. Reported: “That explains the failed expectation: the engine drew group 0 frame 0 exactly. The disassembly says the automatic lookup only runs when object byte +0x0b is 2, 3, or >=4; view 11 appears to leave that byte below the threshold, so it was a bad fixture for this flag.”

    Action/result: Exact comparison showed the capture matched view 11 group 0 frame 0. Later source review kept the result but corrected the reason to a fixture-lifecycle problem rather than the view’s group count.

  346. Reported: “The right fixture should use a view whose loaded metadata crosses that threshold. I’m going to generalize the helper from ‘view 11 only’ to ‘selected view,’ use a four-group SQ2 view, and rerun the bit-0x2000 pair against QEMU.”

    Action/result: Inspected view resources and selected view 4 as a compact four-group fixture target.

  347. Reported: “One important wrinkle just popped out: these probe logics loop, so a setup sequence inside the main body can keep reselecting group 0 every cycle after the engine’s update pass. I’m checking the loop shape now; the fix may be to guard initialization so the automatic selector has a later cycle where our script no longer resets the group.”

    Action/result: Re-read base_code and self_loop.

  348. Reported: “I need to revise my earlier loop thought: the fixture’s self_loop is an infinite bytecode jump at the end, so the script body is not repeating, but it may also prevent the engine’s later per-cycle object update from running. I’m going to make these two cases use an end-style logic so the engine can advance into the frame-timer pass, then freeze via the already-drawn persistent object state.”

    Action/result: Compared the logic probe shape to the movement harness, which uses a normal 0x00 end action for per-cycle movement tests.

  349. Reported: “The movement harness already has a pattern for this: initialize once, let per-cycle actions run until a flag, and end the logic instead of pinning the interpreter in a bytecode jump. I’m borrowing that structure conceptually for the logic opcode probe rather than inventing a separate tester.”

    Action/result: Located the guarded one-time setup pattern in tools/qemu_fixture.py.

  350. Reported: “Before editing, I’m going to keep the change small: add a reusable ‘end after body’ option to the logic probe case builder, add an arbitrary-view setup helper, and switch only the two 0x2000 cases to that mode. Then QEMU can tell us whether the static interpretation survives runtime.”

    Action/result: Added end_code, arbitrary-view object setup, and an expected-view parameter to tools/logic_interpreter_probe.py.

  351. Reported: “One more refinement before running it: an end case that redraws the picture every cycle would erase useful evidence, so I’m putting the load/show/setup sequence behind a one-time flag guard. That gives the engine normal cycles afterward without the script resetting the object or repainting the background each time.”

    Action/result: Added guarded one_time_code support.

  352. Reported: “I’ve added the guarded one-time execution path; now I’m wiring the two cases to it and using a loaded view whose group metadata should make the direction table path observable.”

    Action/result: Reworked the 0x2000 cases to use view 4, direction 6, and one-time initialization flags.

  353. Reported: “The probe now initializes view 4 exactly once, sets direction 6 and the bit state once, then returns from logic each cycle. I’m running focused unit tests first so the generated fixture shape is sane before spending another QEMU cycle.”

    Action/result: Focused unit tests passed.

  354. Reported: “The focused tests passed. I accidentally launched a one-case QEMU run with zero waits while checking the command path; I’m letting it finish/close cleanly before starting the real two-case validation.”

    Action/result: The zero-wait run produced a throwaway mismatch and exited.

  355. Reported: “That zero-wait run produced the expected throwaway mismatch, so I’m ignoring it. Now I’m running the real two-case snapshot batch with the normal wait times.”

    Action/result: QEMU batch object_bit_2000_002 matched both cases.

  356. Reported: “Good, the corrected 0x2000 pair matches the original engine: clear bit allows direction-based group selection, set bit suppresses it. I’m promoting those opcodes in the evidence table now and then I’ll update the spec notes with the false start and the static addresses that explain it.”

    Action/result: Added 0x2d and 0x2e to QEMU_ACTIONS.

  357. Reported: “The docs already had the raw 0x2d/0x2e bit writes, but not the higher-level meaning. I’m adding the two direction-to-group data tables and the frame-update helper labels so future version comparisons can key off names instead of SQ2 addresses.”

    Action/result: Added symbolic labels for the two direction-to-group tables.

  358. Reported: “The evidence generator now points 0x2d and 0x2e at the passing object_bit_2000_002 batch. Next I’m adding the stable labels for the two small direction lookup tables in AGIDATA.OVL.”

    Action/result: Continued symbol-map update.

  359. Reported: “The symbol map is updated. I’m expanding the bytecode and graphics chapters so the higher-level behavior is visible where an implementer would look first, not only buried in the chronological notes.”

    Action/result: Patched logic_bytecode.md.

  360. Reported: “The opcode chapter now states both the raw field mutation and the runtime meaning. I’m doing the same in the object pipeline chapter, including the two actual table byte sequences so a clean implementation can reproduce the mapping.”

    Action/result: Patched graphics_object_pipeline.md.

  361. Reported: “The object pipeline chapter now has the implementation-level mapping and the QEMU replay name. I’m adding the chronological clean-room record next, including the first mismatching fixture and why it was wrong.”

    Action/result: Added the clean-room chronology section for bit 0x2000.

  362. Reported: “The chronology now captures both the successful source model and the fixture correction. I’m updating the handoff/status and compatibility chapters so this is visible in the project dashboard too.”

    Action/result: Updated current status.

  363. Reported: “The compatibility patch missed because that chapter’s wording has drifted a bit. I’m locating the nearby section and applying the same replay block against the current text.”

    Action/result: Located the root-partition compatibility section.

  364. Reported: “I found a stale compatibility sentence still calling the old bitfield batch ‘dispatch smoke.’ Since the evidence matrix no longer has smoke rows, I’m cleaning that wording while inserting the new 0x2000 replay command.”

    Action/result: Patched compatibility testing with the new replay command and updated the stale smoke wording.

  365. Reported: “The progress log is caught up through the docs edits. I’m regenerating the opcode evidence chapter now, then I’ll run the full local validation set.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  366. Reported: “The evidence chapter regenerated cleanly. I noticed two long helper lines in the probe while reviewing the diff, so I’m wrapping those before the full validation run.”

    Action/result: Wrapped helper code in tools/logic_interpreter_probe.py.

  367. Reported: “The helper is tidied up. I’m running the full validation pass now: Python unit tests, regenerated evidence check, mdBook build, and whitespace checks.”

    Action/result: python3 -B -m unittest discover -s tests passed 97 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check passed.

  368. Reported: “Validation passed: all 97 tests, evidence check, mdBook build, and git diff --check. I’m doing a quick stale-wording/status scan and then I’ll record the validation result in the progress log.”

    Action/result: Stale scan found only historical progress/chronology mentions and the still-supported generator/category prose, not current opcode evidence rows.

  369. Reported: “I’ll run this as a full pass rather than a proposal: first finish the automatic direction/group semantics, then trace the per-cycle scheduler, then use that to promote more source-backed opcode rows, and finally document the timing model plus the next less-visual families. I’m starting by reading the current evidence matrix and the relevant object/frame-update code so the next probes stay source-led.”

    Action/result: Created the five-step task plan and read current status, opcode evidence, and probe code.

  370. Reported: “The current 0x2000 validation covers the four-plus-groups table only. I’m going to add three focused cases now: one for the 2/3-group table, one sentinel value that must leave the group alone, and one +0x01 != 1 gate case that should block selection even when the table says to change.”

    Action/result: Inspected view 5 as a visibly distinct three-group fixture and dumped the two direction tables from SQ2/AGIDATA.OVL.

  371. Reported: “View 5 is a good 3-group target: group 0 and group 1 are visibly distinct mirror-like cels, so the 2/3-group table can be observed cleanly. I’m adding those cases to the existing logic probe list now.”

    Action/result: Added three initial bit-0x2000 follow-up cases.

  372. Reported: “The three new fixtures are in: 3-group direction 6, 3-group sentinel direction 5, and the +0x01 gate. I’m updating the case registry test, then I’ll run the focused unit tests before QEMU.”

    Action/result: Updated the logic probe registry test.

  373. Reported: “The focused registry tests passed. I again started a zero-wait harness sanity run while checking fixture build behavior; I’ll let that close and then run the real snapshot batch with normal timing.”

    Action/result: The zero-wait dry run mismatched, as expected.

  374. Reported: “The zero-wait dry run mismatched as expected because it captured before the engine had useful draw time. Now I’m running the actual three-case QEMU batch.”

    Action/result: Started QEMU batch object_bit_2000_003.

  375. Reported: “The QEMU batch is still running; it’s in the snapshot execution phase. I’ll wait for the result before deciding whether these fixtures are good enough or need the same kind of source-led correction as the previous one.”

    Action/result: Batch object_bit_2000_003 matched the table and sentinel cases but mismatched the initial +0x01 gate expectation.

  376. Reported: “Two of the three new cases matched: the 2/3-group table and sentinel value are confirmed. The +0x01 != 1 case changed anyway, so I’m inspecting the capture and then tracing who decrements or rewrites +0x01; that may turn the ‘gate’ into a cadence condition rather than a permanent block.”

    Action/result: Exact comparison showed the mismatching case eventually selected group 1.

  377. Reported: “The capture shows the +0x01 = 2 object eventually selected group 1. The source explains why: code.object.frame_timer_update checks +0x01 before code.motion.update_objects decrements the countdown, so a one-shot 2 skips once, then becomes 1 for the next cycle. I’m changing this into two clearer probes: one for that countdown behavior, and one that rewrites +0x01 = 2 every logic cycle to prove the gate itself.”

    Action/result: Added a one-time setup plus per-cycle action fixture helper.

  378. Reported: “I’ve added a reusable one-time-setup plus per-cycle-action fixture shape, which is exactly what we need for timing-sensitive engine behavior. Now I’m revising the +0x01 case and adding the explicit ‘keep forcing 2’ gate probe.”

    Action/result: Replaced the initial gate case with a countdown case and added a forced-gate case.

  379. Reported: “The old gate case is now a countdown case, and the new gate case keeps setting +0x01 to 2 before each engine update. I’m updating the tests and rerunning the targeted batch.”

    Action/result: Updated the registry test for the renamed and new cases.

  380. Reported: “I’m running the focused tests and then a four-case QEMU batch: the two table cases, the countdown case, and the forced-gate case. If the forced case holds, that completes the 0x2000 semantic set cleanly.”

    Action/result: Focused tests passed and QEMU batch object_bit_2000_004 started.

  381. Reported: “The unit tests passed; QEMU is still running the four fixtures. This is the interesting one because it tests timing, not just final object state.”

    Action/result: QEMU batch object_bit_2000_004 matched all four cases.

  382. Reported: “The four-case batch matched: both direction tables, sentinel behavior, countdown-to-1, and the forced +0x01 != 1 gate are now validated. I’m moving to the scheduler trace next: who calls the frame/group update, motion update, logic execution, and redraw steps, and in what order.”

    Action/result: Completed the automatic direction/group semantics plan item.

  383. Reported: “The near-call scan found the key top-level calls: code.object.frame_timer_update is called at image 0x024b, and a pre-pass at 0x0644 is called at 0x0198. I’m disassembling that top-level range now to pin the cycle ordering rather than relying on old notes.”

    Action/result: Disassembled image 0x0100..0x0270 and scanned direct calls in that range.

  384. Reported: “The top-level loop is now visible at 0x0150: it calls input/system helpers, a pre-motion pass, then repeatedly calls logic 0 through code.logic.call_logic, and only after that reaches code.object.frame_timer_update at 0x024b. I’m labeling that cycle and identifying the currently unknown calls well enough to document the ordering without over-naming uncertain helpers.”

    Action/result: Read existing labels and call references around the top-level loop.

  385. Reported: “A useful correction fell out of the scheduler trace: the pre-motion mode dispatcher is at image 0x0644, not 0x0844, and its rectangle helper is 0x06d9, not 0x08d9. The earlier docs had those labels shifted; I’m going to correct the symbolic map and prose before building on them.”

    Action/result: Located all current references to the shifted labels.

  386. Reported: “The scheduler correction also gives us an easy next promotion target: some resource/display opcodes are still source-backed but can be observed visually. After I patch the scheduler labels, I’ll add narrow probes for view discard and picture overlay/priority display where possible.”

    Action/result: Added code.engine.main_cycle and corrected motion helper labels in docs/src/symbolic_labels.md.

  387. Reported: “The symbolic map now has the top-level code.engine.main_cycle label and corrected motion helper addresses. I’m fixing the object pipeline prose so the scheduler order matches the actual top-level call sites.”

    Action/result: Updated per-cycle movement prose in the graphics/object pipeline chapter.

  388. Reported: “The movement chapter now distinguishes the pre-logic motion-mode pass from the post-logic frame/group/movement pass. I’m scanning the evidence matrix for source-backed rows that can be promoted with small, deterministic visual probes.”

    Action/result: Listed source-backed opcode rows from the generated matrix.

  389. Reported: “The remaining source-backed rows are mostly UI/save/sound, but a few are still small and visual. The rectangle-boundary opcodes 0x5a/0x5b already have movement semantics in the harness, so I’m checking whether they can be promoted from existing QEMU batches before writing new fixtures.”

    Action/result: Confirmed existing movement cases exercise 0x5a; 0x5b still needed a focused case.

  390. Reported: “The existing rectangle movement batch already exercises 0x5a because it configures the crossing bounds. 0x5b is not isolated yet, so I’m adding one movement case that sets the bounds and then clears them; the object should reach the target instead of stopping at the rectangle edge.”

    Action/result: Located fixture helper and movement harness extension points.

  391. Reported: “I need a tiny helper for action 0x5b in the fixture layer, then I can add the movement case without special-casing the generated logic. This stays inside the existing object movement harness.”

    Action/result: Added clear_rect_bounds_action().

  392. Reported: “I’m making the 0x5b support as a simple bytecode helper, plus one boolean on the movement case. Then the case can share the same comparison and snapshot machinery as the existing rectangle-boundary probes.”

    Action/result: Added move_rect_boundary_clear_bounds_reaches_target.

  393. Reported: “The new 0x5b movement case is in. I’m running focused tests, then I’ll run the one-case QEMU batch for the clear-bounds behavior.”

    Action/result: Focused fixture/movement tests passed; first QEMU attempt failed under the sandbox VNC bind restriction.

  394. Reported: “The focused tests passed. The QEMU run hit the sandbox’s VNC bind restriction, so I’m rerunning the exact same one-case batch with the required elevated permission.”

    Action/result: Elevated QEMU batch rect_bounds_clear_001 matched with 1 match, 0 mismatches, and 0 errors.

  395. Reported: “The 0x5b QEMU probe matched: after 0x5a sets rectangle bounds, 0x5b clears them and the object reaches the target. I’m promoting 0x5a and 0x5b in the evidence matrix now: 0x5a is covered by the existing rectangle-boundary batch, and 0x5b by this new clear-bounds batch.”

    Action/result: Promoted 0x5a and 0x5b in tools/logic_opcode_evidence.py.

  396. Reported: “The evidence generator is updated. I’m adding the fixture helper test coverage so the new 0x5b bytecode helper is protected like the other generated opcodes.”

    Action/result: Located the relevant fixture and movement registry tests.

  397. Reported: “I found the helper tests and the movement case registry test. I’m adding one assertion for the 0x5b bytecode and one assertion that the new movement case is registered.”

    Action/result: Updated tests/test_qemu_fixture.py and tests/test_object_movement_probe.py.

  398. Reported: “The tests now cover the 0x5b helper and case registration. I’m regenerating the opcode evidence matrix and running the focused fixture/movement tests once more.”

    Action/result: Regenerated the evidence matrix; focused tests passed 48 tests.

  399. Reported: “The focused tests passed and the evidence matrix regenerated. I’m doing the documentation pass now: first the opcode/object chapters, then compatibility/current-status, then the chronological clean-room log with the exact commands and corrections.”

    Action/result: Began documentation updates.

  400. Reported: “A small checkpoint: steps 1 through 3 are now done in code and QEMU evidence. I’m currently on step 4, turning the scheduler/order findings into spec prose that a future implementation can follow.”

    Action/result: Marked the first three plan items complete.

  401. Reported: “The bytecode chapter text has slightly different surrounding lines, so I’m applying this as smaller patches: one new cycle-timing section, one replacement for the 0x2000 QEMU paragraph, and one table-row update for 0x5a/0x5b.”

    Action/result: Updated docs/src/logic_bytecode.md.

  402. Reported: “The bytecode chapter now has the top-level timing model, the expanded 0x2000 behavior, and QEMU-backed 0x5a/0x5b rows. I’m aligning the object pipeline chapter’s 0x2000 paragraph with the new four-case batch.”

    Action/result: Updated docs/src/graphics_object_pipeline.md.

  403. Reported: “Next I’m adding replay commands to the compatibility chapter: the expanded 0x2000 batch and the 0x5b clear-bounds movement batch. That keeps the QEMU evidence directly reproducible.”

    Action/result: Updated docs/src/compatibility_testing.md.

  404. Reported: “The compatibility chapter has the new replay commands. I’m updating the handoff/status page next so future sessions see these as completed findings, not just raw test reports.”

    Action/result: Updated docs/src/current_status.md.

  405. Reported: “The status page now reflects the completed scheduler and rectangle-boundary work. I’m adding the clean-room chronology next, including the correction that the 0x067a mode dispatcher is reached from 0x0644, not 0x0563.”

    Action/result: Corrected an older clean-room chronology paragraph.

  406. Reported: “The historical correction is in place. I’m appending a new chronology section with the exact commands and results from this pass.”

    Action/result: Added the expanded direction/scheduler/rectangle chronology section.

  407. Reported: “The clean-room notes now have the new command trail and the corrected scheduler addresses. I’m adding the remaining-family survey so the ‘what next’ trail is explicit for UI/save/sound/text instead of vague.”

    Action/result: Added the remaining source-backed family survey to current status.

  408. Reported: “That completes the survey step in the handoff doc. I’m marking the last two plan items complete, then I’ll update the progress log and run the full validation suite.”

    Action/result: Marked all five requested steps complete in the task plan.

  409. Reported: “The progress log is caught up. I’m running the full validation suite now: all Python tests, evidence check, mdBook build, and whitespace checking.”

    Action/result: python3 -B -m unittest discover -s tests passed 97 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check passed.

  410. Reported: “The full validation suite passed: 97 tests, evidence check, mdBook build, and whitespace check. I’m doing a final stale-address scan for the corrected scheduler labels, then I’ll record the validation result.”

    Action/result: The stale-address scan found only deliberate historical correction entries and the intermediate object_bit_2000_003 batch recorded in the chronology.

  411. Reported: “I’m picking up from the resource-lifecycle probe mismatch. The useful clue from the disassembly is that overlay_picture_var appears to require the picture to already be loaded/cached, so I’m going to correct the synthetic bytecode around that rather than treating the black-box result as mysterious.”

    Action/result: Re-read current probe and test changes around resource lifecycle fixtures.

  412. Reported: “The failure now lines up with the code path: 0x1c is not a load-and-overlay operation, it’s an overlay of an already resident picture. I’m adjusting the probe to exercise that exact precondition, and I’ll add a discard-picture lifecycle case while we’re in this neighborhood.”

    Action/result: Planned the 0x18 + 0x1c fixture correction and a 0x1b discard/reload case.

  413. Reported: “I’m also checking the shared QEMU snapshot harness before adding input/text probes. If we can represent post-launch keystrokes as data on each fixture, the same runner can handle text prompts and menu/input cases without a separate one-off script.”

    Action/result: Inspected tools/qemu_snapshot.py and related docs.

  414. Reported: “There’s already a clean place to put post-launch input: SnapshotFixtureCase can grow optional key text, and existing callers stay unchanged. That gives us the scaffolding for prompt/menu/save probes even before every UI path has a pixel-accurate comparator.”

    Action/result: Chose a backward-compatible post_launch_keys / post_launch_wait fixture extension.

  415. Reported: “The text/window work is going to be staged honestly: I can add the reusable capture/input plumbing now, but pixel-accurate text rendering is a separate model from the 160x168 graphics renderer. I’ll document it as capture/scaffolding plus source assessment, not pretend a coarse screenshot proves the UI semantics.”

    Action/result: Scoped UI work to deterministic input plumbing plus narrow visible-output probes.

  416. Reported: “I’ve got the concrete additions now: resource lifecycle cases, text/input cases using delayed monitor keystrokes, and menu/sound dispatch-smoke cases. Next I’m making the fixture schema carry that post-launch input through to QEMU.”

    Action/result: Began code edits in tools/qemu_snapshot.py and tools/logic_interpreter_probe.py.

  417. Reported: “The QEMU runner can now type fixture-specific input after launch. I’m threading those fields into the logic probe cases and adding the new bytecode fixtures around the source-backed families.”

    Action/result: Added post-launch input fields and logic-probe fixture cases.

  418. Reported: “I’m keeping these probes visible-output driven where possible: they don’t just run an opcode and hope; they make the original interpreter proceed to a known view draw only if the opcode path returns and the expected state was produced.”

    Action/result: Added message, numeric input, menu, sound, and resource lifecycle cases that end in known draw comparisons.

  419. Reported: “One little plumbing issue surfaced: _draw_if_case did not yet accept input fields, so I’m widening that helper too. This keeps the input cases as normal logic-probe fixtures instead of a special path.”

    Action/result: Extended _draw_if_case to pass input settings through.

  420. Reported: “The probe definitions are in place. I’m adding regression tests for the new case IDs and for the new snapshot input fields so this doesn’t silently break later when we add more UI fixtures.”

    Action/result: Updated logic-probe and QEMU snapshot unit tests.

  421. Reported: “The static tests are next. If these pass, I’ll run the new QEMU batches in smaller groups so a bad UI timing assumption doesn’t obscure the resource-lifecycle results.”

    Action/result: Ran focused unit tests and the opcode evidence check; they passed.

  422. Reported: “The focused Python tests passed. I’m running the resource lifecycle batch first: logic-var load, picture overlay with the now-correct load precondition, discard/reload picture, and view discard/reload variants.”

    Action/result: Started QEMU batch resource_lifecycle_002.

  423. Reported: “The lifecycle batch is in QEMU now. It has built the snapshot disk and is stepping through the five fixtures from the saved DOS prompt.”

    Action/result: Awaited the QEMU lifecycle batch.

  424. Reported: “The corrected overlay precondition still mismatched, so I’m not going to paper over it. I’m reading the report and then I’ll go back to the picture-handler code path to see whether the expected composition model is wrong, or whether another action such as show/finalize is needed after overlay.”

    Action/result: Read resource_lifecycle_002; only overlay pixels were missing.

  425. Reported: “The mismatch is narrower now: the view sprite is being drawn, but the overlaid picture pixels are not visible in the display capture. That fits the handler split: 0x1c mutates the logical picture buffers, while 0x1a is the full-screen display/finalization path, so I’m adding that explicit show step after the overlay.”

    Action/result: Added 0x1a after 0x1c in overlay fixtures.

  426. Reported: “I’ve corrected the overlay fixture to include the display finalization path. I’m rerunning the local tests for the probe shape, then the lifecycle batch again.”

    Action/result: Focused unit tests passed.

  427. Reported: “The local shape tests are still green. I’m rerunning the five-case lifecycle QEMU batch with the explicit 0x1a finalization after overlay.”

    Action/result: Started QEMU batch resource_lifecycle_003.

  428. Reported: “QEMU is running the lifecycle batch again now. If this passes, I’ll move on to the text/input/menu/sound group as separate batches because those touch blocking UI helpers.”

    Action/result: Awaited lifecycle batch completion.

  429. Reported: “The lifecycle batch passed all five cases. That validates the exact overlay nuance: 0x1c composes into the logical picture state, and 0x1a is needed to push that composition to the visible screen. Next I’m running the text/message and typed-input fixtures.”

    Action/result: resource_lifecycle_003 matched 5/5 and text/input QEMU batch was started.

  430. Reported: “The text/input batch is running. These cases use the new post-launch keystroke path: Enter to dismiss message windows, then typed look and 42 for prompt handlers.”

    Action/result: Awaited text_input_001.

  431. Reported: “The three message-window cases passed; the typed string prompt did not reach the expected final draw. I’m inspecting the capture/report before deciding whether the typed input timing is wrong or the assumed parsed word id/condition is wrong.”

    Action/result: Inspected text_input_001; 0x65, 0x66, and 0x97 matched, while the 0x73 string prompt did not.

  432. Reported: “The mismatch region is exactly where the final sprite should be, so the script probably stayed on the prompt path or the condition was false. I’m going to inspect the screenshot visually and then decide whether to relax this to a prompt-capture case or fix the input timing/terminator.”

    Action/result: Converted and viewed the prompt capture.

  433. Reported: “The screenshot is helpful: the prompt displayed and look was typed, but it did not accept/advance before capture. I’m going to give prompt-style input an extra Enter; message windows accepted a single Enter, but this editor helper appears to need a less brittle dismissal sequence under QEMU monitor timing.”

    Action/result: Retried the 0x73 prompt fixture with an extra Enter.

  434. Reported: “The extra Enter still didn’t advance the string prompt. I’m checking whether the second Enter is being ignored while the typed buffer remains active, which would mean this handler needs a different completion key or a more direct event injection strategy.”

    Action/result: Confirmed the string prompt remained active; then ran the numeric prompt case separately.

  435. Reported: “The numeric prompt case passed with the new key-input path, so the input scaffolding is real. The string-editor prompt still stays active after typed text; I’m removing that from the default compatibility suite for now and documenting it as an observed harness limitation/open item rather than leaving a known-failing default case.”

    Action/result: Removed the failing 0x73 case from default probes and kept 0x76 as QEMU-validated input evidence.

  436. Reported: “The default suite now contains only input cases we can make deterministic. I’m rerunning the text/input batch with the three message paths plus numeric prompt.”

    Action/result: Started QEMU batch text_input_002.

  437. Reported: “The trimmed text/input batch is running now. This should give us stable QEMU evidence for message display variants and one typed-input path without overclaiming the string editor behavior.”

    Action/result: Awaited text_input_002.

  438. Reported: “The text/input batch passed all four cases. I’m moving to the menu/list and sound dispatch-smoke probes next; these are deliberately narrower, proving handler execution and return-to-bytecode rather than full UI/audio semantics.”

    Action/result: text_input_002 matched 4/4 and menu/sound smoke batch was started.

  439. Reported: “QEMU is running the menu/sound smoke batch now. If any of these fail, I’ll treat it as a missing precondition and go back to the handler disassembly rather than weakening the result.”

    Action/result: Awaited menu_sound_001.

  440. Reported: “The menu/sound smoke batch passed. I’m updating the generated evidence matrix inputs next so the docs distinguish true pixel/value validation from dispatch-smoke coverage for menu and sound handlers.”

    Action/result: Updated tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  441. Reported: “The evidence generator now knows about the new resource, text/input, menu, and sound probes. I’m regenerating the mdBook evidence chapter from that single source.”

    Action/result: Regenerated the opcode evidence chapter.

  442. Reported: “I’m turning the QEMU results into spec prose now: one pass in the bytecode reference for behavior, one in compatibility testing for replay commands, one in current status for handoff, and one chronological log with the failed string-prompt attempt included.”

    Action/result: Updated bytecode, compatibility, current-status, and clean-room chronology docs.

  443. Reported: “A small but important wording point for the spec: I’m documenting the overlay as a two-stage operation, because the failed capture proved that logical composition alone is not the same as a visible full-screen refresh.”

    Action/result: Added the two-stage 0x1c plus 0x1a overlay note.

  444. Reported: “The handoff docs now reflect which families moved from ‘source-backed’ into QEMU-backed or smoke-tested. I’m appending the chronological evidence trail with the exact commands and the failed 0x73 attempt, because that negative result matters for future work.”

    Action/result: Appended the clean-room chronology section for this pass.

  445. Reported: “The chronological notes are updated. I’m catching up the progress log now with the user-facing updates from this run so the conversational history remains traceable.”

    Action/result: Updated this progress log.

  446. Reported: “I’ll take the whole chain: start source-first at 0x0da9, then adjust the input harness only where the disassembly says it should help, then use QEMU as validation rather than exploration.”

    Action/result: Began the string editor and event-path pass.

  447. Reported: “I’m gathering the local disassembly context first: existing notes, the 0x73 handler, the editor helper, and the event wait path.”

    Action/result: Searched docs/tools for prior 0x73 and 0x0da9 evidence.

  448. Reported: “The existing docs already have the high-level 0x73 shape, but not the completion key details. I’m reading raw disassembly around the helper now.”

    Action/result: Confirmed the existing source-backed handler summary and prepared focused executable slices.

  449. Reported: “The full disassembly file appears to be stale around this helper, so I’m making fresh focused slices from the decrypted executable with explicit image origins.”

    Action/result: Generated and disassembled slices around image 0x0c20 and 0x4420.

  450. Reported: “The editor helper is now clear enough to read structurally: clamp length, copy current string to a local buffer, wait for events, then dispatch through a key table. I’m dumping the table bytes so we don’t infer key names from control flow alone.”

    Action/result: Dumped key dispatch bytes at file offset 0x1060.

  451. Reported: “The dispatch table is the important bit: Enter maps to the accept/copy-back path, Escape returns without copy, Backspace edits, and Ctrl-C/Ctrl-X clear. So QEMU should be able to complete 0x73; the harness probably isn’t delivering the right event shape or timing.”

    Action/result: Identified 0x0d as the accept key for code.input.edit_string.

  452. Reported: “The disassembly says Enter really is a completion key, so I’m going to separate two questions in the probes: did the prompt return at all, and did it copy the edited string into the slot?”

    Action/result: Planned separate return-only and string-slot equality fixtures for 0x73.

  453. Reported: “I’m adding a per-fixture key delay now; text prompts are one of the few places where monitor keystroke timing can masquerade as interpreter behavior.”

    Action/result: Added post_launch_key_delay to the QEMU fixture model.

  454. Reported: “The input delay plumbing is in. Next I’m making the 0x73 cases explicit and keeping them out of the broad default batch until they pass on their own.”

    Action/result: Added string prompt fixtures and kept them targeted.

  455. Reported: “I’m also adding low-risk system/diagnostic probes while I’m in this file, because several remaining opcodes should only need an Enter acknowledgement plus a validation draw.”

    Action/result: Added formatted text, input-line, text-window, and diagnostics fixture cases.

  456. Reported: “The case registry tests need to learn about the new targeted cases, then I’ll do a focused Python test pass before waking QEMU.”

    Action/result: Updated unit tests for the new case registry and QEMU fixture defaults.

  457. Reported: “The local code is ready for a sanity pass. I’m running focused Python tests for the logic probe definitions and snapshot runner.”

    Action/result: Ran focused unit tests for tools/logic_interpreter_probe.py and tools/qemu_snapshot.py.

  458. Reported: “Focused tests passed. I’m running two 0x73 probes first: return-after-Enter and stores-typed-word.”

    Action/result: Started QEMU batch prompt_string_001.

  459. Reported: “QEMU is running string prompt checks. This is the narrowest place to debug the key path before adding the larger text UI batch.”

    Action/result: Awaited the first string-prompt QEMU run.

  460. Reported: “The return-only 0x73 case still did not advance to the draw after typed look plus Enter, despite the source saying Enter should accept. I’m going to inspect the capture and then try sending the return key as a named key event rather than as a typed newline character.”

    Action/result: Treated the mismatch as a harness/event-shape question.

  461. Reported: “The capture is the same editor-active state, so the next probe change is to extend the key sender rather than change interpreter expectations.”

    Action/result: Added support for named post-launch QEMU key events.

  462. Reported: “I’m also separating type text from press named key in the fixture model, with a short wait between them. That gives the DOS keyboard path a cleaner event sequence.”

    Action/result: Added post_launch_after_text_wait and post_launch_key_names.

  463. Reported: “The 0x73 fixtures now type look, pause, then send a named ret key. I’m rerunning the focused unit tests before trying QEMU again.”

    Action/result: Updated the string prompt fixtures for named Enter.

  464. Reported: “The local schema tests passed with the named-key fields. I’m rerunning 0x73 now.”

    Action/result: Started QEMU batch prompt_string_002.

  465. Reported: “QEMU revised string prompt batch is running. If this still stalls, the next source check will be the event normalizer around 0x45d7 and 0x4634.”

    Action/result: Awaited prompt_string_002.

  466. Reported: “Aha, the capture is more subtle: the typed prompt text is still on-screen, but the validation draw may be happening underneath it. I’m adding a full picture refresh after the prompt before comparing pixels.”

    Action/result: Diagnosed the mismatch as text overlay persistence rather than editor non-completion.

  467. Reported: “I’ve inserted the refresh after 0x73. That should make the fixture prove string semantics instead of comparing against leftover text pixels.”

    Action/result: Added 0x1a before the validation draw in the 0x73 probes.

  468. Reported: “The refreshed string-prompt batch is running now.”

    Action/result: Started QEMU batch prompt_string_003.

  469. Reported: “Nice, 0x73 is now validated: both the return-only case and the typed-word storage case matched. The earlier failure was a display cleanup artifact, not an editor completion failure.”

    Action/result: prompt_string_003 matched 2/2.

  470. Reported: “I’m batching UI cases by risk: formatted messages and simple input-line/window state first, then diagnostics/system actions after those pass.”

    Action/result: Started the text UI QEMU probe sequence.

  471. Reported: “QEMU is running the text UI group now.”

    Action/result: Started QEMU batch text_ui_001.

  472. Reported: “The first formatted-message case mismatched, so I’m reading the capture pattern before changing anything. Given the 0x73 lesson, text overlay is the prime suspect.”

    Action/result: Investigated the first formatted-message mismatch.

  473. Reported: “The mismatch is exactly at the formatted message text location. I’m applying the same validation split: acknowledge the message, refresh the picture, then draw the object for comparison.”

    Action/result: Added refresh-before-validation to formatted message cases.

  474. Reported: “The formatted-message probes now separate text display from graphics validation. I’m rerunning the six-case text UI batch.”

    Action/result: Started QEMU batch text_ui_002.

  475. Reported: “QEMU revised text UI batch is running.”

    Action/result: Awaited text_ui_002.

  476. Reported: “Four of six text UI cases passed. The rectangle-clear probe is different: it deliberately changes top text rows, so I need to make the fixture prove it returns before drawing, not preserve the cleared rows.”

    Action/result: Identified the text-rectangle clear comparison problem.

  477. Reported: “The rectangle-clear case returned but intentionally cleared screen rows that the expected image assumed were normal. I’m inserting a refresh before the validation draw there too.”

    Action/result: Added refresh-before-validation to text rectangle clear.

  478. Reported: “The text rectangle probe is corrected. I’m running just the two remaining text-window cases first.”

    Action/result: Started QEMU batch text_clear_001.

  479. Reported: “The remaining text-clear/window cases passed. Now I’m rerunning the full six-case text UI batch to keep one clean evidence artifact.”

    Action/result: text_clear_001 matched 2/2 and text_ui_003 was started.

  480. Reported: “QEMU clean combined text UI batch is running.”

    Action/result: Awaited text_ui_003.

  481. Reported: “The combined text UI batch passed. I’m moving on to the diagnostic/system message group.”

    Action/result: text_ui_003 matched 6/6 and diagnostics were started.

  482. Reported: “Diagnostics batch running now: pause, heap/status, interpreter version, plus low-risk global action dispatch smoke.”

    Action/result: Started QEMU batch diagnostics_system_001.

  483. Reported: “All QEMU batches passed. I’m updating the generated opcode evidence matrix so the docs reflect the new validated and dispatch-smoke rows.”

    Action/result: diagnostics_system_001 matched 4/4 and evidence metadata was updated.

  484. Reported: “Generated evidence chapter refreshed. I’m doing the narrative docs now: bytecode semantics, compatibility replay commands, symbolic labels, current status, and the clean-room/progress logs.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md and began the documentation update pass.

  485. Reported: “I’ll proceed source-first: re-read the opcode handlers and shared text/input helpers from the executable, then only use QEMU where it gives us a clean confirmation test.”

    Action/result: Started the text/status configuration pass.

  486. Reported: “The prior docs already have decent summaries for this family, but I’m going back to the bytes instead of trusting the summaries.”

    Action/result: Created focused executable slices around image offsets 0x3400, 0x7600, 0x4c00, and 0x0d60.

  487. Reported: “The slices are ready. I’m reading them now with explicit origins so the addresses line up with the existing symbolic map and later cross-version comparisons.”

    Action/result: Disassembled the focused slices with ndisasm.

  488. Reported: “The static read confirms the family is more about global text/display state than hidden game semantics: 0x70/0x71 are just status-line flag plus redraw/clear; 0x6f stores row/config globals; 0x79 appends a 4-byte key mapping slot.”

    Action/result: Decided to add narrow QEMU dispatch-smoke tests while keeping richer key-map semantics source-backed.

  489. Reported: “Before editing, I’m checking the probe helper shapes so the new cases fit the existing harness instead of inventing a second style.”

    Action/result: Reviewed tools/logic_interpreter_probe.py, evidence metadata, and case registry tests.

  490. Reported: “I’m adding small, explicit smoke fixtures now: one for text-attribute mode setup/teardown, one for status line show/hide, one for prompt/config globals, one for key-map table insertion, and one for screen-shake return.”

    Action/result: Added five targeted QEMU cases.

  491. Reported: “The new cases are in the registry. I’m updating the case-list tests and the evidence generator so the metadata matches the harness.”

    Action/result: Updated tests/test_logic_interpreter_probe.py and tools/logic_opcode_evidence.py.

  492. Reported: “The metadata is patched. I’m running the focused Python tests before QEMU so any mistake in fixture definitions fails cheaply.”

    Action/result: Focused Python tests passed.

  493. Reported: “Focused tests passed. I’m going to run just the five new QEMU cases as a tight batch; that keeps this as confirmation evidence, not fishing around.”

    Action/result: Started QEMU batch text_status_001.

  494. Reported: “QEMU is running the five-case status/input batch from a snapshot now. If one of these fails, I’ll treat it as a missing precondition and go back to the static path rather than broadening the test blindly.”

    Action/result: Awaited text_status_001.

  495. Reported: “The first two new cases matched: text-attribute setup/teardown and one-count screen shake both returned cleanly. The prompt/config case mismatched, so I’m inspecting that artifact before changing anything.”

    Action/result: Inspected text_status_001 JSON and the mismatching PPM.

  496. Reported: “The mismatch is informative rather than mysterious: using 0x6f with row/config byte 1 changes display-position state enough that the validation sprite appears at a different vertical offset than the local renderer expects.”

    Action/result: Changed the 0x6f smoke fixture to use first operand 0.

  497. Reported: “The fixture correction is deliberately narrow. I’m rerunning the Python sanity check, then I’ll rerun the same five-case QEMU batch so we have one clean artifact.”

    Action/result: Focused Python tests passed after the fixture correction.

  498. Reported: “Focused tests are still green. The revised QEMU batch is starting now with the neutral 0x6f row/config operand.”

    Action/result: Started QEMU batch text_status_002.

  499. Reported: “QEMU is running the corrected batch. The earlier failed run will go into the clean-room notes as a useful constraint on 0x6f: operand 0 affects display offset state, so a later behavior probe can target that directly.”

    Action/result: Awaited text_status_002.

  500. Reported: “Four of five have matched in the corrected batch; only the key-event mapping smoke case is still running/awaiting capture.”

    Action/result: Awaited the final key-event mapping case.

  501. Reported: “The corrected batch matched 5/5. I’m regenerating the opcode evidence chapter next, then I’ll write down the static source findings plus the QEMU confirmation and the one failed 0x6f offset probe.”

    Action/result: text_status_002 matched 5/5 and docs/src/logic_opcode_evidence.md was regenerated.

  502. Reported: “I’m updating the symbolic map first. These labels give us stable names for the status redraw, prompt marker, text attribute, input-line configuration, and key-map insertion helpers instead of tying future notes to raw offsets.”

    Action/result: Updated docs/src/symbolic_labels.md.

  503. Reported: “Next I’m folding the new source/QEMU distinction into the bytecode chapter: the handlers are now smoke-tested, but some deeper behavior, especially key-map event conversion and 0x6f display offset effects, remains a separate target.”

    Action/result: Updated docs/src/logic_bytecode.md.

  504. Reported: “I’m adding the replay command to the compatibility chapter now, including the failed text_status_001 lesson so future probes don’t accidentally rediscover that offset issue.”

    Action/result: Updated docs/src/compatibility_testing.md.

  505. Reported: “I’m updating the handoff/status page so ‘remaining source-backed text opcodes’ doesn’t keep pointing at work that now has at least dispatch-smoke coverage.”

    Action/result: Updated docs/src/current_status.md.

  506. Reported: “The main spec pages are updated. I’m appending the clean-room evidence trail with the exact disassembly slices, the QEMU mismatch, the corrected run, and what each result proves.”

    Action/result: Updated docs/src/clean_room_executable_notes.md.

  507. Reported: “I’ll turn the 0x6f observation into a real behavior case now: script draws the object at baseline 80, but the expected capture baseline is 88 when 0x6f operand 0 is 1.”

    Action/result: Began behavior-level probes for 0x6f, 0x79, and 0x74.

  508. Reported: “I’m going to quantify the offset rather than eyeballing it. The quick check is: compare the operand-1 capture against the same expected sprite at several baselines and see which one minimizes mismatches.”

    Action/result: Compared the recreated operand-1 QEMU capture against expected baselines 70..90; baseline 88 matched exactly.

  509. Reported: “That resolved the ambiguity: the operand-1 capture matches exactly if the expected sprite baseline is moved from 80 to 88.”

    Action/result: Confirmed 0x6f first operand 1 produces an eight-logical-row visible offset in the observed mode.

  510. Reported: “Source check found the right path for 0x79: condition 0x0d does not use the mapping table, but the top-level input helper does.”

    Action/result: Re-read condition 0x0d and helper 0x4566; identified condition 0x0c as the observation point for mapped type-3 events.

  511. Reported: “I’m adding two behavior-level cases now: one where 0x6f(1,...) must move the visible baseline from 80 to 88, and one where 0x79 maps x to status byte 7 and a later cycle draws only after condition 0x0c 7 sees it.”

    Action/result: Added input_line_config_operand1_offsets_display_by_8 and mapped_key_sets_status_byte.

  512. Reported: “The behavior cases are added. I’m updating tests and evidence metadata so 0x6f and 0x79 can move from smoke evidence to behavior evidence if the batch matches.”

    Action/result: Updated the case registry test and opcode evidence generator.

  513. Reported: “The focused test caught a harness-shape mistake: _draw_if_case doesn’t take init_once_flag. I’m switching that mapped-key case to the lower-level _custom_case.”

    Action/result: Reworked the mapped-key case as one-time setup plus per-cycle conditional draw.

  514. Reported: “Focused tests are green. I’m running the two behavior confirmations now: 0x6f offset and 0x79 mapped key to status byte.”

    Action/result: Started QEMU batch input_key_behaviour_001.

  515. Reported: “The 0x6f behavior case matched: operand 1 produced the expected 8-row visible offset. The mapped-key case is still running.”

    Action/result: First case of input_key_behaviour_001 matched.

  516. Reported: “Both behavior probes matched. I’m moving to 0x74 now: first I’ll inspect the table bytes around 0x0c8f, then decide whether a fixture-local AGIDATA.OVL patch is a safe way to create a non-empty table entry for dynamic confirmation.”

    Action/result: input_key_behaviour_001 matched 2/2 and the 0x74 table area was inspected.

  517. Reported: “0x74 has a convenient zero-filled pocket right after the pointer table. I’m going to make the dynamic test explicit and synthetic: patch only the generated fixture’s AGIDATA.OVL so table entry 0 points to a local look\\0 string.”

    Action/result: Added fixture-local AGIDATA.OVL patch support and a synthetic 0x74 behavior case.

  518. Reported: “The synthetic AGIDATA patch support is in. I need one small follow-up: thread that optional patch list through _draw_if_case, since the new 0x74 case uses that convenience wrapper.”

    Action/result: Passed agidata_patches through _draw_if_case.

  519. Reported: “The probe and evidence metadata are ready. I’m running focused tests again before the QEMU batch that combines 0x6f, 0x79, and synthetic 0x74.”

    Action/result: Focused Python tests passed.

  520. Reported: “Focused tests passed. I’m running the three targeted QEMU cases now; the 0x74 one uses only a fixture-local AGIDATA.OVL patch, not a change to the SQ2 source files.”

    Action/result: Started QEMU batch input_key_string_behaviour_001.

  521. Reported: “QEMU is running the three-case behavior batch. This should give us one clean artifact covering the offset, mapped-key event path, and the patched pointer-table copy.”

    Action/result: Awaited input_key_string_behaviour_001.

  522. Reported: “The three targeted confirmations all matched. I’ll regenerate the evidence matrix and update the docs for these before moving on to the inventory/menu source pass, so the text/input family has a clean stopping point.”

    Action/result: input_key_string_behaviour_001 matched 3/3 and the opcode evidence chapter was regenerated.

  523. Reported: “The evidence chapter is regenerated. I’m updating the narrative docs with the new distinction: 0x6f, 0x79, 0x74, and condition 0x0c now have behavior evidence, with 0x74 clearly marked as a synthetic table-entry fixture.”

    Action/result: Updated bytecode, compatibility, and current-status docs.

  524. Reported: “The user-facing docs now reflect the behavior batch. I’m appending the clean-room evidence trail with the exact commands, including the synthetic AGIDATA patch rationale for 0x74.”

    Action/result: Updated docs/src/clean_room_executable_notes.md.

  525. Reported: “I’m picking up from the source-first inventory/menu pass. The text/key/string-table probes are in place; now I’m going to turn the inventory disassembly notes into a couple of focused behavior checks so the docs don’t just say ‘looks like,’ they have original-engine evidence behind them.”

    Action/result: Re-read local harness, QEMU input helpers, test registry, symbolic labels, and the existing 0x7c documentation.

  526. Reported: “The local state already includes the static inventory description, and the symbolic label file has the core inventory table label. I’m checking the harness details before editing so the new probes use the same QEMU input path as the earlier text/editor cases.”

    Action/result: Confirmed post_launch_keys and named-key support in tools/qemu_snapshot.py.

  527. Reported: “The source-backed model for 0x7c is tight enough to probe: flag 13 selects interactive mode, carried entries are the ones with marker 0xff, Enter stores the selected index in variable 0x22, and Escape stores 0xff. I’m adding exactly those cases now.”

    Action/result: Added initial inventory selection probes, later corrected the variable interpretation from bytecode variable 0x22 to absolute byte DS:0x0022.

  528. Reported: “The three new inventory fixtures are deliberately small: one Enter path, one Escape path, and one noninteractive acknowledgement path. They all draw only after 0x7c returns, so a match tells us the handler both accepted the key and resumed the bytecode stream.”

    Action/result: Added probe registry tests for the three inventory cases.

  529. Reported: “The harness-level tests are happy. Next I’m running the original engine batch; this is the useful part for compatibility because it checks the disassembly-derived interpretation against DOS/QEMU captures.”

    Action/result: Focused Python tests passed; started QEMU batch inventory_selection_001.

  530. Reported: “QEMU is in the snapshot batch now: it has prebuilt the three DOS fixture directories and is replaying them from one DOS prompt snapshot. If the Escape monitor key name is wrong, this run should make that obvious from the first mismatch.”

    Action/result: Initial QEMU batch mismatched on the Enter case.

  531. Reported: “The first inventory probe did not match, so I’m not going to paper over it. I’m going back to the generated fixture and capture to see whether the key timing, carried-entry setup, or my conditional draw expectation is the wrong piece.”

    Action/result: Inspected the JSON report and generated capture; the handler returned but the validation condition was false.

  532. Reported: “The capture is not an inventory screen; it is essentially a text-mode/DOS-looking bottom band, which means the probe did not make it through the intended visual path before the screenshot. I’m checking whether the fixture launched, whether the carried-object setup exposed a blocking text window, and whether the baseline expectation needs to account for text-mode cleanup.”

    Action/result: Re-read the inventory disassembly and identified the absolute byte store at DS:0x0022.

  533. Reported: “Found the issue, and it’s a good catch from the disassembly: the inventory handler writes absolute DS:0x0022, while byte variables are based at DS:0x0009. So the script-visible variable is 0x19, not 0x22. I’m correcting the probe and docs language rather than treating the failed QEMU run as noise.”

    Action/result: Renamed and corrected the inventory Enter/Escape probes to check bytecode variable 0x19.

  534. Reported: “The corrected bytecode now checks variable 0x19, matching the absolute store at 0x0022. I’m rerunning the same original-engine batch with the corrected case IDs.”

    Action/result: Focused tests passed; started the corrected QEMU batch.

  535. Reported: “The batch is running again from a fresh snapshot disk. This should also tell us whether QEMU’s monitor esc key name is accepted by the DOS event loop for this interpreter path.”

    Action/result: Corrected inventory_selection_001 matched 3/3, including the named esc key path.

  536. Reported: “Good, all three inventory probes match now. The failed run was useful: it exposed that the handler’s absolute byte store maps to script variable 0x19, which is exactly the kind of cross-address detail we want nailed down before generalizing.”

    Action/result: Prepared to promote 0x7c in the opcode evidence matrix.

  537. Reported: “I’m promoting 0x7c in the evidence generator from source-only/smoke status to behavior-validated status now that the Enter, Escape, and acknowledgement paths have QEMU matches.”

    Action/result: Updated tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  538. Reported: “I’m updating the written trail now: the bytecode chapter needs the corrected variable mapping, the compatibility chapter needs the replay command, and the clean-room notes need both the failed and successful runs because that failure changed the spec.”

    Action/result: Updated the 0x7c bytecode row.

  539. Reported: “The 0x7c table row now says ‘absolute DS:0x0022, exposed as variable 0x19,’ which is the key correction. I’m also adding stable symbolic names for the inventory/list and menu routines so later interpreter-version comparisons have anchors beyond raw addresses.”

    Action/result: Added inventory and menu labels to docs/src/symbolic_labels.md.

  540. Reported: “The symbolic labels now include code.inventory.*, code.menu.*, and the selection result byte. I’m recording the QEMU replay batch in the compatibility chapter next.”

    Action/result: Added the inventory_selection_001 replay command and result to docs/src/compatibility_testing.md.

  541. Reported: “The status and compatibility docs are updated. I’m appending the detailed evidence log now, including the initial mismatch because it documents the correction from ‘variable 0x22’ to ‘absolute 0x0022 / variable 0x19.’”

    Action/result: Added the inventory selection source/QEMU pass to docs/src/clean_room_executable_notes.md.

  542. Reported: “The documentation trail is caught up. I’m running the full verification set now: unit discovery, opcode evidence check, mdBook build, and whitespace diff check.”

    Action/result: Started full validation.

  543. Reported: “All verification passed: 99 unit tests, evidence check, mdBook build, and git diff --check. I’m doing one final diff/status pass so I can summarize exactly what changed without mixing generated build artifacts into the answer.”

    Action/result: Verified final status and diff summary.

  544. Reported: “I’ll work through the five families in order, source-first: menu interaction, view-resource display, system/dialogs, file-backed save/log behavior, then sound completion. I’ll keep QEMU probes narrow and only use them where the disassembly gives us a concrete side effect to validate.”

    Action/result: Started the five-family follow-up pass.

  545. Reported: “I’ve got the current open list. I’m going into the disassembly around the menu interaction, view-resource display, trace/system, file/log, and sound handlers before touching probes; there are a few places where an opcode’s visible result is indirect, so source context matters.”

    Action/result: Created initial source slices.

  546. Reported: “The slices are ready. I’m disassembling the target ranges now and looking for direct byte/flag side effects that can be observed by logic conditions, because those make much better compatibility tests than broad ‘screen changed’ assertions.”

    Action/result: Found the initial slices were misaligned for some targets.

  547. Reported: “One correction from the tooling pass: these image offsets need the executable-file header adjustment when slicing (file offset = image offset + 0x200). I caught that because the first 0x5ebf slice landed in DOS file wrappers instead of the documented view-display handler, so I’m regenerating the slices with the correct file offsets.”

    Action/result: Regenerated aligned slices using image offset plus 0x200.

  548. Reported: “Now the slices are aligned to the image addresses used in the docs. I’m re-disassembling the corrected ranges and pulling out the control-flow facts we can turn into fixtures.”

    Action/result: Re-disassembled menu, view-resource, save/restore, log, sound, trace, signature, and joystick ranges.

  549. Reported: “The source pass is giving us several good anchors: menu Enter enqueues a type-3 event with the item id via 0x44a9, 0x81/0xa2 share 0x5edb, 0x90 appends to logfile, 0x95/0x96 are observable through trace-window globals, and 0x63 clears its completion flag before starting sound. I’m checking how those internal events surface back to logic bytecode so the probes can assert state instead of just ‘the program didn’t hang.’”

    Action/result: Located event/status and helper paths for the planned probes.

  550. Reported: “The menu source shows the interaction routine itself cleanly, but I still need the caller path: 0xa1 only sets [0x1d22], and some top-level code must notice that and call code.menu.interact. I’m locating those references before writing the menu fixture.”

    Action/result: Searched references to [0x1d22].

  551. Reported: “The caller reference is around file offset 0x358d, which maps to image 0x338d. I’m reading that neighborhood; it should tell us how to trigger the menu loop from script-level bytecode.”

    Action/result: Confirmed the menu request word participates in the input/event path.

  552. Reported: “I have enough source detail to add focused cases now. The probes I’m adding are intentionally small: menu Enter should surface as condition 0x0c on the item id; view display and dialogs should return after acknowledgement/cancel; 0x90 should at least execute the DOS append path and return; and 0x63 should clear its completion flag operand as the source shows.”

    Action/result: Added initial QEMU probe cases for menu, view-resource, system/dialog, file/log, and sound.

  553. Reported: “The new cases are in the harness. I’m adding them to the registry test next so future edits don’t silently drop any of these coverage points.”

    Action/result: Updated tests/test_logic_interpreter_probe.py.

  554. Reported: “The registry test has the new cases. I’m running the focused Python tests before QEMU, because it’s much cheaper to catch bad bytecode construction here than after a DOS boot.”

    Action/result: Focused tests passed.

  555. Reported: “Focused tests pass. I’m running the probes in smaller QEMU batches by family, so if something mismatches we can tie it back to one source path instead of sorting through a mixed bag.”

    Action/result: Started menu_interaction_001.

  556. Reported: “The first menu attempt mismatched, which likely means either my trigger path is incomplete or Enter is arriving before the menu loop is actually waiting. I’m inspecting the capture/report before changing the fixture.”

    Action/result: The menu validation sprite was present, but menu/status text polluted the comparison.

  557. Reported: “This mismatch is just the menu/status text strip still visible at the top, not a missing validation sprite. That means the Enter path worked and set the item status byte; the fixture needs a picture refresh before the validation draw, just like the text-window probes.”

    Action/result: Added 0x1a before the menu validation draw.

  558. Reported: “I updated the menu validation draw to refresh the picture first. The underlying behavior was already present; this just prevents the top text strip from polluting the graphics comparison.”

    Action/result: Reran menu_interaction_001.

  559. Reported: “Menu Enter is now QEMU-validated: opening through 0xa1, pressing Enter, and observing condition 0x0c 7 all match. I’m running the view-resource pair next.”

    Action/result: menu_interaction_001 matched 1/1 and view_resource_display_001 started.

  560. Reported: “The view-resource batch is running. These cases are slightly heavier because 0x81/0xa2 load and temporarily render view resources before displaying their text-like payload.”

    Action/result: view_resource_display_001 matched 2/2.

  561. Reported: “The immediate and variable view-resource display paths both match. I’m moving to the system/dialog group now: signature check, restart/confirmation cancel, joystick no-device, guarded display toggle, and trace-window configuration.”

    Action/result: Started system_dialog_001.

  562. Reported: “The system/dialog batch is underway. The risky ones here are the two confirmation prompts; if Escape timing is off, I’ll adjust those from the capture/report rather than changing the source interpretation.”

    Action/result: Awaited system/dialog batch.

  563. Reported: “Still running; this batch has six snapshot restores plus a couple of blocking prompts. I’m waiting for the result rather than starting anything else that could contend for the QEMU/VNC slot.”

    Action/result: Continued waiting for QEMU.

  564. Reported: “By ‘QEMU-validated’ I mean: we ran a generated mini-game/fixture inside the original SQ2 interpreter under DOS in QEMU, drove the needed input, captured the original engine’s screen, and compared that capture against the expected result from our local model.”

    Action/result: Clarified evidence terminology for the user.

  565. Reported: “The trace-window mismatch is similar in shape: the action deliberately draws a trace window, so the screen no longer matches the plain sprite expectation. I’m making that fixture source-observable instead: enable the trace window, then run 0x95 a second time, which should consume one extra byte when [0x1d10] is nonzero.”

    Action/result: First system batch matched 5/6; trace drawing polluted the comparison.

  566. Reported: “The screenshot confirms the trace action is doing exactly what the source says: it draws a boxed trace area. I’m changing the probe to validate the more interesting source detail, the second-call byte-consumption behavior, and then refresh the picture before the comparison.”

    Action/result: Adjusted trace case, then found text-plane pixels still persisted.

  567. Reported: “Continuing. I’ve converted the trace test from ‘screen must stay plain’ to ‘exercise the second-call skip behavior, then clear the trace drawing before comparing,’ which better matches the disassembly.”

    Action/result: Reran focused tests and the system batch.

  568. Reported: “Harness tests are clean. I’m rerunning just the system/dialog batch with the corrected trace case.”

    Action/result: Started the corrected system run.

  569. Reported: “The corrected six-case system batch is running. If the trace case still mismatches, it will tell us that 0x1a doesn’t fully clear text-plane trace output, and I’ll move that case to a source-backed note instead of forcing a visual assertion.”

    Action/result: Trace still mismatched after enabled drawing.

  570. Reported: “The trace case still leaves text-plane pixels after the graphics refresh, so I’m splitting it out: the source notes will document its drawn-window and skip-byte behavior, while the QEMU-validated system batch will cover the five cases that compare cleanly. Next I’m running the file/log and sound cases.”

    Action/result: Started file_log_001.

  571. Reported: “The file/log batch is running. I expect the log append case to be clean; save/restore selector Escape is the part that may need key timing adjustment.”

    Action/result: file_log_001 matched 3/3.

  572. Reported: “File/log paths matched: append returned after touching DOS file I/O, and save/restore selectors both cancel cleanly with Escape. I’m running the sound-completion flag case now.”

    Action/result: Initial sound flag case mismatched.

  573. Reported: “The sound flag case mismatched, so I’m inspecting whether the sound start failed before clearing the flag, whether the flag is later reset on immediate completion, or whether the captured screen simply includes audio-related text/state.”

    Action/result: Capture showed no validation sprite.

  574. Reported: “The sound case didn’t draw the validation sprite, so the condition was false. Looking back at the source, 0x63 clears the flag before starting, but the sound subsystem can quickly set it again if the selected sound completes or fails immediately. I’m adjusting this to a simpler source-backed dispatch validation for 0x63 rather than overclaiming stable completion-flag timing.”

    Action/result: Replaced flag assertion with sound start/stop dispatch.

  575. Reported: “I’m replacing the sound flag probe with a start-and-stop dispatch case. That still gives 0x63 QEMU coverage, while the exact completion flag lifetime stays documented from source until we can instrument a less racy sound resource.”

    Action/result: Added sound_start_stop_dispatch_smoke.

  576. Reported: “The sound case is now a start/stop dispatch-smoke. I’m updating the test registry and running that single QEMU batch again.”

    Action/result: Sound start/stop still mismatched without a prior load.

  577. Reported: “Even the start/stop sound dispatch case didn’t reach the validation draw, so this is not just flag timing. I’m inspecting the report/capture and then I’ll decide whether 0x63 needs a synthetic sound fixture instead of using SQ2 sound 1.”

    Action/result: Determined 0x63 needs the sound resource loaded first.

  578. Reported: “The capture shows the validation draw never happened, and the source explains why: 0x63 asks for an already available sound resource record and can route into the interpreter error path if it is not loaded. I’m adding the preceding 0x62 load before 0x63, then stopping with 0x64.”

    Action/result: Added 0x62(1) before 0x63(1,77).

  579. Reported: “The sound start case now mirrors the resource lifecycle: load sound, start it with a completion flag, stop/clear state, then draw. I’m rerunning the focused test and sound batch.”

    Action/result: Focused tests passed and sound_completion_001 matched 1/1.

  580. Reported: “The loaded-start sound case now matches. Before updating evidence/docs, I’m also tightening the trace fixture: the enabled trace window intentionally leaves text pixels, so the reusable QEMU case should be the no-flag gated path for 0x95/0x96; the enabled-window behavior stays source-documented with the screenshot observation.”

    Action/result: Narrowed trace case to the flag-clear gated path.

  581. Reported: “Trace is now a gated no-op QEMU case, which is a clean dispatch check for 0x95/0x96; the enabled drawing path will be described from source and the observed mismatch capture. I’m rerunning the system batch to get a clean report.”

    Action/result: Started final system_dialog_001 run.

  582. Reported: “The corrected system batch is running again. After this I’ll update the evidence table and docs in one pass.”

    Action/result: Awaited final system batch.

  583. Reported: “The corrected system batch is running again. After this I’ll update the evidence table and docs in one pass.”

    Action/result: Duplicate status update while waiting for QEMU.

  584. Reported: “Great, the system/dialog report is clean now. I’m updating the opcode evidence generator to promote the newly matched cases, then I’ll regenerate the evidence chapter.”

    Action/result: system_dialog_001 matched 6/6; updated tools/logic_opcode_evidence.py.

  585. Reported: “I’m promoting the cases according to what they actually prove: cancellation and menu/view behavior go into QEMU-validated evidence; trace, log append, and sound start are dispatch-smoke because their deeper side effects need a different assertion path.”

    Action/result: Promoted QEMU evidence scopes accurately.

  586. Reported: “The evidence mapping is updated. I’m regenerating the mdBook evidence chapter from it.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  587. Reported: “Evidence chapter regenerated. I’m updating the prose docs now with the exact scope of each batch, including the trace-window and sound caveats so the spec doesn’t overclaim.”

    Action/result: Updated docs/src/logic_bytecode.md, docs/src/current_status.md, and docs/src/compatibility_testing.md.

  588. Reported: “Compatibility docs now have the replay commands. I’m adding a few symbolic labels for the new anchors: menu trigger/status, trace globals, log file handle/name, and sound state.”

    Action/result: Updated docs/src/symbolic_labels.md.

  589. Reported: “Symbolic labels are updated for the new stable anchors. I’m appending the clean-room evidence notes with the source slices, failed intermediate probes, and final successful QEMU batches.”

    Action/result: Appended the follow-up probe evidence to docs/src/clean_room_executable_notes.md.

  590. Reported: “I’m going to pick this back up at the verification stage: first make sure the generated opcode evidence, unit suite, mdBook, and whitespace checks all agree with the new source-backed/QEMU-backed notes. After that I’ll inspect the diff so the final summary is concrete.”

    Action/result: Ran the full unit suite, opcode evidence check, mdBook build, and whitespace check; all passed.

  591. Reported: “The validation pass is clean: 99 tests, opcode evidence check, mdBook build, and diff whitespace all passed. I’m doing one quick diff/status pass now so I can give you a useful handoff rather than a vague ‘it worked.’”

    Action/result: Checked git status --short, git diff --stat, and the progress log diff.

  592. Reported: “There are two new progress updates from this resumed bit, so I’m adding those to the historical log before I wrap. Tiny bookkeeping, but it keeps the clean-room audit trail intact.”

    Action/result: Added the resumed verification updates to this progress log.

  593. Reported: “I’ll take these in the order we sketched: room transitions, priority screen, object diagnostics, menu edge behavior, then promotion of selected dispatch-smoke cases. I’m starting source-first by reading the existing handler notes and probe harness so the new tests line up with the interpreter rather than just poking at it.”

    Action/result: Reviewed current status, opcode evidence, probe harness, and tests.

  594. Reported: “The docs already summarize these handlers, but I’m going back to disassembly for the next changes. In particular I want the branch details for 0x1792, 0x731b, 0x72b5, the menu interaction loop, and the file/log path before I add or promote probes.”

    Action/result: Re-read focused disassembly for room switch, priority screen, object diagnostics, menu interaction, and log append paths.

  595. Reported: “A few probe shapes are emerging cleanly from the source pass: room switching can be exposed through var0/var1, priority screen and object diagnostics can be tested as blocking UI actions that return after Enter, and menu disabled/Escape/navigation behavior can be asserted through status-byte conditions. The trace enabled path is still awkward for pixel comparison because it intentionally leaves text-plane artifacts, so I’m not going to overclaim that one.”

    Action/result: Selected initial source-derived fixture designs.

  596. Reported: “I’m going to add new harness cases now. The cases are intentionally narrow: each one turns a source-observed side effect into either a variable/status-byte assertion or a stable return-to-draw assertion, so the evidence level stays honest.”

    Action/result: Added new logic probe cases for room attempts, priority screen, object diagnostics, menu edges, and sound stop flag.

  597. Reported: “The first batch of new cases is in: immediate/variable room switch, priority screen return, object diagnostics return, menu Escape/disabled/re-enable/down-arrow, and a sound-stop completion-flag assertion. I’m wiring them into the registry test before I ask QEMU anything.”

    Action/result: Updated tests/test_logic_interpreter_probe.py.

  598. Reported: “Registry coverage is updated. I’ll run the cheap Python checks now; then I’ll run the new QEMU cases by family so any failure points back to a small source path.”

    Action/result: Focused Python tests and opcode evidence check passed.

  599. Reported: “The local tests are clean. I’m starting with the non-menu QEMU cases: room switch, priority display, object diagnostics, and sound stop flag. Those should tell us quickly whether the source-derived assertions are stable under the original engine.”

    Action/result: Started room_priority_diag_sound_001; the first room case mismatched.

  600. Reported: “The immediate room-switch case mismatched first, so I’m stopping there and inspecting the capture/report. This is useful: room switching is broad enough that one of the “obvious” assumptions, likely initial previous-room value or post-switch control flow, is off.”

    Action/result: Report showed the validation sprite was absent; first previous-room assertion was rejected.

  601. Reported: “The room switch did change control flow enough to clear the expected sprite, but the var1 == 0 assertion was too specific. The source says var1 receives the previous room byte, and the boot fixture appears not to start from zero there, so I’m narrowing the QEMU assertion to the stable source effect: var0 becomes the target room.”

    Action/result: Narrowed and renamed the room cases.

  602. Reported: “Room switching still isn’t returning to logic 0 with a simple var0 assertion, which is itself a useful correction. I’m adjusting the fixture to validate the destination-room execution path instead: after 0x12/0x13, the target logic resource should be loaded/run and draw the marker.”

    Action/result: Reworked room cases to draw from target logic.

  603. Reported: “The target logic ran into another source-derived reset effect: room switching clears resource/object state, so the destination logic cannot rely on the preloaded view/picture from before the switch. I’m updating the destination logic to load/show picture 0 and load view 11 before drawing.”

    Action/result: Made target logic self-contained; room cases still mismatched.

  604. Reported: “The room-switch fixture still doesn’t produce a stable draw, even with a self-contained destination logic. I’m going to treat 0x12/0x13 as source-backed for now and document the failed attempts; they probably need a fuller synthetic logic-0/current-room loop rather than a tiny one-shot fixture. I’m removing those failing cases from the reusable base registry and continuing with the other four steps.”

    Action/result: Removed failing room cases from reusable probe registry.

  605. Reported: “The failing room cases are out of the reusable suite. I’m running the remaining priority/diagnostics/sound family now; these still directly cover steps 2, 3, and part of step 5.”

    Action/result: Started priority_diag_sound_001.

  606. Reported: “The non-room batch is running with three stable assertions: 0x64 setting the completion flag, 0x1d returning from priority display, and 0x85 returning from object diagnostics.”

    Action/result: priority_diag_sound_001 matched 3/3.

  607. Reported: “Good: sound stop flag, priority screen, and object diagnostics all matched. I’m moving to the menu edge batch now: Escape, disabled item Enter, disable-then-enable, and down-arrow selection.”

    Action/result: Started menu_edges_001.

  608. Reported: “The menu edge cases are running. If one fails, the likely culprit is key timing or the exact QEMU key name for arrows, so I’ll separate timing problems from semantic problems by checking the capture/report.”

    Action/result: Three menu edge cases matched; down-arrow case mismatched.

  609. Reported: “Three of four menu edge cases matched. The down-arrow case mismatched, so I’m checking whether down was the wrong key name/timing or whether the menu interpreter uses a different event for vertical movement than I assumed.”

    Action/result: Capture/report showed the down-arrow case did not reach the expected status-8 validation path.

  610. Reported: “The failed arrow case may simply be the key sequence arriving too tightly while the menu is redrawing. I’m increasing the delay between Down and Enter and rerunning just that case once; if it still fails, I’ll keep arrow navigation as an attempted-but-not-promoted path.”

    Action/result: Slower down-arrow retry still mismatched.

  611. Reported: “The slower Down/Enter attempt still mismatched, so I’m taking that failed arrow fixture out of the reusable suite. We’ll keep the source mapping and failed capture as evidence, but not as a compatibility test until we can instrument the exact key/event conversion path.”

    Action/result: Removed the down-arrow case from the reusable suite.

  612. Reported: “The reusable menu suite now contains the three stable edge cases: Escape without status, disabled Enter without status, and disable-then-enable followed by Enter setting status. I’m rerunning that menu batch cleanly.”

    Action/result: menu_edges_002 matched 3/3.

  613. Reported: “Menu edges are clean. For the dispatch-smoke promotion step, I’ve already got a stable sound completion-flag assertion; now I’m going to see if the 0x90 logfile content can be inspected from the post-run qcow image after a single-case run. If that works, we can promote log append beyond pixels.”

    Action/result: Ran log_file_contents_001; visual comparison matched.

  614. Reported: “The single log case matched visually. I’m converting that qcow back to a raw image and trying to pull LOGFILE out of the fixture directory with mtools, which will tell us whether file-content assertions are practical in this harness.”

    Action/result: Converted the qcow image to raw and extracted LF00000/LOGFILE.

  615. Reported: “Great, the converted post-run image contains LOGFILE, and mtools extracted it. I’m reading the bytes now so we can decide whether to formalize a file-content check in the harness or document it as a reproducible manual assertion.”

    Action/result: File content decoded to two leading newlines, Room 0, empty Input line: , and LOG.

  616. Reported: “The logfile content matches the source-derived format exactly: blank line, Room 0, Input line: , and the message LOG. I’m promoting only the parts now backed by stable evidence, while leaving room switching and enabled trace as source-backed or attempted.”

    Action/result: Updated opcode evidence mapping.

  617. Reported: “Evidence mapping is updated: priority display, object diagnostics, log append content, stable menu setup/toggle behavior, and sound stop flag are promoted; room switching and enabled trace stay out of the promoted set. I’m regenerating the evidence chapter.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  618. Reported: “Now I’m updating the prose docs with the exact scope: three successful menu edge cases, priority/diagnostics/sound flag successes, logfile extraction, and the failed room/down-arrow attempts as non-promoted evidence.”

    Action/result: Updated docs/src/logic_bytecode.md.

  619. Reported: “The logic bytecode chapter now records both the successful promotions and the failed room/down-arrow attempts. I’m adding replay commands for the new batches and logfile extraction to the compatibility chapter next.”

    Action/result: Updated docs/src/compatibility_testing.md.

  620. Reported: “I’m refreshing the current-status handoff so the next session starts from the real frontier: room switch still needs a fuller fixture, menu arrows still need better key/event instrumentation, but priority/diagnostics/log/sound/menu toggles moved forward.”

    Action/result: Updated docs/src/current_status.md.

  621. Reported: “I’m adding labels for the newly touched stable anchors: room switch helper, priority display flag/action, object diagnostics action, and updating existing menu/sound/log notes to mention the new evidence.”

    Action/result: Updated docs/src/symbolic_labels.md.

  622. Reported: “I’m appending a new clean-room note for this pass with the exact disassembly commands, successful QEMU batches, failed room/down-arrow attempts, and the logfile extraction bytes.”

    Action/result: Updated docs/src/clean_room_executable_notes.md.

  623. Reported: “I’m catching the progress log up with the actual updates from this run before doing final validation. This one is a little verbose because the room/menu failures are historically useful, not just noise.”

    Action/result: Added these progress-log entries.

  624. Reported: “The docs and progress log are caught up. I’m running the full validation pass now: unit suite, evidence check, mdBook build, and whitespace check.”

    Action/result: Unit tests, evidence check, and mdBook build passed; whitespace check found one trailing space in a logfile code block.

  625. Reported: “Validation is clean except for one trailing space in the literal logfile block. I’m fixing that formatting nit and rerunning the doc/whitespace checks.”

    Action/result: Removed the trailing space and clarified that the input line buffer is empty.

  626. Reported: “The trailing-space issue is fixed, and the prose now explicitly says the input-line buffer is empty so the code block can stay whitespace-clean. Rechecking the touched validation pieces.”

    Action/result: mdBook build, whitespace check, and opcode evidence check passed.

  627. Reported: “The rechecks are clean. I’m adding the last validation updates to the progress log, then I’ll inspect the final diff/status for the handoff.”

    Action/result: Added final validation updates to this progress log.

  628. Reported: “Commit bc02913 is in place; only generated/untracked directories remain. I’m moving into the next pass now, starting with source around the room cycle and input event pipeline because those are the two places where tiny QEMU probes were too shallow.”

    Action/result: Confirmed the previous commit and began a source-first pass over room switching and menu/input events.

  629. Reported: “The existing notes already captured the earlier failed room-switch fixture shapes, which is useful because it tells us what not to trust yet. I’m going to build the next room probes around the concrete source effect the helper definitely performs: setting flag 5 and re-entering the logic cycle.”

    Action/result: Re-read the room-switch helper and prepared a flag-5-based fixture shape.

  630. Reported: “The disassembly confirms the room-switch wrapper itself returns zero after the helper, and code.engine.main_cycle immediately re-runs logic 0 while that zero return persists. That means a good fixture should expect logic 0 to re-enter after 0x12/0x13, not expect the switched-to logic to execute automatically.”

    Action/result: Confirmed wrapper return behavior and corrected the fixture hypothesis away from automatic target-logic execution.

  631. Reported: “For menu arrows, the source shows a second event-type path rather than normal status-byte mapping. There is a fixed table at 0x16b3 mapping raw event words 0x4800/0x4900/0x4d00/0x5100/0x5000/0x4f00/0x4b00/0x4700 to menu movement codes 1..8; 0x5000 is the down-arrow candidate.”

    Action/result: Identified and recorded the menu-direction key table.

  632. Reported: “I’m adding two room-switch probes that lean on the source-backed flag-5 effect rather than the earlier mistaken ‘target logic should run automatically’ assumption. I’ll also add a small down-arrow key mapping probe so we can separate ‘QEMU produced the raw arrow event’ from ‘the menu loop navigated.’”

    Action/result: Added temporary room-switch and down-arrow probe cases.

  633. Reported: “The room-cycle source gives us a sharper correction: after logic 0 returns zero from the switch action, the engine clears a few variables and immediately invokes logic 0 again in the same top-level loop until it gets a nonzero interpreter return. That’s why the fixture must guard against repeated switching with its own init flag.”

    Action/result: Added an init-flag guard to the temporary room fixtures.

  634. Reported: “I’ve wired the new cases into the local registry test. Next I’m running just the Python suite, then I’ll take the new probes through QEMU in small batches.”

    Action/result: Updated local registry tests and ran the unit suite; it passed before QEMU execution.

  635. Reported: “The immediate room-switch probe still mismatched, so I’m stopping before treating it as evidence. I’m opening the report and the generated fixture bytes now; this is exactly the kind of case where the disassembly should explain why the synthetic control flow is still wrong.”

    Action/result: room_reentry_001 mismatched on the immediate room-switch case.

  636. Reported: “The ‘failed’ room probe actually drew the validation sprite; the mismatch is priority/composition, not control flow. That is a good catch: the source-backed re-entry model appears right, but the fixture’s expected priority assumption is too strict after the room switch rebuilds display state.”

    Action/result: Initially suspected a composition issue from the comparison sample, then inspected the screenshot and rejected that interpretation.

  637. Reported: “One nuance: the report samples are from the downsampled logical buffer, while the raw screenshot inspection reports only two RGB colors in the VGA capture. I’m checking the actual image and the generated LOGIC resource bytes so I don’t misread a pixel-comparison artifact as engine behavior.”

    Action/result: Converted and inspected the QEMU capture; it showed a blank white screen, confirming the validation sprite was not drawn.

  638. Reported: “The fixture stores resources inside VOL files, so there are no standalone LOGIC.* files to inspect in that directory. I’ll use the probe’s Python objects for bytecode inspection and look at the screenshot directly.”

    Action/result: Inspected generated case bytecode through the Python probe object rather than nonexistent standalone resource files.

  639. Reported: “The screenshot confirms no sprite, so this is a real failed control-flow assertion. The most likely source-side explanation is that the room switch calls 0x10d0, which I haven’t fully accounted for; if it clears script flags, my guard flag gets wiped and logic 0 keeps switching forever.”

    Action/result: Re-read 0x10d0; this did not prove flag clearing, so the investigation moved to logic resume pointers.

  640. Reported: “The source points to a better explanation than ‘flags got cleared’: logic records carry a resume pointer. A room switch returns zero from the current action, so logic 0 may be called again from its saved post-switch instruction pointer unless the fixture explicitly restores the logic entry IP first. I’m going to fold opcode 0x92 into the synthetic switch path and rerun.”

    Action/result: Added 0x92 before the temporary synthetic room-switch calls.

  641. Reported: “That edit keeps the fixture narrow: it does not claim 0x12 itself resets logic 0, only that the switch helper sets flag 5 and the engine observes it after an explicit entry-IP restore. I’m running the targeted unit check and QEMU batch again.”

    Action/result: Targeted unit test passed; QEMU room_reentry_002 still mismatched.

  642. Reported: “0x92 did not change the outcome. I’m going back to the interpreter loop now, because the exact place it stores or reuses the logic IP is the source of truth for why logic 0 does not re-enter the way the synthetic fixture expects.”

    Action/result: Re-read code.logic.interpret_main and code.logic.call_logic.

  643. Reported: “The interpreter loop is clear: it starts from record +0x06, and 0x92 does set +0x06 to the logic’s entry pointer. The remaining mismatch looks like display-state contamination around the tiny sprite area rather than a missing draw, so I’m zooming the capture and then I’ll rerun the two room cases without --stop-on-failure to see whether the variable-target case behaves the same.”

    Action/result: Reran both room cases without stop-on-failure; both mismatched.

  644. Reported: “Both room cases mismatch the same way, which is still useful evidence: the fixture reaches a stable screen but not the expected compatibility assertion. I’m going to keep these as attempted/non-promoted for now and move the validated work to the down-arrow event split.”

    Action/result: Decided not to promote the room re-entry fixtures.

  645. Reported: “I’m not going to leave failing room probes in the reusable case list. I’ll preserve the attempted evidence in docs instead, then keep only stable probes in the tool. First I’m checking whether the raw down-arrow status mapping is stable.”

    Action/result: Ran down_key_001; it mismatched.

  646. Reported: “The down-arrow mapping did not validate either, which tells us QEMU’s sendkey down is not currently arriving as the raw 0x5000 event that the source table expects, or it arrives outside the polling window. I’ll remove that from the reusable suite too and document it as an input-instrumentation gap rather than a behavior claim.”

    Action/result: Removed temporary failing room and down-arrow cases from the reusable probe registry.

  647. Reported: “The reusable suite is back to stable cases only. I’m adding symbolic labels for the event-direction table and the logic resume/entry-IP helpers, because those are exactly the cross-version anchors we’ll want when comparing other interpreter builds.”

    Action/result: Added symbolic labels for logic resume helpers and the menu-direction event table.

  648. Reported: “The docs already had most of the raw input machinery; I’m tightening it with two cross-version-friendly names: the type/value event enqueue helper and the menu-direction raw key map.”

    Action/result: Added code.input.enqueue_event and data.input.menu_direction_event_map labels.

  649. Reported: “I’m updating the bytecode chapter to make the important distinction explicit: source shows down-arrow maps to movement code 5 inside the menu event path, but our current QEMU key injection has not produced that raw event reliably.”

    Action/result: Updated logic_bytecode.md with down-arrow and room-switch evidence boundaries.

  650. Reported: “The bytecode chapter now states the boundary between source-backed facts and failed QEMU instrumentation. I’m adding the detailed clean-room trail next: exact disassembly ranges, exact QEMU commands, and what each failed probe ruled out.”

    Action/result: Added a clean-room notes section for this pass.

  651. Reported: “I’m also updating current-status and compatibility notes so the next session doesn’t accidentally retry the same naive room/down-arrow fixtures without new instrumentation.”

    Action/result: Updated current_status.md and compatibility_testing.md with attempted-but-not-promoted fixture details.

  652. Reported: “Docs and logs are updated. I’m running the validation pass now: unit tests, opcode evidence check, mdBook build, and whitespace check.”

    Action/result: python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check all passed.

  653. Reported: “Validation is clean. I’m doing a final diff/status pass now so I can give you an accurate handoff without accidentally including generated artifacts.”

    Action/result: Final status showed docs-only tracked changes plus the existing untracked build/ and 002962_ms_dos_622/ directories.

  654. Reported: “Got it: I’ll leave the current docs changes uncommitted and keep working on top of them. I’m starting with the real SQ2 logic resources, because that should tell us what the room-switch contract actually looks like before we spend more QEMU cycles.”

    Action/result: Started a source-first pass over SQ2 logic resources.

  655. Reported: “The repo already has a local logic disassembler and resource readers, so I can stay inside the clean-room tooling. I’m checking how much it currently prints before deciding whether to extend it for logic0/room-call analysis.”

    Action/result: Re-read tools/disassemble_logic.py and disassembled logic 0.

  656. Reported: “Logic 0 is the real ‘director’ script: it has early room switches during boot, then a flag-5 block that resets ego/object state and preloads resources for the current room. I’m narrowing on the opcodes that actually call room scripts and trigger room switches.”

    Action/result: Searched SQ2 logic 0 for switch/load/call/resume actions.

  657. Reported: “The pattern is already visible in real resources: many room logics begin with if flag 5, do room-entry setup, then continue to per-cycle behavior and end. Logic 0 does not call the current room by number as a var; instead the room resource itself is loaded by the switch helper and resumed/called as part of the linked logic cache behavior. I’m going to map that across room logics rather than infer from one example.”

    Action/result: Checked room logic resources 1 through 4 and then broadened the scan; the next step corrected the initial inference.

  658. Reported: “This corrects my last inference: logic 0 is not calling every room directly, but the loaded room logic clearly begins at offset 0 and handles flag 5 as its entry block. I’m checking whether the engine calls loaded logics through a separate cache/list runner, because code.engine.main_cycle only has the obvious call_logic(0) call in the slice we already read.”

    Action/result: Re-read nearby executable helpers and continued searching logic 0.

  659. Reported: “Found it: logic 0 does call the current room, but later than the entry/menu block. At offset 0x053e it does call_logic_var(v0), so the room number in variable 0 is the dispatch key. That explains why synthetic room fixtures need a logic-0 loop with call_logic_var(v0), not a target logic that magically runs after switch_room.”

    Action/result: Identified SQ2 logic 0 bytecode offset 0x053e as the current-room dispatch point.

  660. Reported: “Now I have a better fixture shape: mimic logic 0’s real pattern by switching rooms, then having logic 0 call call_logic_var(v0) so the loaded room logic runs while flag 5 is still set. I’m adding that as a targeted compatibility probe instead of the earlier one-shot draw.”

    Action/result: Temporarily added two logic-0-shaped room dispatch probes.

  661. Reported: “The new cases are in the reusable suite, but only provisionally until QEMU agrees. I’m running the targeted local test and then the room-switch batch.”

    Action/result: Targeted registry test passed; generated bytecode looked as intended.

  662. Reported: “The bytecode shape looks right: logic 0 switches once, then uses call_logic_var(v0) to run the current room logic. I’m putting the two cases through QEMU now.”

    Action/result: Started QEMU batch room_dispatch_001.

  663. Reported: “Still mismatched, so I’m not promoting it. This time the fixture matches the real call_logic_var(v0) pattern, which tells us another part of real logic 0’s entry sequence is still required. I’m opening the capture/report and then I’ll pull these provisional cases back out.”

    Action/result: room_dispatch_001 mismatched with the same blank-screen signature as prior room attempts.

  664. Reported: “The capture is the same blank screen signature. I’m checking fixture construction too, because if extra logic resources are not patched into LOGDIR correctly then call_logic_var(v0) would never reach the target logic no matter how good the script pattern is.”

    Action/result: Inspected LOGDIR and VOL.3; the extra logic resource was patched at the expected offset.

  665. Reported: “The fixture construction looks correct, including patched LOGDIR entries for logic 1 and 2. So this failure is now genuinely about the runtime room/logic lifecycle, not a missing resource patch. I’m removing the provisional cases again and documenting the stronger source finding: real logic 0 calls call_logic_var(v0) at offset 0x053e, while room logics gate entry setup on flag 5.”

    Action/result: Removed the temporary failing room-dispatch cases from the reusable probe registry.

  666. Reported: “I’m updating the spec now with the real room-script structure: byte variable 0 is current room, byte variable 1 is previous room, byte variable 2 is entry boundary, and SQ2 logic 0 calls the current room via call_logic_var(v0) after the global entry/menu work.”

    Action/result: Updated symbolic labels and logic bytecode prose with the room variable roles and logic-0 dispatch offset.

  667. Reported: “The main bytecode chapter and labels now have the real SQ2 room dispatch model. I’m adding the chronological command trail and the failed QEMU replay name, then I’ll run tests/docs.”

    Action/result: Updated clean-room notes, current status, and compatibility testing with the real-SQ2 room dispatch source pass and failed QEMU batch.

  668. Reported: “The temporary QEMU cases are back out, so the reusable test suite should remain stable. I’m doing a quick diff check on tools/tests now, then I’ll validate the docs and local suite.”

    Action/result: Confirmed there was no remaining tracked diff in tools/logic_interpreter_probe.py or tests/test_logic_interpreter_probe.py.

  669. Reported: “Progress log is caught up. I’m running the validation pass: unit suite, evidence check, mdBook, and whitespace.”

    Action/result: Ran the local unit suite, opcode-evidence check, mdBook build, and diff whitespace check successfully after the room-dispatch documentation updates.

  670. Reported: “Validation is clean. I’m checking final status now so I can hand off exactly what changed and what remains uncommitted.”

    Action/result: Checked final Git status; the remaining worktree changes are documentation files, with generated build/ artifacts and local DOS installer images still untracked.

  671. Reported: “I’ll take the five-step list as the work queue: room lifecycle first, then input/menu, selection/system, sound, and labels/docs. I’m going source-first and will only use QEMU if a result needs confirmation or turns into a durable test.”

    Action/result: Started a five-step source-first lifecycle pass and created a working plan.

  672. Reported: “First I’m gathering the existing symbol map, notes, and helper scripts so I can extend the current evidence trail instead of creating a parallel one.”

    Action/result: Read the symbol map, searched existing notes/tools/tests, and confirmed only generated/local directories were untracked.

  673. Reported: “The current docs already have many labels, so this pass can be a tightening pass rather than a broad search. I’m opening the disassembly around the five target families now, especially the call sites that explain why the previous synthetic room fixture is too thin.”

    Action/result: Opened real SQ2 logic 0 and the first broad disassembly windows for room, main-cycle, input, menu, save, and sound paths.

  674. Reported: “One wrinkle: the raw full disassembly includes executable header bytes, so some addresses are offset from the “image” addresses in the docs. I’m checking the existing slice/disassembly workflow before trusting any raw line numbers.”

    Action/result: Reconfirmed the documented convention that file offset is image offset plus 0x200 for build/cleanroom/AGI.decrypted.exe.

  675. Reported: “The project’s convention is clear: file offset is image offset plus 0x200. I’m using focused ndisasm windows with that correction for the room switch, main cycle, input/menu, save/restore, and sound paths.”

    Action/result: Re-disassembled focused corrected windows for 0x175c, 0x0150, 0x4529, and 0x93d1.

  676. Reported: “The first source pass already answers two useful questions: room switching deliberately returns zero to force the main cycle back into logic 0, and menu arrow navigation is driven by normalized type-2 events, not status bytes. I’m reading save/system and sound now.”

    Action/result: Identified the room-switch zero return and menu type-2 movement dispatch, then opened save, restore, selector, and sound windows.

  677. Reported: “I’m going one layer down on the room reset calls now. The switch helper’s call list is compact, so mapping those callees should give us a higher-level lifecycle spec without guessing from QEMU symptoms.”

    Action/result: Mapped reset/resource-event callees around 0x10d0, 0x1485, 0x7060, and restore replay helper 0x681c.

  678. Reported: “The save/restore path is also cleaner now: the selector helper is responsible for prompt-mode setup, path validation, and preserving the input marker; the save/restore handlers do the actual block I/O after it returns a nonzero selection. I’m checking the event queue root next so the menu/input notes can name the globals.”

    Action/result: Mapped event queue enqueue/dequeue helpers and identified queue storage 0x11ba, write pointer 0x120a, and read pointer 0x120c.

  679. Reported: “I spotted one bad byte dump: I asked xxd for the executable at the data-table offset, which is the wrong backing file for AGIDATA data. I’m correcting that against SQ2/AGIDATA.OVL before I document the menu table.”

    Action/result: Discarded the executable dump and confirmed DS:0x16b3/DS:0x16d7 movement tables from SQ2/AGIDATA.OVL.

  680. Reported: “I have enough source-backed material to start editing: this will be mostly spec/label expansion, plus the progress log. I’m going to keep the wording careful: QEMU did not validate new behavior here, but the disassembly improves the model and narrows what future tests should target.”

    Action/result: Prepared documentation-only edits with no new QEMU cases.

  681. Reported: “I’m making the documentation edits now. The main additions are: the room switch’s exact return-to-main-cycle behavior, event queue/menu navigation roles, save/restore selector responsibilities, restore-time resource replay, and sound state labels.”

    Action/result: Updated docs/src/logic_bytecode.md with refined room, menu/input, save/restore, and sound semantics.

  682. Reported: “The bytecode chapter has the first wave of updates. I’m adding the stable labels next, including the event queue globals and room/save/sound helper roles that future version comparisons will need.”

    Action/result: Added symbolic labels for heap reset, input event queue, menu drawing/navigation helpers, restore replay, sound helpers, and event queue globals.

  683. Reported: “Labels are expanded. I’m adding the chronological clean-room notes for the commands and observations, then I’ll refresh the current-status page so the handoff reflects this pass.”

    Action/result: Added a clean-room notes section for the source-first lifecycle pass.

  684. Reported: “The clean-room note is in place. I’m checking its placement now; if I accidentally inserted it inside an older section instead of after it, I’ll move it so the chronology stays readable.”

    Action/result: Found the new lifecycle note had split an older picture/view command list.

  685. Reported: “Placement is good. I’m reading the following lines too just to make sure the older picture/view section still continues cleanly after the new note.”

    Action/result: Confirmed the split was real because older picture/view commands continued after the new lifecycle note.

  686. Reported: “Yep, one issue: the new section split an older picture/view command list. I’m moving the lifecycle note down below that older section so the historical record stays tidy.”

    Action/result: Removed the misplaced lifecycle note from the middle of the picture/view command list.

  687. Reported: “The accidental split is removed. I’m inserting the lifecycle pass after the picture/view section’s documented result now.”

    Action/result: Reinserted the lifecycle pass after the picture/view documented result and before the next historical section.

  688. Reported: “The note is back in chronological shape. I’m updating current status now: several “what’s next” items have changed from “map this” to “we have the source model; build targeted tests only where possible.””

    Action/result: Updated docs/src/current_status.md with the refined room, menu, save/restore, and sound source models and next-test guidance.

  689. Reported: “The main docs are updated. I’m recording the work-session updates in the progress log before running validation, so the historical trail includes the source pass and the small correction I made while editing.”

    Action/result: Added progress-log entries for the source-first lifecycle pass, including the corrected AGIDATA table dump and the note-placement fix.

  690. Reported: “Progress log is caught up through the documentation edits. I’m doing a quick read of the touched sections for continuity before validation.”

    Action/result: Reviewed the edited bytecode and clean-room note sections for continuity.

  691. Reported: “The touched sections read coherently now. I’m running the validation suite and docs build next; since these are documentation-only edits, the full local unit suite plus mdBook/diff checks should be enough.”

    Action/result: Ran the full local unit suite, opcode evidence check, mdBook build, and diff whitespace check successfully.

  692. Reported: “Validation is clean. I’m checking the final diff/status and then I’ll add the closing progress-log entries for the validation and handoff.”

    Action/result: Checked final status and diff summary; the worktree has documentation changes only, plus expected untracked build/ and 002962_ms_dos_622/ directories.

  693. Reported: “I’m going to turn the room-switch finding into a fixture that mirrors the source-shaped lifecycle more closely: logic 0 performs the switch once, then on engine re-entry dispatches through call_logic_var(v0) into a target room logic that owns its own picture/view setup. Then I’ll let QEMU tell us whether that structure matches the original engine rather than treating a guess as fact.”

    Action/result: Started a room-switch re-entry probe pass focused on source-shaped logic-0/current-room dispatch.

  694. Reported: “The helper insertion point moved a little from what I had in my head, so I’m checking the exact neighborhood before patching. Small friction, but it’s useful because the harness has accumulated a lot of deliberately-shaped fixture helpers.”

    Action/result: Re-read the probe helper area and call-logic case list in tools/logic_interpreter_probe.py.

  695. Reported: “I’ve added explicit helper code for the re-entry shape, with the initialization flag set before the room switch because the switch path itself short-circuits the current logic invocation. That detail is exactly the kind of thing that made the earlier fixtures slippery.”

    Action/result: Added room re-entry helper functions and initial immediate and variable-selected room-switch probe cases.

  696. Reported: “I’m also pinning the new cases in the unit coverage list. It’s not deep verification by itself, but it prevents these probe definitions from quietly disappearing while we iterate on the harder QEMU behavior.”

    Action/result: Added unit coverage assertions for switch_room_reentry_dispatches_current_room and switch_room_v_reentry_dispatches_current_room.

  697. Reported: “The first unit pass caught a naming mismatch in the dataclass constructor, not a behavioral problem. I’m correcting that before moving on to QEMU so the probe harness stays internally clean.”

    Action/result: Fixed the new case constructor to use expected_group_no, expected_frame_no, and expected_baseline_y.

  698. Reported: “The dataclass fix is in. Next I’m doing the quick deterministic test run again, then I’ll run the two new fixtures through the original interpreter.”

    Action/result: python3 -B -m unittest tests.test_logic_interpreter_probe passed: 7 tests OK.

  699. Reported: “The local harness tests pass now. I’m moving to the important part: running just the new room-switch cases under QEMU so we have original-engine evidence before documenting them as validated.”

    Action/result: First QEMU command attempted a bare --snapshot flag, but the harness only exposes snapshot image path options.

  700. Reported: “This harness doesn’t have a --snapshot flag on the current branch; it only exposes the snapshot image paths. I’ll use its normal serial runner for the two-case check.”

    Action/result: Re-ran the room-switch cases with the supported harness arguments.

  701. Reported: “Both room-switch re-entry cases matched the original engine in QEMU, including the variable-selected room form. I’m going to run the project’s compatibility unit suite next, then I’ll update the docs with the evidence and the higher-level semantics.”

    Action/result: QEMU batch room_switch_reentry_001 matched 2/2 with 0 errors and 0 mismatches.

  702. Reported: “The full local compatibility suite is green. I’m documenting the new evidence now: the source-shaped model, what the QEMU cases prove, and why the target room logic has to perform its own resource setup after the switch.”

    Action/result: python3 -B -m unittest discover -s tests passed: 99 tests OK.

  703. Reported: “The docs still correctly preserve the earlier failures, but now need a follow-up paragraph that supersedes their status. I’m also checking the opcode evidence generator so the evidence table doesn’t lag behind the new QEMU result.”

    Action/result: Found tools/logic_opcode_evidence.py still marked action rows 0x12 and 0x13 as source-backed.

  704. Reported: “The evidence generator still marks room switching as source-backed. Since the new QEMU cases match the original interpreter, I’m promoting only the tested behavior: zero-return re-entry plus current-room dispatch, not every side effect of the broad reset helper.”

    Action/result: Updated the evidence generator to cite the two matched room-switch re-entry cases for action rows 0x12 and 0x13.

  705. Reported: “The generator is updated. I’m regenerating the opcode evidence chapter now so the book reflects the promoted room-switch cases.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  706. Reported: “I’m updating the handoff/status text so it no longer tells future us that the room-switch fixture still needs to be built. The older failed attempts stay in the record; the new matched case becomes the current evidence.”

    Action/result: Updated docs/src/current_status.md with the validated room-switch re-entry fixture and revised next steps.

  707. Reported: “I’m adjusting the logic bytecode chapter next. The key nuance is that QEMU validates the control-flow shape, while several internal reset effects are still grounded in disassembly rather than direct fixture assertions.”

    Action/result: Updated docs/src/logic_bytecode.md to describe room_switch_reentry_001 and separate QEMU-validated dispatch behavior from source-backed reset details.

  708. Reported: “I’m adding the exact QEMU command to the compatibility chapter and marking the older failed room fixtures as superseded experiments, not current blockers.”

    Action/result: Updated docs/src/compatibility_testing.md with the new room-switch re-entry batch and superseded-fixture notes.

  709. Reported: “I’m appending the clean-room notes with the actual commands and observed result. This is the audit trail piece: future readers should be able to see exactly how the room-switch fixture went from failed attempts to a matched QEMU batch.”

    Action/result: Added a clean-room notes section for the room-switch re-entry QEMU validation pass.

  710. Reported: “The main docs are updated. I’m logging the intermediate progress updates now so the historical record includes the small test failure, the harness flag correction, and the successful QEMU validation.”

    Action/result: Added progress-log entries for the room-switch re-entry fixture work and QEMU result.

  711. Reported: “The progress log is caught up through the docs edits. I’m running validation now: the local unit suite again, mdBook build, and a quick diff/status pass.”

    Action/result: Ran python3 -B -m unittest discover -s tests and mdbook build docs; both passed.

  712. Reported: “Validation is clean. I’m checking the final diff now so I can give you the concise “what changed / what’s next” without making you sift through generated noise.”

    Action/result: Checked git status --short and git diff --stat.

  713. Reported: “The core validation passed. I’m doing one last whitespace check and a focused status read; then I’ll hand back the result and the next concrete reverse-engineering steps.”

    Action/result: git diff --check passed with no whitespace errors; final status still includes pre-existing modified docs and untracked generated directories.

  714. Reported: “The whitespace check is clean too. I’m adding the closing validation entries to the progress log so this turn’s record includes the green tests and book build.”

    Action/result: Added closing progress-log entries for validation and handoff.

  715. Reported: “I’ll start with the v2 room-entry boundary probe, source-first. I’m going to re-read the switch helper and the existing probe helpers, then shape the QEMU cases so they validate the entry placement through ordinary logic bytecode rather than peeking at memory.”

    Action/result: Re-read room-switch helper 0x1792, probe helper code, and existing room-switch fixtures.

  716. Reported: “The switch helper confirms the four v2 cases in code: 1 writes object 0 Y to 0xa7, 2 writes X to 0, 3 writes Y to 0x25, and 4 writes X to 0xa0 - object_width, then clears v2. I’m shaping the cases so the destination logic reads object 0 with the normal getter and only draws if the expected field matches.”

    Action/result: Added helper code for boundary-selector fixtures that use action 0x27 to read object 0 after room-switch re-entry.

  717. Reported: “I’m going to cover all four boundary selectors. The fourth case depends on object width, so I’ll initialize object 0 with view 11 frame 0 before the switch; the disassembly leaves width intact and uses it for 0xa0 - width, which should give X 140 for that 20-pixel-wide cel.”

    Action/result: Added four base cases for selectors 1 through 4 and pinned them in the logic probe unit test list.

  718. Reported: “The cases are registered. I’m running the local unit test for the probe definitions first; if that’s clean, I’ll run just these four cases through QEMU.”

    Action/result: Logic probe unit tests and py_compile passed.

  719. Reported: “The definition tests pass. I’m launching the four boundary-selector fixtures in QEMU now; this will tell us whether the disassembled field writes line up with visible original-engine behavior.”

    Action/result: Started QEMU batch room_boundary_001.

  720. Reported: “The batch is running from one snapshot boot. It has built all four fixture directories and is now executing the captures.”

    Action/result: room_boundary_001 continued running under QEMU snapshot mode.

  721. Reported: “The first boundary case mismatched, so I’m not promoting the set yet. I’m going to inspect the generated report and capture signature to see whether the validation draw never happened or whether one of the expected coordinates is wrong.”

    Action/result: The first capture was all white; no validation draw occurred.

  722. Reported: “The capture is a blank all-white screen, which means the destination room ran far enough to show its picture but the coordinate condition did not pass. I’m going back to the object-position getter and setup path in the disassembly before trying new hypotheses, because the field write may be right while my bytecode-level observation is reading a different or reset field.”

    Action/result: Re-read object getter/setup-related disassembly.

  723. Reported: “The getter path is byte-based and normal object fields are at +0x03/+0x05, as expected. The failure likely means the switch helper’s later refresh calls alter object 0 after the boundary write, or object 0’s special lifecycle differs from ordinary objects. I’m going to build a diagnostic fixture that encodes the observed value into a visible draw choice, still using bytecode and QEMU rather than debugger memory.”

    Action/result: Generated a diagnostic under build/ to test whether action 0x27 can observe object 0 after ordinary setup.

  724. Reported: “Before guessing the boundary value, I’m checking the observation mechanism itself with a generated diagnostic case under build/: set object 0, read it back with action 0x27, and draw only if the getter reports the fields we wrote. If that passes, the mismatch is specifically post-switch behavior.”

    Action/result: Diagnostic object-0 getter case matched QEMU.

  725. Reported: “The diagnostic getter case matched, so action 0x27 can observe object 0 normally. Now I’m generating a single visual diagnostic that draws different marker positions for several post-switch (x,y) hypotheses, plus a separate marker if v2 was cleared. That should reveal which part of the condition is false.”

    Action/result: Generated and ran the boundary marker-map diagnostic; it still produced an all-white capture.

  726. Reported: “Aha, the diagnostic never drew even the v2 == 0 marker because my pre-switch object setup bound view 11 without loading it first. That likely aborted before the switch. I’m fixing the fixture to load view 11 before setting up object 0, then I’ll rerun the boundary batch.”

    Action/result: Corrected boundary fixtures to load view 11 before binding object 0.

  727. Reported: “The pre-switch setup now loads the view resource before binding object 0. I’m re-running the quick unit check and then the four-case QEMU batch.”

    Action/result: Logic probe unit tests and py_compile passed again.

  728. Reported: “The corrected boundary batch is executing now. If the disassembly-derived values are right, all four should draw their validation sprite after the re-entry dispatch.”

    Action/result: QEMU batch room_boundary_002 matched 4/4 with 0 mismatches and 0 errors.

  729. Reported: “Great, all four boundary selectors matched QEMU after fixing the pre-switch setup. I’m going to promote these as compatibility cases and update the docs with the exact distinction we just learned: object 0 must have a loaded/bound view before the switch for the right-edge width case to be meaningful.”

    Action/result: Promoted the four boundary-selector cases and began documentation updates.

  730. Reported: “I’m checking the relevant doc sections and the evidence generator now so the probe list, opcode evidence, compatibility instructions, and clean-room notes all agree.”

    Action/result: Found the evidence generator needed to mention the new boundary-selector cases for action 0x12.

  731. Reported: “I’m promoting the boundary coverage in the evidence generator and docs now. The wording will stay careful: the bytecode-visible entry-boundary placements are QEMU-validated; unrelated internals like resource-event recording are still source-backed.”

    Action/result: Updated tools/logic_opcode_evidence.py.

  732. Reported: “The generator is updated. I’m regenerating the opcode evidence chapter before editing the prose around it.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  733. Reported: “Next I’m editing the room-switch prose and compatibility instructions to include the four matched v2 selectors and the pre-switch view-load lesson from the failed first attempt.”

    Action/result: Updated docs/src/logic_bytecode.md and docs/src/compatibility_testing.md.

  734. Reported: “The bytecode and compatibility chapters now include the boundary batch. I’m updating the handoff page so “entry boundary” moves out of the recommended next step and into validated room-switch behavior.”

    Action/result: Updated docs/src/current_status.md.

  735. Reported: “I have the concise switch-helper dump now. I’m appending a clean-room note section with the failed first batch, the diagnostic getter check, the corrected batch, and the resulting semantics.”

    Action/result: Added the room entry-boundary selector QEMU validation section to docs/src/clean_room_executable_notes.md.

  736. Reported: “I’ll take the next small, crisp room-switch probe: controlled previous-room updates. I’m going to make the fixture set v0 to a known synthetic previous room before switching, then the destination room logic will assert v0, v1, and cleared v2 through normal bytecode before drawing.”

    Action/result: Started the current/previous-room variable validation pass.

  737. Reported: “I’m checking the current dirty state and helper locations first, since we’re building on the uncommitted boundary-selector work from the last slice.”

    Action/result: Confirmed the uncommitted boundary-selector changes were present and identified the room-switch helper insertion points.

  738. Reported: “The existing helpers are a good fit. I’m adding a narrow previous-room helper now: pre-switch logic writes a synthetic old room into v0, switches to room 1, then the destination room draws only if v0 == 1, v1 == old_room, and v2 == 0.”

    Action/result: Added helper code for current/previous-room validation fixtures.

  739. Reported: “The helper is in. I’m registering both immediate and variable room-switch versions so 0x12 and 0x13 both get previous-room coverage.”

    Action/result: Added switch_room_sets_current_previous_and_clears_boundary and switch_room_v_sets_current_previous_and_clears_boundary.

  740. Reported: “The new cases are pinned in the registry tests. I’m running the local probe tests and Python compile check before QEMU.”

    Action/result: tests.test_logic_interpreter_probe and py_compile passed.

  741. Reported: “The local checks pass. I’m running the two previous-room cases in QEMU now.”

    Action/result: QEMU batch room_previous_001 matched 2/2 with 0 errors and 0 mismatches.

  742. Reported: “Both previous-room cases matched QEMU. I’m updating the evidence generator and docs now so the room-switch section reflects v0/v1/v2 as validated behavior, with the rest still source-backed.”

    Action/result: Began promoting the current/previous-room evidence into docs.

  743. Reported: “I’m going to regenerate the opcode evidence after adding the new case names, then fold the same result into the narrative docs.”

    Action/result: Updated tools/logic_opcode_evidence.py.

  744. Reported: “The evidence table is regenerated. I’m updating the room-switch prose and current-status page next.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  745. Reported: “I’m patching the docs now: v1 moves from planned/source-backed to QEMU-validated, while resource replay and broader reset details remain next.”

    Action/result: Updated docs/src/logic_bytecode.md, docs/src/compatibility_testing.md, and docs/src/current_status.md.

  746. Reported: “The narrative docs are updated. I’m appending the clean-room note section for the v1 validation run with the exact QEMU command and result.”

    Action/result: Added the room current/previous variable QEMU validation section to docs/src/clean_room_executable_notes.md.

  747. Reported: “I’ll proceed with the low-risk custom-logic path first: add the 0x13 variable-room versions of the four v2 boundary selector tests. That gives us another clean behavioral brick before we reach for memory snapshots or patched instrumentation.”

    Action/result: Started the variable-selected room boundary pass.

  748. Reported: “I’m checking the committed baseline and the helper shape so I can add these as a small extension rather than duplicating the immediate-room boundary code.”

    Action/result: Confirmed the working tree only had untracked generated directories and inspected room-switch helper definitions.

  749. Reported: “The helper already takes an arbitrary switch action, so the change can stay tidy: parameterize the boundary case over immediate vs variable switch action, then add four switch_room_v_boundary_* cases.”

    Action/result: Planned a small parameterization of room_boundary_case.

  750. Reported: “I’m making room_boundary_case accept a switch action, defaulting to 0x12, then using that for the four 0x13 variants.”

    Action/result: Updated room_boundary_case to accept an optional caller-supplied switch action.

  751. Reported: “The helper is parameterized. I’m inserting the four variable-room boundary cases next to the immediate boundary cases and using separate validation draw positions so mismatches are easy to identify.”

    Action/result: Added four switch_room_v_boundary_* probe cases.

  752. Reported: “The four 0x13 boundary cases are registered. I’m pinning them in the unit test list now.”

    Action/result: Added unit assertions for the four variable-room boundary cases.

  753. Reported: “I’m running the local probe tests and compile check before launching QEMU.”

    Action/result: tests.test_logic_interpreter_probe and py_compile passed.

  754. Reported: “Local checks pass. I’m running the four variable-room boundary cases under QEMU now.”

    Action/result: Started QEMU batch room_boundary_var_001.

  755. Reported: “The QEMU batch is running from one snapshot boot. It has built the fixtures and is executing the capture/compare loop now.”

    Action/result: QEMU batch execution continued.

  756. Reported: “All four variable-room boundary selectors matched. I’m updating the evidence table and docs now, then I’ll run the full validation suite.”

    Action/result: QEMU batch room_boundary_var_001 matched 4/4 with 0 mismatches and 0 errors.

  757. Reported: “First I’ll update the generated evidence source so 0x13 cites the boundary cases alongside the re-entry and previous-room cases, then regenerate the markdown.”

    Action/result: Updated tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  758. Reported: “The evidence chapter is regenerated. I’m updating the room-switch prose, compatibility commands, current-status handoff, clean-room notes, and progress log.”

    Action/result: Began docs updates for variable-room boundary validation.

  759. Reported: “I’m patching those sections so they explicitly say both immediate and variable-selected room switches now share the same boundary behavior.”

    Action/result: Updated docs/src/logic_bytecode.md, docs/src/compatibility_testing.md, and docs/src/current_status.md.

  760. Reported: “I’m appending a clean-room note section for this run: exact command, matched result, and the fact that it completes the v2 selector coverage for 0x13.”

    Action/result: Added the variable-room entry-boundary selector QEMU validation section to docs/src/clean_room_executable_notes.md.

  761. Reported: “I’ll continue with room-switch object reset behavior using the unmodified interpreter first. I’m going to make a fixture where a persistent object is visible before the switch, then verify the destination room does not retain that draw state.”

    Action/result: Began a targeted room-switch persistent-object reset probe.

  762. Reported: “I’m reading the current helper and comparison code so the new case fits the existing QEMU snapshot harness instead of inventing a new path.”

    Action/result: Inspected logic probe helpers and expected-render comparison behavior.

  763. Reported: “The comparator can already catch ‘extra survivor’ sprites, which is perfect for this. I’m adding two cases now: immediate switch and variable-selected switch, both with a pre-switch active object.”

    Action/result: Planned paired 0x12 and 0x13 object-reset fixtures.

  764. Reported: “The object-reset fixture builder is in. It loads view 11, activates object 10 before the room switch, then expects only the destination-room validation sprite afterward.”

    Action/result: Added room_pre_switch_logic0_code and room_pre_switch_object_reset_case to tools/logic_interpreter_probe.py.

  765. Reported: “The cases are registered and the unit expectations know about them. I’m running the quick local tests and compile check before starting QEMU.”

    Action/result: Added switch_room_removes_preexisting_persistent_object and switch_room_v_removes_preexisting_persistent_object plus unit coverage.

  766. Reported: “Oops, I just noticed the plan still says the local checks are running; they actually passed. I’m correcting that and moving on to the QEMU validation.”

    Action/result: Quick local unit test and py_compile checks passed.

  767. Reported: “Local checks pass. I’m launching the two-case snapshot batch now; if the pre-switch object survives into room 1, the rendered output should mismatch as an extra sprite.”

    Action/result: Started QEMU batch room_object_reset_001.

  768. Reported: “Both object-reset cases matched. That validates the visible effect: an active persistent object from before the room switch is absent in the destination render for both 0x12 and 0x13. I’m documenting that carefully as an observable rendering result, not a complete proof of every object-table field reset.”

    Action/result: QEMU batch room_object_reset_001 matched 2/2 with 0 mismatches and 0 errors.

  769. Reported: “I’ll add the two new case names to the generated opcode evidence, then regenerate the markdown so the action tables point to the new proof.”

    Action/result: Updated tools/logic_opcode_evidence.py evidence rows for actions 0x12 and 0x13.

  770. Reported: “The evidence table is regenerated. I’m updating the higher-level bytecode notes, compatibility testing chapter, and current status with the precise scope of this result.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md and began documentation updates.

  771. Reported: “I’m updating these sections to add the ‘persistent object removed’ observable behavior without overstating it as a full object-field memory reset.”

    Action/result: Updated docs/src/logic_bytecode.md, docs/src/compatibility_testing.md, and docs/src/current_status.md.

  772. Reported: “Now I’ll add the new QEMU command and matched result into the compatibility chapter so the fixture can be rerun later.”

    Action/result: Added the room_object_reset_001 command and result to docs/src/compatibility_testing.md.

  773. Reported: “I’m updating current status with the new observable and the remaining uncertainty around broader room-switch resource/object reset internals.”

    Action/result: Refined docs/src/current_status.md room-lifecycle status.

  774. Reported: “I’m appending the clean-room notes for this object-reset probe: the fixture shape, command, matched result, and the boundary of what it proves.”

    Action/result: Added the room-switch persistent-object reset QEMU validation section to docs/src/clean_room_executable_notes.md.

  775. Reported: “I’ll pick this back up at the object-reset documentation point and then run the full local checks. The useful result we already have is a small but solid one: pre-switch active object drawing does not visibly survive either immediate or variable room switches.”

    Action/result: Resumed from the room-switch object-reset documentation handoff.

  776. Reported: “The repo is exactly where the handoff said it was: variable-room boundary notes are already in place, and the object-reset result still needs its clean-room trail. I’m adding that trail now, including the QEMU command and the narrower interpretation of what the fixture proves.”

    Action/result: Confirmed dirty files and appended the object-reset clean-room evidence section.

  777. Reported: “That note is now in the executable log. Next I’m preserving the user-facing step log, then I’ll validate the code, generated evidence, and mdBook together so the docs don’t drift from the probes.”

    Action/result: Added progress entries for the object-reset probe work.

  778. Reported: “The historical log is caught up through this run. I’m running the usual verification set now: unit tests, mdBook build, and whitespace checks.”

    Action/result: Ran python3 -B -m unittest discover -s tests, mdbook build docs, and git diff --check; all passed.

  779. Reported: “All three checks are green. I’m cleaning up the generated Python cache and then I’ll take one last status/diff snapshot so I can give you a clean handoff.”

    Action/result: Removed tools/__pycache__ and checked status/stat output.

  780. Reported: “The object-reset probe is validated and documented, so I’m going to keep moving rather than stop there. Next I’ll go back to the disassembly first and try to pin down which room-switch helper clears/initializes object state, then I’ll only use QEMU if there’s a specific observable to confirm.”

    Action/result: Shifted from QEMU fixture work back to source-first disassembly analysis of room-switch reset helpers.

  781. Reported: “I’ve got the current handoff notes in view. The next useful static target is code.room.switch_state at image 0x1792 and the dynamic reset helper at 0x1485, because those are where the room switch seems to fan into object/resource cleanup.”

    Action/result: Re-read current status and symbolic labels; searched for room-switch/reset references.

  782. Reported: “One trap popped up in the search output: the whole-file disassembly includes the MZ header, so its printed offsets are not the same as the project’s image offsets. I’m using the focused ndisasm -o image_offset -e image_offset+0x200 form now, which is the reliable one we’ve been documenting.”

    Action/result: Rejected misleading whole-file offset readings and used focused image-offset disassembly.

  783. Reported: “The room-switch body gives a very concrete object-record reset loop: it walks every 0x2b-byte object record and clears only selected fields/bits, while seeding several timing bytes to 1. I’m checking the adjacent helpers now so I can name the calls around that loop instead of leaving them as raw addresses.”

    Action/result: Identified the room-switch object loop at 0x17b6..0x17e5 and inspected helpers around 0x10d0, 0x30d6, 0x4482, and 0x4c23.

  784. Reported: “The static pass found a correction worth making: earlier prose says the room switch clears object bytes +0x1e, +0x1f, and +0x20, but the instructions keep AL = 1 and store 1 into those three bytes. That matters for a portable spec, so I’m going to fix the docs and label the cache-reset helpers while I’m here.”

    Action/result: Determined that room switch seeds object step/frame-timer bytes to 1 rather than clearing them.

  785. Reported: “The object field map confirms those three bytes are step size and frame-timer reload/current counters. I’m checking whether there’s an existing bytecode getter we can use for a small QEMU confirmation, but the spec correction itself already comes straight from the room-switch instruction sequence.”

    Action/result: Re-read object field documentation and opcode getter coverage; no direct bytecode getter exists for all three reset bytes.

  786. Reported: “There’s a second correction in the same static pass: room switching does not wipe the whole logic cache root. The helper at 0x10f7 preserves the first logic cache record and unlinks later records, while separate helpers clear the view, picture, and sound cache roots.”

    Action/result: Mapped helper 0x10d0: 0x10f7 truncates the logic cache to its head, while 0x396d, 0x50cc, and 0x49dc clear view, sound, and picture cache roots.

  787. Reported: “I’m going to make this as a source-backed correction rather than invent a new behavioral claim: exact object bytes from 0x17b6..0x17e5, exact cache reset calls from 0x10d0, and the QEMU result only for the visible persistent-object disappearance.”

    Action/result: Updated docs/src/logic_bytecode.md with the corrected object-reset and cache-reset source model.

  788. Reported: “The bytecode chapter now reflects the corrected reset bytes and cache behavior. I’m adding the same source-backed cache distinction to the logic-resource chapter so future work doesn’t accidentally rebuild the older ‘clear everything’ model.”

    Action/result: Added a room-switch cache reset section to docs/src/logic_resources.md.

  789. Reported: “I’m assigning symbolic names for the newly clarified helpers, since these are exactly the kinds of routines that should carry across later interpreter builds even when addresses move.”

    Action/result: Updated docs/src/symbolic_labels.md with labels for the logic-cache truncation helper, room-cache reset helper, cache-root clear helpers, input reset helper, and cache-root globals.

  790. Reported: “The symbolic map is updated. I’m threading the correction into the status handoff now, so a later session starts from the refined source model instead of the older shorthand.”

    Action/result: Updated docs/src/current_status.md with the corrected room-switch reset model.

  791. Reported: “Before I write the clean-room note, I’m rerunning the key disassembly slices in short form. That gives the documentation a tidy command trail instead of relying on the oversized exploratory dumps.”

    Action/result: Reran compact ndisasm slices for room-switch object reset, room cache reset, view/picture/sound cache root clear helpers, and input reset.

  792. Reported: “The compact slices confirm the correction cleanly. I’m appending the source-pass note now: what changed, what commands support it, and what remains dynamic/QEMU-backed versus source-backed.”

    Action/result: Added the room-switch object/cache reset source-correction section to docs/src/clean_room_executable_notes.md.

  793. Reported: “Verification is green again. I’m doing one last scan for the old incorrect wording and then I’ll summarize where we landed.”

    Action/result: Ran the final test/book/whitespace verification set; an initial wording-scan command failed because shell backticks in the search string were not quoted safely.

  794. Reported: “That last scan command tripped over shell backticks in the search string, not over the repo. I’m rerunning the wording scan with safer quoting.”

    Action/result: Reran the wording scan and found one older historical clean-room note that still said the room switch clears the logic cache root.

  795. Reported: “The scan found one old historical note still saying ‘clears the logic cache root.’ Since that sentence is now known to be inaccurate, I’m correcting it in place and leaving the new source-correction section as the evidence trail for why.”

    Action/result: Corrected the older clean-room note to say room switching resets caches through 0x10d0, with the later correction identifying that it preserves the first logic cache record and clears view, sound, and picture cache roots.

  796. Reported: “I’ll rerun the wording scan and the lightweight checks after that correction.”

    Action/result: Reran the wording scan, mdbook build docs, and git diff --check. The checks passed; the only remaining scan hit is the intentional correction sentence describing the old wording.

  797. Reported: “I’ll pick up the source-first thread: event/resource recording and restore replay, then connect it back to the logic opcodes and docs. I’ll keep QEMU on the shelf unless the disassembly leaves a behavior ambiguous enough to merit a probe.”

    Action/result: Started a source-first pass over the resource-event recorder and restore replay path, using existing docs and disassembly rather than new QEMU probes.

  798. Reported: “The event recorder shape is already clearer from the disassembly: it is a compact two-byte pair log, gated by both a recording-enable word and flag 7. I’m now chasing every call site so the docs tie the bytecode actions to the replayable resource events instead of treating the event buffer as a side note.”

    Action/result: Disassembled 0x705e..0x714c and the event call sites, mapping the pair buffer base/write/read/count globals, capacity, high-water word, recording gates, and all direct code.event.record_pair callers.

  799. Reported: “One useful connection dropped out: event kind 5 is not a normal resource load at all. It records a four-pair packet for a temporary/display object path at 0x2d52, then restore consumes the next three pairs as parameters before replaying that display operation.”

    Action/result: Mapped restore replay dispatch at 0x681c and helper 0x2d52, identifying event kinds 0..8 and the special kind-5 transient object/display packet format.

  800. Reported: “There is also a nice negative rule in the source: the view-resource text/display helper disables event recording while it loads and later discards a temporary view. So the replay log is intentionally about persistent room state, not every internal resource touch.”

    Action/result: Disassembled 0x5edb, confirming that actions 0x81 and 0xa2 disable event recording around their temporary load/display/discard sequence and re-enable recording before returning.

  801. Reported: “I’m going to update the docs now: symbolic labels first, then the bytecode chapter’s higher-level resource-event model, then the chronological evidence log and status handoff. The edits are documentation-only; no generated artifacts should need to be committed.”

    Action/result: Added symbolic code/data labels for the event recorder, replay cursors, action handlers, transient-display object helper, and temporary view-resource display helper.

  802. Reported: “The bytecode chapter now has the high-level replay model in spec language: pair format, capacity/gates, event-kind meanings, and the special four-pair transient-object packet. I’m adding the clean-room command trail next so the claim remains auditable.”

    Action/result: Updated docs/src/logic_bytecode.md with the replay-log model and appended this source-pass evidence trail to docs/src/clean_room_executable_notes.md.

  803. Reported: “A source detail worth tightening before verification: restore replay disables event recording, and the replay routine itself does not show a matching re-enable call in the slice I read. I’m checking the caller path so the docs don’t overstate that lifecycle.”

    Action/result: Disassembled the restore action caller, the save action for surrounding context, and all observed calls to 0x705e, 0x706d, and 0x681c.

  804. Reported: “The caller check confirms it: the only 0x706d calls in the executable are room switch and the temporary view-display helper. Restore replay and display-mode rebuild call 0x681c, which disables recording, and I don’t see a re-enable on those paths. That’s odd enough to document carefully rather than smooth over.”

    Action/result: Corrected the replay documentation and symbolic label so they no longer imply automatic recording re-enable after restore replay.

  805. Reported: “I’ve corrected the docs so they don’t imply replay turns recording back on. The current model is more honest: replay disables recording, duplicate prevention is clear, but the later lifecycle needs a targeted dynamic check or more source context.”

    Action/result: Added the no-observed-re-enable finding to docs/src/clean_room_executable_notes.md, docs/src/logic_bytecode.md, docs/src/symbolic_labels.md, and docs/src/current_status.md.

  806. Reported: “I’ll take those in order: first settle the replay recording gate from source, then map the save/restore data it depends on, then add only the QEMU validation that gives us new confidence. I’ll keep the docs updated as I go, since this is exactly the sort of trail future us will be grateful for.”

    Action/result: Began a follow-up source-first pass over the replay log, save/restore blocks, and display-mode replay path.

  807. Reported: “The first source pass is already showing a deeper wrinkle: the replay log’s active count appears to be carried through the save/restore block around [0x05e1], but replay itself reads [0x0143]. I’m tracing that carefully now, because it affects whether 0xab/0xac are just script rollback helpers or part of the save/restore contract.”

    Action/result: Re-examined the save/read block helpers and the memory ranges passed by the save and restore action handlers.

  808. Reported: “One of those disassembly slices was shifted by the EXE header offset, so I’m rerunning the save/read helper slices with the correct image offset + 0x200 file skip. This is exactly why keeping the command trail matters; the wrong slice was plausible-looking but not the helper we needed.”

    Action/result: Corrected the image/file-offset relationship used for the whole-file disassembly and reran the relevant save/restore slices.

  809. Reported: “The save-block dependency is now clearer: the first length-prefixed save block is not a tiny [0x05e1] block. It writes 0x05e1 bytes starting at DS:0x0002, which includes the pair count at [0x0143] and capacity at [0x0141]. The actual pair bytes are a later block from [0x1707], and the recording gate [0x170d] is not in either.”

    Action/result: Confirmed that save/restore persist replay capacity and active pair count in the first state block, persist pair bytes in a separate block, and do not persist the recording-enabled gate there.

  810. Reported: “For dynamic validation, a full save/restore UI probe would be useful but expensive and brittle. A better first target is action 0x8c: it calls the same replay routine without involving the save selector UI. If we can build a room-switch fixture that records events and then triggers 0x8c, we get a replay validation path with much less machinery.”

    Action/result: Chose display-mode replay as the first QEMU validation target because it reaches the same replay helper while avoiding the save-slot UI.

  811. Reported: “I’ll make the replay probe use the existing logic harness rather than a new tool. It can already patch AGIDATA.OVL, so if needed I can force the display-mode guard values for this fixture without changing the original DOS image.”

    Action/result: Extended the logic snapshot harness to support per-case launch commands, needed for SIERRA -p -c, and added monitor key mapping for -.

  812. Reported: “For the 0x8c replay fixture, I want the guard to actually enter the replay branch. The source says it requires display hardware word [0x112e] == 0 and mode word [0x1130] not 2 or 3, so I’m checking whether our fixture overlay starts that way or whether we need a small AGIDATA.OVL patch.”

    Action/result: Checked SQ2/AGIDATA.OVL; the words at 0x112e and 0x1130 initialize to 0xffff, so the QEMU fixture patches both words to zero and launches with SIERRA -p -c.

  813. Reported: “I’m picking the replay thread back up from the source-first angle: finish the save/restore dependency map, add the least brittle dynamic check, then fold it back into the spec. I’ll also preserve these working updates in the progress log before I make new substantive edits.”

    Action/result: Reviewed current docs, harness state, and diffs before continuing the replay probe.

  814. Reported: “The replay harness change is in place, and the regular unit suite passes. The first QEMU run is interesting in exactly the useful way: the engine reaches the display-mode replay fixture, but the visible background is still the second picture. I’m going back to source and memory state before assuming the replay model is wrong.”

    Action/result: Initial QEMU display-mode replay probe produced a screenshot mismatch against the first-picture hypothesis, while confirming the fixture reached the expected visual state after 0x8c.

  815. Reported: “I’m adding a second replay case that uses flag 7 instead of 0xab/0xac. If the source model is right, both should exclude the second picture from the event log; if the screen still shows the second picture, the missing piece is in display refresh rather than the log gates.”

    Action/result: Added display_mode_replay_skips_flag7_unrecorded_picture beside the 0xab/0xac rollback case.

  816. Reported: “Both replay probes show the same visible result: the second-picture background remains. That narrows it nicely: either 0x8c is not taking the replay branch under this launch mode, or the replay branch rebuilds resource state without clearing the currently visible CGA buffer. I’m checking memory around [0x112e], [0x1130], and the event buffer next.”

    Action/result: Switched from screenshot comparison to a direct QEMU memory probe of display-mode words and replay-log state.

  817. Reported: “The QEMU memory probe found the branch did execute: [0x1130] changed from 0 to 1 after 0x8c. The event log also excludes the flag-7 picture as expected. So the surprising part is display-buffer behavior, not the replay-pair gate.”

    Action/result: With DS = 0x16a5, reads showed [0x112e] = 0, [0x1130] = 1, capacity 0x32, pair count 8, and recording enabled again after the later script action.

  818. Reported: “The pair buffer is wonderfully concrete: it has room-switch logic 1, picture 0 load/prepare, view 11 load, and the final transient object packet. No picture 1 event is present. I’m capturing one fresh screenshot from the same paused VM so we can tie the memory evidence to the visible mismatch.”

    Action/result: Decoded the pair buffer as (0,1), (2,0), (4,0), (1,11), (5,0), (11,0), (0,50), (80,255) and captured the same visible background as the earlier automated run.

  819. Reported: “Fresh capture from the memory-probed VM has the same result: the log excludes picture 1, 0x8c toggled display mode, but the screen still shows picture 1’s color. I’m going to change the automated cases so they validate the observed screen behavior, while documenting the memory probe as the stronger evidence for replay-log semantics.”

    Action/result: Updated the replay fixture expectations to compare against the visible second-picture background instead of the initial first-picture hypothesis.

  820. Reported: “I’ll pick this back up from the replay work and keep it source-first. I’m going to check the current diffs and the doc spots that need to be brought into line with the QEMU memory probe before I edit anything.”

    Action/result: Reviewed the working tree, replay-related docs, and the code/test diffs for the launch-command and replay-fixture changes.

  821. Reported: “The current tree has the replay probe code changes, but the docs still contain the earlier no re-enable observed wording. I also found the new progress section inserted into an old fuzz section; I’ll move that history to the chronological tail so the log stays readable.”

    Action/result: Identified the stale replay lifecycle language and the misplaced progress section.

  822. Reported: “I’m going to patch the docs in one pass: correct the replay lifecycle wording, add the memory-probe evidence, connect kind-4/kind-5 replay back to graphics/object rendering, and move the misplaced progress section to the end with the new updates appended.”

    Action/result: Started the documentation patch pass.

  823. Reported: “I’m editing now. First pass is housekeeping: remove the replay section from the middle of the older fuzz chronology and append it after the current logic-interpreter entries with the newer replay-memory findings.”

    Action/result: Removed the misplaced replay progress section from the synthetic picture fuzz chronology.

  824. Reported: “That misplaced section is out of the fuzz chapter now. I’ll append it at the chronological end, keeping the earlier updates and the fresh observations together so the evidence trail reads in order.”

    Action/result: Appended the replay follow-up progress entries here.

  825. Reported: “The progress log now has the replay work in the right chronological spot. Next I’m tightening the spec language so it says what we actually know: replay-pair duplicate suppression is confirmed, but the later recording lifecycle and visible buffer behavior have sharper caveats.”

    Action/result: Updated the replay model in logic_bytecode.md, current_status.md, and symbolic_labels.md.

  826. Reported: “The compatibility chapter now separates the screen assertion from the memory-backed replay semantics. I’ll add the graphics/object pipeline connection next, since replay kind 4 and kind 5 are where the resource log actually turns back into drawn pixels.”

    Action/result: Linked replay event kinds 4, 5, and 8 to picture decode, overlay decode, and transient-object drawing in graphics_object_pipeline.md.

  827. Reported: “The clean-room notes now have the corrected save layout and the QEMU memory probe. I’m going to scan for stale replay wording before running the executable checks.”

    Action/result: Appended the save-block correction, static recording-gate scan, and display-mode memory probe to clean_room_executable_notes.md.

  828. Reported: “The first wording scan accidentally let shell backticks run as commands, so that result is just a quoting miss. I’m rerunning it with single quotes and then I’ll move into tests.”

    Action/result: Reran the scan safely; only intentional current caveats and historical correction wording remained.

  829. Reported: “The unit suite is green and the whitespace check is clean. I’m running the two replay fixtures against the original engine now; this is the slowest check because it boots QEMU and captures the screenshots.”

    Action/result: python3 -B -m unittest discover -s tests passed with 99 tests, git diff --check passed, and the first QEMU replay batch started.

  830. Reported: “The first replay fixture still mismatched, so I’m not going to paper over it. I’ll inspect the generated report and capture comparison to see whether the expected B background is mapped differently in this launch mode, or whether the local expected picture setup is still not matching the original screen.”

    Action/result: The generated report showed the capture and expectation were not a plain first-picture or plain second-picture match.

  831. Reported: “I misread the tuple direction from the report. In this harness, samples are (x, y, captured, expected): QEMU is showing nibble 6 and the new expected payload is nibble 4. I’m checking the old manual capture and an A-vs-B local comparison now, because the fixture should follow the evidence rather than my earlier shorthand.”

    Action/result: Compared the capture against both single-picture expectations and confirmed neither matched.

  832. Reported: “Neither plain A nor plain B matches: row 0 looks like nibble 6, while row 1 and onward show nibble 4 in the sample set. That points to the display-mode toggle changing the screen interpretation or row mapping. I’m sampling the downsampled capture by row before changing the fixture expectation.”

    Action/result: Downsampled row sampling showed an alternating pattern: even rows are nibble 6, odd rows are nibble 4.

  833. Reported: “The capture is an alternating-row display: even logical rows are nibble 6, odd rows nibble 4. I’m changing the replay fixtures to expect that interleaved background, which matches the actual display-mode effect better than either single-picture hypothesis.”

    Action/result: Added alternating_row_picture_payload() and changed both replay cases to use it as the expected background.

  834. Reported: “The remaining 62 pixels are the validation sprite, not the replay background. Since these cases are about display-mode replay, I’m going to make them background-only instead of mixing in object-color behavior from the toggled display mode. The separate memory probe already covers the replay log.”

    Action/result: Added compare_view=False, skipped the post-replay validation sprite in both replay fixtures, and taught compare_capture() to compare background-only cases.

  835. Reported: “The current spec pages now say row-interleaved and note that the automated comparison is background-only. I’m correcting the clean-room note’s result wording too.”

    Action/result: Replaced the earlier second-picture shorthand in current docs with the row-interleaved display observation.

  836. Reported: “Unit tests are green at 100 tests and whitespace is clean. I’m rerunning the replay QEMU batch with the background-only row-interleaved expectation.”

    Action/result: The corrected unit suite passed with 100 tests, and the replay QEMU batch was rerun.

  837. Reported: “The first replay case now matches. QEMU is still running the second case from the same snapshot, so I’ll let it finish and then inspect the report.”

    Action/result: Both replay cases matched QEMU with 2 matches, 0 mismatches, and 0 errors.

  838. Reported: “Both corrected replay cases match QEMU now. I’m recording that result in the compatibility and clean-room notes, then I’ll run mdBook.”

    Action/result: Added the passing build/logic-interpreter-probes/batches/replay_visible_001.json result to compatibility_testing.md and clean_room_executable_notes.md.

  839. Reported: “The compatibility chapter has the passing replay-batch result. I’m adding the same outcome to the clean-room entry beside the harness changes.”

    Action/result: Completed the clean-room result note for the corrected replay batch.

  840. Reported: “Clean-room notes have the successful batch result. I’m appending the latest working updates to the progress log so the failed hypothesis and correction are preserved rather than erased.”

    Action/result: Added progress entries for the single-picture mismatch, row-interleaving discovery, background-only harness correction, and QEMU replay success.

  841. Reported: “The progress log now records the failed single-picture hypothesis, the row-interleaving discovery, and the passing QEMU rerun. I’m building the mdBook now.”

    Action/result: mdbook build docs succeeded and git diff --check passed.

  842. Reported: “mdBook builds cleanly and whitespace is still clean. I’ll do one final wording scan and status check before wrapping this pass.”

    Action/result: Checked replay wording, working-tree status, diff stat, and the corrected QEMU replay report.

  843. Reported: “The final scan only finds historical progress-log text for the earlier working hypothesis plus the current row-interleaved wording. I’m logging the last verification steps, then I’ll rebuild mdBook once more because the progress log is itself a docs change.”

    Action/result: Recorded this final progress-log update before the last docs build.

  844. Reported: “That framing makes sense: I’ll treat the row-interleaving as a display-adapter/mode artifact, not as normative AGI semantics for the EGA path. I’m going source-first through the 0x8c display refresh chain now, with QEMU only if the disassembly leaves a specific ambiguity worth checking.”

    Action/result: Started a source-first pass over startup display-mode selection, 0x8c, display refresh helpers, and graphics overlays.

  845. Reported: “The source scan is already separating two things: the row-interleaving fixture deliberately forces hardware selector [0x112e] == 0 and toggles mode [0x1130] from 0 to 1, which is not the normal full EGA path. I’m tracing where startup assigns EGA values and where the graphics overlay branches on those words.”

    Action/result: Disassembled the command-line parser, display auto-detect, 0x8c, cursor-save/restore helpers, and logical-buffer clear/display helpers.

  846. Reported: “The static path is pretty telling: command-line -c sets [0x1130]=0, -r sets [0x1130]=1, and -p forces [0x112e]=0. The EGA-ish auto-detected/full-color path is elsewhere in startup and does not satisfy 0x8c’s hardware guard, so I’m digging into the overlay entry that only runs for [0x112e]==0.”

    Action/result: Disassembled the graphics overlay entry tables for EGA, CGA, VGA-like, and JR/Tandy-like overlays.

  847. Reported: “There’s a better explanation than old picture leaking through: the CGA overlay’s color mapper returns two bytes in mode 1, so replaying recorded color 6 after 0x8c can itself produce alternating visible colors. I’m checking the AGIDATA tables that the CGA overlay indexes now; that will tell us whether odd-row color 4 is actually the mode-1 mapping for color 6.”

    Action/result: Inspected AGIDATA.OVL:0x1d36 and confirmed the CGA overlay uses a three-byte-per-color table, with mode 1 returning a two-byte word.

  848. Reported: “The CGA table backs that up: for [0x112e]==0, the color mapper indexes three bytes per color in AGIDATA.OVL:0x1d36 and uses a two-byte mapping when [0x1130]==1. So the odd rows are more likely the recorded picture being redrawn under a different CGA mapping, not the unrecorded picture surviving. I’m checking the overlay selection code next so the docs can say why this is out of the EGA target path.”

    Action/result: Confirmed from source that 0x5685 returns colors unchanged for non-CGA/EGA-target paths and delegates to the overlay mapper only for hardware selector [0x112e] == 0 with modes other than 2 or 3.

  849. Reported: “The replay path also clears before drawing: 0x4acf -> 0x6445 -> 0x5257(0x4f4f) resets the logical picture buffer, then decodes the recorded picture. That rules out a persistent unrecorded-picture buffer as the primary explanation. I’m updating the docs and labels to classify this as a CGA-only mode-toggle artifact, outside the EGA target semantics.”

    Action/result: Updated the bytecode chapter, compatibility chapter, graphics pipeline, current status, harness descriptions, and symbolic labels to classify the row-interleaved fixture as CGA-only remapping.

  850. Reported: “I’m making a small but important correction now: the fixture names still describe the event-log exclusion, but their descriptions and docs should say the visible rows come from CGA remapping of the replayed recorded picture, not from the second picture surviving.”

    Action/result: Corrected the replay case descriptions in tools/logic_interpreter_probe.py.

  851. Reported: “The bytecode and compatibility chapters now say this is CGA-only remapping, not replay leakage. I’ll add the source trail to the graphics pipeline chapter and symbolic labels.”

    Action/result: Added the CGA color-map explanation to graphics_object_pipeline.md.

  852. Reported: “The graphics pipeline now explains the CGA mapper. I’m adding stable labels for the main color mapper, the CGA overlay mapper, and the data table so later interpreter-version comparisons can track this by role.”

    Action/result: Added symbolic labels for 0x5685, the CGA overlay mapper at near 0x9815, and AGIDATA.OVL:0x1d36.

  853. Reported: “Symbolic labels are in. I’ll update the handoff status so the next session doesn’t treat the CGA row effect as an EGA compatibility requirement.”

    Action/result: Updated current_status.md with the CGA-only/EGA-target distinction.

  854. Reported: “I’m adding the evidence trail now: startup flags, the 0x8c guard, 0x5685, CGA overlay 0x9815, the AGIDATA.OVL:0x1d36 color table, and the picture decode clear that rules out buffer leakage.”

    Action/result: Appended the source-backed correction section to clean_room_executable_notes.md.

  855. Reported: “The clean-room notes now have the correction and command trail. I’m appending the progress-log entries for this turn, then I’ll run the normal checks.”

    Action/result: Recorded this progress-log update before verification.

  856. Reported: “The documentation updates are in. I’ll scan for stale unrecorded picture supplies odd rows wording, then run tests, mdBook, and whitespace checks.”

    Action/result: The stale-wording scan found only intended corrected wording and historical progress text. python3 -B -m unittest discover -s tests passed with 100 tests, mdbook build docs succeeded, and git diff --check passed.

  857. Reported: “The scan only finds the intended corrected wording and historical progress text. Tests, mdBook, and whitespace all passed; I’ll record that final verification in the progress log and do one last mdBook/whitespace pass because the log changed.”

    Action/result: Recorded this final verification note before the last docs build.

  858. Reported: “I’ll take the recommended slice: source-first mapping of the event/replay/restore machinery, with QEMU only if the disassembly leaves a behavior question. I’ll update the historical progress log as I go so the trail stays intact.”

    Action/result: Began the replay/restore source pass and checked current status, recent clean-room notes, labels, and git status.

  859. Reported: “The current docs already contain a decent first pass on event pairs, but there’s still a gap around exactly what save/restore writes back and where recording becomes enabled again. I’m narrowing onto those routines now, with the source addresses already named in the labels file.”

    Action/result: Re-read the prior resource-event and save/restore notes plus the existing symbolic labels.

  860. Reported: “A useful correction is already staring at us: the save block explicitly excludes data.event.recording_enabled, and the static scan only found two enable calls. I’m going to re-read the raw routines around restore/replay and the callers, because the unresolved piece is probably not a hidden write but a control-flow path we haven’t named cleanly yet.”

    Action/result: Re-disassembled the replay, event helper, restore, and display-toggle routines.

  861. Reported: “The disassembly confirms the replay routine starts by stopping/clearing runtime display state, disabling event recording, and then consuming the pair stream. The restore action then performs several display/menu refreshes after replay, but still no obvious re-enable in that immediate path. Next I’m checking the saved state helpers and the room-switch enable path so the spec can distinguish ‘saved data’ from ‘runtime-only gate.’”

    Action/result: Re-read logic-cache serialization, room-switch setup, and temporary view-resource display helpers.

  862. Reported: “Found the likely missing link. In the earlier replay disassembly, the jump table bytes caused ndisasm to misparse the instruction immediately after the table; if I start disassembly at the loop-exit target itself, the first instruction should be the re-enable call. I’m checking that precise target now before changing the docs.”

    Action/result: Disassembled at image 0x6927 and confirmed call 0x706d, the event-recording re-enable helper.

  863. Reported: “That resolves the dynamic/static mismatch: replay disables recording while rebuilding resources, then explicitly calls code.event.enable_recording at image 0x6927 after the replay-pair loop. The earlier static scan missed it because the jump table bytes swallowed the E8 43 07 instruction when disassembled linearly.”

    Action/result: Promoted the post-loop re-enable from hypothesis to source-backed behavior and updated the plan.

  864. Reported: “I’ve got enough to edit. The core change is not a new behavior, but a better source map: 0x681c contains both the temporary recording disable and the post-loop re-enable at 0x6927, with the event-kind jump table at 0x6915 sitting right before it.”

    Action/result: Patched logic_bytecode.md with the corrected replay lifecycle.

  865. Reported: “The bytecode chapter now has the corrected replay lifecycle: disable during pair replay, re-enable at the post-table exit target, then rebuild visible state. Next I’m touching the labels and handoff docs so future cross-version work has the right anchors.”

    Action/result: Updated symbolic labels for the re-enable helper, replay dispatch table, replay finish target, and replay entry.

  866. Reported: “Labels now include the replay jump table and the post-loop re-enable target. I’m updating the status/compatibility prose so the current project state no longer carries the older open question.”

    Action/result: Updated current_status.md, graphics_object_pipeline.md, and compatibility_testing.md.

  867. Reported: “That patch missed because the status paragraph has slightly different wrapping. I’m reading that exact block and will patch it with the current text shape.”

    Action/result: Re-read the status paragraph and applied the corrected patch.

  868. Reported: “The narrative docs now agree on the corrected replay gate lifecycle. I’m adding the evidence section to the chronological clean-room notes, including why the earlier scan failed.”

    Action/result: Added the clean-room note section for the replay re-enable source correction.

  869. Reported: “The clean-room notes now preserve the command trail and the correction. I’m appending the matching progress-log entries for this turn, then I’ll scan for stale wording.”

    Action/result: Recorded this progress-log batch before stale-wording scans and verification.

  870. Reported: “The stale scan found only the historical section that originally recorded the unresolved state. I’m going to annotate that old paragraph so readers immediately see it was corrected by the later source pass, while preserving the history.”

    Action/result: Patched the earlier clean-room note to point to the 0x6927 correction instead of leaving a dangling unresolved statement.

  871. Reported: “That old note now points forward to the correction instead of leaving a dangling open question. I’ll rerun the stale-wording scan and then verification.”

    Action/result: Reran the stale-wording scan and git diff --check; both were clean.

  872. Reported: “The stale scan is clean and whitespace checks pass. I’m running the mdBook build plus the local unit suite now; there were no decoder/parser code changes, but this is a useful sanity check after touching the spec around tests.”

    Action/result: mdbook build docs succeeded and python3 -B -m unittest discover -s tests passed with 100 tests.

  873. Reported: “Both checks passed: mdBook built cleanly and the 100-test unittest suite is green. I’m recording that verification in the progress log, then I’ll rebuild once more because the log itself is part of the book.”

    Action/result: Recorded this verification note before the final mdBook build.

  874. Reported: “Final verification pass is running now: mdBook after the progress-log update, plus a last whitespace/status check.”

    Action/result: mdbook build docs and git diff --check passed; status showed only the intended modified docs plus the expected untracked 002962_ms_dos_622/ and build/ directories.

  875. Reported: “The final build and whitespace pass are clean; only the intended docs are modified, with build/ and the DOS images still untracked. I’m adding that last verification note to the log and doing one no-comment rebuild after it.”

    Action/result: Recorded the final verification note before a no-comment mdBook rebuild.

  876. Reported: “I’ll build this as a living project dashboard rather than a throwaway checklist: opcode coverage plus broader engine areas, with explicit status labels and evidence pointers. I’ll read the current opcode docs/generator first so the names match what we already use.”

    Action/result: Started the PROGRESS.md pass and checked the current git status, AGENTS instructions, and opcode evidence generator.

  877. Reported: “One search command tripped over unescaped backticks in the shell, so I’m ignoring that output and using the local opcode tables directly. The evidence generator imports the canonical ACTION_NAMES and COND_NAMES, which is exactly what we want for a no-drift progress file.”

    Action/result: Used the local opcode-name and evidence tables from tools/disassemble_logic.py and tools/logic_opcode_evidence.py.

  878. Reported: “I’m going to generate the opcode checklist text from the existing clean-room tables rather than hand-copying 195 labels. That keeps PROGRESS.md aligned with tools/disassemble_logic.py and the evidence matrix.”

    Action/result: Generated the action/condition opcode checklist from the local Python tables, writing only via apply_patch.

  879. Reported: “The generated checklist shows only a handful of opcode entries are still at dispatch-smoke or source-backed level; most action and condition rows have focused QEMU evidence. I’ll fold that into a broader dashboard so it’s useful for ‘how close are we’ at a glance, not just as an opcode dump.”

    Action/result: Counted opcode evidence levels: 148 QEMU-validated action opcodes, one structural action opcode, 27 dispatch-smoke action opcodes, 18 QEMU-validated condition opcodes, and one source-backed condition.

  880. Reported: “I’m creating PROGRESS.md now with a simple ASCII status legend: [x] for sufficiently specified/evidenced, [~] for partial or smoke/source-backed, and [ ] for not yet covered. The opcode section will stay compact, while the engine-area section will carry the real remaining-work list.”

    Action/result: Added root PROGRESS.md with structural bytes, all action opcodes, all condition opcodes, subsystem coverage areas, and highest value remaining work.

  881. Reported: “PROGRESS.md is in place with all action opcodes, condition opcodes, structural bytes, and subsystem coverage areas. I’m updating AGENTS.md now so future work treats this as a maintained dashboard, not a one-time snapshot.”

    Action/result: Updated AGENTS.md to require keeping PROGRESS.md aligned with opcode/status and subsystem progress.

  882. Reported: “The agent instructions now point future work at PROGRESS.md and define when it must be updated. I’m adding the corresponding progress-log entries, then I’ll run the book and whitespace checks.”

    Action/result: Recorded this progress-log batch before validation.

  883. Reported: “Validation is running now. Since this is documentation/tracking rather than decoder code, the key checks are mdBook and whitespace; I’ll also run the existing unittest suite so we don’t unknowingly disturb the broader working set.”

    Action/result: mdbook build docs succeeded, git diff --check passed, and python3 -B -m unittest discover -s tests passed with 100 tests.

  884. Reported: “All checks passed: mdBook, whitespace, and the 100-test suite. I’m recording that validation in the progress log and then doing one last mdBook/whitespace pass because the log changed.”

    Action/result: Recorded the validation result before the final post-progress-log checks.

  885. Reported: “Final pass is just making sure the freshly updated progress log still renders cleanly and has no whitespace issues.”

    Action/result: mdbook build docs and git diff --check passed. Status showed the expected modified docs and untracked PROGRESS.md, plus a generated tools/__pycache__/ directory from the Python checks.

  886. Reported: “The final checks passed, and running the Python helpers left a generated tools/__pycache__/ behind. I’m cleaning only that generated cache directory; the requested PROGRESS.md stays untracked until you decide whether to commit.”

    Action/result: Removed generated tools/__pycache__/.

  887. Reported: “Cache cleanup is done. I’m recording the final verification/cleanup note and doing one last lightweight status/build check so the handoff is tidy.”

    Action/result: Recorded the final cleanup note before the last status and mdBook checks.

  888. Reported: “I’ll treat this as a real work batch: first I’ll read the current tracker and harnesses, then I’ll promote only the opcode coverage that the probes or disassembly actually justify, add the raw-key condition probe, and update the docs/test suite as evidence lands.”

    Action/result: Began the Highest-Value Remaining Work pass and set the active checklist for tracker, opcode, raw-key, graphics, state-machine, and verification work.

  889. Reported: “I’m reading the tracker and the probe/evidence scripts now so I can distinguish already-tested behavior from smoke coverage. That should keep the next edits from accidentally overstating what we know.”

    Action/result: Read PROGRESS.md, tools/logic_interpreter_probe.py, tests/test_logic_interpreter_probe.py, and git status.

  890. Reported: “The tracker is current and the harness already has many cases; the fastest useful path is to add a raw-key condition case and promote only opcodes with existing behavior probes behind them. I’m narrowing in on the event/input helpers and the overlay cases now.”

    Action/result: Searched the logic, picture, view, overlay, and docs harnesses for raw-key, dispatch-smoke, replay, sound, and graphics edge evidence.

  891. Reported: “I’m picking up exactly where the last pass left off: first I’m checking the existing opcode evidence mappings and the focused probe definitions so I can promote only things the disassembly/probes really support.”

    Action/result: Re-read the relevant logic probe case definitions and opcode evidence maps.

  892. Reported: “The existing suite already has one strong replay case for 0xab/0xac, and a sound completion case that observes the 0x63/0x64 flag path rather than just ‘it returned.’ I’m checking the disassembly notes around the raw-key predicate before I add a probe for it.”

    Action/result: Reviewed raw-event queue documentation, symbolic labels, and source-backed notes for condition 0x0d.

  893. Reported: “The raw-key predicate is source-mapped well enough to make a tight test: it calls the raw event helper directly, so the probe should press a plain key and draw only after 0x0d sees the nonzero low byte. Next I’m making that case and adding a couple of valid edge-render cases that are cheap to keep in the compatibility suite.”

    Action/result: Identified the raw-key probe shape and the view/object edge cases to add.

  894. Reported: “I have enough context to edit now. I’m going to keep the code changes narrow: one raw-key condition helper/case, a small --case filter for the overlay batch so focused QEMU runs are practical, two clip cases, and then the evidence/docs tracker updates that tie those to the clean-room record.”

    Action/result: Began code edits in the logic and object overlay probe harnesses.

  895. Reported: “Before editing, I also found that the overlay harness always ran its entire base set. I’m adding the same repeated --case filtering the logic harness already has, because it will make future original-engine graphics checks much faster and less noisy.”

    Action/result: Added selected-case loading and CLI filtering to tools/object_overlay_probe.py.

  896. Reported: “One subtle evidence point: I’m not going to claim the whole sound system is specified. The existing sound_stop_sets_completion_flag case does validate the opcode-level contract for load sound, start sound with completion flag, and stop sound sets that flag, so I’ll promote those opcode rows while leaving audio playback semantics as partial.”

    Action/result: Scoped the sound opcode promotion to load/start/stop completion-flag behavior only.

  897. Reported: “I’m applying the code edits now. After this I’ll run the focused raw-key probe under QEMU; if it matches, the last condition opcode can move from source-backed to QEMU-validated.”

    Action/result: Added raw_key_event_available_condition() and the raw_key_event_available_draws_after_typed_key logic probe case.

  898. Reported: “The raw-key probe is in place. I’m adding the focused overlay filtering and the missing left/top clip cases next, so graphics compatibility can grow without needing a full 20-plus-case run every time.”

    Action/result: Added focused overlay cases for left-edge and top-edge placement.

  899. Reported: “The overlay harness now has --case, matching the logic harness. I’m tightening the tests around those new IDs and the filter behavior before I do any emulator runs.”

    Action/result: Added unit assertions for the raw-key case, overlay case IDs, overlay filtering, and top-edge expected-position override.

  900. Reported: “The logic test now tracks the new raw-key case. Next I’m adding overlay test assertions for left/top clipping and proving the new case filter keeps its ordering and rejects unknown IDs.”

    Action/result: Completed overlay test updates.

  901. Reported: “The tests now cover the new fixture selectors. I’m updating the opcode evidence generator next so the docs and PROGRESS.md don’t drift from the actual harness cases.”

    Action/result: Promoted 0x62, 0x63, 0xab, 0xac, and condition 0x0d in tools/logic_opcode_evidence.py, pending dynamic validation of the new raw-key case.

  902. Reported: “The focused unit tests pass. I’m running the raw-key case in the original interpreter now; this is the piece that decides whether condition 0x0d can be promoted rather than just source-described.”

    Action/result: Ran python3 -B tools/logic_interpreter_probe.py --dos-prefix RK ... --case raw_key_event_available_draws_after_typed_key; it matched QEMU with 1 match and 0 mismatches.

  903. Reported: “The raw-key probe matched under QEMU: one typed x was enough for condition 0x0d to trigger the validation draw, without any key mapping. I’m doing the small overlay clip run now so the new graphics cases have original-engine evidence too.”

    Action/result: Started the two-case object overlay QEMU batch.

  904. Reported: “The overlay run hit the sandbox’s VNC socket restriction, the same one we’ve seen before. I’m rerunning the identical command with escalation so QEMU can bind its local VNC display.”

    Action/result: The first overlay run failed with QEMU VNC bind permission error; the escalated rerun matched QEMU with 2 matches and 0 mismatches.

  905. Reported: “The clip batch matched both cases in the original interpreter. I’m regenerating the opcode evidence chapter now, then I’ll fold the new QEMU results into the spec, tracker, and progress log.”

    Action/result: Ran python3 -B tools/logic_opcode_evidence.py.

  906. Reported: “The generated evidence matrix is current. I’m editing the human-readable chapters next: raw-key behavior, the promoted sound/replay opcodes, the graphics clip captures, and concise state machines for implementation work.”

    Action/result: Began documentation updates across bytecode, compatibility, graphics, runtime model, clean-room notes, and tracker.

  907. Reported: “One small cleanup before documenting: the new left-edge fixture is really ‘flush against the left edge,’ not a negative-X clip, because script operands are bytes. I’m correcting that wording so the case name doesn’t smuggle in a false interpretation.”

    Action/result: Corrected the left_clip_view11_priority15 description.

  908. Reported: “I’m converting the results into implementation-facing docs now. The key change is to separate ‘validated observable contract’ from ‘everything about the subsystem’: sound load/start/stop has opcode-level flag evidence, while actual playback/audio timing remains explicitly partial.”

    Action/result: Updated logic_bytecode.md with raw-key, sound, and replay rollback evidence.

  909. Reported: “The bytecode chapter now records the raw-key match and the sound/replay promotions. I’m adding the graphics edge-capture notes and the state-machine summaries next.”

    Action/result: Updated graphics_object_pipeline.md with the clip_edges_001 result.

  910. Reported: “The graphics chapter now names the new clip batch. I’m putting the subsystem state machines in runtime_model.md, where future implementers or agents will naturally look for the language-neutral model.”

    Action/result: Added resource lifecycle, object drawing lifecycle, and motion/animation state-machine tables to runtime_model.md.

  911. Reported: “The state-machine section is in place. I’m updating the compatibility chapter so the commands somebody reruns later include the new raw-key and overlay-filter cases, not just the older broad batches.”

    Action/result: Updated compatibility_testing.md with raw-key, clip-edge, sound, and replay-rollback validation notes.

  912. Reported: “The compatibility docs now point at the focused replayable commands. I’m updating PROGRESS.md to reflect what actually moved: four action opcodes promoted, the final condition opcode validated, and the high-value list revised to the next frontier.”

    Action/result: Updated opcode counts, condition status, subsystem evidence, and highest-value remaining work in PROGRESS.md.

  913. Reported: “PROGRESS.md is updated. I’m adding the clean-room evidence trail now, including the failed sandboxed QEMU attempt and the successful escalated rerun so the history stays reproducible.”

    Action/result: Added the raw-key/edge-render evidence section to docs/src/clean_room_executable_notes.md.

  914. Reported: “The clean-room notes have the new command evidence. I’m appending the user-facing progress updates now, then I’ll run the full test and book checks.”

    Action/result: Appended this progress-log batch before validation.

  915. Reported: “The documentation pass is complete. I’m running the full local suite, the generated evidence check, the mdBook build, and whitespace checks now.”

    Action/result: Ran python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check.

  916. Reported: “All four checks passed: 102 unit tests, evidence matrix --check, mdBook, and git diff --check. I’m recording that validation in the progress log and then I’ll do a final lightweight status/whitespace check because the log changed.”

    Action/result: Recorded the successful validation result before final status and whitespace checks.

  917. Reported: “Final mdBook and whitespace checks still pass after the validation log entry. I’m doing the last internal wrap-up now: marking the checklist complete and preparing the concise summary with the exact QEMU batches and checks that passed.”

    Action/result: Final mdBook and whitespace checks had passed; the plan was marked complete before this final log correction.

  918. Reported: “I just sent one more status update, so I’m adding that to the progress log too before the final checks. Tiny bookkeeping, but it keeps the historical trail honest.”

    Action/result: Added this final progress-log correction before rerunning final mdBook and whitespace checks.

  919. Reported: “I’ll commit the finished reverse-engineering batch now, staging only the tracked source/docs/test changes and leaving the generated build/ and DOS installer images alone.”

    Action/result: Began the requested commit pass and confirmed only tracked source/docs/test files would be staged.

  920. Reported: “I added the commit-prep update to the progress log, so the evidence trail still matches what you saw. I’m doing the quick doc/whitespace check for that tiny log change and then I’ll create the commit.”

    Action/result: Added the final commit-prep progress note before re-running mdBook and whitespace checks.

  921. Reported: “I’ll take the next slice from PROGRESS.md: first I’ll read the current remaining-work list and partial opcode rows, then pick a source-backed target that can be turned into concrete probes or implementation-ready docs without overclaiming.”

    Action/result: Started the next PROGRESS-driven work pass.

  922. Reported: “The tracker is pointing pretty clearly at text/input UI now: most remaining partial opcodes are in that cluster, and the current screenshot harness is weak for text-plane state. I’m checking the QEMU harness shape to see whether a small memory-observation probe would let us validate those globals directly instead of only ‘it returned.’”

    Action/result: Read PROGRESS.md, QEMU snapshot helpers, text/input docs, and partial opcode evidence.

  923. Reported: “There’s one good quick win in the remaining list: 0xaa copies the save-description buffer into a string slot, and we can validate it cleanly by patching only the fixture’s AGIDATA.OVL buffer to look and comparing it against a normal message-backed string slot. I’m going to add that probe, then use this same pass to add a text/input UI state-machine summary.”

    Action/result: Selected an initial 0xaa probe candidate and a text/input state-machine documentation target.

  924. Reported: “The 0xaa case is nice because it exercises saved-state-adjacent behavior without needing a memory probe or BIOS text rendering. I’m making it a normal draw-if fixture so it can live in the reusable compatibility suite.”

    Action/result: Added a provisional 0xaa draw-if fixture and evidence mapping.

  925. Reported: “The new 0xaa fixture and evidence mapping are in place. I’m running the focused unit test and regenerating the opcode matrix before booting QEMU for the new case.”

    Action/result: Focused logic-probe tests passed and the opcode matrix was regenerated.

  926. Reported: “The focused test passes and the evidence matrix regenerated cleanly. I’m running the original-engine QEMU case now to check that 0xaa really copies the patched save-description buffer into the script string slot.”

    Action/result: Ran the provisional 0xaa QEMU fixture; it mismatched.

  927. Reported: “The first 0xaa run did not match, so I’m treating that as useful evidence rather than forcing the promotion. I’m going back to the disassembled handler and the generated fixture bytes to find whether the source buffer address, slot operand, or string terminator assumption is off.”

    Action/result: Inspected the QEMU report, generated AGIDATA.OVL bytes around 0x0e72, and the 0xaa handler disassembly.

  928. Reported: “That mismatch is actually informative: the validation view did not draw, so the runtime 0x0e72 buffer was not equal to the patched file bytes by the time the script ran. I’m not going to promote 0xaa on that. I’m looking for another remaining opcode whose state change can be observed through existing object or logic behavior, and I’ll either pivot or keep this as an attempted-but-not-promoted note.”

    Action/result: Removed the 0xaa promotion plan and searched for a better visible-state target among remaining partial opcodes.

  929. Reported: “I’m pivoting to 0x84 instead: the handler’s source says it clears object 0’s motion mode, and the movement harness already has a clean random-motion stop oracle for the sibling 0x4e. I’ll add a parallel movement case for 0x84, and remove the unpromoted 0xaa fixture from the reusable base set.”

    Action/result: Removed the provisional 0xaa base case/evidence and added the 0x84 movement-probe plan.

  930. Reported: “The helper insert missed the exact location because the action helpers are packed a little differently than I remembered. I’m locating that block and applying the small helper patch against the actual file shape.”

    Action/result: Located the object-action helper block in tools/qemu_fixture.py.

  931. Reported: “Found it. I’m inserting the 0x84 helper alongside the nearby object-motion helpers now.”

    Action/result: Added set_global_0139_and_clear_object0_field_22_action().

  932. Reported: “The movement case is added. It starts random motion on object 0, immediately runs action 0x84, and expects the object to remain at its starting position, matching the source claim that 0x84 clears object 0’s motion byte.”

    Action/result: Added action_84_after_random_motion_stops_motion to the movement harness and tests.

  933. Reported: “Local tests pass for the movement and fixture changes, and the evidence chapter is regenerated. I’m running the focused QEMU movement case now; this should either promote 0x84 or give us another boundary note.”

    Action/result: Focused movement/logic/fixture tests passed and the 0x84 QEMU batch started.

  934. Reported: “The 0x84 QEMU case matched, so that one can move from dispatch-smoke to behavior evidence. I’m updating the docs/tracker now, and I’ll record the 0xaa attempt as deliberately not promoted because the runtime buffer did not retain the fixture-file patch.”

    Action/result: QEMU batch action_84_motion_001 matched with 1 match and 0 mismatches.

  935. Reported: “I’m updating the human docs around 0x84 in three places: the opcode chapter, the movement compatibility commands, and the runtime model. The key wording is that QEMU validates the object-0 motion-byte effect; the broader [0x0139] role remains source-backed.”

    Action/result: Updated logic_bytecode.md and graphics_object_pipeline.md for the 0x84 movement effect.

  936. Reported: “I found the compatibility movement section; I’ll add 0x84 beside the existing 0x4e single-case stop probe because they share the same observable motion-byte contract.”

    Action/result: Added the action_84_motion_001 command and result to compatibility_testing.md.

  937. Reported: “PROGRESS.md now reflects the one-opcode promotion. I’m also adding the failed 0xaa experiment to the ‘attempted but not promoted’ record, because it tells future us not to assume file-patching that buffer is enough.”

    Action/result: Updated action coverage to 154 of 176 and recorded the unpromoted 0xaa probe in compatibility docs.

  938. Reported: “The compatibility docs now keep the failed 0xaa probe out of the registry while preserving why it failed. I’m appending the clean-room command/results section next.”

    Action/result: Added the clean-room notes section for the 0xaa attempt, 0x84 movement probe, and text/input lifecycle model.

  939. Reported: “The clean-room notes have the new command trail. I’m adding this turn’s progress updates to progress_log.md, then I’ll run the full test/book checks.”

    Action/result: Appended this progress-log batch before validation.

  940. Reported: “The progress log is caught up. I’m running the full unit suite, evidence-matrix check, mdBook build, and whitespace check now.”

    Action/result: Ran python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check.

  941. Reported: “All four validations passed: 102 tests, opcode evidence --check, mdBook, and whitespace. I’m recording that result in the progress log, then I’ll do the final status/diff pass.”

    Action/result: Recorded the validation result before final status and diff checks.

  942. Reported: “One final mdBook/whitespace check is needed because I just updated the progress log with the validation result. After that I’ll give you the short handoff.”

    Action/result: Added the final validation-log note before rerunning mdBook and whitespace checks.

  943. Reported: “I added that last update to the log; now I’m doing the actual final check without more commentary unless something fails.”

    Action/result: Added the final progress-log bookkeeping note before the final check.

  944. Reported: “That was the last bookkeeping loop; running final checks now.”

    Action/result: Added the final short bookkeeping note before final mdBook, whitespace, status, and diff checks.

  945. Reported: “I’ll commit the current PROGRESS-driven batch now, staging the tracked docs/tools/tests changes and leaving generated build/ plus installer images untracked.”

    Action/result: Began the requested commit pass and confirmed the intended tracked change set.

  946. Reported: “The docs still build and whitespace is clean after the commit-log note. The tracked change set is staged; I’m creating the commit now.”

    Action/result: Recorded the final commit-status update before committing.

  947. Reported: “I’ll pick up from PROGRESS.md, find the next highest-value open items, and keep the trail in the docs as I go. First I’m going to re-read the current progress map and status so I don’t step on anything already changed.”

    Action/result: Read PROGRESS.md, current git status, recent progress log entries, and searched the remaining-work markers.

  948. Reported: “The tracker is clean after the last commit, and the open work is concentrated in the remaining partial action opcodes plus subsystem writeups. I’m going to read the rest of PROGRESS.md and then choose a small batch that can be grounded in disassembly first, with QEMU only as confirmation.”

    Action/result: Read the engine coverage and highest-value remaining work sections, then searched the partial text/input/system opcodes.

  949. Reported: “There are 22 partial actions left. The quickest useful batch looks like the text/input cluster: several opcodes already have source-backed handlers, and we can turn at least the geometry/status/prompt cases into observable QEMU probes instead of mere ‘it returned’ checks.”

    Action/result: Inspected existing text/input logic probe cases and fixture helpers.

  950. Reported: “The current harness compares rendered pixels, so behavior-level promotion is easiest when an opcode changes where or whether a known object appears. I’m checking how the comparator derives expected frames before I add cases, because a sloppy probe here would only look stronger than it is.”

    Action/result: Read the logic probe comparator and existing runtime text model.

  951. Reported: “Before editing probes, I’m re-reading the actual handler disassembly for the candidate opcodes and nearby helpers. The goal is to make each new fixture test one source-derived state transition, not just discover behavior by poking at the executable.”

    Action/result: Re-read disassembly around text/status/input handlers, including 0x34bd, 0x3726, 0x76ca, and 0x78cb.

  952. Reported: “One promising non-UI target is 0x8e: the disassembly says it changes the resource-event pair capacity, which should have visible consequences during display-mode replay. I’m reading that event buffer code now because it may give us a cleaner QEMU validation than trying to model BIOS text glyphs first.”

    Action/result: Re-read resource-event helpers around 0x705e and 0x716a, plus existing replay docs and tests.

  953. Reported: “0x8e does reset capacity, but overflowing the pair buffer calls the interpreter’s error path, so I’m treating that as a risky validation target for now. I’m looking for cases where changing the capacity resets or narrows a replay log without causing the original engine to walk off into error handling.”

    Action/result: Reviewed existing display-mode replay fixtures and kept 0x8e as a later target.

  954. Reported: “A better first promotion is the rectangle-clear pair 0x69/0x9a: the source says they clear text regions through BIOS scroll/clear helpers, and existing message probes already show formatted text can remain on the captured surface unless we refresh the picture. I’m going to add cases that display text, clear only via those actions, and then compare the clean graphics result.”

    Action/result: Chose the text rectangle clear pair as the focused behavior-promotion target.

  955. Reported: “I’m making the probe change now: two cases, one for the row-clear wrapper and one for explicit rectangle bounds. Both start from source-derived operands and deliberately avoid the 0x1a picture refresh that would mask leftover text.”

    Action/result: Added initial text_rect_clear_rows_removes_formatted_text and text_rect_clear_bounds_removes_formatted_text probe cases.

  956. Reported: “The fixture cases are in place. I’m adding small unit coverage so the case catalog keeps these behavior probes from silently disappearing during later refactors.”

    Action/result: Inspected and prepared updates to tests/test_logic_interpreter_probe.py.

  957. Reported: “The catalog test already has a good ‘known case ids’ check, so I’m just extending that list for the two new behavior probes.”

    Action/result: Added the two text-rectangle behavior case ids to the probe catalog test.

  958. Reported: “Next I’m running the local unit check for the probe catalog, then I’ll run just the two new cases under QEMU. If either case mismatches, I’ll treat that as feedback on my operand assumptions rather than forcing the docs to fit.”

    Action/result: Ran python3 -B -m unittest tests.test_logic_interpreter_probe successfully and reviewed the focused diff.

  959. Reported: “The local probe tests pass. I’m starting a two-case QEMU batch now; this should tell us whether the row and bounded clears really remove the formatted-message residue in the original engine.”

    Action/result: Started text_rect_clear_behaviour_001; the first command used an invalid bare --snapshot option.

  960. Reported: “Small harness wrinkle: this probe runner does not have a bare --snapshot flag, only explicit snapshot image paths. I’m rerunning the same two cases through the normal batch path.”

    Action/result: Reran the two-case text rectangle batch without the invalid option.

  961. Reported: “QEMU is running both cases from a generated snapshot disk now. I’ll wait for the captures and then inspect any mismatch instead of assuming the rectangle operands are right.”

    Action/result: Waited for the QEMU snapshot batch.

  962. Reported: “The row-clear case mismatched, so I’m treating that as a useful correction. I’m inspecting the report and capture now to see whether the clear bounds were wrong, the formatted helper draws somewhere else, or the action is clearing in text coordinates that don’t line up with the assumed row.”

    Action/result: Inspected text_rect_clear_behaviour_001; the mismatch showed a black band at logical Y 40..55.

  963. Reported: “The mismatch is actually informative: 0x69 did clear exactly rows 5-6, but to black text-background pixels, while my expected image assumed the white picture remained. I’m updating the comparator to let a probe declare expected screen rectangles, which is the right model for text clears that alter the display surface rather than the picture resource.”

    Action/result: Decided to model expected display-surface rectangles in the logic probe comparator.

  964. Reported: “I’ll keep the rectangle expectation local to the fixture comparator: it changes only the low visual nibble over an expected text-cell rectangle, preserving the picture/control half of the cell. That matches the source-level split between text display effects and the picture/control buffers.”

    Action/result: Inspected agi_graphics.py structures to patch the expected visual nibbles without changing picture decoding.

  965. Reported: “The case schema now carries optional expected rectangles. I’m wiring those rectangles into comparison and setting the two text-clear cases to the source-derived text-cell coordinates.”

    Action/result: Added expected_visual_rects to the logic probe case schema and initial expected rectangles.

  966. Reported: “I’m patching the probe model now so the expected image can include ‘display-only’ visual rectangles. This keeps the picture renderer itself clean while letting text/UI probes assert the observable screen state.”

    Action/result: Began adding the display-rectangle application helper.

  967. Reported: “The patch anchor was off by a function name, so I’m locating the fixture builder and applying the comparison helper at the actual spot.”

    Action/result: Located build_logic_fixture and compare_capture.

  968. Reported: “Found it. I’m inserting the rectangle helper just before compare_capture and then rerunning the local tests.”

    Action/result: Added apply_expected_visual_rects() and called it from compare_capture.

  969. Reported: “The expected-rectangle support is wired in. I’m running the unit tests again, then the QEMU batch with the corrected expectations.”

    Action/result: Ran the focused unit tests and py_compile successfully.

  970. Reported: “The probe code still compiles and the catalog tests pass. I’m rerunning the two original-engine captures now; this time the expected image includes the black text-clear rectangles.”

    Action/result: Started text_rect_clear_behaviour_002.

  971. Reported: “QEMU is through fixture build and running the snapshot batch. I’m waiting on the two captures now.”

    Action/result: Waited for the second QEMU text rectangle batch.

  972. Reported: “The row-clear case now matches; the bounded-rectangle case still mismatches, so I’m narrowing that one. The first result already gives us a solid 0x69 behavior probe.”

    Action/result: Inspected text_rect_clear_behaviour_002 and saw the bounded case expected X range was wrong.

  973. Reported: “The bounded clear did run, but the X mapping corrected my assumption: column 5 maps to logical X 20, not 40. I’m checking the BIOS wrapper helper before updating the expected rectangle so the docs describe the coordinate scale correctly.”

    Action/result: Re-read code.text.clear_bounds and code.text.clear_rows disassembly.

  974. Reported: “The helper confirms the documented argument order: top, left, bottom, right, attribute. The remaining surprise is how QEMU’s graphics text grid maps columns onto logical pixels, so I’m measuring the capture row directly rather than guessing from the mismatch summary.”

    Action/result: Measured the bounded-clear capture directly and found black ranges X 20..83 for rows 64..71.

  975. Reported: “Measured directly: 0x9a(8,5,8,20,0) clears logical X 20-83 over Y 64-71. That matches a 40-column text grid: column units are four logical pixels wide and row units are eight logical pixels tall. I’m correcting the expected rectangle.”

    Action/result: Corrected the bounded expected rectangle to X 20..83/Y 64..71.

  976. Reported: “The bounded case expectation is fixed. I’m adding a test assertion for those exact expected rectangles so this coordinate mapping stays visible in the test suite.”

    Action/result: Added test assertions for the expected display-surface rectangles.

  977. Reported: “The unit test now pins the text-clear rectangle mapping. I’m running the focused tests and then the two-case QEMU batch one more time.”

    Action/result: Ran the focused unit tests and py_compile successfully.

  978. Reported: “The focused local tests pass with the new rectangle expectations. I’m rerunning the original-engine comparison now.”

    Action/result: Started text_rect_clear_behaviour_003.

  979. Reported: “The QEMU batch is running from its snapshot disk again; waiting for both comparisons to finish.”

    Action/result: Waited for the final two-case QEMU text rectangle batch.

  980. Reported: “Both text-clear probes now match the original engine. I’m promoting 0x69 and 0x9a in the evidence matrix, then I’ll regenerate the generated opcode evidence chapter and update the human docs/progress trail.”

    Action/result: Confirmed text_rect_clear_behaviour_003 matched 2/2 and prepared evidence promotion.

  981. Reported: “With the generated evidence refreshed, I’m updating the human-facing docs: progress counts, opcode descriptions, compatibility command/results, and the clean-room notes about the source helper plus the QEMU correction from the first mismatch.”

    Action/result: Inspected the relevant docs and symbolic labels before documentation updates.

  982. Reported: “I’m updating tools/logic_opcode_evidence.py so the generated matrix treats 0x69 and 0x9a as QEMU-validated by the new behavior probes instead of smoke-only.”

    Action/result: Promoted 0x69 and 0x9a in the evidence registry and removed them from smoke-only actions.

  983. Reported: “The evidence registry is updated. I’m checking the generator options and then regenerating the opcode evidence chapter from the registry.”

    Action/result: Checked tools/logic_opcode_evidence.py --help and script behavior.

  984. Reported: “The generator writes the mdBook chapter by default. I’m regenerating that file now.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  985. Reported: “I don’t see stable labels for the clear helpers yet, so I’m adding them to symbolic_labels.md while I’m touching this subsystem. That will make later cross-version comparisons easier than referring to raw 0x2b78/0x2bc4 everywhere.”

    Action/result: Checked existing text labels in symbolic_labels.md.

  986. Reported: “I’m adding the helper labels right beside the other text labels, with the observed QEMU coordinate mapping in the notes.”

    Action/result: Added code.text.clear_rows and code.text.clear_bounds symbolic labels.

  987. Reported: “Now I’m updating PROGRESS.md: two more action opcodes are covered at behavior level, so the covered count moves from 154 to 156 and partial actions drop from 22 to 20.”

    Action/result: Updated PROGRESS.md counts and marked 0x69/0x9a as QEMU-validated.

  988. Reported: “I’m tightening the opcode chapter next: the handler rows now mention the display-surface coordinate mapping, and the QEMU paragraph changes from smoke-only to behavior-level evidence for the two clear operations.”

    Action/result: Updated docs/src/logic_bytecode.md for 0x69, 0x9a, and the new behavior fixture.

  989. Reported: “I’m also adding a short implementation-facing note in the runtime model: these clears are display-surface operations, not picture-resource edits. That distinction matters for a clean-room engine.”

    Action/result: Added text-rectangle clear semantics to docs/src/runtime_model.md.

  990. Reported: “Next I’m adding the exact QEMU command/result to compatibility_testing.md, including the corrected first failed run so the evidence trail shows why the expected rectangles were added.”

    Action/result: Added text_rect_clear_behaviour_003 command/results and the earlier mismatch correction to compatibility docs.

  991. Reported: “I’m appending the clean-room notes section now with the disassembly commands, QEMU commands, the mismatch correction, and the exact behavior promoted.”

    Action/result: Prepared the clean-room executable notes update.

  992. Reported: “I’m adding the new section after the 0x84 section, so the chronology stays intact.”

    Action/result: Appended the 2026-07-04 text rectangle clear behavior section to clean_room_executable_notes.md.

  993. Reported: “I’ve got the substantive docs updated. I’m doing the progress-log bookkeeping now, then I’ll run the full validation suite for the changed probe/tool/docs set.”

    Action/result: Began appending this progress-log batch before final validation.

  994. Reported: “The progress log is caught up through the documentation pass. I’m running the full validation set now: unit tests, generated evidence check, mdBook build, whitespace, and status.”

    Action/result: Ran python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check.

  995. Reported: “All four validations passed: 103 unit tests, evidence --check, mdBook, and whitespace. I’m adding that validation result to the progress log and then doing a final status/diff pass.”

    Action/result: Recorded the successful validation result before final status and diff checks.

  996. Reported: “Because the progress log changed after validation, I’m rerunning the lightweight doc/whitespace checks and then I’ll give you the concise handoff.”

    Action/result: Reran mdbook build docs, git diff --check, status, and diff-stat checks.

  997. Reported: “The final checks are clean, and I spotted a generated tools/__pycache__/ from the Python runs. I’m removing that disposable cache and recording this last validation/status update so the handoff is tidy.”

    Action/result: Removed generated tools/__pycache__/ and confirmed the tracked change set plus existing untracked generated/input directories.

  998. Reported: “Last log entry is in. I’ll do one quiet final check now.”

    Action/result: Reran mdBook, whitespace, and status checks; this note was added because that status update itself is part of the historical log.

  999. Reported: “One final bookkeeping note got added by my own update, so I’m recording that too and then I’ll stop the commentary loop.”

    Action/result: Recorded the final bookkeeping note before the truly quiet final mdBook, whitespace, and status checks.

  1000. Reported: “I’ll continue from the current PROGRESS.md map and keep the work focused on the remaining partial opcodes. I’m going to re-check the tracker, evidence matrix, and working tree first so the next probe batch lands cleanly.”

    Action/result: Re-read PROGRESS.md, git status --short, the end of this progress log, and the opcode evidence/current tracker references.

  1001. Reported: “The remaining partial list is still mostly text/input and a few VM-global toggles. I’m going to look for the next source-backed state change that can be made observable without inventing a glyph renderer; status/input clears and global motion/input gates look like the best candidates.”

    Action/result: Re-read the text/input opcode notes, disassembled around action 0x83, and inspected existing logic-interpreter probe cases.

  1002. Reported: “I’m resuming at the partial text/status/input opcodes and will start with the ones whose source clearly funnels into row-clearing code. That should let us promote a couple of opcodes with source-backed, QEMU-validated behavior instead of just dispatch smoke.”

    Action/result: Re-read the probe catalog, unit tests, evidence mapping, and text opcode chapter around the input/status handlers.

  1003. Reported: “The source path is lining up: both status-hide and input-disable appear to use the same cleared text-row primitive that we already validated for rectangle clears. I’m checking the exact dispatch targets now so the new probes can cite the code path rather than just the visual outcome.”

    Action/result: Searched docs for 0x70, 0x71, 0x77, and input/status labels; inspected the relevant probe cases and disassembly ranges.

  1004. Reported: “One minor wrinkle: direct ndisasm with manual skips landed midstream in one range, so I’m switching to the existing full disassembly artifact for address-aligned evidence. That keeps the notes tied to the same address map the rest of the project uses.”

    Action/result: Checked the full disassembly artifact and existing notes for the status/input helper address map.

  1005. Reported: “The previous notes already captured the core handlers; I’m adding narrowly-scoped probes now. The fixture will configure the target row, run the hide/disable opcode, then draw the usual validation object, so any leftover text-row state shows up as a capture mismatch.”

    Action/result: Inspected the aligned source snippets and test helper assertions before editing.

  1006. Reported: “I’m going to make the row clears visible by first drawing a short formatted message on the same text row, then running the opcode under test. That turns a global/UI side effect into an ordinary screen comparison: if the source interpretation is wrong, the text remnants should remain.”

    Action/result: Confirmed existing text clear evidence and planned the two row-clear fixtures.

  1007. Reported: “I’m about to edit the probe catalog and its unit assertions. I’ll keep the new cases small: one for 0x71 clearing the configured status row, one for 0x77 clearing the configured input row.”

    Action/result: Added input_line_disable_clears_configured_row and status_line_hide_clears_configured_row to tools/logic_interpreter_probe.py.

  1008. Reported: “The two probe cases are in place. I’m wiring the catalog tests next so future edits don’t silently drop the behavior coverage.”

    Action/result: Added unit assertions for the two new case ids and their expected visual clear rectangles.

  1009. Reported: “The static catalog checks are updated. I’m running the focused unit test before invoking QEMU, since that catches bad fixture metadata cheaply.”

    Action/result: Ran the two focused tests.test_logic_interpreter_probe.LogicInterpreterProbeTests methods; both passed.

  1010. Reported: “The unit checks passed. I’m running the two new cases through the original interpreter now; this is the point where the clean-room hypothesis either earns behavior-level evidence or gets revised.”

    Action/result: Started QEMU snapshot batch text_hide_clear_behaviour_001 with the two new cases.

  1011. Reported: “QEMU is running both fixtures from a snapshot batch now. The build phase completed and the interpreter is executing the cases, so I’m waiting on the captures/comparisons.”

    Action/result: Waited for the running QEMU batch to finish.

  1012. Reported: “Both QEMU cases matched: 0x77 and 0x71 now have visible row-clear behavior, not just ‘returns safely.’ I’m updating the evidence matrix and docs so the tracker reflects that promotion.”

    Action/result: Promoted action opcodes 0x71 and 0x77 from smoke to QEMU-validated in tools/logic_opcode_evidence.py.

  1013. Reported: “The evidence script supports direct regeneration, so I’m letting it rewrite the opcode evidence chapter from the source-of-truth mapping rather than hand-editing the table.”

    Action/result: Ran python3 -B tools/logic_opcode_evidence.py to regenerate docs/src/logic_opcode_evidence.md.

  1014. Reported: “The generated evidence table is refreshed. I’m updating PROGRESS.md next: the action coverage count moves up by two, and the remaining partial list loses 0x71 and 0x77.”

    Action/result: Updated PROGRESS.md to 158/176 action opcodes at [x] level, with 18 partial action opcodes remaining.

  1015. Reported: “PROGRESS.md is updated. I’m scanning for stale counts or old ‘dispatch-smoke’ references before touching the narrative docs.”

    Action/result: Started a stale-reference scan; the first command failed because a literal backtick confused the shell quoting.

  1016. Reported: “That scan tripped on a shell quote in the literal backtick pattern, so I’m rerunning it with simpler text patterns. No state changed.”

    Action/result: Reran the stale-reference scan and found only historical notes from earlier work.

  1017. Reported: “The stale hits are historical notes from earlier runs, not current trackers. I’m adding a new dated notes section rather than rewriting that history.”

    Action/result: Re-read symbolic labels, opcode docs, runtime model, and compatibility text to prepare focused updates.

  1018. Reported: “I’m also adding a symbolic label for the single-row clear helper used by both handlers. That gives later cross-version comparisons a stable name instead of just another absolute address.”

    Action/result: Disassembled code.text.clear_row at image 0x2ba6 and added it to docs/src/symbolic_labels.md.

  1019. Reported: “The symbolic label is added. I’m tightening the opcode chapter now, with the implementation detail that 0x2ba6 is the single-row wrapper around the broader text-row clear helper.”

    Action/result: Updated opcode rows for 0x71 and 0x77 in docs/src/logic_bytecode.md.

  1020. Reported: “The opcode rows now carry the behavioral evidence. I’m adding the batch summary near the other text/UI QEMU notes so readers see exactly how those two opcodes were promoted.”

    Action/result: Added the text_hide_clear_behaviour_001 narrative to the logic bytecode chapter.

  1021. Reported: “I’m adding the higher-level runtime contract too: these handlers are ‘visible text surface’ operations, not changes to the picture resource. That distinction is useful for a future implementation.”

    Action/result: Added status/input single-row clear semantics to docs/src/runtime_model.md.

  1022. Reported: “The runtime model has the visible-surface contract now. I’m adding the exact QEMU command and result to the compatibility chapter.”

    Action/result: Added the text_hide_clear_behaviour_001 command and result to docs/src/compatibility_testing.md.

  1023. Reported: “The compatibility chapter has the new batch. I’m appending the clean-room notes section with the disassembly command, fixture changes, QEMU result, and tracker updates.”

    Action/result: Added the dated clean-room notes section for the status/input single-row clear behavior probes.

  1024. Reported: “The main docs are updated. I’m doing the progress-log bookkeeping now, including the short status messages from before and after the context handoff so the historical trail stays continuous.”

    Action/result: Appended this progress-log batch before final validation.

  1025. Reported: “The progress log is caught up through the doc edits. I’m running the full validation pass now: unit suite, generated evidence check, mdBook build, and whitespace check.”

    Action/result: Ran python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check.

  1026. Reported: “All four validations passed: 103 unit tests, evidence --check, mdBook, and whitespace. I’m recording that validation result and then I’ll do a final diff/status pass.”

    Action/result: Recorded the successful validation result before final diff and status inspection.

  1027. Reported: “Because the progress log changed after validation, I’m rerunning the lightweight doc/whitespace checks and grabbing the final status/diff summary.”

    Action/result: Reran mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, git status --short, and git diff --stat.

  1028. Reported: “The second mdBook/evidence/whitespace pass is clean. Final status shows the expected tracked edits plus the existing untracked DOS installer/images under 002962_ms_dos_622/ and generated build/.”

    Action/result: Recorded the final validation/status summary after the second lightweight check pass.

  1029. Reported: “I’ll commit the current row-clear/evidence work first, leaving the existing generated build/ and DOS installer directory untracked. After that I’ll pick up the next highest-value partial opcode from PROGRESS.md and keep the new work uncommitted until you ask again.”

    Action/result: Re-read status, diff stat, and PROGRESS.md before staging the completed row-clear work.

  1030. Reported: “The commit candidate is exactly the 11 modified files from the row-clear work. I’m staging only those tracked files now; build/ and 002962_ms_dos_622/ stay out of the commit.”

    Action/result: Staged the 11 tracked files from the status/input row-clear validation pass.

  1031. Reported: “Staging succeeded. I’m committing this as the status/input row-clear behavior validation, then I’ll continue from the next partial opcode cluster.”

    Action/result: Attempted git commit -m "Validate status and input row clears".

  1032. Reported: “The sandbox blocked the commit while trying to create .git/index.lock, so I’m rerunning the same commit with escalation.”

    Action/result: Reran the commit with escalation. Commit aa55bda (Validate status and input row clears) succeeded with 11 files changed.

  1033. Reported: “Commit aa55bda is in. I’m back on the tracker now, and the next likely wins are still in the text/input group: 0x70 status redraw, 0x78 input redraw, and the refresh/erase helpers. I’ll read the source path first and only use QEMU once there’s a precise behavior hypothesis to validate.”

    Action/result: Confirmed the post-commit status and re-read the relevant source-backed text/input opcode notes and disassembly.

  1034. Reported: “The committed tree is clean aside from the long-standing untracked input/generated directories. I’m noticing the same address-map trap as before: one disassembly artifact is file-offset oriented, while the docs use image-oriented labels, so I’m cross-checking against byte patterns before naming any new behavior.”

    Action/result: Searched for byte patterns and reran image-oriented ndisasm commands around the status, input, and text-attribute handlers.

  1035. Reported: “Two behavior probes look worth trying from the disassembly: 0x78 should redraw/clear the configured input row, and 0x6a should enter alternate text mode and clear the visible text surface through code.text.clear_rows. I’m adding both as screen comparisons, with QEMU as confirmation rather than discovery.”

    Action/result: Began adding input_line_enable_clears_configured_row and text_attribute_enable_clears_visible_surface to the probe catalog.

  1036. Reported: “That patch missed one nearby context block, so I’m reopening the exact probe catalog slice and applying the additions in smaller pieces.”

    Action/result: Re-read the probe catalog slice around the existing text/input cases.

  1037. Reported: “I’ve got the exact insertion points now. I’m adding the 0x78 row-redraw case and the 0x6a visible-surface clear case separately.”

    Action/result: Added the 0x78 input-line enable row-clear probe.

  1038. Reported: “The 0x78 case is in. I’m adding the 0x6a full visible-surface clear check right after the existing text-attribute smoke case.”

    Action/result: Added the initial 0x6a visible-surface clear probe.

  1039. Reported: “Both new probe definitions are in place. I’m updating the unit assertions now so the catalog and expected rectangles stay pinned down.”

    Action/result: Re-read the unit-test catalog and expected-rectangle assertions.

  1040. Reported: “The test file already has the recent row-clear assertions; I’m extending that same check for 0x78 and the full-surface 0x6a case.”

    Action/result: Added unit assertions for the two new case ids and expected visual rectangles.

  1041. Reported: “The catalog tests are updated. I’m running the focused unit checks before taking the two hypotheses to QEMU.”

    Action/result: Ran the two focused logic-interpreter probe unit tests; both passed.

  1042. Reported: “The focused checks passed. I’m running the new 0x78 and 0x6a cases through the original engine as a two-case QEMU snapshot batch now.”

    Action/result: Started QEMU batch text_enable_attr_behaviour_001.

  1043. Reported: “The 0x78 input-line enable case matched. The 0x6a full-surface case is still running, so I’m waiting for that capture before updating evidence.”

    Action/result: Waited for the second case in text_enable_attr_behaviour_001.

  1044. Reported: “The batch split neatly: 0x78 matched, while my 0x6a full-black expectation was too blunt. I’m inspecting the mismatch before deciding whether to revise that case or leave 0x6a as source-backed smoke for now.”

    Action/result: Inspected the QEMU report, the 0x6a PPM capture, and text-attribute helper disassembly.

  1045. Reported: “The 0x6a mismatch is interesting rather than bad: the capture is entirely black, so the surface clear happened, but the later transient-object validation draw did not appear while alternate text mode was active. I’m adjusting the harness carefully so this case can compare the visible surface without requiring the usual object draw.”

    Action/result: Re-read the probe helper and comparator paths for compare_view handling.

  1046. Reported: “I’m going to keep the 0x6a probe, but make the expected result match what the original actually does in this mode: black visible surface, no composed validation object. That means adding a small compare_view switch to the shared case helper instead of special-casing the comparator.”

    Action/result: Added a compare_view parameter to _custom_case and set the 0x6a case to compare_view=False.

  1047. Reported: “The harness now supports a no-composed-view expectation for special display states, and the 0x6a case uses it. I’m pinning that in the unit test before rerunning QEMU.”

    Action/result: Added a unit assertion that the 0x6a case does not compare the usual composed view.

  1048. Reported: “The unit expectation now records that 0x6a is a surface-only comparison. I’m rerunning the focused tests and then the two QEMU cases.”

    Action/result: Reran the focused unit tests and started QEMU batch text_enable_attr_behaviour_002.

  1049. Reported: “The focused tests passed again and QEMU has re-confirmed the 0x78 case. I’m waiting on the revised 0x6a comparison.”

    Action/result: Waited for the second case in text_enable_attr_behaviour_002.

  1050. Reported: “The revised QEMU batch matched both cases. I’m promoting 0x78 and 0x6a in the generated evidence map now, while leaving 0x6c, 0x6b, and 0x6d at their current partial levels.”

    Action/result: Re-read evidence, symbolic-label, opcode, compatibility, and clean-room note context before promotion.

  1051. Reported: “The evidence source now promotes 0x6a and 0x78. I’m regenerating the evidence chapter and updating the progress counts from 158 to 160 covered action opcodes.”

    Action/result: Updated tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  1052. Reported: “The generated evidence chapter is refreshed. I’m aligning PROGRESS.md with two more [x] promotions: 0x6a and 0x78.”

    Action/result: Updated PROGRESS.md to 160/176 action opcodes at [x] level, with 16 partial action opcodes remaining.

  1053. Reported: “I’m updating the narrative docs next. The key wording is: 0x78 is a normal input-row redraw/clear, while 0x6a is alternate text-attribute mode, where the visible surface clears and the usual composed object check is intentionally not expected.”

    Action/result: Updated docs/src/logic_bytecode.md rows and behavior fixture narrative for 0x6a and 0x78.

  1054. Reported: “The opcode chapter is updated with the new behavior fixture. I’m adding the same command/result to the compatibility chapter and adjusting the runtime model’s state-machine notes.”

    Action/result: Updated docs/src/compatibility_testing.md and docs/src/runtime_model.md.

  1055. Reported: “I’m also tightening the symbolic-label notes for the two helpers implicated here, so later cross-version work has the behavioral evidence attached to the label map.”

    Action/result: Updated docs/src/symbolic_labels.md entries for code.text.enter_attr_mode and code.input.redraw_input_line.

  1056. Reported: “I’m correcting one older compatibility paragraph too, so it remains historically true without implying 0x6a and 0x78 are still only smoke-covered.”

    Action/result: Revised the text/status smoke-batch wording in docs/src/compatibility_testing.md.

  1057. Reported: “The compatibility history is now clearer. I’m appending the clean-room notes for the 0x78/0x6a disassembly-backed QEMU pass, including the first failed expectation for 0x6a.”

    Action/result: Added the clean-room notes section for text_enable_attr_behaviour_001 and text_enable_attr_behaviour_002.

  1058. Reported: “The clean-room notes now have the command/result trail. I’m doing a consistency scan for stale counts and smoke labels before the final validation pass.”

    Action/result: Ran stale-reference scans, checked PROGRESS.md, docs/src/logic_opcode_evidence.md, status, and diff stat.

  1059. Reported: “The current stale-count hits are only historical notes from the just-committed previous section, so I’m leaving them intact. I’m appending the progress-log entries for this commit-and-continue pass now, then I’ll run validation.”

    Action/result: Began appending this progress-log batch.

  1060. Reported: “I’m adding a fairly long progress-log batch because this turn included the requested commit, a sandbox retry, a failed hypothesis for 0x6a, and the corrected validation. This is exactly the sort of trail future-us will be grateful not to reconstruct.”

    Action/result: Appended this progress-log batch before final validation.

  1061. Reported: “The progress log is caught up through the corrected 0x6a/0x78 work. I’m running the full validation set now: unit tests, evidence check, mdBook, and whitespace.”

    Action/result: Ran python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check.

  1062. Reported: “All four validations passed: 103 unit tests, evidence --check, mdBook, and whitespace. I’m recording that and then doing a final status/diff pass.”

    Action/result: Recorded the successful validation result before final status and diff inspection.

  1063. Reported: “Because the progress log changed after validation, I’m rerunning the lightweight checks and grabbing the final status summary.”

    Action/result: Reran mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, git status --short, and git diff --stat.

  1064. Reported: “One last log entry was added for the lightweight rerun, so I’m doing a quiet final check now and then I’ll stop the commentary loop.”

    Action/result: Recorded the final bookkeeping note before quiet final validation and status checks.

  1065. Reported: “I’ll commit the current 0x6a/0x78 behavior work first, keeping build/ and the DOS installer images untracked. Then I’ll continue with the next partial opcodes from PROGRESS.md, again starting from the disassembled source and using QEMU only to validate a concrete hypothesis.”

    Action/result: Re-read status, diff stat, and the remaining partial opcode list in PROGRESS.md.

  1066. Reported: “The uncommitted set is the expected 11 tracked files from the 0x6a/0x78 pass. I’m staging just those tracked files now and leaving generated inputs alone.”

    Action/result: Staged the tracked 0x6a/0x78 behavior-validation files.

  1067. Reported: “Staging succeeded. I’m committing the input-enable/text-attribute behavior validation now; commit writes to .git, so I’m using escalation for that part.”

    Action/result: Created commit 1229d68 (Validate input enable and text attribute mode).

  1068. Reported: “Commit 1229d68 is in. I’m continuing from the remaining 16 partial action opcodes; next I’m looking for another source-backed visible text/input behavior, especially status redraw 0x70, prompt marker 0x6c, and the 0x89/0x8a refresh/erase pair.”

    Action/result: Confirmed the post-commit status and re-read the remaining text/input partial opcode notes and disassembly.

  1069. Reported: “The disassembly suggests a clean way to validate 0x6c without implementing font glyphs: set a non-empty prompt marker, then set it to an empty message and redraw the input row. If 0x6c really stores the first message byte, the redraw stays all black; otherwise a marker glyph appears and the capture mismatches.”

    Action/result: Re-read prompt-marker and input-line helper notes, existing cases, and focused disassembly around 0x38b4 and 0x37f7.

  1070. Reported: “I’m adding two targeted cases now: one for 0x6c clearing a previously non-empty prompt marker by loading an empty message, and one for 0x6b leaving alternate text mode so the normal picture/object draw becomes visible again. Both are small enough to be decisive.”

    Action/result: Added text_attribute_disable_restores_picture_draw and input_prompt_empty_message_suppresses_marker to the probe catalog.

  1071. Reported: “The two new probe cases are in the catalog. I’m adding unit assertions for their presence and the 0x6c expected row-clear rectangle.”

    Action/result: Updated tests/test_logic_interpreter_probe.py for the two new case ids and expected rectangle.

  1072. Reported: “The unit assertions are updated. I’m running the focused catalog tests, then I’ll run the two new cases through QEMU if those pass.”

    Action/result: Ran the two focused logic-interpreter probe unit tests; both passed.

  1073. Reported: “The focused tests passed. I’m running these two cases against the original interpreter now; if they match, they should promote 0x6b and 0x6c from smoke to behavior-level coverage.”

    Action/result: Started QEMU batch text_prompt_attr_behaviour_001.

  1074. Reported: “The 0x6b case matched: leaving alternate text mode restores the normal picture/object draw path. I’m waiting on the 0x6c prompt-marker suppression case now.”

    Action/result: Waited for the second case in text_prompt_attr_behaviour_001.

  1075. Reported: “Both cases matched in QEMU, so 0x6b and 0x6c can move up to behavior-level evidence. I’m updating the generated evidence map and the tracker, then I’ll add the source/QEMU notes.”

    Action/result: Re-read evidence, opcode, compatibility, runtime, and symbolic-label context before promotion.

  1076. Reported: “I’m promoting 0x6b and 0x6c in the evidence source now. The docs will distinguish the 0x6c evidence as an empty-message prompt-marker behavior, not a full glyph-rendering spec.”

    Action/result: Updated tools/logic_opcode_evidence.py.

  1077. Reported: “The evidence source is updated. I’m regenerating the evidence chapter and moving the tracker to 162 covered action opcodes.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md and updated PROGRESS.md to 162/176 action opcodes at [x] level.

  1078. Reported: “PROGRESS.md now reflects 162 covered actions and 14 partials. I’m updating the opcode chapter and runtime docs with the specific contracts we just validated.”

    Action/result: Updated docs/src/logic_bytecode.md.

  1079. Reported: “The opcode chapter now names the new QEMU fixture and narrows the remaining smoke list. I’m adding the compatibility command/result and then updating the runtime/symbolic summaries.”

    Action/result: Updated docs/src/compatibility_testing.md.

  1080. Reported: “The compatibility chapter has the new text_prompt_attr_behaviour_001 batch. I’m adding the implementation-facing notes now.”

    Action/result: Updated docs/src/runtime_model.md.

  1081. Reported: “The runtime model now captures prompt-marker suppression and text-mode exit. I’m attaching the same evidence to the stable symbolic-label map.”

    Action/result: Updated docs/src/symbolic_labels.md.

  1082. Reported: “I’m appending the clean-room notes for the prompt-marker and text-mode-exit probes, including the source commands and the exact QEMU batch.”

    Action/result: Added the dated clean-room notes section for text_prompt_attr_behaviour_001.

  1083. Reported: “The clean-room notes are updated. I’m adding the progress-log batch for this turn now, covering the commit, the two new probes, the QEMU results, and the documentation updates.”

    Action/result: Began appending this progress-log batch.

  1084. Reported: “I’m keeping the log concise but complete: every progress update gets an entry, while command details live in the clean-room notes. After this I’ll run the full validation suite.”

    Action/result: Appended this progress-log batch before final validation.

  1085. Reported: “The progress log is caught up through the 0x6b/0x6c work. I’m running the full validation pass now: unit suite, generated evidence check, mdBook, and whitespace.”

    Action/result: Ran python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check.

  1086. Reported: “All four validations passed: 103 unit tests, evidence --check, mdBook, and whitespace. I’m recording that result and then doing the final status/diff pass.”

    Action/result: Recorded the successful validation result before final status and diff inspection.

  1087. Reported: “The progress log changed after validation, so I’m rerunning the lightweight checks and collecting the final status summary.”

    Action/result: Reran mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, git status --short, git diff --stat, and git log -2 --oneline.

  1088. Reported: “The lightweight checks are clean and the final status shows the expected uncommitted 0x6b/0x6c work plus the existing untracked generated/input directories. I’m recording that last status note and doing one quiet final check.”

    Action/result: Recorded the final status note before quiet final validation and status checks.

  1089. Reported: “One last note was appended, so I’ll run the final quiet check now and then hand this back without another progress-log loop.”

    Action/result: Recorded the final bookkeeping note before quiet final validation and status checks.

  1090. Reported: “I’ll commit the current 0x6b/0x6c validation work, keeping the generated build/ artifacts and DOS installer images untracked. I’ll add a tiny progress-log note for this commit turn, then stage only the tracked project files.”

    Action/result: Re-read status, diff stat, and the tail of this progress log before staging the commit.

  1091. Reported: “The commit candidate is the expected 11 tracked files, and the previous validation is already recorded. I’m appending the commit-turn log entry, then I’ll do a lightweight check and commit.”

    Action/result: Appended the commit-turn progress-log entries before final lightweight checks and staging.

  1092. Reported: “I’ll continue from the freshly committed state and target the remaining partial opcodes in PROGRESS.md. I’ll start by rereading the tracker and source notes, then look for the next behavior that can be proven from disassembly and validated with a narrow QEMU fixture.”

    Action/result: Re-read repository status, PROGRESS.md, and current opcode/probe references.

  1093. Reported: “I’m going to take the next partial opcode that looks most tractable from the disassembly: 0x6d, the text attribute pair setter. The goal is to turn it from “dispatch-smoked” into a small behavior spec with an original-engine confirmation, then update the tracker and docs.”

    Action/result: Selected 0x6d as the next promotion target.

  1094. Reported: “The first pass confirms the remaining tracker entries are mostly “partial because we only proved dispatch.” I’m drilling into the existing probe harness now so the next test is shaped like the engine code, not just a random observation.”

    Action/result: Re-read the logic interpreter probe harness and existing text-attribute cases.

  1095. Reported: “The existing notes already identify the helper chain (0x77d5 -> 0x7803/0x78a1/0x78ad). I’m going back to that disassembly now to pin down which operand combinations should produce a visible, stable EGA result.”

    Action/result: Re-read disassembly around 0x76ca, 0x77af, and 0x77d5.

  1096. Reported: “The disassembly supports a good controlled case: set the pair to foreground 0, background-ish operand 1, then enter attribute mode. Because 0x6a recomputes with [0x1757] = 1, the fill attribute should become 0xf0, which ought to show as a full white background in the EGA capture.”

    Action/result: Added planned case text_attribute_pair_changes_attr_mode_clear_color.

  1097. Reported: “I’ve added that as a real fixture case rather than a one-off script. Now I’m wiring the unit expectations around it, then I’ll let QEMU tell us whether the source-derived 0xf0 prediction matches the original engine.”

    Action/result: Updated tools/logic_interpreter_probe.py and tests/test_logic_interpreter_probe.py.

  1098. Reported: “The fixture is in place with an explicit “no sprite expected” comparison, since active attribute mode hides the normal validation draw. I’m running the local probe tests before spending a QEMU boot on it.”

    Action/result: Ran the focused unit tests for case coverage and expected visual rectangles; both passed.

  1099. Reported: “The harness tests are clean. Next I’m running just this new 0x6d case through the original interpreter; if it matches, we can promote the opcode’s evidence level instead of leaving it as dispatch-only.”

    Action/result: Ran the one-case QEMU batch text_attr_pair_behaviour_001.

  1100. Reported: “QEMU matched exactly: the original engine clears the whole visible surface to color 15 after 0x6d(0,1) followed by 0x6a. I’m updating the evidence tables and prose now so the source-derived helper behavior and the dynamic confirmation line up.”

    Action/result: Confirmed the original-engine capture matched the local expected full-screen color-15 surface.

  1101. Reported: “The match gives us a nice high-level rule: 0x6d stores the logical pair, and 0x6a reinterprets that saved pair as a packed text attribute once attr mode is enabled. I’m promoting 0x6d in the generated evidence source, then I’ll regenerate the mdBook page from it.”

    Action/result: Moved 0x6d from dispatch-smoke to behavior-level evidence in tools/logic_opcode_evidence.py and regenerated the evidence chapter.

  1102. Reported: “The generated opcode matrix now marks 0x6d as behavior-level QEMU evidence. I’m folding the same result into PROGRESS and the implementation-oriented text sections so the tracker, opcode chapter, and compatibility notes all tell the same story.”

    Action/result: Began updating tracker and documentation prose.

  1103. Reported: “One small bookkeeping wrinkle: docs/src/progress_log.md is long enough that a narrow sed range landed in an older section, so I’m using the tail for the current append point. The substantive 0x6d changes are straightforward.”

    Action/result: Located the current progress-log append point.

  1104. Reported: “I found the append point. Before final validation I’ll add the current-turn progress entries there, including the QEMU result and the docs updates, so the historical log stays complete.”

    Action/result: Prepared to append the current-turn progress-log entries.

  1105. Reported: “PROGRESS.md is bumped to 163/176 action opcodes at full coverage, with 13 partials left. I’m updating the opcode prose next so implementers can see the exact pair-to-attribute behavior we proved.”

    Action/result: Updated PROGRESS.md and docs/src/logic_bytecode.md.

  1106. Reported: “The opcode row now carries both the storage globals and the visible consequence. I’m adding the same rule to the runtime model because this is really part of the text-surface state machine, not just a bytecode footnote.”

    Action/result: Updated docs/src/runtime_model.md.

  1107. Reported: “Runtime prose is updated. I’m attaching the new case name and the 0xf0 observation to the symbolic label map, since that file is the cross-version anchor we’ll need when addresses move in other AGI builds.”

    Action/result: Updated docs/src/symbolic_labels.md.

  1108. Reported: “The symbolic map now links code.text.set_attribute_pair to the new validation case. I’m adding the reproducible QEMU command/result to the compatibility chapter so future runs can replay this exact check.”

    Action/result: Updated docs/src/compatibility_testing.md.

  1109. Reported: “Compatibility docs have the exact TA batch command and result. I’m appending the clean-room notes section now with the disassembly evidence, unit/QEMU commands, and what changed in the model.”

    Action/result: Updated docs/src/clean_room_executable_notes.md.

  1110. Reported: “The notes already have the previous text-mode batches, so I’m appending this as a small follow-on section rather than rewriting history. That keeps the trail readable: source helper, new fixture, QEMU match, tracker promotion.”

    Action/result: Appended the dated clean-room notes section for the 0x6d text-attribute-pair behavior probe.

  1111. Reported: “The clean-room notes now include the 0x6d pass. I’m catching the progress log up through this point before validation; after the checks run, I’ll append a short validation-result entry too.”

    Action/result: Appended the current progress-log batch before validation.

  1112. Reported: “The progress log is caught up through the documentation work. I’m running the full validation pass now: unit suite, generated evidence check, mdBook build, and whitespace check.”

    Action/result: Ran python3 -B -m unittest discover -s tests, python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check.

  1113. Reported: “All four validations passed: 103 unit tests, evidence --check, mdBook, and whitespace. Because I’m adding that validation note to the log, I’ll rerun the lightweight docs/evidence checks afterward so the final state is clean.”

    Action/result: Recorded the successful validation result before lightweight final checks.

  1114. Reported: “The validation result is recorded. I’m doing the final lightweight pass now: rebuild the book after the log edit, confirm generated evidence is still current, and inspect the final diff/status.”

    Action/result: Ran final lightweight checks and inspected the uncommitted diff/status.

  1115. Reported: “I spotted one more user-facing update from this validation loop that needs to be logged. I’m adding that final progress-log entry and rerunning the docs/evidence/whitespace checks once more, quietly after this.”

    Action/result: Recorded the final progress-log update before quiet validation checks.

  1116. Reported: “I’ll keep moving from the current uncommitted 0x6d state and choose the next partial opcode(s) from PROGRESS.md. I’ll keep the updates concise, but I’ll work in a longer continuous pass and only stop if validation fails in a way that needs a decision.”

    Action/result: Resumed from the uncommitted text-attribute state and selected the next partial opcodes from PROGRESS.md.

  1117. Reported: “I’m looking at the remaining partial list now. The next best candidate looks like the input-line pair 0x89/0x8a, because the disassembly already exposes visible buffer globals and there may be a narrow display-surface probe hiding in the existing text harness.”

    Action/result: Chose 0x89/0x8a as the next behavior-level probe target.

  1118. Reported: “The input-line path is a little more awkward than 0x6d: proving it exactly would require either text glyph rendering or a targeted predicate comparison. I’m checking the helper code first to avoid building a test that merely “sees something changed” without knowing why.”

    Action/result: Re-read input-line helpers before designing a fixture.

  1119. Reported: “The helper confirms a useful exact sequence: 0x8a repeatedly sends backspace through the same input character helper until visible length reaches zero, while 0x89 repopulates visible buffer 0x0fa4 from source buffer 0x0fce. I’m going to add focused typed-input cases plus a small rectangle-signal comparator for the one path where exact glyph pixels are not yet modeled.”

    Action/result: Planned typed-input probes and a bounded rectangle comparator for UI text rows.

  1120. Reported: “I’m editing the probe harness in a contained way: exact full-frame comparisons stay the default, and the new rectangle checks are only for UI text rows where the source behavior is known but glyph rendering is not part of the local expected renderer yet.”

    Action/result: Added optional rectangle checks without changing default exact frame comparison behavior.

  1121. Reported: “The new cases separate three things: a baseline that typed input really appears, 0x8a making that row black again, and 0x8a followed by 0x89 bringing the typed buffer back. I’m adding the rectangle-check evaluator now so only the baseline/refresh glyph-bearing cases use it.”

    Action/result: Added typed-input baseline, erase, and refresh candidate cases.

  1122. Reported: “Rectangle checks are now a narrow alternate comparison path: they count specific colors inside a bounded logical row and return a normal match/mismatch report. I’m wiring unit tests around the new cases and the comparator before running QEMU.”

    Action/result: Implemented compare_rect_checks and began focused unit coverage.

  1123. Reported: “The unit tests now assert the new cases exist and that rectangle checks both match and fail when they should. I’m running the focused probe tests before the original-engine batch.”

    Action/result: Added unit assertions for the new cases and comparator.

  1124. Reported: “Focused tests pass. Next I’m running a four-case QEMU batch: status show, typed-input baseline, 0x8a erase, and 0x8a plus 0x89 refresh.”

    Action/result: Focused unit tests passed and the first mixed QEMU batch was launched.

  1125. Reported: “The batch is running from a single DOS snapshot now. It built the selected cases in base-case order, which is fine; I’m waiting for QEMU to finish and then I’ll inspect any mismatch rather than guessing.”

    Action/result: Waited for the snapshot-based input/status QEMU run.

  1126. Reported: “QEMU matched the typed-input baseline and the 0x8a erase case, so that part is solid. The 0x8a+0x89 refresh case mismatched, which likely means my assumed source-buffer persistence is wrong or the refresh timing/path differs; I’m inspecting the report and capture before changing the model.”

    Action/result: First QEMU run matched baseline/erase and exposed a refresh mismatch.

  1127. Reported: “The mismatch is informative: 0x8a and 0x8a+0x89 produce the same black-row capture, so the refresh did not restore from the source buffer as I predicted. I’m doing a small pixel-count check on the captured rows now to distinguish “text glyph” from “whole-row/ background color.””

    Action/result: Inspected the failed refresh capture and began row color counts.

  1128. Reported: “That quick row-count script is still running a moment longer than expected, so I’m polling it instead of starting another image read.”

    Action/result: Waited for the row-count inspection to complete.

  1129. Reported: “The row counts explain the failure: before Enter, typed characters live in the visible/edit buffer, not the source string that 0x89 replays from. I’m correcting the 0x89 case to type look plus Enter first, so the source buffer at 0x0fce should be populated before refresh.”

    Action/result: Corrected the refresh fixture to use accepted input rather than unaccepted live-edit text.

  1130. Reported: “The case is corrected to use the entered-command path instead of the live edit buffer. I’m rerunning the focused tests and then a smaller QEMU batch for the three input-line cases.”

    Action/result: Renamed/corrected the 0x89 case and reran focused tests.

  1131. Reported: “The corrected input batch is running. If it passes, 0x8a is exact-row validated and 0x89 is validated as a source-buffer repaint, with the entered-command detail documented.”

    Action/result: Launched the corrected input-line QEMU batch.

  1132. Reported: “The corrected input batch passed: baseline visible typed text, 0x8a erasing to a black row, and 0x89 repainting after Enter all matched. I’m running the status-line show case separately now, since the first mixed batch stopped before it.”

    Action/result: Corrected input-line batch matched and the status-line QEMU case was launched.

  1133. Reported: “With those matches, I can promote 0x70, 0x89, and 0x8a: 0x70 as a status-row draw signal, 0x8a as an exact typed-row erase, and 0x89 as repainting from the entered source buffer. I’m updating the evidence generator and tracker first.”

    Action/result: Promoted 0x70, 0x89, and 0x8a in the evidence plan.

  1134. Reported: “The generator now points those opcodes at their behavior cases instead of smoke cases. I’m regenerating the opcode evidence page and then updating PROGRESS.md counts.”

    Action/result: Updated tools/logic_opcode_evidence.py and regenerated docs/src/logic_opcode_evidence.md.

  1135. Reported: “The generated evidence page is refreshed. I’m changing the tracker from 163 to 166 covered action opcodes, leaving 10 partial action rows.”

    Action/result: Prepared the PROGRESS.md coverage-count update.

  1136. Reported: “PROGRESS.md is updated. I’m tightening the opcode prose next, including the correction that 0x89 replays the entered command buffer, not the unaccepted live edit buffer.”

    Action/result: Updated PROGRESS.md for 166/176 action opcode coverage.

  1137. Reported: “The opcode chapter now records both the successful cases and the failed pre-Enter hypothesis for 0x89. I’m adding that higher-level distinction to the runtime model so an implementation knows which input buffer is replayed.”

    Action/result: Updated docs/src/logic_bytecode.md for 0x70, 0x89, and 0x8a.

  1138. Reported: “The runtime model now distinguishes live edit text from the entered source buffer. I’m updating the symbolic label map with the newly validated input/status helpers and their SQ2 addresses.”

    Action/result: Updated docs/src/runtime_model.md with the live/source input-buffer distinction.

  1139. Reported: “The symbolic map has new stable labels for the input character helper, erase, refresh, and source-to-visible append helper. I’m adding the QEMU batch commands/results to the compatibility chapter now.”

    Action/result: Updated docs/src/symbolic_labels.md with input/status helper labels.

  1140. Reported: “The compatibility chapter has the earlier text batches in the right spot, so I’m inserting the new input-refresh/status-show evidence alongside them and marking the old smoke batch as superseded for three more opcodes.”

    Action/result: Added input-refresh and status-show QEMU commands/results to docs/src/compatibility_testing.md.

  1141. Reported: “Compatibility docs now have both new batch commands and the failed 0x89 pre-Enter correction. I’m checking for any older “still smoke-only” wording that needs to be superseded.”

    Action/result: Searched for stale smoke-only wording.

  1142. Reported: “I found two stale “dispatch-smoke” summaries that predate the new behavior cases. I’m revising them to say which parts are now superseded instead of letting the docs contradict the tracker.”

    Action/result: Revised stale text/status smoke summaries.

  1143. Reported: “The stale summaries now point forward to the focused behavior probes. I’m making the high-level progress areas a little less stale as well, especially the input/text subsystem summary.”

    Action/result: Updated high-level subsystem tracker wording in PROGRESS.md.

  1144. Reported: “The subsystem tracker now reflects that visible input-line refresh/erase is no longer just smoke coverage. I’m appending the clean-room evidence section with the exact failed and successful QEMU batches, since the failed pre-Enter hypothesis is part of the useful history.”

    Action/result: Prepared the clean-room notes append for input/status.

  1145. Reported: “The notes file ends with the 0x6d section, so I’m appending a new dated input/status section after it. This will preserve the row-count correction and the final promotion result.”

    Action/result: Appended the input-line refresh/erase and status-line show notes section.

  1146. Reported: “I’m going to keep pushing into the remaining partials. The trace-window pair 0x95/0x96 looks like the next feasible source-first target: the existing smoke case deliberately leaves flag 10 clear, but the disassembly says setting flag 10 should draw a boxed trace area.”

    Action/result: Selected trace-window enable/configure as the next partial opcode pair.

  1147. Reported: “I’m picking up exactly where the trace-window disassembly left off. The key thing I’m checking now is whether the visible effect of 0x95 can be validated without getting tangled in the trace pause mechanism that may intercept the very next opcode.”

    Action/result: Resumed trace-window validation after context compaction.

  1148. Reported: “The static trace code confirms two separate responsibilities: 0x96 only writes trace configuration globals, while 0x95 consults flag 10 and then draws the window through the normal boxed-text helper. I’m going to make the QEMU case line up with that split rather than treating it as a generic “some pixels changed” test.”

    Action/result: Re-read trace docs/source and planned a focused enabled trace-window case.

  1149. Reported: “There’s already an older note saying an enabled trace attempt showed a box but wasn’t in the comparison suite. I’m turning that into a repeatable case now, with a bounded rectangle predicate attached to the exact configured rows.”

    Action/result: Located the prior trace-window attempt and began converting it into a stable fixture.

  1150. Reported: “The case should end right after enabling trace, or use a one-shot branch, because the disassembly says an already-active 0x95 consumes an extra byte. That extra-byte behavior is precisely the kind of footgun I want the test to avoid while we’re validating the window draw itself.”

    Action/result: Chose a one-shot trace fixture shape to avoid repeated active-state byte consumption.

  1151. Reported: “I’ve confirmed the fixture harness can already express this cleanly: compare_view=False plus a rectangle check lets us validate the trace text/window pixels without pretending we have a full glyph model. Next I’m adding the enabled-trace case and a unit assertion for its expected bounds.”

    Action/result: Prepared to add the trace case and unit assertion.

  1152. Reported: “For the trace window’s vertical position, I’m using the source formula directly: top row is the configured input/status base row plus the trace row offset plus one. With 0x6f(0,0,5) and 0x96(...,1,2), the box should land around logical rows 48..63.”

    Action/result: Formed an initial trace rectangle hypothesis.

  1153. Reported: “Small correction from the source formula: the trace vertical base is the first 0x6f operand ([0x05dd]), not the status-row operand. I’m setting that deliberately in the fixture so the expected rectangle is derived from the actual globals the handler reads.”

    Action/result: Corrected the vertical-position hypothesis before adding the fixture.

  1154. Reported: “I’m making the trace case one-shot and omitting the validation sprite, because the trace dispatcher can pause before later bytecode. The observable we need is the boxed trace area itself, so the case will compare that surface directly.”

    Action/result: Added trace_window_enable_draws_box_when_flag10_set and a unit assertion for its initial rectangle checks.

  1155. Reported: “The fixture and unit assertion are in place. I’m running the focused tests first, then I’ll let QEMU tell us whether the exact row window is right or whether the text helper’s border math needs a tighter bound.”

    Action/result: Ran focused unit tests for the trace fixture and rectangle comparator.

  1156. Reported: “Focused tests pass. I’m running the enabled trace-window case through the original engine now; this one may pause inside the trace UI, but that’s acceptable because the screenshot is the evidence we need.”

    Action/result: Focused tests passed and QEMU trace batch trace_window_enable_001 was launched.

  1157. Reported: “The enabled trace case matched on the first pass, so the source-derived row band is correct enough for automation. I’m inspecting the capture/report anyway before promoting the opcodes, because a match count alone doesn’t tell us whether we’re seeing the border, trace text, or both.”

    Action/result: First trace QEMU run matched and report/capture inspection began.

  1158. Reported: “The report path points to the fixture capture rather than the batch directory; I asked the quick inspector for the wrong copy. I’m rerunning that inspection against the actual saved PPM now, then I’ll update the evidence mappings.”

    Action/result: Re-ran capture inspection against the correct fixture PPM.

  1159. Reported: “The capture is stranger than a small bordered box: most of the upper logical rows are white, with a few trace-text/background pixels inside. That may be the boxed text helper filling a large text area, so I’m checking the image visually and then I’ll keep the automated predicate honest by describing exactly what it proves.”

    Action/result: Inspected downsample color counts and prepared visual inspection.

  1160. Reported: “The image viewer could not read that PPM directly, so I’m converting a PNG copy under build/ for inspection. This is just for local sanity checking; the test continues to use the saved PPM.”

    Action/result: Converted the trace PPM capture to PNG for visual inspection.

  1161. Reported: “The visual check is useful: the helper draws a red-bordered, white-filled trace box with black trace text like 0: 12(94). I’m tightening the check to look for both the white fill and red border, so it’s less likely to pass on an unrelated white screen.”

    Action/result: Identified the visible trace-window components from the capture.

  1162. Reported: “The visual mapping says my first rectangle was broad enough but not ideal: the red border is around logical row 5 in the downsampled frame, while the white fill spans below it. I’m checking the local disassembly helpers briefly before tightening the predicate, because the helper’s coordinate system clearly is not the same as the 8-pixel text-row helpers.”

    Action/result: Compared observed trace-window pixel rows against the source-derived coordinate expectations.

  1163. Reported: “I’m revising the predicate into three signals: red border pixels, a large white fill area, and black trace text inside it. That matches the observed UI without requiring exact glyph reproduction.”

    Action/result: Tightened the trace rectangle checks to require red, white, and black visible signals.

  1164. Reported: “The trace predicate is now tighter. I’m rerunning the focused tests and then the same original-engine capture to make sure the stricter checks still pass.”

    Action/result: Re-ran focused unit tests after tightening the predicate.

  1165. Reported: “The stricter unit checks pass. I’m rerunning the QEMU trace case; if it matches again, I’ll promote 0x95 and 0x96 from dispatch-smoke to QEMU-validated in the evidence and tracker.”

    Action/result: Launched final trace QEMU batch trace_window_enable_002.

  1166. Reported: “The stricter QEMU trace capture matched. I’m updating the generated evidence mapping now so the opcode table points at the enabled trace-window case instead of the older flag-clear smoke case.”

    Action/result: Final trace QEMU batch matched and evidence mapping update began.

  1167. Reported: “0x95 and 0x96 are moving out of the smoke bucket together: the enabled case exercises 0x96’s stored row/height configuration and 0x95’s flag-gated draw path in the original interpreter.”

    Action/result: Updated tools/logic_opcode_evidence.py to map 0x95 and 0x96 to the enabled trace case.

  1168. Reported: “The evidence generator is patched. I’m regenerating the opcode evidence chapter, then I’ll update PROGRESS.md from 166 to 168 covered action opcodes.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  1169. Reported: “The generated evidence page is refreshed. I’m updating the tracker counts and the two trace rows now, then I’ll put the new behavior in the opcode/runtime/compatibility notes.”

    Action/result: Prepared the PROGRESS.md promotion update.

  1170. Reported: “The tracker still only has eight partial action opcodes after this promotion: 0x6e, 0x83, 0x8e, 0xa3, 0xa4, 0xa9, 0xaa, and 0xad. I’m making that count explicit in PROGRESS.md.”

    Action/result: Updated PROGRESS.md to 168/176 action opcode coverage.

  1171. Reported: “I’m updating the spec prose carefully here: the table still needs the disassembled control-flow details, while the paragraph below can carry the QEMU-visible result: red border, white fill, black trace text, and the pause-before-next-action behavior.”

    Action/result: Began updating the trace opcode prose.

  1172. Reported: “That patch missed the paragraph because the file has slightly different wrapping after earlier edits. I’m rereading the local section and applying the update against the exact text.”

    Action/result: Re-read the exact docs/src/logic_bytecode.md trace block after a patch-context miss.

  1173. Reported: “I found the exact block. The update also fixes wording from “input-line row” to “input-line base row,” which matches the 0x6f storage we just rechecked.”

    Action/result: Updated docs/src/logic_bytecode.md for the trace-window behavior and wording correction.

  1174. Reported: “The opcode chapter now carries both the source-backed internals and the new QEMU-visible trace behavior. I’m adding the same higher-level interpretation to the runtime model: this is developer tracing state, not ordinary game logic state.”

    Action/result: Updated docs/src/runtime_model.md.

  1175. Reported: “The runtime model is updated. I’m refreshing the symbolic labels next so the cross-version map says the enabled draw path is now validated, not merely observed as a one-off mismatch.”

    Action/result: Updated docs/src/symbolic_labels.md trace entries.

  1176. Reported: “The symbolic map now points to the new trace batch. I’m adding the exact QEMU command/result to the compatibility chapter and marking the older trace smoke entry as superseded for 0x95/0x96.”

    Action/result: Updated docs/src/compatibility_testing.md.

  1177. Reported: “The compatibility chapter has the old system batch grouped with several follow-ups. I’m adding a small focused trace subsection immediately after it, so future runs can reproduce the promotion without rerunning unrelated dialog cases.”

    Action/result: Inserted the focused enabled trace-window command/result in the compatibility chapter.

  1178. Reported: “Compatibility evidence is now reproducible. I’m appending a clean-room notes section with the source locations, the QEMU command, and the observed pixel/UI shape, then I’ll update the progress log.”

    Action/result: Prepared the enabled trace-window notes section.

  1179. Reported: “The notes section will include the failed/awkward history too: older enabled trace attempts were excluded because they polluted the validation sprite, but the new rectangle-check path lets us validate the trace UI directly.”

    Action/result: Appended the enabled trace-window validation section to docs/src/clean_room_executable_notes.md.

  1180. Reported: “I’m catching the historical progress log up now before doing more opcode work. This will be a longer append because it needs to preserve both the input/status work from before compaction and the trace-window work from this pass.”

    Action/result: Appended progress-log entries for the input/status and trace-window work through this point.

  1181. Reported: “The progress log is caught up through the trace promotion. I’m moving on to the remaining eight partial action opcodes now, starting by rereading their current descriptions so the next probe is driven by disassembly rather than trial-and-error.”

    Action/result: Reviewed the remaining partial opcode descriptions.

  1182. Reported: “Of the remaining eight, 0xa9 looks like the best next target: it has a visible restore path through the same saved-rectangle helper used by text windows, so we may be able to validate it with a modal message/window setup and an exact surface check.”

    Action/result: Selected 0xa9 as the next validation candidate.

  1183. Reported: “0xa9 may not be easiest after all: ordinary message-display actions close their own text-window state before the following opcode, so a plain “show message then 0xa9” would still only cover the inactive path. I’m checking the 0x0d0f/input helper path because 0xa9 also clears that flag unconditionally, which may give us a cleaner behavior probe and cover 0xa3/0xa4 at the same time.”

    Action/result: Redirected the probe design toward the input-width flag path shared by 0xa3, 0xa4, and 0xa9.

  1184. Reported: “The source gives a promising behavioral hook: code.input.handle_input_char caps visible input length at 0x24 when [0x0d0f] is set, but otherwise uses 0x28 - len(string_slot_0). I’m adding long-input probes that make that cap visible, which should cover 0xa3, 0xa4, and the unconditional 0xa9 clear path.”

    Action/result: Began adding long-input probes based on the disassembled input-width calculation.

  1185. Reported: “The three long-input cases are in the harness. I’m adding unit assertions for their presence and expected color-count thresholds before trying them in QEMU.”

    Action/result: Added the initial 0xa3/0xa4/0xa9 input-width cases to the probe harness.

  1186. Reported: “The unit assertions are in place. I’m running the focused tests now; if those pass, I’ll run a three-case QEMU batch to tune the row-count thresholds against the real interpreter.”

    Action/result: Added focused unit tests for the input-width cases.

  1187. Reported: “Focused tests pass. I’m running the original-engine batch for 0xa3, 0xa4, and 0xa9 now; this will tell us whether the source-derived input-width effect is visible enough for stable compatibility checks.”

    Action/result: Started the first QEMU input-width validation batch.

  1188. Reported: “The three-case batch is running from one snapshot. I’m waiting for QEMU to finish rather than launching anything else, since the harness owns the shared VNC/socket while it runs.”

    Action/result: Waited on the snapshot QEMU batch.

  1189. Reported: “The 0xa3 case matched, but the 0xa4 case did not: clearing the flag didn’t reduce visible text as much as my first threshold expected. I’m inspecting the capture and counts before deciding whether this is a threshold issue or a wrong model of when the long slot is consulted.”

    Action/result: Identified the first input-width mismatch and began inspecting capture counts.

  1190. Reported: “The mismatch is large: the 0xa4 case still has 548 white pixels in the input row. That suggests the long string in slot 0 may not be affecting the cap because slot 0 is being cleared or not the same slot 0x3652 measures; I’m waiting for the detailed row-count script and then I’ll adjust based on the source path.”

    Action/result: Captured the large row-count mismatch for the first 0xa4 attempt.

  1191. Reported: “The row counts show 0xa3 and 0xa4 looked identical because my long slot-0 string was visible prompt text, not just an invisible cap. I’m switching that slot to a long run of spaces: same length for the source formula, but no glyph pixels from the prefix itself.”

    Action/result: Changed the fixture string slot to long blank prompt text.

  1192. Reported: “The fixtures now use a long blank string slot, so any white pixels on the row should come from typed live input rather than the slot-0 prefix. I’m rerunning the focused tests, then the same three-case QEMU batch.”

    Action/result: Prepared the second input-width batch.

  1193. Reported: “The focused tests still pass. I’m rerunning the input-width QEMU batch without changing the thresholds yet, so the original engine tells us whether the long-blank-slot model is right.”

    Action/result: Started the second QEMU input-width batch.

  1194. Reported: “The rerun is still inside QEMU. I’m polling it rather than starting another disassembly pass, since these cases depend on the shared snapshot harness completing cleanly.”

    Action/result: Waited on the second snapshot QEMU batch.

  1195. Reported: “Now the 0xa3 case is the one that mismatched, which is good evidence the prompt pollution is gone. I’m checking the exact row count; if it’s just below the threshold we can tune it, but if it is near zero then the blank slot may be suppressing typed input differently than expected.”

    Action/result: Observed that the long blank prompt moved the visible effect rather than removing it.

  1196. Reported: “The source model is still useful, but the visible signal is one row lower: the long blank prefix moves the typed characters into the next text row, so 0xa3 shows glyphs at logical Y 48..55. I’m retargeting the checks there; 0xa4/0xa9 should keep that wrapped row empty if they clear the flag.”

    Action/result: Retargeted input-width checks to the wrapped text row.

  1197. Reported: “The expected checks now target the wrapped row. I’m rerunning the focused unit test and then the three-case QEMU batch again, this time with all three cases able to exercise the same wrapped-row predicate.”

    Action/result: Started the third validation attempt.

  1198. Reported: “The unit check passes. I’m rerunning the QEMU batch; this one should distinguish 0xa3 from both clearing paths if the disassembly-derived cap model is correct.”

    Action/result: Began another snapshot QEMU run for the retargeted checks.

  1199. Reported: “The batch is running. This pass is a good example of QEMU as confirmation rather than discovery: the key distinction came from 0x3652; QEMU is just helping pin down the visible row where the effect lands.”

    Action/result: Waited on the retargeted QEMU batch.

  1200. Reported: “0xa3 now matches on the wrapped row, but 0xa4 still shows wrapped-row pixels. That means either 0xa4 is not being reached before typing, or the long-slot cap is not recomputed the way I expected after the flag clear. I’m checking the report and source-flow details before changing the fixture again.”

    Action/result: Investigated the remaining wrapped-row mismatch.

  1201. Reported: “The 0xa4 mismatch is actually a full white wrapped row, which looks like the blank prefix itself wrapped and painted as a white text rectangle, not necessarily typed characters. I’m waiting on the row breakdown and then I’ll avoid relying on wrapped text rows for this flag test.”

    Action/result: Distinguished white row fill from typed glyph pixels.

  1202. Reported: “A memory-backed check is probably the right tool for these tiny globals. Before adding anything, I’m reading the existing QEMU snapshot helper to see if we can extend it narrowly with monitor xp reads instead of building a separate debugger harness.”

    Action/result: Considered, but did not need, a monitor-backed memory check for this flag.

  1203. Reported: “There is a usable visible signal after all, but it’s the inverse of my first check: the wrapped row is white fill in both paths, while only the 0xa3 path contains black glyph pixels from accepted typed characters. I’m changing the cases to compare black glyph pixels, which aligns with the source distinction and the captures.”

    Action/result: Changed the predicate from white fill to black glyph pixels.

  1204. Reported: “The harness now checks for black glyph pixels in the wrapped row. I’m updating the unit expectations to match that corrected signal, then I’ll rerun all three original-engine cases.”

    Action/result: Updated the harness and test expectations.

  1205. Reported: “The unit expectation is corrected. I’m running the focused unit test and then a final QEMU pass for 0xa3, 0xa4, and 0xa9 with the black-glyph predicate.”

    Action/result: Started focused tests for the corrected predicate.

  1206. Reported: “The focused unit test passes. I’m rerunning the three-case QEMU batch; this should also exercise the 0xa9 clearing path now that 0xa4 is expected to pass.”

    Action/result: Started the final QEMU input-width batch.

  1207. Reported: “The batch is running again. If it passes, I’ll promote 0xa3 and 0xa4 for the input-width flag behavior, and 0xa9 for the unconditional flag clear while leaving its active saved-rectangle restore source-backed.”

    Action/result: Waited on the final input-width batch.

  1208. Reported: “The corrected input-width batch passed all three cases. I’m promoting 0xa3, 0xa4, and 0xa9 now, with the caveat documented that 0xa9’s active saved-rectangle restore remains source-backed while its unconditional [0x0d0f] clear is QEMU-validated.”

    Action/result: Promoted 0xa3, 0xa4, and 0xa9.

  1209. Reported: “I’m updating the evidence generator first so the generated opcode evidence table agrees with the new QEMU batch before I touch the prose tracker.”

    Action/result: Updated tools/logic_opcode_evidence.py.

  1210. Reported: “The generator now points at the input-width behavior cases. I’m regenerating the evidence page and then bumping the tracker to 171/176 covered action opcodes.”

    Action/result: Regenerated the logic opcode evidence chapter.

  1211. Reported: “The evidence chapter is regenerated. I’m updating PROGRESS.md; after this, the only partial action opcodes left should be 0x6e, 0x83, 0x8e, 0xaa, and 0xad.”

    Action/result: Prepared the tracker update.

  1212. Reported: “The tracker is updated to 171/176. I’m revising the opcode prose next so it explains the actual high-level behavior: [0x0d0f] changes the live input width calculation, and 0xa9 always clears that flag even without an active text window.”

    Action/result: Updated the opcode prose for input-width state.

  1213. Reported: “The row updates need a smaller patch because one of the surrounding summaries has been rewrapped by earlier edits. I’m applying the opcode-row changes first, then I’ll adjust the two stale summary paragraphs against their exact text.”

    Action/result: Split the opcode chapter patch after a context miss.

  1214. Reported: “I’ve got the exact paragraphs. I’m replacing the opcode rows and then cleaning the old “smoke-only” summaries so the chapter doesn’t contradict the new QEMU evidence.”

    Action/result: Removed stale smoke-only wording for promoted opcodes.

  1215. Reported: “The opcode chapter is now consistent. I’m updating the runtime model’s text/alternate-mode state row so implementers see why [0x0d0f] matters outside a one-line opcode description.”

    Action/result: Updated the runtime model.

  1216. Reported: “I accidentally triggered an empty web search while switching tools; no external material was consulted or used. I’m continuing with the local runtime-model edit.”

    Action/result: Recorded that the accidental empty search produced no external source material.

  1217. Reported: “The runtime model now includes the input-width state. I’m updating the symbolic label map with stable labels for the input-width flag and the small 0xa3/0xa4 action handlers, so future interpreter versions can be compared by role rather than raw address.”

    Action/result: Began updating symbolic labels for input-width state.

  1218. Reported: “The symbol map already had code.text.close_window_state; I’m expanding it and adding the flag/action labels in the same Text/Input section.”

    Action/result: Added and expanded text/input symbolic labels.

  1219. Reported: “The symbolic labels now include the width flag and its handlers. I’m adding the successful input_width_flag_004 batch to the compatibility chapter, with a short note about what the black-glyph predicate proves.”

    Action/result: Prepared compatibility evidence for the input-width batch.

  1220. Reported: “The compatibility chapter’s text/input section is the right home for this, so I’m placing the input-width batch between the prompt/text-attribute probes and the older text/status smoke batch.”

    Action/result: Inserted the input-width compatibility evidence.

  1221. Reported: “The compatibility chapter now has the reproducible successful batch. I’m appending the clean-room notes with the failed threshold/string attempts too, because those corrections explain why the final black-glyph predicate is the right one.”

    Action/result: Added the input-width observations and corrections to the clean-room notes.

  1222. Reported: “The input-width work is documented. I’m continuing into the last five partials now. The next likely candidate is 0x83, because it writes global [0x0139], and that same global is touched by first-object motion helpers, so there may be a source-driven movement probe available.”

    Action/result: Started the 0x83 investigation from disassembly.

  1223. Reported: “0x83 itself is extremely small in the disassembly: it only writes zero to [0x0139]. I’m looking at consumers of that word now; if no existing script-visible condition depends on it, I’ll keep it source-backed rather than inventing a brittle visual test.”

    Action/result: Confirmed that the action body only clears [0x0139].

  1224. Reported: “The consumer is the main cycle’s direction mirror between object 0 byte +0x21 and global byte [0x000f]. I’m reading that small source block directly; if 0x83 flips which side wins, we may be able to observe it with an existing object field getter and a conditional draw.”

    Action/result: Identified the main-cycle direction-mirror consumer for [0x0139].

  1225. Reported: “I’ll keep moving from PROGRESS.md and avoid waiting for repeated “continue” prompts. First I’m catching the progress log up with the recent input-width and 0x83 investigation updates, then I’ll continue from the disassembly-backed direction-mirror probe.”

    Action/result: Resumed the PROGRESS.md task stream and prepared to update the historical progress log.

  1226. Reported: “The tracker confirms the remaining partial action opcodes are 0x6e, 0x83, 0x8e, 0xaa, and 0xad. I’m adding the recent updates to the historical log now, then I’ll build the 0x83 probe around the main-cycle object0 direction mirror.”

    Action/result: Confirmed the partial opcode list and appended prior progress-log entries through the input-width work.

  1227. Reported: “The progress log is caught up. Now I’m reading the existing object-field probe helpers so the 0x83 case can reuse established fixture patterns instead of adding a one-off script shape.”

    Action/result: Reviewed object field setter/getter fixture helpers.

  1228. Reported: “The existing harness already has clean helpers for setting and reading object byte +0x21, which is exactly what the 0x83 consumer needs. I’m checking the fixture builder now so the new case can span multiple interpreter cycles without relying on timing guesswork.”

    Action/result: Confirmed 0x56/0x57 helper coverage and inspected multi-cycle fixture support.

  1229. Reported: “The case can be cycle-structured with two flags: phase 0 seeds object0 direction and clears [0x0139]; phase 1 lets the main loop copy that into global [0x000f], then sets [0x0139]; phase 2 verifies the global value was copied back into object0. I’m checking the exact helper bytes for nested if and flag conditions before patching it in.”

    Action/result: Designed the first attempted 0x83 multi-cycle fixture.

  1230. Reported: “The phase plan is sound: it observes 0x83 indirectly through 0x84 and 0x57, after the main loop has had a full cycle to perform each mirror direction. I’m going to add this as a narrowly named compatibility case, then run it alone under QEMU.”

    Action/result: Began adding the attempted 0x83 compatibility case.

  1231. Reported: “I found a useful detail: the existing object helpers normally use object 10, but the main-loop mirror is specifically object 0. The new fixture will initialize object 0 as a normal object entry, then use the same +0x21 setter/getter to observe the global mirror.”

    Action/result: Adjusted the attempted fixture to target object 0.

  1232. Reported: “One subtlety: if phase 0 simply sets a flag, phase 1 would run later in the same logic pass. I’m using an explicit end inside each successful phase so the handoff happens at the next main cycle, where the disassembled mirror code actually runs.”

    Action/result: Added phase-ending end actions to the attempted fixture design.

  1233. Reported: “The probe case is in the harness. I’m adding a unit assertion for it now, plus a small structural test that its bytecode includes the phase-ending end actions and both 0x83/0x84, so future edits do not accidentally collapse it back into a same-cycle test.”

    Action/result: Added temporary unit assertions for the attempted fixture.

  1234. Reported: “The focused structural test is added. I’m running just the probe tests that cover the case list and this new multi-cycle shape before I let QEMU execute it.”

    Action/result: Ran focused unit tests for the attempted fixture; they passed.

  1235. Reported: “The unit checks pass. I’m running the single 0x83 original-engine case now; if it matches, we’ll have a behavior-level validation of the selector bit rather than only a dispatch smoke.”

    Action/result: Started QEMU batch object0_direction_mirror_001.

  1236. Reported: “That command bounced because this particular harness doesn’t use a boolean --snapshot; it has snapshot image path options and otherwise runs its snapshot path by default. I’m rerunning with the harness’s actual CLI.”

    Action/result: Corrected the logic probe command after the ambiguous --snapshot option.

  1237. Reported: “The first QEMU run completed but did not match. I’m reading the generated comparison report and capture summary before changing anything; the key question is whether the phase logic failed to reach phase 2 or whether the mirror copied a different value than expected.”

    Action/result: Inspected QEMU report object0_direction_mirror_001.

  1238. Reported: “The mismatch is interesting, not a total failure: the validation sprite did draw, but its pixels are a different cel than the default expected one. That suggests the probe reached phase 2 and changed the object/direction state, but the transient validation draw is being influenced by direction-related selection. I’m going to identify the actual cel before deciding whether the behavioral check should expect that variant.”

    Action/result: Compared the capture against local view/cel renders.

  1239. Reported: “The mismatch is only inside the validation sprite, which is reassuring: the draw condition fired. I’m going to use a quick local comparison against available view/group/frame combinations to identify what the real engine drew.”

    Action/result: Determined that an exact transient/persistent marker was not a clean signal.

  1240. Reported: “The real engine drew view 11 frame 7, even though the validation helper requested frame 0, because the transient draw path is also seeing the direction state. That is useful evidence, but for this opcode probe I want the pass/fail signal to be just the object0 mirror, so I’m switching the conditional marker to a persistent object with explicit setup instead of the transient validation helper.”

    Action/result: Reworked the attempted fixture marker to use a persistent object.

  1241. Reported: “The marker now uses object 10 with bit 0x2000 set, so its cel choice should stay fixed while the condition still depends on object0 byte +0x21. I’m rerunning the focused structural test, then the same single QEMU case.”

    Action/result: Ran the updated attempted fixture; it still mismatched.

  1242. Reported: “It still reaches a mismatch, so I’m inspecting the new report. If this is another cel/priority difference we can correct the expected marker; if there is no marker, the phase logic needs adjustment.”

    Action/result: Inspected object0_direction_mirror_002.

  1243. Reported: “Still mismatched. I’m checking whether 0x46 actually stabilizes the marker in this setup or whether persistent-object activation sets the animation bit after the clear.”

    Action/result: Investigated persistent marker frame advancement.

  1244. Reported: “The remaining mismatch is animation timing: the persistent marker advances to frame 7 during the draw wait. Since this probe is about 0x83, I’m using the already-documented 0x46 action to clear the animation bit on the marker so the expected cel stays frame 0.”

    Action/result: Added 0x46 to the attempted marker setup.

  1245. Reported: “The marker now suppresses automatic group selection and frame cycling before activation. I’m doing one more focused unit check and QEMU run for 0x83.”

    Action/result: Ran focused unit check and QEMU batch object0_direction_mirror_003; it still mismatched.

  1246. Reported: “Still mismatched. I’m checking whether 0x46 actually stabilizes the marker in this setup or whether persistent-object activation sets the animation bit after the clear.”

    Action/result: Confirmed the marker still advanced.

  1247. Reported: “The marker still advances to frame 7, so activation probably sets the animation bit after my clear. I’m moving 0x46 after activation; that should leave the marker active but non-advancing during the subsequent frame update.”

    Action/result: Reordered the marker actions.

  1248. Reported: “I’ve reordered the marker actions. I’m rerunning the single QEMU case; if this still advances, I’ll just set the expected frame to the observed stable frame and document why.”

    Action/result: Ran QEMU batch object0_direction_mirror_004; it still mismatched.

  1249. Reported: “The marker remains animated, so an exact-frame comparison is the wrong assertion for this probe. I’m switching the case to a rectangle predicate that only asks “did the conditional marker place non-background sprite pixels here?”, which keeps the test about the 0x83 mirror instead of frame timing.”

    Action/result: Reconsidered the validation predicate after confirming the capture had no marker.

  1250. Reported: “The capture shows no marker at all, so the phase condition is false. I’m generating a disposable diagnostic fixture under build/ that draws a marker at different X positions for object0 direction values 0..8; this will tell us what 0x57 reads after the mirror sequence without adding a speculative permanent test.”

    Action/result: Generated disposable diagnostic manual_direction_value_cases.json.

  1251. Reported: “The disposable case is generated. I’m running it through QEMU with comparison against a blank picture, so any drawn marker will show up as a mismatch bbox and we can map that X position back to the value.”

    Action/result: Ran object0_direction_value_diag_001; it matched blank, showing no value marker in 0..8.

  1252. Reported: “The value diagnostic stayed blank, which means either phase 2 is not being reached or +0x21 is outside 0..8. I’m generating one more disposable variant with an unconditional phase-2 marker, so we can separate phase-control failure from an unexpected direction byte.”

    Action/result: Generated disposable diagnostic manual_direction_phase_cases.json.

  1253. Reported: “The second diagnostic uses high-numbered flags as well, just in case the earlier phase flags were touched by interpreter/game state. I’m running it now.”

    Action/result: Ran object0_direction_phase_diag_001.

  1254. Reported: “The phase-2 marker did draw, so the multi-cycle flag scaffolding is fine. I’m reading the bbox and pixel locations now to infer which value-specific marker, if any, appeared alongside the unconditional one.”

    Action/result: Mapped the value marker to direction value 0.

  1255. Reported: “The phase-2 getter reads direction 0, not 6. That suggests the first object entry’s direction is being cleared before the next top-of-cycle mirror can seed [0x000f], likely because the object is inactive/stationary. I’m testing a source-driven variant that activates object 0 during the seed phase so its direction byte survives long enough to be mirrored.”

    Action/result: Generated active-object disposable diagnostic.

  1256. Reported: “The active-object diagnostic is generated. I’m running it now; the value marker should tell us whether activation preserves the seed direction.”

    Action/result: Ran object0_direction_active_diag_001.

  1257. Reported: “The active-object diagnostic produced a marker. I’m extracting the X buckets now to map it back to the direction value.”

    Action/result: The active-object variant still mapped to direction value 0.

  1258. Reported: “Activating object 0 still yields value 0, so the issue is not just inactive-object cleanup. I’m going back to the disassembly references for [0x0139] and [0x000f]; something after the action may be restoring the selector or clearing the global before the next cycle.”

    Action/result: Re-read references to [0x0139] and [0x000f].

  1259. Reported: “The main-cycle source explains the failed fixture: after logic returns, the cycle writes global [0x000f] back into object0 +0x21 unconditionally. So a script-set object0 direction after the top-of-cycle mirror is clobbered before the next cycle. I’m reading the neighboring code and references now to document 0x83 precisely rather than forcing a misleading QEMU test.”

    Action/result: Identified the cycle-end global-to-object restore.

  1260. Reported: “At this point the clean result is source-backed, not QEMU-promoted: 0x83 is a selector write whose effect occurs before logic, while our script-level attempts happen after that point and are clobbered by the cycle-end global-to-object copy. I’m going to document that timing explicitly and mark 0x83 covered as source-backed rather than pretending the failed fixture was a useful compatibility test.”

    Action/result: Decided to promote 0x83 as source-backed.

  1261. Reported: “I’m updating the evidence generator so 0x83 is recorded as source-backed with a timing caveat, not as a QEMU smoke. Then I’ll update the opcode prose and progress tracker to reduce the partial list to four.”

    Action/result: Prepared the evidence-generator update.

  1262. Reported: “Since the script-level 0x83 fixture does not prove the selector behavior, I’m removing it from the reusable probe registry rather than leaving a misleading failing case around. The failed attempts will stay documented in the notes as evidence about cycle timing.”

    Action/result: Removed the attempted reusable helper from tools/logic_interpreter_probe.py.

  1263. Reported: “The helper is removed. I’m removing the corresponding registry entry and unit assertions next, then the evidence generator will carry 0x83 as source-backed.”

    Action/result: Removed the attempted base-case entry.

  1264. Reported: “The failing 0x83 registry case is gone. I’m cleaning up the unit test references that were only there to protect that abandoned fixture.”

    Action/result: Removed the temporary unit assertions.

  1265. Reported: “The abandoned fixture is cleaned out. I’m running the case-list unit test once to make sure the registry is back to a consistent shape before changing the docs.”

    Action/result: The case-list unit test passed.

  1266. Reported: “The registry test passes. I’m changing the generated evidence matrix so 0x83 has its own source-backed note about the main-cycle mirror and the failed script-level probe timing.”

    Action/result: Added SOURCE_BACKED_ACTIONS evidence for 0x83.

  1267. Reported: “The generator now treats 0x83 as a source-backed timing primitive rather than a smoke. I’m regenerating the evidence chapter.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  1268. Reported: “The evidence chapter is regenerated. I’m updating PROGRESS.md now: 0x83 is covered as source-backed, leaving 0x6e, 0x8e, 0xaa, and 0xad partial.”

    Action/result: Updated PROGRESS.md to 172/176 covered action opcodes.

  1269. Reported: “The tracker is updated. I’m expanding the opcode prose next, because implementers need the timing rule: 0x83 affects the next cycle’s pre-logic mirror, but logic-script attempts to seed object0 direction after that point are overwritten at cycle end.”

    Action/result: Began updating docs/src/logic_bytecode.md.

  1270. Reported: “The top-level cycle section already mentions the mirror, but it doesn’t say which branch corresponds to [0x0139] == 0 or mention the cycle-end copy. I’m adding that there and in the 0x83 opcode row.”

    Action/result: Added branch direction and cycle-end restore prose.

  1271. Reported: “I found two older smoke summaries that still list opcodes we’ve since promoted or source-backed. I’m cleaning those alongside the 0x83 timing prose so the book stays internally consistent.”

    Action/result: Updated old smoke summaries in the bytecode chapter.

  1272. Reported: “The logic bytecode chapter now carries the exact branch direction and the failed-probe timing reason. I’m updating the compatibility chapter’s old smoke summary to stop claiming 0x83 is only smoke-covered.”

    Action/result: Updated docs/src/compatibility_testing.md.

  1273. Reported: “Compatibility notes are consistent now. I’m adding the same high-level timing rule to the runtime model’s motion/object lifecycle, since that’s where an implementer is likely to look when modeling object0 direction and keyboard/global direction state.”

    Action/result: Added an object0/global direction mirror row to docs/src/runtime_model.md.

  1274. Reported: “The runtime model now has the special mirror row. I’m updating the symbolic label map with stable data labels for [0x0139] and [0x000f], plus a clearer main-cycle note for cross-version comparison.”

    Action/result: Began updating docs/src/symbolic_labels.md.

  1275. Reported: “The label file already has the first-object pointer, so I’m placing the direction mirror globals in that same data section and sharpening the main-cycle description.”

    Action/result: Added data.motion.global_direction_000f and data.motion.direction_mirror_selector_0139.

  1276. Reported: “The symbolic labels now include the two mirror globals. I’m appending a clean-room notes section with the disassembly commands, the failed/diagnostic QEMU attempts, and the conclusion that 0x83 is source-backed because its branch point is outside script control.”

    Action/result: Prepared the clean-room notes section.

  1277. Reported: “The notes currently end at the input-width promotion, so I’m adding a new dated section immediately after it for the 0x83 source pass and diagnostics.”

    Action/result: Appended the 0x83 direction-mirror timing section to docs/src/clean_room_executable_notes.md.

  1278. Reported: “The clean-room notes now capture the 0x83 investigation. I’m catching the progress log up again before moving to the next remaining partial opcode, since this pass had several diagnostic detours worth preserving.”

    Action/result: Prepared to append the 0x83 investigation progress-log entries.

  1279. Reported: “The progress log is caught up through the 0x83 source-backed promotion. I’m moving on to the four remaining partials now; I’ll start with 0xad because it is small, source-local, and likely another timing/global side effect we can either document cleanly or validate with a narrow probe.”

    Action/result: Began the 0xad source pass.

  1280. Reported: “0xad is a tiny handler too: inc byte [0x1530] and return. I’m reading the keyboard-interrupt consumer around 0x6036 because that byte is only useful if we can explain when the nonzero value changes observable behavior.”

    Action/result: Disassembled the action body and keyboard IRQ consumer.

  1281. Reported: “The consumer is clearer now: [0x1530] is a nonzero gate in the keyboard IRQ path. On tracked key release, if the per-key pressed latch was set and [0x1530] is nonzero, the ISR calls the same event enqueue/display-input helper path. I’m checking where the tracked-key table is initialized before turning this into a source-backed spec row.”

    Action/result: Identified the tracked-key release gate behavior.

  1282. Reported: “The only static hits for [0x1530] are the action increment and the keyboard ISR test, so this looks like an enable/count gate rather than ordinary game state. I’m checking the existing event-helper labels so the docs can name the called helper symbolically instead of using a raw address.”

    Action/result: Reused code.input.enqueue_event as the symbolic helper name for the IRQ enqueue call.

  1283. Reported: “I’m treating 0xad as source-backed: the action body and the only observed consumer are both local and compact, while building a QEMU fixture around raw IRQ key-release timing would be brittle. I’m updating the evidence matrix and docs to call it a key-release enqueue gate.”

    Action/result: Decided to promote 0xad as source-backed.

  1284. Reported: “The generator has a specific source-backed entry for 0xad. I’m removing it from the smoke-only set and regenerating the evidence page.”

    Action/result: Added 0xad to source-backed evidence and prepared to remove its smoke classification.

  1285. Reported: “0xad is no longer classified as smoke in the generator. I’m regenerating the matrix now.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  1286. Reported: “The evidence page is regenerated. I’m updating PROGRESS.md so 0xad is covered as source-backed, leaving only 0x6e, 0x8e, and 0xaa partial.”

    Action/result: Updated PROGRESS.md to 173/176 covered action opcodes.

  1287. Reported: “The tracker is updated. I’m expanding the raw event queue section and the 0xad opcode row so the source-backed status has real semantics, not just “increments a byte.””

    Action/result: Updated docs/src/logic_bytecode.md for the IRQ release-event gate.

  1288. Reported: “The bytecode chapter now links 0xad to the IRQ release path. I’m updating the compatibility chapter so the old diagnostics batch is clearly just smoke for 0x8e/0xaa, while 0xad is source-backed.”

    Action/result: Updated docs/src/compatibility_testing.md.

  1289. Reported: “The compatibility chapter is consistent. I’m adding the key-release gate to the runtime model’s input/event lifecycle so implementation readers know 0xad is an input subsystem detail.”

    Action/result: Prepared the runtime-model update.

  1290. Reported: “The event/edit loop row is the right place for this; I’m extending its contract rather than adding another separate section.”

    Action/result: Updated docs/src/runtime_model.md.

  1291. Reported: “The runtime model now mentions the release-event gate. I’m adding symbolic labels for the IRQ hook and its small data tables so future version comparisons can find this feature without relying on raw addresses.”

    Action/result: Prepared symbolic-label additions for the IRQ hook and tables.

  1292. Reported: “The input data table section already has the queue and key-map entries, so the release-tracking tables fit cleanly there. I’m patching both code and data labels together.”

    Action/result: Added code.input.keyboard_irq_hook and related data labels.

  1293. Reported: “The symbol map now names the IRQ hook and its latch/gate tables. I’m appending a short clean-room note for 0xad, including the disassembly evidence and why it stays source-backed instead of QEMU-validated.”

    Action/result: Appended the 0xad key-release enqueue gate section to docs/src/clean_room_executable_notes.md.

  1294. Reported: “The 0xad clean-room note is in place. I’m logging the 0xad work in progress_log.md before moving on to the last three partial opcodes.”

    Action/result: Appended the 0xad progress-log entries.

  1295. Reported: “0xad is logged. I’m moving to 0x8e next, since it sits in the resource-event replay system we already documented; the goal is to tighten its exact capacity/reset behavior from disassembly and see whether existing replay probes already cover the observable contract.”

    Action/result: Began the 0x8e source pass.

  1296. Reported: “0x8e is already well supported by the resource-event source pass: it writes data.event.pair_capacity, wraps code.event.reset_pair_buffer with flush/rebuild helpers, and the reset helper’s capacity/count semantics are documented. I’m going to promote it as source-backed rather than manufacture a replay fixture that would mostly re-test the larger 0x8c replay machinery.”

    Action/result: Decided to promote 0x8e as source-backed.

  1297. Reported: “That patch missed because the smoke table has already collapsed to a shorter shape after the previous edits. I’m re-reading the exact generator block and applying a narrower patch.”

    Action/result: Re-read tools/logic_opcode_evidence.py after a patch-context miss.

  1298. Reported: “The generator block is straightforward. I’m adding 0x8e to the source-backed map and leaving only 0x6e in the smoke map.”

    Action/result: Updated the evidence generator for 0x8e.

  1299. Reported: “0x8e is now source-backed in the generator. I’m regenerating the evidence page and updating the tracker to 174/176.”

    Action/result: Regenerated the logic opcode evidence chapter.

  1300. Reported: “The evidence page is regenerated. I’m updating PROGRESS.md; after this only 0x6e and 0xaa remain partial in the action table.”

    Action/result: Updated PROGRESS.md to 174/176 covered action opcodes.

  1301. Reported: “The tracker now leaves two partial actions. I’m expanding the 0x8e row and cleaning the old smoke paragraph so it no longer treats event capacity reset as merely dispatch-smoked.”

    Action/result: Updated docs/src/logic_bytecode.md.

  1302. Reported: “The bytecode chapter now treats 0x8e as the source-backed event log capacity reset. I’m updating the compatibility chapter’s diagnostics summary to leave only 0xaa as smoke-covered.”

    Action/result: Updated docs/src/compatibility_testing.md.

  1303. Reported: “Compatibility notes now align with the source-backed promotion. I’m checking the runtime model’s resource-event section; it likely already has the necessary capacity/reset contract, but I’ll add a line if it’s missing.”

    Action/result: Reviewed the runtime model resource lifecycle.

  1304. Reported: “The resource lifecycle table mentions replay/recording but not the capacity reset itself. I’m adding a small paragraph after the table so 0x8e is visible in the high-level model.”

    Action/result: Updated docs/src/runtime_model.md.

  1305. Reported: “The runtime model now has a direct 0x8e capacity-reset paragraph. I’m tightening the existing symbolic label note for code.event.set_pair_capacity_action with the same semantics.”

    Action/result: Updated docs/src/symbolic_labels.md.

  1306. Reported: “The symbolic map is updated. I’m adding a short 0x8e clean-room note that ties the handler, reset helper, and existing replay evidence together.”

    Action/result: Appended the 0x8e event-pair capacity reset section to docs/src/clean_room_executable_notes.md.

  1307. Reported: “0x8e is documented. I’m moving to 0xaa, the save-description copy action. There was an earlier failed attempt to force the buffer; I’ll re-read the save selector/source path first so we can decide whether it is cleanly source-backed or worth a new QEMU fixture.”

    Action/result: Began the 0xaa source pass.

  1308. Reported: “The 0xaa source path is compact and the earlier QEMU attempt patched the wrong layer: the action copies from the interpreter’s runtime buffer at DS:0x0e72, not from the fixture’s static AGIDATA bytes. I’m going to promote this as source-backed and document that proper dynamic validation would need to drive the save/restore selector to populate that runtime buffer.”

    Action/result: Decided to promote 0xaa as source-backed.

  1309. Reported: “The generator now has source-backed evidence for 0xaa. I’m regenerating the matrix and updating the tracker; after this, only the screen-shake-like 0x6e remains partial.”

    Action/result: Updated the evidence generator and regenerated the matrix.

  1310. Reported: “The evidence matrix is regenerated. I’m bumping PROGRESS.md to 175/176 covered action opcodes.”

    Action/result: Updated PROGRESS.md to 175/176 covered action opcodes.

  1311. Reported: “The tracker now leaves only 0x6e partial. I’m updating the 0xaa opcode prose and retiring the last old “dispatch-smoke” wording in the diagnostics/system paragraph.”

    Action/result: Updated docs/src/logic_bytecode.md.

  1312. Reported: “The bytecode chapter now explains the static-patch failure correctly. I’m updating the compatibility chapter’s save-description section so it records that failed QEMU attempt as a fixture-shape issue, not an unresolved opcode.”

    Action/result: Updated docs/src/compatibility_testing.md.

  1313. Reported: “The compatibility note now distinguishes static fixture bytes from the runtime buffer. I’m adding a brief runtime-model note under save/restore so 0xaa shows up at the subsystem level too.”

    Action/result: Checked for an existing save/restore runtime section.

  1314. Reported: “The runtime model doesn’t yet have a save/restore subsection, so I’m adding a compact one rather than scattering 0xaa into unrelated text/input state.”

    Action/result: Added a save/restore data model table to docs/src/runtime_model.md.

  1315. Reported: “The runtime model now has a save/restore data model and names the 0xaa contract. I’m adding symbolic labels for the action handler and runtime description buffer.”

    Action/result: Prepared save-description symbolic labels.

  1316. Reported: “The save code labels are grouped already. I’m placing 0xaa there and adding the buffer in the data section near other runtime globals.”

    Action/result: Added code.save.copy_description_to_string_action and data.save.description_buffer.

  1317. Reported: “The symbol map now includes the 0xaa handler and runtime save-description buffer. I’m appending a clean-room note for 0xaa so the failed static-patch QEMU attempt and the source-backed conclusion are both in the evidence trail.”

    Action/result: Appended the 0xaa save-description buffer copy section to docs/src/clean_room_executable_notes.md.

  1318. Reported: “0xaa is now source-backed and logged in the notes. I’m turning to the final partial action, 0x6e, the screen-shake-like handler; I’ll inspect the disassembly first and decide whether a visual QEMU validation is practical or whether the effect is hardware-timing-specific.”

    Action/result: Began the 0x6e source pass.

  1319. Reported: “The first disassembly window caught the neighboring input-line config code, not the shake handler. The opcode table says 0x6e starts around 0x7a00, so I’m reading that exact region next.”

    Action/result: Re-read the exact 0x6e handler region.

  1320. Reported: “0x6e is the last partial and the source is now clear. It is a hardware/display timing effect: for normal EGA-like modes it walks a small byte table and writes CRT controller registers 0x02 and 0x07, waiting one timer tick between offsets; other display modes delegate to overlay helpers. A screenshot-after-return fixture can only prove dispatch, so I’m promoting this as source-backed.”

    Action/result: Decided to promote 0x6e as source-backed.

  1321. Reported: “The generator now treats 0x6e as source-backed with a note that QEMU only dispatch-smoked it. I’m regenerating the evidence matrix and then the opcode table will be complete.”

    Action/result: Updated the evidence generator and regenerated the matrix.

  1322. Reported: “The evidence matrix is regenerated. I’m updating PROGRESS.md to show all 176 action opcodes covered at the current spec target.”

    Action/result: Updated PROGRESS.md to all 176 action opcodes covered.

  1323. Reported: “The action opcode tracker is now complete. I’m checking the remaining-work section to make sure it no longer implies opcode coverage is still the highest-value gap.”

    Action/result: Reviewed PROGRESS.md remaining-work section.

  1324. Reported: “The highest-value list still has the old “promote remaining dispatch-smoke opcodes” item. I’m replacing that with the next useful opcode-adjacent work: hardening source-backed edge cases and moving back into subsystem specs/tests.”

    Action/result: Updated PROGRESS.md highest-value remaining work.

  1325. Reported: “The remaining-work list now reflects that opcode coverage is complete at the current target. I’m expanding the 0x6e row with the exact normal-path register loop and display-mode branch behavior.”

    Action/result: Updated the 0x6e opcode prose.

  1326. Reported: “The opcode row now has the source-level shake loop. I’m updating the text/status compatibility section so it says QEMU smoke only proves return, while the shake semantics are source-backed.”

    Action/result: Updated docs/src/compatibility_testing.md.

  1327. Reported: “The compatibility chapter now classifies 0x6e correctly. I’m adding a small display-hardware note to the runtime model because this opcode is really a hardware timing operation, not a logical surface mutation.”

    Action/result: Prepared the runtime-model display note.

  1328. Reported: “There’s a short miscellaneous action list at the end of the runtime model, so I’m adding 0x6e there with its “transient register effect” contract.”

    Action/result: Updated docs/src/runtime_model.md.

  1329. Reported: “The runtime model now states the portable contract for shake: short display offset animation, no persistent buffer change. I’m adding labels for the shake handler and its offset table/base bytes.”

    Action/result: Prepared symbolic labels for the shake path.

  1330. Reported: “The display labels are grouped near the graphics helpers and display globals. I’m adding the 0x6e action label there, plus the three data globals/table it uses in the normal CRT path.”

    Action/result: Added code.display.shake_screen_action and related display data labels.

  1331. Reported: “The symbol map now has the shake action and data labels. I’m adding the final clean-room note for 0x6e, then I’ll run the verification suite.”

    Action/result: Appended the 0x6e screen-shake source pass section to docs/src/clean_room_executable_notes.md.

  1332. Reported: “I’ve picked the thread back up at the verification stage. First I’m going to finish checking the opcode-coverage edits, then I’ll roll straight into the next PROGRESS.md item instead of waiting for another nudge.”

    Action/result: Resumed from the opcode-coverage verification pass.

  1333. Reported: “mdbook build docs is clean. I’m doing the last mechanical checks now, including whitespace/diff hygiene and a quick scan for stale “partial opcode” wording before moving on.”

    Action/result: Confirmed mdbook build docs succeeds and started final hygiene checks.

  1334. Reported: “The verification pass surfaced only expected historical mentions of earlier “173/174/175” milestones, not current stale status. I also see two probe/test files modified, so I’m going to inspect those before deciding whether they are intentional work to carry forward or leftovers from the opcode push.”

    Action/result: Inspected the probe and unit-test diffs.

  1335. Reported: “I’m going to preserve these updates in the historical progress log now. The extra probe edits look aligned with the next PROGRESS.md item, namely text/input UI semantics, so I’ll treat them as in-flight work to validate and document rather than discard.”

    Action/result: Began documenting the verification handoff and selected text/input UI semantics as the next workstream.

  1336. Reported: “Text/input coverage is more advanced than the high-level tracker implies: the newer batches all report match with zero mismatches. I’m going to tighten the tracker around that and then use the next gap in the same area, menu navigation, as the next source-first target.”

    Action/result: Checked recorded QEMU batch outputs for the text/input cases and selected menu navigation as the next gap.

  1337. Reported: “There is already a menu label cluster and a couple of QEMU probes, but the “remaining” risk is navigation behavior. I’m rereading the menu interaction routine at 0x93d1 and the event normalizer paths around 0x4529..0x46e8 so the next test cases come from the control flow rather than guesswork.”

    Action/result: Re-read code.menu.interact and the shared input/event helpers from disassembly.

  1338. Reported: “The navigation table is clear in the disassembly: movement values 1..8 jump to eight small branches at 0x9492, 0x94a6, 0x94b2, 0x94cb, 0x94da, 0x94e5, 0x94f6, and 0x9509. I’m going to inspect the menu node construction now so I can name those branches correctly in terms of next/previous item and heading movement.”

    Action/result: Decoded the menu movement dispatch table and inspected menu node construction.

  1339. Reported: “The menu construction confirms both heading and item lists are circular doubly-linked lists: offset +0 is next and +2 is previous; headings point at their item list at +0c, and item enable/selection id live at +0a/+0c. I’m going to add a compact source-backed navigation table to the docs and tracker, then consider whether a non-keyboard event-injection probe is worth adding.”

    Action/result: Prepared source-backed menu navigation documentation.

  1340. Reported: “I’m making a source-backed documentation pass now: correcting the old “enabled item navigation” wording, adding the exact movement-code table, and recording the branch targets as symbolic labels so this survives future interpreter-version comparisons.”

    Action/result: Added the menu navigation source table and updated symbolic labels, runtime model, compatibility notes, clean-room notes, and PROGRESS.md.

  1341. Reported: “That patch didn’t apply because the clean-room note heading text has drifted slightly. No files were changed by that failed patch; I’m locating the exact anchors and I’ll apply it in smaller chunks.”

    Action/result: Located the exact clean-room and progress-log anchors.

  1342. Reported: “I found the exact anchors. I’m applying the menu-navigation docs in smaller patches now so each change has a clean landing point.”

    Action/result: Applied the logic-bytecode menu navigation table.

  1343. Reported: “The logic bytecode chapter now has the exact movement table and the corrected disabled-item semantics. I’m carrying the same model into the runtime overview and symbolic label map.”

    Action/result: Updated the runtime model and symbolic label map.

  1344. Reported: “The runtime model now has a portable menu state description, and the symbol map has separate root/current pointers plus the navigation jump table. Next I’m updating the tracker and compatibility notes so the remaining gap is accurately framed as dynamic movement-event validation, not unknown semantics.”

    Action/result: Updated PROGRESS.md and compatibility notes.

  1345. Reported: “The tracker now says menu navigation is source-backed and names the remaining validation gap precisely. I’m adding the clean-room evidence note and progress-log entries for this source pass.”

    Action/result: Appended the menu-navigation clean-room section and this progress-log catch-up.

  1346. Reported: “The menu source pass is documented. I’m going to run the quick verification checks now, then I’ll move into the next PROGRESS.md item: picture/view renderer compatibility, using the existing renderer and QEMU captures as confirmation tools.”

    Action/result: Ran mdBook, diff whitespace, and full unittest checks.

  1347. Reported: “Verification is clean: mdBook builds, whitespace checks pass, and the full unittest suite still runs green. I’m switching into the picture/view renderer area now and reading the current renderer/test coverage before picking a narrow edge case.”

    Action/result: Began reviewing renderer, view-batch, and graphics tests.

  1348. Reported: “The graphics test file I guessed at doesn’t exist; the renderer coverage is split across other test modules. I’m locating the actual graphics tests and then I’ll pick an edge case that lines up with both the disassembly and the current harness.”

    Action/result: Located tests/test_graphics_rendering.py and related overlay/movement tests.

  1349. Reported: “The renderer surface is clearer now: picture tests live in tests/test_graphics_rendering.py, while object-overlay and movement probes exercise composed view cels. I’m reading the remaining edge docs around transparent/mirroring/clipping to choose a useful, source-backed next probe.”

    Action/result: Reviewed graphics object-pipeline notes and object overlay case coverage.

  1350. Reported: “A good next edge is the object placement/search helper around 0x593a, especially the weird right-edge result that currently lives as an observation. I’m going to read that disassembly before adding any new QEMU probes, because the existing behavior probably explains itself in the placement code.”

    Action/result: Disassembled code.object.place and code.object.control_acceptance.

  1351. Reported: “The placement helper explains the odd right-edge capture: 0x593a first tries the requested position, then does a spiral search with growing segment lengths: left 1, down 1, right 2, up 2, left 3, down 3, and so on. I’m checking the current prose because it may already have part of this but not the full search contract.”

    Action/result: Found the existing placement prose and identified the missing exact spiral contract.

  1352. Reported: “I’m going to codify the spiral search locally rather than keep right-edge placement as a magic expected coordinate. First I’m checking the derived sequence against the known QEMU result; if it lands on (140,67), that gives us a much better compatibility oracle.”

    Action/result: Simulated the source sequence and confirmed it reaches (140, 67) for the known right-edge case.

  1353. Reported: “The derived spiral lands exactly on the known right-edge QEMU placement (140,67), which is a nice little moment. I’m going to turn that into a reusable helper and unit tests, then update the object-overlay comparison to use the source-derived placement instead of hard-coded coordinates where possible.”

    Action/result: Prepared the placement-search helper and tests.

  1354. Reported: “I’m editing the local graphics model now: adding a 0x593a-style placement search helper, switching the overlay comparison to use it for ordinary bounds adjustment, and replacing the old hard-coded edge-position tests with source-derived expectations.”

    Action/result: Added search_object_placement() and updated overlay comparisons/tests.

  1355. Reported: “The placement helper is in place and the edge cases now derive their expected positions from that source model. I’m running the focused graphics/object-overlay tests before I touch the docs.”

    Action/result: Ran focused graphics, object-overlay, and view-batch tests successfully.

  1356. Reported: “The focused Python tests pass. Before running a fresh emulator batch, I’m checking the existing QEMU captures for the top/right edge cases against the new source-derived placement model; that gives a quick original-engine sanity check without burning another boot.”

    Action/result: Existing top/right QEMU captures matched the new source-derived placement model with 0 mismatches.

  1357. Reported: “The existing top/right QEMU captures both match with the new source-derived placement helper. I’m documenting the exact spiral search now and tightening the compatibility notes so future work treats this as a modeled routine, not a one-off captured coordinate.”

    Action/result: Began updating the object-placement documentation.

  1358. Reported: “The docs anchor moved again in that paragraph, so I’m doing the same smaller-patch treatment here. No changes landed from that failed patch.”

    Action/result: Located exact placement documentation anchors.

  1359. Reported: “I’ve got the exact paragraphs. I’m applying the placement-search documentation separately now.”

    Action/result: Added the exact 0x593a spiral and acceptance tests to the graphics object-pipeline chapter.

  1360. Reported: “The placement section now states the exact spiral and acceptance tests. I’m replacing the older “weird right edge” prose with the source-derived explanation.”

    Action/result: Rewrote the top/right edge placement explanation.

  1361. Reported: “The object-pipeline chapter now treats the top/right placements as outputs of the 0x593a spiral. I’m updating the compatibility and tracker notes, plus the symbol map, to match the new model.”

    Action/result: Updated compatibility notes, symbolic labels, and PROGRESS.md.

  1362. Reported: “The compatibility/tracker docs are aligned. I’m adding the clean-room evidence entry for the placement-source pass and logging the recent work updates.”

    Action/result: Appended the object-placement source-pass notes and this progress-log catch-up.

  1363. Reported: “Full verification is clean: 109 tests now pass, opcode evidence check passes, mdBook builds, and diff whitespace is clean. I’ll continue with renderer compatibility; next I’m looking for picture-fuzz or view-corpus gaps that are still only lightly covered.”

    Action/result: Verified the full local suite, opcode-evidence check, mdBook build, and whitespace check, then moved to renderer-compatibility gaps.

  1364. Reported: “The next picture-side risk the docs call out is seed-fill traversal: the local renderer uses a queue, while the original appears to have its own stack/span helper. I’m going to inspect the seed-fill routine around 0x533b and see whether the observable contract can be made more implementation-ready without overfitting internals.”

    Action/result: Began source-first inspection of picture seed fill around code.picture.seed_fill (0x533b).

  1365. Reported: “I’m picking up at the seed-fill source pass. I’ll first write the two recent progress updates into the log, then tighten the docs around the span-stack fill behavior before deciding whether new compatibility cases are worth adding.”

    Action/result: Resumed from the seed-fill source pass and checked current tracker/docs state.

  1366. Reported: “The repo is in the expected in-progress state, with the object placement pass already documented and tested. I’ve found the outstanding picture-renderer note: seed fill is documented as span-based, but the exact source-derived contract can be sharper.”

    Action/result: Identified seed-fill traversal documentation as the next high-value picture-renderer refinement.

  1367. Reported: “I’m going back to the actual 0x533b disassembly rather than just polishing prose from memory. The goal is to describe what the original routine commits to observably, and keep implementation guidance portable.”

    Action/result: Re-read the seed-fill helper disassembly and the current picture-renderer compatibility notes.

  1368. Reported: “The seed-fill routine confirms the docs’ broad statement, and adds useful specifics: it chooses exactly one expansion channel, rejects no-op fills before scanning, writes spans with the normal odd/even masks, and uses stack-pushed span state for branches. I’m turning that into a clearer spec paragraph now.”

    Action/result: Prepared a source-backed seed-fill contract update for the graphics pipeline documentation.

  1369. Reported: “I’m going to keep the seed-fill labels conservative: the scratch bytes around 0x126c clearly form span state, but several fields change roles during branch handling. A single “span scratch block” label is more honest than naming every byte too confidently.”

    Action/result: Reviewed existing picture symbolic labels and chose a conservative scratch-block label strategy for seed-fill state.

  1370. Reported: “There’s already an older seed-fill refinement note, so I’m not going to pretend this is a first discovery. This pass will add the missing traversal details and separate “observable behavior” from “how SQ2’s executable happens to organize its stack state.””

    Action/result: Compared the older seed-fill notes with the new disassembly pass to avoid duplicating or overstating evidence.

  1371. Reported: “PROGRESS.md points next at picture/view compatibility and then implementation-ready subsystem state machines. I’ll finish the seed-fill spec cleanup as part of that renderer work, then use the tracker to choose the next concrete gap rather than wandering.”

    Action/result: Re-read the high-value tracker section and kept the next work item aligned to renderer compatibility.

  1372. Reported: “I’m editing the picture pipeline chapter now. The important distinction is: original traversal order is source-backed, but clean implementations can use a different flood-fill algorithm if they preserve target selection and pixel-write semantics on valid resources.”

    Action/result: Updated the 0xf8 seed-fill section with explicit channel selection, early exits, span-stack traversal, and portable final-buffer semantics.

  1373. Reported: “The main seed-fill chapter now separates channel selection, no-op rejection, span traversal, and the portable observable contract. I’m adding the scratch-block label and evidence note so future cross-version work has something stable to map.”

    Action/result: Added data.picture.seed_fill_span_scratch to the symbolic label map.

  1374. Reported: “The compatibility notes still say the traversal itself is an open risk. I’m narrowing that: traversal class is now source-backed; what still needs broader proof is edge-case parity across barriers, masks, and multiple seeds.”

    Action/result: Reframed the seed-fill compatibility risk around expanded parity coverage instead of unknown traversal class.

  1375. Reported: “I’m appending the clean-room evidence entry for this seed-fill pass, including the commands that were useful and the small correction to the previous “queue versus span” uncertainty.”

    Action/result: Appended the picture seed-fill span-stack source-pass note to the clean-room evidence log.

  1376. Reported: “The evidence note will also capture a minor tooling lesson: one of the broad disassembly windows was noisy, but the useful evidence is still the focused helper body and the existing renderer tests.”

    Action/result: Recorded the noisy broad disassembly as limited evidence and documented the source-backed result.

  1377. Reported: “I’m updating PROGRESS.md now so the tracker reflects the narrower seed-fill status: source-backed traversal, still needing broader parity cases. That should make the next renderer step clearer.”

    Action/result: Updated the picture-decoding tracker with source-backed seed-fill span traversal and the remaining coverage targets.

  1378. Reported: “The tracker currently treats picture decoding as one broad bucket. I’ll add the seed-fill evidence there without marking the whole renderer done; the remaining work is still real, just better bounded.”

    Action/result: Kept picture decoding at partial status while adding the refined seed-fill evidence.

  1379. Reported: “I noticed one wording detail worth tightening before moving on: the control fill value lives as high-nibble 4, which appears as 0x40 in the buffer byte. I’m making that explicit so a future implementation doesn’t compare the wrong byte value.”

    Action/result: Clarified the control-channel seed-fill target and no-op value as high-nibble 4 / buffer byte 0x40.

  1380. Reported: “The seed-fill docs and tracker now agree: traversal is source-backed, final-buffer equivalence remains the portable contract, and the remaining risk is coverage depth. I’m going to run the lightweight checks for these doc-only changes before choosing the next PROGRESS.md task.”

    Action/result: Started verification for the seed-fill documentation pass.

  1381. Reported: “The doc build and whitespace check are clean after the seed-fill update. Next I’m going to turn that remaining seed-fill coverage list into concrete valid synthetic picture cases, then decide whether a small original-engine QEMU batch is worthwhile.”

    Action/result: Verified the seed-fill documentation changes and began adding curated picture fuzz cases.

  1382. Reported: “The fuzz base list already has two seed-fill cases, but they don’t cover multiple seeds or a narrow barrier shape. I’m reading the local renderer shape helpers before adding cases, so the fixtures stay valid and intentional.”

    Action/result: Reviewed picture renderer command handling and existing seed-fill tests before adding new valid cases.

  1383. Reported: “The local renderer’s write_cell() already models the odd/even row mask path, so a good seed-fill case can exercise that without new renderer machinery. I’m adding a few curated safe base cases rather than relying on random generation to stumble into them.”

    Action/result: Chose curated seed-fill fixture shapes for deterministic fuzz coverage.

  1384. Reported: “For QEMU screenshots, visual-channel cases are the most useful because the batch comparator sees the rendered EGA image. I’ll still include one control-channel case in local tests, but the curated QEMU candidates should mostly produce visible differences.”

    Action/result: Balanced visible QEMU cases with one local control-channel semantic test.

  1385. Reported: “I’m making three small curated fixtures: a full-height one-pixel visual barrier, two separate boxes filled by one multi-seed command, and a control-channel fill that crosses a visual-only barrier. They each target a specific seed-fill edge without malformed data.”

    Action/result: Added base_021, base_022, and base_023 to tools/picture_fuzz.py.

  1386. Reported: “The new base cases are in the fuzz catalog. I’m adding direct renderer assertions next, because these cases encode semantics that are clearer to test as cell values than as screenshot hashes alone.”

    Action/result: Added local renderer tests for the full-height barrier, multi-seed boxes, and control-channel barrier-crossing case.

  1387. Reported: “The local semantic tests are in place. I’m running the renderer and fuzz-tool tests now; if they pass, I’ll regenerate a small corpus and consider a targeted QEMU batch for the visible fill cases.”

    Action/result: Ran targeted renderer/fuzz tests and generated a small corpus containing the new curated cases.

  1388. Reported: “The new tests pass, and a small regenerated corpus reports 24 curated base cases plus randoms. I’m checking the batch command path before running QEMU so I use the snapshot harness correctly and don’t waste a boot cycle.”

    Action/result: Confirmed the new cases render locally and are marked safe for QEMU.

  1389. Reported: “I’m going to run the three new safe seed-fill fixtures through the original engine using the snapshot batch harness. The first two should validate visible fill geometry; the third is mostly a guard that control-only fill does not disturb the visible barrier.”

    Action/result: Started a QEMU snapshot batch for base_021, base_022, and base_023.

  1390. Reported: “The snapshot batch built its disk, then QEMU was blocked by the sandbox from binding the local VNC socket. That’s a permissions issue rather than a renderer result, so I’m rerunning the same harness with escalation.”

    Action/result: Re-ran the same seed-fill QEMU batch with permission to bind the local VNC socket.

  1391. Reported: “The escalated QEMU batch is running now from the snapshot disk. I’ll wait for the JSON summary, then fold the result into the compatibility docs and tracker.”

    Action/result: Waited for the original-engine seed-fill batch to finish.

  1392. Reported: “The original-engine batch matched all three new seed-fill cases with 0 mismatches. That gives us QEMU-backed coverage for the full-height barrier, multi-seed fill, and the visible side of the control-channel barrier case.”

    Action/result: Captured the successful QEMU report at build/picture-fuzz/batches/seed_fill_edges_001.json.

  1393. Reported: “I’m updating the compatibility chapter with the new corpus count and the seed-fill batch result. I’ll be careful to say the control-only case’s screenshot validates visible stability, while the local cell test validates the control-channel crossing behavior.”

    Action/result: Began documenting the new seed-fill fuzz cases and QEMU results.

  1394. Reported: “The docs currently say there are 21 curated base cases and that QEMU coverage stops at base_020. I’m bumping that to 24 and adding the seed_fill_edges_001 batch as the new evidence point.”

    Action/result: Updated the compatibility chapter with the new curated case count and QEMU seed-fill batch result.

  1395. Reported: “I’m also revising the “remaining risk” paragraph so it doesn’t keep asking for cases we just added. Multi-seed and narrow-barrier coverage are now present; broader mask and pattern interactions still remain.”

    Action/result: Narrowed the remaining picture-renderer risk to broader mask, pattern, and interleaved operation coverage.

  1396. Reported: “I’m adding the clean-room note for the new fuzz cases now, including the failed non-escalated QEMU attempt as a permissions artifact and the successful escalated run as the evidence.”

    Action/result: Appended the seed-fill fuzz expansion note to docs/src/clean_room_executable_notes.md.

  1397. Reported: “PROGRESS.md needs the same refinement: seed-fill now has specific QEMU-backed edge fixtures, while broader pattern/fill combinations remain open. I’m updating that tracker line next.”

    Action/result: Updated the picture-decoding tracker with the new QEMU-backed seed-fill edge fixtures.

  1398. Reported: “The tracker is updated. I’m regenerating the standard 1,024-random corpus once so the documented counts are backed by the actual command, then I’ll run the local suite/checks.”

    Action/result: Regenerated the standard picture fuzz corpus and reran targeted renderer/fuzz tests.

  1399. Reported: “The standard corpus command now confirms the documented numbers: 1,048 total cases and 1,046 safe for QEMU. The targeted renderer/fuzz tests still pass after adding the three curated cases.”

    Action/result: Confirmed the documented fuzz corpus counts and targeted test pass.

  1400. Reported: “I’ve folded the verified standard corpus count into the evidence note. Next I’ll run the broader project checks, then continue to the next renderer gap if everything is clean.”

    Action/result: Updated the clean-room evidence note with the verified standard corpus generation command.

  1401. Reported: “I’m running the usual verification set now: full unit tests, opcode-evidence consistency, mdBook build, and diff whitespace. After that I’ll continue with the next PROGRESS.md item instead of stopping.”

    Action/result: Ran the full verification set after the seed-fill fuzz expansion.

  1402. Reported: “Verification is clean: 112 tests pass, opcode evidence is consistent, mdBook builds, and diff whitespace is clean. I’m moving to the next renderer gap in PROGRESS.md: view/cel drawing coverage, especially mirroring and transparent-color edges.”

    Action/result: Began the view/cel drawing coverage pass.

  1403. Reported: “The view docs already mention more transparent-color samples than the tracker summary remembered, so I’m checking the actual coverage before adding duplicate cases. The next useful step looks like selecting a few largest or unusual cels from the local corpus and validating them through the existing view batch harness.”

    Action/result: Scanned existing view docs, tests, and the local view corpus for large, mirrored, and transparent-color candidate cels.

  1404. Reported: “The corpus scan gives good candidates: large cels with transparent colors not yet emphasized by the small default view batch, plus a tall 129-row cel. I’m checking the view-batch tests before deciding whether to expand the built-in batch or keep these as a separate stress list.”

    Action/result: Reviewed tests/test_view_batch.py and candidate cel dimensions/control bytes.

  1405. Reported: “I’m going to add an optional stress suite to view_batch.py rather than making every default run heavier. It will be reusable for compatibility work while the default six-case smoke stays quick.”

    Action/result: Chose an optional stress-suite design for view validation.

  1406. Reported: “The stress suite will deliberately cover transparent colors 0,1,2,5,6,7,8,10,13,14,15 and a bit-0x80 transparent-10 frame. That complements the existing smaller probe set without changing the default batch.”

    Action/result: Selected eleven stress cases from the local SQ2 view corpus.

  1407. Reported: “The stress cases are defined. I’m wiring them into the CLI as --include-stress, so scripted runs can opt in without breaking quick smoke runs or JSON case loading.”

    Action/result: Added stress_cases() and --include-stress to tools/view_batch.py.

  1408. Reported: “The CLI flag is in. I’m extending the view-batch unit tests to lock down that the stress suite stays optional and actually includes the broader transparent-color coverage.”

    Action/result: Added unit coverage for optional stress-case loading.

  1409. Reported: “The optional stress suite is covered by tests. I’m running the view-batch unit tests and a quick local frame render check for those stress cases before involving QEMU.”

    Action/result: Verified stress cases render locally and fit on screen; targeted view tests passed.

  1410. Reported: “The stress suite renders locally and all placements fit the screen. I’m running the base plus stress view batch through QEMU snapshot mode now; this is the compatibility check that matters for the new cases.”

    Action/result: Started the 17-case original-engine view stress batch.

  1411. Reported: “The 17-case view stress batch is running from a single QEMU snapshot now. It includes the six existing smoke cases plus eleven larger/transparent/mirrored cels.”

    Action/result: Waited for the view stress QEMU batch to complete.

  1412. Reported: “The view batch is still running; no result lines yet, which is normal while the snapshot harness drives each DOS fixture and captures screens. I’m waiting it out rather than interrupting the emulator.”

    Action/result: Continued waiting for QEMU snapshot results.

  1413. Reported: “Still waiting on QEMU. This longer run is expected for 17 cases, but it should return a compact match/mismatch summary once the harness finishes.”

    Action/result: Continued waiting for QEMU snapshot results.

  1414. Reported: “The emulator batch is taking its time but is still alive. I’m letting it continue, since stopping here would throw away the original-engine evidence we’re trying to collect.”

    Action/result: Continued waiting for QEMU snapshot results.

  1415. Reported: “Still no output from the harness, which means it’s inside the snapshot-run loop rather than comparison/report writing. I’ll give it another interval before deciding whether to inspect for a stuck QEMU process.”

    Action/result: Continued waiting; the batch later returned result lines.

  1416. Reported: “Good, results are coming back: the first 13 view cases all match, including several large transparent-color samples and the tall 129-row cel. I’m waiting for the last four and the JSON summary.”

    Action/result: Observed the first 13 view stress cases matching QEMU.

  1417. Reported: “The full 17-case view batch matched with 0 mismatches and 0 errors. I’m reading the report, then I’ll document the optional stress suite and update the view coverage tracker.”

    Action/result: Completed QEMU view stress validation with all cases matching.

  1418. Reported: “The QEMU report confirms every stress case matched. I noticed the new test import line is a bit ungainly, so I’m tidying that before documenting the result.”

    Action/result: Read view_stress_001.json and formatted the test import cleanly.

  1419. Reported: “I’m updating the docs in two places: command examples for the optional stress suite, and the compatibility evidence list showing the 17-case view_stress_001 result.”

    Action/result: Updated the compatibility-testing chapter with the stress command and QEMU result.

  1420. Reported: “The compatibility chapter now has the stress command and result. I’m adding a shorter note in the graphics pipeline chapter near the view layout section so readers see that the row/transparent model has broader QEMU coverage now.”

    Action/result: Added the view stress result to the graphics object pipeline chapter.

  1421. Reported: “I’m appending the clean-room evidence for the view stress batch, including the corpus scan that selected the cases and the QEMU report path.”

    Action/result: Appended the optional view stress batch expansion note to the clean-room executable notes.

  1422. Reported: “The evidence note is in. I’m updating PROGRESS.md so the view area no longer lists broad transparent-color coverage as an untouched gap; the remaining view work is more about clipping, priority/control combinations, and animation state.”

    Action/result: Updated the view coverage tracker in PROGRESS.md.

  1423. Reported: “I’m catching the progress log up for the view stress work before running another verification pass. The log is long, but it’s doing its job as the clean-room trail.”

    Action/result: Recorded the view stress work in the progress log.

  1424. Reported: “The progress log is caught up. I’m running the full checks again after the view-batch code/docs changes, then I’ll keep moving to the next tracker item if it’s clean.”

    Action/result: Ran the full verification set after the view stress pass.

  1425. Reported: “Verification is clean again: 113 tests pass, opcode evidence is consistent, mdBook builds, and whitespace is clean. I’m checking PROGRESS.md for the next highest-value gap now; likely candidates are right/bottom clipping or interleaved picture line/fill/pattern cases.”

    Action/result: Re-read PROGRESS.md and selected picture pattern/ interleaving coverage as the next renderer task.

  1426. Reported: “PROGRESS.md now points me back to picture renderer coverage: interleaved line/fill/pattern streams and broader pattern modes. I’m going to add a few valid curated pattern cases next and run them through the same fuzz/QEMU path.”

    Action/result: Began adding pattern-focused curated picture fuzz cases.

  1427. Reported: “The existing pattern source notes already cover bits 0x10 and 0x20, but the curated QEMU cases don’t isolate 0x10 or mix fill/line/pattern in one stream. I’m adding those as safe base cases.”

    Action/result: Reviewed pattern source notes and existing fuzz coverage before adding new cases.

  1428. Reported: “I’ll add three pattern cases: 0x10 mask bypass alone, an interleaved rectangle-fill-line-pattern stream, and a combined 0x10|0x20 pseudo-random pattern sequence. The local tests will assert the first two at the pixel level.”

    Action/result: Added base_024, base_025, and base_026 to tools/picture_fuzz.py.

  1429. Reported: “The new pattern cases are in the fuzz catalog. I’m adding renderer assertions for mask-bypass geometry and the interleaved operation order so these aren’t just anonymous hashes.”

    Action/result: Added local pixel-level tests for pattern mask-bypass and interleaved operation ordering.

  1430. Reported: “The pixel-level pattern tests are in. I’m running the targeted renderer/fuzz tests and regenerating the standard corpus so the base-case counts stay truthful.”

    Action/result: Targeted renderer/fuzz tests passed and the standard corpus regenerated with 1,051 cases, 1,049 safe for QEMU.

  1431. Reported: “The local pattern tests pass, and the standard corpus now reports 1,051 total cases with 1,049 safe for QEMU. I’m running the three new pattern fixtures through the original engine next.”

    Action/result: Started the pattern_interleaved_001 QEMU snapshot batch.

  1432. Reported: “The pattern QEMU batch is running from the snapshot disk. These cases should tell us whether the local renderer’s mask-bypass and mixed operation ordering match the original engine.”

    Action/result: Waited for the original-engine pattern batch to finish.

  1433. Reported: “The original-engine pattern batch matched all three new cases with 0 mismatches. I’m documenting the result and updating the remaining-picture-work wording so interleaved line/fill/pattern coverage is no longer listed as missing.”

    Action/result: Read pattern_interleaved_001.json and began documenting the successful QEMU result.

  1434. Reported: “The compatibility chapter still has the pre-pattern counts. I’m bumping it to 27 curated base cases, adding pattern_interleaved_001, and narrowing the remaining picture risk again.”

    Action/result: Updated compatibility-testing counts and pattern QEMU evidence.

  1435. Reported: “I’m appending the clean-room evidence entry for the pattern additions now, including the source-note check, local tests, corpus regeneration, and QEMU report.”

    Action/result: Appended the pattern/interleaved picture fuzz expansion note.

  1436. Reported: “The pattern evidence note is in. I’m updating the picture tracker so the remaining renderer work focuses on odd/even-mask variation and broader real-resource parity rather than the interleaved cases we just validated.”

    Action/result: Updated PROGRESS.md for the new pattern/interleaving coverage.

  1437. Reported: “I’m catching the progress log up for the pattern-fuzz pass, then I’ll run the full verification set again. After that, I’ll keep going into the next remaining gap.”

    Action/result: Recorded the pattern-fuzz work in the progress log.

  1438. Reported: “The progress log is current again. I’m running the full check set after the pattern-fuzz changes: unit tests, opcode evidence, mdBook, and whitespace.”

    Action/result: Ran the full verification set after pattern-fuzz changes.

  1439. Reported: “Verification is clean: 115 tests pass, opcode evidence is consistent, mdBook builds, and whitespace is clean. I’m moving next to the object placement/search gap, specifically what happens when collision or control rejection makes the spiral continue past the first bounds-acceptable spot.”

    Action/result: Began a source-first pass on placement-search rejection predicates.

  1440. Reported: “My first disassembly window landed on the familiar MZ-offset trap, so I’m rerunning the helper slices with the corrected file skip. I’ll use the existing docs as guardrails and only refine what the source clearly supports.”

    Action/result: Re-ran 0x4719 and 0x56b8 disassembly with corrected file offsets.

  1441. Reported: “The corrected source slices confirm the caller contract already in the docs: placement tests bounds, object-object collision, then control acceptance at every spiral candidate. I’m going to make the local placement helper’s accept hook explicit and tested, so collision/control rejection can be modeled without hard-coding only bounds cases.”

    Action/result: Prepared a local placement-helper clarification and test.

  1442. Reported: “I’m editing the helper and tests now: the source-backed spiral remains the same, but the test will prove an external collision/control predicate can reject early candidates and force the same spiral onward.”

    Action/result: Began adding placement-helper documentation and coverage.

  1443. Reported: “The helper already had the hook; this is mostly documentation and coverage, not new behavior. That’s the right kind of small change for a source-confirmed routine.”

    Action/result: Added a docstring to search_object_placement().

  1444. Reported: “The helper docstring is in. I’m adding a regression test that rejects the first few otherwise-valid candidates and verifies the next accepted point follows the exact source spiral order.”

    Action/result: Added the placement accept-hook regression test.

  1445. Reported: “The accept-hook test now pins the first rejected-candidate sequence: (20,80), (19,80), (19,81), (20,81), then (21,81). I’m reflecting that in the placement docs.”

    Action/result: Updated the graphics pipeline placement documentation.

  1446. Reported: “I’m recording this as a small source-model refinement, not as new original-engine dynamic evidence: the source shows the later predicates are applied at each candidate, and the local helper now exposes/tests that structure.”

    Action/result: Appended the placement-search predicate-hook evidence note.

  1447. Reported: “The evidence note is in. I’m updating the object-pipeline tracker to say the local placement model now has a tested predicate hook, while full object-record collision/control fixtures remain future work.”

    Action/result: Updated PROGRESS.md for the placement-search predicate hook.

  1448. Reported: “I’m checking the symbol map before verification; if the collision helper already has a label, I’ll leave it alone, and if not I’ll add one so future version comparisons can map both placement predicates.”

    Action/result: Found the control helper label but no collision helper label.

  1449. Reported: “The control helper has a label, but the object-object collision helper doesn’t. I’m adding code.object.collision_test at 0x4719 so the placement predicate pair is complete in the symbol map.”

    Action/result: Added code.object.collision_test to the symbolic label map.

  1450. Reported: “The symbol map now has both placement predicates named. I’m adding that to the evidence note, then I’ll run the targeted and full checks.”

    Action/result: Updated the placement evidence note with the new symbolic label.

  1451. Reported: “I’m running the focused graphics tests first for the placement-hook change. If those pass, I’ll run the full project checks again.”

    Action/result: Ran focused graphics tests for placement changes.

  1452. Reported: “The focused graphics tests pass, including the new placement predicate hook case. I’m running the full verification set now, then I’ll keep going from the tracker.”

    Action/result: Ran the full verification set after the placement-hook change.

  1453. Reported: “Full verification is clean again: 116 tests pass, opcode evidence is consistent, mdBook builds, and whitespace is clean. I’m logging the placement-hook work, then I’ll move to the next highest-value non-graphics gap: text/input UI semantics.”

    Action/result: Confirmed the full suite and prepared to move to text/input UI semantics.

  1454. Reported: “I’m shifting into the text/input UI area now. First I’m auditing what is already QEMU-backed versus what is only dispatch-smoked so I don’t spend time duplicating evidence.”

    Action/result: Began auditing text/input coverage against the tracker and existing probes.

  1455. Reported: “0xa9’s active saved-window path may not be reachable cleanly from the existing simple fixtures, but the source check is still useful: it tells us exactly which state bit gates the restore call and which globals are cleared afterward.”

    Action/result: Re-read action 0xa9 and identified the saved-window restore gate and cleanup writes.

  1456. Reported: “The remaining text/input gap is narrower than PROGRESS.md says. Most of the input-line, prompt, mapped-key, raw-key, status, and width-mode behavior already has focused QEMU coverage; I’m updating the tracker to name the real gap instead of the stale broad one.”

    Action/result: Narrowed the PROGRESS.md text/input remaining-work entry.

  1457. Reported: “I’m adding a short evidence note for this text/input audit so the tracker change has a source trail. After that I’ll pick the next partial subsystem rather than overfitting a brittle 0xa9 fixture.”

    Action/result: Added the text/input tracker audit note.

  1458. Reported: “With the text/input tracker narrowed, I’m moving to another partially covered subsystem from PROGRESS.md: sound. I’ll start from the load/start/stop source that the current QEMU probes already touch, then see how much of the resource format falls directly out of the code.”

    Action/result: Started the source-first sound-resource pass.

  1459. Reported: “The first sound disassembly window was actually joystick/picture code, so I corrected the address window and landed on the sound cache lookup/load/start/stop cluster. The loader is doing something pleasantly concrete: reading four little-endian offsets from the payload into the cache record.”

    Action/result: Corrected the sound disassembly window and identified the four-channel offset setup.

  1460. Reported: “The sound loader source is clear on the resource container, and a quick SQ2 corpus scan says all present sound resources follow the same four-offset header shape. I’m reading the driver-start/tick routines next to see what each channel stream record contains.”

    Action/result: Scanned SQ2 sound resources and moved to the playback start/tick source.

  1461. Reported: “I’m going to add a small sound-resource parser, but only for the source-confirmed container/event fields: four channel offsets, then duration/tone/control records ending in 0xffff. Pitch and timing can stay provisional until the driver code is better understood.”

    Action/result: Added tools/agi_sound.py.

  1462. Reported: “The parser is added. I’m adding tests that scan every present SQ2 sound resource so the format claim is pinned to the local corpus, not just sound 1.”

    Action/result: Added tests/test_sound_resources.py.

  1463. Reported: “The sound tests are in. I’m running them now, then I’ll update the subsystem docs and tracker if the corpus scan stays clean.”

    Action/result: Ran targeted sound-resource tests.

  1464. Reported: “The sound parser tests pass across all 49 SQ2 sound resources: every channel offset is sorted/in-bounds, every channel reaches an in-payload 0xffff terminator, and sound 1 matches the first event shape from the source pass. I’m checking the symbol map for the sound channel globals before documenting this.”

    Action/result: Confirmed the targeted sound-resource tests and prepared sound symbol-map updates.

  1465. Reported: “The symbol map already names the main sound code paths, but it didn’t yet name the channel pointer/countdown/state globals that 0x7f96 initializes. I’m adding those data labels so later interpreter versions can be mapped by role instead of address.”

    Action/result: Prepared sound channel data labels.

  1466. Reported: “The sound label block has a slightly different neighbor order than I expected, so I’m patching it at the existing sound section rather than moving unrelated labels around.”

    Action/result: Added the sound data labels in the existing sound symbol section.

  1467. Reported: “I found the sound block and added the channel stream pointer, countdown, active-word, and attenuation labels. Next I’ll finish the docs for the sound resource shape and run the full verification set before the next commit point.”

    Action/result: Completed the symbol-map update and queued sound documentation/verification work.

  1468. Reported: “I’ll get the current work into a clean commit. First I’m checking the tree and the recent docs/test state so I don’t accidentally freeze an unfinished evidence trail.”

    Action/result: Checked git status, diff stats, and the tail of the progress log.

  1469. Reported: “The tree is large but coherent: opcode/probe work, graphics fuzz/view validation, placement modeling, and the new sound parser. I found the progress log stops just before the text/input and sound updates, so I’m going to patch that evidence gap and the sound docs before committing.”

    Action/result: Decided to finish missing progress-log and sound-doc updates before staging.

  1470. Reported: “The sound parser itself is small and the source-backed shape is clear: loader builds four channel pointers from the payload header, and the tick routine consumes duration/tone/control records. I’m adding that to the model and compatibility docs so the commit tells the full story.”

    Action/result: Added sound-resource shape documentation to the runtime, opcode, compatibility, progress, and evidence notes.

  1471. Reported: “Before editing, I’m keeping the patches scoped to documentation and one tiny test cleanup. No new reverse-engineering claim here without a source or test hook behind it.”

    Action/result: Kept the commit-prep edits scoped to evidence and verification support.

  1472. Reported: “The documentation gap is patched. I’m running the project’s full pre-commit checks now: unit tests, opcode evidence consistency, mdBook build, and whitespace scan.”

    Action/result: Ran the full pre-commit verification set.

  1473. Reported: “All four checks passed cleanly, and the full test suite is now 120 tests with the sound parser included. I’m recording that verification result in the progress log, then I’ll stage only the tracked project files plus the new sound parser/tests, leaving generated DOS/build artifacts alone.”

    Action/result: Confirmed python3 -B -m unittest discover -s tests passed with 120 tests, opcode evidence check passed, mdBook built, and git diff --check passed.

  1474. Reported: “The intended files are staged and the generated build/ and DOS installer directory are still untracked. I’m doing one staged diff sanity check, then I’ll write the commit.”

    Action/result: Verified staged status and staged diff summary before the commit.

  1475. Reported: “I added the final staging update to the historical log as well, so the record stays complete. Now I’m restaging that one log file and committing.”

    Action/result: Restaged the progress log before committing.

  1476. Reported: “Staged whitespace is clean and the only unstaged items are the expected generated directories. I’m committing this batch now.”

    Action/result: Committed the staged reverse-engineering, documentation, and compatibility-test updates.

  1477. Reported: “I’ll pick up from the tracker and avoid committing. First I’m rereading PROGRESS.md and the current tree so I can choose the next highest-value source-first work instead of wandering.”

    Action/result: Re-read the progress tracker, git status, progress log, and remaining-work references.

  1478. Reported: “The tracker points to sound playback and implementation-ready subsystem text as a good next seam. I’m going source-first there: re-read the sound driver/tick code around the parser I just added, then turn any concrete timing/state behavior into docs and tests.”

    Action/result: Began a source-first pass over the sound playback driver.

  1479. Reported: “The first pass exposed a useful state machine: in the one-channel path the tick loop only advances channel 0, while the four-channel path advances BX offsets 0,2,4,6. I’m checking the gate call at 0x7502 and the timer hook now so the docs don’t accidentally imply every tick always advances audio.”

    Action/result: Identified active-channel selection and moved to the flag gate and timer-hook source.

  1480. Reported: “The tick gate is flag 9: if that flag is clear, the sound tick stops playback immediately and sets the configured completion flag. I’m scanning the SQ2 sound corpus for duration edge cases before writing a schedule helper, because duration zero would have a very non-obvious 16-bit countdown consequence.”

    Action/result: Confirmed the flag-9 gate and scanned sound-event durations.

  1481. Reported: “The SQ2 corpus has 3,619 sound events and no zero-duration events, but the source would treat duration zero as a 16-bit countdown wrap before the next record. I’m adding a small schedule helper that captures the source timing rule without pretending to synthesize actual audio.”

    Action/result: Added source-backed sound scheduling helpers.

  1482. Reported: “The helper now models three source-backed things: which channels tick for the hardware selector, the initial one-tick delay before the first record, and the 16-bit countdown wrap. I’m adding tests against SQ2 sound 1, a longer multi-channel sound, and a synthetic zero-duration edge.”

    Action/result: Added sound scheduling tests.

  1483. Reported: “The targeted sound tests pass: the schedule helper matches sound 1’s tick-40 termination, distinguishes sound 60’s one-channel versus four-channel completion, and pins the zero-duration wrap. I’m folding this into the mdBook and the symbolic map now.”

    Action/result: Ran python3 -B -m unittest tests.test_sound_resources; all 9 targeted sound tests passed.

  1484. Reported: “The source also ties natural completion to the timer interrupt hook, not script bytecode: the IRQ calls the tick only while [0x1258] is active, and the tick sets the completion flag when the last active channel terminates. I’m making that distinction explicit in the docs and tracker.”

    Action/result: Documented sound tick scheduling, channel selection, flag-9 gating, natural completion, and remaining hardware-output gaps.

  1485. Reported: “The sound docs and labels are updated. I’m running the cheap checks for this slice now, then I’ll move to the next tracker item rather than stopping.”

    Action/result: Ran the targeted sound tests, mdBook build, whitespace check, and status check; the checks passed, with only expected modified project files and generated/untracked directories present.

  1486. Reported: “The sound slice is clean: targeted tests, book build, and whitespace check all passed. Next I’m tackling the remaining 0xa9 active saved-window path from source by finding every writer of the saved-window globals before deciding whether a dynamic probe is worth building.”

    Action/result: Began the text-window source pass and searched references to the saved-window globals and helpers.

  1487. Reported: “The active 0xa9 path is clearer now: message-window setup at 0x1d96 closes any prior saved window, computes two packed rectangle coordinates, draws/saves through 0x5590, sets [0x0d1d]=1, and later 0xa9 restores via 0x560c. This looks source-complete even if it’s awkward to isolate dynamically.”

    Action/result: Identified the modal saved-window producer at 0x1d96, the boxed draw/save helper at 0x5590, the restore helper at 0x560c, and the close consumer at 0x1f2b.

  1488. Reported: “I’m picking up from the active text-window restore pass and the tracker, with the source-first constraint in mind. I’ll close out the 0xa9 saved-window evidence cleanly, then move to the next highest-value item in PROGRESS.md without touching git.”

    Action/result: Re-read git status, the progress tracker, the relevant opcode/runtime/symbolic-label sections, and the recent progress log.

  1489. Reported: “The log is current through the sound documentation update, so I’m adding the missing verification and text-window source-pass entries before I edit the book. That keeps the historical trail aligned with what already happened rather than retrofitting it at the end.”

    Action/result: Prepared to record the missing verification and active text-window source-pass progress-log entries.

  1490. Reported: “I’m going to patch the text-window sections now: symbolic labels first, then the opcode/runtime prose, then the tracker and executable notes. The main change is to promote the active 0xa9 path from "helper calls seen" to a traced open/restore lifecycle with the producer at 0x1d96 and the close path at 0x1f2b.”

    Action/result: Added symbolic labels for the modal message-window opener, boxed draw/save helper, restore helper, active flag, and packed rectangle words; then updated the opcode, runtime, tracker, and executable notes.

  1491. Reported: “The symbolic map now has stable names for the modal window opener, draw helper, restore helper, active flag, and packed restore-coordinate words. Next I’m tightening the spec prose so readers see the lifecycle rather than a pile of addresses.”

    Action/result: Tightened the 0xa9 and modal text-window lifecycle prose in docs/src/logic_bytecode.md and docs/src/runtime_model.md.

  1492. Reported: “The 0xa9 docs now describe both sides of the saved-window lifecycle: where the rectangle is created and where it is restored. I’m updating the historical log with those intermediate reports next, then I’ll run the book/whitespace checks and continue to the next tracker item.”

    Action/result: Updated the historical progress log for the sound verification and active text-window restore documentation pass.

  1493. Reported: “I’m running the lightweight verification for the text-window documentation now. If that passes, the next likely target is save/restore path semantics from the tracker, since the 0xa9 gap is now source-backed.”

    Action/result: Ran mdbook build docs and git diff --check; both passed. A first search for old 0xa9 wording had a harmless shell quoting error from backticks in the pattern.

  1494. Reported: “The book build and whitespace check passed. I tripped a harmless shell quoting issue while searching for the old 0xa9 wording, so I’ll re-run that search safely and then start the save/restore path pass from disassembly.”

    Action/result: Re-ran the search with safe quoting and confirmed only historical progress-log wording still contained the old phrase.

  1495. Reported: “The tracker’s new top practical item is save/restore path selection and state transitions. I’m re-reading the existing save docs plus the handler and selector disassembly now, looking for concrete data-flow we can promote into a higher-level spec.”

    Action/result: Re-read the existing save/restore mdBook sections, symbolic labels, progress tracker entries, and source windows for the save, restore, and selector handlers.

  1496. Reported: “The selector helper is richer than the current docs show: 0x85e5 is mostly orchestration, with subhelpers at 0x8705 for path prompting/validation, 0x86a3 for drive/path availability messages, 0x8814 for enumerating/selecting slots, and 0x8794 for the modal text edit field. I’m narrowing those subhelpers from the disassembly file now so I can document them without guessing from UI behavior.”

    Action/result: Identified the save selector’s major subhelpers and moved to bounded disassembly windows for each one.

  1497. Reported: “I noticed the prebuilt whole-file disassembly is not using the same image-offset origin as these helper windows, so I’m avoiding it for exact save-selector addresses. I’ll use bounded ndisasm | sed windows from the decrypted executable instead, where the origin/skip convention matches the earlier notes.”

    Action/result: Used bounded ndisasm windows for 0x85e5, 0x8794, 0x8814, and 0x8b9f rather than relying on the stale origin in the prebuilt disassembly file.

  1498. Reported: “The save selector splits cleanly now: it returns zero for cancel/no valid choice, otherwise returns a 1-based-ish file selector that gets formatted into 0x1c8c. The save-mode special case is also visible: when saving into an empty-description slot, it prompts for a description into 0x1c6c before creating the file.”

    Action/result: Mapped selector return behavior, selected filename formatting, and the save-mode empty-description prompt.

  1499. Reported: “There are real SQ2 save files in the local game directory, which is perfect for deterministic parser tests. I’m going to inspect their block lengths and headers, then add a small save-file parser under tools/ if the files match the source-derived layout.”

    Action/result: Scanned SQ2/SQ2SG.* and found 11 local saves matching a 31-byte header plus five length-prefixed blocks.

  1500. Reported: “Good catch from the real files: the existing save-block table had the first block backward. The source writes a 1,505-byte block starting at data address 0x0002, not a 2-byte block starting near 0x05e1; all local SQ2 saves confirm the five block lengths [1505, 903, 328, 200, variable]. I’m adding a parser/test so this correction is pinned.”

    Action/result: Corrected the first save-block interpretation and added a plan to pin it with parser tests.

  1501. Reported: “I’m adding a tiny parser rather than a full save emulator. Its job is deliberately narrow: prove the file envelope the source writes and reads, keep block offsets/lengths explicit, and fail on truncation so future compatibility work has a trustworthy fixture reader.”

    Action/result: Added tools/agi_save.py with parse_save/load_save and save block dataclasses; added tests/test_save_resources.py.

  1502. Reported: “The save parser and tests are in place. I’m running the new save tests now, then I’ll fold the corrected block layout and selector flow into the mdBook and tracker.”

    Action/result: Ran python3 -B -m unittest tests.test_save_resources; all four save parser tests passed.

  1503. Reported: “The new save tests pass and they pin the source correction. I’m updating the docs now: first the exact save block envelope, then the selector state machine, then the compatibility/tracker notes.”

    Action/result: Began updating the executable, opcode, runtime, compatibility, progress, and symbolic-label documentation for the corrected save-file and selector model.

  1504. Reported: “I’m also naming the selector subhelpers in the symbol map. That matters for later cross-version work: the addresses will move, but the pattern of select_slot_or_path -> prompt_path -> list_slots -> read_slot_summary should be recognizable.”

    Action/result: Prepared symbolic labels for the selector subhelper chain.

  1505. Reported: “The executable chapter now has the corrected block table and selector flow. I’m mirroring the same model into the opcode chapter, keeping it concise enough that 0x7d/0x7e remain readable.”

    Action/result: Updated docs/src/agi_executable.md and then docs/src/logic_bytecode.md with the save-block envelope and selector flow.

  1506. Reported: “The opcode chapter now says exactly what goes on disk and how the slot selector exits. I’m turning that into a small implementation-facing save/restore data model next.”

    Action/result: Updated the save/restore data model in docs/src/runtime_model.md.

  1507. Reported: “The runtime model is updated. I’m adding the save selector’s subroutine/data labels now so future version comparisons can look for behavior, not just the SQ2 addresses.”

    Action/result: Added symbolic labels for selector subhelpers and save/path/header/filename buffers.

  1508. Reported: “The symbol map has the save selector broken into reusable labels. I’m adding the new save parser tests to the compatibility chapter and then I’ll mark the tracker’s save/file work as more advanced, with the remaining gaps narrowed.”

    Action/result: Documented tests.test_save_resources in docs/src/compatibility_testing.md and updated PROGRESS.md.

  1509. Reported: “The tracker now narrows the save/file gap to round trips, error paths, and path-validation edges. I’m adding the clean-room evidence note for this pass with the exact commands and the save-file block correction, then I’ll run the relevant checks.”

    Action/result: Added the clean-room executable notes section for the save-file selector and block-envelope source pass.

  1510. Reported: “I’m bringing the progress log up to date with the text-window verification and save-selector work before running the next check batch. The log is getting long, but it’s doing exactly what the project asks: leaving a breadcrumb trail for the clean-room story.”

    Action/result: Updated the historical progress log through the save-selector documentation and parser-test work.

  1511. Reported: “The cleanup search is clean. Next I’m taking the tracker’s heap/allocation item source-first, because the disassembly should tell us whether this is a true free-list allocator, a bump allocator, or some hybrid tied to room/resource lifetimes.”

    Action/result: Ran broad cleanup searches after the save-selector pass. A first search pattern accidentally used shell-expanded backticks in a double-quoted command, then the safe single-quoted searches found no stale save-block wording. Began source-first heap/allocation analysis.

  1512. Reported: “The heap source pass is already yielding a compact model: this is a bump allocator with marks, not a general free list. I’m following each mark helper now so we can describe which lifetimes are temporary, room-scoped, or diagnostic-only.”

    Action/result: Identified the current-top, limit, temporary-mark, room/reset-mark, and high-water heap globals around 0x0a55..0x0a5f.

  1513. Reported: “The allocator helpers are now source-clear enough to document as a normative model. One important detail: allocation failure does not look recoverable here; it displays the out-of-memory text and enters the restart/exit helper.”

    Action/result: Documented 0x13d6 as a bump allocation helper with a fatal out-of-memory path and high-water/free-memory updates.

  1514. Reported: “The startup path confirms one key lifecycle anchor: after initial object/inventory setup and logic 0 load, the engine stores the room/reset heap mark with 0x1476. That makes the later room-switch cleanup much less mysterious.”

    Action/result: Connected startup’s 0x1476 call to the room/reset mark consumed by room switch, restart, and restore cleanup helper 0x1485.

  1515. Reported: “The logic-resources chapter now describes the heap as a mark-and-rewind bump allocator. I’m mirroring that into the runtime model next, because implementers should not have to reconstruct lifetime semantics from a helper table.”

    Action/result: Added the heap helper table and diagnostic formulas to docs/src/logic_resources.md.

  1516. Reported: “The runtime model has the heap lifecycle table now. I’m adding the same labels to the symbolic map, including the individual globals, so this remains useful when we compare another interpreter build with moved addresses.”

    Action/result: Added the implementation-facing heap/allocation lifecycle table to docs/src/runtime_model.md.

  1517. Reported: “That patch missed because the data labels have shifted. I’m reopening the exact symbol-map sections and applying it in smaller pieces instead of guessing at the surrounding text.”

    Action/result: Re-read the symbol-map sections before applying the heap label updates.

  1518. Reported: “I’ll pick up from the heap/allocation pass that was in flight, finish wiring that evidence into the tracker and docs, then keep moving down PROGRESS.md until there’s a real blocker.”

    Action/result: Re-read PROGRESS.md, the symbol map, the progress log, and the current executable notes to resume from the in-progress heap work.

  1519. Reported: “I found the in-progress state: the heap model is already written into two chapters, but the symbol map and tracker still have the older compressed allocator note. I’m tightening those now so the cross-version map has names for the allocator routines instead of one catch-all heap label.”

    Action/result: Replaced the catch-all heap label with individual routine labels for allocation, current-top lookup, direct rewind, temporary mark save/restore, room/reset mark save, reset, free-memory update, and heap-status display.

  1520. Reported: “The allocator routines are now individually labeled. Next I’m adding the matching heap globals, because those names are what will make later “same source, different address” comparisons less brittle.”

    Action/result: Added symbolic labels for heap current top, base, room/reset mark, limit, temporary mark, and high-water globals.

  1521. Reported: “One small documentation cleanup: the allocator docs now refer to the free-memory byte by name, but that byte variable did not have a symbol row yet. I’m adding that before updating PROGRESS.md, so the references resolve cleanly.”

    Action/result: Added data.vars.free_memory_pages_0011 to the symbol map.

  1522. Reported: “The heap symbol map is complete enough for this pass. I’m marking the memory/allocation tracker as source-backed now, with the remaining work narrowed to initial heap setup and any observable out-of-memory UI edge we actually care about.”

    Action/result: Updated PROGRESS.md to describe the source-backed bump-heap model and narrow remaining memory/allocation work.

  1523. Reported: “The tracker now reflects the allocator as a mark-and-rewind bump heap instead of an unknown free-list. I’m adding the evidence note with the disassembly commands and the exact helper behavior, then I’ll run the book checks before choosing the next PROGRESS.md item.”

    Action/result: Added the heap allocation and mark/rewind source-pass section to docs/src/clean_room_executable_notes.md.

  1524. Reported: “I’m catching up the progress log now, including the allocator updates I reported before the context handoff and the shorter updates from this resumed pass. It’s a bit bookkeeping-heavy, but it keeps the clean-room timeline intact.”

    Action/result: Updated this progress log through the resumed heap documentation pass.

  1525. Reported: “The heap pass is now recorded across docs, tracker, symbols, and the progress log. I’m running the lightweight checks now; after that I’ll continue with the next high-value item, most likely restore/restart transitions from the source.”

    Action/result: Ran mdbook build docs, git diff --check, and targeted save/sound unit tests; all passed.

  1526. Reported: “The heap docs build cleanly, whitespace check is clean, and the targeted save/sound tests still pass. I’m moving to restore/restart transitions next and starting by rereading the existing source-backed notes so I don’t duplicate old ground.”

    Action/result: Re-read existing save/restore, replay, restart, and symbol-map notes.

  1527. Reported: “The existing notes already cover replay well, so I’m aiming this pass at the narrower gap: restart confirmation and restart-state cleanup. I’m going back to the handlers and their shared fatal/restart helper before changing prose.”

    Action/result: Began source-first restart/termination disassembly pass.

  1528. Reported: “One of the disassembly commands was too broad because ndisasm -e is a skip offset, not an end address. I caught that before using it as evidence; I’m switching to the existing full disassembly and bounded sed slices so the addresses I document are reliable.”

    Action/result: Discarded the broad exploratory output and switched to bounded slices with the project image/file-offset convention.

  1529. Reported: “The address convention is the EXE image address, with the file slice starting 0x200 bytes later. I’m using that convention now: -o image_address and -e image_address+0x200, then small bounded slices.”

    Action/result: Used corrected ndisasm commands for handlers 0x02ae, 0x027f, 0x2472, 0x2512, 0x2753, and shutdown helpers.

  1530. Reported: “The restart/restore slice confirms one important thing already: the fatal helper at 0x02ae calls cleanup and exits via the lower-level termination helper; restore read failure closes the file, displays the error message, and then enters that same helper. I’m mapping the confirm/restart action handlers next.”

    Action/result: Identified code.system.exit_with_cleanup and confirmed restore read failure is not recoverable in the observed source.

  1531. Reported: “The existing opcode chapter has good handler summaries; I’m verifying them against the slices so I can promote restart transitions into the runtime model without just restating the opcode table.”

    Action/result: Verified 0x80, 0x86, 0x7e, and 0x7d source slices against the opcode chapter.

  1532. Reported: “The restart path has a clearer shape now: 0x80 is an in-engine reset that returns zero to stop the current logic stream, while 0x86(1) and restore read failure go through 0x02ae, which performs shutdown/exit instead of a room-style reset. I’m checking that shutdown helper before naming it.”

    Action/result: Traced 0x02ae into 0x8275 and DOS termination wrapper 0x00ae.

  1533. Reported: “Shutdown cleanup is not just “exit”: 0x8275 closes the log file if it is open, then calls an interrupt/vector cleanup helper and a final display/driver helper before DOS termination. I’m documenting it at that level unless a later test needs each vector detail.”

    Action/result: Mapped shutdown cleanup through log close helper 0x838c, interrupt-vector restore helper 0x849f, and BIOS video-mode helper 0x5a5e.

  1534. Reported: “I’m adding symbolic names for the restart and termination helpers now. The key distinction I want the docs to preserve is “reset game state and keep running” versus “cleanup and terminate DOS process.””

    Action/result: Added restart, termination, shutdown cleanup, interrupt hook, and video-mode labels to docs/src/symbolic_labels.md.

  1535. Reported: “The symbol map now separates restart, fatal exit, shutdown cleanup, and interrupt restoration. I’m turning that into a short runtime lifecycle table so implementers can model the behavior without copying the interpreter’s exact globals.”

    Action/result: Began adding a restart/termination lifecycle table to docs/src/runtime_model.md.

  1536. Reported: “That insert missed because the next heading text is slightly different than I remembered. I’m reopening that small section and patching against the exact lines.”

    Action/result: Re-read the save/restore and object-lifecycle boundary in docs/src/runtime_model.md.

  1537. Reported: “The runtime model already has a good object lifecycle immediately after save/restore, so I’m placing restart/termination between those. That keeps all whole-session transitions together.”

    Action/result: Added the restart and termination lifecycle table to docs/src/runtime_model.md.

  1538. Reported: “The runtime model now has explicit rows for accepted restart, canceled restart, restore success, restore read failure, and fatal exit. I’m updating PROGRESS.md so restart polish is no longer listed as an open gap.”

    Action/result: Updated the room/restart/save/restore tracker entry and highest-value remaining work in PROGRESS.md.

  1539. Reported: “The tracker now reflects the restart distinction. I’m recording the source pass in the evidence log, including the corrected ndisasm address convention, so the trail is reproducible.”

    Action/result: Added the restart, restore-failure, and shutdown cleanup source-pass section to docs/src/clean_room_executable_notes.md.

  1540. Reported: “The evidence log is updated. I’m catching the progress log up for the restart pass, then I’ll run checks and continue into the next item rather than stopping here.”

    Action/result: Updated this progress log through the restart/termination documentation pass.

  1541. Reported: “The restart checks passed. For the save/restore item, I’m going source-first but adding a small compatibility-facing tool improvement too: if we can reserialize the parsed save envelope byte-for-byte, future tests can mutate or generate save files without hand-writing binary glue.”

    Action/result: Began the save/restore round-trip pass by inspecting the current save parser, save tests, compatibility docs, executable notes, tracker entry, and DOS wrapper disassembly.

  1542. Reported: “I’ll pick up exactly where the context left off: the save/restore round-trip item. I’m going to add a byte-for-byte save serializer and fold the DOS file-wrapper source notes into the docs so this moves from “we can parse saves” to “we can preserve and generate the exact envelope.””

    Action/result: Confirmed the next implementation target after context compaction and re-read the relevant parser, tests, docs, and tracker sections.

  1543. Reported: “The current save helper is intentionally minimal, so the next edit will stay small: serialize the same five-block envelope the parser already accepts, then test every checked-in SQ2 save for exact byte preservation. That gives us a useful compatibility primitive without pretending we’ve modeled every in-memory field yet.”

    Action/result: Prepared the save serializer/test edit scope.

  1544. Reported: “The serializer is now in place and deliberately validates the same structural promises the parser relies on: exact 31-byte header, exactly five blocks, matching block order, and matching length prefixes. Next I’m expanding the save tests so we prove every local SQ2SG.* file round-trips byte-for-byte.”

    Action/result: Added serialize_save, u16le_bytes, and write_save to tools/agi_save.py.

  1545. Reported: “The save tests now cover exact serialization plus validation failures for malformed in-memory save objects. I’m running the focused test module before I touch the prose, so the docs describe something we’ve actually checked.”

    Action/result: Added byte-for-byte round-trip coverage for all local SQ2SG.* files and serializer structural mismatch tests.

  1546. Reported: “The focused save tests pass: 6 checks, including byte-for-byte reserialization of all 11 checked-in saves. I’m documenting that as structural compatibility evidence, while keeping the dynamic original-engine restore path marked as separate remaining work.”

    Action/result: Ran python3 -B -m unittest tests.test_save_resources, which passed 6 tests.

  1547. Reported: “The compatibility chapter now distinguishes “container envelope is exact” from “the engine successfully restores a generated scenario.” I’m making the same distinction in the executable notes so future readers don’t overread the static test.”

    Action/result: Updated docs/src/compatibility_testing.md and docs/src/agi_executable.md with save envelope serialization evidence.

  1548. Reported: “While checking the DOS wrapper pass, I found an older symbol-map problem that’s worth fixing immediately: several DOS wrapper labels after open_file were shifted to the wrong addresses. The disassembly is clear here, so I’m correcting the label map before I write more prose against those names.”

    Action/result: Rechecked the DOS wrapper disassembly and found the correct post-open wrapper map beginning at 0x5cef.

  1549. Reported: “That patch missed because the surrounding lines had already shifted slightly. I’m reopening the small symbol-table window and applying the correction against the exact current text.”

    Action/result: Re-read the current DOS wrapper rows in docs/src/symbolic_labels.md.

  1550. Reported: “The stale rows are isolated. I’m replacing just that DOS wrapper block, so the rest of the resource/event labels stay untouched.”

    Action/result: Corrected the DOS wrapper symbolic labels and added labels for handle duplication, current-directory/drive helpers, find-first/find-next, drive probing, file-time reads, and the shared pre-call helper.

  1551. Reported: “The DOS symbol map is corrected now. I’m recording the correction in the evidence trail too, because stale labels are exactly the kind of thing that would cause pain when we compare another interpreter build later.”

    Action/result: Added the save-envelope round-trip and DOS wrapper correction section to docs/src/clean_room_executable_notes.md.

  1552. Reported: “The evidence notes now have the serializer result and the corrected DOS wrapper table. I’m catching up the progress log with these intermediate updates, then I’ll run the docs/tests checks and move on to the next PROGRESS item.”

    Action/result: Updated this progress log through the save-envelope and DOS-wrapper correction pass.

  1553. Reported: “One more small tracker tweak: since the wrapper map was corrected, I’m adding that explicitly to PROGRESS.md so the dashboard reflects the source-backed DOS helper names too.”

    Action/result: Added the corrected DOS wrapper symbolic-label map to the DOS file I/O tracker evidence.

  1554. Reported: “The tracker is caught up. I’m running the focused save tests, mdBook build, and whitespace checks now; after that I’ll continue down the remaining high-value list instead of stopping here.”

    Action/result: Ran focused save tests, mdbook build docs, and git diff --check; all passed.

  1555. Reported: “Checks are clean: save tests pass, mdBook builds, and git diff --check is quiet. Next I’m staying on the save/restore item, but shifting back to the disassembly to map the actual read/write helper failure paths rather than inferring them from the file format.”

    Action/result: Started source inspection of the save and restore handler failure paths around image offsets 0x2512, 0x26b0, 0x2753, and 0x28c6.

  1556. Reported: “The source pass confirms the error split: save write failures are recoverable after closing and deleting the partial file, while restore block-read failures go through fatal cleanup. I’m checking the local strings around those message offsets so the docs name the observable prompts more clearly.”

    Action/result: Inspected AGIDATA.OVL strings around 0x0d34..0x0e46 and confirmed the save/restore confirmation and error messages.

  1557. Reported: “The strings confirm the observable messages: restore read failure says “Error in restoring game” and then quits, while save create/write problems are “directory full/write-protected” or “disk full” style continue prompts. I’m adding a concise failure-path table to the implementation-facing docs.”

    Action/result: Prepared runtime-model save/restore failure lifecycle update.

  1558. Reported: “The runtime model already had restore success/failure, but it didn’t distinguish recoverable save/open failures from fatal restore reads. I’m extending that lifecycle table so an implementer can model the continuation behavior directly.”

    Action/result: Added save create failure, save write failure, and restore open failure rows to docs/src/runtime_model.md.

  1559. Reported: “The lifecycle table now captures save create failure, save write failure, restore open failure, restore success, and restore read failure as separate transitions. I’m adding the lower-level call/return details to the executable chapter next.”

    Action/result: Updated docs/src/agi_executable.md with write/read helper return rules and save/restore failure continuations.

  1560. Reported: “The executable chapter now has the helper-level behavior. I’m also tightening the opcode rows, because 0x7d and 0x7e are where most readers will first look for save/restore continuation semantics.”

    Action/result: Updated the 0x7d and 0x7e rows in docs/src/logic_bytecode.md with create/open/write/read failure behavior.

  1561. Reported: “The opcode rows now include the recoverable versus fatal failure distinction too. I’m recording this source pass in the clean-room notes with the exact disassembly/string probes that support it.”

    Action/result: Added the save/restore file-error source-pass section to docs/src/clean_room_executable_notes.md.

  1562. Reported: “The clean-room notes now have the save/restore error-path pass. I’m updating the progress log, then I’ll run checks and continue to the next highest-value area in PROGRESS.md.”

    Action/result: Updated this progress log through the save/restore file-error documentation pass.

  1563. Reported: “Since the source-backed file error paths are now documented, I’m narrowing the tracker wording. The remaining save work is mainly dynamic round-trip and representative UI probes, not basic source mapping.”

    Action/result: Narrowed the save/restore and DOS file I/O remaining-work text in PROGRESS.md.

  1564. Reported: “The tracker now reflects that the source mapping is done and the dynamic/UI side remains. I’m running checks for the doc changes, then I’ll inspect the existing QEMU logic probe harness to see whether a save/restore round-trip case can be added cleanly without inventing a one-off path.”

    Action/result: Ran focused save tests, mdbook build docs, and git diff --check; all passed. Searched the logic probe harness for save/restore cases and input support.

  1565. Reported: “The harness search shows existing save/restore coverage is mostly Escape/cancel smoke, not a full file round-trip. I’m reading the probe generator now to see how it handles post-launch keys and fixture DOS directories before deciding whether to add a dynamic save case or leave it as a larger follow-up.”

    Action/result: Re-read tools/logic_interpreter_probe.py helpers, case definitions, and snapshot runner.

  1566. Reported: “A full save/restore round trip through the UI is probably more involved than a single new case, but the harness can patch AGIDATA.OVL. I’m checking the selector source to see whether a prefilled path/description buffer lets us trigger a representative open/create error without brittle key navigation.”

    Action/result: Disassembled the save/restore selector around 0x85e5..0x8814 and inspected save-related initial data.

  1567. Reported: “The selector does have a noninteractive path when [0x0e72] is already nonzero, but it still goes through slot matching/formatting rather than simply trusting 0x1c8c. I’m reading that branch before I decide whether a patched fixture will be stable enough for QEMU evidence.”

    Action/result: Inspected the noninteractive slot-matching branch around 0x894e..0x8b99 and the filename formatter/path validator helpers.

  1568. Reported: “This selector path is not quite a clean one-liner: the prefilled-buffer branch still scans slot summaries and may fall back through UI-like selection logic. Rather than force a brittle dynamic save probe, I’m going to document that constraint and move to the next high-value item, the picture/view renderer compatibility work, where we have more direct harnesses.”

    Action/result: Deferred a dynamic save/restore probe as a larger focused task and moved to the picture/view compatibility tracker items.

  1569. Reported: “The picture/view tracker points to two practical gaps: valid picture edge semantics and broader view clipping. I’m starting with the view batch because the test already says base coverage includes mirror and top/left clipping, but PROGRESS.md still calls out right/bottom clipping as remaining.”

    Action/result: Inspected picture/view progress entries, view-batch tests, picture fuzz tests, and related docs.

  1570. Reported: “The object-overlay harness already has right and bottom edge cases, but the simpler picture-plus-view batch only has left/top. I’m going to broaden that base batch with right/bottom clipping cases and add local tests so the coverage is visible before any QEMU run.”

    Action/result: Re-read tools/view_batch.py, object-overlay clip cases, and clipping-related docs/tests.

  1571. Reported: “View 11’s frame is 20 by 5, so clean right and bottom cases are straightforward: request left 150 to exercise right clamping to 140, and baseline 170 to exercise bottom clipping past the 168-row logical screen. I’m adding those to the base view batch and tests.”

    Action/result: Added view_011_right_clip and view_011_bottom_clip to the base view-batch registry.

  1572. Reported: “The local frame type names the raw control byte rather than transparent_color, so that quick dimension probe tripped on an attribute name. I’m rerunning it with the actual fields and checking the compose clipping function before adding cases.”

    Action/result: Confirmed view 11/group 0/frame 0 dimensions as 20x5 with control byte 0x01, and reran view-batch tests.

  1573. Reported: “The base view batch now includes right and bottom clipping. I’m updating the tests so they assert all four clip directions explicitly and keep the expected base/stress counts honest.”

    Action/result: Updated tests/test_view_batch.py for four edge case IDs and the new base count.

  1574. Reported: “The local coverage tests are updated. I’m running the view-batch tests now, then I’ll decide whether to run a small QEMU snapshot for the two new cases or the full base batch.”

    Action/result: Ran python3 -B -m unittest tests.test_view_batch; all 5 tests passed.

  1575. Reported: “The view tests pass. To run just the two new QEMU cases cleanly, I’m adding the same repeated --case filter that the other probe harnesses already have, instead of creating an ad hoc JSON fixture file.”

    Action/result: Added repeated --case filtering to tools/view_batch.py.

  1576. Reported: “The view harness has the filter now. I’m adding a small unit test for selected-case loading, including the unknown-case error, so the CLI behavior is covered before I use it.”

    Action/result: Added view-batch case-filtering tests.

  1577. Reported: “The filter test is in place. I’m running the view-batch unit tests again; if they pass, I’ll launch just the two new clipping cases through QEMU snapshot mode.”

    Action/result: Ran python3 -B -m unittest tests.test_view_batch; all 6 tests passed.

  1578. Reported: “The view-batch tests pass with the new filter. I’m running a two-case QEMU snapshot batch for view_011_right_clip and view_011_bottom_clip now, which should give us original-engine evidence without running the whole suite.”

    Action/result: Ran clip_right_bottom_001; QEMU produced a mismatch for view_011_right_clip.

  1579. Reported: “The right-edge QEMU case mismatched, so that’s useful rather than bad: our simple local composition model is missing an observable placement rule for this path. I’m inspecting the report and generated capture to see whether this is the same spiral placement behavior already seen in object-overlay probes or a separate view-batch fixture issue.”

    Action/result: Inspected the failed report and capture; the mismatch bbox aligned with placement-search behavior rather than a decode failure.

  1580. Reported: “The mismatch is the same placement-search rule already documented for add_to_pic: a right-edge request for view 11 at left 150, baseline 80 lands at left 140, baseline 67, not at a simple clamped baseline 80. I’m going to make the view-batch case model allow expected placement overrides, then rerun right and bottom together.”

    Action/result: Rechecked object-overlay clip cases and placement-search tests for comparison.

  1581. Reported: “The object-overlay helper already has a source-derived fallback for the right-edge placement. I’m reusing that idea in the simpler view batch by adding optional expected position fields, rather than changing the renderer’s direct composition primitive.”

    Action/result: Inspected ObjectOverlayCase and its search_object_placement-based comparison path.

  1582. Reported: “Actually the better reuse is the existing search_object_placement helper from agi_graphics, which already models the bounds-only spiral search. I’m wiring view-batch comparison through that helper by default, with optional overrides for future odd cases.”

    Action/result: Re-read the placement-search helper and computed candidate placements for the new view requests.

  1583. Reported: “The placement search predicts the new requests as (150,80) -> (140,71) and (20,170) -> (23,167). I’m updating view_batch.py so QEMU comparisons use this source-derived placement search, matching how object-overlay probes already handle add_to_pic.”

    Action/result: Added expected_view_tuple and source-derived placement comparison to tools/view_batch.py.

  1584. Reported: “The view comparison now runs requested placements through search_object_placement unless a case provides an explicit expected override. I’m adding unit checks for the predicted right and bottom placements so the behavior is pinned locally too.”

    Action/result: Added placement expectation tests for the right and bottom view-batch cases.

  1585. Reported: “The placement expectations are now explicit in tests. I’m running the view-batch tests, then I’ll rerun the two-case QEMU batch.”

    Action/result: Ran python3 -B -m unittest tests.test_view_batch; all 7 tests passed.

  1586. Reported: “The local view tests pass, including the source-derived placement expectations. I’m rerunning the same two QEMU cases now to see whether right and bottom clipping line up with the original engine.”

    Action/result: Ran clip_right_bottom_002; both right and bottom cases matched with 0 mismatches.

  1587. Reported: “The rerun matched both cases: right and bottom clipping are now QEMU-validated in the view batch using the placement-search expectation. I’m updating the docs and tracker with both the failed first run and the corrected source-derived result so the evidence trail stays honest.”

    Action/result: Began documentation updates for the view-batch right/bottom placement validation.

  1588. Reported: “I’m updating the compatibility chapter now: the base view registry has grown from the original six to eight, and the new right/bottom cases have a focused QEMU report with 2 matches. The older six-case/stress notes stay as historical runs rather than being rewritten as if we reran everything.”

    Action/result: Updated docs/src/compatibility_testing.md with the focused right/bottom view-batch command, initial mismatch note, and corrected match result.

  1589. Reported: “The compatibility notes now record the initial mismatch and the corrected two-case QEMU match. I’m adding the same placement details to the graphics pipeline chapter so the implementation model and test evidence stay connected.”

    Action/result: Updated docs/src/graphics_object_pipeline.md with the new right/bottom placement-search evidence.

  1590. Reported: “The graphics chapter now ties the new view-batch evidence to the existing 0x593a placement model. I’m narrowing PROGRESS.md so right/bottom clipping is no longer listed as an open view-renderer gap.”

    Action/result: Updated the view resource tracker in PROGRESS.md.

  1591. Reported: “The tracker is narrowed. I’m recording the view-batch source/test/QEMU pass in the evidence notes, including the failed first comparison because it explains why the harness now uses placement search.”

    Action/result: Added the view-batch right/bottom placement validation section to docs/src/clean_room_executable_notes.md.

  1592. Reported: “The evidence notes now have the right/bottom view placement pass. I’m catching the progress log up with the save-probe decision and the view-batch work before I run the broader checks.”

    Action/result: Updated this progress log through the view-batch right/bottom placement validation pass.

  1593. Reported: “Focused checks are clean. I’m staying in picture/view compatibility now, since PROGRESS.md still calls out valid-picture edge semantics and broader renderer comparisons as a high-value open area.”

    Action/result: Returned to the picture/view compatibility tracker after the view-batch validation pass.

  1594. Reported: “The picture fuzz base already has both corner commands and the lower-right edge behavior pinned. I’m looking for the next useful source-backed gap: either a compact real-resource batch or a focused priority/control interaction, and I’ll choose the one with the cleanest evidence path.”

    Action/result: Reviewed existing picture fuzz and view/object coverage to avoid duplicating already-covered edge cases.

  1595. Reported: “There isn’t a reusable real-picture batch harness yet, only one-off fixture generation and comparison. I’m going to add that first so we can keep growing original-engine parity checks without rebuilding the plumbing each time.”

    Action/result: Started a reusable real-picture QEMU batch harness.

  1596. Reported: “Before picking real-picture batch seeds, I’m scanning the local picture directory for a couple of useful representatives: first present resource, largest payload, and pattern-command coverage.”

    Action/result: Scanned the local SQ2 picture corpus to choose small base cases for the real-picture batch.

  1597. Reported: “Picture 45 is still the largest payload in this local corpus, and picture 1 gives us an early resource with pattern plotting. I’m using those as the initial real-picture batch so the first run is meaningful but not huge.”

    Action/result: Selected picture 1 and picture 45 as the first reusable real-picture parity cases.

  1598. Reported: “The new picture-batch harness is in place. It can run either serially or through the existing QEMU snapshot path, and it writes the same kind of JSON summary we use for the fuzz/view batches.”

    Action/result: Added tools/picture_batch.py.

  1599. Reported: “The picture-batch tests are written for case loading, filtering, DOS directory naming, and report summaries. I’m running them alongside the view-batch tests before using QEMU.”

    Action/result: Added tests/test_picture_batch.py.

  1600. Reported: “The local picture/view batch tests pass. I’m running the two-case real-picture batch in QEMU snapshot mode now.”

    Action/result: Ran the local picture/view batch unit tests successfully.

  1601. Reported: “The picture batch built its fixtures, but QEMU couldn’t bind the local VNC port from the sandbox, so it failed before the game ran. I’m rerunning that exact harness with the existing escalation path rather than changing the evidence target.”

    Action/result: Recorded the unprivileged QEMU/VNC bind failure as a sandbox execution issue, not interpreter behavior.

  1602. Reported: “The real-picture QEMU batch passed: picture 1 and picture 45 both matched with 0 mismatches. I’m adding this reusable command to AGENTS.md, then I’ll update the compatibility docs and progress tracker.”

    Action/result: Ran picture_base_001; both real-picture cases matched.

  1603. Reported: “AGENTS now includes the real-picture batch command. I’m adding the compatibility report details next: the base batch covers the first present picture and the largest valid picture payload, both matched against the original engine.”

    Action/result: Added the real-picture batch command to AGENTS.md.

  1604. Reported: “That doc patch missed on the later provisional paragraph because it has shifted wording. I’m reopening the exact sections and applying the update in smaller pieces.”

    Action/result: Re-opened the compatibility sections and applied the real-picture batch documentation in smaller patches.

  1605. Reported: “The evidence trail is caught up for the real-picture batch. I’m running the focused unit tests and doc build now; if those are clean, I’ll use PROGRESS.md to choose the next reverse-engineering chunk rather than stopping at bookkeeping.”

    Action/result: Ran focused picture/view/save tests, mdBook build, and whitespace checks successfully.

  1606. Reported: “Focused verification passed: picture/view/save tests, mdBook, and whitespace checks are clean. I’m moving to the next open PROGRESS.md item now, with a source-first pass and QEMU only if it gives us a durable compatibility test.”

    Action/result: Re-read the high-value remaining-work list and selected picture/view renderer compatibility as the next source-first target.

  1607. Reported: “The next tracker items overlap: picture/view parity and implementation-ready object drawing. Since the user has explicitly pushed for source-first work, I’m going to inspect the picture drawing routines around the mask/pattern paths before adding more QEMU cases.”

    Action/result: Began a picture pattern/mask disassembly pass.

  1608. Reported: “The source map already has labels for the picture command scanner and pattern data tables, so I’m narrowing onto the pattern-plot routine itself. The aim is to turn “odd/even mask interactions” from a tracker phrase into exact behavior we can encode and test.”

    Action/result: Re-read the pattern plot documentation, local renderer, and disassembly windows around picture command dispatch and pixel writes.

  1609. Reported: “The first disassembly window landed in the middle of adjacent code and table bytes, so I’m realigning from the known scanner entry and following the dispatch target into 0xfa. This is exactly the sort of place where labels help but raw source still needs a careful re-read.”

    Action/result: Realigned disassembly to the command scanner, pattern handler, coordinate readers, and common pixel writer.

  1610. Reported: “One useful correction surfaced immediately: the picture routine labels in the docs are loaded-image offsets, while ndisasm -e is reading file offsets. For this executable that creates a 0x200-byte difference in this region, so I’m keeping the existing symbolic labels but recording file-offset windows explicitly in the evidence notes.”

    Action/result: Kept existing symbolic labels and recorded the file-offset detail in the clean-room notes.

  1611. Reported: “The disassembly confirms pattern plotting does not have its own channel semantics: it stores candidate coordinates in the normal picture pixel register and calls the same pixel writer as lines and fills. The odd/even behavior therefore lives in the color-enable commands and pixel_write, so I’m reading the color mapper next.”

    Action/result: Inspected the common pixel writer and EGA color-mapper path.

  1612. Reported: “For full 16-color EGA, the mapper returns the same nibble in AL and AH, so odd/even masks exist but do not diverge for visual colors. A good next compatibility step is to add valid synthetic pattern cases that cross multiple rows with visual-only, control-only, and visual+control active, proving the shared pixel writer’s channel-mask behavior through QEMU.”

    Action/result: Chose three safe pattern-channel fuzz cases based on the source-backed common pixel-writer path.

  1613. Reported: “I’m going to add three curated valid picture-fuzz cases: visual+control pattern writes, visual-disabled/control-only pattern writes, and control-disabled/visual-only pattern writes. The local tests will assert both nibbles; the QEMU batch will validate the visible EGA surface for these streams against the original engine.”

    Action/result: Added base_027, base_028, and base_029 to tools/picture_fuzz.py, plus renderer tests for channel-mask behavior.

  1614. Reported: “The curated fuzz cases and local channel assertions are in. I’m adding a small harness test too, so the new case IDs stay part of the stable base corpus rather than quietly drifting.”

    Action/result: Added a base-case ID assertion to tests/test_picture_fuzz.py.

  1615. Reported: “The local assertions now distinguish visible and control nibbles for pattern plotting. I’m running the focused renderer/fuzz tests before regenerating the corpus and asking QEMU to confirm the visible surface.”

    Action/result: First focused test run failed, revealing that the sample control class used in the both-active case matched the default control nibble and therefore did not show as a control change.

  1616. Reported: “The new tests caught something useful before QEMU: my assumptions about the sample payload were off, not the executable. The cell values show the command stream I chose is not isolating the intended channel state, so I’m inspecting the renderer command stepping and then I’ll adjust the fixtures to match the source semantics.”

    Action/result: Probed the three sample payloads locally and identified default control nibble 4 as the reason one assertion was wrong.

  1617. Reported: “Found the issue: the default control nibble is already 4, so using control color 4 made “changed control pixels” look unchanged. I’m switching the both-active case to control 5 and adjusting the control-disabled expectation to preserve the default high nibble.”

    Action/result: Changed base_027 to control class 5 and corrected the control-disabled expected cell value.

  1618. Reported: “The channel tests now use a non-default control class when they need to observe a control change. I’m rerunning the focused tests and regenerating the small corpus so the manifest matches the patched cases.”

    Action/result: Focused renderer/fuzz tests passed; regenerated the small pattern-channel corpus with 38 cases and 36 safe-for-QEMU cases.

  1619. Reported: “The local renderer and corpus tests are clean. I’m running the three new valid pattern-channel cases through the original engine now; this only validates the visible EGA output, while the control-nibble part stays source-backed and locally tested.”

    Action/result: Started QEMU snapshot batch pattern_channel_masks_001.

  1620. Reported: “QEMU is running the three-case snapshot batch now. It has built all fixtures and booted the shared snapshot disk; I’m waiting on the captures/comparisons.”

    Action/result: Waited for the running QEMU snapshot batch.

  1621. Reported: “The QEMU batch matched all three new cases with zero mismatches. I’m documenting the source result and the visible-surface confirmation now, including the caveat that QEMU screenshots do not expose the control buffer directly.”

    Action/result: Began updating compatibility, graphics pipeline, progress, and clean-room evidence notes for the pattern channel-mask pass.

  1622. Reported: “The old compatibility paragraph still says there are 27 curated base cases. With the three new channel-mask cases, that needs to become 30; I’m updating the docs and then I’ll regenerate the standard corpus so the recorded count is true.”

    Action/result: Updated compatibility docs and PROGRESS.md for the three new pattern-channel cases and the narrowed EGA odd/even-mask gap.

  1623. Reported: “The compatibility chapter and tracker now describe the channel-mask cases and narrow the odd/even visual-mask gap to non-EGA behavior. I’m regenerating the standard deterministic corpus next so the docs’ 1,054/1,052 counts match the current base-case set.”

    Action/result: Regenerated the standard fuzz corpus; it reported 1,054 total cases and 1,052 safe-for-QEMU cases.

  1624. Reported: “The regenerated corpus reports 1,054 total cases and 1,052 safe-for-QEMU cases, as expected. I’m recording the exact source windows, tests, corpus generation, and QEMU result in the clean-room notes now.”

    Action/result: Added the pattern channel-mask source/QEMU evidence section to docs/src/clean_room_executable_notes.md.

  1625. Reported: “The evidence notes are updated with the source-first channel-mask pass. I’m catching the progress log up now, then I’ll run the relevant checks and decide the next PROGRESS.md item.”

    Action/result: Updated this progress log through the pattern channel-mask pass.

  1626. Reported: “The progress log is caught up through the channel-mask pass. I’m running focused checks now; if they pass, I’ll keep going into the next open item instead of stopping.”

    Action/result: Ran focused picture/fuzz/picture-batch/view/save tests, mdBook build, and whitespace checks successfully.

  1627. Reported: “Focused checks are clean after the channel-mask work. The next useful picture task is broader real-resource parity, so I’m scanning the local picture corpus for representative resources instead of simply picking room numbers by hand.”

    Action/result: Scanned all valid local PICDIR payloads and ranked them by payload size, pattern count, fill count, and command-family diversity.

  1628. Reported: “The corpus scan gives a better broad-picture set than just “more numbers”: picture 46 is pattern-heavy, 44 is fill-heavy, 17 exercises all command families with several pattern-mode changes, and 43/45 are large dense resources. I’m extending the real-picture batch harness with base, broad, and all presets, then I’ll run the broad preset in QEMU.”

    Action/result: Added broad_cases, all_present_cases, and preset selection to tools/picture_batch.py.

  1629. Reported: “The harness now has a dynamic all preset plus a curated broad preset. I’m running its unit tests before taking the broad set to QEMU.”

    Action/result: Added preset/discovery tests and ran python3 -B -m unittest tests.test_picture_batch; all 8 tests passed.

  1630. Reported: “The picture-batch tests pass. I’m running the broad eight-picture preset through the original engine with one QEMU snapshot now; this should give us a much stronger real-resource parity sample without committing to a full 74-picture run yet.”

    Action/result: Started QEMU snapshot batch picture_broad_001.

  1631. Reported: “The broad real-picture run has built all eight fixtures and is executing from the snapshot disk. I’m waiting for the captures and comparisons; if one fails, the report should stop at the first mismatch because this is a parity run.”

    Action/result: Waited for the broad real-picture QEMU batch.

  1632. Reported: “Still waiting on the broad QEMU batch; the larger real pictures take longer to render/capture than the tiny synthetic cases. The run is still active, so I’m leaving it alone and polling.”

    Action/result: Continued polling the running broad QEMU batch.

  1633. Reported: “Five of the eight broad real-picture cases have matched so far, including the dense/fill-heavy ones. I’m waiting on the remaining largest/pattern-heavy cases now.”

    Action/result: Observed the first five broad cases matching during the running QEMU batch.

  1634. Reported: “The broad real-picture batch passed: all eight representative resources matched the original engine with zero mismatches. I’m adding the preset command/result to the docs and progress tracker now.”

    Action/result: Recorded picture_broad_001 as 8 matches, 0 mismatches, and 0 errors.

  1635. Reported: “The broad batch evidence is now in the compatibility chapter and tracker. I’m adding the broad preset command to AGENTS.md too, so a future agent can rerun the representative real-resource check directly.”

    Action/result: Added the broad picture-batch command to AGENTS.md.

  1636. Reported: “AGENTS.md has the broad real-picture command now. I’m recording the corpus-selection scan, harness preset changes, tests, and QEMU result in the clean-room notes before running the verification suite again.”

    Action/result: Added the broad real-picture preset parity section to docs/src/clean_room_executable_notes.md.

  1637. Reported: “The progress log is current through the broad real-picture batch. I’m running the focused checks plus mdBook and diff whitespace again; after that I’ll move to the next remaining item.”

    Action/result: Ran focused picture-batch, graphics-rendering, picture-fuzz, view-batch, and save tests plus mdBook and whitespace checks; all passed.

  1638. Reported: “Checks are clean. Since the broad preset passed, the natural next step is a full present-picture parity batch; the harness now supports it, and this would retire most of the remaining “broader real-resource parity” risk if the DOS image has enough room. I’m checking the snapshot-disk constraints before launching a long run.”

    Action/result: Inspected snapshot helper behavior, all-present case count, fixture sizes, and current DOS snapshot image size/free space.

  1639. Reported: “The full 74-picture run would likely exceed the 64 MB DOS snapshot image because each fixture directory carries a full runnable game copy, and 74 copies would be around 70 MB before filesystem overhead. I’m checking whether we can shrink picture fixtures or whether the practical next step should be a few preset batches rather than one giant disk.”

    Action/result: Compared full-tree fixture contents and confirmed repeated original volumes/save files dominated picture-batch fixture size.

  1640. Reported: “There’s a better way around the full-corpus disk problem: pack each tested picture payload into that fixture’s VOL.3 alongside the generated LOGIC.0, and copy only the small engine/support files. That should make a 74-picture snapshot feasible while preserving the original picture data being tested. I’m going to implement this as a packed fixture path for picture_batch.py and validate it against the already-passing broad preset before attempting all pictures.”

    Action/result: Designed the packed picture fixture approach.

  1641. Reported: “I’m adding a new packed picture-fixture builder rather than changing the older one-off fixture generator. That keeps historical commands stable while letting batch runs use the smaller, purpose-built layout.”

    Action/result: Added copy_minimal_picture_tree and build_packed_picture_fixture to tools/qemu_fixture.py.

  1642. Reported: “picture_batch.py now uses packed picture fixtures, while qemu_fixture.py picture remains the older full-tree generator. I’m adding a unit check that the packed fixture actually omits the big original volumes and repoints PICDIR into VOL.3.”

    Action/result: Updated tools/picture_batch.py and added packed-fixture structural coverage to tests/test_qemu_fixture.py.

  1643. Reported: “There is already a qemu-fixture test module, so I’m putting the packed-fixture structural check there instead of squeezing it into picture-batch tests.”

    Action/result: Integrated the packed-fixture test with existing qemu-fixture tests.

  1644. Reported: “The packed fixture structure test is in. I’m running the qemu-fixture and picture-batch unit tests now; after that I’ll validate the packed layout with a small QEMU run before considering all 74 pictures.”

    Action/result: Ran tests.test_qemu_fixture and tests.test_picture_batch; all 37 tests passed. A local size probe showed packed picture fixtures are about 72 KB of input files.

  1645. Reported: “The packed fixture is tiny now, about 72 KB per picture instead of roughly 1.7 MB. Unit tests pass, so I’m running the two-picture base QEMU batch with the packed layout to make sure the original engine is happy with the trimmed fixture set.”

    Action/result: Ran picture_base_packed_001; pictures 1 and 45 matched with 0 mismatches.

  1646. Reported: “The packed base QEMU run matched both pictures, so the trimmed fixture set is valid. I’m launching the full 74-picture present resource batch now with packed fixtures; this may run for a while, but it should fit on the snapshot image.”

    Action/result: Started QEMU snapshot batch picture_all_001 using --preset all and packed fixtures.

  1647. Reported: “The full-picture batch built all 74 packed fixtures and is now running in QEMU from one snapshot. I’ll keep polling; this is the long parity pass.”

    Action/result: Confirmed the full QEMU batch had entered the capture phase.

  1648. Reported: “No comparison output yet; QEMU is still active. The first batch output usually appears after the initial cases have rendered and screendumped, so I’m continuing to wait.”

    Action/result: Continued polling the active QEMU process.

  1649. Reported: “Still no per-case results from the full-picture run, but the QEMU process has not exited. I’m letting it continue; with 74 cases the snapshot setup and early captures can be a little quiet.”

    Action/result: Continued waiting on the full-picture QEMU batch.

  1650. Reported: “A quick note on the silence: picture_batch.py compares only after run_snapshot_qemu_cases finishes all captures, so it won’t print per-picture matches during the QEMU phase. This is expected for the full run.”

    Action/result: Clarified the batch harness output behavior while the run continued.

  1651. Reported: “The full QEMU run is still active. I’m continuing to poll and will report the summary once the capture phase completes.”

    Action/result: Continued polling the active QEMU process.

  1652. Reported: “This is taking long enough that I’m checking the capture directory from the host side while QEMU continues, just to make sure files are being produced and we’re not waiting on a dead run.”

    Action/result: Counted 19 generated captures, proving the full run was progressing.

  1653. Reported: “Host-side check shows 19 captures have already been written, so the full-picture batch is progressing normally. I’m letting it keep running.”

    Action/result: Continued the full-picture QEMU batch.

  1654. Reported: “The full QEMU capture phase is still running. I’m staying with it; once QEMU exits the script will compare all generated screenshots in one pass.”

    Action/result: Continued polling the active QEMU process.

  1655. Reported: “Another quick progress check from the filesystem side: I’m checking how many captures have landed so far.”

    Action/result: Counted 26 generated captures.

  1656. Reported: “We’re at 26 captures out of 74, so the run is moving steadily. No action needed beyond waiting.”

    Action/result: Continued the full-picture QEMU batch.

  1657. Reported: “The full-picture parity run is still in the capture phase. I’m continuing to let QEMU work through the list.”

    Action/result: Continued polling the active QEMU process.

  1658. Reported: “Polling the capture count again so we have a rough sense of progress.”

    Action/result: Counted 33 generated captures.

  1659. Reported: “33 of 74 captures are present now. The run is almost halfway through the QEMU phase.”

    Action/result: Continued the full-picture QEMU batch.

  1660. Reported: “Still running; I’m continuing to poll. The silence from the script is expected until all 74 screenshots have been captured.”

    Action/result: Continued polling the active QEMU process.

  1661. Reported: “Checking capture count again.”

    Action/result: Counted 40 generated captures.

  1662. Reported: “40 of 74 captures are in. The packed fixture approach is paying off; the disk is not the bottleneck now, just the per-case draw/capture loop.”

    Action/result: Continued the full-picture QEMU batch.

  1663. Reported: “The full-picture run is still active. I’m waiting on the remaining capture loop.”

    Action/result: Continued polling the active QEMU process.

  1664. Reported: “When asked about using input to cycle through resources: "Yes, absolutely, and it’s a good idea. The current snapshot harness optimizes away DOS boot, but it still starts a fresh engine process per case so every capture is isolated and easy to reason about…"”

    Action/result: Identified carousel-style resource sweeps as a useful future throughput optimization while keeping the current isolated harness as a reference oracle.

  1665. Reported: “The current full-picture batch is still running in the slower per-process snapshot style. I’m going to let it finish for this run, then I can add a carousel mode as a follow-up because it fits exactly the bottleneck we’re hitting.”

    Action/result: Continued the existing full-picture batch rather than interrupting it to change harness strategy mid-run.

  1666. Reported: “Good call. Simply growing the raw file would not help by itself because the DOS partition/FAT geometry inside it would still describe the old 64 MB volume; we’d need a larger formatted/bootable DOS test image or a purpose-built large fixture image. For the current run the packed fixtures avoid the limit, so I’m letting it finish, but I’ll note the larger-image path in the docs and can build one if the carousel/all- in-one fixture starts wanting more room.”

    Action/result: Confirmed that packed fixtures solved the current DOS image limit and documented the need for a properly formatted larger image if future batches need more space.

  1667. Reported: “The long run is still active, so I’m checking capture progress again while it continues.”

    Action/result: Counted 56 generated captures.

  1668. Reported: “56 of 74 captures are present. We’re through most of the current batch; after it finishes I’ll document both your carousel idea and the DOS-image-size note, then decide whether to implement carousel mode next.”

    Action/result: Continued the full-picture QEMU batch.

  1669. Reported: “Agreed. Once this run finishes, I’m going to treat batch throughput as part of the reverse-engineering infrastructure, not just a convenience: carousel-style scripts for picture/view sweeps, larger or purpose-built DOS test images where needed, and keeping the isolated per-case harness as the slow but simple reference path. That will matter a lot when we start comparing interpreter versions across games.”

    Action/result: Promoted high-throughput batch infrastructure to an explicit future work item for cross-game/interpreter comparison.

  1670. Reported: “The run is still alive. I’m checking the capture count again; if it completes cleanly, the next infrastructure task is clearly a faster in-engine resource sweep mode rather than just adding more one-shot batches.”

    Action/result: Counted 64 generated captures.

  1671. Reported: “64 of 74 captures are present. We’re on the final stretch of this slower full-picture pass.”

    Action/result: Continued the full-picture QEMU batch.

  1672. Reported: “Still running; I’m letting QEMU finish the last ten-ish cases.”

    Action/result: Continued polling the active QEMU process.

  1673. Reported: “Polling capture count one more time as it nears the end.”

    Action/result: Counted 71 generated captures.

  1674. Reported: “71 of 74 captures are in. The capture phase should finish soon, then the script will compare all 74 against the local renderer.”

    Action/result: Continued the full-picture QEMU batch.

  1675. Reported: “The capture phase finished and comparisons have started. First two pictures matched; I’m waiting for the full comparison summary.”

    Action/result: Observed the first two full-picture comparisons matching.

  1676. Reported: “The comparison pass is moving quickly now: the first 30 present pictures have matched. Continuing to poll for the rest.”

    Action/result: Observed the first 30 full-picture comparisons matching.

  1677. Reported: “60 of 74 comparisons have matched. The full corpus parity result is looking very good; waiting on the final fourteen.”

    Action/result: Observed 60 full-picture comparisons matching.

  1678. Reported: “Full present-picture parity passed: all 74 valid SQ2 pictures matched the original engine with 0 mismatches. I’m going to document that result, plus the packed-fixture optimization and your carousel/larger- image notes, then I’ll run the full checks.”

    Action/result: Recorded picture_all_001 as 74 matches, 0 mismatches, and 0 errors.

  1679. Reported: “I’m updating the docs now in two layers: first the factual result (74/74 pictures matched), then the infrastructure lesson (packed fixtures solved the 64 MB pressure, and carousel/input-driven sweeps should be added for future multi-game work).”

    Action/result: Updated compatibility docs and the progress tracker with the full present-picture parity result.

  1680. Reported: “The report gives us a strong milestone: every valid local SQ2 picture resource now matches pixel-for-pixel against the original EGA engine. I’m making sure the tracker reflects that this piece is no longer merely “broader parity pending.””

    Action/result: Updated PROGRESS.md to move full-corpus SQ2 picture parity from remaining work to evidence.

  1681. Reported: “I’ve added the full-picture command and the packed-fixture note to the reusable instructions. I’m adding the detailed evidence note next, including the throughput lesson from this long run and the future carousel strategy.”

    Action/result: Added AGENTS.md commands/notes and the packed picture/full-parity clean-room evidence section.

  1682. Reported: “The clean-room evidence now records both the full 74-picture result and the infrastructure lesson. I’m also going to put the carousel recommendation into AGENTS.md, because it is exactly the kind of future-agent context that should not be buried only in the long notes.”

    Action/result: Added the carousel-style high-throughput recommendation to AGENTS.md.

  1683. Reported: “AGENTS.md now flags carousel-style fixtures as the preferred future direction for high-throughput sweeps. I’m updating the progress log with this longer run and the two throughput discussions, then I’ll verify everything.”

    Action/result: Updated the progress log through the full-picture parity run and infrastructure discussion.

  1684. Reported: “The log is current through the full parity run and the infrastructure notes. Before starting a new harness feature, I’m running the verification suite once, so any later carousel work starts from a clean baseline.”

    Action/result: Ran all 146 tests, opcode evidence check, mdBook build, and whitespace checks successfully.

  1685. Reported: “Full verification is clean: all 146 tests, opcode evidence check, mdBook, and diff whitespace. I’m going to prototype the carousel mode now, starting from existing bytecode helpers rather than inventing a separate control path.”

    Action/result: Began implementing a picture carousel harness.

  1686. Reported: “I’m going to implement the carousel as a separate batch tool rather than modifying the existing picture-batch semantics. That gives us a fast path for sweeps while keeping the one-case-per-engine-run harness intact as the simple reference oracle.”

    Action/result: Added carousel bytecode helpers and packed carousel fixture generation to tools/qemu_fixture.py.

  1687. Reported: “The bytecode side of the carousel is now in qemu_fixture.py: it shows the first picture once, advances on raw key events, and discards the previous picture after showing the next one so cache growth doesn’t become the new bottleneck. I’m adding structural tests for that generated fixture now.”

    Action/result: Started adding carousel fixture tests.

  1688. Reported: “The test file has shifted a little from my expected context, so I’m reopening the import block and helper-test section and applying the carousel tests in smaller patches.”

    Action/result: Reopened tests/test_qemu_fixture.py and split the test patch into smaller edits.

  1689. Reported: “The smaller patches are straightforward: imports first, then the condition helper assertions, then the packed carousel fixture tests near the existing packed-picture test.”

    Action/result: Added carousel-related imports, helper assertions, and fixture layout tests.

  1690. Reported: “Imports are updated. I’m adding the assertions for the raw-key condition bytes and the carousel fixture layout next.”

    Action/result: Added raw-key and carousel fixture assertions.

  1691. Reported: “The fixture tests are in. I’m adding the runner tool now: build one packed carousel fixture, start the engine once, capture picture 0, send a key to advance, capture picture 1, and so on.”

    Action/result: Added tools/picture_carousel.py.

  1692. Reported: “The carousel runner tool is in place. I’m adding lightweight unit tests around its report and orchestration path with mocks, then I’ll do a short QEMU smoke run to validate the raw-key advance behavior in the actual engine.”

    Action/result: Added tests/test_picture_carousel.py.

  1693. Reported: “The unit tests cover the carousel’s naming/reporting and that it builds one fixture while comparing each capture separately. I’m running these plus the qemu-fixture tests now.”

    Action/result: Ran carousel/qemu-fixture tests successfully and confirmed a two-picture carousel fixture is about 77 KB.

  1694. Reported: “The carousel unit tests pass and the two-picture carousel fixture is tiny, about 77 KB. I’m running the two-picture carousel against QEMU now; this is the important proof that raw-key advancement works in the original engine.”

    Action/result: First unprivileged QEMU carousel attempt failed at VNC bind before the engine ran.

  1695. Reported: “As expected, the first carousel QEMU run failed at the sandbox VNC bind, before the engine ran. I’m rerunning the exact command with the same escalation pattern we’ve used for the other QEMU harnesses.”

    Action/result: Reran with approved tools/picture_carousel.py prefix; the first picture matched but the second mismatched.

  1696. Reported: “The carousel ran under QEMU, but only the first picture matched; the second capture mismatched. That means the packed carousel fixture boots and captures correctly, but the raw-key advance either didn’t fire or didn’t settle before capture. I’m inspecting the report and capture rather than treating this as a renderer problem.”

    Action/result: Compared the second capture and found it was closest to picture 1 with a visible UI/text damage rectangle.

  1697. Reported: “The failed carousel smoke is behaving like the key is being handled by the normal input path, not by our advance condition. There’s already a validated key-mapping/status-byte path for logic probes, so I’m switching the carousel advance trigger from raw key condition to map_key_event plus status byte condition. That should consume x as a mapped event instead of typed parser input.”

    Action/result: Investigated status-byte mapping as a possible carousel trigger.

  1698. Reported: “That search command had a quoting mistake. I’m rerunning a simpler search for the status-byte table and then I’ll patch the carousel trigger.”

    Action/result: Re-ran the status-byte search successfully.

  1699. Reported: “The status-byte path would need either explicit status clearing or many one-shot mapped statuses, so I’m trying the lighter source-backed fix first: disable the normal input line in the carousel setup. The failed capture looked like the typed key was affecting normal input UI, so keeping input-line processing out of the sweep may let the raw-key predicate own the advance event cleanly.”

    Action/result: Added input-line disable action to carousel setup.

  1700. Reported: “The carousel setup now disables the normal input line before drawing the first picture. I’m rerunning the structural tests and then the QEMU two-picture carousel smoke.”

    Action/result: Tests passed; QEMU base carousel still mismatched the second picture.

  1701. Reported: “Disabling the input line did not fix the carousel advance: first picture still matches, second still mismatches. I’m checking whether the second capture is still basically picture 1 with UI damage, or whether the advance happened but the display state carried over.”

    Action/result: Confirmed the second capture remained closest to picture 1 with the same UI/text mismatch area.

  1702. Reported: “The second capture is still closest to picture 1, with a mismatch rectangle that looks like UI/text damage. So the raw-key advance is not the right trigger as currently wired. I’m trying a non-printing key next; if it fires the raw-key predicate without typing into the parser UI, it may be enough for carousel advancement.”

    Action/result: Tried f1 as the raw-key advance key; it still mismatched.

  1703. Reported: “f1 also failed to advance. I’m going to stop treating this as a quick harness tweak and inspect the generated bytecode plus the known event/update ordering; the carousel tool can stay, but it needs a better advance mechanism before we mark it validated.”

    Action/result: Re-read the earlier validated raw-key logic probe.

  1704. Reported: “The first two attempts prove something useful but not complete: “press a key and check raw-key condition” is not enough in this carousel setting, because the normal command/input path is still producing visible UI changes while the picture index stays put. I’m reading the earlier validated raw-key probe to see what setup difference made that one work.”

    Action/result: Compared carousel logic against the existing raw-key probe setup.

  1705. Reported: “Aha, found the likely bug in my carousel bytecode: raw-key caches at absolute byte [0x001c], while AGI variable actions are offset from [0x0009]. I used variable index 0x1c, which clears [0x0025]; the correct variable slot for absolute [0x001c] is 0x13. That would let one key event advance twice in the same logic pass and wrap back to picture 1. I’m patching that now.”

    Action/result: Corrected the raw-key cache clear to script variable v19.

  1706. Reported: “The raw-key cache clear is corrected to variable slot 0x13. I’m tightening the test so this exact off-by-base mistake is pinned.”

    Action/result: Added a regression assertion for assignn(v19, 0).

  1707. Reported: “The regression check now looks for assignn(v19, 0), which is the bytecode way to clear absolute [0x001c]. I’m rerunning tests and then the QEMU carousel smoke.”

    Action/result: Tests passed; QEMU base carousel picture_carousel_base_003 matched both pictures.

  1708. Reported: “The carousel tests pass with the corrected raw-key slot. I’m rerunning the QEMU base carousel; this should tell us whether the fast path is genuinely usable.”

    Action/result: Confirmed the corrected two-picture raw-key carousel passed with 2 matches.

  1709. Reported: “The corrected carousel smoke passed: one engine process, two pictures, two matches, zero mismatches. I’m going to try the eight-picture broad preset next, which is the real speed comparison against the snapshot-per-case approach.”

    Action/result: Started broad raw-key carousel run.

  1710. Reported: “The broad carousel run is active. It should complete much faster than the old eight-process-style snapshot batch if the per-key advance remains stable.”

    Action/result: Broad raw-key carousel matched first three pictures, then mismatched five later captures.

  1711. Reported: “The broad carousel advanced correctly through the first three pictures, then mismatched on the larger resources. That smells like capture timing, not bytecode: the larger pictures need more time to decode/draw after the key. I’m rerunning broad with a longer per-advance wait.”

    Action/result: Reran broad raw-key carousel with --advance-wait 8.

  1712. Reported: “The longer-wait broad carousel run is in progress. If this passes, we’ll have a usable fast mode with an explicit wait-time knob for heavier resources.”

    Action/result: Waited on the longer broad carousel run.

  1713. Reported: “The longer broad carousel run is still active. It captures and compares after the run finishes, so silence here just means it is stepping through the eight resources.”

    Action/result: Longer broad raw-key carousel failed at the same boundary.

  1714. Reported: “The longer wait did not change the failure boundary: pictures 1, 6, and 17 match, then the larger packed resources fail. I’m checking whether capture 4 is the wrong picture, a partially rendered picture, or a bad resource-load effect.”

    Action/result: Found captures 4 onward were exactly picture 17.

  1715. Reported: “The broad failure is now clearer: after picture 17, every later capture is still exactly picture 17. So the carousel is not misrendering big pictures; it stops advancing after the third displayed picture. I’m going to probe whether that is tied to picture 17, the third index, or repeated key delivery.”

    Action/result: Created and ran a manual four-picture carousel probe.

  1716. Reported: “That combined command included a small inline Python file-write before the carousel run, so the approved prefix didn’t cover the QEMU segment cleanly. The case file is written now; I’m rerunning just the carousel command.”

    Action/result: Reran the manual four-picture carousel command.

  1717. Reported: “The four-picture manual carousel is running now. This should tell us whether the stall is “third advance” generally or something about picture 17/broad ordering.”

    Action/result: Manual raw-key carousel also stalled after the third displayed picture.

  1718. Reported: “The manual four-picture run also stalls after the third displayed picture, so it’s not picture 17 or large-resource decode. The next likely culprit is my persistent index variable: I used a high scratch-style variable (v249), which may be fine for immediate operands but not safe as per-cycle state. I’m moving the carousel index to a lower dedicated variable and retesting.”

    Action/result: Changed the carousel index variable from v249 to v32.

  1719. Reported: “The carousel index now uses v32 instead of v249. I’m updating the tests to assert the new state variable, then I’ll rerun the manual four-picture carousel.”

    Action/result: Updated tests for v32.

  1720. Reported: “The test now pins the lower carousel index variable. I’m running the structural tests and the same four-picture QEMU probe again.”

    Action/result: Tests passed; the four-picture raw-key carousel still stalled after the third displayed picture.

  1721. Reported: “The structural tests pass with v32. I’m rerunning the four-picture carousel to see whether the third-advance stall disappears.”

    Action/result: Confirmed the lower index variable did not fix the stall.

  1722. Reported: “The lower index variable didn’t change the stall, so the script state is probably fine. The remaining suspect is QEMU/DOS key delivery for repeated identical monitor keys. I’m teaching the runner to accept a comma-separated key cycle, then I’ll try x,y,z so each advance is a distinct key event.”

    Action/result: Added comma-separated key cycling to the carousel runner.

  1723. Reported: “The runner can now cycle through a comma-separated key list. I’m adding a tiny test for rejecting an empty key list, then I’ll rerun the four-picture QEMU probe with x,y,z.”

    Action/result: Added empty advance-key validation test.

  1724. Reported: “The empty-key guard test is in. I’m running the carousel tests and then the distinct-key four-picture QEMU probe.”

    Action/result: Tests passed; distinct printable keys still stalled after the third displayed picture.

  1725. Reported: “The distinct-key carousel run is active. If this still stalls after the third capture, the key-repeat theory is out and we’ll need a different advance event source.”

    Action/result: Confirmed the key-repeat theory did not explain the stall.

  1726. Reported: “The raw-key route is too flaky for long carousels. I’m switching the carousel to the interpreter’s already QEMU-validated mapped-key/status-byte mechanism: setup maps each advance key to a unique status byte, each transition tests “current index and that status,” and the carousel does not wrap. That avoids needing to clear status bytes and fits representative sweeps well.”

    Action/result: Reworked carousel bytecode to use mapped keys and status byte conditions.

  1727. Reported: “The carousel logic now uses mapped status events and has one transition per key, no wrap. I need to update the tests from “raw key advance” to “mapped key/status advance.””

    Action/result: Updated qemu-fixture tests for mapped-key carousel logic.

  1728. Reported: “The tests now expect mapped-key bytecode. I’m wiring the key list through the runner so the fixture maps the same keys that QEMU sends.”

    Action/result: Passed advance key words through tools/picture_carousel.py into the generated carousel fixture.

  1729. Reported: “The runner now defaults to a long mapped-key list and errors if there are not enough keys for the selected carousel. I’m running the tests, then the four-picture and broad QEMU probes again.”

    Action/result: Mapped-key tests passed.

  1730. Reported: “Tests pass with mapped-key carousel bytecode. I’m rerunning the four-picture QEMU probe using the default key list.”

    Action/result: Four-picture printable-key carousel matched two pictures, then showed picture 20 with UI/text artifact and stalled.

  1731. Reported: “The mapped-key four-picture carousel is running. If this passes, I’ll move straight to the broad mapped-key run.”

    Action/result: The mapped-key four-picture carousel did not pass.

  1732. Reported: “Mapped keys improved the repeated-key issue differently but still stalls, now after the second displayed picture. I’m checking the captured image identity again; this will tell us whether status-byte triggering is only firing once.”

    Action/result: Found the third capture was mostly picture 20 with a visible UI/text mismatch, and the fourth capture remained the same.

  1733. Reported: “The second transition did draw picture 20, but with a small UI/text mismatch, and then subsequent captures stayed there. So mapped status events are advancing, but the normal input UI still leaves visible damage after the transition. For a fast oracle, we either need to suppress/repair that UI or compare only after a clean picture refresh.”

    Action/result: Localized the mismatch rectangle to the same visible text/window area.

  1734. Reported: “The mismatch rectangle is the same visible text/window area, so printable mapped keys are still being interpreted by the command parser. I’m adding support for non-printing function keys (f1, f2, …) as mapped advance keys; those should produce key events without putting text into the input/parser path.”

    Action/result: Added function-key BIOS word mapping to tools/picture_carousel.py.

  1735. Reported: “Function-key names now map to BIOS key words for the fixture and are sent to QEMU as the same key names. I’m fixing the carousel bytecode validation to allow those 16-bit key words.”

    Action/result: Updated carousel bytecode validation for 16-bit mapped keys.

  1736. Reported: “The fixture generator now accepts 16-bit mapped key words. I’m running the carousel tests, then the four-picture QEMU run with the function-key defaults.”

    Action/result: Tests passed; function-key four-picture carousel still stalled after the second displayed picture.

  1737. Reported: “Tests pass with function-key support. I’m running the four-picture QEMU carousel with the default f1,f2,f3,... advance keys now.”

    Action/result: Ran the function-key four-picture carousel.

  1738. Reported: “The function-key carousel run is active. This is the cleanest version of the idea so far: mapped non-printing keys, one engine process, no raw-key cache juggling.”

    Action/result: The function-key four-picture run still failed after two displayed pictures.

  1739. Reported: “Function keys still stall after the second displayed picture, so the problem is not only printable input. I’m going to stop short of marking carousel validated beyond the two-picture smoke and document this as a partially working prototype: useful direction, but it needs a better event/ack strategy before replacing snapshot batches.”

    Action/result: Decided to document carousel as prototype infrastructure rather than broad compatibility evidence.

  1740. Reported: “Before documenting the limitation, I’m running the two-picture base carousel once more with the current mapped function-key implementation. That gives us a clean “validated for two-step smoke, not yet broad sweep” boundary.”

    Action/result: Ran picture_carousel_base_mapped_fkey_001; it matched both base pictures with 0 mismatches.

  1741. Reported: “The current carousel implementation is validated for the two-picture base smoke: 2 matches, 0 mismatches. The four/broad sweeps still stall after two displayed pictures, so I’m recording it as a prototype with a clear limitation rather than overclaiming it.”

    Action/result: Updated compatibility docs, PROGRESS.md, and AGENTS.md with the carousel smoke status and limitation.

  1742. Reported: “I’m updating the docs with the precise carousel status: why it exists, what passed, what failed, and what a future fix needs to solve.”

    Action/result: Added carousel status to docs/src/compatibility_testing.md.

  1743. Reported: “The compatibility chapter and progress tracker now mark carousel as a two-picture smoke prototype, not a broad oracle. I’m updating AGENTS.md with the same caveat so future runs don’t accidentally treat it as production-grade.”

    Action/result: Added carousel caveat to AGENTS.md.

  1744. Reported: “AGENTS.md now carries the caveat. I’m adding the detailed carousel evidence trail to the clean-room notes, including the raw-key cache bug and the failed broader runs.”

    Action/result: Added the picture carousel prototype section to docs/src/clean_room_executable_notes.md.

  1745. Reported: “Absolutely. I’m going to treat the current carousel work as a throughput prototype rather than a side experiment: first I’ll make sure the docs/log reflect what we learned, then I’ll verify the repo, and if there’s a clean next improvement for resource iteration I’ll make it rather than leaving it as a vague note.”

    Action/result: Confirmed the progress log contains the carousel evidence trail through entry 1892 and began promoting cross-game resource iteration throughput into the tracker.

  1746. Reported: “Good catch. I’m not currently using the interpreter’s speed setting in the harness; the QEMU waits so far are conservative wall-clock sleeps, and the new timed carousel I’m wiring up uses interpreter cycles but has not yet set the engine speed.”

    Action/result: Searched local docs, SQ2 logic messages, and disassembly for speed/cycle handling.

  1747. Reported: “Answer to the direct question: no, not yet. I’ve been using conservative --draw-wait/--advance-wait sleeps and QEMU snapshotting, not an explicit “fastest” interpreter speed setting.”

    Action/result: Confirmed no obvious SQ2 script message for speed and moved the investigation to the executable.

  1748. Reported: “Found it. The cycle throttle is right at 0x7f78: it reads byte [0x0013], which is script variable v10 if variables start at [0x0009], then spins until timer/counter word [0x1784] reaches that value and clears [0x1784].”

    Action/result: Added a symbolic label and fixture support for setting the speed variable in timed carousel scripts.

  1749. Reported: “For the actual timed QEMU run, I’m not going to use speed 0 for the first probe because it can advance all pictures before the first screendump; I’ll use v10 = 1 with a larger cycle hold so each picture remains visible long enough to capture.”

    Action/result: Timed two-picture carousel picture_carousel_base_timed_001 matched 2/2.

  1750. Reported: “Nice, the timed two-picture carousel matched 2/2 with one engine process. I’m trying the broad eight-picture version with the same speed/hold settings; this is the real test of whether the timed approach avoids the key-event stall.”

    Action/result: The first fixed-sleep broad timed run matched 2/8; identity checks showed wrong-picture cadence misses.

  1751. Reported: “The identity check is revealing: after picture 1, the carousel jumped to picture 17 and then stayed there. That means timing alone is not the whole story; the timed script is losing or corrupting its carousel state after the second transition.”

    Action/result: Moved carousel state back to high scratch variables and confirmed that did not fix the fixed-sleep broad cadence.

  1752. Reported: “The two-picture 17 -> 43 case passes, so picture 43 is fine. The broad stall is likely inside the transition bookkeeping.”

    Action/result: Reordered timed/key carousel transition bytecode to update carousel state before discarding the old picture.

  1753. Reported: “The reorder changed the failure shape: picture 76 now matches, so state is advancing through the sequence. The remaining broad mismatches are cadence alignment, not a hard stall.”

    Action/result: Cached identity check showed captures landing on exact renders for other broad-preset pictures.

  1754. Reported: “The identity pass shows clean cadence drift: captures saw 1,17,43,44,46,76,76,76, so the carousel is advancing roughly twice as fast as the capture interval.”

    Action/result: Tried delay-cycles 240; this aligned picture 6 but still drifted later.

  1755. Reported: “The calibrated run shows why fixed sleeps will be brittle across games: picture load/draw time changes the cadence. I’m going to add a polling mode for timed carousels instead.”

    Action/result: Added --poll, --poll-interval, and --poll-timeout to tools/picture_carousel.py.

  1756. Reported: “Good news: the polling timed carousel has matched the first six broad pictures in sequence. It’s still waiting/capturing the last two, so I’m letting that finish.”

    Action/result: picture_carousel_broad_timed_poll_001 matched all 8 broad pictures with delay-cycles 240.

  1757. Reported: “The faster polling run passed 8/8 in one engine process. I’m trying one more shorter hold (delay_cycles=60) to find a practical lower bound; if it passes, that becomes the better recommendation.”

    Action/result: picture_carousel_broad_timed_poll_fast_001 matched all 8 broad pictures with delay-cycles 120; delay-cycles 60 missed intermediate pictures and is not recommended.

  1758. Reported: “The 60 hold was too short and missed almost everything, so the practical default is delay_cycles=120, speed_value=1, polling every half-second. I’m making the CLI defaults reflect that stable setting and documenting the faster carousel path now.”

    Action/result: Updated CLI defaults, AGENTS.md, compatibility docs, PROGRESS.md, symbolic labels, logic bytecode notes, and clean-room notes with the timed polling carousel evidence.

  1759. Reported: “The clean tree is just generated artifacts now. I’m going to take the next compatibility-suite step: scale the timed polling carousel from the 8-picture broad preset to the full 74-picture SQ2 picture set, because that directly exercises the faster iteration path we’ll need for more games and interpreter versions.”

    Action/result: Began a full-present-picture timed polling carousel run.

  1760. Reported: “The full carousel fixture is built and QEMU is running it now. I’m watching for the first reported comparisons; if this becomes too slow or hits an engine lifecycle limit, the next move will be chunking the picture list rather than restarting per picture.”

    Action/result: Confirmed the full all-picture timed polling fixture could launch under QEMU, but no per-case output appeared during the polling phase.

  1761. Reported: “No per-picture output yet, which means the harness is still inside the QEMU polling phase. That is expected for a large sweep, but I’m noting this as a harness ergonomics issue: future long runs should print poll progress while they are still inside QEMU, not only after QEMU exits.”

    Action/result: Identified the need for live per-case polling progress in tools/picture_carousel.py.

  1762. Reported: “This has now gone past the broad-run timing, which is not surprising for 74 pictures but is exactly why the harness needs internal progress output. I’m letting it finish rather than interrupting, because even a partial failure shape will tell us where the single-process carousel breaks.”

    Action/result: Let the single all-picture QEMU run continue to preserve the failure evidence.

  1763. Reported: “The all-picture run is still active. Given the current timeout settings, the theoretical ceiling is high if one early picture never appears, so I’m waiting a bit longer and then I’ll either read the report or use the partial captures to see what state the engine reached.”

    Action/result: Continued waiting for the report rather than killing the QEMU process.

  1764. Reported: “The report is coming back now. The first 19 all-present pictures matched in sequence; I’m reading the rest of the mismatches to see whether this is renderer drift, a timing issue, or an engine prompt state.”

    Action/result: Single all-picture timed polling run produced a report with 19 matches and 55 mismatches.

  1765. Reported: “The full timed polling run finished: 19 matches, 55 misses. I’m doing an identity pass over the mismatched captures now; that will tell us whether QEMU drew different valid pictures, got stuck on one picture, or produced a UI/error screen.”

    Action/result: Started comparing mismatched QEMU captures against all present local picture renders.

  1766. Reported: “The identity pass shows a clean stall: every later capture is closest to picture 19. I’m opening one of those captures next, because the most likely explanations are either a disk/resource prompt or the generated script failing to advance after a specific resource.”

    Action/result: Determined that captures for picture 20 onward were not renderer mismatches; they stayed visually at picture 19.

  1767. Reported: “The picture 20 capture explains the stall: the engine is showing ‘Please insert disk 3 and press ENTER.’ over picture 19. I’m checking the generated disk contents and packed offsets now before deciding whether this is a fixture bug or an original-engine resource lifecycle limit.”

    Action/result: Inspected the picture 20 capture and found the original engine disk-insert prompt.

  1768. Reported: “The packed record header for picture 20 is correct, and the PICDIR entry points at the right offset. I’m also checking the DOS snapshot directory so we don’t misdiagnose a missing VOL.3 copy as interpreter behavior.”

    Action/result: Confirmed picture 20’s generated PICDIR entry and packed VOL.3 record header were correct.

  1769. Reported: “The DOS snapshot has the large VOL.3 intact, so the prompt is not the obvious missing-file case. I’m treating the single huge carousel as crossing an original-engine resource/disk lifecycle boundary, and I’m adding chunking so large sweeps stay inside the behavior we want to model.”

    Action/result: Confirmed VOL.3 was present in the generated DOS fixture and chose chunking for large picture sweeps.

  1770. Reported: “I’ve got the shape: one process is good up to 19 pictures, but the all-in-one fixture hits a disk prompt before picture 20 even though the generated volume file is present. I’m adding chunked carousel execution now so the all-picture sweep can still run much faster than one boot per picture.”

    Action/result: Began adding chunked carousel execution to tools/picture_carousel.py.

  1771. Reported: “The code change is small: split the case list, build one carousel fixture per chunk, and suffix the DOS directory plus snapshot paths so each chunk is isolated. I’m adding unit coverage for the split and naming behavior before rerunning QEMU.”

    Action/result: Implemented chunk directory/path helpers and chunked carousel orchestration.

  1772. Reported: “Chunked execution is wired into the CLI now. I’m updating the tests to assert the exact chunk split and generated snapshot names, since that is the part future agents are most likely to accidentally break.”

    Action/result: Added unit coverage for chunk splitting and generated snapshot path names.

  1773. Reported: “The main path looks correct, but I’m patching the test import and expectations rather than trusting it by inspection. After that I’ll run the focused carousel tests, then the full 74-picture chunked QEMU sweep.”

    Action/result: Completed test import/expectation updates for chunked carousel support.

  1774. Reported: “I caught one index mismatch in the expected generated DOS names while reading the tests; fixing that now. This is exactly the kind of tiny harness naming issue that’s cheap to catch before a QEMU run.”

    Action/result: Corrected the expected chunked DOS directory names.

  1775. Reported: “Now I’m running focused carousel tests before spending time on QEMU. If those pass, the next command will be the all-picture timed polling sweep split into chunks of 16.”

    Action/result: python3 -B -m unittest tests.test_picture_carousel passed 7 tests.

  1776. Reported: “The chunking tests pass. I’m launching the all-picture sweep again with --chunk-size 16; that should tell us whether the disk prompt was caused by the oversized single carousel rather than picture 20 itself.”

    Action/result: Started the chunked all-present-picture timed polling carousel run.

  1777. Reported: “Chunk 1 of 5 is running now. This is already a better harness shape: we get bounded engine lifetimes and still avoid paying a boot for every individual picture.”

    Action/result: Chunk 1 began under QEMU.

  1778. Reported: “Chunk 1 passed all 16 pictures, so the chunked path is past the easy first segment. The important test is chunk 2, because that includes picture 20, where the single all-picture run hit the disk prompt.”

    Action/result: Chunk 1 matched 16/16.

  1779. Reported: “Chunk 2 passed too, including picture 20. That strongly supports the interpretation that the previous failure was the oversized all-in-one fixture lifecycle, not picture 20 decoding or local rendering.”

    Action/result: Chunk 2 matched all expected pictures, including picture 20.

  1780. Reported: “Chunk 3 also passed. I’m letting the last two chunks finish; if they stay clean, we’ll have full 74-picture carousel evidence with five engine launches instead of 74.”

    Action/result: Chunk 3 matched all expected pictures.

  1781. Reported: “Chunk 4 passed all 16. One short final chunk remains, and if that passes I’ll document the chunked command as the recommended high-throughput real-picture sweep.”

    Action/result: Chunk 4 matched all expected pictures.

  1782. Reported: “I’m picking up the harness-scaling thread from PROGRESS.md: the all-picture timed carousel now works in chunks, so I’m going to finish the evidence trail around that, tighten the harness a little, and then run the standard docs/tests checks.”

    Action/result: Resumed from PROGRESS.md and confirmed the uncommitted chunked carousel work and generated QEMU outputs.

  1783. Reported: “The chunked all-picture run already proved the big compatibility gain: 74 of 74 SQ2 pictures matched when split into 16-picture chunks. I’m going to add the missing evidence notes now, and I’ll also make the polling runner print per-case progress so future long sweeps don’t look frozen.”

    Action/result: Prepared documentation updates and a live polling progress improvement for tools/picture_carousel.py.

  1784. Reported: “One useful limitation surfaced here: the all-in-one run did not reveal a renderer error, it revealed an engine resource/disk prompt boundary after picture 19. The chunked run gives us the practical compatibility path while keeping that boundary documented instead of papered over.”

    Action/result: Recorded the all-in-one disk-prompt boundary as a fixture lifecycle observation, not renderer semantics.

  1785. Reported: “I’m making one small harness edit before the docs: polling mode will now print each expected picture as it matches or times out. That gives us live feedback during big resource sweeps without changing the comparison semantics.”

    Action/result: Added per-case poll matched / poll timed out progress output to the QEMU polling runner.

  1786. Reported: “Now I’m updating the clean-room record: the important detail is that the failed 74-picture single carousel is evidence about original-engine fixture limits, while the chunked version is the reusable high-throughput path.”

    Action/result: Updated AGENTS.md, compatibility docs, and clean-room executable notes with the all-picture chunking evidence.

  1787. Reported: “The docs now say exactly what we learned from the prompt boundary, including the checked VOL.3 and PICDIR bytes. Next I’m updating PROGRESS.md so the dashboard reflects that the picture carousel has moved from ‘broad smoke’ to full 74-picture coverage in chunks.”

    Action/result: Updated PROGRESS.md to include the chunked all-74-picture timed polling carousel validation.

  1788. Reported: “PROGRESS.md is updated. I’m adding the progress-log entries now; I’m keeping them concise but preserving each reported step/result so the historical trail remains useful without turning into raw transcript sludge.”

    Action/result: Added progress-log entries for the all-picture and chunked-carousel work.

  1789. Reported: “The historical log is caught up through the chunked sweep. I still need to log the final result and the documentation pass after verification, but the substantive evidence is now in the project docs.”

    Action/result: Reviewed the working diff before final verification.

  1790. Reported: “I noticed the new test import and a couple of assertions are a bit wide, so I’m cleaning that up before running the full suite. The behavior stays the same; this is just keeping the harness readable for the next pass.”

    Action/result: Wrapped the new tests/test_picture_carousel.py import and long assertions, and wrapped a couple of wide lines in tools/picture_carousel.py.

  1791. Reported: “The code cleanup is done. I’m going to add the last few progress-log entries for this resumed pass, then run the standard verification commands.”

    Action/result: Finished progress-log maintenance and moved to verification.

  1792. Reported: “Verification time. I’m running the unit suite, opcode evidence check, and mdBook build in parallel; after those finish I’ll do the whitespace diff check and one final status pass.”

    Action/result: python3 -B -m unittest discover -s tests passed 158 tests; python3 -B tools/logic_opcode_evidence.py --check passed; and mdbook build docs completed successfully.

  1793. Reported: “All three main checks passed: 158 unit tests, the opcode evidence check, and the mdBook build. I’m doing the final git diff --check and status now.”

    Action/result: git diff --check passed. The remaining tracked changes are the chunked carousel harness, tests, and documentation updates.

  1794. Reported: “The current changes are verified and uncommitted, with only the usual generated build/ and DOS installer artifacts untracked. I’m going to keep going from the next high-value PROGRESS.md item: a representative save/restore or file-error probe, starting from the existing local tools/docs so I can reuse the established clean-room path.”

    Action/result: Began inspecting existing save/restore and file-error evidence for the next PROGRESS.md task.

  1795. Reported: “For the next item I’m looking for the shortest useful dynamic probe: something observable in QEMU, but backed by the existing source/file-format notes instead of freeform poking. First pass is finding the current save/restore tooling and where the docs say the gaps still are.”

    Action/result: Searched existing tools, tests, and docs for save/restore coverage and confirmed the remaining dynamic gap.

  1796. Reported: “The existing gap is exactly where PROGRESS.md says it is: we have static save-file envelope tests and Escape-cancel QEMU checks, but not a real round-trip through the original engine. I’m reading the fixture builder and save-file parser next to see whether we can generate a controlled slot and restore it dynamically.”

    Action/result: Re-read tools/agi_save.py, tools/qemu_fixture.py, and the save-selector notes.

  1797. Reported: “A full restore of an arbitrary existing SQ2 save would pull us into actual game-state rendering, which is less controlled. A more useful first dynamic probe is narrower: generate a fixture with no save files, drive the original save selector to create SQ2SG.1, then pull that file back through the source-backed parser.”

    Action/result: Chose a dynamic save-write probe before attempting a full restore round trip.

  1798. Reported: “I’m going to add this as a reusable tool rather than a one-off experiment. The probe will build a synthetic save fixture, drive the real selector, convert the post-run disk back to raw, extract SQ2SG.1, and parse it with our save envelope code.”

    Action/result: Added the first version of tools/save_roundtrip_probe.py.

  1799. Reported: “The probe tool is in place. I’m adding lightweight tests for the fixture-building pieces now, then I’ll run it against QEMU and tune the key sequence if the selector needs a different path.”

    Action/result: Added tests/test_save_roundtrip_probe.py.

  1800. Reported: “The unit tests cover the generated bytecode shape, fixture save-file removal, and JSON reporting. I’m running those focused tests now before spending QEMU time.”

    Action/result: python3 -B -m unittest tests.test_save_roundtrip_probe passed 4 tests.

  1801. Reported: “Focused tests pass. I’m launching the new save probe with the simplest likely selector sequence: Enter to select the first empty slot, type Codex probe, Enter to accept the description. If that misses, the capture/report should show which selector screen we landed on.”

    Action/result: First QEMU run hit the sandbox VNC socket restriction.

  1802. Reported: “QEMU hit the sandbox’s VNC socket restriction for this new tool, so I’m rerunning the same probe with escalation. This is the same pattern as the other QEMU harnesses: local emulator, local disk image, local VNC endpoint.”

    Action/result: Escalated QEMU run completed, but the probe failed because it tried to compare synthetic picture 0 through the real SQ2 picture comparator.

  1803. Reported: “The QEMU run itself completed, but my probe made a bad local comparison assumption: picture 0 is synthetic in the fixture, not a real SQ2 picture, so compare_picture_capture(0, ...) quite rightly refused it. I’m fixing the probe to compare against the generated blank-picture plus validation-view frame instead.”

    Action/result: Replaced the real-picture comparison with a synthetic blank-picture plus view-11 validation comparison.

  1804. Reported: “That comparison fix keeps the probe honest: it now checks the fixture’s own expected post-save screen rather than pretending the synthetic picture is a stock SQ2 resource. I’m rerunning the focused tests, then the QEMU probe again.”

    Action/result: Focused tests passed; QEMU ran, but no SQ2SG.1 file was created.

  1805. Reported: “The probe ran through QEMU but no SQ2SG.1 was created, so the first key sequence didn’t accept the save. I’m inspecting the post-run capture and DOS directory now to see which save-selector state it reached.”

    Action/result: DOS directory listing showed no save file after the first key-sequence attempt.

  1806. Reported: “The directory listing confirms no save file was written. I converted the capture and I’m going to inspect it visually; that should tell us whether we’re still at the path prompt, the slot list, or a validation screen.”

    Action/result: Visual capture showed the save-description prompt with a blank input line.

  1807. Reported: “The capture shows the engine is sitting at the save-description prompt with a blank input line. That means the no-save fixture skips straight to description entry; I’m rerunning with a longer wait and without the leading Enter, so the typed description lands in the line editor.”

    Action/result: The adjusted command needed escalation because shell newline quoting did not match the approved prefix.

  1808. Reported: “That rerun used shell quoting for the newline, so it didn’t match the approved prefix and hit the same local VNC sandbox restriction. I’m rerunning it escalated; if this sequence works I’ll make newline handling less awkward in the tool.”

    Action/result: Rerun produced no save file; the capture showed a path error for \SVRTcodex probe.

  1809. Reported: “Still no save file, so this is not just the leading Enter. I’m opening the second capture; if the text appears there, the missing step is an acceptance/confirmation key after description, otherwise the key delivery needs a staged delay.”

    Action/result: Visual capture showed the path prompt had interpreted the description text as part of a directory name.

  1810. Reported: “That capture is very helpful: the text landed in the path prompt, producing \SVRTcodex probe. So the selector needs staged input: accept the path, wait for the description prompt, then type the description. I’m changing the save probe to own its small QEMU input loop instead of using the generic one-shot post-launch key field.”

    Action/result: Reworked the tool to drive staged QEMU input directly.

  1811. Reported: “I spotted a variable shadowing bug in that staged-input patch before rerunning: the description argument was being overwritten by the parsed-result field. Fixing that now.”

    Action/result: Fixed the save-description argument handling.

  1812. Reported: “The staged-input path is fixed. I’m running the focused tests again, then the QEMU save creation probe with the new default staged sequence.”

    Action/result: Focused tests passed; QEMU reached the description prompt but still did not write a save file.

  1813. Reported: “The staged sequence still did not create the file. I’m checking the capture again; this should distinguish ‘still in description prompt’ from ‘description accepted but another confirmation/error appeared.’”

    Action/result: Capture again showed the blank description prompt.

  1814. Reported: “It is consistently reaching the description prompt, but the description text is being sent before that editor is actually accepting keystrokes. I’m increasing the staged wait after the path Enter and slowing the key cadence a little.”

    Action/result: Longer description wait still left the prompt blank.

  1815. Reported: “Still no file. I’m checking whether the slower run left typed text on the prompt; if it is still blank, the issue may be that this editor is using the raw keyboard path and QEMU sendkey timing needs a different staging method.”

    Action/result: Capture remained blank, motivating a no-submit debug run.

  1816. Reported: “To separate ‘letters are ignored’ from ‘Enter submits and redraws the prompt before capture,’ I’m adding a debug switch that types the description without the final Enter. Then a capture can show whether the description line editor is actually receiving characters.”

    Action/result: Added --no-submit-description for staged-input debugging.

  1817. Reported: “The debug switch is in. I’m running a no-submit capture now: it should leave the typed description visible if the editor is accepting input.”

    Action/result: No-submit run reached the save-slot selector, proving an intermediate slot-selection stage was missing.

  1818. Reported: “As expected, the no-submit run did not create a file. I’m inspecting the capture now; this is purely to see whether abc reached the description input line.”

    Action/result: Capture showed the numbered save-slot selector rather than the description prompt.

  1819. Reported: “Aha. The staged capture shows the missing screen: after accepting the path, the engine displays the numbered slot selector. So the correct sequence is path Enter, slot Enter, then description text. I’m adding that middle stage to the probe.”

    Action/result: Added --slot-keys and --slot-wait staging.

  1820. Reported: “The tool now has the three stages the source/UI path needs: path prompt, slot selector, description prompt. I’m rerunning the probe with the new defaults.”

    Action/result: Three-stage run accepted the description and reached the final save confirmation screen.

  1821. Reported: “Still no save file. I’m inspecting this capture to see whether the staged sequence is now at the description prompt, the slot selector, or a save error message.”

    Action/result: Capture showed About to save the game described as: codex probe, so a final confirmation Enter was still needed.

  1822. Reported: “Good, now the description was accepted and the engine is showing its final ‘About to save’ confirmation. One more staged Enter is needed after that. I’m adding the confirmation stage.”

    Action/result: Added --confirmation-wait and --confirmation-keys.

  1823. Reported: “The confirmation stage is wired in. I’m rerunning the save probe with the default path/slot/description/confirmation sequence; this should be the actual original-engine save-write path now.”

    Action/result: Original engine wrote a save, but it was named SG.1 rather than the probe’s expected SQ2SG.1.

  1824. Reported: “No file yet after confirmation, so I’m checking whether the final Enter was too early, whether a disk/path error appeared, or whether the save wrote to a different directory/name than the extraction assumes.”

    Action/result: DOS directory listing showed SG.1 of size 2889 bytes, and the capture matched the validation screen.

  1825. Reported: “The save actually succeeded. The generated file is named SG.1, not SQ2SG.1, in this synthetic no-save fixture, and the validation view drew after the save returned. I’m updating the extractor to accept the observed save stem instead of hardcoding SQ2SG.”

    Action/result: Added --save-stem and changed the default extracted filename to SG.1.

  1826. Reported: “The extracted SG.1 parses cleanly: description codex probe, blocks [1505, 903, 328, 100, 12], size 2889 bytes. I’m turning the observed save stem into a CLI option so the probe report goes green instead of failing on the filename assumption.”

    Action/result: Confirmed the original-engine save output parses through tools/agi_save.py.

  1827. Reported: “The extractor now looks for SG.1 by default, with --save-stem available for other interpreter/game launches. I’m rerunning the same probe; this time it should extract, parse, and compare the post-save validation capture.”

    Action/result: save_roundtrip_007 passed with status match, parsed description codex probe, block lengths [1505, 903, 328, 100, 12], and 0 visual mismatches.

  1828. Reported: “That’s the dynamic save-write probe we wanted: original engine created SG.1, the parsed save envelope is valid, the description matches, and the post-save validation draw matched with zero visual mismatches. I’m documenting it and updating the progress tracker now.”

    Action/result: Began updating AGENTS.md, compatibility docs, clean-room notes, and PROGRESS.md.

  1829. Reported: “The compatibility chapter now records the dynamic save-write result and keeps the restore part honest as remaining work. I’m adding the detailed clean-room notes next, including the failed key-sequence discoveries because they explain the final staged UI driver.”

    Action/result: Updated docs/src/compatibility_testing.md and appended dynamic save-write evidence to docs/src/clean_room_executable_notes.md.

  1830. Reported: “The clean-room notes now include the full trail: wrong filename assumption, path prompt, slot selector, final confirmation, and the parsed SG.1 envelope. I’m updating PROGRESS.md so the save/write part no longer looks purely static.”

    Action/result: Updated PROGRESS.md to list dynamic original-engine save-write evidence and leave restore round-trip/file-error UI as remaining work.

  1831. Reported: “I’m catching up the progress log for the save probe now. There were several useful failed attempts, and they matter because they map the real save UI sequence: path prompt, slot selector, description prompt, confirmation.”

    Action/result: Added progress-log entries for the dynamic save-write probe work.

  1832. Reported: “The save-write documentation and tracker updates are done. I’m doing a quick code/readability pass now, then I’ll run the full verification suite again.”

    Action/result: Ran a Python syntax check over the new save probe and reviewed the new test file.

  1833. Reported: “The new save tool/test are still untracked, so they did not appear in git diff --stat; I’m checking status and cleaning any py_compile cache if it appeared.”

    Action/result: Found untracked tools/save_roundtrip_probe.py and tests/test_save_roundtrip_probe.py, plus generated __pycache__ directories from py_compile.

  1834. Reported: “py_compile left __pycache__ directories behind. I’m removing only those generated Python cache directories; they aren’t project artifacts.”

    Action/result: Removed generated tools/__pycache__ and tests/__pycache__.

  1835. Reported: “The generated caches are gone. I’m wrapping the new test imports/long line next so the added test file matches the style of the surrounding suite.”

    Action/result: Wrapped long imports and a long generated-save assertion in tests/test_save_roundtrip_probe.py.

  1836. Reported: “With the style cleanup done, I’m running the full verification set again: all unit tests, opcode evidence, and mdBook. After that I’ll do whitespace/status checks.”

    Action/result: python3 -B -m unittest discover -s tests passed 162 tests; python3 -B tools/logic_opcode_evidence.py --check passed; and mdbook build docs passed.

  1837. Reported: “Full verification passed: 162 tests, opcode evidence check, and mdBook. I’m doing the final diff whitespace and status pass now.”

    Action/result: git diff --check passed. Tracked changes plus the new save probe/test remain uncommitted; generated build/ and 002962_ms_dos_622/ remain untracked.

  1838. Reported: “The final checks are clean. I’m adding the last verification/status entries to progress_log.md so the documentation trail is complete for this turn.”

    Action/result: Completed progress-log updates for the verification pass.

  1839. Reported: “I’ll stage only the tracked project files plus the two new save-probe source files, leaving build/ and the DOS installer images untracked. Then I’ll commit with a concise message for the harness/doc work.”

    Action/result: Checked status before staging the save-write and chunked carousel work.

  1840. Reported: “The untracked generated directories are exactly the usual build/ and installer images. I’m staging the seven modified files and the two new save-probe files now.”

    Action/result: Staged AGENTS.md, PROGRESS.md, docs, carousel harness changes, and the new save probe/tool test.

  1841. Reported: “Staged. I’m checking the staged summary once before committing, mainly to make sure no generated files slipped in.”

    Action/result: Staged diff check passed; only source/docs/tests were staged.

  1842. Reported: “The staged set is clean: 9 source/doc files, no generated artifacts. I’m creating the commit now.”

    Action/result: Created commit 9a314b1 with message Add save write probe and chunk picture carousel.

  1843. Reported: “Commit succeeded. I’m doing one final status check so I can give you the exact commit hash and what remains untracked.”

    Action/result: Confirmed only build/ and 002962_ms_dos_622/ remained untracked after the commit.

  1844. Reported: “I’ll pick up from the committed state and use PROGRESS.md to choose the next highest-value gap. Given the last commit closed the save-write side, I expect the next useful target to be either restore round-trip/file-error UI or renderer/resource sweep expansion, but I’ll let the tracker and existing notes steer it.”

    Action/result: Read PROGRESS.md and selected dynamic restore round-trip work as the next target.

  1845. Reported: “PROGRESS.md points straight at restore round-trip now. I’m going to extend the save probe rather than start from scratch: use the generated SG.1, build a restore fixture whose LOGIC.0 has the same byte layout except 0x7e instead of 0x7d, then drive the original restore selector and check that the restored continuation draws the same validation view.”

    Action/result: Added restore fixture and restore-mode scaffolding to tools/save_roundtrip_probe.py.

  1846. Reported: “The restore mode is patched in. Before running QEMU, I’m checking the new control-flow block carefully; this tool has enough staged input that a small indentation bug would waste a boot cycle.”

    Action/result: Focused save-roundtrip tests passed and the restore-mode code was reviewed.

  1847. Reported: “The focused tests still pass, and the restore mode reads cleanly. I’m adding a couple of small tests for the new restore fixture path before I spend a QEMU run on it.”

    Action/result: Added tests for restore action byte layout, stale save removal, and restore fixture save-copy behavior.

  1848. Reported: “The restore fixture tests are in. I’m running the focused test module, then I’ll try restore mode using the SG_007.1 save generated by the previous probe.”

    Action/result: python3 -B -m unittest tests.test_save_roundtrip_probe passed 6 tests; confirmed build/save-roundtrip/SG_007.1 exists.

  1849. Reported: “Focused tests pass and the generated save is present. I’m running restore mode now with the same staged path/slot/confirmation timing; if restore has a different confirmation shape, the capture will tell us.”

    Action/result: First restore QEMU run parsed the generated save but mismatched visually.

  1850. Reported: “Restore mode selected and parsed the save, but the validation comparison mismatched. I’m opening the capture now to see whether restore reached a UI screen, resumed at a different instruction, or restored a different visible state than the save-return validation screen.”

    Action/result: Capture showed the restore path prompt, not restored game state.

  1851. Reported: “The restore capture is still at the restore path prompt, with the default \RSVT path visible. So restore’s selector is slower to become input-ready than save’s selector; I’m rerunning with a longer path-prompt wait before the first Enter.”

    Action/result: Longer path-prompt wait still left the capture at the restore path prompt.

  1852. Reported: “Still mismatched after the longer wait. I’m checking the second restore capture to see whether it advanced past the path prompt or landed on another restore UI stage.”

    Action/result: Second capture was identical to the path-prompt screen.

  1853. Reported: “The restore prompt still doesn’t leave the path screen. One plausible source-backed explanation is that the selector is not finding a save under the filename pattern it expects, so it returns to the path prompt. I’m checking the restore fixture disk contents and then I’ll try the same generated save under the SQ2SG.1 stem.”

    Action/result: Confirmed the restore fixture contained SG.1; prepared an alternate-stem restore run.

  1854. Reported: “The restore fixture contains SG.1, so I’m testing the alternate stem explicitly: copy the same generated save into the restore fixture as SQ2SG.1 and see whether the original restore selector advances.”

    Action/result: Restore run with --save-stem SQ2SG matched with 0 visual mismatches.

  1855. Reported: “That worked: with the generated save copied in as SQ2SG.1, restore mode matched the validation screen with 0 mismatches. So the round-trip is now: save action writes SG.1 in the synthetic fixture; restore selector accepts the same bytes when staged as SQ2SG.1. I’m documenting that observed stem asymmetry carefully rather than smoothing it over.”

    Action/result: Added restore command guidance to AGENTS.md.

  1856. Reported: “AGENTS.md now has both save and restore commands. I’m updating the compatibility docs and PROGRESS.md next so the tracker reflects an actual restore round-trip, with the filename-stem caveat preserved.”

    Action/result: Updated compatibility docs and PROGRESS.md with dynamic restore evidence and the unresolved stem asymmetry.

  1857. Reported: “The compatibility docs and progress dashboard now show the restore probe as complete evidence, while keeping the filename-stem asymmetry as the next source question. I’m adding the detailed clean-room notes for the restore attempt/results now.”

    Action/result: Appended dynamic restore probe notes to docs/src/clean_room_executable_notes.md.

  1858. Reported: “I noticed the previous save-write section still ended by saying restore was future work. Since the next section now supplies that restore evidence, I’m correcting that transition so the docs don’t contradict themselves.”

    Action/result: Corrected the save-write section transition.

  1859. Reported: “I’m updating docs/src/progress_log.md for the commit and this restore pass now. The important bits are the failed SG.1 restore attempt, the successful SQ2SG.1 restore, and the unresolved stem question.”

    Action/result: Recorded commit and restore-probe progress entries.

  1860. Reported: “With restore evidence recorded, the new highest-value item is the stem asymmetry itself. I’m switching back to source-first mode now: inspect the selector/read-summary code that formats save filenames, then use QEMU only if the disassembly leaves a genuine ambiguity.”

    Action/result: Began source-first inspection of save filename formatting and slot summary filtering.

  1861. Reported: “The selector source confirms that both save and restore go through the same numbered-slot helper, which calls the filename formatter at 0x5b73. The stem question is probably in that formatter or its backing data, so I’m reading 0x5b73 and the nearby save-name string buffers now.”

    Action/result: Read formatter 0x5b73 and backing strings around 0x1327..0x135f.

  1862. Reported: “I’m continuing from the restore probe work. First I’m tightening the source evidence around the save-name formatter, because that stem mismatch is now the most useful loose thread in PROGRESS.md.”

    Action/result: Confirmed formatter string %s%s%ssg.%d.

  1863. Reported: “The formatter is already looking much less mysterious: it uses the format string %s%s%ssg.%d, so the slot filename is built from a directory string, a separator string, a prefix string, and the slot number. I’m checking the backing strings and the prefix initializer next, because that should tell us why one run wrote SG.1 while restore selected SQ2SG.1.”

    Action/result: Identified path/separator strings and the prefix argument as pointer DS:0x0002.

  1864. Reported: “The formatter’s third %s argument is a pointer to data offset 0x0002, not a hard-coded SQ2 string at the call site. That makes the asymmetry a runtime-data question: what initializes DS:0x0002, and why did our save and restore harnesses see different effective prefixes?”

    Action/result: Shifted investigation to initialization and consumers of DS:0x0002.

  1865. Reported: “I found the important source-level detail: the save slot list reader rejects files unless the final saved state block begins with the same string at DS:0x0002. Since DS:0x0002 is also the filename prefix used before sg.N, restore scanning is tied to that runtime prefix, not just to the file bytes being structurally valid.”

    Action/result: Read code.save.read_slot_summary at 0x8b9f, including the first-block signature compare against DS:0x0002.

  1866. Reported: “Aha, this project already has a source note for a verifier/helper that copies a logic message into DS:0x0002 and checks it against embedded SQ2. I’m reading that path now, because it may be both the game-signature check and the save filename prefix initializer.”

    Action/result: Re-read action 0x8f and helper 0x5b49; confirmed the SQ2 signature guard writes/checks DS:0x0002.

  1867. Reported: “That explains half the mismatch cleanly: our synthetic save fixture did not necessarily run the normal 0x8f signature action before saving, so an empty prefix naturally produces SG.1. The surprising half is the restore fixture’s SQ2SG.1 behavior, so I’m checking the generated fixture bytecode and launcher path instead of guessing.”

    Action/result: Confirmed the old generated fixture bytecode did not call 0x8f.

  1868. Reported: “The generated save/restore logic is intentionally tiny and does not call 0x8f; I hit a tool assumption while trying to disassemble the fixture directly, so I’m reading the local disassembler/resource helpers before deciding whether to add a small fixture disassembly path or inspect the bytes by hand.”

    Action/result: Inspected fixture VOL.3 bytes directly and confirmed the old save/restore payloads differed only by action byte.

  1869. Reported: “The fixture bytecode confirms no signature opcode: it draws picture 0, loads view 11, performs 0x7d or 0x7e, then draws the validation object. So if restore required SQ2SG.1, some earlier startup path or copied runtime state is setting DS:0x0002 before logic 0 runs.”

    Action/result: Rechecked launcher files and runtime setup as possible sources of prefix state.

  1870. Reported: “One more clue: the copied launcher is SIERRA.COM, but its embedded strings include _sq2.* and agidata.ovl; the batch file is present but probably unused by our harness. I’m narrowing the launch sequence and startup initialization now, because the prefix is probably set before our synthetic logic 0 gets control.”

    Action/result: Confirmed the harness launches SIERRA; no direct launcher conclusion was needed after later source/QEMU corrections.

  1871. Reported: “The selector source makes the restore result fit if DS:0x0002 == \"SQ2\" at selection time: it scans SQ2SG.N, then verifies the first seven bytes of the first saved state block against that same string. I’m rechecking the saved disk image now, because if save really only produced SG.1, then save and restore saw different prefix state and we need to know why.”

    Action/result: Verified old save_roundtrip_007 wrote only SG.1.

  1872. Reported: “The generated SG.1 state block starts with zero bytes, so the save run really did have an empty/zeroed DS:0x0002 when it wrote state. The successful restore from SQ2SG.1 means the restore run was also compatible with that zeroed state by the time it validated/drew, so I’m checking the report and capture timing before treating the stem behavior as a source rule.”

    Action/result: Found the old restore validation was visually ambiguous.

  1873. Reported: “There’s a subtle flaw in the current restore validation: the post-restore visual can also happen if the restore action simply returns to the following bytecode. I’m going to make the probe distinguish success from cancel/failure by saving one variable value and using a different pre-restore value in the restore fixture; then the final object position tells us whether state was actually restored.”

    Action/result: Planned a stronger X=50/X=90 restore oracle.

  1874. Reported: “I’m changing the fixture so the visual check is no longer just “did execution continue?” The save fixture stores marker X=50 in a byte variable; the restore fixture starts with X=90, and only a real restore should put X back to 50 before the final draw.”

    Action/result: Patched tools/save_roundtrip_probe.py to draw validation from variables.

  1875. Reported: “The fixture code is patched; I’m cleaning up the tests now so they assert the stronger restore/cancel distinction instead of the old immediate-draw shape.”

    Action/result: Updated focused save/restore fixture tests.

  1876. Reported: “I caught a small test-shape issue before running it: the marker assignment is followed by other setup assignments before the save/restore action, so the assertion should look for the assignment itself and the later action separately.”

    Action/result: Corrected the test assertions.

  1877. Reported: “The stronger fixture shape is in place. I’m running the focused save-probe tests first, then I’ll regenerate the save and rerun the restore cases so the QEMU evidence matches the new oracle.”

    Action/result: Focused tests.test_save_roundtrip_probe passed.

  1878. Reported: “Focused tests passed. I’m starting with a fresh save run now, because the old SG_007.1 was produced by the weaker fixture and can’t prove the restored-variable marker.”

    Action/result: Generated SG_008.1; it still wrote a blank-prefix save and matched the save-side visual check.

  1879. Reported: “The fresh save run matched and still wrote SG.1. I’m now running two restore variants against the stronger marker: first with the generated file staged as SG.1, then as SQ2SG.1, so we can tell whether either path truly restores state rather than merely continuing.”

    Action/result: SG.1 restore stayed mismatched.

  1880. Reported: “I checked the saved state block and initially used the absolute data offset without subtracting the block base. Correcting that, the marker variable is inside the saved first block as intended; I’m running the restore probes now.”

    Action/result: Confirmed saved validation variables include X=50.

  1881. Reported: “The SG.1 restore variant still mismatched, so it did not reach the restored marker. I’m running the SQ2SG.1 variant with the stronger variable marker now; this will tell us whether the earlier success was a real restore or just a continuation artifact.”

    Action/result: SQ2SG.1 restore drew the unrestored X=90 marker.

  1882. Reported: “Good, the stronger oracle exposed the old false positive: SQ2SG.1 no longer matches restored-state X=50. Its mismatch is much smaller, which likely means the action returned and drew the unrestored X=90 marker. I’m quantifying that against both expected positions.”

    Action/result: Compared captures against X=50 and X=90; SQ2SG.1 matched X=90 exactly.

  1883. Reported: “The image conversions are done; the comparison script is still crunching a full-frame Python comparison because that path is slower than I expected. I’m polling it now, then I’ll fold the result back into the docs and tracker.”

    Action/result: Comparison completed and confirmed the X=90 false positive.

  1884. Reported: “The stronger comparison is decisive: the SQ2SG.1 run drew the unrestored X=90 marker exactly, so the previous restore “match” was a false positive. I’m checking the captures and slot-selection source now to see whether the file is rejected during candidate scanning or whether our key timing is causing a cancel path.”

    Action/result: Inspected captures and returned to selector source.

  1885. Reported: “The clean way forward is to make the fixture behave like normal SQ2 logic: call 0x8f verify_game_signature with a local SQ2 message before save/restore. That initializes DS:0x0002, which source shows is both the filename prefix and the saved-state signature, so I’m updating the harness default to use SQ2SG.N and keeping the stronger variable oracle.”

    Action/result: Patched the harness to call 0x8f("SQ2") and default to SQ2SG.

  1886. Reported: “The harness now calls 0x8f and defaults to SQ2SG. I’m adding test assertions for the signature action so this doesn’t accidentally regress back to the ambiguous no-prefix fixture.”

    Action/result: Added test assertions for 0x8f 01.

  1887. Reported: “The signature assertions are in; I’m rerunning the focused tests and then the QEMU save/restore pair with the corrected default stem.”

    Action/result: Focused tests passed.

  1888. Reported: “Focused tests pass again. I’m generating a new signed-prefix save now; if the source interpretation is right, this one should be named SQ2SG.1 and its first state block should begin with SQ2.”

    Action/result: Generated SQ2SG_009.1; save block began SQ2\0.

  1889. Reported: “That worked: the corrected fixture wrote SQ2SG.1. I’m checking the saved prefix bytes and then immediately using that file for a restore run with the variable-position oracle.”

    Action/result: Confirmed SQ2SG.1, block lengths, prefix bytes, and validation variables.

  1890. Reported: “The saved block now begins SQ2\0, and the marker variable is saved as X=50. I’m running the restore with SQ2SG.1; this should only match if the original engine actually restores the saved variable state.”

    Action/result: First signed-prefix restore remained at the path prompt.

  1891. Reported: “The signed-prefix restore still did not match, so the remaining problem is not just the filename/signature. I’m opening the capture now; then I’ll adjust the harness around the selector flow rather than changing the spec based on a failed interaction.”

    Action/result: Capture showed the restore path prompt.

  1892. Reported: “The capture is still at the path prompt, so this specific run simply missed or failed the path-entry Enter. Since the save side used the same line-editor path successfully, I’m rerunning restore with a longer path-prompt delay before drawing any conclusion from it.”

    Action/result: Longer delay still did not complete restore.

  1893. Reported: “Longer delay did not solve it. I’m checking whether the path validator is rejecting the default current directory in restore mode, then I’ll either feed an explicit path string or adjust the fixture to bypass the path prompt using source-supported state.”

    Action/result: Re-read path/selector source.

  1894. Reported: “The selector source confirms that when restore finds zero valid candidates and no saved-description filter, it displays a “no games to restore” message and returns zero. Since our capture remains at the path edit itself, I’m checking the key injection helper and trying an explicit path/Enter sequence next.”

    Action/result: Inspected QEMU monitor key injection and restore fixture bytes.

  1895. Reported: “The fixture bytes look right: 0x8f 01, marker X=90 before restore, then variable draw. I’m going to try a deliberately redundant Enter sequence through the path/slot prompts; if that moves past the prompt, it confirms this is a harness timing/input issue rather than a resource or source-semantics issue.”

    Action/result: Initial redundant-Enter run hit a sandboxed VNC bind failure.

  1896. Reported: “That attempt hit the sandboxed VNC bind rather than engine behavior. I’m rerunning the same QEMU restore command outside the sandbox so the emulator can bind its local display socket.”

    Action/result: Rerun completed and drew the X=90 failure path.

  1897. Reported: “The redundant keys moved past the path prompt but still drew X=90, so restore did not load the saved variable state. I’m comparing that capture to X=50/X=90 and then going back to the restore handler source around the open/read/return paths.”

    Action/result: Confirmed the capture matched X=90 exactly.

  1898. Reported: “I noticed one of the restore-handler disassemblies was shifted by using the wrong executable-header skip. I’m rerunning that source read with the correct image+0x200 skip before drawing conclusions from those addresses.”

    Action/result: Correctly disassembled restore action at 0x2512.

  1899. Reported: “The restore handler source explains the oracle problem: a successful restore returns zero and ends the current logic stream, so code immediately after 0x7e is a failure/cancel path, not a success path. I’m changing the fixture again: save will set a flag plus marker variables, and restore logic will draw the success marker only when the restored flag is present on the next cycle.”

    Action/result: Planned the final restored-flag branch oracle.

  1900. Reported: “That patch missed the exact import layout. I’m reading the top of the file and applying the same change against the current shape.”

    Action/result: Reapplied the restored-flag branch patch successfully.

  1901. Reported: “The restore fixture now has a “restored state” branch at the top, so its payload is no longer the same length as the save fixture. I’m updating the tests to assert the branch and the failure marker separately.”

    Action/result: Updated focused tests for the restored-flag branch.

  1902. Reported: “The tests now describe the intended restore oracle: save sets the restored marker flag, and restore has a top-level branch for that flag. I’m running them before regenerating the save again.”

    Action/result: Focused tests passed.

  1903. Reported: “Focused tests pass. I’m generating a new save with the restored-state flag included, then I’ll run restore against that save.”

    Action/result: Generated SQ2SG_010.1, matching the save-side visual check.

  1904. Reported: “The new save wrote and matched. I’m checking the saved flag/variable bytes, then restoring with the redundant prompt keys because that was the sequence that reliably moved through the selector.”

    Action/result: Confirmed saved X variable was 50; noted the flag is packed rather than a direct byte slot.

  1905. Reported: “The saved X variable is definitely 50; the flag lives in a packed flag area rather than a one-byte slot, so that quick byte check was not meaningful. I’m running the restore now; the branch itself will be the real flag proof.”

    Action/result: First restore run was blocked by sandboxed VNC bind.

  1906. Reported: “The sandbox blocked the VNC socket again; I’m rerunning the same restore probe outside the sandbox.”

    Action/result: restore_roundtrip_sq2stem_006 matched with 0 visual mismatches, proving actual restored state through the restored flag and variables.

  1907. Reported: “Now we have the real restore round trip: signed-prefix save writes SQ2SG.1, the saved block starts with SQ2, and the restore probe only matches after the restored flag/variable branch draws X=50. I’m updating the docs and tracker to replace the earlier ambiguous restore note with this stronger evidence.”

    Action/result: Began doc/tracker updates for the corrected restore evidence.

  1908. Reported: “I’ve got the documentation targets. I’m going to update them in one pass: AGENTS commands, compatibility evidence, clean-room notes, executable/source spec, symbolic data labels, PROGRESS, and the progress log.”

    Action/result: Updated AGENTS.md and compatibility docs with the signed-prefix save/restore commands.

  1909. Reported: “The historical notes now preserve the false start and the corrected oracle. Next I’m tightening the implementation-facing source description: filename prefix, slot signature filtering, and restore-success continuation.”

    Action/result: Updated docs/src/clean_room_executable_notes.md and docs/src/agi_executable.md.

  1910. Reported: “I’m adding the stable labels for this now: the slot filename formatter and the DS:0x0002 signature/prefix buffer are important for future cross-version comparisons.”

    Action/result: Added symbolic labels for code.save.format_slot_filename and data.save.signature_prefix_0002.

  1911. Reported: “The symbol map is updated. I’m removing the stem asymmetry from the “highest value” queue now, because source plus the corrected QEMU run explain it: blank 0x0002 produced the old SG.1, while 0x8f(\"SQ2\") produces and validates SQ2SG.1.”

    Action/result: Updated PROGRESS.md; next save/restore item is a representative file-error UI probe.

  1912. Reported: “PROGRESS.md now points at file-error UI as the next save/restore task. I’m adding one short implementation-facing note to the runtime model so the DS:0x0002 prefix/signature rule is visible outside the low-level executable chapter.”

    Action/result: Added the save filename/signature prefix row to docs/src/runtime_model.md.

  1913. Reported: “I’m resuming from the PROGRESS-guided thread and picking up the file-error UI probe work first. I’ll keep this source-led and use QEMU as the representative observable check once the fixture is in place.”

    Action/result: Confirmed the tree was clean apart from generated artifacts and selected the save/restore file-error probe from PROGRESS.md.

  1914. Reported: “I’ve verified the tree is clean apart from generated inputs/artifacts, and the current tracker really does point to save/restore failure behavior as the next high-value gap. I’m patching the existing save-roundtrip harness rather than creating a one-off script, so the evidence stays reusable for later interpreter versions.”

    Action/result: Inspected tools/save_roundtrip_probe.py, tests/test_save_roundtrip_probe.py, and the existing source-backed save/restore docs.

  1915. Reported: “The fixture shape is now clear from the source path: a truncated save can still be listed by the restore selector if its 31-byte description and first seven signature bytes look right. The actual restore then asks the block reader for the full first block and trips the documented read-error path.”

    Action/result: Added restore-read-error fixture support to tools/save_roundtrip_probe.py.

  1916. Reported: “The harness now has a first-class restore-read-error mode and unit coverage for the malformed-but-selector-visible save envelope. I’m running the focused tests before spending QEMU time on it.”

    Action/result: python3 -B -m unittest tests.test_save_roundtrip_probe passed with 8 tests.

  1917. Reported: “The source-backed fixture is ready, and the narrow test suite is green. I’m launching the original engine with that fixture now; if the local VNC bind is sandboxed again, I’ll rerun the same command with approval escalation.”

    Action/result: Sandboxed QEMU launch failed to bind the local VNC socket, as expected.

  1918. Reported: “As expected, the sandbox blocked QEMU’s VNC socket, not the probe itself. I’m rerunning the exact same original-engine check outside the sandbox so we can get the capture.”

    Action/result: The broad-key restore-read-error probe completed, but the capture showed DOS because redundant Enters dismissed the fatal dialog.

  1919. Reported: “The original-engine run completed and produced a stable capture: the 40-byte save fixture was accepted by the selector, then the restore read failed on the declared 1505-byte first block. I’m converting and inspecting the image so the docs can record exactly what was observed.”

    Action/result: Converted and inspected restore_read_error_001; the image showed the final DOS prompt rather than the error dialog.

  1920. Reported: “The first capture landed back at DOS, which is useful but not the UI evidence I wanted. I’m tightening the capture timing now to see whether the engine displays the restore-read error briefly before terminating, or whether this path goes straight through cleanup too quickly for a static end-state screenshot.”

    Action/result: A short final capture still landed at DOS, indicating the key sequence rather than the wait duration needed correction.

  1921. Reported: “The short capture still shows DOS, which suggests the failure path exits before the current harness’s final screenshot point. I’m going to trace the prompt timing with intermediate screenshots rather than guess from the final state.”

    Action/result: Started one-key-at-a-time restore UI timing captures.

  1922. Reported: “I’m narrowing where the interaction actually is: first I’ll capture the restore prompt before sending any keys, then I’ll advance one key at a time if needed. That should separate “we missed a brief error” from “the prompt sequence is different for this failure fixture.””

    Action/result: Captured the restore directory prompt with the default fixture directory in the input field.

  1923. Reported: “Good, the first prompt is visible and waiting for the restore directory. The default path field is the fixture directory, so I’m sending a single Enter next and capturing before any slot-selection keys.”

    Action/result: Captured the selector listing the truncated save as codex probe.

  1924. Reported: “The selector lists the truncated save as expected, which proves the malformed file passed the source-backed signature scan. I’m sending the slot-selection Enter next and capturing immediately after that transition.”

    Action/result: Captured the restore confirmation dialog naming \rera\sq2sg.1.

  1925. Reported: “After slot selection, the engine shows the confirmation dialog with the truncated save’s filename. I’m now using the exact one-Enter-per-stage sequence; this avoids the earlier extra keys that were spilling into DOS after the fatal restore path exited.”

    Action/result: Captured the restore-read error dialog: Error in restoring game. Press ENTER to quit.

  1926. Reported: “That nailed it: with exactly one Enter at directory, slot, and confirmation, the screenshot is the restore failure dialog: “Error in restoring game. Press ENTER to quit.” I’m doing one stable timed run now with a normal wait, then I’ll fold the command and hashes into the docs and tracker.”

    Action/result: Stable 8-second capture restore_read_error_002.ppm matched the quick dialog capture with RGB SHA-256 556971f26fc34deb32497a9d10c08eedeb28f6bdb0957cd7676a8ef26830849c.

  1927. Reported: “The stable run matches the quick capture exactly: same hash and same dialog geometry after an 8-second wait, so this failure dialog is persistent until Enter. I’m updating the reusable commands, evidence notes, compatibility chapter, and PROGRESS.md now.”

    Action/result: Updated AGENTS.md, compatibility notes, clean-room executable notes, and PROGRESS.md for the restore-read-error probe.

  1928. Reported: “The capture sequence also documents the UI lifecycle: directory prompt, save selector row, restore confirmation, then the fatal restore-read dialog. I’m making the docs reflect that nuance because it matters for compatibility tests.”

    Action/result: Added prompt-sequence details and the stable capture hash to docs/src/compatibility_testing.md and docs/src/clean_room_executable_notes.md.

  1929. Reported: “The compatibility command should use single Enter keys, not the broader redundant key sequence used for the success restore. I’m recording that explicitly so future runs don’t accidentally advance past the error dialog into DOS.”

    Action/result: Added the single-Enter restore-read-error command to AGENTS.md.

  1930. Reported: “I’m also updating PROGRESS.md so the dashboard stops advertising this as remaining work. The next queue item after this will be graphics/view compatibility and spec polish unless the verification pass uncovers a regression.”

    Action/result: Removed the representative file-error UI probe from the highest-value remaining-work list.

  1931. Reported: “The tracker is updated: the file-error UI probe has moved from “remaining” to evidence. I’m adding the historical log entries for the QEMU attempts and then I’ll run the full verification suite for these harness/docs changes.”

    Action/result: Completed progress-log entries through the stable restore-read-error capture.

  1932. Reported: “The file-error work is documented and logged. I’m running the standard local verification stack now: unit tests, opcode evidence check, mdBook build, and whitespace diff check.”

    Action/result: Verification passed: 166 unit tests, opcode evidence check, mdBook build, and git diff --check.

  1933. Reported: “Verification is clean: 166 unit tests passed, opcode evidence check passed, mdBook built, and git diff --check found no whitespace issues. I’m checking the resulting diff now, then I’ll continue down the next PROGRESS.md item.”

    Action/result: Reviewed the diff and cleaned up long import/test lines.

  1934. Reported: “Readability cleanup is done. I’m rerunning the same verification commands so the current working tree, not just the previous one, is known good.”

    Action/result: Verification passed again with the same command set.

  1935. Reported: “The refreshed verification pass is clean again: 166 tests, opcode evidence, mdBook, and diff whitespace all pass. I’m moving to the next remaining item in PROGRESS.md, which is picture/view renderer compatibility work.”

    Action/result: Re-read the graphics/view/object coverage and identified that pattern and object-overlay edge cases are already broadly covered.

  1936. Reported: “The first remaining item is explicitly optional and already says those opcodes are covered unless a representative dynamic fixture is worth adding. I’m treating the concrete next work as graphics compatibility: source/test review first, then one focused edge-case addition rather than random probing.”

    Action/result: Inspected picture fuzz, renderer tests, and current picture/view tracker entries.

  1937. Reported: “The picture side already has broad real-resource parity; the remaining useful work is the thin edge around valid synthetic streams. I’m looking at the renderer and fuzz corpus together so the next addition is source-aligned and testable.”

    Action/result: Re-read pattern renderer tests, base fuzz cases, and related source-backed documentation.

  1938. Reported: “One candidate edge is random pattern plotting state: it has both a seed byte and per-plot mask logic, and those semantics are easy to accidentally model incorrectly. I’m checking the disassembly around the pattern handler before adding or changing any fixture.”

    Action/result: Disassembly at 0x64ff..0x6602 confirmed the existing pattern-mode and random-seed model already matches documented tests and QEMU coverage.

  1939. Reported: “The pattern/channel cases are already QEMU-covered, including the base_027..029 channel-mask trio. I’m shifting to the view/object side of the same graphics item, where the tracker still calls out priority/control combinations and placement semantics.”

    Action/result: Inspected tools/view_batch.py, tests/test_view_batch.py, and compatibility notes for view/object coverage.

  1940. Reported: “The view batch already covers clipping and transparency stress, while object overlay probes carry the actual priority/control visibility semantics. I’m reading that harness next; it looks like the best place to add a focused priority-band fixture if there’s a real gap.”

    Action/result: Confirmed the object overlay harness already covers threshold pairs, low/high nibble behavior, auto-priority rebuilds, persistent objects, and selected group/frame offsets.

  1941. Reported: “The object overlay suite is already broader than the tracker wording: it has threshold pairs, low/high nibble priority checks, auto-priority rebuilds, persistent objects, and selected group/frame offsets. Rather than duplicate that, I’m taking the next concrete tracker item: make save/file selection more implementation-ready in the spec.”

    Action/result: Switched from adding duplicate graphics cases to improving the save/file selector spec.

  1942. Reported: “The save section has the facts, but it is still compressed into a few table rows. I’m going back to the selector disassembly and the existing source notes, then I’ll turn that into an explicit implementation-facing state machine.”

    Action/result: Re-read selector/path/slot disassembly around 0x85e5, 0x8705, 0x8814, and 0x8b9f.

  1943. Reported: “The disassembly confirms the selector is a small UI state machine around path editing, slot scanning, list interaction, optional save-description editing, and caller-side file I/O. I’m adding that model now, with the uncertain internals kept out of the normative contract.”

    Action/result: Added a save/restore selector state-machine table to docs/src/runtime_model.md.

  1944. Reported: “The runtime model now has a selector state machine instead of just a compact data row. I’m updating the dashboard to reflect that save/file selection has moved forward, then I’ll verify the docs build again.”

    Action/result: Updated PROGRESS.md to remove save/file selection from the remaining implementation-ready state-machine examples.

  1945. Reported: “The remaining spec-polish examples are now sound hardware output, heap initialization, and menu movement/event delivery. I’m adding the corresponding progress-log entries and then running the documentation checks.”

    Action/result: Ran mdbook build docs and git diff --check; both passed.

  1946. Reported: “The latest docs build and whitespace check pass. The remaining implementation-spec examples are now sound hardware output, heap initialization, and menu movement/event delivery; I’m taking heap initialization next because it is most likely to be source-complete without fragile hardware/QEMU behavior.”

    Action/result: Began heap initialization source review.

  1947. Reported: “The heap notes cover allocation/reset well, but initialization is still thin. I’m searching for the startup writes to the heap globals rather than inferring them from the later allocator helpers.”

    Action/result: Found writes to heap globals around raw/image offsets 0x1644, 0x1669, 0x1696, and 0x4420..0x4431.

  1948. Reported: “The byte search found startup writes to the heap globals around raw offsets 0x1644, 0x1669, 0x1696, and 0x4420..0x4431. I’m disassembling those local regions now to see which are true initialization sites versus later helper writes.”

    Action/result: Disassembly showed 0x1644, 0x1669, and 0x1696 are helper writes, while startup memory allocation at 0x43ea..0x4431 seeds heap current/base/limit.

  1949. Reported: “The startup allocation path is source-backed now: DOS AH=48h returns a memory segment, the interpreter converts it into a DS-relative byte offset, seeds heap current/base from that, and computes the limit from the requested paragraph count. I’m documenting that as the missing heap-initialization contract.”

    Action/result: Added code.startup.allocate_runtime_memory and clarified heap global labels in docs/src/symbolic_labels.md.

  1950. Reported: “The runtime model and symbol map now explain where heap base/current/limit come from, not just how later allocation uses them. I’m adding the clean-room evidence note with the exact searches and disassembly observations.”

    Action/result: Added a heap startup initialization source-pass section to docs/src/clean_room_executable_notes.md.

  1951. Reported: “The clean-room notes now show the exact startup allocator evidence. I’m updating PROGRESS.md so heap initialization is no longer listed as an open implementation-spec item.”

    Action/result: Updated PROGRESS.md; heap initialization is now evidence, leaving only optional observable out-of-memory UI behavior for the memory subsystem.

  1952. Reported: “Docs and whitespace are clean. I’m moving to sound hardware output next, but I’ll keep it source-first: identify what the interpreter hands to the hardware driver, and avoid trying to declare PC-speaker electrical behavior unless the executable itself makes it clear.”

    Action/result: Began source-first sound driver output review.

  1953. Reported: “The sound model already covers stream parsing and scheduling; the gap is the low-level write helpers. I’m disassembling driver_write_tone and driver_write_attenuation now to decide what can be specified portably.”

    Action/result: Disassembled the sound driver start/tick/stop/tone and attenuation write helpers around raw/image regions 0x81a0..0x83f6.

  1954. Reported: “The driver output path is now clearer: PC-speaker-like selectors use PIT ports 0x43/0x42/0x61, while other selectors write encoded bytes to port 0xc0. I’m going to capture the portable part in code/tests too: the source-backed PC-speaker divisor formula.”

    Action/result: Added pc_speaker_divisor() and pc_speaker_event_enabled() to tools/agi_sound.py.

  1955. Reported: “I added a small source-backed helper for the PC-speaker divisor formula and the simple attenuation gate. That gives the spec a tested foothold for hardware output without pretending we have full audible synthesis yet.”

    Action/result: Added a sound-resource unit test for sound 1’s first event divisor 10560 and its silent attenuation nibble.

  1956. Reported: “The sound-resource tests now include the hardware-facing divisor/gate check. I’m running that focused suite before updating the spec text.”

    Action/result: python3 -B -m unittest tests.test_sound_resources passed with 10 tests.

  1957. Reported: “The focused sound tests pass with 10 tests. I’m updating the sound runtime model now: event stream semantics, PC-speaker divisor formula, silence gate, and the separate port-0xc0 path for other hardware selectors.”

    Action/result: Updated docs/src/runtime_model.md with the hardware-output driver-interface model.

  1958. Reported: “The runtime model now distinguishes portable sound semantics from hardware port writes. I’m recording the driver-output source pass in the clean-room notes with the disassembly ranges and the new test coverage.”

    Action/result: Added a sound hardware-output source-pass section to docs/src/clean_room_executable_notes.md.

  1959. Reported: “The evidence note captures what the port writers do without turning it into an overbroad audio spec. I’m tightening the symbol-map descriptions for the two sound driver helpers to preserve the same cross-version labels.”

    Action/result: Updated code.sound.driver_write_tone and code.sound.driver_write_attenuation notes in docs/src/symbolic_labels.md.

  1960. Reported: “The symbol map now has the port-writer details attached to the existing labels. I’m updating the compatibility chapter and tracker next so sound hardware output is no longer listed as an open spec-polish example.”

    Action/result: Updated compatibility text and PROGRESS.md for the source-backed sound hardware-output model.

  1961. Reported: “The highest-value spec-polish queue is down to menu movement/event delivery. I’m logging the sound-output work and then running the focused sound tests plus docs checks again.”

    Action/result: Finished the sound-output evidence updates and prepared for verification.

  1962. Reported: “The sound work is logged. Since this touched code and docs, I’m running the full local verification stack again, not just the focused sound suite.”

    Action/result: Ran the full verification stack for the sound changes.

  1963. Reported: “Full verification is clean: 167 tests now pass, opcode evidence passes, mdBook builds, and diff whitespace is clean. I’m moving to the last named implementation-spec item: menu movement/event delivery.”

    Action/result: Confirmed the last full verification pass and switched to menu interaction analysis.

  1964. Reported: “I’m picking up from the verified sound-output pass and moving into the remaining menu interaction item in PROGRESS.md. First I’m re-reading the existing menu notes and labels so the next edits are anchored in the disassembly trail, not just the test harness history.”

    Action/result: Re-read menu opcode prose, existing clean-room notes, symbolic labels, compatibility notes, and PROGRESS.md.

  1965. Reported: “The existing menu chapter already has the core dispatch table, so the gap is not “what does each arrow do?” so much as “what would an implementer build from this?” I’m going to turn that into a runtime state-machine description and then reassess PROGRESS.md for the next highest-value item.”

    Action/result: Compared the existing menu evidence against docs/src/runtime_model.md and identified the missing implementation model.

  1966. Reported: “For the menu work I’m doing one source reread of code.menu.interact itself before editing. The documentation already says the dispatch table result; I want the state-machine text to reflect the actual loop shape and persistence points.”

    Action/result: Disassembled the menu setup and interaction regions and rechecked the local AGIDATA raw-key movement table.

  1967. Reported: “The source reread confirms the useful implementation shape: menu setup owns circular heading/item lists, interaction is a modal event loop, and selection only fires on Enter if the current item’s enable word is nonzero. I’m adding that as a data model plus lifecycle, with the failed QEMU arrow probe still treated as a test gap rather than a spec blocker.”

    Action/result: Added menu/list data-model and interaction-lifecycle tables to docs/src/runtime_model.md.

  1968. Reported: “The runtime model now has the menu lifecycle in implementer-facing form. I’m tightening the tracker and symbolic label file next so future cross-version work has stable names for the newly documented helper/state fields.”

    Action/result: Added code.menu.remember_item_and_restore_rect plus menu saved-rectangle globals to docs/src/symbolic_labels.md.

  1969. Reported: “Tiny correction while editing the label map: the existing navigation row uses “last item” for movement value 4, so I’m patching against the actual current text.”

    Action/result: Applied the symbolic-label update against the current table text.

  1970. Reported: “The symbol map has the helper and rectangle globals now. I’m updating PROGRESS.md so menu movement is marked as implementation-specified from source, while leaving arrow-key dynamic validation as an optional compatibility-suite gap.”

    Action/result: Updated PROGRESS.md and docs/src/compatibility_testing.md to reflect source-backed menu movement semantics and remaining optional dynamic validation.

  1971. Reported: “The menu item is now closed at the spec level: source-backed lifecycle, labels, tracker, and compatibility notes are aligned. I’m running the docs checks for this docs-only pass, then I’ll pick the next item from PROGRESS.md.”

    Action/result: mdbook build docs, git diff --check, and python3 -B tools/logic_opcode_evidence.py --check all passed.

  1972. Reported: “The menu docs pass is clean: mdBook builds, opcode evidence still checks, and whitespace is clean. Next I’m moving to the first concrete remaining renderer item: picture/view compatibility and implementation-ready edge semantics.”

    Action/result: Began reviewing picture/view renderer documentation and test coverage against PROGRESS.md.

  1973. Reported: “One search was noisy because I asked for a non-existent chapter name and rg obediently threw the whole kitchen at me. The useful signal is in graphics_object_pipeline.md, so I’m narrowing to the renderer/model sections now.”

    Action/result: Re-read the graphics pipeline and compatibility sections covering picture fuzz, view rendering, and object overlay coverage.

  1974. Reported: “The renderer docs show a good next target: SQ2 real pictures never use corner-path commands 0xf4/0xf5, so they’re easy to under-specify unless synthetic fixtures cover them. I’m inspecting the fuzz corpus generator and tests to see whether those paths are already pinned down or need curated cases.”

    Action/result: Confirmed existing base cases already cover 0xf4 and 0xf5 and that QEMU evidence exists for the safe base cases through base_020.

  1975. Reported: “Corner paths are already in the base corpus and have been through the “all safe base cases through base_020” QEMU batch. The more useful next bit is to add explicit implementation tests for the source-described command termination behavior and channel interleavings around those paths.”

    Action/result: Chose command-byte scanner-resume as the next picture compatibility expansion.

  1976. Reported: “I’m going to add three curated, safe picture fuzz cases around command-byte termination and scanner resume. These are the sort of edge cases a future engine can get wrong even when real SQ2 pictures happen not to stress them.”

    Action/result: Added base_030_line_pair_command_resume, base_031_corner_command_resume, and base_032_fill_command_resume to tools/picture_fuzz.py.

  1977. Reported: “The new corpus entries are in place. I’m adding focused local assertions so the Python renderer’s scanner behavior is locked down independently of QEMU.”

    Action/result: Added local renderer and fuzz-corpus tests for the three new command-resume cases.

  1978. Reported: “The local tests now pin the three scanner-resume contracts: incomplete coordinate pair, corner path, and seed-fill point list. I’m running the focused graphics/fuzz suites before asking QEMU for the original-engine comparison.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering tests.test_picture_fuzz passed with 51 tests; regenerated the fuzz corpus with 1,057 cases and 1,055 safe for QEMU.

  1979. Reported: “Focused local tests pass, and the regenerated corpus now has 1,057 cases with 1,055 marked safe for QEMU. I’m running just the three new curated cases through the snapshot harness so this becomes original-engine evidence, not only a local assertion.”

    Action/result: Started QEMU snapshot batch command_resume_001.

  1980. Reported: “QEMU is running the three-case snapshot batch now. This is one of the places where the snapshot path earns its keep: one boot, three renderer edge cases.”

    Action/result: QEMU completed command_resume_001 with 3 matches, 0 mismatches, and 0 errors.

  1981. Reported: “The QEMU batch matched all three new cases with zero mismatches. I’m folding that evidence into the docs and tracker, including the updated corpus counts.”

    Action/result: Updated docs/src/graphics_object_pipeline.md, docs/src/compatibility_testing.md, docs/src/clean_room_executable_notes.md, and PROGRESS.md with command-resume evidence and corpus counts.

  1982. Reported: “The graphics chapter and compatibility chapter now record the scanner-resume evidence, and PROGRESS.md reflects the expanded fuzz corpus. I’m updating the progress log before running the broader verification stack.”

    Action/result: Updated this progress log for the menu and picture scanner-resume work.

  1983. Reported: “The log is caught up through the QEMU batch. Since this touched code, tests, and docs, I’m running the full local verification stack now.”

    Action/result: python3 -B -m unittest discover -s tests passed with 171 tests; python3 -B tools/logic_opcode_evidence.py --check, mdbook build docs, and git diff --check also passed.

  1984. Reported: “Full verification is clean after the scanner-resume expansion: 171 tests, opcode evidence, mdBook, and diff whitespace all pass. I’m logging that and then moving to the next renderer-suite item: whether the view/object sweeps can use the faster carousel strategy too.”

    Action/result: Recorded the verification result and began reviewing the existing view/object batch harnesses for possible carousel reuse.

  1985. Reported: “The existing picture carousel already solved the “one engine process, many resources” problem for pictures. I’m comparing it with the current view batch harness to see whether a view carousel can be built without disturbing the simpler reference snapshot tests.”

    Action/result: Re-read tools/view_batch.py, tools/picture_carousel.py, and the view-batch tests.

  1986. Reported: “A view carousel is feasible without replacing the existing view batch harness: a generated logic script can refresh the picture, load the next view, draw one transient object, wait a fixed number of cycles, then move on. I’m adding that as a separate timed/poll harness so the current per-case snapshot batch stays as the simple reference oracle.”

    Action/result: Added view_carousel_case_actions and view_timed_carousel_logic_payload to tools/qemu_fixture.py.

  1987. Reported: “The fixture generator now has a generic “view timed carousel” logic payload. Next I’m adding the packed fixture builder so each carousel directory carries only the needed pictures and views in VOL.3.”

    Action/result: Added build_view_timed_carousel_fixture, including selected picture/view packing and PICDIR/VIEWDIR patching.

  1988. Reported: “The packed fixture builder is in place. I’m adding unit tests around the emitted bytecode and packed directory entries before writing the QEMU runner.”

    Action/result: Added fixture tests for view-carousel case actions, timed logic, and packed picture/view records.

  1989. Reported: “The fixture-level tests now cover the view carousel payload and packed PICDIR/VIEWDIR layout. I’m adding the actual view_carousel.py runner, modeled on the timed polling picture carousel.”

    Action/result: Added tools/view_carousel.py.

  1990. Reported: “The new runner is in place. I’m adding lightweight tests for case conversion, chunk naming, report summaries, and mocked carousel execution so regressions get caught without launching QEMU.”

    Action/result: Added tests/test_view_carousel.py.

  1991. Reported: “The tests are written. I’m checking the comparison dataclass shape, then I’ll run the focused fixture/carousel tests and fix anything the type/constructor assumptions missed.”

    Action/result: Checked PictureCaptureComparison and corrected the new test constructor.

  1992. Reported: “Good catch: the capture comparison dataclass is simpler than I first assumed, so the test is patched. I’m running the focused fixture, view-batch, and carousel tests now.”

    Action/result: python3 -B -m unittest tests.test_qemu_fixture tests.test_view_batch tests.test_view_carousel passed with 48 tests.

  1993. Reported: “The focused local tests pass. I’m running a tiny real QEMU smoke for the new view carousel next: two view cases in one engine process, polled against the existing local comparison model.”

    Action/result: Initial sandboxed QEMU run failed because VNC socket bind was not permitted.

  1994. Reported: “The smoke run hit the sandbox on QEMU’s local VNC bind, not a harness bug. I’m rerunning that exact view-carousel command with approval so QEMU can open its local display socket.”

    Action/result: Approved rerun of tools/view_carousel.py matched both smoke cases with 0 mismatches.

  1995. Reported: “The two-case view carousel smoke matched QEMU. Since the harness is now proven, I’m going straight to the base eight view cases from one engine process; that gives us useful suite evidence instead of just a toy smoke.”

    Action/result: Started view_carousel_base_001.

  1996. Reported: “The base view carousel is halfway through and the first four captures matched. I’m waiting on the remaining placement and priority cases.”

    Action/result: view_carousel_base_001 completed with 8 matches, 0 mismatches, and 0 errors.

  1997. Reported: “The full base view carousel matched all eight cases from a single engine process. I also noticed the docs still mention an older “17 total” stress count while the current base-plus-stress list is 19, so I’m checking and correcting that while I document the new carousel.”

    Action/result: Confirmed base_cases() has 8 entries and stress_cases() has 11 entries, for 19 total current view cases.

  1998. Reported: “The current registry is 8 base cases plus 11 stress cases, 19 total. Before I change the text, I’m going to see whether the new carousel can handle all 19 in one process; if it does, that is better evidence than merely correcting the count.”

    Action/result: Started view_carousel_stress_001.

  1999. Reported: “The 19-case carousel is running; the first four matched. I’m letting it continue through the edge placements and larger transparent-color cels.”

    Action/result: Continued the 19-case QEMU run.

  2000. Reported: “The base eight and the first two stress cels have matched. The carousel is still progressing cleanly, so I’m waiting for the remaining nine stress cases.”

    Action/result: Continued the 19-case QEMU run through case 10.

  2001. Reported: “Sixteen of nineteen have matched. Only the last three larger/transparent stress cases remain; this is looking like the right fast path for future view sweeps.”

    Action/result: Continued the 19-case QEMU run through case 16.

  2002. Reported: “All nineteen poll comparisons matched; I’m just waiting for the process to print the final summary and exit cleanly.”

    Action/result: view_carousel_stress_001 completed with 19 matches, 0 mismatches, and 0 errors.

  2003. Reported: “The full 19-case view carousel matched from one engine process. I’m documenting the new tool, the base and stress commands, and cleaning up the stale 17-case wording.”

    Action/result: Started documentation updates for tools/view_carousel.py and the corrected view-suite counts.

  2004. Reported: “I found the stale count in the compatibility chapter and PROGRESS.md. I’m patching those now and adding tools/view_carousel.py to the QEMU workflow notes so future agents use the faster path.”

    Action/result: Updated AGENTS.md.

  2005. Reported: “AGENTS.md now has the view carousel command. I’m updating the compatibility narrative to distinguish the snapshot oracle from the new one-process carousel evidence.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2006. Reported: “The tracker now credits the 19-case view carousel. I’m adding the chronological clean-room note with the exact commands and the QEMU results.”

    Action/result: Updated PROGRESS.md and docs/src/clean_room_executable_notes.md.

  2007. Reported: “The clean-room note records the new harness and the socket-permission hiccup. I’m adding the user-facing progress updates to the historical log now, then I’ll run the full test/docs checks.”

    Action/result: Updated this progress log for the view carousel work.

  2008. Reported: “The view-carousel work is logged. I’m running the full verification stack again because this added a new tool, new fixture helpers, tests, and docs.”

    Action/result: python3 -B -m unittest discover -s tests passed with 178 tests; opcode evidence, mdBook, and git diff --check also passed.

  2009. Reported: “Full verification is clean again: 178 tests, opcode evidence, mdBook, and diff whitespace all pass. I’m checking the diff shape, then I’ll pick the next remaining PROGRESS.md item.”

    Action/result: Reviewed git status --short, git diff --stat, the progress-log tail, and the high-value remaining-work section.

  2010. Reported: “The diff is broad but coherent: restore/sound work, menu runtime model, picture fuzz expansion, and the new view carousel. Next I’m turning the picture/view renderer notes into a compact runtime-model contract so implementation agents do not have to mine the long evidence chapter for core behavior.”

    Action/result: Added picture decoder and view/cel drawing contracts to docs/src/runtime_model.md.

  2011. Reported: “The runtime model now has compact picture-decoder and view/cel drawing contracts. I’m updating PROGRESS.md so the remaining renderer work points to new edge coverage, not missing baseline implementation text.”

    Action/result: Updated PROGRESS.md for the new implementation-facing renderer contracts.

  2012. Reported: “The clean-room note now records the renderer contract synthesis as a documentation step. I’m logging these latest updates, then I’ll run the docs checks for the new runtime-model text.”

    Action/result: Added the renderer contract synthesis section to docs/src/clean_room_executable_notes.md and updated this progress log.

  2013. Reported: “The progress log is current through the renderer contract work. This was docs-only after the last full test pass, so I’m running mdBook, opcode evidence, and diff whitespace before continuing.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, and git diff --check passed.

  2014. Reported: “Docs checks are clean. The next high-value gap in PROGRESS.md is parser/input edge behavior, so I’m reading the parser and input sections before deciding whether this wants a source pass, tests, or a spec synthesis pass.”

    Action/result: Reviewed parser/input documentation, runtime-model notes, compatibility coverage, tools/inspect_words.py, and existing logic parser probes.

  2015. Reported: “The parser docs already state two interesting said-style condition semantics that only have thin evidence: word id 0x0001 as a wildcard and 0x270f as a success terminator. I’m checking the local vocabulary so I can add small QEMU probes for those without guessing.”

    Action/result: Used tools/inspect_words.py to confirm look is word ID 0x0002 and get is word ID 0x0005; avoided around because it maps to 0x0000.

  2016. Reported: “The local vocabulary gives look as word id 0x0002 and get as 0x0005. I’m adding three parser probes: exact two-word matching, wildcard matching, and terminator-prefix matching.”

    Action/result: Added three parser-edge cases to tools/logic_interpreter_probe.py.

  2017. Reported: “The parser cases are in the probe catalog. I’m updating the catalog coverage test so those edge cases stay visible in the suite.”

    Action/result: Added the parser-edge case IDs to tests/test_logic_interpreter_probe.py.

  2018. Reported: “The local catalog test now names the new parser cases. I’m running that focused test first, then the three cases through the original engine.”

    Action/result: The focused catalog test passed and QEMU batch parser_edges_001 started.

  2019. Reported: “The parser-edge QEMU batch is running from one snapshot. This should tell us whether the wildcard and terminator rows are truly observable behavior, not just source-model lore.”

    Action/result: parser_edges_001 completed with 3 matches, 0 mismatches, and 0 errors.

  2020. Reported: “The parser-edge batch matched all three cases. I’m updating the runtime model and compatibility docs so wildcard and terminator behavior are QEMU-backed now.”

    Action/result: Updated docs/src/runtime_model.md, docs/src/compatibility_testing.md, and PROGRESS.md.

  2021. Reported: “The parser edge behavior is now reflected in the runtime model, compatibility chapter, and tracker. I’m adding the chronological evidence note with the vocabulary lookup and QEMU batch.”

    Action/result: Added a parser wildcard/terminator probe section to docs/src/clean_room_executable_notes.md.

  2022. Reported: “The parser evidence note is in place. I’m updating the progress log with the parser work and then I’ll run the focused logic-probe tests plus docs checks.”

    Action/result: Updated this progress log for the parser-edge work.

  2023. Reported: “I’m picking up at the optional dynamic-probe audit. The useful distinction here is whether a dynamic probe would prove normal AGI semantics, or just poke timing/hardware plumbing in a brittle way; I’m going to reflect that in the tracker so it stops looking like an unfinished core opcode gap.”

    Action/result: Reviewed the current PROGRESS.md high-value list and confirmed that the relevant opcode rows were already [x] source-backed for the current spec target.

  2024. Reported: “The tracker confirms the opcodes themselves are already covered; the remaining wording was carrying an “optional probes” task as if it were core work. I’m going to turn that into a documented audit result, then move back to the substantive renderer/suite/spec gaps.”

    Action/result: Reframed PROGRESS.md so renderer parity, subsystem spec text, and compatibility-suite growth are the highest-value remaining tasks.

  2025. Reported: “I found the existing compatibility note already explains why the save-description and key-release cases are poor direct probes. I’m adding one consolidated audit section now so the decision is explicit instead of scattered across failed-fixture notes.”

    Action/result: Added a source-backed opcode audit paragraph to docs/src/compatibility_testing.md.

  2026. Reported: “The high-value list is now aimed at work that will actually move the spec forward. Next I’m putting the audit rationale into the evidence trail, because future-us should not have to rediscover why those five opcodes were left source-backed.”

    Action/result: Added the chronological clean-room audit section to docs/src/clean_room_executable_notes.md.

  2027. Reported: “The compatibility chapter now makes the “not worth a brittle QEMU probe” call concrete. I’m adding the same conclusion to the chronological clean-room notes with the commands and rows I reviewed.”

    Action/result: Recorded the reviewed commands and per-opcode rationale for 0x6e, 0x83, 0x8e, 0xaa, and 0xad.

  2028. Reported: “That audit is now in the clean-room notes too. I’m logging the user-facing updates themselves, then I’ll run the docs checks before choosing the next PROGRESS item.”

    Action/result: Updated this progress log for the source-backed dynamic probe audit.

  2029. Reported: “The checks passed. I’m moving into the renderer pipeline next, with the source code as the first authority: draw ordering, priority/control gating, and persistent-object behavior are the parts still marked partial.”

    Action/result: Reviewed docs/src/graphics_object_pipeline.md, tools/object_overlay_probe.py, and related renderer tests.

  2030. Reported: “The current docs already pin down a lot of overlay behavior, including the two priority-gate branches and several persistent-object priority bytes. The remaining weak spot I’m seeing is the update-list/draw-order machinery around persistent objects, so I’m reading that cluster in the executable next.”

    Action/result: Started source inspection around update-list roots, dirty-rectangle helpers, and object overlay entries.

  2031. Reported: “One caution: those first ndisasm windows were too broad and one of them used the project’s easy-to-trip offset convention poorly. I’m rerunning the relevant slices with the EXE header offset accounted for, then I’ll only document the corrected source observations.”

    Action/result: Discarded the exploratory offset-confused disassembly windows and reran corrected slices with image offset plus EXE header skip.

  2032. Reported: “The corrected source slices confirm the docs are mostly current: 0x6a8e rebuilds/draws root 0x1703 first and root 0x16ff second, and 0x6aab refreshes dirty rectangles in the same root order. I’m checking the existing probe cases now to see whether adding a small local model/test is better than another QEMU run.”

    Action/result: Reviewed existing root-partition QEMU cases and compatibility notes.

  2033. Reported: “The QEMU evidence already covers the two-root partition. The remaining source question is the in-root sort: whether objects are ordered by baseline and how fixed-priority objects alter the key. I’m reading the list-builder and insertion helpers (0x0358..0x045e) now, since that should be answerable statically.”

    Action/result: Inspected shared update-list builder 0x0358, node insertion 0x042f, draw walker 0x045e, and reverse-priority helper 0x4cbb.

  2034. Reported: “The insertion/sort pass gives a nice precise result: each root sorts by ascending key, where the key is baseline Y unless fixed-priority bit 0x0004 is set, in which case it maps object +0x24 back to a Y-like row through 0x4cbb. Equal keys are stable in object-table order, and because drawing starts from the list tail, later table entries draw later for equal keys.”

    Action/result: Identified the in-root draw-order contract from source.

  2035. Reported: “I’m going to add a small local model for the update-list draw order rather than another QEMU fixture. It will encode the source-backed root partition, stable ascending sort key, and fixed-priority key mapping, which makes the renderer contract easier to reuse in future compatibility tests.”

    Action/result: Checked existing renderer helpers and tests for a suitable place to add the local model.

  2036. Reported: “There’s an interesting wrinkle in 0x4cbb: the default-table scan starts at index 0xa8, one byte past the 168-row table, and the local initial byte there is zero. I’m not going to over-model fixed-priority sorting beyond the source-backed normal cases until I can tie that byte to runtime initialization; the helper can still encode the exact observed source behavior with a supplied sentinel.”

    Action/result: Inspected the bytes around 0x127a and 0x1322, then treated the one-past-table value as an explicit helper parameter.

  2037. Reported: “The byte search shows [0x124a] is only cleared by the table-rebuild helper in this executable; I don’t see a source write that enables the direct formula path. For SQ2’s normal path, the table scan behavior is the portable thing to document, including the sentinel byte caveat.”

    Action/result: Searched source/docs for 0x124a and found no SQ2 write enabling the alternate direct formula branch.

  2038. Reported: “I’m adding the helper with an explicit after_table_value parameter instead of hard-coding a meaning for the byte after 0x127a. For local SQ2’s initial data that byte is zero, and the tests will lock down what that means without pretending it is a general AGI rule yet.”

    Action/result: Added ObjectDrawCandidate and update-list ordering helpers to tools/agi_graphics.py.

  2039. Reported: “The source-order helper is in place. I’m adding focused tests for the one-past-table sentinel, root ordering, stable equal-key ordering, and fixed-priority sort keys.”

    Action/result: Added focused update-list ordering tests to tests/test_graphics_rendering.py.

  2040. Reported: “The tests now capture the exact local ordering model. I’m running the graphics test module before updating the docs, because this is the kind of small helper where a one-line sort mistake would be easy to miss by reading.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering passed with 43 tests.

  2041. Reported: “The graphics tests pass. I’m documenting the in-root sorting details now and adding stable labels for the shared list-builder helpers, so the cross-version map has more than just the root wrappers.”

    Action/result: Updated docs/src/symbolic_labels.md with labels for 0x0358, 0x042f, 0x045e, 0x0488, and 0x4cbb.

  2042. Reported: “The label map now has the shared builder, insertion, tail-to-head drawing, refresh helper, and reverse-priority helper. I’m tightening the graphics chapter around those details next, including the “later object wins on equal key” behavior.”

    Action/result: Expanded the update-list section in docs/src/graphics_object_pipeline.md.

  2043. Reported: “The graphics chapter has the detailed source behavior. I’m adding the short implementation-facing version to the runtime model so a future clean-room engine gets the ordering rule without having to re-read the evidence chapter.”

    Action/result: Updated docs/src/runtime_model.md with the concise update-list ordering contract.

  2044. Reported: “The runtime model now has the concise draw-order contract. I’m updating the compatibility chapter and tracker to show that draw ordering has moved from “partial” to source-modeled plus QEMU-backed for the root partition.”

    Action/result: Updated docs/src/compatibility_testing.md and PROGRESS.md.

  2045. Reported: “The tracker now treats draw order as covered at the current source/test level. I’m adding the chronological note with the corrected disassembly offsets and the rejected first reads, since that is part of the clean-room trail.”

    Action/result: Added the update-list draw-order source-model section to docs/src/clean_room_executable_notes.md.

  2046. Reported: “The clean-room note is in place. I’m logging the working updates themselves, then I’ll run docs/evidence checks and continue to the next partial renderer item.”

    Action/result: Updated this progress log for the update-list draw-order source-model work.

  2047. Reported: “I’ll pick up from the dirty-rectangle source model that was mid-edit, get that tested and documented, then keep walking the remaining PROGRESS.md items in order. I’ll also keep adding the work-log entries as I go so the evidence trail stays continuous.”

    Action/result: Inspected the worktree, current high-value progress tracker, graphics helper, and graphics tests before resuming edits.

  2048. Reported: “The worktree is still intentionally dirty from the accumulated reverse-engineering changes. The current high-value list has four broad tracks left, so I’m going to keep converting concrete source observations into helpers/tests/docs before moving to broader sweeps.”

    Action/result: Confirmed remaining high-value tracks and located the dirty-rectangle helper and object-pipeline documentation.

  2049. Reported: “The dirty-rectangle helper is present but not yet covered by tests or prose. I’m going to wire that into the graphics tests first, then carry the exact formula into the object pipeline chapter and runtime model.”

    Action/result: Opened the relevant test and documentation sections for a targeted dirty-rectangle update.

  2050. Reported: “I found the existing prose already had the broad dirty-rectangle claim, but it stops before the actual coordinate math. I’m adding the math as executable tests now, then I’ll make the prose precise enough for a future implementation.”

    Action/result: Added DirtyRect and dirty_rect_union() imports plus dirty-rectangle union tests to tests/test_graphics_rendering.py.

  2051. Reported: “The unit coverage now checks identical old/current footprints and both orderings of an offset old/current footprint. I’m running the focused graphics tests before touching the docs so the helper’s coordinate convention is pinned down.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering passed with 45 tests.

  2052. Reported: “The focused graphics tests pass. I’m taking one focused disassembly slice for 0x5762 now so the documentation points to the exact routine behind the helper rather than just inheriting the earlier broad object-pipeline read.”

    Action/result: Ran an ndisasm read from image offset 0x5762; the first routine body confirmed the dirty-rectangle union and the command also demonstrated that ndisasm -e is a skip offset rather than an end offset.

  2053. Reported: “The focused ndisasm command confirmed the 0x5762 body, though it also reminded me that ndisasm -e is a skip offset, not an end offset, so the terminal dump kept going after the routine. I have the needed first block; next I’m updating the docs and log with that caveat instead of pretending the command was neatly bounded.”

    Action/result: Searched existing notes for disassembly conventions before writing the new dirty-rectangle evidence note.

  2054. Reported: “I’m going to record that ndisasm -e lesson in the clean-room note too, because these offset mechanics matter for later cross-version work. Then I’ll keep pushing into the next object pipeline gap rather than letting this become just a prose cleanup pass.”

    Action/result: Prepared documentation edits for the source-backed dirty-rectangle formula.

  2055. Reported: “The object pipeline chapter now has the exact rectangle formula and register arguments. I’m adding the shorter implementation-facing version to the runtime model so the spec has both evidence detail and a direct contract.”

    Action/result: Added the exact dirty-rectangle formula to docs/src/graphics_object_pipeline.md.

  2056. Reported: “The runtime model now has the dirty-refresh contract in the lifecycle table. I’m marking that piece as source-modeled in PROGRESS.md, leaving the object-record collision/control fixture work as the main remaining object-pipeline gap.”

    Action/result: Added the runtime-model dirty-refresh contract.

  2057. Reported: “PROGRESS.md now reflects the dirty-rectangle coverage. I’m adding the chronological evidence note and the progress-log entries next, then I’ll run the focused checks and move to the remaining placement/collision-control work.”

    Action/result: Updated PROGRESS.md and added the dirty-rectangle source model note to docs/src/clean_room_executable_notes.md.

  2058. Reported: “The clean-room note captures the exact routine behavior and the ndisasm caveat. I’m updating the progress log with each user-facing update from this stretch so the historical record stays complete.”

    Action/result: Updated this progress log with entries for the dirty-rectangle source-model work.

  2059. Reported: “The dirty-rectangle documentation and log are in place. I’m running the docs/evidence hygiene checks now; after that I’ll return to the remaining object placement and collision/control semantics rather than stopping on this checkpoint.”

    Action/result: Ran mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, and git diff --check; all passed.

  2060. Reported: “The book build, opcode-evidence check, and whitespace check are clean. I’m moving to the remaining object-pipeline gap now: placement acceptance, collision, and control-screen semantics from source first, with QEMU only if we need an observable confirmation.”

    Action/result: Read current placement, collision, and control-acceptance helper notes and local object-pipeline tests.

  2061. Reported: “The existing notes already cover a lot of 0x4719/0x56b8, and the remaining tracker wording is narrower than it first looked: we need full object-record placement acceptance semantics polished, not a brand-new discovery from scratch. I’m reading the current source-backed helper descriptions against the local harnesses before deciding what small model/test should come next.”

    Action/result: Reviewed current movement/control QEMU cases and the local graphics helper surface.

  2062. Reported: “The harness already has QEMU movement cases for the important control classes, but the local graphics helpers don’t yet expose the 0x56b8 acceptance rule as a small deterministic model. I’m reading the exact routine body now so I can add that kind of helper without inferring from QEMU outcomes alone.”

    Action/result: Disassembled focused slices for code.object.control_acceptance (0x56b8) and code.object.collision_test (0x4719).

  2063. Reported: “The 0x56b8 source clarifies one correction: class 0x20 is not a permanent “encountered anywhere” latch in the scan; the routine resets its class state at each scanned cell, so the final scanned non-rejected cell controls the post-scan flag gates. I’m adding a small helper and tests for that exact source behavior.”

    Action/result: Added ControlAcceptance and control_acceptance_scan() to tools/agi_graphics.py.

  2064. Reported: “The helper is in place as a scanline-level model of 0x56b8, including the priority-15 bypass and the global flag values for event byte zero. I’m adding tests that exercise the source-only edge cases, including the “last scanned class wins” correction.”

    Action/result: Added control-acceptance scan tests to tests/test_graphics_rendering.py.

  2065. Reported: “The tests now lock down the class gates and the final-class behavior for event flag updates. I’m running the focused graphics module again; if it passes, I’ll correct the prose around 0x56b8 so it no longer implies an accumulated class-2 latch.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering passed with 47 tests.

  2066. Reported: “The focused tests pass with 47 graphics cases. I’m updating the docs now to spell out 0x56b8 as a scanline state machine: zero rejects, class 1 needs bit 0x0002, class 2 and class 3 use different post-scan gate bits, and the last scanned class state is what survives.”

    Action/result: Opened the symbolic label, graphics chapter, and runtime model sections that describe object control acceptance.

  2067. Reported: “The symbolic label for code.object.control_acceptance already exists, so I don’t need a new label. I’m revising its description and the graphics chapter now, mainly replacing “encountered class 2” with “current/final class state” to match the disassembly.”

    Action/result: Updated docs/src/symbolic_labels.md.

  2068. Reported: “The label map now says the routine is source-backed for the final scanned class state. I’m updating the detailed graphics chapter and runtime model next so the implementation contract is explicit.”

    Action/result: Updated docs/src/graphics_object_pipeline.md with the source-backed 0x56b8 state machine.

  2069. Reported: “The graphics chapter now states the exact source scan behavior, including the priority-15 bypass and the global flag updates. I’m adding a compact version to the runtime model so implementers don’t have to reconstruct it from the evidence chapter.”

    Action/result: Added the compact control-acceptance contract to docs/src/runtime_model.md.

  2070. Reported: “The runtime model now has an implementation-ready acceptance rule. I’m recording this as source-model progress in PROGRESS.md and the clean-room notes, then I’ll run checks before selecting the next PROGRESS.md item.”

    Action/result: Updated PROGRESS.md.

  2071. Reported: “PROGRESS.md now treats the control-acceptance scan as covered at the source/local-test level, with only optional direct placement fixtures left. I’m adding the evidence note with the 0x56b8 and 0x4719 disassembly slices and the correction to the old wording.”

    Action/result: Added the control-acceptance source-model section to docs/src/clean_room_executable_notes.md.

  2072. Reported: “The clean-room note captures the 0x56b8 model and the correction to the earlier “encountered” language. I’m bringing the progress log up to date for this object-acceptance pass before running the next check set.”

    Action/result: Updated this progress log with entries for the control-acceptance source-model work.

  2073. Reported: “The progress log is current through the control-acceptance work. I’m running the standard docs/evidence/whitespace checks again, then I’ll reassess PROGRESS.md for the next highest-value item.”

    Action/result: Ran mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, and git diff --check; all passed.

  2074. Reported: “The checks are clean again. The next broad high-value item is picture/view renderer compatibility, so I’m scanning the docs and tests for remaining provisional renderer semantics rather than inventing a new probe from the outside.”

    Action/result: Searched current docs/tests for renderer unknowns and remaining-work wording.

  2075. Reported: “The renderer chapter has one stale-looking provisional note: the prepare-picture versus show-picture distinction says it still needs live confirmation, even though later evidence and opcode coverage likely already cover the mechanism. I’m checking the existing probe coverage and source path before either correcting the wording or adding a narrow confirmation.”

    Action/result: Located existing resource-lifecycle QEMU evidence for 0x19, 0x1a, and 0x1c.

  2076. Reported: “Existing evidence already confirms the picture lifecycle distinction: 0x19/0x1c decode into the logical buffer, and 0x1a is the visible refresh/finalization step. I’m removing the stale “needs live confirmation” wording and pointing it at the existing resource-lifecycle QEMU probe.”

    Action/result: Updated the picture-flow section in docs/src/graphics_object_pipeline.md.

  2077. Reported: “That stale picture-lifecycle gap is now corrected using existing source and QEMU evidence. The next concrete renderer unknown is the first two bytes of view resources, so I’m going after the view-loader source to see whether those bytes are actually used by the interpreter.”

    Action/result: Opened current view-layout docs, symbolic labels, and disassembly around the view loader and frame selector.

  2078. Reported: “The view loader/binder source only touched payload +0x02 and later offsets in the slices so far. I’m reading the group/frame selector and preview-text helper next; if those also skip +0x00/+0x01, the honest conclusion is “reserved or unused by observed SQ2 interpreter paths” rather than a fabricated meaning.”

    Action/result: Disassembled code.object.select_group_table and the view preview/display helper, and inspected a sample view header.

  2079. Reported: “The selector and preview slices also skip bytes +0x00/+0x01; the local view inspector shows view 0 has header 01 01 .... I’m doing a local census across all present view resources now, then I’ll update the spec to call those two bytes reserved/unused by observed SQ2 runtime paths if the evidence supports that.”

    Action/result: Counted first-two-byte headers across all valid SQ2 view resources; all 203 were 01 01.

  2080. Reported: “All 203 valid local SQ2 view resources have header bytes 01 01. Since the inspected interpreter paths begin meaningful view parsing at byte +0x02, I’m adding a small census test and changing the docs from “unknown” to “reserved/unused by observed SQ2 code paths.””

    Action/result: Added a view-header reserved-byte census test to tests/test_graphics_rendering.py.

  2081. Reported: “The view-header census test is in place. I’m running the focused graphics tests again before editing the docs, because this is exactly the sort of tiny claim that should be executable.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering passed with 48 tests.

  2082. Reported: “The focused graphics suite passes with 48 tests. I’m updating the view layout prose now: bytes +0x00/+0x01 are stable 01 01 in SQ2 and appear unused by the observed loader/binder/preview paths, while byte +0x02 starts the meaningful layout.”

    Action/result: Updated the view payload layout in docs/src/graphics_object_pipeline.md.

  2083. Reported: “The graphics chapter now treats the first two view bytes as reserved, with both source-path and resource-census evidence. I’m adding the same compact contract to the runtime model and updating the tracker.”

    Action/result: Updated docs/src/runtime_model.md.

  2084. Reported: “The runtime model now has the reserved-byte rule too. I’m updating PROGRESS.md so view decoding reflects the source-backed header interpretation rather than leaving that as an open unknown.”

    Action/result: Updated the view resource decoding evidence line in PROGRESS.md.

  2085. Reported: “PROGRESS.md now records the view header bytes as source-backed. I’m adding the clean-room evidence note for the disassembly slices and the local resource census before running the check set.”

    Action/result: Added the view-header reserved-byte section to docs/src/clean_room_executable_notes.md.

  2086. Reported: “The clean-room note now records the view-header evidence. I’m adding one line to the compatibility coverage summary so the new view-header census test is visible alongside the other local renderer tests.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2087. Reported: “The compatibility chapter now includes the view-header census. I’m updating the progress log for the picture lifecycle cleanup and view-header source pass, then I’ll run the standard checks again.”

    Action/result: Updated this progress log with entries for the picture-lifecycle cleanup and view-header source-model work.

  2088. Reported: “The progress log is current through the view-header work. I’m running the standard checks now, then I’ll continue into the next remaining area from PROGRESS.md.”

    Action/result: Ran mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, and git diff --check; all passed.

  2089. Reported: “Checks are clean. The picture decoder still has two handlers that local SQ2 never uses in real resources, 0xf4 and 0xf5, so I’m checking whether our synthetic coverage is balanced there before choosing any new fuzz/QEMU work.”

    Action/result: Reviewed corner-path renderer code, fuzz cases, unit tests, and coverage notes.

  2090. Reported: “Corner commands are already in the fuzz corpus and QEMU coverage, but the focused graphics unit tests only assert the resume behavior for 0xf4; they don’t directly assert the full 0xf5 X-first path. I’m adding a small deterministic local test for both corner orientations so that rare-but-valid handlers have explicit regression coverage.”

    Action/result: Located existing indirect 0xf4 tests through seed-fill rectangle cases.

  2091. Reported: “I found the seed-fill tests use 0xf4 rectangles, so 0xf4 has indirect coverage. I’m still adding direct corner-path tests because they make the intended point set obvious and put 0xf5 on equal footing.”

    Action/result: Added direct 0xf4 and 0xf5 corner-path point-set tests to tests/test_graphics_rendering.py.

  2092. Reported: “The direct corner-path tests are in place. I’m running the focused graphics suite to make sure the expected point sets match the existing renderer and source semantics.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering passed with 50 tests.

  2093. Reported: “The graphics suite passes with 50 tests. I’m recording the new direct 0xf4/0xf5 coverage in the testing chapter and tracker, then I’ll keep moving through remaining renderer risk areas.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2094. Reported: “The compatibility chapter now calls out direct corner-path unit coverage. I’m updating PROGRESS.md and the clean-room notes with the same small renderer-suite improvement.”

    Action/result: Updated the picture decoder evidence line in PROGRESS.md.

  2095. Reported: “PROGRESS.md now includes the rare corner-path handlers in picture evidence. I’m adding a short evidence note that this was a local regression-coverage improvement, not a new QEMU observation.”

    Action/result: Added the direct corner-path unit-coverage note to docs/src/clean_room_executable_notes.md.

  2096. Reported: “The clean-room note now distinguishes this as local regression coverage for already-source-modeled handlers. I’m updating the progress log and then running the normal check set.”

    Action/result: Updated this progress log with entries for the direct corner-path coverage work.

  2097. Reported: “The log is current through the corner-path coverage. I’m running the standard checks now before moving on again.”

    Action/result: Ran mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, and git diff --check; all passed.

  2098. Reported: “Checks are clean. The view item still says runtime animation state needs broadening, so I’m checking what’s already source-backed and QEMU-backed there before deciding whether the tracker wording is stale or there is a real missing mode/edge.”

    Action/result: Reviewed frame-animation source/model notes, movement probe cases, and test coverage.

  2099. Reported: “The animation side is not actually an uncovered view-decoder gap anymore: modes 0..3, interval seeding, and bit 0x0020 gating are source-backed and QEMU-covered in the object movement harness. I’m tightening PROGRESS.md so the view row’s remaining work is about additional priority/control combinations, not animation state that is already tracked elsewhere.”

    Action/result: Updated the view resource decoding row in PROGRESS.md.

  2100. Reported: “The tracker now no longer double-counts animation as a view-decoder gap. I’m moving to another concrete partial item: vocabulary/tokenization edge cases, checking whether there’s a small source-backed local parser model we should expose for final compatibility work.”

    Action/result: Reviewed parser/vocabulary docs and tools/inspect_words.py.

  2101. Reported: “The parser docs already have a good high-level model, but inspect_words.py is only a utility without tests. I’m adding focused local tests for the WORDS.TOK decoder so the vocabulary format evidence is executable, especially the prefix compression and known IDs used by QEMU parser probes.”

    Action/result: Confirmed no existing test module covered tools/inspect_words.py.

  2102. Reported: “The local decoder reports 1,099 entries and the IDs used in the QEMU parser cases: anyword=0x0001, look=0x0002, get=0x0005. I’m adding a dedicated test module for those facts and the 26-letter offset table.”

    Action/result: Added tests/test_words.py.

  2103. Reported: “The WORDS.TOK tests are in place. I’m running that new test module and the graphics tests together, since both are affected by this round of local compatibility coverage.”

    Action/result: python3 -B -m unittest tests.test_words passed with 3 tests, and python3 -B -m unittest tests.test_graphics_rendering passed with 50 tests.

  2104. Reported: “The new WORDS.TOK tests pass, and the graphics suite still passes. I’m documenting this as local parser-format coverage, then I’ll keep working through the remaining tracker items.”

    Action/result: Started updating parser coverage docs.

  2105. Reported: “The compatibility paragraph I wanted has shifted a bit, so I’m locating the parser section and applying the update against the current text instead of forcing a stale patch.”

    Action/result: Located the parser edge section in docs/src/compatibility_testing.md.

  2106. Reported: “I found the parser section. I’m adding the WORDS.TOK decoder-test summary right after the QEMU parser edge paragraph so the static vocabulary format and dynamic condition behavior sit together.”

    Action/result: Prepared the compatibility-testing update.

  2107. Reported: “The exact paragraph is in hand now. I’m patching against that text and then I’ll update the tracker/notes for the new parser-format tests.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2108. Reported: “The compatibility chapter now links the WORDS.TOK decoder tests to the QEMU parser probes. I’m updating PROGRESS.md and the clean-room notes with this parser-format coverage.”

    Action/result: Updated the parser/input coverage line in PROGRESS.md.

  2109. Reported: “PROGRESS.md now reflects executable WORDS.TOK decoder coverage. I’m adding the chronological note with the exact inspected IDs and offsets.”

    Action/result: Added the WORDS.TOK decoder test section to docs/src/clean_room_executable_notes.md.

  2110. Reported: “The parser-format evidence note is in place. I’m updating the progress log for the animation-tracker cleanup and WORDS.TOK test work, then I’ll run the standard checks plus the new parser test.”

    Action/result: Updated this progress log with entries for the animation tracker cleanup and WORDS.TOK decoder tests.

  2111. Reported: “The progress log is current again. I’m running docs/evidence/whitespace checks plus the new parser test module now.”

    Action/result: Ran mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest tests.test_words; all passed.

  2112. Reported: “The check set passed. I’m moving to another tracker item with a concrete “remaining” note: DOS save path validation. I’ll inspect the existing source map and tests first, then decide whether a small local model/test can close part of that gap.”

    Action/result: Reviewed path-selection docs, symbolic labels, progress wording, and save-resource helpers.

  2113. Reported: “The save/restore state machine is well documented, but the validator itself is still mostly a named box. I’m reading the 0x5bdd path validator source now and will turn any stable rule into a small local helper/test if it’s straightforward.”

    Action/result: Disassembled code.dos.validate_path and neighboring DOS helpers.

  2114. Reported: “The validator source gives a useful split: it normalizes the path string before delegating to DOS. It skips leading spaces, fills an empty path with the current directory, strips a trailing slash/backslash when length is greater than one, accepts a single slash/backslash immediately, treats X: as a drive-only check, and otherwise uses DOS find-first with directory attributes. I’m going to model that source-level classification locally, leaving actual DOS availability as an external result.”

    Action/result: Read the separator table and drive helper source.

  2115. Reported: “The separator table at 0x135f is exactly backslash and slash, and the drive helper lowercases drive letters before probing DOS. I need one more corrected slice for 0x5db2; the earlier dd skip hit the previous helper because I used the wrong file offset.”

    Action/result: Re-read code.dos.get_current_directory at the corrected file offset.

  2116. Reported: “The corrected 0x5db2 slice shows the default path helper writes a leading backslash, calls DOS get-current-directory, and may switch that first separator to slash if the returned path contains one. I’m adding a local “validation plan” helper now: it models source string handling and says which DOS check the interpreter would perform, without pretending to know host/DOS availability.”

    Action/result: Added SavePathValidationPlan and save_path_validation_plan() to tools/agi_save.py.

  2117. Reported: “The path-validation planning helper is in tools/agi_save.py. I’m adding unit tests for the source-visible edge cases: leading spaces, empty-path defaulting, trailing separator stripping, single-root acceptance, and drive-only classification.”

    Action/result: Opened and extended tests/test_save_resources.py.

  2118. Reported: “The save tests already cover the file envelope, so I’m extending that module rather than creating a separate path test file.”

    Action/result: Added save path-validation plan tests.

  2119. Reported: “The path-validation edge tests are in place. I’m running the save-resource tests now to make sure the new model matches the source-derived expectations.”

    Action/result: python3 -B -m unittest tests.test_save_resources passed with 7 tests.

  2120. Reported: “The save-resource tests pass with the new path-validation cases. I’m documenting the validator as a source-level string-normalization and DOS-check plan, and adding the missing symbolic label for code.dos.validate_path.”

    Action/result: Updated docs/src/symbolic_labels.md.

  2121. Reported: “The path validator label is now in the cross-version map. I’m updating the runtime model and compatibility chapter with the exact edge behavior covered by the new helper/tests.”

    Action/result: Updated the save/restore selector state machine in docs/src/runtime_model.md.

  2122. Reported: “The runtime model now spells out the path validator’s string handling and DOS probe choices. I’m adding the same coverage note to the compatibility chapter and tracker.”

    Action/result: Located the current save/restore section after an initial stale patch context.

  2123. Reported: “That save/restore paragraph has shifted too; I’m locating the restore-read-error section and patching the path-validation note into the current wording.”

    Action/result: Opened the save/restore compatibility-testing section.

  2124. Reported: “I found the save/restore section. I’m inserting the path-validation note after the structural save-resource test description, before the dynamic QEMU save/restore probes.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2125. Reported: “The compatibility chapter now captures the path validation plan. I’m updating PROGRESS.md to narrow that remaining item, then I’ll add the clean-room source note.”

    Action/result: Updated the DOS file I/O progress row in PROGRESS.md.

  2126. Reported: “The DOS path-validation row now treats the source-level string rules as covered, leaving only optional dynamic UI failure cases. I’m adding the source-note with the disassembly and test commands.”

    Action/result: Added the save path validation plan section to docs/src/clean_room_executable_notes.md.

  2127. Reported: “The clean-room note captures the path validator’s source behavior and the limits of the local helper. I’m updating the progress log, then I’ll run the relevant tests and standard checks.”

    Action/result: Updated this progress log with entries for the save path validation plan work.

  2128. Reported: “I’m picking this back up at the resource/cache layout work: first I’m going to land the cache-record documentation update that the disassembly already supports, then I’ll re-read PROGRESS.md and keep walking the remaining checklist from the highest-value items down.”

    Action/result: Read the current tracker, resource chapter, progress log, clean-room notes, and worktree status.

  2129. Reported: “The tracker confirms the opcode matrix itself is done, so I’m staying in the subsystem-spec layer now: cache records, renderer edge cases, UI/text/parser/save/audio contracts, and the compatibility suite. The cache table is the next small concrete improvement because the offsets are all source-backed.”

    Action/result: Re-read the remaining engine coverage areas in PROGRESS.md and the existing resource-loader prose.

  2130. Reported: “I’m editing the mdBook resource chapter now. The important implementation-facing point is that each resource family keeps a tiny linked cache record with a different payload-specific layout, so I’m documenting that as a table rather than leaving it scattered through notes.”

    Action/result: Added the resource cache record table to docs/src/resource_files.md.

  2131. Reported: “The resource chapter now has the cache-record table, and PROGRESS.md no longer treats that layout as unresolved. I’m adding the evidence note with the exact disassembly slices so future version comparisons can map changed addresses back onto the same symbols.”

    Action/result: Updated PROGRESS.md and added a resource cache record layout section to docs/src/clean_room_executable_notes.md.

  2132. Reported: “I’m also logging the working updates themselves. That log is deliberately a narrative trail, so I’m adding both the status updates and the concrete result behind each one before I move into the next tracker item.”

    Action/result: Added the current resource-cache progress entries to this log.

  2133. Reported: “The cache-record docs are in place. I’m running the standard documentation/evidence checks now, then I’ll continue down PROGRESS.md rather than pausing at this milestone.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, and git diff --check all passed.

  2134. Reported: “The checks passed. I’m scanning for the next concrete gaps that are both source-discoverable and useful for the final implementation spec, starting with renderer and subsystem TODO language rather than inventing new dynamic probes first.”

    Action/result: Searched PROGRESS.md, docs, tools, and tests for remaining/provisional language and opened the graphics renderer model.

  2135. Reported: “The renderer chapter is mostly in good shape, but I found a couple of stale “unknown” statements: view header bytes are now reserved/unused, and the cache chapter still says view/picture parsing remains to be decoded. I’ll clean those while I’m in this pass, then move to an actual remaining edge.”

    Action/result: Identified stale wording in resource_files.md and the graphics chapter summary.

  2136. Reported: “Before diving into new disassembly, I’m doing a small documentation consistency pass. These aren’t new findings, just removing old uncertainty that the later source work already settled.”

    Action/result: Updated the resource and graphics chapters to point at the now-documented view/picture parsers and to remove view-header bytes from the renderer unknown list.

  2137. Reported: “That stale wording is cleaned up. Next I’m going back to the remaining renderer edge semantics; I’m going to inspect the picture draw helpers around the less common command paths and compare them against the current Python model before adding tests.”

    Action/result: Returned to source-first picture renderer inspection.

  2138. Reported: “I’m checking the local renderer tests against the source-modeled command families now. The first useful target is not a big new harness; it’s locking down byte-reader edge cases where a command byte interrupts an active command and must be reprocessed by the scanner.”

    Action/result: Reviewed existing graphics/fuzz tests and disassembled picture scanner and draw helper slices around 0x6475, 0x6494, 0x6603, and 0x66ab.

  2139. Reported: “The source exposed a real edge: not every operand uses the coordinate/data reader. Commands 0xf0, 0xf2, and 0xf9 consume a raw next byte, so a byte that looks like another command is data in that position. The Python renderer currently treated those operands too strictly, so I’m fixing that and adding regression tests.”

    Action/result: Added PictureRenderer.read_raw_byte() and changed visual, control, and pattern-mode operands to consume raw bytes.

  2140. Reported: “The renderer now distinguishes raw single-byte operands from coordinate/data operands. I’m running the graphics tests; if the hashes stay stable, this should only add edge coverage and not change ordinary SQ2 picture renders.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering passed with 53 tests.

  2141. Reported: “The focused graphics suite passes with 53 tests, and the existing real-picture hashes did not move. I’m going to turn this source edge into reusable corpus coverage as well, so future renderer comparisons don’t lose it.”

    Action/result: Opened the picture fuzz base-case registry and tests.

  2142. Reported: “I found the synthetic fuzz corpus has the right place for this: the existing command-resume cases cover coordinate readers, but not raw one-byte operands. I’m adding three safe base cases so the distinction is visible in the reusable corpus.”

    Action/result: Added base_033_raw_visual_operand, base_034_raw_control_operand, and base_035_raw_pattern_mode_operand to tools/picture_fuzz.py, plus test coverage in tests/test_picture_fuzz.py.

  2143. Reported: “The fuzz base cases now include raw visual/control/pattern-mode operands. I’m running the picture-fuzz tests next, then I’ll regenerate the corpus metadata so the documented counts are real.”

    Action/result: python3 -B -m unittest tests.test_picture_fuzz passed with 12 tests.

  2144. Reported: “The fuzz-tool tests pass. I’m regenerating the deterministic corpus with the three new base cases, which should take it from 1,057 to 1,060 cases while keeping only the two intentional overread cases out of QEMU.”

    Action/result: Regenerated build/picture-fuzz/corpus; it reported 1,060 cases and 1,058 safe for QEMU.

  2145. Reported: “The regenerated corpus reports 1,060 cases, 1,058 safe for QEMU. Since this is a renderer edge and the harness already supports it, I’m going to run the three new raw-operand cases through the original engine as a focused snapshot batch.”

    Action/result: Started snapshot QEMU batch raw_operand_001 for the three new raw-operand cases.

  2146. Reported: “The QEMU snapshot batch is running from one boot and has built all three fixtures. I’m waiting on the captures now; this is the confirmation step, not the discovery step.”

    Action/result: Waited for the QEMU snapshot batch to finish.

  2147. Reported: “The original engine matched all three raw-operand cases with zero mismatches. I’m documenting this as QEMU-confirmed picture semantics and updating the corpus counts in the tracker and compatibility chapter.”

    Action/result: Opened the compatibility chapter, tracker, and notes for updates.

  2148. Reported: “I’m updating the implementation-facing docs now: the nuance is that “command bytes remain pending” applies to coordinate/list readers, while raw one-byte operands are consumed as operands even if they look like commands. That distinction matters for compatibility.”

    Action/result: Updated the picture decoder section of docs/src/graphics_object_pipeline.md.

  2149. Reported: “The renderer chapter now states both sides of the scanner rule. I’m adding the same contract to the runtime model and compatibility chapter, then I’ll record the exact disassembly/QEMU commands in the evidence notes.”

    Action/result: Updated docs/src/runtime_model.md.

  2150. Reported: “The runtime model has the raw-operand rule now. I’m updating the compatibility chapter with the new 1,060-case corpus count and the three-case QEMU batch result.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2151. Reported: “The compatibility chapter now names the raw-operand batch. I’m tightening the tracker too, so the dashboard reflects both the added renderer evidence and the updated corpus size.”

    Action/result: Updated PROGRESS.md.

  2152. Reported: “The tracker is updated. I’m adding the clean-room evidence entry now: disassembly slices, the renderer/test changes, corpus regeneration, and the original-engine batch result.”

    Action/result: Added the picture raw-operand scanner edge section to docs/src/clean_room_executable_notes.md.

  2153. Reported: “The evidence note is in place. I’m updating the progress log with the whole raw-operand sequence before running the standard checks again.”

    Action/result: Added the raw-operand progress entries to this log.

  2154. Reported: “The raw-operand checks passed. I’m moving to the next high-value partial subsystem that is mostly source-discoverable: sound/audio, specifically whether the remaining “pitch/envelope” wording can be turned into a clearer driver-facing contract from the disassembly and existing sound parser.”

    Action/result: Opened tools/agi_sound.py, sound-related docs, and the current sound progress row.

  2155. Reported: “The sound docs already cover the gameplay contract and PC-speaker divisor. The remaining wording is about the non-PC-speaker attenuation/envelope helper, so I’m reading that exact source path now rather than guessing from sound data alone.”

    Action/result: Disassembled code.sound.driver_write_attenuation and nearby driver start/tick/tone helpers, and inspected AGIDATA bytes around the default envelope table.

  2156. Reported: “The attenuation helper is clearer than the tracker implies: it has a specific per-channel ramp table, sentinel byte 0x80, clamp to 0..15, and selector-2 adjustment before the port write. I’m pulling the tone helper slice too so the local model can cover both driver-facing outputs.”

    Action/result: Re-ran the correctly aligned tone/helper disassembly and scanned local SQ2 sound control/tone byte distributions.

  2157. Reported: “One oddity in the tone helper is that the event control byte’s upper bits are not plainly reloaded before code.sound.driver_write_tone; I’m not going to overclaim that path. The attenuation helper, though, has enough direct state reads and writes to model its output byte precisely.”

    Action/result: Limited the new model to the directly source-backed attenuation/output-byte state machine.

  2158. Reported: “I’m going to add a small source-level model for attenuation output rather than an audio synthesizer. It will model the state the driver actually mutates and the byte it writes to port 0xc0; audible waveform reproduction can stay out of the portable spec.”

    Action/result: Added SoundAttenuationState, SoundAttenuationOutput, default envelope decoding, channel masks, and sound_attenuation_output() to tools/agi_sound.py.

  2159. Reported: “The attenuation helper is in tools/agi_sound.py. I’m adding focused tests for the default envelope table, channel masks, selector-2 adjustment, negative/positive clamps, and the 0x80 envelope terminator.”

    Action/result: Extended tests/test_sound_resources.py with attenuation output tests.

  2160. Reported: “The sound tests now cover the driver-facing attenuation state machine directly. I’m running that module to make sure the helper matches the source-derived edge cases.”

    Action/result: python3 -B -m unittest tests.test_sound_resources passed with 14 tests.

  2161. Reported: “The targeted sound tests pass. I’m updating the sound spec text now: attenuation/envelope byte output is no longer an open semantic gap, while actual audible synthesis remains hardware-specific and outside the portable game-state contract.”

    Action/result: Opened the sound sections in the runtime model, compatibility chapter, clean-room notes, and tracker.

  2162. Reported: “I’m patching the sound runtime model with the exact attenuation helper: base attenuation, envelope index/value, default delta table, 0x80 sentinel, channel mask, selector-2 lift, and final port byte.”

    Action/result: Updated docs/src/runtime_model.md.

  2163. Reported: “The sound runtime model now has the driver-facing attenuation contract. I’m adding a compatibility-suite note so the new local tests are visible alongside the existing QEMU load/start/stop probes.”

    Action/result: Located the existing static sound-resource parser section in docs/src/compatibility_testing.md.

  2164. Reported: “The compatibility chapter already had a sound-resource section, so I’m extending that paragraph rather than adding a new one.”

    Action/result: Updated the compatibility-testing sound paragraph with the new attenuation output coverage.

  2165. Reported: “The compatibility note is updated. I’m narrowing the sound row in PROGRESS.md: envelope/attenuation byte behavior is covered now; what remains is actual audible synthesis or optional dynamic timing confirmation.”

    Action/result: Updated the sound/audio row in PROGRESS.md.

  2166. Reported: “The sound tracker now distinguishes driver-byte compatibility from actual sound synthesis. I’m adding the clean-room note with the new disassembly and table observations.”

    Action/result: Added the sound attenuation envelope source-model section to docs/src/clean_room_executable_notes.md.

  2167. Reported: “The sound evidence note is in place. I’m adding the corresponding progress-log entries, then I’ll run the standard checks and continue to the next tracker item.”

    Action/result: Added the sound attenuation progress entries to this log.

  2168. Reported: “The sound checks passed. I’m moving next to parser/vocabulary because that is another remaining partial area where source inspection and local tests can improve the implementation spec without needing a lot of emulator time.”

    Action/result: Searched parser/vocabulary docs, opened the WORDS.TOK decoder and tests, and reviewed the runtime parser summary.

  2169. Reported: “The docs already separate direct string comparison from WORDS.TOK parsing. I’m looking for a source-backed tokenization detail that is useful enough to model locally, especially delimiters, unknown-word behavior, and parser buffer limits.”

    Action/result: Located existing parser notes, data tables, and labels for parsed-word buffers and normalized string comparison.

  2170. Reported: “The earlier notes already identified parser helper addresses, so I’m re-reading those slices directly. If the normalization/token buffers are as clear as the notes suggest, I’ll turn them into a small local parser helper and tests.”

    Action/result: Disassembled action 0x75, parser helper 0x18ac, normalization helper 0x199d, and dictionary lookup helper 0x1a6b.

  2171. Reported: “The tokenization source gives a neat implementation boundary: normalize into a space-separated buffer, then lookup advances a global pointer through that buffer one word at a time. I’m reading the two tail helpers before I code the local model.”

    Action/result: Disassembled unknown-token truncation helper 0x1bc7 and dictionary-entry advance helper 0x1be4, and reviewed earlier parser evidence notes.

  2172. Reported: “The parser source has one subtle correction worth preserving: ignored dictionary words with ID zero do not advance the parsed output index, so an unknown word after “the” reports output slot 1, not raw token 2. I’m coding a local source-model helper for normalization and parsed IDs.”

    Action/result: Added parser normalization and parsed-word helpers to tools/inspect_words.py.

  2173. Reported: “The parser helper is added. I’m extending tests/test_words.py now with source-visible normalization, zero-ID filtering, unknown-slot reporting, and the 10-word parsed buffer limit.”

    Action/result: Added parser/tokenizer tests.

  2174. Reported: “The WORDS tests now exercise the parser model. I’m running them; if any local word ID assumption is off, I’ll adjust from the decoded file rather than guessing.”

    Action/result: First tests.test_words run found that gem has local word ID 0x0174, not the assumed ID.

  2175. Reported: “One assumption was off: gem decodes to 0x0174, not the ID I casually reused from older notes. I’m correcting the test to the local dictionary value.”

    Action/result: Updated the test to assert the decoded gem ID from WORDS.TOK.

  2176. Reported: “The parser test now references the decoded dictionary value explicitly. I’m rerunning the WORDS tests.”

    Action/result: python3 -B -m unittest tests.test_words passed with 8 tests.

  2177. Reported: “The WORDS/parser tests pass. I’m updating the docs and symbolic label map with the parser tables and the corrected “output slot” wording for unknown words after ignored zero-ID terms.”

    Action/result: Began updating symbolic labels and parser documentation.

  2178. Reported: “I’m adding stable labels for the parser separator/ignored tables, dictionary base pointer, normalized buffer, and parsed pointer table. Those are exactly the sort of labels that will help when another interpreter build moves the code.”

    Action/result: Added parser data labels to docs/src/symbolic_labels.md.

  2179. Reported: “The data labels are in. I’m adding the companion routine labels for parse action, normalization, dictionary lookup, unknown-token truncation, and dictionary-entry advancement.”

    Action/result: Located the insertion point near input helpers.

  2180. Reported: “The label section had the view helper immediately after input mapping, so I’m inserting the word-parser routines in that slot.”

    Action/result: Added parser routine labels to docs/src/symbolic_labels.md.

  2181. Reported: “The routine labels are in. I noticed the parser’s current-token pointer also deserves a data label, so I’m adding that before updating the prose.”

    Action/result: Added data.words.current_parse_pointer_0cd1 to the symbolic label map.

  2182. Reported: “I’m updating the parser prose now, especially the zero-ID filtering and unknown-word position semantics. This is a small wording change, but it prevents a future implementation from reporting the wrong parser slot.”

    Action/result: Updated the parser section in docs/src/runtime_model.md.

  2183. Reported: “The runtime model now has the parser contract. I’m mirroring the output-slot correction in the bytecode chapter where the lower-level action 0x75 behavior is described.”

    Action/result: Located the parsed-input producer paragraph in docs/src/logic_bytecode.md.

  2184. Reported: “That paragraph had a slightly different shape than my patch context. I found it and am applying the correction directly.”

    Action/result: Updated the action 0x75 parser-result handling wording in docs/src/logic_bytecode.md.

  2185. Reported: “The bytecode chapter is corrected. I’m updating the compatibility chapter to mention the new local parser normalization/output-slot tests.”

    Action/result: Opened the parser edge section in docs/src/compatibility_testing.md.

  2186. Reported: “The compatibility chapter now points at the parser tests. I’m updating PROGRESS.md so the variables/parser row reflects the new source-modeled tokenizer coverage.”

    Action/result: Updated the variables/parser progress row.

  2187. Reported: “The tracker is updated. I’m adding the evidence note for the parser source-model pass with the exact helper addresses and test command.”

    Action/result: Added the parser normalization and output-slot model section to docs/src/clean_room_executable_notes.md.

  2188. Reported: “The parser evidence note is now in the clean-room log. I’m adding the progress-log entries for this parser pass, then I’ll run checks and continue.”

    Action/result: Added the parser pass progress entries to this log.

  2189. Reported: “The parser progress log is current. I’m running the WORDS tests and standard documentation/evidence checks now.”

    Action/result: Re-ran the parser tests and standard checks after the parser pass.

  2190. Reported: “The parser checks passed. I’m doing a quick tracker audit now so the next pass is guided by actual remaining gaps instead of inertia.”

    Action/result: Reviewed PROGRESS.md, the runtime model, symbolic labels, and compatibility notes for the next high-value subsystem.

  2191. Reported: “The startup/display docs are already broader than I expected, and the display globals are labeled. I’m going to avoid a speculative startup pass for now and instead harden the final compatibility suite: first by running the full local unit suite to catch integration fallout from the new helpers.”

    Action/result: Started the full local unit suite.

  2192. Reported: “The full local suite passes: 205 tests, including the carousel harness tests that build snapshot disks. That gives a good integration checkpoint after the renderer, sound, and parser additions.”

    Action/result: python3 -B -m unittest discover -s tests passed with 205 tests.

  2193. Reported: “I’m going to strengthen the memory/heap row next with a small local source model for allocator/status formulas. The docs already describe them; adding executable tests makes those formulas part of the compatibility suite rather than just prose.”

    Action/result: Began the heap formula test-model pass.

  2194. Reported: “The heap source pass matches the docs cleanly. I’m adding a tiny agi_heap helper module with allocation, free-byte, mark/rewind, reset, and diagnostic formulas, then focused tests to make those formulas executable.”

    Action/result: Added tools/agi_heap.py with source-modeled heap helper formulas.

  2195. Reported: “I’m picking up exactly where the compaction left off: the heap helper has been added, and I’m turning that source-derived model into tests and documentation now. After that I’ll keep working down PROGRESS.md rather than stopping at this checkpoint.”

    Action/result: Inspected working-tree state and the memory/heap tracker row.

  2196. Reported: “The working tree is in the expected state: lots of reverse-engineering edits already staged only in the filesystem, no commit. I’m going to keep the next edits tightly scoped: heap tests, the evidence notes, and the progress dashboard.”

    Action/result: Read the relevant PROGRESS.md, compatibility_testing.md, progress_log.md, and clean-room notes sections.

  2197. Reported: “I’ve got the heap source model and the existing docs lined up. Next I’m adding tests that pin the old-top return value, free-memory page byte, temporary mark restore, room reset rewind, and diagnostic formulas.”

    Action/result: Added tests/test_heap.py.

  2198. Reported: “The heap tests are in. I’m doing one quick readability pass on the helper itself before running them, mostly to keep the return-value formulas easy to inspect later.”

    Action/result: Reformatted long return paths in tools/agi_heap.py.

  2199. Reported: “The helper now reads cleanly. I’m running the new focused heap tests first, then I’ll document the source addresses and fold the result into the progress tracker.”

    Action/result: python3 -B -m unittest tests.test_heap passed with 7 tests.

  2200. Reported: “The heap tests pass: 7 focused checks. I’m recording this as executable compatibility evidence now, with the caveat that it models the source formulas rather than a visible out-of-memory dialog.”

    Action/result: Began updating compatibility notes, clean-room notes, and PROGRESS.md for the heap model.

  2201. Reported: “The heap evidence is now in the docs and dashboard. I’m running the standard checks plus the full local suite so the new helper lands on the same footing as the parser and renderer work.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest discover -s tests passed; the full suite ran 212 tests.

  2202. Reported: “All checks passed, including the full suite now at 212 tests. I’m moving back to the highest-value queue: renderer compatibility, starting by auditing picture/view docs and tests for the next real source-backed gap instead of inventing a random probe.”

    Action/result: Audited renderer docs, tests, and helpers for picture/view coverage gaps.

  2203. Reported: “The renderer docs are dense, but a useful next gap stands out: the view/cel side has good layout coverage and carousel validation, while the low-level run decoder and mirror/orientation helpers could use more executable tests tied to source offsets. I’m checking the disassembly and local implementation around those routines now.”

    Action/result: Reviewed the view-frame decoder implementation, view/cel documentation, graphics tests, and symbolic/evidence notes for the bit-0x80 mirror path.

  2204. Reported: “The mirror model is already QEMU-validated for real resources, but the executable tests only cover one natural sample. I’m rereading code.object.rewrite_frame_orientation so the next tests capture source-visible edge cases like all-transparent rows and long implicit transparent padding.”

    Action/result: Disassembled 0x587d and nearby placement helpers and re-read the earlier orientation-rewrite evidence note.

  2205. Reported: “The source confirms the important rewrite details: leading transparent runs are skipped until the first visible run, all-transparent rows collapse to an empty row, and implicit trailing transparency is emitted in 15-pixel chunks before reversing the counted run bytes. I’m adding those as direct local tests.”

    Action/result: Added focused mirror-row tests to tests/test_graphics_rendering.py.

  2206. Reported: “The mirror edge tests are added. I’m running the graphics suite now; if any expected run differs, I’ll go back to the 0x587d instruction flow rather than massaging the tests.”

    Action/result: First graphics test run found an arithmetic mistake in one expected transparent-run length.

  2207. Reported: “The failing mirror test was my arithmetic, not the model: that row’s explicit width is 10, so the mirrored implicit transparent run is 10 pixels (0x1a), not 9. I’m correcting the expected byte and rerunning.”

    Action/result: Corrected the expected run byte; python3 -B -m unittest tests.test_graphics_rendering passed with 57 tests.

  2208. Reported: “The graphics suite passes with 57 tests. I’m documenting the new mirror edge coverage now so it’s clear these are source-derived row-rewrite semantics, not just arbitrary Python behavior.”

    Action/result: Began documenting the mirror edge tests in the compatibility chapter, graphics/object pipeline, clean-room notes, and progress tracker.

  2209. Reported: “The view mirror edge pass is documented. I’m doing a quick source/test scan around the object priority gate next; that’s the other renderer edge called out in PROGRESS.md, and it’s tightly tied to valid object/view drawing.”

    Action/result: Reviewed object priority-gate tests, graphics helper code, symbolic/evidence notes, and attempted an initial base-executable slice.

  2210. Reported: “The priority-gate test coverage already has the main “higher priority” and “scan downward” cases. I’m checking the overlay file offsets carefully now, because this draw routine lives in the object overlay rather than the base executable and I don’t want to cite the wrong binary slice.”

    Action/result: Confirmed SQ2/IBM_OBJS.OVL contains the object-overlay draw entry and re-read the earlier evidence note.

  2211. Reported: “The overlay disassembly shows a couple of priority-gate edges worth pinning: a low-control destination can still draw if the downward scan finds an equal priority, and rejected pixels inside a run don’t abort the rest of the run. I’m adding local tests for those exact source branches.”

    Action/result: Added object-overlay priority-gate edge tests to tests/test_graphics_rendering.py.

  2212. Reported: “The priority-gate tests are in. I’m running the graphics suite again; this gives us a tighter local oracle for object-over-picture composition without launching QEMU.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering passed with 60 tests.

  2213. Reported: “The graphics suite is now at 60 tests. I’m writing down the object-overlay priority-gate edges with the IBM_OBJS.OVL:0x9e35 branch points, then I’ll run the standard checks again.”

    Action/result: Began documenting the object-overlay priority gate edge tests and updating the progress tracker.

  2214. Reported: “The renderer edge docs are updated. I’m running the standard doc/evidence checks and full test suite again before choosing the next PROGRESS.md item.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest discover -s tests passed; the full suite ran 219 tests.

  2215. Reported: “All checks passed; the full suite is now 219 tests. I’m shifting back to picture bytecode next, looking for valid synthetic cases that the source says are real but the current QEMU corpus may not exercise, especially the rare 0xf4/0xf5 corner-path commands.”

    Action/result: Audited tools/picture_fuzz.py, picture fuzz tests, and renderer docs; confirmed curated QEMU evidence already includes corner path cases.

  2216. Reported: “The corner-path corpus is better covered than I first suspected: both 0xf4 and 0xf5 are already in curated QEMU fuzz evidence, plus local point-set tests. I’m moving to the parser/input side now to see whether the source-backed tokenizer has a matching condition model, since that is important for a portable implementation.”

    Action/result: Audited parser docs, inspect_words.py, parser tests, and opcode evidence for condition 0x0e.

  2217. Reported: “The parser docs already describe the wildcard and terminator behavior, but I don’t see a small local matcher in the tools yet. I’m rereading condition handler 0x095c and will add that model if the source shape is clean.”

    Action/result: Disassembled condition handler 0x095c and re-read the runtime/bytecode parser sections.

  2218. Reported: “The source shape is clean and a little subtle: the terminator word 0x270f succeeds immediately after the previous matches and skips any remaining operand words, while an extra non-terminator after all parsed words are consumed fails. I’m adding a small matcher helper and tests for those cases.”

    Action/result: Added input_word_sequence_matches() and result dataclass to tools/inspect_words.py.

  2219. Reported: “I’m making the matcher small but explicit: it takes the parsed IDs plus parser flags, and returns whether the condition matches, whether flag 4 would be set, and how many operand words were skipped after a terminator or mismatch. That mirrors the handler’s control flow without importing the whole logic VM.”

    Action/result: Completed the local matcher implementation.

  2220. Reported: “The matcher and tests are in. I included one source-derived edge that is easy to miss: a terminator-only pattern can match an unknown parse state because the parser count/error-position is nonzero and flag 2 is set.”

    Action/result: Added parser matcher tests to tests/test_words.py.

  2221. Reported: “The local WORDS suite passes with 13 tests. Because the terminator-on-unknown behavior is surprising, I’m checking whether the existing QEMU probe harness can validate it with one small generated logic case.”

    Action/result: python3 -B -m unittest tests.test_words passed with 13 tests; inspected parser cases in tools/logic_interpreter_probe.py.

  2222. Reported: “The harness can validate this cheaply. I’m adding one parser-edge fixture that parses an unknown word and then tests a terminator-only 0x0e pattern, which should draw if the source model is right.”

    Action/result: Added input_word_sequence_terminator_matches_unknown_word to tools/logic_interpreter_probe.py and its harness test.

  2223. Reported: “The new parser-edge fixture is wired into the harness. I’m running the relevant unit tests first, then I’ll use QEMU for just this one behavior check.”

    Action/result: python3 -B -m unittest tests.test_logic_interpreter_probe tests.test_words passed with 26 tests, and opcode evidence check passed.

  2224. Reported: “The parser and harness unit tests pass. I’m running the single QEMU parser-edge case now to confirm the unknown-word terminator behavior against the original engine.”

    Action/result: QEMU batch parser_unknown_terminator_001 matched the original engine with 1 match, 0 mismatches, and 0 errors.

  2225. Reported: “The QEMU probe matched: the original engine does draw for a terminator-only word sequence after parsing an unknown token. I’m updating the spec text and evidence trail because that’s a real compatibility edge, not just a local helper detail.”

    Action/result: Updated parser/runtime/compatibility docs, symbolic labels, PROGRESS.md, and opcode evidence generator.

  2226. Reported: “I’m also updating the generated opcode-evidence source entry for condition 0x0e, since the condition now has a richer QEMU-backed edge case than the older one-line probe reference.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md.

  2227. Reported: “I’ve got the doc insertion points. The wording here needs to be precise: 0x270f is not “end of all parsed input”; it is an immediate successful terminator for the condition pattern once the parser state is otherwise eligible.”

    Action/result: Refined parser wording in the bytecode and runtime model.

  2228. Reported: “The parser spec text and label map are updated. I changed the opcode-evidence generator too, so I’m regenerating its mdBook chapter before continuing the evidence note.”

    Action/result: Ran python3 -B tools/logic_opcode_evidence.py.

  2229. Reported: “The opcode-evidence chapter is regenerated. I’m adding the clean-room note and progress-log entries for the parser matcher/QEMU confirmation now.”

    Action/result: Added the input-word sequence matcher evidence note and progress-log entries.

  2230. Reported: “The parser matcher evidence is in. I’m running the standard checks again, including the full suite, because this touched generated opcode evidence, logic-probe cases, and parser helpers.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest discover -s tests passed; the full suite ran 224 tests.

  2231. Reported: “The parser pass checks are clean; the full suite is now 224 tests. I’m looking at the compatibility-harness gap next: there are many strong individual probes, but a single manifest/runner would make the final suite easier to reproduce across future games and interpreter versions.”

    Action/result: Audited existing compatibility docs, tools, tests, and PROGRESS.md for a top-level suite runner gap.

  2232. Reported: “I’m going to add a lightweight suite manifest/runner rather than another ad hoc command list. The default will run only local checks; QEMU smoke and broad sweeps stay opt-in so future agents can choose the right cost level.”

    Action/result: Added tools/compatibility_suite.py.

  2233. Reported: “The suite runner is in place. I’m adding tests around the manifest and command selection/execution plumbing, with subprocess calls mocked so the normal unit suite stays fast and deterministic.”

    Action/result: Added tests/test_compatibility_suite.py.

  2234. Reported: “The runner tests are ready. I’m running the focused suite tests and doing a dry-run manifest check so we know the new tool is usable without triggering QEMU by accident.”

    Action/result: python3 -B -m unittest tests.test_compatibility_suite passed with 6 tests; dry-run output listed local checks by default and included QEMU smoke only with --include-qemu-smoke.

  2235. Reported: “The suite manifest behaves as intended: local-only by default, QEMU smoke opt-in. I’m running the default runner once now so it writes a real report and proves the plumbing outside mocks.”

    Action/result: python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_001.json passed, running 230 unit tests, building mdBook, and checking opcode evidence.

  2236. Reported: “The default suite runner passed and wrote a local report under build/compatibility-suite/. I’m documenting the runner in the compatibility chapter and AGENTS so future work uses it as the top-level entry point.”

    Action/result: Updated AGENTS.md, docs/src/compatibility_testing.md, PROGRESS.md, and clean-room notes for the compatibility suite runner.

  2237. Reported: “The suite runner is documented. I’m running the standard checks once more after the docs/AGENTS updates, then I’ll reassess PROGRESS.md for what is genuinely left versus what is waiting on future game/interpreter inputs.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest discover -s tests passed; the full suite ran 230 tests.

  2238. Reported: “The checks pass again: mdBook, opcode evidence, diff check, and 230 tests. I’m doing a tracker audit now to separate actionable SQ2 work from items that are intentionally waiting for future interpreter versions or optional hardware paths.”

    Action/result: Reviewed the current PROGRESS.md remaining-work rows and working-tree state.

  2239. Reported: “The audit shows most remaining SQ2 items are either optional UI/hardware paths or future cross-version work. One still-actionable row is sound: we have event scheduling and port-write formulas, but not a compact implementation-facing “audible channel state” helper, so I’m checking the current sound model before deciding how far that can be taken cleanly from source.”

    Action/result: Reviewed tools/agi_sound.py, sound tests, sound docs, and the existing driver-output source notes.

  2240. Reported: “The sound row is already stronger than it looked: scheduling, PC-speaker divisor, non-PC tone bytes, and attenuation envelopes are all source-backed. I’m checking the driver tick around 0x801c to avoid inventing an “audio synthesis” layer beyond what the interpreter actually outputs.”

    Action/result: Disassembled code.sound.driver_tick and re-read runtime sound documentation.

  2241. Reported: “There’s one sound improvement I can make without overreaching into synthesis: model the actual non-PC tone bytes and stop-silence bytes the driver writes, alongside the existing PC-speaker divisor. That keeps the spec at the interpreter’s hardware-output boundary, which is what the source directly gives us.”

    Action/result: Added SoundToneOutput, sound_tone_output(), and sound_stop_silence_output() to tools/agi_sound.py.

  2242. Reported: “The sound tone-output helper is added. I’m extending the sound tests to pin PC-speaker silence/enable state, non-PC high/low byte writes, high-byte suppression of the low byte, and stop-core silence output.”

    Action/result: Added tone/silence output tests to tests/test_sound_resources.py.

  2243. Reported: “The sound tests now cover the port-output boundary. I’m running them to catch any mismatch against the source formulas.”

    Action/result: python3 -B -m unittest tests.test_sound_resources passed with 16 tests.

  2244. Reported: “The sound tests pass at 16 cases. I’m updating the sound docs to mark the port-output boundary as executable evidence, while keeping physical waveform synthesis out of scope unless we later need it.”

    Action/result: Updated sound sections in the runtime model, compatibility chapter, PROGRESS.md, and clean-room notes.

  2245. Reported: “The sound port-output model is documented. I’m running the standard checks again; after that I’ll decide whether the remaining PROGRESS.md rows need more SQ2 work or are genuinely deferred.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest discover -s tests passed; the full suite ran 232 tests.

  2246. Reported: “The checks pass at 232 tests. The one fully blank tracker row is cross-version workflow; we can’t apply it to another interpreter until you provide one, but I can still document the repeatable workflow and what evidence to capture so that row is no longer an empty placeholder.”

    Action/result: Reviewed mdBook summary, symbolic-label rules, and existing cross-version references.

  2247. Reported: “I’m adding a dedicated cross-version workflow chapter to mdBook. It won’t pretend we’ve compared another interpreter yet; it will define the evidence package, label-mapping method, and compatibility-suite layers to use when the next game/version arrives.”

    Action/result: Added docs/src/cross_version_workflow.md, linked it from docs/src/SUMMARY.md, updated PROGRESS.md, and recorded the evidence note.

  2248. Reported: “I’ve got the thread context and the AGENTS rules in hand. I’m picking up at the compatibility-suite/QEMU smoke validation point: the local suite was passing, but the QEMU smoke layer hit a sandbox VNC socket bind error, so I’m going to rerun that through the approved escalation path rather than treating it as an engine failure.”

    Action/result: Reran python3 -B tools/compatibility_suite.py --include-qemu-smoke --report build/compatibility-suite/qemu_smoke_001.json with local VNC/socket access.

  2249. Reported: “The escalated run is past the local test/mdBook/opcode layers and is now inside the QEMU smoke probes. Good sign so far: this is exercising the same engine fixtures through the compatibility runner rather than a one-off command.”

    Action/result: The local unit suite passed with 232 tests, mdBook built, opcode evidence checked cleanly, and the parser-edge QEMU batch began.

  2250. Reported: “The parser edge smoke cases matched the original engine. The run has moved on to the unknown-word terminator probe, which is the small but important “condition terminator accepts this parser state” case we added earlier.”

    Action/result: parser_edges_suite.json reported 3 matches, 0 mismatches, and 0 errors.

  2251. Reported: “The second parser QEMU probe matched too. Now it’s running the picture fuzz smoke set that specifically checks command-resume semantics for line, corner, and fill commands against the real interpreter.”

    Action/result: parser_unknown_terminator_suite.json reported 1 match, 0 mismatches, and 0 errors.

  2252. Reported: “The command-resume fuzz cases matched all three. The final smoke group is the raw-operand picture decoder behavior, which is useful for valid-but-odd byte streams without wandering into exploit/garbage- memory territory.”

    Action/result: command_resume_suite.json reported 3 matches, 0 mismatches, and 0 errors.

  2253. Reported: “The escalated QEMU smoke run finished successfully. I’m going to fold that result back into the project docs/progress tracker now, including the earlier sandbox-only failure so the evidence trail is honest.”

    Action/result: raw_operand_suite.json reported 3 matches, 0 mismatches, and 0 errors; the compatibility-suite process exited zero.

  2254. Reported: “The JSON report confirms every selected layer returned 0: local unit tests, mdBook, opcode evidence, and all four QEMU smoke commands. I’m updating the book and tracker with the suite-level result rather than leaving those as isolated probe runs.”

    Action/result: Updated the compatibility chapter, progress tracker, clean-room notes, and this progress log with the qemu_smoke_001.json suite result.

  2255. Reported: “With the smoke layer recorded, I’m moving to the next high-value item in PROGRESS.md: broad picture/view compatibility. First I’m checking the suite manifest so I know exactly which QEMU batches --include-qemu-broad will run.”

    Action/result: Confirmed that broad mode selects the local checks, QEMU smoke layer, eight-picture broad carousel, and 19-case view/object stress carousel.

  2256. Reported: “The broad flag includes the smoke layer plus two larger resource sweeps: the eight-picture timed carousel and the current 19-case view/object stress carousel. I’m going to run that as a suite report now; it’s exactly the kind of reusable validation layer PROGRESS.md is asking us to grow.”

    Action/result: Started python3 -B tools/compatibility_suite.py --include-qemu-broad --report build/compatibility-suite/qemu_broad_001.json.

  2257. Reported: “The broad suite is through the local layers and has started the smoke probes. Since --include-qemu-broad deliberately includes smoke too, this gives us a single report that proves both the targeted edge probes and the larger resource carousels in one pass.”

    Action/result: The local unit suite passed with 232 tests, mdBook built, opcode evidence checked cleanly, and the parser-edge smoke batch began.

  2258. Reported: “Smoke parser edges are matching again inside the broad run. I’m letting it continue into the picture-fuzz probes and then the broader picture/view carousel sweeps.”

    Action/result: Parser-edge smoke probes matched 3/3.

  2259. Reported: “The unknown-word terminator QEMU probe matched. The command-resume picture fuzz batch is underway now; after that, the broad resource sweeps should start.”

    Action/result: Unknown-word terminator smoke probe matched 1/1.

  2260. Reported: “Command-resume matched all three again. The raw-operand picture fuzz smoke batch is running now; this is the last small probe before the broad picture carousel.”

    Action/result: Command-resume picture fuzz smoke probes matched 3/3.

  2261. Reported: “The smoke layer is clean inside the broad run. We’re into the eight-picture timed carousel now, which keeps one original-engine process alive and polls captures until each expected picture appears.”

    Action/result: Raw-operand picture fuzz smoke probes matched 3/3; the broad picture carousel began.

  2262. Reported: “Five of the eight broad-picture carousel captures have matched so far. This is the useful fast path for future multi-game sweeps, because we’re validating several real resources without rebooting DOS per case.”

    Action/result: The broad picture carousel was progressing through the expected SQ2 picture list.

  2263. Reported: “The broad picture carousel matched all eight. The view/object stress carousel has started, and the first view case has already matched.”

    Action/result: picture_carousel_broad_suite.json matched 8/8 with 0 mismatches and 0 errors; the view/object stress carousel began.

  2264. Reported: “The view carousel is progressing cleanly through normal and clipping cases. I’m watching for priority/control edge cases later in the sequence, since those are the ones most likely to reveal renderer-contract mistakes.”

    Action/result: View/object stress carousel matched the first 6 cases.

  2265. Reported: “Twelve of nineteen view/object cases have matched, including the low-priority and several transparent-color variants. The remaining cases are the stress overlays and line/priority combinations.”

    Action/result: View/object stress carousel matched 12/19 cases.

  2266. Reported: “Seventeen of nineteen matched now. The broad suite is in the final stretch of the view/object carousel.”

    Action/result: View/object stress carousel matched 17/19 cases.

  2267. Reported: “The broad suite exited cleanly. It matched all eight broad picture cases and all nineteen current view/object stress cases from one-engine carousel runs, so I’m recording that suite-level report next.”

    Action/result: view_carousel_stress_suite.json matched 19/19 with 0 mismatches and 0 errors; qemu_broad_001.json recorded return code 0 for every selected command.

  2268. Reported: “I’m folding the broad suite into the docs now. After that I’ll go back to source-first renderer work, using these QEMU reports as regression evidence rather than as the primary discovery method.”

    Action/result: Updated the compatibility chapter, progress tracker, clean-room notes, and this progress log with the qemu_broad_001.json suite result.

  2269. Reported: “The broad suite is documented. Next I’m going source-first again: I’ll inspect the picture/view renderer progress rows and the symbolic labels to find a concrete edge where the disassembly can still sharpen the implementation contract.”

    Action/result: Re-read picture/view rows in PROGRESS.md, renderer labels in docs/src/symbolic_labels.md, and graphics/compatibility docs.

  2270. Reported: “The tracker is now pointing at two renderer gaps: picture edge semantics for valid streams, and broader view/object priority-control interactions. I hit two stale chapter names while searching, so I’m listing the docs and then I’ll drill into the current graphics chapter plus the disassembly labels.”

    Action/result: Confirmed the active graphics docs live in docs/src/graphics_object_pipeline.md and docs/src/resource_files.md.

  2271. Reported: “The existing docs already carry a lot of renderer detail. I’m checking the local renderer code and tests for explicit gaps now, because the best next step is likely to codify one source-backed edge as a deterministic test/model rather than adding another broad capture.”

    Action/result: Reviewed tools/agi_graphics.py, tests/test_graphics_rendering.py, tests/test_picture_fuzz.py, and tools/picture_fuzz.py.

  2272. Reported: “The local picture renderer is fairly complete, but one place worth source-checking is relative line decoding and clamping: it is simple in Python, yet edge behavior around signed nibbles and boundaries is exactly the sort of thing a future implementation can get subtly wrong. I’m going back to the disassembly for 0xf7 and the shared line helper before adding anything.”

    Action/result: Disassembled code.picture.cmd_draw_relative_lines (0x665e) and code.picture.draw_line (0x66e1).

  2273. Reported: “The source confirms a boundary nuance in 0xf7: negative relative deltas are unsigned 8-bit subtraction, then clamped only on the high side. That means underflow clamps to the right/bottom edge, not to 0, so the current Python helper is too “reasonable” for that edge. I’m going to patch the renderer and add tests/fuzz cases from the disassembly.”

    Action/result: Identified the source-backed relative-line underflow rule.

  2274. Reported: “I’m making the renderer match the source rather than the intuitive clamp. The key edit is small: relative deltas wrap in an 8-bit register before the helper clamps values above the screen maximum.”

    Action/result: Updated PictureRenderer.draw_relative_lines() and added local graphics tests plus two curated picture-fuzz cases.

  2275. Reported: “The code and deterministic tests are patched. I’m running the focused renderer/fuzz tests first; if those pass, I’ll run the new two-case QEMU batch to confirm the source reading against the original engine.”

    Action/result: tests.test_graphics_rendering passed with 62 tests and tests.test_picture_fuzz passed with 13 tests.

  2276. Reported: “The focused local tests passed: graphics is at 62 tests and picture fuzz at 13. Now I’m running the two new relative-underflow picture fixtures in QEMU as confirmation, with source still being the primary evidence.”

    Action/result: The first QEMU attempt failed before launching QEMU because the on-disk fuzz corpus did not yet include the new base-case directories.

  2277. Reported: “The QEMU batch didn’t reach QEMU yet: the corpus on disk predates the new base cases, so the harness couldn’t find their case.json files. I’m regenerating the local fuzz corpus, then I’ll rerun the same confirmation batch.”

    Action/result: Regenerated build/picture-fuzz/corpus; it now contains 1,062 cases, 1,060 marked safe for QEMU.

  2278. Reported: “The regenerated corpus now has 1,062 total cases, with 1,060 marked safe for QEMU. The two new relative-underflow cases are in that safe set, so I’m rerunning the original-engine confirmation batch.”

    Action/result: relative_underflow_001 matched both cases in QEMU with 0 mismatches and 0 errors.

  2279. Reported: “The original engine matched both relative-underflow fixtures. Since this is a compact, source-backed renderer edge, I’m going to promote it into the compatibility suite’s QEMU smoke layer so future runs don’t lose it.”

    Action/result: Added picture_fuzz_relative_underflow_qemu to tools/compatibility_suite.py and updated the suite manifest test.

  2280. Reported: “The new underflow probe is now part of the smoke manifest. I’m running the suite-manifest tests and then I’ll produce a fresh smoke report that includes this new command.”

    Action/result: tests.test_compatibility_suite passed and the smoke dry-run listed the new relative-underflow command.

  2281. Reported: “The manifest tests pass and the dry-run shows the new relative-underflow smoke command. I’m running the updated QEMU smoke suite now so the report reflects the current manifest, not the previous one.”

    Action/result: Started python3 -B tools/compatibility_suite.py --include-qemu-smoke --report build/compatibility-suite/qemu_smoke_002.json.

  2282. Reported: “The updated smoke suite is through the expanded local tests: 235 unit tests now pass, reflecting the new renderer and suite tests. It’s in the QEMU parser probes again.”

    Action/result: Local tests, mdBook, and opcode-evidence check completed inside the smoke runner.

  2283. Reported: “Parser smoke is progressing normally. I’m waiting it through to the new relative-line underflow QEMU command, which is the fresh evidence this run is meant to capture.”

    Action/result: Parser-edge smoke was in progress.

  2284. Reported: “The parser QEMU probes matched. The suite is now in the existing picture-fuzz smoke checks before it reaches the new underflow pair.”

    Action/result: Parser-edge smoke matched 3/3 and unknown-word terminator matched 1/1.

  2285. Reported: “Command-resume matched all three. Raw-operand smoke is running now; after this, the updated suite should execute the new relative-underflow command.”

    Action/result: Command-resume smoke matched 3/3.

  2286. Reported: “Raw-operand smoke matched, and the fresh relative-underflow command is now running inside the suite report. This is the one that proves the 8-bit wrap-and-clamp behavior against QEMU.”

    Action/result: Raw-operand smoke matched 3/3.

  2287. Reported: “The updated smoke suite passed, including the new relative-underflow command. I’m updating the renderer prose, compatibility evidence, and progress tracker so this edge is no longer just a local code change.”

    Action/result: qemu_smoke_002.json exited zero; the relative-underflow suite batch matched 2/2.

  2288. Reported: “One bit of bookkeeping: regenerating the corpus made the old “1,060-case corpus” wording stale. The new state is 1,062 total cases, 1,060 safe for QEMU, so I’m correcting that wherever it matters.”

    Action/result: Searched active docs and tracker for stale corpus/report wording.

  2289. Reported: “I found the expected stale corpus mentions in the progress tracker, compatibility chapter, and earlier raw-operand notes. I’m leaving historical progress-log entries alone unless they’re current documentation, but I’ll update the active spec/tracker text and add a new clean-room note for the relative-line source finding.”

    Action/result: Prepared documentation updates for the active compatibility and progress surfaces.

  2290. Reported: “I’m also going to add the relative-underflow rule to the compact runtime contract, not only the graphics chapter. That way a future implementation has the high-level rule in the spec section and the disassembly-backed detail in the evidence section.”

    Action/result: Located the exact runtime-model and graphics-pipeline anchors.

  2291. Reported: “I’ve got the exact anchors. The docs update will say the relative endpoint is produced by 8-bit register arithmetic, then clamped only if it exceeds the screen maximum; that phrasing avoids implying a symmetric clamp to zero.”

    Action/result: Updated docs/src/graphics_object_pipeline.md and docs/src/runtime_model.md.

  2292. Reported: “That patch was too broad and one context line had drifted, so I’m splitting it into smaller edits. Same content, just less brittle.”

    Action/result: Retried the documentation patch in smaller chunks.

  2293. Reported: “The renderer contract text is updated. I’m patching the compatibility chapter next, including the current smoke report name and the corpus count.”

    Action/result: Updated the compatibility-suite command and smoke report description to qemu_smoke_002.json.

  2294. Reported: “The current smoke report now points to qemu_smoke_002. I’m adding the specific relative-underflow batch to the picture-fuzz evidence list.”

    Action/result: Added relative_underflow_001 to the compatibility chapter’s fuzz evidence list.

  2295. Reported: “The edge batch is recorded. I’m correcting the corpus count in the same chapter now.”

    Action/result: Updated the active fuzz corpus count to 1,062 cases, 1,060 QEMU-safe.

  2296. Reported: “Compatibility chapter is current. I’m updating PROGRESS.md so the dashboard reflects both the new 0xf7 edge and the expanded smoke suite.”

    Action/result: Updated the picture and compatibility-suite rows in PROGRESS.md.

  2297. Reported: “The dashboard is updated. I’m adding the clean-room note with the exact disassembly commands and QEMU confirmation for the underflow rule.”

    Action/result: Added the clean-room note for the picture relative-line underflow edge.

  2298. Reported: “The progress log is caught up through the underflow work. I’m running the standard validation now: mdBook, opcode evidence freshness, whitespace, and the full unit suite.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest discover -s tests passed; the full unit suite ran 235 tests.

  2299. Reported: “Validation passed: mdBook, opcode evidence, diff check, and 235 unit tests are clean. I’m recording that result, then I’ll continue with the next source-first renderer/object item from PROGRESS.md.”

    Action/result: Added the validation result to this progress log.

  2300. Reported: “For the next renderer-side gap, I’m looking at the object placement/control acceptance path. The tracker says full object-record placement fixtures are optional, but the disassembly may still let us tighten the implementation-facing model without inventing new behavior.”

    Action/result: Re-read tools/agi_graphics.py, the control-acceptance tests, graphics docs, and disassembly for code.object.control_acceptance at 0x56b8.

  2301. Reported: “The control-acceptance helper already has a good source model, but I see a small unpinned edge in the local tests: high nibbles outside 0x00..0x30 are treated as nonzero/pass-through classes with final state (flag3=false, flag0=false). I’m adding direct tests for that source branch before hunting a larger placement fixture.”

    Action/result: Identified source-branch coverage for the other-nonzero class state and priority-15 bypass path.

  2302. Reported: “The test anchor shifted a little, so I’m reading the immediate test block and will insert the new cases at the right spot.”

    Action/result: Located the control-acceptance test block in tests/test_graphics_rendering.py.

  2303. Reported: “Found the right insertion point. I’m adding the direct source-branch tests now.”

    Action/result: Added local tests for other-nonzero high-nibble classes and priority-15 scan bypass/event-flag clearing.

  2304. Reported: “The source-branch tests are in. I’m running the graphics suite to make sure the local control-acceptance model still lines up cleanly.”

    Action/result: python3 -B -m unittest tests.test_graphics_rendering passed with 64 tests.

  2305. Reported: “Graphics tests pass at 64. I’m documenting this as a local source-model tightening rather than a QEMU result: it pins the remaining class-state branches in 0x56b8.”

    Action/result: Updated the progress tracker, compatibility chapter, clean-room notes, and this progress log for the control-acceptance branch tests.

  2306. Reported: “Since the broad suite includes the smoke layer, qemu_broad_001 is now slightly stale: it predates the relative-underflow smoke command. I’m going to run a fresh broad report so the top-level compatibility suite is current end to end.”

    Action/result: Started python3 -B tools/compatibility_suite.py --include-qemu-broad --report build/compatibility-suite/qemu_broad_002.json.

  2307. Reported: “The refreshed broad suite is through local checks with 237 tests now passing. It’s in the smoke probes first, and then it will rerun the broad picture and view carousels.”

    Action/result: Local tests, mdBook, and opcode-evidence check completed inside the refreshed broad runner.

  2308. Reported: “Parser edge smoke matched again inside the refreshed broad suite. The run is continuing through the rest of smoke before the resource carousels.”

    Action/result: Parser-edge QEMU probes matched 3/3.

  2309. Reported: “The unknown-word parser terminator probe matched. Command-resume picture fuzz is running now.”

    Action/result: Unknown-word terminator probe matched 1/1.

  2310. Reported: “Command-resume matched. Raw operands are next, then the refreshed relative-underflow pair.”

    Action/result: Command-resume picture fuzz probes matched 3/3.

  2311. Reported: “Raw operands matched. The relative-underflow pair is now running as part of the refreshed broad suite.”

    Action/result: Raw-operand picture fuzz probes matched 3/3.

  2312. Reported: “The refreshed smoke layer, including relative underflow, matched. The broad picture carousel has started and has already matched its first two pictures.”

    Action/result: Relative-underflow probes matched 2/2 and the broad picture carousel began.

  2313. Reported: “All eight picture carousel captures have appeared; it’s printing the per-case match summary now before moving into the view/object stress carousel.”

    Action/result: Broad picture carousel polling reached all 8 expected captures.

  2314. Reported: “The broad picture carousel matched all eight. The view/object carousel is underway and has matched the first four cases.”

    Action/result: picture_carousel_broad_suite.json matched 8/8 with 0 mismatches and 0 errors; view/object stress carousel began.

  2315. Reported: “Ten of nineteen view/object cases matched, including the clipping set and low-priority case. The transparent-color stress cases are next.”

    Action/result: View/object stress carousel matched 10/19 cases.

  2316. Reported: “Fifteen of nineteen matched. The broad suite is nearing the end of the view/object carousel.”

    Action/result: View/object stress carousel matched 15/19 cases.

  2317. Reported: “All nineteen view/object captures have appeared; it’s finishing the match summary now.”

    Action/result: View/object stress carousel polling reached all 19 expected captures.

  2318. Reported: “The refreshed broad suite exited cleanly: smoke, eight-picture carousel, and nineteen view/object cases all matched. I’m checking the report and then updating the docs from qemu_broad_001 to the current qemu_broad_002.”

    Action/result: Verified qemu_broad_002.json has return code 0 for every selected command.

  2319. Reported: “The report confirms every selected command returned zero, including the new picture_fuzz_relative_underflow_qemu. I’m updating the report references and broad-suite note now.”

    Action/result: Updated compatibility docs, PROGRESS.md, and clean-room notes to reference qemu_broad_002.json.

  2320. Reported: “The current broad report is documented. I’m adding the matching progress-log entries for the refreshed broad run.”

    Action/result: Added this progress-log batch for the refreshed broad compatibility run.

  2321. Reported: “With the suite current, I’m re-reading the remaining tracker items. I’ll keep taking the next source-backed item that can be advanced locally, and I’ll avoid turning optional future-version work into fake completion.”

    Action/result: Re-read the remaining PROGRESS.md subsystem rows and highest-value work list.

  2322. Reported: “The remaining list is now mostly conditional or future-input work. One still-actionable item is the final spec polish: turning dense notes into implementation-ready contracts. I’m going to start by checking whether the graphics/runtime chapters now duplicate or conflict after the new relative-line and control-acceptance additions.”

    Action/result: Searched active docs for stale report names, corpus counts, relative-underflow wording, and provisional/remaining-risk language.

  2323. Reported: “I found one active prose section that is lagging behind the evidence: the “Provisional areas” picture paragraph still says the renderer has only two real SQ2 resources, even though we now have all 74 via snapshot/chunked carousel. I’m tightening that section so the high-level status matches the tracker.”

    Action/result: Located the stale paragraph in docs/src/compatibility_testing.md.

  2324. Reported: “This is exactly the kind of spec-polish work left in PROGRESS: not new reversing, just removing stale or underspecified wording so another implementer gets the right confidence level.”

    Action/result: Updated the provisional picture-renderer paragraph with all-picture SQ2 coverage, raw operand, relative-underflow, and full-EGA mask-scope wording.

  2325. Reported: “The provisional picture paragraph now reflects the current all-picture SQ2 coverage and the new relative-underflow evidence. I’m logging that polish pass.”

    Action/result: Added this progress-log entry for the compatibility prose polish.

  2326. Reported: “Next I’m checking current_status.md, since that kind of summary page often drifts while the detailed chapters stay accurate. If it’s stale, I’ll bring it in line with the tracker and current suite reports.”

    Action/result: Reviewed docs/src/current_status.md and found stale focus/immediate-work text.

  2327. Reported: “current_status.md is indeed stale: it still says the immediate focus is “return to the logic interpreter,” while the tracker now says logic opcodes are covered and the active risk is renderer/spec polish/future-version breadth. I’m going to rewrite the handoff sections so the next agent starts from the actual current state.”

    Action/result: Updated the current-focus section with the completed logic opcode state, current compatibility-suite reports, relative-line underflow, and control-acceptance branch-test work.

  2328. Reported: “The top handoff summary is current now. I’m updating the graphics findings and immediate-next-work sections so they don’t send the next pass back toward already-completed opcode coverage.”

    Action/result: Updated confirmed graphics findings and immediate next work in docs/src/current_status.md.

  2329. Reported: “current_status.md still has a long old “Remaining Source-Backed Families” section underneath the handoff list. I’m checking the headings so I can either trim or rewrite it without accidentally dropping a useful later section.”

    Action/result: Confirmed the stale section was the final section of the file.

  2330. Reported: “The stale “Remaining Source-Backed Families” section is the final section, so I can replace it cleanly with a short deferred-work summary that points back to PROGRESS.md for detail.”

    Action/result: Replaced the stale long section with a compact deferred or conditional work summary.

  2331. Reported: “current_status.md is now a real handoff again: current suite reports, renderer edge state, immediate next work, and deferred items are all aligned with PROGRESS.md. I’m logging that documentation cleanup.”

    Action/result: Added this progress-log entry for the current-status cleanup.

  2332. Reported: “I’m doing a quick stale-reference scan now. If the active docs are clean, I’ll run validation again and then reassess whether the remaining PROGRESS.md items are genuinely blocked on future inputs or optional paths.”

    Action/result: Active summary/tracker docs had no stale qemu_smoke_001/qemu_broad_001 or old corpus-count references; old references remain only in chronological logs.

  2333. Reported: “The active summary pages are clean: stale qemu_smoke_001/ qemu_broad_001 and old corpus counts remain only in chronological logs, where they describe what happened at the time. I’m running the standard checks again after the handoff cleanup.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest discover -s tests passed; the full unit suite ran 237 tests.

  2334. Reported: “The standard checks passed again: mdBook, opcode evidence, diff check, and 237 tests. I’m updating PROGRESS.md’s high-value list so it reflects the current local stopping point instead of implying there is an obvious next SQ2 opcode batch still waiting.”

    Action/result: Rewrote the high-value remaining-work list to separate future-version blockers, source-first renderer edges, spec polish, compatibility-suite maintenance, and optional conditional paths.

  2335. Reported: “PROGRESS.md now separates real blockers from optional future work: additional interpreter inputs, new source-discovered renderer edges, continued spec polish, and manifest maintenance. I’m logging that and then I’ll run one final validation/status pass.”

    Action/result: Added this progress-log entry before the final validation pass.

  2336. Reported: “Final validation pass now: book, opcode-evidence check, whitespace check, full unit suite, then I’ll inspect the worktree status.”

    Action/result: mdbook build docs, python3 -B tools/logic_opcode_evidence.py --check, git diff --check, and python3 -B -m unittest discover -s tests passed; the full unit suite ran 237 tests.

  2337. Reported: “Final validation passed: mdBook, opcode evidence, diff check, and 237 tests. I’m recording that result, then doing a last status/diff-stat read.”

    Action/result: Added this final validation result to the progress log.

  2338. Reported: “Because the progress log changed after the validation pass, I’m doing a lightweight final docs/whitespace check plus status/diff stat.”

    Action/result: mdbook build docs and git diff --check passed. Git status shows the expected in-progress tracked edits plus untracked generated build/ artifacts and new project files.

  2339. Reported: “The lightweight check passed too, and the worktree is in the expected large in-progress state with generated build/ artifacts untracked. I’m adding one final progress-log note and then a last mdBook/whitespace check so the log itself is covered.”

    Action/result: Added this final progress-log note before the last lightweight check.

  2340. Reported: “I’ll stage the tracked project changes plus the new docs/tests/tools, leaving generated build/ artifacts and installer images out of the commit. I’ll make the commit message explicit that the work stops here because the remaining items are future-input dependent or optional/conditional rather than a concrete local task.”

    Action/result: Began the commit turn by reviewing status, diff stat, and this progress-log tail.

  2341. Reported: “I’ll treat this as a repo hygiene/setup task: first I’ll audit what build/ contains and what tracked files still point at it or the old MS-DOS installers, then I’ll replace those assumptions with a reproducible FreeDOS setup path before deleting anything.”

    Action/result: Started the build/MS-DOS cleanup pass by scanning active scripts, tests, docs, and git status.

  2342. Reported: “FreeDOS’ official download page currently presents FreeDOS 1.4 as the stable release, with a separate July 2026 test distribution. I plan to make the setup script pin stable 1.4 by default, with URL and checksum overrides so we can update it cleanly later.”

    Action/result: Chose FreeDOS 1.4 LiteUSB as the reproducible default for the setup script and planned override flags for future releases.

  2343. Reported: “I found the new external game copy under games/SQ2, and the only untracked top-level directories right now are games/, build/, and 002962_ms_dos_622/. I’ll keep games/ ignored and private, and make the scripts look there only through a configurable path.”

    Action/result: Confirmed the game data is outside tracked files and added ignore rules for private/generated directories.

  2344. Reported: “I’m going to add a small path helper rather than sprinkling new literals around: game data should come from AGI_GAME_DIR, while QEMU defaults should move from the old MS-DOS image to a generated FreeDOS image.”

    Action/result: Added tools/project_paths.py and began replacing direct SQ2/ and build/dos622/dos622.img assumptions in active tooling.

  2345. Reported: “For the disk image setup, I’m aiming for a script that downloads the FreeDOS USB image, verifies its checksum, extracts the raw image, and optionally copies a local game directory into it. I’m also teaching the QEMU helpers to detect the FAT partition offset instead of assuming the old sector-63 layout.”

    Action/result: Added mtools partition-offset auto-detection to the QEMU snapshot helpers and started the FreeDOS setup script.

  2346. Reported: “Understood. I’m correcting the half-step I made before the interruption: no games/SQ2 fallback. The tooling can accept AGI_GAME_DIR and I’ll add explicit --game-dir where practical, but an omitted game directory should fail loudly instead of silently picking SQ2.”

    Action/result: Removed the implicit SQ2 default and made game_dir() require either --game-dir PATH or AGI_GAME_DIR=PATH.

  2347. Reported: “I’m going to use a single project-level --game-dir PATH/ AGI_GAME_DIR mechanism for the existing tools. A few scripts import shared resource helpers before their own argument parsing runs, so the helper will consume the global --game-dir option early; that keeps the existing tool surface working without copying path plumbing through every file.”

    Action/result: Implemented project-wide early consumption of --game-dir for tools that import resource helpers before their own parsers run.

  2348. Reported: “Now I’m adding the FreeDOS image builder. It won’t copy a game unless a game directory is explicitly supplied, which keeps the base DOS setup separate from whichever interpreter/game we’re examining.”

    Action/result: Added tools/setup_freedos_image.py to download and verify FreeDOS LiteUSB, extract the raw image, patch prompt boot files, and optionally copy an explicit local game directory.

  2349. Reported: “Small cleanup while I’m here: the setup script should not inspect game options unless --copy-game is used, so I’m trimming an unnecessary check from its entrypoint.”

    Action/result: Removed an unnecessary entrypoint check from the FreeDOS setup script.

  2350. Reported: “I’m tightening decrypt_agi.py as well: if someone provides explicit loader/payload paths, it should not unnecessarily demand a game directory; otherwise it derives those paths from the required game parameter.”

    Action/result: Updated tools/decrypt_agi.py so --loader/--payload may be explicit, while path derivation requires --game-dir or AGI_GAME_DIR.

  2351. Reported: “For the setup script specifically, I’m making --game-dir an explicit documented option because it only matters when --copy-game is requested. That avoids hidden behavior in the bootstrap path.”

    Action/result: Added explicit --game-dir handling to tools/setup_freedos_image.py for --copy-game runs.

  2352. Reported: “I’m doing another pass over hard-coded paths now. The goal is not to rewrite historical evidence notes, but active scripts and setup docs should no longer imply SQ2 is the default or that the old MS-DOS image is required.”

    Action/result: Scanned active scripts/tests/docs for old SQ2, MS-DOS, and build/dos622 assumptions.

  2353. Reported: “I caught a small Python standard-library slip in the setup script before running it: URL parsing lives in urllib.parse, not urllib.request. Tiny, but exactly the kind of tiny that ruins a bootstrap script at step one.”

    Action/result: Fixed the FreeDOS setup script to use urllib.parse.urlparse.

  2354. Reported: “I’m updating the project-facing instructions next. This is where I’m making the multi-game expectation explicit: games/ is a private local area, tools require --game-dir or AGI_GAME_DIR, and generated DOS images live under disposable build/.”

    Action/result: Added root README.md and updated AGENTS.md for explicit game directories, ignored private game data, and FreeDOS image setup.

  2355. Reported: “I noticed the new docs want --print-mtools-image to be a harmless query when the image already exists. I’m adjusting the script so that option can be used safely in mtools examples without re-downloading or re-extracting anything.”

    Action/result: Made tools/setup_freedos_image.py --print-mtools-image return the existing image target without rebuilding when possible.

  2356. Reported: “One more nicety: querying the image target should not require mtools to already be installed. I’m moving that requirement to the setup/copy path.”

    Action/result: Delayed the mtools requirement check until the setup script actually needs to modify the image.

  2357. Reported: “I’m now updating the mdBook-facing setup references. Historical command logs can keep their old paths, but the current compatibility chapter should teach the new explicit game-directory workflow.”

    Action/result: Updated active mdBook pages and PROGRESS.md to clarify explicit --game-dir/AGI_GAME_DIR selection and remove old active setup assumptions.

  2358. Reported: “The docs now distinguish ‘this evidence came from SQ2’ from ‘the tooling should choose SQ2 automatically.’ I’m doing one more active-reference scan before I remove the generated directories.”

    Action/result: Scanned active instructions and compatibility commands for stale default-game and old DOS-image assumptions.

  2359. Reported: “I’m adding a small unit test for the no-default rule. That way a future cleanup can’t quietly reintroduce games/SQ2 as a fallback while we’re focusing on other interpreter versions.”

    Action/result: Added tests/test_project_paths.py covering required game parameters, environment selection, and global --game-dir consumption.

  2360. Reported: “At this point the generated outputs have been replaced by rebuild instructions and the old installer path is no longer needed for setup. I’m removing only build/ and 002962_ms_dos_622/, leaving games/ alone and ignored.”

    Action/result: Removed build/ and 002962_ms_dos_622/; retained the private ignored games/ directory.

  2361. Reported: “The old generated directories are gone. I’m logging the setup/cleanup steps now before validation, so the historical record includes both the path-policy correction and the artifact removal.”

    Action/result: Added progress-log entries for the FreeDOS setup and cleanup pass before validation.

  2362. Reported: “Validation pass now: syntax, unit tests with an explicit AGI_GAME_DIR, mdBook, opcode evidence, and whitespace. If anything still assumes a default game, this should flush it out quickly.”

    Action/result: python3 -B -m py_compile, AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests, mdbook build docs, AGI_GAME_DIR=games/SQ2 python3 -B tools/logic_opcode_evidence.py --check, and git diff --check all passed. The unit suite ran 242 tests.

  2363. Reported: “Validation passed: syntax compile, mdBook, opcode evidence, whitespace, and the full unit suite with AGI_GAME_DIR=games/SQ2 all succeeded. I’m checking the post-test worktree now, including whether any generated docs/build output appeared.”

    Action/result: Post-validation status showed the intended tracked edits and new files, plus only a generated tools/__pycache__/ cache.

  2364. Reported: “The checks created only Python bytecode under tools/__pycache__; I’m cleaning that generated cache out of the worktree. build/ and the old installer directory remain removed.”

    Action/result: Removed tools/__pycache__/.

  2365. Reported: “I’m adding the official FreeDOS download link to the README so the default URL/checksum choice is traceable without burying it inside the script. Then I’ll do the final lightweight checks again because the progress log and README changed after the first validation pass.”

    Action/result: Linked the README setup section to the official FreeDOS download page before the final lightweight validation pass.

  2366. Reported: “I’ll run the base FreeDOS setup first, without copying any game data, since that should prove the reproducible image bootstrap path independently of SQ2/LSL/KQ inputs. If the sandbox blocks the download, I’ll rerun with the required network approval.”

    Action/result: The sandboxed download failed with DNS resolution blocked, as expected for network-restricted shell commands.

  2367. Reported: “The first run reached the expected sandbox network wall: DNS resolution failed while downloading the FreeDOS zip. I’m rerunning the same setup command with network escalation so it can actually fetch the official image.”

    Action/result: The escalated download succeeded, but the script rejected the cached zip because the baked-in SHA-256 was wrong.

  2368. Reported: “The escalated download worked, and the failure is useful: my baked-in SHA-256 was wrong. The downloaded file matches FreeDOS’ official verify.txt value for FD14-LiteUSB.zip, so I’m correcting the script to the official hash and rerunning.”

    Action/result: Corrected FREEDOS_LITEUSB_SHA256 to 857dcd2ebf9d3d094320154db5fb5b830acba6fb98f981a95a0ca7ab3350338b.

  2369. Reported: “The cached zip is already present from the successful download, so the rerun should verify and extract without needing another network fetch. After that I’ll inspect the image with mtools and, if promising, do a quick QEMU boot screenshot.”

    Action/result: python3 -B tools/setup_freedos_image.py --force completed, extracted FD14LITE.img to build/freedos/freedos.img, and auto-detected the mtools target build/freedos/freedos.img@@32256.

  2370. Reported: “The setup script now completes: it extracted FD14LITE.img to build/freedos/freedos.img, and auto-detected the FAT partition at @@32256. I’m checking the filesystem contents next, then I’ll try a QEMU boot.”

    Action/result: mdir showed FreeDOS boot files, patched AUTOEXEC.BAT/FDAUTO.BAT, and about 13 MB free on the image.

  2371. Reported: “The image has the expected FreeDOS boot files and our patched AUTOEXEC.BAT/FDAUTO.BAT. I’m booting it under QEMU now and will capture the VGA output so we can see whether it lands somewhere usable.”

    Action/result: The sandbox blocked binding QEMU’s local VNC socket.

  2372. Reported: “QEMU itself started, but the sandbox blocked binding the local VNC socket. I’m rerunning QEMU with escalation for the local display socket so I can capture a screenshot.”

    Action/result: QEMU booted the generated FreeDOS image with local VNC enabled.

  2373. Reported: “QEMU is running now. I’m giving FreeDOS a few seconds to finish booting, then I’ll ask the monitor for a screenshot and shut it down cleanly.”

    Action/result: Captured build/freedos/boot.ppm and shut QEMU down.

  2374. Reported: “The screenshot was captured. I’m shutting QEMU down, then I’ll convert the PPM to PNG so we can inspect what FreeDOS actually displayed.”

    Action/result: Converted build/freedos/boot.ppm to build/freedos/boot.png; the screenshot shows FreeDOS at a plain C:\> prompt.

  2375. Reported: “The boot screenshot is good: FreeDOS reaches a plain C:\> prompt. I’m going to test the optional explicit game-copy path too, since that’s the README path people will use for manual engine runs.”

    Action/result: Checked games/SQ2 size and file count before the copy test.

  2376. Reported: “The local SQ2 copy is small enough for the LiteUSB image, so I’m rerunning setup with an explicit game directory and DOS target name.”

    Action/result: python3 -B tools/setup_freedos_image.py --force --copy-game --game-dir games/SQ2 --dos-game-dir SQ2 completed and copied the game to C:\SQ2.

  2377. Reported: “The explicit --copy-game --game-dir games/SQ2 path completed too. I’m checking the DOS directory listing, then I’ll do one launch screenshot of C:\SQ2\SIERRA under FreeDOS.”

    Action/result: mdir confirmed the SQ2 files inside C:\SQ2 with about 12 MB free remaining.

  2378. Reported: “The copied game directory looks right inside the FreeDOS image. I’m booting QEMU again and launching SIERRA from C:\SQ2 to confirm the generated image is actually usable for our engine runs.”

    Action/result: Booted the image in QEMU, typed cd \SQ2 and SIERRA through the monitor, and captured build/freedos/sq2_freedos.ppm.

  2379. Reported: “FreeDOS boots, and the copied SQ2 run reaches the game title screen under QEMU. I’m recording the checksum correction and validation screenshots in the progress log, then I’ll run a small final check on the edited script/docs.”

    Action/result: Converted build/freedos/sq2_freedos.ppm to build/freedos/sq2_freedos.png; the screenshot shows the SQ2 title screen under FreeDOS.

  2380. Reported: “I’ll add a short ‘manual image use’ section to the README: mtools target discovery, copying files/directories into the FAT image, and the exact QEMU command plus monitor basics.”

    Action/result: Added README instructions for --print-mtools-image, mdir, mmd, mcopy, manual QEMU boot, monitor sendkey, screendump, and ImageMagick conversion.

  2381. Reported: “I found the current FreeDOS section; it has launch basics but not enough mtools detail. I’m adding concrete copy/list examples that use the script’s --print-mtools-image output so nobody has to remember the partition offset.”

    Action/result: Expanded the README FreeDOS image section with concrete mtools examples that derive the image target from the setup helper.

  2382. Reported: “Got it: any dynamic validation I do from here will use the FreeDOS setup, and I’ll keep MS-DOS out of the workflow unless you explicitly ask for historical comparison. I’m going to continue the GR v3 pass source-first and only use QEMU/FreeDOS if I need behavior confirmation.”

    Action/result: Started the Gold Rush / AGI v3 comparison as a static disassembly/resource-format pass.

  2383. Reported: “The repo is clean apart from an untracked run.sh, and games/GR is present with the combined GRDIR/GRVOL.* layout. I’m checking the existing docs and resource scripts now so the v3 notes land in the right places and the tooling follows the game-dir parameterization rule.”

    Action/result: Checked git status --short, listed project files, and inventoried games/GR and games/SQ2.

  2384. Reported: “The existing resource chapter is SQ2/v2-specific, so I’ll add a GR/v3 section rather than disturb the v2 evidence. One useful contrast already holds up: SQ2 resource records are direct 5-byte-header payloads, while GR records use a 7-byte header with expanded and stored lengths plus transform selection.”

    Action/result: Read the resource, symbolic-label, and progress-tracker chapters plus current resource-related scripts.

  2385. Reported: “I’m going back to the disassembly now, particularly the GR directory loader and the two decompression call sites. The goal is to turn the first-pass observations into a concrete parser/decompressor, so we can inspect GR logic resources directly instead of treating compression as a black box.”

    Action/result: Verified the GR executable header and regenerated the decrypted SQ2 executable for side-by-side static comparison.

  2386. Reported: “I’ve confirmed the old offset rule still applies to GR: the MZ header is 0x200 bytes, so the stable “image offset” documentation maps to file offset image + 0x200. I’m using dd slices with explicit image origins to avoid the earlier ndisasm -e ambiguity.”

    Action/result: Disassembled focused GR windows around image offsets 0x30a0, 0x44d0, 0x07d0, and 0x9a40.

  2387. Reported: “The GR decompression paths are now clear enough to model locally. The “general” path is a reset-capable 9-to-11-bit dictionary stream with 0x100 as reset and 0x101 as end; the picture path is a nibble realigner that packs the color byte after 0xf0 and 0xf2 into half-bytes, then expands them back to ordinary picture opcodes.”

    Action/result: Interpreted GR image 0x07f4 as the dictionary decompressor and GR image 0x9a5b as the picture-nibble transform.

  2388. Reported: “I’m going to add a small resource module now rather than fold this into the SQ2-only disassembler. It will autodetect split v2 directories versus combined v3 directories, require an explicit game path at the CLI, and expose the GR decompression routines as reusable code for later interpreter-version comparisons.”

    Action/result: Added tools/agi_resources.py with v2/v3 directory detection, v3 record reading, dictionary expansion, and picture-nibble expansion.

  2389. Reported: “The first reusable parser/decompressor is in place. I’m running it against GR and SQ2 now; the useful check is that GR logic/view/sound payloads expand to plausible resource bytes, and picture resources expand back into the same ordinary picture opcode stream shape the v2 renderer already understands.”

    Action/result: The first CLI run exposed an argument-order bug: the project-wide --game-dir option was parsed after the tool’s local argparse parser.

  2390. Reported: “Tiny CLI snag: the project-wide --game-dir consumer needs to run before this tool’s own argparse parser. I’m fixing that plumbing now; the resource code itself hasn’t run yet.”

    Action/result: Moved configured_game_dir() before local argument parsing in tools/agi_resources.py.

  2391. Reported: “The new code expands every present GR resource successfully: 182 logic entries, 186 pictures, 247 views, and 44 sounds. The transform census is useful too: all pictures use the nibble path; logic/view mostly use the dictionary path; a few logic/sound resources are direct because stored length equals expanded length.”

    Action/result: Ran the GR parser over all present entries; the transform census was direct 5, dictionary 468, picture-nibble 186.

  2392. Reported: “I’ve added focused tests for the two decompression primitives plus GR/SQ2 container detection. Now I’m running the new test file first, then I’ll run the normal local suite with the explicit SQ2 game path so I don’t mask any regressions in the older tooling.”

    Action/result: Added tests/test_agi_resources.py; the new focused tests passed. The full suite exposed an unrelated read-only fixture-copy permission problem.

  2393. Reported: “The new GR tests pass. The full existing suite hits an unrelated fixture-copy problem: the private game files are read-only, and several fixture builders copy them into temp dirs and then try to overwrite LOGDIR or VOL.3 without changing permissions. I’m not going to blur that into the GR compression change unless it becomes necessary, but I’ll record it as a verification caveat.”

    Action/result: Recorded the full-suite failure as a fixture permission caveat rather than a GR parser failure.

  2394. Reported: “There’s another version-level difference beyond compression: the GR v3 dispatcher tables are larger. The action dispatcher checks through 0xb5 and calls AGIDATA table 0x0440; the condition dispatcher checks through 0x25 and calls table 0x0762. SQ2 v2 topped out at 0xaf actions and 0x12 conditions, so I’m doing a quick decoded-logic census to see which of those newer slots are actually used in Gold Rush.”

    Action/result: Disassembled GR dispatch code and ran a decoded-logic census using v3 table bases; all present GR logic parsed without errors.

  2395. Reported: “I’m also extending the local logic disassembler just enough to consume the new resource module. That gives us an immediate cross-version sanity check: decoded GR logic can be walked with the v3 table bases, while SQ2 still uses the existing v2 table bases.”

    Action/result: Updated tools/disassemble_logic.py to use tools/agi_resources.py for logic payload loading and to select v3 table bases for combined-directory games.

  2396. Reported: “The disassembler now has format-aware payload loading and table-base selection. I’m checking it on SQ2 first for backward compatibility, then on GR to confirm that compressed logic disassembles without parse errors.”

    Action/result: Disassembled SQ2 and GR logic 0 and ran tools/disassemble_logic.py --game-dir games/GR --stats successfully.

  2397. Reported: “The logic disassembler can now walk GR’s compressed logic resources. A decoded census found no parse errors across the present GR logic scripts; interestingly, although the v3 dispatcher supports action slots through 0xb5 and condition slots through 0x25, this Gold Rush data set only uses action opcodes through 0xa9 and conditions through 0x0e.”

    Action/result: Confirmed the GR logic opcode-use range from the stats output and kept the extra v3 slots marked as not yet behavior-specified.

  2398. Reported: “I’m updating the docs now: resource format chapter, executable notes, symbolic labels, progress dashboard, and progress log. I’ll keep the GR sections explicitly marked as v3/Gold Rush observations rather than rewriting the SQ2-centered spec as if every version behaves identically.”

    Action/result: Added a Gold Rush / AGI v3 resource-container comparison section and a clean-room evidence note.

  2399. Reported: “The evidence notes now capture the key commands, offsets, and the full-suite caveat. I’m adding the GR address associations to the symbolic label map next so future v3/v2 comparisons can refer to stable routine names rather than raw offsets.”

    Action/result: Added initial GR / AGI v3 symbolic label associations for dispatch tables, resource loaders, decompression routines, and directory globals.

  2400. Reported: “The symbolic map now has a GR/v3 association section for the resource loader, decompression routines, dispatch tables, and moved globals. I’m updating PROGRESS.md so the dashboard reflects that cross-version work has actually started rather than being purely future work.”

    Action/result: Updated PROGRESS.md with Gold Rush v3 resource coverage, v3 opcode-table caveats, and next highest-value work.

  2401. Reported: “PROGRESS.md now points at the next GR/v3 work directly, and it records the current full-suite blocker as a separate fixture permission issue. I’m appending the progress-log entries for this pass before running mdBook.”

    Action/result: Appended the progress-log entries for the Gold Rush v3 resource/decompression pass.

  2402. Reported: “The documentation trail is updated. I’m running the book build and focused tests now; after that I’ll check the diff for accidental noise, especially because build/ is disposable and run.sh was already untracked.”

    Action/result: mdbook build docs, tests/test_agi_resources.py, and focused SQ2 logic/sound tests all passed.

  2403. Reported: “The book builds cleanly and the focused tests pass. The only untracked file unrelated to me is still run.sh; the new untracked files are the resource module and its tests. I’m doing a final diff scan for accuracy before I wrap up.”

    Action/result: Reviewed git diff --stat, selected diffs, and a GR parser summary command.

  2404. Reported: “The diff scan looks coherent. One small thing I noticed from the stat: untracked files don’t show in git diff --stat, so I’m checking the new resource module and tests directly before the final status.”

    Action/result: Read tools/agi_resources.py, tests/test_agi_resources.py, and the final git status --short.

  2405. Reported: “I spotted two housekeeping bits before closing: make split-directory detection case-insensitive like the file opener, and log the final verification updates too. Then I’ll rerun the focused checks.”

    Action/result: Made split-directory detection case-insensitive in tools/agi_resources.py and recorded the final verification updates in this progress log.

  2406. Reported: “Everything I changed still verifies: mdBook passes, the new GR resource tests pass, and the existing SQ2 logic/sound focused tests pass. I’m checking final status now.”

    Action/result: Final status showed modified docs/tooling plus new tools/agi_resources.py and tests/test_agi_resources.py; pre-existing untracked run.sh remains unrelated.

  2407. Reported: “I’ll wire this in at two levels: first the documentation chapter and summary entry, then the fixture builders/tests that currently mutate copied read-only game files. I’ll start by finding the fixture code paths that touch games/ or preserve read-only permissions.”

    Action/result: Searched docs, tests, and tools for fixture builders, LOGDIR/VOL.3 patching, game-directory references, and copy/write operations.

  2408. Reported: “I found the likely permission caveat called out in PROGRESS.md, and the fixture tooling is centered in tools/qemu_fixture.py plus the probe wrappers. I’m reading those paths now so the fix lands in the shared primitive instead of scattering chmods through tests.”

    Action/result: Read tools/qemu_fixture.py, related tests, and wrapper probe code that uses copy_sq2_tree().

  2409. Reported: “The shared fixture builder is SQ2-v2-specific right now and writes patched LOGDIR/PICDIR/VOL.3 into whatever destination it’s given. The change I’m aiming for is to make the fixture destination a fresh, writable copy under build/, leaving games/* as immutable inputs.”

    Action/result: Identified copy_sq2_tree() and copy_minimal_picture_tree() as the shared copy points that should make generated copies writable.

  2410. Reported: “I’m also going to add a guard so fixture builders refuse destinations inside games/. That makes the intended contract executable: games/ is evidence input, build/ is where experimental copies and mutations happen.”

    Action/result: Planned a fixture-destination guard before patching copy logic.

  2411. Reported: “The docs already have a cross-version workflow chapter, so the new Versions chapter can be the dashboard: one row per observed interpreter/game version plus concrete deltas like resource container, compression, dispatch-table size, and fixture status. I’m adding that as a lightweight reference rather than burying it in the long evidence log.”

    Action/result: Read the existing mdBook summary, cross-version workflow, current status, and GR resource-container notes to shape the new chapter.

  2412. Reported: “I’ve got the edit shape now. I’m patching the fixture copy primitive to: clean generated destinations safely, copy source game files as writable files, preserve .ppm captures, and fail fast if someone points a fixture builder at games/.”

    Action/result: Updated tools/qemu_fixture.py with writable-copy helpers, generated-destination cleanup, .ppm preservation, and a guard rejecting destinations under games/.

  2413. Reported: “The core fixture copy path is patched. I’m adding focused tests for the two failure modes we care about: copied files from read-only game inputs must be writable, and generated fixtures must not be allowed inside games/.”

    Action/result: Added tests in tests/test_qemu_fixture.py for read-only source-file copying and games/ destination rejection.

  2414. Reported: “The fixture tests now cover the read-only-input bug directly. I’m running that slice before updating the docs so I can record the actual result rather than a hopeful one.”

    Action/result: Ran AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests/test_qemu_fixture.py; all 39 tests passed.

  2415. Reported: “The new chapter is in the book index, and AGENTS.md now states the immutable-games/ rule explicitly. I’m updating the high-level tracker and evidence notes next, including the fact that the earlier fixture-copy permission caveat is now addressed in the shared builder.”

    Action/result: Added docs/src/versions.md, linked it from docs/src/SUMMARY.md, updated the docs README, and recorded the immutable input rule in AGENTS.md.

  2416. Reported: “The tracker still had the fixture permission problem listed as future work, so I’m changing that from a blocker into a completed infrastructure note. After that I’ll run the broader suite to see whether this uncovers anything else.”

    Action/result: Updated PROGRESS.md and docs/src/clean_room_executable_notes.md for the fixture-copy fix before broad verification.

  2417. Reported: “The code and docs are patched; now I’m verifying the book and the local suite. The important check is whether the full suite gets past the old read-only fixture-copy failure.”

    Action/result: Ran mdbook build docs and AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests. mdBook passed, and the full local suite passed 250 tests.

  2418. Reported: “Good result: mdBook passes, and the full local unit suite now passes 250 tests. I’m recording that in the clean-room notes and progress log so the previous caveat is closed rather than just fixed in code.”

    Action/result: Updated PROGRESS.md and docs/src/clean_room_executable_notes.md with the successful full-suite verification.

  2419. Reported: “One extra safety check fell out of the diff scan: the guard should also reject destinations that are parents of the selected game directory, because the cleanup step could otherwise delete the input. I’m adding that small hardening now.”

    Action/result: Hardened the fixture-destination guard and added a test that rejects parent directories of the selected game input.

  2420. Reported: “The guard is now a little harder to misuse, and I added a test for that parent-directory case. I’m rerunning the focused fixture tests and the full suite once more because this is exactly the kind of safety code where “probably fine” is too breezy.“

    Action/result: Reran AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests/test_qemu_fixture.py and AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests; the focused fixture slice passed 40 tests and the full local suite passed 251 tests.

  2421. Reported: “I’ve got the static comparison pass well underway: the shared action/condition tables are mapped, the GR-only action slots are identified, and the resource/view/picture/object runtime slices have an initial normalized comparison. I’m going to tighten the docs and tracker now, then run the local checks so the evidence trail is solid rather than just ‘interesting notes in build/’.”

    Action/result: Resumed the GR/SQ2 static-comparison pass, reviewed the generated report, and prepared the tracker/doc update plan.

  2422. Reported: “The tracker still reflects the comparison as ‘in progress’ even though the generated report now has concrete classifications. I’m going to make the tracker reflect the evidence we actually have, and I’ll also correct the v3 condition-table boundary so the tooling does not overinterpret bytes that are really string/data territory.”

    Action/result: Re-read PROGRESS.md, the existing clean-room notes, progress log, symbolic labels, comparison helper, version ledger, and generated static report.

  2423. Reported: “The static report’s key caveat is important: GR’s predicate dispatcher bound is wider, but the bytes after the 19 shared condition entries decode as punctuation and filenames, not handler records. I’m going to encode that distinction in both code and docs so future comparisons don’t quietly inherit a false table size.”

    Action/result: Located the v3 condition-table size in tools/disassemble_logic.py and the older documentation claims that needed correction.

  2424. Reported: “There are a few older docs that phrase the GR condition range too strongly. I’m reading those exact spots now and will change only the GR-specific claims, leaving the SQ2 opcode evidence alone unless the local source actually requires it.”

    Action/result: Checked logic_bytecode.md, logic_opcode_evidence.md, resource_files.md, versions.md, and symbolic_labels.md; SQ2 wording already treated 0x13..0x25 as reserved, while GR-specific text needed correction.

  2425. Reported: “The current subsystem comparison is useful, but I want it a bit more complete before I call it solid. I’m going to extend the report to cover the full picture command table and more of the object/update-list surface, then I’ll regenerate it and fold the results back into the docs.”

    Action/result: Printed SQ2 and GR picture command dispatch tables, mapped additional view, picture, display, object, and motion routine addresses, and prepared to expand tools/compare_gr_sq2_static.py.

  2426. Reported: “The expanded scan is already paying off: GR’s core object/update-list routines sit at the same early-executable locations shifted by a few bytes, while object rectangle save/restore/draw calls target main-image routines instead of SQ2’s object overlay entry table. I am using that as a packaging difference, not a behavioral claim.”

    Action/result: Confirmed GR update-list routine addresses around 0x0351, 0x0428, 0x0457, and 0x0481, and noted GR main-image rectangle save/draw calls.

  2427. Reported: “I’m patching the comparison helper now. The main additions are a fuller picture-command sweep, the view group-table helper, object update-list and frame/motion routines, and a compact interpretation note for the shared handlers that actually differ.”

    Action/result: Extended tools/compare_gr_sq2_static.py with broader subsystem pairs and static notes for changed shared actions and GR-only actions.

  2428. Reported: “The helper now compares more of the interpreter surface, including all eleven picture commands and the core object update-list/motion routines. I’m making the parser boundary correction next, then I’ll regenerate the report to see which of those broader slices actually diverge.”

    Action/result: Changed the v3 condition-table count in tools/disassemble_logic.py from the dispatcher bound to the observed structured table size 0x13.

  2429. Reported: “That condition-table fix is deliberately conservative: it preserves the observed GR action table size, but treats only the 19 structured predicate entries as decodable table records. Now I’m regenerating the report and checking whether the expanded subsystem sweep exposes any new static differences.”

    Action/result: Regenerated build/gr-sq2-static/opcode_static_report.md and py-compiled the updated comparison and logic-disassembly tools.

  2430. Reported: “The expanded report found two kinds of differences: expected display-path divergences, and a couple of object/motion mismatches that may be either real or address/normalization artifacts. I’m checking those by reading the raw disassembly before I document them, because a table that confidently compares the wrong entry point is worse than no table.”

    Action/result: Read raw SQ2 and GR disassembly around frame timers, frame advancement, motion dispatch, and boundary checking.

  2431. Reported: “Those raw reads separate the real deltas from the straight-line disassembler noise: GR adds an object-frame group-count/version branch, and its motion dispatcher accepts one more mode value. The frame-advance and boundary-check ‘differences’ in the generated table are embedded jump-table bytes, so I’ll label them as manual-neutral rather than behavioral differences.”

    Action/result: Classified GR frame-timer and motion-dispatch differences as real static deltas, while treating frame-advance and boundary-check straight-line differences as embedded jump-table artifacts.

  2432. Reported: “I’m adding those manual caveats directly into the generated report notes, so the artifact says ‘real object-mode extension here’ and ‘jump-table bytes here’ without making someone rediscover that distinction later.”

    Action/result: Added subsystem-pair notes for GR display refresh omissions, object frame-timer branching, extra motion selector, and embedded jump-table caveats.

  2433. Reported: “The comparison helper is patched with the manual caveats; I’m regenerating the report one more time so the build artifact matches the code and the docs I’m about to write.”

    Action/result: Regenerated build/gr-sq2-static/opcode_static_report.md from the updated helper.

  2434. Reported: “I’m updating PROGRESS.md now: the new section is moving from ‘todo list’ to an evidence dashboard, including the 17 changed shared action snippets, the six GR-only action slots, and the object/view/picture static deltas.”

    Action/result: Updated the GR/SQ2 static comparison tracker and cross-version remaining-work sections in PROGRESS.md.

  2435. Reported: “I’m updating the clean-room notes with a dated static-comparison section now. This will record the commands, the generated artifact path, and the corrected condition-table interpretation so the clean-room trail doesn’t depend on memory.”

    Action/result: Added a new clean-room executable-notes section for the GR/SQ2 static opcode, object, view, and picture comparison, and corrected the earlier v3 condition-slot wording.

  2436. Reported: “The evidence notes now have a concrete comparison section. I’m sweeping the version/resource/symbol tables next so older wording doesn’t still imply that GR has real predicate handlers through 0x25.”

    Action/result: Updated docs/src/versions.md and docs/src/resource_files.md with the corrected GR condition-table boundary and static-comparison summary.

  2437. Reported: “The version ledger is corrected. I’m making the same adjustment in the resource chapter and then I’ll extend the GR address map with the object/view/picture routine associations from the static pass.”

    Action/result: Completed the resource chapter correction and began extending the GR address-association table.

  2438. Reported: “I’m extending the symbolic map with the GR addresses for the routines the report now compares. The notes include the SQ2 anchor offsets so later interpreter comparisons can keep using the same labels rather than chasing raw addresses.”

    Action/result: Added GR address associations for compared view, picture, display, object, and motion routines in docs/src/symbolic_labels.md.

  2439. Reported: “The symbolic map now has GR associations for the compared view, picture, object, display, and motion routines. I’m scanning for stale ‘condition through 0x25’ wording and then I’ll update the progress log before running checks.”

    Action/result: Scanned for stale GR condition-range claims and found only historical progress-log wording plus older SQ2-specific notes.

  2440. Reported: “I found one stale progress-log entry from the earlier GR pass that records the old condition-slot hypothesis; I’ll add today’s correction and the comparison updates after the current tail rather than rewriting history. After that, I’ll run the documentation and unit checks.”

    Action/result: Added progress-log entries for the static comparison pass and left the older progress-log hypothesis intact as historical context.

  2441. Reported: “The docs and tracker are patched. I’m running the local verification now: mdBook for documentation integrity, the unit suite for parser/disassembler regressions, and then I’ll clean up generated Python cache files so the worktree only shows intentional files plus the pre-existing run.sh.”

    Action/result: Ran mdbook build docs, AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests, and a stale-wording scan. mdBook passed, and the unit suite continued running.

  2442. Reported: “mdBook passed. The stale wording scan now only finds a historical progress-log entry from the earlier hypothesis, which I’m leaving as history because the new entries and evidence notes record the correction. The unit suite is still running, so I’m waiting for that before the final cleanup.”

    Action/result: Waited for the full unit suite, which passed 251 tests.

  2443. Reported: “The full local unit suite passed 251 tests. I’m running the project compatibility-suite wrapper as a final belt-and-suspenders check because it also covers the book/opcode-evidence checks that aren’t obvious from plain unittest output.”

    Action/result: Ran python3 -B tools/compatibility_suite.py; it failed because no explicit game directory was supplied, causing import-time AGI_GAME_DIR guard errors.

  2444. Reported: “The wrapper failed without AGI_GAME_DIR, which is the project’s explicit-game-directory guard doing its job. I’m rerunning the same compatibility-suite command with AGI_GAME_DIR=games/SQ2, matching the successful unit-suite invocation.”

    Action/result: Reran AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py; it passed 251 tests and mdBook.

  2445. Reported: “The compatibility wrapper passes once the explicit SQ2 input is provided: 251 tests and mdBook both green. I’m cleaning the generated tools/__pycache__ now and then I’ll do the final diff/status sanity pass.”

    Action/result: Removed generated tools/__pycache__.

  2446. Reported: “I’m recording the verification results in the evidence notes and progress log now, including the one failed wrapper attempt without AGI_GAME_DIR and the successful rerun with the explicit game directory.”

    Action/result: Added verification commands and outcomes to the clean-room executable notes.

  2447. Reported: “I’ll take this from the GR-only slots first: pin down each handler, then chase any state writes to their consumers so we can separate real behavior from reserved/no-op entries. I’ll keep this as a source-first pass and only reach for QEMU if the disassembly leaves a genuine ambiguity.”

    Action/result: Re-read the GR/SQ2 static comparison state and began a focused source pass over GR-only action slots 0xb0..0xb5.

  2448. Reported: “I’m drilling into the two non-trivial slots now. One writes a word near the low runtime globals, and the other pairs with GR’s changed 0xad; the useful bit is finding who reads those bytes afterward.”

    Action/result: Located GR action handlers 0xb1 at image 0x970b and 0xb5 at image 0x63b0, then searched local disassembly for consumers of [0x0403] and [0x0405].

  2449. Reported: “I’ve got the first solid shape: four of the GR-only action slots are deliberately inert after argument consumption, while the two real ones wire into existing menu/input state. I’m going back through the surrounding routines now so the names don’t outrun the evidence.”

    Action/result: Confirmed handler 0x5286 is a generic no-op/return handler and inspected the surrounding GR menu and keyboard routines.

  2450. Reported: “A useful anchor popped out: GR’s regular menu-building opcodes still make the same linked menu structures, and opcode 0xb1 is a separate gate that lets the menu interaction routine run at all. That makes it a control switch, not another menu item/heading builder.”

    Action/result: Read GR menu-build handlers around 0x9457..0x970a and menu interaction routine 0x9724; identified [0x0403] as an interaction gate checked before menu drawing/input.

  2451. Reported: “The paired input gate is clearer now too: GR’s 0xad sets a byte that the keyboard interrupt hook checks before enqueueing a (type=2, value=0) event on certain key-release paths; 0xb5 clears that same byte. That’s the strongest ‘extra opcode’ behavioral finding so far, because the consumer is right there in the disassembly.”

    Action/result: Traced [0x0405] from GR action 0xad and GR-only action 0xb5 to the keyboard interrupt hook at 0x63b8.

  2452. Reported: “I’m going to patch the tooling and docs now: add conservative v3 names for the extra slots, tighten the static report notes, and record the source evidence with the exact offsets. I’m leaving the SQ2 opcode catalog semantics intact because those bytes are still invalid in SQ2; the GR names live as v3-specific labels.”

    Action/result: Began updating disassembly tooling, static report notes, and documentation for the GR-only action slots.

  2453. Reported: “The disassembler now keeps SQ2’s ACTION_NAMES exactly as the tests expect, but when it sees a v3-sized table it can call out 0xb1 as the menu gate and 0xb5 as the key-release-event gate clearer. Small change, but it’ll save future archaeology.”

    Action/result: Added v3-specific action-name overrides in tools/disassemble_logic.py.

  2454. Reported: “PROGRESS.md now treats the extra slots as source-backed rather than just ‘interesting.’ I’m adding the same evidence into the mdBook pages next, with the distinction that these are Gold Rush/v3 observations, not SQ2 rules.”

    Action/result: Updated the GR/SQ2 static comparison tracker in PROGRESS.md.

  2455. Reported: “The logic-bytecode chapter now has a dedicated GR/v3 extra-slot table. I’m adding stable symbolic labels too, so later notes can say data.menu.interaction_gate_0403 instead of scattering raw offsets everywhere.”

    Action/result: Updated docs/src/versions.md and docs/src/logic_bytecode.md with source-backed GR extra opcode details.

  2456. Reported: “The symbolic map now has the new GR action labels plus the two state globals. I’m writing the clean-room evidence trail now, including the exact disassembly ranges and the decision not to run QEMU yet because this particular pass can be proven from local source paths.”

    Action/result: Added GR action/global labels to docs/src/symbolic_labels.md.

  2457. Reported: “The clean-room notes have the core evidence now. I’m appending the user-facing progress entries before I regenerate the report and run checks, so the historical trail stays aligned with what you saw during the work.”

    Action/result: Added this progress-log block for the GR extra opcode pass.

  2458. Reported: “The new log entries are ASCII-clean now. I’m regenerating the GR/SQ2 static report so the build artifact carries the refined 0xb1/0xb5 notes, then I’ll run the focused parser/docs checks.”

    Action/result: Regenerated build/gr-sq2-static/opcode_static_report.md.

  2459. Reported: “The report regenerated cleanly. I’m doing a quick readback of the generated extra-slot section and a GR disassembler stats run next, mostly to catch naming/report drift before the heavier checks.”

    Action/result: Confirmed the generated report includes the refined [0x0403]/[0x0405] notes; GR logic stats parsed with no errors.

  2460. Reported: “The focused checks are clean so far: the report contains the refined notes, GR logic still parses with no errors, and both touched Python tools compile. I’m running the book and unit suite now; those are the real regression guards for this repo.”

    Action/result: Ran mdbook build docs and AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests; both passed, with 251 unit tests.

  2461. Reported: “Book build and the 251-test unit suite both passed. I’m running the compatibility wrapper with explicit SQ2 input now, plus a whitespace diff check; after that I’ll clean any generated cache files and record the verification in the notes.”

    Action/result: Ran AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py and git diff --check; both passed.

  2462. Reported: “The compatibility wrapper passed too, and git diff --check is clean. A Python cache directory appeared from the runs; I’m removing just that generated cache and then I’ll do one final status/diff pass.”

    Action/result: Removed generated tools/__pycache__.

  2463. Reported: “The cache cleanup is done. I’m adding the verification results to the evidence notes and progress log now, then I’ll check the final diff so the close-out is concrete.”

    Action/result: Added verification results to docs/src/clean_room_executable_notes.md.

  2464. Reported: “The final diff matches the shape of the work: docs/tracker updates, v3 naming in the disassembler, and the comparison helper notes. I’m recording the successful validation commands now.”

    Action/result: Inspected git status --short, git diff --stat, and selected diffs for the extra opcode pass.

  2465. Reported: “The clean-room notes now include the validation results. I’m adding the matching progress-log tail entries and then I’ll do the last status check.”

    Action/result: Added the final verification progress-log entries.

  2466. Reported: “I’ve got the thread back in my head. I’m continuing on the v3 fixture writer path now: first removing the remaining hidden selected-game coupling in the fixture tool, then adding a direct-record v3 resource patch path we can use for Gold Rush probes.”

    Action/result: Resumed from the top PROGRESS.md item and inspected the existing v2 fixture builder, v3 resource parser, and fixture tests.

  2467. Reported: “The fixture code has a clean insertion point: the old v2 record writer and directory patcher can stay as-is, while v3 gets its own combined-directory patcher and direct-record writer. I’m going to keep the old function names for existing callers, but route source-game selection through an explicit parameter or AGI_GAME_DIR.”

    Action/result: Confirmed tools/qemu_fixture.py still imported a global SQ2 path from tools/disassemble_logic.py and identified the copy helpers as the place to parameterize source selection.

  2468. Reported: “I’m editing the fixture tool now. The useful shape is: copy_game_tree(..., game_dir=...) for any evidence input, old v2 helpers unchanged for current SQ2 harnesses, and a new v3 helper that appends a direct uncompressed record to an existing prefixed volume and patches the combined directory.”

    Action/result: Removed the qemu-fixture module’s import-time dependency on SQ2, added explicit source-game selection, and added v3 direct record / combined-directory patch helpers.

  2469. Reported: “The synthetic test game for v3 is tiny, but it exercises the same directory shape Gold Rush uses: one GRDIR, prefixed GRVOL.1, section offsets in the first eight bytes, and exact ff ff ff absent entries. That gives us a local test without touching private game files.”

    Action/result: Added fixture tests for v3 direct-record wrapping, combined-section entry patching, and logic-record replacement in a synthetic Gold Rush-style resource container.

  2470. Reported: “The first pass of the code is in place. I’m running the focused tests now; if the direct-record assumption or any import cleanup is wrong, this should catch it before I write docs around it.”

    Action/result: Ran python3 -B -m py_compile tools/qemu_fixture.py tools/agi_resources.py, which passed, and a focused unittest run, which found a missing end_action import in the new test.

  2471. Reported: “The focused suite found only a test import miss (end_action), not a resource-format issue. I’m fixing that and rerunning.”

    Action/result: Imported end_action in tests/test_qemu_fixture.py and reran the focused fixture/resource tests successfully.

  2472. Reported: “The focused fixture/resource tests are green. I’m doing a quick source scan next for stale SQ2 assumptions in the fixture path, then I’ll update PROGRESS.md and the docs with exactly what changed and what remains provisional.”

    Action/result: Scanned the fixture code and docs for stale selected-game assumptions; remaining fixture-module SQ2 references are compatibility names or v2-specific fixture paths rather than import-time defaults.

  2473. Reported: “The scan shows the fixture module itself no longer imports SQ2, and the remaining SQ2 references there are compatibility-oriented function names or v2-specific fixture builders. I’m updating the tracker now so the next work item becomes targeted v3 behavior probes, not ‘build the v3 writer.’”

    Action/result: Updated PROGRESS.md to mark the basic v3 direct logic fixture writer as available and to make targeted GR behavior probes the top remaining item.

  2474. Reported: “One more small improvement before the docs: I’m adding a CLI entry for the v3 logic fixture writer, so it’s not just a Python helper. It will still require an explicit selected game via --game-dir or AGI_GAME_DIR; no default game path.”

    Action/result: Added tools/qemu_fixture.py v3-logic with payload, logic-number, optional volume, explicit game directory, and output arguments.

  2475. Reported: “The CLI is in place too. I’m moving the documentation from ‘not v3-aware yet’ to the more precise state: basic v3 direct logic fixtures exist; picture/view v3 fixture packing and the behavioral probes are still next.”

    Action/result: Updated docs/src/versions.md and AGENTS.md with the v3 direct logic fixture command and current limitations.

  2476. Reported: “The evidence notes now record the commands and the decision boundary for v3 fixtures. I’m appending the matching progress-log entries, then I’ll run the full local checks.”

    Action/result: Added this v3 fixture writer progress-log block.

  2477. Reported: “The tracker and docs are caught up. I’m running the regression set now: full unit suite with explicit SQ2 input, mdBook build, compatibility wrapper, and whitespace checks.”

    Action/result: Ran AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests (254 tests), mdbook build docs, AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py, and git diff --check; all passed.

  2478. Reported: “The full unit suite is now 254 tests and passed; mdBook and the compatibility wrapper passed too, and git diff --check is clean. I’m doing a final compile/status pass after the CLI addition so the close-out is precise.”

    Action/result: Ran python3 -B -m py_compile tools/qemu_fixture.py tools/agi_resources.py successfully and inspected git status --short plus git diff --stat.

  2479. Reported: “The final status picked up a generated tools/__pycache__ from the test runs. I’m removing only that generated cache, then I’ll record the verification results in the log.”

    Action/result: Removed generated tools/__pycache__ and recorded the final verification result in docs/src/clean_room_executable_notes.md.

  2480. Reported: “The v3 fixture writer is done and verified, so I’m rolling straight into the first targeted delta: GR’s switch_room_like #0x7e..0x80 remap. I’ll start source-first by making the generated fixtures for #0x7e and #0x49, then use QEMU only if the existing harness/image is ready to compare their visible result.”

    Action/result: Inspected games/GR, QEMU snapshot helpers, and the current FreeDOS build state.

  2481. Reported: “There isn’t currently a build/freedos/freedos.img, so a QEMU confirmation would need the FreeDOS setup step before it can run. I’m still going to prepare the source-level fixture/test pieces first; if the image setup is quick and local, I’ll use it for confirmation.”

    Action/result: Confirmed the build directory lacked the FreeDOS image and read tools/setup_freedos_image.py / README setup notes.

  2482. Reported: “For the room-remap probe, the cleanest observable check is pairwise: build one fixture whose first logic switches to 0x49, and another whose first logic switches to 0x7e. If GR really remaps 0x7e to 0x49, those two generated copies should converge to the same room behavior under the original engine.”

    Action/result: Disassembled GR logic 73 and logic 0, confirming that room 0x49 has real picture/setup behavior and that original logic 0 dispatches the current room later in its script.

  2483. Reported: “The FreeDOS builder needs to recreate build/freedos/freedos.img before any QEMU probe can run. I’m trying the normal setup first; if the sandbox blocks the download, I’ll request the narrow approval for that command.”

    Action/result: The sandboxed FreeDOS setup failed with DNS blocked while downloading the official FreeDOS LiteUSB zip.

  2484. Reported: “The sandbox blocked DNS for the FreeDOS download, as expected. I’m asking for approval to run the same setup command outside the sandbox so it can fetch the official FreeDOS image and build the local QEMU disk.”

    Action/result: Reran python3 -B tools/setup_freedos_image.py --force with approval; it downloaded and extracted FD14LITE.img to build/freedos/freedos.img.

  2485. Reported: “The FreeDOS setup is running with approval now. While that finishes, I’m setting up the room-remap helper shape so the dynamic probe can be repeatable instead of a one-off manual run.”

    Action/result: Added tools/gr_v3_behavior_probe.py with room-remap fixture generation and optional QEMU comparison.

  2486. Reported: “I’m going to make the v3 patcher a little more reusable before writing the probe: build_v3_logic_fixture will remain the copy-then-patch entry point, and a new lower-level helper will patch additional logic resources in an already-copied v3 fixture. That lets the room-remap test replace both logic 0 and the destination room logic.”

    Action/result: Added patch_v3_logic_resource() and tests proving an already-generated v3 fixture can be patched again.

  2487. Reported: “I’m adding a small GR-specific behavior probe tool now. It will build two copied v3 fixtures: one switches to room 0x49, the other to 0x7e; both replace logic 0x49 with the same deterministic picture-display logic so the QEMU oracle can compare the two captures directly.”

    Action/result: Added structural tests for the GR v3 room-remap probe fixture builder.

  2488. Reported: “The room-remap probe tool and local structural tests are added. I’m checking them now, and I’ll see whether the FreeDOS image build has finished so I can run the original-engine comparison.”

    Action/result: python3 -B -m py_compile tools/gr_v3_behavior_probe.py tools/qemu_fixture.py and focused room-remap/qemu-fixture tests passed.

  2489. Reported: “Good, the FreeDOS image rebuilt successfully, and the new probe tests pass. I’m running the room-remap probe in build-only mode first to inspect the generated fixtures, then I’ll run the QEMU capture comparison.”

    Action/result: Verified the FreeDOS root with mdir; the first build-only probe run exposed an argument-consumption issue.

  2490. Reported: “I found the real issue: importing qemu_snapshot computes its default DOS image through project_paths, and that path currently asks for a selected game too early. I’m adjusting the probe so build-only mode does not import QEMU snapshot helpers until --run-qemu is actually requested.”

    Action/result: Narrowed the failure further to project-wide --game-dir consumption during imports below qemu_fixture.

  2491. Reported: “More precisely, the project-wide --game-dir hook is being consumed during import by older resource helpers below qemu_fixture, before this probe’s own parser sees it. I’ll make the probe accept the project convention by reading that selected game through project_paths.game_dir() when argparse no longer has --game-dir.”

    Action/result: Reworked the new probe to lazy-import qemu_fixture and QEMU helpers so its own --help and parser work before game selection is consumed.

  2492. Reported: “I’ve made the probe imports lazy so --help and argument parsing work normally. Now I’m rerunning the build-only fixture generation and reading the JSON report back.”

    Action/result: gr_v3_behavior_probe.py --help and the build-only room-remap report succeeded.

  2493. Reported: “Build-only generation works now. The two fixtures are ready; I’m checking the report and then launching the QEMU comparison from the rebuilt FreeDOS image.”

    Action/result: Read back generated fixtures; logic 0 differed only in switch_room_like(#0x49) vs switch_room_like(#0x7e), and logic 0x49 matched in both.

  2494. Reported: “The fixture readback is exactly what we want: logic 0 differs only by switch_room_like #0x49 versus #0x7e, and logic 0x49 in both fixtures is the same deterministic picture-display script. I’m launching the QEMU comparison now.”

    Action/result: The sandbox blocked the local VNC bind for QEMU when run from the Python probe.

  2495. Reported: “QEMU built the snapshot disk but the sandbox blocked the VNC socket bind from inside the Python probe. I’m rerunning the same probe outside the sandbox with a narrow approval for this probe command.”

    Action/result: The approved QEMU run completed and wrote build/gr-v3-behavior/room_remap_qemu_001.json.

  2496. Reported: “The QEMU room-remap probe completed successfully. I’m reading the report and inspecting the captures so I can document exactly what was validated.”

    Action/result: Found both captures byte-identical but all black, so the run was not accepted as behavioral evidence.

  2497. Reported: “The first QEMU pair matched, but both captures are just a blank black screen, so that is not strong evidence yet. I’m treating that as a harness/probe issue, not a behavioral conclusion, and I’ll adjust the marker logic so the destination room visibly draws a known resource.”

    Action/result: Checked that GR pictures 1 and 73 are present and nonblank via the v3 resource reader and PictureRenderer.

  2498. Reported: “The old render_picture.py path is still split-directory-only, so it can’t render GR directly. I’ll use the v3 resource reader plus the existing PictureRenderer class directly to inspect marker picture choices.”

    Action/result: Rendered GR picture payloads directly from agi_resources; picture 1 has 14 visual colors and picture 73 has 8.

  2499. Reported: “The real GR direct records use the same shape we write: header byte equals the volume for direct records, with equal expanded/stored lengths. I’m checking the selected marker picture next; it may simply be blank, which would make the equality test technically true but useless.”

    Action/result: Confirmed the generated direct-record header matches real GR direct logic/sound records.

  2500. Reported: “The marker pictures are not blank locally, so the black QEMU result means the script probably is not reaching/drawing the marker. I’m rerunning with picture 1 and a longer wait to separate ‘bad picture choice’ from ‘room-switch fixture flow.’”

    Action/result: A longer QEMU room-remap run with picture 1 still produced equal all-black captures.

  2501. Reported: “The adjusted QEMU run is still in progress. If it still comes back black, I’ll switch from ‘room switch then destination logic draws’ to a probe that records the remapped room number through a more direct engine-visible side effect.”

    Action/result: The adjusted run completed successfully but still did not produce useful visual evidence.

  2502. Reported: “The picture-1 run completed. I’m inspecting whether that produced a real screen or just the same black false-positive.”

    Action/result: inspect_ppm again reported one unique color and no non-background bounding box.

  2503. Reported: “The longer picture-1 run is still black, so the current remap probe is not yet valid. I’m adding a one-case direct-draw mode to the same tool: patch logic 0 to show a picture immediately. That will tell us whether v3 direct logic replacement executes at all under GR in QEMU.”

    Action/result: Added --probe direct-draw mode to tools/gr_v3_behavior_probe.py.

  2504. Reported: “Direct-draw mode is added. I’m compiling it and running one QEMU capture with picture 1; this is a sanity check for whether our patched v3 logic 0 executes and draws at all.”

    Action/result: Direct-draw pycompile and tests passed; the QEMU capture ran successfully.

  2505. Reported: “The direct-draw QEMU sanity run completed. I’m inspecting the capture; a nonblank image means the v3 fixture writer is executing correctly and the room-remap blankness is specifically about the switch flow.”

    Action/result: Direct draw produced a nonblank 640x400 capture with 14 unique colors.

  2506. Reported: “The direct-draw capture is nonblank, so v3 direct logic replacement works. The black room-remap captures make sense now: logic 0 was switching rooms every cycle, likely preventing the destination room logic from ever settling. I’m changing the switch-room fixture to guard the switch so it fires once, then lets the destination logic run.”

    Action/result: Added a guard variable to the switch-room payload and reran the room-remap probe; captures remained black.

  2507. Reported: “Even guarded, the switch pair stays black, while direct-draw works. That points back to the room-switch helper resetting or short-circuiting more state than the simple guard assumed. I’m going back to the GR disassembly for the room switch path before trying another fixture shape.”

    Action/result: Re-read GR logic 0 and found the original global dispatcher calls call_logic_var(v0) near bytecode offset 0x0ca0.

  2508. Reported: “The GR global logic dispatches the current room near the end with call_logic_var(v0). Since replacing logic 0 removes that dispatch, a room switch alone will never call our patched destination room logic. I’m adjusting the probe: after the one-shot switch, logic 0 should explicitly call call_logic_var(v0) each cycle, matching the original dispatcher shape.”

    Action/result: Updated switch_room_payload() to append call_logic_var(v0) before end.

  2509. Reported: “The switch probe now preserves the essential dispatcher tail: after the guarded switch, logic 0 calls call_logic_var(v0). I’m rerunning the local test and then the QEMU pair.”

    Action/result: Local tests and build-only generation passed.

  2510. Reported: “The dispatcher-tail build is ready and the tests pass. Now I’m running the QEMU comparison again; this one should finally exercise the remap through the original room-switch code and then visibly call the destination room script.”

    Action/result: The dispatcher-tail QEMU run completed successfully and wrote room_remap_dispatch_qemu_pic001_001.json.

  2511. Reported: “The updated QEMU probe completed. I’m inspecting the screen stats now; if both captures match and are nonblank, this becomes our first dynamic v3 behavioral delta test.”

    Action/result: Both captures were byte-identical and nonblank: 14 unique colors, non-background bounding box (0, 0, 639, 399), and matching PPM SHA-256 45518c409f738a1fb2f4233db202f64d2e0e94011a9559e8ace0d952362814ab.

  2512. Reported: “That did it: the dispatcher-tail room-remap probe produced identical nonblank captures for direct 0x49 and alias 0x7e. I’m updating the tracker/docs now, including the false start, because the ‘black-screen equality’ was an important harness lesson.”

    Action/result: Updated PROGRESS.md, docs/src/versions.md, AGENTS.md, docs/src/symbolic_labels.md, and docs/src/clean_room_executable_notes.md with the v3 room-remap probe result.

  2513. Reported: “The high-level docs now show the v3 room-remap result. I’m also tagging the symbolic label entry so future cross-version work sees that the 0x7e case is no longer just source-backed; it has a QEMU evidence artifact.”

    Action/result: Updated docs/src/symbolic_labels.md and added the promoted probe note to docs/src/compatibility_testing.md.

  2514. Reported: “The v3 room-remap docs and tracker are updated. I’m running the full local validation set again, including the new probe tests, then I’ll clean generated caches and report the exact state.”

    Action/result: Ran AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests (257 tests), mdbook build docs, AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py, python3 -B -m py_compile tools/gr_v3_behavior_probe.py tools/qemu_fixture.py tools/agi_resources.py, and git diff --check; all passed.

  2515. Reported: “Validation is clean: 257 tests, mdBook, compatibility wrapper, pycompile, and diff whitespace all passed. I’m removing generated Python cache directories and doing the final status/diff readback.”

    Action/result: Found and removed generated tools/__pycache__; status still has the pre-existing untracked run.sh plus the new probe/test files and edited docs/tools.

  2516. Reported: “Only tools/__pycache__ is generated; run.sh is still the pre-existing untracked file, so I’m leaving it alone. I’m removing the cache and then I’ll add the final verification note to the docs.”

    Action/result: Added the final verification summary to docs/src/clean_room_executable_notes.md.

  2517. Reported: “I’ll keep moving from the tracker’s top item: extend the GR v3 room-remap probe from the validated 0x7e -> 0x49 case to the remaining aliases 0x7f and 0x80, then promote that into the docs/tests if QEMU gives us nonblank matches.”

    Action/result: Re-read PROGRESS.md, tools/gr_v3_behavior_probe.py, and tests/test_gr_v3_behavior_probe.py.

  2518. Reported: “The current probe shape is already right; it just has a one-alias case list. I’m expanding that case list to cover 0x7e, 0x7f, and 0x80 in one QEMU batch, with the report recording per-alias equality against the direct 0x49 capture.”

    Action/result: Updated tools/gr_v3_behavior_probe.py to generate direct 0x49 plus aliases 0x7e, 0x7f, and 0x80, and to report matches_direct per alias.

  2519. Reported: “The code now builds direct 0x49 plus all three alias fixtures. I’m updating the tests to assert the whole alias set and the patched payloads, then I’ll run the probe.”

    Action/result: Updated tests/test_gr_v3_behavior_probe.py to assert fixture labels and switch payloads for all three aliases.

  2520. Reported: “The local expectations now cover alias_7e, alias_7f, and alias_80. I’m running the focused tests and a build-only report before launching QEMU.”

    Action/result: Focused pycompile/tests passed and build/gr-v3-behavior/room_remap_all_build_001.json was generated.

  2521. Reported: “The focused tests and build-only report passed. I’m reading the report and payloads once, then running the four-case QEMU batch.”

    Action/result: Verified generated logic payloads differ only by target bytes 0x49, 0x7e, 0x7f, and 0x80.

  2522. Reported: “The generated fixture payloads are exactly differentiated by the room byte. I’m launching the QEMU run now; it should produce four captures and compare every alias back to the direct 0x49 case.”

    Action/result: Started the approved QEMU run for room_remap_all_qemu_pic001_001.json.

  2523. Reported: “The expanded QEMU run is in progress. This one has four fixtures, so it takes a little longer than the previous two-case run.”

    Action/result: The QEMU run completed and wrote build/gr-v3-behavior/room_remap_all_qemu_pic001_001.json.

  2524. Reported: “The four-case QEMU run completed. I’m inspecting the per-alias match flags and screen stats now before promoting the result.”

    Action/result: The report shows alias_7e, alias_7f, and alias_80 all match direct 0x49; all four captures are nonblank with 14 unique colors and identical PPM SHA-256 45518c409f738a1fb2f4233db202f64d2e0e94011a9559e8ace0d952362814ab.

  2525. Reported: “All three aliases matched the direct room target with nonblank captures. I’m promoting the probe from ‘one alias validated’ to ‘full 0x7e..0x80 range validated’ across the tracker and docs, and I’ll update the probe label so future reports say what they actually cover.”

    Action/result: Updated the probe report label and began updating PROGRESS.md, AGENTS.md, and mdBook chapters to reference the all-alias evidence.

  2526. Reported: “The tracker now treats the whole room-alias range as covered. I’m updating the command references and evidence text next.”

    Action/result: Updated AGENTS.md, docs/src/versions.md, docs/src/compatibility_testing.md, docs/src/symbolic_labels.md, and docs/src/clean_room_executable_notes.md for the all-alias room-remap evidence.

  2527. Reported: “I’ve got the thread state back. I’m at the validation pass for the expanded Gold Rush v3 room-remap probe, then I’ll update the evidence log with the exact checks and give you the compact outcome.”

    Action/result: Ran the validation pass after the expanded room-remap probe and documentation updates.

  2528. Reported: “The core validation pass is clean: 257 unit tests, mdBook, pycompile, and whitespace checks all passed. I’m running the compatibility suite now because it catches the cross-doc opcode/evidence consistency that the plain test run doesn’t cover.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests, mdbook build docs, python3 -B -m py_compile tools/gr_v3_behavior_probe.py tools/qemu_fixture.py tools/agi_resources.py, and git diff --check all passed.

  2529. Reported: “Compatibility suite passed as well. A generated tools/__pycache__ appeared from the runs, so I’m cleaning only that generated directory and then I’ll record the validation result in the project log.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py passed, and the generated tools/__pycache__ directory was removed.

  2530. Reported: “The detailed evidence note already contains the final verification block, so I only need to add the matching progress-log entries. After that I’ll rerun the lightweight checks touched by the log edit.”

    Action/result: Added the validation and cleanup entries to this log.

  2531. Reported: “The expanded room-remap pass is wrapped and validated. I’m going back to PROGRESS.md now and taking the next highest-value item, staying source-first and using QEMU only if there’s a concrete behavior worth confirming.”

    Action/result: Re-read PROGRESS.md, the GR/SQ2 static comparison helper, and relevant key/menu/save/object references.

  2532. Reported: “The next item is the GR v3 key/menu event delta: 0x79, 0xad, 0xb1, and 0xb5. I’m going to pin down the disassembled routines first, because here the useful outcome is a portable description of the event tables and gates rather than just a visual probe.”

    Action/result: Located the existing GR v3 key/menu source-map notes and symbolic labels for code.input.map_key_event, code.menu.interact, and the key-release gate globals.

  2533. Reported: “The docs already contain a solid source map for the key/menu gates; what’s missing is a focused behavioral fixture. I’m reading the current v3 probe builder and the existing SQ2 key/menu probes so I can extend the same harness without inventing a separate path.”

    Action/result: Read tools/gr_v3_behavior_probe.py, tools/logic_interpreter_probe.py, tools/qemu_fixture.py, and the focused GR v3 probe tests.

  2534. Reported: “There’s a nice fit here: the existing SQ2 logic probe already has code snippets for mapped-key/status-byte tests. I’m extracting the minimal bytecode patterns from that rather than building a new comparison mechanism.”

    Action/result: Reused the existing 0x79 mapped-key/status-byte fixture shape as the model for the GR v3 capacity probe.

  2535. Reported: “For the key-map capacity probe, I can avoid any generated graphics: show one original GR picture when the mapped status byte fires, and compare that capture to a direct draw of the same picture. That keeps this about interpreter event behavior, not renderer fidelity.”

    Action/result: Chose original GR picture 1 as the marker image for both direct and keyed captures.

  2536. Reported: “Before I wire the fixture, I’m re-reading the GR disassembly around the four handler entry points so the code and docs are anchored to exact local evidence, not just the earlier summary text.”

    Action/result: Re-read GR disassembly around 0x4e98, 0x63a8, 0x63b0, 0x63b8, 0x970b, and 0x9724.

  2537. Reported: “The disassembly confirms the key-map capacity is a literal loop bound change to 0x31, and the gate pair is very small: 0xad writes one byte, 0xb5 clears it, and the IRQ hook checks that byte. I’m going to add a probe that exercises the expanded 49th mapping slot, since that is the most observable part of this cluster.”

    Action/result: Planned a slot-48 key-map capacity fixture while leaving raw release/menu gate timing as source-backed follow-up work.

  2538. Reported: “The key-map probe I’m adding fills 48 dummy mapping slots, then puts the real x -> status 7 mapping in the final GR slot. Under the source model this should work in GR v3 (0x31 slots) and would fail under the SQ2-sized 0x27 table.”

    Action/result: Started extending tools/gr_v3_behavior_probe.py and tests/test_gr_v3_behavior_probe.py.

  2539. Reported: “The first patch missed because the file had shifted from the context I targeted. I’m splitting the edit into smaller hunks so it stays readable and avoids touching unrelated sections.”

    Action/result: Re-opened tools/gr_v3_behavior_probe.py with line numbers and resumed with smaller patches.

  2540. Reported: “The file is compact, so the extension is straightforward. I’m adding constants and the payload/builder first, then I’ll add the CLI branch.”

    Action/result: Added key-map slot-count constants and post-launch key metadata to ProbeCase.

  2541. Reported: “Constants and case metadata are in place. Next I’m adding the actual bytecode payload: 48 filler 0x79 mappings, then the real x mapping in slot 48, followed by a per-cycle status check that displays an original GR picture.”

    Action/result: Added key_map_capacity_payload().

  2542. Reported: “The payload is now expressed as reusable bytecode, which makes it testable without booting QEMU. I’m adding the fixture builder and making the QEMU runner honor post-launch keystrokes.”

    Action/result: Added build_key_map_capacity_fixtures() and taught run_qemu_cases() to pass post-launch key fields into SnapshotFixtureCase.

  2543. Reported: “The runner can now type the probe key after launch. I’m wiring the --probe key-map-capacity branch so it produces the same style of JSON report as the room-remap probe.”

    Action/result: Added the key-map-capacity CLI branch and report fields.

  2544. Reported: “The CLI branch is in. I’m updating the focused tests to assert the generated v3 fixture really puts the live mapping in the last GR slot and patches only copied fixture data.”

    Action/result: Added tests for the key-map payload and copied fixture contents.

  2545. Reported: “The unit tests now cover the new payload and fixture builder. I’m running those focused checks and a build-only probe before trying QEMU.”

    Action/result: Focused GR v3 tests, pycompile, and build-only key_map_capacity_build_001.json generation passed.

  2546. Reported: “The focused tests and build-only run are clean. I’m inspecting the generated report and payload once, then I’ll launch the QEMU validation for the final-slot mapping.”

    Action/result: Confirmed the generated payload had 49 map actions, with the target x mapping after 48 prior 0x79 opcodes.

  2547. Reported: “The generated logic has exactly 49 0x79 actions and the target mapping is after 48 filler slots, which is the edge we wanted. I’m running the original GR interpreter now and comparing the final-slot key capture to a direct picture draw.”

    Action/result: Ran the first QEMU key-map capacity probe, producing build/gr-v3-behavior/key_map_capacity_qemu_pic001_001.json.

  2548. Reported: “The QEMU run completed successfully. I’m checking both the JSON match flag and the actual capture stats so we know this wasn’t an all-black false positive.”

    Action/result: The keyed slot-48 capture matched the direct capture; both had the same PPM SHA-256 as the known nonblank picture-1 capture.

  2549. Reported: “The match flag is true and the two PPM files have the same SHA-256 as the earlier nonblank picture-1 capture. I tried to pass both files to inspect_ppm.py at once, but that helper accepts one image at a time, so I’m rerunning it separately.”

    Action/result: Re-ran inspect_ppm.py separately; both captures were 640x400, 14 unique colors, with full-screen non-background bounds.

  2550. Reported: “I’m going to tighten this one more notch: add a paired no-key fixture using the same slot-48 table. The positive case should match the direct picture only after x; the no-key case should not. That guards against a preexisting status byte or accidental initial draw.”

    Action/result: Added a slot_48_no_key fixture using the same payload without post-launch key input.

  2551. Reported: “The no-key fixture is added. I’m updating the report logic so this probe has explicit expected true and expected false comparisons instead of treating every case as ‘should match.’”

    Action/result: Added expected_matches_direct and passed fields for the key-map capacity report.

  2552. Reported: “The report now distinguishes positive and negative expectations. I’m adjusting the tests for the extra fixture and then rerunning the focused checks.”

    Action/result: Updated tests to verify the direct, keyed, and no-key fixtures.

  2553. Reported: “The tests now expect both the positive and no-key controls. I’m rerunning the focused suite and the QEMU validation with the three-case batch.”

    Action/result: Focused tests, pycompile, and build-only key_map_capacity_build_002.json passed.

  2554. Reported: “Focused tests and build-only generation are still clean. I’m launching the updated QEMU run; this one should show direct = keyed slot-48, and no-key different.”

    Action/result: Started the three-case QEMU key-map capacity batch.

  2555. Reported: “The three-case QEMU batch is still running. It boots once, saves the DOS prompt, then restores that snapshot for each fixture, so this should finish shortly.”

    Action/result: The QEMU batch completed and wrote build/gr-v3-behavior/key_map_capacity_qemu_pic001_002.json.

  2556. Reported: “The three-case QEMU run finished. I’m checking the expected true/false matches and the capture stats now.”

    Action/result: The report passed: slot_48_key_map matched direct, slot_48_no_key did not; direct/keyed were nonblank with 14 colors, and no-key was blank.

  2557. Reported: “The capacity probe passed: keyed slot 48 matches the direct picture, while the no-key control stays blank. I’m promoting this into the tracker/docs now, keeping the key-release/menu gates as source-backed unless we later need raw scan-code timing evidence.”

    Action/result: Began promoting the key-map capacity result to PROGRESS.md and the mdBook evidence.

  2558. Reported: “I’m updating the docs in the places that act as navigational anchors: PROGRESS.md, AGENTS.md, versions, logic_bytecode, compatibility_testing, symbolic labels, and the clean-room evidence note. The detailed opcode rows stay SQ2-specific; the GR behavior goes into the cross-version notes.”

    Action/result: Read the relevant documentation anchors for targeted updates.

  2559. Reported: “I found the existing v3 compatibility section, so I’ll extend that rather than creating a duplicate. The new evidence note will sit after the room-remap section because it uses the same fixture harness.”

    Action/result: Patched PROGRESS.md to record QEMU-validated GR key-map capacity and narrow the remaining v3 behavioral work list.

  2560. Reported: “PROGRESS.md now treats key-map capacity as QEMU-validated and leaves the raw release/menu gate timing as optional follow-up. I’m adding the runnable command to AGENTS.md next so future sessions can reproduce it.”

    Action/result: Added the key-map capacity QEMU command and pass criteria to AGENTS.md.

  2561. Reported: “The reproduction command is in AGENTS.md. I’m updating the mdBook version and bytecode notes so someone reading the spec sees both the source delta and the QEMU confirmation.”

    Action/result: Started updating docs/src/versions.md.

  2562. Reported: “The versions chapter wording was slightly different than expected, so I’m patching the exact nearby lines now.”

    Action/result: Updated the GR key/menu row and dynamic probe paragraph in docs/src/versions.md.

  2563. Reported: “The versions chapter now records both the source delta and the final-slot QEMU evidence. I’m making the same concise update in the logic bytecode cross-version note.”

    Action/result: Updated the GR cross-version key/menu row in docs/src/logic_bytecode.md.

  2564. Reported: “The bytecode chapter now points readers at the observable slot-48 behavior. Next I’m extending the compatibility testing chapter with the exact command and pass criteria.”

    Action/result: Added the key-map capacity command and expected positive/no-key control behavior to docs/src/compatibility_testing.md.

  2565. Reported: “Compatibility testing now has the reproducible command and acceptance criteria. I’m adding a short symbolic-label note on the GR code.input.map_key_event association so the evidence is discoverable from the address map too.”

    Action/result: Updated docs/src/symbolic_labels.md for GR code.input.map_key_event.

  2566. Reported: “The symbolic map now links 0x4e98 to the slot-48 QEMU evidence. I’m appending the detailed chronological evidence note with the disassembly anchors, fixture shape, and capture stats.”

    Action/result: Added the Gold Rush v3 key-map capacity behavior probe section to docs/src/clean_room_executable_notes.md.

  2567. Reported: “The evidence note has the full source/QEMU record. I’m appending the progress-log entries for this work block now; it’s a little long because it preserves the intermediate updates you asked to keep.”

    Action/result: Added progress-log entries for the GR v3 key-map capacity work block.

  2568. Reported: “The docs and log are updated. I’m running the full local validation pass now; after that I’ll record the verification result and clean any generated cache.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed with 259 tests, mdbook build docs passed, python3 -B -m py_compile tools/gr_v3_behavior_probe.py tools/qemu_fixture.py tools/agi_resources.py passed, and git diff --check passed.

  2569. Reported: “The first validation group is clean: 259 tests, mdBook, pycompile, and diff hygiene passed. I’m running the compatibility suite as the final consistency check.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py passed.

  2570. Reported: “The compatibility suite passed too. A generated tools/__pycache__ came back from the run, so I’m removing just that generated cache and then I’ll add the final verification note for this key-map pass.”

    Action/result: Removed generated tools/__pycache__.

  2571. Reported: “The cache is cleaned. I’m adding the validation commands/results to the evidence note and progress log, then I’ll run the final mdBook and diff checks after those edits.”

    Action/result: Added the final verification block to docs/src/clean_room_executable_notes.md.

  2572. Reported: “The key-map evidence note now includes its verification block. I’m adding the matching progress-log entries for validation and cleanup.”

    Action/result: Added validation and cleanup entries to this log.

  2573. Reported: “The final mdBook and diff checks are clean. I’m continuing to the next PROGRESS item: the GR v3 save-envelope/object-inventory XOR delta. I’ll start by reading the existing save probe and the GR/SQ2 disassembly notes before deciding whether to add a QEMU save-file check.”

    Action/result: Read tools/save_roundtrip_probe.py, save-related docs, the GR/SQ2 source-pass notes, and tools/agi_save.py.

  2574. Reported: “The existing notes already identify the GR save handler and XOR helper, but this needs to become more implementation-ready. I’m checking whether we can make a targeted original-engine save-file probe for GR, and if that’s too much for this pass I’ll at least codify the XOR transform with source-backed tests.”

    Action/result: Checked local GR files, GR logic usage of save/restore opcodes, and existing SQ2 save-roundtrip harness assumptions.

  2575. Reported: “GR logic 0 itself calls 0x8f(#3), so the save prefix/signature likely comes from a local message rather than being hard-coded to SQ2. I’m reading that logic resource/message and the exact save handler bytes next, because a GR save probe needs the right signature setup to produce a parseable file.”

    Action/result: Read GR logic 0, exact-offset disassembly for save action 0x29e5, XOR helper 0x07bc, and restore action 0x2792.

  2576. Reported: “The first exact-offset read confirmed the save handler calls 0x07bc before entering the selector and later around the write path. One helper command failed because I passed a string where the resource reader expected a configured/Path game directory, so I’m rerunning the message extraction with Path(...).”

    Action/result: Re-ran the local reads with Path("games/GR"); exact save block disassembly showed the XORed range is written as the third block.

  2577. Reported: “GR’s XOR key is not an ASCII string; the helper resets DI to image offset 0x072c and uses those local bytes until the first zero byte, then wraps. That means the clean-room spec should describe it as observed key bytes, not as a named text key.”

    Action/result: Found the first zero byte at image 0x0767, making the observed repeating XOR sequence 59 bytes long.

  2578. Reported: “The GR save layout differs from SQ2’s fixed block sizes: the exact handler writes a third block from [0x07d6] with length [0x07da], and that is the range XORed before and after the save path. I’m going to capture that as a source-backed transform first; a full GR save UI probe can build on it once we know the right signature/prompt sequence.”

    Action/result: Chose to implement a source-backed helper/test model before attempting full GR save-file extraction.

  2579. Reported: “For this save pass I’m adding a small version-specific transform helper instead of forcing the whole GR save UI immediately. The source-backed contract is the important bit: block 2 is XORed on disk with the observed 59-byte sequence and the same pass restores memory afterward.”

    Action/result: Added GR_V3_OBJECT_INVENTORY_XOR_KEY, xor_with_repeating_key(...), and gr_v3_object_inventory_save_xor(...) to tools/agi_save.py.

  2580. Reported: “The save helper now has the GR v3 object/inventory XOR transform as a named function with the observed key bytes. I’m adding focused tests for round-trip behavior and the 59-byte wrap point.”

    Action/result: Started updating tests/test_save_resources.py.

  2581. Reported: “The save tests have a slightly different import block than I expected. I’m opening the file and patching against its actual shape.”

    Action/result: Re-opened tests/test_save_resources.py and patched the imports/test methods against its current layout.

  2582. Reported: “I’ve got the exact test file layout now. I’m adding the imports and the three transform tests at the end of the existing save-resource test class.”

    Action/result: Added tests for GR transform round-trip, 59-byte key wrap, and empty-key rejection.

  2583. Reported: “The transform tests are in place. I’m running the focused save tests and pycompile before documenting this source-backed model.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests/test_save_resources.py passed with 10 tests, and python3 -B -m py_compile tools/agi_save.py passed.

  2584. Reported: “Focused save tests pass. I’m documenting this as a source-backed GR save model: the transform is now executable in the local helpers, while a future full GR save UI probe can check the on-disk block bytes directly.”

    Action/result: Updated PROGRESS.md to treat the save XOR model as source-backed and tested, with full GR save extraction left optional.

  2585. Reported: “PROGRESS.md now treats the save XOR as source-modeled with tests, not as an unstarted item. I’m adding the concrete key/range details to the version and opcode docs.”

    Action/result: Updated docs/src/versions.md.

  2586. Reported: “The versions chapter now includes the 59-byte save transform detail. I’m making the bytecode cross-version note match.”

    Action/result: Updated docs/src/logic_bytecode.md.

  2587. Reported: “The bytecode note is aligned. I’m adding a short runtime-model note so the portable spec distinguishes SQ2’s plain save blocks from GR’s transformed object/inventory block.”

    Action/result: Updated docs/src/runtime_model.md.

  2588. Reported: “The runtime model now has the GR v3 save-block note. I’m checking the surrounding markdown so I didn’t accidentally split a table in an awkward place.”

    Action/result: Verified the new runtime-model paragraph sits after the save/restore selector table and before the lifecycle table.

  2589. Reported: “The note sits cleanly between the selector table and lifecycle table. I’m adding symbolic labels for the GR save block start/length and key bytes so future comparisons can track if another v3 interpreter moves them.”

    Action/result: Updated docs/src/symbolic_labels.md with GR save block and XOR key data labels.

  2590. Reported: “The symbolic map now records the GR save block pointer, length, and key region. I’m adding a chronological evidence section for the save XOR model, including the exact disassembly calls and the new local tests.”

    Action/result: Added the Gold Rush v3 save object/inventory XOR model section to docs/src/clean_room_executable_notes.md.

  2591. Reported: “The detailed evidence note now captures the save transform. I’m adding a concise compatibility-testing note so the helper tests show up in the suite narrative.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2592. Reported: “The compatibility chapter now includes the GR v3 save transform tests. I’m appending progress-log entries for this save-XOR block, then I’ll run the full validation again with the new helper/tests/docs.”

    Action/result: Added progress-log entries for the GR v3 save XOR work block.

  2593. Reported: “The save-XOR work block is logged. I’m running the full validation pass again now that both code and docs changed.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed with 262 tests, mdbook build docs passed, python3 -B -m py_compile tools/agi_save.py tools/gr_v3_behavior_probe.py tools/qemu_fixture.py tools/agi_resources.py passed, and git diff --check passed.

  2594. Reported: “The main validation group is clean again: 262 tests, mdBook, pycompile, and diff hygiene passed. I’m running the compatibility suite as the final check for this save-XOR update.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py passed.

  2595. Reported: “The compatibility suite passed. I’m removing the generated cache again and then recording the save-XOR verification result in the evidence note/log.”

    Action/result: Removed generated tools/__pycache__.

  2596. Reported: “The cache is gone. I’m adding the final verification line for the save-XOR pass, then I’ll run the two lightweight doc hygiene checks.”

    Action/result: Added the final verification block to docs/src/clean_room_executable_notes.md.

  2597. Reported: “The evidence note has the final verification block. I’m adding the corresponding progress-log entries now.”

    Action/result: Added validation and cleanup entries to this log.

  2598. Reported: “The final doc checks are clean. I’m moving on to the next remaining v3 delta, restart prompt-marker preservation, and I’ll stay with the same source-first pattern.”

    Action/result: Read PROGRESS.md, restart/prompt-marker references, and exact GR disassembly for 0x26e0, 0x3b00, 0x3ab0, and 0x3ad9.

  2599. Reported: “The GR restart source slice has an important nuance: canceled restart preserves hidden prompt-marker state, but accepted restart still calls the show-marker helper before returning zero into the reset flow. I’m going to correct that wording and add a tiny tested truth table so the spec is precise.”

    Action/result: Searched for stale GR restart wording and planned a tested truth-table helper.

  2600. Reported: “The search found one stale sentence saying GR redraws only when restart was canceled and the marker had been visible; the disassembly shows accepted OR previously-visible. I’m adding a tiny agi_restart helper and tests to pin that truth table down.”

    Action/result: Added tools/agi_restart.py with gr_v3_restart_redraws_prompt_marker(...).

  2601. Reported: “The restart helper is in place. I’m adding a focused test file for the four prompt-marker redraw cases.”

    Action/result: Added tests/test_restart_model.py.

  2602. Reported: “The restart truth table has a local test now. I’m running the focused restart test and pycompile before I patch the docs.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests/test_restart_model.py passed, and python3 -B -m py_compile tools/agi_restart.py passed.

  2603. Reported: “Focused restart checks pass. I’m correcting the stale wording now: the GR v3 branch redraws after accepted restart, and after canceled restart only if the marker had been visible beforehand.”

    Action/result: Updated tools/compare_gr_sq2_static.py.

  2604. Reported: “The static comparison note is corrected. I’m updating the tracker and version docs to reflect the tested truth table.”

    Action/result: Updated PROGRESS.md.

  2605. Reported: “PROGRESS.md now narrows the remaining v3 behavioral item to object motion mode 4, with restart QEMU left optional. I’m patching the mdBook wording in the cross-version sections.”

    Action/result: Updated docs/src/versions.md.

  2606. Reported: “The versions table now has the precise accepted/canceled restart behavior. I’m updating the logic bytecode note and runtime model next.”

    Action/result: Updated docs/src/logic_bytecode.md.

  2607. Reported: “The bytecode cross-version note is updated. I’m adding a concise GR v3 note in the restart lifecycle section of the runtime model.”

    Action/result: Opened the restart lifecycle section and patched docs/src/runtime_model.md after adjusting for the current table layout.

  2608. Reported: “The restart lifecycle section has drifted slightly from the context I targeted, so I’m opening that block and patching the actual text.”

    Action/result: Inspected docs/src/runtime_model.md around the restart lifecycle table.

  2609. Reported: “The lifecycle table doesn’t have a separate fatal row label I expected. I’m inserting the GR restart note right after the table, before the picture decoder section.”

    Action/result: Added the GR v3 restart prompt-marker truth-table note to docs/src/runtime_model.md.

  2610. Reported: “The runtime model now has the GR truth table note. I’m correcting the stale clean-room note and symbolic label text, then I’ll add a compact evidence section for the restart model.”

    Action/result: Corrected stale GR restart wording in docs/src/clean_room_executable_notes.md and updated docs/src/symbolic_labels.md.

  2611. Reported: “The stale wording is fixed. I’m adding the restart truth-table tests to the compatibility narrative and then a short chronological evidence section.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2612. Reported: “Compatibility testing now mentions the restart truth table. I’m appending the chronological source-model note for the GR restart branch.”

    Action/result: Added the Gold Rush v3 restart prompt-marker truth-table section to docs/src/clean_room_executable_notes.md.

  2613. Reported: “The restart evidence note is in place. I’m logging this restart-model block, then I’ll run validation again with the new helper/test/docs.”

    Action/result: Added progress-log entries for the GR v3 restart prompt-marker work block.

  2614. Reported: “The restart-model block is logged. I’m running the full validation pass with the new helper and docs.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed with 263 tests, mdbook build docs passed, python3 -B -m py_compile tools/agi_restart.py tools/agi_save.py tools/gr_v3_behavior_probe.py tools/qemu_fixture.py tools/agi_resources.py tools/compare_gr_sq2_static.py passed, and git diff --check passed.

  2615. Reported: “The first restart validation group is clean: 263 tests, mdBook, pycompile, and diff hygiene passed. I’m running the compatibility suite one more time.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py passed.

  2616. Reported: “The compatibility suite passed too. I’m cleaning the generated cache, adding the restart verification note, and then I’ll do the final lightweight checks.”

    Action/result: Removed generated tools/__pycache__.

  2617. Reported: “The cache is cleaned. I’m recording the restart validation results now.”

    Action/result: Added the final verification block to docs/src/clean_room_executable_notes.md.

  2618. Reported: “The restart evidence note has its verification block. I’m adding the matching progress-log validation entries.”

    Action/result: Added restart validation and cleanup entries to this log.

  2619. Reported: “I’ll use PROGRESS.md as the steering file, then pick the highest-value unfinished item that can be advanced from the local disassembly and existing tools. First I’m refreshing the dashboard and nearby docs so I don’t drift from the current evidence trail.”

    Action/result: Re-read PROGRESS.md, AGENTS.md, current git status, and v3-related docs. The dashboard pointed to GR object motion mode 4 and the frame-selection gate as the top remaining v3 behavior items.

  2620. Reported: “The dashboard points at one main unfinished v3 behavior item: Gold Rush object motion mode 4, plus the related frame-selection gate. I’m going source-first now: inspect the existing comparison helper outputs, disassembly labels, and v3 probe scaffolding before deciding what fixture to add.”

    Action/result: Re-read tools/gr_v3_behavior_probe.py, tools/qemu_fixture.py, the static GR/SQ2 comparison helper, and build/gr-sq2-static artifacts.

  2621. Reported: “I found the existing docs already treat mode 4 as source-backed but not behavior-validated. There’s one minor shell wart in my search because Markdown backticks were interpreted inside a quoted pattern; the useful matches are intact, and I’ll avoid that quoting shape for the next searches.”

    Action/result: Confirmed current docs mention GR mode 4 and avoided that shell quoting pattern in later searches.

  2622. Reported: “The v3 fixture builder can already patch direct logic into a copied GR directory, which is enough for a behavior probe if the original game’s existing picture/view resources are suitable. Next I’m reading the exact GR motion dispatch and frame-timer snippets around the documented addresses.”

    Action/result: Read GR/SQ2 ndisasm around code.motion.dispatch_mode_step and code.object.frame_timer_update.

  2623. Reported: “The disassembly confirms the narrow delta: SQ2 dispatch decrements mode and accepts resulting values 0..2 (modes 1..3), while GR accepts 0..3 and the fourth jump-table slot lands on the same target-direction handler as mode 3. I’m looking at the existing movement harness now so the v3 probe reuses the proven object setup pattern instead of inventing a new one.”

    Action/result: Re-read tools/object_movement_probe.py for the existing persistent-object movement setup and comparison patterns.

  2624. Reported: “There’s an important source question before writing a probe: normal logic opcodes set motion modes 1, 2, and 3, but I don’t yet have a script-visible setter for +0x22 = 4. I’m searching the GR image for the write sites that create mode 4; that will determine whether the fixture should be pure logic, saved-state based, or keyboard/input driven.”

    Action/result: Found GR mode-4 write-like code at image 0x1975, plus mode-4 special cases at 0x18cf, room switch cleanup, and action 0x84.

  2625. Reported: “The mode-4 setter is not a logic opcode write. GR writes +0x22 = 4 inside the input/motion area around image 0x198e, and several helpers special-case mode 4 afterward. I’m opening that neighborhood now to map what observable path leads there.”

    Action/result: Inspected GR image 0x1888..0x1a84, including target-direction helper 0x1888, completion helper 0x18cf, helper-shaped code at 0x1975, and room switch cleanup.

  2626. Reported: “The action table only routes room-switch opcodes 0x12/0x13 into that neighborhood; no action points at the mode-4 helper. If a bytecode opcode routes to it we can write a clean pure-logic probe; if not, the route is likely through input/click handling.”

    Action/result: Parsed the local GR action table; only 0x12 and 0x13 point near 0x19d4/0x19eb, not at 0x1975.

  2627. Reported: “Rizin needed the seek form for xrefs here, and it also treats this GR executable as a flat image, which matches the ndisasm evidence. I’m correcting that and continuing with the local disassembly as the primary source.”

    Action/result: Tried rizin xrefs, then relied on direct ndisasm and a byte-level call scan because rizin did not produce useful xrefs for this flat 16-bit image.

  2628. Reported: “The mode-4 setter at 0x1975 is a helper, not a direct call in the linear disassembly. I’m checking the action table next, because if a bytecode opcode routes to it we can write a clean pure-logic probe; if not, the route is likely through input/click handling.”

    Action/result: Confirmed again that no action table entry directly routes to 0x1975.

  2629. Reported: “The byte-level scan shows no direct near calls to the mode-4 target seeder. The address appears only as data-like words, so I’m inspecting those references to avoid inventing a path that the interpreter doesn’t actually use.”

    Action/result: Scanned direct near-call targets and little-endian word occurrences. No direct calls to image 0x1975 were found.

  2630. Reported: “The action table confirms mode 4 is generated outside normal logic, and the setter’s body uses screen coordinates plus the object’s dimensions to seed target bytes. That looks like mouse/joystick-click style ego movement: set object0 mode 4, set target X/Y, preserve current step, then let the ordinary target-direction machinery run.”

    Action/result: Recorded the hypothesis that 0x1975 is an input-driven first-object target seeder, while keeping the natural entry path unresolved.

  2631. Reported: “I’m not finding a script-visible or direct-call path into the mode-4 seeder, so I’m treating that as evidence rather than forcing it. Before patching anything, I’m checking the GR file set and resource scripts for any local inputs that might naturally exercise the mode-4 path.”

    Action/result: Listed games/GR and ran tools/disassemble_logic.py --game-dir games/GR --stats; local GR scripts use motion actions heavily but no direct mode-4 setter exists.

  2632. Reported: “GR scripts use the normal motion opcodes heavily, but no local script directly creates mode 4; that reinforces that it’s an engine/input state. I also confirmed my attempted --opcode option doesn’t exist on the local disassembler, so I’m staying with --stats and raw disassembly for this pass.”

    Action/result: Noted the disassembler CLI limitation and continued with source-first ndisasm reads.

  2633. Reported: “There is no opcode that writes arbitrary object bytes, so a pure bytecode fixture cannot set +0x22 = 4. The cleanest validation route I see is an explicitly instrumented copied interpreter: change the move_object_to setup byte in the build copy from mode 3 to mode 4, then compare its capture against the unmodified mode-3 path. That would test the GR dispatcher while clearly separating it from normal game-data compatibility evidence.”

    Action/result: Chose an instrumented copied-interpreter probe rather than presenting mode 4 as ordinary script-visible behavior.

  2634. Reported: “I’m going to build this as an ‘instrumented mode-4 dispatch probe,’ not as ordinary unmodified-engine compatibility. First I need a compact GR picture/view pair that renders cleanly with existing resources, so I’m scanning the local GR resource directory and renderer support.”

    Action/result: Used tools/agi_resources.py to list present GR resources and selected picture 1/view 0/group 0/frame 0 for the probe.

  2635. Reported: “The older graphics helper is SQ2-oriented for direct rendering, but the resource parser can read GR v3 records. For this probe I can avoid local rendering entirely: compare original-engine captures between unmodified mode-3 setup and the instrumented mode-4 setup, with a stationary control.”

    Action/result: Designed the three-case capture comparison: stationary, unmodified mode 3, and instrumented mode 4.

  2636. Reported: “View 0 is a good candidate: it has a compact 7-pixel-wide walking figure with multiple groups, and picture 1 is present. I’m going to implement the probe around picture 1/view 0, with three cases: stationary control, unmodified mode 3, and instrumented mode 4.”

    Action/result: Implemented the motion-mode payload and fixture builder in tools/gr_v3_behavior_probe.py.

  2637. Reported: “I’m going to keep the interpreter patch local to the v3 behavior probe rather than generalizing it into the fixture builder. It’s a deliberately instrumented test, so keeping that sharp edge near the report code makes the evidence trail clearer.”

    Action/result: Added a local helper that patches only generated GR fixture copies and checks the expected action-0x51 byte context.

  2638. Reported: “One small cleanup before tests: the script’s global --picture default was room-remap-specific. I’m making the per-probe default explicit so the new motion probe naturally uses picture 1 unless told otherwise.”

    Action/result: Changed --picture to use per-probe defaults.

  2639. Reported: “Now I’m adding focused unit coverage for the new probe: payload shape, fixture construction, and the safety check that only a copied GR interpreter with the expected byte sequence gets patched.”

    Action/result: Added focused tests in tests/test_gr_v3_behavior_probe.py.

  2640. Reported: “The focused test failed at import time because one of the legacy graphics modules still demands AGI_GAME_DIR during module import. I’ll rerun with an explicit local game path for now, and then check whether the test invocation should be made independent.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests.test_gr_v3_behavior_probe passed with 8 tests.

  2641. Reported: “The focused tests pass with AGI_GAME_DIR=games/SQ2, matching the repo’s current legacy import pattern. I’m running the new GR motion-mode probe through QEMU now; it will produce a JSON report under build/gr-v3-behavior/.”

    Action/result: Started QEMU motion-mode probe build/gr-v3-behavior/motion_mode_4_qemu_pic001_001.json.

  2642. Reported: “Good catch from the harness: the documented address is a loaded-image offset, while the real GR file has a 0x200-byte MZ header. I’m fixing the patch helper to translate image offsets to file offsets instead of assuming the two are identical.”

    Action/result: Corrected the patch helper to apply the MZ header size when patching copied GR executables.

  2643. Reported: “The patch helper now handles both flat test files and real MZ-wrapped GR executables. I’m rerunning the focused tests, then I’ll retry the QEMU probe.”

    Action/result: Focused tests passed again.

  2644. Reported: “The focused tests are green again. I’m rerunning the QEMU probe with the corrected image-to-file offset translation.”

    Action/result: Reran the GR motion-mode QEMU probe.

  2645. Reported: “QEMU is running the three-case snapshot batch now. I’ll wait for the report and then inspect the comparisons, especially whether the stationary control differs from the moving captures.”

    Action/result: QEMU finished and wrote build/gr-v3-behavior/motion_mode_4_qemu_pic001_001.json.

  2646. Reported: “The QEMU run finished and wrote the report. I’m reading the JSON now to see whether the instrumented mode-4 capture matched mode 3 and whether the stationary control stayed distinct.”

    Action/result: The JSON report passed: mode4_instrumented_move_object_to_matches_mode3 was true and stationary_control_matches_mode3 was false.

  2647. Reported: “The report passed: instrumented mode 4 produced the same capture as unmodified mode 3, and the stationary control did not match. I’m updating the docs carefully so this is recorded as an instrumented dispatcher probe, not as an unmodified-game-data behavior claim.”

    Action/result: Began documentation updates in PROGRESS.md, compatibility docs, runtime/object docs, version notes, symbolic labels, and clean-room notes.

  2648. Reported: “The worktree has the expected GR mode-4 changes plus an old untracked run.sh; I’m leaving that alone. One tiny shell got bitten by Markdown backticks in the search pattern, so I’m switching to simpler file reads for the last doc pass.”

    Action/result: Confirmed the changed files and left the pre-existing untracked run.sh untouched.

  2649. Reported: “I found one remaining stale place in the logic bytecode chapter: it mentioned GR preserving mode 4, but not the new instrumented dispatcher validation. I’m adding that caveat there, then I’ll record the documentation checkpoint in the progress log.”

    Action/result: Added a logic-bytecode note explaining that mode 4 dispatcher behavior is source-backed and instrumented-QEMU-validated, but no ordinary bytecode setter has been observed.

  2650. Reported: “That chapter now makes the distinction explicit: source-level dispatcher behavior is validated, but the script-visible path for creating mode 4 remains unobserved. I’m appending the same checkpoint to the historical log before running checks.”

    Action/result: Updated the historical progress log for the GR mode-4 documentation pass.

  2651. Reported: “The notes are caught up enough to validate. I’m running the full local unit suite with an explicit AGI_GAME_DIR, building the mdBook, compiling the touched probe, and checking the diff for whitespace damage.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 267 tests; mdbook build docs, python3 -B -m py_compile tools/gr_v3_behavior_probe.py tests/test_gr_v3_behavior_probe.py, and git diff --check all passed.

  2652. Reported: “The validation set is green so far: 267 unit tests passed, mdBook built, the touched Python compiled, and git diff --check found nothing. I’m running the project compatibility wrapper too, since it includes the opcode-evidence checks the tracker cares about.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py passed, rerunning the 267-test suite and rebuilding the book.

  2653. Reported: “The compatibility wrapper also passed; it reran the 267-test local suite and rebuilt the book successfully. I’m doing a final status/diff review now so I can tell you exactly what changed and where the evidence landed.”

    Action/result: Final diff review found a duplicated remaining-work block in PROGRESS.md, which was removed.

  2654. Reported: “The tracker duplication is fixed. The only untracked generated directories are Python __pycache__ folders from the checks, so I’m going to remove those generated caches and then rerun the lightweight sanity checks affected by the last doc edit.”

    Action/result: Removed generated tools/__pycache__ and tests/__pycache__ directories from the workspace.

  2655. Reported: “Generated caches are gone. I’m adding the final validation notes to progress_log.md; since that chapter is part of the book, I’ll rebuild mdBook one last time afterward.”

    Action/result: Added final validation and cleanup entries to the historical progress log.

  2656. Reported: “I’ll continue from the next PROGRESS.md item: the GR v3 frame-selection gate for exactly-four-loop and more-than-four-loop views. I’ll start source-first by reading the tracker, existing static comparison notes, and the probe scaffolding before deciding whether a QEMU fixture is warranted.”

    Action/result: Began the GR frame-selection gate pass from PROGRESS.md.

  2657. Reported: “The tracker points squarely at code.object.frame_timer_update: SQ2 and GR are both labeled, and the previous comparison already calls out a real branch delta. I’m narrowing the disassembly to just that routine and the adjacent group-selection tables so I can turn the vague ‘gate’ wording into exact branch semantics.”

    Action/result: Read the tracker and symbolic-label context for SQ2 0x0563 and GR 0x055c.

  2658. Reported: “The first slice landed a bit late in the file, so I’m switching to address-anchored searches instead of line guesses. The labels are in place; now I need the exact instructions around 0x0563/0x055c and the table bytes they index.”

    Action/result: Switched to address-anchored ndisasm reads and found the exact SQ2/GR frame-timer branch ranges.

  2659. Reported: “Now the branch is crisp: GR inserts a flag test before using the four-plus-groups table, and it treats exactly 4 loops differently from SQ2. I’m reading the tail of the same routine to make sure this branch only affects automatic group selection and not frame-timer advancement.”

    Action/result: Confirmed the GR delta sits before frame-timer advancement and affects automatic direction group selection only.

  2660. Reported: “The GR fixture builder already copies the selected game into build/ before patching, so it’s a good fit. I’m checking the bytecode helpers now; if they can set flags, direction, and object group cleanly, this can be an unmodified-interpreter QEMU probe rather than another instrumented one.”

    Action/result: Confirmed the v3 fixture path can use copied GR resources and ordinary bytecode.

  2661. Reported: “The needed script operations are present: set flag, set/clear object bit 0x2000, set object direction, and one-shot persistent object setup. I’m checking existing opcode helpers for the exact bytes so the GR probe stays in the same style as the SQ2 movement probes.”

    Action/result: Reused the established object setup pattern from the SQ2 direction/group-selection probes.

  2662. Reported: “This can stay uninstrumented: we can use 0x2e to allow auto-selection, 0x56 to set direction byte +0x21, and flag action 0x0c for GR flag 20. I’m scanning GR’s view resources next to pick concrete four-loop and five-plus-loop views whose groups render differently enough for capture comparisons.”

    Action/result: Planned an ordinary-bytecode QEMU probe using GR flag 0x14, object direction 6, and copied fixtures.

  2663. Reported: “One local scan tripped over the older agi_graphics import requiring an explicit game directory. That’s harmless; I’m rerunning it with AGI_GAME_DIR=games/GR and also checking whether the existing SQ2 probe code has exactly the setup pattern we need to port.”

    Action/result: Re-ran the GR resource scan with an explicit game directory and reviewed the SQ2 probe setup pattern.

  2664. Reported: “Interesting: the local GR resource set itself has no views with four or more groups, so the branch is present in the interpreter but not directly exercised by stock GR view data. That means this is exactly the case where we need a generated v3 view payload in a copied fixture, rather than modifying games/GR.”

    Action/result: Initial scan used the wrong view header byte and was later corrected; no generated v3 view payload was ultimately needed.

  2665. Reported: “The old renderer helper assumes split VIEWDIR files, so it can’t load GR directly. I’m doing the frame comparison from the decoded v3 payloads instead, using the same row decoding rules already in agi_graphics.py.”

    Action/result: Compared candidate GR view frames from decoded v3 payloads without relying on split-directory helpers.

  2666. Reported: “The corrected GR census shows plenty of four-plus-loop views; my first scan had used the wrong header byte. Static reread also corrected the wording: exactly four groups bypasses the new flag gate and still uses the four-plus direction table; only more-than-four groups require flag 20. I’m choosing two views whose group-0 and group-1 frames differ enough for clean capture comparisons.”

    Action/result: Corrected the interpretation and selected local GR view 177 for the exact-four case and view 39 for the more-than-four case.

  2667. Reported: “For exact-four behavior, view 177 has clearly different group 0 and group 1 frames. For more-than-four, view 33 is a nice contrast: group 0 is tiny and group 1 is visibly larger. I’m checking actual visible-pixel counts so the controls won’t be ambiguous.”

    Action/result: Checked visible-pixel counts; kept view 177 for exact-four and chose view 39 for a clearer more-than-four group-0/group-1 contrast.

  2668. Reported: “I have enough to implement the probe. I’m adding a frame-selection-gate mode to the GR v3 behavior tool: it will build copied GR fixtures for group-0/group-1 controls, exact-four flag-clear/flag-set cases, and more-than-four flag-clear/flag-set cases, then compare QEMU captures against the controls.”

    Action/result: Added frame-selection payload and fixture builders to tools/gr_v3_behavior_probe.py.

  2669. Reported: “The fixture builders are in place. I’m wiring that into the CLI report now, including explicit expected comparisons so the JSON tells us exactly which branch behavior was proven.”

    Action/result: Added --probe frame-selection-gate CLI handling and report comparisons.

  2670. Reported: “The CLI now knows the expected exact-four versus more-than-four outcomes. I’m adding focused unit coverage so the generated bytecode and fixture labels don’t drift.”

    Action/result: Added tests for frame-selection payloads, controls, and fixture construction.

  2671. Reported: “The focused tests now cover the new payloads and fixture set. I’m running them before trying QEMU, because any bytecode-shape mistake is much cheaper to catch here than inside DOS.”

    Action/result: Focused tests and Python compilation passed.

  2672. Reported: “Focused tests passed. I’m running the new GR frame-selection batch through QEMU now: eight copied fixtures, one bootable snapshot, and capture comparisons against group-0/group-1 controls.”

    Action/result: Started the QEMU batch that wrote build/gr-v3-behavior/frame_selection_gate_qemu_001.json.

  2673. Reported: “QEMU is still running the snapshot batch; I’ll let it finish and then inspect the JSON comparisons before changing the docs.”

    Action/result: Waited for the eight-case QEMU run.

  2674. Reported: “Still waiting on the eight-case QEMU run. This one is slower than the small motion-mode batch, but it’s doing exactly the useful thing: one original-engine pass per copied fixture, then byte-for-byte capture comparisons.”

    Action/result: Continued waiting for QEMU to finish.

  2675. Reported: “The QEMU batch completed and wrote the report. I’m reading the comparisons now; if the exact-four correction is right, those cases should match group 1 regardless of flag 20, while the more-than-four cases should depend on flag 20.”

    Action/result: Parsed frame_selection_gate_qemu_001.json; all expected comparisons passed.

  2676. Reported: “The report passed and it corrected the previous wording nicely: exact-four views auto-select through the four-plus table even when flag 20 is clear; more-than-four views require flag 20. I’m updating PROGRESS.md and the spec docs to reflect that source-first correction plus the QEMU evidence.”

    Action/result: Began documentation updates for the validated GR frame-selection gate.

  2677. Reported: “One more shell search got nicked by backticks in a Markdown pattern, but it still exposed the stale spots. I’m correcting the exact-four wording across the dashboard and subsystem docs now.”

    Action/result: Located stale wording in PROGRESS.md, version notes, symbolic labels, runtime model, logic bytecode, object pipeline, and compatibility docs.

  2678. Reported: “I’m patching the docs in the same terms as the disassembly and QEMU report: SQ2 says ‘4 or more uses the table’; GR says ‘exactly 4 still uses it, greater than 4 uses it only when flag 20 is set.’”

    Action/result: Updated PROGRESS.md to mark the frame-selection gate complete and revise highest-value remaining work.

  2679. Reported: “PROGRESS.md is updated: the frame-selection gate has moved out of remaining work, with the exact-four correction captured. I’m carrying the same correction into the implementation-facing chapters and evidence sections.”

    Action/result: Updated docs/src/versions.md and docs/src/symbolic_labels.md.

  2680. Reported: “The version matrix and label table now cite the exact QEMU report. I’m updating the object pipeline and opcode chapter next, since those are the places an implementer is most likely to read for runtime semantics.”

    Action/result: Began object-pipeline and logic-bytecode updates.

  2681. Reported: “The object-pipeline patch missed because of a small wording/line-wrap mismatch. I’m reopening that paragraph and patching around the actual text.”

    Action/result: Reopened the object-pipeline paragraph for a targeted patch.

  2682. Reported: “I’ve got the exact paragraph now; the update will sit directly after the shared SQ2 behavior and add the GR-specific branch as a version delta.”

    Action/result: Updated docs/src/graphics_object_pipeline.md.

  2683. Reported: “The object pipeline now states the GR branch precisely. I’m mirroring that in the logic bytecode notes near the 0x2d/0x2e group-selection explanation.”

    Action/result: Updated docs/src/logic_bytecode.md.

  2684. Reported: “The logic chapter has the version-specific rule and QEMU evidence. I’m adding the reusable command/result to compatibility testing so the probe can be rerun later across interpreter versions.”

    Action/result: Added the frame-selection QEMU command and result to docs/src/compatibility_testing.md.

  2685. Reported: “The runtime model still had the old ‘pending’ frame-gate wording, so I’m replacing that with the validated rule and keeping the mode-4 caveat intact.”

    Action/result: Updated docs/src/runtime_model.md.

  2686. Reported: “The runtime model now has the validated version rule. I’m appending a clean-room evidence note with the disassembly offsets, local resource choice, QEMU command, and result so the reasoning trail is complete.”

    Action/result: Added the Gold Rush v3 frame-selection gate section to docs/src/clean_room_executable_notes.md.

  2687. Reported: “I’m adding the new frame-selection evidence immediately after the mode-4 note, since both are GR v3 object-runtime deltas from the same static comparison pass.”

    Action/result: Placed the new clean-room evidence after the mode-4 probe section.

  2688. Reported: “The clean-room notes now include the static branch walk, local view-resource choices, QEMU command, and conclusion. I’m catching the historical progress log up with the updates from this pass before final validation.”

    Action/result: Appended progress-log entries for the GR frame-selection pass.

  2689. Reported: “The progress log is caught up. Before validation, I’m doing a quick stale-wording scan without shell-sensitive backticks, then I’ll run the test/book checks.”

    Action/result: Stale-wording scan found one earlier clean-room note with the old exact-four wording.

  2690. Reported: “The stale scan only found old historical log entries plus one earlier clean-room note that may need context. I’m checking that clean-room paragraph; historical progress-log wording can remain because it records what I thought at the time.”

    Action/result: Reviewed the earlier clean-room comparison note around the GR frame-timer delta.

  2691. Reported: “That earlier clean-room note still had the incorrect exact-four conclusion. I’m correcting it in place and pointing forward to the later QEMU section that proves the correction.”

    Action/result: Corrected the earlier clean-room note: exactly four groups use the table without the new flag gate; more than four groups require flag 0x14.

  2692. Reported: “The stale clean-room note is fixed. I’m running the validation set now: full unit suite, mdBook, compatibility wrapper, Python compile, and whitespace check.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 270 tests; mdbook build docs, python3 -B -m py_compile tools/gr_v3_behavior_probe.py tests/test_gr_v3_behavior_probe.py, and git diff --check passed.

  2693. Reported: “The main validation is green: 270 tests passed, mdBook built, Python compile passed, and git diff --check is clean. I’m running the compatibility wrapper as the final project-level check.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py passed, rerunning the 270-test suite and rebuilding the book.

  2694. Reported: “The compatibility wrapper passed too. I’m adding those validation results to the progress log, then I’ll rebuild the book once more because the log itself changed.”

    Action/result: Added final validation results for the GR frame-selection pass to the progress log.

  2695. Reported: “I’ll pick up from the GR v3 work and re-anchor on PROGRESS.md so the next slice follows the tracker instead of wandering. I’ll keep this source-first and only use QEMU if there’s a behavior worth confirming.”

    Action/result: Read git status, PROGRESS.md, versions.md, and remaining-work references.

  2696. Reported: “The tracker now has the GR frame-selection and mode-4 items in the validated bucket. The next useful work is to turn one of the source-backed v3 deltas into a tighter behavioral artifact; I’m going after the GR save-file extraction because it affects a real persisted file format and is higher value than text/UI-only redraw quirks.”

    Action/result: Selected GR save extraction as the next highest-value PROGRESS item.

  2697. Reported: “I’ve got the target: GR’s save code is already source-modeled, but not yet checked against bytes emitted by the original interpreter. I’m reading the existing SQ2 save harness and v3 fixture writer so I can add the smallest GR-specific extraction path without touching games/.”

    Action/result: Reviewed tools/save_roundtrip_probe.py, tools/gr_v3_behavior_probe.py, tools/qemu_fixture.py, and tools/agi_save.py.

  2698. Reported: “The GR fixture can probably reuse the same interpreter save UI action sequence as SQ2, but with v3 resource patching and a GR signature message. Before coding that, I’m checking the local binary/logic evidence for the save-name convention and the block transform so the probe asserts something meaningful, not just ‘a file appeared.’”

    Action/result: Searched local docs, strings, and GR logic opcode usage for save, restore, and verifier evidence.

  2699. Reported: “GR’s own scripts use verify_game_signature once before save/restore, so the v3 path does share that filename/signature mechanism. I’m going to inspect that local logic resource and the nearby v3 save routine one more time, then wire a probe that extracts the produced save and checks the XORed third block against the decoded live runtime block captured from the copied fixture.”

    Action/result: Disassembled GR logic 0 and reread the source-backed save notes before implementation.

  2700. Reported: “The source notes confirm the third save block is the transformed one. One nuance: the existing local save parser assumes SQ2 fixed block lengths, but the GR proof only needs generic length-prefixed parsing plus a block-3 transform check, so I can keep this narrowly scoped.”

    Action/result: Decided to use the generic five-block parser and GR-specific third-block XOR checks rather than SQ2 fixed lengths.

  2701. Reported: “The disassembler prints opcode references but not decoded message text. I’m doing a local resource parse for GR logic 0’s message table so the synthetic fixture can use the same signature prefix the original game initializes.”

    Action/result: First local parse hit the explicit AGI_GAME_DIR guard.

  2702. Reported: “That parse hit the project’s ‘explicit game directory’ guard through an import side effect. I’ll rerun it with AGI_GAME_DIR set, keeping the same local-only evidence path.”

    Action/result: Reran the message-table parse with AGI_GAME_DIR=games/GR.

  2703. Reported: “The GR logic message bytes did not decode with the SQ2 message key, which is itself useful: I won’t assume the SQ2 message text transform for v3 logic messages. For the save probe I can still use our fixture writer’s known-encoded synthetic message and verify whether GR’s action 0x8f accepts it; if not, I’ll fall back to the blank-prefix save path and still inspect the block transform.”

    Action/result: Identified GR logic message handling as a version-specific fixture concern.

  2704. Reported: “I caught the message parse mistake: the offset table is plain and only the message text bytes are XORed. Re-parsing that should tell us the local GR signature string cleanly.”

    Action/result: Corrected the local message-table parser, then found GR resource message text is already readable without applying the SQ2 XOR.

  2705. Reported: “The message bytes still look encoded, so GR likely uses either a different message key phase or a different message transform than SQ2. That matters for any v3 fixture with messages, so I’m going source-first into the GR message decode routine rather than papering over it.”

    Action/result: Continued into GR message data/source inspection; later checks showed the observed local GR messages are plain in resource bytes.

  2706. Reported: “The v2 message key location lives in AGIDATA.OVL; GR has its own AGIDATA.OVL, so I’m checking that local data segment and the GR image labels next. If the key moved, fixing the fixture encoder will also help future v3 tests that need messages.”

    Action/result: Confirmed GR AGIDATA.OVL contains Avis Durgan at offset 0x072c, while observed GR logic messages are plain.

  2707. Reported: “GR logic messages are plain in the observed resource bytes. That gives me the missing piece for a v3 save fixture: I’ll extend the local fixture builder so it can emit plain-text message tables for v3 while keeping the existing encrypted v2 default intact.”

    Action/result: Added encrypt_messages to logic_resource(...), default True.

  2708. Reported: “Before I choose the signature text, I’m checking GR’s 0x8f verifier handler in the local image for the embedded comparison string. That avoids guessing whether the prefix should be GR, GOLD, or something else.”

    Action/result: Inspected GR image bytes/disassembly around 0x108c and 0x5ede; found embedded GR\0 bytes.

  2709. Reported: “The embedded GR signature string is present locally as GR\\0; I’m correcting for the MZ header when reading the handler bytes, then I’ll use GR as the fixture’s signature message and expected filename stem GRSG.”

    Action/result: Corrected image/file-offset handling and verified the 0x8f copy/compare helper shape.

  2710. Reported: “I’m making the fixture-format change first: one optional parameter on logic_resource controls message encryption, defaulting to the existing v2 behavior. The GR-specific code will opt into plain messages explicitly.”

    Action/result: Patched tools/qemu_fixture.py.

  2711. Reported: “I’m adding two tiny unit checks around message table encoding: existing encrypted behavior stays unchanged, and v3/plain mode leaves the text bytes readable in the resource.”

    Action/result: Added message-encryption tests to tests/test_qemu_fixture.py.

  2712. Reported: “I’m adding the GR save probe as a new --probe save-xor-extract mode rather than mixing it into the older SQ2 save tool. It still reuses the generic QEMU snapshot and save extraction helpers, but the fixture construction stays v3-specific.”

    Action/result: Added initial GR save extraction payload, fixture builder, QEMU runner, and CLI branch to tools/gr_v3_behavior_probe.py.

  2713. Reported: “Now I’m extending the focused GR probe tests so the new v3 save fixture is checked without requiring private game writes or QEMU. The QEMU run will be the behavioral confirmation after the fixture bytes look right.”

    Action/result: Added GR save payload/fixture tests.

  2714. Reported: “The code/tests are patched. I’m running the focused GR and fixture tests now, then I’ll try one real QEMU extraction if the local checks pass.”

    Action/result: Focused tests found one test-structure error; py_compile passed.

  2715. Reported: “The compile passed; one test failure is just my patch landing in the wrong spot inside an existing assertion block. I’m fixing the test structure now.”

    Action/result: Inspected and repaired the misplaced frame-selection assertion.

  2716. Reported: “The final frame-selection assertion was orphaned into the new save test. I’m moving it back under the frame-selection fixture test.”

    Action/result: Moved the assertion back to the correct test.

  2717. Reported: “The unit-test structure is fixed; I’m rerunning the focused suite before starting QEMU.”

    Action/result: Focused GR/fixture tests passed 59 tests; py_compile passed.

  2718. Reported: “Focused tests pass. I’m going to run one QEMU save extraction now; this should build a disposable copied GR fixture, drive the save UI, pull GRSG.1 back out of the qcow, and compare the third block through the source-modeled XOR helper.”

    Action/result: First QEMU attempt failed because GRSG.1 was not present.

  2719. Reported: “The QEMU run completed far enough to convert the disk, but GRSG.1 was not present. I’m inspecting the disposable DOS directory now to see whether the engine wrote a blank-prefix SG.1, didn’t save, or saved under another stem.”

    Action/result: mdir found no save file in GRS0; capture had only two colors.

  2720. Reported: “There’s no save file at all, and the capture is a two-color text/error screen, so the fixture likely exits before reaching the save UI. I’m converting the capture so I can see which guard failed.”

    Action/result: Converted the PPM capture to PNG and inspected fixture logic bytes.

  2721. Reported: “The synthetic logic has the intended 8f 01 7d and a plain GR\\0 message table, so the verifier text itself looks right. I’m going to view the capture to identify the failure path before changing the probe.”

    Action/result: Viewed the capture; it showed the typed description at DOS after the game exited before saving.

  2722. Reported: “The capture shows the game exited before the save UI, and the later keystrokes landed at DOS. Since the fixture bytes look structurally valid, I’m comparing its tiny message table against an original GR table and the resolver’s expected layout; this smells like an offset/table convention mismatch, not the save action itself.”

    Action/result: Confirmed the generated message table shape and read the GR resolver/copy helper disassembly.

  2723. Reported: “Since the verifier path is still exiting, I’m checking how the original GR scripts call 0x8f: which logic, which message number, and what raw message text sits there. That will tell us whether the synthetic message table is the issue or whether this probe should use the blank-prefix save path for now.”

    Action/result: Found the original GR 0x8f use in logic 101 with message 55a.

  2724. Reported: “Original GR’s own verifier call is in logic 101 with message 55a, not GR. That means 0x8f is more of a version/build compatibility check than a save prefix initializer in this interpreter, despite the shared slot being reused by filename code. I’m going to switch the GR save extraction to omit 0x8f and intentionally extract the blank-prefix SG.1, which is enough to validate the v3 save block transform.”

    Action/result: Decided to promote a blank-prefix save extraction and leave GR’s verifier/save-prefix path for future source-first work.

  2725. Reported: “I’m adjusting the GR save probe to make the blank-prefix behavior explicit: no verifier action, no message table, expected output SG.1. The report will still state the signature-prefix check as ‘blank prefix observed,’ so the limitation is clear rather than hidden.”

    Action/result: Changed the GR save probe default to omit 0x8f and use save stem SG.

  2726. Reported: “I’m updating the tests to pin both paths: the default extraction fixture omits the verifier and writes no message table, while the optional verifier form still emits a plain v3 message if a future probe needs it.”

    Action/result: Updated GR save tests for blank-prefix default and optional plain-message verifier payload.

  2727. Reported: “The blank-prefix save fixture is now explicit. I’m rerunning the focused tests, then I’ll rerun QEMU looking for SG.1.”

    Action/result: Focused tests passed 60 tests; py_compile passed.

  2728. Reported: “Focused tests pass again. I’m rerunning the extraction with the default SG stem now.”

    Action/result: QEMU extraction passed and wrote build/gr-v3-behavior/save_xor_extract_qemu_001.json.

  2729. Reported: “The QEMU extraction passed this time. I’m inspecting the JSON and save bytes so I can document the exact block lengths and what the XOR check proved.”

    Action/result: Inspected save_xor_extract_qemu_001.json, SG_001.1, capture metadata, and the DOS directory listing.

  2730. Reported: “The extracted GR save has block lengths [1028, 989, 1811, 100, 12], and the third block round-trips under the 59-byte XOR helper. I’m checking its relationship to the local OBJECT file because the length being 1811 versus OBJECT size 1814 is a nice concrete clue for the subsystem spec.”

    Action/result: Compared encoded/decoded third-block bytes with games/GR/OBJECT; neither form directly matches the source file.

  2731. Reported: “The third block does not directly match the local OBJECT file after either form, which makes sense because the runtime object/inventory table has already been initialized and relocated before saving. I’ll document the direct evidence narrowly: original GR wrote a five-block save, block 3 length 1811, and the source-modeled XOR is a reversible transform over that emitted block.”

    Action/result: Scoped the conclusion to the emitted save envelope and XOR transform.

  2732. Reported: “I’m moving into documentation now: tracker first, then the subsystem/version chapters, then the clean-room notes and progress log with the exact QEMU command/result.”

    Action/result: Began docs/tracker update pass.

  2733. Reported: “I’m going to keep the documentation precise: ‘GR save XOR extraction is QEMU-validated using a blank-prefix SG.1 fixture,’ and separately note that the verifier/signature path was not part of this probe. That keeps the behavioral model honest rather than overclaiming.”

    Action/result: Chose wording for the blank-prefix caveat.

  2734. Reported: “The tracker text has line wraps that didn’t match my patch. I’m reading the exact snippets and applying smaller edits.”

    Action/result: Reread exact PROGRESS.md snippets around snapshot, action deltas, object runtime, and highest-value work.

  2735. Reported: “I’ve got the exact tracker text now. I’m applying the progress update in smaller patches so the line-wrapped Markdown stays clean.”

    Action/result: Updated the current snapshot in PROGRESS.md.

  2736. Reported: “The snapshot now mentions the extracted GR save. I’m updating the detailed v3 action-delta paragraph and remaining-work list next.”

    Action/result: Added the SG.1 extraction result and narrowed remaining GR save work to signature-prefixed save/restore behavior.

  2737. Reported: “The detailed action-delta status is updated with the extracted block lengths and XOR check. I’m clearing the old ‘full save extraction’ item from highest-value remaining work, replacing it with the narrower signature-prefixed save/restore question.”

    Action/result: Updated Highest-Value Remaining Work.

  2738. Reported: “Next I’m updating versions.md so the concise version ledger reflects that GR save extraction is now observed, with the blank-prefix caveat.”

    Action/result: Updated the GR room/state action row in versions.md.

  2739. Reported: “I’m adding a short paragraph below the existing GR probe descriptions with the exact save extraction command/result.”

    Action/result: Added the GR save extraction paragraph to versions.md.

  2740. Reported: “I’m updating the runtime model’s save section now: the normative rule stays source-first, and the QEMU sentence records the blank-prefix validation artifact.”

    Action/result: Updated the save/restore section in runtime_model.md.

  2741. Reported: “I’m also updating the v3 opcode-delta note so 0x7d points at the promoted QEMU extraction instead of only the helper model.”

    Action/result: Updated the GR v3 opcode-delta table in logic_bytecode.md.

  2742. Reported: “I’m revising the symbolic label entry for GR’s save action with the QEMU report path and the observed third-block length.”

    Action/result: Updated docs/src/symbolic_labels.md.

  2743. Reported: “The logic resource chapter still read as if every observed interpreter uses encrypted message text. I’m adding a version note for local GR resources and the new fixture builder option.”

    Action/result: Added the GR message plaintext/version note to logic_resources.md.

  2744. Reported: “I’m updating the compatibility chapter in two places: the local save helper section now says the GR transform has original-engine extraction evidence, and the v3 probe section gets the rerunnable command.”

    Action/result: Updated the save helper paragraph in compatibility_testing.md.

  2745. Reported: “The save helper section is current. I’m inserting the exact save-xor-extract command alongside the other GR v3 QEMU probes.”

    Action/result: Added the GR save extraction command/result to compatibility_testing.md.

  2746. Reported: “The v3 probe section has a ‘recent attempted’ block immediately after mode 4, so I’m inserting the save extraction note just before that.”

    Action/result: Placed the new compatibility note before the attempted fixture registry.

  2747. Reported: “Now I’m adding the detailed clean-room note: it includes the failed verifier attempt as a documented harness observation, then the promoted blank-prefix extraction and what it proves.”

    Action/result: Added the Gold Rush v3 Save Extraction Probe section to clean_room_executable_notes.md.

  2748. Reported: “Before validation, I’m checking whether the promoted GR save probe should be added to the compatibility suite manifest or left as a documented targeted command. If the suite already has version-specific optional layers, I’ll hook it in there.”

    Action/result: Inspected tools/compatibility_suite.py and its tests.

  2749. Reported: “The suite currently has local, SQ2 QEMU smoke, and SQ2 broad layers. I’m adding a separate opt-in qemu-v3 layer for the GR save extraction so it doesn’t surprise normal SQ2 runs or public users without private GR files.”

    Action/result: Added gr_save_xor_extract_qemu and the --include-qemu-v3 flag to tools/compatibility_suite.py.

  2750. Reported: “I found the suite tests. I’m adding the qemu-v3 layer with tests so the manifest is discoverable but still explicit.”

    Action/result: Updated tests/test_compatibility_suite.py.

  2751. Reported: “I’m adding the new --include-qemu-v3 suite invocation to the compatibility docs so future runs can reproduce the GR save check from the manifest.”

    Action/result: Updated the command set in docs/src/compatibility_testing.md.

  2752. Reported: “I’m patching the command set with the v3 opt-in examples and a note that it needs games/GR.”

    Action/result: Documented the separate private-input qemu-v3 layer.

  2753. Reported: “Since the suite manifest now has an opt-in v3 layer, I’m updating PROGRESS.md so the compatibility-suite tracker reflects it.”

    Action/result: Updated the compatibility-suite section of PROGRESS.md.

  2754. Reported: “I’m adding the qemu-v3 layer to the compatibility-suite evidence paragraph without marking it as a full-suite run yet; I’ll validate the manifest locally after docs are done.”

    Action/result: Clarified qemu-v3 status in PROGRESS.md.

  2755. Reported: “I’m adding the suite-manifest change into the clean-room note’s implementation list so the evidence trail includes the new opt-in runner path.”

    Action/result: Updated the GR save extraction clean-room note.

  2756. Reported: “Docs and code are updated. I’m running the validation set now: full unit suite, mdBook, py_compile, manifest dry-run, and whitespace check first; then I’ll run the local compatibility wrapper and the named v3 QEMU suite command.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 275 tests; mdbook build docs, py_compile, AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --dry-run --include-qemu-v3, and git diff --check passed.

  2757. Reported: “The first validation pass is green: 275 tests, mdBook, py_compile, v3 dry-run, and diff check all passed. I’m running the compatibility wrapper now, then the named qemu-v3 save extraction from the suite manifest.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_002.json passed.

  2758. Reported: “The local compatibility wrapper passed and wrote build/compatibility-suite/local_002.json. Now I’m running the single named v3 QEMU suite command to prove the manifest entry itself works.”

    Action/result: The first sandboxed wrapper attempt failed before booting QEMU because VNC socket binding was not permitted from the sandboxed child process.

  2759. Reported: “The named v3 suite command failed before booting because QEMU could not bind its VNC socket from inside the sandboxed wrapper process. The same probe worked when run directly; I’m rerunning the suite wrapper with escalated permissions so its child QEMU process has the same socket access.”

    Action/result: Escalated rerun of the named gr_save_xor_extract_qemu suite command passed and wrote build/compatibility-suite/qemu_v3_save_001.json.

  2760. Reported: “The escalated suite run passed and wrote the v3 save extraction report. I’m checking the suite report and the probe JSON, then I’ll add the validation results to the log and do the final book/diff checks.”

    Action/result: Inspected qemu_v3_save_001.json, save_xor_extract_suite.json, local_002.json, and git status.

  2761. Reported: “Validation produced only generated __pycache__ directories as untracked noise. I’m removing those generated caches, then I’ll log the validation results and rerun the final doc/diff checks because the log will change.”

    Action/result: Removed generated tools/__pycache__ and tests/__pycache__ directories.

  2762. Reported: “The cache directories are gone. Since the v3 suite command passed, I’m updating the tracker/docs from ‘layer exists’ to ‘named v3 suite run passed’ with the report path.”

    Action/result: Updated PROGRESS.md and compatibility_testing.md with build/compatibility-suite/qemu_v3_save_001.json.

  2763. Reported: “The tracker now names the passing v3 suite report. I’m updating the compatibility chapter’s command-set status similarly.”

    Action/result: Recorded the passing v3 suite report in docs/src/compatibility_testing.md.

  2764. Reported: “I’m adding the suite report path to the clean-room save extraction note too, so the direct probe and manifest-level validation are both recorded.”

    Action/result: Added the suite-level report path to docs/src/clean_room_executable_notes.md.

  2765. Reported: “I’m appending the validation results to the progress log now, then I’ll rebuild mdBook and run the final diff check.”

    Action/result: Added validation entries for the GR save extraction and v3 suite-manifest pass.

  2766. Reported: “I’ll pick back up from PROGRESS.md and the current tree, then choose the next highest-value item rather than waiting for another nudge. First I’m checking the tracker and repo state so I don’t step on anything freshly changed.”

    Action/result: Read PROGRESS.md, docs/src/versions.md, and git status. The only pre-existing untracked file was run.sh.

  2767. Reported: “PROGRESS.md says the current interesting frontier is still GR/v3: source-backed deltas exist for save/signature, restart, key-release/menu gates, and v3 resource packing. I’m going to inspect the probe/tooling around those so the next step is driven by the disassembly-backed paths rather than random behavior poking.”

    Action/result: Re-read tools/gr_v3_behavior_probe.py, tests, and relevant tracker/doc references.

  2768. Reported: “The cleanest next bite is the GR 0x8f verifier/save-prefix path: the last probe deliberately avoided it, and the failed synthetic attempt is a clue rather than a conclusion. I’m going to map that path from the GR disassembly first, then decide whether a QEMU confirmation is warranted.”

    Action/result: Located GR verifier references around image offsets 0x108c, 0x245e, 0x5035, and 0x5ec2..0x5eff.

  2769. Reported: “The prior notes already point to GR image offsets around 0x5035 and 0x5ede for the verifier. I’m re-reading those bytes and the local logic use, because the failed 0x8f(\"GR\") fixture probably means the expected signature text is subtler than the filename stem.”

    Action/result: Confirmed helper 0x5ede compares DS:0x0002 against embedded GR\0.

  2770. Reported: “The verifier bytes are direct: GR has a GR\0 string in the code segment and a routine comparing DS:0002 against it. The puzzle is likely in how the generated v3 logic message address is being resolved, so I’m checking the original GR script call and our v3 fixture layout next.”

    Action/result: Disassembled GR logic 101 and found 0x8f(#3) at bytecode offset 0x0004.

  2771. Reported: “My first disassemble_logic call was too broad and dumped the whole game, which is noisy but harmless. I’m narrowing with a small local parser so I can inspect just logic 101’s header, code prefix, and message table bytes.”

    Action/result: Re-ran the disassembler without --limit and inspected logic 101 only.

  2772. Reported: “Logic 101 confirms the original script does call 0x8f with message 3 before normal setup, so using the verifier in a synthetic fixture is legitimate in principle. I’m checking how the message lookup routine expects offsets, because a one-byte mismatch there would explain the early exit.”

    Action/result: Re-read the message resolver and bounded-copy routines.

  2773. Reported: “The quick Python snippet tripped the project’s ‘no default game’ guard, so I’ll pass AGI_GAME_DIR explicitly even for local byte inspection. That keeps the tooling behavior aligned with the repo rule.”

    Action/result: Re-ran local message parsing with AGI_GAME_DIR=games/GR.

  2774. Reported: “The verifier handler copies at most six bytes from the selected message into DS:0002, then compares that string with the embedded GR\0. That means the old ‘plain GR messages’ observation is worth re-testing against the exact message table, especially logic 101 message 3.”

    Action/result: Parsed logic 101’s message table with table-base-relative offsets and decrypted from the message text-region start.

  2775. Reported: “This turned up a useful correction: GR logic messages are encrypted with the same local message-text XOR pattern; logic 101’s message 3 decrypts to GR\0. The earlier synthetic verifier failed because the v3 fixture wrote GR in plain text, so I’m going to fix that and promote a signed GR save probe rather than leaving the verifier path unresolved.”

    Action/result: Confirmed encrypted message bytes for logic 101 message 3 are 35 35 61, decrypting to GR\0.

  2776. Reported: “I’ll keep the blank-prefix probe for the focused XOR evidence, and add a signed variant as a separate QEMU-v3 command. That gives us both: the isolated save-block transform and the real 0x8f -> GRSG.N filename/signature path.”

    Action/result: Chose to add --verify-signature rather than replacing the existing blank-prefix probe.

  2777. Reported: “I’m about to edit the probe/tooling: the verifier path will use encrypted message text, the save extractor will understand expected blank versus GR prefixes, and the suite will gain an explicit signed GR save case.”

    Action/result: Updated tools/gr_v3_behavior_probe.py with signed fixture generation, expected prefix checks, and default GRSG save stem selection when --verify-signature is used.

  2778. Reported: “The probe now has a signed mode. I’m tightening the tests around the message encoding so this correction stays pinned: GR’s verifier message should be encrypted in the resource, not stored as plain GR.”

    Action/result: Updated tests/test_gr_v3_behavior_probe.py to assert encrypted fixture bytes decrypt to GR\0.

  2779. Reported: “I’m adding the signed fixture assertion too, so the generated copy is checked for both the opcode sequence and the patched v3 resource payload.”

    Action/result: Added a test for build_gr_save_extract_fixture(..., verify_signature=True).

  2780. Reported: “Now I’m wiring the signed probe into the optional qemu-v3 layer as a separate named command, with its own fixture root and report paths.”

    Action/result: Added gr_signed_save_xor_extract_qemu to tools/compatibility_suite.py.

  2781. Reported: “I’m updating the suite manifest test so it knows about the new signed GR case and keeps qemu-v3 opt-in only.”

    Action/result: Updated tests/test_compatibility_suite.py.

  2782. Reported: “The code changes are in. I’m running the focused unit tests and a syntax check before trying QEMU, since this path touches fixture generation and suite selection.”

    Action/result: Focused unit tests for GR behavior probes, qemu fixtures, and compatibility suite passed; py_compile passed.

  2783. Reported: “Focused tests passed. Next I’m checking the manifest selection, then I’ll run the signed GR probe under QEMU to see whether the original engine writes GRSG.1 and embeds the expected prefix in block 0.”

    Action/result: compatibility_suite.py --dry-run --include-qemu-v3 showed both blank and signed GR commands; signed dry-run fixture generation wrote save_xor_extract_signed_dryrun.json.

  2784. Reported: “The dry run shows the signed fixture being generated cleanly and the suite keeping both GR cases in the opt-in layer. I’m launching the signed QEMU probe now; this may take a little while because it boots DOS, saves, snapshots the disk, and extracts the save.”

    Action/result: Direct signed QEMU probe passed and wrote build/gr-v3-behavior/save_xor_extract_signed_qemu_001.json.

  2785. Reported: “Signed QEMU passed. I’m reading the JSON report and extracted save metadata now so the docs can record exact evidence rather than just ‘it worked.’”

    Action/result: Confirmed expected file GRSG.1, first-block prefix 47 52 00, block lengths 1028, 989, 1811, 100, 12, and matching third-block XOR hashes.

  2786. Reported: “The signed save is exactly what the source predicted: GRSG.1, block 0 starts 47 52 00, and the XOR block hashes match the blank-prefix save. I’m correcting the docs now, including the earlier mistaken ‘plain v3 messages’ note.”

    Action/result: Searched the docs for stale plain-message and signature-save remaining-work references.

  2787. Reported: “I found the stale doc text: it says GR messages were plain and still lists signed saves as remaining work. I’m replacing that with the corrected source observation and the new QEMU evidence.”

    Action/result: Updated PROGRESS.md to mark signed GR save extraction as covered and narrow remaining save work to signed restore if needed.

  2788. Reported: “PROGRESS.md now treats signed GR saving as done and narrows the remaining v3 save question to restore-side confirmation. I’m carrying the same correction into the version ledger and runtime model.”

    Action/result: Updated docs/src/versions.md.

  2789. Reported: “The logic-resource chapter had the most important stale statement, so I’m replacing it with the exact GR evidence: encrypted text region, table offsets relative to the table base, and logic 101 message 3 decrypting to GR.”

    Action/result: Updated docs/src/logic_resources.md.

  2790. Reported: “Now I’m updating the runtime model so the implementation-facing save section describes both filename/signature cases and does not imply the blank-prefix probe is the whole story.”

    Action/result: Updated docs/src/runtime_model.md.

  2791. Reported: “The opcode chapter’s GR delta row now needs the signed-save report too, so 0x7d points at both original-engine confirmations.”

    Action/result: Updated docs/src/logic_bytecode.md.

  2792. Reported: “I’m updating the symbolic label map so future version comparisons can anchor the signed GR path by label instead of rediscovering this address behavior.”

    Action/result: Updated docs/src/symbolic_labels.md.

  2793. Reported: “The compatibility chapter gets two small updates: the qemu-v3 layer now has both blank and signed save commands, and the signed command gets its reproducible invocation recorded.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2794. Reported: “I’m also noting that the signed save did not change the state-block shape or XOR hashes, which is a nice small sanity check on the prefix path.”

    Action/result: Added signed-vs-blank save comparison details to the compatibility docs.

  2795. Reported: “I’m fixing the clean-room notes next. Rather than hiding the old mistaken observation, I’ll record it as corrected evidence: the raw bytes looked readable only because the wrong offset/decryption basis was used.”

    Action/result: Corrected the earlier GR save extraction note.

  2796. Reported: “This is the evidence trail bit where being explicit matters: I’m writing down the failed signed attempt, the corrected encrypted-message interpretation, and the successful signed QEMU run as a follow-up correction.”

    Action/result: Added Gold Rush v3 Signed Save Extraction Correction to docs/src/clean_room_executable_notes.md.

  2797. Reported: “Docs now include the correction and the signed run. I’m running the full local validation set next, then the signed suite command through the compatibility runner so the manifest path itself is exercised.”

    Action/result: Full unit suite passed 276 tests; mdbook build docs and py_compile passed.

  2798. Reported: “Full unit tests passed at 276 tests, and mdBook plus syntax checks are green. I’m doing the manifest dry-run and whitespace check, then I’ll run the signed QEMU command through compatibility_suite.py.”

    Action/result: compatibility_suite.py --dry-run --include-qemu-v3 and git diff --check passed.

  2799. Reported: “Dry-run and diff check passed. The full tests created only __pycache__ noise; I’ll clean that up after the remaining QEMU-suite run.”

    Action/result: The sandboxed suite wrapper attempt failed before booting QEMU because the child QEMU process could not bind its local VNC socket.

  2800. Reported: “The suite wrapper hit the same sandboxed VNC bind problem we saw before: QEMU itself never got to boot. I’m rerunning the identical named suite command with elevated permission so the child QEMU process can bind the local VNC socket.”

    Action/result: Escalated named suite command gr_signed_save_xor_extract_qemu passed and wrote build/compatibility-suite/qemu_v3_signed_save_001.json.

  2801. Reported: “The escalated suite run passed and wrote the signed suite report. I’m checking the report contents, then I’ll remove generated caches and update the log/tracker with final validation details.”

    Action/result: Inspected qemu_v3_signed_save_001.json and save_xor_extract_signed_suite.json; both record return code zero and the expected GRSG.1 checks.

  2802. Reported: “The signed suite report is clean: return code 0, GRSG.1, prefix 47 52 00, and the expected XOR checks. I’m removing the generated __pycache__ directories now so the working tree only shows source/doc changes plus the existing untracked run.sh.”

    Action/result: Removed generated tools/__pycache__ and tests/__pycache__.

  2803. Reported: “With generated caches removed, I’m updating the tracker to name the passing signed suite report and the current unit-test count.”

    Action/result: Updated PROGRESS.md with build/compatibility-suite/qemu_v3_signed_save_001.json and the 276-test local run.

  2804. Reported: “I’m adding the suite-level signed report path to the compatibility chapter too, so direct and manifest validation are both recorded.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2805. Reported: “The final book and diff checks are clean, and no cache directories remain. I’m running the local compatibility wrapper once more so the opcode-evidence freshness check is covered alongside tests and mdBook.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_signed_save_001.json passed. The report records 276 passing tests, mdbook build docs, and tools/logic_opcode_evidence.py --check.

  2806. Reported: “The local compatibility wrapper passed too, including 276 tests, mdBook, and opcode-evidence freshness. I’m cleaning the cache noise it created and recording that final validation in the log.”

    Action/result: Inspected local_signed_save_001.json; no __pycache__ directories were present after the -B run.

  2807. Reported: “I’ll pick this back up from the GR v3 restore thread: first I’m going to rescan the current tree and the relevant probe/docs so I’m not leaning on stale state, then I’ll implement the next PROGRESS.md item source-first and use QEMU only as confirmation.”

    Action/result: git status --short showed only existing untracked run.sh; PROGRESS.md still listed signed GR restore as high-value remaining v3 work.

  2808. Reported: “The tree is clean except for the existing untracked run.sh. The dashboard still has the signed GR restore behavior as the most useful source-backed v3 item, so I’m reading the probe internals around save extraction and QEMU snapshot execution before patching it.”

    Action/result: Re-read tools/gr_v3_behavior_probe.py, tools/save_roundtrip_probe.py, tools/qemu_fixture.py, tools/qemu_snapshot.py, and focused tests.

  2809. Reported: “The current GR probe already has the save-side pieces and a reusable save extractor. I’m going to add the restore round-trip as a separate v3 probe rather than changing the existing save probe, so the evidence stays split between ‘file envelope’ and ‘restore behavior.’”

    Action/result: Designed a separate signed-restore-roundtrip probe that generates GRSG.1, restores it in a second fixture, and compares against direct saved/unrestored controls.

  2810. Reported: “Before I edit the harness, I’m going back to the disassembly for the restore routine so the probe is tied to the actual v3 code path, not just the SQ2 harness pattern. The key thing I’m checking is where the first block and object/inventory block land, and whether GR transforms the latter after reading.”

    Action/result: Read existing restore/save notes and tried local disassembly around the documented GR restore/XOR offsets.

  2811. Reported: “That rizin call defaulted to the host architecture, so I’m discarding that excerpt and rerunning with explicit 16-bit x86 settings. Tiny mistake, easy correction.”

    Action/result: Discarded the incorrect host-architecture rizin output.

  2812. Reported: “The GR executable is an MZ-style image with the code image starting after the header, so the raw disassembler view is about 0x202 bytes later than the image labels used in our docs. I found the restore prologue at raw 0x2994, which matches documented image 0x2792; now I’m pulling the relevant raw-offset snippets.”

    Action/result: Re-ran rizin -q -a x86 -b 16 at raw offsets 0x2994, 0x2b44, 0x2ac8, and 0x09be, confirming GR restore reads five blocks and calls the same XOR helper over [0x07d6]..+[0x07da].

  2813. Reported: “I’m going to patch tools/gr_v3_behavior_probe.py now with a signed-restore round-trip probe: generate a real GRSG.1 through the v3 engine, boot a restore fixture that starts in a deliberately different visual state, and compare the restored capture against a direct ‘saved state’ fixture.”

    Action/result: Added bytecode helpers and signed restore save/restore/ direct payload builders to tools/gr_v3_behavior_probe.py.

  2814. Reported: “The bytecode payload side is in place now. I’m adding fixture builders next, keeping the generated save and restore copies under build/ and leaving games/GR as read-only evidence input.”

    Action/result: Added generated GR fixture builders for save production, restore from generated GRSG.1, and saved/unrestored direct controls.

  2815. Reported: “The builder now creates three fixture roles: the save producer, the restore-under-test, and two comparison captures. I’m wiring the QEMU runner so the save file produced by the original engine becomes the input to the restore fixture.”

    Action/result: Added run_gr_signed_restore_qemu(...) to chain original save extraction, comparison captures, and restore capture comparison.

  2816. Reported: “The QEMU runner is now chained: save extraction first, then restore validation, then capture comparisons. I’m adding the CLI surface and report shape so it can be run directly and later from the compatibility suite.”

    Action/result: Added --probe signed-restore-roundtrip to tools/gr_v3_behavior_probe.py.

  2817. Reported: “The CLI branch is ready. I’m adding focused unit tests now so the generated logic bytes, encrypted signature message, and copied save-file fixture behavior are pinned down before I try booting QEMU.”

    Action/result: Added focused tests for signed restore payloads and fixture construction in tests/test_gr_v3_behavior_probe.py.

  2818. Reported: “The focused tests are in. I’m running the lightweight validation now; if that’s clean, I’ll do a build-only probe report and then the QEMU confirmation.”

    Action/result: py_compile passed; running the test without AGI_GAME_DIR hit the project-wide game-directory guard.

  2819. Reported: “The pycompile passed, but the unittest import path is hitting the project’s ‘game directory required’ guard before the fixture tests run. I’m checking which import is calling the configured game directory so I can keep the tests synthetic and parameterized.”

    Action/result: Confirmed the guard is expected from shared project path helpers; reran with AGI_GAME_DIR=games/SQ2 and the 18 focused tests passed.

  2820. Reported: “With AGI_GAME_DIR set, the synthetic fixture tests pass. That’s consistent with the project-wide path guard; I’ll use the explicit environment for validation commands and keep the new probe’s own --game-dir games/GR parameter explicit.”

    Action/result: Build-only signed restore probe wrote build/gr-v3-behavior/signed_restore_roundtrip_dryrun_001.json.

  2821. Reported: “The dry run generated the fixture report cleanly. I’m going to run the full QEMU probe now; this should boot three short batches: save producer, direct comparison controls, and restore-under-test.”

    Action/result: Started direct QEMU probe signed_restore_roundtrip_qemu_001.json.

  2822. Reported: “The QEMU probe is still running; it got past fixture generation and is in the emulator-driven part. I’ll let it finish and inspect the JSON rather than guessing from the runtime length.”

    Action/result: Direct QEMU probe continued running.

  2823. Reported: “Still running. This is the cost of using the original engine as the oracle, but the probe is structured so a passing run gives us a much stronger restore claim than a parser-only check.”

    Action/result: Direct QEMU probe completed and wrote build/gr-v3-behavior/signed_restore_roundtrip_qemu_001.json.

  2824. Reported: “The QEMU run completed and wrote its report. I’m reading the checks and capture hashes now to see whether the restored screen matched the saved-state control.”

    Action/result: Report checks all passed: restored capture matched direct saved-state control and differed from the unrestored control.

  2825. Reported: “The QEMU report passed: restored capture equals the saved-state direct capture and differs from the unrestored control; the generated save still has the GR signature prefix and XOR-round-tripping third block. I’m promoting this into the optional qemu-v3 suite next.”

    Action/result: Added named compatibility-suite command gr_signed_restore_roundtrip_qemu.

  2826. Reported: “The suite manifest now has a named signed-restore command. I’m updating the manifest tests so future changes keep it in the explicit opt-in v3 layer.”

    Action/result: Updated tests/test_compatibility_suite.py for the new qemu-v3 command.

  2827. Reported: “The suite test now tracks the new command. I’m running the focused tests plus a qemu-v3 dry run; that checks command selection without spending another emulator pass yet.”

    Action/result: Focused tests passed 24 tests, and compatibility_suite.py --dry-run --include-qemu-v3 showed the new signed-restore command.

  2828. Reported: “The dry run shows the new named command in qemu-v3. Since the direct QEMU probe already passed, I’m running the suite wrapper for just that command to make sure the manifest path itself is executable too.”

    Action/result: Sandboxed suite-wrapper run failed before boot because QEMU could not bind the local VNC socket.

  2829. Reported: “The suite wrapper hit the usual sandboxed VNC bind failure before DOS boot. I’m rerunning the same named command with escalation so QEMU can bind its local VNC socket.”

    Action/result: Started escalated named suite command gr_signed_restore_roundtrip_qemu.

  2830. Reported: “The escalated suite run is in progress now. It’s repeating the same save/control/restore chain, this time through the compatibility-suite entry.”

    Action/result: Escalated suite command continued running.

  2831. Reported: “Still running under the suite wrapper. No output yet is normal for these QEMU probes; I’ll inspect the report as soon as it returns.”

    Action/result: Escalated suite command completed successfully and wrote build/gr-v3-behavior/signed_restore_roundtrip_suite.json.

  2832. Reported: “The suite command completed successfully and wrote the probe JSON. I’m checking both the suite report and the underlying probe report now, then I’ll update the docs and tracker.”

    Action/result: Inspected build/compatibility-suite/qemu_v3_signed_restore_001.json and build/gr-v3-behavior/signed_restore_roundtrip_suite.json; return code was zero and all restore checks passed.

  2833. Reported: “The docs still describe signed restore as remaining, so I’m replacing that with the source/QEMU result. I’ll keep the language careful: the model is for valid save data and the probe confirms the ordinary signed restore path, not malformed save/exploit behavior.”

    Action/result: Began updating PROGRESS.md, runtime docs, symbolic labels, compatibility notes, and clean-room notes.

  2834. Reported: “I’m editing the tracker and docs in one pass now: PROGRESS gets the dashboard update, symbolic labels gets the GR restore routine association, and the evidence chapters get the commands/results needed for clean-room provenance.”

    Action/result: Updated the GR/SQ2 tracker summary and remaining-work list in PROGRESS.md.

  2835. Reported: “I found a second dashboard paragraph and the ‘Highest-Value’ list still naming signed restore as future work. I’m updating those too so the tracker doesn’t contradict the new evidence.”

    Action/result: Updated compatibility-suite and highest-value sections in PROGRESS.md.

  2836. Reported: “The runtime model now includes the restore-side XOR and visual round-trip result. I’m adding the corresponding symbolic label entry for GR 0x7e so future version comparisons can anchor the routine by role instead of by raw address.”

    Action/result: Added GR code.save.restore_game_state association to docs/src/symbolic_labels.md.

  2837. Reported: “The compatibility chapter currently says the v3 layer only covers save extraction. I’m updating that to include the restore round-trip command and suite report.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2838. Reported: “I’m adding a dedicated clean-room note section for this pass. It records the disassembly offsets, the fixture shape, the direct QEMU command, the suite command, and the exact pass conditions from the report.”

    Action/result: Added Gold Rush v3 Signed Restore Round Trip to docs/src/clean_room_executable_notes.md.

  2839. Reported: “The clean-room evidence section is in place. I’m checking the Versions chapter too, because this GR restore behavior is a version-specific delta and should be visible in the concise ledger as well.”

    Action/result: Updated docs/src/versions.md with the GR signed restore delta and report path.

  2840. Reported: “I’m also adding the new signed-restore command to AGENTS.md’s local tool notes, so future sessions can rerun it without rediscovering the flags.”

    Action/result: Added the signed GR save/restore round-trip command to AGENTS.md.

  2841. Reported: “The reusable command is now in AGENTS.md. I’m appending the progress log entries for this whole pass, including the discarded bad rizin architecture read and the sandbox/VNC rerun, so the historical trail stays complete.”

    Action/result: Appended progress-log entries for the signed GR restore implementation, QEMU validation, suite promotion, and documentation pass.

  2842. Reported: “The log tail is from the previous signed-save pass, so I’m appending the new signed-restore entries after that rather than rewriting history.”

    Action/result: Continued the numbered progress log from entry 2955.

  2843. Reported: “Docs and tracker are updated. I’m moving into final validation: full unit discovery, mdBook, syntax checks, and then the local compatibility wrapper so opcode evidence freshness is covered too.”

    Action/result: Full unit discovery passed 279 tests; mdbook build docs and py_compile checks passed.

  2844. Reported: “Full unit discovery passed at 279 tests, mdBook built, and syntax checks are clean. I’m updating the tracker’s test count, then I’ll run the local compatibility manifest.”

    Action/result: Updated PROGRESS.md to record the 279-test local run.

  2845. Reported: “The test count in PROGRESS.md now reflects the 279-test run. I’m running the local compatibility wrapper next; this should cover unit tests, mdBook, and opcode-evidence freshness in one report without booting QEMU.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_signed_restore_001.json passed.

  2846. Reported: “The local compatibility wrapper passed and produced the expected unit/mdBook output. I’m checking the JSON report, then I’ll do whitespace checks and clean any generated cache directories.”

    Action/result: Inspected local_signed_restore_001.json; all three local commands returned zero. git diff --check passed.

  2847. Reported: “The checks are clean, and only generated __pycache__ directories plus the existing run.sh are untracked. I’m removing the cache directories so the remaining diff is source/docs only.”

    Action/result: Removed generated tests/__pycache__ and tools/__pycache__.

  2848. Reported: “The cache directories are removed. I’m doing one final status/diff summary and then I’ll add the last validation entries to the progress log.”

    Action/result: Final status showed source/doc/test changes plus the existing untracked run.sh; no cache directories remained.

  2849. Reported: “I’ll pick this back up from the current tracker rather than guessing from memory. First I’m checking the live status and PROGRESS.md, then I’ll choose the next highest-value item and keep the evidence trail updated.”

    Action/result: Read git status --short, PROGRESS.md, the progress-log tail, and the Versions chapter. The existing signed-restore pass was still uncommitted, with only pre-existing run.sh untracked.

  2850. Reported: “The live tree is already carrying the signed-restore pass, and PROGRESS.md now points to the remaining work as mostly optional GR probes plus broader renderer/UI/audio/spec polishing. I’m going to locate the explicit remaining-work sections and pick something source-led rather than launching another blind QEMU sweep.”

    Action/result: Searched remaining-work markers and GR restart/menu/key references. The restart prompt-marker truth table was already source-modeled and listed as an optional observable confirmation target.

  2851. Reported: “There are two threads worth pursuing next: optional observable probes for GR’s remaining source-backed deltas, or polishing the implementation spec. I’m going to start with the smallest source-first delta, the GR restart prompt-marker behavior, because the model already exists and a focused original-engine confirmation should either retire that optional item or reveal where the source reading needs tightening.”

    Action/result: Re-read the restart truth-table section, tools/agi_restart.py, and tests/test_restart_model.py.

  2852. Reported: “The restart truth table is already modeled from source and tested locally, but it remains marked optional for observable confirmation. I’m reading the existing GR fixture machinery and the older SQ2 restart/input probes so I can add this as a compact v3 probe instead of inventing a parallel harness.”

    Action/result: Read tools/gr_v3_behavior_probe.py, relevant logic_interpreter_probe.py cases, and fixture helper functions.

  2853. Reported: “The accepted-restart side is awkward to capture because the engine resets and can immediately re-enter the generated logic. The cancel side is much cleaner: make the marker visible or hidden, call 0x80, press Escape, and compare the final screen against direct visible/hidden controls. That still tests the GR-specific conditional branch that differs from the simple SQ2 description.”

    Action/result: Chose a four-fixture QEMU design: hidden control, visible control, hidden then Escape-canceled restart, and visible then Escape-canceled restart.

  2854. Reported: “One small harness gap surfaced: the v3 probe case type can type characters, but it doesn’t yet expose named keys like esc, while the shared QEMU snapshot runner already supports them. I’m going to wire that through, then add the restart-cancel cases and compare visible/hidden prompt-marker controls.”

    Action/result: Confirmed SnapshotFixtureCase already supports post_launch_key_names, then planned to forward that field from ProbeCase.

  2855. Reported: “For the actual pass/fail signal, I’ll avoid relying only on whole-screen equality. The shared tools can downsample QEMU captures into logical EGA nibbles, so the probe can count prompt-row foreground pixels and still include whole-capture comparisons as extra evidence.”

    Action/result: Reused downsample_qemu_picture_nibbles() and selected logical prompt rectangle (0,40)..(39,47) for foreground-pixel counts.

  2856. Reported: “I’ve got the shape now. I’m going to add a restart-prompt-marker probe with four fixtures: direct hidden, direct visible, cancel-after-hidden, and cancel-after-visible. The QEMU check will compare prompt-row foreground counts, with capture equality reported but not used as the sole oracle.”

    Action/result: Added the new v3 restart probe to tools/gr_v3_behavior_probe.py, including named-key forwarding, fixture builders, prompt-row counting, CLI handling, and JSON reporting.

  2857. Reported: “The probe code is in. I’m adding fixture-level tests next so the new bytecode stays pinned: visible uses 0x78, hidden uses 0x77, restart cases use 0x80, and the cancel cases carry the named esc input through the snapshot runner.”

    Action/result: Added focused tests for restart prompt-marker payloads and generated fixture cases in tests/test_gr_v3_behavior_probe.py.

  2858. Reported: “The local tests now cover the generated restart fixture shapes. I’m also adding this as an opt-in qemu-v3 suite command so it can be rerun by name and won’t surprise the default local suite.”

    Action/result: Added gr_restart_prompt_marker_qemu to tools/compatibility_suite.py.

  2859. Reported: “The suite manifest has the named command now. I’m updating the manifest test so future changes don’t accidentally drop the v3 restart probe from the opt-in layer.”

    Action/result: Updated tests/test_compatibility_suite.py to assert the new command is in the qemu-v3 layer.

  2860. Reported: “I’ve finished the first edit pass. Now I’m running focused syntax and unit checks before trying the QEMU case, because if the fixture bytes are wrong it’s nicer to catch that locally.”

    Action/result: py_compile passed for the edited tools/tests. Focused unit run over GR behavior, compatibility suite, and restart model tests passed 28 tests.

  2861. Reported: “The focused checks are clean: syntax passed and the three focused test modules ran 28 tests. I’m generating the dry-run fixture report next, then I’ll boot QEMU for the original-engine confirmation if the report shape looks right.”

    Action/result: Built dry-run report build/gr-v3-behavior/restart_prompt_marker_dryrun_001.json and confirmed the suite dry-run lists gr_restart_prompt_marker_qemu under qemu-v3.

  2862. Reported: “The report shape is good: four cases, the two cancel cases send esc, and the prompt row is recorded as logical Y 40..47. I’m launching the original-engine QEMU run now; if the sandbox blocks the VNC listener I’ll rerun it with the existing QEMU approval path.”

    Action/result: Started the direct QEMU run for build/gr-v3-behavior/restart_prompt_marker_qemu_001.json.

  2863. Reported: “QEMU is still running the four-case restart batch. This one boots once, saves a DOS-prompt snapshot, then restores between the hidden/visible control and Escape-cancel cases.”

    Action/result: The direct QEMU process continued and then completed successfully.

  2864. Reported: “The QEMU run completed successfully. I’m inspecting the JSON now, especially the prompt-row counts, because that’s the actual behavioral signal for the restart branch.”

    Action/result: Direct report passed. Hidden control and hidden cancel both had 0 prompt-row foreground pixels and matching captures; visible control and visible cancel both had 8 prompt-row foreground pixels and matching captures.

  2865. Reported: “The direct QEMU result is exactly the signal we wanted: hidden control and hidden cancel both have 0 prompt-row foreground pixels; visible control and visible cancel both have 8, and the full captures match their respective controls. I’m running the named compatibility-suite command once so the manifest path is verified too.”

    Action/result: Initial named suite run failed before the DOS snapshot because nested QEMU could not bind VNC from the sandbox: Failed to bind socket: Operation not permitted.

  2866. Reported: “The suite wrapper hit the expected sandbox VNC bind restriction, not a probe failure. I’m rerunning that exact named suite command with escalation so QEMU can bind its local VNC socket.”

    Action/result: Reran AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --name gr_restart_prompt_marker_qemu --report build/compatibility-suite/qemu_v3_restart_prompt_001.json with escalation.

  2867. Reported: “The escalated suite run is in progress. It’s the same four-case QEMU batch, just launched through the manifest so the reusable command path is covered.”

    Action/result: The named suite command passed and wrote build/compatibility-suite/qemu_v3_restart_prompt_001.json plus build/gr-v3-behavior/restart_prompt_marker_suite.json.

  2868. Reported: “The named suite command passed after the VNC permission rerun. I’m checking the suite report and underlying probe JSON, then I’ll update the docs/tracker to retire the optional restart confirmation item.”

    Action/result: Confirmed the suite return code was zero and the suite probe repeated the 0-vs-8 prompt-row foreground count result.

  2869. Reported: “The restart probe is now original-engine validated. I’m updating the evidence docs and tracker in the same style as the prior GR probes: source reading first, then QEMU as confirmation, with the suite report path recorded for reruns.”

    Action/result: Updated PROGRESS.md, docs/src/runtime_model.md, docs/src/versions.md, and docs/src/compatibility_testing.md.

  2870. Reported: “The rerun command is now in AGENTS.md. I’m adding a short clean-room evidence section with the exact commands, the direct disassembly-based model it confirms, and the QEMU counts/hashes.”

    Action/result: Added the restart prompt-marker QEMU command to AGENTS.md and appended a clean-room evidence section to docs/src/clean_room_executable_notes.md.

  2871. Reported: “The evidence log now has the QEMU confirmation, including the expected sandbox/VNC rerun note. I’m doing one small symbolic-label tweak so the restart routine’s GR association points to the new observable evidence too.”

    Action/result: Updated docs/src/symbolic_labels.md for GR code.restart.confirm_restart_action.

  2872. Reported: “The symbolic map now points to the restart QEMU report. I’m preserving the intermediate work log before the final validation pass, so the sequence from tracker read through QEMU confirmation is recorded rather than just the end result.”

    Action/result: Appended progress-log entries 2997 through 3019 for the GR restart prompt-marker probe pass.

  2873. Reported: “The progress log now records this pass through the docs updates. I’m moving into validation: full unit discovery, mdBook, syntax checks, the local compatibility wrapper, and whitespace checks.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 282 tests; mdbook build docs passed; focused py_compile checks passed.

  2874. Reported: “Full unit discovery passed 282 tests, mdBook built, and syntax checks are clean. I’m updating the tracker’s test count, then I’ll run the local compatibility wrapper and final whitespace/status checks.”

    Action/result: Updated PROGRESS.md to record the 282-test local run.

  2875. Reported: “The tracker now reflects the 282-test run. I’m running the local compatibility manifest next; this covers unit tests, mdBook, and opcode-evidence freshness without launching QEMU again.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_restart_prompt_001.json passed.

  2876. Reported: “The local compatibility wrapper passed too, again with 282 tests and a clean mdBook build. I’m checking its JSON, then I’ll run git diff --check and clean any generated cache directories left behind.”

    Action/result: Inspected build/compatibility-suite/local_restart_prompt_001.json; unit tests, mdBook, and opcode evidence all returned zero. git diff --check passed. tests/__pycache__ and tools/__pycache__ were present.

  2877. Reported: “git diff --check is clean, and the local compatibility report has all three return codes at zero. The only generated clutter is tests/__pycache__ and tools/__pycache__, so I’m removing those before the final status.”

    Action/result: Removed generated Python cache directories.

  2878. Reported: “The cache directories are gone. I’m doing one final status/stat pass, then I’ll add the final validation entries to the progress log.”

    Action/result: Final status showed the intended source/docs/test changes plus the pre-existing untracked run.sh; no __pycache__ directories remained. git diff --check still passed.

  2879. Reported: “The final log entries are in. Since that changed the mdBook source after the earlier build, I’m doing a quick final mdBook build and whitespace check so the last edit is covered too.”

    Action/result: mdbook build docs passed, git diff --check passed, and final status still showed only the intended modified files plus the pre-existing untracked run.sh.

  2880. Reported: “I’ll pick up where the menu-gate probe left off: first I’ll update the docs and progress tracker with the source-backed/QEMU-confirmed result, then I’ll run the local checks so this lands as a coherent evidence step.”

    Action/result: Resumed from a clean committed baseline except for the uncommitted menu-gate probe implementation, generated Python caches, and the pre-existing untracked run.sh.

  2881. Reported: “The code/test side is already in place and the successful QEMU evidence exists; the remaining work is bookkeeping and making the docs describe the actual oracle cleanly, including the false start where the logic never yielded back to the main cycle.”

    Action/result: Read the current tracker, versions chapter, runtime model, opcode chapter, compatibility chapter, AGENTS instructions, symbolic labels, and the tail of the clean-room evidence notes.

  2882. Reported: “I’m going to make a compact docs patch now: tracker status, version/runtime bytecode notes, compatibility commands, symbolic labels, AGENTS rerun instructions, and the chronological evidence/progress logs.”

    Action/result: Began the documentation pass for the GR v3 menu interaction gate probe.

  2883. Reported: “The tracker currently still treats the menu gate as a remaining item even though the new probe confirmed it. I’m tightening that up so the dashboard points next at raw key-release behavior rather than sending future-us back over solved ground.”

    Action/result: Updated PROGRESS.md current snapshot and GR/SQ2 comparison sections to mark the menu gate QEMU-confirmed and leave raw key-release as the remaining source-backed gate behavior.

  2884. Reported: “That removes the stale remaining-work pointer. I’m folding the same result into the menu subsystem summary and compatibility-suite paragraph so the status reads consistently from both angles.”

    Action/result: Updated PROGRESS.md menu evidence, compatibility-suite evidence, and Highest-Value Remaining Work.

  2885. Reported: “Next I’m updating the version ledger and opcode chapter. These are the places someone comparing v2/v3 will probably land first, so the wording needs to distinguish ‘source says this gate exists’ from ‘we confirmed the observable gate effect.’”

    Action/result: Updated docs/src/versions.md and docs/src/logic_bytecode.md with the menu_gate_suite evidence and the zero/nonzero gate behavior.

  2886. Reported: “The runtime model is getting a small implementation-facing note too: for v2, 0xa1 plus flag 14 is enough to request the menu; for GR v3, the request is additionally filtered by the [0x0403] gate before drawing/waiting.”

    Action/result: First runtime-model patch missed the exact table anchor; reread the nearby lines and inserted the GR v3 gate note before the menu interaction lifecycle table.

  2887. Reported: “Compatibility docs already know about the v3 suite layer, but not the promoted menu-gate named command. I’m adding both the short result paragraph and the exact rerun command.”

    Action/result: Updated docs/src/compatibility_testing.md with the v3 menu-gate suite report, direct behavior paragraph, and rerun command.

  2888. Reported: “I’m adding the reusable command to AGENTS as well, since that file is the quick-start memory for future sessions and needs to expose promoted probes without hunting through the mdBook.”

    Action/result: Added the Gold Rush v3 menu interaction gate command and expected comparisons to AGENTS.md.

  2889. Reported: “Now I’m appending the clean-room evidence section. I’m including the useful failure, because it explains a subtle interpreter scheduling point: a generated logic script that self-loops never returns to the main cycle, so the menu request flag is never serviced.”

    Action/result: Appended the clean-room evidence section covering source reads, generated fixture design, the self-loop correction, successful QEMU direct report, and suite report.

  2890. Recorded retrospectively from the current menu-gate implementation pass: Began from PROGRESS.md highest-value remaining work and selected the source-backed GR v3 menu interaction gate 0xb1 as the next target.

    Action/result: Chose a probe that could be driven from ordinary generated logic in a copied GR fixture, using QEMU only as confirmation.

  2891. Recorded retrospectively from the current menu-gate implementation pass: Reused the existing SQ2 menu probes as the behavioral template for one-heading/one-item menu setup, finalization, item enable state, and status-byte selection.

    Action/result: Identified the pieces needed for a GR fixture: 0x9c/0x9d/0x9e menu construction, flag 14, 0xa1 menu request, and GR-only 0xb1.

  2892. Recorded retrospectively from the current menu-gate implementation pass: Re-read the GR disassembly around action 0xb1, action 0xa1, code.menu.interact, and the main-cycle request check.

    Action/result: Confirmed that 0xb1 writes word [0x0403], 0xa1 writes request word [0x1b67], the main cycle calls 0x9724, and 0x9724 returns immediately while [0x0403] == 0.

  2893. Recorded retrospectively from the current menu-gate implementation pass: Added menu-gate constants and payload builders to tools/gr_v3_behavior_probe.py.

    Action/result: Implemented generated marker-draw helpers, direct control payloads, menu-gate request payloads, fixture builders, QEMU comparison logic, and the --probe menu-gate CLI branch.

  2894. Recorded retrospectively from the current menu-gate implementation pass: Added local test coverage for the new fixture builder and suite command.

    Action/result: Updated tests/test_gr_v3_behavior_probe.py, tools/compatibility_suite.py, and tests/test_compatibility_suite.py; focused syntax and unit checks passed.

  2895. Recorded retrospectively from the current menu-gate implementation pass: Ran the dry-run menu-gate fixture build and v3 compatibility-suite dry-run.

    Action/result: Confirmed the fixture cases and the named gr_menu_gate_qemu suite command were wired into the manifest.

  2896. Recorded retrospectively from the current menu-gate implementation pass: Ran the first Enter-driven QEMU oracle.

    Action/result: The enabled and disabled cases both matched the blocked marker control, so the initial visual oracle failed to prove the gate.

  2897. Recorded retrospectively from the current menu-gate implementation pass: Rechecked the disassembly and generated logic bytes after the first QEMU failure.

    Action/result: The source model and 0xb1 byte encoding were still correct; the failure pointed to fixture scheduling rather than a decoded handler mistake.

  2898. Recorded retrospectively from the current menu-gate implementation pass: Ran a longer-wait QEMU diagnostic and inspected why the request was never serviced.

    Action/result: Found that ending the generated logic with self_loop() kept logic 0 inside the interpreter, preventing the main cycle from reaching the [0x1b67] request check.

  2899. Recorded retrospectively from the current menu-gate implementation pass: Replaced the generated self-loop with the structural end action and reran QEMU.

    Action/result: The fixture now yielded back to the main cycle, but the Enter-driven accepted-marker oracle was still not reliable enough to promote.

  2900. Recorded retrospectively from the current menu-gate implementation pass: Refactored the probe into a no-key modal-gate oracle.

    Action/result: The final comparisons became: disabled request must match the blocked control, enabled request must differ from the blocked control, and enabled request must differ from the disabled request.

  2901. Recorded retrospectively from the current menu-gate implementation pass: Ran the direct QEMU confirmation build/gr-v3-behavior/menu_gate_qemu_003.json.

    Action/result: The report passed. Blocked control and disabled request shared hash 160a4ed1bab5ec6eb901ae2c5e3198a081000c0261cf6ad89eec4033e88861b4; enabled request had hash e463cb17d86267bda970277df82d51c6b51dc743327f51c856a25de65399155b.

  2902. Recorded retrospectively from the current menu-gate implementation pass: Ran the named compatibility-suite command gr_menu_gate_qemu.

    Action/result: The first unprivileged run failed before launch with VNC socket permission, then the escalated rerun passed in build/compatibility-suite/qemu_v3_menu_gate_001.json.

  2903. Reported: “The documentation is now aligned with the promoted result. I’m going to run the focused checks first, then the full local suite and mdBook build; after that I’ll update any test-count line that needs changing.”

    Action/result: Focused py_compile checks passed, and AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests.test_gr_v3_behavior_probe tests.test_compatibility_suite passed 30 tests.

  2904. Reported: “Focused syntax and unit checks are clean. I’m running the full local suite and mdBook now; this will also tell me whether the tracker’s ‘282 tests’ line needs to become ‘285 tests’ after the added menu-gate cases.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 285 tests, and mdbook build docs passed.

  2905. Reported: “Full unit discovery passed 285 tests and mdBook built. I’m updating the tracker count, then I’ll run the local compatibility wrapper and final whitespace/status checks.”

    Action/result: Updated PROGRESS.md from 282 to 285 tests.

  2906. Reported: “The count is current. I’m running the local compatibility wrapper now; it’s the project’s normal ‘unit tests + mdBook + opcode evidence’ belt-and-suspenders check without launching QEMU.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_menu_gate_001.json passed.

  2907. Reported: “The local compatibility wrapper passed with 285 tests and a clean mdBook build. I’m checking the report, whitespace, and generated cache clutter now.”

    Action/result: The compatibility report showed zero return codes for local unit tests, mdBook, and opcode-evidence freshness. git diff --check passed. tests/__pycache__ and tools/__pycache__ were the only generated cache directories.

  2908. Reported: “Whitespace is clean and the compatibility report has all zero return codes. The only generated clutter is Python cache directories, so I’m removing those before the final status.”

    Action/result: Removed tests/__pycache__ and tools/__pycache__.

  2909. Reported: “One stale sentence jumped out in PROGRESS.md: that GR/SQ2 section still says QEMU confirmation is deferred, which is no longer true for the promoted v3 probes. I’m correcting that and doing one tiny final check.”

    Action/result: Updated the GR/SQ2 tracker preface to say QEMU confirmation is added after source mapping justifies a targeted probe.

  2910. Reported: “I’ll continue from the updated tracker and leave the uncommitted menu-gate work intact. The next obvious source-backed gap is the GR v3 raw key-release gate, so I’ll start by rereading the disassembly and existing input/event probes before deciding whether it deserves a QEMU fixture.”

    Action/result: Read current status, PROGRESS.md highest-value work, key-release references, and existing input/key probe helpers.

  2911. Reported: “The existing docs already describe the byte gate, but they still avoid the exact release-event observable behavior because timing is touchy. I’m going source-first here: the question is whether disassembly gives enough detail to model the event shape without needing a brittle keyboard fixture.”

    Action/result: Re-read SQ2 and GR keyboard IRQ disassembly windows plus current opcode/runtime/compatibility notes for the release-gate path.

  2912. Reported: “The GR and SQ2 IRQ paths are nearly identical after relocation: both filter scan codes 0x47..0x51, require an enable byte, set a per-scan pressed latch on keydown, and enqueue (type=2, value=0) on release only when the gate is nonzero. The real v3 difference is the gate writer: SQ2 increments [0x1530]; GR sets/clears [0x0405] with 0xad/0xb5.”

    Action/result: Identified the portable tracked-key latch state machine and the version-specific gate-writer differences.

  2913. Reported: “I’m going to turn this source-only IRQ path into a small local model with tests rather than a QEMU screenshot probe. That captures the exact latch/gate semantics, including SQ2’s byte-increment wraparound, without pretending QEMU key-release timing is a stable compatibility oracle.”

    Action/result: Added tools/agi_input.py with KeyReleaseIrqState, SQ2/GR gate helpers, and process_tracked_key_irq_scan(); added tests/test_input_model.py.

  2914. Reported: “The model is in place. I’m running it now because there’s a small but important edge in there: SQ2’s gate is an 8-bit increment, so repeated 0xad can wrap back to zero, while GR’s v3 gate is explicitly set/clear.”

    Action/result: Focused py_compile and tests.test_input_model passed.

  2915. Reported: “The new model tests pass. I’m updating the evidence strings and docs next so 0xad/0xb5 read as a modeled IRQ latch contract, not just a loose ‘key release gate’ note.”

    Action/result: Read current opcode evidence, bytecode, runtime, versions, and tracker text before patching.

  2916. Reported: “I’ve got enough to promote this as source-modeled behavior. I’m updating the spec/tracker to remove raw key-release from the ‘highest-value remaining’ bucket, while keeping the caveat that a direct QEMU release fixture is still optional and not the source of truth.”

    Action/result: Updated tools/logic_opcode_evidence.py, docs/src/logic_bytecode.md, docs/src/runtime_model.md, docs/src/versions.md, and PROGRESS.md.

  2917. Reported: “The progress tracker now treats the release-gate work as source-modeled rather than a pending QEMU target. I’m updating labels and compatibility notes so future readers can jump straight to the helper and tests.”

    Action/result: First symbolic-label patch missed current wording; reread exact rows, then updated docs/src/symbolic_labels.md and docs/src/compatibility_testing.md.

  2918. Reported: “I’m appending a clean-room evidence note for this pass now. It’s short but important: the useful new fact is not a screenshot, it’s a portable state-machine contract extracted from the IRQ code.”

    Action/result: Appended the tracked key-release IRQ source-model evidence section to docs/src/clean_room_executable_notes.md.

  2919. Reported: “Docs and labels now point to the model. I’m regenerating the opcode evidence chapter so the generated table stays consistent with the updated 0xad evidence text.”

    Action/result: First generator run refused to assume a game directory.

  2920. Reported: “The generator correctly refused to assume a default game directory. I’m rerunning it with the explicit local SQ2 evidence input.”

    Action/result: Regenerated docs/src/logic_opcode_evidence.md with AGI_GAME_DIR=games/SQ2 python3 -B tools/logic_opcode_evidence.py.

  2921. Reported: “Opcode evidence regenerated cleanly with AGI_GAME_DIR=games/SQ2. I’m doing the focused checks and then I’ll update the final tracker count if the new six tests move the suite total as expected.”

    Action/result: Focused py_compile passed; the first doc-coverage test command failed because it lacked AGI_GAME_DIR.

  2922. Reported: “One focused test command failed for the same explicit-input reason: the doc coverage test invokes the opcode evidence checker. I’m rerunning that with AGI_GAME_DIR=games/SQ2.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests.test_input_model tests.test_logic_doc_coverage passed 11 tests.

  2923. Reported: “Focused source-model and doc-coverage tests are clean. I’m adding the input-model test to the subsystem tracker now; the final suite run will set the exact total count.”

    Action/result: Updated the text/input subsystem tracker in PROGRESS.md.

  2924. Reported: “The log is current through the source-model pass. I’m moving into the full validation cycle now: unit discovery, mdBook, opcode evidence check, and whitespace/status cleanup.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 291 tests; mdbook build docs passed; AGI_GAME_DIR=games/SQ2 python3 -B tools/logic_opcode_evidence.py --check passed.

  2925. Reported: “Full unit discovery passed 291 tests, mdBook built, and opcode evidence is fresh. I’m updating the tracker count, then I’ll run the local compatibility wrapper once more.”

    Action/result: Updated PROGRESS.md from 285 to 291 tests.

  2926. Reported: “The tracker count is current. The compatibility wrapper is next; that redoes unit tests, mdBook, and opcode-evidence freshness from the suite manifest.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_input_model_001.json passed.

  2927. Reported: “The local compatibility wrapper passed with 291 tests. I’m checking its JSON result, whitespace, status, and generated cache directories before the final note.”

    Action/result: The compatibility report showed zero return codes for local unit tests, mdBook, and opcode-evidence freshness. git diff --check passed. tests/__pycache__ and tools/__pycache__ were the only generated cache directories.

  2928. Reported: “Validation is clean; only Python cache directories were generated. I’m removing those, then I’ll do one last mdBook/whitespace/status pass after adding the final log entries.”

    Action/result: Removed tests/__pycache__ and tools/__pycache__.

  2929. Reported: “I’m picking back up from the v3 fixture-packing work: the code path is already sketched in, so I’m going to finish the documentation/tracker trail, then run the broader checks so the new GR-style fixture support is grounded rather than just “looks plausible.””

    Action/result: Rechecked working-tree state and the current PROGRESS.md remaining-work section.

  2930. Reported: “The tree has both the earlier interpreter/input-model changes and the newer v3 fixture changes. I’m leaving the unrelated run.sh alone and treating the current pass as additive: make the v3 fixture capability explicit in the docs, then verify it doesn’t disturb the broader suite.”

    Action/result: Located stale documentation and tracker references that still described v3 fixtures as logic-only.

  2931. Reported: “I found the stale spots: they still say v3 fixtures can only patch direct logic records. I’m going to replace that with the narrower, source-backed statement we can actually defend now: direct v3 logic/view records plus v3 picture-nibble picture records in copied GR-style fixtures.”

    Action/result: Read the resource, version, and current progress-log sections that needed updates.

  2932. Reported: “I’m checking the exact helper shape before writing the evidence note. One thing that matters for the spec is that this still does not invent GR’s dictionary compressor; it deliberately uses the interpreter’s already-observed direct-record path for logic/view and the observed picture-nibble path for pictures.”

    Action/result: Confirmed the new helper/API shape in tools/qemu_fixture.py and tools/agi_resources.py.

  2933. Reported: “I’m making the doc edits now. I’ll keep them factual and scoped: this is a fixture-writing capability, not a claim that we have implemented every v3 compression path or QEMU-validated a new graphics behavior yet.”

    Action/result: Updated PROGRESS.md so v3 picture/view fixture packing is no longer listed as missing work.

  2934. Reported: “The high-level tracker now treats v3 picture/view fixture packing as available tooling, with the remaining work reframed around using it for source-backed probes rather than building it from scratch.”

    Action/result: Updated AGENTS.md with the v3-synthetic-picture and v3-synthetic-picture-view commands and the direct-record caveat.

  2935. Reported: “I’ve also updated the agent instructions so future runs don’t rediscover the old limitation. Next I’m bringing the mdBook resource and version chapters into sync with the new fixture commands.”

    Action/result: Updated docs/src/resource_files.md with picture-nibble encoding and v3 copied-fixture patching evidence.

  2936. Reported: “The resource chapter now records the encoder and fixture-writer boundary. I’m updating the Versions chapter next, because that’s the most likely place future “compare another interpreter” work will look first.”

    Action/result: Updated docs/src/versions.md with generated v3 picture/view fixture commands and compatibility notes.

  2937. Reported: “The Versions chapter now has the new commands and the important caveat: direct records for controlled generated data, dictionary decoding for original resources. I’m adding the clean-room evidence note and progress-log entries before the validation pass.”

    Action/result: Added the v3 generated picture/view fixture-packing section to docs/src/clean_room_executable_notes.md.

  2938. Reported: “The clean-room notes now have the evidence chain for this pass. I’m adding the step-by-step progress log entries, then I’ll run the full checks.”

    Action/result: Added this progress-log block through the documentation update phase.

  2939. Reported: “The docs are now caught up with the implementation. I’m starting validation from the narrow end first, then I’ll widen to full unit discovery, mdBook, opcode-evidence freshness, and the compatibility wrapper.”

    Action/result: python3 -B -m py_compile tools/agi_resources.py tools/qemu_fixture.py tests/test_agi_resources.py tests/test_qemu_fixture.py passed, and AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests.test_agi_resources tests.test_qemu_fixture passed 59 tests.

  2940. Reported: “Focused validation is clean: the new resource and fixture tests pass. I’m running the whole local suite now so we catch any interaction with the existing opcode/resource tooling.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 298 tests.

  2941. Reported: “Full unit discovery passed 298 tests, which matches the expected bump from the new fixture/resource tests. I’m updating the tracker count, then I’ll build the book and run the generated evidence checks.”

    Action/result: Updated PROGRESS.md from 291 to 298 tests.

  2942. Reported: “There’s one current tracker count to bump from 291 to 298; the older progress-log mentions are historical and I’m leaving those as-is.”

    Action/result: Confirmed only the current tracker count was changed.

  2943. Reported: “The tracker count is current. I’m running mdBook and the opcode evidence freshness check in parallel, then the compatibility wrapper will re-run the core local checks as a single manifest.”

    Action/result: mdbook build docs passed and AGI_GAME_DIR=games/SQ2 python3 -B tools/logic_opcode_evidence.py --check passed.

  2944. Reported: “mdBook and the opcode evidence check passed. I’m running the local compatibility wrapper now; that gives us one report file tying the unit/book/evidence checks together.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_v3_fixture_packing_001.json passed with zero return codes for local unit tests, mdBook, and opcode-evidence freshness.

  2945. Reported: “The compatibility wrapper passed with 298 tests and rebuilt the book. I’m checking the report JSON and whitespace/status now, then I’ll clean any generated Python caches.”

    Action/result: The compatibility report showed zero return codes, git diff --check passed, and tests/__pycache__ plus tools/__pycache__ were the only generated cache directories.

  2946. Reported: “The report is clean and git diff --check passed. The only generated clutter is Python cache directories, so I’m removing those before the final status pass.”

    Action/result: Removed tests/__pycache__ and tools/__pycache__.

  2947. Reported: “Caches are gone. I’m adding the validation results to the progress log now, then I’ll do one last mdBook/whitespace/status sweep because the log itself changed after the previous checks.”

    Action/result: Added this validation progress-log block.

  2948. Reported: “The validation log is recorded. I’m doing the last sweep now: rebuild the book after the log edit, check whitespace, confirm caches stayed gone, and summarize the remaining worktree cleanly.”

    Action/result: mdbook build docs passed, git diff --check passed, no __pycache__ directories remained under tests/ or tools/, and git status --short showed the expected modified/untracked files.

  2949. Reported: “Final sweep is clean: mdBook builds, whitespace check passes, and cache dirs are gone. I’m reviewing the diff shape now so the handoff is accurate and doesn’t blur this v3 fixture work with the earlier uncommitted interpreter/input-model changes.”

    Action/result: Reviewed git diff --stat and the focused v3 resource, fixture, test, and documentation diffs.

  2950. Reported: “The diff review confirms the newest slice is the v3 fixture packing plus docs; the larger tree also contains the earlier uncommitted menu-gate and input-model work from this batch. I’m logging these last two status updates, then I’ll rerun the tiny final checks one more time.”

    Action/result: Added this final progress-log entry before the last mdBook/whitespace/status check.

  2951. Reported: “I’ll continue from the freshly finished v3 fixture packing. I’m going to re-read the current tracker and then pick the next highest-value item, keeping the existing uncommitted work intact and logging the new steps as I go.”

    Action/result: Re-read git status --short and the current PROGRESS.md tracker sections.

  2952. Reported: “The tracker points to one useful bridge before more renderer work: the v3 writer is locally tested, but not yet proven against the original GR engine. I’m going to inspect the existing GR probe/QEMU helpers and, if it fits cleanly, add a small QEMU smoke that draws a synthetic v3 picture/view fixture produced by the new writer.”

    Action/result: Read the GR behavior probe, existing tests, and graphics helpers.

  2953. Reported: “The existing GR probe is a good fit: it already builds copied fixtures, runs QEMU cases, hashes captures, and compares controls. I’m reading the runner/argument layer now so the new smoke can be plugged in as one more probe instead of becoming a one-off script.”

    Action/result: Read the QEMU case runner, GR probe CLI, compatibility manifest, and transient view/action references.

  2954. Reported: “I have the runner shape now. The new probe can be deliberately modest: build one all-synthetic v3 picture/view fixture, run it under the original GR interpreter, and assert the capture is nonblank plus distinct from an end-only blank control.”

    Action/result: Inspected picture_view_logic_payload, existing transient-object tests, and the new v3 synthetic fixture tests.

  2955. Reported: “This will also exercise the freshly added v3 picture-nibble encoder under the real interpreter, which is exactly the confidence gap left by the last pass. Before editing, I’m checking the low-level picture/view payload builders so the synthetic resources stay tiny and valid.”

    Action/result: Confirmed the probe should use a tiny picture fill and a one-loop one-frame direct view payload.

  2956. Reported: “The probe will use three captures: blank control, synthetic picture-only, synthetic picture+view. That gives a compact oracle: the v3 picture-nibble record must draw something, and the direct v3 view record must visibly change the picture capture.”

    Action/result: Reviewed compatibility-suite tests and manifest placement before editing.

  2957. Reported: “I’m editing the GR probe now. The important design choice is to keep this as a compatibility check for the fixture format, not as new picture/view semantic evidence: the source-backed semantics are already the v3 reader paths; QEMU will just prove the original engine accepts the generated records and renders them.”

    Action/result: Added generated picture/view constants to tools/gr_v3_behavior_probe.py.

  2958. Reported: “The synthetic payloads are intentionally tiny: picture fill through the v3 nibble path, and a 4x4 opaque view frame stored as a direct v3 view record. Next I’m adding fixture construction and capture comparison helpers.”

    Action/result: Added build_gr_synthetic_picture_view_fixtures().

  2959. Reported: “Fixture construction is in place. I’m adding the QEMU result reducer now, so the report says exactly what changed instead of just “the command exited.””

    Action/result: Added pixel-difference and unique-color report helpers plus run_gr_synthetic_picture_view_qemu().

  2960. Reported: “The reducer compares pixels between blank, picture-only, and picture+view captures. I’m wiring the new probe into the CLI and then I’ll add unit coverage around the generated records.”

    Action/result: Added CLI probe --probe synthetic-picture-view.

  2961. Reported: “The CLI now has --probe synthetic-picture-view. I’m updating the local tests so fixture packing, directory patching, and the new compatibility manifest entry are pinned before any QEMU run.”

    Action/result: Added local GR fixture read-back test coverage.

  2962. Reported: “The GR unit test now reads the generated v3 records back through the parser, which is a nice little loop: writer output must be accepted by the same resource reader model. I’m adding the new QEMU probe to the opt-in compatibility manifest next.”

    Action/result: Added compatibility-suite command gr_synthetic_picture_view_qemu.

  2963. Reported: “The manifest entry is in the v3 opt-in layer, so it won’t slow the default local suite but can be run by name or with --include-qemu-v3. I’m pinning that in the manifest tests.”

    Action/result: Updated tests/test_compatibility_suite.py to include the new qemu-v3 command.

  2964. Reported: “The code and tests are patched. I’m running focused validation now before touching docs, so any syntax or fixture-model mistake gets caught while the change is still small.”

    Action/result: Focused py_compile passed and AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests.test_gr_v3_behavior_probe tests.test_compatibility_suite passed 31 tests.

  2965. Reported: “Focused local tests pass. I’m going to run the new probe without QEMU first against games/GR; that will build the copied fixtures and produce a report without launching the emulator.”

    Action/result: Fixture-only report build/gr-v3-behavior/synthetic_picture_view_001.json was generated.

  2966. Reported: “The fixture-only run succeeded, so the actual local GR directory layout accepts the generated entries. I’m checking the report and then I’ll run the QEMU confirmation by compatibility-suite name.”

    Action/result: Inspected the fixture-only report and generated fixture file list.

  2967. Reported: “The first QEMU attempt failed before the guest launched because sandboxed QEMU couldn’t bind the local VNC socket. That’s the same permission failure we’ve seen before, so I’m rerunning the exact named compatibility command with escalation.”

    Action/result: Reran AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --name gr_synthetic_picture_view_qemu --report build/compatibility-suite/qemu_v3_synthetic_picture_view_001.json with elevated execution.

  2968. Reported: “QEMU is running now under the compatibility wrapper. I’m waiting for the snapshot cases to finish and will inspect the JSON/captures when it returns.”

    Action/result: The QEMU compatibility command completed successfully.

  2969. Reported: “The QEMU run completed. I’m checking the probe report now to make sure both expected differences are present and to capture the exact evidence values for the docs.”

    Action/result: Confirmed build/gr-v3-behavior/synthetic_picture_view_suite.json passed: picture-only differed from blank by 215,040 pixels, picture-plus-view differed from picture-only by 128 pixels, and unique color counts were 1, 2, and 3.

  2970. Reported: “The QEMU probe passed. The useful numbers: picture-only differs from blank by 215,040 pixels, picture+view differs from picture-only by 128 pixels, and color counts go 1 → 2 → 3. I’m updating the docs/tracker with that evidence now.”

    Action/result: Located the relevant AGENTS, tracker, resource, version, compatibility, and clean-room evidence sections.

  2971. Reported: “I’ve got the relevant documentation locations. I’m adding the new probe command and its result to the operational docs, then I’ll update the high-level tracker and evidence log.”

    Action/result: Added the reusable synthetic picture/view QEMU command to AGENTS.md.

  2972. Reported: “The reusable command is now in AGENTS.md. I’m updating the tracker to show that v3 generated picture/view fixtures are no longer just locally readable; they’ve been exercised by the original GR engine.”

    Action/result: First PROGRESS.md patch missed due paragraph wrapping.

  2973. Reported: “One tracker patch missed because that paragraph has shifted wrapping. I’m reading the exact current lines and applying it in smaller chunks.”

    Action/result: Re-read the current PROGRESS.md paragraphs.

  2974. Reported: “I found the exact current paragraphs. Applying the tracker updates as focused replacements now.”

    Action/result: Updated PROGRESS.md with the QEMU-validated generated v3 fixture path.

  2975. Reported: “The tracker now records the QEMU result but I’ll leave the final unit-test count alone until the full suite rerun confirms it. Next I’m updating the resource/version/compatibility chapters with the exact probe outcome.”

    Action/result: Updated docs/src/resource_files.md with the QEMU result and pixel counts.

  2976. Reported: “The resource chapter now has the direct QEMU evidence numbers. I’m updating the version ledger so future interpreter comparisons know this is validated tooling, not merely a parser round trip.”

    Action/result: Updated docs/src/versions.md with the promoted synthetic picture/view QEMU probe.

  2977. Reported: “The version ledger is updated. I’m adding a short compatibility-testing section beside the other GR v3 probes, including the command and the promoted pass criteria.”

    Action/result: Updated docs/src/compatibility_testing.md.

  2978. Reported: “The compatibility chapter now explains what this probe proves and what it doesn’t. I’m appending the clean-room evidence note with the source/model, commands, and QEMU result.”

    Action/result: Added the v3 synthetic picture/view fixture QEMU probe section to docs/src/clean_room_executable_notes.md.

  2979. Reported: “The clean-room note is in place. I’m logging the work-in-progress updates now, then I’ll run the full validation cycle and update the test count if the suite total changes.”

    Action/result: Added this progress-log block through the documentation update phase.

  2980. Reported: “The progress log is current through the docs pass. I’m running full validation now: unit discovery, mdBook, opcode-evidence freshness, and the local compatibility wrapper.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 299 tests; mdbook build docs passed; and AGI_GAME_DIR=games/SQ2 python3 -B tools/logic_opcode_evidence.py --check passed.

  2981. Reported: “Full unit discovery passed 299 tests and the book/evidence checks are clean. I’m bumping the tracker count from 298 to 299, then I’ll run the local compatibility wrapper.”

    Action/result: Found only the current PROGRESS.md count needed updating; older progress-log mentions remained historical.

  2982. Reported: “Only the current tracker count needs updating; the progress-log references are historical.”

    Action/result: Updated PROGRESS.md from 298 to 299 tests.

  2983. Reported: “The tracker count is updated. I’m running the local compatibility wrapper now, which redoes the local unit suite, mdBook, and opcode-evidence freshness from the manifest.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_v3_synthetic_picture_view_001.json passed.

  2984. Reported: “The local compatibility wrapper passed with 299 tests and rebuilt the book. I’m checking the reports, whitespace, and generated caches now.”

    Action/result: The local compatibility report showed zero return codes, git diff --check passed, and tests/__pycache__ plus tools/__pycache__ were the only generated cache directories.

  2985. Reported: “The report and whitespace check are clean; only Python cache directories were generated. I’m removing those, then I’ll add the final validation log entries and do one last quick sweep.”

    Action/result: Removed tests/__pycache__ and tools/__pycache__.

  2986. Reported: “Caches are removed. I’m recording the validation results in the progress log now, then I’ll rebuild/check once more after that final log edit.”

    Action/result: Added this validation progress-log block.

  2987. Reported: “The validation log is recorded. I’m doing the final quick sweep now: mdBook after the log edit, whitespace, cache check, and status.”

    Action/result: mdbook build docs passed, git diff --check passed, no __pycache__ directories remained under tests/ or tools/, and git status --short showed the expected modified/untracked files.

  2988. Reported: “The final sweep is clean: mdBook builds, whitespace passes, and cache dirs are gone. I’m adding that last sweep result to the log and doing one final status-only check after it.”

    Action/result: Added this final progress-log entry.

  2989. Reported: “I’ll pick up from the clean commit…”

    Action/result: Rechecked repository state and PROGRESS.md; only the unrelated untracked run.sh was present after the previous commit.

  2990. Reported: “The tracker is clean after the commit…”

    Action/result: Selected the sound/audio tracker row as the next useful implementation-spec target and began inspecting the relevant docs, tests, and helper scripts.

  2991. Reported: “There isn’t a sound-specific chapter…”

    Action/result: Confirmed tools/agi_sound.py and tests/test_sound_resources.py already model the source-backed sound resource format, scheduling, port-output boundary, and envelope behavior, while the mdBook lacked a dedicated sound/audio chapter.

  2992. Reported: “I found the next useful gap: the project has source-backed sound parsing and driver evidence, but it’s scattered across runtime notes, tests, and labels. I’m going to turn that into a dedicated implementation-oriented docs chapter and wire it into the book/tracker.”

    Action/result: Read the summary, runtime model sound section, symbolic sound labels, sound tests, and sound helper to gather the contract points for a new chapter.

  2993. Reported: “The sound helper/tests are nicely concrete: they already encode the channel record format, countdown semantics, PC-speaker divisor, and non-PC port byte behavior. I’m going to keep the new chapter at the ‘observable interpreter contract’ level, with the port writes as the hardware boundary and analog synthesis marked out of scope.”

    Action/result: Chose the chapter scope: resource parsing, load/start/stop semantics, tick scheduling, completion flags, tone/attenuation output, and explicit deferral of analog waveform synthesis.

  2994. Reported: “The current status file already calls out analog sound as deferred, so the new chapter should make that explicit rather than accidentally widening the target. I’m patching docs now: summary entry, sound chapter, progress log, clean-room notes, and tracker wording.”

    Action/result: Added docs/src/sound_and_audio.md, linked it from docs/src/SUMMARY.md, updated PROGRESS.md and docs/src/current_status.md, and added this clean-room evidence note.

  2995. Reported: “The edit is mostly consolidation, not new claims. I’m anchoring each rule to an existing local artifact: tools/agi_sound.py, tests/test_sound_resources.py, the symbolic labels, and the prior SQ2 corpus observations.”

    Action/result: Completed the sound/audio documentation patch and prepared to validate the mdBook and focused sound tests.

  2996. Reported: “The new chapter is in place. I’m validating it now with the focused sound tests, mdBook build, and whitespace checks, then I’ll clean up any generated Python caches.”

    Action/result: mdbook build docs passed and git diff --check passed. The first focused sound test run failed because the explicit AGI_GAME_DIR/--game-dir requirement was not supplied.

  2997. Reported: “The first focused test run reminded me of our newer no-default-game rule: it failed fast because AGI_GAME_DIR was not set. I’m rerunning it with the explicit local SQ2 evidence directory, which is the right shape for these legacy SQ2 corpus tests.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest tests.test_sound_resources passed 16 tests. No __pycache__ directories were present under tests/ or tools/.

  2998. Reported: “The explicit SQ2 sound tests pass: 16 tests in the focused suite. I’m adding the validation notes, then I’ll rebuild the book once more after that final docs edit.”

    Action/result: Added validation details to docs/src/clean_room_executable_notes.md and this progress-log block.

  2999. Reported: “The validation trail is recorded. I’m doing the final quick sweep after those log edits: rebuild mdBook, whitespace check, cache check, and status.”

    Action/result: mdbook build docs passed, git diff --check passed, no Python __pycache__ directories were present under tests/ or tools/, and git status --short showed the expected documentation changes plus the unrelated untracked run.sh.

  3000. Reported: “The final sweep is clean: mdBook and whitespace pass, no Python caches, and the only untracked non-project file remains run.sh. I’m going to log that and then move to the next PROGRESS.md item instead of stopping at the sound chapter.”

    Action/result: Recorded the sound/audio final sweep and continued toward the next high-value tracker item.

  3001. Reported: “Next I’m re-reading the high-value list and the v3/version notes to choose a source-first task. I’ll prefer something that strengthens the cross-version spec without needing a QEMU run unless the disassembly leaves a behavior ambiguous.”

    Action/result: Re-read PROGRESS.md, docs/src/versions.md, and docs/src/cross_version_workflow.md.

  3002. Reported: “The v3 notes are currently concentrated in the Versions chapter, while Resource Files still begins as an SQ2-only chapter. A portable implementer will need the v2/v3 container contract in the resource chapter too, so I’m checking whether that chapter already covers the v3 combined directory and transformed records before adding anything.”

    Action/result: Confirmed docs/src/resource_files.md already contains a detailed Gold Rush / AGI v3 container comparison, including combined directory sections, 7-byte volume headers, dictionary expansion, and picture-nibble expansion.

  3003. Reported: “Resource Files already has a solid v3 container section, so I won’t duplicate it. Since you’ve added more local games, the next useful cross-version step is a read-only census tool/report that can summarize each game’s layout, version string, resource counts, and transform mix without hard-coding SQ2 or GR.”

    Action/result: Inspected the local games/ directory and found PQ1, KQ1, KQ2, KQ3, KQ4D, LSL1, SQ2, and GR.

  3004. Reported: “The local games/ directory now has several interpreters: PQ1, KQ1-3, KQ4D, LSL1, SQ2, and GR. I’m going to add a small read-only census script that requires explicit paths, so future comparison passes can start from a reproducible inventory instead of ad hoc shell scans.”

    Action/result: Reviewed shared path handling and existing tests, then designed tools/game_census.py around explicit --game-dir or --games-root inputs.

  3005. Reported: “I’m adding this as reusable infrastructure, not just a one-off report: repeated --game-dir for selected inputs, or explicit --games-root for a first-level scan. The tool will emit JSON or Markdown and continue past individual bad records so malformed/out-of- range entries are evidence, not fatal surprises.”

    Action/result: Added tools/game_census.py and synthetic unit tests in tests/test_game_census.py.

  3006. Reported: “The census script and synthetic tests are added. Before using it on the private games/ tree, I’m running the isolated tests and a compile check so the tool’s behavior is pinned down without depending on any copyrighted local input.”

    Action/result: python3 -B -m py_compile tools/game_census.py tests/test_game_census.py passed, and python3 -B -m unittest tests.test_game_census passed 5 tests.

  3007. Reported: “The isolated census tests pass. I noticed two imports that the first draft doesn’t need, so I’m cleaning those before running the tool against the local game directories.”

    Action/result: Removed unused imports from tools/game_census.py.

  3008. Reported: “Now I’m running the census on the explicit local games/ root and writing reports under build/, which keeps the private input-derived report out of source while still giving us concrete observations for the docs.”

    Action/result: Wrote build/cross-version/game_census.json and build/cross-version/game_census.md.

  3009. Reported: “The read-only census completed cleanly. I’m inspecting the generated summary now for anything surprising, especially layout/version spread and record errors that would affect the next comparison pass.”

    Action/result: Inspected the generated Markdown/JSON census and identified six split-directory inputs plus two v3 combined-directory inputs.

  3010. Reported: “The census surfaced useful evidence: six split-directory games plus two v3 combined-directory inputs, and a few record-header errors in KQ1, KQ4D, and SQ2. I’m looking at those errors closely before deciding whether they are malformed data, unsupported container variants, or just directory sentinels our generic parser should treat more carefully.”

    Action/result: Compared error details for KQ1, KQ4D, and SQ2. SQ2’s two errors are the already known out-of-range end entries; KQ1 and KQ4D sound entries need later source inspection before being modeled.

  3011. Reported: “The error rows are themselves useful: SQ2’s two are the already-known out-of-range end entries, while KQ1/KQ4D need later source checks before we treat their suspect sound entries as valid resources. I’m documenting the census tool and the current local findings as a starting point for future version passes, without making those errors part of the portable spec.”

    Action/result: Documented the census workflow and snapshot in docs/src/cross_version_workflow.md, docs/src/versions.md, PROGRESS.md, docs/src/current_status.md, and docs/src/clean_room_executable_notes.md.

  3012. Reported: “The first doc patch missed because PROGRESS.md wording had shifted. I’m applying the same content in smaller pieces against the current text.”

    Action/result: Added the census workflow to docs/src/cross_version_workflow.md and the local census snapshot to docs/src/versions.md.

  3013. Reported: “The workflow and Versions docs now point at the census tool. I’m updating the progress tracker next so this infrastructure shows up in the dashboard rather than being buried in prose.”

    Action/result: Updated PROGRESS.md to mention the multi-game census in the current snapshot, symbolic-map row, and resource-loading row.

  3014. Reported: “The tracker now reflects the census work. I’m adding the clean-room evidence trail and Useful Files pointer, then I’ll run validation over the new tool and docs.”

    Action/result: Added tools/game_census.py to Useful Files and recorded the census work in docs/src/clean_room_executable_notes.md.

  3015. Reported: “One quick correction in the log: I typed ‘seven split-directory’ in one entry, but the census shows six split-directory inputs and two v3 combined inputs. I’m fixing that before validation so the historical log is clean.”

    Action/result: Corrected the progress-log census count.

  3016. Reported: “The census docs are in. I’m validating the new tool and resource parser tests together, plus mdBook and whitespace, because this touched both tooling and the cross-version chapters.”

    Action/result: python3 -B -m py_compile tools/game_census.py tests/test_game_census.py passed; python3 -B -m unittest tests.test_game_census tests.test_agi_resources passed 13 tests; mdbook build docs passed; and git diff --check passed.

  3017. Reported: “Focused validation passed: 13 tests covering the new census tool plus resource parser, and mdBook/whitespace are clean. I’m running the full local unittest discovery once too, since this added a new test file that should fit the normal suite.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 304 tests and generated tests/__pycache__ plus tools/__pycache__.

  3018. Reported: “Full local discovery passed 304 tests, and it generated the usual Python cache directories. I’m removing only those generated caches, then I’ll update the test count and final validation notes.”

    Action/result: Removed tests/__pycache__ and tools/__pycache__.

  3019. Reported: “Full local discovery is up to 304 tests now and caches are removed. I’m finding the current tracker count so I can update only the live dashboard, leaving the older progress-log counts as historical entries.”

    Action/result: Found the live count in the compatibility-suite tracker row.

  3020. Reported: “The live test-count line is in the compatibility-suite row, currently 299. I’m bumping that to 304 and recording the validation commands/results for the census pass.”

    Action/result: Updated PROGRESS.md to 304 tests and added validation details to docs/src/clean_room_executable_notes.md.

  3021. Reported: “The final sweep is clean, with run.sh still the only unrelated untracked file. The census exposed a concrete next source-first question, so I’m going one level deeper on KQ4D’s v3 directory: why the sound section has many present-looking entries that fail the generic v3 record header check.”

    Action/result: Inspected KQ4D DMDIR, DMVOL.*, and executable file types. The sound section starts at 0x02d5 and begins with many ff ff ff absent entries.

  3022. Reported: “I’m checking the raw KQ4D directory and the referenced volume offsets first. If the bad entries are just filler/trailing data, that should show up before I spend time mapping the executable routine.”

    Action/result: Decoded KQ4D sound entries. Clean records appear at sound indices 70..79; later present-looking triples generally point inside non-header volume data.

  3023. Reported: “The sound section starts with a long block of ff ff ff, then real-looking entries. That makes the generic exact-ff ff ff absent rule plausible, but the later bad entries are not obviously just the initial empty range, so I’m decoding the sound section indices and target headers next.”

    Action/result: Printed present-like KQ4D sound entries and confirmed the clean 12 34 headers at indices 70..79.

  3024. Reported: “The target dump is telling: KQ4D has ten clean sound records at indices 70-79, then later present-looking triples that mostly land inside compressed data rather than at 12 34 headers. I’m checking decoded KQ4D logic references now, because if scripts never request those later sound numbers, they are directory tail/data artifacts rather than valid-resource semantics.”

    Action/result: Initial disassemble_logic.py calls used nonexistent flags or the old GR-specific v3 table bases, revealing that KQ4D needed per-build dispatch-table detection.

  3025. Reported: “I guessed nonexistent flags on disassemble_logic.py; it takes explicit logic numbers plus --stats. I’m checking its CLI and then I’ll use the supported path.”

    Action/result: Confirmed the supported CLI and reran with AGI_GAME_DIR=games/KQ4D, still exposing wrong table data from the hard-coded GR v3 bases.

  3026. Reported: “The script consumes --game-dir before its own parser, so help itself needs AGI_GAME_DIR set. I’m using --stats now, then I’ll narrow to sound-related opcodes.”

    Action/result: Verified KQ4D stats were incoherent before the fix, with bogus handler/argc/meta values.

  3027. Reported: “KQ4D also exposed a tooling gap: disassemble_logic.py hard-codes GR’s v3 dispatch-table offsets, so KQ4D --stats is decoding with the wrong table. I’m going to inspect the dispatch-table signatures and see if we can infer v3 table offsets per game instead of treating GR as the only v3 layout.”

    Action/result: Compared SQ2, GR, and KQ4D AGIDATA bytes and found exact action/condition argc/meta signatures at SQ2 0x061d/0x08fd, GR 0x0440/0x0762, and KQ4D 0x0620/0x0942.

  3028. Reported: “Good, KQ4D’s action table scores perfectly at AGIDATA.OVL:0x0620 and its condition table at 0x0942; GR’s are at 0x0440/0x0762. I’m going to replace the v3 hard-code with a signature scan so KQ4D and future local v3 builds can disassemble with their own table bases.”

    Action/result: Patched tools/disassemble_logic.py with signature-based dispatch table detection and added tests/test_disassemble_logic_tables.py.

  3029. Reported: “The table shape is consistent: KQ4D has the same v3 extra action slots 0xb0..0xb5, just at different AGIDATA offsets. I’m adding a small signature-based detector around the known operand metadata pattern so the disassembler can use 0x0620/0x0942 for KQ4D automatically.”

    Action/result: Completed the detector patch and test file.

  3030. Reported: “The detector patch is in, but I don’t need to keep the old hard-coded helper around as live code. I’m trimming that before running KQ4D stats again.”

    Action/result: Removed the unused hard-coded static helper.

  3031. Reported: “Now I’m validating the detector and rerunning KQ4D disassembly stats. If the stats become sane and still show no sound opcodes, that supports treating the suspect KQ4D sound entries as non-script-observed until source inspection says otherwise.”

    Action/result: py_compile passed, dispatch-table tests passed 3 tests, KQ4D stats became coherent, and decoded KQ4D scripts referenced only sound resources 70..79.

  3032. Reported: “With the corrected table bases, KQ4D stats are sane and decoded scripts only reference sound resources 70-79; those are exactly the clean 12 34 sound records. The later bad sound-section triples remain non-observed by current KQ4D scripts, so I’m documenting that and the new table detector.”

    Action/result: Updated resource, bytecode, version, symbolic-label, and progress docs to record build-specific v3 dispatch-table bases and KQ4D sound-reference evidence.

  3033. Reported: “I’m updating the docs to stop presenting GR’s dispatch-table offsets as the v3 offsets. The portable statement is now: v3 keeps the same operand metadata shape and extra action slots, but the table bases are per-build and detected from AGIDATA.”

    Action/result: Added the implementation/evidence section for KQ4D dispatch-table detection and sound references.

  3034. Reported: “The KQ4D evidence is documented. I’m running focused validation again, then the full suite so the tracker count reflects the three new dispatch-table tests.”

    Action/result: py_compile passed; python3 -B -m unittest tests.test_disassemble_logic_tables tests.test_game_census tests.test_agi_resources passed 16 tests; mdbook build docs passed; and git diff --check passed.

  3035. Reported: “Focused validation is clean: 16 tests for table detection, census, and resources, plus mdBook/whitespace. I’m running full local discovery now.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B -m unittest discover -s tests passed 307 tests and generated tests/__pycache__ plus tools/__pycache__.

  3036. Reported: “Full discovery is now 307 tests. I’m removing the generated cache directories again, then I’ll bump the live tracker count and do the final sweep.”

    Action/result: Removed tests/__pycache__ and tools/__pycache__.

  3037. Reported: “Caches are removed. I’m updating the live test count from 304 to 307 and recording the focused/full validation for the dispatch-table work.”

    Action/result: Updated PROGRESS.md to 307 tests and added validation details to docs/src/clean_room_executable_notes.md.

  3038. Reported: “The tracker and evidence log are current. I’m doing the final sweep now: mdBook, whitespace, cache check, and status.”

    Action/result: mdbook build docs passed, git diff --check passed, no Python __pycache__ directories were present, and status showed the expected working tree changes plus unrelated run.sh.

  3039. Reported: “The final sweep is clean. Because tools/disassemble_logic.py changed, I’m also going to run the opcode-evidence freshness check and the local compatibility wrapper so the generated evidence pipeline still agrees with the updated disassembler.”

    Action/result: AGI_GAME_DIR=games/SQ2 python3 -B tools/logic_opcode_evidence.py --check passed; AGI_GAME_DIR=games/SQ2 python3 -B tools/compatibility_suite.py --report build/compatibility-suite/local_game_census_dispatch_001.json passed.

  3040. Reported: “The opcode-evidence check and local compatibility wrapper passed. I’m checking the report and cleaning any caches the wrapper regenerated, then I’ll record those validation results.”

    Action/result: The compatibility report had zero return codes for local unit tests, mdBook, and opcode evidence. No Python cache directories were present.

  3041. Reported: “The compatibility report has all zero return codes and no cache directories were left behind. I’m appending that final validation note now.”

    Action/result: Added final compatibility-suite validation notes to docs/src/clean_room_executable_notes.md.

  3042. Reported: “Final validation notes are recorded. I’m running one last mdBook/whitespace/cache/status sweep after that documentation edit.”

    Action/result: mdbook build docs passed, git diff --check passed, no Python __pycache__ directories were present, and status showed the expected working tree changes plus unrelated run.sh.

  3043. Reported: “The last sweep is clean too. I’m adding that sweep result to the progress log; then I’ll do a status-only check so the final note reflects the exact working tree.”

    Action/result: Added this final sweep entry.

  3044. Reported: “Understood, and that distinction changes how the documentation should be organized. I’ll establish spec/ as the implementation-independent behavioral contract, keep docs/ as the evidence and reverse-engineering record, and make that two-role separation explicit in both the repository README and the contributor instructions.”

    Action/result: Created the separate spec/ mdBook with scope and conformance rules, clarified the clean-room two-role boundary in the repository and evidence-book introductions, and updated project guidance and progress tracking so future findings are promoted into the spec only as portable externally observable behavior.

  3045. Reported: “The initial separation is now in place. One more piece is needed to make it durable: the normal compatibility check currently builds only the evidence book, so I’m updating that manifest to build spec/ as well and adding a test that prevents the specification check from silently disappearing later.”

    Action/result: Added mdbook_spec_build to the default local compatibility manifest, covered it in the manifest tests, and updated validation documentation to build both books.

  3046. Reported: “The existing mdBook version rejects the newer multilingual setting in the scaffold. That is a configuration compatibility issue rather than content; I’m removing the unsupported field and rebuilding the specification before I call this done.”

    Action/result: Removed the unsupported mdBook setting after the first specification build failed; the full 307-test suite and evidence-book build had already passed.

  3047. Reported: “Both books now build cleanly, and the complete default compatibility run passes all 307 tests plus both mdBook builds and the opcode-evidence check. I’m recording that final validation in the evidence trail and doing a last status check; no commit will be made unless you request one.”

    Action/result: Recorded the successful spec/ build and default local compatibility report local_spec_split_001.json; git diff --check also passed.

  3048. Reported: “The highest-value gap is now the deliverable itself: spec/ has its boundary but almost no AGI behavior yet. I’ll start promoting the strongest, least ambiguous material into portable chapters: the resource-container contract, the shared runtime/state model, and sound scheduling, while keeping addresses, registers, DOS calls, and evidentiary commentary in docs/.”

    Action/result: Selected resource containers, core runtime state, and sound scheduling as the first substantive specification promotion set.

  3049. Reported: “The evidence separates cleanly into two kinds of contract. Resource files and sound streams have byte-exact external formats; runtime state is better specified as abstract types and ordered effects, not as copies of the DOS memory layout. I’m extracting those separately so the spec stays precise without becoming a disguised decompilation.”

    Action/result: Extracted byte-exact format rules separately from abstract state and lifecycle rules.

  3050. Reported: “The first promotion set is now bounded: exact v2/v3 resource containers, abstract runtime state and cycle ordering, and the sound resource/scheduler contract. I’m deliberately leaving incomplete four-channel envelope initialization and other evidence-only details out of the normative text until the observable rule can be stated without gaps.”

    Action/result: Defined the promotion boundary and recorded the remaining sound-envelope gap rather than inferring missing behavior.

  3051. Reported: “I’m writing the chapters now and adding a small structural test around the clean-room boundary. It will verify that every specification chapter linked by the mdBook exists and that substantive chapters do not accumulate analysis paths, debugger names, symbolic machine-code labels, or disassembly terminology.”

    Action/result: Added version, resource, runtime, and sound specification chapters plus tests/test_spec_book.py.

  3052. Reported: “The new chapters build and pass their boundary checks. Before promoting them in PROGRESS.md, I’m doing a second accuracy pass against the actual local resource bytes and existing models, especially around dictionary stream initialization and the distinction between engine-cycle behavior and game-authored logic conventions.”

    Action/result: Rechecked the promoted contracts and scanned all 468 readable Gold Rush dictionary streams; every stream begins with reset code 0x100.

  3053. Reported: “The accuracy pass confirmed all 468 currently readable Gold Rush dictionary-compressed records begin with reset code 0x100, so I’m making that a valid-stream requirement rather than leaving decoder startup ambiguous. I’m also correcting the handoff dashboard, which still contained stale language saying additional interpreter inputs were unavailable.”

    Action/result: Added the valid-stream reset requirement, created a specification-coverage dashboard, reprioritized remaining work around the behavioral deliverable, and corrected the stale handoff text.

  3054. Reported: “The specification now has its first real behavioral content, and PROGRESS.md tracks specification coverage separately from reverse-engineering coverage. I’ve also reprioritized the remaining work so completing portable chapters comes before gathering more evidence that does not resolve a spec ambiguity.”

    Action/result: Completed the first specification promotion pass and moved validation into progress.

  3055. Reported: “Validation is clean at 309 tests, including the new specification guardrails. I’m continuing with the next dashboard item rather than stopping there: the logic bytecode chapter will begin with the complete stream grammar and all 19 conditions, then promote action families in bounded, reviewable groups.”

    Action/result: Began the logic-bytecode promotion pass after both books, all 309 tests, opcode evidence, and whitespace checks passed.

  3056. Reported: “The bytecode format has a clean portable boundary: resource framing and message decoding, stream control bytes, condition-list semantics, operand interpretation, and operation effects. I’m promoting the complete condition set plus actions 0x00..0x20 first, including room-switch re-entry and picture load/prepare/show distinctions that a compatible engine must preserve.”

    Action/result: Added spec/src/logic_bytecode.md with the complete grammar and condition catalog plus the first 33 action rows.

  3057. Reported: “The first logic section is written, but I’m not treating the existing prose as infallible. I’m checking the nested-call return rule directly against the local disassembly before validation, because a single mistaken ‘callee termination propagates’ sentence would materially alter control flow for every implementation using the spec.”

    Action/result: Re-read the local logic call and interpreter instruction streams and found a stale opcode-0x00 return description.

  3058. Reported: “That check caught a real documentation error before it reached validation. Opcode 0x00 returns the instruction position after the terminator, not zero; ordinary called logic therefore returns to its caller. Only a callee path that explicitly returns zero, such as room switching, propagates termination into the caller. I’m correcting both the evidence book and the new spec now.”

    Action/result: Corrected normal logic termination and nested-call continuation semantics in both documentation roles.

  3059. Reported: “The source-level correction is now reflected on both sides of the clean-room boundary. I’m running the full suite again, including the spec terminology guard, so the final state verifies both behavioral content and separation discipline.”

    Action/result: All 309 tests, both mdBook builds, opcode-evidence freshness, and whitespace checks passed.

  3060. Reported: “Everything passes after the control-flow correction: 309 tests, both mdBooks, opcode evidence, and whitespace checks. I’m recording that validation and leaving the next specification task clearly bounded at action opcodes 0x21..0xaf, rather than mixing more unreviewed material into this pass.”

    Action/result: Recorded final validation and retained the remaining action catalog as the next bounded specification task.

  3061. Reported: “I’m taking the next specification milestone end to end: promote the remaining 2.936 action catalog in coherent families, source-check any vague field-based labels before naming their behavior, then add the v3 extension rows and validate the whole book. I’ll keep the evidence and progress logs current as each family lands.”

    Action/result: Began a source-first audit of action opcodes 0x21..0xaf.

  3062. Reported: “The remaining actions fall into natural behavioral groups rather than one flat machine-code table: object/view selection, animation and movement, inventory, text/input, save/restart, diagnostics, menus, and replay control. I’m using those domains as the spec organization so an implementer can understand state transitions without learning the original field offsets.”

    Action/result: Organized the remaining catalog around portable subsystem behavior.

  3063. Reported: “The object half is now semantically mapped: view/loop/cel selection, priority and update partitions, horizon/control/collision gates, four frame-cycling modes, three autonomous motion modes, rectangle boundaries, and inventory locations. I’m promoting those names and behaviors now, then I’ll do the UI/system half with the same source-first audit.”

    Action/result: Promoted action opcodes 0x21..0x64 into the behavioral specification.

  3064. Reported: “The UI/system half has two compatibility traps worth preserving explicitly: action 0x95 can consume an extra byte when tracing is already active, while runtime action 0xaf consumes no operand despite its scanner metadata. I’m keeping those observable stream effects in the spec and treating unresolved configured-window parameter meanings as a named gap instead of inventing semantics.”

    Action/result: Promoted actions 0x65..0xaf, added v3 extension actions, and added a test requiring every accepted profile opcode to appear.

  3065. Reported: “All accepted action bytes now have portable catalog entries, and the completeness test makes that mechanically visible. I’m doing a consistency pass next: operand counts against the dispatch tables, clean-room terminology checks, and spot checks of the unusual runtime-length cases before moving on to graphics.”

    Action/result: The focused specification tests, mdBook build, opcode-evidence check, and whitespace check passed; the action catalog remained internally consistent.

  3066. Reported: “The opcode catalog is complete enough to shift the center of gravity to graphics. I’m first checking the pending edits and the exact picture raster rules, then I’ll promote the picture format into the clean-room spec with completeness checks and keep moving into view/cel behavior if validation stays green.”

    Action/result: Began the picture-command specification pass from the already accumulated source and behavioral evidence.

  3067. Reported: “The picture path is unusually mature: all commands have source-backed semantics, scanner edge cases are pinned, and the rasterizer has exact byte-width arithmetic rather than a vague ‘draw a line’ description. I’m turning that into a portable contract now, including the pattern masks and the linear right-edge write behavior that a conforming implementation would otherwise be very likely to miss.”

    Action/result: Extracted the exact eight pattern-mask families and organized the normative picture contract around lifecycle, command scanning, rasterization, fill, and patterned plotting.

  3068. Reported: “The picture chapter is now in the clean-room book, with every accepted command represented and the malformed-stream boundary stated explicitly. I’m validating it against the existing renderer tests now; after that I’ll use the same promotion pattern for view resources, where mirroring and clipped run decoding are the next places an independent implementation could silently diverge.”

    Action/result: Corrected a stale focused-test module name and passed 68 specification and graphics-rendering tests.

  3069. Reported: “The focused picture checks pass: 68 specification and graphics tests. One attempted test name was stale (test_agi_graphics); I corrected it to the repository’s actual test_graphics_rendering module and am recording that false start rather than erasing it. The view contract is next, including shared-cel mirroring state, transparent runs, baseline placement, and the priority scan below low-control pixels.”

    Action/result: Began the view/cel specification promotion from the accumulated payload and drawing evidence.

  3070. Reported: “I’ve finished the source-to-behavior mapping for views. The important distinction is that mirroring is stateful at the cel level: the control byte records the loop orientation currently represented by a possibly shared cel, so selecting another loop can reverse the stored run stream and update that orientation. I’m specifying that transition, not merely saying ‘flip the image,’ because aliases and repeated loop changes can expose the difference.”

    Action/result: Added the normative view payload, run decoding, mutable mirroring, placement, priority-composition, and preview contract.

  3071. Reported: “The view chapter passes 69 focused checks. Its portable contract now covers the entire path from payload offsets through mutable mirroring and per-pixel priority acceptance. I’m moving into object behavior next, splitting it into lifecycle/update ordering, animation, movement modes, bounds/collision/control acceptance, and placement so the spec describes observable state transitions without inheriting the original record layout.”

    Action/result: Began the object-behavior promotion pass.

  3072. Reported: “The object evidence is broad, but one collision sentence is still too abstract for a normative spec: ‘baseline equality/crossing’ does not tell an implementer which inequalities fire. I’m reopening that helper’s local instruction stream before writing the chapter, and I’m also correcting the rectangle wording so the strict inside/outside test is not mislabeled as inclusive.”

    Action/result: Regenerated the disposable decrypted executable and read the collision helper directly.

  3073. Reported: “The direct source check resolved the collision rule precisely: touching horizontal extents count as overlap, and baselines collide when currently equal or when their strict relative order reverses between saved and current positions. It also exposed three catalog summaries that were too loose: object initialization enables update/cycling state, rectangle membership is strict, and the two control options are final-scan gates rather than simple one-class blockers. I’m correcting those while writing the object chapter.”

    Action/result: Added the object chapter, corrected the action summaries, and passed 75 focused checks after correcting another stale test name.

  3074. Reported: “The object chapter now passes 75 focused checks, and the catalog corrections are consistent with the evidence checks. I’ve left the subsystem honestly partial at one narrow point: exact random-motion timing and approach-mode recovery. Since that is now the highest-value remaining item, I’m staying source-first and isolating those two helper ranges for a direct instruction-level pass rather than papering over them with observed end positions.”

    Action/result: Isolated and decoded the approach, random-motion, and shared target-direction helper ranges.

  3075. Reported: “The isolated helpers close the remaining gap cleanly. Nearness uses strict bands (-threshold < delta < threshold), so equality at the threshold still requests movement; random mode chooses direction modulo 9 and a retry countdown modulo 51 until it is at least 6; approach recovery uses half the center/baseline Manhattan distance plus one and samples a delay no smaller than the step. I’m encoding those transitions and adding deterministic model tests around the random source abstraction.”

    Action/result: Added deterministic target/random/approach transition helpers and tests, promoted the exact rules, and marked object behavior complete for the current profiles.

  3076. Reported: “The motion gap is closed: 83 focused checks now pass, including strict target bands, random countdown rejection, and approach recovery transitions. The object subsystem can move to complete for the current profiles. I’m continuing into input and parsing now, starting from the resource and state model rather than the UI probes, because word normalization and event consumption determine what scripts can observe before any text is drawn.”

    Action/result: Began parser, event, text, inventory, and menu promotion.

  3077. Reported: “The input subsystem separates into four clean contracts: dictionary parsing, event normalization, text-surface state, and modal list interaction. I’m promoting those as one chapter but keeping font glyph shapes and the two still-unresolved configured-window parameters explicitly outside the completed claim; parser and event semantics can be normative without pretending the remaining presentation details are solved.”

    Action/result: Added the input/text/menu/inventory specification chapter and structural coverage checks.

  3078. Reported: “The parser/input/menu chapter passes 90 focused checks. I hit and corrected one more stale module name (test_agi_input versus test_input_model), which will go into the historical log. I’m continuing into session state now: room transitions first, then restart, the save envelope, restore ordering, and resource-event replay, with v2/v3 differences kept explicit instead of blended.”

    Action/result: Began the room/replay/persistence promotion pass.

  3079. Reported: “The session model has a useful portable core even before every save byte is semantically named: room-switch abort/re-entry, the replay-pair language, selector control flow, five-block framing, failure behavior, and the v3 transform are all externally testable. I’m writing those now, while labeling the still-opaque portions of serialized state as the remaining blocker for binary save-file conformance.”

    Action/result: Added the room/replay/persistence chapter and passed 101 focused specification, save, input, graphics, and logic-document tests.

  3080. Reported: “The persistence chapter passes 101 focused checks. It now gives an implementation team the room/replay state machine and all currently known save framing, while drawing a hard line around the unmapped bytes inside the five state blocks. Before attempting that much larger serialization map, I’m consolidating the evidence trail, updating the handoff/dashboard, and running the complete project validation so this long pass ends at a trustworthy checkpoint rather than a pile of individually green fragments.”

    Action/result: Updated the handoff and prepared the full validation run.

  3081. Reported: “The full suite is running now across the whole repository, not just the new chapters. After it finishes I’ll build both mdBooks, run the opcode-evidence freshness check, and inspect the complete diff for clean-room boundary leaks and accidental generated-file changes.”

    Action/result: The full local suite passed all 323 tests.

  3082. Reported: “Everything is green so far: 323 tests passed, both books build, and opcode evidence is current. I’m on the final audit now, checking whitespace, the substantive-spec terminology guard’s coverage, newly generated artifacts, and the exact diff footprint; then I’ll update the validation record and leave the next serialization task clearly bounded.”

    Action/result: Both mdBooks, opcode evidence, and whitespace validation passed; the only unrelated untracked file remained run.sh.

  3083. Reported: “I’m picking up at the highest-value remaining item: profile 2.936 save block 1. I’ll map it in block-relative portable fields, use the disassembly and existing symbolic data map to distinguish real state from padding, and add a coverage check so every one of its 1,505 bytes is either named or explicitly unknown rather than silently skipped.”

    Action/result: Began a byte-complete profile 2.936 block-1 map from the local executable and saves.

  3084. Reported: “The block boundary is now clear: block 1 is a contiguous runtime snapshot beginning with the seven-byte signature, followed immediately by all 256 variables and 32 packed flag bytes. The harder half is its tail, where key mappings, string slots, timers, horizon/rectangle controls, and text configuration are interleaved with currently unlabeled bytes; I’m inventorying every referenced field before assigning unknown ranges.”

    Action/result: Regenerated the static instruction listing and inventoried references throughout the full 1505-byte saved region.

  3085. Reported: “A useful anomaly turned up: the saved region from the first string-slot base to the text globals is 960 bytes, exactly 24 slots of 40 bytes, while the parser explicitly accepts only the first 12. I’m checking direct references around the midpoint before deciding whether this is 24 general slots, two 12-slot banks, or 12 slots plus unrelated zeroed state; the clean spec should not flatten those possibilities.”

    Action/result: Confirmed twelve parser-visible slots and retained the following 480 bytes as an opaque bank rather than inferring extra slots.

  3086. Reported: “The source reference inventory supports a complete first-pass partition: two small unknown words among the engine globals, a 44-byte unreferenced gap after the 39-entry key map, and a 480-byte opaque bank after the twelve validated string slots. I’m preserving those as byte ranges with known initial values instead of guessing names, while mapping the timer, horizon, movement rectangle, current prepared picture, replay counters, and text configuration precisely.”

    Action/result: Added an exhaustive block-1 region map and checked the five opaque ranges across all 11 local saves.

  3087. Reported: “The first save block map is ready to turn into both evidence and a portable contract. I’m going to land that documentation first, then use the same coverage discipline on blocks 2 and 4, which appear structurally complete: 21 fixed-size object records and 100 replay pairs respectively.”

    Action/result: Added complete block-relative maps for profile 2.936 save blocks 1, 2, and 4, plus deterministic splitters and coverage tests.

  3088. Reported: “I have enough source evidence to make two distinctions explicit in the spec: a save block may contain portable values plus opaque compatibility bytes, and pointer-shaped object fields are serialized but are not portable object identity. On restore, resource replay and view rebinding reconstruct those associations, so the contract will name the bytes while requiring implementations to rebuild references from resource selections rather than preserve process addresses.”

    Action/result: Separated serialized reference tokens from portable object identity in the normative block-2 contract.

  3089. Reported: “Before I describe those serialized references as disposable, I’m checking the successful-restore path field by field. The key question is not whether the bytes look like addresses, but whether any of them can affect valid behavior before the restored view, loop, cel, and render state is rebuilt.”

    Action/result: Confirmed that successful restore rebinds view/loop/cel state, rebuilds list participation, restores flags, and normalizes the event identifier to the object index.

  3090. Reported: “I’m editing the save helper, tests, and persistence chapter now. The maps will be mechanically exhaustive, with a validator that rejects gaps or overlaps; the prose will keep block-relative byte positions separate from the portable state model and will mark unresolved bytes instead of assigning speculative semantics.”

    Action/result: Updated the helper, tests, specification, dashboard, symbolic labels, handoff, and chronological evidence record.

  3091. Reported: “The restore pass resolves the reference-token question cleanly. It preserves the saved loop and cel selectors, reloads the selected view, recomputes loop/cel counts and references plus cel dimensions, rebuilds active/list state from saved flags, and restores those flags afterward. It also normalizes each object’s event identifier to its object index, so that byte is present in the file but is not authoritative after a successful restore.”

    Action/result: Added the post-restore normalization rule to the clean specification and a local save-corpus invariant test.

  3092. Reported: “The first tranche passes 28 focused checks. I’m moving straight into block 3 now; its 328 bytes strongly suggest the inventory table’s one-byte header plus 109 three-byte entries, but I’m treating that only as a hypothesis until the loader, inventory actions, and save corpus all agree on the boundary and field meanings.”

    Action/result: Rejected the initial arithmetic-only hypothesis after comparing the loader, inventory actions, source file, and save corpus.

  3093. Reported: “The block-3 hypothesis has sharpened: it is not 109 records. The saved bytes begin with 40 three-byte entries, each holding a name offset and one-byte location; those offsets all point to byte 0x78, where the zero-terminated item-name pool begins. The local source file is 331 bytes while the runtime/save block is 328 bytes, indicating a three-byte file prefix is consumed during loading. I’m tracing that loader now to establish the item count and offset origin exactly.”

    Action/result: Identified the 120-byte entry table and 208-byte name pool from the decoded data and source consumers.

  3094. Reported: “The loader confirms the format and ties three blocks together. After XOR decoding, the metadata file begins with name_table_offset:u16le and maximum_object_index:u8; the remaining bytes are exactly save block 3. For this game those values are 120 and 20, yielding 40 inventory entries, 21 drawable-object records, a 208-byte name pool, and therefore the observed block-2 and block-3 lengths without any padding.”

    Action/result: Added the inventory metadata file contract, exhaustive block-3 parser/tests, symbolic loader labels, and the derived block-length relationship to the evidence and clean specification.

  3095. Reported: “Block 3 is now complete and the focused suite remains green. I’m on the genuinely variable part, block 5: I’ll first derive its sizing formula and record grammar from the logic-cache allocator and save helper, then correlate each 4-byte growth step with loaded logic/resume state across the 11 saves.”

    Action/result: Reopened the logic-cache serializer, restore lookup, and all local variable block-5 payloads.

  3096. Reported: “Block 5’s grammar is now source-complete. It is a sequence of four-byte (logic_number:u16le, resume_offset:u16le) records, preceded by a serialized zero-valued head record and terminated by a four-byte record whose logic number is 0xffff. The offset is measured from that logic’s bytecode entry, so it remains portable across reloads; restore scans this table by logic number and rebuilds each resume position as new_entry + saved_offset.”

    Action/result: Added a variable block-5 parser with terminator, duplicate, relative-offset, and first-match tests.

  3097. Reported: “One subtle but important distinction emerged from the corpus: block 5 does not decide which logics are loaded. The replay-pair sequence does that. Block 5 is only a lookup table consulted as each replayed logic load occurs; the first matching entry supplies a relative resume offset, no match leaves the logic at its entry, and unmatched block-5 records are ignored. This explains why the saved cache list and replayed logic list overlap without being identical.”

    Action/result: Completed the five-block profile 2.936 map and promoted the replay-versus-resume-table distinction into the clean specification.

  3098. Reported: “All five blocks now pass 35 focused checks. I’m moving to the next dashboard item rather than stopping: a conformance matrix that tells an independent implementer what is universal, what is selected by interpreter profile, what comes from each game’s data, what remains unresolved, and what is deliberately outside the current full-EGA target.”

    Action/result: Began the standalone subsystem/version conformance matrix.

  3099. Reported: “The matrix will not just be a progress checklist. I’m making it normative claim guidance: an implementer can see which chapters must be combined for a 2.936 full-EGA claim, which deltas must be added for 3.002.149, which dimensions come from the selected game rather than interpreter code, and which incomplete areas prohibit narrower claims such as exact four-channel amplitude or v3 binary save interchange.”

    Action/result: Added the matrix chapter, claim requirements, structural test, summary link, and updated dashboard/handoff priorities.

  3100. Reported: “The conformance matrix passes its structural checks, bringing the focused total to 36. I’m doing a consistency audit now because this pass corrected two older evidence assumptions: block 3 is game-metadata-sized rather than interpreter-fixed, and block 5 includes a cache-head record before the linked logic records. After that audit I’ll run the complete suite and both books.”

    Action/result: Corrected stale block-5 evidence text and the completed matrix handoff item; source compilation and whitespace checks passed.

  3101. Reported: “The complete suite is green: 341 tests, up from 323 at the last checkpoint. I’m building both books and checking opcode evidence now, then I’ll do one final diff audit for stale claims and accidental changes; run.sh remains unrelated and untouched.”

    Action/result: The full 341-test suite passed.

  3102. Reported: “Validation is fully clean: both mdBooks build, opcode evidence is current, and whitespace checks pass. The final audit found only the expected project files plus the pre-existing untracked run.sh; the Python cache directories created during compilation have been removed.”

    Action/result: Completed the final validation and artifact audit for the save-map and conformance-matrix pass.

  3103. Reported: “The profile 2.936 save map and conformance matrix are complete, so I’m taking the next priority into source discovery rather than editing more spec by analogy. I’ll inventory the available Gold Rush save artifacts and locate the five v3 save source ranges first; any v2-shaped fields will only be promoted after the relocated v3 code confirms them.”

    Action/result: Reopened GR v3 save block evidence and source labels as the next PROGRESS.md priority.

  3104. Reported: “The v3 inventory block exposed a correction rather than a new mystery: the saved bytes decode exactly with the repeating Avis Durgan key and then match the decoded OBJECT runtime block byte-for-byte. The existing 59-byte helper constant produces nonsense on the same original-engine save, so I’m reopening the v3 transform extraction before changing the spec; this is precisely the kind of cross-check the byte-complete pass is meant to catch.”

    Action/result: Compared the original-engine GR save block against the decoded GR OBJECT runtime payload and found the previous helper key was wrong despite round-trip tests passing.

  3105. Reported: “The correction is now conclusive: 0x072c is a data-segment address, and AGIDATA.OVL contains Avis Durgan there. The earlier 59-byte constant came from reading main-code bytes at the same numeric offset, a segment-confusion error that round-trip-only tests failed to detect. I’m correcting the helper, spec, labels, and tests, and adding a known input/output assertion so this class of mistake cannot pass again.”

    Action/result: Corrected the GR save transform model from the accidental code-image bytes to the DS:0x072c data key.

  3106. Reported: “I’m applying the correction now. The dynamic save remains valid evidence for the transform, but the previous check only proved “XOR twice returns the input,” which is true for any repeating key. The replacement test pins the actual bytes: decoded runtime prefix 89 01 00 8b 01 1c must encode as c8 77 69 f8 21 58, matching the original-engine save.”

    Action/result: Updated the helper/test/spec files with exact key, wrap-point, and known-vector assertions.

  3107. Reported: “Continuing. The immediate thread is to finish validating the GR v3 save-key correction, then I’ll keep moving into the next PROGRESS.md item rather than stopping at the cleanup point.”

    Action/result: Resumed from the corrected GR save-key state and checked the current tree before continuing.

  3108. Reported: “The code already has the corrected key, but the helper is still SQ2-shaped in places. I’m going to validate the correction first, then generalize the save parser enough to map GR’s block 2/3/4/5 from source-derived metadata instead of hardcoded SQ2 constants.”

    Action/result: Ran the focused save/spec tests successfully and identified generic parser work for GR save blocks.

  3109. Reported: “The GR saves all agree: block 2 is 23 * 43, block 3 decodes byte-for-byte to OBJECT[3:], block 4 is 50 replay pairs, and block 5 currently contains head, cached logic 0, terminator. Block 1 still needs a real source map; I’ll avoid pretending it is complete and mark only the source-backed prefix/portable fields.”

    Action/result: Compared generated GR saves against the decoded GR OBJECT metadata and derived blocks 2 through 5.

  3110. Reported: “The focused correction tests are green. I’m now deriving the GR save dimensions from the GR OBJECT file and the generated original-engine saves, so the next spec step can say “23 object records and 131 inventory entries” because the data proves it, not because it resembles SQ2.”

    Action/result: Promoted decoded-object metadata as the source for GR object/inventory save dimensions.

  3111. Reported: “I’m going to add generic parsers rather than a second pile of GR-only code. The durable contract is: object record stride is still 43 bytes, inventory table size comes from the decoded OBJECT header, and replay capacity comes from the saved block length/profile, so the helper should express those dimensions directly.”

    Action/result: Added generic object-record, replay-pair, inventory-block, and object-metadata decode helpers in tools/agi_save.py.

  3112. Reported: “The generic parser helpers are in place. I’m adding tests that use games/GR only when the private directory is present, and QEMU-generated save artifacts only when they exist under build/, so the public repo can still run without bundled game data.”

    Action/result: Added optional GR metadata/save structure tests with private-input and generated-artifact guards.

  3113. Reported: “The tests now pin the GR dimensions against the decoded metadata and the generated signed save. I’m running that focused suite; if it passes, I’ll promote the block 2-5 mapping into the clean spec and evidence docs.”

    Action/result: Focused save/spec tests passed with 39 checks.

  3114. Reported: “Focused tests are green at 39 checks. I’m updating the spec now with the portable parts of the GR save layout: block 1 length/signature remains partial, while blocks 2-5 have concrete structure for the observed initial save state.”

    Action/result: Added the profile 3.002.149 observed Gold Rush block section to spec/src/session_and_persistence.md.

  3115. Reported: “The clean spec now has a separate GR v3 block section, with block 1 deliberately partial and blocks 2-5 expressed in portable terms. I’m reflecting that narrower completion state in the conformance matrix and project tracker.”

    Action/result: Updated spec/src/conformance_matrix.md, PROGRESS.md, and docs/src/current_status.md.

  3116. Reported: “The evidence-facing runtime notes are getting the same detail, including the object metadata derivation. This keeps the source trail clear: GR’s block dimensions come from decoded local metadata plus original-engine saves, not from a hand-transposed SQ2 table.”

    Action/result: Updated runtime/evidence documentation with GR blocks 2-5 derivation.

  3117. Reported: “Validation is clean and there are no generated __pycache__ directories. I’m not stopping there: the next PROGRESS.md item is GR block 1, so I’m moving back to disassembly around the v3 save writer to identify the source ranges for that 1028-byte block.”

    Action/result: Reopened GR save/restore disassembly around image 0x29e5 and 0x2aba.

  3118. Reported: “The save writer gives the crucial source boundary: GR block 1 is a contiguous 0x0404 bytes from DS:0x0002, exactly like the SQ2 block-1 method but shorter. The expanded 49-slot key map consumes almost all of SQ2’s old gap, the string-slot bank remains 12 slots, and the tail includes the GR menu/key gates.”

    Action/result: Derived the GR block-1 address/length from the writer helper arguments and mapped the main shifted regions.

  3119. Reported: “I’ve added the GR block-1 region table with explicit opaque gaps rather than smoothing them over. I’m adding tests for byte coverage, the expanded key-map/string/tail layout, and the observed signed save values.”

    Action/result: Added GR_V3_BLOCK1_REGIONS, split_gr_v3_block1(...), and focused block-1 tests.

  3120. Reported: “The GR block-1 parser tests pass. That closes the current highest-value item at the structural level, so I’m updating the clean spec from “block 1 partial” to a byte-complete observed Gold Rush block-1 map with explicit opaque ranges.”

    Action/result: Promoted the GR block-1 map into the clean persistence specification.

  3121. Reported: “The spec now has the full observed GR block-1 partition, including the expanded key-map and GR-specific tail gates. I’m moving the dashboard from “finish GR block 1” to the next real gaps: text-window parameters and sound envelope behavior.”

    Action/result: Updated the conformance matrix, PROGRESS.md, and current status handoff.

  3122. Reported: “The tracker now reflects that the GR save-map task is structurally complete for the observed Gold Rush profile, with opaque ranges still honestly marked. I’m adding the evidence-note section for the block-1 source boundary and region map.”

    Action/result: Added a clean-room evidence section for GR block-1 writer source ranges and map coverage.

  3123. Reported: “The runtime chapter now includes the block-1 source boundary. I’m recording the exact disassembly evidence in the clean-room notes, because that writer call is the thing that makes the 1028-byte block boundary solid.”

    Action/result: Updated runtime model prose and evidence notes with the block-1 writer call details.

  3124. Reported: “The evidence note now contains the block-1 writer call and full region map. I spotted one stale sentence in the version profile that still says the v3 save maps are incomplete, so I’m correcting that before validation.”

    Action/result: Corrected the profile 3.002.149 save-map status in the clean version profile.

  3125. Reported: “Final audit is clean: no whitespace errors, no cache dirs, and run.sh is still the unrelated untracked file. I’ll keep going into the new top item: resolving actions 0x97/0x98 from disassembly before changing the spec.”

    Action/result: Started the source-first configured modal-message pass.

  3126. Reported: “The existing evidence already has the handler addresses: SQ2 0x97 at 0x1c54 and 0x98 at 0x1c71, storing three bytes into [0x0d0b], [0x0d0d], and [0x0d09]. I’m reading the callee chain now to map what those globals actually do in the modal text-window geometry.”

    Action/result: Reopened the shared helper at 0x1c96 and modal window-builder path at 0x1d96.

  3127. Reported: “The disassembly resolves the parameters cleanly: parameter 3 is the maximum formatted text width, parameter 1 overrides the window row, and parameter 2 overrides the window column. I’m checking the derived rectangle math so the spec can describe observable behavior rather than just naming globals.”

    Action/result: Mapped [0x0d09] to width, [0x0d0b] to row, and [0x0d0d] to column, including zero-width default handling.

  3128. Reported: “The formulas show the display-helper role: parameter 3 feeds the formatter width, parameter 1 becomes the message-window row (relative to display base), and parameter 2 becomes the message-window column; omitted/default behavior centers the computed text window. I’m promoting that and leaving only pixel-rectangle exactness to the existing text-window section.”

    Action/result: Promoted the row/column/width behavior into the clean logic-bytecode and input/text chapters.

  3129. Reported: “The clean spec no longer treats the 0x97/0x98 parameters as unknown. I’m updating the evidence docs and dashboard next, then the only high-value partial domains left are mostly sound and font-target details.”

    Action/result: Updated evidence logic-bytecode, runtime model, current status, and PROGRESS.md.

  3130. Reported: “These labels make the cross-reference much clearer: [0x0d0b] is the one-shot row override, [0x0d0d] the one-shot column override, and [0x0d09] the one-shot width override. I’m patching those labels and the evidence log now.”

    Action/result: Added symbolic labels for the configured modal-message row, column, and width globals.

  3131. Reported: “One stale summary line still described the configured-message fields as incomplete. I’m correcting that historical summary so the evidence book doesn’t contradict the new source pass.”

    Action/result: Corrected the stale evidence summary and added the configured modal-message source note.

  3132. Reported: “I’ll re-anchor on PROGRESS.md and the current status notes, then pick the highest-value unfinished item that keeps the clean-room spec moving. After that I’ll update the evidence/spec/docs alongside any tests so the trail stays coherent.”

    Action/result: Re-read the tracker, handoff note, conformance matrix, and current git status. Selected the four-channel sound attenuation envelope as the top stale specification gap.

  3133. Reported: “The tracker says the biggest remaining spec gap is the four-channel sound attenuation envelope, with glyph exactness as a policy decision rather than something to chase blindly. I’m going source-first on sound now: labels, disassembly notes, then portable behavior only if the evidence is strong enough.”

    Action/result: Reopened sound/audio evidence, the clean sound chapter, symbolic labels, and existing sound helper/tests.

  3134. Reported: “There’s already a surprisingly good source model in tools/agi_sound.py; the spec is lagging behind it. I’m reading the helper/tests and the exact disassembly notes so I can promote the envelope contract without accidentally smuggling implementation addresses into spec/.”

    Action/result: Confirmed local tests already model the envelope table, delta clamps, channel masks, selector-2 adjustment, tone output, and stop-silence output.

  3135. Reported: “The evidence book already records the key envelope mechanics: reset timing, channel-3 persistence, signed deltas from base attenuation, 0x80 sentinel, global adjustment, selector-2 adjustment, and channel masks. I’m doing one fresh disassembly spot-check before editing the spec, just to keep the promotion grounded in the actual bytes.”

    Action/result: Re-ran ndisasm windows for the driver start, playback tick, and attenuation helper, plus an xxd table dump for the envelope bytes.

  3136. Reported: “The spot-check agrees with the existing helper: start seeds envelope pointers/indexes, ticks reset indices for channels 0-2 but not channel 3, and the attenuation helper applies one table byte per call until 0x80. I’m going to update the clean spec, conformance matrix, and progress tracker to mark the four-channel amplitude contract as specified at the command-output boundary.”

    Action/result: Promoted the four-channel attenuation envelope transition contract into spec/src/sound.md.

  3137. Reported: “The clean sound chapter now has the missing attenuation state machine. I’m tightening the matrix and tracker so they no longer call sound partial for envelope reasons, while still keeping analog waveform synthesis outside the target.”

    Action/result: Updated the conformance matrix and began revising the progress dashboard.

  3138. Reported: “One of the tracker hunks drifted since the last commit, so I’m splitting the update into smaller patches against the current text. Same intent, just less brittle.”

    Action/result: Re-read the exact PROGRESS.md sections and split the tracker update.

  3139. Reported: “The dashboard now treats sound as covered at the command-output boundary. I’m checking the renumbered high-value list and then I’ll patch the handoff note plus evidence log.”

    Action/result: Found and corrected stale sound-next-work wording and high-value list numbering.

  3140. Reported: “The handoff note now points at cross-version and remaining renderer/text questions instead of already-promoted sound work. I’m adding a structural test for the sound chapter’s envelope terms.”

    Action/result: Updated docs/src/current_status.md and added a spec-book structural test for sound timing/envelope coverage.

  3141. Reported: “That closes the stale sound item. I’m continuing into the next PROGRESS.md item rather than stopping: source-first cross-version work, looking for a mapped v3/SQ2 delta that still has a real observable spec ambiguity.”

    Action/result: Re-read the GR/SQ2 static comparison, version profiles, and remaining cross-version rows.

  3142. Reported: “The remaining v3 deltas in PROGRESS.md are mostly already source-mapped, and the tracker says additional versions should only become spec profiles after observable differences are checked. I’m going to refresh the local multi-game census and pick one concrete interpreter/version difference to document without assuming SQ2 or GR behavior applies.”

    Action/result: Re-ran the explicit local game census over KQ1/KQ2/KQ3/KQ4D/LSL1/PQ1/SQ2/GR and reviewed the versions chapter.

  3143. Reported: “The census refresh still points to one useful source-first question: KQ1 Version 2.917 has four sound-directory entries that look present to the generic v2 parser but do not point at valid volume headers. Before treating that as a container rule, I’m checking whether KQ1 scripts can actually reference those sound numbers.”

    Action/result: Disassembled KQ1 logic stats and sound actions; inspected KQ1 SNDDIR entries 34..37.

  3144. Reported: “KQ1 scripts heavily use sound, but the decoded references I saw are all in the low range. I’m extracting the unique referenced sound numbers directly so we can distinguish directory-looking garbage/end padding from anything scripts can observe.”

    Action/result: Extracted KQ1 immediate sound references 0..21 with gaps and confirmed unreadable sounds 34..37 are not immediately referenced. Rechecked KQ4D and found immediate sound references only 70..79.

  3145. Reported: “The one-off audit is clear enough to document, but repeatability would be better. I’m checking whether disassemble_logic.py exposes enough parser pieces to add a lightweight ‘script-referenced resources’ audit without reimplementing the whole bytecode decoder.”

    Action/result: Determined that importing disassemble_logic.py would force an environment-selected game path, so a standalone audit helper was more appropriate.

  3146. Reported: “I’m adding a small repeatable audit tool now. It scans decoded logic bytecode for immediate resource references and compares those against readable/unreadable directory entries, which is exactly the question raised by KQ1/KQ4D’s suspect sound records.”

    Action/result: Added tools/resource_reference_audit.py.

  3147. Reported: “The audit tool is added. I’m writing a synthetic test now so its bytecode scan catches immediate sound references and distinguishes unreadable directory entries that are actually script-referenced.”

    Action/result: Added tests/test_resource_reference_audit.py.

  3148. Reported: “The test fixture makes one valid sound and one bad sound that the script references, so it exercises the failure mode we care about. I’m running it now before applying the tool to KQ1/KQ4D.”

    Action/result: Py-compile and focused unit test for the audit tool passed.

  3149. Reported: “The audit test passes. I’m applying the tool to KQ1 and KQ4D now, since those are the two local inputs with suspect sound-directory records in the census.”

    Action/result: Generated build/cross-version/resource_reference_audit_kq1_kq4d.json.

  3150. Reported: “The raw JSON is large, so I’m summarizing the fields that matter: referenced unreadable records and unreferenced unreadable records per game/resource kind.”

    Action/result: Confirmed no referenced unreadable resources for KQ1 or KQ4D; KQ1 unreadable sounds 34..37 and KQ4D unreadable high sound entries are unreferenced by immediate decoded script operands.

  3151. Reported: “The audit confirms both suspicious sets are unreferenced by decoded scripts: KQ1 bad sounds 34-37, and KQ4D’s suspect high sound entries. I’m documenting that as planning evidence, not a new runtime rule.”

    Action/result: Updated docs/src/versions.md with the focused script-visible resource reference audit.

  3152. Reported: “The versions chapter now has the focused audit result and the clean-room boundary: unreferenced bad entries stay out of the behavioral model. I’m updating the tracker and handoff files so this tool is discoverable later.”

    Action/result: Updated PROGRESS.md and docs/src/current_status.md with the new audit tool and KQ1/KQ4D conclusion.

  3153. Reported: “The tracker has one policy-shaped gap that is worth resolving cleanly before chasing more probes: exact glyph bitmaps. Since the project target is portable full-EGA behavior, I’m checking the current text chapter and spec boundary to decide whether glyph pixels belong in the core profile or stay as an optional font input.”

    Action/result: Reviewed the text/input chapter, scope/conformance boundary, conformance matrix, and existing glyph-related evidence notes.

  3154. Reported: “The spec already leans the right way: glyph pixels are described as font inputs, not interpreter behavior. I’m going to make that explicit as a conformance decision: core AGI compatibility requires text cell geometry and text bytes/attributes, while bitmap-identical screenshot claims must supply a font profile.”

    Action/result: Added the text cell/font-profile boundary to the clean scope chapter.

  3155. Reported: “The scope chapter now makes the font boundary explicit. I’m updating the text chapter and conformance matrix so glyph exactness is no longer presented as unresolved work.”

    Action/result: Replaced the text chapter’s remaining glyph gap with a Font boundary section and moved exact glyph bitmaps outside the core target unless a font profile is supplied.

  3156. Reported: “The conformance matrix now excludes exact glyph bitmaps unless a font profile is declared. I’m updating the tracker/current-status wording to remove the glyph decision from the remaining work.”

    Action/result: Updated PROGRESS.md, docs/src/current_status.md, and the spec structural test for the renamed text chapter section.

  3157. Reported: “I’m picking up from the completed sound, resource-reference, and font-boundary work. I’ll use PROGRESS.md to choose the next concrete, source-first gaps, keep both books and the evidence trail synchronized, and carry each item through tests before moving on.”

    Action/result: Reviewed the dashboard, handoff, worktree, compatibility manifest, and remaining partial/opaque-state references.

  3158. Reported: “The dashboard is now mostly complete; the two genuinely open portable contracts are persistence’s opaque global-state bytes and broader version coverage. I’m going after the opaque save ranges first because they directly limit binary save interchange, and I’ll begin with static cross-references in the SQ2 and GR executables before deciding whether any narrow runtime probe is warranted.”

    Action/result: Reopened both save maps, existing save tests, symbolic labels, and the complete SQ2/GR disassembly listings.

  3159. Reported: “A useful cross-version pattern has emerged already: three SQ2 ‘opaque’ areas line up exactly with capacity or alignment changes in GR. I’m now checking every direct code reference to the underlying data addresses, including range-based accesses that a simple exact-address search can miss; that should let us distinguish reserved serialization bytes from state that merely lacked a label.”

    Action/result: Confirmed the SQ2 39-slot and GR 49-slot key-map bounds, common string root, removed 480-byte SQ2 tail, and absent direct references to the standalone reserved words.

  3160. Reported: “The static evidence supports a stronger result than ‘unknown’: the SQ2 tail after slot 39 is ten inactive key-map records plus four reserved bytes, the 480-byte bank is a removed legacy/reserved string bank, and the single-byte holes are word-alignment storage. GR confirms those boundaries by expanding the key map and deleting the extra bank. I’m going to encode these as reserved, preserved serialization state with canonical initialization, which closes the valid-execution ambiguity without inventing game-visible fields.”

    Action/result: Defined the portable reserved-state classification and canonical/preservation rule.

  3161. Reported: “I’m adding the save reserved-state contract now. The changes will rename the unresolved save regions into explicit reserved categories, define their canonical bytes and preservation rule, update the clean spec’s interchange claims, and add regression tests that prevent them from drifting back into vague ‘unknown’ state.”

    Action/result: Updated save helpers, save tests, the persistence chapter, version profile, and conformance matrix.

  3162. Reported: “The focused save/spec tests pass with the new partition. This also upgrades the GR claim: its five blocks were already byte-complete, and the only stated blocker was the supposedly opaque block-1 bytes; with those now classified as reserved serialization state, the spec can define Gold Rush save interchange for the mapped game/profile dimensions rather than leaving it categorically partial.”

    Action/result: tests.test_save_resources and tests.test_spec_book passed 43 focused tests.

  3163. Reported: “I’ve got enough evidence to edit. The changes will rename the unresolved save regions into explicit reserved categories, define their canonical bytes and preservation rule, update the clean spec’s interchange claims, and add regression tests that prevent them from drifting back into vague ‘unknown’ state. I’ll keep the disassembly/address rationale confined to the evidence book and symbolic map.”

    Action/result: Updated the evidence-facing versions ledger, symbolic labels, progress dashboard, and current handoff.

  3164. Reported: “The save-state gap is now closed cleanly and both mdBooks build. I’m moving to the next dashboard item: KQ4D’s 3.002.102 interpreter is the best next profile candidate because it sits close to GR’s 3.002.149 but has a distinct dispatch-table layout, so a source comparison can tell us which GR variants are family-wide and which are build-specific.”

    Action/result: Selected KQ4D as the next profile and inspected its MZ executable, combined resources, table offsets, and existing census.

  3165. Reported: “KQ4D is suitable: its AGI is directly disassemblable and its v3 action table has the same 182-entry shape as GR. I’m adding a generic table-comparison helper rather than hard-coding another pair, so future interpreter versions can be compared by detected contracts and normalized handler bodies with explicit game directories.”

    Action/result: Added tools/compare_interpreter_tables.py and tests.

  3166. Reported: “The comparison helper will stay deliberately conservative: matching operand contracts are meaningful, while normalized entry-snippet differences are only triage leads until the disassembled routines are read. I’m wiring that distinction into both the report and tests so a future agent cannot accidentally promote ‘different bytes’ into ‘different behavior.’”

    Action/result: Generated the first KQ4D/GR table report with explicit triage language.

  3167. Reported: “The generic comparator is working and the first KQ4D/GR report is generated. Both builds have identical parser contracts for every shared action and condition; I’m now reading the smaller set of handler-entry differences to identify actual observable deltas, starting with the v3-only slots and any shared actions already known to vary between SQ2 and GR.”

    Action/result: Found zero contract differences, zero condition snippet differences, and 12 shared action snippet differences.

  3168. Reported: “The first real result is crisp: 3.002.102 is not just ‘older GR.’ It shares GR’s v3 opcode-table shape and all 19 condition handlers, but for the 12 differing shared actions it mostly retains the 2.936 behavior: no room alias remap, 39 key slots, and the display-mode/input-width branches that GR later removes. I’m verifying each cluster in focused disassembly before promoting a 3.002.102 profile.”

    Action/result: Read focused KQ4D/GR disassembly for room, key map, input width, close-window, v3 gates, and save handlers.

  3169. Reported: “Focused disassembly confirms the table triage: KQ4D’s room action passes the byte directly, key mapping stops at 39, 0xa3/0xa4 really set and clear the input-width word, and 0xa9 clears it. Separately, KQ4D shares GR’s set/clear release gate, menu gate, v3 no-op slots, and pre-save XOR call. I’m comparing it directly with SQ2 now to pin the mixed profile precisely rather than describing it by age.”

    Action/result: Generated the KQ4D/SQ2 table comparison.

  3170. Reported: “The direct SQ2 comparison narrows KQ4D’s shared-action deltas to just five: inventory temporary state, v3 save transform, restart prompt handling, motion-mode-4 preservation, and the set-style release gate. Everything else among 0x00..0xaf, including room switching and input-width behavior, matches 2.936 at normalized source level. I’m extending this into KQ4D’s save layout now; its writer exposes a particularly clean hybrid block: the full 2.936 block-1 shape plus the v3 menu/release gates.”

    Action/result: Source-mapped the 0x05e4 first block and writer roles.

  3171. Reported: “One KQ4D-specific wrinkle needs resolving before I write the save dimensions into the spec: the eight-byte OBJECT file is structurally valid as plain metadata, while the interpreter’s startup path appears to apply the same Avis Durgan XOR helper used by GR. I’m tracing the demo launcher/install path and file handling around that call, because treating those eight bytes with the wrong transform would produce impossible counts and contaminate the save map.”

    Action/result: Confirmed the launcher does not transform OBJECT and the interpreter XOR helper is instruction-identical to GR’s relocated helper.

  3172. Reported: “The source path is unambiguous enough to justify one confirmation probe. I’m adding a reusable v3 inventory-metadata encoding probe that makes two writable copies under build/: one with the supplied OBJECT bytes unchanged and one XOR-encoded with the interpreter’s local key, then boots both in one QEMU snapshot run. This will tell us whether the local demo input is pre-decoded packaging or whether another startup step compensates for it.”

    Action/result: Added the copied-fixture encoding probe and local test.

  3173. Reported: “The QEMU confirmation is running as a two-case snapshot batch now. It uses copied fixtures only; the private KQ4D directory remains untouched. Once both captures are in, I’ll distinguish ‘engine failed before graphics’ from ‘same playable output’ by inspecting the actual framebuffer rather than relying on process completion.”

    Action/result: Sandbox VNC binding failed; requested the required local QEMU elevation.

  3174. Reported: “The first elevated run exposed a fixture hygiene bug before QEMU started: copytree preserved the read-only directory modes from games/, so the generated copy could not be replaced on the second attempt. I’m fixing the probe to make directories as well as files writable under build/, matching the project’s other fixture builders, then I’ll rerun the same two cases.”

    Action/result: Corrected copied directory modes and reran the probe.

  3175. Reported: “Both first captures are the Sierra loader splash, so they prove only that the launcher starts; the palette difference is timing during that animated screen. I’m advancing past the loader in the same probe and recapturing after the interpreter has actually consumed OBJECT, which is the point where the two encodings can meaningfully diverge.”

    Action/result: Added --advance-loader and reran both cases past Enter.

  3176. Reported: “After advancing into the actual demo, both copies produce the same game frame. That rules out a simple ‘plain file fails, encoded file works’ story. I’m returning to the disassembly around the second XOR call; the likely explanation is that this build treats the metadata buffer as a reversible encoded store and toggles it at two different lifecycle points, so the eight-byte file alone is not enough to infer which representation is canonical.”

    Action/result: Determined the second XOR call belongs to logic-message decoding, not an inventory re-encode lifecycle.

  3177. Reported: “The second XOR call was unrelated logic-message decoding, so the dynamic result does not make the unchanged OBJECT file valid; it only shows this demo reaches its intro despite malformed inventory metadata it does not yet exercise. The source-backed valid path is still clear: decode with the repeating key, yielding the eight-byte intended metadata. I’m using that bounded valid representation to map KQ4D’s save blocks and keeping the packaging anomaly in the evidence book, outside the clean behavioral contract.”

    Action/result: Added KQ4D save constants, parsers, and source-derived dimension tests.

  3178. Reported: “The save helper tests now pin KQ4D’s source-derived dimensions: block 1 is 0x05e4, object state is 16 records, decoded inventory state is one three-byte entry plus \"?\\0\", and the demo configures one replay-pair slot. I’m promoting this as a bounded 3.002.102 resource/logic/persistence profile, while explicitly withholding a full gameplay claim until its renderer and object-update subsystems receive the same source comparison.”

    Action/result: Added the bounded profile, persistence map, and conformance limitation to the clean specification.

  3179. Reported: “The bounded 3.002.102 profile is now in the clean spec and its focused tests pass. It deliberately stops short of a gameplay claim: we now know exactly how KQ4D mixes 2.936-style room/input behavior with v3 gates, save transform, restart, and motion state, but pictures, views, and object-update internals still need role-based comparison before inheriting either complete profile.”

    Action/result: Updated the versions ledger, symbolic labels, progress dashboard, and handoff toward KQ4D renderer/object comparison.

  3180. Reported: “The source mapping is settling into stable relocation bands, so I’m extending the generic comparator with explicit symbolic role pairs. That keeps the comparison address-independent at the reporting level and lets later builds reuse the same role vocabulary.”

    Action/result: Added repeatable --role-pair support and a parser/report regression test to tools/compare_interpreter_tables.py.

  3181. Reported: “With logic and persistence mapped, I’m now comparing KQ4D’s view loader, picture scanner/raster helpers, and object update pipeline against the already-labeled Gold Rush build. I’ll treat normalized snippets as triage and inspect every reported difference in disassembly.”

    Action/result: Generated the first 46-role KQ4D/GR subsystem report.

  3182. Reported: “Rizin can analyze both MZ files, but its raw 16-bit function matcher is not reliable enough here: it includes the DOS header in raw offsets and the function-diff command rejects the required 16-bit architecture setting. I’m using the local ndisasm-based role comparator and direct call relationships instead, with every candidate checked at the instruction level.”

    Action/result: Kept Rizin as exploratory triage only; no behavioral conclusion depends on its function matcher.

  3183. Reported: “The source mapping is already strong: all six view roles, the full picture command scanner, every line/fill/pattern helper, and the object update-list pipeline match after relocation. The only picture differences so far are KQ4D retaining the older alternate-display refresh branches; its primary full-EGA path is the same.”

    Action/result: Classified the decode/fill/full-refresh differences as alternate display-mode wrappers outside the current target.

  3184. Reported: “The role-pair report now covers 46 renderer/object helpers. One animation result is a false mismatch caused by an embedded jump table; I’m manually checking its branch bodies and filling the remaining dirty-rectangle, placement, and motion roles before upgrading the profile.”

    Action/result: Confirmed the animation branch bodies and identified the remaining KQ4D helper entries from their callers.

  3185. Reported: “I’m resuming at the KQ4D/Gold Rush source comparison. The immediate goal is to finish mapping motion, placement, and dirty-rectangle behavior from disassembly, then decide whether the 3.002.102 profile has enough evidence to graduate beyond its current bounded status.”

    Action/result: Confirmed the complete KQ4D object-motion loop and dirty-rectangle helper as relocation matches.

  3186. Reported: “The main object-motion loop is a direct relocation match between KQ4D and Gold Rush, including collision, control-line acceptance, placement adjustment, edge reporting, and motion completion. I also confirmed the dirty-rectangle routine instruction-for-instruction; the remaining work is locating two helper entry points whose addresses shifted outside the dominant relocation band.”

    Action/result: Located placement at image 0x5d64, pre-mode update at 0x065b, mode dispatch at 0x0691, and boundary checking at 0x06f2.

  3187. Reported: “All six remaining role pairs are now mapped. Four normalize exactly, while the motion dispatcher and boundary checker differ only where ndisasm interprets their embedded jump tables as instructions; their executable branch bodies and state transitions match after relocation. That completes the source comparison named as the blocker in PROGRESS.md, so I’m recording the evidence and promoting the KQ4D profile for the primary full-EGA valid-data target, while keeping its alternate display path explicitly version-specific.”

    Action/result: Promoted 3.002.102 to a full-EGA profile and recorded all 52 KQ4D renderer/object role associations.

  3188. Reported: “The clean spec now carries an explicit 3.002.102 full-EGA claim, with KQ4D’s mixed variant choices spelled out rather than inherited by version number. I’ve also added every KQ4D renderer/object address to the cross-version symbol map and preserved the failed Rizin matcher attempt in the evidence trail, so this promotion remains auditable.”

    Action/result: Focused 49-test set and both mdBooks passed.

  3189. Reported: “The profile promotion passes its focused 49-test set, and both mdBooks build cleanly. I’m moving straight to the next dashboard item: selecting another local interpreter version by census, then comparing its dispatch contracts and subsystem roles source-first before deciding whether it adds a genuinely new behavioral profile.”

    Action/result: Selected KQ1/2.917 as the next earlier v2 source target.

  3190. Reported: “The first 2.917 table pass exposed a tooling issue rather than an engine delta: KQ1’s table addresses line up strikingly with 2.936, but the executable body is still transformed, so every disassembly snippet becomes nonsense and the last two table records are misread. I’m tracing the project’s existing SQ2 decryption path and will make the comparator reject or decode this state instead of producing a misleading ‘176 differences’ report.”

    Action/result: Discarded the transformed-file report and decoded KQ1 with its own SIERRA.COM key.

  3191. Reported: “After decrypting KQ1 with its own local loader key, the comparison collapses from nonsense to one clean result: all 19 conditions and actions 0x00..0xad match 2.936 exactly, including handler bodies and operand contracts. The apparent 0xae/0xaf rows are not valid 2.917 table records; I’m verifying the dispatch bound and adjacent data in disassembly before defining the earlier profile’s opcode range.”

    Action/result: Confirmed the action dispatcher maximum is 0xad.

  3192. Reported: “The table geometry gives a reusable answer across every local v2 build: a fixed 32-byte trailer separates the action and condition tables, so the valid action count is derivable instead of assumed. It yields 170 actions for 2.411/2.440, 174 for 2.917, and 176 for 2.936. I’m correcting the disassembler/comparator now so future earlier-version reports cannot accidentally parse trailer bytes as opcodes.”

    Action/result: Implemented geometry-derived v2 action counts and added KQ1/KQ2/LSL1 regression tests.

  3193. Reported: “The subsystem pass found one real 2.917 runtime delta amid otherwise matching code: direction-driven loop selection uses the four-loop table only when a view has exactly four loops. In 2.936 the same branch accepts four or more loops. Everything else in the 52-role renderer/object set matches after relocation, so I’m now mapping 2.917’s save dimensions and absent opcode boundary before deciding how complete the new profile can be.”

    Action/result: Promoted the exact-four-loop rule as a 2.917 variant.

  3194. Reported: “The 2.917 save writer confirms the same five-block grammar and identical 0x05e1 first-state block. KQ1’s game data changes only the object count: 18 records instead of 21; its decoded inventory block remains 0x0148, and logic 0 configures the same 100 replay pairs. I’m encoding those dimensions as tests before promoting the profile, so the gameplay claim and the KQ1-specific binary-save claim stay properly separated.”

    Action/result: Added KQ1 save constants, split/decode helpers, and tests.

  3195. Reported: “The 2.917 model is now internally consistent: 174 actions, 19 conditions, the full-EGA renderer/object pipeline, the exact-four-loop variant, and all five KQ1 save-block dimensions are covered by source-derived tests. I’m writing the evidence/profile ledger next, including the loader-specific executable transform so later comparisons do not repeat the encrypted-image false start.”

    Action/result: Promoted the 2.917 full-EGA and KQ1 binary-save claims.

  3196. Reported: “I’ve reached a coherent commit point: the KQ4D profile promotion is complete, and the new KQ1/2.917 profile has source-backed opcode, renderer/object, loop-selection, and save-dimension coverage. I’m doing the final evidence-log and validation pass now, then I’ll commit only the intended project files and leave run.sh untouched.”

    Action/result: Began final full-suite, mdBook, and diff validation.

  3197. Reported: “I’ll treat KQ4 as an independent evidence input and verify its version, container, executable, opcode tables, and resource census before assuming it matches KQ4D.”

    Action/result: Identified full KQ4 as AGI 3.002.086 with combined v3 resources, distinct from the KQ4D 3.002.102 demo.

  3198. Reported: “It is not the same interpreter build: full KQ4 reports 3.002.086, while the demo is 3.002.102. I’m comparing the dispatch tables and source roles now so the version profile follows observed behavior.”

    Action/result: Generated full-KQ4/KQ4D and full-KQ4/SQ2 table reports.

  3199. Reported: “The first table report exposed a useful tooling bug: it assumed every v3 build had 182 actions and was reading KQ4 trailer data as opcodes. I’m deriving the v3 count from table geometry and adding a regression test before trusting the comparison.”

    Action/result: Replaced the fixed v3 action count with the observed 0x4a-trailer geometry rule; KQ4 correctly parses 178 actions.

  3200. Reported: “Understood: KQ4D is the demo, while KQ4 is the full game. I’m keeping those labels explicit throughout the evidence and spec so the selected-game save dimensions are not mistaken for version constants.”

    Action/result: Renamed documentation sections to distinguish full KQ4 from the KQ4D demo and scoped save dimensions to each selected game.

  3201. Reported: “With the corrected bounds, all 178 shared KQ4/KQ4D action contracts and all 19 conditions match. The actual opcode deltas are narrow: KQ4 increments the release gate, its 0xb0 consumes one ignored byte, and its valid action range ends at 0xb1.”

    Action/result: Mapped KQ4’s action boundary and shared handler variants.

  3202. Reported: “The source comparison is revealing an evolutionary midpoint: KQ4 already has the v3 inventory, save, restart, and motion-mode changes, but retains the earlier room, input-width, key-map, and release-gate behavior. I’m finishing the renderer/object role pass before promotion.”

    Action/result: Compared 52 renderer, view, object, motion, and animation roles against KQ4D after relocation.

  3203. Reported: “The save layout is distinct from the demo: full KQ4 keeps the 0x05e1 first block, has 26 object records, 45 inventory entries, and 250 replay pairs. Its inventory block uses the v3 XOR transform.”

    Action/result: Added full KQ4 save constants, object decoding, block splitters, and source-derived regression tests.

  3204. Reported: “The resource audit finds no immediate reference to KQ4’s missing-volume picture/view entries. Picture selection is variable-based, so I’m recording that as a valid-data exclusion rather than claiming the entries are unreachable.”

    Action/result: Scoped absent-volume records outside the promoted profile and preserved the variable-reference caveat.

  3205. Reported: “There is now enough source evidence to promote 3.002.086: the full-EGA picture/view pipeline matches after relocation, with two object-edge variants in loop selection and exact-zero left-boundary reporting. I’m translating those into portable contracts.”

    Action/result: Added the 3.002.086 profile to the clean specification and conformance matrix.

  3206. Reported: “The portable profile now captures KQ4 as an evolutionary midpoint without exposing DOS implementation details. I’m completing the evidence addresses, progress trackers, book builds, and full test pass.”

    Action/result: Updated the versions chapter, symbolic map, handoff state, progress dashboard, and evidence ledger for full KQ4.

  3207. Reported: “The focused verification is clean: 58 KQ4/save/table/spec tests pass, and both mdBooks build. I’m doing the full repository suite and a final wording/data audit now.”

    Action/result: Confirmed the focused tests and both documentation builds.

  3208. Reported: “The full suite passes: 362 tests, including the resource parsers, save maps, dispatch-table comparisons, renderer models, and book-content checks. No QEMU run was needed because every promoted difference was directly resolved in the disassembly.”

    Action/result: Completed the full local regression suite and retained disassembly as the primary evidence for this profile.

  3209. Reported: “The aggregate runner’s first invocation failed because I omitted the required AGI_GAME_DIR; resource-dependent modules correctly refused to import. This is the intentional no-default-game safeguard, so I’m rerunning with games/SQ2 explicitly selected.”

    Action/result: Classified the failed aggregate invocation as a command configuration error rather than a code regression.

  3210. Reported: “The explicitly configured aggregate manifest is clean: all 362 tests pass, both mdBooks build, and the generated opcode-evidence chapter is current.”

    Action/result: Wrote the successful local compatibility report to build/compatibility-suite/kq4_3002086_local.json.

  3211. Reported: “I’ll move directly into the highest-value remaining work: source-first analysis of the 2.411 and 2.440 interpreters, beginning with executable decoding and dispatch boundaries, then shared opcode handlers, renderer/object roles, and save dimensions.”

    Action/result: Began independent KQ2/2.411 and LSL1/2.440 analysis.

  3212. Reported: “The two targets have clean direct-resource sets, but their executable packaging differs: KQ2 has transformed AGI plus SIERRA.COM, while LSL1 has neither filename. I’m identifying LSL1’s executable before decoding anything.”

    Action/result: Identified LSL1 LL.COM as a complete 38 KiB MZ interpreter; decoded KQ2 AGI with its local loader key.

  3213. Reported: “The table comparison is unusually clean. Versions 2.411 and 2.440 have identical 170-action and 19-condition contracts; only restart handler 0x80 differs between them. Against 2.917, the investigation set is limited to a handful of handlers and the 0x97/0x98 table records.”

    Action/result: Generated KQ2/LSL1, KQ2/KQ1, and LSL1/KQ1 static reports.

  3214. Reported: “A deeper source read shows 0x97/0x98 physically consume four bytes in every build, although 2.411/2.440 record three in AGIDATA. The raw early count makes linear disassembly drift, so I’m correcting the analysis tool using handler-observed width.”

    Action/result: Added an effective operand-count rule and regression test for early configured-message actions.

  3215. Reported: “The local save files exposed and corrected an important detail: early block 1 is 0x05df, not 0x05e1. Relative to 2.917, the omitted tail is exactly the two-byte saved replay-checkpoint count.”

    Action/result: Corrected the early save map and confirmed the first four block lengths from two KQ2 and three LSL1 saves.

  3216. Reported: “The picture command dispatch tables reveal the first major 2.411/2.440 split. LSL1 already has the later pattern organization, while KQ2 routes pattern setup and plotting to shorter routines.”

    Action/result: Proved KQ2 0xf9 ignores its byte and 0xfa plots one pixel per coordinate pair.

  3217. Reported: “The complete role-pair report confirms the boundary cleanly: view loading, line/fill rasterization, object composition, collision, placement, animation, and motion match; only pattern behavior reaches different full-EGA output.”

    Action/result: Generated the 55-role KQ2/LSL1 subsystem report and classified nonobservable draw-state and embedded-table differences.

  3218. Reported: “Real-resource census adds a useful nuance: KQ2’s pictures never invoke 0xf9 or 0xfa; five LSL1 pictures use 0xfa but retain the default zero-radius mode.”

    Action/result: Recorded selected-game command usage separately from the interpreter’s valid-data capability.

  3219. Reported: “The high-level sound cache/load/start/stop paths match, but the low-level driver does not normalize to 2.936. I’m following the driver calls rather than assuming the later envelope model.”

    Action/result: Mapped early driver start, tick, stop, event output, and timer-hook entries in both builds.

  3220. Reported: “The early sound boundary is substantive: neither profile has attenuation envelopes; selector zero alone is single-channel; and 2.411 always writes both non-PC tone bytes while 2.440 conditionally suppresses the low byte.”

    Action/result: Added early channel, tone-byte, and attenuation-output switches to the local sound oracle.

  3221. Reported: “The focused model tests pass, including early single-pixel patterns, both real save families, and early sound outputs. Both profiles now have coverage across resources, opcodes, graphics, objects, sound, restart, and persistence.”

    Action/result: Passed 142 focused tests before spec promotion.

  3222. Reported: “I’m writing the clean profiles in portable terms now, keeping implementation evidence out of spec/; addresses and table anomalies remain in the evidence book.”

    Action/result: Added separate 2.411 and 2.440 behavioral profiles, conformance claims, and subsystem variants.

  3223. Reported: “The clean-spec promotion passes 152 focused tests and builds successfully. I’m completing the evidentiary half, then I’ll cross-check another game in the 2.917/2.936 families.”

    Action/result: Verified the profile specification and began final evidence/tracker updates.

  3224. Reported: “The evidence now separates executable packaging, table geometry, command targets, sound-driver variants, and save dimensions from the portable contracts.”

    Action/result: Updated the versions chapter, symbolic map, executable notes, and historical progress log for both early profiles.

  3225. Reported: “The early profiles are fully reflected in the evidence book, clean spec, symbolic map, and progress dashboard. I’m continuing with PQ1/2.917 and KQ3/2.936 same-version cross-checks.”

    Action/result: Advanced to additional-game profile validation.

  3226. Reported: “PQ1’s AGI is already MZ, while KQ3 uses the transformed loader-managed form. I’m decoding only KQ3 before same-version table comparison.”

    Action/result: Decoded KQ3 and preserved PQ1’s direct executable image.

  3227. Reported: “PQ1/KQ1 match all 174 actions and 19 conditions; KQ3/SQ2 match all 176 actions and 19 conditions, with zero normalized handler differences.”

    Action/result: Generated both same-version table reports.

  3228. Reported: “After removing MZ headers, PQ1/KQ1 differ by only three bytes and KQ3/SQ2 by two; those bytes are embedded game signatures. All 55 subsystem roles match at the same addresses.”

    Action/result: Established strong same-version executable equivalence apart from selected-game identity.

  3229. Reported: “PQ1 has 20 object records, 25 inventory entries, and 250 replay pairs; KQ3 has 17 records, 55 entries, and 127 pairs. I’m adding these as game-data dimensions, not behavioral variants.”

    Action/result: Added save helpers and tests for PQ1 and KQ3 dimensions.

  3230. Reported: “The same-version cross-check is complete. With all locally observed version families profiled, I’m building a reusable normalized role matcher for future relocated interpreters.”

    Action/result: Began generalizing call-target and handler role matching.

  3231. Reported: “The role matcher finds every KQ3/SQ2 subsystem role and returns KQ2’s known variants as review targets rather than false matches.”

    Action/result: Added tools/match_interpreter_roles.py, four tests, and generated KQ3/KQ2 role reports.

  3232. Reported: “I’m documenting the matcher and updating the tracker, then I’ll run the entire suite and both books as the natural stopping point for this extended pass.”

    Action/result: Updated AGENTS, cross-version workflow, current status, and remaining-work guidance for scalable future comparisons.

  3233. Reported: “The aggregate verification is clean: 374 tests pass, both books build, and opcode evidence is current. I’m removing one stale handoff sentence and completing the final repository audit.”

    Action/result: Wrote build/compatibility-suite/cross_version_profiles_local.json; confirmed no tracked or untracked change under games/ was produced by this work.

  3234. Reported: “I’ll pick up from the newly committed cross-version profiles, read the current completion dashboard and evidence trail, then take the highest-value unresolved items through disassembly, portable specification, and tests.”

    Action/result: Confirmed all current local interpreter inputs already belong to seven promoted profiles and narrowed the remaining work to source-visible behavioral edges and suite breadth.

  3235. Reported: “The dashboard is now mature: every known opcode and major subsystem has a portable contract, so the useful next move is not another broad sweep.”

    Action/result: Audited partial/remaining markers and selected source-first renderer/resource lifecycle work rather than speculative QEMU probing.

  3236. Reported: “There are no unanalyzed interpreter directories in the current local set; all nine inputs map to seven promoted profiles.”

    Action/result: Rechecked the local game census and graphics/symbolic-map coverage.

  3237. Reported: “One genuinely open source-backed area remains in the executable evidence: resource cache descriptors still contain under-described fields.”

    Action/result: Determined that the overlay descriptor field is unused by the runtime loader and does not justify a portable behavior rule.

  3238. Reported: “The descriptor gap is linker/startup bookkeeping rather than a game-visible cache rule.”

    Action/result: Reconfirmed that v3 combined-directory fallback and exact absent-entry behavior were already present in both evidence and spec.

  3239. Reported: “I’m running the normalized role audit across every promoted profile, not just the two examples used to develop the matcher.”

    Action/result: Generated SQ2-reference reports for KQ1, PQ1, KQ2, LSL1, KQ4, KQ4D, and GR. Every unmatched role maps to an existing documented profile delta or matcher-candidate limitation; no new variant emerged.

  3240. Reported: “I’m moving to a valid-script lifecycle edge that the current spec states too loosely: what happens to already-bound objects or active playback when a resource is discarded from its cache.”

    Action/result: Disassembled picture/view lookup, discard, and heap rewind routines and established ordered cache truncation.

  3241. Reported: “The discard routines reveal a substantive rule missing from the portable lifecycle: discard is stack-shaped, not an arbitrary map deletion.”

    Action/result: Confirmed selected-and-later same-family resources become unreachable; identified stale selected-payload use as outside the stable valid lifecycle contract.

  3242. Reported: “I’ve confirmed the exact list operation in both picture and view paths and across the promoted builds.”

    Action/result: Added the ordered-retention source model, focused tests, evidence notes, and clean behavioral contract.

  3243. Reported: “The focused model and spec checks pass. One documentation asymmetry showed up: the symbolic map had cross-version associations for view discard but no primary SQ2 role row.”

    Action/result: Added the missing primary symbolic role and structural spec checks for ordered picture/view discard.

  3244. Reported: “The implementation/model tests pass; the only failure is a structural assertion that treated a Markdown line break as semantic text.”

    Action/result: Made the clean-spec assertion whitespace-tolerant before broader verification; no behavioral model change was needed.

  3245. Reported: “Replay executes the same discard handlers, so kind 6 and 7 inherit ordered truncation; this matters for save/restore reproducibility and is now explicit rather than implicit.”

    Action/result: Connected ordered resource retention to restore replay, updated the dashboard/handoff, and prepared full local verification.

  3246. Reported: “The lifecycle work itself is clean, but I invoked the aggregate runner’s --name as a report label; in this tool it selects a registered command.”

    Action/result: Corrected the invocation and reran with --report only.

  3247. Reported: “The rerun exposed a real harness usability gap rather than a behavior failure: the default local suite launches tests that require an explicit game directory, but the runner has no --game-dir option.”

    Action/result: Added explicit --game-dir propagation and report metadata without introducing a default game; updated tests and commands.

  3248. Reported: “The runner fix passes its focused tests and the aggregate suite is now executing with games/SQ2 explicitly selected.”

    Action/result: The local layer passed 381 tests, both mdBooks, and opcode evidence checks; the JSON report records the selected game directory.

  3249. Reported: “The disassembler does accept --game-dir; the earlier failure was specifically bare --help, because the shared option is consumed before the script’s parser.”

    Action/result: Left the established shared-option architecture intact and ran all corpus commands with explicit game paths.

  3250. Reported: “Discard is not merely synthetic: every profile family uses it, with full KQ4 alone containing 201 picture/view discard actions.”

    Action/result: Generated all-game logic disassemblies and inspected discard contexts; no selected game uses variable-view action 0x99.

  3251. Reported: “The corpus clarifies why Sierra’s allocator discipline works: KQ2 logic 67 loads views 53,59,51,52,57,60 and later discards 60,57,52,51,59,53, exactly in reverse order.”

    Action/result: Recorded per-profile usage and the concrete LIFO sequence as game-data support for the source-derived ordered-retention rule.

  3252. Reported: “The repository audit is clean apart from the intended edits and pre-existing untracked run.sh/cache directories.”

    Action/result: Updated suite selection/report documentation and the current 381-test dashboard count before final aggregate verification.

  3253. Reported: “The final aggregate run is clean: 381 tests pass, both books build, and opcode evidence is current.”

    Action/result: Preserved the final report at build/compatibility-suite/local_ordered_resource_discard_final.json and moved to the immutable-input/diff audit without an unnecessary QEMU run.

  3254. Reported: “I’m picking up at the genuinely old interpreter pair now: SQ1 2.089 and XMAS 2.272.”

    Action/result: Resumed the expanded-game comparison after permissions were corrected; inventoried the seven new game directories and their executable/container forms.

  3255. Reported: “The XMAS directory is internally coherent, but it preserves three installation methods.”

    Action/result: Matched active XMAS files to the original variants and classified apparent missing-volume census errors as multi-disk packaging rather than malformed resources.

  3256. Reported: “The oldest action-table difference is now source-confirmed.”

    Action/result: Disassembled SQ1/XMAS action 0x86; established the zero-operand unconditional 2.089 exit and the one-operand 2.272 immediate/confirmed selector.

  3257. Reported: “The apparent XMAS menu support is another important version boundary.”

    Action/result: Mapped 0x9c..0xa0 to operand-advance stubs with no menu state and confirmed 0x9b as a two-byte no-op.

  3258. Reported: “The new save files add useful game-data coverage, but they also caught an assumption in our helper.”

    Action/result: Parsed BC, MG, and SQ1.22 original saves; identified MG’s metadata/save object-count discrepancy instead of forcing later metadata semantics onto it.

  3259. Reported: “The old OBJECT question is resolved for SQ1 and XMAS: those files are plain, not XOR-transformed.”

    Action/result: Parsed the raw headers and inventory tables, added a transform-neutral parser, and added regression tests for both old files.

  3260. Reported: “I have enough evidence for a first durable pass.”

    Action/result: Updated the evidence/version ledgers and clean spec, qualified old metadata transforms, added partial 2.089/2.272 profiles, and corrected the 3.002.149 room-alias generalization using MH2.

  3261. Reported: “The documentation pass now distinguishes three kinds of result cleanly: exact same-build behavior, mapped subsystem equivalence, and partial profiles.”

    Action/result: Updated symbolic labels and the high-level dashboard with the new build associations, confirmed equivalences, and specific next source-first investigations.

  3262. Reported: “Verification is clean now: all 389 local tests pass and both mdBooks build.”

    Action/result: Corrected the single new XMAS expected-name assertion, reran the complete suite successfully, built both books, and confirmed that private game files and generated artifacts are absent from the diff.

  3263. Reported: “One remaining question is cheap enough to answer now: whether MH1/MH2 scripts visibly reference any of the unreadable directory entries.”

    Action/result: Ran the existing reference audit; it exposed an abort-on- unreadable-logic limitation before producing a result.

  3264. Reported: “The audit itself exposed a harness assumption.”

    Action/result: Made the audit record and skip unreadable source logics, added a regression test, and retained the explicit limitation on conclusions drawn from skipped scripts.

  3265. Reported: “The revised audit gives a useful answer.”

    Action/result: Classified MH1 as incomplete due to six directly referenced unreadable views; classified MH2 as inconclusive because 31 unreadable logics remain despite no direct bad references in readable scripts.

  3266. Reported: “The final expanded-game pass is verified.”

    Action/result: All 390 local tests pass, both mdBooks build, and git diff --check reports no whitespace errors; no QEMU confirmation was needed because the promoted deltas are explicit disassembly observations.

  3267. Reported: “The audit found several dashboard omissions, not new behavioral discoveries.”

    Action/result: Expanded PROGRESS.md with the early plain/XOR metadata boundary, XMAS distribution packaging, BC/MG/SQ1.22 save dimensions, partial-profile opcode ranges, MH1/MH2 completeness results, additional symbolic-map coverage, and the now-repeated cross-version workflow.

  3268. Reported: “I’m starting with the two highest-value source questions.”

    Action/result: Began source-first SQ1 2.089/XMAS 2.272 picture, object, input, sound, and save comparisons, with the MG save discrepancy queued behind those profile maps.

  3269. Reported: “The role reports show XMAS is close enough.”

    Action/result: Generated full local 16-bit disassemblies and used the existing relocation reports to anchor corresponding early routines.

  3270. Reported: “The picture scanner reveals a larger early boundary.”

    Action/result: Proved that both early scanners dispatch only 0xf0..0xf8; 0xf9 and 0xfa do not exist as picture commands in profiles 2.089 and 2.272.

  3271. Reported: “Both old builds use the same automatic-loop rule.”

    Action/result: Proved that both select direction loops on every eligible post-logic pass, without the cadence-countdown gate introduced by 2.411.

  3272. Reported: “I’ve now got two concrete early-version differences to carry forward.”

    Action/result: Extended the source comparison into parser slot bounds, word matching, sound event output, and save construction before editing the specification.

  3273. Reported: “The input path is also separating cleanly by age.”

    Action/result: Mapped six string slots in both builds; SQ1 uses exact word-sequence counts without 0x270f, while XMAS implements the later tail terminator.

  3274. Reported: “The sound comparison has exposed another real version step.”

    Action/result: Distinguished SQ1 unchanged control-byte output, XMAS whole-byte adjustment with signed clamp, and the later low-nibble-only adjustment rule.

  3275. Reported: “The old save constructors are substantially different.”

    Action/result: Mapped SQ1’s four-block envelope and XMAS’s five-block envelope, including source-derived selected-data object and metadata lengths.

  3276. Reported: “I have enough source coverage to start promoting the findings.”

    Action/result: Added portable executable models and focused regression tests for picture command bounds, automatic loops, old word matching, sound-control output, and early save dimensions.

  3277. Reported: “The executable models are in place.”

    Action/result: Ran 153 focused tests successfully and resolved MG as an artifact-version mismatch: the historical save predates and contradicts the selected interpreter’s source-derived block lengths.

  3278. Reported: “The specification now has portable profile rules.”

    Action/result: Promoted the new behavior to the clean-room spec while retaining addresses, source traces, and file-date evidence only in the reverse-engineering book.

  3279. Reported: “Verification is clean.”

    Action/result: All 396 local tests passed, both mdBooks built, and git diff --check found no whitespace errors.

  3280. Reported: “The old block-1 tail is now partly recoverable.”

    Action/result: Partitioned replay capacity/count, 39 key mappings, six live strings, six reserved string records, and terminal text state. Corrected block 4 to use configured replay capacity rather than active occupancy; left the earlier scalar prefix explicitly partial.

  3281. Reported: “One correction surfaced during the final source-to-spec cross-check.”

    Action/result: Added the oldest drivers’ device-selector-2 attenuation adjustment to the model, tests, evidence, and specification before their profile-specific direct/whole-byte output steps.

  3282. Reported: “I’ll treat the deleted MG save as retired historical evidence.”

    Action/result: Split the MG regression into a current metadata-derived 91-record test and an optional historical-save comparison, removing any requirement that the private save remain present.

  3283. Reported: “The opcode-to-handler map gives us a better route through the unknown prefix.”

    Action/result: Traced saved scalar words through display, horizon, navigation, motion rectangle, direction coupling, picture preparation, replay, and key-map handlers.

  3284. Reported: “The prefix has resolved into a complete field partition.”

    Action/result: Added a dedicated 2.089/2.272 block-1 layout and local partition test instead of reusing later profile offsets and names.

  3285. Reported: “I’m promoting the completed save partition now.”

    Action/result: Promoted semantic offsets and round-trip preservation while leaving canonical initial bytes outside current binary-synthesis claims.

  3286. Reported: “I’m picking up at the remaining early-interpreter subsystem edges.”

    Action/result: Selected SQ1 2.089 versus XMAS 2.272 object redraw and update ordering as the next source-first comparison.

  3287. Reported: “The portable question is narrower than the implementation difference.”

    Action/result: Traced both temporary object-list representations through membership, key generation, tie handling, composition, and refresh.

  3288. Reported: “This comparison found a real visible version delta.”

    Action/result: Established that 2.089 draws the earlier partition in object-number order while 2.272 drawing-key sorts both partitions.

  3289. Reported: “I’ll encode that delta in the reusable ordering model and tests.”

    Action/result: Added the profile-selectable ordering model, regression test, and portable specification rule.

  3290. Reported: “I’ve now confirmed that frame advancement, collision, control-footprint acceptance, placement, dirty rectangles, and the movement loop itself match after relocation.”

    Action/result: Recorded that the old movement wrappers implement the 2.089 redraw architecture but do not alter movement-state transitions.

  3291. Reported: “The opcode-table triage leaves six shared-action differences that still need semantic classification before promotion.”

    Action/result: Read each remaining SQ1/XMAS shared handler difference and separated portable state/output effects from cleanup, diagnostics, and temporary storage changes.

  3292. Reported: “Two more early action deltas are now definite.”

    Action/result: Established that SQ1 actions 0x4d and 0x4e leave autonomous-motion mode active while XMAS clears it.

  3293. Reported: “The target-motion handlers expose another important early rule.”

    Action/result: Established that 2.089/2.272 defer their first target direction and completion calculation, unlike 2.411 and later.

  3294. Reported: “The early profile boundary is sharpening nicely.”

    Action/result: Traced early show-picture and object-distance semantics and identified retained f15/text-window state plus byte wrapping.

  3295. Reported: “The new regression checks pass.”

    Action/result: Confirmed the early save, object-ordering, distance, and specification regressions together after correcting source addresses.

  3296. Reported: “Inventory was the last major full-EGA surprise.”

    Action/result: Established that 2.089/2.272 inventory is always acknowledgement-only and that interactive v25 selection begins later.

  3297. Reported: “I’ll commit the completed early-profile work now.”

    Action/result: Folded the established inventory result into the evidence record and portable specification before verification and commit.

  3298. Reported: “Verification is running across the full compatibility tests and both books.”

    Action/result: All 400 local tests passed with one optional historical MG-save test skipped, both mdBooks built, and git diff --check passed.

  3299. Reported: “I’m resuming the early-profile completion pass from the committed state.”

    Action/result: Selected the remaining ordinary-EGA input, presentation, restart, and view-preview handler differences for source classification.

  3300. Reported: “The tracker still contains stale byte-map saves language.”

    Action/result: Confirmed the early semantic save map is complete and separated optional pristine synthesis from gameplay conformance.

  3301. Reported: “The normal EGA input paths line up.”

    Action/result: Reduced input configuration, number prompts, line state, refresh, and erase differences to alternate-mode or timing branches.

  3302. Reported: “The source coverage now supports promotion.”

    Action/result: Promoted 2.089 and 2.272 to full-EGA valid-data gameplay profiles while retaining explicit save-synthesis limitations.

  3303. Reported: “A cross-check found one stale persistence paragraph.”

    Action/result: Corrected the early save status to complete field/reserved assignment with caller-supplied pristine reserved-byte initialization, and added structural promotion regressions.

  3304. Reported: “The focused suite caught a useful structural detail.”

    Action/result: Kept the 2.272 binary-interchange claim name contiguous in Markdown so the conformance regression can identify it reliably.

  3305. Reported: “The early-profile promotion now passes its focused tests.”

    Action/result: Moved past incomplete MH inputs and audited current partial tracker entries for the next source-backed actionable task.

  3306. Reported: “The next concrete gap is in the suite manifest.”

    Action/result: Identified all-picture, movement, and overlay evidence that had passed separately but was absent from an aggregate suite layer.

  3307. Reported: “I’m adding a separate qemu-exhaustive layer.”

    Action/result: Added opt-in inherited exhaustive scheduling for all current picture, movement, and overlay original-engine cases.

  3308. Reported: “The exhaustive dry run is correct.”

    Action/result: Launched the first aggregate local, smoke, broad, and exhaustive original-engine compatibility run.

  3309. Reported: “The aggregate run has passed all 401 local tests.”

    Action/result: Confirmed both books and the initial parser snapshot cases before continuing into the remaining QEMU layers.

  3310. Reported: “The first aggregate run exposed a manifest dependency bug.”

    Action/result: Added deterministic fuzz-corpus generation as an explicit smoke prerequisite after the clean-build run lacked named fuzz cases.

  3311. Reported: “The corrected exhaustive run has reached the all-picture stage.”

    Action/result: Passed 403 local tests, both mdBooks, parser/fuzz smoke, all 8 broad pictures, all 19 view cases, and all 74 present pictures.

  3312. Reported: “The movement stage exposed a fixture-capacity limit.”

    Action/result: The unchunked 37-case movement disk filled while copying fixture 14; no interpreter mismatch caused the stop.

  3313. Reported: “I’m splitting object probes into snapshot chunks.”

    Action/result: Added reusable chunk-specific snapshot paths and ten-case movement/overlay batching without changing case semantics.

  3314. Reported: “The deterministic movement set reached 34 matches.”

    Action/result: The next autonomous-random case produced a stationary capture, which is valid because the selected random direction can be zero.

  3315. Reported: “I’m marking nondeterministic cases explicitly.”

    Action/result: Classified random_motion_visible_somewhere as exploratory and excluded it from the required exhaustive gate while retaining both deterministic random-motion clearing cases.

  3316. Reported: “The filter and manifest tests pass.”

    Action/result: Passed 25 focused tests and confirmed the new --deterministic-only command-line selection.

  3317. Reported: “The named object sweep is clean.”

    Action/result: Matched all 36 deterministic movement cases and all 24 overlay cases in chunked original-engine runs with no errors.

  3318. Reported: “I’m launching the complete inherited aggregate.”

    Action/result: Started one report covering local checks, both books, smoke/broad probes, all pictures, movement, and overlays.

  3319. Reported: “The aggregate’s local phase is clean.”

    Action/result: Passed 403 tests with one optional historical-save skip, built both mdBooks, and passed opcode-evidence checks.

  3320. Reported: “All smoke and broad semantics match.”

    Action/result: Regenerated the 1,062-case fuzz corpus and matched parser, picture-fuzz, 8-picture, and 19-view original-engine probes.

  3321. Reported: “All 74 picture resources matched inside the aggregate.”

    Action/result: Completed five chunked picture carousels without a disk prompt, mismatch, or capture error.

  3322. Reported: “The complete aggregate report passed all 15 commands.”

    Action/result: Recorded 36/36 deterministic movement and 24/24 overlay matches in build/compatibility-suite/qemu_exhaustive_001.json.

  3323. Reported: “The next actionable gap is the result adapter.”

    Action/result: Defined a language-neutral versioned bundle with canonical 160 by 168 EGA-index frame observations and SHA-256 digests.

  3324. Reported: “The spec guard caught an evidence-side tool path.”

    Action/result: Kept normative interchange semantics in spec/ and moved repository adapter commands exclusively to the evidence book.

  3325. Reported: “The first export exposed a private-input dependency.”

    Action/result: Removed game-resource imports from the adapter by making EGA capture normalization self-contained.

  3326. Reported: “The first portable reference bundle is complete.”

    Action/result: Exported 165 successful deterministic visual cases with 165 frame artifacts and self-compared all 165 with zero failures.

  3327. Reported: “The result adapter is hardened for independent producers.”

    Action/result: Added duplicate-ID, canonical-frame, artifact-digest, and producer-error validation; all focused adapter tests pass.

  3328. Reported: “Final verification is clean.”

    Action/result: Passed 408 local tests with one optional historical-save skip, built both mdBooks, checked opcode evidence, and passed the diff whitespace check.

  3329. Reported: “I’m auditing the next concrete resource gap.”

    Action/result: Selected KQ1’s four suspect sound-directory entries for source-first classification against the 2.917 volume reader.

  3330. Reported: “The KQ1 entries point beyond the selected volume.”

    Action/result: Decoded offsets 0x20e2f..0x2126b, all at least 43,812 bytes beyond VOL.2; ruled out an alternate sound-record format.

  3331. Reported: “The census now identifies out-of-volume offsets directly.”

    Action/result: Added a precise parser diagnostic and focused regression; 18 resource/census tests passed.

  3332. Reported: “I’m applying the same classification to KQ4D.”

    Action/result: Distinguished missing KQ4 volumes from KQ4D’s sound-table tail and inspected the reachable target bytes.

  3333. Reported: “KQ4D exposed an addressability bug in the local parser.”

    Action/result: Established that byte resource numbers make entries above 255 unreachable; prior pseudo-entries 387 through 661 were tool artifacts.

  3334. Reported: “Sound 198 is an accidental picture alias.”

    Action/result: Confirmed picture-nibble metadata, picture command bytes, and failure under the sound channel parser.

  3335. Reported: “The corrected resource audit passes.”

    Action/result: Passed 34 focused tests and reduced KQ4D to 15 unreferenced addressable bad-header entries plus the unreferenced picture alias.

  3336. Reported: “I’m scaling the portable bundle beyond SQ2.”

    Action/result: Selected eight completed Gold Rush source-mapped visual probes and mapped their cases/qemu report envelope.

  3337. Reported: “The v3 adapter needs path-safe artifact names.”

    Action/result: Separated stable probe/label IDs from sanitized, digest-suffixed artifact filenames after focused tests caught / paths.

  3338. Reported: “The first v3 reference bundle is clean.”

    Action/result: Exported 32/32 Gold Rush 3.002.149 cases with 32 artifacts and self-compared all cases with zero failures.

  3339. Reported: “Raw save digests would over-constrain independent engines.”

    Action/result: Kept nonvisual persistence output pending a semantic canonical form instead of requiring DOS-era serialized references.

  3340. Reported: “The complete verification pass is clean.”

    Action/result: Passed 414 tests with one optional historical-save skip, built both mdBooks, checked opcode evidence, and passed git diff --check.

  3341. Reported: “I’m auditing the partial core runtime contract.”

    Action/result: Compared spec/src/runtime_state.md against promoted input, object, sound, room, and persistence subsystem contracts.

  3342. Reported: “The first cycle stage is too vague.”

    Action/result: Identified that timer/sound IRQ work was incorrectly grouped with synchronous pacing and input processing.

  3343. Reported: “I’m reading the main-cycle instructions directly.”

    Action/result: Regenerated the decrypted SQ2 executable and disassembled image 0x0150, plus the six helpers called around the logic boundary.

  3344. Reported: “The cycle ordering and state lifetimes are now exact.”

    Action/result: Separated asynchronous ticks; mapped transient status, input, direction, pre-motion, logic re-entry, cleanup, and post-update phases; promoted core runtime coverage to complete.

  3345. Reported: “The first guard exposed a Markdown-wrapping assumption.”

    Action/result: Scoped the structural check to the cycle section and normalized whitespace so it tests the behavioral contract rather than source line breaks.

  3346. Reported: “The instruction-level cycle trail is now preserved.”

    Action/result: Recorded the reproducible disassembly command, direct call order, transient-state clears, re-entry branch, text-mode gate, and asynchronous-tick inference in the evidence book.

  3347. Reported: “The next locally actionable gap is portable nonvisual results.”

    Action/result: Chose the compatibility bundle’s frame-only implementation gap after classifying incomplete MH inputs and alternate display/IRQ work as blocked or conditional under the current target.

  3348. Reported: “The bundle now carries semantic values without engine layout.”

    Action/result: Added canonical JSON observations for deterministic state, input, ordered sound commands, and persistence outcomes, with recursive typed comparison and JSON Pointer difference paths.

  3349. Reported: “The complete local verification gate passes.”

    Action/result: Passed 418 tests before the final artifact-validation guard, with three optional generated-GR-save skips and the intentionally absent historical-MG-save skip; checked opcode evidence, built both mdBooks, and passed git diff --check.

  3350. Reported: “The result-format review tightened canonical validation.”

    Action/result: Rejected malformed known observations and statuses, required lowercase hexadecimal frame digests, and verified artifact length and EGA-index range in addition to content hashes.

  3351. Reported: “The tightened format passes the complete gate.”

    Action/result: Passed 419 tests with the same four expected optional skips, checked opcode evidence, built both mdBooks, and passed git diff --check after the final validation guard.

  3352. Reported: “The handoff summary had fallen behind the dashboard.”

    Action/result: Recorded the completed cycle and nonvisual-result work, marked deleted build/ paths as historical generated locations, and restored the incomplete MH1/MH2 resource-set blocker to the next-work summary.

  3353. Reported: “The trace has narrowed this down nicely.”

    Action/result: Confirmed that SQ2 prepared and inverted the correct glyph and redirected vector 43h, while the VGA BIOS call never read the redirected scratch bytes.

  3354. Reported: “I’m moving to the targeted workaround now.”

    Action/result: Selected an alternate VGA option ROM as the narrow test; the system BIOS and immutable game input remained unchanged.

  3355. Reported: “The legacy ROMs are downloaded and checksum-pinned.”

    Action/result: Downloaded official LGPL VGABIOS 0.7a standard and Cirrus binaries into disposable build/ output and recorded their SHA-256 values.

  3356. Reported: “I’m testing the standard VGA variant first.”

    Action/result: Booted FreeDOS with the stock 0.7a standard VGA option ROM, advanced SQ2 to its first inverse dialog, and captured the same repeated glyph corruption.

  3357. Reported: “Merely swapping SeaVGABIOS for an older binary is not enough.”

    Action/result: Rejected VGA BIOS age alone as the cause and focused the requirement on honoring the current INT 43h vector at glyph-draw time.

  3358. Reported: “I’m inspecting the firmware’s AH=09h path now.”

    Action/result: Downloaded the matching VGABIOS source and found that its planar, CGA, and linear graphics character paths use private font arrays.

  3359. Reported: “There is enough unused space inside the ROM.”

    Action/result: Located verified option-ROM padding and designed a small planar EGA fetch routine that reads font offset/segment from vector 43h while retaining the existing pixel renderer.

  3360. Reported: “I’m adding a reproducible patch builder.”

    Action/result: Added a pinned validator/patcher and NASM source with source checksum, exact call-site, empty-area, size, and final ROM checksum guards.

  3361. Reported: “The patched VGA BIOS works.”

    Action/result: Booted QEMU with the generated ROM and advanced SQ2 to the first playable-room dialog; all inverse text rendered as distinct, readable black-on-white glyphs without FIXAGI.COM.

  3362. Reported: “The root cause is confirmed as VGA BIOS behavior.”

    Action/result: Classified QEMU’s bypass of the live font vector as the compatibility fault; no game executable, resource, DOS image, or system BIOS patch is required.

  3363. Reported: “I’m turning this into a durable project setup now.”

    Action/result: Added patcher tests, README/manual QEMU instructions, compatibility guidance, and the complete static/dynamic evidence trail.

  3364. Reported: “I’ll put the experimental FIXAGI helper back into a non-dangerous state.”

    Action/result: Restored PAM0 to readable/write-protected mode after the corrected font-copy verification and documented that this utility cannot repair a VGA BIOS that ignores vector 43h.

  3365. Reported: “The durable change is scoped to the analysis environment.”

    Action/result: Kept the downloaded and patched ROM under disposable build/, with only its deterministic generator, patch source, tests, and documentation entering the repository.

  3366. Reported: “The focused tests and both mdBooks pass.”

    Action/result: Passed the three patcher guards, rebuilt a byte-identical corrected ROM with SHA-256 cfbbc5e3...f01247, built both books, and passed the whitespace check.

  3367. Reported: “The automated QEMU harnesses currently launch the bundled VGA BIOS.”

    Action/result: Audited all direct QEMU command construction sites and identified a common launch-argument helper as the smallest durable integration point.

  3368. Reported: “I’m adding one launch-argument helper.”

    Action/result: Made harnesses automatically select the generated corrected ROM when present, with explicit environment controls for an alternate ROM or the QEMU default.

  3369. Reported: “The harness integration passes 45 focused tests.”

    Action/result: Passed snapshot, picture/view carousel, fuzz, save/restore, patcher, and environment-selection tests after the shared launch change.

  3370. Reported: “I’m running the full local compatibility gate now.”

    Action/result: Passed all 425 local tests with four expected optional fixture skips, the full compatibility runner, both mdBooks, opcode evidence checks, deterministic ROM comparison, and whitespace checks.

  3371. Reported: “I’ll make the unmodified VGABIOS a tracked third-party input.”

    Action/result: Established the artifact policy: track the pristine ROM, license, provenance, patch source, and builder while keeping the patched derivative exclusively under ignored build/.

  3372. Reported: “I’ve confirmed the redistributable input is the official LGPL VGABIOS 0.7a standard ROM.”

    Action/result: Copied the exact 41,472-byte upstream binary and LGPL 2.1 text under third_party/vgabios/ and reverified SHA-256 cd9fdd6a...246c6.

  3373. Reported: “The build flow will no longer depend on a network download.”

    Action/result: Changed the builder to consume and validate the tracked pristine ROM, require a 44-byte assembled patch, verify source and output digests, and atomically emit only the generated ROM under build/.

  3374. Reported: “The normal FreeDOS setup will invoke that step.”

    Action/result: Integrated VGA BIOS build/verification into setup_freedos_image.py, with --skip-vgabios reserved for intentional bundled-firmware control environments.

  3375. Reported: “The artifact boundary is now explicit.”

    Action/result: Added upstream binary/source URLs and checksums, the LGPL text, generated-output policy, and deterministic patched digest to the repository and operational documentation.

  3376. Reported: “I’m adding a dedicated evidence-book chapter next.”

    Action/result: Added a self-contained chapter covering symptoms, rejected hypotheses, decisive trace, patch map, artifacts, reproduction, validation, troubleshooting, and license/source availability.

  3377. Reported: “I’m doing the final end-to-end verification now.”

    Action/result: Built a separate temporary FreeDOS image through the integrated setup path without touching the populated manual image, then passed all 427 tests with four expected skips, the complete compatibility runner, both mdBooks, opcode evidence, and whitespace validation.

  3378. Reported: “I’m staging the complete reproducible solution now.”

    Action/result: Staged the pristine upstream BIOS, license/provenance, patch source and builder, FreeDOS/harness integration, tests, dashboard, and operational/evidence documentation while excluding generated output and unrelated local files.

  3379. Reported: “The upstream license text contains formatting artifacts.”

    Action/result: Removed one whitespace-only line and the extra final blank line from the license copy so the staged repository passes its whitespace gate without changing the license wording.

  3380. Reported: “I’ll rebuild the FreeDOS image from scratch.”

    Action/result: Confirmed the previous generated image was 32 MiB and enumerated 16 top-level private game directories for the requested copy.

  3381. Reported: “I’m checking the available disk-formatting tools.”

    Action/result: Confirmed mtools supplies partition-aware FAT formatting and boot-sector templating, allowing a host-side reproducible large image without an interactive DOS installation.

  3382. Reported: “I’m going to make the builder create a fresh 1 GiB disk.”

    Action/result: Added active FAT16-LBA MBR construction, enlarged FAT16 formatting, source boot-code preservation, full FreeDOS tree transfer, atomic output replacement, and configurable 64-2048 MiB sizing.

  3383. Reported: “The geometry tests pass.”

    Action/result: Added deterministic tests for the 1 GiB partition entry, CHS encoding/saturation, active/type/LBA fields, and invalid source MBRs.

  3384. Reported: “The setup process is still downloading in the background.”

    Action/result: Observed the slow transfer through its temporary filename; the atomic downloader prevented the partial archive from being accepted as the persistent FreeDOS cache.

  3385. Reported: “The 1 GiB FAT16 volume is populated.”

    Action/result: Copied all 16 game directories, matched every recursive host/DOS file count, and measured 1,009,057,792 bytes free afterward.

  3386. Reported: “I’m doing the final boot test.”

    Action/result: Booted the enlarged type-0x0e image with the patched VGA BIOS and reached the FreeDOS C:\> prompt; recorded the benign legacy CHS consistency warning for this LBA volume.

  3387. Reported: “I’m running the full local test suite and both mdBooks now.”

    Action/result: Passed 431 tests with four expected optional-fixture skips, built both mdBooks, checked opcode evidence and whitespace, and retained the populated boot-tested 1 GiB image as disposable build output.

  3388. Reported: “I’ll regenerate the 1 GiB FreeDOS image.”

    Action/result: Rebuilt the deleted FreeDOS image and patched VGA BIOS from tracked inputs using the committed large-image setup path.

  3389. Reported: “The FreeDOS download is still in progress.”

    Action/result: Allowed the atomic temporary-cache transfer to complete; no partial ZIP or disk image was exposed as a completed artifact.

  3390. Reported: “The image is rebuilt and populated.”

    Action/result: Copied all 16 top-level private game directories, matched every recursive host/DOS file count, confirmed the exact 1 GiB raw size, and measured 1,009,057,792 bytes free on the resulting FAT volume.

  3391. Reported: “I’m resuming from the resource census and the opening-route reconstruction.”

    Action/result: Resumed the SQ1.22 game-specific playthrough detour from canonical resources and divided the remaining analysis into Kerona, Ulence Flats, and Deltaur phases.

  3392. Reported: “The indexer has already exposed a useful fact: the game declares 202 as the maximum, while all positive award sites sum to 221.”

    Action/result: Enumerated all score mutations, confirmed logic 104’s maximum-score assignment, and identified mutually exclusive awards, reversible awards, and penalties that prevent a naive positive-site sum from describing a playable route.

  3393. Reported: “The Kerona route is resolving into two distinct puzzle chains.”

    Action/result: Source-traced the survival-kit expansion, Orat water solution, spider-droid boulder sequence, rock/geyser point reversal, acid traversal, reflective-glass barrier, Orat proof handoff, cartridge reader, and skimmer departure.

  3394. Reported: “The city phase shows the intended economy rather than a direct corridor.”

    Action/result: Reconstructed the skimmer sale, three-beer sector-HH clue, random slot-machine funding dependency, correct flight-droid and cruiser purchases, mutually exclusive ship-price branches, droid load, and sector entry.

  3395. Reported: “I have enough structure to start preserving the result.”

    Action/result: Added a dedicated SQ1.22 playthrough-analysis chapter, indexed it in the evidence mdBook, promoted the workstream to PROGRESS.md, and changed the analysis index to extract maximum-score assignments directly from logic actions.

  3396. Reported: “The score discrepancy is now narrower and more informative.”

    Action/result: Proved that the two ship awards and two vent-entry awards are mutually exclusive, retained the required rock-taking deduction, and isolated the remaining over-202 ambiguity to reachable Deltaur and optional-interaction branches rather than forcing an unsupported ledger.

  3397. Reported: “I’m rendering the remaining room pictures as a navigation cross-check.”

    Action/result: Rendered the present pictures from 34 through 65 into a disposable contact sheet, visually confirming Ulence exteriors, the Deltaur approach and corridor families, the Star Generator chamber, launch bay, ending scene, and numeric self-destruct keypad. Missing picture numbers 40, 44, and 63 were absent canonical entries rather than renderer failures.

  3398. Reported: “A shared one-time flag resolves the largest ambiguity.”

    Action/result: Proved the five-point boulder and ten-point cave outcomes are alternative Orat/spider resolutions, identified penalty-free rock acquisition in room 25, corrected the required first Keronian audience, and derived the designed score equation 221 - 4 - 2 - 10 - 3 = 202. Isolated a possible 205/202 overscore if both guard-defeat awards can coexist.

  3399. Reported: “I’m doing a full local verification pass now.”

    Action/result: The focused SQ1.22 message-decoder/index checks passed. A first whole-suite run selected SQ1.22 globally and demonstrated that legacy corpus/hash tests are intentionally SQ2-specific; rerunning with the intended SQ2 fixture passed all 432 tests with four optional-fixture skips, both mdBooks, opcode-evidence validation, and whitespace checks.

  3400. Recorded: Final static route refinements.

    Action/result: Added phase score checkpoints 61, 110, 153, and 202, and included the three separately scored disguised-guard interactions: talk, kiss, and answering yes to the King’s Quest II ownership question.

  3401. Reported: “I’ll apply the same resource-only method to SQ2.”

    Action/result: Selected games/SQ2 explicitly and began reconstructing its route from local logic, message, vocabulary, object, picture, and view resources without consulting external game material.

  3402. Reported: “SQ2 immediately exposed a corpus edge.”

    Action/result: Found that logic-directory entry 141 names VOL.0:0x1ffff, where no valid resource header exists. Changed the playthrough indexer to preserve the unreadable-entry evidence and continue indexing all readable resources.

  3403. Reported: “The SQ2 profile is now indexed.”

    Action/result: Indexed 118 readable logics, 2,472 parser conditions, 182 room transitions, 70 score mutations, and 40 inventory slots. Confirmed logic 104 assigns the maximum score of 250.

  3404. Reported: “The score structure is already beginning to close.”

    Action/result: Grouped the score sites by story phase and traced their parser, inventory, room, and flag guards to distinguish cumulative awards from duplicate parser branches and alternative puzzle solutions.

  3405. Reported: “The score ledger now closes exactly.”

    Action/result: Proved that the 283 positive score sites reduce to the declared 250 after excluding 33 points from alternate airlock, spore, rope, gem, stone, and platform-guard branches. No negative score action is required by the designed route.

  3406. Reported: “The full static story path is now coherent.”

    Action/result: Reconstructed the route through XOS 4, Labion, Vohaul’s asteroid, clone-launch cancellation with code SHSR, escape-pod launch, and terminal suspended animation in logic 93, with phase checkpoints 10, 166, and 250.

  3407. Reported: “I’ve completed the first static SQ2 route reconstruction and am tightening the score ledger now.”

    Action/result: Reviewed the preserved chapter against the extracted event groups and found two transcription errors confined to its compact numeric ledger, not the route or phase totals.

  3408. Reported: “The chapter’s narrative route is sound, but the compact numeric ledger has two transcription mistakes.”

    Action/result: Corrected the Labion and asteroid award lists. An apparent duplicated inventory loop was then checked against the source directly.

  3409. Reported: “One correction to my last update.”

    Action/result: Confirmed the apparent duplicated inventory loop came from overlapping terminal excerpts, not the source file. The indexer already emits each of SQ2’s 40 inventory slots exactly once.

  3410. Reported: “I’m updating three things together.”

    Action/result: Promoted the SQ2 250-point candidate and remaining replay work into PROGRESS.md, and aligned the highest-value work queue with both SQ1.22 and SQ2 playthrough validation.

  3411. Reported: “The corrected ledger now sums mechanically.”

    Action/result: Verified 10 + 156 + 84 = 250 independently, then enumerated the 75 present picture-directory entries for a visual route cross-check.

  3412. Reported: “The visual sweep rendered all 74 valid SQ2 pictures.”

    Action/result: Rendered 74 pictures without error and found that picture 147 points to an invalid resource header at VOL.0:0x2ffff. Preserved it as unreadable directory evidence parallel to logic 141 rather than treating bytes outside a valid record as picture semantics.

  3413. Reported: “The contact sheet corroborates the route’s geography.”

    Action/result: Visually checked the Labion forest, swamp, cave, shuttle, asteroid, Vohaul machinery, ruptured tube, pod-bank, and escape-pod families. Recorded that pictures 140 through 146 are title/interface imagery and marked the picture-rendering validation step complete.

  3414. Reported: “The regenerated index reproduces every claimed count exactly.”

    Action/result: Rebuilt the SQ2 JSON index and independently confirmed 118 readable logics, 2,472 parser conditions, 182 transitions, 70 score events, 40 inventory slots, one unreadable logic entry, and logic 104’s 250-point maximum assignment.

  3415. Reported: “I’m at the verification pass now.”

    Action/result: Ran the focused message/table tests, all 432 local tests with four expected optional-fixture skips, both mdBook builds, the SQ2 opcode-evidence check, and the whitespace check successfully.

  3416. Reported: “Everything passes.”

    Action/result: Completed the final review while preserving the boundary between the resource-proven static route and the exact movement, hazard-timing, and parser-input stream still requiring original-engine replay.

  3417. Reported: “I’ll apply the same clean-room, resource-only reconstruction to games/KQ1.”

    Action/result: Began a KQ1 maximum-score route reconstruction from local logic, message, vocabulary, object, picture, and view resources, with generated artifacts confined to build/ and no changes to private game inputs.

  3418. Reported: “KQ1 indexes cleanly.”

    Action/result: Indexed 90 readable logic resources, 1,478 parser conditions, 277 room transitions, 180 score mutations, and 27 inventory slots. Confirmed logic 0 declares a 158-point maximum; all positive score sites sum to 269 before duplicate, reversible, and alternative branches are resolved.

  3419. Reported: “The 158-point structure is resolving into three treasure chains.”

    Action/result: Reconstructed the mirror chain through the well and dragon, the shield chain through the witch, rat, and leprechauns, and the chest chain through the gnome, beanstalk, and giant. Static score branches consistently assign more points to nonviolent water, food, music, and sleep solutions than to destructive or treasure-surrender alternatives.

  3420. Reported: “The score ledger now closes at 158.”

    Action/result: Distinguished show carrot from give/feed carrot in the parser branches. Showing it awards five points while retaining the two-point carrot; giving it first subtracts those two points. Combined with net water, bowl, cheese, and mushroom exchanges, the selected static route now totals exactly the declared maximum.

  3421. Reported: “The route topology is now coherent.”

    Action/result: Traced the condor’s jump/contact animation through room 80 to room 48, the fall into rooms 73 through 78, and the rat/leprechaun complex. Separated that shield route from the independently planted beanstalk route to the giant’s cloud region, and identified the high-score mushroom exit from room 78 to room 36.

  3422. Reported: “All 82 present KQ1 pictures render successfully.”

    Action/result: Rendered the complete present picture set and visually corroborated the surface map, well and dragon caves, condor landing, underground complex, beanstalk/cloud region, giant territory, castle return, and ending imagery. Pictures 83 and 84 are title/transition assets rather than traversable rooms.

  3423. Reported: “I now have enough corroborated structure to preserve the complete static candidate.”

    Action/result: Added a dedicated KQ1 playthrough-analysis chapter, indexed it in the evidence mdBook, promoted the 158-point candidate and remaining replay work into PROGRESS.md, and expanded the highest-value queue to cover all three game-level candidate playthroughs.

  3424. Reported: “The preserved ledger checks mechanically.”

    Action/result: Independently summed phase totals 4 + 79 + 23 + 23 + 25 + 4 = 158 and applied alphabet mirroring to the local parser token ifnkovhgroghprm, yielding rumplestiltskin without relying on an external solution source.

  3425. Reported: “I’m running the same verification gate used for SQ1.22 and SQ2 now.”

    Action/result: Ran 15 focused KQ1 decoder/table tests, all 432 SQ2-based regression tests with four expected optional-fixture skips, both mdBook builds, the opcode-evidence check, and the whitespace check successfully.

  3426. Reported: “Verification is clean.”

    Action/result: Completed the final diff review while retaining a clear distinction between the resource-proven 158-point route and the exact movement, command, random-event, and timing stream still requiring an original-interpreter QEMU replay.

  3427. Reported: “I’ll apply the same resource-only method to games/KQ2.”

    Action/result: Began a KQ2 maximum-score route reconstruction from local logic, message, vocabulary, object, picture, and view resources, keeping private game inputs immutable and generated analysis under build/.

  3428. Reported: “KQ2 indexes cleanly as a larger game.”

    Action/result: Indexed 133 readable logics, 1,406 parser conditions, 290 room transitions, 82 score mutations, and 35 named inventory objects in slots 50 through 84. Confirmed logic 180 assigns the 185-point maximum; positive score sites sum to 222 before alternate and consumed-item branches are resolved.

  3429. Reported: “The route is organizing around three key quests and a final rescue world.”

    Action/result: Identified high-value branches using flowers for the mermaid, returning Neptune’s trident, transforming the snake with the bridle, recovering the covered nightingale for the lamp, using disguise or the cross at the poisoned lake, helping Grandma with soup, feeding the lion ham, and rescuing the golden fish. Lower-valued violent and treasure- payment branches remain separate negative conformance cases.

  3430. Reported: “I’ve got the three-key structure and the major alternate- solution branches.”

    Action/result: Began closing the exact 185-point ledger by tracing the variable Dracula bonus, Neptune’s trident sequence, duplicate candle sites, and the five final-world fish awards rather than assuming every positive score site can coexist.

  3431. Reported: “The score equation exposed an important branch detail.”

    Action/result: Proved that returning Neptune’s trident for four points and waving it personally for two points are alternatives: either action opens the clam and sets the same one-time state. Continued tracing the shared three-point variable through logic 67 to determine which bonus applications belong to the winning Dracula sequence.

  3432. Reported: “The 185-point equation now closes exactly.”

    Action/result: Proved that the ruby ring and black cloak share one three-point disguise-completion award, and identified the variable bonuses as three points for resolving Dracula plus five on first reaching Valanice. With mutually exclusive branches removed, the declared route totals exactly 185.

  3433. Reported: “The visual sweep rendered all 108 present KQ2 pictures.”

    Action/result: Rendered every present picture without a record error and built a disposable contact sheet. The images corroborate the Kolyma map, underwater kingdom, mountain and castle quests, iridescent final world, and quartz-tower ending geography.

  3434. Reported: “One static edge case is important enough not to bury.”

    Action/result: Found that logic 48 clears its side markers after each one-point bridge traversal and checks for collapse only when the traversal counter is already greater than six. Recorded 191 as an original-engine overscore hypothesis alongside the exact declared-max 185 route.

  3435. Recorded: Preserved the KQ2 static playthrough reconstruction.

    Action/result: Added the dependency-ordered three-key route, exact score ledger, terminal wedding state, lower-scoring alternatives, deaths and dead ends, picture evidence, bridge hypothesis, and replay requirements to a dedicated evidence chapter and the project progress tracker.

  3436. Reported: “The documentation and tracker updates are in place.”

    Action/result: Regenerated the KQ2 index; all 15 focused message/table tests passed. The full SQ2-anchored suite passed all 432 tests with four expected optional-fixture skips, both mdBooks built, opcode evidence remained synchronized, and whitespace validation passed.

  3437. Reported: “I’ll apply the same clean-room, resource-only workflow to games/KQ3.”

    Action/result: Began a KQ3 maximum-score winning-route reconstruction from local logic, message, vocabulary, object, picture, and view resources. Kept the private game input immutable and reserved QEMU for later validation of ambiguities and an exact replay.

  3438. Reported: “KQ3 is larger and much more parser-heavy than the earlier King’s Quest games.”

    Action/result: Indexed 125 readable logics, 2,994 parser conditions, 277 room transitions, 67 score mutations, and 55 inventory slots with no decode failures. Confirmed logic 101 declares a 210-point maximum and began separating raw ingredients, transformed spell products, and the wizard-supervision timing state.

  3439. Reported: “The score ledger has a clean shape.”

    Action/result: Summed 215 positive score-site points and proved that the two four-point logic-14 branches and two one-point dog-fur branches are same-result alternatives. Excluding those duplicate five points yields the declared 210. Confirmed all seven successful spell preparations are independent, one-time ten-point events.

  3440. Reported: “The full route now resolves into four coherent acts.”

    Action/result: Reconstructed the wizard-house stealth/timed-chore phase, Llewdor ingredient and seven-spell phase, poisoned-porridge liberation, and pirate/mountain/Daventry finale. Identified logic 74’s family reunion as the terminal completion sequence after the four-point castle entry.

  3441. Reported: “All 97 present KQ3 pictures render successfully.”

    Action/result: Built a disposable contact sheet and visually confirmed Manannan’s house/laboratory, Llewdor, bandit tree, pirate ship, landing beach, snowy mountain labyrinth, ruined Daventry, dragon cloud land, and restored castle. Found no malformed picture-directory entry.

  3442. Reported: “I have enough evidence to preserve the KQ3 result.”

    Action/result: Added a dedicated evidence chapter covering the timed-safe house strategy, all scored acquisitions, seven exact spell recipes, poisoned-porridge liberation, pirate/mountain/dragon route, 210-point ledger, terminal assertions, deaths, dead ends, and replay requirements. Added KQ3 to the project tracker and evidence-book summary without promoting game-specific material into the portable specification.

  3443. Reported: “The route and ledger are now documented.”

    Action/result: Regenerated the KQ3 index and passed all 15 focused message/table tests. The full SQ2-anchored suite passed all 432 tests with four expected optional-fixture skips; both mdBooks built, opcode evidence remained synchronized, and whitespace validation passed.

  3444. Reported: “I’ll do the full games/KQ4 next with the same evidence standard.”

    Action/result: Began a KQ4 maximum-score winning-route reconstruction from its local interpreter profile and canonical resources. Kept the private game directory immutable and directed generated indexes and renders to build/playthrough/kq4.

  3445. Reported: “KQ4 is the full 3.002.086 v3 build, not the later demo.”

    Action/result: Confirmed the combined KQ4DIR/prefixed-volume profile. The first index pass exposed a message-table decoding failure at message 148; began distinguishing a malformed/missing-volume record from an incorrect v3 decoding assumption before altering the reusable indexer.

  3446. Reported: “I’m narrowing the failure before touching the decoder.”

    Action/result: Scanned every present KQ4 logic record. The failures affected many dictionary-expanded records rather than one damaged resource. Raw expanded message regions contained readable text while unconditional XOR produced the missing terminators.

  3447. Reported: “The raw KQ4 records resolve the ambiguity.”

    Action/result: Compared KQ4 and GR direct/dictionary-expanded records. KQ4 has 174 expanded and three direct logic records; the direct records’ message text requires the repeating key while expanded records are already plain. GR exhibits the same storage-dependent distinction.

  3448. Reported: “The executable confirms the exact rule.”

    Action/result: Read KQ4 image 0x30f7..0x3365 and logic setup 0x13d9..0x1498. A direct read sets word [0x0f5e] to one, dictionary expansion clears it, and logic setup calls the repeating-key XOR helper only when that word is nonzero. Updated the disassembler/indexer to select message decoding from the record transform and added a plain-text decoder test.

  3449. Reported: “The corrected pass is clean: all 177 present KQ4 logics decode.”

    Action/result: Generated the complete KQ4 logic/message index: 5,148 parser predicates, 469 room transitions, 86 score-changing sites, no unreadable logic, and declared maximum score 230. Began clustering score events and ordering story dependencies.

  3450. Reported: “The score ledger now reconciles exactly.”

    Action/result: Distinguished alternate room copies from sequential awards. Lolotte’s three completed errands each award seven points, while the board’s first two successful crevice crossings each award two. The resulting intended ledger totals exactly 230.

  3451. Reported: “The first picture sweep exposed another reusable-tool assumption rather than a KQ4 defect.”

    Action/result: Found agi_graphics.py still opened v2 split directory names directly. Routed picture/view lookup through the established version-aware resource reader so v3 combined directories and expanded records can be rendered without special-case copies.

  3452. Reported: “The v3 payload routing works, but the render attempt found a second, narrower limitation.”

    Action/result: Confirmed the patterned-brush tables still use SQ2 image offsets. The SQ2 graphics baseline passed all 91 focused tests. Rendered a clearly qualified brush-disabled KQ4 contact sheet with all 146 locally readable pictures; pictures 150–151 remain unavailable with missing KQ4VOL.6.

  3453. Reported: “The dependency graph is now coherent enough to preserve.”

    Action/result: Reconstructed the maximum route through trading, ocean, haunted manor, crypt, swamp, three Lolotte errands, castle escape, and ending. Identified the crown-then-recatch frog sequence as necessary to retain both its direct two-point award and separate five-point kiss sequence.

  3454. Reported: “I’m writing the evidence chapter with that non-obvious branch.”

    Action/result: Added the full KQ4 playthrough chapter, 230-point grouped ledger, global timing/resource constraints, death/dead-end inventory, and deterministic replay requirements. Added KQ4 to the evidence-book summary and high-level tracker without promoting game-specific material into the portable specification.

  3455. Reported: “Verification is clean.”

    Action/result: Confirmed expanded logic 0 decodes its King’s Quest IV version message and direct logic 97 decodes Like a heavy blanket, darkness enfolds you. Regenerated the 177-logic index. The full suite passed 433 tests with four expected optional-fixture skips; both mdBooks, opcode-evidence synchronization, and whitespace validation passed.

  3456. Reported: “I’ll apply the same resource-only maximum-score reconstruction to games/GR.”

    Action/result: Began a clean-room Gold Rush analysis from the local game resources only. Selected the v3 combined-resource reader and generated a disposable logic/message index under build/playthrough/gr/ without modifying the immutable game directory.

  3457. Reported: “The first pass is unusually rich: all 182 present logics decode. There are two apparent score ceilings.”

    Action/result: Decoded all 182 readable logic resources with no failures and indexed 6,227 parser predicates, 431 room transitions, and 150 score mutations. Found the normal startup maximum of 250 and a route-specific later assignment of 255.

  3458. Reported: “The 255 ceiling is deliberate. The game explicitly raises it on the Cape Horn branch.”

    Action/result: Traced the cheap-ticket purchase branch in logic 3 to a nine-point award and an explicit maximum-score change to 255. Correlated this with the arrival checkpoint that reports 100 points for Cape Horn and 95 for the other routes, establishing Cape Horn as the required route for the highest terminal score.

  3459. Reported: “The Cape Horn score structure now reconciles cleanly.”

    Action/result: Reconstructed the 40 voyage points as five three-point fishing-tool components, seven points for the Bible interaction, eight for catching the fish, five for completing the rescue promptly, two for the storm repair, and three for safely eating an early piece of ham. Identified duplicate room/state award sites and the later diseased-ham death branch so they are not double-counted.

  3460. Reported: “The direct assignments resolve the numeric mapping but expose a useful correction.”

    Action/result: Traced route variable values through their downstream narration instead of relying on the purchased item’s apparent purpose. Corrected the provisional route label: route value 2 is Panama, requires mosquito netting, invokes the Panamanian-jungle logic, and carries the 255-point maximum; route value 1 is Cape Horn and requires oranges. Consequently the previously grouped 40-point ship ledger belongs to the Cape voyage and cannot be used as the maximum-route Panama ledger.

  3461. Reported: “The Panama phase now closes exactly.”

    Action/result: Reconciled the Panama crossing as four points for cooperating with the armed group, four for the ant/vine escape, seven for the resting traveler’s Bible, five for the highest traversal branch, ten for the ancient gold disk, and ten for the stream crossing. These 40 points carry the route from the Brooklyn 60 checkpoint to the explicit California-arrival 100 checkpoint.

  3462. Reported: “The full score arithmetic now reconciles.”

    Action/result: Identified the apparent four-point Brooklyn excess as the ferry sequence used by the overland route, not the Panama ship departure. Traced logic 110’s gold progression to a shared 70-award cap and separated Psalm 23’s five points from the arrival checkpoint. The resulting route totals 60 Brooklyn, 40 Panama, 5 Psalm, 80 California one-time, and 70 gold-progression points, or 255.

  3463. Reported: “All 186 present GR pictures decode in the brush-disabled qualitative mode.”

    Action/result: Added an explicit --no-pattern-brushes option to the reusable picture CLI and generated a disposable contact sheet. It corroborates Brooklyn, ship and jungle travel, Sacramento, Sutter’s Fort, hotel, mule, cabin, and mine geography without claiming pixel fidelity from still-unmapped v3 patterned-brush tables.

  3464. Reported: “I’m writing the evidence chapter now.”

    Action/result: Added the Gold Rush playthrough chapter with the static Panama route, 255-point grouped ledger, timing and inventory constraints, death/dead-end families, and original-interpreter replay requirements. Linked it into the evidence book and added GR to the high-level progress tracker and replay backlog.

  3465. Reported: “The hotel coin consistency check supports the route.”

    Action/result: Confirmed logic 12 materializes the hotel-room coin from its persistent Brooklyn discovery flag rather than requiring its current inventory location, leaving the one-point recovery available after the Panama robbery sequence. Rebuilt the GR index, exercised the new renderer flag, built both mdBooks, checked opcode evidence and whitespace, and ran 433 tests with four expected optional-fixture skips. An initial test run omitted the deliberately required AGI_GAME_DIR; rerunning against the SQ2 regression baseline passed cleanly.

  3466. Reported: “I’ll apply the same clean-room route reconstruction to games/PQ1.”

    Action/result: Began a resource-only Police Quest analysis from the immutable local evidence directory. Preserved the existing uncommitted playthrough work and unrelated run.sh, and selected a full resource, score, parser, transition, message, and picture census as the first pass.

2026-07-11 16:15

Resumed the PQ1 maximum-score reconstruction at the unresolved score-ledger gap. The resource census found 118 readable logic resources, 71 pictures, 220 views, a declared maximum score of 245, and 114 positive score operations whose raw sum is 270. Shared one-time guards account for 12 points of alternative or duplicate awards, leaving 13 further points to classify by following the disassembled controller and room-state conditions rather than assuming every syntactic score operation is reachable in one playthrough.

Two bundled local save files were inspected read-only as independent consistency evidence. Both represent a score-156 checkpoint, but neither is being used to derive the route; the route remains based on decoded logic, messages, inventory transitions, and room transitions.

Direct inspection of logic 44 and logic 45 confirmed that their briefing, message, newspaper, and informant awards contribute 19 distinct obtainable points after accounting for the shared newspaper-availability guard. The next step is to identify the remaining cross-phase and mutually exclusive score branches in source order, then construct and independently sum the route ledger.

2026-07-11 16:55

Completed the first PQ1 static winning-route reconstruction. Direct logic and message analysis establishes the playable dependency chain from briefing and patrol procedure through the DUI/Hoffman arrests, Narcotics transfer, warrant, park bust, Cotton Cove body identification, Hotel Delphoria cover, poker, Room 404 transmitter, Bains capture, trial, and terminal parade. The route and failure constraints are recorded in games/pq1_playthrough_analysis.md.

Rendered all 71 present PQ1 pictures with patterned brushes disabled and built a qualitative contact sheet under disposable build/playthrough/pq1/ output. The sweep corroborates route geography but is explicitly not pixel-conformance evidence because the PQ1-specific brush table has not been mapped.

Corrected the score analysis after following nested conditions directly. Six proved alternative groups remove 13 points from the raw 270-point syntax sum, leaving a 257-point static upper bound. The remaining 12-point reachability gap against the declared maximum of 245 is preserved as open work; no unproved score closure is claimed. Updated the evidence book summary, executable notes, and PROGRESS.md accordingly.

Verification passed 433 deterministic tests with four expected optional-input skips. Both mdBooks built successfully, the generated opcode-evidence chapter was current, and git diff --check reported no whitespace errors. No file under games/PQ1 was modified.

2026-07-11 17:10

Began a clean-room maximum-score winning-route reconstruction for the immutable local games/LSL1 evidence set. The planned pass starts with complete logic, parser, transition, score, inventory, and terminal-state indexing; follows the decoded control flow and messages to establish puzzle dependencies; and uses brush-disabled picture rendering only as qualitative geographical evidence.

2026-07-11 17:45

Completed the LSL1 static maximum-score reconstruction. All 46 present logic resources decode, and their 49 positive score sites sum exactly to logic 51’s declared maximum of 222; no negative score operation exists. Direct dependency analysis places every award in one route from Lefty’s through the store, telephone, casino, disco, chapel, hotel, Faith, Eve, and logic 45’s terminal penthouse sequence.

Rendered all 43 present pictures with patterned brushes disabled and built a qualitative contact sheet under disposable build/playthrough/lsl1/ output. Added games/lsl1_playthrough_analysis.md with the route, exact score ledger, money and inventory constraints, death/dead-end map, and replay requirements. Updated the evidence-book summary, executable notes, and PROGRESS.md. No file under games/LSL1 was modified.

Verification passed 433 deterministic tests with four expected optional-input skips. Both mdBooks built successfully, the compatibility runner’s generated opcode-evidence check passed, and git diff --check reported no whitespace errors.

2026-07-11 18:00

Began reorganizing the newly added game-specific playthrough-analysis chapters under docs/src/games/. The move will preserve every chapter in the mdBook navigation and update all evidence-book, progress-dashboard, and historical-log path references to the new location.

Moved all nine playthrough-analysis chapters into docs/src/games/. Added a dedicated Game Playthrough Analyses section to the mdBook summary, retained all nine chapters in navigation, and added an Interpreter Evidence heading before the remaining engine-focused chapters. Updated PROGRESS.md and all historical-log filename references to use the nested paths.

Verification found no stale top-level playthrough path, built both mdBooks, generated all nested HTML pages, and passed 433 deterministic tests with four expected optional-input skips. git diff --check reported no whitespace errors.

The final Git audit found that the broad games/ ignore pattern also hid docs/src/games/. Anchored the rule as /games/, preserving the private root-level game-input exclusion while making the nested documentation chapters trackable.

2026-07-11 18:15

Began separating whole-game playthrough progress from interpreter and portable- specification progress in PROGRESS.md. The nine game-specific route entries will move together under a dedicated section without changing their evidence, status, or remaining replay work.

Moved the nine route-analysis entries from Current Snapshot into a dedicated Game-Specific Playthroughs section immediately before behavioral- specification coverage. Interpreter, version, save, fixture, and corpus status now remain together in the general snapshot, while each game’s score closure, evidence chapter, uncertainty, and replay backlog remain grouped separately.

Rebuilt both mdBooks successfully after the dashboard reorganization. git diff --check reported no whitespace errors, and the section audit confirms the intended order: Current Snapshot, Game-Specific Playthroughs, Behavioral Specification Coverage, and the later remaining-work dashboard.

2026-07-11 18:30

Began a clean-room maximum-score winning-route reconstruction for the immutable local games/BC evidence set. The pass will index all logic, parser, score, inventory, transition, and terminal-state evidence; derive the route from local resources; and place the resulting game-specific chapter under docs/src/games/.

2026-07-11 18:52

Completed the static BC resource census and score-branch reconciliation. All 85 present logics decode, logic 107 declares a 230-point maximum, and the 40 award sites reduce from a raw 463 to exactly 230 after grouping mutually exclusive rescue, route, encounter, resolution, and reward branches. Rendered all 69 present pictures qualitatively and drafted the maximum-score route, score ledger, failure map, and replay checklist in the game-specific evidence chapter.

Verified the BC chapter and dashboard changes with git diff --check, both mdBook builds, and the full compatibility-suite runner. The suite passed all 433 deterministic tests with four expected optional-input skips, rebuilt both books, and completed the opcode-evidence checks. The rendered evidence book contains the new games/bc_playthrough_analysis.html chapter.

2026-07-11 19:05

Began a clean-room maximum-score winning-route reconstruction for the immutable local games/MG evidence set. The pass will census and decode all present resources, classify scoring and terminal alternatives from local logic, render pictures for qualitative geography, and add a game-specific evidence chapter without modifying the private game input.

Completed the static MG reconstruction. All 73 present logics decode and show that the apparent 18-point maximum is an eighteen-rhyme completion counter. Mapped the 35-room outdoor grid, nine attached rooms, twenty randomized props, all eighteen recipients, the one-prop carrying protocol, Old King Cole’s three-stage exception, and logic 102’s terminal celebration. Rendered all 49 present pictures qualitatively and added the route strategy, completion ledger, recovery model, and deterministic replay backlog to the game-specific chapter.

Verified the MG chapter and tracker updates with git diff --check, both mdBook builds, and the full compatibility-suite runner. All 433 deterministic tests passed with four expected optional-input skips; both books rebuilt and the rendered evidence book includes games/mg_playthrough_analysis.html.

2026-07-11 19:35

Began a clean-room whole-game reconstruction for the immutable local games/MH1 evidence set. The pass will prioritize readable disassembled logic, catalogue any unavailable resource evidence, identify the winning and maximum- score states, render readable pictures, and add a game-specific evidence chapter without modifying the private input.

The MH1 resource census identified a version 3 combined-directory input with 66 present logics. The first indexing pass exposed a generic error in the intended unreadable-resource path: it treated a structured directory entry as an old tuple. Corrected the indexer to report the entry’s volume and offset through named fields, then regenerated the index successfully.

Sixty-five MH1 logics decode. Logic 136 is unavailable because its directory entry selects MHVOL.3:0x1d323, beyond the local file length of 0xfe00. The readable scripts contain no score mutations or maximum-score assignment; instead they establish four ordered assignments, four late module-installation states, and four distinct ship bomb-drop states. All four bomb states are required before the switch to logic 162 and its To be continued... ending.

Rendered 196 of 237 present picture entries for qualitative story and location evidence. The remaining 41 require unavailable volume bytes, and the readable scripts also directly reference six unreadable views. Added a bounded MH1 chapter documenting the proven phase skeleton, inventory, Alliance computer, terminal condition, failure/retry evidence, candidate route, and explicit complete-input blocker. Updated the evidence notes, mdBook summary, and game-specific dashboard without modifying games/MH1.

Verified the MH1 work with a fresh tolerant index run, git diff --check, both mdBook builds, and the full compatibility-suite runner. The regenerated index reports exactly 65 readable logics, 138 room switches, 93 inventory mutations, zero score events, and one explicit unreadable record for logic 136 at volume 3 offset 0x1d323. All 433 deterministic tests passed with four expected optional-input skips, and the evidence book contains the new games/mh1_playthrough_analysis.html chapter.

2026-07-11 20:10

Began a clean-room whole-game reconstruction for the immutable local games/MH2 evidence set. The pass will identify the observable completion model, index all readable logic and inventory transitions, render available graphics for qualitative context, and preserve the already known missing-logic boundary rather than inferring unsupported route steps.

The MH2 census found a v3 combined-directory game with 96 present logics, 248 pictures, 181 views, and 195 sounds. Indexing initially stopped when a logic selected absent MH2VOL.3. Extended the generic unreadable-resource path to include missing volume files, then regenerated the index with 65 readable and 31 explicitly unavailable logics.

The readable logic contains six parser predicates, 135 room switches, 32 inventory mutations, and no score or maximum assignment. It establishes the New York-to-San Francisco pursuit, acquisition of MAD and the ID Card, two Orb assignments, the travel network, a 32-item inventory, local arcade/retry contracts, and the hybrid-experiment plot. Logic 0 directly dispatches into many of the missing rooms, so the absent volume prevents a complete route and identification of the real terminal state. In particular, readable The End and YOU WON messages belong to in-world presentations and local challenges, not the whole-game ending.

Rendered all 177 pictures available from the present volumes. Seventy-one present pictures, 67 views, and 73 sounds remain unavailable with volume 3. Added a bounded MH2 chapter containing the resource boundary, assignment and story model, inventory table, partial candidate route, failure classes, and the exact work needed after a matching MH2VOL.3 is supplied. Updated the evidence notes, mdBook summary, and game-specific dashboard without modifying games/MH2.

Verified the MH2 work with fresh MH1 and MH2 index runs, git diff --check, both mdBook builds, and the full compatibility-suite runner. MH1’s out-of-range logic and all 31 MH2 missing-volume logics remain explicit unreadable records. All 433 deterministic tests passed with four expected optional-input skips, and the evidence book contains the new games/mh2_playthrough_analysis.html chapter.

2026-07-11 21:05

Began a source-first cross-game audit of picture pattern-brush behavior. The pass will inspect each locally available interpreter build, group identical binaries, map the 0xf9 mode and 0xfa plot handlers plus their referenced shape tables, and document observable differences before changing any renderer assumptions.

2026-07-11 21:53

Completed the source-first brush audit across all 16 selected game directories. The resulting evidence divides the interpreters into four groups: 2.089/2.272 stop at picture command 0xf8; 2.411 consumes 0xf9 but uses 0xfa as point plotting; 2.439 through 2.936 have complete v2 brushes; and all observed 3.002 builds have a distinct full-brush variant.

Added tools/brush_table_audit.py, which explicitly accepts repeated --game-dir inputs, decodes loader-protected local interpreters when needed, finds each command scanner and dispatch table structurally, and reports brush handlers, table offsets, radius-one rows, and horizontal clamps. Corrected an initial tool interaction in which importing the global game-path parser consumed the first repeated argument and omitted SQ1. The corrected report at build/brush-audit/report.md contains all games and confirms that every full brush routine directly references its selected tables.

The v2 and v3 complete brush cores have identical column masks, radius 0 and radii 2 through 7, mode bits, stipple recurrence, iteration order, and pixel write path. V2 uses radius-one rows e000 e000 e000 and clamp 0x0140; v3 uses 4000 e000 4000 and clamp 0x013e. A rendering sanity check corrected the provisional description “cross”: 4000 intersects neither examined logical-column mask, so normal v3 radius-one output is two adjacent center-row pixels, compared with v2’s 2 by 3 block. KQ2, SQ2, KQ4, and GR produced one, six, two, and two logical pixels respectively for the same synthetic radius-one plot.

Changed the local renderer to discover relocated mask and pointer tables from their structure instead of using SQ2 offsets. It now selects the observed v2 or v3 horizontal limit and automatically uses point behavior when no complete brush table exists. Added structural scanner/table tests and clamp-family tests. Updated the evidence chapters, symbolic labels, versions chapter, runtime model, clean-room picture specification, version profiles, and PROGRESS.md. Also corrected stale game chapters while preserving that their older brush-disabled contact sheets remain qualitative rather than pixel conformance evidence.

Validation resolved the expected table/clamp family independently in every game directory. The full deterministic suite passed 436 tests with four expected optional-input skips. The compatibility-suite runner passed, both mdBooks built successfully, and git diff --check reported no whitespace errors. No game input was modified; generated audit files remain under disposable build/.

2026-07-11 22:08

Audited replacement MH1 and MH2 inputs after the user supplied alternate copies. Both now contain volume 3. Fresh census, reference-audit, and playthrough-index runs show zero skipped source logics: MH1 decodes all 66 present logics, 237 pictures, and 138 views; MH2 decodes all 96 logics, 248 pictures, and 181 views.

Investigated the remaining two sound errors per game. MH1 entries 136 and 138 point into non-header bytes in MHVOL.0; MH2 entries 215 and 216 select absent MH2VOL.6. None is referenced. MH1’s other 99 sounds and MH2’s other 193 sounds all decode, and each valid set exactly equals that game’s static sound reference set. Classified the four entries as inert directory-tail anomalies, not missing valid gameplay resources.

Corrected a reference-audit operand-map bug found during closure checking. The tool had counted set.loop’s loop number as a view dependency and read the cel rather than view operand from add.to.pic. It now ignores set.loop, reads add.to.pic operand 0, and reports references absent from the complete readable set. Added synthetic coverage for those cases and reran both games with no unavailable references.

Confirmed that replacement MH1 uses interpreter 3.002.102: its AGIDATA is byte-identical to KQ4D and its AGI differs only at two signature bytes. MH2 retains the known 3.002.149/Gold Rush relationship. Updated the versions, game-analysis, symbolic-label, current-status, and progress documentation to preserve the old incomplete-copy findings as history while removing the current resource blocker.

Verification passed 22 focused resource/census tests and all 436 deterministic tests with four expected optional-input skips. Both mdBooks built successfully, the project-level compatibility runner passed, and git diff --check reported no whitespace errors.

2026-07-11 22:18

Started a from-scratch reconstruction of the MH1 and MH2 playthrough chapters using the replacement complete resource sets. Deleted both prior partial chapters before beginning the new route analysis. The replacement work will derive story phases, room transitions, inventory dependencies, failure/retry paths, and terminal states from fresh logic indexes and disassembly rather than editing the former missing-resource narrative.

2026-07-11 22:36

Completed the from-scratch MH1 and MH2 playthrough reconstruction against the replacement complete resource sets. Fresh indexes covered all 66 MH1 and all 96 MH2 present logics with no unreadable scripts. The analysis traced terminal incoming edges first, then worked backward through assignment phases, report parsers, inventory mutations, room transitions, retry branches, and late-game controllers.

MH1’s unique continuation ending is logic 162. Its incoming ship-flight edge requires the late authorization state, flight stage 12, and four independent bomb-region completion flags. The rebuilt route records the four assignments, the recognized MAD names, Modules A through D and their independent cockpit consumption, Alliance-computer state, and the four-target bombing requirement.

MH2’s unique continuation ending is logic 187. Its incoming edge from the wraparound maze requires maze state 4 and the player crossing the narrow top exit at X 130 through 143. The rebuilt route now includes the formerly missing Rat Mask/Full Flask, ring, hatchet, Orb-on-a-Stick, statue/Orb Card, lava and captive controller, helicopter, final-control, and toroidal-maze chains.

Rendered fresh representative pictures referenced by both ending scripts into build/playthrough/*-replacement/media/ as qualitative scene checks. No numerical score or maximum-score mutations exist in either game, so each chapter defines winning by its unique To be continued... terminal state. Both chapters explicitly retain exact report answers, movement, arcade timing, and late controller inputs as deterministic replay work rather than guessing.

Validation passed all 436 deterministic tests with four expected optional-input skips. Both mdBooks and the project compatibility-suite runner completed successfully, and git diff --check reported no whitespace errors.

2026-07-11 22:44

Removed game-specific playthrough tracking from PROGRESS.md so it remains an engine reverse-engineering dashboard. Deleted the MH1/MH2 route, puzzle-input, and deterministic-playthrough backlog entries. Retained only MH1/MH2 references that provide interpreter-version, dispatch-table, or resource-container evidence relevant to the engine specification.

2026-07-12

Began replacing the high-level SQ1.22 candidate route with a precise static-data playthrough state machine. The work will trace every selected score event back through parser words, room and position tests, inventory, flags, variables, object state, timers, and random branches in the immutable games/SQ1.22 resources. The canonical reusable result will be JSON with a deterministic Graphviz renderer, accompanied by a detailed evidence chapter; no external AGI material or prior walkthrough is being consulted.

The initial audit confirmed that the existing chapter is a prerequisite-level outline rather than a replay script. Its current index records conditions whose byte ranges enclose an action, but it does not reconstruct jumps and therefore cannot by itself express exact branch reachability. Full logic disassembly and control-flow tracing will be used for the new graph; the index remains a useful locator for score, inventory, parser, and room-transition sites.

Movement analysis will combine every selected room logic with both the visual and priority/control channels of its picture. Required transitions will record the safe approach region and direction against control-line barriers, plus any logic action that changes priority, horizon, object control, or the picture’s effective traversability. This is necessary to distinguish a syntactically present room edge from one the player can actually reach.

Completed the first static pass over all SQ1.22 score sites and the principal room transitions. The remaining pass is tightening parser commands, timing/random branches, and priority/control constraints before encoding the canonical success-path state machine.

Resolved three late-game ambiguities from full disassembly. The 6858 shutdown code is entered by physically walking across numbered keypad regions in room 65; the disguise sequence requires entering the open laundry unit from its narrow baseline box; and gambling is a genuine random loss/win loop whose winnings saturate at 250 buckazoids. These will be represented as coordinate- sensitive and retrying graph edges rather than prose shortcuts.

Created the canonical SQ1.22 JSON state graph with 45 selected score nodes totaling 202, explicit precondition nodes, movement/parser/wait edges, and retry cycles for gambling and guard dialogue. Replaced the candidate chapter with coordinate- and state-specific instructions tied to the rendered priority/control channels; verification of the renderer, tests, and both books is now in progress.

The graph-specific tests and both mdBooks passed. A broad test run with AGI_GAME_DIR=games/SQ1.22 exposed the suite’s existing SQ2-bound assertions for resource hashes/counts, save names, and interpreter tables; those failures are unrelated to the new graph. The unchanged baseline suite is being rerun without the incompatible override, and both outcomes will be retained in the handoff.

Verification completed. The focused graph tests pass; the standard SQ2-backed baseline passes all 438 tests with four expected skips; both mdBooks build; the Graphviz renderer regenerates the committed SVG; and git diff --check is clean. The SQ1.22-selected broad run’s expected SQ2-bound failures remain a documented harness limitation, not a graph failure.

Changed the SQ1.22 Graphviz renderer from left-to-right to top-to-bottom layout and added a focused assertion for the vertical rank direction. The committed SVG is being regenerated from the unchanged canonical JSON state graph.

Started the persistent interpreter-controller implementation with QMP for VM, input, screenshots, and checkpoints; GDB for cycle stops and coherent memory; and a localhost JSON API for semantic state and actions.

The title Enter test exposed a press/release sequencing fault. Confirmed from static logic 69 that the following name field is the ordinary opcode-0x73 shared input mode, not a startup-only editor.

Interrupted the blocked editor and inspected its live registers and stack. The return chain contained 0x0df8, exactly matching the local disassembly, while targeting only image 0x0df2 stopped reliably. This isolated a QEMU real-mode single-breakpoint constraint rather than an incorrect interpreter offset.

Changed the controller to keep the cycle hook active normally, classify a blocking string/modal stack after a bounded interrupt, switch the one active hook to that UI, and restore the cycle hook when the UI exits.

Completed live semantic integration: Enter reached shared string input, submitting roger returned to room 2 cycle control, look entered a detected modal, and dismissing it restored the cycle hook and cleared both modal oracles.

Final verification passed: 13 focused controller tests, the 451-test SQ2-backed repository suite with four expected skips, both mdBook builds, and git diff --check. The controller and QEMU processes were stopped afterward.

Audited interpreter_controller.py for SQ1.22-specific assumptions. Added a prominent non-generic warning, moved the runtime signature and blocking-stack return addresses into the version profile, marked the 2.917-only decoders and screen oracle, and made unsupported object-record widths fail explicitly.

Playthrough Development Workflow

User request:

Add a chapter to the docs that gives advice for developing playthroughs including instructions on how to use the interpreter controller and the general problem-solving lessons you described above.

  1. Reported: “I’ll turn the session’s lessons into a reusable workflow chapter rather than an SQ1-specific walkthrough. I’ll anchor the controller examples to its current API, cover static-first hypothesis building, guarded execution and diagnosis, and clearly separate reusable techniques from the current SQ1.22/2.917 limitations.”

    Action/result: Audited the existing playthrough analyses, state graph, Graphviz renderer, static indexing/rendering tools, controller API chapter, and book structure before drafting the workflow.

  2. Reported: “The chapter structure is now clear: a proof standard for each playthrough edge, a static-resource workflow, a controller runbook, and a failure-diagnosis loop. One point I’m making explicit is that the controller’s local priority planner is a verifier for a room-level hypothesis—not a substitute for tracing room logic or planning multi-room/ elevator routes.”

    Action/result: Added developing_playthroughs.md, linked it from the book summary and controller chapter, and documented static analysis, state-graph construction, semantic transactions, input modes, movement, priority planning, waits, checkpoints, failure diagnosis, recording, and completion criteria.

  3. Reported: “The first draft is in place and cross-linked from both the book summary and the controller chapter. It includes concrete API examples for inspection, transactions, movement, guarded waits, dialogs, input recovery, checkpoints, recordings, and shutdown, plus a symptom-driven diagnostic table. I’m validating the rendered book now and will correct any broken examples or navigation before handing it over.”

    Action/result: Both mdBooks and git diff --check passed. The documented static index, logic disassembly, visual/control rendering, and Graphviz commands ran successfully against the selected SQ1.22 input; the chapter’s JSON and shell examples also passed syntax validation.

Playthrough Guidance in AGENTS.md

User request:

Update AGENTS.md to mention the interpreter controller and developing playthroughs chapters as something that should be consulted for playthroughs

  1. Reported: “I’ll add a concise playthrough-workflow rule to AGENTS.md that points agents to both chapters before static reconstruction or controller-driven replay, while preserving the existing clean-room and explicit-game-directory requirements.”

    Action/result: Added a dedicated playthrough-development section requiring consultation of docs/src/developing_playthroughs.md before playthrough analysis or validation and docs/src/interpreter_controller.md before controller-driven QEMU work. The guidance also preserves the current adapter’s explicit SQ1.22/2.917 limitation.

SQ1.22 Original-Interpreter Playthrough

User request:

Run the real SQ1.22 game under QEMU and play the statically reconstructed success path to completion.

  1. Reported: “I’ll begin by checking the existing worktree and the two controller/playthrough guides, then validate the static route and local SQ1.22 inputs before launching anything. I’ll keep one controller/QEMU session alive, establish deterministic entropy plus checkpoint restore first, and record concrete progress as we go.”

    Action/result: Confirmed that games/SQ1.22 is present, inspected the playthrough/controller guidance and static route, and found only the unrelated untracked run.sh in the worktree.

  2. Reported: “The repository is clean except for an unrelated untracked run.sh, which I’ll leave untouched. The SQ1.22 input is present, and the prior controller work confirms the adapter was live-tested. I’m now extracting the exact API/action semantics and graph edge contracts; after that I’ll prepare a disposable disk and run the required entropy/checkpoint smoke test before attempting route stage 1.”

    Action/result: Began a focused audit of controller endpoints, route-edge preconditions, local runtime prerequisites, and existing disposable artifacts before launch.

  3. Reported: “No reusable controller disk or base FreeDOS image remains under build/, so I’m rebuilding the documented disposable runtime from local inputs. I’m deliberately leaving continuous per-cycle capture off for normal play; I’ll take milestone captures and bounded trace slices, which keeps the persistent session responsive and follows the repository’s performance guidance.”

    Action/result: Rebuilt the derived VGA BIOS and 1 GiB FreeDOS image, then prepared a disposable SQ1.22 qcow2 disk whose copied interpreter passed the fixed-seed patch validation.

  4. Reported: “The disposable environment is ready: the base image rebuilt successfully, and preparation validated and patched the copied SQ1.22 interpreter for fixed seed 0x5eed. I’m launching the persistent controller now, then I’ll discover the cycle hook and verify the selected profile, initial input mode, and checkpoint/restore behavior before entering the route.”

    Action/result: Launched one persistent controller/QEMU session, discovered the SQ1.22/2.917 cycle hook in title room 67, and confirmed the SQ122Adapter fixed-seed profile.

  5. Reported: “The first smoke pass reached the title’s documented random call after exactly 100 cycles and produced v126=20. Restore did reinstate the cycle breakpoint itself, but the restored VM is labeled debug_stop, so the guarded runner refused to advance and could not replay the sequence. I’ve stopped input and am inspecting this bounded controller-state mismatch before proceeding; I won’t work around it with blind key/cycle calls.”

    Action/result: Confirmed through /v1/debug that restore reinstalled the cycle breakpoint. A single bounded semantic step realigned the restored VM from the post-hook instruction to the next cycle boundary.

  6. Reported: “The checkpoint smoke now passes: after one semantic re-alignment step, the replay reaches the same title RNG call in the same total 100 interpreter cycles, again yielding v126=20 and the identical randomized object placement. The active hook is restored correctly; I’ve recorded the debug_stop labeling caveat and am moving through the name prompt into the actual game.”

    Action/result: Saved a title milestone capture and used a transaction to enter room 69’s shared name editor, with both room and input-mode postconditions observed.

  7. Reported: “The first navigation contract was correctly interrupted before movement: room 2 opened an automatic modal from logic 94 while the initial walk-in completed, leaving Roger at (97,66) and stationary. I’m handling that dialog explicitly and checking its static owner before retrying the room-1 exit; no movement input will be repeated until the modal is identified and dismissed.”

    Action/result: Identified and dismissed the Arcada boarding alarm, then reached room 1 through its exact room-2 doorway condition.

  8. Reported: “Dynamic replay exposed one omission in the static route: the scientist sequence is not armed on the first room-1 entry. The game requires a brief room 1 -> 2 -> 1 loop, which sets f53; I confirmed that transition and am now back in room 1 with f53=true and the scientist countdown at v32=247. I’ll preserve this correction in the evidence/route after the live stage is stable.”

    Action/result: Proved the arming loop, positioned Roger safely, and waited through the scientist entry and collapse dialogs to v51=2, v34=6.

  9. Reported: “A second static omission is now confirmed: v33 never starts by waiting alone. Room-1 logic requires TALK TO SCIENTIST while v51=2, v34=6, and Roger is beside him. The command reached a modal, but its full postcondition did not match, so I’m identifying the actual dialog and timer state before dismissing anything.”

    Action/result: Corrected the intermediate hypothesis: TALK TO SCIENTIST selects the nonconversational response, while LOOK AT SCIENTIST selects the wound-description branch that initializes v33 after dismissal.

  10. Reported: “Understood. I’m treating the guide as a hypothesis, not authority. The live state already disproved two route assumptions, and I’ll re-analyze each owning logic whenever a contract fails. This latest LOOK AT SCIENTIST did not set the timer either, so I’m decoding the exact parser branch and current dialog before choosing the next command.”

    Action/result: Verified that the blocking wound-description action precedes the v33 assignment; dismissing it started the countdown, and dismissing the two terminal messages awarded the expected 2 points.

  11. Reported: “The scientist branch is now proved end to end: the trigger is LOOK AT SCIENTIST, not TALK; the two final dialogs then award exactly 2 points. The archive console accepted ASTRAL BODY, and after a bounded 205-cycle retrieval sequence the live state reached v50=2 and f35=true. I’m taking the cartridge next, then I’ll checkpoint and update the route evidence with these corrections before navigating onward.”

    Action/result: Took the cartridge for 5 points, independently verified inventory object 1 is carried, dismissed the result dialog, and saved checkpoint score7_cartridge plus milestone capture sequence 3 at room 1, score 7, position (82,108).

  12. Reported: “I’m switching the remaining Arcada movement to the live priority channel: each local route will be planned from the decoded priority screen, while elevator doors and room edges remain separate guarded transitions.”

    Action/result: Used live-priority plans for every local corridor and console approach. Dynamic stages established the two-elevator route to the room-3 keycard, the room-7 reader/elevator transition, the room-9 airlock, and the room-8 platform-to-pod route.

  13. Reported: “The room-7 entry armed a hostile random encounter, so I’ve stopped the crossing and am checking its owning logic before moving again.”

    Action/result: Identified v67=1 as the armed entry state. Three immediate room-7 retreats/re-entries remained armed; the fourth produced v67=0, allowing a safe priority-planned crossing without replaying the fatal input.

  14. Reported: “The pre-launch milestone is ready: room 10, score 19, door shut, belt fastened, power on, and AutoNav engaged. I’m completing the F5 save now, then I’ll launch and handle each automatic transition as a guarded step.”

    Action/result: Overwrote built-in slot 1 with Score 19 prelaunch. Earlier F7 testing had restored the slot’s score-7 state and confirmed that the original interpreter’s save/restore path reinstates room, position, inventory, and score.

  15. Reported: “The first throttle command was not accepted: the save dialog had just returned control and the interpreter discarded the leading keystrokes, leaving only hrottle at the prompt. I’ve stopped instead of repeating blindly; I’m clearing that partial command, waiting for normal input mode, and will retry from the verified pre-launch state.”

    Action/result: Submitted the partial text once to prove it caused only a parser error, dismissed that modal, reconciled input, and retried. The complete PULL THROTTLE then set f80 with all launch prerequisites still true.

  16. Reported: “Launch is behaving as the local logic predicts, with one guide omission: it first switches back to room 8 for the visible pod-exit cutscene, then enters room 12.”

    Action/result: Followed the bounded automatic sequence through room 8 and room 12. Logic 12 awarded 15 points, raising the live score from 19 to 34, and the narrow-escape modal matched the local message resource.

  17. Reported: “This confirms another substantive guide error: room 13’s 25-point award is conditional on returning from room 37 later in the game, not on the first Kerona approach. The live score is still 34, and I’m preserving that observed contract instead of carrying the static guide’s inflated total forward.”

    Action/result: Waited through in-flight room 10, first-arrival room 13, room 30’s landing animation, and room 14. The score remained 34 until GET SURVIVAL KIT, which raised it to 36.

  18. Reported: “Before continuing across the desert, I caught an omitted dependency from the guide: the survival kit must be opened to replace it with dehydrated water and the Xenon Army Knife.”

    Action/result: Opened the kit outside the crashed pod and verified carried inventory objects 12 and 19. A live-priority plan moved the ego into room 30’s full-width glass rectangle; GET GLASS then raised the score to 39.

  19. Reported: “We’ve reached a clean Kerona milestone at score 39 with the kit opened and glass collected. The guide’s claimed score 61 is definitively wrong at this point: the first room-13 arrival gives no 25-point bonus.”

    Action/result: Updated the playthrough prose, graph, and clean-room notes with the dynamically confirmed Arcada topology, alien retry, closet mapping, airlock, launch sequence, inventory expansion, and relocated 25-point award. The focused graph tests still pass.

2026-07-15: XMAS.230 / AGI 2.230 profile

  1. Reported: “I’ll treat games/XMAS.230 as a new evidence profile: first inventory the executable/resources, then compare its dispatch tables and mapped subsystems against the neighboring early interpreters before adding any normative spec claims.”

    Action/result: Confirmed a clean worktree apart from the unrelated untracked run.sh, kept games/ read-only, and began a focused census of XMAS.230, SQ1 2.089, and XMAS 2.272.

  2. Reported: “The local overlay identifies itself as Version 2.230. I’m using 2.089 and 2.272 as the nearest source baselines and checking parser contracts before interpreting relocated addresses as behavior changes.”

    Action/result: Identified a direct MZ interpreter and split direct v2 resources. Generated selected-game census and two dispatch-table comparison reports under build/cross-version/.

  3. Reported: “The first table pass shows 2.230 is a hybrid rather than a simple relocation of either neighbor. I’m manually reducing the small set of changed handlers and then checking subsystem roles.”

    Action/result: Found 155 actions and 19 conditions. Against 2.089, six shared action entries and two condition entries differed; against 2.272, seven shared actions differed, all condition handlers matched, and 2.272 alone supplied actions 0x9b..0xa0.

  4. Reported: “The new game directory became unreadable during the source pass, so I’ve stopped rather than changing private evidence permissions. Please restore access to games/XMAS.230 and I’ll continue from the saved comparison artifacts.”

    Action/result: Stopped all reads after a permissions failure and did not chmod or otherwise mutate the private game input. No QEMU/controller process was running.

  5. Reported: “Access is restored. I’m resuming at the key 2.230 anomaly: several local view records encode flag bits in the loop header’s high nibble, and the 2.230 last.cel handler explicitly masks them. I’m tracing every cel-count consumer before promoting that behavior into the new spec profile.”

    Action/result: Compared paired 2.230/2.272 view payloads and disassembled loop selector 0x350d, row-mirroring helper 0x50af, and action 0x31 at 0x36e2. Confirmed packed low-nibble count plus mutable loop-wide orientation and mirroring.

  6. Reported: “The view difference is now source-backed, not just a data oddity. Version 2.230 stores mirroring state in the loop header (count & 0x0f, orientation in the upper bits) and mirrors every cel in the shared loop when orientation changes; 2.272 stores orientation in each cel control byte. I’m checking the remaining EGA/output and profile subsystems so the new profile separates real contracts from relocated implementation.”

    Action/result: Confirmed six selected resources use 0xc4/0xc6 packed loop headers where corresponding 2.272 resources use ordinary counts and per-cel bit 0x80. Mapped picture, movement, object, sound, save, input, and EGA output roles.

  7. Reported: “The remaining source pass is closed: 2.230’s EGA overlay entries normalize exactly against both neighboring builds, while its core is a deliberate hybrid—2.272-style position/composition/parser/save behavior, 2.089-style exit/motion-clear/sound behavior, plus the unique loop-header view encoding. I’ve added deterministic model tests and am promoting those contracts into the spec now.”

    Action/result: Added packed-loop header transition/count tests, a local source-byte guard for action 0x31, selected metadata/save-dimension tests, and the new normative 2.230 profile and conformance rows.

  8. Reported: “The interpreter profile and clean-room evidence are in place. I’m finishing the last source-level cross-check—XMAS 2.230’s startup interpretation of the OBJECT header—then I’ll rerun the final consistency checks and hand over the profile.”

    Action/result: Reopened the startup metadata/object initializer in 2.230 and its relocated 2.272 counterpart and recorded the matching header-count and allocation path.

  9. Reported: “The OBJECT capacity is now tied to the executable path itself: 2.230 reads header byte 0x11, increments it, and allocates 18 records of 0x2b bytes. That removes the last inference-only piece from the save-envelope profile; I’m running the final book and diff checks now.”

    Action/result: Added the startup role to the stable symbolic map and recorded the exact read, increment, and record-size multiplication evidence in the executable notes.

  10. Reported: “The combined check stopped immediately because the tests correctly reject an implicit game directory. I’m rerunning with the suite’s documented SQ2 reference input explicitly selected; no analysis result or file was affected.”

    Action/result: Repeated the focused verification with AGI_GAME_DIR=games/SQ2; 161 tests passed with four expected skips, both mdBooks built, and git diff --check passed.

  11. Reported: “Focused verification is green (161 tests, 4 expected skips), both mdBooks build, and the diff is whitespace-clean. I’m doing one final full-suite run against the explicit reference corpus so the handoff reflects the exact current tree, including the last evidence note.”

    Action/result: The complete 482-test suite passed with four expected skips. A process-list check found no QEMU or persistent interpreter controller process running.

2026-07-15: Public repository introduction

  1. Reported: “I’ll reshape the README’s opening for a public audience: a short explanation of AGI, what this repository produces, and the clean-room constraint, while keeping enough concrete terminology that AGI practitioners can identify the scope immediately. I’ll preserve the existing technical material below the introduction.”

    Action/result: Reviewed the existing root README and the two mdBook introductions to establish the public-facing explanation and retain their evidence/specification separation.

  2. Reported: “There are two pre-existing changes in docs/book.toml and spec/book.toml, likely related to publication. I’m checking those diffs so the README edit doesn’t overwrite or accidentally absorb them; the README itself is currently clean.”

    Action/result: Confirmed that both changes add publication site-url settings. Preserved them without modification and kept the README work separate.

  3. Reported: “The existing publication-path edits are separate and will remain untouched. I’m replacing only the README introduction, adding a general AGI reference plus the resource and runtime vocabulary—LOGIC, PICTURE, VIEW/cels, priority/control data, WORDS.TOK, OBJECT, and volumes—that makes the project’s scope immediately legible to AGI developers.”

    Action/result: Rewrote the introduction with an AGI overview and external introductory link, a concise inventory of the reverse-engineered subsystems, a clear statement that the deliverable is a specification, and an explanation of the docs//spec/ clean-room boundary.

  4. Reported: “I’ll add a clear ‘read the published book’ link to each bullet while retaining the repository-directory links for readers who want the source.”

    Action/result: Added the public GitHub Pages URLs for the behavioral specification and reverse-engineering evidence book to their corresponding README bullets.

  5. Reported: “I’ll place a prominent ‘Project repository’ link directly below each book title so it appears immediately on both landing pages, then rebuild both books to verify the rendered sources.”

    Action/result: Added the peterkelly/agi-re GitHub link to the first page of both the evidence and specification books.