Skip to content

fix(tooling): let the clocked-window rule see a load routed through a same-package helper - #19201

Merged
os-try-charles merged 2 commits into
mainfrom
claude/issue-17658-clocked-window-helper-reach
Sep 19, 2026
Merged

os-try-charles merged 2 commits into
mainfrom
claude/issue-17658-clocked-window-helper-reach

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Part of #17658

What was silent

The clocked-window rule classifies loads by scanning comment-masked source for a literal specifier sitting inside an import(...) / require(...) form. A wrapper offers no such site:

// the test file — the specifier is literal, but it is an ARGUMENT
const load = await loadOptionalPackage('@objectstack/cloud-connection');

// one frame down, in the same package's optional-package.ts
const module = await import(specifier);            // a VARIABLE

So the file earned no clocked entry and no moduleScope entry — both of the conditions the diagnostic needs, unmet at once — and the gate said nothing over a probe measured at 5005ms against a 5000ms testTimeout.

⭐ The live instance is not red today: packages/cli/src/utils/optional-package.test.ts:61 carries the module-top import '@objectstack/cloud-connection'; that #17180 landed, and lines 55-59 are a hand-written comment describing this exact blind spot. Until this PR the file was protected by a comment, not by a detector. ⛔ No file under packages/cli is touched here — that is the measured object.

Both candidate predicates, priced over the whole repo

