Skip to content

test(types): derive the zod-mirror-parity population instead of writing it down - #7731

Merged
os-justin merged 2 commits into
mainfrom
claude/issue-7433-parity-population-derived
Sep 5, 2026
Merged

test(types): derive the zod-mirror-parity population instead of writing it down#7731
os-justin merged 2 commits into
mainfrom
claude/issue-7433-parity-population-derived

Conversation

@os-justin

@os-justin os-justin commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Fixes #7433

Route 2 of objectui#6141, which triage (comment 5548620618) made mandatory: ⛔ a third prose correction is not a fix. The defect is the mechanism — packages/types/src/__tests__/zod-mirror-parity.test.ts quoted the registry population and the two differences taken from it as prose literals that no assertion read — so this PR makes the number derived and leaves the digits alone.

Re-derived on this branch's base, inheriting nothing

Triage boundary 2 requires re-deriving on the tree as of starting. On b74a859, two independent instruments:

quantity AST walk over the MIRRORS initializer line-oriented parse of the same block
MIRRORS members 157 157

Ledgers, from the same AST: KnownDrift 42, UnmirroredDeclared 14, RuntimeOnlyDeclared 7, union of the two unmirrored ledgers 15. Both differences derived twice — by subtraction and by a set walk over the registry — agreeing at 142 (no entry in either unmirrored ledger) and 115 (no KnownDrift entry).

The header's digits on b74a859 are correct today. That is the card, not a refutation of it: the figure was re-measured by hand a fourth time since objectui#6141 (objectui#7655), and no assertion anywhere in the file compares the registry size to a constant. A correct hand-maintained number is still a hand-maintained number.

What the pin is

One written-down constant in the runtime-census region at the bottom of the file, where the census already reads MIRRORS at runtime:

  • EXPECTED_MIRROR_PAIRS, asserted against Object.keys(MIRRORS).length. It is the only count in the file a human edits.
  • Both differences the header used to state are derived from that constant and the live ledger sizes, and each is derived twice — once by walking the registry for pairs the ledger does not name, once by subtracting. The two part company exactly when a ledger records a key MIRRORS does not register, which makes this the runtime twin of assertionUnmirroredLedgerKeysAreRegistered and extends the same cover to the drift half.
  • The ledgers are type-level interfaces with no runtime value to count, so their sizes are read from this file's own AST with the TypeScript parser the census already runs for specReferencingExports — the same instrument, not a second one, and a measurement rather than a list to maintain.
  • A non-vacuity case: a reader returning an empty list would make both differences equal the whole population and pass while measuring nothing.

The failure message names which side to change (triage boundary 5), printing both numbers and both remedies, with the discriminator being which of the two the diff moved — not which number looks right. The second commit adds the dependency between the two cases to that message: when the population pin is the one that moved, the difference case fails as a consequence, and its own hint would otherwise be a wrong lead.

Prose: derives, does not restate

Nine sites rewritten to name the constant or the census instead of a digit. ⚠️ The dispatch's site list had moved: three sites quote the population beyond the ones it names — a KNOWN_DRIFT is a ratchet paragraph, a ReconcileAgainstLedger docstring, and the seeding-floor paragraph. The historical narrative that quotes superseded figures (163, 160, the 141→147 delta chain, the 158-pair seeding run) is deliberately left alone: it describes the past and cannot rot.

⛔ Not touched, per the dispatch: any MIRRORS entry, any ledger entry, any EXCLUSIONS row. ⛔ The withdrawn "142 vs 123 contradiction" stays withdrawn — the two subtractions have different, labelled subtrahends. The three ledger counts the card records as never having rotted keep their digits.

Red-first proof

