Skip to content

Fix: no base package may write into the table the stock DELAY reads - #1457

Merged
repeat98 merged 2 commits into
mainfrom
fix/delay-table-guard
Nov 12, 2026
Merged

repeat98 merged 2 commits into
mainfrom
fix/delay-table-guard

Conversation

@repeat98

Copy link
Copy Markdown
Owner
  • What was wrong or hard: The stock DELAY reads a table of 1,024 coefficients at 0x400d1ce0..0x400d2cdf. From 0x400d24d0 on the table is zero in the stock OS, so it looks like free space. Card builds put overflow code there, and that dulled DELAY repeats (Overflow region 0x400d24d0..0x400d2ce0 is the stock DELAY's coefficient table (synth builds dull DELAY repeats) #1176). The card composer left the repository this morning (Improvement: retire the Octatrack card firmware builder; modules go through the base, over USB or as a card file #1451, Improvement: Octatrack modules prove a base package only; the card composer and its checks are removed #1453), and the draft that fixed it there went with it (Fix: Octatrack card builds keep the 16 bytes the stock DELAY reads past its table #1045). What stayed open: nothing stopped a module's package for the Modwerk base, or a site of the base itself, from writing into the same bytes.

  • What this changes:

    • npm run modules:compat refuses any write into the table. For a module that is what its package installs on the base: a detour, poke, reference, pinned unit, emitted poke, declared run-time write or grown table. For the base it is its own sites, hooks and tables. Kept bytes and stock copies only read the table, so they pass. The message names the module, the bytes it writes and the table, and the fix line sends the author to free space or to a unit the build places.
    • The range is the whole table, 0x400d1ce0 up to 0x400d2ce0, not the 16 bytes Fix: Octatrack card builds keep the 16 bytes the stock DELAY reads past its table #1045 kept. Every address comes from a file already in the repository:
      • sdk/octabam/docs/FAILURE_MODES.md, "A cave at 0x400d24d0 changes the stock DELAY": the routine reads 0x400d1ce0 + 4 * (x >> 6); the low-pass index is (BASE + WDTH) >> 6, up to 1016 with both knobs at 127; boot reads entry 1023; "the whole run 0x400d24d0..0x400d2ce0 is table data (entries 508..1023, zero in stock)".
      • sdk/octabam/docs/remixer/PLACEMENT.md lists the same run as not free, and docs/OCTATRACK_HARDWARE_TRAPS.md carries the trap.
      • 1,024 longwords from 0x400d1ce0 end at 0x400d2ce0, so the two ends agree.
    • What is not proven: reads are measured for entries 508 and 764 (in an emulator; the dull repeats were heard on a unit as reported in Overflow region 0x400d24d0..0x400d2ce0 is the stock DELAY's coefficient table (synth builds dull DELAY repeats) #1176). Entries 1016 and 1023 are read off the stock instructions. No record shows a read of entries 1017 to 1022 (24 bytes). I guard them too: the documents call the whole run table data, and nothing committed uses them.
    • The check judges the package form only. FM Synth's and Scale Quantizer's native manifests still pin units at 0x400d24d0, 0x400d2ca8 and 0x400d2cb0. That was the card form; their packages bind those addresses to symbols of their own (fm_runtime.py, quantizer_runtime.py in sdk/machines/octatrack/module-adapters), and this check does not read the native pins.
    • docs/OCTATRACK_HARDWARE_TRAPS.md: the stale sentence "Card builds still put overflow code there" now says that modules:compat refuses any write there. The file is one byte shorter than on main (57,189 against 57,190).
    • A changelog entry.
  • How I checked it:

    • python3 -X utf8 -B -m unittest discover -s sdk/tests -p test_module_compat.py: 18 tests pass. The new one proves a write inside the table is refused at both ends, one just outside passes at both ends, reads pass, a base site is refused and a native pin is not judged. test_repository_passes runs the new rule over every active module and the base.
    • python3 -B scripts/module-compat.py with main merged (41aa57a, the modules in sdk/octatrack/modules): 36 active modules, 630 pairs, 0 problems.
    • Beyond what the gate models, I read what is committed. All 35 packages in public/octatrack-modules, decoded with sdk/runtime/loader/verify_static.py: 196 sites and 133 stock copies, none in the table, and no word in a package image holds a table address. The base package (src/engine/assets/octatrack-base.elemod): none of its 304 sites, none of the 92 hook and table sites and none of its 145 absolute symbols is in the table, and no word in its code holds a table address. So the rule flags nothing that is committed, and I added no exception.
    • The changelog check and the document size check against main.
    • Not run on my computer: npm run pr:ready, npm run check, sdk:check and the app tests. CI runs them. Nothing was tried on a unit or in an emulator: this is a check on declarations.
  • What the guides lacked or got wrong, and where I fixed it: docs/OCTATRACK_HARDWARE_TRAPS.md still said card builds put overflow code in the table. Fixed in that line.

Two limits, as for the gate's other byte rules: a pinned unit counts with its first six bytes, because the gate knows where a pinned unit starts and not how long it is, so a unit pinned just below the table that runs into it is not seen. A run-time write a manifest does not declare is not seen either.

Related to #1176

🤖 Generated with Claude Code

repeat98 and others added 2 commits November 12, 2026 11:22
…hat writes into the table the stock DELAY reads.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@github-actions github-actions Bot added the bug Something isn't working label Nov 12, 2026
@repeat98
repeat98 merged commit c38a723 into main Nov 12, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant