Repository navigation
feat(spec)!: a page declares nothing the console does not honour — isDefault only on a bound record page, a closed template set, regions its template places - #23708
Conversation
… the registered set, refuse unplaced regions Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
…ir slots Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
… template as a literal Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
…ge-isdefault-template-slots
📓 Docs Drift CheckThis PR changes 3 package(s): 26 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 12 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 143 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin bdae71e3b7dcc154515bfc7787b8c3f64bbf40a0 && git checkout bdae71e3b7dcc154515bfc7787b8c3f64bbf40a0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 29c7157af4fed4738b3da14bbfb008496cbd1f6a d36a804054a170573b12506d797277d6ecdba05f && git checkout -B drift-repro 29c7157af4fed4738b3da14bbfb008496cbd1f6a && git merge --no-ff d36a804054a170573b12506d797277d6ecdba05f
node scripts/docs-audit/affected-docs.mjs --json 29c7157af4fed4738b3da14bbfb008496cbd1f6a
|
席位核对 — patch round, landing held ·
|
…y filled The renderer draws the first region of a name and excludes that name from the rest, so a second main (on dashboard, a second header or footer) was never drawn. Part of ruling 6190536588 Q2: a region the template will not place is refused. Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
…ge-isdefault-template-slots
Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Written 2026-10-15T23:29Z. Read-only, these inputs and nothing else: card #23610's body and all 13 comments; PR #23708's body, file list (29) and net diff against ① Derived judgmentsJudged against ruling 6190536588 (Q1 A · Q2 A · half 1) and the director's executor terms 6189618343. Q1 —
Q2 — the closed template set. RIGHT.
Half 1. RIGHT. The Public surface. RIGHT. New exports objectui#12585 —
② Semver levelobjectstack
objectui
③ Boundary flagsDev report 6198386632 (objectstack, round 1).
Dev report 6200739195 (objectstack, patch round).
Dev report 6204227787 (objectui).
Coupling plan — sufficient for the pinned console? YES on what was read, with the serialisation above.
Implemented-by: VERDICT: PASS Generated by Claude Code |
…ge-isdefault-template-slots
… the default template) Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TC6DKN349m4i7okGWPe4RG Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Written 2026-10-16T01:55Z. A DELTA record: the full review PASSED on ① Derived judgmentsThe merge The PR's own delta: 4 files, +25/−7, and nothing else. Does the pin move carry the owed objectui fix (AGENTS.md Post-Task Checklist step 4)? YES — RIGHT. Does Is the lockstep re-record byte-faithful (no port owed)? YES — RIGHT. The SDUI manifest re-record. RIGHT. ② Semver level
The PR's existing changeset
③ Boundary flagsDev report 6205895856 (patch round 2, this head).
Flags of the PASS record
What is measured only after landing. Implemented-by: VERDICT: PASS |
Part of #23610
Clause-②: yes (narrowing)
Executes ruling
6190536588items 1, 2 and 3 (Q1 A · Q2 A, plus half 1) under claim6194235384. Item 4 (skills/objectstack-ui/rules/pages.md) is a separate Tier H PR (claim6204703954). That PR carries the card's closing keyword, so this one isPart ofand the card closes with its last piece; item 5's follow-ups (the objectui card, the hotcrm memo) belong to the director seat. One PR, not split: +1055/−100 across 33 files after patch round 2 (pin bump included), generated artifacts included, about two of precedent #23331's size for two refusals, as the ruling's workload line estimated.What changes
Q1 —
isDefault: trueoff a record page bound to an object is refused at every door. One sentence,misplacedDefaultPageRefusal(packages/spec/src/ui/default-record-page.ts, next todefaultRecordPageObject, whose reading it reuses — no second judge). It names where a landing is really set: the app's first navigation item, and the app's ownisDefaultfor the root landing. A record page with noobjectgets the bind-the-object variant.Q2 —
templatecloses and each template declares its slots.PageTemplateSchema=default,header-sidebar-main,three-column,dashboard;full-widthis retired by name throughenumWithRetiredValues(prescription: usedefault, renders the same).PAGE_TEMPLATE_SLOTSdeclares the slots per the ruling;PAGE_TEMPLATE_OPEN_GRID=dashboard.checkPageRegionPlacementrefuses, atregions.N.name, a region the template does not place, naming the template's slots and a rename hint (left_sidebartosidebar,right_sidebartoaside,contenttomain). Judged onkind: 'full'pages only (aslottedpage renders itsslots,html/reacttheirsource) and case-insensitively, as the renderer'sfindRegionis. A second region that fills a slot an earlier region already fills is refused the same way, naming the region that fills it, becausefindRegionplaces the first match only. This came in the seat's patch round (record6199121442item 2). Ondashboard, a secondheaderorfooteris refused; two regions of any other name stay two grid cells.Half 1 — the text says what runs.
PageTypeSchema's docblock and enum comments:home,appandutilityare one region layout at three content widths;homeis not a landing declaration;utilityis an ordinary inline page with no floating or docked shell slot, and stays a type because the print door and the page-type width read it. Theprint-on-utilityrefusal no longer says "floating panel" (its pin inpage-print.test.tsnow also asserts the word is gone).content/docs/ui/pages.mdx(page types, a Templates table, theisDefaultrow, the region snippet'scontenttomain), and the livenesstype,template,regions,isDefaultrows (re-read at objectui0656b0e3c0).Door by door (PM mechanism assumption 1, measured)
PageSchema?definePage/defineStack(stack.zod.ts,pages: z.array(PageSchema)), soos validate/os buildsuperRefines refuseSTACK_SCHEMA_INVALID422 atpages.N.isDefault/pages.N.template/pages.N.regions.M.name(page-default-and-region-placement.test.ts,stack-default-record-page.test.ts)saveMetaItem,getMetadataTypeSchema('page'))422 INVALID_METADATA, nothing stored, both topologies (default-record-page-save-door.test.ts)SchemaRegistry.installPackage)refuseDefaultRecordPageConflictsfirst refuses misplaced defaults (misplacedDefaultPages, same sources asdeclaredDefaultRecordPages, nestedplugins[]included), ahead of every mutationMisplacedDefaultPageError,INVALID_METADATA422 (existing code, no new one), no package record left (registry-default-record-page.test.ts)registerItemwith apackageId)registerItemwith no package:sys_metadatahydration)corestack-organization-record-page.tsdefaultRecordPageObject, not a doorcoresuite greenQ2's refusals are parse-only (the ruling names
os validateand save), so the registry carries no template or region judgement.Stored metadata (assumption 4, measured)
No D2 conversion touches these shapes and the read path does not refuse them: a
sys_metadatapage row laid in the store with a non-recordisDefault: true,template: 'full-width'or aleft_sidebarregion is served bygetMetaItemunchanged, on both the environment-scoped and the host-config kernel; saving it again answers 422.applyConversionsToStoredItemreturns each row byte-equal with zero notices, and the parse still refuses it. The changeset's "Stored metadata keeps loading" paragraph states exactly this.First-party writers (assumption 5)
examples/app-showcase/src/ui/pages/capability-map.page.tsdropsisDefault: true; it stays the landing as the firstShowcaseApp.navigationitem.content/docs/protocol/objectui/layout-dsl.mdx: threeos:check-yamlpages namedtemplate: standard/console(withleft/rightregions), red undercheck:yaml-examples— nowdefaultandheader-sidebar-mainwithsidebar/main; the callouts that calledtemplatea free-form string are corrected.examples/app-showcase/src/ui/pages/task-visualizations.pages.ts: its shared base heldtemplate: 'default'as a widenedstringand stopped type-checking against the closed set (+7 root-program errors undercheck:type-check-debt); nowas const. The changeset carries the same one-line migration for consumers.full-widthor an unplaced region in source. Census:full-widthin two test fixtures only; everyregionsentry inexamples/**,packages/**,content/docs/**read by name (main 226, header 40, sidebar 9, footer 4, aside 1, the rest test-only).Fixture triage (rule's consumption radius, not the edited package):
stack-default-record-page.test.ts"an isDefault page that is not a record page is outside the rule",registry-default-record-page.test.tssame,default-record-page-save-door.test.tssame — each now asserts the refusal, with a no-flag control beside it.page.test.ts"should accept page with custom template" (three-column-layout) and "should accept default page" (noobject).buildDefaultPageSchemaseed fixtures (specandlint*-22537.test.ts) fromfull-widthtodefault, with a note.expression-scope-app-root.pin.test.ts's LIT control quoted the old page-type sentence.object-refinement-check-exports.test.tscatalogues the two new checks (bijection, attached-by-identifier, barrel identity).Renderer premise (assumption 3, re-read)
objectui
mainat0656b0e3c0(and the sparse read at2bacbf08b4):TEMPLATE_REGISTRYstill holdsdefault,full-width,header-sidebar-main,three-column,dashboard;defaultandfull-widthare the sameFullWidthTemplate, so no rendering fork and nothing was posted on the card for it. Slots match the ruling's table;findRegionis case-insensitive, which this PR follows.One premise did not hold — "zero first-party writers" of
full-width. objectui'spackages/plugin-detail/src/synth/buildDefaultPageSchema.tsreturnstemplate: 'full-width', and Studio's record-page create seed (app-shell/src/views/metadata-admin/anchors.ts,createSeed) copies it into the page it saves. Retirement proceeds as ruled (identical rendering, no alias window), but that seed must saydefaultbefore or with the pin bump that ships this, or a Studio "new record page" save answers 422. objectui'sPageNodeSchemaalso redeclaredtemplateasstringover the spec member, which is TS2430 against this spec (measured on a mirror, report6200739195). Both are fixed in objectstack-ai/objectui#12585, the sibling fix that AGENTS.md (Post-Task Checklist step 4) ships with this PR.Ledger
Two D3 entries,
page-is-default-off-record-page-refusedandpage-template-closed-region-unplaced-refused; no D2 conversion (ruling: no grace or alias window); no tombstone (no key removed). NoSTEP18_RATIONALEfragment was added: neither precedent entry forisDefaultcarried one, and draft PR #23418 is editingregistry.ts.template. BREAKING changeset.changeset/23610-page-isdefault-template-slots.md:@objectstack/specminor,@objectstack/objectqlpatch, ADR-0087 markerregisterednaming both ids. New exports regenerateapi-surface/,export-origins/,declaration-map/andcontent/docs/references/. The template block sits afterPageComponentSchemaon purpose, soskills/objectstack-ui/references/_index.md(first five exports of the file) stays byte-identical and noskills/**path enters this PR.Verification (final head
4815bfa99, after mergingorigin/mainf77ba411e)@objectstack/spec: 742 files / 21,868 tests passed.check:generated: all 14 artifacts current.objectql8,157,metadata-protocol20,560 (19 skipped),core2,586,lint6,771,metadata-core728,platform-objects1,091,plugin-approvals1,080,cloud-connection555,mcp467,downstream-contract31,example-showcase411,example-crm46,cliunit 4,354 (integration layer declared to CI).objectql,metadata-protocol,example-showcasere-run on the final head after the merge.typecheckgreen for spec, objectql, metadata-protocol, core, lint, cli, platform-objects, plugin-approvals, cloud-connection, mcp, downstream-contract, example-showcase, example-crm; root program back to its ledger's 26.dispatch-gates --commands, 119 families) on the final head: all exit 0;--ranreconciliation "119 derived, 119 run, 0 NOT-MEASURED (a DERIVED zero)". Two families first refused on the shallow clone (check-engine-split-ratio,check-plugin-teardown-shape --self-test) and passed after the deepening they prescribe. Local-only:check:dev-prereqs0,check:skill-frame-freshness0.ablation-replace.mjs, mutation proven on disk, restore proven by an emptygit diff HEAD): dropcheckPageDefaultPlacement8 red; dropcheckPageRegionPlacement4 red;templateback toz.string()5 red; drop the package-door throw 1 red (the item seam still catches the top-level pages; the nested-plugin and no-record pin goes red); drop the item-seam throw 1 red.template: 'full-width'in a showcase page givesTS2322 … not assignable to type '"dashboard" | "default" | "header-sidebar-main" | "three-column"', so the rebuilt.d.tswas read.Landing order
defaulttemplate and type the pagetemplateby reference to the spec objectui#12585 merged on objectuimainasdaeb77fc84dd. The Studio record-page seed saysdefault, andPageNodeSchema.templatetakes the spec's type in both the TS and zod faces.d36a804054):mainat140238a47b, after chore(objectui): move the console pin to f96f771140f1, carrying objectstack-ai/objectui#12453 and objectstack-ai/objectui#12519 #23738 had moved the pin tof96f771140f1.scripts/bump-objectui.shmoved.objectui-shaforward todaeb77fc84dd, which carries test(spec,drivers): add the VALUE_ROUNDTRIP conformance case-set — what you wrote is what you read back, per driver per dialect #12585, and wrote.changeset/console-daeb77fc84dd.md(@objectstack/console: minor).scripts/sdui-manifest.record.jsonandpackages/sdui-parser/objectui-lockstep.jsonare re-recorded at the new pin.sdui.manifest.jsonis byte-unchanged, and the lockstep needs no port.6206263948(the full PASS6204434889onc2b9935b4stands for everything it judged). The seat then marks this PR ready.Fixes #23610) is marked ready, and fix(spec): page.print and the flow terminal-toast translations read live in the liveness ledger, so a print page is no longer warned that nothing applies it #23776 (spec liveness: the console pin hop to objectui 1f23d5b070fa makespage.printandtranslation.flows.successMessage/errorMessagereadplannedwhile the shipped console applies them (family card; theparentDataSourceleg is #23585) #23710) mergesmainand lands after it (landing-operations D).Patch round (head
c2b9935b4,origin/main8c85141c5merged)@objectstack/spec: 742 files / 21,876 tests passed. The downstream consumer set is unchanged and green. The duplicate-slot ablation (the branch never fires) gives 6 red of 285; restored.dispatch-gates --commands: 119 families, 119 exit 0 (twoPREREQUISITE NOT METexits on a fresh worktree passed after the full build).check:generated14/14. CI onc2b9935b4: 41 check-runs, 36 success, 5 skipped.Acceptance notes
main) were accepted and the second was dropped by the renderer. They are now refused in this PR (patch round,c2b9935b4).skills/objectstack-ui/rules/pages.mdrows for the Tier H follow-up are listed in the dispatch report on spec:PageTypeSchemasayshomeis "the platform-level landing page" andutilitya "floating utility panel", but the landing is the first navigation item and both types render as ordinary inline pages #23610.Generated by Claude Code