Skip to content

Declare the examples/** input radius for the cli and lint test suites - #8991

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-8946-examples-input-radius
Aug 16, 2026
Merged

Declare the examples/** input radius for the cli and lint test suites#8991
os-project-manager merged 2 commits into
mainfrom
claude/issue-8946-examples-input-radius

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#8946

packages/cli and packages/lint reach examples/app-showcase through test-only relative imports across a workspace boundary no package dependency declares. Both of CI's scoping layers judge those four tests by where they live, so an examples-only PR could not fail on them and the first signal was a red Test Core in the shared merge queue — which stalls every lane, not just the one that made the edit.

This declares the input radius those four tests actually read and mirrors it onto the matching #test tasks in turbo.json.

The card's framing, corrected

The title says these packages have no declared input radius. Measured: both already had a CROSS_PACKAGE_TEST_INPUTS entry (cli at :112, lint at :129) — neither declared any examples/ glob. So this extends two existing entries; their prose comments are extended alongside, not replaced.

Radius taken per package, not as one flat set

The card lists five paths. Re-taken from pnpm examples:live-imports on the merged inventory (PR #8945), the real read-set splits 3 / 3 per package, with contact.view.ts the only shared file:

packagedeclared example paths
@objectstack/cliui/views/contact.view.ts, data/objects/semantic-zoo.object.ts, ui/pages/task-triage.page.ts
@objectstack/lintdata/objects/contact.object.ts, system/translations/index.ts, ui/views/contact.view.ts

The union is the card's five, so the card was right about the set — but applying that flat list to both packages would have declared each package two files it never reads. Per-package is what landed.

Narrowness is also honest at the source level: the transitive relative-import closure of all five entry modules is the five modules themselves (their only other imports are @objectstack/spec subpaths), so the read set really is the file set, and there is no deeper app file that a per-file glob would miss.

The coupled consequence the dispatch did not name

Declaring the globs flips these four files from the invisible tier to inputs-declared in check-examples-live-imports.mjs, which made check:examples-live-imports go red with four STALE entry findings naming each one for deletion. That is the ratchet working as designed, so the four registry entries are deleted here and the registry is left empty with a comment saying why an empty registry is the goal state rather than dead code. The knowledge in those notes — which app module moves which assertion, and the _sections / _tabs namespace split that made one cli file flip while its sibling did not — is preserved as the justification comments on the new globs.

Why the classifier also changed — narrowing would otherwise weaken a guard

packagesWithExampleInputs keyed visibility on the package: any package declaring anything under examples/ had every one of its couplings reported as inputs-declared. With a whole-app glob that was nearly true. With a per-file radius it is not, and the failure is silent in the worst direction: a future live import in cli or lint to a fourth app file would be classified as visible, so the ratchet would stop asking for it while neither CI layer ran it — the exact blind spot this registry exists to close, reopened inside it, by this PR's own narrowing.

So coverage is now judged per coupling target. Today's classification is unchanged (all six targets are covered); what changes is that an uncovered target keeps the file in invisible, where the ratchet demands the radius be widened or the coupling recorded. The header comment already described the tier as requiring a matching glob, and the Map already carried the globs unused — the code had drifted from its own stated contract.

This is bounded: same defect class as the card, in a file no other claim holds (#8900 owns --union-into in the sibling script, which is untouched), and it adds no gate family beyond the one the STALE findings already put in scope.

Glob semantics are duplicated rather than imported, because check-cross-package-test-inputs.mjs runs its gate at module load — importing it would execute a second gate as a side effect of classifying. Both sides are pinned by --self-test.

Proof the declaration is not a no-op

Layer A — the affected subset. Simulating an examples-only PR (turbo ls --affected yielding zero packages) and running --union-into:

diff touchespackages unioned in
ui/pages/task-triage.page.ts (cli-only)@objectstack/cli, @objectstack/dogfood
system/translations/index.ts (lint-only)@objectstack/lint, @objectstack/dogfood
ui/views/contact.view.ts (shared)@objectstack/cli, @objectstack/lint, @objectstack/dogfood
ui/pages/my-work.page.ts (not declared)@objectstack/dogfood only

The last row is the narrowness half: an app file none of the four tests read does not pull either package in.

Reverse verification. The same shared-path input run against origin/main's script unions in @objectstack/dogfoodonly — cli and lint absent. Expected direction here is fewer packages, not red: the pre-change baseline is the blindness itself.

Layer B — the turbo cache.turbo run test --dry=json task hashes, measured:

tree state@objectstack/cli#test@objectstack/lint#test
baselineba98b5591af9996a40f3bf4f710b1882
touch task-triage.page.ts790edf2cfeb44429unchanged
touch translations/index.tsunchanged6ab05c42bcad4dc8
touch contact.view.tscd3d942e725463fbac157f4bd767dad0
touch my-work.page.tsunchangedunchanged

Removing the turbo.json mirror while keeping the script declaration fails --verify naming all six missing globs, so Layer B is enforced rather than merely written down.

The new precision guard. Dropping one glob from cli's #test inputs (a deliberately partial radius) fails the inventory by name: none of them covers: examples/app-showcase/src/ui/pages/task-triage.page.ts. Under the old package-granular check that state reported green.

All probe edits were reverted; git status clean at the union run.

Verification

Union re-run after the final commit, at bb7c03cb0, tree clean:

check:cross-package-test-inputs PASS (exit 0) 26/26 self-test; 12 packages declared
check:examples-live-imports PASS (exit 0) 31/31 self-test; 0 invisible, 6 inputs-declared, 63 graph-visible
node scripts/check-cross-package-test-inputs.mjs PASS (exit 0) the ci.yml invocation
check:nul-bytes PASS (exit 0)

Gate set re-derived from the real changed paths with node scripts/pm/dispatch-gates.mjs; it returned the two the dispatch named plus check:examples-live-imports, which the dispatch did not — the addition this PR's coupled edit put in scope.

The four coupled tests were run to confirm the declaration surfaces a green baseline rather than a latent red, after building the dependency closure (--filter '@objectstack/cli^...' --filter '@objectstack/lint^...' build):

cli i18n-section-coverage + i18n-tab-coverage 2 files, 38 tests passed
lint validate-translatable-sections + validate-translation-references 2 files, 68 tests passed

RECOGNISED_PATH_SPELLINGS and its AGENTS.md mirror are untouched, and no recognised path spelling was added, so that pair did not need to move. scripts/ and turbo.json are not published package source ⇒ skip-changeset.

Out of scope, deliberately

Whether these four tests should keep asserting over the live app is still open (#8515 made that fork package-by-package). Nothing is decoupled here — a declared radius makes today's coupling honest to CI without deciding that question, and it shrinks with the tests if the fork later resolves toward fixtures.

Generated by Claude Code


Generated by Claude Code

…uites
packages/cli and packages/lint reach examples/app-showcase through test-only
relative imports across a workspace boundary no package dependency declares.
Both of CI's scoping layers judge those four tests by where they live, so an
examples-only PR could not fail on them and the first signal was a red
Test Core in the shared merge queue -- which stalls every lane.
Extends the existing CROSS_PACKAGE_TEST_INPUTS entries for both packages with
the app modules their tests actually read, taken per package from the live
import inventory rather than as one flat set, and mirrors them onto the
matching #test tasks in turbo.json so the task cache moves with them too.
Also makes the live-import inventory's inputs-declared classification judge
coverage per coupling TARGET instead of per package. Without that, narrowing a
radius to individual files would let a package that declares one app file be
read as covering every coupling it has, so the next live import to a fourth
file would report as visible while neither CI layer ran it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm
… none
The undeclared-coupling message chose its wording from uncoveredTargets, which
is also non-empty when the package declares no examples glob at all -- so the
zero-glob case was told its globs did not cover the target. Choose on whether
any glob is declared instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm
@vercel

vercelBot commented Aug 16, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 16, 2026 4:31am

Request Review

@os-project-manageros-project-manager added tooling skip-changeset PR has no user-facing published change; bypasses the changeset gate labels Aug 16, 2026 — with Claude
@os-project-manager
os-project-manager marked this pull request as ready for review August 16, 2026 04:34
@os-project-manager
os-project-manager added this pull request to the merge queueAug 16, 2026
Merged via the queue into main with commit ab4bb08Aug 16, 2026
35 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-8946-examples-input-radius branch August 16, 2026 05:02
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-project-manager@claude