Each was implemented against the real scan and run over every workspace package with tests. Baseline (today's reader) reports 0 clocked findings repo-wide.

candidate newly reported files true positives false positives
1 — a test file names a registered specifier as a string literal anywhere, with no module-scope load of it 418 (502 findings) 0 502
2 — follow ONE hop into a same-package helper and judge the load there 0 0 (the one call site it reaches is already compliant) 0

Candidate 1's 502 findings, classified by the reading that decides each — not one of them is a load:

  • 383 — a type-only import clause. import type { RemoteTable, SchemaValidationResult } from '@objectstack/spec/contracts' (packages/cli/src/commands/datasource/envelope-unwrap.test.ts:76), import type { IObjectQLEngine } from '@objectstack/spec/contracts' (packages/cli/src/commands/migrate/meta.stored-flow-resolution.integration.test.ts:26). Erased before anything resolves — this gate's own header states a type-only clause is accepted as neither a finding nor a compliance token.
  • 78 — a vi.mock registration. vi.mock('@objectstack/platform-objects/plugin', ...) (packages/cli/src/commands/secret/orphans.guards.test.ts:48), vi.mock('@objectstack/runtime', ...) (packages/cloud-connection/src/marketplace-install-local-corrupt-ledger.test.ts:42). The specifier names a module to REPLACE; no cold transform of the real dependency is paid at that site at all.
  • 25 — a plain string. JSON.stringify({ name: '@objectstack/spec', version: '1.0.0' }) writing a manifest into a tempdir (packages/cli/src/commands/doctor-unexamined-spec-tree.test.ts:341); require_.resolve('@objectstack/plugin-security') (packages/cli/src/utils/unmanaged-tables.integration.test.ts:61) — a resolve, not a load.
  • 16 — a specifier quoted inside generated source. "import { defineStack } from '@objectstack/spec';" as fixture file CONTENT (packages/cli/test/i18n-extract-check-dry-run.test.ts:89), and expect(survivor.stdout).toContain("import * as Data from '@objectstack/spec/data'") (packages/cli/test/generate-agent-retired.e2e.test.ts:150).

⇒ candidate 1 is not a reach fix, it is a different rule with a 100% false-positive rate on this tree. Candidate 2 landed.

Candidate 2 reaches exactly one call site in the repo — packages/cli/src/utils/optional-package.test.ts:139, loadOptionalPackage('@objectstack/cloud-connection'), via ./optional-package.js — and reports nothing, because line 61 pays the load at module top. That is the correct verdict: the file is compliant. Its binding detector finds a same-package loader in 13 test files (loadOptionalPackage, bootStack, createHostImporter, mergeRuntimeModule, probeOrganizations); none of the others hands it a registered specifier as a literal, so none is reported.

Red first, then green

The real instance, reproduced. Line 61 blanked in memory only (nothing written to packages/cli; git status packages/cli stayed clean), full gate over the real tree:

reader clocked findings
before this change 0 — the card's leg B, on today's tree
after this change 1, verbatim below
✗ packages/cli/src/utils/optional-package.test.ts:139: `loadOptionalPackage('@objectstack/cloud-connection')` is paid inside a function body — a CLOCKED window.
    The literal specifier is the ARGUMENT: `loadOptionalPackage` (via `./optional-package.js`) hands it to a dynamic
    `import()` of a VARIABLE one frame down, so the specifier is literal HERE and nowhere else.
    ...
      import '@objectstack/cloud-connection';

That remedy is the one-line change #17180 landed, and it is what the card's leg C printed when the load was spelled as a literal.

The self-test fixture, ablated. From the committed tree, helperRoutedLoadSites was disabled with an early return []. The mutation was proved on disk (marker occurrences 0 → 1, git hash-object 680a0a39 → different), and restored with git checkout HEAD -- ... verified by hash equality and an empty git diff HEAD.

=== --self-test with the one-hop reader disabled ===   EXIT=1
  - a load routed one hop through a same-package helper went unseen — the literal scanner is still the only reader (#17658)
  - the routed finding did not name the hop it followed — an author cannot tell it from a false positive
  - the routed finding printed no module-top import to add — the remedy is the same one, not a new one
  - the one-hop reader did not report exactly the one routed load this fixture pays in a clocked window

=== --self-test with the reader present ===            EXIT=0

4 of the 7 new cases drive red under the ablation; the other 3 are the negative controls (the non-loader callee, the bare-specifier callee, the paid control), which are vacuous without the reader by construction.

The control fixture. packages/clocked-helper-routed-paid is the same routed call in a file that already pays the load at module top — the remedy this gate prints, and the state the real instance is in today. It must report nothing, and does.

Scope held

  • No population change. The reported specifier is still one the package was already measured to resolve through dist/, read at the same granularity. @objectstack/cloud-connection is already in KNOWN_UNALIASED_TEST_IMPORTS['@objectstack/cli']; the gate already meant to cover it and simply could not SEE the call. The ledger is byte-identical.
  • No cold-load verb list. bootStack shows up in the binding scan and is deliberately not reported: the rule still requires a dynamic load, not a boot. That widening has an open question on the thread.
  • No census. Not run, not filed.
  • SELF_TEST_BATTERY_FLOOR stays 9. The clocked-window battery declares 12 to 19.

Gates

command verdict
node scripts/check-test-source-alias.mjs exit 0
node scripts/check-test-source-alias.mjs --self-test exit 0
pnpm check:test-source-alias exit 0
pnpm check:cross-package-test-inputs exit 0 — 255 self-test cases, 2036 test files judged
node scripts/check-self-test-wired.mjs + --self-test exit 0, exit 0
node scripts/check-scripts-symbol-anchors.mjs + --self-test exit 0, exit 0
node scripts/check-declaration-mirrors.mjs + --self-test exit 0, exit 0
pnpm check:nul-bytes exit 0 — 8994 files, no raw control bytes
all 29 families dispatch-gates --commands derives 29 run, 29 exit 0, 0 NOT-MEASURED (reconciled with --ran)
pnpm lint (repo-wide, eslint . --no-inline-config) exit 0 at a66ebc98

Type check: the diff is one .mjs gate script that no tsconfig program compiles and no TypeScript file imports (git grep finds only prose references), and it carries no .d.mts mirror — check-declaration-mirrors audits that in both directions and is green. So there is no type-check lane for this diff, which is why the dispatch-gates typecheck-shaped family names are not silence here.

Gate timing: 5.1s to 6.4s on the full scan; the projections a file needs are now computed once and handed to both readers instead of per rule.

Acceptance notes

Changeset: none, and skip-changeset is applied. Nothing already published moves — no published package's files[] reaches a repo-root scripts/ path (checked across every non-private workspace manifest), and the root manifest is private with no files[].

Out of scope, noted and not filed:


Generated by Claude Code

… same-package helper

The clocked-window rule in `check-test-source-alias` classifies loads by
scanning comment-masked source for a LITERAL specifier sitting inside an
`import(...)` / `require(...)` form. A wrapper offers no such site: the test
writes `loadOptionalPackage('@objectstack/cloud-connection')` and the helper
one frame down writes `await import(specifier)` — a VARIABLE. The file
therefore earned no `clocked` entry AND no `moduleScope` entry, so both of
the conditions the diagnostic needs were unmet at once and the gate stayed
silent over a probe measured at 5005ms against a 5000ms `testTimeout`.

The reader now follows ONE hop: a callee declared in the test file itself, or
imported through a RELATIVE specifier resolving inside the same package, whose
body performs a dynamic load of a non-literal specifier. Everything else is
unchanged — the population is still the specifiers the package was already
measured to resolve through `dist/`, read at the same granularity. A callee
reached through a bare specifier is another package's code and is not
followed; one that imports a literal is already read at its own site.

Measured over the whole repo: the reader newly reports zero files, because
the one call site it reaches (`packages/cli/src/utils/optional-package.test.ts`)
already pays the load at module top. With that module-top import ablated in
memory, the old reader reports nothing and the new one reports that call —
the defect this fixes, reproduced on today's tree.

The cheaper variant priced against it — flag a test file naming a registered
specifier as a string literal anywhere with no module-scope load — reports 502
findings across 418 files and not one true positive: 383 type-only import
clauses, 78 `vi.mock` registrations, 25 plain fixture strings and 16 specifiers
quoted inside generated-source literals.

Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
…lation

An `every()` over an empty finding list is vacuously true, so both text
assertions passed with the reader disabled and only the presence and the
count legs drove red. Pairing each with the count makes four of the seven
new cases fail when the reader is removed.

Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants