Skip to content

feat(types,plugin-kanban)!: object-kanban's conditionalFormatting takes the spec list view's { condition, style } rule only; the native and flat-colour dialects are refused by name (objectui#11522) - #11532

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-11522-kanban-rule-dialect-retired
Oct 3, 2026

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11522

Clause-②: no (narrowing)

object-kanban's conditionalFormatting takes one rule dialect, the spec list view's { condition, style }. The native { field, operator, value, backgroundColor, borderColor } rule and the flat CEL rule (a colour written beside condition instead of inside style) are retired with no alias window and refused by name. This executes triage's ruling 5963861071 (retire, not widen). objectstack-ai/objectstack#21464 can then type the member by reference to its list-view member.

What changes

Rule on object-kanban Before (BASE 6903eafb) After
{ condition, style } (string, envelope or '' condition) accepted on all three zod faces accepted, unchanged
native { field, operator, value, backgroundColor } accepted on all three faces refused at field, operator, value and backgroundColor, each naming the retirement
flat CEL { condition, backgroundColor } refused as a bare invalid_union at the rule refused at backgroundColor (named) and style (required)
{ condition, style, backgroundColor } tolerant face accepted it (the colour key was stripped from the parse, while the shared resolver paints a top-level colour over style, as listConditional.test.ts pins); strict face refused it as invalid_union refused at backgroundColor on every face
{ condition, style, label } tolerant face accepted it, strict face refused it refused on every face, unrecognized_keys with the spec rule's own message

The three faces are ObjectKanbanSchema, safeValidateSchema (tolerant) and StrictAnyComponentSchema (strict). The before and after columns were read with a throwaway probe on each tree. The probe was deleted and never committed.

  • zod (@object-ui/types, zod/objectql.zod.ts). KanbanConditionalFormattingRuleSchema is the spec ListViewSchema.conditionalFormatting element, taken through stripImportedDefaults and .extend()-ed. It is no longer a union. It inherits the spec rule's strictness and its style record. Two things are layered on top. First, condition is SpecRuleConditionSchema, the list view's and the grid's own condition arm (objectui#10946), so a string condition is still not canonicalized and '' is still accepted. Second, six retirement tombstones: field, operator, value, backgroundColor, borderColor, textColor.
  • TS (objectql.ts). KanbanConditionalFormattingRule is an interface that extends SpecConditionalFormattingRule and declares the same six keys ?: never. KanbanNativeConditionalFormattingRule is deleted and dropped from the barrel (TS2305 for an importer). tsc reports a retired key by name (TS2322 at each key).
  • @object-ui/plugin-kanban. The registration's conditionalFormatting description no longer teaches the native or flat-colour rule. KanbanImpl's comments say what did and did not narrow. No render path changed: the description string is the only non-comment line.
  • Docs. The object-kanban row in content/docs/api/schema-reference.md documents the one rule and its respelling.
  • One changeset (11522-kanban-rule-dialect-retired.md): types and plugin-kanban minor, with BREAKING and FROM/TO spelled out.

Mechanism hypotheses, measured

H1, the census (writers of each retired dialect). The census used three instruments, and each one caught something the others missed. (1) Rule objects inside a conditionalFormatting: [ array. (2) Every object literal carrying a top-level colour key, classified by its other keys. (3) Every rule-shaped object within 400 characters after any conditionalFormatting token, in any syntax, which catches tuples and key:/value: rows. A fourth pass listed every { field, operator } literal in files that mention both conditionalFormatting and kanban. Each remaining hit was triaged by hand as a filter rule, a grid, list-view or report carrier, or a resolver unit test.

Where Writers on object-kanban at BASE Disposition
packages/types/src/__tests__/kanban-conditional-formatting.test.ts 3 native (2 zod documents, 1 TS literal) turned around: pins both refusals
packages/types/src/__tests__/object-kanban-allow-collapse-retired-8801.test.ts 1 native (the "still accepts the live member" row) respelled { condition: "record.status == 'open'", style: { backgroundColor: '#fee2e2' } }
packages/plugin-kanban/src/__tests__/ObjectKanban.structuredMembersReachTheirSinks-8313.test.tsx 1 native, 1 flat CEL respelled { condition: "record.owner == 'ann'", style: { backgroundColor: 'rgb(1, 2, 3)' } } and { condition: "record.owner == 'bob'", style: { backgroundColor: 'rgb(4, 5, 6)' } }, plus one new row for the whole style map
packages/plugin-kanban/src/__tests__/structuredKeysAreDeclaredAndHonoured-8313.test.ts 1 native respelled { condition: "record.owner == 'ann'", style: { backgroundColor: '#eef' } }
packages/plugin-kanban/src/__tests__/objectFieldsIsAPropNotASchemaKey-7742.test.tsx 1 native (relation field) respelled { condition: "record.owner == 'u1'", style: { backgroundColor: PAINT } }
packages/plugin-kanban/src/index.tsx (registration description) taught both rewritten
content/docs/api/schema-reference.md taught native rewritten
apps/console/src/__tests__/registry-inputs-spec-parity.test.ts (member-pin prose) described both rewritten
objectui examples/, apps/console non-test code, skills/ zero; controls fire (object-kanban in 4 examples/ files, kanban in 9 skills/ files) none
objectstack examples/ at f9a8eb88 zero. The one conditionalFormatting (app-showcase field-zoo.view.ts) is { condition, style } on a list view. Controls fire: kanban hits in app-crm views, and { field, operator, value } filter literals match the same matcher none
objectstack-ai/hotcrm NOT MEASURED: not in this container. Triage measured zero none

H2, by reference. The installed @objectstack/spec 17.5.0 exports no named rule schema. The rule is reachable as ListViewSchema.shape.conditionalFormatting.unwrap().element, a strict object of condition and style. The zod twin .extend()s that element through stripImportedDefaults. It does not override the condition with the bare spec slot, because the spec slot canonicalizes a string condition into an envelope and refuses ''. The 10946 pins assert both behaviours on object-kanban. The TS twin is SpecConditionalFormattingRule, which already indexes ObjectListViewSchema's slot by reference. It is extended, not restated. A new pin asserts shape.style is the spec element's own style, by identity. Its control is that shape.condition is not the bare slot.

H3, the refusal. With one arm, zod reports at the retired key's own path, and no invalid_union remains at the rule. The messages are identical on safeValidateSchema and StrictAnyComponentSchema. They are shown below, with backticks spelled as in the source:

  • Native rule, at conditionalFormatting.N.field (and the same at .operator and .value, with the key name swapped):

    field belongs to the native kanban rule dialect { field, operator, value, backgroundColor, borderColor }, which object-kanban's conditionalFormatting no longer accepts: RETIRED (objectui#11522), with no alias window. A rule is { condition, style } — a CEL condition over record.* and a CSS style map, the rule @objectstack/spec's ListViewSchema.conditionalFormatting declares. Respell { field: 'priority', operator: 'equals', value: 'high', backgroundColor: '#fee2e2' } as { condition: "record.priority == 'high'", style: { backgroundColor: '#fee2e2' } } (not_equals is !=, contains is .contains(…), in is record.f in [ … ]).

  • Flat CEL rule, and any top-level colour, at conditionalFormatting.N.backgroundColor (borderColor and textColor are the same; textColor says style: { color }):

    backgroundColor is a colour written at the top level of the rule, which object-kanban's conditionalFormatting no longer accepts: RETIRED (objectui#11522), with no alias window. A rule is { condition, style } — a CEL condition over record.* and a CSS style map, the rule @objectstack/spec's ListViewSchema.conditionalFormatting declares. Move the colour into the rule's CSS map: style: { backgroundColor }.

  • Beside these, a native rule also draws invalid_union at .condition and invalid_type at .style (both required), and a flat CEL rule draws invalid_type at .style. An undeclared key draws the spec rule's own unrecognized_keys message. For expression that message adds "Did you mean expression → condition?".

The retirementTombstone helper is the one used. aliasKeyRefusal does not fit: these keys are a retired dialect, not aliases of one canonical key.

H4, the resolver. Every arm of resolveConditionalFormatting still has a live authorable carrier. This was measured on the built safeValidateSchema and ObjectGridSchema:

Arm object-grid node (properties bag) ObjectGridSchema (view table slot / renderer props) object-view table slot list-view node object-kanban node
condition + style accepts accepts accepts accepts accepts
expression accepts accepts accepts accepts refuses
field / operator / value accepts accepts accepts accepts refuses
backgroundColor / textColor / borderColor overrides accepts accepts accepts accepts refuses

No arm has a measured zero carrier, so listConditional.ts is untouched.

H5, the render. A throwaway probe drew each rule through the real SchemaRenderer → object-kanban board, and through KanbanRenderer with and without objectFields. It ran at BASE and again after the change. The two readings are byte-identical:

native (8313): Alpha=[background-color: rgb(1, 2, 3);] Beta=[(none)]
native respelled: Alpha=[background-color: rgb(1, 2, 3);] Beta=[(none)]
flat CEL (8313): Alpha=[(none)] Beta=[background-color: rgb(4, 5, 6);]
flat CEL respelled: Alpha=[(none)] Beta=[background-color: rgb(4, 5, 6);]
native (7742) objectFields=true: paint=[rgb(255, 0, 0)]
native (7742) objectFields=false: paint=[(none)]
native respelled (7742) objectFields=true: paint=[rgb(255, 0, 0)]
native respelled (7742) objectFields=false: paint=[(none)]

Each respelling paints the card the retired rule painted, with the same style string. The respelled 8313 and 7742 rows pin this permanently through the real board, each with the live non-matching control.

The pins

  • kanban-conditional-formatting.test.ts (turned around). For each of the three faces, it pins: the { condition, style } control; the native rule refused at each retired key, with the message starting with the key's name and containing RETIRED (objectui#11522) and { condition, style }; the accepted rule at index 0 of the same document drawing no issue; the flat CEL rule refused at backgroundColor with the style: { backgroundColor } respelling and no invalid_union at the rule; and all three colour keys refused beside a style. It also pins the identity of style with the spec element (with its control) and the inherited strictness. On the TS face, @ts-expect-error covers each retired key, keyof equality holds between the two faces, and condition and style types are equal.
  • spec-expression-wire-slots-10946.test.ts reads condition straight off the rule's shape. There is no union arm left to index.
  • zod-mirror-parity.test.ts: the KanbanConditionalFormattingRuleSchema exclusion reason is rewritten. Its old reason ("a union of two rule dialects … the 'kanban' arm") was false twice over. It stays an exclusion, compared where it is pinned, the way ExpressionWireSchema is.

Pending changesets

  • Dated note appended: 10946-expression-wire-slots-by-reference.md. Its sentence "the list view's and the kanban board's rule unions share one condition schema" describes the kanban union.
  • Dated note appended: 7664-kanban-arm-plugin-dialect.md. Its sentence "KanbanConditionalFormattingRuleSchema is … the rule union the 'object-kanban' arm already applied" is now false.
  • Left alone, still true:
    • 7664-plugin-kanban-declared-schema.md: says nothing about rules.
    • 8932-retire-kanban-enhanced.md: only names KanbanConditionalFormattingRule as the type to use, which still exists.
    • 8313-kanban-structured-authoring-keys.md: the key is still declared and honoured, and its description still states what the board reads.
    • 7727-conditional-formatting-record-scope.md: about record.* conditions.
    • 7928-listviews-by-reference-fold.md, 9242-stray-kanban-groupby-lane-second-route.md: about named-view kanban config keys.
    • 8801-object-kanban-allow-collapse-retired.md: conditionalFormatting is still a live control key in plugin-kanban.
    • 7742-kanban-arm-batch70.md: about objectFields.
    • 7322-object-kanban-group-by-limit.md: its "it now authors groupBy" remark about the kanban test still holds.
    • 6349, 8165 and 8261: they name the one-authority gate, whose behaviour did not change; only its comments did.
    • The 13 grid and list-view entries that mention conditional formatting: none makes a kanban rule claim. One of them, 10275, names kanban only as a view binding.
  • check:changeset-overwrite reports the two modified entries with their declarations unchanged (types: minor), which is the appended-note case.

Verification (head 6d3b4da0)

  • pnpm exec vitest run --maxWorkers=2 packages/types/ packages/plugin-kanban/ apps/console/src/__tests__/registry-inputs-spec-parity.test.ts scripts/__tests__/one-authority-per-exported-name-6273.test.ts: 411 files, 9878 tests passed. VERDICT command-exit 0.
  • pnpm --filter @object-ui/types run type-check (src, examples and test configs): exit 0. Before the types pin was turned around, the same check reported TS2322 at the four retired keys of its old native literal. pnpm --filter @object-ui/plugin-kanban run type-check: exit 0, after pnpm --filter '@object-ui/plugin-kanban^...' build.
  • The doc gates ran after the scoped turbo run build (35/35 tasks):
    • check:doc-snippets: 777 of 777 blocks, 0 failed.
    • check:doc-examples: exit 0.
    • check:doc-types, check:readme-exports: OK.
  • With the console built, check:sdui-registration-pins and check:component-surface-parity (report-only, no kanban row): both green.
  • All exit 0: check:new-line-citations (0 new), check:control-bytes, check:changeset-claims, check:pending-changeset-literals, check:test-path-roots, check:spec-symbols, check:doc-fences, check-changeset-no-major, check-changeset-presence, check-changeset-fixed, check-doc-expression-carriage, check-type-check-coverage.
  • NOT MEASURED: the Spec Main Shape Gate (it needs objectstack main's spec; it belongs to CI). Spec main declares the rule with the same strictObject helper and no refinements (read at f9a8eb88), so .extend() is expected to hold there. The repo-wide lint is also left to CI.

Acceptance notes

  • What the board still paints. The board still paints any rule a relay hands it, because the shared resolver keeps every arm. For example, ObjectView's kanban branch relays a named or active view's conditionalFormatting, and objectui's ListViewSchema member still declares the native rule ("broader than spec, migration deferred", per its own docblock). The generated object-kanban node can therefore carry a rule the authored object-kanban contract now refuses. It is never validated, which is the same shape as the groupField note in that branch. Carrier: none.
  • The grid's native arm. On objectstack main, the object-grid block is typed by reference to the list view (objectstack PR #21463, per the card). objectui's grid properties bag and ListViewSchema still declare the native arm, and the installed 17.5.0 row is z.unknown() for both object-grid and object-kanban. The grid's native arm meets the same disagreement on a spec bump. Carrier: none named.
  • The skills guide. skills/objectui/guides/schema-expressions.md lists "the native { field, operator, value } form … still work" under renderer-side facts for "list/grid/kanban". That is true of the evaluator and no longer of object-kanban authoring. skills/** is governed, and this PR stays ungoverned, so it is left. Carrier: none.

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


Generated by Claude Code

claude added 4 commits October 3, 2026 01:55
…st view's { condition, style } rule only; the native and flat-colour rule dialects are refused by name (objectui#11522)

KanbanConditionalFormattingRuleSchema is the spec ListViewSchema rule element
by reference (.extend()), with the list view's own condition arm and the six
retired keys (field, operator, value, backgroundColor, borderColor, textColor)
as retirement tombstones. The TS twin extends SpecConditionalFormattingRule
with the same keys as `?: never`; KanbanNativeConditionalFormattingRule is
removed. The types pin is turned around to pin both refusals on all three
zod faces.

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
… { condition, style } rule; the kanban fixtures are respelled (objectui#11522)

The registry input description for conditionalFormatting no longer teaches
the native or flat-colour rule. The three plugin-kanban fixtures that authored
a retired dialect write the same predicate and paint as { condition, style }
and assert the same card is styled; a row pins that the whole style map
reaches the card. The schema-reference row, the console member-pin prose and
the one-authority test's note on the retired type name follow.

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
… on the two pending entries it makes false (objectui#11522)

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
… to { condition, style } (objectui#11522)

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 59 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/10872-container-children-channel.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Also in this change, with no behaviour change: objectql.zod.ts's two public-block arms (object-metric, object-master-detail-form) build their properties member with the same propsBag helper as the other public-block arms, instead of a byte copy of it. The member's description text is unchanged.

.changeset/11068-grid-declared-keys.md

  • names schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was wrong. ObjectGridSchema declared eight keys the grid never read. An author who wrote description, emptyState, name, placeholder, rowSpecActions or bulkSpecActions on an object-grid got no type error, no validator refusal and no effect. The reference example in schema-reference.md taught description and showFilters as if they worked. It now authors only keys the grid reads.

.changeset/11355-small-p1-sites-r2.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ObjectChartSchema.isAnimationActive?: boolean is declared on the TypeScript face. Code sets it false for a render with no entrance animation: DashboardRenderer and DashboardGridLayout on the object-chart nodes they build, and DatasetWidget and DatasetReportRenderer on the nodes they hand the chart registration. ChartRenderer honours it. The zod mirror declares no member for it, so it is not an authoring key; zod-mirror-parity.test.ts files it as runtime-only.

.changeset/3917-retire-action-condition-branch.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    • ActionCondition is removed from @object-ui/types (and from the barrel export). - ActionSchema.condition is retyped to the predicate the runtime actually honours: boolean | string | { dialect?: string; source: string } — the same three arms ActionRunner's own ActionDef.condition carries, and the same vocabulary visible and disabled use. - ActionConditionSchema is removed from @object-ui/types/zod (and from the zod barrel); the condition key now validates against that predicate union. - The two teaching sites (content/docs/core/enhanced-actions.mdx Conditional Execution, content/docs/api/schema-reference.md ActionSchema table) are rewritten to the live vocabulary: condition is a gate; a branch is expressed as separate actions with mutually exclusive conditions.

.changeset/5903-objectgantt-declared-keys.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

  • names src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743); the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair — but at that time the ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction, not that nothing was there. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger requires every registered pair's mirrored-but-undeclared key set to equal that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.changeset/5928-classname-style-props-rename.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Where the non-pair is recorded now. zod-mirror-parity.test.ts keys its existing EXCLUSIONS entry — the mechanism that accounts for every exported const with no TypeScript declaration to mirror, each with its stated reason — to ClassNameStylePropsSchema. Named for its own two keys, the const leaves no like-named declaration for a name-derived pairing to reach for.

.changeset/6051-gantt-flat-config-declared-keys.md

  • names packages/types/src/index.ts → packages/types/src/index.ts — edited by this change

    GanttConfig itself gains nine members and is a published type, exported by name from packages/types/src/index.ts: lockField, objectField, summaryExtent, defaultCollapsedDepth, borderColorField, dependencyTypes, timeZone, exportFileName, interactions. The entry file's diff is empty only because the export list already named the type — the widening happened at the declaration.

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743) — the same retirement objectui#5903's entry carries, for the same clause and the same reason; the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair, at a time when that ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger reconciles every registered pair's mirrored-but-undeclared key set against that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.changeset/6150-undeclared-but-consumed-keys.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ AMENDED, and the amendment ships in this same release. The TreeViewSchema slice (604476d97) gave the key a zod arm after all — a NAMED REFUSAL (handlerKeyRefusal(key, 'runtime-slot', label)), never a shape — because "no mirror entry" is not neutral under BaseSchema.passthrough(): it meant an authored { "type": "tree-view", "onNodeClick": { "action": "toast" } } parsed GREEN, survived the parse, and reached a call site that expects a function. ⇒ the three clauses this bullet used to carry are no longer true of the code shipping beside it. The key is now a MEMBER of TreeViewSchema.shape and an authored value is refused BY NAME at path onNodeClick; it has LEFT zod-mirror-parity.test.ts's RuntimeOnlyDeclared for that file's KnownDrift; and it is no longer "the first pair to sit there without also sitting in UnmirroredDeclared" — draining it emptied that difference, so RuntimeOnlyDeclared is now a SUBSET of UnmirroredDeclared and the union of the two equals UnmirroredDeclared itself. ⛔ objectui#6152's ruling is untouched by any of this: what the key still does not have, and never will, is a z.function() shape — no serialized document could satisfy one.

.changeset/6152-object-form-unmirrored-members.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectFormSchema in @object-ui/types (objectql.ts) declared a set of members that its zod mirror in @object-ui/types/zod had never heard of. Every one of them is read by the object-form renderer (ObjectForm in @object-ui/plugin-form). The two published faces answered differently:

.changeset/6170-retire-timeline-dead-keys.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Also in this change: the in-repo example packages/types/examples/data-display-examples.json (its timeline node authored all three) is migrated to items / variant; the two content/docs/api/schema-reference.md snippets that authored events: [] now author items: []; and the plugin-timeline docs callout says retired rather than deprecated.

.changeset/6172-markdown-kanban-one-authority.md

  • names KanbanImpl.tsx → packages/plugin-kanban/src/KanbanImpl.tsx — edited by this change

    KanbanCard / KanbanColumn — the three in-package copies converged to one. KanbanImpl.tsx and KanbanEnhanced.tsx each redeclared both names. A TypeScript-AST comparison found them strict-SUBSET copies of ./types with nothing typed differently, so their extra members moved onto the one declaration and, at this change, both files re-pointed at it.

.changeset/6175-column-state-persistence.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Nothing is retired. Both spellings remain declared on DataTableSchema; onColumnReorder stays declared and stays unwired, exactly as the RuntimeOnlyDeclared ledger in zod-mirror-parity.test.ts records it. Which of the two survives is a declared-surface ruling that stays open and is deliberately not settled here.

.changeset/6349-types-internal-name-collisions-batch-1.md

  • names scripts/__tests__/one-authority-per-exported-name-6273.test.ts → scripts/__tests__/one-authority-per-exported-name-6273.test.ts — edited by this change

    The three KNOWN_COLLISIONS lines came down in the same change; that baseline (scripts/__tests__/one-authority-per-exported-name-6273.test.ts) is shrink-only and fails in both directions, so converging without deleting them would have been red too. 43 entries → 40.

.changeset/6639-objectgrid-title-mirrored.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The gain is the typed refusal: the mirror's .passthrough() base was already admitting any title unexamined, and it now enforces the declared string. zod-mirror-parity.test.ts's UnmirroredDeclared ledger records the key as worked off — the ledger's first shrink by repair (97 + 1 mirrored + 23 reclassified is what the seeded "121" now means).

.changeset/6896-retire-chart-inline-data.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ One correction to the record the ruling rests on. The ruling states zero authorship of a populated series[].data outside tests across packages/ / apps/ / examples/. The re-measurement finds one such site inside those roots — packages/types/examples/data-display-examples.json (2 series) — plus four outside them, in documentation: content/docs/api/schema-reference.md (3) and content/docs/core/report-schema.mdx (1).

.changeset/6939-kanban-column-cards.md

  • names KanbanImpl.tsx → packages/plugin-kanban/src/KanbanImpl.tsx — edited by this change

    Breaking, deliberately. KanbanColumn declared its card list as items in complex.ts and in the zod mirror complex.zod.ts. Every board reads cards. Measured on origin/main 78a3cc238: KanbanImpl.tsx reads .cards on 12 lines, KanbanEnhanced.tsx on 8, and bucketCardsIntoColumns twice more as col.cards || []; .items had zero read sites in either board (a same-shaped .title control on the same two files returns 8 and 3, so those zeros are readings and not a mis-shaped probe). Both catalog entries, the plugin docs and content/docs/api/schema-reference.md all author cards.

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Breaking, deliberately. KanbanColumn declared its card list as items in complex.ts and in the zod mirror complex.zod.ts. Every board reads cards. Measured on origin/main 78a3cc238: KanbanImpl.tsx reads .cards on 12 lines, KanbanEnhanced.tsx on 8, and bucketCardsIntoColumns twice more as col.cards || []; .items had zero read sites in either board (a same-shaped .title control on the same two files returns 8 and 3, so those zeros are readings and not a mis-shaped probe). Both catalog entries, the plugin docs and content/docs/api/schema-reference.md all author cards.

.changeset/6940-rowactions-boolean-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The list view's same-named rowActions in zod/objectql.zod.ts — z.array(z.string()), the legacy bare-name action list on ObjectGridSchema — is a different key that is correct as it stands, is in parity with its own TS twin (rowActions?: string[]), and is not touched.

.changeset/6951-tree-view-data-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was measured, on this branch's base. TreeViewSchema declared two spellings for its one inline-nodes slot — nodes (read second) and data (read third: boundData || schema.nodes || schema.data || [] at renderers/data-display/tree-view.tsx:105), both declared by objectui#6150. data had been REQUIRED until 777e5c6f4 (PR fix(types): tree-view mirror stops requiring the limb it reads third (group 2 of objectui#6939) #7533) made it optional, so this retirement starts from a declared-and-optional member on both faces. The in-repo corpus at the retirement: seven tree-view nodes under examples/schema-catalog and packages/types/examples plus one content/docs fence — six on nodes, two on data (packages/types/examples/data-display-examples.json and content/docs/api/schema-reference.md), both rewritten; no package source authored either spelling.

.changeset/7113-chart-data-model.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    .extend() with a NEW key still works and preserves the fold and the refinement; .optional(), z.discriminatedUnion, z.toJSONSchema and safeValidateSchema are all unaffected. Nothing in this repository calls the throwing combinators on either const, and the published surface already ships refined mirrors (objectql.zod.ts, complex.zod.ts, form.zod.ts, app.zod.ts), so the class is not new — but it is a real behaviour change on a published export and it belongs in the release note rather than in a reviewer's file.

.changeset/7200-object-form-section-style-keys-undeclared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The authored-metadata type now agrees with @objectstack/spec, whose FormSectionSchema is a strict object declaring neither key, and with the ruling's rationale (maintainer 2026-09-01, verbatim): "retire the reads … Declaring the keys was weighed and not adopted: it would formally invite free Tailwind strings into authored metadata, the exact class the boundary exists to keep out." A ?: never tombstone was not used: ObjectFormSection has no zod mirror (ObjectFormSchema in zod/objectql.zod.ts does not declare sections), so there is no parse door to refuse at, and a tombstone is still a declaration in completion and in the published .d.ts.

.changeset/7265-types-user-filter-field-derives.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    zod/objectql.zod.ts declared two schemas under names @objectstack/spec/ui already exports. They were triaged separately, by reading their sites, and went different ways.

.changeset/7322-object-kanban-group-by-limit.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

  • names packages/types/src/__tests__/kanban-conditional-formatting.test.ts → packages/types/src/__tests__/kanban-conditional-formatting.test.ts — edited by this change

    Who is NOT affected. The VIEW-LEVEL kanban config is untouched: kanban.groupField there is a live legacy alias of the spec's groupByField (packages/core/src/utils/normalize-list-view.ts maps it; plugin-list's ListView and plugin-view's ObjectView still read it). groupField is dead only on the object-kanban NODE. The declarative kanban node (KanbanSchema) is untouched, BaseSchema's unknown-key policy is byte-identical (an undeclared key still passes through), and the renderer is unchanged — boards authored the documented way rendered before and render now. One in-repo fixture authored groupField on this node (packages/types/src/__tests__/kanban-conditional-formatting.test.ts); it now authors groupBy. No doc snippet, catalog entry, skill or app in this repository authored groupField on an object-kanban node.

.changeset/7344-handler-string-any-mirrors.md

.changeset/7352-drill-down-config-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    DrillDownConfigSchema is the zod mirror of DrillDownConfig, and both declarations that carry drillDown reference it — ChartSchema (zod/data-display.zod.ts) and ObjectDataTableSchema (zod/objectql.zod.ts) — so the published validator under @object-ui/types/zod reads the key for the first time (objectui#7352).

.changeset/7363-objectql-union-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

.changeset/7632-shared-record-source-config.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    That ladder is published contract on both faces — packages/types/src/objectql.ts and its zod mirror both ship .describe() strings naming getDataConfig's order (77cb489b4, maintainer ruling 2026-09-02), pinned by objectql-record-source-refinement-6939.test.ts — and it was hand-copied into five plugin components with no gate holding them together. A change to the ruled order had five edit sites and nothing that noticed a missed one; that is the AGENTS.md #0.1 drift class.

.changeset/7654-floating-chatbot-trigger-icon-tombstone.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Every other tombstone in this package pairs ?: never with a retirementTombstone() refusal on the Zod twin. There is no twin here to carry one: FloatingChatbotConfig has no Zod mirror at all, and floatingConfig sits in the UnmirroredDeclared ledger (zod-mirror-parity.test.ts, complex.zod.ts#ChatbotSchema). BaseSchema is .passthrough(), so the whole floatingConfig object rides through unvalidated — before this change and after it. Minting a mirror to host a refusal would be the declared-but-UNMIRRORED axis (objectui#6152), a different defect: a key can be mirrored and inert, or unmirrored and live, and fixing one says nothing about the other. This change does not widen into it.

.changeset/7804-objectql-handler-key-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The four plain objectql.ts node faces declare the nine handler keys their registered renderers read (the objectql.ts slice): ObjectFormSchema.onCancel / .onError / .onOpenChange / .onStepChange / .onSuccess, ObjectGallerySchema.onCardClick / .onRowClick, ObjectGridSchema.onNavigate and ObjectViewSchema.onNavigate.

.changeset/7804-tree-view-handler-slot.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    'runtime-slot' and not 'retired', measured at this key's own channel. 'retired' publishes "no renderer reads this key, so nothing could ever run it" — true of the two siblings already tombstoned on this arm (onSelectChange, onExpandChange) and flatly false here, since the read is live and INVOKED. ⚠️ No in-repo host builds a tree-view node carrying the key: the channel is wired end to end and only the supplier is absent, which is the same shape as ObjectFormSchema.onStepChange in this card's objectql.ts slice and is not evidence of a dead read. The TypeScript declaration is unchanged and still callable, so a programmatic host supplies it exactly as before.

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The pair moves from zod-mirror-parity.test.ts's RuntimeOnlyDeclared to its KnownDrift, which empties the former of the one entry the latter did not also hold — so the two unmirrored ledgers are now in a containment relation, and the cross-ledger figure that recorded their difference states the containment instead.

.changeset/7917-export-breadcrumb-object-tree-zod-schemas.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    AnyComponentSchema declares 107 node component types. 105 of them could be named on the ./zod barrel — ButtonSchema.safeParse(node), which is what a designer, a form builder or a targeted test needs. The arms declaring type: 'breadcrumb' (navigation.zod.ts) and type: 'object-tree' (objectql.zod.ts) could not: both were already export const in their own module, but index.zod.ts — the package's only zod entry point — did not re-export them, so the schemas existed, were maintained, and were applied by the union while no consumer could name them.

.changeset/7963-alert-dialog-footer-keys-retired.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Nothing else moves. These spellings are overloaded across the tree and every other owner is a live key on a different declaration — FormSchema.cancelLabel, objectql.ts's confirmLabel, plugin-designer's ConfirmDialog React props, plugin-grid's def.confirmLabel, and plugin-form's ModalForm / DrawerForm, which build a local cancelLabel from schema.cancelText. None is an AlertDialogSchema; none is touched, and a pin asserts it. No fixture, catalog schema, example app or doc fence authored any of the three on an alert-dialog node, so no shipped document is stranded.

.changeset/7997-detail-view-related-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Documentation. packages/plugin-detail/README.md and content/docs/api/schema-reference.md stop teaching the retired array and gain a migration block each.

.changeset/8067-component-input-member-kind.md

  • names apps/console/src/__tests__/registry-inputs-spec-parity.test.ts → apps/console/src/__tests__/registry-inputs-spec-parity.test.ts — edited by this change

    A registration's type: 'array' said a value was a list and stopped there, so a member that drifted from @objectstack/spec was invisible to every layer that reads a declaration. page:header.actions is the measured cost: the contract declares z.array(z.string()) ("Action IDs"), the renderer read the members as ActionDef objects, and the repo-wide parity gate in apps/console/src/__tests__/registry-inputs-spec-parity.test.ts stayed green for the whole life of the drift because both sides carried the key and neither could say what was inside it. What settled it was a maintainer ruling, not a test — and even after the fix, "these are ids" survived only as English in the registration's description.

.changeset/8261-translatefn-i18n-authority.md

  • names scripts/__tests__/one-authority-per-exported-name-6273.test.ts → scripts/__tests__/one-authority-per-exported-name-6273.test.ts — edited by this change

    The TranslateFn entry in the one-authority gate's KNOWN_COLLISIONS baseline (scripts/__tests__/one-authority-per-exported-name-6273.test.ts) is removed: the name now has one declaration.

.changeset/8268-testid-emitted-as-data-testid.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    The other direction — retiring the promise — was considered and declined. It is what c1fe272ad did for BaseSchema.hidden, but that key had a working behaviour to describe and zero named consumers, and the ruling's decline turned on exactly that. This promise already has carriers outside the type declaration: content/docs/api/schema-reference.md states it as a table row and authors testId in that page's own base-schema example, @object-ui/cli's OBJECTUI_STRUCTURAL_KEYS identifies a file as an ObjectUI schema node by this key, at this change ObjectGridSlotKey / ObjectFormSlotKey pin it, SchemaBuilder.testId() writes it, and ADR-0054 C4 — shipped — reads "the renderer emits data-testid … derived from metadata".

.changeset/8338-retire-toast-action.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The parity ledgers drain with it, every figure re-derived by zod-mirror-parity.test.ts's own AST and mirror instruments rather than stepped by hand: KnownDrift 42 entries / 64 keys → 41 / 63 (the entry's whole content, so the entry went too — the ledger's first loss by RETIRING a key rather than by moving either face toward the other), and WiderThanDeclared 23 / 36 / 47 arms, split 6 / 30 / 0 / 11 → 22 / 35 / 45, split 6 / 29 / 0 / 10. The pair itself stays registered, so EXPECTED_MIRROR_PAIRS does not move.

.changeset/8478-describe-line-addresses.md

.changeset/8572-chatbot-body-retired.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Why this key and not another. It was the ONE place in this vocabulary where body did not mean "what goes inside this component": zod-mirror-parity.test.ts carried the pair under KnownDrift as "two different meanings of one key", and the same collision was the whole reason chatbot was the single arm of the component union whose output was not assignable to SchemaNode. Both ledger rows move with this change, and the two pins that recorded the old state are INVERTED rather than deleted (see below).

.changeset/8653-listview-title-retired-rowactiondefs-pinned.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    title — retired. ListView resolved its export filename through schema.label || (schema as any).title. @objectstack/spec/ui's ListViewSchema refuses title by name (unrecognized_keys: ['title']) while ObjectGridPropsSchema accepts it; packages/types mirrors the platform contract rather than ruling over it, so declaring title on ListViewSchema would have made this repo accept what the platform save gate rejects. That asymmetry is also why objectui#6639 could take the declare branch for ObjectGridSchema.title one package over and this site could not. A parse-based census of apps/ examples/ content/ and packages/ found zero list-view nodes authoring title, so the retirement costs no author a filename. Over that same corpus the instrument reports three object-grid nodes carrying the key: two authored ones, both in content/docs/api/schema-reference.md, plus one that is not authored at all — packages/plugin-view/src/ObjectView.tsx composes title: schema.table?.title onto a grid node it builds, so it is a producer writing the key rather than an author declaring it. ObjectGrid's own title reads are untouched — they remain declared, ruled and read.

.changeset/8735-objectql-mirror-docblocks-not-defaulted.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Correct four zod/objectql.zod.ts docblocks that described the behaviour objectui#8317 removed. Since that change the zod mirrors strip imported @objectstack/spec defaults at this package's import boundary, but the docblocks on HttpRequestSchema, ListColumnSchema, SelectionConfigSchema and PaginationConfigSchema still said, in the present tense, that method, prefix.type, type and pageSize are defaulted on parse — the opposite of what each export does. Each now says the key is declared and accepted but NOT defaulted on parse.

.changeset/8767-object-grid-refuses-string-sort.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Migration. Write the array: sort: [{ field: 'name', order: 'desc' }]. Both keys are required. SortConfig.order carries no ? in @object-ui/types (packages/types/src/objectql.ts) and no .optional() in its zod mirror, and the protocol's own reusable SortItemSchema requires order as well — measured: that schema refuses [{ field: 'name' }] with invalid_value at 0.order. Do not omit it: this block's array arm interpolates whatever is present, so an omitted order lowers to $orderby: 'name undefined' today. That is pre-existing behaviour on the arm this change does not touch, and it is filed as a successor card rather than widened into here.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.
  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.
  • names object-kanban-allow-collapse-retired-8801.test.ts → packages/types/src/__tests__/object-kanban-allow-collapse-retired-8801.test.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.
  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8885-object-chart-drilldown-title-compareto.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

.changeset/8913-object-kanban-columns-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

.changeset/8990-object-kanban-groupby-optional.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

.changeset/8992-user-actions-collapse-and-docblock.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    objectql.zod.ts's UserActionsSchema read stripImportedDefaults(Spec).extend({ group, hideFields, rowColor }), an extension that existed only because @objectstack/spec did not declare those three keys while normalizeListViewSchema folded objectui's legacy showGroup / showHideFields / showColor onto them. The protocol adopted all three in 17.3.0 (objectui#5435's ruling), so the extension is now a second local copy of a protocol declaration — the shape two faces start drifting from — and it collapses into the plain by-reference re-export its own note always said it would become.

.changeset/9092-inline-locale-declared-face.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    • AppComponentSchema.label (app.ts) - ObjectGridSchema.label and .description (objectql.ts) - PageNodeSchema.aria.ariaLabel (layout.ts)

.changeset/9187-record-highlights-layout-two-values.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ The census behind this narrowing covers this repository only, and it found no in-repo authoring to migrate: every in-tree layout: 'grid' belongs to a different component (detail-view in content/docs/api/schema-reference.md and phase2-schemas.test.ts, ai-recommendations in packages/plugin-ai/README.md), and the one in-repo consumer of this interface that writes a layout (p1-spec-alignment.test.ts) writes 'horizontal'. So no document in this repository stops type-checking. A TypeScript consumer outside this repo that wrote grid is not observable from here and gets a compile error (TS2322) naming the key — which is why the FROM/TO is spelled out above.

.changeset/9309-object-gallery-filter-destination-typed.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

.changeset/9511-record-id-is-a-string.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ The declaration alone would not have been enough, and this is the reusable part. A TypeScript declaration does not run at parse time. The hand-written zod mirror is the only face in this repository that can refuse an authored number, so narrowing the declaration without the mirror would have shipped declared !== enforced on a published surface — and zod-mirror-parity.test.ts would have stayed GREEN through it, because that instrument asserts a mirror accepts everything its declaration declares and a mirror left WIDER passes. Both faces moved together for that reason.

.changeset/9549-tree-filter-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

.changeset/9550-object-tree-root-barrel.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectQLComponentSchema declares the node types an ObjectQL block may be. Every one of its arms was a named export of this package's root barrel except ObjectTreeSchema, which was declared in objectql.ts, applied by the union, and re-exported by the ./zod barrel (objectui#7917) — while no TypeScript consumer could name it. There is no ./objectql subpath to reach around the barrel: the package's exports map is pinned by packages/types/src/__tests__/package-exports-manifest.test.ts, and the root barrel was the only route to this type.

.changeset/9606-object-kanban-card-title.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

.changeset/9628-kanban-column-collapsed-honoured.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The key was declared on both published faces of the object-kanban arm — the lane element of ObjectKanbanSchema (objectql.ts and its Zod mirror) and the runtime lane KanbanColumn (complex.ts and its mirror) — and read by KanbanEnhanced alone, a module no production source imports. An authored { "id": "todo", "title": "To Do", "collapsed": true } therefore parsed green on both faces and reached a board that did nothing with it: KanbanImpl's only collapse is the SWIMLANE row's, held in viewer state under objectui:kanban-collapsed:ANGLE-BRACKETS(swimlaneField) and never keyed to a lane's declared value. That is the ADR-0049 declared-but-unhonoured shape.

.changeset/calendar-view-schema-converge.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Runtime renderer behaviour is unchanged. @object-ui/plugin-calendar's README and content/docs/api/schema-reference.md are repaired to the converged surface in the same change, so no copy of the old contradiction survives.

.changeset/component-meta-converge-and-deprecate-alias-5893.md

  • names packages/types/src/index.ts → packages/types/src/index.ts — edited by this change

    ⚠️ Dated note, 2026-09-29 — the one-occurrence reading above has since moved — objectui#10979. "In-repo, PluginComponentMeta has exactly one occurrence — its own export line" above is the reading of the commit this change landed on (575b71c850), where a whole-tree search for the name returned that one line, in packages/types/src/index.ts. This change then added its own pins and this entry, and later in this same release objectui#5674's retirement of the sibling alias PluginComponentInput (PR objectui#10826) added mentions in its test and its entry. Re-measured on main at 2eaf5be27, the name occurred on 19 lines in 7 files. In non-test source it appeared only on the export line and on one doc-comment line in plugin-scope.ts, and the one file that imported it was this change's own component-meta-single-declaration.test.ts. The text above is kept as the reading of this change.

.changeset/issue-5373-retire-crud-schema.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    crud had four declaration faces and no registered renderer, for the whole life of the key: the TS interface (packages/types/src/crud.ts), the zod mirror (packages/types/src/zod/crud.zod.ts), a dedicated branch in validateSchema that affirmatively PASSED it, and CRUDBuilder in @object-ui/core. A node spelling it painted the OBJUI-001 "Unknown component type" panel, and content/docs/api/schema-reference.md published it as reference material — so a reader (or an AI author) who copied the page got a red panel.

  • names api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Authoring crud is now REFUSED BY NAME rather than passed or silently ignored. validateSchema returns an error with code: 'RETIRED_TYPE' on schema.type — at any depth, since it is what validateChildren recurses with — so assertValidSchema throws and isValidSchema answers false. The message names the migration: object-grid for the record table with its toolbar, filters, pagination and row/batch actions, object-form for the create/edit form, and detail for the record view. api/schema-reference.md is rewritten around those shapes.

.changeset/object-view-unmirrored-keys-7779.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    listViews stays unmirrored, on the ruling's own fallback clause. The declaration's value is the local NamedListView — 64 declared top-level members (⚠️ re-taken at objectui#8980, which added the seventeen the protocol declares on this surface to the 47 this entry first measured), of which the renderer reads 21 off a named view. data is one of the 21 now: it used to reach the renderer through an as any cast on the named-view config in packages/plugin-view/src/ObjectView.tsx and be declared nowhere, and the objectui#8980 ruling declared it by name — objectui#7928's open half, answered. The spec's ViewSchema.listViews is a record of the STRICT ObjectListViewSchema, which requires columns and refuses options, ObjectQL tuple filters and default — that is, it refused the named views this package's own README and content/docs/api/schema-reference.md taught when this entry was written ({ label: 'All Users' } fails at columns; filter: [["owner", "=", "..."]] fails at filter.0), and objectui#8255 has since rewritten them in the spec shape. Mirroring the spec value would have lost documented behaviour; mirroring the local value would enforce 43 unread members (64 declared, minus the 21 that are both declared and read) into the contract — the very thing ruling B refused for the six local keys. The key therefore stays in the parity ledger with that measurement, pinned, until the maintainer decides its value type. It is not papered over with z.any().

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Who is NOT affected: every correctly typed document, and every document that never wrote these keys — absent stays valid on all nine. No renderer changed. The parity ledger (zod-mirror-parity.test.ts) records the move: UnmirroredDeclared 14 entries / 96 keys to 14 / 87, the ObjectViewSchema entry re-derived into the SPEC-DERIVED half because the mirror now references the spec in code.

.changeset/table-renderer-declared-column-contract-5350.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What makes this site different from its three siblings is that the alias was not merely tolerated, it was published. content/docs/api/schema-reference.md §TableSchema shipped a copyable { "name": "id", "label": "#" } example and a property row reading "Column definitions with name, label, …", while packages/types declared the opposite pair. Docs and type disagreed about one type they both call TableColumn, each internally consistent. Retiring the alias without correcting the page would have turned a documented, working example into a silently broken one, so both halves land together: the page now authors accessorKey/header. The same row also advertised a render property that TableColumn has never declared — the renderer's hook is cell — and that claim is dropped rather than re-spelled.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with 58d1f5f4b (merge-base with origin/main): 15 file(s) changed outside .changeset/, read against 2060 pending declaration(s) that publish a body (2692 pending in total). · run

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3551.1 KB 3574.6 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-C7l9k7qt.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.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 571.09KB 136.86KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.53KB 22.84KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.41KB 38.32KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 233.13KB 63.89KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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.81KB 3.58KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.14KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 6d3b4da0954918c4061b12afac26b3dc3184e384
Local-runs: none

Inputs: card #11522 (body, comments 5963861071 ruling, 5964207453 claim, 5964832134 dev report), PR #11532 (body, 18-file list, three-dot diff against main), the check-runs on the head, and every pending .changeset/*.md at the head read as text from the git tree (.changeset tree 80d99fa8, 2,695 blobs, not truncated, 0 fetch errors). Head files read by REST where a judgment turned on them: packages/types/src/zod/index.zod.ts, zod/objectql.zod.ts, zod/tombstone.zod.ts, zod/complex.zod.ts, src/index.ts, src/objectql.ts, src/complex.ts, packages/types/package.json, .changeset/config.json, packages/core/src/evaluator/listConditional.ts, packages/plugin-kanban/src/{index,KanbanImpl,ObjectKanban}.tsx, apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, skills/objectui/guides/schema-expressions.md. Nothing built, run or re-run.

Check-runs on the head: first read 2026-10-03T02:56:10Z, 42 runs, 37 success, 3 skipped (Test (coverage), Test (coverage shard), dependabot: structural skips), 2 in_progress (Test shards 1/8 and 4/8). Second read 2026-10-03T03:07:37Z: 40 success, 3 skipped, 0 pending, 0 red. Spec Main Shape Gate, Type Check, Lint, Governed Surface Queue Guard, Changeset Bump Policy, Changeset Claim Re-read, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report, Doc Snippet Type Check all success. The dev's three NOT MEASURED families (spec-main-shape, repo-wide lint, full test matrix) are answered green by the head's own runs.

① Derived judgments

Accept-set changes the diff implies, each judged against the head sources:

  1. ObjectKanbanSchema.conditionalFormatting[] element (zod, objectql.zod.ts:2981, applied at :3244): a z.union([native z.object, spec-shape z.object]) becomes stripImportedDefaults(SpecListViewSchema).shape.conditionalFormatting.unwrap().element.extend({...}). RIGHT, and the ruling's shape (the spec list view's rule by reference). The same expression already fed SpecRuleConditionSchema (:348), so the reference is the established one.
  2. Native { field, operator, value, backgroundColor?, borderColor? } on object-kanban: accepted on all three faces before, refused at each key now via retirementTombstone() (z.never({ error }).optional().describe(), tombstone.zod.ts:64), so an absent key passes and a present one is refused at its own path with the remedy. RIGHT; named in the PR table and the changeset table.
  3. Flat CEL { condition, backgroundColor }: refused before as a bare invalid_union, refused now at backgroundColor by name plus invalid_type at the required style. RIGHT; named.
  4. { condition, style, backgroundColor | borderColor | textColor }: the tolerant face accepted and stripped the key before (while the shared resolver would have painted it over style, listConditional.ts:509-511); refused on every face now. RIGHT; named in both tables. The textColor tombstone adds a key neither old arm declared; it is ?: never / undefined-only, so it widens nothing, and the keyof parity between faces is pinned.
  5. Any other undeclared key (label): the tolerant face accepted and stripped it before; refused now with the spec rule's own unrecognized_keys message, because .extend() keeps the spec element's strictness. RIGHT and WITHIN the ruling ("the spec's { condition, style } only", typed by reference means the spec's strictness comes with it); named as row 5 of both tables, so an author is not surprised by it.
  6. condition: still SpecRuleConditionSchema (string arm first, spec envelope slot by reference second), so a string is not canonicalized and '' is still accepted. UNCHANGED, and the 10946 pins now read it off .shape directly. RIGHT.
  7. style: the spec element's own member by identity (pinned), with z.input equal to the TS Record of strings (pinned by expectTypeOf, enforced by the green Type Check). No widening measurable from the inputs. RIGHT.
  8. TS KanbanConditionalFormattingRule (objectql.ts:5111): union becomes interface extends SpecConditionalFormattingRule plus six ?: never. RIGHT; @ts-expect-error pins on every retired key, Type Check green.
  9. KanbanNativeConditionalFormattingRule deleted and dropped from the root barrel (src/index.ts): a public type leaves @object-ui/types. RIGHT, and NAMED in the changeset ("removed. Importing it is a compile error (TS2305)"). No pending entry names the symbol (grep over all 2,695).
  10. @object-ui/plugin-kanban: the object-kanban registration input description (index.tsx:675) is the one runtime string that changes; KanbanRendererProps.schema.conditionalFormatting (index.tsx:238) and the alias ConditionalFormattingRule (KanbanImpl.tsx:132) narrow transitively, which is a published-type narrowing for that package. RIGHT; both named in the changeset's plugin-kanban paragraph. No render path changes: getCardStyles still hands every rule to resolveConditionalFormatting.
  11. resolveConditionalFormatting (listConditional.ts): untouched; every arm (condition, expression, field/operator/value, the three colour overrides) still has a live authored carrier because ObjectGridSchema.conditionalFormatting (objectql.zod.ts:653) and the list view's member still declare the native union. That is exactly the ruling's condition for leaving an arm in. RIGHT.
  12. No second consumer of KanbanConditionalFormattingRuleSchema remains at head (complex.zod.ts names it in a comment only; the 'kanban' arm retired in objectui#8802), so the narrowing reaches object-kanban alone and no unnamed arm moves. RIGHT.
  13. WRONG, the one defect: the public LOCUS of KanbanConditionalFormattingRuleSchema. The changeset (11522-kanban-rule-dialect-retired.md, the @object-ui/types bullet) writes "KanbanConditionalFormattingRuleSchema (@object-ui/types/zod)", and the dated note appended to 7664-kanban-arm-plugin-dialect.md writes "It is still exported from @object-ui/types/zod under the same name." At this head the ./zod barrel (packages/types/src/zod/index.zod.ts) re-exports KanbanCardSchema, KanbanColumnSchema and ObjectKanbanSchema from the kanban family and nothing else, has no export *, and the package exports map has no deeper zod path; the root barrel exports types only. The symbol is a module export inside @object-ui/types (src/zod/objectql.zod.ts), which is why the PR's own kanban-conditional-formatting.test.ts imports it by relative path from ../zod/objectql.zod while taking ObjectKanbanSchema, safeValidateSchema and StrictAnyComponentSchema from ../zod/index.zod. The 7664 entry's original bullet made the same locus claim; whether it held at 7664's own commit is not determinable from these inputs, but at this head it is false and the new note asserts it as current fact, and the new changeset introduces it afresh into the release note of two packages. The PR body's own file-surface line has it right ("zod (@object-ui/types, zod/objectql.zod.ts)"). A consumer-facing CHANGELOG line that names a non-existent public import is a public-surface statement named wrong.

② Semver level

Changeset 11522-kanban-rule-dialect-retired.md: '@object-ui/types': minor, '@object-ui/plugin-kanban': minor, BREAKING in the first line, before/after table, respelling, per-package paragraphs, "not changed" paragraph, pins. Both packages move in the diff (judgments 8-10); both sit in the one fixed group of .changeset/config.json, so the whole group bumps together either way, and the Fixed Group Check is green. minor for a spelled-out break is this repo's version-alignment rule, stated in the pending 7664, 7742 and 7645 entries, and Changeset Bump Policy is green. Level: RIGHT. One file declaring both packages (the card's "One changeset" over the claim's "one per released package that moves"): RIGHT against the diff, each package gets the body in its CHANGELOG, and nothing in the diff moves a third released package (@object-ui/core is untouched; the console and scripts/ are not released surfaces).

Clause-②: no (narrowing). RIGHT. Every face moves one way: two dialects refused, undeclared keys refused, nothing newly accepted; condition and style keep their accept sets (judgments 6-7).

Pending sweep (read, not recalled). Of 2,695 entries, the readings this change makes false are exactly two, and both carry a dated, append-only note (+14/-0 and +10/-0 in the diff), dated 2026-10-03, in the dominant house form (⚠️ **Dated note, DATE — topic — objectui#N.**, 79 of the existing openers), each ending "The rest of this entry is kept as the reading of this change":

  • 10946-expression-wire-slots-by-reference.md line 9, "the list view's and the kanban board's rule unions share one condition schema": made false (no kanban union). Note RIGHT: it names the sentence, states the new shape, and keeps the condition claims (string arm, envelope, '', reference identity) that still hold, which the retargeted 10946 pins confirm.
  • 7664-kanban-arm-plugin-dialect.md lines 74-76, "the rule union the 'object-kanban' arm already applied, now shared with the 'kanban' arm": made false. Note RIGHT on the union and on the 'kanban' arm's own retirement (objectui#8802); WRONG in its last sentence, the @object-ui/types/zod locus (judgment 13).
    Entries examined and rightly left alone, each read: 8313-kanban-structured-authoring-keys (says the description states what the board honours, still true), 8932-retire-kanban-enhanced (names KanbanConditionalFormattingRule as the type, which exists), 7742-kanban-arm-batch70 (objectFields for relation rules, still needed by a CEL rule), 7645-schema-registry-kanban-honesty (dialects there are kanban vs declarative), 7664-plugin-kanban-declared-schema, 7727, 7928 and 9242 (named-view relay keys), 8801 (conditionalFormatting as a live sibling key), 7322, 8818, 8213, 8254, 8220, 8772, 10275, 10582, 11013, 11117 (both), 7216, 6172 (both), objectview-sort-sink-4869, and the sixteen grid or list-view entries that mention conditionalFormatting without kanban (10689 x2, 10758, 10885, 10976, 11276, 4730, 6152 x2, 8167, 8972, 9318, 9645, lucky-moons-shake, member-pins-object-grid-row-layer-8071, row-predicate-phase2-record-only-5741): none makes a kanban-rule claim. 6349, 8165, 8261 do not name KanbanNativeConditionalFormattingRule. No false reading is left without a note; the sweep itself passes. The ② defect is the locus wording inside the new changeset and the 7664 note, not a missing note.

③ Boundary flags

open_questions: none declared; none found.

Dev deviations: (1) git fetch origin main in the shared objectstack checkout, refs and objects only, to read examples/ for the census: no contract bearing, noted for the seat as a touch of a shared checkout. (2) The doc-gate build moved to the background past the tool ceiling and was awaited: process only, and the head's Doc Snippet Type Check is green. (3) "One changeset" over "one per package": judged RIGHT above. (4) Model-free commit trailers per objectui AGENTS.md: not a contract matter.

Out-of-scope findings, each answered: (a) ObjectView's kanban branch relays a named view's conditionalFormatting onto a generated object-kanban node that is never validated, so a native rule can still reach the board. ANSWERED: the generated node is a runtime product, not an authored object-kanban document; the ruling retires the AUTHORED member; the relayed rule is validated under objectui's ListViewSchema, whose member still declares the native union (objectql.ts:1350); paint is unchanged because the resolver keeps every arm. No action on this card; it folds into (b). (b) ObjectGridSchema, the grid properties bag and ListViewSchema still accept the native rule and the colour keys, while objectstack main types the grid by reference to the list view (objectstack PR #21463). ESCALATED to the seat: this is a forthcoming two-doors disagreement at the next spec bump (objectui#11438 is in flight), it is not covered by objectstack#21464's staging, and it is owed a bare finding card with the dev's dedupe words (object-grid conditionalFormatting native rule, ListViewSchema conditionalFormatting broader than spec, grid rule dialect spec bump). (c) skills/objectui/guides/schema-expressions.md lines 332-337 say the native { field, operator, value } form "still work[s]" under a heading naming list/grid/kanban. ESCALATED to the governed-surface queue: true of the evaluator, false of object-kanban authoring since this change; skills/** is governed and this card is ungoverned (Governed Surface Queue Guard green confirms nothing governed was touched), so it is a follow-up for that queue, not a defect of this PR.

Boundary note, each item: KanbanNativeConditionalFormattingRule leaving the public exports IS named in the changeset (RIGHT). One changeset declaring both packages: RIGHT (above). listConditional.ts conditional: rightly untouched, every arm has a measured live carrier (judgment 11). Files outside the claim's list: packages/types/src/index.ts FORCED (the barrel re-exported the deleted type, TS2305 otherwise); spec-expression-wire-slots-10946.test.ts FORCED (it indexed .options[1] of a union that no longer exists); apps/console/src/__tests__/registry-inputs-spec-parity.test.ts NOT forced by a gate (memberPinProblem checks only that the pin file exists, is collected, and names the block and the key) but WARRANTED and in the claim's "other pins that author the retired dialects": its pins prose authored both dialects textually and would have stood false once the pinned rows were respelled, one prose line, no logic; scripts/__tests__/one-authority-per-exported-name-6273.test.ts NOT forced (the fixture is synthetic source and still is) but WARRANTED, comments only: they asserted the repo "really writes" KanbanNativeConditionalFormattingRule, false after the deletion, and two stale line citations came out (Line Citation Gate green, 0 new).

Dev NOT MEASURED items: hotcrm, accepted on triage's own zero (5963861071); spec-main-shape, lint and the full matrix, answered green on the head (above).

What the FAIL asks for, and nothing else: in .changeset/11522-kanban-rule-dialect-retired.md, replace "(@object-ui/types/zod)" after KanbanConditionalFormattingRuleSchema with its real locus (a module export of @object-ui/types, src/zod/objectql.zod.ts, not on the ./zod barrel); in the dated note on .changeset/7664-kanban-arm-plugin-dialect.md, replace "It is still exported from @object-ui/types/zod under the same name." with a true sentence (it is not on the ./zod barrel at this head, and the entry's "newly exported from @object-ui/types/zod" above does not hold there either). Every other judgment in this record holds at this head and needs no re-derivation beyond a diff of those two files.

Implemented-by: claude/issue-11522-kanban-rule-dialect-retired
Reviewed-by: session_01XvhGmGAP79ZB8swnkapxPC

VERDICT: FAIL

…ocus, a module export of src/zod/objectql.zod.ts that is not on the @object-ui/types/zod barrel (objectui#11522)

The new changeset's @object-ui/types bullet and the dated note on the 7664
entry both placed the schema on `@object-ui/types/zod`. At this head that
barrel does not re-export it and no `exports` entry carries it; the note now
says so, and records that the 7664 bullet's own locus claim does not hold in
this release either. Text only; no export added.

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3551.1 KB 3574.6 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-C7l9k7qt.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.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 571.09KB 136.86KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.53KB 22.84KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.41KB 38.32KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 233.13KB 63.89KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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.81KB 3.58KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.14KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e423e415cad8b07b78dc232432f11ae8ab6bbd0d
Local-runs: none

Round 2, re-review of round 1's record 5964941644 (FAIL on ① judgment 13 only, head 6d3b4da0954918c4061b12afac26b3dc3184e384). Inputs: that record; card #11522's comments after it (the dev's patch report 5964964405); the compare 6d3b4da0...e423e415 (1 commit, 2 files); the two changed files read in full at this head; the locus facts at this head, read by REST: packages/types/src/zod/index.zod.ts, packages/types/src/index.ts, packages/types/package.json, plus packages/types/src/zod/objectql.zod.ts for the one grep the new sentences turn on, and the source behind each remaining exports entry (src/base.ts, layout.ts, form.ts, data-display.ts, feedback.ts, overlay.ts, navigation.ts, complex.ts, data.ts, internal/retired-field-keys.ts), because the new sentence claims every entry; the check-runs on this head. Nothing built, run or re-run; no worktree, no checkout.

Check-runs on this head: first read 2026-10-03T03:15:20Z, 42 runs, 27 success, 3 skipped (Test (coverage), Test (coverage shard), dependabot: structural skips), 12 in_progress (Test shards 1-8, Type Check, Lint, Spec Main Shape Gate, Doc Snippet Type Check, Skill Example Check, README Export Check), 0 red. Already green on the first read: Changeset Bump Policy, Changeset Claim Re-read, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate, Control Byte Scan, Build and E2E, Test (dist pins), Build Docs. Second read 2026-10-03T03:19:39Z, just before this post: 28 success, 3 skipped, 11 in_progress (Test shards 1-8, Type Check, Lint, Spec Main Shape Gate), 0 red; Doc Snippet Type Check, Skill Example Check and README Export Check turned green between the reads. The eleven still pending do not bear on this contract: the only change since 6d3b4da0 is two .changeset/*.md bodies, which none of Type Check, Lint, Spec Main Shape Gate or the vitest shards takes as input, and on 6d3b4da0 all of them were success (round 1's second read, 40 green, 0 red) over sources that are byte-identical at this head. Every gate that does read a changeset body (Changeset Bump Policy, Claim Re-read, Declaration, Fixed Group Check, Overwrite Report, Line Citation Gate, Control Byte Scan) is green on this head. Not waited on.

① Derived judgments

  1. The compare is one commit (e423e415, "chore(changeset): name KanbanConditionalFormattingRuleSchema's real locus ...") touching exactly two files: .changeset/11522-kanban-rule-dialect-retired.md (+1/-1, line 24) and .changeset/7664-kanban-arm-plugin-dialect.md (+9/-2, lines 99-107). Nothing under packages/**, no barrel, no package.json, no test moved: no code or export change. RIGHT, and it is what the FAIL asked for and nothing else.
  2. The new 11522 bullet, sentence by sentence at this head. "the rule schema ObjectKanbanSchema applies, is a module export of this package's src/zod/objectql.zod.ts": export const KanbanConditionalFormattingRuleSchema = SpecListViewRuleSchema.extend({ at objectql.zod.ts:2981, applied at :3244 inside ObjectKanbanSchema (:3131); the bullet sits under the @object-ui/types paragraph heading (line 20), so "this package" is anchored even though the body lands in both CHANGELOGs. TRUE. "It is not on the @object-ui/types/zod barrel": index.zod.ts has zero occurrences of the name, no export * anywhere, and its ./objectql.zod.js block (lines 315-362) names ObjectKanbanSchema and not this schema. TRUE. "or on any other entry of the package's exports map": the map has 12 entries (., ./base, ./layout, ./form, ./data-display, ./feedback, ./overlay, ./navigation, ./complex, ./data, ./zod, ./internal/retired-field-keys); main, module and types point at the same dist/index.* as ., and there is no typesVersions; src/index.ts takes ./objectql.js through export type { only (lines 471-517; ObjectKanbanSchema at 495 and KanbanConditionalFormattingRule at 496 are the TS types), has no export * and no zod re-export; each of the other ten entry sources has zero occurrences of the name, no export *, and at most an import type from a zod file (layout.ts:21, complex.ts:26). TRUE. "so it is not an import a consumer can name": follows under an exports map, which closes every deep path. TRUE. The rest of the bullet is round 1's text unchanged, judged RIGHT there (judgments 1 and 5-7).
  3. The new 7664 note sentences. "a module export of src/zod/objectql.zod.ts inside @object-ui/types, NOT an export of the @object-ui/types/zod barrel": TRUE (as 2). "that barrel re-exports KanbanCardSchema, KanbanColumnSchema and ObjectKanbanSchema from the kanban family and not this schema": index.zod.ts:279-280 (from ./complex.zod.js) and :331 (from ./objectql.zod.js), all three inside export { blocks; the name is absent. TRUE. "no entry of the package's exports map carries it": TRUE (as 2). "the bullet above that calls it "newly exported from @object-ui/types/zod" does not hold in this release either": the entry's own bullet at lines 74-76 reads "KanbanConditionalFormattingRuleSchema is newly exported from @object-ui/types/zod", quoted exactly, and both entries are pending in the same release. TRUE. "whether it held at objectui#7664's own commit was not measured": a declared NOT MEASURED, matching the patch report (shallow history). RIGHT. The note no longer asserts a locus that is false, and the changeset no longer introduces one.
  4. Round 1's judgments 1-12 carry over unchanged: no file outside the two changesets moved, so every source they were read against is byte-identical to 6d3b4da0. Judgment 13 is now RIGHT. No ① defect remains.

② Semver level

11522-kanban-rule-dialect-retired.md frontmatter unchanged: '@object-ui/types': minor, '@object-ui/plugin-kanban': minor (lines 1-4); the BREAKING first line, the before/after table, the respelling, the per-package paragraphs, the "Not changed" paragraph and the pins paragraph are all unchanged; only line 24 moved. Level RIGHT as in round 1; Changeset Bump Policy, Changeset Fixed Group Check, Changeset Declaration and Changeset Claim Re-read are green on this head.

Clause-②: no (narrowing), unchanged in the PR body, and a text-only commit widens nothing. RIGHT.

The 7664 note stays append-only. The hunk is @@ -96,5 +96,12 @@; the two removed lines ("(objectui#8802). It is still exported from @object-ui/types/zod under the same" and "name. The rest of this entry is kept as the reading of this change.") are lines of the note this PR itself appended (round 1 quotes both as note text), not lines of the pre-PR entry; lines 1-90 (the original entry) and the opener at line 92 sit outside the hunk and are untouched. House form kept: the opener is the ⚠️ **Dated note, DATE — topic — objectui#N.** form with DATE 2026-10-03 and N 11522, and the note still closes with "The rest of this entry is kept as the reading of this change." Changeset Overwrite Report is green on this head. The 10946 note did not move.

③ Boundary flags

Patch report 5964964405: open_questions none; out_of_scope_findings none; files_changed matches the compare exactly; api_writes 1 (the report itself). Deviations: (1) a throwaway locus probe file written inside the dev's own worktree under packages/types and deleted before the commit, git status clean: not in the diff, no contract bearing; (2) no git command in the shared objectstack checkout this round: a process note, nothing owed. Its locus measurement (the 12 exports entries imported by self-reference, every one false for the name; the ./zod control true for ObjectKanbanSchema) agrees with the static reading in ① and was not re-run here. "Not merged, mergeable clean": the PR is open at this head. Nothing new bears on the contract.

Carried from round 1, unchanged and not defects of this PR: escalation (b), the grid's native arm against objectstack main's by-reference typing, owed a finding card to the seat with the dev's dedupe words; escalation (c), skills/objectui/guides/schema-expressions.md lines 332-337, owed to the governed-surface queue.

Implemented-by: claude/issue-11522-kanban-rule-dialect-retired
Reviewed-by: session_01XvhGmGAP79ZB8swnkapxPC

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 3, 2026 03:28
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 3, 2026 03:28
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit c73cdb5 Oct 3, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11522-kanban-rule-dialect-retired branch October 3, 2026 03:44
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.

finding(plugin-kanban): kanban conditionalFormatting accepts a native rule dialect the spec's list-view member refuses, blocking the spec from typing it

2 participants