Skip to content

fix(types,components,core)!: stack, flex and grid gap are each one of their renderer's steps, on both faces and the registrations; one enumeration pin for every layout spacing key (objectui#11474) - #11489

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-11474-layout-spacing-sets
Oct 2, 2026

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11474

Clause-②: no

Why no (a narrowing): stack.gap, flex.gap and grid.gap shrink from every number to each renderer's mapped set, and the flex / grid describes stop advertising "0-8". Nothing widens. The changeset is minor and states the breaking authoring meaning, because objectui never declares major (AGENTS.md section 9, version alignment).

Dispatched by the domain:spec @ objectui seat (objectui#10217) under triage's family direction (comment 5955082167) and the seat's claim (comment 5956674102), session https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC. This is the family's last step after objectui#10286 (container.maxWidth) and objectui#11424 (container.padding).

The accept-set change

surface before (base 50c73fed0) after (head 1db960ca)
zod StackSchema.gap z.number() literal set 0, 1, 2, 3, 4, 5, 6, 8, 10; the message lists the set
zod FlexSchema.gap, and the authored bag (properties.gap, the same schema object by reference) z.number(), describe "Tailwind scale 0-8" literal set 0 to 8; describe "Gap step, one of 0, 1, 2, 3, 4, 5, 6, 7, 8; 0 is none (default 2)"
zod GridSchema.gap z.number(), describe "Tailwind scale 0-8" literal set 0, 1, 2, 3, 4, 5, 6, 8, 10, 12
TS FlexLayoutProps.gap (shared by FlexSchema and the bag type FlexBlockNode) number literal union 0 to 8, @default 2 kept
TS StackSchema.gap number, inherited from FlexLayoutProps its own literal union 0 to 6, 8, 10; the heritage clause is Omit of gap over FlexLayoutProps (no index signature there, so no member is erased; stack-schema-emitted-members.test.ts measures the emitted declaration and stays green)
TS GridSchema.gap number literal union of the ten grid steps
stack / flex / grid registration, gap input type: 'number' type: 'enum', { label, value } entries with numeric values, in container.padding's object form
GridBuilder.gap() / FlexBuilder.gap() in @object-ui/core number the declared set (NonNullable of the member)
renderers gap === N branches; grid's GAPS map and its runtime-built fallback unchanged; comments only at the registration inputs. Nothing rounds or clamps.

container.padding moved onto the same shared helper (rendererSpacingSteps in layout.zod.ts, the dispatch's suggested route: the spelling now repeats four times). Its refusal text is byte-identical to base (compared against the built dist), and its describe is unchanged.

The three refusals as stored (read from the built dist at head):

  • stack: "gap on a stack is one of 0, 1, 2, 3, 4, 5, 6, 8, 10 (objectui#11474): those are the steps the renderer maps to a gap class, and 0 means none. Any other number drew NO gap class at all, not even the default 2, so it is refused here rather than rendered with no gap. Pick the step you meant from that set."
  • flex: the same sentence with the set 0 to 8.
  • grid: "... Any other number built a class at runtime that no compiled stylesheet defines, so the grid rendered with no gap at all, not even the default 4; it is refused here instead. ..."

Measurements (the dispatch's zone 2)

H1, the three sets, derived by rendering (a throwaway probe through the real SchemaRenderer and registry at base 50c73fed0, candidates 0 to 32 plus -1, 0.5, 1.5, 2.5, 9.5): stack draws a gap class for 0 to 6, 8, 10 and none for 7, 9, 11 to 32 or any fraction. flex (flat or bag) draws one for 0 to 8 and none for 9 upward. grid draws gap-0 to gap-6, gap-8, gap-10, gap-12 from its map and a runtime-built gap-[N*0.25rem] for everything else (gap-[2.25rem] for 9, gap-[-0.25rem] for -1). At base, every candidate on all four spellings parsed green on safeValidateSchema and on StrictAnyComponentSchema. H1 holds as the dispatch stated it.

H3, grid.gap measured first: closed. Instrument: both Tailwind entry sheets compiled exactly as their builds compile them (postcss plus @tailwindcss/postcss, from set to the entry so its @source lines resolve): apps/console/src/index.css (482,775 bytes) and packages/components/src/index.css, the sheet the package ships as style.css (158,414 bytes). Control: every mapped grid class (gap-0 ... gap-12), md:gap-10 and gap-1.5 are present in both sheets. The arbitrary-value lookup is live: max-w-[16rem] and px-[0.3rem] are found in both by the same matcher. Reading: all 28 runtime-built classes (for 7, 9, 11, 13 to 32, -1, 0.5, 1.5, 2.5, 9.5) are absent from both. So an unmapped grid gap reaches no rule, and grid.gap closes like the other two. The pin re-derives this against the package's own sheet on every run. The console reading was taken once and nothing re-derives it.

H2, the flex bag. Closing FlexSchema.gap flowed into the bag and into FlexBlockNode with no edit there. { type: 'flex', properties: { gap: 9 } } is refused at properties.gap on both faces with the set in the issue. { type: 'flex', gap: 9 } stays refused by name toward properties.gap, as every flat flex prop already was. tsc refuses { type: 'flex', properties: { gap: 9 } } typed as FlexBlockNode (a compile-time pin under the package's type-check).

H4, the enumeration. Derived by the new pin: every registration in @object-ui/components with isContainer, and every input on it whose values are numbers. It finds aspect-ratio.ratio, container.padding, flex.gap, grid.columns, grid.smColumns, grid.mdColumns, grid.lgColumns, grid.xlColumns, grid.gap and stack.gap. Rendering classifies four as spacing keys: container.padding, flex.gap, grid.gap, stack.gap. One other open member of the family is reported, ⛔ not closed here: see "Reported, not closed" below. card has no numeric input, and no layout node has a responsive gap object.

H5, corpus. git grep of every gap literal in tracked files (CHANGELOGs and the lockfile excluded), triaged by node. No corpus document authors an unmapped gap on a stack, flex or grid. The off-set literals are inline CSS (style objects in content/docs/guide/react-pages.md, an old changeset, two plugin demos, DatasetReportRenderer.tsx), DashboardConfigSchema.gap (a different schema), and a prose comment in the schema-catalog test. The catalog values (0, 1, 2, 3, 4, 6, 8) sit inside every set. The same sweep over the objectstack checkout (examples/**, packages/*/src) found inline CSS only. Re-judged by running: examples/schema-catalog (40 files, including safe-validate-corpus-6318.test.ts), pnpm check:doc-snippets, pnpm check:doc-examples and pnpm check:skill-examples, all green.

The pins

  • packages/components/src/__tests__/layout-spacing-sets-11474.test.tsx generalises container-padding-set-11424.test.tsx, which is deleted. Its assertions are held here in general form; the absent-key control now compares with the registration's default step instead of a literal class list. It enumerates as above. A candidate counts as MAPPED when the spacing utilities its value draws are all rules in the package's compiled stylesheet. Each spacing key is then held to three things. Its declaration accepts exactly that set on the tolerant and strict faces, at the authored spelling: flat, or the properties bag when the node refuses the key flat; the spelling is derived from the declaration. Its registration input is a closed enum of exactly that set. An absent key draws exactly what the registration's default step draws. An unmapped number draws no spacing rule, so nothing is rounded or clamped. The non-spacing numeric inputs are classified and held to nothing else. Lit controls: the stylesheet reader sees a variant, an escaped dot and an arbitrary value; the enumeration finds container.padding.
  • packages/types/src/__tests__/layout-gap-sets-11474.test.ts: per key and per face, unmapped numbers (including a fraction and -1) are refused at the key with code invalid_value, the set in issue.values and in the message. Every mapped step parses, and an absent key parses. The flat flex spelling stays refused by name. The describes state the set and no longer say "0-8". Compile-time pins check that the TS faces refuse 7 on stack, 9 and 10 on flex (node, FlexLayoutProps and FlexBlockNode), and 9 on grid, and that each zod and TS pair states one set.
  • Fixture re-judged: flex-properties-bag-11276.test.ts pinned gap: '4' in the bag as invalid_type. A literal union judges by value, so it is now invalid_value at the same path. The assertion's purpose (the bag keeps the mirror's verdict, at its own path) is unchanged, so the code was updated in place. container-padding-set-11424.test.ts and container.tsx only had their pointer to the deleted file repointed.

Ablations (committed implementation, node ../objectstack/scripts/ablation-replace.mjs wrap mode, trap-armed restore, each restore proven by blob equal to HEAD and an empty git diff HEAD)

leg mutation (landed on disk: anchor count and blob moved) expected observed
A1b stack registration drops 10 from its enum red red: stack.gap registration enum: expected [ +0, 1, 2, 3, 4, 5, 6, 8 ] to deeply equal [ +0, 1, 2, 3, 4, 5, 6, 8, 10 ]
A2b stack.tsx gains a gap === 7 branch red red: stack.gap on the tolerant face: expected [ +0, 1, 2, 3, 4, 5, 6, 8, 10 ] to deeply equal [ +0, 1, 2, 3, 4, 5, 6, 7, 8, 10 ]
A3 STACK_GAP_STEPS gains 7 red red in both pins (types: mirror set, describe, and each "refuses gap N" on both faces; components: stack.gap)
A4 grid's GAPS map drops 10 (10 then builds gap-[2.5rem]) red: shows the stylesheet criterion is live, not just "a class string is present" red: grid.gap (1 failed, 11 passed)
A5 TS StackSchema.gap gains 7 tsc -p tsconfig.test.json red red: unused @ts-expect-error and true not assignable to false in the new types pin, plus the existing zod-mirror-parity.test.ts parity pin

First attempts at A1 and A2 were no-ops. The tool refused both before running anything: A1 was a delete passed as an empty replacement, and A2's anchor was a substring of its replacement. Both were re-run with corrected anchors as A1b and A2b above.

Gates at head 1db960ca

  • Build first: pnpm --filter '@object-ui/components^...' --filter @object-ui/components run build (9 packages), then turbo run build --filter='./packages/*' --concurrency=2 (39 tasks) for the doc gates.
  • type-check (script name echoed): @object-ui/types 0, @object-ui/core 0, @object-ui/components 0. The test tsconfigs include the new pins (--listFilesOnly).
  • vitest from the worktree root: packages/types/ 334 files, 8840 passed. packages/core/ 193 files, 3844 passed, 27 skipped. packages/components/ 353 passed, 1 skipped; 3584 tests passed. examples/schema-catalog/ 40 files, 2259 passed. packages/sdui-parser/ 20 files, 289 passed. Registry-reading suites (9 files, 584 passed): console component-input-union-specimens, ga-honoured-inputs-author-reach, html-tier-manifest, public-contract, registry-inputs-spec-parity; app-shell widget-dom-leak-sweep; layout containment-declared-slot-9910; plugin-designer designerRegistrationInputs-11434; scripts/__tests__/check-component-surface-parity.test.ts.
  • exit 0: check:component-surface-parity, check:doc-types, check:doc-snippets (776 of 776 judged, 0 failed), check:doc-examples, check:skill-examples, check:doc-fences, check:new-line-citations, check:control-bytes, check:changeset-claims, check:pending-changeset-literals, check-changeset-no-major.mjs, check-changeset-presence.mjs, check:i18n-designer-parity, check:i18n-keys, check:designer-field-key-parity, check:registry-bare-names, check:unreferenced-sources, check:test-path-roots.
  • SDUI manifest, measured once by a throwaway probe (real registry, manifestFromConfigs plus validateTree): stack gap 7, flex gap 9, grid gap 9 and container padding 9 each answer invalid-enum naming the set. Controls stack 4, flex 8, grid 12 and container 8 answer nothing.
  • lint, narrowed: eslint --format json over the 11 changed .ts/.tsx files. All 11 are linted by the root config (isPathIgnored false for each), and the JSON reports 11 files with 0 errors. The 9 warnings are all on untouched lines (no-explicit-any, react-refresh). The config enables no type-aware linting, so this diff cannot move a verdict on an untouched file. The repo-wide pnpm lint belongs to CI.

NOT MEASURED: check:sdui-registration-pins. Reason: it weighs apps/console/dist/assets, which needs a full console build. It pins that the registration keys named by the sideEffects arrays survive bundling. This diff moves no sideEffects array and no registration key, only an input's type. CI runs it.

Reported, not closed

  • grid.columns (and the four flat smColumns to xlColumns inputs, and the responsive object's values). This is the same family shape: declared z.number() / number, while the renderer maps 1 to 12 through its GRID_COLS* maps. Readings through the real SchemaRenderer: columns: 13 draws grid-cols-1 sm:grid-cols-2, so the md count is silently dropped. columns: 0 and columns: -1 draw grid-cols-2, a substituted value. columns: { md: 13 } draws grid-cols-1. All four parse green on both faces. The dispatch says report, ⛔ not close; the report names it for the seat.

Acceptance notes (observations, not filed)

  • examples/schema-catalog/test/layout-props-conversion.test.tsx keeps its own hand-written GAP_LADDER and CONTAINER_PADDING sets. They agree with the derived sets today and could now read the declarations instead. That is unexercised drift, so it is noted here and not filed. Carrier: none.
  • grid.tsx's gap line still carries the comment "Fallback for arbitrary values if not in map", which no longer describes a reachable authored case and never produced a compiled rule. It sits on a renderer branch line, which the claim's file surface excludes. Carrier: none.

Generated by Claude Code

claude added 2 commits October 2, 2026 16:42
…r renderers' steps on both faces

`StackSchema.gap`, `FlexSchema.gap` (and the authored `flex` bag, which holds
the member by reference) and `GridSchema.gap` were `z.number()` / `number`.
Each renderer maps a closed set of steps; any other number drew no gap rule.
`grid` builds an arbitrary-value class at runtime for an unmapped number, and
no compiled stylesheet defines it.

- zod mirror: one shared helper for "a literal union of the renderer's steps
  with a refusal naming them", used by `container.padding` and the three gaps.
- TS face: literal unions; `StackSchema` declares its own `gap` through an
  `Omit` over `FlexLayoutProps`, which carries no index signature.
- registrations: each `gap` input is a closed enum in `container.padding`'s
  object form. The renderers' branches are unchanged.
- core builders: `GridBuilder.gap` / `FlexBuilder.gap` take the declared set.
- one generalised enumeration pin replaces the container-only one.

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
…pages; one minor changeset

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

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 16 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/4895-retire-block-schema-family.md

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

    ⚠️ Not this family, and not touched. The live slotted record-page vocabulary — PageNodeSchema.kind === 'slotted' with slots?: PageSlotMap (packages/types/src/layout.ts), rendered by usePageAssignment / PageBlockCanvas / PageBlockInspector in @object-ui/app-shell — shares the words "block" and "slot" with the retired family and shares no declaration, type or file with it. Neither is the type: 'component' NAVIGATION item kind ({ type: 'component', componentRef }, NavigationItemSchema in zod/app.zod.ts), a different declaration in a different module.

.changeset/5632-svg-host-dom-passthrough.md

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

    Both renderers forwarded their whole prop bag to the SVG they render, so every authored SDUI key on the node became an attribute — 14 per target, and icon="check" on all 71 icon nodes in the schema catalog. The two nodes declare different keys, and each renderer consumes its own node's keys by name: IconSchema (packages/types/src/layout.ts) against the pass-through docblock in renderers/basic/icon.tsx, and SpinnerSchema (packages/types/src/feedback.ts) against the one in renderers/feedback/spinner.tsx. icon and color are IconSchema's alone — SpinnerSchema declares neither. Read those two declarations for what they carry; this paragraph deliberately copies no member list. So the SDUI pass-through list withholds nothing they need.

.changeset/6951-text-value-retired.md

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

    Two published faces, one retirement. The TypeScript interface TextSchema (@object-ui/types, layout.ts) declares value?: never; the Zod mirror TextSchema (@object-ui/types/zod, layout.zod.ts) declares value as a retirementTombstone(), so the key stays DECLARED and is refused BY NAME — a plain deletion would have let an authored value ride BaseSchema's .passthrough() into a silent blank, which is worse than the tolerated fallback it replaces. The value?: string members of TextSpanSchema and TabsSchema in the same file are other schemas' contracts and are unchanged.

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

    Two published faces, one retirement. The TypeScript interface TextSchema (@object-ui/types, layout.ts) declares value?: never; the Zod mirror TextSchema (@object-ui/types/zod, layout.zod.ts) declares value as a retirementTombstone(), so the key stays DECLARED and is refused BY NAME — a plain deletion would have let an authored value ride BaseSchema's .passthrough() into a silent blank, which is worse than the tolerated fallback it replaces. The value?: string members of TextSpanSchema and TabsSchema in the same file are other schemas' contracts and are unchanged.

.changeset/7097-grid-2xl-breakpoint.md

  • names grid.tsx → packages/components/src/renderers/layout/grid.tsx — edited by this change

    The drop was in two layers, and both are fixed. grid.tsx had neither a 2xl read arm nor a GRID_COLS_2XL static class map. Adding the read arm alone would have produced a class name Tailwind never compiles — Tailwind v4 finds utilities by scanning source text, so a 2xl:grid-cols-${n} assembled at runtime is not a utility that exists, and the node would have rendered unstyled while a unit test went green. The twelve literal class strings are what make the class real; measured against the package's own Tailwind build, the 2xl:grid-cols-* rules go from 0 to 12 in the compiled stylesheet, with the twelve xl:grid-cols-* rules unchanged as the control.

.changeset/7735-zod-mirrors-stop-authoring-defaults.md

  • names container.tsx → packages/components/src/renderers/layout/container.tsx — edited by this change

    | key | mirror wrote | the renderer applies | |---|---|---| | ContainerSchema.maxWidth | 'lg' | container.tsx: ?? 'xl' | | FlexSchema.align | 'center' | flex.tsx: \|\| 'start' |

  • names flex.tsx → packages/components/src/renderers/layout/flex.tsx — edited by this change

    | key | mirror wrote | the renderer applies | |---|---|---| | ContainerSchema.maxWidth | 'lg' | container.tsx: ?? 'xl' | | FlexSchema.align | 'center' | flex.tsx: \|\| 'start' |

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

    What changed. All 41 .default() call sites under packages/types/src/zod/ are removed — layout.zod.ts 22, crud.zod.ts 11, form.zod.ts 5, views.zod.ts 2, app.zod.ts 1. @object-ui/components reconciles the third face a separate finding found: flex's registration defaultProps.align seeded 'center', the value its own renderer never applies, so a designer-made node laid out differently from a hand-authored one; it now seeds 'start'.

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

.changeset/8478-zod-pins-form-layout.md

.changeset/8499-node-slot-registered-arms.md

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

    • SemanticElementSchema (zod/layout.zod.ts) — the seven HTML sectioning tags renderers/layout/semantic.tsx registers: aside main header nav footer section article. - HtmlElementSchema (zod/layout.zod.ts) — the 37 safe flow/inline tags renderers/basic/html-elements.tsx registers (h1…h6, p, a, ul, img, …), plus the per-tag keys that module forwards to the DOM (href, target, rel, title, src, alt, width, height, dateTime, cite). ⚠️ Dated note, 2026-09-27 — that set has since gained code — objectui#10756. At this change TAGS and this arm both named 37 tags; both now name 38, and the parity pin counts 38. The rest of this entry is kept as the reading of this change. - InputShorthandSchema (zod/form.zod.ts) — email / password, the two aliases renderers/form/input.tsx registers onto the input renderer with inputType pinned. inputType is deliberately NOT declared on this arm: the wrapper spreads its own value last, so an authored one is overwritten. ⚠️ Dated note, 2026-09-28 — inputType is now declared on this arm, as a refusal — objectui#8762. Later in this same release the arm declares inputType on both faces and refuses it by name (?: never on the TypeScript face, a retirementTombstone on the zod mirror, at path inputType), with guidance pointing at { "type": "input", "inputType": "email" }. So "inputType is deliberately NOT declared on this arm" no longer holds; the reason does, since the wrapper still spreads its own value last. The rest of this entry is kept as the reading of this change. - UiCalendarSchema (zod/form.zod.ts) — ui:calendar, the date-picker primitive renderers/form/calendar.tsx registers under exactly that key (skipFallback, because bare calendar belongs to the plugin-calendar view).

.changeset/8505-grid-columns-breakpoint-narrowing.md

.changeset/8516-8556-mirror-partial-record-narrowing.md

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

    | key | mirror was | mirror is | | :-- | :--------- | :-------- | | GridSchema.columns (zod/layout.zod.ts) | z.record(z.string(), z.number()) | a PARTIAL record over the six breakpoints | | ReportComponentSchema.exportConfigs (zod/reports.zod.ts) | z.record(z.string(), ReportExportConfigSchema) | a PARTIAL record over ReportExportFormat |

.changeset/8871-page-node-refuses-breadcrumbs.md

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

    What was measured, on this branch's base 93127bd6f. Zero readers, with a point-access probe rather than a bare word: on that base \.breadcrumbs scores 0 tree-wide (exit 1) against \.breadcrumb\b's 12 files tree-wide (10 under packages/) as the lit control. At head the same two probes read 16 and 13 and \.breadcrumbs is exit 0 over 4 files — every hit one of this branch's own four files (this changeset, the refusal pin, layout.ts, zod/layout.zod.ts) quoting the probe string, and the pin's own exclusions put head back at exit 1. The base reading is the measurement; the head reading is this branch's echo of it. The bare word would have lied — it also names Sentry's own unrelated concept (app-shell/src/observability/sentry.ts) and appears in two comments listing UI surfaces (core/src/utils/record-title.ts, layout/src/NavigationRenderer.tsx), so a bare probe reports five readers that do not exist.

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

    What was measured, on this branch's base 93127bd6f. Zero readers, with a point-access probe rather than a bare word: on that base \.breadcrumbs scores 0 tree-wide (exit 1) against \.breadcrumb\b's 12 files tree-wide (10 under packages/) as the lit control. At head the same two probes read 16 and 13 and \.breadcrumbs is exit 0 over 4 files — every hit one of this branch's own four files (this changeset, the refusal pin, layout.ts, zod/layout.zod.ts) quoting the probe string, and the pin's own exclusions put head back at exit 1. The base reading is the measurement; the head reading is this branch's echo of it. The bare word would have lied — it also names Sentry's own unrelated concept (app-shell/src/observability/sentry.ts) and appears in two comments listing UI surfaces (core/src/utils/record-title.ts, layout/src/NavigationRenderer.tsx), so a bare probe reports five readers that do not exist.

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

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

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

.changeset/catalog-layout-props-sweep-4891-4890.md

  • names stack.tsx → packages/components/src/renderers/layout/stack.tsx — edited by this change

    StackSchema extends OmitANGLE-BRACKETS(FlexSchema, 'type'), whose spacing key is gap. spacing was declared by nothing: not the TypeScript interface, not the zod mirror, not the renderer's own inputs registration. stack.tsx read it anyway, as schema.gap ?? (schema as any).spacing ?? 2 — and the as any is the whole story, since it existed to get past the type system saying the key was not there. A lenient consumer leg does not stay in the consumer: it becomes a second de-facto contract that producers write to, and 135 nodes across 39 files of the shipped schema catalog did exactly that. Every one of them rendered correctly, so nothing ever pointed at it, while the examples went on teaching the key to every author who copied them.

.changeset/grid-dom-attribute-whitelist-4787.md

  • names grid.tsx → packages/components/src/renderers/layout/grid.tsx — edited by this change

    grid.tsx ended in a bare {...gridProps} spread that removed only data-obj-* and style, so everything else SchemaRenderer hands a registered component reached the element. Measured on a canary node, eight attributes leaked: columns="4", gap="4", mdcolumns="2", smcolumns="2", name="grid_node", props="[object Object]", colorvariant="x" (the flattened props container) and an unknown authored zzcanary="leak". A responsive columns object rendered as columns="[object Object]". Layout was unaffected, so every catalog grid example rendered with them — the reason this went unnoticed.

.changeset/layout-default-jsdoc-7361.md

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

    The published @default documentation on two layout.ts members now matches the value the renderer actually applies. ContainerSchema.maxWidth documented 'lg' while container.tsx applies schema.maxWidth ?? 'xl', and the shared FlexLayoutProps.align documented 'center' while flex.tsx applies schema.align || 'start' and stack.tsx applies schema.align || 'stretch'. The renderers are unchanged — they are the authority for what runs — so only the docblocks moved; align now states both consumers in prose instead of carrying a single @default, because one member shared by two deliberately divergent component types cannot have one correct default.

  • names container.tsx → packages/components/src/renderers/layout/container.tsx — edited by this change

    The published @default documentation on two layout.ts members now matches the value the renderer actually applies. ContainerSchema.maxWidth documented 'lg' while container.tsx applies schema.maxWidth ?? 'xl', and the shared FlexLayoutProps.align documented 'center' while flex.tsx applies schema.align || 'start' and stack.tsx applies schema.align || 'stretch'. The renderers are unchanged — they are the authority for what runs — so only the docblocks moved; align now states both consumers in prose instead of carrying a single @default, because one member shared by two deliberately divergent component types cannot have one correct default.

  • names flex.tsx → packages/components/src/renderers/layout/flex.tsx — edited by this change

    The published @default documentation on two layout.ts members now matches the value the renderer actually applies. ContainerSchema.maxWidth documented 'lg' while container.tsx applies schema.maxWidth ?? 'xl', and the shared FlexLayoutProps.align documented 'center' while flex.tsx applies schema.align || 'start' and stack.tsx applies schema.align || 'stretch'. The renderers are unchanged — they are the authority for what runs — so only the docblocks moved; align now states both consumers in prose instead of carrying a single @default, because one member shared by two deliberately divergent component types cannot have one correct default.

  • names stack.tsx → packages/components/src/renderers/layout/stack.tsx — edited by this change

    The published @default documentation on two layout.ts members now matches the value the renderer actually applies. ContainerSchema.maxWidth documented 'lg' while container.tsx applies schema.maxWidth ?? 'xl', and the shared FlexLayoutProps.align documented 'center' while flex.tsx applies schema.align || 'start' and stack.tsx applies schema.align || 'stretch'. The renderers are unchanged — they are the authority for what runs — so only the docblocks moved; align now states both consumers in prose instead of carrying a single @default, because one member shared by two deliberately divergent component types cannot have one correct default.

.changeset/layout-direction-default-jsdoc-7734.md

  • names flex.tsx → packages/components/src/renderers/layout/flex.tsx — edited by this change

    The published @default documentation on FlexLayoutProps.direction no longer states a value that only one of its two consumers applies. The member is declared once (objectui#6151) but flex.tsx reads schema.direction || 'row' while stack.tsx reads schema.direction || 'col' ("Default to column for Stack"), so the single @default 'row' was correct for flex and wrong for stack — whose own defaultProps.direction is 'col'. The renderers are unchanged — they are the authority for what runs — so only the docblock moved: direction now names both consumers in prose, the same remedy objectui#7361 applied to the sibling align. justify is shared by the same two consumers and both read || 'start', so its tag is correct and stays: the criterion is a DIVERGENT shared member, not a shared one.

  • names stack.tsx → packages/components/src/renderers/layout/stack.tsx — edited by this change

    The published @default documentation on FlexLayoutProps.direction no longer states a value that only one of its two consumers applies. The member is declared once (objectui#6151) but flex.tsx reads schema.direction || 'row' while stack.tsx reads schema.direction || 'col' ("Default to column for Stack"), so the single @default 'row' was correct for flex and wrong for stack — whose own defaultProps.direction is 'col'. The renderers are unchanged — they are the authority for what runs — so only the docblock moved: direction now names both consumers in prose, the same remedy objectui#7361 applied to the sibling align. justify is shared by the same two consumers and both read || 'start', so its tag is correct and stays: the criterion is a DIVERGENT shared member, not a shared one.

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 9de0b3483 (merge-base with origin/main): 15 file(s) changed outside .changeset/, read against 2029 pending declaration(s) that publish a body (2658 pending in total). · run

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3550.7 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-RmIZllqK.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.20KB 136.84KB
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.25KB 66.11KB
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.36KB 11.18KB
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) 141.23KB 38.00KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.27KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.14KB 45.06KB
plugin-grid (index.js) 232.66KB 63.77KB
plugin-kanban (index.js) 49.51KB 15.54KB
plugin-list (index.js) 116.60KB 28.96KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
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 (complex.js) 3.32KB 1.64KB
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: 1db960caedc67c5a89c652188ea9bf5f7f14bcd4
Local-runs: none

Inputs: card objectui#11474 (body and its three comments: triage 5955082167, claim 5956674102, os-dev report 5957503910), PR #11489 (body, 16-file list, net diff against main at the head), the head's check-runs, and every pending .changeset/*.md at the head read as text from the git tree (.changeset tree 1f7020c564565a8e52cc8ee260e69f87a35e811c, 2659 blobs, each fetched by its blob sha, sizes equal to the tree's). Nothing built, run or re-run.

Check-runs on the head, read at 2026-10-02T17:25Z: 39 success (Type Check, Lint, Test (shard 1/8) to Test (shard 8/8), Test (dist pins), Build & E2E, Bundle Analysis, Build Docs, Doc Snippet Type Check, Governed Surface Queue Guard, Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read, Changeset Overwrite Report, Line Citation Gate, Skill Example Check and the rest), 1 in_progress (Test, the aggregate over the eight green shards), 3 skipped (Test (coverage), its shard matrix, dependabot: path-conditional, not verdicts), 0 red. None of the pending or skipped ones bears on the contract; the verdict below turns on ②, not on a gate.

① Derived judgments

Each accept-set and public-surface change the diff implies, named right or wrong. The three mapped sets were re-derived by reading the renderers at the head, not taken from the report: stack.tsx carries gap === N branches for 0 to 6, 8 and 10; flex.tsx for 0 to 8; grid.tsx's GAPS map has keys 0 to 6, 8, 10 and 12 and then builds gap-[N*0.25rem] at runtime.

  1. zod StackSchema.gap to the literal set 0, 1, 2, 3, 4, 5, 6, 8, 10 (invalid_value, set in the issue and in the message) — right; it is exactly the branch set.
  2. zod FlexSchema.gap to 0 to 8 — right; and because FlexPropsBag is FlexSchema.omit(FLEX_NODE_LEVEL_KEYS) the authored properties.gap narrows by reference with no edit, and the flat gap stays refused by name toward properties.gap (pinned). Right.
  3. zod GridSchema.gap to 0, 1, 2, 3, 4, 5, 6, 8, 10, 12 — right. The card's "measure grid first" condition was met: the dev read both compiled sheets (console and the package's style.css) with a live arbitrary-value control and found none of the 28 runtime-built classes; the new pin re-derives that against the package sheet on every run, so the runtime-built fallback is unreachable from a validated document and grid closes like the other two. Accepted as the H3 answer.
  4. TS FlexLayoutProps.gap to the 0 to 8 union; StackSchema now extends BaseSchema and Omit of FlexLayoutProps without gap, declaring its own 0 to 6, 8, 10 union; GridSchema.gap to the ten-step union — right. FlexLayoutProps carries no index signature, so this Omit is not the objectui#6151 collapse (that one crossed BaseSchema's index signature); the emitted-members guard stack-schema-emitted-members.test.ts still holds the two member sets equal, and Type Check is green. FlexBlockNode is ClosedArmInput of FlexBlockSchema, so the bag's TS face follows the zod narrowing. Right.
  5. Registration gap inputs on stack, flex, grid from type: 'number' to a closed enum of { label, value } objects with numeric values — right; it is container.padding's object form, the SDUI manifest's validateTree answers invalid-enum, and the enumeration pin reads that form. This is a public-surface narrowing of @object-ui/components (manifest and generated intrinsics) and is declared.
  6. container.padding moved onto the shared rendererSpacingSteps helper — right. Recomposing both template strings gives a refusal and a describe byte-identical to base (padding on a container is one of 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16 (objectui#11424) … rendered flush. Pick the step you meant from that set.), and the removed CONTAINER_PADDING_REFUSAL const was module-local, never exported, so no public surface moves there.
  7. @object-ui/core: GridBuilder.gap() and FlexBuilder.gap() parameters narrowed to the declared sets via NonNullable of the member — right, and forced by tsc once the members narrowed; FlexLayoutProps and GridSchema are already imported there. A public API narrowing of a typed producer, outside the claim's file surface and declared (deviation and changeset).
  8. Renderers' branches untouched; nothing rounds or clamps — right, as the card and the claim demanded; the diff touches only the input blocks and one pointer comment. grid.tsx's "Fallback for arbitrary values" comment is now stale prose on an unreachable branch (the dev's note, carrier none) — not a contract matter.
  9. Fixture flex-properties-bag-11276.test.ts: gap: '4' in the bag from invalid_type to invalid_value — right; a zod literal union judges by value, the path is unchanged, and the changeset states it.
  10. Enumeration pin layout-spacing-sets-11474.test.tsx replacing container-padding-set-11424.test.tsx — right in design: population derived from every isContainer registration's numeric inputs; "mapped" means every drawn spacing utility is a rule in the package's compiled sheet (postcss and @tailwindcss/postcss are the package's devDependencies); declaration held on both faces at the derived authored spelling; registration held to a closed enum; absent-key control against the registration default; lit controls for the sheet reader and for container.padding. Five ablations red in the expected direction, including A4 which proves the stylesheet criterion is live. Right.
  11. Docs stack.mdx, flex.mdx, grid.mdx state the sets — right (AGENTS Add automated testing infrastructure and CI/CD workflows #2). Corpus: no tracked document authors an unmapped gap (dev's H5; schema-catalog, doc-snippets, doc-examples, skill-examples re-judged by running, and Doc Snippet Type Check, Skill Example Check green on the head). Accepted.
  12. grid.columns left open and reported — right; it is not a spacing key and the dispatch said report, not close. It goes to ③.

No derived judgment in the diff is wrong.

② Semver level

  • The changeset .changeset/11474-layout-spacing-sets.md: @object-ui/types, @object-ui/components, @object-ui/core each minor, a Breaking banner, the three sets in a table, and a migration line. Right: every package that publishes a narrowing is listed, minor with the breaking meaning stated is this repository's spelling (it never declares major), the core builders' narrowed parameters are declared in their own bullet, and check-changeset-no-major, Changeset Bump Policy, Changeset Fixed Group Check and Changeset Declaration are green.
  • The PR body's Clause-② declaration reads no, with the direction stated on the next line ("Why no (a narrowing)"). The value is right: nothing widens. The (narrowing) arm is not on the declaration line itself, so the line as read declares no direction; the breaking fact is carried by the changeset banner and the prose. Spell it no (narrowing) on the line when the body is next edited; not a fail on its own.
  • Pending entries this change makes false, and the notes they owe. Read against all 2659 pending bodies at the head (not the gate's list of 17, which was read too). Two entries carry a standing reading this diff makes false, and the PR adds no note to any pending entry (its only .changeset path is the new file):
    1. .changeset/6151-stack-schema-omit-collapse.md — "gap is now number | undefined and that line is a tsc error", "stack.tsx feeds gap to a Tailwind numeric scale", "the members are declared once rather than duplicated", and "FlexSchema and StackSchema each extend BaseSchema and FlexLayoutProps". At the head StackSchema.gap is its own literal union over an Omit of FlexLayoutProps without gap, so gap is declared twice and is no longer number. Owed: a dated, append-only note naming objectui#11474 in the house form (⚠️ Dated note, 2026-10-02 — … — objectui#11474. At this change …; now …. The rest of this entry is kept as the reading of this change.).
    2. .changeset/11441-retire-nav-responsive-grid-layout.md — the migration "{ "type": "grid", "columns": C, "gap": G }. grid accepts the same breakpoint columns object … and a gap number". ResponsiveGrid's prop is gap?: number | string with its own class map for 0 to 6 and 8, so every G it ever drew is inside grid's set and the recipe still works for those; but grid no longer accepts "a gap number", it accepts one of ten steps, and a G of 7, 9, 11 and up is now refused. Owed: the same dated note, stating the set G must be in.
      Read and judged not false: 11424-container-padding-set.md (refusal, describe and enum form unchanged byte for byte), 11276-flex-properties-bag.md ("stay published and unchanged in shape" describes what that change moved; the bag still judges gap "exactly as" the flat mirror, by reference), 11276-core-flex-builder-properties-bag.md (output shape only, no gap parameter type), 11441-known-types-retired-layout-keys.md ("with the same … gap" holds for every step ResponsiveGrid mapped; the dev may mirror the note there), catalog-layout-props-sweep-4891-4890.md, grid-dom-attribute-whitelist-4787.md, 7097-grid-2xl-breakpoint.md, layout-default-jsdoc-7361.md, layout-direction-default-jsdoc-7734.md, 7735-zod-mirrors-stop-authoring-defaults.md, the two 8478-* describe entries, 8505/8516 (columns), 8871, 9092, 4895, 5632, 6951, 8499, and every other gap-mentioning entry (a different schema, a prose "gap", or a mapped value). No pending entry names container-padding-set-11424.test.tsx or the removed CONTAINER_PADDING_REFUSAL.

② fails on the two unnoted entries. The remedy is prose-only and frontmatter-untouched (the Changeset Overwrite Report gate records such an edit as its legitimate case 2): append the two dated notes, push, and the record is re-owed on the new head.

③ Boundary flags

Dev flags (the report's deviations), each answered:

  • Node tarball placed on PATH from the run's scratch dir only — local toolchain, nothing in the tree; cleared.
  • PR assignee not set (the local write classifier refused label-write --assign) — not a contract matter; escalated to the seat: mirror the card's assignee os-tesla on fix(types,components,core)!: stack, flex and grid gap are each one of their renderer's steps, on both faces and the registrations; one enumeration pin for every layout spacing key (objectui#11474) #11489.
  • File surface beyond the claim (schema-builder.ts, three .mdx, one fixture code, pointer comments) — each is a consequence of the narrowing or AGENTS Add automated testing infrastructure and CI/CD workflows #2, each declared, and the @object-ui/core surface is covered by the changeset; cleared. The claim's "not their branches" held: the renderers' branches are untouched.
  • check:sdui-registration-pins not measured locally — it runs in performance-budget.yml (check-run Bundle Analysis, path-filtered on packages/**), green on the head; the diff moves no sideEffects array and no registration key; cleared.
  • Lint narrowed to the 11 changed files — Lint green on the head carries the repo-wide verdict; cleared.
  • Commit trailers model-free — AGENTS' prescribed form; cleared.
  • Ablation legs A1/A2 first ran as refused no-ops, re-run as A1b/A2b — the five observed reds are in the expected direction; cleared.

open_questions: none declared, none found.

out_of_scope_findings: grid.columns (and smColumns to xlColumns, and the responsive object's values) — class (c), public door plus wrong answer, measured through the real SchemaRenderer: columns: 13 draws grid-cols-1 sm:grid-cols-2, 0 and -1 draw grid-cols-2. The same family shape as this card, not a spacing key, deliberately not closed here. Escalated to the seat: a reproducible defect takes a card (Prime Directive #10); the seat files the follow-up (dedupe words in the report) or rules it folded into this family. The two "carrier: none" notes (the schema-catalog test's hand-written GAP_LADDER / CONTAINER_PADDING, and the stale fallback comment in grid.tsx) are acceptance notes and need no card.

Implemented-by: claude/issue-11474-layout-spacing-sets
Reviewed-by: session_01XvhGmGAP79ZB8swnkapxPC

VERDICT: FAIL


Generated by Claude Code

… make false

`.changeset/6151-stack-schema-omit-collapse.md` read `gap` as one `number`
member declared once on `FlexLayoutProps`; `StackSchema` now declares its own
literal union over an `Omit` of it. `.changeset/11441-retire-nav-responsive-grid-layout.md`
said `grid` accepts a `gap` number; it now accepts one of ten steps. Each gets
an append-only dated note in the house form naming objectui#11474 and the
changeset that ships.

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

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3550.7 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-RmIZllqK.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.20KB 136.84KB
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.25KB 66.11KB
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.36KB 11.18KB
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) 141.23KB 38.00KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.27KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.14KB 45.06KB
plugin-grid (index.js) 232.66KB 63.77KB
plugin-kanban (index.js) 49.51KB 15.54KB
plugin-list (index.js) 116.60KB 28.96KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
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 (complex.js) 3.32KB 1.64KB
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: 17cbfb394a6e7506eacdfdf0d461ea2bf082c118
Local-runs: none

Re-review after one patch round. Inputs: card objectui#11474 (body and its three comments: triage 5955082167, claim 5956674102, os-dev report 5957503910), PR #11489 (body, 18-file list, net diff against main at the head), the head's check-runs, the earlier record 5957735951 on 1db960ca (FAIL on ② only), compare/1db960ca...17cbfb39, and every pending .changeset/*.md at the head read as text from the git tree (.changeset tree d2e682aa9be7aba74299c293866abbe800df2563, 2658 .md blobs plus config.json, each fetched by its blob sha, every size equal to the tree's). Nothing built, run or re-run.

What the patch round touched, read off the compare, not the dev's list: one commit, 17cbfb3 ("changeset: dated notes on the two pending entries the closed gap sets make false"), two files, both append-only (+14 -0, +2 -0): .changeset/6151-stack-schema-omit-collapse.md and .changeset/11441-retire-nav-responsive-grid-layout.md. No source, test, doc or registration hunk moved, so the net diff at this head is the earlier diff plus those two notes. On that basis ① and ③ are carried from 5957735951 after re-reading every hunk of the net diff at this head; ② is re-judged in full below.

Check-runs on the head, read twice. At 2026-10-02T17:37:52Z: 31 success, 3 skipped, 11 in_progress (Lint, Type Check, Spec Main Shape Gate, Test (shard 1/8) to Test (shard 8/8)), 0 red. At 2026-10-02T17:46:44Z, just before this post: 39 success (Type Check, Lint, the eight Test shards, Test (dist pins), Build & E2E, Bundle Analysis, Build Docs, Doc Snippet Type Check, Governed Surface Queue Guard, Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read, Changeset Overwrite Report, Line Citation Gate, Skill Example Check, Spec Main Shape Gate and the rest), 3 skipped (Test (coverage), its shard matrix, dependabot: path-conditional, not verdicts), 1 queued (Test, the aggregate over the eight shards, every one of which is green), 0 red. The pending aggregate and the skipped ones bear on nothing in the contract; every derived gate family the record leans on is green on this head.

① Derived judgments

Carried from 5957735951, each hunk re-read at this head; the twelve judgments stand and none is wrong. In brief: (1) zod StackSchema.gap to the literal set 0, 1, 2, 3, 4, 5, 6, 8, 10 — right, the stack.tsx branch set; (2) zod FlexSchema.gap to 0 to 8, flowing by reference into the authored properties.gap, the flat spelling still refused by name — right; (3) zod GridSchema.gap to 0, 1, 2, 3, 4, 5, 6, 8, 10, 12 after grid was measured first (no runtime-built class in either compiled sheet, with a live arbitrary-value control; the components pin re-derives it against the package sheet) — right, the card's condition met; (4) TS FlexLayoutProps.gap to the 0 to 8 union, StackSchema extending BaseSchema and an Omit of FlexLayoutProps without gap with its own 0 to 6, 8, 10 union, GridSchema.gap to the ten-step union — right; re-read at this head, FlexLayoutProps in packages/types/src/layout.ts carries no index signature, so the Omit erases no member name; (5) the three registration gap inputs from type: 'number' to a closed enum of { label, value } objects in container.padding's form — right, a declared narrowing of the manifest and intrinsics; (6) container.padding moved onto the shared rendererSpacingSteps helper — right; recomposing the template with the container arguments gives the refusal and the describe byte-identical to base, and the removed CONTAINER_PADDING_REFUSAL const was module-local; (7) @object-ui/core GridBuilder.gap() / FlexBuilder.gap() narrowed to NonNullable of the member — right, forced by tsc, declared; (8) renderers' branches untouched, nothing rounds or clamps — right; (9) the flex-properties-bag-11276 fixture code from invalid_type to invalid_value — right, a literal union judges by value; (10) layout-spacing-sets-11474.test.tsx replacing container-padding-set-11424.test.tsx, population derived from every isContainer registration's numeric inputs, "mapped" meaning every drawn utility is a rule in the compiled sheet, held on both faces at the derived spelling, five ablations red in the expected direction — right; (11) the three .mdx pages state the sets, and no corpus document authors an unmapped gap — right; (12) grid.columns left open and reported — right, not a spacing key; it goes to ③.

② Semver level

The changeset .changeset/11474-layout-spacing-sets.md. @object-ui/types, @object-ui/components, @object-ui/core, each minor; a Breaking banner; the three sets in a table with their defaults; one bullet per package; a migration line. Right. Every package whose published surface narrows is listed: types (the TS faces and the zod mirrors), components (the registration inputs, hence the SDUI manifest's validateTree answer and the generated intrinsics), core (the two builder parameters, declared in their own bullet, as the brief asked). No other released package has a source hunk. minor with the breaking meaning stated in the body is this repository's spelling: AGENTS.md's version-alignment rule says a changeset never declares major (the fixed group would leave objectstack's major) and a breaking change is marked minor with the breaking semantics written in the body; check-changeset-no-major and the Changeset Bump Policy, Changeset Fixed Group Check and Changeset Declaration gates are green on the head.

The Clause-②: line. The PR body reads Clause-②: no, with "Why no (a narrowing)" on the next line. The value is right for a narrowing on this repository's PR line: nothing widens, and the family's previous member, PR #11470 (container.padding, landed at contract tier), spells its line identically. The (narrowing) arm sits off the line, so the line as read declares no direction and the breaking fact is carried by the changeset banner; spell the arm on the line when the body is next edited. Not a fail.

The two notes, re-read sentence by sentence against the diff and the head.

  1. .changeset/6151-stack-schema-omit-collapse.md, +14. "At this change gap was a number member of FlexLayoutProps, declared once and inherited by FlexSchema and StackSchema alike" — true to the entry's own lines 24 to 38. "stack.tsx was read as feeding it to a Tailwind numeric scale" — the entry's line 39. "now each node's gap is the closed set of steps its renderer maps" — the diff. "FlexLayoutProps.gap is 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8, shared by FlexSchema and the authored flex bag" — layout.ts hunk; the bag's TS face is ClosedArmInput of FlexBlockSchema, which holds the member by reference. "StackSchema extends BaseSchema and Omit of FlexLayoutProps without gap, and declares its own gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10, the nine steps stack.tsx has a gap class for" — layout.ts hunk; nine steps; the card's own branch reading. "gap is declared twice while the other members stay declared once" — true. "tsc refuses any other number on a stack, as it refuses gap: 'large'" — the types pin's @ts-expect-error on gap: 7, under Type Check. "That Omit crosses no index signature (FlexLayoutProps carries none)" — read at the head: the interface body has no index member. "stack-schema-emitted-members.test.ts … still passes" — the Test shards. ".changeset/11474-layout-spacing-sets.md states what ships" — the file exists. House form held: the ⚠️ Dated note, date — summary — objectui#11474. opener, "At this change …; now …", the closing "The rest of this entry is kept as the reading of this change." — the form the two notes on 8499-node-slot-registered-arms.md use; this entry had no earlier note of its own. Append-only, names the card.

  2. .changeset/11441-retire-nav-responsive-grid-layout.md, +2. "At this change grid accepted any gap number" — the entry's own line 13 and the base z.number(). "now it accepts one of 0, 1, 2, 3, 4, 5, 6, 8, 10 and 12, the steps the grid renderer maps" — GRID_GAP_STEPS, the GAPS map. "objectui validate refuses any other G at gap on both faces with that set named: 7, 9, 11, a number above 12, a negative number or a fraction" — the types pin refuses 7, 9, 11, 16, 2.5 and -1 at gap on both faces with the set in issue.values and in the message; "both faces" is the entry's own phrase for objectui validate (its line 11). "For such a number grid drew no gap anyway, because the class it built at runtime is in no compiled stylesheet" — the H3 reading, re-derived by the components pin against the package sheet. "So in the migration above G must be one of those ten steps" — follows. "each step ResponsiveGrid's own class map drew (0 to 6 and 8) is one of them" — read packages/layout/src/ResponsiveGrid.tsx at the head: GAP_CLASSES has keys 0, 1, 2, 3, 4, 5, 6 and 8, every one inside the grid set. ".changeset/11474-layout-spacing-sets.md states what ships" — exists. Same house form, append-only, names the card; this entry had no earlier note.

The sweep, in full, over all 2658 pending bodies at the head (not the gate's list, which resolves file names, not meaning, and names 16 entries, none of them the two above). Patterns read: the word gap (100 entries); 0-8 / 0–8 / "Tailwind scale" (only the new entry, describing the past); GridBuilder / FlexBuilder / schema-builder / .gap( (only the new entry); CONTAINER_PADDING / container-padding-set / rendererSpacingSteps / 11424 (only 11424-container-padding-set.md); padding with container (9 entries); FlexLayoutProps / StackSchema / FlexPropsBag / FlexBlockNode (9); GridSchema / FlexSchema (51). Of the 100 gap entries, 83 use the word as prose (a coverage gap) or as a CSS literal; 17 name a layout key. Entries whose standing reading this change makes false: the two above, now noted. Read and judged not false, each by name: 11424-container-padding-set.md (asserts the TS literal union, untouched; invalid_value at padding with the twelve values in the issue and a message listing the set; the enum object form — all still so; it quotes no refusal text, and the helper recomposes the refusal and the describe byte-identical anyway); 11276-flex-properties-bag.md ("their values are judged exactly as before, now in the bag" and "stay published and unchanged in shape" sit under "What did not move" and are scoped to that change; the bag still holds gap by reference and judges it as the mirror does; its example gap: 4 is a mapped step); 11276-core-flex-builder-properties-bag.md (output shape only; the build() type it quotes is unchanged; no parameter type stated); 11441-known-types-retired-layout-keys.md ("with the same breakpoint columns object and gap" names the keys that carry and states no accept set; it abbreviates the sibling entry's migration, which now carries the qualification of G; a mirrored note there is optional, not owed); catalog-layout-props-sweep-4891-4890.md (the rename recipe's population, the catalog's spacing values 0, 1, 2, 3, 4, 6, 8, is inside the stack set, and its heritage-clause sentence was already superseded by objectui#6151 without a note, the house's own precedent on this entry); 11468-bag-carrier-node-types.md, 7735-zod-mirrors-stop-authoring-defaults.md, layout-default-jsdoc-7361.md, layout-direction-default-jsdoc-7734.md ("declared once (objectui#6151)" is said of direction, still declared once), 6751-flex-props-envelope-lift.md, 7097-grid-2xl-breakpoint.md, 7926-page-node-refuses-actions.md (a flat flex gap: 2, a mapped step, in a page-node example), grid-dom-attribute-whitelist-4787.md, layout-renderers-dom-props-5574.md, dashboard-declare-honoured-inputs.md (DashboardSchema.gap, a different schema), 5928-classname-style-props-rename.md and 7578-classname-style-describe.md (the StyleProps vocabulary), the two page-source-tailwind-* entries (structured prop names), 11166-page-header-breadcrumb-slot-retired.md and 6740-flex-is-container.md (CSS literals), 8505 / 8516 / 8912 / 10084 (columns, children), 10872-flat-arm-responsive-styles.md, and the gate's remaining file-name hits (4895, 5632, 6951, the two 8478 entries — the new describes carry no line address, Line Citation Gate green — 8499, 8871, 9092). No pending entry names container-padding-set-11424.test.tsx or CONTAINER_PADDING_REFUSAL. The Changeset Overwrite Report gate is green on the head, recording the two appends as its legitimate case.

② passes. The changeset declares every narrowing the diff publishes, minor with the breaking meaning stated is right for each of the three packages, the core builders' narrowed parameters are declared, and the two pending readings this change made false now carry dated, append-only notes naming the card, every sentence of which is true at this head.

③ Boundary flags

Carried from 5957735951: the patch commit touches no source, test, report or flag. Dev flags (the report's deviations), each answered: the Node tarball on PATH from the run's scratch dir only — cleared; PR assignee not set (the local write classifier refused label-write --assign) — not a contract matter, escalated to the seat to mirror the card's assignee os-tesla on #11489 (still unset at this head); file surface beyond the claim (schema-builder.ts, three .mdx, one fixture code, pointer comments) — each a consequence of the narrowing or of AGENTS #2, declared, the @object-ui/core surface in the changeset — cleared, and the claim's "not their branches" held; check:sdui-registration-pins not measured locally — it runs under Bundle Analysis, green on the head, and the diff moves no sideEffects array or registration key — cleared; lint narrowed to the 11 changed files — Lint on the head carries the repo-wide verdict (see the check-run reading above) — cleared; model-free commit trailers — AGENTS' prescribed form — cleared; ablation legs A1/A2 first refused as no-ops and re-run as A1b/A2b — the five observed reds are in the expected direction — cleared.

open_questions: none declared, none found.

out_of_scope_findings: grid.columns (and smColumns to xlColumns, and the responsive object's values) — class (c), public door plus wrong answer, measured through the real SchemaRenderer: columns: 13 draws grid-cols-1 sm:grid-cols-2, 0 and -1 draw grid-cols-2. The same family shape as this card, not a spacing key, deliberately not closed here. Escalated to the seat: a reproducible defect takes a card (Prime Directive #10); the seat files the follow-up with the report's dedupe words or rules it folded into this family. The two "carrier: none" notes (the schema-catalog test's hand-written GAP_LADDER / CONTAINER_PADDING, and the stale "Fallback for arbitrary values" comment in grid.tsx) are acceptance notes and need no card.

Implemented-by: claude/issue-11474-layout-spacing-sets
Reviewed-by: session_01XvhGmGAP79ZB8swnkapxPC

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 2, 2026 17:49
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 2, 2026 17:49
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit 4abc0aa Oct 2, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11474-layout-spacing-sets branch October 2, 2026 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant