docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337
Merged
os-project-manager merged 2 commits intoAug 30, 2026
Merged
Conversation
Every YAML fence on the page is now validated by check:yaml-examples: 18 tagged / 0 untagged, up from 6 tagged / 17 untagged. Each of the 17 untagged fences was refused by every live schema it could plausibly claim (re-derived by safeParse on this base); each is now either rewritten to the declared shape and tagged, or removed with a Callout recording what it taught and why it is gone. Rewritten and tagged: the two page templates (no `context:` key; `name` + `label` are required), custom span widths (`span: auto|full`, not twelfths), the field-group examples (section `columns` + per-field `span`), related lists and widgets (page components with `properties`, not form sections), the master-detail and kanban blocks (`object-master-detail-form` / `object-kanban`, not a page-level `layout:` mapping), Customer 360 (`regions` is an array), and the onboarding wizard (a `tabbed` form view). Removed rather than implemented, per ADR-0049 enforce-or-remove in the docs direction: the `steps:` wizard template, section `variant:`, related-list `mode: inline_edit`, and the `card_grid` block (whose per-breakpoint `columns` map is the same defect class already removed from this page). No packages/spec source is touched — the docs move to the spec, not the reverse.
The replacement Callout linked /docs/protocol/automation/flow, a route that does not exist — the page is content/docs/automation/flows.mdx, which 18 other links already spell /docs/automation/flows. Caught by the Check Documentation Links job (lychee --offline resolves root-relative links against content/); check:doc-anchors did not, because it judges in-page #fragments rather than route destinations.
os-project-manager
marked this pull request as ready for review
August 30, 2026 04:16
os-project-manager
enabled auto-merge
August 30, 2026 04:16
os-project-manager
deleted the
claude/issue-13266-layout-dsl-untrue-fences
branch
August 30, 2026 04:42
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 free
to 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.
Brings
content/docs/protocol/objectui/layout-dsl.mdxdown to the shapes the liveschemas actually accept, and pins every example so it cannot drift again.
Census (from the gate's own output, not counted by hand):
content/docs/protocol/objectui/layout-dsl.mdx: 6 tagged / 17 untagged→18 tagged / 0 untagged. Corpus-wide,check:yaml-examplesgoes from6 tagged / 147 untaggedto18 tagged / 130 untagged.Premise re-derived on this base, before editing
The card's readings were measured on the #13086 branch. Re-derived here on
origin/main@2fc11958(which contains the merged checker,2ebfe7e9) byextracting all 23 YAML fences and running
safeParseagainst every schema eachcould plausibly claim —
PageSchema,PageRegionSchema,PageComponentSchema,FormViewSchema,FormSectionSchema,FormFieldSchema,ListViewSchema, pluswrapper-unwrapped (
key=section/sections/layout/steps) variants.Result: 6 tagged, 17 untagged, and zero of the 17 was accepted by any candidate
schema. The card's premise holds in full; no section had been repaired in the
interim. Every grouping in the card reproduced verbatim.
Section × disposition
Default per triage is DELETE/rewrite — bring the docs to the spec. Nothing here
widens the accepted set, and no
packages/specsource is touched.pagecontext:is on no schema;name/labelrequired.page:sectioncarries onlychildren, so the field body isrecord:detailspagecontext:defect;record:listis not a component type — the list block isobject-gridstepsexists on no schema.template: wizardparses (free string) while naming a template no renderer providesFormSectionSchema key=sectionlayout:; fieldspanis the enumauto/full,colSpanis 1–4 — there is nospan: 6variantis a phantom key onFormSectionSchemafield_groupis a type on no schema; sectioncolumns+ per-fieldspanalready express itaddress/compositePageComponentSchemaobjectName/relationshipField, andactionsis a list of idsRecordRelatedListPropsdeclares nomode, and itscolumnsis field-name strings, never column objectsPageComponentSchemaobject-metric; it aggregates its object and has no literalvalue:;colorVariant, notcolorPageComponentSchemarecord:activity, bound to the page's record — noobject/filter of its ownPageComponentSchemacustom.*type is a legitimate open extension point; thetype: widget+component:/config:wrapper is notlayout:block (layoutaliases totemplate); the declared block isobject-master-detail-formcolumnsmap is the same breakpoint-map class already removed from this pagePageComponentSchemaobject-kanban;columnsare swimlane definitions, not a field projectionpageregionsis an array, not a map;labelwas missing; innertype: section/widget/related_listspellings correctedFormViewSchemastepsdefect; the declared staged-form shape is atabbedform viewTwo further corrections in the same class, found while re-anchoring and fixed
here because they teach the same refused structure on the same page: the
Layout Hierarchy diagram nested "Field Group", "Widget" and "Related List"
under a Section (regions hold components; only a form-shaped component holds
sections), and it carried
span: 6. The 12-Column Grid System heading nowopens with a Callout stating what is actually authorable (
columns1–4,span: auto|full) — "12 columns" describes the renderer's internal grid, never anauthorable span vocabulary.
Escalations — reported, not built
Per the triage ruling, implementing a documented-but-undeclared surface is a
Feature on the manual floor. Two deleted sections describe capabilities that may
deserve a decision card rather than permanent removal; neither is built here:
stepssurface exists atany tier. The nearest declared shapes are a
tabbedform view (no progressmodel, no per-step validation gate) and a flow. This is the larger of the two.
compact/spacious/danger). Purelycosmetic and nothing reads it today; lower value, recorded for completeness.
card_grid,field_group, related-listmode: inline_editand thesplit_view/
list_view/detail_viewtypes are not escalated — each is either aduplicate of a declared shape or a defect class this page has already removed.
Verification
Gate families derived from the diff with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(26 matched; the 2 changeset-triggered ones donot apply — see below). All re-run at
92d1a709, the final commit; each exit codecaptured before any pipe.
Green, quoting each gate's own verdict line:
check:yaml-examples—✅ 18 tagged YAML example(s) across 1 file(s) validate against their declared live spec schemascheck:docs—✅ 230 generated files in sync with packages/speccheck:doc-anchors—✅ check-doc-anchors: 282 internal #fragment link(s) across 409 source file(s) all resolve to a real heading(this is what pins the two new in-page links)check:skill-examples—✅ 260 prose examples type-check across 3 surface(s)check:doc-security-posture—✅ 26 ObjectSchema.create example(s) … carry an os validate-clean security posturecheck:doc-formula-expressions,check:doc-authoring,check:docs-single-h1,check:docs-audit-scope,check:docs-redirects,check:role-word,check:nul-bytes,check:published-readme-links,check:react-page-adapter-contract,check:cross-package-test-inputs,check:liveness,check:empty-state,check:strictness-ledger,check:variant-docs, and the fivescripts/check-doc*/check-docs*/check-section-landing-index/check-ci-filter-parityfamilies — all exit 0.Two CI reds on
943e9216; one real, one an artifact.Check Documentation Linksfailed on943e9216: the replacement wizard Callout linked/docs/protocol/automation/flow, aroute that does not exist — the page is
content/docs/automation/flows.mdx, spelled/docs/automation/flowsby 18 existing links. Fixed in92d1a709. Worth recording whythe local sweep missed it:
check:doc-anchorsjudges in-page#fragmenttargets, notroute destinations, so it was green on both commits; the job that catches this is lychee
--offlineresolving root-relative links againstcontent/, and lychee is not installedin the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same
content/+.mdx/.mdfallback rule lychee uses), and nothinganywhere links into an anchor this PR deleted (
grep -rn 'layout-dsl#'finds none).TypeScript Type Checkalso showed red on943e9216, and that one is not a defect inthis diff. Run 33291367599's own conclusion is
cancelled:lint.ymlsetscancel-in-progress: truekeyed on the PR, so pushing the link fix superseded thein-flight run, and all four member lanes (
workspace,consumer gates,debt ledger,plus
Lint & Repo Gates) were CANCELLED rather than failed.TypeScript Type Checkisan aggregator whose final step asserts every
needs:lane succeeded, so cancelled lanesmake it report
failure. Nothing was changed for it, and it is green on the new head.pnpm --filter @objectstack/spec check:generatedwas run locally against the same treeto make sure nothing generated had gone stale behind it —
exit 0.Final state on
92d1a709: 27 success, 6 skipped, zero non-green, includingCheck Documentation Links,TypeScript Type Checkand all four Type Check lanes.Check Changesetis among the skipped — theskip-changesetlabel doing its job.check:skill-examples,check:doc-formula-expressionsandcheck:doc-security-postureeach first returnedPREREQUISITE NOT MET/"package is not built" — not measurements. They were re-run green after
turbo run build --filter=@objectstack/lint --filter=@objectstack/formula --filter=@objectstack/client-react --filter=@objectstack/client.Beyond the tags — a limit worth stating.
PageComponentSchema.propertiesisan open record of string to unknown, so an
os:check-yaml PageComponentSchematagvalidates the component node's own keys and not the props bag. Every rewritten
component's
propertieswas therefore additionally dispatched throughComponentPropsMapby hand, and all of them are accepted (custom.approval_timelineexcepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not:
record:details.columnsis the string enum"1"|"2"|"3"|"4",so
columns: 2is refused; the Customer 360 example writescolumns: '2'. Filed asa follow-up finding, since the gap is the gate's, not this page's.
Changeset
None, and
skip-changesetis applied: the diff is a single file undercontent/docs/**, which no package publishes, so this PR declares no release ofits own — the exemption's stated meaning in
pr-automation.yml. Same shape as therecent docs/tooling PRs #13199 and #13202, which landed without one.
Fixes #13266
Generated by Claude Code
Generated by Claude Code