Out-of-scope finding from implementing #7122 (PR pending), recorded per PD #10. Unassigned, not queued. Duplicate search: no open issue matches "dist freshness precondition" or "exported-any stale dist"; in:title dist returns only #7122 itself.
#7122's third suggestion asked whether any other dist-reading generator has the same unenforced precondition. It does — three, and they were deliberately left out of that PR to keep it scoped.
The three
Each resolves its public entry points to the built dist/** declarations with the same collectEntries shape #7122 fixed, and each documents the precondition in prose while asserting nothing:
| script |
npm script |
docblock line |
packages/spec/scripts/check-dual-source-exports.ts |
check:dual-source-exports |
":46 — Reads the built dist — run after pnpm --filter @objectstack/spec build." |
packages/spec/scripts/check-exported-any.ts |
check:exported-any |
":28 — asked structurally instead, from the built .d.ts a consumer's import resolves to" |
packages/spec/scripts/check-skill-examples.ts |
check:skill-examples |
":51 — Because it reads the built dist/*.d.ts, this runs AFTER the workspace build" |
Verified on origin/main @ 5087ac6: zero reads of distIsStale, .build-input-hash, or any other freshness signal in all three. Positive control on the same scan — distIsStale matches in check-generated.ts and (after #7122) in lib/dist-freshness.ts, so the scanner is not returning zero for the wrong reason.
Why this is filed as an observation and not as #7122's severity
#7122's damage came from the WRITE: gen:api-surface commits a baseline that deletes a live export, and check:api-surface then agrees with it against the same stale dist. All three above are check-only — none writes a tracked artifact, so none can launder a wrong baseline into a commit. check:exported-any and check:skill-examples each carry an anti-vacuity floor of their own, and check-dual-source-exports.ts reads a hand-maintained baseline rather than regenerating one.
What remains is a false verdict on a stale dist, and it is local-only: CI runs all three after the build step, so the stale condition cannot arise there. The exposure is a developer running one of them directly in a worktree whose dist predates their edit — the same tree #7122 measured — and reading a verdict about a build nobody made.
Cheap fix, if triage wants it
#7122 landed the primitive as packages/spec/scripts/lib/dist-freshness.ts. Adopting it in each of the three is an import plus a four-line guard before the first .d.ts is read, with mode: 'check'. The wording it prints already says "a verdict now would be computed against a build that no longer matches src", which is exactly these three cases.
Worth grading rather than assuming: the mode argument would want a third value, since none of these three is gen-shaped and the current check wording names check:api-surface by hand.
Refs: #7122, #4687, #5726, #5864.
Generated by Claude Code
Out-of-scope finding from implementing #7122 (PR pending), recorded per PD #10. Unassigned, not queued. Duplicate search: no open issue matches "dist freshness precondition" or "exported-any stale dist";
in:title distreturns only #7122 itself.#7122's third suggestion asked whether any other dist-reading generator has the same unenforced precondition. It does — three, and they were deliberately left out of that PR to keep it scoped.
The three
Each resolves its public entry points to the built
dist/**declarations with the samecollectEntriesshape #7122 fixed, and each documents the precondition in prose while asserting nothing:packages/spec/scripts/check-dual-source-exports.tscheck:dual-source-exportspnpm --filter @objectstack/spec build."packages/spec/scripts/check-exported-any.tscheck:exported-any.d.tsa consumer's import resolves to"packages/spec/scripts/check-skill-examples.tscheck:skill-examplesdist/*.d.ts, this runs AFTER the workspace build"Verified on
origin/main@5087ac6: zero reads ofdistIsStale,.build-input-hash, or any other freshness signal in all three. Positive control on the same scan —distIsStalematches incheck-generated.tsand (after #7122) inlib/dist-freshness.ts, so the scanner is not returning zero for the wrong reason.Why this is filed as an observation and not as #7122's severity
#7122's damage came from the WRITE:
gen:api-surfacecommits a baseline that deletes a live export, andcheck:api-surfacethen agrees with it against the same stale dist. All three above are check-only — none writes a tracked artifact, so none can launder a wrong baseline into a commit.check:exported-anyandcheck:skill-exampleseach carry an anti-vacuity floor of their own, andcheck-dual-source-exports.tsreads a hand-maintained baseline rather than regenerating one.What remains is a false verdict on a stale dist, and it is local-only: CI runs all three after the build step, so the stale condition cannot arise there. The exposure is a developer running one of them directly in a worktree whose dist predates their edit — the same tree #7122 measured — and reading a verdict about a build nobody made.
Cheap fix, if triage wants it
#7122 landed the primitive as
packages/spec/scripts/lib/dist-freshness.ts. Adopting it in each of the three is an import plus a four-line guard before the first.d.tsis read, withmode: 'check'. The wording it prints already says "a verdict now would be computed against a build that no longer matches src", which is exactly these three cases.Worth grading rather than assuming: the
modeargument would want a third value, since none of these three isgen-shaped and the currentcheckwording namescheck:api-surfaceby hand.Refs: #7122, #4687, #5726, #5864.
Generated by Claude Code