Re-run on the FINAL head 40171f5f, so the evidence matches what is pushed. Trap-guarded, absolute paths, mutation proven on disk by anchor counts before/after (⛔ never by an editor's exit code), restore proven by blob hash against HEAD and an empty git diff HEAD.

leg mutation on-disk proof result
A — constant hand-edited wrongly EXPECTED_MIRROR_PAIRS 157 → 156 anchor before=1, after: old=0 new=1 vitest exit 1; message: MIRRORS holds 157, EXPECTED_MIRROR_PAIRS says 156update EXPECTED_MIRROR_PAIRS from 156 to 157 / put it back to 157
B — registry shrank one MIRRORS entry removed entry lines before=1, after=0 vitest exit 1; message: MIRRORS holds 156, EXPECTED_MIRROR_PAIRS says 157update EXPECTED_MIRROR_PAIRS from 157 to 156 / put it back to 156

Both restores: restore OK — blob 5860bd3160b64446595bfa42788305cd22f39c0f matches HEAD, tree clean, git diff HEAD empty.

Predicted direction was RED in both legs, in opposite directions, and that is what was observed.

Changeset

check-changeset-presence.mjs counts the test file as source of a released package (it does not read the tsconfig exclude), so it demanded a declaration and got the empty-frontmatter form — the gate documents that as the explicit exemption, a pass rather than a workaround. ⛔ No skip-changeset label: it is a phantom in this repo.

The claim that nothing ships from __tests__/ is measured, not asserted: packages/types/tsconfig.json excludes **/__tests__/** by directory, and tsc -p tsconfig.json --listFilesOnly lists 0 files under __tests__. The pin is inside tsconfig.test.json's program — tsc -p tsconfig.test.json --listFilesOnly lists the file.

Gates (exit codes captured before any pipe; heavy runs through the shared verify lock)

All re-run on the final head 40171f5f:

gate exit
pnpm exec vitest run --maxWorkers=2 packages/types/ 0 — 114 files, 1963 tests
pnpm --filter @object-ui/types type-check 0
node scripts/check-changeset-presence.mjs 0
node scripts/check-changeset-fixed.mjs 0
node scripts/check-changeset-no-major.mjs 0
node scripts/check-changeset-overwrite.mjs 0
pnpm run check:control-bytes 0 — 6298 tracked text files
pnpm run check:spec-symbols 0
pnpm run check:published-tsconfig-exclude 0
pnpm exec eslint on the changed file 0

The three new cases were confirmed to actually execute under --reporter=verbose, not merely to be collected.

Governed-surface predicate on the final file list: 0 of 2 paths hit the register — ordinary queue landing applies.


🤖 Generated with Claude Code

https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s

…ng it down

`zod-mirror-parity.test.ts` quoted the registry population and the two
differences taken from it as prose literals that no assertion read. The
figures were corrected by hand four times since objectui#6141, which had
written down that a prose correction "rots again the next time an entry
lands"; one of those corrections was false on the day it was written, and
another was a maintainer who correctly updated the ledger counts in front
of them and could not see that the minuend under them had moved.

Route 2 of objectui#6141, as objectui#7433's triage requires: the runtime
census now carries one written-down constant, `EXPECTED_MIRROR_PAIRS`,
pinned against `Object.keys(MIRRORS).length`, and derives both differences
the header used to state. The ledgers are type-level `interface`s with no
runtime value, so their sizes are read from this file's own AST with the
TypeScript parser the census already runs for `specReferencingExports`.
Each difference is derived twice -- by walking the registry and by
subtracting from the pinned population -- so the two disagree exactly when
a ledger names a pair `MIRRORS` does not register.

The failure message names both remedies and their discriminator: whether
the diff moved the registry or the constant. Every prose site that quoted
the population or either difference now names the constant or the census
instead of a digit; no `MIRRORS` entry, ledger entry or `EXCLUSIONS` row
moves, and the ledger counts the card records as never having rotted are
left alone.

Empty-frontmatter changeset: `@object-ui/types` publishes nothing from
`__tests__/` -- the package `tsconfig.json` excludes the directory and its
build program lists zero files under it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
…in first

When `EXPECTED_MIRROR_PAIRS` itself is the thing that moved, both cases in
the new census fail together, and the second one's hint ("a ledger entry
names a pair MIRRORS does not register") is the wrong lead. Name the
dependency: the difference subtracts from the pinned population, so it
fails as a consequence and the population case is the one to fix.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3186.4 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-BJfNoOjq.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
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.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 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.68KB 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) 510.70KB 116.21KB
core (index.js) 6.96KB 2.79KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 180.00KB 50.20KB
fields (index.js) 242.27KB 61.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.98KB 10.98KB
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.75KB
mobile (index.js) 1.99KB 0.87KB
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.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 47.87KB 13.31KB
plugin-charts (index.js) 70.92KB 19.75KB
plugin-chatbot (index.js) 196.37KB 46.41KB
plugin-dashboard (index.js) 132.87KB 34.68KB
plugin-designer (index.js) 212.86KB 43.19KB
plugin-detail (index.js) 250.55KB 64.06KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 132.87KB 32.66KB
plugin-gantt (index.js) 167.26KB 41.00KB
plugin-grid (index.js) 209.29KB 56.78KB
plugin-kanban (index.js) 52.71KB 14.55KB
plugin-list (index.js) 113.28KB 27.59KB
plugin-map (index.js) 20.44KB 6.78KB
plugin-markdown (index.js) 13.93KB 4.81KB
plugin-report (index.js) 43.59KB 11.97KB
plugin-timeline (index.js) 30.84KB 8.85KB
plugin-tree (index.js) 9.20KB 3.19KB
plugin-view (index.js) 85.24KB 20.94KB
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.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 4.93KB 2.24KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 10.35KB 3.60KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 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-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
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 (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
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

@os-justin
os-justin marked this pull request as ready for review September 5, 2026 13:17
@os-justin
os-justin added this pull request to the merge queue Sep 5, 2026
Merged via the queue into main with commit 3bde19b Sep 5, 2026
34 checks passed
@os-justin
os-justin deleted the claude/issue-7433-parity-population-derived branch September 5, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants