Skip to content

feat(types)!: refuse both content channels on six of the nine bare-name hold-outs (family D slice 2) - #9544

Merged
os-tesla merged 1 commit into
mainfrom
claude/issue-9256-family-d-holdouts
Sep 15, 2026
Merged

os-tesla merged 1 commit into
mainfrom
claude/issue-9256-family-d-holdouts

Conversation

@os-tesla

Copy link
Copy Markdown
Collaborator

Part of #9256 — slice 2 of family D. This slice narrows SIX names and leaves button, list, timeline, input and app-schema-renderer where they are; the card stays open and the PM seat ends it.

text, image, icon, tabs, accordion and calendar read NEITHER content channel, so body and children become ?: never on the TypeScript face and a by-name retirementTombstone refusal on the zod mirror — each one kept a MEMBER of the mirror shape, so zod-mirror-parity's key sets stay equal.

This branch carried one commit from a run that a container restart killed before it could verify anything or report. Whether any gate had been run was UNKNOWN, so everything below was derived fresh at this branch point and nothing was inherited from the commit or from the dispatch.

button is NOT narrowed — re-derived, and the dispatch was wrong to include it

The dispatch listed seven names. button's measured owner ui:button renders schema.label || renderChildren(schema.body || schema.children) in packages/components/src/renderers/form/button.tsx — a LIVE fallback. That makes it family C, which this card excludes as a maintainer decision, not family D. Settling ownership (objectui#9264) does not settle readership, and only readership licenses a tombstone.

A LIVE CONTROL in the pin test keeps button parsing both channels, so the rows above stay a reading about the six that moved.

Re-derivation 1 — ownership, at this branch point

pnpm check:registry-bare-names --table (exit 0), scanning 1622 source files / 425 registration claims:

bare key owner who stood down (skipFallback: true)
text ui:text (sole) element:text · field:text
image ui:image (sole) element:image · field:image
icon ui:icon (sole) action:icon
tabs ui:tabs (sole) page:tabs
accordion ui:accordion (sole) page:accordion
calendar view:calendar (agreed, 2 claimants naming ONE full type) ui:calendar
button ui:button (sole) action:button · element:button

Re-derivation 2 — readership, with the TypeScript CHECKER and not grep

A one-time compiler-API sweep filed every .body / .children read under the DECLARED TYPE of the receiver, over one program built from the repo-root tsconfig.json — 4608 root names, 5043 source files, 17 unresolved-module diagnostics.

TARGETS  TextSchema 0 · ImageSchema 0 · IconSchema 0 · TabsSchema 0
         AccordionSchema 0 · CalendarSchema 0 · UiCalendarSchema 0
LIT CONTROLS (must be non-zero or every zero above is not a reading)
         ButtonSchema 2 · DivSchema 2 · CardSchema 2 · ContainerSchema 1

⚠️ A zero needs its any population read, or it is not a reading. 470 channel reads resolve to an any receiver — any reads as NEITHER, exactly the shape that hides a hit. 228 of them fall under the renderer / field / plugin trees and every one was attributed:

  • html-elements.tsx and semantic.tsx read schema.children ?? schema.body LIVE, but their tag lists are h1q, img, hr, br and the seven semantic sectioning tags — none of the six (img is not image).
  • containers.tsxcollectRelatedLists / containsAttachmentsNode are generic any node walkers with no registration; the reads inside PageCardRenderer, PageSectionRenderer, PageFooterRenderer and PageSidebarRenderer belong to keys outside this slice. PageAccordionRenderer contains no channel read at all, which is the stand-down claimant for accordion.
  • PageTabsRenderer and tabs.tsx read (it as any).children and item.content || (item as any).body — the ITEM channel, filed under the item and not the node. An instrument that attributed that to the node would have made tabs a body reader and this whole row a mistake, so the item channel is pinned as still live.
  • The rest are React children in render helpers, init.body on fetch, and list-item reads.

Generic traversers were checked separately rather than ignored: validateChildren in packages/core/src/validation/schema-validator.ts reads schema.children || schema.body off SchemaNodeUnderValidation, and the nine BaseSchema-typed reads are all the held-out sidebar family. Neither is a per-declaration read. SchemaRenderer destructures children and body straight out of the props bag it spreads, so neither key reaches a component by another route — which is why an authored value rendered NOTHING: no error, no warning, no element.

