Skip to content

test(cli): mask comments in the nightly-tier readers of this package's own source, and derive the pins that bound a spelling - #18924

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-18520-nightly-pin-source-readers
Sep 18, 2026
Merged

os-support-ai merged 2 commits into
mainfrom
claude/issue-18520-nightly-pin-source-readers

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes #18520

Clause-②: no

The nightly-tier test files under packages/cli/test/ that read this package's own source
TEXT now read it through the shared mask (scripts/js-comment-mask.mjs), and the pins that
bound a byte-exact SPELLING now bind a property derived from the source instead. Every file
was judged on its own; the table below gives the rung and the reason per file.

The population, re-derived — no number inherited

Predicate, stated: a file under packages/cli/test/ whose NAME puts it in a nightly tier
(scripts/nightly-tiers.mjs*.e2e.test.* / *.live.test.*, and nothing else selects a
tier), which READS this package's own source text at test time, directly or through a helper
under test/helpers/ it imports. Evaluated over each file's local import closure, on MASKED
text, so a read one module away still counts and a path named only in prose does not.

predicate count measured at
card's: test/*.e2e.test.ts containing readFileSync 26 reproduces exactly
card's: of those, importing the shared mask 3 reproduces exactly — serve-port-readback, published-entry-stderr-nonblocking, run-dev-stderr-nonblocking
claim's: grep -rl readFileSync test/*.e2e.test.ts | xargs grep -l 'src/' 20 reproduces exactly
mine (above) — nightly-tier readers of this package's own source 15 12 raw, 3 already masked

20 and 15 are not a contradiction — they are two predicates, and the delta is readable
both ways.
Eight files are in the claim's 20 and not in mine, three are in mine and not in
its 20:

  • prose onlylint-eval-generator-load-envelope matches src/ in a docblock sentence
    and reads /definitely/not/here.json. This is the false positive the dispatch predicted.
  • a temp fixture's src/, not oursbuild-docs-step-count, build-multi-package-artifact,
    generate-skill, serve-publishes-bound-port create src/docs or src/skills inside a
    scratch project and read dist/objectstack.json back.
  • another package's sourcescaffold-emission-policy reads packages/create-objectstack's
    template package.json. JSON carries no comments, so no rung applies.
  • own source, but bin/ not src/published-entry-stderr-nonblocking (already masked)
    and run-dev-unbuilt-workspace (raw). Both read a hand-written published entry; the second is
    in this PR, the first was already correct.
  • missed by the claim's grep, found by mineconfig-miss-stdout-purity reads
    src/commands through test/helpers/config-miss-family.ts and never spells src/ itself;
    invocation-loudness and serve-host-fallback-base DO spell ../src/... but never read it
    as text — they symlink/execFile it, so they are readers of a module, not of prose.

Rung per file

