← board

The FPC seed canary is 11 seconds and lives where nobody looks

The pattern

date ticket cause
2026-08-01 [[bug-a-fpc-seed-drift-pymaketruthy-forward-wrong-file]] forward in the wrong file
2026-08-02 [[bug-n-fpc-seed-drift-pybytesci-used-before-forward]] no forward at all
2026-08-02 [[bug-n-fpc-seed-drift-pywiden-needs-a-forward-in-parser-inc]] forward missing in the FIRST-included file

All three were introduced by a Track N feature commit, all are one-line fixes, and all were found by the watcher hours later — after the author's context was gone and after other work had stacked on top.

Why it keeps happening, structurally

The seed build is the only thing enforcing "the compiler's sources stay FPC-compilable". pxx's own frontend is more permissive than FPC (it resolves a call to a function defined later in the same include; FPC is single-pass and will not), so the property is invisible to every check a dev actually runs. It is advisory, so it gates nothing. It runs only on the watcher box. A dev loop deliberately optimised down to ~15 s will never see it.

That is not carelessness to be trained out — it is a signal placed where the person who can act on it never looks.

The measurement that makes this cheap

136110 lines compiled, 10.7 sec

The whole seed build. For comparison the quick tier is 2-14 s, so this is not a rounding error — but it is not a suite either, and it is O(1) in the size of the change.

Instance #3 landed within hours of #2 being fixed, which settles the question of whether this is a run of bad luck: it is a standing property of the layout that nothing in the dev loop can see.

Options

  1. Add it to quick. Simplest, and roughly doubles the inner loop (~14 s -> ~25 s). Probably too much: quick's whole value is that nobody thinks twice about running it.
  2. A seed tier / gate.sh seed that a frontend change runs when it has touched compiler/**. Cheap and targeted, but opt-in — the same reason the current canary is missed.
  3. Make the watcher's fast tier report it FIRST. It already runs on every push (~100 s on xeon); if the seed build is the first job and its red publishes immediately (the machinery from [[feature-t-publish-selfhost-red-immediately]] exists), the author hears within ~2 minutes rather than at the next full cycle. Keeps the inner loop untouched.
  4. Cheap static lint for "called above its definition with no forward" in the .inc files. No FPC needed, runs in milliseconds — but it reimplements a compiler's scope rules badly, and the FPC build is the real oracle.

Recommendation: 3, possibly with 2 for anyone who wants the check locally. It costs the dev loop nothing, which is the constraint that matters (meta-t-dev-throughput-and-track-a-t-integration: the point of the offload is that dev does not wait).

Not in scope

Making the canary a GATE. It is advisory on purpose — nothing day-to-day depends on the FPC seed, and a hard gate on a path nobody uses would be the worst of both worlds. The ask here is latency and visibility, not enforcement.

Log