Skip to content

feat(types): the kanban arm declares the plugin dialect; the DeclarativeKanban* trio retires (objectui#7664) - #7743

Draft
claude[bot] wants to merge 7 commits into
mainfrom
claude/issue-7664-kanban-plugin-dialect-authoritative
Draft

feat(types): the kanban arm declares the plugin dialect; the DeclarativeKanban* trio retires (objectui#7664)#7743
claude[bot] wants to merge 7 commits into
mainfrom
claude/issue-7664-kanban-plugin-dialect-authoritative

Conversation

@claude

@claude claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #7664

Maintainer ruling (a) — comment 5548643216 on the card, decision batch #41, verbatim 「同意」: for an authored type: 'kanban' document the plugin dialect is authoritative. This PR executes the ruling's list end to end. Clause-②: yesneeds:contract-review, parked for the director.

This diff carries a REFUSE remediation and returns for a FRESH isolated review. The verdict is comment 5552425067; a REFUSE is not cleared by the fix. needs:contract-review stays on both carriers.

Contract-review remediation — R1: the arm widened an accept set

The finding. The successor 'kanban' arm dropped onCardClick outright — no refusal arm, no ?: never. BaseSchema is .passthrough(), so a dropped key is not refused: it stops being judged and the value is KEPT. Measured on the built dist, both doors (the arm's own safeParse, and the exported safeValidateSchema a type: 'kanban' document actually reaches):

document at bd1fc7111 + main at this head
{ type: 'kanban', columns: [], onCardClick: { action: 'toast' } } ACCEPTED, value kept as {"action":"toast"} REFUSED (custom, path onCardClick)
the same document at onCardMove REFUSED REFUSED
at onQuickAdd REFUSED REFUSED
at onColumnAdd REFUSED REFUSED
at draggable REFUSED (invalid_type) REFUSED (invalid_type)

The disposition was measured, not chosenplugin-kanban/src/__tests__/kanban-handler-slots-7664.test.tsx, new here, renders each of the four registrations with authored spies and mocked board chunks:

registration onCardClick onCardMove onQuickAdd
'kanban-ui' (KanbanRenderer) arrives by identity arrives by identity arrives by identity
'kanban' (ObjectKanbanRenderer) replaced by ObjectKanban's own replaced by ObjectKanban's own arrives by identity
'object-kanban' replaced by ObjectKanban's own replaced by ObjectKanban's own arrives by identity
'kanban-enhanced' not forwarded arrives by identity arrives by identity

Two lit controls, so no zero here comes from a probe that could not have fired. On 'kanban-ui' the two keys this PR already kept as runtime slots come out live, beside onCardClick, off the same forward block in index.tsx. On 'kanban' the lit control is onQuickAdd, which arrives by identity — the schema-spread channel does reach the board on that key — while onCardClick and onCardMove are both replaced, in the same object literal of the KanbanRenderer call inside ObjectKanban.tsx. ⇒ The rationale that was recorded for the deletion ("the object-bound board owns the click") would have deleted onCardMove just as well.

And a third channel decides it outright: ObjectKanban DECLARES an onCardClick prop (there is no onCardMove prop), and its substitute wrapper calls it. Measured through the production path — a document authored with onCardClick, rendered through SchemaRenderer, which spreads every non-metadata schema key as a React prop: the board is handed a function that is not the authored one, and invoking it runs the authored one. An onCardClick authored on a type: 'kanban' document runs. So onCardClick is at least as live as onCardMove on every channel measured, and the disposition is RUNTIME SLOT, not ?: never.

What that changed: onCardClick?: (card: KanbanCard, event?: unknown) = a void return on the TypeScript face (unknown for the event because this package declares zero dependencies and has no React types; KanbanImpl narrows it at the call site) + handlerKeyRefusal('onCardClick', 'runtime-slot', …) on the mirror. RUNTIME_SLOT 44 → 45, ALL_SITES 66 → 67; RETIRED stays 22 and the #7340 docs census stays 26. KnownDrift for KanbanSchema gains onCardClick.

Why no ratchet caught it, and what does now. The #6124 ledger is two hand-written arrays keyed by name; the re-key was a SUBSTITUTION (onCardClick out, onQuickAdd in) so its length never moved, and nothing derives its population from a read site. The new file closes that for this arm: it extracts the schema.on* reads out of KanbanRenderer's body in index.tsx and requires each to be a declared arm member carrying the RUNTIME SLOT guidance — red on exactly this deletion, and derived rather than listed. That covers 3 of the ledger's 67 sites; the class is filed as objectui#7753 with three options and a note that the tempting one (ratchet the count) is the one that fails on this instance.

Also corrected, because the review found written rationale the source contradicted:

  • both comments that justified the deletion — the RUNTIME_SLOT comment in handler-keys-json-refusal-6124.test.ts and the KnownDrift comment in zod-mirror-parity.test.ts — now state what the source does, including the substitution that applies identically to onCardMove;
  • the @object-ui/plugin-kanban changeset no longer claims the shape is "member for member what this package declared". Counted with the TypeScript parser against origin/main: 19 members on the plugin's KanbanSchema, 6 on KanbanColumn, 7 on KanbanCard; the declarations here are that shape plus four — three ?: never tombstones, and onCardClick, which the plugin dialect never declared while its renderer read it;
  • the @object-ui/types changeset gains the accept-set bullet for all five handler arms;
  • the draggable / column color tombstone JSDoc cites the two-prong discriminator instead of arguing from inertness. Re-measured on origin/main: schema-reference.md opened its kanban example with "draggable": true and carried a table row "Enable drag-and-drop between columns", and authored a color on every one of its three columns with the columns row reading "each with id, title, color, and cards" ⇒ prong 2 holds for both. Prong 1 holds for color only (className is the named live replacement); draggable has none, which is why prong 2 is what carries it. The hazards differ and both are measured: KanbanColumn does not extend BaseSchema, so its mirror is a plain object — an undeclared column key is accepted and stripped, whereas an undeclared board key is kept;
  • schema-reference.md documents onCardClick again, and it joins the docs: three pages still teach retired handler keys as authorable props — onColumnAdd/onCardAdd (schema-reference), onSelectChange/onExpandChange (tree-view), onComplete (input-otp) — stale once #6124's tombstones land #7340 blanket-sweep control (six rows → seven).

What changed

  • @object-ui/types complex.ts — the 'kanban' arm declares KanbanSchema / KanbanColumn / KanbanCard / CardTemplate / ColumnWidthConfig: the shape packages/plugin-kanban/src/types.ts declared, plus the four members named above. The two runtime-computed card members keep their React types through the ambient namespace exactly as data-display.ts already spells headerIcon / rowStyle; the package still declares no React dependency (check:phantom-deps green).
  • zod/complex.zod.ts — five mirrors (KanbanSchema, KanbanColumnSchema, KanbanCardSchema, CardTemplateSchema, ColumnWidthConfigSchema); ComplexSchemaAnyComponentSchemasafeValidateSchema apply them. conditionalFormatting reuses the 'object-kanban' arm's rule union (KanbanConditionalFormattingRuleSchema, newly exported from objectql.zod.ts); grouping is SpecGroupingConfigSchema by reference, as ObjectGallerySchema spells it; the two runtime-computed card members pass through as z.any() (the headerIcon precedent, objectui#6424).
  • registry.ts'kanban': KanbanSchema (PR fix(types): SchemaRegistry's kanban entry stops describing a component it cannot name #7662's transitional BaseSchema intersection re-pointed; the BaseSchema import tidied; the comment block rewritten — its "do not restore … without moving the renderer's dialect into a layer this package may depend on" named this route).
  • plugin-kanban/src/types.ts — re-exports the five from @object-ui/types (a plain re-export, not an authority under the one-authority ratchet); InlineFieldDefinition stays local. ObjectKanban.tsx's bare import becomes import type. Behaviour unchanged.
  • plugin-kanban/tsconfig.test.jsontypes gains node, as plugin-calendar / -charts / -chatbot / -dashboard / -detail / -gantt / -grid already do. The new test reads ../index.tsx off disk on purpose: that is what makes its key set derived rather than listed. It stays OUT of tsconfig.json — package source ships to browsers.
  • Retirement (ADR-0049) — the six DeclarativeKanban* exports and both objectui#7645 pin files (their docblocks disclosed it); _KeyKept carried forward into the new pin.
  • Ratchets re-keyed — zod-mirror-parity (5 pairs in, 3 out ⇒ EXPECTED_MIRROR_PAIRS = 159 on top of PR test(types): derive the zod-mirror-parity population instead of writing it down #7731's derived population, merged here; KnownDrift KanbanSchema: onCardMove | onCardClick | onQuickAdd; KanbanSchema added to SPEC_DERIVED_PAIRS; the rule union excluded with its reason), handler-keys-6124 (owner rename plus onCardClick restored and onQuickAdd added ⇒ 45 + 22 = 67), component-docs-retired-handler-keys-7340 (CONTROL re-keyed and extended to 7; census 26 unchanged because the onColumnAdd / onCardAdd tombstones carry over onto the successor arm), one-authority baseline history note.
  • Docsapi/schema-reference.md kanban section moves to the plugin dialect (in-page anchor and the import line follow; check-doc-links green); api/index.md, both READMEs, examples/zod-validation-example.ts.
  • Changesets@object-ui/types minor with a BREAKING banner; @object-ui/plugin-kanban patch. major not declared (check-changeset-no-major green).

The two numbers the dispatch said not to inherit

  • Body count. The ruling said "18-member"; a same-day AST census said 19. Re-derived with the TypeScript parser over complex.ts and pinned in the new test: the plugin dialect's own body is 19 live members (type is the one the ruling did not count), and the arm declared here is 20 live — those 19 plus onCardClick — plus 3 tombstones (draggable, onColumnAdd, onCardAdd). The twentieth is the R1 remediation: measured on origin/main, plugin-kanban/src/types.ts contains zero occurrences of the name while KanbanRenderer forwards it, so copying that dialect member for member reproduced its undeclared read.
  • objectui#6973. Re-measured before folding: already closed completed at 2026-09-05T00:43Z (its three keys had converged on the declarative face after objectui#6939). Nothing to fold. This PR moves the example it measured to the plugin dialect; it is referenced only.

How the ruling's refusal pin was read

The ruling's pin says "a columns / cards board is refused". Read literally that contradicts the ruled shape: the plugin dialect DECLARES columns[].cards[] — the two catalog entries are static boards of exactly that shape and render every card (examples/schema-catalog/test/kanban-column-cards-6939.test.tsx, still green). So the refusal keys on what the retired dialect had and this one does not: the board's draggable and a column's color. The retired CARD keys (labels, assignees, dueDate, priority, content) are deliberately NOT refused: a card is an open record (bucketCardsIntoColumns pushes raw records into lanes), so those are legitimate field names.

Read census, re-measured

Over packages/plugin-kanban/src (non-test), matching schema.KEY and the (schema as any).KEY cast form the first census missed, with every hit classified code-vs-comment by reading the line. Reads not named by KanbanSchema: titleField (2 real reads plus 2 comment mentions), filter (2 real plus 1 comment — objectui#7712), navigation (1), objectFields (1, an internal channel ObjectKanban writes, never authored), and the 'kanban-enhanced' trio onColumnToggle / enableVirtualScrolling / virtualScrollThreshold (1 each, on a registration with no declared arm at all). bind is not undeclared — it is a live member of BaseSchema, which this arm extends. Zero-read declared members: allowCollapse, cardTemplates, columnWidths (type also reads zero and is not a finding — the registry dispatches on it). The five missing rows and both corrections are posted to objectui#7742; onCardClick is recorded there as the row this PR closes, so it does not die when the card does.

Verification — all at 1a5915f26 (this head, after the origin/main merge)

Exit codes captured before any pipe; verdicts quoted from the instruments.

  • R1 probe, red-first then green, both doors, at each head above. The pre-fix reading was taken on a clean rebuild (tsconfig.tsbuildinfo removed with dist, or tsc emits nothing and the old dist answers).
  • packages/plugin-kanban$ pnpm run type-check — the exact command the Type Check job runs — reproduced red (exit 2, 5 errors) on the previous head and exit 0 here. Repo-wide turbo run type-check81 successful, 81 total.
  • The parity ratchet's instrument is tsc -p packages/types/tsconfig.test.json --noEmit, not vitest: exit 0, zero diagnostic lines.
  • Vitest packages/types/ packages/plugin-kanban/ examples/schema-catalog/169 files, 4240 tests passed.
  • Ablation — the type instrument is lit for the new assertion. Committed first, then onCardClick mutated back to ?: never; mutation proved on disk (live signature 1→0, never form 0→1); tsc -p packages/types/tsconfig.test.json exit 2 with exactly two diagnostics, both naming the ablation — TS2344 at handler-keys-json-refusal-6124.test.ts(549,10) (the new KeepsFunction line) and TS2322 at zod-mirror-parity.test.ts(1555,14) (the KnownDrift entry stops being an allowed drift once the faces agree). Restored under a trap … EXIT INT TERM with an absolute path, proved by git hash-object == the HEAD blob 84392c98f… and an empty git diff HEAD. The second ablation was not re-run because it was already taken: the new derived guard's red-first run on the unfixed head reported onCardClick as declared: false, guidance: false beside onCardMove and onQuickAdd at true.
  • ESLint eslint . over the repo: exit 0 — 0 errors, warnings only (all pre-existing no-explicit-any, none on a line this diff adds).
  • Gates, exit 0 each: changeset:check, check-changeset-presence ("17 source file(s) of 2 released package(s) changed, and this change declares 2 changeset(s)"), check-changeset-overwrite, check:control-bytes ("scanned 6318 tracked text file(s)"), check:doc-fences, check:doc-types, check:doc-links ("Links are valid across 17 scan roots"), check:vi-mock-specifiers, check:vi-mock-inherit, check:published-tsconfig-exclude, check-type-check-coverage, check:phantom-deps, check:self-import, check:dist-completeness.
  • The two gates the previous round could not run are now measured, not skipped. Their prerequisite (every package's dist on disk) was built here: check:doc-snippets ⇒ exit 0, "456 of 456 block(s) judged, 0 failed"; check:readme-exports ⇒ exit 0, "421 self-imports judged (421 real, 0 wrong-path, 0 fabricated)".

Refs: objectui#6172 · objectui#7645 · objectui#7651 (closed not_planned) · objectui#6973 (closed completed) · objectui#7322 · objectui#7712 · objectui#7742 · objectui#7753 · PR #7643 · PR #7662 · PR #7731 · PR #7732.

Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3

🤖 Generated with Claude Code

https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3

…ativeKanban* trio retires

For an authored `type: 'kanban'` document two types were authoritative
depending on who asked: `safeValidateSchema` honoured `DeclarativeKanbanSchema`
while the renderer registered for the key consumed `@object-ui/plugin-kanban`'s
own `KanbanSchema`, so a board could validate and render empty. Maintainer
ruling (a) (2026-09-05, batch #41): the plugin dialect is authoritative.

- `@object-ui/types` declares `KanbanSchema` / `KanbanColumn` / `KanbanCard` /
  `CardTemplate` / `ColumnWidthConfig` (member for member the plugin's shape),
  mirrors them in `zod/complex.zod.ts`, and `SchemaRegistry['kanban']` names
  the declaration; `plugin-kanban/src/types.ts` re-exports the five.
- The retired dialect's inert keys (`draggable`, column `color`) are `?: never`
  tombstones refused by name; `onColumnAdd` / `onCardAdd` carried over.
- The six `DeclarativeKanban*` exports retire (ADR-0049) with their two
  objectui#7645 pins; a 7664 pin on each side replaces them. The parity,
  handler-key and docs-retired ratchets are re-keyed; the docs page moves to
  the plugin dialect.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
…ban-plugin-dialect-authoritative

# Conflicts:
#	packages/types/src/__tests__/zod-mirror-parity.test.ts
@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-CefIat3_.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 (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 (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

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Contract review — ⛔ VERDICT: REFUSE

domain:ui PM seat, session_01KbJQ1y1J12nZxYzFWhP8Q3. Reviewed in isolation at head bd1fc71118 by a subagent running as claude-fable-5-1, in a detached scratch worktree since removed clean (git status --porcelain 0, no stash, no GitHub writes, throwaway ref deleted); every ablation under an EXIT INT TERM trap with the restore proven by blob hash. origin/main..HEAD is exactly this PR.

A REFUSE is not cleared by the fix. The remediated diff comes back for a fresh isolated review. needs:contract-review stays on both carriers.


R1 — the blocking finding: this PR widens an accept set, in the direction #6124 ruled out

onCardClick was refused by name on the 'kanban' arm under the #6124 handler-key regime. This PR deletes the key outright — no ?: never, no refusal arm. Measured on the built dist:

document before at this head
{type:'kanban', columns:[], onCardClick:{action:'toast'}} REFUSED ACCEPTED
the same shape at onCardMove / onQuickAdd / onColumnAdd / draggable REFUSED REFUSED

'onCardClick' in KanbanSchema.shapefalse. On the TS face the key now reads any through BaseSchema's index signature, where it read a callable. That is the bare deletion #6124 states as ⛔ 不裸删, and its own counter-probe describes this exact failure.

⭐ And the recorded rationale is contradicted by a read site the PR did not check

Two places in this diff justify the deletion — the RUNTIME_SLOT comment in handler-keys-json-refusal-6124.test.ts, and the KnownDrift comment in zod-mirror-parity.test.ts ("has no onCardClick member — the object-bound board owns the click").

But KanbanRendererpackages/plugin-kanban/src/index.tsx:194, one of the four registrations the ruling itself counts — forwards:

onCardClick={schema.onCardClick}

…in the same block as the onCardMove / onQuickAdd forwards this PR keeps as runtime slots. And the docblock on the removed DeclarativeKanbanSchema.onCardClick cited that very read site as its reason to exist.

⇒ The argument that deleted onCardClick would have deleted onCardMove just as well. The PR kept one and dropped the other, on a rationale the source contradicts. ⛔ It is named in neither the changeset nor #7742.

⚠️ Why no ratchet caught it — worth more than this PR

The 6124 ledger was re-keyed by substitution (onCardClickonQuickAdd, 44 held constant). A hand-written ledger cannot see a deleted key. That is precisely how a refused key became an accepted one while every gate stayed green.

Remedy to re-verify

Give onCardClick a #6124 disposition on the successor arm — ⛔ measure which, do not choose by preference:

  • runtime-slotonCardClick?: (card: KanbanCard, event?: unknown) => void on the TS face + handlerKeyRefusal('onCardClick','runtime-slot'); RUNTIME_SLOT 44 → 45; KnownDrift gains onCardClick.
  • retired — only if measured dead on the 'kanban' key because ObjectKanban overrides it: ?: never + the 'retired' arm; RETIRED 22 → 23; the 7340 census 26 → 27.

Then correct both comments, add a bullet to the @object-ui/types changeset, extend #7742's undeclared-read table, and re-run the probe: onCardClick: {…} must read REFUSED.


Everything else in the PR is sound, and two things are worth confirming on the record

The ruling's number was wrong and the dev was right. Counted member for member off origin/main:packages/plugin-kanban/src/types.ts: 19, not the ruling's 18 — the omission is type. The new KanbanSchema carries those 19 plus three tombstones = 22 property signatures. ⭐ Refusing to inherit a ruling's number is the behaviour this seat wants, and it is confirmed rather than merely accepted.

The dev's open question → A, and the pin's literal wording was wrong. The pin says "a columns/cards board is refused", but that rested on a false premise — that the plugin dialect is data-bound only. Measured: draggable 0 read sites, allowCollapse/cardTemplates/columnWidths 0, with coverImageField lit as the control (2 files / 7 hits); column color's only .color reads are select-option colours (ObjectKanban.tsx:492-553); bucketCardsIntoColumns does push raw records into cards, and SortableCard reads card[swimlaneField] off the record. Under C the catalog's two static boards and kanban-column-cards-6939 (green, 64/86 elements) are exactly columns[].cards[] documents. ⇒ B refuses record field names the board reads back; C refuses the declaration. A executes the ruling's own principle — accept what the registered renderer reads, refuse what it does not. ⛔ But A does not clear R1, because R1 is a key the renderer does read.

Ratchets look, and were proven to look. 213 export const − 54 EXCLUSIONS = 159 = MIRRORS = EXPECTED_MIRROR_PAIRS, independently derived under #7731's derivation. Lit controls: deleting CardTemplateSchema's entry ⇒ 3 red (including MIRRORS holds 158, EXPECTED_MIRROR_PAIRS says 159); onQuickAdd refusal → z.any() ⇒ 4 red in 6124; deleting the onQuickAdd docs row ⇒ 1 red in 7340. All restored by hash.

Discriminator. The six whole-name exports are removed, not alias-tombstoned — correct, since a whole exported name has no carrier. [key: string]: any is at base.ts:467 (inside BaseSchema, declared :70) — my brief's ~:440 had drifted; the fact had not. ⚠️ KanbanColumn does not extend BaseSchema, so for color?: never the loud-vs-silent argument reaches only non-fresh objects; the tombstone is still legitimate on prong 2 (schema-reference.md taught both keys as working).

CI, 32 runs read individually: 27 success, 3 skipped, 2 in_progress (Test shard 1/4 and 4/4) at review time; nothing red. content/docs/releases/ 0 files. Both carriers carry needs:contract-review.

Non-blocking, to ride with the remediation

(a) The plugin changeset says the shape is "member for member what this package declared" — false by four tombstones (draggable, onColumnAdd, onCardAdd on KanbanSchema; color on KanbanColumn), disclosed only on the sibling @object-ui/types entry.
(b) The draggable/color tombstone JSDoc argues from inertness and cites no prong — cite prong 2 so the file does not read as another instance of #7678.
(c) #7742 is incomplete. Its zero-read rows are true, and titleField is at ObjectKanban.tsx:303 and :977, and the root README does author columns: [{ value, label, color }] with col.value/col.label at zero reads. But the full schema.* census gives nine undeclared reads: titleField(4), filter(3), onCardClick(1, index.tsx:194), objectFields, navigation, bind, and the kanban-enhanced trio. ⭐ The onCardClick row is what turns R1 into a finding that would otherwise have died when Fixes #7664 closed the card.


Generated by Claude Code

…ission

The successor `'kanban'` arm dropped `onCardClick` instead of giving it a
#6124 disposition. `BaseSchema` is `.passthrough()`, so a dropped key is not
refused — it stops being judged and the value is KEPT. Measured on the built
dist before this commit, `{ type: 'kanban', columns: [], onCardClick: {
action: 'toast' } }` was ACCEPTED with `{"action":"toast"}` surviving into the
parsed output, while the same document at `onCardMove` / `onQuickAdd` /
`onColumnAdd` / `draggable` was REFUSED. After it, all five are REFUSED.

The rationale that was recorded for the deletion — "the object-bound board owns
the click" — is contradicted by the source. Measured per registration
(`plugin-kanban/src/__tests__/kanban-handler-slots-7664.test.tsx`, new here):

  - `'kanban-ui'`: `KanbanRenderer` forwards `onCardClick`, `onCardMove` and
    `onQuickAdd` to the board by identity, from one block. Lit controls: the
    two keys already ruled runtime slots come out live on this probe.
  - `'kanban'` / `'object-kanban'`: `ObjectKanban` substitutes its own function
    for `onCardClick` — and for `onCardMove`, in the same object literal, with
    `onQuickAdd` arriving by identity as the lit control on this key. The two
    keys have identical reachability here, so that reading retires both or
    neither.
  - and the substitute CALLS the authored handler: `ObjectKanban` declares an
    `onCardClick` prop (there is no `onCardMove` prop), which `SchemaRenderer`
    supplies by spreading non-metadata schema keys. An `onCardClick` authored
    on a `type: 'kanban'` document runs.

So the disposition is RUNTIME SLOT: callable on the TypeScript face, refused by
name on the mirror. `RUNTIME_SLOT` 44 -> 45, `ALL_SITES` 66 -> 67; `RETIRED`
stays 22 and the #7340 docs census stays 26.

Why no ratchet caught it: the #6124 ledger is hand-written by key, so a
substitution holds its length constant and a deleted key is invisible to it.
The new file derives the required key set from the read site instead — it
extracts the `schema.on*` reads out of `KanbanRenderer`'s body and requires
each to be a declared arm member, which is red on exactly this deletion.

Also in this commit, riding with the remediation:

  - the `@object-ui/plugin-kanban` changeset no longer claims the shape is
    "member for member what this package declared". Counted with the TypeScript
    parser against `origin/main`, it is that shape plus four members: three
    `?: never` tombstones, and `onCardClick`, which the plugin dialect never
    declared while its renderer read it.
  - the `@object-ui/types` changeset gains the accept-set bullet for the five
    handler arms.
  - the `draggable` / column `color` tombstone JSDoc cites the two-prong
    discriminator instead of arguing from inertness. Re-measured on
    `origin/main`: `schema-reference.md` opened its kanban example with
    `"draggable": true`, documented it in the property table, and authored a
    `color` on every one of its three columns.
  - `schema-reference.md` documents `onCardClick` again, and it joins the #7340
    blanket-sweep control (six rows -> seven).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
@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.5 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-CumQ-WR_.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.63KB 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.44KB 61.25KB
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 (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 (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

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

⛔ CI red on ecdaafaf0Type Check. Ruled in as this PR's, handed to the implementing seat with the diagnosis.

domain:ui PM seat. Recording this once so the failure and its attribution are on the PR, not only in a dispatch channel.

The failure

Run 33973229787, job 101325327748, packages/plugin-kanban pnpm run type-check exit 2:

Property 'dataSource' is missing in type '{ children: Element; }' but required in type
  '{ children: ReactNode; dataSource: any; debug?: boolean; … }'      ×2
Cannot find name 'node:fs' / 'node:path' / 'node:url'.

It is not the base's — measured before anything else

reading result
Type Check on main (81a2eb1fb) success (14:40:40Z, and again at 14:26:34Z)
Type Check on this PR's previous head bd1fc7111 success (14:11:52Z)
Type Check on ecdaafaf0 failure
the failing project packages/plugin-kanban — the package this remediation adds a test file to

The range bd1fc7111...ecdaafaf0 adds packages/plugin-kanban/src/__tests__/kanban-handler-slots-7664.test.tsx (+251). Green base, green previous head, red once that file lands, in that package's own type-check. ⛔ Not a flake, not the base's, and no re-run is being spent on it — the two green baselines are what a re-run would have been buying.

Two distinct errors, not one

⚠️ Cannot find **name** 'node:fs' — not "cannot find module". That is a bare specifier read in a type/value position, or a file needing node in its tsconfig types; the same tsconfig is green on main, so something in the diff put those specifiers where the compiler reads them as names. It must be diagnosed separately from the dataSource errors, and ⛔ neither may be silenced by loosening the source: making the provider prop optional or casting it away would be a type-surface change on a PR whose entire subject is that the type surface must be honest.

Four test shards were still in_progress when Type Check went red; they are owed a reading too.

State

needs:contract-review stays on both carriers. This remediated diff returns for a fresh isolated contract review regardless of CI — a REFUSE is never cleared by the fix. The R1 disposition (onCardClick runtime-slot vs retired) still has to be measured, not chosen; the ledger still owes an answer on what would catch a deleted key (a hand-written ledger cannot, which is how R1 got in); and objectui#7742 still owes its missing undeclared-read rows.


Generated by Claude Code

…age's own type-check

`Type Check` went red on the previous head, in `packages/plugin-kanban`'s own
`pnpm run type-check`, on the file the remediation added. Two distinct causes,
both reproduced with that exact command before and after:

  - TS2591 ×3 (`node:fs` / `node:path` / `node:url`) — `tsconfig.test.json`
    names `types`, which switches off automatic `@types/*` inclusion, and its
    comment recorded the invariant the new file breaks: "nothing in these tests
    touches Node globals". The file reads `../index.tsx` off disk on purpose —
    that is what makes the guard derive the forwarded key set from the read
    site instead of from a list. `node` is named alongside
    `@testing-library/jest-dom`, exactly as plugin-calendar / -charts /
    -chatbot / -dashboard / -detail / -gantt / -grid already do, and the
    comment now says why. It stays OUT of `tsconfig.json`: package source ships
    to browsers.
  - TS2741 ×2 — `SchemaRendererProvider` requires `dataSource`. Spelled
    `dataSource={undefined}`, the form three other call sites in this repo use
    for a surface that fetches nothing; these boards author their lanes
    statically, so it is the same runtime value the measurements were taken
    with. ⛔ Not fixed by loosening the prop or casting the provider — the
    subject of this PR is that the type surface must be honest.

`packages/plugin-kanban$ pnpm run type-check` exit 2 -> 0, and
`turbo run type-check` is 81/81 across the repo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
@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.5 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-CumQ-WR_.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.63KB 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.44KB 61.25KB
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 (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 (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

@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.7 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-BJOuTw-1.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.63KB 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.44KB 61.25KB
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 (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 (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

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

R1 remediated at 1a5915f26 — and ⛔ parked: the fresh contract review this owes now waits on the director seat

domain:ui PM seat, session_01KbJQ1y1J12nZxYzFWhP8Q3. The maintainer has told this seat that its claude-fable-5-1 budget is exhausted and that contract review now routes to the director seat. ⛔ A REFUSE is never cleared by the fix, so this remediated diff needs a fresh, full isolated review — and this seat can no longer run one. needs:contract-review stays on both carriers (PR #7743, card #7664). ⛔ Not landing it.

R1 is fixed, and it was reproduced red-first rather than argued

Measured on the built dist, at both doors (KanbanSchema.safeParse and the exported safeValidateSchema), with a clean rebuild (tsconfig.tsbuildinfo removed alongside dist, or tsc emits nothing):

document before after
{type:'kanban', columns:[], onCardClick:{action:'toast'}} ACCEPTED, and passthrough: onCardClick survives into the parsed output = {"action":"toast"} REFUSED / REFUSED, custom @ ["onCardClick"]
onCardMove · onQuickAdd · onColumnAdd · draggable (controls) REFUSED REFUSED, unchanged
arm shape declares onCardClick false true

The disposition was measured, not chosen: onCardClick is a runtime slot — callable on the TS face, refused by name on the mirror. Ledger deltas: RUNTIME_SLOT 44 → 45, ALL_SITES 66 → 67, RETIRED stays 22, the 7340 docs census stays 26.

⭐ The systemic answer, and it is bigger than this PR

The question this seat put to the remediation was "what would now catch a deleted key?" — because the re-key that let R1 through was a substitution, which holds the ledger's length constant. The answer is filed as objectui#7753: the #6124 handler-key ledger is hand-written by name, so it cannot see a deletion at all. The new derived guard closes this for the kanban arm only — 3 of the ledger's 67 sites. The other 64 reproduce the same failure with every gate green. And the card names the trap: ratcheting the count is the tempting fix and is precisely the one that fails on this very instance.

It corrected the review, and re-measured #7742 rather than pasting into it

The two gates the previous round declared NOT MEASURED are now measured

Rather than declaring the narrowing a second time, the seat built the 34-task prerequisite: check:doc-snippets exit 0 (456 of 456 blocks judged, 0 failed) and check:readme-exports exit 0 (421 self-imports judged, 421 real, 0 wrong-path, 0 fabricated).

Type Check — the failure I attributed to this PR, root-caused and closed

Reproduced with the exact job command (packages/plugin-kanban$ pnpm run type-check) at exit 2 with five errors — TS2591 ×3 on node:fs/node:path/node:url and TS2741 ×2 on a missing dataSourceboth causes root-caused separately, now exit 0, with repo-wide turbo run type-check at 81 successful / 81 total.

⚠️ And a reading not to inherit: the previous head f88304691 shows its checks cancelled because the newer push superseded them, so there is no shard result from that head to carry forward — including the "Type Check went green there" reading I posted earlier. The seat ran a 104-suite cross-package blast radius in its place (1735 tests, exit 0).

What is owed, precisely

  1. A fresh isolated contract review of the whole remediated diff — 25 files, not just the R1 hunk. ⛔ Not a re-read of the old verdict.
  2. CI to terminal on 1a5915f26: 24 success / 3 skipped / 0 failed, 5 still running as of this comment (Type Check + the four shards).
  3. Only then the three landing checks and the queue.

Handing the review to the director seat. ⛔ Until it returns, this PR does not move.


Generated by Claude Code

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Status refresh — CI is now terminal green; one item remains, and it is not this seat's to do

Updating the "what is owed" list from my park notice (5552874537) so whoever picks this up does not have to re-derive it.

owed state
CI to terminal on 1a5915f26 32 check runs enumerated individually — 29 success, 3 skipped by design, 0 failed, 0 in progress. ⛔ Not read from the check_suite rollup.
A fresh, full isolated contract review of all 25 files OUTSTANDING — director seat. This seat's claude-fable-5-1 budget is exhausted.
the three landing checks, then the queue blocked on the above

A REFUSE is never cleared by the fix, so what is owed is a fresh review of the whole remediated diff — not a re-read of the REFUSE verdict, and not a spot-check of the R1 hunk. needs:contract-review stays on both carriers (this PR and card #7664). ⛔ This seat is not landing it and is not reviewing it.

For the reviewer's convenience, the two things I would put at the top of an attack list — both are the remediation's own claims and neither has been independently verified:

  1. The R1 probe{type:'kanban', columns:[], onCardClick:{action:'toast'}} reported REFUSED at both doors on the built dist, with the four controls unchanged. That probe is the whole point of the remediation; ⛔ re-run it rather than reading the table.
  2. The dispositiononCardClick judged a runtime slot (RUNTIME_SLOT 44 → 45, ALL_SITES 66 → 67, RETIRED unchanged at 22, the 7340 census unchanged at 26). The card's alternative was retired; the choice rests on whether an authored onCardClick on a type: 'kanban' document actually reaches KanbanRenderer's forward at index.tsx:194, or whether ObjectKanban always supplies its own.

And one correction the remediation made to my REFUSE that a reviewer should carry rather than re-derive: bind is not an undeclared read — it is a live BaseSchema member at base.ts:248, so it belongs on no count of undeclared reads.


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

1 participant