Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

HeadRush acks before it is ready: loadRig and loadedName both return before the chain is replaced

Open
#166 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
28/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
python
Domain
backend

Research direction

Start from HeadrushAdapter.select_preset() and how it uses PresetName plus settle_s after loadRig. Read tools/verify_headrush.py for the three-way wait (name match, chain shape change, three stable reads 250 ms apart, 2.5 s ceiling). Decide whether that logic lives in the adapter or a separate wait_until_loaded(). Done means a caller can tell the rig is safe to write, the simulator models the ack-before-ready gap, and a select-then-write sequence on ##HRB presets no longer races.

Written by the indexing model from the issue text.

Description

Found during #126's hardware pass and measured on #134; @monzta1 asked for it to get its own number if it was real. It is.

The defect

loadRig returns, and loadedName flips, before the engine has replaced the chain. Anything written in that window races the tail of the load and loses: the unit installs the rig's own stored values over the write, and the read-back reports a mismatch that is not the writer's fault.

Measured on a Core at 5.1.0.2a63755:

trial 1: loadedName flipped at t+332 ms, and the chain was STILL THE PREVIOUS
         RIG'S (9 modules). It became the new rig's (4 modules) at t+1392 ms.
trial 2: loadedName flipped at t+195 ms, chain already stable.
trial 3: loadedName flipped at t+185 ms, chain changed at t+1140 ms.

So the name flips 185..332 ms after loadRig, and the chain can keep being rebuilt for about a second after that.

This is what the "unexplained" topology transient on #136 turned out to be. The check wrote Chain.Routing, the load finished underneath it, and the read-back reported the rig's stored routing:

routing moved 0 -> 0 and read back; adapter reports ok=False
wanted routing 0, unit reads 1; the restoring write reported ok=False
  (Chain Routing: wrote 0, unit reads 1 after 0.5 s)

Inverted rather than stale, which rules out a slow write. Routing itself is fast: read back in 17..38 ms over 14 writes, nowhere near the adapter's settle.

What it affects today

HeadrushAdapter.select_preset() reads PresetName back after settle_s and reports success on it. That is fine for reporting the load. What it does not do is make the rig safe to write to, so any caller that selects a preset and then writes has this race, silently, with a read-back mismatch as the only symptom.

Worth being precise about what is and is not wrong in #135: the id fix and the settle are right, and select_preset returning after its own read-back is a reasonable contract. The gap is that nothing tells a caller when the rig has actually finished loading.

Two things that do not work as the signal

  • loadedName / PresetName. Measured above: they flip first.

  • A fixed sleep. The rebuild tail is not predictable from the rig or from recency. The same rig swapped at 173 ms and at 526 ms on different loads, and loading one twice in a row was no cheaper:

    alternating A B A B A B ->  526, 163, 294, 397, 197, 170 ms
    same rig twice in a row ->  189, 178 ms
    

What #136 does, for reference

tools/verify_headrush.py waits for three things: the name matching, the chain no longer being the shape captured before the load, and that shape holding still across three reads 250 ms apart. A chain that legitimately never differs (reloading a rig, or two rigs sharing a chain) waits out a 2.5 s ceiling instead of failing. Three consecutive full runs pass with it, where the previous build failed two of five.

Whether the adapter should do the same, or expose it as a separate wait_until_loaded() so select_preset keeps a narrow contract, is a design call in your component rather than something the measurement settles.

Related

@bschmalz81401's HeadrushRigBuilder AGENTS.md records the block-level version of the same thing: setModuleTypeInternal returns before the engine has instantiated the block, numbers survive being written into that gap but a file path does not, so the NAM block answered FileMissing: "No Files", dropped the path, and the rig saved with an amp block that had no model. Their fix is to re-apply every parameter after a settle, before saving.

Same shape at two levels: this device acks before it is ready, for rig loads and for block instantiation. #165 would hit the block-level one immediately.

Acceptance

  1. A caller can tell when a loaded rig is safe to write to, by whatever contract you prefer.
  2. Test against the simulator, which would need to model the ack-before-ready gap for the test to mean anything.
  3. Hardware: a select-then-write sequence that fails today passes, on ##HRB presets only.
Dominant language
Python
Stars
7
Forks
3
Avg merge
2h 20m
Merged PRs (30d)
48

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from monzta1/ToneCommand

All issues in monzta1/ToneCommand

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.