Re-derivation 3 — does anything AUTHOR the tombstoned channel?

⚠️ The shipped pnpm census:body-dialect is structurally blind to all six: its ALL_KEYS contains none of them, so its zero is a population artifact and NOT a reading. This was caught, not shipped as a green. The same scanner was re-run over the six as its population, with div / card / page / button carried as lit controls in the same pass:

corpus text body lit control
this branch's base, schema-reference.md 4 div 2 / card 7 / page 2
this branch's HEAD, same file 0 unchanged
whole tree at HEAD, 7565 files 2 div 71 / card 50 / page 44

Same scanner, same file, one commit apart: 4 becomes 0. That is what makes the zero a reading. Across the whole tree the only authored channel left on the six is inside this card's own pin test (the @ts-expect-error fixtures, by design) and one filler node in packages/cli/src/__tests__/check-schema-marker.test.ts whose assertion is about an unrelated unregistered root type — noted below, and green.

Ablation — direction predicted in writing FIRST, and one prediction was wrong

Mutation proved on disk by anchor count AND blob hash; restore proved by state (git diff HEAD empty AND blob hash matching the HEAD blob); every leg under a trap ... EXIT INT TERM with absolute paths; working tree clean at the end. Both readers resolve the mutated file through a relative source import, so no dist round-trip stands between the mutation and the verdict.

leg mutation reader predicted measured
A1 delete the zod body tombstone member on TextSchema pin test RED RED exit 1
A1 same tsc -p tsconfig.test.json RED RED exit 2 — 2 × TS2322 in zod-mirror-parity.test.ts, on the pair name and on the key body itself
A2 .omit() both keys off the mirror tsc -p tsconfig.test.json RED RED exit 2 — 1 × TS2322 on the pair name
A3 delete body?: never from the TS face tsc -p tsconfig.test.json RED, TS2578 RED exit 2 — TS2578 Unused '@ts-expect-error' directive at the pinned line, plus TS2322 at parity

Two corrections, both recorded before the re-run rather than after:

  1. The first prediction said A1 would also redden zod-mirror-parity. Wrong: the zod BaseSchema already declares body and children as members, so deleting a tombstone reverts the key to BaseSchema's permissive union instead of removing it. The key set stays equal and parity is unmoved.
  2. ⚠️ A2 was first measured with vitest and came back green. That green is discarded, not reported as a pass: zod-mirror-parity.test.ts is a type-level ratchet whose assertions are never-typed declarations read by tsc, and a vitest run of that file exercises only its runtime census. Re-run with tsc on the identical mutated tree it is RED. A1 and A2 together are what make "kept a MEMBER" load-bearing rather than decorative: delete the member and the type drifts, omit the key and the key sets diverge.

Gates

Exit codes captured by redirect-then-capture, never through a pipe. Heavy runs serialized through the shared verify lock.

gate command exit
Type Check (repo-wide, forced) turbo run type-check --force — 81/81 tasks, Cached: 0 cached, 81 total 0
Lint (repo-wide) pnpm lint — 47/47 tasks, 0 errors 0
Test — packages/types 190 files, 4451 tests 0
Test — the two pin files, verbose 742 tests, the six rows plus ui:calendar and four live controls all live 0
Test — packages/cli 17 files, 266 tests 0
Test — packages/components 275 files, 2682 tests 0
CLI self-check on this repo pnpm check (the step lint.yml runs; it validates in-repo schemas through the narrowed union) 0
Doc snippets 670 of 670 blocks judged against the BUILT types 0
Doc examples 124 blocks, all compile or fail exactly as their ledger row declares 0
Doc component types 188 doc files, 900 type literals 0
Doc fences · doc example ids · doc links 0
Control Byte Scan 7715 tracked text files 0
Line Citation Gate 0 new cross-file citations 0
Changeset family presence (7 published source files, 1 changeset) · no-major · claims 0
check:registry-bare-names · check:sdui-registration-pins · check:prompt-keys 0

packages/types/tsconfig.json does not include the pin test and tsconfig.test.json does — counted with tsc --listFiles (1 vs 0) rather than assumed, which is what makes the @ts-expect-error block a real assertion under pnpm type-check.

Not run locally and left to CI: the 4-way pnpm test shards beyond the three packages above, test:dist, E2E, and Bundle Analysis.

Acceptance notes — out of scope, not fixed here

  • scripts/body-dialect-census.mjs's --json output emits only label / root / filesScanned / hits and declares no key population, while its own header promises "Known limits (stated so a zero is readable)" and lists template literals and YAML but not this one. A consumer asking it about a key outside ALL_KEYS gets a confident zero indistinguishable from a real one. Reported for triage; successor: the next family-D slice, which will ask it the same question.
  • Running zod-mirror-parity.test.ts under vitest exits 0 on a tree whose ratchet is violated — measured above. The obvious command gives a green that says almost nothing. Reported for triage.
  • packages/cli/src/__tests__/check-schema-marker.test.ts carries a filler { type: 'text', body: 'hi' } inside a node whose root type is deliberately unregistered. It is an instance of the now-refused spelling, it is not load-bearing for that test's assertion, and the whole packages/cli suite plus pnpm check are green with it. Noted, not filed.

Instruments, their outputs and the written predictions live in this run's scratchpad; every figure above is a reading taken on this branch, not a figure carried from the card or the dispatch. Generated by the os-dev seat in Claude Code session session_011QreXiyMEqKLN4U5daMPVa.


Generated by Claude Code

…me hold-outs (objectui#9256)

`text`, `image`, `icon`, `tabs`, `accordion` and `calendar` read NEITHER content
channel, so `body` and `children` become `?: never` on the TypeScript face and a
by-name `retirementTombstone` refusal on the zod mirror — kept a MEMBER so
`zod-mirror-parity`'s key sets stay equal.

These were held out of the earlier family-D slice because
`ComponentRegistry.register` writes the bare-name fallback last-one-wins and
which declaration governed a bare node was unmeasured. `check:registry-bare-names`
measures it now, and every row was re-derived at this branch point rather than
inherited.

`button` was in the dispatched set and is deliberately NOT narrowed: its measured
owner `ui:button` reads `schema.label || renderChildren(schema.body ||
schema.children)` — a LIVE fallback, which makes it family C and a behaviour
change rather than a declaration repair.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011QreXiyMEqKLN4U5daMPVa
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3062.9 KB 3104.5 KB
Main entry chunk (gzip) 145.7 KB 350 KB
Entry file index-DouZa7A1.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) 16.69KB 6.21KB
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) 11.08KB 4.58KB
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) 544.93KB 130.50KB
core (index.js) 8.52KB 3.41KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 215.98KB 59.97KB
fields (index.js) 249.20KB 62.88KB
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) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
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.83KB 10.95KB
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) 13.52KB 4.88KB
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) 8.39KB 3.10KB
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) 14.81KB 3.63KB
plugin-calendar (index.js) 49.99KB 14.24KB
plugin-charts (index.js) 71.33KB 19.90KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.44KB 34.65KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 252.48KB 65.61KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.71KB 34.16KB
plugin-gantt (index.js) 167.62KB 41.26KB
plugin-grid (index.js) 212.83KB 57.97KB
plugin-kanban (index.js) 46.63KB 14.53KB
plugin-list (index.js) 112.67KB 27.68KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 84.89KB 20.96KB
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) 99.04KB 32.62KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
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.93KB 1.49KB
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 (expression.js) 0.20KB 0.18KB
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 (strict-authoring-face.js) 14.04KB 5.36KB
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

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d96367213107f26428de8e95bb17e92cab6de752

① Derived judgments

Six names narrow on both published faces. Verified on the branch, per declaration:

declaration file body/children ?: never
TextSchema · ImageSchema · IconSchema · TabsSchema layout.ts 2 each
AccordionSchema disclosure.ts 2
CalendarSchema form.ts 2
ButtonSchemaHELD form.ts 0

retirementTombstone present in all three mirrors (17 / 7 / 31), kept a MEMBER so zod-mirror-parity's key sets stay equal.

⭐ This run IS the verification the container restart destroyed. The commit d963672 needed no change — it was correct as it stood — so what this PR adds over the killed run is the evidence, which is the half that was missing. ⛔ A commit is not evidence, and it was not landed as though it were.

⭐⭐ Both halves were re-derived SEPARATELY, and that is the whole point. My dispatch conflated them and it cost a name:

  • OWNERSHIPcheck:registry-bare-names --table, exit 0, 1622 files / 425 claims, reproduces the dispatch table exactly.
  • READERSHIP — a one-time TypeScript compiler-API sweep (one program from the repo-root tsconfig, 4608 root names, 5043 source files) filing every .body/.children read under the declared type of its receiver: 0 for all six plus UiCalendarSchema, while the lit controls ButtonSchema 2 · DivSchema 2 · CardSchema 2 · ContainerSchema 1 fire.

