← board

Track corrected P -> B: the test source is a Track B test and the subject is lib/rtl/scheduler.pas, a Track B file. The guess read the .pas extension as "Pascal frontend"; P is the frontend that compiles Pascal, not every test written in it. Nothing in the compiler is implicated — the same source is red or green depending only on thread timing.

origin/master has advanced 12 commit(s) since this sha. Re-verify at current HEAD before acting — the callback is tagged to the sha that was tested, which may no longer be the state of the tree.

regression: test-threads#src:test/test_sched_reactor_exhaustion.pas red at c687ffeecb1f (auto-filed by twatch)

Repro

tools/testmgr.py --tier native --job 'test-threads#src:test/test_sched_reactor_exhaustion.pas' at c687ffeecb1f60010c98799c26f5b2a2bb5b5a50

Range

The named sha c687ffeecb1f CANNOT be the cause — it touches no buildable file (docs / tickets / tstate only). It is the sha that was TESTED, i.e. the upper bound of an untested range; the cause is somewhere below it.

bad c687ffeecb1f, last good d1b84e6c9604, 2 commit(s) in range — the watcher narrows this by idle bisect; check tstate/TSTATE.md for the current range.

Log tail

-fatal: scheduler out of reactor slots (MAX_REACTORS)
(tail)
ok: /tmp/testmgr-scratch-1499318/test_sched_exhaust26  [code=130125B  data=3976B  bss=47348B  procs=298]
expect_same: MISMATCH [test_sched_exhaust26-msg]
--- expected
+++ actual
@@ -1 +1 @@
-fatal: scheduler out of reactor slots (MAX_REACTORS)
+

Stub ticket: signal only. Track T agent (face 2) enriches or a dev track takes it from the repro line.

Triage (frank-b, 2026-08-29) — CONFIRMED, cause found, fixed

Mine, and a real defect in the fix I landed as 9bd3da8b2, not a flake.

Cause. Every refused thread calls Halt(216); exactly one of them first wins a CAS and prints the fatal. Halt is exit_group (since the compiler fix in bug-b-concurrent-halt-from-several-threads-exits-0), so a losing thread reaching Halt ends every thread — including the winner, mid-writeln. The window is CAS-win → write syscall. When a loser wins that race the process still exits 216 with an empty log: a fatal that reports its number and not its reason. That is exactly the observed evidence — the -rc assertion passed and only -msg mismatched.

Reproduced locally, so this is not host-specific — it is timing-thin, and seven is simply wider:

shape empty message
4 workers, output to a file 0 / 40
24 workers, output to a pipe 0 / 12
24 workers, output to a file 5 / 40

The pipe row is why my first local check said "cannot reproduce" and the harness disagreed: I probed a shape the harness does not use. The recipe redirects to a file. A refutation is scoped to the shape that was tested — and I tested the wrong one first.

Fix. The winner sets fatalDone after writing; a loser waits on it before calling Halt. Bounded (FATAL_SPIN_MAX), because a winner that never arrives must degrade to a late fatal, never to a hang — a hang is the one outcome worse than a quiet exit here.

After: 40/40 correct at 24 workers (the width that reproduced 5/40 before), 40/40 on the real test, test_sched_reactors_wide and test_async_parallel_compat 5/5 each, self-host fixedpoint converged in 2 rounds.

Not claimed: I did not reproduce the original 4-worker-on-24-core condition seven hit; I reproduced the mechanism by widening it on a 12-core box. The fix removes the race by construction, so both are covered, but the seven-shaped run is verified by Track T's next sweep, not by me.

Log