Uh oh!
There was an error while loading. Please reload this page.
docs(layout): add maxVisible and mobileMaxVisible to page-header's PageHeaderProps key list - #6257
Merged
Merged
Conversation
…geHeaderProps key list
`content/docs/layout/page-header.mdx` named 8 of the contract's keys. Walking
`PageHeaderProps`' zod shape in the installed @objectstack/spec 17.2.0 gives 11
DECLARED keys — 10 live plus the `icon` ADR-0087 D2 tombstone (`optional -> never`),
which this page already excludes correctly. The two the list omitted, `maxVisible` and
`mobileMaxVisible`, are live and authorable.
Derived from the shape's declared keys, not from a `safeParse` output: an optional key
with no default never appears in a parse result, so a parse of `{title, subtitle}` yields
only 6 keys and would have deleted `actions` and `aria` while never surfacing these two.
The added paragraph states that both keys belong to the canonical `page:header` renderer
in `@object-ui/components` (which reads them) rather than to `@object-ui/layout`'s
`PageHeader` (which does not) — the same component-vs-contract split this page already
draws for `icon`.yinlianghui
marked this pull request as ready for review
August 25, 2026 05:19
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#6083
content/docs/layout/page-header.mdx:66-68claimed@objectstack/spec/ui'sPageHeaderProps"declarestitle / subtitle / breadcrumb / actions / recordChrome / showStar / showCopyId / aria" — 8 keys, where the shape declares 10 live ones. The two omitted (maxVisible,mobileMaxVisible) are live and authorable, so an author following this page never learns the header's action-overflow budget is authorable at all.Scope is this one file. The guide's copy of the same list (
content/docs/guide/layout.md) is #5923's surface and is untouched here.Derivation — independently re-derived, not copied
Measured against the installed
@objectstack/spec17.2.0, by walking the zod shape's DECLARED keys:Corroborations from the same run:
safeParseof an object carrying all ten live keys →success = true, and all ten come back in the output.safeParse({title, icon})→success = false, message`page:header` property `icon` was removed in @objectstack/spec 17.0.0 (#6946, ADR-0087 D2) — no renderer ever read it … Delete the key.Why the method is load-bearing. Deriving from a
safeParseoutput would have been wrong:safeParse({title, subtitle})returns only["title","subtitle","breadcrumb","recordChrome","showStar","showCopyId"]— an optional key with no default never appears in a parse result. That list would have silently deletedactionsandariafrom the page and never surfaced the two keys this PR is about. Reproduced here rather than taken on trust.The repo already encodes this distinction:
packages/layout/src/__tests__/page-header-authorable-keys.test.tsxderives from the shape and skips tombstones, for exactly the reason its header records —Object.keys(shape)reports a key whether the spec accepts it or rejects it by name.Cross-check against PR #6082 — zero delta
#6082 (
content/docs/guide/layout.md, #5923, unmerged at the time of writing) recorded its own derivation. Compared key-by-key against this one: identical — same 11 declared keys in the same order, sameicontombstone (optional -> never), same 10 live, and the same per-key optional/default/inner-type annotations. Two independent derivations against the same installed spec agree; nothing was copied from the unmerged PR.What the added paragraph asserts, and why it is true
The new text says
maxVisible/mobileMaxVisiblebelong to the contract, not to the component this page documents. Verified in-tree:packages/layout/src/(the@object-ui/layoutPageHeaderthis page documents) — zero occurrences ofmaxVisibleormobileMaxVisible.page:headerrenderer reads both:packages/components/src/renderers/layout/containers.tsx:1410(maxVisible/mobileMaxVisibleare overridable on the page:header …) and:1440(… ?? 1for the mobile budget), with the designer inputs at:1789giving defaults 3 and 1 — matching the shape's owndescribe()text, which the page now quotes verbatim rather than paraphrasing.That is the same component-vs-contract split this page already draws for
icon, and it is deliberately not smoothed into consistency:iconremains simultaneously a spec tombstone and a live@object-ui/layoutregistration input (packages/layout/src/index.tsdeclares four:title,subtitle,icon,actions). Different renderers, not a contract defect.Verification
Anchor uniqueness asserted before writing (
showCopyId / aria: exactly 1 occurrence, at line 68). Mutation proven on disk by grepping the injected text and the removed text separately: after the edit,showCopyId / aria→ 0 andshowCopyId / maxVisible / mobileMaxVisible / aria→ 1.git diff HEAD --statshows this one file, 11 insertions / 2 deletions.Gate union re-run after the final commit, at
3ffa34b94, tree clean:node scripts/check-changeset-presence.mjsnode scripts/check-control-bytes.mjsnode scripts/check-doc-component-types.mjsnode scripts/check-doc-links.mjsnode scripts/check-doc-fence-languages.mjsnode scripts/check-doc-snippet-types.mjsGate set derived by enumerating each workflow's own step list, not from a remembered list.
ci.ymlandlint.ymlboth carry':(exclude,glob)content/**'in their in-jobDecide whether this change needs a full runstep, so acontent/**-only diff skips their heavy work.No changeset, on the gate's own verdict quoted above.
check-doc-component-typesreadstypeliterals in code blocks;check-doc-snippet-typescompilests/tsxfences. Neither parses a prose key list in an.mdx. The edited claim is prose, in no fence. So their green means this PR broke nothing — it is not evidence the new list is correct. The zod-shape derivation above is the verification.Measured rather than asserted. Reverting the fix in place (
git checkout HEAD~1 -- content/docs/layout/page-header.mdx, proven on disk: injected text → 0, pre-fix text → 1, 13612 → 12986 bytes) and re-running the gates:check-doc-component-typescheck-doc-linkscheck-doc-fence-languagescheck-control-bytescheck-changeset-presencecheck-doc-snippet-typesEvery assertion in this repo still passes on a revert. Six for six, byte-identical verdict lines, including on the wrong 8-key list. That is the finding, not a passing test: nothing mechanical guards this claim in either direction. Predicted before running; observed as predicted.
The restore command was
git -C WORKTREE_PATH checkout HEAD -- FILE_PATH— absolute, cwd-independent, so it does not depend on where the shell happens to be — run undertrap … EXIT INT TERM, andgit diff HEAD --statconfirmed empty afterwards (the trap firing is not the trap restoring).One declared local narrowing
check-readme-exportsis red locally, at exit 1, for a reason unrelated to this diff: 46 self-imports acrosspackages/plugin-ai,packages/plugin-ganttandpackages/plugin-mapreport "its type entry./dist/index.d.tsis not on disk -- runpnpm buildfirst". Its CI job builds every package first (pnpm exec turbo run build --filter='./packages/*'); I built only the 21 the snippet gate derives, and left the rest alone (a sibling agent is live onpackages/plugin-gantt). The gate readspackages/**/README.mdand package export surfaces — 0 references tocontent/in its output — so it cannot see this diff. Real / wrong-path / fabricated counts are 332 / 0 / 0. CI judges this one.Generated by Claude Code