You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
assertLazyLinterStaysLazy ignores resolveSpecDistInjection's output — the counter-probe fails every console build made with OBJECTSTACK_SPEC_DIST set #5388
Companion to objectstack-ai/objectstack#10136, which measured this from the consumer side. It blocks objectstack#10129 (bumping the objectui pin) and will turn objectstack's Console Pin Gate red on any pin at or after 6d5368ac8 (this repo's #5323).
What breaks
scripts/build-console.sh in objectstack sets OBJECTSTACK_SPEC_DIST so the console bundles that tree's spec instead of the last published one. apps/console/vite.config.ts honours it, and the console build then dies in generateBundle:
[plugin assert-lazy-linter-stays-lazy]
RolldownError: counter-probe failed: no eagerly loaded chunk contains an `@objectstack/spec` module.
(entry chunks: assets/index-mpVXni3j.js; eager chunks: 59/508)
The counter-probe is not wrong about what it saw — it is reading a module-id shape the injection deliberately abolishes, and it correctly refuses to return a verdict from a walk that sees nothing. The bug is upstream of its judgement.
The seam, verified on origin/main at apps/console/vite.config.ts
The file already computes an injection-aware spec test, and one consumer reads it while the other does not:
chunk grouping uses vendorObjectstackTest ✅ reads the injection-aware test
76–78
assertLazyLinterStaysLazy() declares its own privateconst LINT = /@objectstack[\\/+]lint/ and const SPEC = /@objectstack[\\/+]spec/
366
assertLazyLinterStaysLazy() is registered with no argument — it cannot see vendorObjectstackTest ❌
Under the injection, resolveSpecDistInjection rewrites all 18@objectstack/spec* specifiers to absolute paths in the framework tree (/…/objectstack/packages/spec/dist/<sub>/index.mjs). Those ids contain no @objectstack segment at all, so the private SPEC regex matches zero modules and the counter-probe fires.
This is not path-shape-specific to one machine: on GitHub's runner the framework path is /home/runner/work/objectstack/objectstack/packages/spec, which also has no @objectstack segment.
Fix — contract-first
Make assertLazyLinterStaysLazy()take the spec test as a parameter and pass the injection-aware value at line 366, the same way line 442 already does. resolveSpecDistInjection already publishes the correct answer (its widened vendorChunkTest); the defect is a consumer that does not read its producer's output. Widening the private regex by hand, or having objectstack drop the injection, would both paper over that.
Review the LINT half in the same pass.@objectstack/lint is not injected today, so its regex still matches and the probe's primary assertion is unaffected — but objectstack#9659 proposes injecting four more @objectstack/* packages the same way, and lint is a plausible member of that set. Decide deliberately whether LINT should become injection-aware now or is genuinely out of scope; say which in the PR either way.
Reproduction — the injection is the only variable
Same tree, same commit, same command:
OBJECTSTACK_SPEC_DIST
result
set
Build failed in 11.73s, counter-probe error above
unset
EXIT=0, dist written
Acceptance
The console build succeeds withOBJECTSTACK_SPEC_DIST pointing at a framework spec dist, and the lazy-linter assertion still does its real job in that mode — i.e. the probe finds the injected spec in the eager closure rather than being skipped or defanged. A probe that passes because it stopped looking is a regression, not a fix.
The build still succeeds without the injection, with the assertion unchanged.
Companion to
objectstack-ai/objectstack#10136, which measured this from the consumer side. It blocks objectstack#10129 (bumping the objectui pin) and will turn objectstack's Console Pin Gate red on any pin at or after6d5368ac8(this repo's #5323).What breaks
scripts/build-console.shin objectstack setsOBJECTSTACK_SPEC_DISTso the console bundles that tree's spec instead of the last published one.apps/console/vite.config.tshonours it, and the console build then dies ingenerateBundle:The counter-probe is not wrong about what it saw — it is reading a module-id shape the injection deliberately abolishes, and it correctly refuses to return a verdict from a walk that sees nothing. The bug is upstream of its judgement.
The seam, verified on
origin/mainatapps/console/vite.config.tsThe file already computes an injection-aware spec test, and one consumer reads it while the other does not:
resolveSpecDistInjection(process.env.OBJECTSTACK_SPEC_DIST, { vendorChunkTest: VENDOR_OBJECTSTACK_TEST })const vendorObjectstackTest = specDistInjection ? specDistInjection.vendorChunkTest : VENDOR_OBJECTSTACK_TESTvendorObjectstackTest✅ reads the injection-aware testassertLazyLinterStaysLazy()declares its own privateconst LINT = /@objectstack[\\/+]lint/andconst SPEC = /@objectstack[\\/+]spec/assertLazyLinterStaysLazy()is registered with no argument — it cannot seevendorObjectstackTest❌Under the injection,
resolveSpecDistInjectionrewrites all 18@objectstack/spec*specifiers to absolute paths in the framework tree (/…/objectstack/packages/spec/dist/<sub>/index.mjs). Those ids contain no@objectstacksegment at all, so the privateSPECregex matches zero modules and the counter-probe fires.This is not path-shape-specific to one machine: on GitHub's runner the framework path is
/home/runner/work/objectstack/objectstack/packages/spec, which also has no@objectstacksegment.Fix — contract-first
Make
assertLazyLinterStaysLazy()take the spec test as a parameter and pass the injection-aware value at line 366, the same way line 442 already does.resolveSpecDistInjectionalready publishes the correct answer (its widenedvendorChunkTest); the defect is a consumer that does not read its producer's output. Widening the private regex by hand, or having objectstack drop the injection, would both paper over that.Review the
LINThalf in the same pass.@objectstack/lintis not injected today, so its regex still matches and the probe's primary assertion is unaffected — but objectstack#9659 proposes injecting four more@objectstack/*packages the same way, and lint is a plausible member of that set. Decide deliberately whetherLINTshould become injection-aware now or is genuinely out of scope; say which in the PR either way.Reproduction — the injection is the only variable
Same tree, same commit, same command:
OBJECTSTACK_SPEC_DISTBuild failed in 11.73s, counter-probe error aboveEXIT=0, dist writtenAcceptance
OBJECTSTACK_SPEC_DISTpointing at a framework spec dist, and the lazy-linter assertion still does its real job in that mode — i.e. the probe finds the injected spec in the eager closure rather than being skipped or defanged. A probe that passes because it stopped looking is a regression, not a fix.@objectstack/linteager and confirm the linter assertion still goes red. A guard that can no longer fail is not a guard (perf(console): keep the lazily-imported @objectstack/lint out of the eager chunk #5323's own reasoning).Non-goals
resolveSpecDistInjectionrewrites.