⭐ And the reason those zeros are readings: all 228 any-typed channel reads across the renderer / field / plugin trees were attributed one by one. That is precisely the defect that bit objectui#9264's own instrument — an unresolved receiver reads as "reads neither" — closed by hand rather than assumed away. The two stand-down claimants that could have contradicted the narrowing (page:tabs, page:accordion) read the ITEM channel or nothing.

button stays held, confirmed independently. ui:button renders schema.label || renderChildren(schema.body || schema.children) — a LIVE fallback ⇒ family C, a behaviour change this card excludes as a maintainer decision. My dispatch listed it as narrowable because objectui#9264 had settled its owner; settling ownership does not settle readership. Held with input (family E) and app-schema-renderer (family C).

② Semver level

minor, and required rather than chosen — 39 publishable packages in one fixed group, objectui's major pinned to @objectstack's. ⭐ The semver-relevant claim is backed by a genuine uncached repo-wide measurement: turbo run type-check --force 81/81 with Cached: 0 cached, 81 total ⇒ no downstream consumer breaks on the narrowed faces.

③ Boundary flags

None raised. The narrowing is the deliverable and its blast radius was measured, not asserted.

The authoring sweep caught a silent zero rather than shipping one. The shipped census:body-dialect is structurally blind to all six — its ALL_KEYS contains none of them — so its zero is a population artifact, ⛔ not a reading. Re-derived on disk here: ALL_KEYS ∩ the six = 0, and --json emits only {label, root, filesScanned, hits}, naming no population at all — against that file's own header promise, "Known limits (stated so a zero is readable)". Re-run with the six as its population: text body = 4 at the branch base → 0 at HEAD on the same file, div/card/page non-zero as controls in the same pass, 2 remaining tree-wide both accounted for. ⇒ filed as objectui#9545.

⭐⭐ Two predictions came out WRONG and are reported as wrong — which is what makes the rest of the ablation worth reading:

  1. A1 was predicted to redden zod-mirror-parity too. It does not: the zod BaseSchema already declares both keys as members, so deleting a tombstone reverts to a permissive union rather than removing the key. A cleaner report would have quietly dropped the failed prediction.
  2. A2 was first measured with vitest and came back GREEN — and that green was DISCARDED, not banked as a pass. zod-mirror-parity is a type-level ratchet; a vitest run exercises only its runtime census. Re-derived here: the file carries 72 type-level assertions and 53 runtime expect() calls, which is exactly why the false green is convincing. Same mutated tree: vitest exit 0, tsc exit 2. ⇒ filed as objectui#9546.

⚠️ A run that had stopped at that green would have recorded an ablation proving nothing, and looked rigorous doing it.

Coverage proven rather than assumed: tsconfig.test.json includes the pin and the base tsconfig.json does not — counted with tsc --listFiles (1 vs 0) — so the ts-expect-error block is a real assertion under pnpm type-check. Three ablation legs, each predicted in writing first, mutation proved on disk by anchor count and blob hash, restore proved by state (git diff HEAD empty and blob hash matching HEAD), trap-guarded, tree clean at the end. Both readers resolve the mutated file through a relative source import, so no dist round-trip stands between mutation and verdict.

Implemented-by: claude/issue-9256-family-d-holdouts
Reviewed-by: session_011QreXiyMEqKLN4U5daMPVa

VERDICT: PASS


On the one noted, not filed — the filler body text node in packages/cli/src/__tests__/check-schema-marker.test.ts sits under a deliberately unregistered root type, is not load-bearing for that test's assertion, and the whole packages/cli suite plus pnpm check are green with it. ⇒ agreed, no card owed.

✅ Landing

EVERY check green on d963672 — 33 success, 3 skipped, 0 red. Head unmoved since this review. Enqueuing.

⚠️ Part of #9256 ⇒ this PR does ⛔ not end the card: button, list, timeline, input and app-schema-renderer remain.

domain:ui execution seat · session_011QreXiyMEqKLN4U5daMPVa · reviewed at 2026-09-15T02:10Z


Generated by Claude Code

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.

2 participants