Installing the fixed compiler exposed a blind spot in this gate. On clean main,
with no source changed, soulc-stamp reported OK while the committed amalgam had
gone stale by a line — because the fingerprint covered .el sources and not the
toolchain that turns them into dist/soul.c. That is exactly the class of silent
divergence the gate was written to close, and it had it.
The stamp now fingerprints the elc binary alongside the sources. Demonstrated: with
the old stamp the gate passed after a compiler swap; with this change the same
condition fails, naming __compiler__.
dist/soul.c regenerated under the installed compiler (1,205,027 bytes) and verified:
builds from its own committed input, the declared principal is present in the
resulting binary, interface 110 routes in / 110 out.
Differential evidence that the new compiler is a strict superset — same sources,
both compilers:
neuron soul 1 differing line, the el_cgi_init emission
engram server.el 0 differing lines
mcp-wrapper 0 differing lines
mcp-proxy 0 differing lines
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#133 regenerated the amalgam once and said so itself: 'Nothing in the tree
regenerates this file. Only a human running the recipe. It lags in batches, never
per-change, and it will drift again.'
It drifted again. Every binary deployed on 2026-08-09 was built by build-soul.sh
from a scratch amalgam that never touches dist/soul.c, so the committed build
input fell 2,761 bytes behind the sources by a different route than #133 describes.
Auto-regeneration is not available: the CI workflow records that elc needs 24GB+
of virtual memory and would OOM the runner. So the build cannot regenerate the
file. It can refuse to compile a stale one, for free and with no compiler.
tools/soulc-stamp.sh records a content fingerprint of every .el source at the
moment the amalgam is generated. --check recomputes and compares; divergence exits
1 and names the changed files and the recipe. Wired into CI ahead of the compile.
dist/soul.c regenerated from current sources: 1,176,361 -> 1,179,122 bytes, 1,247
inlined bodies (gate wants >=1200), and verified to compile clean at 903,552 bytes.
Demonstrated to FAIL on the bad input, per postmortem 0004's rule that a gate which
only passes on good input proves nothing:
fresh stamp -> OK, exit 0
one .el modified -> FAIL, exit 1, names memory.el
source restored -> OK, exit 0
Refs #133, #111
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>