Repository navigation
NodeType compile stamps DispatchedBuildInputs through 1 of 11 Pending doors and never clears it on Ok — six kickoff paths can never absorb a release request (#2544), and the stamp lies after completion #3390
Description
Split out of Systemorph/MeshWeaver.SocialMedia#75, whose 2026-08-29 handover recorded "11 production sites flip CompilationStatus to Pending; 1 stamps" and deferred it to "after September 4". That issue is closed on the talk; this is the residue, re-measured on origin/main 1bc0256d8 (2026-09-06).
What the stamp is for
DispatchedBuildInputs (NodeTypeDefinition.cs:844) records which inputs the compile in flight was dispatched for — fw=…;mod=…;src=… — so that a release request arriving while a compile is in flight can be absorbed instead of parked when that compile will produce byte-for-byte what the request asks for (#2544, IsSatisfiedByInFlightCompile, NodeTypeCompilationHelpers.cs:2485-2488, called from the release watcher at :1872 — only after the Pending/Compiling gate at :1852). An unstamped in-flight compile parks, by design: "absorbing against an unknown input set is a guess".
The measurement: eleven doors flip to Pending, one stamps
| door | file:line | stamp |
|---|---|---|
| release watcher dispatch | MeshWeaver.Compiler.Pipeline/NodeTypeCompilationHelpers.cs:1932-1936 |
stamps BuildInputsToken(...) |
| four kickoffs | NodeTypeCompilationHelpers.cs:647-654, :715, :836, :2657-2658 |
explicitly write null (honest: "unstamped") |
NodeTypeCompilationHelpers.cs:1094 |
does not touch it | |
NodeTypeContractHandler.cs:384 |
does not touch it | |
MeshWeaver.Graph/Configuration/NodeTypeEnrichmentHelpers.cs:534 and :1507 |
does not touch it | |
MeshWeaver.Graph/MeshDataSource.cs:1715 |
does not touch it | |
MeshWeaver.Hosting/DynamicTypePreWarmer.cs:913 |
does not touch it |
And no terminal write clears it: a compile that ends Ok (or Error) leaves whatever stamp it found. NodeTypeEnrichmentHelpers.cs:2707 already prints "(unstamped)" for a null, so the field is read as diagnostics.
Live evidence, from the SocialMedia#75 thread (memex, 2026-09-04, read-only): Underwriting/Workbench still carried dispatchedBuildInputs: "fw=s2f22764…;mod=3bac1f7a…;src=25:9b292f90fd8a9a1e" after its successful 09-03T19:49:46 compile, while Publish/Deck and Training/Tour carried none after theirs — their last compiles came through unstamped doors.
Consequences (two, and neither is a wrong absorption)
The absorption is gated on the node already being Pending/Compiling, and the requested token is built from the current sources, so a stale stamp cannot absorb a request against inputs the in-flight compile does not have. What is wrong is narrower:
- NodeType recompile storm: one event mints N release requests, and the watcher queues them instead of coalescing #2544 reaches one door of seven. A compile kicked off by any of the six no-touch doors (enrichment, contract handler, data source, pre-warmer,
:1094) is either unstamped or carries the previous dispatch's stamp — in both cases a release request that arrives during it parks, and the parked trigger re-fires on the terminal write-back and compiles again. That is exactly the "one logical event → N sequential compiles" shape NodeType recompile storm: one event mints N release requests, and the watcher queues them instead of coalescing #2544 was measured against; it is still the outcome for every compile those doors start. - The record lies after completion. "An operator reading a stuck node's record can see WHICH input the standing verdict was formed under" is the stated purpose (
:2466-2469) — but after a terminalOkthe stamp on the node is the previous dispatch's, and after an unstamped door it is absent, so the field cannot be read as "what is in flight now" on the very nodes where an operator would look.
Fix shape
- Every
Pendingflip goes through one helper that either stamps the token it is dispatching for or writesnull— no door leaves the field untouched. The six no-touch doors gain the stamp where the inputs are known at that point (they all havedef.CurrentSourceVersionsand the guards'ModulesHashin reach), else an explicitnull. - Every terminal write (
Ok/Error) clears the stamp, so a non-null value means in flight and nothing else. - A test in
MeshWeaver.Compiler.Pipeline.Testthat walks each door and asserts the invariantDispatchedBuildInputs is non-null ⇔ CompilationStatus is Pending/Compiling and the token matches the dispatched inputs, so the next door added cannot regress it silently.
Line numbers as of origin/main 1bc0256d8, 2026-09-06. The production evidence is quoted from SocialMedia#75 and was not re-measured today.
Activity
rbuergi commentedon Sep 6, 2026
Half done on
main(#3405) — the terminal-clear half. The stamping half stays open.Verified on
origin/mainrather than on the PR's word — all five terminal writes now clear thestamp, and the guard shipped:
So your second bullet — "every terminal write clears the stamp, so a non-null value means in flight
and nothing else" — holds now, and
DispatchedBuildInputsInvariantGuardkeeps it holding: it failsif a terminal
CompilationStatuswrite does not mention the field, with a floor on the sites foundand a self-test of the brace-balanced matcher. Confirmed it can fail by removing one clear
(
PrebuiltAssemblySeeder.cs:483) and watching it redden while the self-test stayed green.🚨 What is deliberately NOT done: the six unstamped
PendingdoorsYour first bullet is untouched, and I want to be explicit about why rather than leave it looking
overlooked.
A wrong stamp is worse than no stamp. An unstamped in-flight compile parks the release request —
the documented safe behaviour, "absorbing against an unknown input set is a guess". An
incorrectly stamped one gets the request absorbed against a compile that will not produce
what was asked, and nothing downstream re-checks. So the six doors are not a mechanical edit: each
needs a judgement about what its inputs genuinely are at that point, and getting one wrong converts
a safe park into a silent wrong answer.
Your fix shape says the doors "all have
def.CurrentSourceVersionsand the guards'ModulesHashinreach" — that is the right starting point, and it is exactly the claim that wants checking per door
rather than assuming across six.
Whoever takes it now has the guard in place. Worth extending it in the same change to assert the
other direction — a
Pendingflip either stamps or writes an explicitnull, never leaves thefield untouched — which is the invariant that stops door number twelve from repeating this.
Third bullet, partially
Your proposed test walks each door and asserts
non-null ⇔ Pending/Compiling and the token matches. What shipped is the writing half of that,enforced statically. The matching half — that a stamped token actually describes the inputs
dispatched for — still needs the runtime test you describe, and that belongs with the stamping work.
🤖 Filed from Claude Code.
rbuergi commentedon Sep 6, 2026
The stamping half is in #3415 — and the count is 12 doors, not 11
Re-measured on
origin/main4248aba7b(i.e. with #3405's terminal-clear half already in):12 sites flip
CompilationStatustoPending; 1 stamped; 4 wrote an honest explicitnull; 7did not mention the field at all.
The table above misses one —
NodeTypeCompilationHelpers.cs:1532-1541, the sources watcher'sparked auto-retry. It is the most interesting of the twelve, because it publishes a NEW source
snapshot in the same write, so stamping
def.CurrentSourceVersionsthere would record the brokenset the dispatch is replacing. It needs the snapshot passed explicitly. Its sibling branch — the
one that finds the type already
Pending/Compilingand only refreshes the snapshot — mustleave the stamp alone, because that compile really was dispatched for the old sources and a
request formed under the new ones must still park.
MeshOperations.cs:4368is in the neighbourhood but is a read (a display fallback), not a door.Structural, per the fix shape
NodeTypeCompilationHelpers.DispatchPending(def, modulesHash | hub)flips the status and writesthe token, and it is now the only
CompilationStatus = …Pendingwrite anywhere insrc/.DispatchedBuildInputsInvariantGuardasserts exactly that, and it is rewritten as a classifierover the assigned expression rather than a substring search for a spelling.
That rewrite found two terminal-clear sites #3405 could not see
Both spell the status as something other than the literal its matcher looked for, so both kept the
stamp across a terminal write:
NodeTypeCompilationHelpers.ApplyCompileFailure— a ternary,Unavailable/ErrorNodeTypeContractHandler:258— theUnavailablemarker writeYour second bullet therefore holds now in a way it did not on
mainan hour ago.Third bullet, the runtime half
DispatchedBuildInputsStampedAtEveryDoorTestcomposes each door's transition withIsSatisfiedByInFlightCompile— the same question the release watcher asks — so it fails if a doorstops stamping and if the stamp is wrong. Reverting the door reddens 6; reopening one door
reddens the structural guard, naming the site. Both counts and both failure texts are in the PR.
What I did not do
Not weakened the absorb predicate — a request against moved sources, a moved framework or a moved
module set still parks, and force still always compiles. Not #3395; but it is the argument for
accurate stamping: an accurate
mod=makes a mid-boot module-set change visible to the absorb read,where an absent stamp merely hid it behind a park that happened to be right.
One thing flagged rather than fixed: a
Pendingflip the compile watcher refuses to dispatch(the parked short-circuit) is briefly stamped before
ApplyGateSettleclears it, so a requestlanding in that window can be absorbed against a compile that never runs. That window is
pre-existing on the release-watcher door and unchanged in shape; closing it means teaching the
absorb read about the park registry, which is #2544's business.
Written up in
Doc/Architecture/NodeTypeCompilation— the absorb mechanism was previouslyundocumented there.
🤖 Filed from Claude Code.
test(#3390): the guard fails closed on an expression it cannot read