Skip to content

fix(devx): check:cross-package-test-inputs sees the new URL, argument-position and climb-and-descend path spellings - #8899

Merged
os-project-manager merged 3 commits into
mainfrom
claude/issue-8698-cross-package-url-seed
Aug 15, 2026
Merged

fix(devx): check:cross-package-test-inputs sees the new URL, argument-position and climb-and-descend path spellings#8899
os-project-manager merged 3 commits into
mainfrom
claude/issue-8698-cross-package-url-seed

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#8698

Verification union re-run at 7f605e543 (tree clean), quoted throughout.

What the card asked, and what measuring it changed

The card offered three directions and the grading made direction 3 mandatory (name the recognised spellings where an author will see them) with 1 and 2 "bounded". Measuring them moved the answer:

Directions 1 and 2, implemented literally, do not fix the card's own headline example. The detector had a second, deeper blind spot the card does not name — it judged a binding by its final depth. A path that climbs past the package root and then descends into a sibling ends at a positive depth while addressing another package entirely, so it scored "inside" no matter how the seed was spelled. Adding a new URL seed on top of final-depth arithmetic catches one file repo-wide and still lets the card's spelling (1) through.

So the fix is three parts, all of which the card's example needs at once:

  1. new URL('…', import.meta.url) as a seed and chain step, bare or under fileURLToPath.
  2. Path expressions in argument position to an fs read — readFileSync(resolve(HERE, '…')) binds file contents, never a path, so a declaration-only scan sees no path at all in the line that does the escaping.
  3. The escape criterion is the shallowest depth a path reaches, not where it ends.

Plus, closing the same class one spelling further: import.meta.dirname / dirname(import.meta.filename). No test uses them today — which is the reason to accept them now rather than file them: the first author to reach for the modern seed would otherwise get silence.

Direction 3 (mandatory) — where an author actually looks

The recognised list is now a published constant (RECOGNISED_PATH_SPELLINGS), printed in the gate's failure text and mirrored in AGENTS.md under Build & Test, with the reason stated: a source scan sees only what it knows, so an unrecognised spelling yields no flag, which means no declaration, silently. Both places tell the author to extend the detector with a --self-test case rather than route around it.

Proof by ablation, not by a green run

A green gate proves nothing about what it can see, so every leg below is a mutation with the mutant verified real (sha + byte delta) and restoration proven byte-identical.

Control — main's detector over the same source tree, main's turbo.json:

OK: 9 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
CONTROL_EXIT=0

That green is over three packages with live, genuinely undeclared cross-package reads. This is not a synthetic ablation — main ships it today.

The card's exact two spellings, end-to-end through the real gate. A probe file in the undeclared @objectstack/objectql, reading a sibling package:

probemain's detectorthis PR
both card spellingsOK: 9 package(s) … all declared — exit 0RED, names @objectstack/objectql — exit 1
spelling (1) alone — readFileSync(fileURLToPath(new URL(…)), 'utf8')RED — exit 1
spelling (2) alone — readFileSync(resolve(HERE, …), 'utf8')RED — exit 1

Per-package ablation — delete one declaration, confirm the gate goes red for the right reason, naming the right test:

--- ABLATION: @objectstack/metadata-protocol
before: 09388ae… 35404 bytes after: 0af7ddee… 35139 bytes (-265)
mutation reached disk: YES | entry still present: no
- @objectstack/metadata-protocol has test(s) that read outside the package but declares no input radius.
packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts
EXIT=1 | restored byte-identical: true

Same shape for @objectstack/formula (names both of its tests) and @objectstack/downstream-contract. Each isolates a different newly-recognised mechanism: metadata-protocol the multi-line new URL in argument position, the other two the shallowest-depth criterion. All three re-confirmed at 7f605e543, tree clean after.

What the widened detector found — live defects, not hypotheticals

