Skip to content

Commit b8feb55

Browse files
test(client): the envelope caller census never enters .cache/ (#22196)
Fixes #22153 Clause-②: no ## What changed One file, a test, which publishes nothing: `packages/client/src/envelope-caller-census.test.ts`. - `SKIP_DIRS` gains `.cache`. A docblock says why: when there is no `../objectui` sibling, `pnpm objectui:build` (`scripts/build-console.sh`) shallow-clones the objectui source tree into `.cache/objectui-SHA/`. That tree contains objectui's own SDK call site. - Section 1 gains a pin, `[#22153] never enters .cache/`. It runs on a throwaway root under the system temp directory: `mkdtempSync(join(tmpdir(), 'os-census-cache-'))`, removed in `finally`. - A planted `.cache/objectui-0123456789ab/` checkout leaves `scanCallSites` deep-equal: the same sites, the same receiver split and the same files-scanned count. - A positive control shows that the same walk and matcher do count the planted site when they are given it directly. So the equality comes from the skip, not from a fixture the census could never read. - The fixture text is built from parts. Section 6 gives the reason: this file sits inside the tree the census walks, so a whole call shape in it would itself be counted. ## Why `SKIP_DIRS` and not a tracked-files walk (PM reading H2) Triage's direction allows either. Measured at `8f395597`: - **It is the shape this repo already uses.** 34 of the 86 one-line `node_modules` skip sets in the tree already list `.cache`. Examples: every `packages/spec/src/**/*-retirement.test.ts` and `scripts/check-agent-test-spelling.mjs`. - **It drops nothing the census counts.** `.cache/` is gitignored (`.gitignore:44`), and `git ls-files | grep -cE '(^|/)\.cache/'` returns 0. Control: the same pattern for `.github/` returns 45. - **A `git ls-files` walk would add a git dependency this test does not have today.** Of the 12 tests in the tree that spawn git, none is in `packages/client`. It would also change whether an untracked file is counted before it is staged. No measured case needs either change. ## Reproduction and proof (PM reading H1 confirmed) I planted `.cache/objectui-test/packages/x/src/index.ts`, holding one `this.client.analytics.query(q)` call, in the worktree. Then I ran `pnpm --filter @objectstack/client exec vitest run --maxWorkers=2 src/envelope-caller-census.test.ts`: | tree | result | |---|---| | base `6ed0c0f3`, planted file present | 3 failed, 17 passed (20). `expected 29 to be 28`; the enumeration gains `.cache/objectui-test/packages/x/src/index.ts` (analytics.query, sdk) | | this branch `8f395597`, planted file present | 21 passed (21) | The planted file was removed afterwards. **Ablation.** Run from the committed state with `node scripts/ablation-replace.mjs`. Anchor `'out', '.cache',` became `'out', 'ABLATED-22153',`: the anchor count went 1 → 0 and the blob `cbf54580cb85` → `c2a77abdd38a`. After the restore the blob equals HEAD and `git diff HEAD` is empty. - Clean tree, no planted file: 1 failed, 20 passed. Only the new section-1 pin goes red (`filesScanned` 1 → 2, and the planted site appears). CI never has a `.cache/`, so it still catches the skip being removed. - Planted file present: 4 failed, 17 passed. The new pin goes red, and so do the three section-3 assertions. - A first attempt used the replacement `'out',`. The tool refused it before any test ran, because the replacement is a substring of the anchor (count 1 → 1). That attempt produced no reading. ## Tests and gates, head `8f395597` - `pnpm --filter @objectstack/client test`: 51 files, 653 passed. That is the 652 from before plus the new pin. - `pnpm --filter @objectstack/client typecheck`: exit 0. `check:test-typecheck` reports OK with 0 errors. The census file is in the `tsconfig.test.json` program (`tsc --listFilesOnly` finds it once). - `dispatch-gates --commands` over this diff derives 54 gates, the same list the dispatch named; `pnpm lint` (full repo) was run on top. All exit 0. - `check:skill-examples` and `check:dual-build-cjs-loads` first exited 3 (PREREQUISITE NOT MET, no `dist/`). After `turbo run build --filter=!@objectstack/docs`, both re-ran and exited 0. - `dispatch-gates --ran`: 54 derived, 54 run, 0 NOT-MEASURED, 0 UNRUN. - No changeset: a test file publishes nothing. ## Acceptance notes - **Scope (PM reading H3).** The card's full `pnpm test`, with the checkout present, turned only `@objectstack/client#test` red. No other test suite has a reproduced instance. The repo-root walkers under `scripts/` whose skip sets lack `.cache` have not been measured against a planted checkout. That is inference only, so nothing was filed. - **Source of the hazard.** `scripts/build-console.sh` clones into the repo root. Cloning outside the tree, or printing the `rm -rf .cache` advice, would retire the whole class. Not touched here: it is outside the claim's file surface. - **New scratch-dir site.** One `mkdtempSync(join(tmpdir(), ...))` under the system temp directory, removed in `finally`. --- _Generated by [Claude Code](https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7d7943d commit b8feb55

1 file changed

Lines changed: 51 additions & 2 deletions

File tree

‎packages/client/src/envelope-caller-census.test.ts‎

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@
125125
*/
126126

127127
import { describe, it, expect } from 'vitest';
128-
import { readdirSync, readFileSync, statSync } from 'node:fs';
128+
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
129+
import { tmpdir } from 'node:os';
129130
import { dirname, join, relative, resolve } from 'node:path';
130131
import { fileURLToPath } from 'node:url';
131132
// The `.mjs` specifier is deliberate; `scripts/js-comment-mask.d.mts` beside it
@@ -163,8 +164,19 @@ const METHODS: ReadonlyArray<readonly [namespace: string, method: string]> = [
163164
['automation', 'trigger'],
164165
];
165166

167+
/**
168+
* Directory NAMES the walk never enters, at any depth.
169+
*
170+
* [#22153] `.cache` is here because `pnpm objectui:build` (`scripts/build-console.sh`)
171+
* shallow-clones the whole objectui source tree into `.cache/objectui-<sha>/` when
172+
* there is no `../objectui` sibling, and that tree carries objectui's own SDK
173+
* call site. Walked, it is counted as a site of THIS repo and §3 reds on an
174+
* untouched `main` for anyone who followed the Console build. `.cache/` is
175+
* gitignored and no tracked path has a `.cache` segment, so skipping it drops
176+
* nothing this census is about. §1 pins it on a planted checkout.
177+
*/
166178
const SKIP_DIRS = new Set([
167-
'node_modules', 'dist', 'build', 'coverage', '.git', '.next', '.turbo', 'out',
179+
'node_modules', 'dist', 'build', 'coverage', '.git', '.next', '.turbo', 'out', '.cache',
168180
]);
169181
const CODE_EXT = /\.(ts|tsx|js|mjs|cjs)$/;
170182

@@ -657,6 +669,43 @@ describe('#13079 §1 — the population actually swept', () => {
657669
expect(tops.has('examples')).toBe(true);
658670
expect(tops.has('apps')).toBe(true);
659671
});
672+
673+
it('[#22153] never enters `.cache/` — an objectui checkout left by `pnpm objectui:build` moves no count', () => {
674+
// Assembled from parts for the reason §6 gives: this file is inside the
675+
// walked tree, so a call shape spelled whole here would BE a counted site.
676+
const NS = 'analytics';
677+
const OWN = `export const rows = async (client: any) => (await client.${NS}.query({ cube: 'orders' })).rows;\n`;
678+
const CHECKOUT = `export class Adapter {\n client: any;\n async aggregate(q: unknown) {\n return this.client.${NS}.query(q);\n }\n}\n`;
679+
const shape = (c: Census) => c.sites.map((s) => [s.file, s.method, s.receiver]);
680+
681+
// A throwaway root under the system temp directory, never this repo's own
682+
// `.cache/`: planting there would race every other walker in a parallel run.
683+
const root = mkdtempSync(join(tmpdir(), 'os-census-cache-'));
684+
try {
685+
mkdirSync(join(root, 'packages', 'client', 'src'), { recursive: true });
686+
writeFileSync(join(root, 'packages', 'client', 'src', 'own.test.ts'), OWN);
687+
const before = scanCallSites(root);
688+
expect(shape(before)).toEqual([['packages/client/src/own.test.ts', 'analytics.query', 'sdk']]);
689+
690+
// `build-console.sh` names its clone `.cache/objectui-<12-hex sha>`.
691+
const checkout = join(root, '.cache', 'objectui-0123456789ab');
692+
mkdirSync(join(checkout, 'packages', 'data-objectstack', 'src'), { recursive: true });
693+
writeFileSync(join(checkout, 'packages', 'data-objectstack', 'src', 'index.ts'), CHECKOUT);
694+
695+
// Positive control: the same walk and matcher DO count the planted
696+
// site once they are handed it, so the equality below is the skip at
697+
// work and not a fixture the census could never have read.
698+
expect(shape(scanCallSites(checkout))).toEqual([
699+
['packages/data-objectstack/src/index.ts', 'analytics.query', 'sdk'],
700+
]);
701+
702+
// THE PIN: sites, their receiver split and the files scanned are all
703+
// unchanged with the checkout present.
704+
expect(scanCallSites(root)).toEqual(before);
705+
} finally {
706+
rmSync(root, { recursive: true, force: true });
707+
}
708+
});
660709
});
661710

662711
describe('#13079 §2 — positive controls on the matcher itself', () => {

0 commit comments

Comments
 (0)