Skip to content

docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences
Aug 30, 2026
Merged

docs(objectui): layout-dsl teaches only shapes the live schemas accept#13337
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Brings content/docs/protocol/objectui/layout-dsl.mdx down to the shapes the live
schemas 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-examples goes from
6 tagged / 147 untagged to 18 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) by
extracting all 23 YAML fences and running safeParse against every schema each
could plausibly claim — PageSchema, PageRegionSchema, PageComponentSchema,
FormViewSchema, FormSectionSchema, FormFieldSchema, ListViewSchema, plus
wrapper-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/spec source is touched.

Fence (old line)SectionDispositionBasis
75Standard Templaterewrite + tagpagecontext: is on no schema; name/label required. page:section carries only children, so the field body is record:details
126Console Templaterewrite + tagpagesame context: defect; record:list is not a component type — the list block is object-grid
187Wizard TemplateDELETE + Calloutsteps exists on no schema. template: wizard parses (free string) while naming a template no renderer provides
250Custom Span Widthsrewrite + tagFormSectionSchema key=sectionno section-level layout:; field span is the enum auto/full, colSpan is 1–4 — there is no span: 6
395Section VariantsDELETE + Calloutvariant is a phantom key on FormSectionSchema
417Inline Field GroupDELETE, replacedfield_group is a type on no schema; section columns + per-field span already express it
442Address Field GroupDELETE, folded into the same replacementditto; a genuinely composite value is a field of type address/composite
593Basic Related Listrewrite + tagPageComponentSchemaa related list is a page component, not a form section; objectName/relationshipField, and actions is a list of ids
623Inline Editing Related ListDELETE + CalloutRecordRelatedListProps declares no mode, and its columns is field-name strings, never column objects
655Metric Widgetrewrite + tagPageComponentSchemathe real block is object-metric; it aggregates its object and has no literal value:; colorVariant, not color
680Activity Feed Widgetrewrite + tagPageComponentSchemarecord:activity, bound to the page's record — no object/filter of its own
693Custom Widgetrewrite + tagPageComponentSchemaa custom.* type is a legitimate open extension point; the type: widget + component:/config: wrapper is not
706Master-Detail Split ViewDELETE as written, replaced + tagno page-level layout: block (layout aliases to template); the declared block is object-master-detail-form
723Grid of CardsDELETE + Calloutno schema, and its per-breakpoint columns map is the same breakpoint-map class already removed from this page
744Kanban Boardrewrite + tagPageComponentSchemathe declared block is object-kanban; columns are swimlane definitions, not a field projection
934Customer 360rewrite + tagpageregions is an array, not a map; label was missing; inner type: section/widget/related_list spellings corrected
990Multi-Step WizardDELETE, replaced + tag FormViewSchemasame steps defect; the declared staged-form shape is a tabbed form view

Two 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 now
opens with a Callout stating what is actually authorable (columns 1–4, span: auto|full) — "12 columns" describes the renderer's internal grid, never an
authorable 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:

  1. Multi-step / wizard authoring (two fences). No steps surface exists at
    any tier. The nearest declared shapes are a tabbed form view (no progress
    model, no per-step validation gate) and a flow. This is the larger of the two.
  2. Section presentation variants (compact / spacious / danger). Purely
    cosmetic and nothing reads it today; lower value, recorded for completeness.

card_grid, field_group, related-list mode: inline_edit and the split_view
/ list_view / detail_view types are not escalated — each is either a
duplicate 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 do
not apply — see below). All re-run at 92d1a709, the final commit; each exit code
captured 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 schemas
  • check:docs✅ 230 generated files in sync with packages/spec
  • check: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 posture
  • check: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 five scripts/check-doc* / check-docs* /
    check-section-landing-index / check-ci-filter-parity families — all exit 0.

Two CI reds on 943e9216; one real, one an artifact.Check Documentation Links failed on
943e9216: the replacement wizard Callout linked /docs/protocol/automation/flow, a
route that does not exist — the page is content/docs/automation/flows.mdx, spelled
/docs/automation/flows by 18 existing links. Fixed in 92d1a709. Worth recording why
the local sweep missed it
: check:doc-anchors judges in-page #fragment targets, not
route destinations, so it was green on both commits; the job that catches this is lychee
--offline resolving root-relative links against content/, and lychee is not installed
in the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same content/ + .mdx/.md fallback rule lychee uses), and nothing
anywhere links into an anchor this PR deleted (grep -rn 'layout-dsl#' finds none).

TypeScript Type Check also showed red on 943e9216, and that one is not a defect in
this diff
. Run 33291367599's own conclusion is cancelled: lint.yml sets
cancel-in-progress: true keyed on the PR, so pushing the link fix superseded the
in-flight run, and all four member lanes (workspace, consumer gates, debt ledger,
plus Lint & Repo Gates) were CANCELLED rather than failed. TypeScript Type Check is
an aggregator whose final step asserts every needs: lane succeeded, so cancelled lanes
make it report failure. Nothing was changed for it, and it is green on the new head.
pnpm --filter @objectstack/spec check:generated was run locally against the same tree
to make sure nothing generated had gone stale behind it — exit 0.

Final state on 92d1a709: 27 success, 6 skipped, zero non-green, including
Check Documentation Links, TypeScript Type Check and all four Type Check lanes.
Check Changeset is among the skipped — the skip-changeset label doing its job.

check:skill-examples, check:doc-formula-expressions and
check:doc-security-posture each first returned PREREQUISITE 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.properties is
an open record of string to unknown, so an os:check-yaml PageComponentSchema tag
validates the component node's own keys and not the props bag. Every rewritten
component's properties was therefore additionally dispatched through
ComponentPropsMap by hand, and all of them are accepted (custom.approval_timeline
excepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not: record:details.columns is the string enum "1"|"2"|"3"|"4",
so columns: 2 is refused; the Customer 360 example writes columns: '2'. Filed as
a follow-up finding, since the gap is the gate's, not this page's.

Changeset

None, and skip-changeset is applied: the diff is a single file under
content/docs/**, which no package publishes, so this PR declares no release of
its own — the exemption's stated meaning in pr-automation.yml. Same shape as the
recent docs/tooling PRs #13199 and #13202, which landed without one.

Fixes#13266


Generated by Claude Code


Generated by Claude Code

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.
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 30, 2026
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
os-project-manager marked this pull request as ready for review August 30, 2026 04:16
@os-project-manager
os-project-manager added this pull request to the merge queueAug 30, 2026
Merged via the queue into main with commit 63cf416Aug 30, 2026
38 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13266-layout-dsl-untrue-fences branch August 30, 2026 04:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] layout-dsl.mdx: most of the 17 still-untagged YAML fences teach shapes the live schemas refuse (per-fence readings attached)

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
docs(objectui): layout-dsl teaches only shapes the live schemas accept by claude[bot] · Pull Request #13337 · objectstack-ai/objectstack · GitHub
Skip to content

docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences
Aug 30, 2026
Merged

docs(objectui): layout-dsl teaches only shapes the live schemas accept#13337
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Brings content/docs/protocol/objectui/layout-dsl.mdx down to the shapes the live
schemas 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-examples goes from
6 tagged / 147 untagged to 18 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) by
extracting all 23 YAML fences and running safeParse against every schema each
could plausibly claim — PageSchema, PageRegionSchema, PageComponentSchema,
FormViewSchema, FormSectionSchema, FormFieldSchema, ListViewSchema, plus
wrapper-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/spec source is touched.

Fence (old line)SectionDispositionBasis
75Standard Templaterewrite + tagpagecontext: is on no schema; name/label required. page:section carries only children, so the field body is record:details
126Console Templaterewrite + tagpagesame context: defect; record:list is not a component type — the list block is object-grid
187Wizard TemplateDELETE + Calloutsteps exists on no schema. template: wizard parses (free string) while naming a template no renderer provides
250Custom Span Widthsrewrite + tagFormSectionSchema key=sectionno section-level layout:; field span is the enum auto/full, colSpan is 1–4 — there is no span: 6
395Section VariantsDELETE + Calloutvariant is a phantom key on FormSectionSchema
417Inline Field GroupDELETE, replacedfield_group is a type on no schema; section columns + per-field span already express it
442Address Field GroupDELETE, folded into the same replacementditto; a genuinely composite value is a field of type address/composite
593Basic Related Listrewrite + tagPageComponentSchemaa related list is a page component, not a form section; objectName/relationshipField, and actions is a list of ids
623Inline Editing Related ListDELETE + CalloutRecordRelatedListProps declares no mode, and its columns is field-name strings, never column objects
655Metric Widgetrewrite + tagPageComponentSchemathe real block is object-metric; it aggregates its object and has no literal value:; colorVariant, not color
680Activity Feed Widgetrewrite + tagPageComponentSchemarecord:activity, bound to the page's record — no object/filter of its own
693Custom Widgetrewrite + tagPageComponentSchemaa custom.* type is a legitimate open extension point; the type: widget + component:/config: wrapper is not
706Master-Detail Split ViewDELETE as written, replaced + tagno page-level layout: block (layout aliases to template); the declared block is object-master-detail-form
723Grid of CardsDELETE + Calloutno schema, and its per-breakpoint columns map is the same breakpoint-map class already removed from this page
744Kanban Boardrewrite + tagPageComponentSchemathe declared block is object-kanban; columns are swimlane definitions, not a field projection
934Customer 360rewrite + tagpageregions is an array, not a map; label was missing; inner type: section/widget/related_list spellings corrected
990Multi-Step WizardDELETE, replaced + tag FormViewSchemasame steps defect; the declared staged-form shape is a tabbed form view

Two 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 now
opens with a Callout stating what is actually authorable (columns 1–4, span: auto|full) — "12 columns" describes the renderer's internal grid, never an
authorable 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:

  1. Multi-step / wizard authoring (two fences). No steps surface exists at
    any tier. The nearest declared shapes are a tabbed form view (no progress
    model, no per-step validation gate) and a flow. This is the larger of the two.
  2. Section presentation variants (compact / spacious / danger). Purely
    cosmetic and nothing reads it today; lower value, recorded for completeness.

card_grid, field_group, related-list mode: inline_edit and the split_view
/ list_view / detail_view types are not escalated — each is either a
duplicate 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 do
not apply — see below). All re-run at 92d1a709, the final commit; each exit code
captured 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 schemas
  • check:docs✅ 230 generated files in sync with packages/spec
  • check: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 posture
  • check: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 five scripts/check-doc* / check-docs* /
    check-section-landing-index / check-ci-filter-parity families — all exit 0.

Two CI reds on 943e9216; one real, one an artifact.Check Documentation Links failed on
943e9216: the replacement wizard Callout linked /docs/protocol/automation/flow, a
route that does not exist — the page is content/docs/automation/flows.mdx, spelled
/docs/automation/flows by 18 existing links. Fixed in 92d1a709. Worth recording why
the local sweep missed it
: check:doc-anchors judges in-page #fragment targets, not
route destinations, so it was green on both commits; the job that catches this is lychee
--offline resolving root-relative links against content/, and lychee is not installed
in the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same content/ + .mdx/.md fallback rule lychee uses), and nothing
anywhere links into an anchor this PR deleted (grep -rn 'layout-dsl#' finds none).

TypeScript Type Check also showed red on 943e9216, and that one is not a defect in
this diff
. Run 33291367599's own conclusion is cancelled: lint.yml sets
cancel-in-progress: true keyed on the PR, so pushing the link fix superseded the
in-flight run, and all four member lanes (workspace, consumer gates, debt ledger,
plus Lint & Repo Gates) were CANCELLED rather than failed. TypeScript Type Check is
an aggregator whose final step asserts every needs: lane succeeded, so cancelled lanes
make it report failure. Nothing was changed for it, and it is green on the new head.
pnpm --filter @objectstack/spec check:generated was run locally against the same tree
to make sure nothing generated had gone stale behind it — exit 0.

Final state on 92d1a709: 27 success, 6 skipped, zero non-green, including
Check Documentation Links, TypeScript Type Check and all four Type Check lanes.
Check Changeset is among the skipped — the skip-changeset label doing its job.

check:skill-examples, check:doc-formula-expressions and
check:doc-security-posture each first returned PREREQUISITE 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.properties is
an open record of string to unknown, so an os:check-yaml PageComponentSchema tag
validates the component node's own keys and not the props bag. Every rewritten
component's properties was therefore additionally dispatched through
ComponentPropsMap by hand, and all of them are accepted (custom.approval_timeline
excepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not: record:details.columns is the string enum "1"|"2"|"3"|"4",
so columns: 2 is refused; the Customer 360 example writes columns: '2'. Filed as
a follow-up finding, since the gap is the gate's, not this page's.

Changeset

None, and skip-changeset is applied: the diff is a single file under
content/docs/**, which no package publishes, so this PR declares no release of
its own — the exemption's stated meaning in pr-automation.yml. Same shape as the
recent docs/tooling PRs #13199 and #13202, which landed without one.

Fixes#13266


Generated by Claude Code


Generated by Claude Code

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.
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 30, 2026
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
os-project-manager marked this pull request as ready for review August 30, 2026 04:16
@os-project-manager
os-project-manager added this pull request to the merge queueAug 30, 2026
Merged via the queue into main with commit 63cf416Aug 30, 2026
38 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13266-layout-dsl-untrue-fences branch August 30, 2026 04:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] layout-dsl.mdx: most of the 17 still-untagged YAML fences teach shapes the live schemas refuse (per-fence readings attached)

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs(objectui): layout-dsl teaches only shapes the live schemas accept by claude[bot] · Pull Request #13337 · objectstack-ai/objectstack · GitHub
Skip to content

docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences
Aug 30, 2026
Merged

docs(objectui): layout-dsl teaches only shapes the live schemas accept#13337
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Brings content/docs/protocol/objectui/layout-dsl.mdx down to the shapes the live
schemas 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-examples goes from
6 tagged / 147 untagged to 18 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) by
extracting all 23 YAML fences and running safeParse against every schema each
could plausibly claim — PageSchema, PageRegionSchema, PageComponentSchema,
FormViewSchema, FormSectionSchema, FormFieldSchema, ListViewSchema, plus
wrapper-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/spec source is touched.

Fence (old line)SectionDispositionBasis
75Standard Templaterewrite + tagpagecontext: is on no schema; name/label required. page:section carries only children, so the field body is record:details
126Console Templaterewrite + tagpagesame context: defect; record:list is not a component type — the list block is object-grid
187Wizard TemplateDELETE + Calloutsteps exists on no schema. template: wizard parses (free string) while naming a template no renderer provides
250Custom Span Widthsrewrite + tagFormSectionSchema key=sectionno section-level layout:; field span is the enum auto/full, colSpan is 1–4 — there is no span: 6
395Section VariantsDELETE + Calloutvariant is a phantom key on FormSectionSchema
417Inline Field GroupDELETE, replacedfield_group is a type on no schema; section columns + per-field span already express it
442Address Field GroupDELETE, folded into the same replacementditto; a genuinely composite value is a field of type address/composite
593Basic Related Listrewrite + tagPageComponentSchemaa related list is a page component, not a form section; objectName/relationshipField, and actions is a list of ids
623Inline Editing Related ListDELETE + CalloutRecordRelatedListProps declares no mode, and its columns is field-name strings, never column objects
655Metric Widgetrewrite + tagPageComponentSchemathe real block is object-metric; it aggregates its object and has no literal value:; colorVariant, not color
680Activity Feed Widgetrewrite + tagPageComponentSchemarecord:activity, bound to the page's record — no object/filter of its own
693Custom Widgetrewrite + tagPageComponentSchemaa custom.* type is a legitimate open extension point; the type: widget + component:/config: wrapper is not
706Master-Detail Split ViewDELETE as written, replaced + tagno page-level layout: block (layout aliases to template); the declared block is object-master-detail-form
723Grid of CardsDELETE + Calloutno schema, and its per-breakpoint columns map is the same breakpoint-map class already removed from this page
744Kanban Boardrewrite + tagPageComponentSchemathe declared block is object-kanban; columns are swimlane definitions, not a field projection
934Customer 360rewrite + tagpageregions is an array, not a map; label was missing; inner type: section/widget/related_list spellings corrected
990Multi-Step WizardDELETE, replaced + tag FormViewSchemasame steps defect; the declared staged-form shape is a tabbed form view

Two 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 now
opens with a Callout stating what is actually authorable (columns 1–4, span: auto|full) — "12 columns" describes the renderer's internal grid, never an
authorable 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:

  1. Multi-step / wizard authoring (two fences). No steps surface exists at
    any tier. The nearest declared shapes are a tabbed form view (no progress
    model, no per-step validation gate) and a flow. This is the larger of the two.
  2. Section presentation variants (compact / spacious / danger). Purely
    cosmetic and nothing reads it today; lower value, recorded for completeness.

card_grid, field_group, related-list mode: inline_edit and the split_view
/ list_view / detail_view types are not escalated — each is either a
duplicate 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 do
not apply — see below). All re-run at 92d1a709, the final commit; each exit code
captured 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 schemas
  • check:docs✅ 230 generated files in sync with packages/spec
  • check: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 posture
  • check: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 five scripts/check-doc* / check-docs* /
    check-section-landing-index / check-ci-filter-parity families — all exit 0.

Two CI reds on 943e9216; one real, one an artifact.Check Documentation Links failed on
943e9216: the replacement wizard Callout linked /docs/protocol/automation/flow, a
route that does not exist — the page is content/docs/automation/flows.mdx, spelled
/docs/automation/flows by 18 existing links. Fixed in 92d1a709. Worth recording why
the local sweep missed it
: check:doc-anchors judges in-page #fragment targets, not
route destinations, so it was green on both commits; the job that catches this is lychee
--offline resolving root-relative links against content/, and lychee is not installed
in the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same content/ + .mdx/.md fallback rule lychee uses), and nothing
anywhere links into an anchor this PR deleted (grep -rn 'layout-dsl#' finds none).

TypeScript Type Check also showed red on 943e9216, and that one is not a defect in
this diff
. Run 33291367599's own conclusion is cancelled: lint.yml sets
cancel-in-progress: true keyed on the PR, so pushing the link fix superseded the
in-flight run, and all four member lanes (workspace, consumer gates, debt ledger,
plus Lint & Repo Gates) were CANCELLED rather than failed. TypeScript Type Check is
an aggregator whose final step asserts every needs: lane succeeded, so cancelled lanes
make it report failure. Nothing was changed for it, and it is green on the new head.
pnpm --filter @objectstack/spec check:generated was run locally against the same tree
to make sure nothing generated had gone stale behind it — exit 0.

Final state on 92d1a709: 27 success, 6 skipped, zero non-green, including
Check Documentation Links, TypeScript Type Check and all four Type Check lanes.
Check Changeset is among the skipped — the skip-changeset label doing its job.

check:skill-examples, check:doc-formula-expressions and
check:doc-security-posture each first returned PREREQUISITE 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.properties is
an open record of string to unknown, so an os:check-yaml PageComponentSchema tag
validates the component node's own keys and not the props bag. Every rewritten
component's properties was therefore additionally dispatched through
ComponentPropsMap by hand, and all of them are accepted (custom.approval_timeline
excepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not: record:details.columns is the string enum "1"|"2"|"3"|"4",
so columns: 2 is refused; the Customer 360 example writes columns: '2'. Filed as
a follow-up finding, since the gap is the gate's, not this page's.

Changeset

None, and skip-changeset is applied: the diff is a single file under
content/docs/**, which no package publishes, so this PR declares no release of
its own — the exemption's stated meaning in pr-automation.yml. Same shape as the
recent docs/tooling PRs #13199 and #13202, which landed without one.

Fixes#13266


Generated by Claude Code


Generated by Claude Code

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.
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 30, 2026
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
os-project-manager marked this pull request as ready for review August 30, 2026 04:16
@os-project-manager
os-project-manager added this pull request to the merge queueAug 30, 2026
Merged via the queue into main with commit 63cf416Aug 30, 2026
38 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13266-layout-dsl-untrue-fences branch August 30, 2026 04:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] layout-dsl.mdx: most of the 17 still-untagged YAML fences teach shapes the live schemas refuse (per-fence readings attached)

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs(objectui): layout-dsl teaches only shapes the live schemas accept by claude[bot] · Pull Request #13337 · objectstack-ai/objectstack · GitHub
Skip to content

docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences
Aug 30, 2026
Merged

docs(objectui): layout-dsl teaches only shapes the live schemas accept#13337
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Brings content/docs/protocol/objectui/layout-dsl.mdx down to the shapes the live
schemas 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-examples goes from
6 tagged / 147 untagged to 18 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) by
extracting all 23 YAML fences and running safeParse against every schema each
could plausibly claim — PageSchema, PageRegionSchema, PageComponentSchema,
FormViewSchema, FormSectionSchema, FormFieldSchema, ListViewSchema, plus
wrapper-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/spec source is touched.

Fence (old line)SectionDispositionBasis
75Standard Templaterewrite + tagpagecontext: is on no schema; name/label required. page:section carries only children, so the field body is record:details
126Console Templaterewrite + tagpagesame context: defect; record:list is not a component type — the list block is object-grid
187Wizard TemplateDELETE + Calloutsteps exists on no schema. template: wizard parses (free string) while naming a template no renderer provides
250Custom Span Widthsrewrite + tagFormSectionSchema key=sectionno section-level layout:; field span is the enum auto/full, colSpan is 1–4 — there is no span: 6
395Section VariantsDELETE + Calloutvariant is a phantom key on FormSectionSchema
417Inline Field GroupDELETE, replacedfield_group is a type on no schema; section columns + per-field span already express it
442Address Field GroupDELETE, folded into the same replacementditto; a genuinely composite value is a field of type address/composite
593Basic Related Listrewrite + tagPageComponentSchemaa related list is a page component, not a form section; objectName/relationshipField, and actions is a list of ids
623Inline Editing Related ListDELETE + CalloutRecordRelatedListProps declares no mode, and its columns is field-name strings, never column objects
655Metric Widgetrewrite + tagPageComponentSchemathe real block is object-metric; it aggregates its object and has no literal value:; colorVariant, not color
680Activity Feed Widgetrewrite + tagPageComponentSchemarecord:activity, bound to the page's record — no object/filter of its own
693Custom Widgetrewrite + tagPageComponentSchemaa custom.* type is a legitimate open extension point; the type: widget + component:/config: wrapper is not
706Master-Detail Split ViewDELETE as written, replaced + tagno page-level layout: block (layout aliases to template); the declared block is object-master-detail-form
723Grid of CardsDELETE + Calloutno schema, and its per-breakpoint columns map is the same breakpoint-map class already removed from this page
744Kanban Boardrewrite + tagPageComponentSchemathe declared block is object-kanban; columns are swimlane definitions, not a field projection
934Customer 360rewrite + tagpageregions is an array, not a map; label was missing; inner type: section/widget/related_list spellings corrected
990Multi-Step WizardDELETE, replaced + tag FormViewSchemasame steps defect; the declared staged-form shape is a tabbed form view

Two 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 now
opens with a Callout stating what is actually authorable (columns 1–4, span: auto|full) — "12 columns" describes the renderer's internal grid, never an
authorable 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:

  1. Multi-step / wizard authoring (two fences). No steps surface exists at
    any tier. The nearest declared shapes are a tabbed form view (no progress
    model, no per-step validation gate) and a flow. This is the larger of the two.
  2. Section presentation variants (compact / spacious / danger). Purely
    cosmetic and nothing reads it today; lower value, recorded for completeness.

card_grid, field_group, related-list mode: inline_edit and the split_view
/ list_view / detail_view types are not escalated — each is either a
duplicate 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 do
not apply — see below). All re-run at 92d1a709, the final commit; each exit code
captured 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 schemas
  • check:docs✅ 230 generated files in sync with packages/spec
  • check: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 posture
  • check: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 five scripts/check-doc* / check-docs* /
    check-section-landing-index / check-ci-filter-parity families — all exit 0.

Two CI reds on 943e9216; one real, one an artifact.Check Documentation Links failed on
943e9216: the replacement wizard Callout linked /docs/protocol/automation/flow, a
route that does not exist — the page is content/docs/automation/flows.mdx, spelled
/docs/automation/flows by 18 existing links. Fixed in 92d1a709. Worth recording why
the local sweep missed it
: check:doc-anchors judges in-page #fragment targets, not
route destinations, so it was green on both commits; the job that catches this is lychee
--offline resolving root-relative links against content/, and lychee is not installed
in the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same content/ + .mdx/.md fallback rule lychee uses), and nothing
anywhere links into an anchor this PR deleted (grep -rn 'layout-dsl#' finds none).

TypeScript Type Check also showed red on 943e9216, and that one is not a defect in
this diff
. Run 33291367599's own conclusion is cancelled: lint.yml sets
cancel-in-progress: true keyed on the PR, so pushing the link fix superseded the
in-flight run, and all four member lanes (workspace, consumer gates, debt ledger,
plus Lint & Repo Gates) were CANCELLED rather than failed. TypeScript Type Check is
an aggregator whose final step asserts every needs: lane succeeded, so cancelled lanes
make it report failure. Nothing was changed for it, and it is green on the new head.
pnpm --filter @objectstack/spec check:generated was run locally against the same tree
to make sure nothing generated had gone stale behind it — exit 0.

Final state on 92d1a709: 27 success, 6 skipped, zero non-green, including
Check Documentation Links, TypeScript Type Check and all four Type Check lanes.
Check Changeset is among the skipped — the skip-changeset label doing its job.

check:skill-examples, check:doc-formula-expressions and
check:doc-security-posture each first returned PREREQUISITE 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.properties is
an open record of string to unknown, so an os:check-yaml PageComponentSchema tag
validates the component node's own keys and not the props bag. Every rewritten
component's properties was therefore additionally dispatched through
ComponentPropsMap by hand, and all of them are accepted (custom.approval_timeline
excepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not: record:details.columns is the string enum "1"|"2"|"3"|"4",
so columns: 2 is refused; the Customer 360 example writes columns: '2'. Filed as
a follow-up finding, since the gap is the gate's, not this page's.

Changeset

None, and skip-changeset is applied: the diff is a single file under
content/docs/**, which no package publishes, so this PR declares no release of
its own — the exemption's stated meaning in pr-automation.yml. Same shape as the
recent docs/tooling PRs #13199 and #13202, which landed without one.

Fixes#13266


Generated by Claude Code


Generated by Claude Code

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.
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 30, 2026
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
os-project-manager marked this pull request as ready for review August 30, 2026 04:16
@os-project-manager
os-project-manager added this pull request to the merge queueAug 30, 2026
Merged via the queue into main with commit 63cf416Aug 30, 2026
38 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13266-layout-dsl-untrue-fences branch August 30, 2026 04:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] layout-dsl.mdx: most of the 17 still-untagged YAML fences teach shapes the live schemas refuse (per-fence readings attached)

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' docs(objectui): layout-dsl teaches only shapes the live schemas accept by claude[bot] · Pull Request #13337 · objectstack-ai/objectstack · GitHub
Skip to content

docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences
Aug 30, 2026
Merged

docs(objectui): layout-dsl teaches only shapes the live schemas accept#13337
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Brings content/docs/protocol/objectui/layout-dsl.mdx down to the shapes the live
schemas 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-examples goes from
6 tagged / 147 untagged to 18 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) by
extracting all 23 YAML fences and running safeParse against every schema each
could plausibly claim — PageSchema, PageRegionSchema, PageComponentSchema,
FormViewSchema, FormSectionSchema, FormFieldSchema, ListViewSchema, plus
wrapper-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/spec source is touched.

Fence (old line)SectionDispositionBasis
75Standard Templaterewrite + tagpagecontext: is on no schema; name/label required. page:section carries only children, so the field body is record:details
126Console Templaterewrite + tagpagesame context: defect; record:list is not a component type — the list block is object-grid
187Wizard TemplateDELETE + Calloutsteps exists on no schema. template: wizard parses (free string) while naming a template no renderer provides
250Custom Span Widthsrewrite + tagFormSectionSchema key=sectionno section-level layout:; field span is the enum auto/full, colSpan is 1–4 — there is no span: 6
395Section VariantsDELETE + Calloutvariant is a phantom key on FormSectionSchema
417Inline Field GroupDELETE, replacedfield_group is a type on no schema; section columns + per-field span already express it
442Address Field GroupDELETE, folded into the same replacementditto; a genuinely composite value is a field of type address/composite
593Basic Related Listrewrite + tagPageComponentSchemaa related list is a page component, not a form section; objectName/relationshipField, and actions is a list of ids
623Inline Editing Related ListDELETE + CalloutRecordRelatedListProps declares no mode, and its columns is field-name strings, never column objects
655Metric Widgetrewrite + tagPageComponentSchemathe real block is object-metric; it aggregates its object and has no literal value:; colorVariant, not color
680Activity Feed Widgetrewrite + tagPageComponentSchemarecord:activity, bound to the page's record — no object/filter of its own
693Custom Widgetrewrite + tagPageComponentSchemaa custom.* type is a legitimate open extension point; the type: widget + component:/config: wrapper is not
706Master-Detail Split ViewDELETE as written, replaced + tagno page-level layout: block (layout aliases to template); the declared block is object-master-detail-form
723Grid of CardsDELETE + Calloutno schema, and its per-breakpoint columns map is the same breakpoint-map class already removed from this page
744Kanban Boardrewrite + tagPageComponentSchemathe declared block is object-kanban; columns are swimlane definitions, not a field projection
934Customer 360rewrite + tagpageregions is an array, not a map; label was missing; inner type: section/widget/related_list spellings corrected
990Multi-Step WizardDELETE, replaced + tag FormViewSchemasame steps defect; the declared staged-form shape is a tabbed form view

Two 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 now
opens with a Callout stating what is actually authorable (columns 1–4, span: auto|full) — "12 columns" describes the renderer's internal grid, never an
authorable 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:

  1. Multi-step / wizard authoring (two fences). No steps surface exists at
    any tier. The nearest declared shapes are a tabbed form view (no progress
    model, no per-step validation gate) and a flow. This is the larger of the two.
  2. Section presentation variants (compact / spacious / danger). Purely
    cosmetic and nothing reads it today; lower value, recorded for completeness.

card_grid, field_group, related-list mode: inline_edit and the split_view
/ list_view / detail_view types are not escalated — each is either a
duplicate 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 do
not apply — see below). All re-run at 92d1a709, the final commit; each exit code
captured 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 schemas
  • check:docs✅ 230 generated files in sync with packages/spec
  • check: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 posture
  • check: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 five scripts/check-doc* / check-docs* /
    check-section-landing-index / check-ci-filter-parity families — all exit 0.

Two CI reds on 943e9216; one real, one an artifact.Check Documentation Links failed on
943e9216: the replacement wizard Callout linked /docs/protocol/automation/flow, a
route that does not exist — the page is content/docs/automation/flows.mdx, spelled
/docs/automation/flows by 18 existing links. Fixed in 92d1a709. Worth recording why
the local sweep missed it
: check:doc-anchors judges in-page #fragment targets, not
route destinations, so it was green on both commits; the job that catches this is lychee
--offline resolving root-relative links against content/, and lychee is not installed
in the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same content/ + .mdx/.md fallback rule lychee uses), and nothing
anywhere links into an anchor this PR deleted (grep -rn 'layout-dsl#' finds none).

TypeScript Type Check also showed red on 943e9216, and that one is not a defect in
this diff
. Run 33291367599's own conclusion is cancelled: lint.yml sets
cancel-in-progress: true keyed on the PR, so pushing the link fix superseded the
in-flight run, and all four member lanes (workspace, consumer gates, debt ledger,
plus Lint & Repo Gates) were CANCELLED rather than failed. TypeScript Type Check is
an aggregator whose final step asserts every needs: lane succeeded, so cancelled lanes
make it report failure. Nothing was changed for it, and it is green on the new head.
pnpm --filter @objectstack/spec check:generated was run locally against the same tree
to make sure nothing generated had gone stale behind it — exit 0.

Final state on 92d1a709: 27 success, 6 skipped, zero non-green, including
Check Documentation Links, TypeScript Type Check and all four Type Check lanes.
Check Changeset is among the skipped — the skip-changeset label doing its job.

check:skill-examples, check:doc-formula-expressions and
check:doc-security-posture each first returned PREREQUISITE 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.properties is
an open record of string to unknown, so an os:check-yaml PageComponentSchema tag
validates the component node's own keys and not the props bag. Every rewritten
component's properties was therefore additionally dispatched through
ComponentPropsMap by hand, and all of them are accepted (custom.approval_timeline
excepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not: record:details.columns is the string enum "1"|"2"|"3"|"4",
so columns: 2 is refused; the Customer 360 example writes columns: '2'. Filed as
a follow-up finding, since the gap is the gate's, not this page's.

Changeset

None, and skip-changeset is applied: the diff is a single file under
content/docs/**, which no package publishes, so this PR declares no release of
its own — the exemption's stated meaning in pr-automation.yml. Same shape as the
recent docs/tooling PRs #13199 and #13202, which landed without one.

Fixes#13266


Generated by Claude Code


Generated by Claude Code

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.
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 30, 2026
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
os-project-manager marked this pull request as ready for review August 30, 2026 04:16
@os-project-manager
os-project-manager added this pull request to the merge queueAug 30, 2026
Merged via the queue into main with commit 63cf416Aug 30, 2026
38 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13266-layout-dsl-untrue-fences branch August 30, 2026 04:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] layout-dsl.mdx: most of the 17 still-untagged YAML fences teach shapes the live schemas refuse (per-fence readings attached)

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs(objectui): layout-dsl teaches only shapes the live schemas accept by claude[bot] · Pull Request #13337 · objectstack-ai/objectstack · GitHub
Skip to content

docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences
Aug 30, 2026
Merged

docs(objectui): layout-dsl teaches only shapes the live schemas accept#13337
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Brings content/docs/protocol/objectui/layout-dsl.mdx down to the shapes the live
schemas 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-examples goes from
6 tagged / 147 untagged to 18 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) by
extracting all 23 YAML fences and running safeParse against every schema each
could plausibly claim — PageSchema, PageRegionSchema, PageComponentSchema,
FormViewSchema, FormSectionSchema, FormFieldSchema, ListViewSchema, plus
wrapper-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/spec source is touched.

Fence (old line)SectionDispositionBasis
75Standard Templaterewrite + tagpagecontext: is on no schema; name/label required. page:section carries only children, so the field body is record:details
126Console Templaterewrite + tagpagesame context: defect; record:list is not a component type — the list block is object-grid
187Wizard TemplateDELETE + Calloutsteps exists on no schema. template: wizard parses (free string) while naming a template no renderer provides
250Custom Span Widthsrewrite + tagFormSectionSchema key=sectionno section-level layout:; field span is the enum auto/full, colSpan is 1–4 — there is no span: 6
395Section VariantsDELETE + Calloutvariant is a phantom key on FormSectionSchema
417Inline Field GroupDELETE, replacedfield_group is a type on no schema; section columns + per-field span already express it
442Address Field GroupDELETE, folded into the same replacementditto; a genuinely composite value is a field of type address/composite
593Basic Related Listrewrite + tagPageComponentSchemaa related list is a page component, not a form section; objectName/relationshipField, and actions is a list of ids
623Inline Editing Related ListDELETE + CalloutRecordRelatedListProps declares no mode, and its columns is field-name strings, never column objects
655Metric Widgetrewrite + tagPageComponentSchemathe real block is object-metric; it aggregates its object and has no literal value:; colorVariant, not color
680Activity Feed Widgetrewrite + tagPageComponentSchemarecord:activity, bound to the page's record — no object/filter of its own
693Custom Widgetrewrite + tagPageComponentSchemaa custom.* type is a legitimate open extension point; the type: widget + component:/config: wrapper is not
706Master-Detail Split ViewDELETE as written, replaced + tagno page-level layout: block (layout aliases to template); the declared block is object-master-detail-form
723Grid of CardsDELETE + Calloutno schema, and its per-breakpoint columns map is the same breakpoint-map class already removed from this page
744Kanban Boardrewrite + tagPageComponentSchemathe declared block is object-kanban; columns are swimlane definitions, not a field projection
934Customer 360rewrite + tagpageregions is an array, not a map; label was missing; inner type: section/widget/related_list spellings corrected
990Multi-Step WizardDELETE, replaced + tag FormViewSchemasame steps defect; the declared staged-form shape is a tabbed form view

Two 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 now
opens with a Callout stating what is actually authorable (columns 1–4, span: auto|full) — "12 columns" describes the renderer's internal grid, never an
authorable 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:

  1. Multi-step / wizard authoring (two fences). No steps surface exists at
    any tier. The nearest declared shapes are a tabbed form view (no progress
    model, no per-step validation gate) and a flow. This is the larger of the two.
  2. Section presentation variants (compact / spacious / danger). Purely
    cosmetic and nothing reads it today; lower value, recorded for completeness.

card_grid, field_group, related-list mode: inline_edit and the split_view
/ list_view / detail_view types are not escalated — each is either a
duplicate 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 do
not apply — see below). All re-run at 92d1a709, the final commit; each exit code
captured 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 schemas
  • check:docs✅ 230 generated files in sync with packages/spec
  • check: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 posture
  • check: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 five scripts/check-doc* / check-docs* /
    check-section-landing-index / check-ci-filter-parity families — all exit 0.

Two CI reds on 943e9216; one real, one an artifact.Check Documentation Links failed on
943e9216: the replacement wizard Callout linked /docs/protocol/automation/flow, a
route that does not exist — the page is content/docs/automation/flows.mdx, spelled
/docs/automation/flows by 18 existing links. Fixed in 92d1a709. Worth recording why
the local sweep missed it
: check:doc-anchors judges in-page #fragment targets, not
route destinations, so it was green on both commits; the job that catches this is lychee
--offline resolving root-relative links against content/, and lychee is not installed
in the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same content/ + .mdx/.md fallback rule lychee uses), and nothing
anywhere links into an anchor this PR deleted (grep -rn 'layout-dsl#' finds none).

TypeScript Type Check also showed red on 943e9216, and that one is not a defect in
this diff
. Run 33291367599's own conclusion is cancelled: lint.yml sets
cancel-in-progress: true keyed on the PR, so pushing the link fix superseded the
in-flight run, and all four member lanes (workspace, consumer gates, debt ledger,
plus Lint & Repo Gates) were CANCELLED rather than failed. TypeScript Type Check is
an aggregator whose final step asserts every needs: lane succeeded, so cancelled lanes
make it report failure. Nothing was changed for it, and it is green on the new head.
pnpm --filter @objectstack/spec check:generated was run locally against the same tree
to make sure nothing generated had gone stale behind it — exit 0.

Final state on 92d1a709: 27 success, 6 skipped, zero non-green, including
Check Documentation Links, TypeScript Type Check and all four Type Check lanes.
Check Changeset is among the skipped — the skip-changeset label doing its job.

check:skill-examples, check:doc-formula-expressions and
check:doc-security-posture each first returned PREREQUISITE 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.properties is
an open record of string to unknown, so an os:check-yaml PageComponentSchema tag
validates the component node's own keys and not the props bag. Every rewritten
component's properties was therefore additionally dispatched through
ComponentPropsMap by hand, and all of them are accepted (custom.approval_timeline
excepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not: record:details.columns is the string enum "1"|"2"|"3"|"4",
so columns: 2 is refused; the Customer 360 example writes columns: '2'. Filed as
a follow-up finding, since the gap is the gate's, not this page's.

Changeset

None, and skip-changeset is applied: the diff is a single file under
content/docs/**, which no package publishes, so this PR declares no release of
its own — the exemption's stated meaning in pr-automation.yml. Same shape as the
recent docs/tooling PRs #13199 and #13202, which landed without one.

Fixes#13266


Generated by Claude Code


Generated by Claude Code

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.
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 30, 2026
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
os-project-manager marked this pull request as ready for review August 30, 2026 04:16
@os-project-manager
os-project-manager added this pull request to the merge queueAug 30, 2026
Merged via the queue into main with commit 63cf416Aug 30, 2026
38 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13266-layout-dsl-untrue-fences branch August 30, 2026 04:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] layout-dsl.mdx: most of the 17 still-untagged YAML fences teach shapes the live schemas refuse (per-fence readings attached)

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs(objectui): layout-dsl teaches only shapes the live schemas accept by claude[bot] · Pull Request #13337 · objectstack-ai/objectstack · GitHub
Skip to content

docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences
Aug 30, 2026
Merged

docs(objectui): layout-dsl teaches only shapes the live schemas accept#13337
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Brings content/docs/protocol/objectui/layout-dsl.mdx down to the shapes the live
schemas 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-examples goes from
6 tagged / 147 untagged to 18 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) by
extracting all 23 YAML fences and running safeParse against every schema each
could plausibly claim — PageSchema, PageRegionSchema, PageComponentSchema,
FormViewSchema, FormSectionSchema, FormFieldSchema, ListViewSchema, plus
wrapper-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/spec source is touched.

Fence (old line)SectionDispositionBasis
75Standard Templaterewrite + tagpagecontext: is on no schema; name/label required. page:section carries only children, so the field body is record:details
126Console Templaterewrite + tagpagesame context: defect; record:list is not a component type — the list block is object-grid
187Wizard TemplateDELETE + Calloutsteps exists on no schema. template: wizard parses (free string) while naming a template no renderer provides
250Custom Span Widthsrewrite + tagFormSectionSchema key=sectionno section-level layout:; field span is the enum auto/full, colSpan is 1–4 — there is no span: 6
395Section VariantsDELETE + Calloutvariant is a phantom key on FormSectionSchema
417Inline Field GroupDELETE, replacedfield_group is a type on no schema; section columns + per-field span already express it
442Address Field GroupDELETE, folded into the same replacementditto; a genuinely composite value is a field of type address/composite
593Basic Related Listrewrite + tagPageComponentSchemaa related list is a page component, not a form section; objectName/relationshipField, and actions is a list of ids
623Inline Editing Related ListDELETE + CalloutRecordRelatedListProps declares no mode, and its columns is field-name strings, never column objects
655Metric Widgetrewrite + tagPageComponentSchemathe real block is object-metric; it aggregates its object and has no literal value:; colorVariant, not color
680Activity Feed Widgetrewrite + tagPageComponentSchemarecord:activity, bound to the page's record — no object/filter of its own
693Custom Widgetrewrite + tagPageComponentSchemaa custom.* type is a legitimate open extension point; the type: widget + component:/config: wrapper is not
706Master-Detail Split ViewDELETE as written, replaced + tagno page-level layout: block (layout aliases to template); the declared block is object-master-detail-form
723Grid of CardsDELETE + Calloutno schema, and its per-breakpoint columns map is the same breakpoint-map class already removed from this page
744Kanban Boardrewrite + tagPageComponentSchemathe declared block is object-kanban; columns are swimlane definitions, not a field projection
934Customer 360rewrite + tagpageregions is an array, not a map; label was missing; inner type: section/widget/related_list spellings corrected
990Multi-Step WizardDELETE, replaced + tag FormViewSchemasame steps defect; the declared staged-form shape is a tabbed form view

Two 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 now
opens with a Callout stating what is actually authorable (columns 1–4, span: auto|full) — "12 columns" describes the renderer's internal grid, never an
authorable 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:

  1. Multi-step / wizard authoring (two fences). No steps surface exists at
    any tier. The nearest declared shapes are a tabbed form view (no progress
    model, no per-step validation gate) and a flow. This is the larger of the two.
  2. Section presentation variants (compact / spacious / danger). Purely
    cosmetic and nothing reads it today; lower value, recorded for completeness.

card_grid, field_group, related-list mode: inline_edit and the split_view
/ list_view / detail_view types are not escalated — each is either a
duplicate 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 do
not apply — see below). All re-run at 92d1a709, the final commit; each exit code
captured 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 schemas
  • check:docs✅ 230 generated files in sync with packages/spec
  • check: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 posture
  • check: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 five scripts/check-doc* / check-docs* /
    check-section-landing-index / check-ci-filter-parity families — all exit 0.

Two CI reds on 943e9216; one real, one an artifact.Check Documentation Links failed on
943e9216: the replacement wizard Callout linked /docs/protocol/automation/flow, a
route that does not exist — the page is content/docs/automation/flows.mdx, spelled
/docs/automation/flows by 18 existing links. Fixed in 92d1a709. Worth recording why
the local sweep missed it
: check:doc-anchors judges in-page #fragment targets, not
route destinations, so it was green on both commits; the job that catches this is lychee
--offline resolving root-relative links against content/, and lychee is not installed
in the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same content/ + .mdx/.md fallback rule lychee uses), and nothing
anywhere links into an anchor this PR deleted (grep -rn 'layout-dsl#' finds none).

TypeScript Type Check also showed red on 943e9216, and that one is not a defect in
this diff
. Run 33291367599's own conclusion is cancelled: lint.yml sets
cancel-in-progress: true keyed on the PR, so pushing the link fix superseded the
in-flight run, and all four member lanes (workspace, consumer gates, debt ledger,
plus Lint & Repo Gates) were CANCELLED rather than failed. TypeScript Type Check is
an aggregator whose final step asserts every needs: lane succeeded, so cancelled lanes
make it report failure. Nothing was changed for it, and it is green on the new head.
pnpm --filter @objectstack/spec check:generated was run locally against the same tree
to make sure nothing generated had gone stale behind it — exit 0.

Final state on 92d1a709: 27 success, 6 skipped, zero non-green, including
Check Documentation Links, TypeScript Type Check and all four Type Check lanes.
Check Changeset is among the skipped — the skip-changeset label doing its job.

check:skill-examples, check:doc-formula-expressions and
check:doc-security-posture each first returned PREREQUISITE 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.properties is
an open record of string to unknown, so an os:check-yaml PageComponentSchema tag
validates the component node's own keys and not the props bag. Every rewritten
component's properties was therefore additionally dispatched through
ComponentPropsMap by hand, and all of them are accepted (custom.approval_timeline
excepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not: record:details.columns is the string enum "1"|"2"|"3"|"4",
so columns: 2 is refused; the Customer 360 example writes columns: '2'. Filed as
a follow-up finding, since the gap is the gate's, not this page's.

Changeset

None, and skip-changeset is applied: the diff is a single file under
content/docs/**, which no package publishes, so this PR declares no release of
its own — the exemption's stated meaning in pr-automation.yml. Same shape as the
recent docs/tooling PRs #13199 and #13202, which landed without one.

Fixes#13266


Generated by Claude Code


Generated by Claude Code

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.
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 30, 2026
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
os-project-manager marked this pull request as ready for review August 30, 2026 04:16
@os-project-manager
os-project-manager added this pull request to the merge queueAug 30, 2026
Merged via the queue into main with commit 63cf416Aug 30, 2026
38 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13266-layout-dsl-untrue-fences branch August 30, 2026 04:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] layout-dsl.mdx: most of the 17 still-untagged YAML fences teach shapes the live schemas refuse (per-fence readings attached)

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); docs(objectui): layout-dsl teaches only shapes the live schemas accept by claude[bot] · Pull Request #13337 · objectstack-ai/objectstack · GitHub
Skip to content

docs(objectui): layout-dsl teaches only shapes the live schemas accept - #13337

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences
Aug 30, 2026
Merged

docs(objectui): layout-dsl teaches only shapes the live schemas accept#13337
os-project-manager merged 2 commits into
mainfrom
claude/issue-13266-layout-dsl-untrue-fences

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Brings content/docs/protocol/objectui/layout-dsl.mdx down to the shapes the live
schemas 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-examples goes from
6 tagged / 147 untagged to 18 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) by
extracting all 23 YAML fences and running safeParse against every schema each
could plausibly claim — PageSchema, PageRegionSchema, PageComponentSchema,
FormViewSchema, FormSectionSchema, FormFieldSchema, ListViewSchema, plus
wrapper-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/spec source is touched.

Fence (old line)SectionDispositionBasis
75Standard Templaterewrite + tagpagecontext: is on no schema; name/label required. page:section carries only children, so the field body is record:details
126Console Templaterewrite + tagpagesame context: defect; record:list is not a component type — the list block is object-grid
187Wizard TemplateDELETE + Calloutsteps exists on no schema. template: wizard parses (free string) while naming a template no renderer provides
250Custom Span Widthsrewrite + tagFormSectionSchema key=sectionno section-level layout:; field span is the enum auto/full, colSpan is 1–4 — there is no span: 6
395Section VariantsDELETE + Calloutvariant is a phantom key on FormSectionSchema
417Inline Field GroupDELETE, replacedfield_group is a type on no schema; section columns + per-field span already express it
442Address Field GroupDELETE, folded into the same replacementditto; a genuinely composite value is a field of type address/composite
593Basic Related Listrewrite + tagPageComponentSchemaa related list is a page component, not a form section; objectName/relationshipField, and actions is a list of ids
623Inline Editing Related ListDELETE + CalloutRecordRelatedListProps declares no mode, and its columns is field-name strings, never column objects
655Metric Widgetrewrite + tagPageComponentSchemathe real block is object-metric; it aggregates its object and has no literal value:; colorVariant, not color
680Activity Feed Widgetrewrite + tagPageComponentSchemarecord:activity, bound to the page's record — no object/filter of its own
693Custom Widgetrewrite + tagPageComponentSchemaa custom.* type is a legitimate open extension point; the type: widget + component:/config: wrapper is not
706Master-Detail Split ViewDELETE as written, replaced + tagno page-level layout: block (layout aliases to template); the declared block is object-master-detail-form
723Grid of CardsDELETE + Calloutno schema, and its per-breakpoint columns map is the same breakpoint-map class already removed from this page
744Kanban Boardrewrite + tagPageComponentSchemathe declared block is object-kanban; columns are swimlane definitions, not a field projection
934Customer 360rewrite + tagpageregions is an array, not a map; label was missing; inner type: section/widget/related_list spellings corrected
990Multi-Step WizardDELETE, replaced + tag FormViewSchemasame steps defect; the declared staged-form shape is a tabbed form view

Two 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 now
opens with a Callout stating what is actually authorable (columns 1–4, span: auto|full) — "12 columns" describes the renderer's internal grid, never an
authorable 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:

  1. Multi-step / wizard authoring (two fences). No steps surface exists at
    any tier. The nearest declared shapes are a tabbed form view (no progress
    model, no per-step validation gate) and a flow. This is the larger of the two.
  2. Section presentation variants (compact / spacious / danger). Purely
    cosmetic and nothing reads it today; lower value, recorded for completeness.

card_grid, field_group, related-list mode: inline_edit and the split_view
/ list_view / detail_view types are not escalated — each is either a
duplicate 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 do
not apply — see below). All re-run at 92d1a709, the final commit; each exit code
captured 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 schemas
  • check:docs✅ 230 generated files in sync with packages/spec
  • check: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 posture
  • check: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 five scripts/check-doc* / check-docs* /
    check-section-landing-index / check-ci-filter-parity families — all exit 0.

Two CI reds on 943e9216; one real, one an artifact.Check Documentation Links failed on
943e9216: the replacement wizard Callout linked /docs/protocol/automation/flow, a
route that does not exist — the page is content/docs/automation/flows.mdx, spelled
/docs/automation/flows by 18 existing links. Fixed in 92d1a709. Worth recording why
the local sweep missed it
: check:doc-anchors judges in-page #fragment targets, not
route destinations, so it was green on both commits; the job that catches this is lychee
--offline resolving root-relative links against content/, and lychee is not installed
in the dev container. Every root-relative link on the page now resolves (10/10, checked
against the same content/ + .mdx/.md fallback rule lychee uses), and nothing
anywhere links into an anchor this PR deleted (grep -rn 'layout-dsl#' finds none).

TypeScript Type Check also showed red on 943e9216, and that one is not a defect in
this diff
. Run 33291367599's own conclusion is cancelled: lint.yml sets
cancel-in-progress: true keyed on the PR, so pushing the link fix superseded the
in-flight run, and all four member lanes (workspace, consumer gates, debt ledger,
plus Lint & Repo Gates) were CANCELLED rather than failed. TypeScript Type Check is
an aggregator whose final step asserts every needs: lane succeeded, so cancelled lanes
make it report failure. Nothing was changed for it, and it is green on the new head.
pnpm --filter @objectstack/spec check:generated was run locally against the same tree
to make sure nothing generated had gone stale behind it — exit 0.

Final state on 92d1a709: 27 success, 6 skipped, zero non-green, including
Check Documentation Links, TypeScript Type Check and all four Type Check lanes.
Check Changeset is among the skipped — the skip-changeset label doing its job.

check:skill-examples, check:doc-formula-expressions and
check:doc-security-posture each first returned PREREQUISITE 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.properties is
an open record of string to unknown, so an os:check-yaml PageComponentSchema tag
validates the component node's own keys and not the props bag. Every rewritten
component's properties was therefore additionally dispatched through
ComponentPropsMap by hand, and all of them are accepted (custom.approval_timeline
excepted by design — an unregistered type has no entry). That audit caught one real
defect the tag could not: record:details.columns is the string enum "1"|"2"|"3"|"4",
so columns: 2 is refused; the Customer 360 example writes columns: '2'. Filed as
a follow-up finding, since the gap is the gate's, not this page's.

Changeset

None, and skip-changeset is applied: the diff is a single file under
content/docs/**, which no package publishes, so this PR declares no release of
its own — the exemption's stated meaning in pr-automation.yml. Same shape as the
recent docs/tooling PRs #13199 and #13202, which landed without one.

Fixes#13266


Generated by Claude Code


Generated by Claude Code

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.
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 30, 2026
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
os-project-manager marked this pull request as ready for review August 30, 2026 04:16
@os-project-manager
os-project-manager added this pull request to the merge queueAug 30, 2026
Merged via the queue into main with commit 63cf416Aug 30, 2026
38 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13266-layout-dsl-untrue-fences branch August 30, 2026 04:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] layout-dsl.mdx: most of the 17 still-untagged YAML fences teach shapes the live schemas refuse (per-fence readings attached)

2 participants

@os-project-manager@claude