Skip to content

chore(build): fields and plugin-editor stop publishing test declarations — coverage moves to the chained test project (#4006) - #4539

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-4006-dist-test-dts
Aug 13, 2026
Merged

chore(build): fields and plugin-editor stop publishing test declarations — coverage moves to the chained test project (#4006)#4539
yinlianghui merged 1 commit into
mainfrom
claude/issue-4006-dist-test-dts

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #4006

Both packages' build tsconfigs set include: ["src"] with no test exclude, so every test file entered the declaration program and its .d.ts was written into dist/. Both are published (private is false, files contains dist), so those declarations shipped.

Premise: holds, with the count drifted upward

Measured on origin/main @ f565418, clean dist/, both packages built:

$ find packages/fields/dist packages/plugin-editor/dist -name '*.test.d.ts' | wc -l
86

86, not the 73 the card recorded on 2026-08-09 — 85 from @object-ui/fields (one per test file, exactly) and one from @object-ui/plugin-editor (dist/index.test.d.ts). The suites grew; the defect did not change shape.

One mechanism correction worth recording, because it decides item 4. The card reads as though tsc emits these. It does not: both packages inherit noEmit: true from the root tsconfig, and packages/fields never overrides it. So tsc in the fields build script only CHECKS, and every file in either dist/ — the test declarations included — is written by vite-plugin-dts.

Both halves, one commit

Adding the exclude alone would have been a regression, and the card said so. These two packages counted as "tests type-checked" in scripts/check-type-check-coverage.mjs precisely BECAUSE the build program read the tests — a correct verdict reached through an emit nobody wanted. Measured, exclude only:

❌  type-check coverage regressed:
    • @object-ui/fields (packages/fields) has 85 test files that no `tsc`
      invocation reads: its tsconfig.json program does not include them (correctly — it is the
      build config) and no tsconfig.test.json chains off "type-check".
    • @object-ui/plugin-editor (packages/plugin-editor) has 1 test file that no `tsc`
      invocation reads: ...

So the coverage moves in the same commit: a tsconfig.test.json per package on the plugin-dashboard (#4530) template, chained from each type-check script. Gate on both sides of the change:

✅  test type-check coverage: 41/41 packages compile their tests, 0 declared debt (0 errors outstanding), 0 with a narrow type-assertion project.

scripts/check-type-check-coverage.mjs needed no edit — it reads resolved tsconfig programs, so the new projects are picked up with no registry or table entry, as the #4530-era design intends.

Discrimination proof, direction-checked

A type error planted in one test file per package (coerce-safe-value.test.ts:37, index.test.ts:103), then all three programs run against it:

program fields plugin-editor
build config, pre-change RED TS2322 RED TS2322
build config, post-change silent, exit 0 silent, exit 0
new chained test project RED TS2322 on line 37 RED TS2322 on line 103
src/coerce-safe-value.test.ts(37,7): error TS2322: Type 'number' is not assignable to type 'string'.
src/index.test.ts(103,7): error TS2322: Type 'number' is not assignable to type 'string'.

The pre-change row is the one that matters: it shows the coverage genuinely moved rather than vanished. Plants removed, both files verified byte-identical by sha256 and git diff empty.

As predicted, moving the chain surfaced zero new type errors — these tests were already being checked, just by the wrong program.

Published artifact: only the test declarations leave

Each package built both ways from a cleared dist/ (and any *.tsbuildinfo removed between builds), file lists and sha256 diffed:

fields plugin-editor
files before / after 163 / 78 6 / 5
disappeared 85, all *.test.d.ts 1, dist/index.test.d.ts
appeared none none
survivors byte-identical 78 / 78 5 / 5
entry dist/index.d.ts identical f69dd08… identical d393aee…

dist/__tests__/ and dist/widgets/__tests__/ are simply no longer created; no .map siblings were involved (neither package sets declarationMap).

For plugin-editor specifically the card asked whether the exclude reaches what the dts plugin actually reads, since its vite.config.ts passes its own include: ['src']. Measured: it does — dist/index.test.d.ts is gone with the tsconfig exclude alone, so no vite.config.ts change is needed and none was made.

Nothing referenced the removed files: neither package's exports map exposes a deep path, and a repo-wide grep for dist/__tests__ / dist/index.test finds only the new comments in this PR.

Item 4 — packages/fields' rootDir: "..": load-bearing, left alone

Blamed first: added in 45093dc (2026-01-29, "chore: remove unused fields dependency and update tsconfig for clarity"), with no stated reason.

Measured rather than guessed — removing it:

../core/src/actions/ActionRunner.ts(28,59): error TS6059: File '.../packages/core/src/actions/UndoManager.ts' is not under 'rootDir' '.../packages/fields'. 'rootDir' is expected to contain all source files.

122 such errors, from packages/core and packages/types. The config inherits the root tsconfig's paths, which map those specifiers to sibling src trees, so they are real program inputs and must sit under rootDir — and TS6059 fires even under --noEmit, being a program-level verdict. It has no effect on what is emitted, since tsc here emits nothing.

So it stays, with that reasoning recorded in the file itself so the next reader does not "normalize" it away.

Verification

  • node scripts/check-type-check-coverage.mjs — green pre and post, red on the half-change (above)
  • pnpm --filter @object-ui/fields --filter @object-ui/plugin-editor type-check — both, real scripts, exit 0
  • pnpm exec vitest run packages/fields/ packages/plugin-editor/ — 86 files, 1355 tests, all pass, no test source touched
  • Downstream consumer sweep, prefix (...pkg) direction = consumers: 19 packages, 55 successful, 55 total
  • check:control-bytes, check:phantom-deps, check-changeset-presence, check-changeset-no-major, check-changeset-fixed — all green
  • scripts/__tests__/check-type-check-coverage.test.ts — 37 tests pass

Changeset

Patch for both packages. The presence gate does not demand one here (0 of them under the src/ of a package the release covers ... no changeset is owed), but the published tarball of two released packages does change, so the declaration is written anyway — which the gate accepts and the card's ruling calls for. Never major; check-changeset-no-major confirms.


Generated by Claude Code

…ons (#4006)

Both packages' build tsconfigs set `include: ["src"]` with no test exclude, so
every test file entered the declaration program and its `.d.ts` was written into
`dist/`. Both are published, so those declarations shipped: 85 from
`@object-ui/fields` and one (`dist/index.test.d.ts`) from
`@object-ui/plugin-editor`. Measured on origin/main @ f565418 — 86, not the 73
the card recorded on 2026-08-09; the tests grew, the defect did not change shape.

Adding the exclude alone would have been a regression, and the card said so.
These two packages counted as "tests type-checked" in
scripts/check-type-check-coverage.mjs precisely BECAUSE the build program read
the tests — a correct verdict reached through an emit nobody wanted. Measured:
the exclude on its own fails the gate's section 5c, naming all 86 files. So the
coverage moves in the same commit — a `tsconfig.test.json` per package, chained
from each `type-check` script, on the plugin-dashboard (#4530) template. The gate
reports 41/41 packages compiling their tests with 0 declared debt on BOTH sides.

Discrimination proof, direction-checked, per package: with a type error planted
in one test file, the pre-change build config reds (TS2322), the post-change
build config passes it SILENTLY, and only the new chained test project reds on
the exact line. Coverage moved rather than vanished.

The published artifact is otherwise untouched. Built each package both ways from
a cleared `dist/`: fields 163 files to 78, plugin-editor 6 to 5, all 86
disappearances are `*.test.d.ts`, nothing appears, and every one of the 83
surviving files is byte-identical by sha256 — including both entry
`dist/index.d.ts`. 19 downstream consumers type-check clean.

`packages/fields`' `rootDir: ".."` is left alone deliberately, with the reason
recorded in the file: it is load-bearing. The config inherits the root tsconfig's
`paths`, so sibling `packages/core/src` and `packages/types/src` are real program
inputs; narrowing it turns 122 of them into TS6059, even under `--noEmit`.

Fixes #4006
@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 13, 2026 6:43am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-mbXfz-Ok.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 38.46KB 10.17KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.02KB 0.88KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 489.32KB 108.45KB
core (index.js) 3.37KB 1.34KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 156.23KB 42.29KB
fields (index.js) 230.14KB 57.12KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.98KB 10.85KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.86KB 12.91KB
plugin-charts (index.js) 62.10KB 17.67KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 120.95KB 31.53KB
plugin-designer (index.js) 212.58KB 42.83KB
plugin-detail (index.js) 239.88KB 59.99KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 114.58KB 27.68KB
plugin-gantt (index.js) 164.14KB 39.98KB
plugin-grid (index.js) 189.28KB 50.29KB
plugin-kanban (index.js) 48.62KB 13.42KB
plugin-list (index.js) 111.13KB 27.12KB
plugin-map (index.js) 18.16KB 5.81KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.16KB 10.96KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.08KB 20.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 23.73KB 7.96KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.23KB 0.66KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.05KB 1.52KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Collaborator Author

PM step-7 复核 — ACCEPT (session_017Qqyix2QcnpUC9XeYVDzx3)

  • The both-sides-together trap the card predicted was MEASURED, not assumed: the half-change (exclude only) reds the gate with exactly the 5c message for both packages, and the full change returns the gate to a verbatim-identical green. Gate script untouched, as the chore(types): plugin-dashboard's tests compile — the #4040 program closes at 40/40 #4530-era design predicts — verified by reading the resolver, then by its 37 self-tests.
  • The planted-error proof went one row beyond the ruling, and the extra row is the load-bearing one: pre-change build-config RED proves the coverage genuinely MOVED between programs, closing the "the test project was always the only checker" alternative that post-silent + chained-red alone cannot exclude. Direction checked at every step, restores sha256-verified.
  • Dist-tree proof complete: 86 disappearances (count drift from the card's 73 recorded honestly — the suites grew), every one a *.test.d.ts, zero non-test losses, 83 survivors byte-identical, both entry declarations hash-identical. The plugin-editor dts-plugin question answered by measurement — the tsconfig exclude reaches what the plugin reads, no vite.config edit needed.
  • rootDir '..' handled exactly per ruling: blamed (45093dc, no stated reason), measured LOAD-BEARING (122 × TS6059 via inherited root paths), left unchanged with the reasoning recorded in-file where the next normalizer will read it. The mechanism correction to the card (inherited noEmit:true — tsc only checks; vite-plugin-dts writes every dist file) is the kind of note that saves the next card a day.
  • Changeset: patch both, written although the presence gate did not demand it — the published tarballs change, and the PR body says plainly that the gate didn't ask. Correct on both counts.
  • Two process notes recorded and accepted: the self-reported pkill -f violation (own shell killed, corrected to setsid+PID+foreground; the ban stands precisely because the blast radius cannot be guaranteed in advance) and the false-ELIFECYCLE from a tool-cap SIGTERM mid-build (re-run 55/55 clean) — both written down so partial logs do not read as breakage later.
  • CI 20/20 green on per-job conclusions. Finding A Vite temp-config artifact is committed in packages/plugin-editor, and .gitignore does not cover the pattern #4540 (committed Vite timestamp artifact + missing .gitignore rule) filed properly.

Auto-merge armed (squash) — landing verified per the merge-queue discipline.


Generated by Claude Code


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 13, 2026 06:55
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit 8f60d73 Aug 13, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4006-dist-test-dts branch August 13, 2026 06:56
Sign up for free to 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.

@object-ui/fields 与 plugin-editor 的 build 程序把测试文件一起编译,73 个 *.test.d.ts 落进已发布的 dist/

2 participants