docs: brief for the T9 library-credential race, the second broker start passes Node's TIMEOUT_MAX interval so no timer tick overlaps the verb sync; mutant must fail a 50-run stress loop (mos-1594, Vikunja 622, #1826); doc only
This commit is contained in:
1 parent
3e5041b43b
commit
2ce476d54c
1 file changed
+49
@@ -0,0 +1,49 @@
|
||||
# T9 library-credential race on the second broker start
|
||||
|
||||
Written 2026-10-24 by Sage for Mos's mos-1594 (Vikunja 622, #1826), after Fethry's row 266 gate saw
|
||||
bus 999/1 (fethry-0032) and Sage's sage-4185/4187 placed it.
|
||||
|
||||
## Brief: the T9 verb sync on the second start runs with no timer tick able to overlap it
|
||||
|
||||
**Why.** `packages/bus/tests/library-credential.test.mjs` T9 (`:265`) starts the broker twice with
|
||||
`librarySync: { command, intervalMs: 50 }` (`:289-290`, one `start` closure for both). On the second start, after a revoke, it waits
|
||||
for the first `library-sync-held` line (`:315`) and then expects the `library.sync` verb to refuse
|
||||
`library-fetch-no-grant` (`:317`). That wait doesn't order the verb against later ticks:
|
||||
|
||||
- `packages/bus/src/runtime.mjs:615` keeps `setInterval(tick, intervalMs)` running after held, and
|
||||
`tick` (`:606-611`) only skips while a pass is in flight. Only `stopSync` (`:618`), called from
|
||||
`close()` (`:679`), stops it.
|
||||
- `packages/library/src/sync.mjs:140-141` refuses `library-sync-busy` while `running` holds the
|
||||
mirror, and `:203` clears it in `finally`. So the startup pass has released by the time its held
|
||||
line is written, but a later 50 ms tick can hold the mirror when the verb arrives.
|
||||
|
||||
When that happens, `:317` sees `library-sync-busy`. Under load it fails. On a quiet host it passes.
|
||||
|
||||
**What ships.**
|
||||
|
||||
1. In T9 only, the second start (`:314`) passes `intervalMs: 2147483647`. That is Node's `TIMEOUT_MAX`, so
|
||||
only the startup tick (`runtime.mjs:614`) fires while the test is open. One more and Node clamps
|
||||
the delay to 1 ms with a `TimeoutOverflowWarning`, so don't round it up. Runtime validation
|
||||
(`runtime.mjs:122`) accepts it. The first start keeps 50 ms, because `:304`
|
||||
("the timer and the verb") needs ticks. A short comment at the change names mos-1594 and the reason.
|
||||
2. No assertion in the file changes, and no other test changes. No product code changes. If the fix
|
||||
seems to need either, stop and tell Sage. That's a mos-1272 question for Mos.
|
||||
3. `agents/<seat>/work/queue-<row>/BUILD.md` records the stress runs and the mutant below as plain
|
||||
text, with commands, counts and host load average.
|
||||
|
||||
**Mutant and stress (Mos's condition).** Build a stress loop that runs T9 alone
|
||||
(`node --test --test-name-pattern` on the file), 50 or more times, each run in a fresh mktemp -d
|
||||
TMPDIR under `/mnt/storage/scratch/tmp`.
|
||||
|
||||
- M1 puts `intervalMs: 50` back on the second start. It must fail at least once in the loop. If 50 ms
|
||||
never fails on the host, run M1 at `intervalMs: 1` as well and record both results. If neither
|
||||
fails, stop and report, because the fix can't be shown to matter.
|
||||
- With the fix in place, the same loop passes every run.
|
||||
- Restore the file after the mutant, and show `git diff --stat` empty against the build commit.
|
||||
|
||||
**Gate.** Boyd gives the first Codex review, and Dewey does the landing review. Every touched test
|
||||
file runs whole, the stress loop and M1 run as above, and the bus suite and every `scripts/test-*.sh`
|
||||
are green on Sage's landing gate. All test runs are slot work: wait for Sage's CLEAR.
|
||||
|
||||
**Out of scope.** The broker timer, `stopSync`, a test-only stop hook, other library tests, and the
|
||||
row278 sign-out flake (Vikunja 620, Sage's).
|
||||
Reference in new issue
Block a user