Skip to content

fix(types): a page node refuses maxWidth and padding by name; the layout guide teaches pageType and the container (objectui#11318) - #11421

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-11318-layout-page-width-padding
Oct 2, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-11318-layout-page-width-padding

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11318

Clause-②: no

The layout guide taught maxWidth and padding: false on a page node. Neither is a page key: both are container members, PageNodeSchema declared neither, and PageRenderer reads neither. This PR makes the page node refuse both by name, with the door that works in the message, and corrects the guide.

Dispatched by the PM loop (claim comment 5943320845, triage direction 5924850908); implemented in session https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37. Not a governed surface: node scripts/check-governed-queue-guard.mjs --test over the eight paths answers NOT GOVERNED.

On the Clause-② line: the claim's reason says the change moves the message, not the accept set. That holds for the strict face, which already refused both keys. On the tolerant face (safeValidateSchema, what objectui validate runs today) this PR narrows the accept set: a page carrying either key used to pass and is now refused. A narrowing is not a widening, so the declaration stays no.

What changed

  • packages/types/src/zod/layout.zod.ts: PageNodeSchema declares maxWidth and padding as retirementTombstone arms (PAGE_MAX_WIDTH_REFUSAL, PAGE_PADDING_REFUSAL). The maxWidth message names pageType, and a wrapping container with its own maxWidth. The padding message names a wrapping container with its own padding. This is the shape actions (objectui#7926) and breadcrumbs (objectui#8871) set on the same node. The node stays open, not .strict().
  • packages/types/src/layout.ts: the TypeScript twin declares both keys ?: never, with docblocks.
  • content/docs/guide/layout.md: the four snippets and the Schema API block are corrected, and each place that taught a key gets a refusal callout. The per-site table below has the details.
  • page-app-dashboard-spec-parity.test.ts: the Page local ledger row lists the two new refusals. Its note asked that a third refusal come with a census, so the note now records that census and says four.
  • New pin page-width-padding-refusal-11318.test.ts. scripts/markdown-test-inputs.mjs records it as a reader of the guide. Its --audit refused the new pin until that row existed.
  • Changeset 11318-page-width-padding-refusal.md (@object-ui/types: minor, breaking for a page node carrying either key).
  • packages/layout/src/__tests__/guide-layout-app-shell-doc.test.ts: a comment only. Its scope note said the page Schema API declares headerClassName / bodyClassName, which this PR made false (Acceptance notes).

Per-site decisions

Section (by heading) Before After Why
Schema API maxWidth?, padding?, headerClassName?, bodyClassName? on the page shape pageType?, plus two NO lines naming the refusals pageType is the declared width control. The two className lines are an in-place fix (Acceptance notes).
Max Width Options, now Content Width "maxWidth": "lg" and a list of sizes "pageType": "utility", plus a second snippet: a container with "maxWidth": "2xl" The section is about the page's own width, and that is pageType. A narrower column is a container.
Settings Page with Tabs "maxWidth": "2xl" "pageType": "utility" A settings page is a utility page.
Page Padding "padding": false on the page, container "className": "p-8" container "padding": 8 and "maxWidth": false The page's inset is fixed, and the declared padding control is the container's. maxWidth: false keeps the container page-wide instead of its default xl cap.
4. Max Width for Forms, now 4. Constrained Width for Forms "maxWidth": "lg" on the page "pageType": "utility", and a container with "maxWidth": "2xl" around the form The passage is about a narrow column for a form, which is a container.

pageType: "utility" matters for the snippets with a title too. A page with no pageType is a record page, and a record page leaves its heading to a page:header block, so its title draws nothing (measured below). The Content Width section says so in one sentence.

Measurements (BASE 0858267e4)

The dispatch's four mechanism assumptions, each measured:

  1. Confirmed. PageNodeSchema declared neither key; ContainerSchema declares both. Measured with one-time render probes through the real SchemaRenderer and registry (not committed):
    • A page with maxWidth: 'lg' drew the inner class mx-auto space-y-6 max-w-7xl, the same as the page without the key. The DOM had no maxwidth attribute.
    • A page with padding: false kept the wrapper class min-h-full w-full bg-background p-3 md:p-4 lg:p-6, the same as the control.
    • With headerClassName / bodyClassName on the page, neither class value appeared anywhere in the DOM.
    • Corrected pageType: 'utility' drew an inner max-w-4xl and the heading. app drew max-w-screen-xl, home drew max-w-screen-2xl, and the default record drew max-w-7xl. Compiled with the repo's Tailwind 4.3.3, max-w-7xl and max-w-screen-xl are both 80rem. So the guide says record, list and app share a cap and home is the widest, and it cites getPageMaxWidth for the mapping rather than copying sizes.
    • The corrected container with maxWidth: '2xl' drew w-full max-w-2xl mx-auto p-2 sm:p-3 md:p-4. The container with padding: 8 drew p-4 sm:p-6 md:p-8.
  2. Confirmed, so item 2 of the direction was not a no-op. On the four fences as written, the tolerant face passed and kept the key. The strict face refused with a bare unrecognized_keys (Unrecognized key: "maxWidth" / "padding") and no prescription. After this PR, both faces answer invalid_type at the key's own path, with the prescription.
  3. Decided per site: see the table above.
  4. No overlap with objectui#11069. That PR edits the paragraph under "With Action Buttons" that begins "label is the button's text key". This PR touches neither that paragraph nor any line next to it.

Census: every git-tracked JSON file and json fence in .md/.mdx (24 type: "page" objects read), plus every TS/TSX/JS object literal through the TypeScript AST (193 type: 'page' literals). Key-matcher control: 28 hits for title / pageType. The only page objects carrying either key were the four guide fences, so the refusals strand no authored document in the tree. This is a reading on the base, not a live count.

Tests and gates (head 0c61074)

  • One run of the whole packages/types/ suite plus the 18 reader and script files below → Test Files 341 passed (341), Tests 9065 passed (9065). On its own, packages/types/ is 323 files and 8632 tests. That includes the new pin: 28 tests, both faces per key, and every page fence of the guide through both faces.
  • pnpm --filter @object-ui/types type-check (script name echoed: type-check) → exit 0. tsc -p tsconfig.test.json --listFilesOnly lists the new pin, so its @ts-expect-error legs are compiled.
  • pnpm --filter @object-ui/types build → ✓ dist completeness: 1 package(s) complete (142 emitted files verified). dist/layout.d.ts carries maxWidth?: never and padding?: never.
  • Guide readers and the changed script's own suite (18 files, 433 tests, in the run above) cover scripts/__tests__/markdown-test-inputs.test.ts plus the nine other test files that name the script, guide-layout-page-buttons-7926, the five packages/layout guide pins, component-node-vocabulary-7434 and doc-version-claims.
  • check:doc-types ✅ · check:doc-fences ✅ · check:doc-example-ids ✅ (415 references resolve) · check-doc-links.mjs "Links are valid across 17 scan roots." · check:control-bytes ✅ · check:new-line-citations "VERDICT new-cross-file-line-citations: 0 new citation(s)" · check:spec-symbols ✅ · check:doc-example-readers OK · check-changeset-presence ✅ (5 source files of 2 released packages, 1 changeset; the layout test sits under src/) · check-changeset-fixed ✅ · check-changeset-no-major ✅ · check-changeset-overwrite ✅ · check:pending-changeset-literals ✅ · check-test-path-roots ✅ · check-type-check-coverage ✅ · check-lint-coverage ✅ · check:unreferenced-sources OK · markdown-test-inputs.mjs --audit "111 candidate test files, all adjudicated".
  • eslint on the changed lintable files, as a proven narrowing. ① Population: eslint --print-config applies 116 to 118 rules to each of the five package files and 0 to scripts/markdown-test-inputs.mjs, which sits outside the linted population. ② --format json reports 6 files, 0 errors and 0 warnings. ③ Invariance: the config extends tseslint.configs.recommended, sets no parserOptions.project / projectService, and no rule under eslint-rules/ reads the file system, so this diff cannot move the verdict on any untouched file.
  • NOT MEASURED: check:doc-snippets and check:doc-examples. Reason: both exit 2 on an unbuilt tree, and their build closure is 34 packages, which does not fit the foreground cap. Basis for the narrowing: check:doc-snippets judges only ts/tsx fences. This diff adds or removes none, and the one it edits (Schema API) carries a doc-snippet: fragment declaration the gate skips. check:doc-examples judges JSDoc @example blocks, and this diff adds none. CI's doc-snippet-types.yml runs both.
  • NOT MEASURED: the downstream type-check sweep (...@object-ui/types). The TS face gains two ?: never members. The AST census above found no type: 'page' literal writing either key anywhere in the tree, and reading a never-typed optional still compiles. CI runs every package's type-check. @object-ui/layout's own type-check was not run either: its one change here is a comment.

Ablations (one-time, each through ablation-replace.mjs from committed head 92cbe41, and no file they mutated or ran has changed since; restore proven by blob equal to HEAD and an empty git diff HEAD):

  • Delete the two zod tombstone lines → 10 failed / 38 passed. All ten are contract-half legs: declared, refused at the key on each face, remedy named on each face. The positive controls and remedy legs stayed green, as predicted.
  • Re-plant "maxWidth": "lg" in the Content Width fence → 3 failed / 25 passed: both faces over the guide, plus the page-key scan. The failing line reads Content Width: invalid_type at maxWidth.
  • Delete maxWidth?: never from the TS twin → tsc -p tsconfig.test.json exit 2. The output shows TS2578 Unused '@ts-expect-error' in the new pin and two TS2322 errors in zod-mirror-parity.test.ts, so the twin pair is enforced from both sides.

Acceptance notes

  • In-place fix, beyond the card's two keys: the Schema API block also declared headerClassName? and bodyClassName? on the page shape. Neither is declared on PageNodeSchema, and both are refused as bare unrecognized_keys by the strict face. The render probe drew neither class anywhere. The two lines were the only place in the tree teaching them, and they sat in the block this PR rewrites. So they are removed from the guide only, with no schema change: the triage direction names two keys, and with zero teaching sites and zero authored sites left, a named refusal for them has no pull. git grep over the tree finds no other page-node use of either spelling; the remaining hits are AppShell prose, VirtualGrid's own prop, and a local variable in RelatedList.
  • In-place fix, same cause: guide-layout-app-shell-doc.test.ts explained its narrow scan by saying the page Schema API declares headerClassName / bodyClassName. That stopped being true here, so the sentence is restated without it. Comment only; the file is in the 18-file set above.
  • Out of scope, reported to the seat rather than filed: a page with a title and no pageType draws no heading and no description. Other guide passages author that shape: Page Component › Basic Usage, With Action Buttons, Detail Page with Actions, and Best Practices § 3. The render probe on the Basic Usage fence verbatim left only the child's text in the DOM. The same fence with pageType: "utility" drew both.
  • Out of scope, reported to the seat rather than filed: ContainerSchema.padding is a bare z.number(), while the container renderer maps only a closed set of values. padding: 9 and padding: 20 pass both faces and render no padding class at all, not even the default. The corrected Page Padding passage points readers at the Container reference for the scale.

Generated by Claude Code

claude added 3 commits October 2, 2026 00:46
…he layout guide teaches `pageType` and the `container` (objectui#11318)

Both keys are `container` members. The layout guide taught them on a
`page` node in four snippets, `PageNodeSchema` declared neither, and
`PageRenderer` reads neither: its max-width class comes from `pageType`
through `getPageMaxWidth`, and its wrapper inset is fixed. The tolerant
face kept the keys through `.passthrough()`, the strict face refused
them as a bare `unrecognized_keys`, and the page rendered unchanged.

- `PageNodeSchema` declares both as `retirementTombstone` arms whose
  messages name `pageType` and a wrapping `container`; the TypeScript
  twin declares them `?: never` (the objectui#7926 / objectui#8871
  shape on the same node).
- `content/docs/guide/layout.md`: the four snippets use `pageType` or a
  `container` with its own `maxWidth` / `padding`; the Schema API block
  drops the two keys and the two inert `headerClassName` /
  `bodyClassName` lines.
- `page-width-padding-refusal-11318.test.ts` pins each refusal on both
  faces and runs every page fence of the guide through both faces.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
…f the layout guide (objectui#11318)

The pin runs the guide's page fences through both faces, so an edit to
`content/docs/guide/layout.md` is an edit to its input; the ledger row
keeps a markdown-only pull request from skipping it.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
… page Schema API declares `headerClassName` / `bodyClassName` (objectui#11318)

The page section's Schema API block dropped both lines as unread, so the
note's reason for keeping the scan narrow is restated without that fact.
Comment only.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation package: types tests package: layout labels Oct 2, 2026
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 14 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/6872-app-shell-branding-title-jsdoc.md

  • names content/docs/guide/layout.md → content/docs/guide/layout.md — edited by this change

    Correct the AppShellBranding.title doc comment. It read "Page title suffix (sets document.title)" while useAppShellBranding assigns document.title = title wholesale — nothing is appended; the caller composes the whole string (the console passes "App label — Product name"). That comment ships in dist/index.d.ts and is the only description a consumer sees on editor hover, so a reader who followed it passed a suffix-only fragment and got a truncated title with no error. The comment now carries the same wording as content/docs/layout/app-shell.mdx, and agrees with the AppShellProps tables in the package README and content/docs/guide/layout.md. No runtime behaviour changes; the wholesale assignment and the four-surface agreement are now pinned by tests.

.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/7735-zod-mirrors-stop-authoring-defaults.md

  • 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/7926-page-node-refuses-actions.md

  • names content/docs/guide/layout.md → content/docs/guide/layout.md — edited by this change

    Scope. One key, by name; the node is NOT strict. A census over this tree read 91 authored page-tagged objects with a blind-spot reading of 8 unreadable sites, and found only actions (3 sites, all in content/docs/guide/layout.md) and breadcrumbs (1 site, its own question, untouched) surviving passthrough on a real page node — every other undeclared key belongs to a different declaration that merely spells type: 'page'. PageNodeSchema still passes unknown renderer props through.

.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.

  • names content/docs/guide/layout.md → content/docs/guide/layout.md — edited by this change

    Three author sites, all teaching passages in content/docs/guide/layout.md, and that count corrects the actions refusal's "1 site": its census reads every git-tracked JSON file, every json fence in .md/.mdx, and every TS/TSX object literal via the TypeScript AST (PR fix(types,docs): refuse actions by name on the page node, teach the shape that draws (objectui#7926) #8870), and it undercounted for two different reasons. The Schema API block declared breadcrumbs?: ArrayANGLE-BRACKETS({ label, href }) outright and its literal does carry type: 'page', but that literal sits inside a markdown typescript fence — a fence language the census's json-fence reader never visits, so it was never read at all. Best Practices §2 authored it on a fragment inside a json fence the census does read, but that fragment never writes type, so a page-tagged filter correctly excluded it. No example app, catalog fixture, template or customer document writes the key, so the refusal strands no authored document in this tree.

  • names page-app-dashboard-spec-parity.test.ts → packages/types/src/__tests__/page-app-dashboard-spec-parity.test.ts — edited by this change

    Scope. One key, by name; the node is not strict. Only 2 of the 23 passthrough- surviving undeclared keys land on a real SDUI page node (actions and this one); the rest belong to different declarations that merely spell type: 'page'. Strictness would also have reddened a living pin — page-app-dashboard-spec-parity.test.ts, "the component envelope still passes unknown renderer props through" — which stays green and is re-asserted from this card's side.

.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/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.

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 e0a9c6760 (merge-base with origin/main): 7 file(s) changed outside .changeset/, read against 1960 pending declaration(s) that publish a body (2582 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) 3552.9 KB 3574.6 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-BPi_JrMe.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.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.62KB 136.73KB
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) 260.97KB 66.19KB
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) 5.60KB 2.33KB
layout (index.js) 40.40KB 11.41KB
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.01KB 3.93KB
plugin-calendar (index.js) 53.15KB 15.45KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 139.77KB 37.47KB
plugin-designer (index.js) 216.57KB 44.72KB
plugin-detail (index.js) 245.70KB 64.54KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.14KB 44.58KB
plugin-gantt (index.js) 178.38KB 44.94KB
plugin-grid (index.js) 231.72KB 63.65KB
plugin-kanban (index.js) 49.49KB 15.54KB
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.04KB 12.21KB
plugin-timeline (index.js) 34.29KB 10.13KB
plugin-tree (index.js) 14.58KB 5.17KB
plugin-view (index.js) 90.32KB 22.76KB
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.19KB 1.62KB
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) 21.59KB 7.71KB
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

…objectui#11318)

objectui#11420 (objectui#11321) landed as e0a9c67 and added its own reader
row to `scripts/markdown-test-inputs.mjs` at the same place as this
branch's row. Resolved by keeping both rows, in the ledger's path order:
`page-width-padding-refusal-11318.test.ts`, then
`public-block-doc-examples-bag-11321.test.ts`.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
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) 3552.9 KB 3574.6 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-YJeUpo4N.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.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.62KB 136.73KB
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) 260.97KB 66.19KB
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) 5.60KB 2.33KB
layout (index.js) 40.40KB 11.41KB
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.01KB 3.93KB
plugin-calendar (index.js) 53.15KB 15.45KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 139.77KB 37.47KB
plugin-designer (index.js) 216.57KB 44.72KB
plugin-detail (index.js) 245.70KB 64.54KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.14KB 44.58KB
plugin-gantt (index.js) 178.38KB 44.94KB
plugin-grid (index.js) 231.72KB 63.65KB
plugin-kanban (index.js) 49.49KB 15.54KB
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.04KB 12.21KB
plugin-timeline (index.js) 34.29KB 10.13KB
plugin-tree (index.js) 14.58KB 5.17KB
plugin-view (index.js) 90.32KB 22.76KB
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.19KB 1.62KB
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) 21.59KB 7.71KB
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
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit a1a44d6 Oct 2, 2026
44 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11318-layout-page-width-padding branch October 2, 2026 02:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: layout package: types tests

Projects

None yet

2 participants