The escaping-package count moves 9 → 12. Every new flag was checked by hand against the source; zero false positives. The most consequential:

  • packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts:451 reads scripts/check-durability-degradation-log-level.mjs — a pin on a root gate's source, undeclared, so a change to that gate never re-ran it. Exactly the defect this gate exists to prevent, live on main.
  • packages/formula/src/rls-predicate.test.ts:188 pins packages/spec/src/security/rls.zod.ts; skill-catalog-sync.test.ts:19 pins the published formula skill.
  • packages/qa/downstream-contract/test/source-resolution.pin.test.ts:87 resolves every spec specifier against spec's real source tree.
  • packages/spec/scripts/file-description.test.ts:1001 and category-title.test.ts:44 walk the whole content/docs/references tree; spec declared only index.mdx.

Each newly declared glob is pinned to the read that justifies it, in a comment naming the test, per the file's existing convention. turbo.json gains matching #test inputs so Layer B hashes them — written from the remedy the gate itself prints.

Two things are deliberately not flagged, both documented in the code and AGENTS.md: a path landing in node_modules (an installed dependency is not a repo source input and no turbo glob can name it), and a path that climbs out and comes straight back in.

--self-test

12 → 26 cases. Every newly recognised spelling gained a pin, and so did every deliberate non-flag; the 12 pre-existing cases are untouched and still pass. A newly recognised shape with no pin is the next silent regression, so the constant and the pins move together.

Verification at 7f605e543 (tree clean)

Gate families re-derived from the actual diff via scripts/pm/dispatch-gates.mjs — it returned exactly the two the dispatch named, adding none for AGENTS.md or turbo.json.

check:cross-package-test-inputs EXIT=0
check:nul-bytes EXIT=0
check:pm-skill-id-lint EXIT=0 ← scans AGENTS.md; no issue numbers in the added prose
check:pm-skill-ratchet EXIT=0
node scripts/check-cross-package-test-inputs.mjs (ci.yml raw) EXIT=0
OK: 12 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.

No package sources are touched, so no package test suite is in scope and ESLint was not run locally — the worktree has no node_modules and a full install for lint-only value is a poor trade in a shared container. CI runs the farm.

Notes for the reviewer


Generated by Claude Code

…ment-position path spellings
The detector was blind in two independent ways. It recognised only
`dirname(fileURLToPath(import.meta.url))` and `__dirname` seeds bound to a
declaration, and it judged a binding by its FINAL depth — so a path that climbs
past the package root and descends into a sibling scored positive and was never
flagged.
Adds `new URL(<rel>, import.meta.url)` (bare and under fileURLToPath) as a seed
and chain step, scans path expressions in argument position to an fs read, and
switches the escape criterion to the shallowest depth the path reaches.
WIP: declarations for what it now finds still to come.
…e what the widened detector finds
Closes the same class one spelling further: import.meta.dirname is the modern
form of the two existing seeds and no test uses it yet, which is exactly why it
is worth accepting now — the first author to reach for it would otherwise get
silence rather than a declaration.
Declares the reads the widened detector newly sees (formula, metadata-protocol,
downstream-contract; wider globs for spec and dogfood) with matching turbo.json
inputs, and publishes the recognised spellings in the failure text + AGENTS.md.
@vercel

vercelBot commented Aug 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 15, 2026 3:49pm

Request Review

@github-actionsgithub-actionsBot added size/m documentation Improvements or additions to documentation labels Aug 15, 2026
@os-project-manageros-project-manager added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 15, 2026 — with Claude
@os-project-manager
os-project-manager marked this pull request as ready for review August 15, 2026 16:00
@os-project-manager
os-project-manager added this pull request to the merge queueAug 15, 2026
Merged via the queue into main with commit 85f5e78Aug 15, 2026
25 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-8698-cross-package-url-seed branch August 15, 2026 16:08
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

check:cross-package-test-inputs does not see a new URL(…, import.meta.url) seed, so an undeclared cross-package read passes green

2 participants

@os-project-manager@claude