fix(test): point test:integration at projects that exist, and pin the script/config agreement - #7327

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project
Sep 2, 2026
Merged

fix(test): point test:integration at projects that exist, and pin the script/config agreement#7327
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#7096

Measured at head 652bd11e0.

The defect, confirmed

pnpm test:integration was vitest run --project ui while no project named ui existed, so the script could not run at all. Reproduced on the base commit ad3d4029a:

$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
INNER_EXIT=1

Why it drifted — history, not a typo

ui was a real project once. It was declared in vitest.workspace.ts (1bdba0693, 2026-02-28) as the complement of unit: every *.test.ts / *.test.tsx under packages, apps and examples except the four pure-logic packages.

85c872487 (2026-05-24) deleted that file, because Vitest 4 removed defineWorkspace and had been silently ignoring it. That took unitandui down together. unit was later re-declared as an inline project in vitest.config.mts (e850c5695) — a commit that never touched package.json — so pnpm test:unit started resolving again by accident. Nothing ever re-declared ui.

So the script had been naming a project that stopped existing three months earlier, and no run ever reported it: a script nobody invokes is a script nobody sees fail.

The change

- "test:integration": "vitest run --project ui",+ "test:integration": "vitest run --project dom --project dom-heavy",

The stale name moves to the projects that exist; no project named ui is added to vitest.config.mts. dom + dom-heavy is what ui covered, expressed in today's split — the two DOM tiers are the complement of unit among the root-level projects, which is precisely the population ui was defined as.

One judgement call, called out for review: apps/console is its own project today (name @object-ui/console, derived by Vitest from that directory's package.json), and the 2026-02 ui glob did include apps/*/src/**. It is not included here — that project is an app's own suite with its own alias config, not the renderer integration tier, and pnpm test covers it either way. Say the word and it becomes a third --project.

The pin

scripts/__tests__/package-scripts-vitest-projects.test.ts holds the two halves to each other: every --project name a root script passes must be a project this repo declares.

The assertion is a subset check (script names ⊆ declared names), so an over-wide declared set can never fail it — which makes every leg of the derivation silently vacuous unless it carries its own control. Each one does, asserted against a name measured on this tree:

  • the extractor collects every--project occurrence, not just the last. This is deliberate and is why parseVitestArgv from scripts/vitest-invocation-guard.mjs is not reused: that parser keeps flags in a plain object, so a repeated flag collapses to its last value — and --project dom --project dom-heavy is exactly that shape. Reusing it would have checked dom-heavy and quietly skipped dom. Controlled by a case asserting both names come back, plus --project=NAME and two no-match forms.
  • the inline projectsunit, dom, dom-heavy, and the env-gated dist — read off the config's source text. Controlled by asserting all four are found.
  • the project brought in by config path@object-ui/console, whose name appears as no name: literal anywhere in the repo. Without this leg a root script that legitimately named it would go red. Controlled by asserting it is found; measured with pnpm exec vitest list --project @object-ui/console, which resolves.
  • a negative control that the derivation does not answer yes to everything, deliberately using a nonsense name rather than ui, so the control stays a control instead of quietly becoming policy about which names are allowed.

Source text, not an import (ZONE 2 assumption 5). An import answers a different question: the dist project only materialises when OBJECTUI_DIST_PINS=1, so the imported project list depends on the environment while the declaration surface does not. Importing would also execute that file's module scope — including its --project dist argv guard, which throws — inside the test process.

Evidence

Every heavy run went through the shared verify lock (OS_VERIFY_LOCK_SLOT=dev-7096); exit codes captured after redirection, never across a pipe.

Pin red before the script change (pin written first, measured on the unmodified tree):

❯ |unit| scripts/__tests__/package-scripts-vitest-projects.test.ts (8 tests | 1 failed)
AssertionError: Root scripts filter on 1 project(s) that vitest.config.mts does not declare,
so those scripts cannot run:
pnpm test:integration → --project ui
Declared: @object-ui/console, dist, dom, dom-heavy, unit
Test Files 1 failed (1)
Tests 1 failed | 7 passed (8)
INNER_EXIT=1

The other 7 — every control — passed there, so the red is the subset check firing, not a broken derivation.

Pin green after, at head 652bd11e0:Test Files 1 passed (1) / Tests 8 passed (8), INNER_EXIT=0.

The card's acceptance — the script now starts and runs:

> object-ui-monorepo@ test:integration
> vitest run --project dom --project dom-heavy --shard=1/16
Test Files 92 passed (92)
Tests 1054 passed (1054)
INNER_EXIT=0

Declared narrowing: that is one shard of sixteen, not the whole tier. pnpm exec vitest list --filesOnly --project dom --project dom-heavy collects 1463 files (1429 dom + 34 dom-heavy) — both filters resolve, and an unsharded run of that surface does not fit this container's ~10-minute foreground cap. CI runs the same files as pnpm test --shard=n/4.

Ablation (after committing, so HEAD holds the fix). Only the script line was reverted to --project ui. The mutation was proven on disk by anchoring on both texts — injected "vitest run --project ui" present ×1, removed --project dom --project dom-heavy absent ×0 — and by blob hash bef1402ad… differing from the HEAD blob 1bb6f8fcc…; the script aborts rather than measure if either check fails. No rebuild leg applies: the pin reads both files off disk with fs.readFileSync, with no built artifact between them. Under the mutation the pin went red naming pnpm test:integration → --project ui, ABLATED_PIN_EXIT=1. Restore was git checkout HEAD -- ABSOLUTE_PATH (with an absolute-path trap … EXIT INT TERM) and is proven by state, not exit code: worktree blob 1bb6f8fccaaaed7c58a61a352e3ae2d3d803d1ae equals the HEAD blob, git diff HEAD empty, git status clean.

Other gates, all with their own verdict line:

commandverdict
pnpm exec vitest run scripts/__tests__/Test Files 97 passed (97) / Tests 2738 passed (2738), exit 0
pnpm test:unit --shard=1/8 (unchanged)Test Files 102 passed (102) / Tests 1546 passed (1546), exit 0
pnpm type-check:scriptsexit 0 — and tsc --listFiles confirms the new file is in the program (1 hit), so this is a measurement, not a vacuous pass
pnpm lint:root✖ 33 problems (0 errors, 33 warnings), exit 0; the new file alone lints clean at exit 0
pnpm lint:coverage✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
pnpm type-check:coverage✅ type-check coverage: 45/46 via type-check … / ✅ test type-check coverage: 41/41
node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6016 tracked text file(s); skipped 85 binary)
node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.
node scripts/check-governed-queue-guard.mjs --test …✅ NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.

No changeset — the presence gate's own verdict line above says none is owed: root package.json is not published source and the pin is a test.

Nothing else teaches this script.git grep -n "test:integration" origin/main returns exactly one hit, package.json:25. Nothing under AGENTS.md, CLAUDE.md, .claude/**, skills/**, content/docs/** or docs/** mentions it, so no governed or docs surface needed touching. For the record, skills/objectui/guides/testing.md:45 does name the project split (--project unit / dom / dom-heavy) and stays accurate after this change.

Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…he agreement
`pnpm test:integration` was `vitest run --project ui` while no project named
`ui` existed, so the script could not run at all:
$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
exit 1
The drift is structural, not a typo. `ui` was real once — declared in
`vitest.workspace.ts` (1bdba06) as the complement of `unit`: every
`*.test.{ts,tsx}` under `packages`/`apps`/`examples` except the four pure-logic
packages. 85c8724 deleted that file because Vitest 4 removed
`defineWorkspace` and had been silently ignoring it, which took `unit` and `ui`
down together. `unit` was later re-declared inline in `vitest.config.mts`
(e850c56, which never touched `package.json`), so `test:unit` started
resolving again by accident; nothing ever re-declared `ui`.
The modern equivalent of what `ui` covered is the two DOM tiers, so the script
now reads `--project dom --project dom-heavy`. No project named `ui` is added:
the stale name moves to the projects that exist rather than the config growing
one to match it.
`scripts/__tests__/package-scripts-vitest-projects.test.ts` pins the two halves
to each other — every `--project` name a root script passes must be a project
this repo declares. The assertion is a subset check, so an over-wide declared
set can never fail it; each leg of the derivation therefore carries its own
control asserted against a name measured on this tree, including the
`@object-ui/console` project, whose name Vitest derives from that directory's
`package.json` and which appears as no `name:` literal anywhere.
Measured: pin red before the script change (`pnpm test:integration → --project
ui`), 8/8 green after; `pnpm test:integration --shard=1/16` runs 92 files /
1054 tests green where it previously could not start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm test:integration cannot run — it filters on a vitest project named ui, which does not exist

2 participants

@os-litant@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(test): point test:integration at projects that exist, and pin the script/config agreement - #7327

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project
Sep 2, 2026
Merged

fix(test): point test:integration at projects that exist, and pin the script/config agreement#7327
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#7096

Measured at head 652bd11e0.

The defect, confirmed

pnpm test:integration was vitest run --project ui while no project named ui existed, so the script could not run at all. Reproduced on the base commit ad3d4029a:

$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
INNER_EXIT=1

Why it drifted — history, not a typo

ui was a real project once. It was declared in vitest.workspace.ts (1bdba0693, 2026-02-28) as the complement of unit: every *.test.ts / *.test.tsx under packages, apps and examples except the four pure-logic packages.

85c872487 (2026-05-24) deleted that file, because Vitest 4 removed defineWorkspace and had been silently ignoring it. That took unitandui down together. unit was later re-declared as an inline project in vitest.config.mts (e850c5695) — a commit that never touched package.json — so pnpm test:unit started resolving again by accident. Nothing ever re-declared ui.

So the script had been naming a project that stopped existing three months earlier, and no run ever reported it: a script nobody invokes is a script nobody sees fail.

The change

- "test:integration": "vitest run --project ui",+ "test:integration": "vitest run --project dom --project dom-heavy",

The stale name moves to the projects that exist; no project named ui is added to vitest.config.mts. dom + dom-heavy is what ui covered, expressed in today's split — the two DOM tiers are the complement of unit among the root-level projects, which is precisely the population ui was defined as.

One judgement call, called out for review: apps/console is its own project today (name @object-ui/console, derived by Vitest from that directory's package.json), and the 2026-02 ui glob did include apps/*/src/**. It is not included here — that project is an app's own suite with its own alias config, not the renderer integration tier, and pnpm test covers it either way. Say the word and it becomes a third --project.

The pin

scripts/__tests__/package-scripts-vitest-projects.test.ts holds the two halves to each other: every --project name a root script passes must be a project this repo declares.

The assertion is a subset check (script names ⊆ declared names), so an over-wide declared set can never fail it — which makes every leg of the derivation silently vacuous unless it carries its own control. Each one does, asserted against a name measured on this tree:

  • the extractor collects every--project occurrence, not just the last. This is deliberate and is why parseVitestArgv from scripts/vitest-invocation-guard.mjs is not reused: that parser keeps flags in a plain object, so a repeated flag collapses to its last value — and --project dom --project dom-heavy is exactly that shape. Reusing it would have checked dom-heavy and quietly skipped dom. Controlled by a case asserting both names come back, plus --project=NAME and two no-match forms.
  • the inline projectsunit, dom, dom-heavy, and the env-gated dist — read off the config's source text. Controlled by asserting all four are found.
  • the project brought in by config path@object-ui/console, whose name appears as no name: literal anywhere in the repo. Without this leg a root script that legitimately named it would go red. Controlled by asserting it is found; measured with pnpm exec vitest list --project @object-ui/console, which resolves.
  • a negative control that the derivation does not answer yes to everything, deliberately using a nonsense name rather than ui, so the control stays a control instead of quietly becoming policy about which names are allowed.

Source text, not an import (ZONE 2 assumption 5). An import answers a different question: the dist project only materialises when OBJECTUI_DIST_PINS=1, so the imported project list depends on the environment while the declaration surface does not. Importing would also execute that file's module scope — including its --project dist argv guard, which throws — inside the test process.

Evidence

Every heavy run went through the shared verify lock (OS_VERIFY_LOCK_SLOT=dev-7096); exit codes captured after redirection, never across a pipe.

Pin red before the script change (pin written first, measured on the unmodified tree):

❯ |unit| scripts/__tests__/package-scripts-vitest-projects.test.ts (8 tests | 1 failed)
AssertionError: Root scripts filter on 1 project(s) that vitest.config.mts does not declare,
so those scripts cannot run:
pnpm test:integration → --project ui
Declared: @object-ui/console, dist, dom, dom-heavy, unit
Test Files 1 failed (1)
Tests 1 failed | 7 passed (8)
INNER_EXIT=1

The other 7 — every control — passed there, so the red is the subset check firing, not a broken derivation.

Pin green after, at head 652bd11e0:Test Files 1 passed (1) / Tests 8 passed (8), INNER_EXIT=0.

The card's acceptance — the script now starts and runs:

> object-ui-monorepo@ test:integration
> vitest run --project dom --project dom-heavy --shard=1/16
Test Files 92 passed (92)
Tests 1054 passed (1054)
INNER_EXIT=0

Declared narrowing: that is one shard of sixteen, not the whole tier. pnpm exec vitest list --filesOnly --project dom --project dom-heavy collects 1463 files (1429 dom + 34 dom-heavy) — both filters resolve, and an unsharded run of that surface does not fit this container's ~10-minute foreground cap. CI runs the same files as pnpm test --shard=n/4.

Ablation (after committing, so HEAD holds the fix). Only the script line was reverted to --project ui. The mutation was proven on disk by anchoring on both texts — injected "vitest run --project ui" present ×1, removed --project dom --project dom-heavy absent ×0 — and by blob hash bef1402ad… differing from the HEAD blob 1bb6f8fcc…; the script aborts rather than measure if either check fails. No rebuild leg applies: the pin reads both files off disk with fs.readFileSync, with no built artifact between them. Under the mutation the pin went red naming pnpm test:integration → --project ui, ABLATED_PIN_EXIT=1. Restore was git checkout HEAD -- ABSOLUTE_PATH (with an absolute-path trap … EXIT INT TERM) and is proven by state, not exit code: worktree blob 1bb6f8fccaaaed7c58a61a352e3ae2d3d803d1ae equals the HEAD blob, git diff HEAD empty, git status clean.

Other gates, all with their own verdict line:

commandverdict
pnpm exec vitest run scripts/__tests__/Test Files 97 passed (97) / Tests 2738 passed (2738), exit 0
pnpm test:unit --shard=1/8 (unchanged)Test Files 102 passed (102) / Tests 1546 passed (1546), exit 0
pnpm type-check:scriptsexit 0 — and tsc --listFiles confirms the new file is in the program (1 hit), so this is a measurement, not a vacuous pass
pnpm lint:root✖ 33 problems (0 errors, 33 warnings), exit 0; the new file alone lints clean at exit 0
pnpm lint:coverage✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
pnpm type-check:coverage✅ type-check coverage: 45/46 via type-check … / ✅ test type-check coverage: 41/41
node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6016 tracked text file(s); skipped 85 binary)
node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.
node scripts/check-governed-queue-guard.mjs --test …✅ NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.

No changeset — the presence gate's own verdict line above says none is owed: root package.json is not published source and the pin is a test.

Nothing else teaches this script.git grep -n "test:integration" origin/main returns exactly one hit, package.json:25. Nothing under AGENTS.md, CLAUDE.md, .claude/**, skills/**, content/docs/** or docs/** mentions it, so no governed or docs surface needed touching. For the record, skills/objectui/guides/testing.md:45 does name the project split (--project unit / dom / dom-heavy) and stays accurate after this change.

Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…he agreement
`pnpm test:integration` was `vitest run --project ui` while no project named
`ui` existed, so the script could not run at all:
$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
exit 1
The drift is structural, not a typo. `ui` was real once — declared in
`vitest.workspace.ts` (1bdba06) as the complement of `unit`: every
`*.test.{ts,tsx}` under `packages`/`apps`/`examples` except the four pure-logic
packages. 85c8724 deleted that file because Vitest 4 removed
`defineWorkspace` and had been silently ignoring it, which took `unit` and `ui`
down together. `unit` was later re-declared inline in `vitest.config.mts`
(e850c56, which never touched `package.json`), so `test:unit` started
resolving again by accident; nothing ever re-declared `ui`.
The modern equivalent of what `ui` covered is the two DOM tiers, so the script
now reads `--project dom --project dom-heavy`. No project named `ui` is added:
the stale name moves to the projects that exist rather than the config growing
one to match it.
`scripts/__tests__/package-scripts-vitest-projects.test.ts` pins the two halves
to each other — every `--project` name a root script passes must be a project
this repo declares. The assertion is a subset check, so an over-wide declared
set can never fail it; each leg of the derivation therefore carries its own
control asserted against a name measured on this tree, including the
`@object-ui/console` project, whose name Vitest derives from that directory's
`package.json` and which appears as no `name:` literal anywhere.
Measured: pin red before the script change (`pnpm test:integration → --project
ui`), 8/8 green after; `pnpm test:integration --shard=1/16` runs 92 files /
1054 tests green where it previously could not start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm test:integration cannot run — it filters on a vitest project named ui, which does not exist

2 participants

@os-litant@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(test): point test:integration at projects that exist, and pin the script/config agreement - #7327

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project
Sep 2, 2026
Merged

fix(test): point test:integration at projects that exist, and pin the script/config agreement#7327
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#7096

Measured at head 652bd11e0.

The defect, confirmed

pnpm test:integration was vitest run --project ui while no project named ui existed, so the script could not run at all. Reproduced on the base commit ad3d4029a:

$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
INNER_EXIT=1

Why it drifted — history, not a typo

ui was a real project once. It was declared in vitest.workspace.ts (1bdba0693, 2026-02-28) as the complement of unit: every *.test.ts / *.test.tsx under packages, apps and examples except the four pure-logic packages.

85c872487 (2026-05-24) deleted that file, because Vitest 4 removed defineWorkspace and had been silently ignoring it. That took unitandui down together. unit was later re-declared as an inline project in vitest.config.mts (e850c5695) — a commit that never touched package.json — so pnpm test:unit started resolving again by accident. Nothing ever re-declared ui.

So the script had been naming a project that stopped existing three months earlier, and no run ever reported it: a script nobody invokes is a script nobody sees fail.

The change

- "test:integration": "vitest run --project ui",+ "test:integration": "vitest run --project dom --project dom-heavy",

The stale name moves to the projects that exist; no project named ui is added to vitest.config.mts. dom + dom-heavy is what ui covered, expressed in today's split — the two DOM tiers are the complement of unit among the root-level projects, which is precisely the population ui was defined as.

One judgement call, called out for review: apps/console is its own project today (name @object-ui/console, derived by Vitest from that directory's package.json), and the 2026-02 ui glob did include apps/*/src/**. It is not included here — that project is an app's own suite with its own alias config, not the renderer integration tier, and pnpm test covers it either way. Say the word and it becomes a third --project.

The pin

scripts/__tests__/package-scripts-vitest-projects.test.ts holds the two halves to each other: every --project name a root script passes must be a project this repo declares.

The assertion is a subset check (script names ⊆ declared names), so an over-wide declared set can never fail it — which makes every leg of the derivation silently vacuous unless it carries its own control. Each one does, asserted against a name measured on this tree:

  • the extractor collects every--project occurrence, not just the last. This is deliberate and is why parseVitestArgv from scripts/vitest-invocation-guard.mjs is not reused: that parser keeps flags in a plain object, so a repeated flag collapses to its last value — and --project dom --project dom-heavy is exactly that shape. Reusing it would have checked dom-heavy and quietly skipped dom. Controlled by a case asserting both names come back, plus --project=NAME and two no-match forms.
  • the inline projectsunit, dom, dom-heavy, and the env-gated dist — read off the config's source text. Controlled by asserting all four are found.
  • the project brought in by config path@object-ui/console, whose name appears as no name: literal anywhere in the repo. Without this leg a root script that legitimately named it would go red. Controlled by asserting it is found; measured with pnpm exec vitest list --project @object-ui/console, which resolves.
  • a negative control that the derivation does not answer yes to everything, deliberately using a nonsense name rather than ui, so the control stays a control instead of quietly becoming policy about which names are allowed.

Source text, not an import (ZONE 2 assumption 5). An import answers a different question: the dist project only materialises when OBJECTUI_DIST_PINS=1, so the imported project list depends on the environment while the declaration surface does not. Importing would also execute that file's module scope — including its --project dist argv guard, which throws — inside the test process.

Evidence

Every heavy run went through the shared verify lock (OS_VERIFY_LOCK_SLOT=dev-7096); exit codes captured after redirection, never across a pipe.

Pin red before the script change (pin written first, measured on the unmodified tree):

❯ |unit| scripts/__tests__/package-scripts-vitest-projects.test.ts (8 tests | 1 failed)
AssertionError: Root scripts filter on 1 project(s) that vitest.config.mts does not declare,
so those scripts cannot run:
pnpm test:integration → --project ui
Declared: @object-ui/console, dist, dom, dom-heavy, unit
Test Files 1 failed (1)
Tests 1 failed | 7 passed (8)
INNER_EXIT=1

The other 7 — every control — passed there, so the red is the subset check firing, not a broken derivation.

Pin green after, at head 652bd11e0:Test Files 1 passed (1) / Tests 8 passed (8), INNER_EXIT=0.

The card's acceptance — the script now starts and runs:

> object-ui-monorepo@ test:integration
> vitest run --project dom --project dom-heavy --shard=1/16
Test Files 92 passed (92)
Tests 1054 passed (1054)
INNER_EXIT=0

Declared narrowing: that is one shard of sixteen, not the whole tier. pnpm exec vitest list --filesOnly --project dom --project dom-heavy collects 1463 files (1429 dom + 34 dom-heavy) — both filters resolve, and an unsharded run of that surface does not fit this container's ~10-minute foreground cap. CI runs the same files as pnpm test --shard=n/4.

Ablation (after committing, so HEAD holds the fix). Only the script line was reverted to --project ui. The mutation was proven on disk by anchoring on both texts — injected "vitest run --project ui" present ×1, removed --project dom --project dom-heavy absent ×0 — and by blob hash bef1402ad… differing from the HEAD blob 1bb6f8fcc…; the script aborts rather than measure if either check fails. No rebuild leg applies: the pin reads both files off disk with fs.readFileSync, with no built artifact between them. Under the mutation the pin went red naming pnpm test:integration → --project ui, ABLATED_PIN_EXIT=1. Restore was git checkout HEAD -- ABSOLUTE_PATH (with an absolute-path trap … EXIT INT TERM) and is proven by state, not exit code: worktree blob 1bb6f8fccaaaed7c58a61a352e3ae2d3d803d1ae equals the HEAD blob, git diff HEAD empty, git status clean.

Other gates, all with their own verdict line:

commandverdict
pnpm exec vitest run scripts/__tests__/Test Files 97 passed (97) / Tests 2738 passed (2738), exit 0
pnpm test:unit --shard=1/8 (unchanged)Test Files 102 passed (102) / Tests 1546 passed (1546), exit 0
pnpm type-check:scriptsexit 0 — and tsc --listFiles confirms the new file is in the program (1 hit), so this is a measurement, not a vacuous pass
pnpm lint:root✖ 33 problems (0 errors, 33 warnings), exit 0; the new file alone lints clean at exit 0
pnpm lint:coverage✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
pnpm type-check:coverage✅ type-check coverage: 45/46 via type-check … / ✅ test type-check coverage: 41/41
node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6016 tracked text file(s); skipped 85 binary)
node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.
node scripts/check-governed-queue-guard.mjs --test …✅ NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.

No changeset — the presence gate's own verdict line above says none is owed: root package.json is not published source and the pin is a test.

Nothing else teaches this script.git grep -n "test:integration" origin/main returns exactly one hit, package.json:25. Nothing under AGENTS.md, CLAUDE.md, .claude/**, skills/**, content/docs/** or docs/** mentions it, so no governed or docs surface needed touching. For the record, skills/objectui/guides/testing.md:45 does name the project split (--project unit / dom / dom-heavy) and stays accurate after this change.

Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…he agreement
`pnpm test:integration` was `vitest run --project ui` while no project named
`ui` existed, so the script could not run at all:
$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
exit 1
The drift is structural, not a typo. `ui` was real once — declared in
`vitest.workspace.ts` (1bdba06) as the complement of `unit`: every
`*.test.{ts,tsx}` under `packages`/`apps`/`examples` except the four pure-logic
packages. 85c8724 deleted that file because Vitest 4 removed
`defineWorkspace` and had been silently ignoring it, which took `unit` and `ui`
down together. `unit` was later re-declared inline in `vitest.config.mts`
(e850c56, which never touched `package.json`), so `test:unit` started
resolving again by accident; nothing ever re-declared `ui`.
The modern equivalent of what `ui` covered is the two DOM tiers, so the script
now reads `--project dom --project dom-heavy`. No project named `ui` is added:
the stale name moves to the projects that exist rather than the config growing
one to match it.
`scripts/__tests__/package-scripts-vitest-projects.test.ts` pins the two halves
to each other — every `--project` name a root script passes must be a project
this repo declares. The assertion is a subset check, so an over-wide declared
set can never fail it; each leg of the derivation therefore carries its own
control asserted against a name measured on this tree, including the
`@object-ui/console` project, whose name Vitest derives from that directory's
`package.json` and which appears as no `name:` literal anywhere.
Measured: pin red before the script change (`pnpm test:integration → --project
ui`), 8/8 green after; `pnpm test:integration --shard=1/16` runs 92 files /
1054 tests green where it previously could not start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm test:integration cannot run — it filters on a vitest project named ui, which does not exist

2 participants

@os-litant@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(test): point test:integration at projects that exist, and pin the script/config agreement - #7327

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project
Sep 2, 2026
Merged

fix(test): point test:integration at projects that exist, and pin the script/config agreement#7327
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#7096

Measured at head 652bd11e0.

The defect, confirmed

pnpm test:integration was vitest run --project ui while no project named ui existed, so the script could not run at all. Reproduced on the base commit ad3d4029a:

$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
INNER_EXIT=1

Why it drifted — history, not a typo

ui was a real project once. It was declared in vitest.workspace.ts (1bdba0693, 2026-02-28) as the complement of unit: every *.test.ts / *.test.tsx under packages, apps and examples except the four pure-logic packages.

85c872487 (2026-05-24) deleted that file, because Vitest 4 removed defineWorkspace and had been silently ignoring it. That took unitandui down together. unit was later re-declared as an inline project in vitest.config.mts (e850c5695) — a commit that never touched package.json — so pnpm test:unit started resolving again by accident. Nothing ever re-declared ui.

So the script had been naming a project that stopped existing three months earlier, and no run ever reported it: a script nobody invokes is a script nobody sees fail.

The change

- "test:integration": "vitest run --project ui",+ "test:integration": "vitest run --project dom --project dom-heavy",

The stale name moves to the projects that exist; no project named ui is added to vitest.config.mts. dom + dom-heavy is what ui covered, expressed in today's split — the two DOM tiers are the complement of unit among the root-level projects, which is precisely the population ui was defined as.

One judgement call, called out for review: apps/console is its own project today (name @object-ui/console, derived by Vitest from that directory's package.json), and the 2026-02 ui glob did include apps/*/src/**. It is not included here — that project is an app's own suite with its own alias config, not the renderer integration tier, and pnpm test covers it either way. Say the word and it becomes a third --project.

The pin

scripts/__tests__/package-scripts-vitest-projects.test.ts holds the two halves to each other: every --project name a root script passes must be a project this repo declares.

The assertion is a subset check (script names ⊆ declared names), so an over-wide declared set can never fail it — which makes every leg of the derivation silently vacuous unless it carries its own control. Each one does, asserted against a name measured on this tree:

  • the extractor collects every--project occurrence, not just the last. This is deliberate and is why parseVitestArgv from scripts/vitest-invocation-guard.mjs is not reused: that parser keeps flags in a plain object, so a repeated flag collapses to its last value — and --project dom --project dom-heavy is exactly that shape. Reusing it would have checked dom-heavy and quietly skipped dom. Controlled by a case asserting both names come back, plus --project=NAME and two no-match forms.
  • the inline projectsunit, dom, dom-heavy, and the env-gated dist — read off the config's source text. Controlled by asserting all four are found.
  • the project brought in by config path@object-ui/console, whose name appears as no name: literal anywhere in the repo. Without this leg a root script that legitimately named it would go red. Controlled by asserting it is found; measured with pnpm exec vitest list --project @object-ui/console, which resolves.
  • a negative control that the derivation does not answer yes to everything, deliberately using a nonsense name rather than ui, so the control stays a control instead of quietly becoming policy about which names are allowed.

Source text, not an import (ZONE 2 assumption 5). An import answers a different question: the dist project only materialises when OBJECTUI_DIST_PINS=1, so the imported project list depends on the environment while the declaration surface does not. Importing would also execute that file's module scope — including its --project dist argv guard, which throws — inside the test process.

Evidence

Every heavy run went through the shared verify lock (OS_VERIFY_LOCK_SLOT=dev-7096); exit codes captured after redirection, never across a pipe.

Pin red before the script change (pin written first, measured on the unmodified tree):

❯ |unit| scripts/__tests__/package-scripts-vitest-projects.test.ts (8 tests | 1 failed)
AssertionError: Root scripts filter on 1 project(s) that vitest.config.mts does not declare,
so those scripts cannot run:
pnpm test:integration → --project ui
Declared: @object-ui/console, dist, dom, dom-heavy, unit
Test Files 1 failed (1)
Tests 1 failed | 7 passed (8)
INNER_EXIT=1

The other 7 — every control — passed there, so the red is the subset check firing, not a broken derivation.

Pin green after, at head 652bd11e0:Test Files 1 passed (1) / Tests 8 passed (8), INNER_EXIT=0.

The card's acceptance — the script now starts and runs:

> object-ui-monorepo@ test:integration
> vitest run --project dom --project dom-heavy --shard=1/16
Test Files 92 passed (92)
Tests 1054 passed (1054)
INNER_EXIT=0

Declared narrowing: that is one shard of sixteen, not the whole tier. pnpm exec vitest list --filesOnly --project dom --project dom-heavy collects 1463 files (1429 dom + 34 dom-heavy) — both filters resolve, and an unsharded run of that surface does not fit this container's ~10-minute foreground cap. CI runs the same files as pnpm test --shard=n/4.

Ablation (after committing, so HEAD holds the fix). Only the script line was reverted to --project ui. The mutation was proven on disk by anchoring on both texts — injected "vitest run --project ui" present ×1, removed --project dom --project dom-heavy absent ×0 — and by blob hash bef1402ad… differing from the HEAD blob 1bb6f8fcc…; the script aborts rather than measure if either check fails. No rebuild leg applies: the pin reads both files off disk with fs.readFileSync, with no built artifact between them. Under the mutation the pin went red naming pnpm test:integration → --project ui, ABLATED_PIN_EXIT=1. Restore was git checkout HEAD -- ABSOLUTE_PATH (with an absolute-path trap … EXIT INT TERM) and is proven by state, not exit code: worktree blob 1bb6f8fccaaaed7c58a61a352e3ae2d3d803d1ae equals the HEAD blob, git diff HEAD empty, git status clean.

Other gates, all with their own verdict line:

commandverdict
pnpm exec vitest run scripts/__tests__/Test Files 97 passed (97) / Tests 2738 passed (2738), exit 0
pnpm test:unit --shard=1/8 (unchanged)Test Files 102 passed (102) / Tests 1546 passed (1546), exit 0
pnpm type-check:scriptsexit 0 — and tsc --listFiles confirms the new file is in the program (1 hit), so this is a measurement, not a vacuous pass
pnpm lint:root✖ 33 problems (0 errors, 33 warnings), exit 0; the new file alone lints clean at exit 0
pnpm lint:coverage✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
pnpm type-check:coverage✅ type-check coverage: 45/46 via type-check … / ✅ test type-check coverage: 41/41
node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6016 tracked text file(s); skipped 85 binary)
node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.
node scripts/check-governed-queue-guard.mjs --test …✅ NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.

No changeset — the presence gate's own verdict line above says none is owed: root package.json is not published source and the pin is a test.

Nothing else teaches this script.git grep -n "test:integration" origin/main returns exactly one hit, package.json:25. Nothing under AGENTS.md, CLAUDE.md, .claude/**, skills/**, content/docs/** or docs/** mentions it, so no governed or docs surface needed touching. For the record, skills/objectui/guides/testing.md:45 does name the project split (--project unit / dom / dom-heavy) and stays accurate after this change.

Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…he agreement
`pnpm test:integration` was `vitest run --project ui` while no project named
`ui` existed, so the script could not run at all:
$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
exit 1
The drift is structural, not a typo. `ui` was real once — declared in
`vitest.workspace.ts` (1bdba06) as the complement of `unit`: every
`*.test.{ts,tsx}` under `packages`/`apps`/`examples` except the four pure-logic
packages. 85c8724 deleted that file because Vitest 4 removed
`defineWorkspace` and had been silently ignoring it, which took `unit` and `ui`
down together. `unit` was later re-declared inline in `vitest.config.mts`
(e850c56, which never touched `package.json`), so `test:unit` started
resolving again by accident; nothing ever re-declared `ui`.
The modern equivalent of what `ui` covered is the two DOM tiers, so the script
now reads `--project dom --project dom-heavy`. No project named `ui` is added:
the stale name moves to the projects that exist rather than the config growing
one to match it.
`scripts/__tests__/package-scripts-vitest-projects.test.ts` pins the two halves
to each other — every `--project` name a root script passes must be a project
this repo declares. The assertion is a subset check, so an over-wide declared
set can never fail it; each leg of the derivation therefore carries its own
control asserted against a name measured on this tree, including the
`@object-ui/console` project, whose name Vitest derives from that directory's
`package.json` and which appears as no `name:` literal anywhere.
Measured: pin red before the script change (`pnpm test:integration → --project
ui`), 8/8 green after; `pnpm test:integration --shard=1/16` runs 92 files /
1054 tests green where it previously could not start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm test:integration cannot run — it filters on a vitest project named ui, which does not exist

2 participants

@os-litant@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(test): point test:integration at projects that exist, and pin the script/config agreement - #7327

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project
Sep 2, 2026
Merged

fix(test): point test:integration at projects that exist, and pin the script/config agreement#7327
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#7096

Measured at head 652bd11e0.

The defect, confirmed

pnpm test:integration was vitest run --project ui while no project named ui existed, so the script could not run at all. Reproduced on the base commit ad3d4029a:

$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
INNER_EXIT=1

Why it drifted — history, not a typo

ui was a real project once. It was declared in vitest.workspace.ts (1bdba0693, 2026-02-28) as the complement of unit: every *.test.ts / *.test.tsx under packages, apps and examples except the four pure-logic packages.

85c872487 (2026-05-24) deleted that file, because Vitest 4 removed defineWorkspace and had been silently ignoring it. That took unitandui down together. unit was later re-declared as an inline project in vitest.config.mts (e850c5695) — a commit that never touched package.json — so pnpm test:unit started resolving again by accident. Nothing ever re-declared ui.

So the script had been naming a project that stopped existing three months earlier, and no run ever reported it: a script nobody invokes is a script nobody sees fail.

The change

- "test:integration": "vitest run --project ui",+ "test:integration": "vitest run --project dom --project dom-heavy",

The stale name moves to the projects that exist; no project named ui is added to vitest.config.mts. dom + dom-heavy is what ui covered, expressed in today's split — the two DOM tiers are the complement of unit among the root-level projects, which is precisely the population ui was defined as.

One judgement call, called out for review: apps/console is its own project today (name @object-ui/console, derived by Vitest from that directory's package.json), and the 2026-02 ui glob did include apps/*/src/**. It is not included here — that project is an app's own suite with its own alias config, not the renderer integration tier, and pnpm test covers it either way. Say the word and it becomes a third --project.

The pin

scripts/__tests__/package-scripts-vitest-projects.test.ts holds the two halves to each other: every --project name a root script passes must be a project this repo declares.

The assertion is a subset check (script names ⊆ declared names), so an over-wide declared set can never fail it — which makes every leg of the derivation silently vacuous unless it carries its own control. Each one does, asserted against a name measured on this tree:

  • the extractor collects every--project occurrence, not just the last. This is deliberate and is why parseVitestArgv from scripts/vitest-invocation-guard.mjs is not reused: that parser keeps flags in a plain object, so a repeated flag collapses to its last value — and --project dom --project dom-heavy is exactly that shape. Reusing it would have checked dom-heavy and quietly skipped dom. Controlled by a case asserting both names come back, plus --project=NAME and two no-match forms.
  • the inline projectsunit, dom, dom-heavy, and the env-gated dist — read off the config's source text. Controlled by asserting all four are found.
  • the project brought in by config path@object-ui/console, whose name appears as no name: literal anywhere in the repo. Without this leg a root script that legitimately named it would go red. Controlled by asserting it is found; measured with pnpm exec vitest list --project @object-ui/console, which resolves.
  • a negative control that the derivation does not answer yes to everything, deliberately using a nonsense name rather than ui, so the control stays a control instead of quietly becoming policy about which names are allowed.

Source text, not an import (ZONE 2 assumption 5). An import answers a different question: the dist project only materialises when OBJECTUI_DIST_PINS=1, so the imported project list depends on the environment while the declaration surface does not. Importing would also execute that file's module scope — including its --project dist argv guard, which throws — inside the test process.

Evidence

Every heavy run went through the shared verify lock (OS_VERIFY_LOCK_SLOT=dev-7096); exit codes captured after redirection, never across a pipe.

Pin red before the script change (pin written first, measured on the unmodified tree):

❯ |unit| scripts/__tests__/package-scripts-vitest-projects.test.ts (8 tests | 1 failed)
AssertionError: Root scripts filter on 1 project(s) that vitest.config.mts does not declare,
so those scripts cannot run:
pnpm test:integration → --project ui
Declared: @object-ui/console, dist, dom, dom-heavy, unit
Test Files 1 failed (1)
Tests 1 failed | 7 passed (8)
INNER_EXIT=1

The other 7 — every control — passed there, so the red is the subset check firing, not a broken derivation.

Pin green after, at head 652bd11e0:Test Files 1 passed (1) / Tests 8 passed (8), INNER_EXIT=0.

The card's acceptance — the script now starts and runs:

> object-ui-monorepo@ test:integration
> vitest run --project dom --project dom-heavy --shard=1/16
Test Files 92 passed (92)
Tests 1054 passed (1054)
INNER_EXIT=0

Declared narrowing: that is one shard of sixteen, not the whole tier. pnpm exec vitest list --filesOnly --project dom --project dom-heavy collects 1463 files (1429 dom + 34 dom-heavy) — both filters resolve, and an unsharded run of that surface does not fit this container's ~10-minute foreground cap. CI runs the same files as pnpm test --shard=n/4.

Ablation (after committing, so HEAD holds the fix). Only the script line was reverted to --project ui. The mutation was proven on disk by anchoring on both texts — injected "vitest run --project ui" present ×1, removed --project dom --project dom-heavy absent ×0 — and by blob hash bef1402ad… differing from the HEAD blob 1bb6f8fcc…; the script aborts rather than measure if either check fails. No rebuild leg applies: the pin reads both files off disk with fs.readFileSync, with no built artifact between them. Under the mutation the pin went red naming pnpm test:integration → --project ui, ABLATED_PIN_EXIT=1. Restore was git checkout HEAD -- ABSOLUTE_PATH (with an absolute-path trap … EXIT INT TERM) and is proven by state, not exit code: worktree blob 1bb6f8fccaaaed7c58a61a352e3ae2d3d803d1ae equals the HEAD blob, git diff HEAD empty, git status clean.

Other gates, all with their own verdict line:

commandverdict
pnpm exec vitest run scripts/__tests__/Test Files 97 passed (97) / Tests 2738 passed (2738), exit 0
pnpm test:unit --shard=1/8 (unchanged)Test Files 102 passed (102) / Tests 1546 passed (1546), exit 0
pnpm type-check:scriptsexit 0 — and tsc --listFiles confirms the new file is in the program (1 hit), so this is a measurement, not a vacuous pass
pnpm lint:root✖ 33 problems (0 errors, 33 warnings), exit 0; the new file alone lints clean at exit 0
pnpm lint:coverage✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
pnpm type-check:coverage✅ type-check coverage: 45/46 via type-check … / ✅ test type-check coverage: 41/41
node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6016 tracked text file(s); skipped 85 binary)
node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.
node scripts/check-governed-queue-guard.mjs --test …✅ NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.

No changeset — the presence gate's own verdict line above says none is owed: root package.json is not published source and the pin is a test.

Nothing else teaches this script.git grep -n "test:integration" origin/main returns exactly one hit, package.json:25. Nothing under AGENTS.md, CLAUDE.md, .claude/**, skills/**, content/docs/** or docs/** mentions it, so no governed or docs surface needed touching. For the record, skills/objectui/guides/testing.md:45 does name the project split (--project unit / dom / dom-heavy) and stays accurate after this change.

Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…he agreement
`pnpm test:integration` was `vitest run --project ui` while no project named
`ui` existed, so the script could not run at all:
$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
exit 1
The drift is structural, not a typo. `ui` was real once — declared in
`vitest.workspace.ts` (1bdba06) as the complement of `unit`: every
`*.test.{ts,tsx}` under `packages`/`apps`/`examples` except the four pure-logic
packages. 85c8724 deleted that file because Vitest 4 removed
`defineWorkspace` and had been silently ignoring it, which took `unit` and `ui`
down together. `unit` was later re-declared inline in `vitest.config.mts`
(e850c56, which never touched `package.json`), so `test:unit` started
resolving again by accident; nothing ever re-declared `ui`.
The modern equivalent of what `ui` covered is the two DOM tiers, so the script
now reads `--project dom --project dom-heavy`. No project named `ui` is added:
the stale name moves to the projects that exist rather than the config growing
one to match it.
`scripts/__tests__/package-scripts-vitest-projects.test.ts` pins the two halves
to each other — every `--project` name a root script passes must be a project
this repo declares. The assertion is a subset check, so an over-wide declared
set can never fail it; each leg of the derivation therefore carries its own
control asserted against a name measured on this tree, including the
`@object-ui/console` project, whose name Vitest derives from that directory's
`package.json` and which appears as no `name:` literal anywhere.
Measured: pin red before the script change (`pnpm test:integration → --project
ui`), 8/8 green after; `pnpm test:integration --shard=1/16` runs 92 files /
1054 tests green where it previously could not start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm test:integration cannot run — it filters on a vitest project named ui, which does not exist

2 participants

@os-litant@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(test): point test:integration at projects that exist, and pin the script/config agreement - #7327

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project
Sep 2, 2026
Merged

fix(test): point test:integration at projects that exist, and pin the script/config agreement#7327
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#7096

Measured at head 652bd11e0.

The defect, confirmed

pnpm test:integration was vitest run --project ui while no project named ui existed, so the script could not run at all. Reproduced on the base commit ad3d4029a:

$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
INNER_EXIT=1

Why it drifted — history, not a typo

ui was a real project once. It was declared in vitest.workspace.ts (1bdba0693, 2026-02-28) as the complement of unit: every *.test.ts / *.test.tsx under packages, apps and examples except the four pure-logic packages.

85c872487 (2026-05-24) deleted that file, because Vitest 4 removed defineWorkspace and had been silently ignoring it. That took unitandui down together. unit was later re-declared as an inline project in vitest.config.mts (e850c5695) — a commit that never touched package.json — so pnpm test:unit started resolving again by accident. Nothing ever re-declared ui.

So the script had been naming a project that stopped existing three months earlier, and no run ever reported it: a script nobody invokes is a script nobody sees fail.

The change

- "test:integration": "vitest run --project ui",+ "test:integration": "vitest run --project dom --project dom-heavy",

The stale name moves to the projects that exist; no project named ui is added to vitest.config.mts. dom + dom-heavy is what ui covered, expressed in today's split — the two DOM tiers are the complement of unit among the root-level projects, which is precisely the population ui was defined as.

One judgement call, called out for review: apps/console is its own project today (name @object-ui/console, derived by Vitest from that directory's package.json), and the 2026-02 ui glob did include apps/*/src/**. It is not included here — that project is an app's own suite with its own alias config, not the renderer integration tier, and pnpm test covers it either way. Say the word and it becomes a third --project.

The pin

scripts/__tests__/package-scripts-vitest-projects.test.ts holds the two halves to each other: every --project name a root script passes must be a project this repo declares.

The assertion is a subset check (script names ⊆ declared names), so an over-wide declared set can never fail it — which makes every leg of the derivation silently vacuous unless it carries its own control. Each one does, asserted against a name measured on this tree:

  • the extractor collects every--project occurrence, not just the last. This is deliberate and is why parseVitestArgv from scripts/vitest-invocation-guard.mjs is not reused: that parser keeps flags in a plain object, so a repeated flag collapses to its last value — and --project dom --project dom-heavy is exactly that shape. Reusing it would have checked dom-heavy and quietly skipped dom. Controlled by a case asserting both names come back, plus --project=NAME and two no-match forms.
  • the inline projectsunit, dom, dom-heavy, and the env-gated dist — read off the config's source text. Controlled by asserting all four are found.
  • the project brought in by config path@object-ui/console, whose name appears as no name: literal anywhere in the repo. Without this leg a root script that legitimately named it would go red. Controlled by asserting it is found; measured with pnpm exec vitest list --project @object-ui/console, which resolves.
  • a negative control that the derivation does not answer yes to everything, deliberately using a nonsense name rather than ui, so the control stays a control instead of quietly becoming policy about which names are allowed.

Source text, not an import (ZONE 2 assumption 5). An import answers a different question: the dist project only materialises when OBJECTUI_DIST_PINS=1, so the imported project list depends on the environment while the declaration surface does not. Importing would also execute that file's module scope — including its --project dist argv guard, which throws — inside the test process.

Evidence

Every heavy run went through the shared verify lock (OS_VERIFY_LOCK_SLOT=dev-7096); exit codes captured after redirection, never across a pipe.

Pin red before the script change (pin written first, measured on the unmodified tree):

❯ |unit| scripts/__tests__/package-scripts-vitest-projects.test.ts (8 tests | 1 failed)
AssertionError: Root scripts filter on 1 project(s) that vitest.config.mts does not declare,
so those scripts cannot run:
pnpm test:integration → --project ui
Declared: @object-ui/console, dist, dom, dom-heavy, unit
Test Files 1 failed (1)
Tests 1 failed | 7 passed (8)
INNER_EXIT=1

The other 7 — every control — passed there, so the red is the subset check firing, not a broken derivation.

Pin green after, at head 652bd11e0:Test Files 1 passed (1) / Tests 8 passed (8), INNER_EXIT=0.

The card's acceptance — the script now starts and runs:

> object-ui-monorepo@ test:integration
> vitest run --project dom --project dom-heavy --shard=1/16
Test Files 92 passed (92)
Tests 1054 passed (1054)
INNER_EXIT=0

Declared narrowing: that is one shard of sixteen, not the whole tier. pnpm exec vitest list --filesOnly --project dom --project dom-heavy collects 1463 files (1429 dom + 34 dom-heavy) — both filters resolve, and an unsharded run of that surface does not fit this container's ~10-minute foreground cap. CI runs the same files as pnpm test --shard=n/4.

Ablation (after committing, so HEAD holds the fix). Only the script line was reverted to --project ui. The mutation was proven on disk by anchoring on both texts — injected "vitest run --project ui" present ×1, removed --project dom --project dom-heavy absent ×0 — and by blob hash bef1402ad… differing from the HEAD blob 1bb6f8fcc…; the script aborts rather than measure if either check fails. No rebuild leg applies: the pin reads both files off disk with fs.readFileSync, with no built artifact between them. Under the mutation the pin went red naming pnpm test:integration → --project ui, ABLATED_PIN_EXIT=1. Restore was git checkout HEAD -- ABSOLUTE_PATH (with an absolute-path trap … EXIT INT TERM) and is proven by state, not exit code: worktree blob 1bb6f8fccaaaed7c58a61a352e3ae2d3d803d1ae equals the HEAD blob, git diff HEAD empty, git status clean.

Other gates, all with their own verdict line:

commandverdict
pnpm exec vitest run scripts/__tests__/Test Files 97 passed (97) / Tests 2738 passed (2738), exit 0
pnpm test:unit --shard=1/8 (unchanged)Test Files 102 passed (102) / Tests 1546 passed (1546), exit 0
pnpm type-check:scriptsexit 0 — and tsc --listFiles confirms the new file is in the program (1 hit), so this is a measurement, not a vacuous pass
pnpm lint:root✖ 33 problems (0 errors, 33 warnings), exit 0; the new file alone lints clean at exit 0
pnpm lint:coverage✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
pnpm type-check:coverage✅ type-check coverage: 45/46 via type-check … / ✅ test type-check coverage: 41/41
node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6016 tracked text file(s); skipped 85 binary)
node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.
node scripts/check-governed-queue-guard.mjs --test …✅ NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.

No changeset — the presence gate's own verdict line above says none is owed: root package.json is not published source and the pin is a test.

Nothing else teaches this script.git grep -n "test:integration" origin/main returns exactly one hit, package.json:25. Nothing under AGENTS.md, CLAUDE.md, .claude/**, skills/**, content/docs/** or docs/** mentions it, so no governed or docs surface needed touching. For the record, skills/objectui/guides/testing.md:45 does name the project split (--project unit / dom / dom-heavy) and stays accurate after this change.

Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…he agreement
`pnpm test:integration` was `vitest run --project ui` while no project named
`ui` existed, so the script could not run at all:
$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
exit 1
The drift is structural, not a typo. `ui` was real once — declared in
`vitest.workspace.ts` (1bdba06) as the complement of `unit`: every
`*.test.{ts,tsx}` under `packages`/`apps`/`examples` except the four pure-logic
packages. 85c8724 deleted that file because Vitest 4 removed
`defineWorkspace` and had been silently ignoring it, which took `unit` and `ui`
down together. `unit` was later re-declared inline in `vitest.config.mts`
(e850c56, which never touched `package.json`), so `test:unit` started
resolving again by accident; nothing ever re-declared `ui`.
The modern equivalent of what `ui` covered is the two DOM tiers, so the script
now reads `--project dom --project dom-heavy`. No project named `ui` is added:
the stale name moves to the projects that exist rather than the config growing
one to match it.
`scripts/__tests__/package-scripts-vitest-projects.test.ts` pins the two halves
to each other — every `--project` name a root script passes must be a project
this repo declares. The assertion is a subset check, so an over-wide declared
set can never fail it; each leg of the derivation therefore carries its own
control asserted against a name measured on this tree, including the
`@object-ui/console` project, whose name Vitest derives from that directory's
`package.json` and which appears as no `name:` literal anywhere.
Measured: pin red before the script change (`pnpm test:integration → --project
ui`), 8/8 green after; `pnpm test:integration --shard=1/16` runs 92 files /
1054 tests green where it previously could not start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm test:integration cannot run — it filters on a vitest project named ui, which does not exist

2 participants

@os-litant@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(test): point test:integration at projects that exist, and pin the script/config agreement - #7327

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project
Sep 2, 2026
Merged

fix(test): point test:integration at projects that exist, and pin the script/config agreement#7327
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#7096

Measured at head 652bd11e0.

The defect, confirmed

pnpm test:integration was vitest run --project ui while no project named ui existed, so the script could not run at all. Reproduced on the base commit ad3d4029a:

$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
INNER_EXIT=1

Why it drifted — history, not a typo

ui was a real project once. It was declared in vitest.workspace.ts (1bdba0693, 2026-02-28) as the complement of unit: every *.test.ts / *.test.tsx under packages, apps and examples except the four pure-logic packages.

85c872487 (2026-05-24) deleted that file, because Vitest 4 removed defineWorkspace and had been silently ignoring it. That took unitandui down together. unit was later re-declared as an inline project in vitest.config.mts (e850c5695) — a commit that never touched package.json — so pnpm test:unit started resolving again by accident. Nothing ever re-declared ui.

So the script had been naming a project that stopped existing three months earlier, and no run ever reported it: a script nobody invokes is a script nobody sees fail.

The change

- "test:integration": "vitest run --project ui",+ "test:integration": "vitest run --project dom --project dom-heavy",

The stale name moves to the projects that exist; no project named ui is added to vitest.config.mts. dom + dom-heavy is what ui covered, expressed in today's split — the two DOM tiers are the complement of unit among the root-level projects, which is precisely the population ui was defined as.

One judgement call, called out for review: apps/console is its own project today (name @object-ui/console, derived by Vitest from that directory's package.json), and the 2026-02 ui glob did include apps/*/src/**. It is not included here — that project is an app's own suite with its own alias config, not the renderer integration tier, and pnpm test covers it either way. Say the word and it becomes a third --project.

The pin

scripts/__tests__/package-scripts-vitest-projects.test.ts holds the two halves to each other: every --project name a root script passes must be a project this repo declares.

The assertion is a subset check (script names ⊆ declared names), so an over-wide declared set can never fail it — which makes every leg of the derivation silently vacuous unless it carries its own control. Each one does, asserted against a name measured on this tree:

  • the extractor collects every--project occurrence, not just the last. This is deliberate and is why parseVitestArgv from scripts/vitest-invocation-guard.mjs is not reused: that parser keeps flags in a plain object, so a repeated flag collapses to its last value — and --project dom --project dom-heavy is exactly that shape. Reusing it would have checked dom-heavy and quietly skipped dom. Controlled by a case asserting both names come back, plus --project=NAME and two no-match forms.
  • the inline projectsunit, dom, dom-heavy, and the env-gated dist — read off the config's source text. Controlled by asserting all four are found.
  • the project brought in by config path@object-ui/console, whose name appears as no name: literal anywhere in the repo. Without this leg a root script that legitimately named it would go red. Controlled by asserting it is found; measured with pnpm exec vitest list --project @object-ui/console, which resolves.
  • a negative control that the derivation does not answer yes to everything, deliberately using a nonsense name rather than ui, so the control stays a control instead of quietly becoming policy about which names are allowed.

Source text, not an import (ZONE 2 assumption 5). An import answers a different question: the dist project only materialises when OBJECTUI_DIST_PINS=1, so the imported project list depends on the environment while the declaration surface does not. Importing would also execute that file's module scope — including its --project dist argv guard, which throws — inside the test process.

Evidence

Every heavy run went through the shared verify lock (OS_VERIFY_LOCK_SLOT=dev-7096); exit codes captured after redirection, never across a pipe.

Pin red before the script change (pin written first, measured on the unmodified tree):

❯ |unit| scripts/__tests__/package-scripts-vitest-projects.test.ts (8 tests | 1 failed)
AssertionError: Root scripts filter on 1 project(s) that vitest.config.mts does not declare,
so those scripts cannot run:
pnpm test:integration → --project ui
Declared: @object-ui/console, dist, dom, dom-heavy, unit
Test Files 1 failed (1)
Tests 1 failed | 7 passed (8)
INNER_EXIT=1

The other 7 — every control — passed there, so the red is the subset check firing, not a broken derivation.

Pin green after, at head 652bd11e0:Test Files 1 passed (1) / Tests 8 passed (8), INNER_EXIT=0.

The card's acceptance — the script now starts and runs:

> object-ui-monorepo@ test:integration
> vitest run --project dom --project dom-heavy --shard=1/16
Test Files 92 passed (92)
Tests 1054 passed (1054)
INNER_EXIT=0

Declared narrowing: that is one shard of sixteen, not the whole tier. pnpm exec vitest list --filesOnly --project dom --project dom-heavy collects 1463 files (1429 dom + 34 dom-heavy) — both filters resolve, and an unsharded run of that surface does not fit this container's ~10-minute foreground cap. CI runs the same files as pnpm test --shard=n/4.

Ablation (after committing, so HEAD holds the fix). Only the script line was reverted to --project ui. The mutation was proven on disk by anchoring on both texts — injected "vitest run --project ui" present ×1, removed --project dom --project dom-heavy absent ×0 — and by blob hash bef1402ad… differing from the HEAD blob 1bb6f8fcc…; the script aborts rather than measure if either check fails. No rebuild leg applies: the pin reads both files off disk with fs.readFileSync, with no built artifact between them. Under the mutation the pin went red naming pnpm test:integration → --project ui, ABLATED_PIN_EXIT=1. Restore was git checkout HEAD -- ABSOLUTE_PATH (with an absolute-path trap … EXIT INT TERM) and is proven by state, not exit code: worktree blob 1bb6f8fccaaaed7c58a61a352e3ae2d3d803d1ae equals the HEAD blob, git diff HEAD empty, git status clean.

Other gates, all with their own verdict line:

commandverdict
pnpm exec vitest run scripts/__tests__/Test Files 97 passed (97) / Tests 2738 passed (2738), exit 0
pnpm test:unit --shard=1/8 (unchanged)Test Files 102 passed (102) / Tests 1546 passed (1546), exit 0
pnpm type-check:scriptsexit 0 — and tsc --listFiles confirms the new file is in the program (1 hit), so this is a measurement, not a vacuous pass
pnpm lint:root✖ 33 problems (0 errors, 33 warnings), exit 0; the new file alone lints clean at exit 0
pnpm lint:coverage✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
pnpm type-check:coverage✅ type-check coverage: 45/46 via type-check … / ✅ test type-check coverage: 41/41
node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6016 tracked text file(s); skipped 85 binary)
node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.
node scripts/check-governed-queue-guard.mjs --test …✅ NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.

No changeset — the presence gate's own verdict line above says none is owed: root package.json is not published source and the pin is a test.

Nothing else teaches this script.git grep -n "test:integration" origin/main returns exactly one hit, package.json:25. Nothing under AGENTS.md, CLAUDE.md, .claude/**, skills/**, content/docs/** or docs/** mentions it, so no governed or docs surface needed touching. For the record, skills/objectui/guides/testing.md:45 does name the project split (--project unit / dom / dom-heavy) and stays accurate after this change.

Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…he agreement
`pnpm test:integration` was `vitest run --project ui` while no project named
`ui` existed, so the script could not run at all:
$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
exit 1
The drift is structural, not a typo. `ui` was real once — declared in
`vitest.workspace.ts` (1bdba06) as the complement of `unit`: every
`*.test.{ts,tsx}` under `packages`/`apps`/`examples` except the four pure-logic
packages. 85c8724 deleted that file because Vitest 4 removed
`defineWorkspace` and had been silently ignoring it, which took `unit` and `ui`
down together. `unit` was later re-declared inline in `vitest.config.mts`
(e850c56, which never touched `package.json`), so `test:unit` started
resolving again by accident; nothing ever re-declared `ui`.
The modern equivalent of what `ui` covered is the two DOM tiers, so the script
now reads `--project dom --project dom-heavy`. No project named `ui` is added:
the stale name moves to the projects that exist rather than the config growing
one to match it.
`scripts/__tests__/package-scripts-vitest-projects.test.ts` pins the two halves
to each other — every `--project` name a root script passes must be a project
this repo declares. The assertion is a subset check, so an over-wide declared
set can never fail it; each leg of the derivation therefore carries its own
control asserted against a name measured on this tree, including the
`@object-ui/console` project, whose name Vitest derives from that directory's
`package.json` and which appears as no `name:` literal anywhere.
Measured: pin red before the script change (`pnpm test:integration → --project
ui`), 8/8 green after; `pnpm test:integration --shard=1/16` runs 92 files /
1054 tests green where it previously could not start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm test:integration cannot run — it filters on a vitest project named ui, which does not exist

2 participants

@os-litant@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(test): point test:integration at projects that exist, and pin the script/config agreement - #7327

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project
Sep 2, 2026
Merged

fix(test): point test:integration at projects that exist, and pin the script/config agreement#7327
os-litant merged 1 commit into
mainfrom
claude/issue-7096-test-integration-project

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#7096

Measured at head 652bd11e0.

The defect, confirmed

pnpm test:integration was vitest run --project ui while no project named ui existed, so the script could not run at all. Reproduced on the base commit ad3d4029a:

$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
INNER_EXIT=1

Why it drifted — history, not a typo

ui was a real project once. It was declared in vitest.workspace.ts (1bdba0693, 2026-02-28) as the complement of unit: every *.test.ts / *.test.tsx under packages, apps and examples except the four pure-logic packages.

85c872487 (2026-05-24) deleted that file, because Vitest 4 removed defineWorkspace and had been silently ignoring it. That took unitandui down together. unit was later re-declared as an inline project in vitest.config.mts (e850c5695) — a commit that never touched package.json — so pnpm test:unit started resolving again by accident. Nothing ever re-declared ui.

So the script had been naming a project that stopped existing three months earlier, and no run ever reported it: a script nobody invokes is a script nobody sees fail.

The change

- "test:integration": "vitest run --project ui",+ "test:integration": "vitest run --project dom --project dom-heavy",

The stale name moves to the projects that exist; no project named ui is added to vitest.config.mts. dom + dom-heavy is what ui covered, expressed in today's split — the two DOM tiers are the complement of unit among the root-level projects, which is precisely the population ui was defined as.

One judgement call, called out for review: apps/console is its own project today (name @object-ui/console, derived by Vitest from that directory's package.json), and the 2026-02 ui glob did include apps/*/src/**. It is not included here — that project is an app's own suite with its own alias config, not the renderer integration tier, and pnpm test covers it either way. Say the word and it becomes a third --project.

The pin

scripts/__tests__/package-scripts-vitest-projects.test.ts holds the two halves to each other: every --project name a root script passes must be a project this repo declares.

The assertion is a subset check (script names ⊆ declared names), so an over-wide declared set can never fail it — which makes every leg of the derivation silently vacuous unless it carries its own control. Each one does, asserted against a name measured on this tree:

  • the extractor collects every--project occurrence, not just the last. This is deliberate and is why parseVitestArgv from scripts/vitest-invocation-guard.mjs is not reused: that parser keeps flags in a plain object, so a repeated flag collapses to its last value — and --project dom --project dom-heavy is exactly that shape. Reusing it would have checked dom-heavy and quietly skipped dom. Controlled by a case asserting both names come back, plus --project=NAME and two no-match forms.
  • the inline projectsunit, dom, dom-heavy, and the env-gated dist — read off the config's source text. Controlled by asserting all four are found.
  • the project brought in by config path@object-ui/console, whose name appears as no name: literal anywhere in the repo. Without this leg a root script that legitimately named it would go red. Controlled by asserting it is found; measured with pnpm exec vitest list --project @object-ui/console, which resolves.
  • a negative control that the derivation does not answer yes to everything, deliberately using a nonsense name rather than ui, so the control stays a control instead of quietly becoming policy about which names are allowed.

Source text, not an import (ZONE 2 assumption 5). An import answers a different question: the dist project only materialises when OBJECTUI_DIST_PINS=1, so the imported project list depends on the environment while the declaration surface does not. Importing would also execute that file's module scope — including its --project dist argv guard, which throws — inside the test process.

Evidence

Every heavy run went through the shared verify lock (OS_VERIFY_LOCK_SLOT=dev-7096); exit codes captured after redirection, never across a pipe.

Pin red before the script change (pin written first, measured on the unmodified tree):

❯ |unit| scripts/__tests__/package-scripts-vitest-projects.test.ts (8 tests | 1 failed)
AssertionError: Root scripts filter on 1 project(s) that vitest.config.mts does not declare,
so those scripts cannot run:
pnpm test:integration → --project ui
Declared: @object-ui/console, dist, dom, dom-heavy, unit
Test Files 1 failed (1)
Tests 1 failed | 7 passed (8)
INNER_EXIT=1

The other 7 — every control — passed there, so the red is the subset check firing, not a broken derivation.

Pin green after, at head 652bd11e0:Test Files 1 passed (1) / Tests 8 passed (8), INNER_EXIT=0.

The card's acceptance — the script now starts and runs:

> object-ui-monorepo@ test:integration
> vitest run --project dom --project dom-heavy --shard=1/16
Test Files 92 passed (92)
Tests 1054 passed (1054)
INNER_EXIT=0

Declared narrowing: that is one shard of sixteen, not the whole tier. pnpm exec vitest list --filesOnly --project dom --project dom-heavy collects 1463 files (1429 dom + 34 dom-heavy) — both filters resolve, and an unsharded run of that surface does not fit this container's ~10-minute foreground cap. CI runs the same files as pnpm test --shard=n/4.

Ablation (after committing, so HEAD holds the fix). Only the script line was reverted to --project ui. The mutation was proven on disk by anchoring on both texts — injected "vitest run --project ui" present ×1, removed --project dom --project dom-heavy absent ×0 — and by blob hash bef1402ad… differing from the HEAD blob 1bb6f8fcc…; the script aborts rather than measure if either check fails. No rebuild leg applies: the pin reads both files off disk with fs.readFileSync, with no built artifact between them. Under the mutation the pin went red naming pnpm test:integration → --project ui, ABLATED_PIN_EXIT=1. Restore was git checkout HEAD -- ABSOLUTE_PATH (with an absolute-path trap … EXIT INT TERM) and is proven by state, not exit code: worktree blob 1bb6f8fccaaaed7c58a61a352e3ae2d3d803d1ae equals the HEAD blob, git diff HEAD empty, git status clean.

Other gates, all with their own verdict line:

commandverdict
pnpm exec vitest run scripts/__tests__/Test Files 97 passed (97) / Tests 2738 passed (2738), exit 0
pnpm test:unit --shard=1/8 (unchanged)Test Files 102 passed (102) / Tests 1546 passed (1546), exit 0
pnpm type-check:scriptsexit 0 — and tsc --listFiles confirms the new file is in the program (1 hit), so this is a measurement, not a vacuous pass
pnpm lint:root✖ 33 problems (0 errors, 33 warnings), exit 0; the new file alone lints clean at exit 0
pnpm lint:coverage✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
pnpm type-check:coverage✅ type-check coverage: 45/46 via type-check … / ✅ test type-check coverage: 41/41
node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6016 tracked text file(s); skipped 85 binary)
node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.
node scripts/check-governed-queue-guard.mjs --test …✅ NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.

No changeset — the presence gate's own verdict line above says none is owed: root package.json is not published source and the pin is a test.

Nothing else teaches this script.git grep -n "test:integration" origin/main returns exactly one hit, package.json:25. Nothing under AGENTS.md, CLAUDE.md, .claude/**, skills/**, content/docs/** or docs/** mentions it, so no governed or docs surface needed touching. For the record, skills/objectui/guides/testing.md:45 does name the project split (--project unit / dom / dom-heavy) and stays accurate after this change.

Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…he agreement
`pnpm test:integration` was `vitest run --project ui` while no project named
`ui` existed, so the script could not run at all:
$ pnpm exec vitest run --project ui
Error: No projects matched the filter "ui".
exit 1
The drift is structural, not a typo. `ui` was real once — declared in
`vitest.workspace.ts` (1bdba06) as the complement of `unit`: every
`*.test.{ts,tsx}` under `packages`/`apps`/`examples` except the four pure-logic
packages. 85c8724 deleted that file because Vitest 4 removed
`defineWorkspace` and had been silently ignoring it, which took `unit` and `ui`
down together. `unit` was later re-declared inline in `vitest.config.mts`
(e850c56, which never touched `package.json`), so `test:unit` started
resolving again by accident; nothing ever re-declared `ui`.
The modern equivalent of what `ui` covered is the two DOM tiers, so the script
now reads `--project dom --project dom-heavy`. No project named `ui` is added:
the stale name moves to the projects that exist rather than the config growing
one to match it.
`scripts/__tests__/package-scripts-vitest-projects.test.ts` pins the two halves
to each other — every `--project` name a root script passes must be a project
this repo declares. The assertion is a subset check, so an over-wide declared
set can never fail it; each leg of the derivation therefore carries its own
control asserted against a name measured on this tree, including the
`@object-ui/console` project, whose name Vitest derives from that directory's
`package.json` and which appears as no `name:` literal anywhere.
Measured: pin red before the script change (`pnpm test:integration → --project
ui`), 8/8 green after; `pnpm test:integration --shard=1/16` runs 92 files /
1054 tests green where it previously could not start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm test:integration cannot run — it filters on a vitest project named ui, which does not exist

2 participants

@os-litant@claude