Skip to content

fix(devx): refuse an appended path filter that a baked positional already swallows (objectui#7814) - #9504

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-7814-vitest-argv-union-guard
Sep 14, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-7814-vitest-argv-union-guard

Conversation

@claude

@claude claude Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #7814

STEP 1 — the measurement, and it says YES

The question the dispatch put: can the guard, at the point it runs, see BOTH the baked packages/cli/ filter and the appended positional?

Captured out of the guard itself on origin/main (d7d0956568), by appending a dump inside assertCanonicalVitestInvocation during a real run of the card's command. Quoted, not summarised:

argv     : ["/opt/node22/bin/node",
            "/home/user/objectui-issue-7814/packages/cli/node_modules/vitest/vitest.mjs",
            "run", "--root", "../..",
            "packages/cli/",
            "packages/cli/src/__tests__/app-generator.test.ts"]
cwd      : /home/user/objectui-issue-7814/packages/cli
repoRoot : /home/user/objectui-issue-7814
parsed.positionals: ["packages/cli/", "packages/cli/src/__tests__/app-generator.test.ts"]
parsed.flags      : {"--root": "../.."}
verdict  : null

Both filters arrive in one positionals array, in one process (pid 16985), for all five config loads of that run — and the guard returned null every time. It could see the union and said nothing. ⇒ STEP 2 is reached.

The instrumented guard was restored byte-identically afterwards: git diff HEAD 0 bytes, on-disk blob back to 695d6f2b93bbed51c1ace196519c3ef2feda6eb4, probe marker count 0.

The card's numbers, re-measured on this base (not copied)

The card recorded 16 files / 246 tests vs 43 from 2026-09-06. Those are timestamps. On d7d0956568:

invocation files tests exit
pnpm --filter @object-ui/cli test packages/cli/src/__tests__/app-generator.test.ts 17 266 0
pnpm exec vitest run --root ../.. packages/cli/src/__tests__/app-generator.test.ts 1 47 0

Same file, same tree, same base. 266 against 47 — and the widened one is bit-identical to the bare pnpm --filter @object-ui/cli test, which also reports 17 / 266. That equality is the defect stated as a measurement: the appended path changed nothing.

STEP 2 — the smallest loud reading

evaluateVitestInvocation gains a subsumed-positional-filter verdict: refuse when one positional contains another as a substring. That is exactly how Vitest matches positionals — substring of the test file path, unioned — so a positional containing another admits a subset of what the other already admits, and adds zero files to the run.

The message names the union and hands back the form that does narrow. Real output of the card's own command on this branch:

  vitest 调用被拒绝:追加的路径过滤没有缩小范围,反而被并进了更宽的那个 (objectui#7814)

  位置参数: packages/cli/ packages/cli/src/__tests__/app-generator.test.ts
  其中 packages/cli/src/__tests__/app-generator.test.ts 被 packages/cli/ 整个包含。
  ...
    pnpm exec vitest run --root ../.. packages/cli/src/__tests__/app-generator.test.ts   # 就在当前目录(packages/cli/)

Exit status 1. The message is Chinese to match the three verdicts already in that file; making the fourth English would have left the guard bilingual.

Only ever refuses MORE — gates_weakened: NONE

The new check runs last, after double-dash-args, package-cwd and missing-path-filter. Every invocation refused before is refused with the same code now; the new verdict can only turn a former null into a refusal. Pinned as its own test.

Non-regression, measured:

  • pnpm --filter @object-ui/cli test (baked filter alone, the legitimate package-level run) → still allowed, exit 0, 17 / 266.
  • pnpm exec vitest run --root ../.. PATH (the form the message recommends) → exit 0, 1 / 47.
  • No package script and no workflow in this repo passes two positionals — every test script carries exactly one, so nothing existing trips the new verdict.

Ablation — the pin's control is the current silent-green run

Fix committed first, then scripts/vitest-invocation-guard.mjs alone reverted to the base blob and restored, each leg proved on disk by blob hash:

leg on-disk guard blob subsumed-positional-filter occurrences pin exit result
ablated (base guard, new pin) 695d6f2b93… 0 1 3 failed / 41 passed (44)
restored (fix) e5069f5263… 1 0 44 passed (44)

The three that fail without the fix: refuses the exact invocation the card measured, reads subsumption the way Vitest matches, yields to the older verdicts. git diff HEAD 0 bytes after restore.

Verification

  • pnpm exec vitest run scripts/158 files passed, 2 skipped; 4644 tests passed, exit 0. (Run whole rather than one file: nine other scripts/__tests__ files read this guard.)
  • pnpm exec tsc -p tsconfig.scripts.json --noEmit → exit 0.
  • pnpm exec eslint on both changed files → exit 0. One pre-existing warning (VITE_CONFIG_NAME unused) that is present at the base revision too, in a part of the file this diff does not touch.
  • check:control-bytes, check:new-line-citations, check:entry-guard, check:test-path-roots, check:shell-escape-residue → all exit 0.
  • node scripts/check-changeset-presence.mjs → exit 0, and it states the reading: 2 files changed, 0 of them published source of a package the release covers. No changeset owed.
  • node scripts/check-governed-queue-guard.mjs --test on both paths → NOT GOVERNED.

Heavy runs were serialised through scripts/pm/os-verify-lock.sh in the sibling checkout.

Scope held

⛔ No package's test script touched — the baked packages/PKG/ filter is a different card's question, and changing it would silently re-scope every package's test run. ⛔ AGENTS.md not touched (governed surface). One sentence there is now stale as a consequence of this change; it is called out in the report on the card rather than edited here.


Generated by Claude Code

…eady swallows (objectui#7814)

`pnpm --filter <pkg> test <one file>` does not narrow the run. objectui#3240
bakes a positional into every package `test` script (`vitest run --root ../..
packages/<pkg>/`), and Vitest UNIONS positional filters, so the appended path
sits beside the baked one and every file the baked filter admits still runs.
It exits 0 and prints a green summary for the PACKAGE, which reads exactly like
a narrowed run for the FILE — the count is real, the attribution is not.

Measured on this base, argv captured from inside the guard itself during a real
run: both filters arrive in ONE `positionals` array, in ONE process, and the
guard returned `null` for every config load of that run. It could see the union
and said nothing.

`evaluateVitestInvocation` now returns a `subsumed-positional-filter` verdict
when one positional contains another as a substring — which is exactly how
Vitest matches them, so the longer one admits a subset of what the shorter
already admits and changes the collected set by nothing. The message names
which filter was swallowed by which, and hands back the form that does narrow
(`pnpm exec vitest run --root ../.. <path>`), spelled for the caller's cwd.

The check runs LAST, after the three existing verdicts, so it only ever adds
refusals: every invocation refused before is still refused with the same code.
The bare `pnpm --filter <pkg> test` — the baked filter alone — stays allowed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VGeMu3p6qEFWR6K6GGLaW
@github-actions github-actions Bot added the tests label Sep 14, 2026
@os-try-charles
os-try-charles marked this pull request as ready for review September 14, 2026 13:08
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 14, 2026
Merged via the queue into main with commit 8fa7d69 Sep 14, 2026
35 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-7814-vitest-argv-union-guard branch September 14, 2026 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants