Skip to content

test(scripts): reconcile the console workspace alias table against its import closure - #6204

Merged
yinlianghui-tw merged 1 commit into
mainfrom
claude/issue-4925-console-alias-reconciliation
Aug 25, 2026
Merged

test(scripts): reconcile the console workspace alias table against its import closure#6204
yinlianghui-tw merged 1 commit into
mainfrom
claude/issue-4925-console-alias-reconciliation

Conversation

@yinlianghui-tw

Copy link
Copy Markdown
Collaborator

Fixes#4925

Adds scripts/__tests__/console-vite-alias-closure-4925.test.ts, which reconciles the hand-written @object-ui/* alias table in apps/console/vite.config.ts against the console's own transitive import closure. No production code changes — the alias table is untouched.

The premise was re-verified first, and it holds

The card measured the table complete on 5ffcc1432 (2026-08-17). Re-derived by the card's own method on this branch's base 2c8474c04 — seed from apps/console/src's value-imports, transitive closure over packages/*/src:

workspace packages : 46
console alias table entries : 35 (34 distinct packages; the 35th is the
`@object-ui/types/zod` subpath entry)
console seed (direct imports): 28
console import closure : 34
in closure, NOT in table : 0
in table, NOT in closure : 0

No drift. The table is complete today, so this test lands green and pins a property that currently holds rather than fixing a live defect. Nothing in the alias table was changed to make it pass.

Why the table stays hand-written (option 2)

Deriving it from packages/cli/src/utils/workspace-vite.ts (PR #4922) would make the table textually disappear, and scripts/__tests__/side-effects-declaration-consistency.test.ts finds alias tables by parsing vite.config.* for the literal shape '@object-ui/x': path.resolve(...). Deriving would therefore silently shrink a second, unrelated gate's scan surface while that gate stayed green — the same failure class this card is about, one file over. The scanner is not modified here; leaving it alone is the point.

The two directions

They are pinned as separate cases with separate messages, because they call for opposite fixes:

directionverdictfix
in the closure, not in the tablered — the #3890 defect: resolves through node_modules/dist instead of source, every static check green, dev server serves 500sadd the alias line
in the table, not in the closurered, with a shrink-only ratchet that is empty todaydelete the alias line

The reverse direction is a red rather than a warning because this repo already ruled on that exact defect one table over: vitest-config-alias-targets-3944.test.ts's header states it as "a dead entry is worse than a missing one, because it reads as connected". Collapsing the two into one assertion would report each finding as the other, so they stay apart.

Reconciliation is folded to package granularity before comparing — otherwise @object-ui/types/zod (an entry, not a package; it exists so the subpath is matched before the bare package) reads as permanently stale.

The pnpm-workspace.yaml trap

The manifest lists all 46 workspace packages; the console's closure is 34 of them. A naive table == workspace assertion reds on day one over @object-ui/cli, @object-ui/plugin-ai, @object-ui/runner, @object-ui/test-support, the examples, and the console itself. The manifest's role here is to say what a workspace package is; the closure says what the console needs. A standing negative control (does not demand an alias for a workspace package the console never imports) reds if the two checks are ever "simplified" back into that shape.

Non-vacuity

Floors on every population, a key census proving no table entry dodges the comparison (an entry written in any other form is reported, never skipped), and both counts in every failure message:

[population: 35 alias entries (34 packages), closure 34 packages from 28 direct
imports, scanned 93 console + 1322 package source files, 46 workspace packages]

Controls — predicted before running, both confirmed

  • Positive — delete '@object-ui/plugin-map' from the table. Predicted: only every package in the console import closure has an alias entry reds, naming it. Observed 1 failed, 7 passed, the finding reading @object-ui/plugin-map (reached via apps/console/src/register-plugins.ts imports '@object-ui/plugin-map').
  • Negative@object-ui/plugin-ai is a packages/* workspace package with no alias entry and no place in the closure; unmutated, the file is green. Probed the other way by adding an alias entry for it: predicted two reds (the stale case, plus the negative control's own named clause, which says in so many words that plugin-ai is not aliased) — observed 2 failed, 6 passed, the stale finding reading ['@object-ui/plugin-ai'].

Both mutations were confirmed on disk by anchored grep -c counts before/after (never an editor's exit code), each mutation script carried a trap '<restore>' EXIT INT TERM, and both restored to an empty git diff HEAD -- apps/console/vite.config.ts (exit 0).

Verification

All at 62e5cf715 (the final commit), exit codes captured by redirect before any pipe:

  • npx vitest run --project unit --maxWorkers=2 scripts/__tests__74 files / 2004 tests passed. This is the derived blast radius: scripts/__tests__ is where every gate that enumerates scripts/**/*.ts lives (scripts-type-check, turbo-test-inputs, vitest-invocation-guard, merge-queue-reporting), and it also contains side-effects-declaration-consistency, the gate whose scanner this ruling exists to protect. Root vitest only (pnpm --filter @object-ui/app-shell test 跑的是 @object-ui/console 的 22 个文件,app-shell 自己的 276 个一个没跑,却报绿 #3378).
  • pnpm type-check:scriptsTC_EXIT=0
  • node scripts/check-control-bytes.mjs✅ OK (scanned 5123 tracked text file(s); skipped 85 binary)
  • node scripts/check-vi-mock-specifiers.mjs✅ OK (3700 tracked source file(s) …)
  • node scripts/check-changeset-presence.mjs✅ No source of a released package changed in this range, so no changeset is owed. (test-only change; no changeset added, on that gate's own verdict)
  • node scripts/check-lint-coverage.mjs✅ 46/46 packages linted
  • node scripts/check-type-check-coverage.mjs✅ 45/46 via type-check (unchanged from base)

Declared narrowing.eslint was run on the one added file (npx eslint --no-inline-config … --format json, ES_EXIT=0, 1 file in the report) rather than repo-wide. Evidence the narrowing excludes nothing: (1) the linted population comes from eslint's own config resolution, not from a guess about which files count; (2) the file count is read from --format json output; (3) eslint.config.js enables no type-aware linting on scripts/**, so a single added file cannot move the verdict on any untouched file. CI runs the full farm regardless.

apps/console/vite.config.ts is byte-identical to origin/main on this branch (git diff HEAD --quiet exit 0 after both control mutations reverted), so the gates that read that file are unaffected by this branch by construction.


Generated by Claude Code

…s import closure
`apps/console/vite.config.ts` keeps a hand-written table aliasing every
`@object-ui/*` specifier at the package's `src/`. The property it has to
maintain — "what does the console transitively import" — moves whenever any
platform package adds one cross-package import, a change that need not touch
`apps/console` at all, and nothing pinned it.
objectui#3890 is the same property failing on another consumer: no build, type-
check, lint or test went red; the symptom was whole pages 500-ing in the dev
server, found by driving the app.
The table stays hand-written on purpose. Deriving it from the CLI helper landed
in #4922 would make it textually disappear, and
`scripts/__tests__/side-effects-declaration-consistency.test.ts` finds alias
tables by parsing `vite.config.*` for the literal `'@object-ui/x':
path.resolve(...)` shape — so deriving would silently shrink a second,
unrelated gate's scan surface while it stayed green.
Re-derived before writing: 35 entries / 34 packages / closure 34 / 0 missing on
2c8474c, matching the measurement on 5ffcc14. The table is complete today,
so this lands green.
Both directions are pinned as separate cases with separate messages, because
they call for opposite fixes: a package in the closure with no entry is the
#3890 defect (add the line), an entry outside the closure is the #3944 defect —
wiring that reads as present and is not — (delete the line). Reconciliation is
folded to package granularity so the `@object-ui/types/zod` subpath entry is not
read as permanently stale.
Non-vacuity: floors on every population, a key census proving no table entry
dodges the comparison, both counts in every failure message, and a standing
negative control that reds if the two checks are ever "simplified" into
`table == pnpm-workspace.yaml`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

apps/console 的 workspace alias 表仍是手工清单(今天 34/34 完整),失效模式与 #3890 同类但无门禁

2 participants

@yinlianghui-tw@claude