file reads rung what changed, and why that rung
build-json-failure-conversions.e2e.test.ts src/commands/compile.ts 3 only Masked. Its indexOf ORDER block (declAt / tryAt / loadAt / normalizeAt) is the #17633 shape verbatim — raw positions over a file whose docblocks name await loadConfig(. ⛔ The six frozen integers are card #18894's and are untouched here.
build-json-failure-warnings.e2e.test.ts src/commands/compile.ts 3 only Masked, same fence — integers untouched.
cloud-login-json-ndjson.e2e.test.ts src/commands/cloud/login.ts 3 + 2 Masked; and the pin that subtracted ONE byte-exact line from the emitJson( hits now partitions the call sites against emitRecord's own brace-matched body: outside must be empty, inside must not be.
login-json-ndjson.e2e.test.ts src/commands/login.ts 3 + 2 Same conversion, same reason.
login-json-noninteractive.e2e.test.ts src/commands/login.ts 3 Masked only. Its rl.question( filter already binds a SHAPE (does the line carry the abort signal), not a spelling — rung 2 has nothing to convert.
json-stdout-purity.e2e.test.ts src/commands/** 3 + 2 Masked; and toHaveLength(10) demoted to a floor. The line above it already binds the SET against the map a sibling nightly file drives, so the integer was a second frozen copy of one fact. It stays as a floor because it is the only guard on the vacuum both sides share.
config-miss-stdout-purity.e2e.test.ts src/commands/** via helper 3 ⭐ No edit in this file — its reader lives in test/helpers/config-miss-family.ts, which this PR masks once for both consumers.
test/helpers/config-miss-family.ts src/commands/** 3 Masked. Both discovery halves are regexes over command source and both are satisfiable by prose: a docblock naming json: Flags.boolean( beside a utils/config.js import invents a direct member; a commented-out export default class X extends Y invents an alias.
diff-usage-error-stream.e2e.test.ts src/commands/** 3 Masked. This scan decides by LINE POSITION — writers above the first flags.json read — which is the print-ORDER failure that opened this card. Its toBeGreaterThan(10) population control was already a floor.
run-dev-unbuilt-workspace.e2e.test.ts bin/run-dev.js 3 Masked. exec takes the FIRST match, so a docblock recording the old STDERR_DRAIN_STALL_MS would be read as the shim's bound. Its sibling over the other published entry already masks; this makes the pair consistent.
serve-app-anchored-optional-import.e2e.test.ts src/commands/serve.ts 1 + 2 + 3 See below — five byte-exact statement pins, rewritten.
validate-json-failure-conversions.e2e.test.ts src/commands/validate.ts 3 Masked, and the paragraph that recorded the opposite decision is corrected rather than left false.
validate-json-failure-warnings.e2e.test.ts src/commands/validate.ts 3 Same.
serve-port-readback · published-entry-stderr-nonblocking · run-dev-stderr-nonblocking own source Already masked. Untouched.

Rung 1 — where it applied, and where it did NOT

Rung 1 permits DELETING a nightly assertion when a per-PR sibling already binds the same
thing. I searched for a sibling for every byte-exact subject in this population and opened
the one I found:

  • Applied once. serve-app-anchored-optional-import bound
    function importFromHost(specifier: string, hostRoot: string = servedAppRootOrCwd()) — an
    argument LIST, the feat(cli): objectstack dev --cert/--key terminates TLS in the dev process, and the canonical origin follows the listener #17725 shape exactly. src/commands/serve-cluster-host-resolution.test.ts
    is queue-tier (its name carries no .e2e, so nightly-tiers.mjs leaves it in the per-PR run)
    and binds that function's EXISTENCE, its module scope and its uniqueness. So this PR does not
    re-pin any of that here; what it keeps, because the sibling does not bind it, is the DEFAULT —
    read off the paren-matched parameter list.
  • Did not apply anywhere else, and this is a measurement. anchorServedApp and
    servedAppRootOrCwd appear in no other test in the package. The login emitter contract
    (emitRecord) appears in no queue-tier test at all. For warningsSoFar, the queue-tier
    test/truncation-remainder-notices.test.ts binds 'warnings: warningsSoFar(),' in
    compile.ts — the CALL SITE, not the declaration and not the spread ORDER these files pin,
    and for validate.ts it binds different payload keys entirely. Not the same thing, so
    nothing was deleted on its account.

serve-app-anchored-optional-import in detail

Five toContain/toMatch pins over whole statements of serve.ts, in a file only the nightly
tier collects. Each now binds what it was written for:

was is
toContain('const { configPath: absolutePath, configExists } = anchorServedApp(args.config!);') exactly ONE anchorServedApp( call site (the declaration excluded by the same function lookbehind the per-PR sibling uses), and its ARGUMENT is args.config!. The destructured local names are deliberately no longer bound.
not.toMatch(/const absolutePath = path\.resolve\(process\.cwd\(\), args\.config!\)/) the same negative as a SHAPE: path.resolve(process.cwd(), args.config with whitespace tolerated. A negative pin on one exact spelling passes for every respelling of the defect.
toContain('function importFromHost(specifier: string, hostRoot: string = servedAppRootOrCwd())') the hostRoot parameter's DEFAULT, read off the paren-matched parameter list. A third parameter or a renamed specifier no longer reddens it.
toContain('const hostRoot = servedAppRootOrCwd();') and toContain('const root = hostRoot ?? servedAppRootOrCwd();') a partition over every const/let host-root binding: at least two exist, and none may be bound without resolving through servedAppRootOrCwd().
toMatch(/^function servedAppRootOrCwd\(\): string \{$/m) exactly one MODULE-SCOPE function servedAppRootOrCwd(, never indented, never a const/let/var. The return-type annotation and the brace are not the defect.

What the mask changed TODAY: nothing — and that is the measurement

Every converted reader was evaluated raw and masked over the same tree, and every verdict is
identical. Masking is therefore behaviour-preserving now and protective later — it did not
launder a stale pin green:

SAME  json-stdout-purity/discoverFamily        (the same command ids)
SAME  config-miss-family/discover              (the same 10 ids)
SAME  diff-usage/offenders                   = []
SAME  diff-usage/withJson count              = 28
SAME  emitJson call sites — login.ts         = 1      cloud/login.ts = 1
SAME  rl.question without signal — login.ts  = []
SAME  payloadLiterals — validate.ts          = 7      compile.ts = 11
SAME  order indexes — validate.ts / compile.ts       (declAt/tryAt/loadAt/normalizeAt)
SAME  serve.ts anchorServedApp / servedAppRootOrCwd sites
SAME  run-dev STDERR_DRAIN_STALL_MS          = "15_000"

scripts/check-comment-mask-adoption.mjs is green before and after and its ledger is
unchanged at 14 rows — because none of these twelve files ever carried a private stripper.
They carried NO masking at all, which is the blind spot the card names and the gate documents.
This PR adds no private stripper; every file imports the shared module.

Ablations

Each is a script with trap restore on EXIT INT TERM, absolute paths, an on-disk occurrence
count proving the mutation landed, exit codes captured BEFORE any pipe, and a restore proven by
git hash-object against the HEAD blob plus a clean git status for both paths.

⚠️ The first attempt of all three read exit 1 everywhere in 17 seconds. That was not a result:
without OS_TEST_TIERS=nightly the package collects none of these files, and it says so
loudly. Recorded here because a run that measured nothing is the failure mode this card is
about. The numbers below are from the re-run with the switch set.

ABL-1 — the #17633 shape, reproduced and then shown fixed. A COMMENT is injected into
src/commands/info.ts between async run( and its first flags.json read, naming
printHeader(. Behaviour is untouched; only prose moved.

leg pin exit reading
masked (this PR) diff-usage-error-stream 0 prose is invisible
raw (pre-conversion, restored from the merge base) same file 1 AssertionError: expected [ 'info.ts' ] to deeply equal []

⭐ That failure line IS the card's first row: a docblock reporting an order change that never
happened.

ABL-2 — serve.ts, both directions.

leg mutation pin exit reading
1 const hostRoot = servedAppRootOrCwd(); becomes process.cwd() converted 1 a host root is bound without resolving through servedAppRootOrCwd(): expected [ Array(1) ] to deeply equal [] — the new partition is not vacuous
2 a THIRD parameter added to importFromHost, same arguments, same behaviour converted 0 the argument LIST is no longer the contract
2 same mutation pre-conversion 1 expected '…' to contain 'function importFromHost(specifier: st…'#17725 verbatim, on a pin no pull request can see

ABL-3 — the login emitter partition.

leg mutation pin exit reading
1 a real second await emitJson( outside emitRecord converted 1 every --json write in login.ts must go through emitRecord(): expected [ Array(1) ] to deeply equal []
2 a COMMENT quoting emitJson(payload, 0) converted 0 prose is invisible
2 same comment pre-conversion 1 same assertion — a comment breaking a pin whose code never moved, the card's second row

All three restored cleanly: git hash-object matches the HEAD blob for every mutated path and
git status --porcelain is empty for both paths in each script.

Verification

  • ⚠️ Tier. OS_TEST_TIERS unset collects none of these files. Every red/green below is
    under OS_TEST_TIERS=nightly. Independently confirmed by pnpm check:tier-file-adoption:
    68 nightly-tier files on disk, owned by one package.
  • packages/cli built (pnpm --filter '@objectstack/cli...' build) so the pins that refuse
    at load on an absent dist/index.js actually run.
  • Both whole-package runs, no --project filter — what CI runs:
pnpm --filter @objectstack/cli test                       Test Files  267 passed (267)   Tests  3485 passed (3485)   exit 0
OS_TEST_TIERS=nightly pnpm --filter @objectstack/cli test  Test Files   68 passed  (68)   Tests   695 passed  (695)   exit 0

The 12 converted files were also run on their own under OS_TEST_TIERS=nightly before the
whole runs: 12 files / 336 tests / exit 0.

  • Gate families derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack and reconciled with --ran: 47 derived, 46 run green, 1 NOT
    MEASURED
    pnpm check:dual-build-cjs-loads exits 3 (PREREQUISITE NOT MET: it reads built
    output for packages outside this closure). ⛔ Recorded as NOT MEASURED, not as a pass and not
    as a red.
  • pnpm lint over the whole repo, unnarrowed. node --stack-size=4000 eslint . --no-inline-config over the whole repository, exit 0.
    This is the unnarrowed run, so no narrowing has to be justified.

skip-changeset, by measurement with controls both ways

This PR's own diff (git diff --name-only origin/main...HEAD) is 12 files, all under
packages/cli/test/. packages/cli's files[] is ["dist","README.md","CHANGELOG.md"] and
tsconfig.build.json has include: ["src"], so test/ reaches neither. Measured against the
built tree rather than argued:

  • negativebodySpan, splitParams, paramsOf (the three symbols this PR introduces):
    0 files in dist, 0 in README.md.
  • positive controlanchorServedApp (2 files), servedAppRootOrCwd (2), emitRecord (3)
    in dist, so the grep over the published tree finds things and the zero above is a reading,
    not a dead search.
  • ⛔ No scripts/** path is touched, so the published surface did not have to be re-derived.

Fences

Acceptance notes

  • src/commands/serve-cluster-host-resolution.test.ts carries a private stripComments at
    line 151. It is a DECLARED row in check-comment-mask-adoption.mjs's shrink-only ledger,
    measured there as agreeing with the shared mask byte for byte over 212 files, so it is
    recorded debt rather than a finding, and converting it is that ledger's per-row work.
    Noted, not filed.
  • validate-json-failure-{warnings,conversions} still pin a multi-line spread ORDER in
    validate.ts byte-exactly (...ruleAdvisories, ...docWarnings, ...), and the two
    build-json-failure-* files pin the same shape over compile.ts. That is a rung-1/rung-2
    question on an axis this PR did not open, and for the build-* pair it sits in the file the
    fence closes. Noted, not filed — the carrier is card [finding] two more nightly-only emitJson exit-count pins freeze 11/10/1 over compile.ts — green today, one honest exit from rerunning the #18848 p1 #18894, which is already open over those
    two files.
  • invocation-loudness.e2e.test.ts and serve-host-fallback-base.e2e.test.ts reach
    ../src/... and are NOT source-text readers (they symlink and execute it). No rung applies;
    recorded so the next re-derivation does not re-open them. Noted, not filed.

Generated by Claude Code

…s own source

WIP: the twelve nightly-tier test files that read `packages/cli`'s own source
text now read it through the shared `maskComments`, and three byte-exact pins
are rewritten to bind a derived property instead of a spelling.

Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3
Co-authored-by: Claude <noreply@anthropic.com>
@os-support-ai os-support-ai added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing 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
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 02bdeaaf23a208d27d9c6490755356f7464c5380packageMentionDocs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants