Uh oh!
There was an error while loading. Please reload this page.
fix(guards): route the route-ledger host-app-reach limb through the shared comment mask - #12474
Conversation
…hared comment mask The host-app-reach limb in three route-ledger conformance guards scanned RAW source, so a COMMENT quoting `getRawApp`, `'http-server'` or `'http.server'` scored as an extra host-app reacher and failed an IDENTITY assertion by naming a file that reaches for nothing. Every sibling limb in those same files already stripped comments first, and each file's own header says why. The limb now runs through `reachesHostApp()`, which strips comments and leaves string, template and regex literals INTACT — two of the three spellings are service keys, which are string literals, so masking literals here would have turned the false positive into a silent disarm. While converting: the three files answered "comment or code?" with their own character scanners. They now import `stripComments` from `scripts/js-comment-mask.mjs`, the tree's one answer, and their rows in `check-comment-mask-adoption.mjs` are deleted in this PR — the half that gate's `stale` branch exists to demand (23 rows -> 20, shrink-only). That swap was measured, and it found live code loss on two of the three: the private scanners read the `//` inside a regex literal as a line-comment opener and deleted real code to end of line — 40 bytes in `packages/metadata/src/ plugin.ts` and 38 bytes in `packages/cloud-connection/src/ marketplace-proxy-plugin.ts`, the latter inside a declared MOUNT SOURCE. The imports are declared in `scripts/cross-package-test-inputs.mjs` and hashed by `turbo.json` for both new consumers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
yinlianghui
commented
Aug 26, 2026
PM review —
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#12398
What was wrong
The host-app-reach limb in the route-ledger conformance guards asserted an IDENTITY —
"
plugin.tsis the only file that reaches for the host app" — over raw source:Every sibling limb in those same files already ran its input through
stripComments()first, and each file's own header says why. So a comment quoting
getRawApp,'http-server'or'http.server'failed the identity by naming a file that reaches fornothing — and the failure text ("ledger its routes and add its module to MOUNT_SOURCES
before adding it here") invites the wrong repair: widening the expectation, which retires
the only property the assertion has.
The population, measured rather than assumed
The card named four guards. Three carry the raw-scan limb; the fourth does not:
packages/metadata/src/metadata-route-ledger.conformance.test.tspackages/cloud-connection/src/cloud-connection-route-ledger.conformance.test.tspackages/triggers/trigger-api/src/trigger-api-route-ledger.conformance.test.tspackages/cli/src/utils/console-route-ledger.conformance.test.tsMOUNT_SHAPED.test(stripComments(readSource(f))), already strippedThe defect is LATENT today, and that is stated rather than glossed
Replaying each guard's own population rule against
origin/main(68c5dba), raw hits andcomment-stripped hits are the same set in all three packages — 0 prose-only hits:
So this PR repairs no live red. It removes a trap that has already fired once (on
#12140's first draft, whose remedy was to not write the sentence) and pins both directions
so it cannot come back. The zero above is reversed by a positive control, below.
The fix
Each limb now runs through a named probe:
Two properties, pulling in opposite directions, both load-bearing:
are string literals (
ctx.getService('http.server')), so applying the siblingmaskStrings()here would have detected nothing and turned the false positive into asilent disarm. Pinned as its own assertion in all three files.
stripCommentsand notmaskCommentsbecause these findings report afile:lineor abare file name — never an offset — which is the projection the shared module's own
guidance selects.
Not a hand-rolled stripper — and the conversion found live code loss
The three files answered "comment or code?" with their own character scanners. They now
import
stripCommentsfromscripts/js-comment-mask.mjs, and their rows incheck-comment-mask-adoption.mjsare deleted here — the other half of a conversion, whichthat gate's
stalebranch exists to demand. First shrink of that ledger: 23 → 20 rows.The swap was a measurement, and it found something. Over each package's scanned population,
private and shared strippers differ on three files:
packages/metadata/src/plugin.ts//inside the regex literal/^https?:\/\//ias a line-comment opener and deleted the 40 bytes of real code that followed it to end of linepackages/cloud-connection/src/marketplace-proxy-plugin.ts/\/packages\/[^/]+\/versions\//cost 38 bytes of real code — and this file is a declared MOUNT SOURCE, i.e. source the census readspackages/triggers/trigger-api/src/api-trigger.ts,plugin.tsfile:linefinding now points at the real lineThat is the naive-
//familyjs-comment-mask.mjs's header measures, found live in thevery file the metadata guard's identity limb pins.
packages/cli/src/utils/console-route-ledger.conformance.test.tskeeps its ledger row: it was out of this card's scope and nobody has re-read its scanner.
Anti-vacuity — the zero above, reversed
In-file pins (three new
its per guard, driven through the same function the live limbcalls, with source injected):
IHttpServer.getRawApp()docblock, and a block commentquoting
'http-server', both scorefalse;true;the prose-only file excluded.
Reverse verification on the real tree (both legs under
trap … EXIT INT TERM, mutationconfirmed on disk by grepping the injected text and the anchor, tree proven restored with
git hash-object). No rebuild is involved on purpose: the guard reads the mutated file astext off disk, so nothing resolves through
dist/.packages/metadata/src/routes/hmr-routes.ts,fix present. Predicted GREEN. Observed:
Tests 22 passed (22).routes/hmr-routes.ts. Observed exactly the diff the card quotes:A first attempt at leg 1 was a no-op — the anchor I injected against said
2026whilethe file says
2025, so nothing landed. The on-disk confirmation caught it (injected-markercount
0) and that reading was discarded rather than quietly re-run; the numbers above arefrom the corrected run.
Verification
Gate union re-derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(it takes the change set from git itself) and run at the final commit
dc9f92383f—26 families, every one exit
0, each read from its own printed verdict line with the exitcode captured before any pipe. Highlights:
pnpm lint(eslint . --no-inline-config, whole repo) — exit0in 55s. No narrowingto declare.
@objectstack/metadata659/659 ·@objectstack/cloud-connection305/305 ·@objectstack/trigger-api24/24, all files passed.typecheck:@objectstack/trigger-api—tsc --noEmit, Done.@objectstack/metadataand
@objectstack/cloud-connectiondeclare notypecheckscript, so the filtered runmatched nothing for them and passed vacuously; saying so rather than reporting three green
typechecks.
check:type-check-coverageandcheck:type-check-debt's structural half aregreen, and
cloud-connectionalready imported this module next door before this PR.Why no changeset
Test files, two gate scripts and
turbo.json— nothing published changes and no user-visiblebehaviour moves. Carrying the
skip-changesetlabel.Generated by Claude Code
Generated by Claude Code