Summary
In a Stacks app building via ./buddy build (stx SSG, 24 pages), the signals runtime
inlined into every page is months older than the installed stx, and
generateSignalsRuntime() is never called during the build.
I can make the installed generator throw and the build still succeeds, emitting a
full runtime. So the runtime that ships is not produced by the stx the build resolves.
Nothing warns. The page looks fine, the build reports success, and every runtime fix silently fails to reach the browser.
Environment
- App: Stacks app,
./buddy build→Build complete! (SSG) Pages generated: 24 bun.lock:@stacksjs/stx@0.2.153; bun 1.4.0 (same version runs the build)node_modules/@stacksjs/stxsymlinked to a local fork checkout (rawln -s)- Both published 0.2.153 and the fork produce a byte-identical runtime, so this is not fork-specific — I originally hit it while checking whether a fork fix landed
Symptom
generateSignalsRuntime() len 158407 setSelectionRange x2 has `function isDerived`
runtime inlined in the page len 156578 setSelectionRange x0 no `function isDerived`
identical prefix 10677 bytes, then divergesSame generator lineage (identical preamble), older vintage. The emitted copy predates
both isDerived and the @model caret guard.
Three proofs it isn't the resolved stx
Each is self-verifying — I confirmed the patch was still applied to dist/ after the
build, so none of these are "the file got rebuilt underneath me".
Identifier marker. Renamed
__stx_model_bound→__stx_model_bound_MK1inpackages/stx/dist/signals.js.generateSignalsRuntime()returns the renamed identifier; the built page contains the original.Tag marker. Added
data-forkmarkto the injected tag indist/runtime-injection.js(and every bundled copy). The page still emits a plain<script data-stx-scoped data-stx-runtime>— marker absent.Throwing generator. Patched
function generateSignalsRuntime() {tothrow new Error("FORK_GEN_CALLED"). Build: succeeded, 24/24 pages,Failed: 0, runtime still inlined. The generator is simply never invoked.
Ruled out (verified, not assumed)
- Duplicate/nested copies —
findfor@stacksjs/stx(following symlinks) returns exactly one entry in the app tree - Global install —
~/.bun/install/global/.../stxis 0.2.153 and has the fix - bun install cache — a stale
stx@0.2.95exists butstatshowslinks=1, i.e. hardlinked into nonode_modules - App caches —
dist/and the SSG cache dir deleted and confirmed absent before every build; builds reportCached: 0 - stx package-local cache —
packages/stx/.stx/cache/moved aside entirely; output unchanged - Stale dev servers — killed all of the app's long-running dev processes; unchanged
- CLI bundling —
@stacksjs/buddy/dist/cli.jsis a 6.6 KB launcher, no inlined runtime - bun binary — the build runs a different bun than my shell; both resolve
@stacksjs/stxto the same path and produce the same 158407-char runtime - Grep across the app tree for a 64-char fingerprint of the emitted runtime: no file on disk contains it, yet it appears in the output
Dating clue
That fingerprint does match packages/stx/.stx/cache/*.html in an stx checkout —
rendered HTML from June 13 – July 16. Moving that cache away didn't change the
output, so it isn't the source, but it dates the emitted runtime to roughly that era.
Possible lead
runtime-injection.ts:118 returns the template untouched if it already contains
data-stx-runtime / window.stx.state / STX Signals Runtime:
if (template.includes('data-stx-runtime') || template.includes('window.stx.state') || template.includes('STX Signals Runtime'))
return templateIf some earlier stage injects a runtime, this guard would make the real injector a silent no-op — matching every observation (injector loads, generator never runs, output carries an old runtime). I could not find what that earlier stage is.
Why this matters
This is the failure mode from #1792: correct, installed, loaded code that never
reaches the output, with no diagnostic anywhere. Concretely it means a runtime fix can
be released, installed, and verified present in dist/ while every built page keeps
the old behaviour — which is exactly how I lost time chasing a caret fix that was
already published in 0.2.153.
Even without a root cause, a cheap guard would have caught it: have the SSG assert that
the runtime it emits is the one generateSignalsRuntime() returns (or log the length /
a short hash at build time) and warn on mismatch.