Skip to content

page renderer: retire the stack-the-rest branch for authored regions once the spec declares each template slots (objectstack#23610 Q2 A follow-up) #12476

Closed

Description

@objectstack-fleet

Blocked-by: #12626

Blocked-by: objectstack-ai/objectstack#23610

Filing gate: a follow-up bound by a maintainer ruling, objectstack#23610 batch #349 item 2, letter Q2 A (ruling comment 6190536588 on that card, item 5). Filed by the director seat (summon #42, session_01AKVFxqmRLqktJspVXwPE9A). ⛔ Not a claim.

What the ruling binds upstream

@objectstack/spec closes PageSchema.template to the renderer's registered names and declares each template's slots (default: header, sidebar, main, aside, footer; header-sidebar-main: header, sidebar, main; three-column: the five; dashboard: header, footer and an open grid). A region the chosen template will not place is refused at os validate and at save. full-width retires: it is the same component as default.

What this card does, after the spec lands and the pin moves

  • packages/components/src/renderers/layout/page.tsx (read on origin/main cf430cd10e): the stack-under-main branch for unplaced regions (getRemainingRegions at :285, :384, :417) becomes unreachable for authored pages; retire it for the slotted templates (dashboard keeps its open grid by design) and drop the full-width row of TEMPLATE_REGISTRY (:475).
  • Pins move from "an unknown region is stacked" to "an unknown region or template is refused upstream"; the renderer keeps no fallback for a shape the spec refuses.

Reader who acts: objectui triage (grade and route), then domain:ui. Order: after objectstack#23610's execution PR lands AND @objectstack/spec with the refusal is installable at objectui's pin (the cross-repo unlock is "the consumer can install", not "merged upstream").

Dedupe (objectui open domain:ui titles read for template, region, getRemainingRegions and stack in this act): none names this branch.

Activity

  1. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock: pm:blocked → pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T04:07Z

    • The condition: Blocked-by: objectstack-ai/objectstack#23610, closed at 2026-10-16T03:01Z with PR #23708 (a69a40a572). That merge is in 18.0.0-next.2's build e5136ff10f (REST compare: ahead), so the fix is installable, read in this act.
    • p3, so it queues behind the p1 and p2 work.
    • Grade, lane and scope are unchanged.

    ⛔ Not a claim.

  2. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Blocked-by: re-pointed: #12629 (closed, a duplicate) → #12626, the next.2 bump in flight · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T07:58Z

    ⛔ Not a claim.

  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock scan: pm:blocked → pm:queue · the refusal is installable · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T12:01Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Serial behind objectui#12624 · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-16T14:36Z

    ⛔ Not a claim. This card stays pm:queue at p3.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 16, serial (priority:p3; maintainer ruling objectstack-ai/objectstack#23610 Q2 A, 6190536588 item 5)
    Session: session_011K9g23W67dy2zwnyzaoB6o
    Account: os-tesla
    Branch: claude/issue-12476-page-template-slots
    Worktree: objectui-issue-12476 (in the cloud session's own container)
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: the card's "What this does", against @objectstack/spec 18.0.0-next.3 (objectui main d2b21a1's lockfile), which closes PageSchema.template to default, header-sidebar-main, three-column and dashboard, declares each one's slots (PAGE_TEMPLATE_SLOTS) and refuses an unplaced region at validate and save.

    • packages/components/src/renderers/layout/page.tsx (main d2b21a1):
      • the stack-under-main branch for regions a slotted template does not place (getRemainingRegions, :94; used at :310 in RegionLayout, :409 in HeaderSidebarMainTemplate, :442 in ThreeColumnTemplate) is retired for authored template pages;
      • the full-width row of TEMPLATE_REGISTRY (:501) is dropped;
      • dashboard keeps its open grid (:480), by the ruling.
    • RegionLayout is also the body of the pageType dispatch (record, home, app, utility; :520–:544). Those paths are not template pages; what they do with an unnamed region stays as it is unless the dev measures that no caller reaches it, and either way the report says which callers were read.
    • Pins beside the page renderer move from "an unplaced region is stacked" to what the retired branch now does; the 12-column block grid in the placed regions (objectui#12624, PR feat(components): page regions lay blocks on a 12-column grid with kind-derived spans; the page description sits under its title #12734) and the narrow-region compact list (objectui#12703) stay pinned.
    • One .changeset/12476-*.md for @object-ui/components.

    Outside the surface:

    • @objectstack/spec and its migration (objectstack, already shipped in 18.0.0-next.2);
    • skills/objectstack-ui/rules/pages.md (the ruling's separate Tier H PR) and the HotCRM memo;
    • the pageType dispatch's own region handling, beyond reading its callers;
    • a second region filling an already-filled slot (also refused upstream; the renderer's first-match findRegion is not this card).

    A route outside the surface stops and reports (stop on breach; explain in the report).
    Container & model: S, mode:cloud, model: opus (default tier; no path-derived mandate)
    Clause-②: no (narrowing)
    Clause-② reason: the page renderer is a published component of @object-ui/components, and PageNodeSchema.regions[].name in @object-ui/types is a string. Retiring the stack branch narrows the renderer's accept set to the names each template places, matching the spec's refusal. No prop, export or pack key is added, so the PR owes one CONTRACT_REVIEW_TIER review for the narrowing. The dev re-measures this: if the published type already excludes the retired shapes, the declaration becomes no, with the evidence.
    Responsibility: (1) objectui's own code: the renderer keeps a fallback for a shape the spec now refuses, so a page the spec rejects would still draw | (2) the platform half is done: objectstack-ai/objectstack#23610's PR #23708 refuses an unplaced region and retires full-width, installed at objectui's pin | (3) every authored page with a template; the ruling's follow-up item 5 names this card
    Thread-read: 6217841173
    Serial constraints cleared: read at objectui main d2b21a1. objectui#12624 (this seat's serial note 6217841173) landed, and so did objectui#12703 (a8add5c). No open PR names page.tsx. The seat holds no other card in flight (serial mode); objectui#12778 landed in 6235317967.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 12476,
      "status": "done",
      "branch": "claude/issue-12476-page-template-slots",
      "pr": 12901,
      "session": "session_01KduCFcSEActo1Znrb6DLqw",
      "premise_still_valid": true,
      "summary": "page.tsx: the default, header-sidebar-main and three-column templates no longer stack a region they do not place. They draw it nowhere and show a visible refusal (data-page-refusal=unplaced-region) in the main column, naming the region and the template's PAGE_TEMPLATE_SLOTS. TEMPLATE_REGISTRY is now Record of the spec's PageTemplate (imported from @objectstack/spec/ui) and drops full-width; FullWidthTemplate is renamed DefaultTemplate. A template name the registry does not hold (full-width, two-column, a prototype key like constructor) draws a refusal (data-page-refusal=unregistered-template) instead of silently falling back to the pageType layout. dashboard's open grid, the 12-column block grid and the compact-region posture are unchanged, and so is the pageType dispatch, which still stacks. Hypotheses: H1 confirmed at d2b21a1 (:94, :310, :409, :442, :480, :499-501); full-width and default were the same component, so there was no fork to report. H2 confirmed: installed spec 18.0.0-next.3 carries PAGE_TEMPLATE_SLOTS, PAGE_TEMPLATE_OPEN_GRID, the closed PageTemplateSchema and checkPageRegionPlacement. H2 PARTLY FALSIFIED on the migration: 18.page-template-closed-region-unplaced-refused rewrites only full-width to default on read. A stored row with an unplaced region is 'served unchanged and renders as before', not migrated, so the H4 fallback is reachable by real stored rows. That is why the loud refusal was chosen over drawing nothing. H6: SpecPage['template'] already excludes full-width in the published type, but regions[].name is a string, so the declaration stays 'no (narrowing)'. The maintainer ruling comment 6190536588 was NOT read: objectstack REST and the issue page both answer 403 from this container. Item 2 was taken from the brief's quote and the upstream source's citations of the same record.",
      "tests": "Run at 572fd84. New file packages/components/src/__tests__/page-template-slots-12476.test.tsx: 16/16 pass. It pins each slotted template refusing unplaced regions (default: left_sidebar, content; header-sidebar-main: aside, footer, right_sidebar; three-column: left_sidebar, right_sidebar), default with no placed region, and full-width / two-column / constructor drawing the unregistered-template refusal. CONTROLS: every placed slot draws on grid-cols-12; names place case-insensitively; dashboard cells are [kpis, charts, main] with header and footer spanning; record/home/app/utility pages without a template still stack region_2. ABLATION at commit 5737745: page.tsx replaced with origin/main's blob (mutant hash dad6a91a = origin/main blob dad6a91a; UnplacedRegionsRefusal count 0 on disk) gives 7 failed and 9 passed. All 7 behaviour pins went red and all 9 controls stayed green. Restored with git checkout HEAD: hash c464da30 = HEAD blob c464da30, git diff HEAD empty, re-run 16/16. Relative import of ../renderers, so no dist leg. Moved pin: packages/types/src/__tests__/layout-default-jsdoc-7361.test.ts row 7 read /'default':\\s*FullWidthTemplate/ and now reads DefaultTemplate (rename only, same intent); 75/75. No existing pin asserted that an unplaced region is stacked. Families: 66 test files naming page.tsx, RegionLayout, getRemainingRegions, TEMPLATE_REGISTRY, data-template, three-column, header-sidebar-main or full-width under packages/ and apps/, plus the new file: 66 passed, 1447 tests, exit 0. pnpm --filter @object-ui/components test (foreground): 402 passed, 1 skipped files, 4036 tests, exit 0. Live reading: NOT MEASURED, reason: it would need the console dev server and a preview route seeded with a slotted page; not cheap in this run.",
      "gates": "Local subset at 572fd84, each exit captured before any pipe: pnpm --filter '@object-ui/components^...' build EXIT=0; pnpm --filter @object-ui/components type-check EXIT=0 (tsc --noEmit and tsconfig.test.json echoed); check:changeset-claims EXIT=0; changeset:check EXIT=0; check:test-path-roots EXIT=0; check:new-line-citations EXIT=0 (VERDICT 0 new citations); check:spec-symbols EXIT=0; node scripts/check-changeset-presence.mjs EXIT=0 (3 source files of 2 released packages, 1 changeset); eslint on the 3 changed source and test files EXIT=0 (0 errors; page.tsx's 8 warnings are all pre-existing, its origin/main blob has 9, and the new test has 0). Deviations: objectui has no scripts/pm/os-verify-lock.sh or dispatch-gates.mjs, so gates were hand-derived as the brief gives them and no --ran reconciliation exists. The CI farm is not cited because there is no PR yet: in_progress.",
      "mcp_calls": "3 — mcp__github__issue_read (get, get_comments on objectui#12476), mcp__claude-code-remote__add_repo (read; answered read_available, nothing attached). No write tool.",
      "api_writes": "0 — the only writes are two git pushes of the branch (empty probe at d2b21a1, then 572fd84).",
      "open_questions": [
        { "question": "H4: what the renderer does with an unplaced region on a slotted template.", "options": ["A loud visible refusal in the main column naming the region and the template's slots; content not drawn, never re-placed (taken)", "B draw nowhere, silently", "C keep stacking"], "recommendation": "A. Business need: stored rows with unplaced regions are served unchanged (the migration does not rewrite them), so B would silently delete live content and C keeps the mis-layout the ruling retires. Long-term: no fallback for a refused shape. AI-error axis: loud beats tolerant, so the author sees what to rename. Startup scope: one small component that reuses the html-tier compile-error styling, with no i18n key (matches the precedent and keeps Clause-② at no)." },
        { "question": "An unregistered template (full-width or any other name): refuse, or fall to the pageType layout?", "options": ["A refusal panel (taken)", "B silently fall back to the pageType layout (what deleting the row alone would do)"], "recommendation": "A. The spec refuses it at parse and the card says the renderer keeps no fallback for a refused shape. No in-repo producer emits full-width (the caller sweep found none), and the server rewrites stored full-width rows to default on read." },
        { "question": "The pageType path (no template) still stacks unplaced regions, but the spec's checkPageRegionPlacement judges a template-less kind:full page as 'default' and refuses those regions too. Should it also refuse?", "options": ["A leave as is (taken, per brief: do not change a path without measuring that nothing reaches it)", "B refuse there as well in a follow-up"], "recommendation": "A here. Real producers reach that path: PageView and PagePreview spread raw stored rows with no parse, Studio's addRegion writes region_N, and preview-samples. Changing it widens this card's surface. The PM may want a follow-up card for B." },
        { "question": "The upstream migration text 18.page-template-closed-region-unplaced-refused says a stored row with an unplaced region 'is served unchanged and renders as before'. After this lands it renders a refusal instead.", "options": ["A amend the objectstack migration text (an objectstack PR)", "B accept the drift"], "recommendation": "A, since the ruling (renderer keeps no fallback) outranks that sentence. It belongs to the seat or objectstack, not this branch." }
      ],
      "out_of_scope_findings": [
        "class: c · reach: named producer: packages/app-shell/src/views/metadata-admin/previews/PageBlockCanvas.tsx:401 addRegion writes name region_N into the page draft, whose template is 'default' when Studio-seeded (anchors.ts:207-221) or absent. The spec refuses either case at save (checkPageRegionPlacement treats absent as default, 422 INVALID_METADATA), so Studio's own 'Add region' button authors metadata the save door rejects. With this change a template:'default' draft shows the refusal in preview. · evidence: PageBlockCanvas.tsx:399-403, spec page.zod.ts checkPageRegionPlacement · dedupe words: PageBlockCanvas addRegion region_ unplaced region save refused",
        "class: b · reach: exception: release-text · objectstack migration 18.page-template-closed-region-unplaced-refused promises stored rows with an unplaced region 'render as before'; objectui#12476 makes that false · Seam: spec:18.page-template-closed-region-unplaced-refused → renderer: page.tsx UnplacedRegionsRefusal · dedupe words: unplaced region migration renders as before upgrade guide"
      ]
    }

    Posted by the domain:ui seat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filled pr with the draft PR it opened, #12901.

    The seat's answers:

    • The ruling the dev could not read: the seat read 6190536588 on spec: PageTypeSchema says home is "the platform-level landing page" and utility a "floating utility panel", but the landing is the first navigation item and both types render as ordinary inline pages objectstack#23610. Item 2 is as the brief quotes it, item 5 names this card ("retires the stack-the-rest branch for authored pages"), and nothing in it keeps a fallback for a refused shape.
    • Open question 1 (an unplaced region on a slotted template): A, as taken. The dev's measurement changes the premise: the migration does not rewrite such a stored row, so the shape does reach the renderer. Drawing it nowhere would hide live content without a word, and stacking is the mis-layout the ruling retires; a visible refusal naming the region and the slots tells the author what to rename. It is styled and worded like the html tier's compile error, the existing author-facing refusal on this page.
    • Open question 2 (an unregistered template): A, as taken. The spec refuses it at the parse, the server replays full-width → default on read, and falling to the pageType layout would draw a different layout than the one named.
    • Open question 3 (the template-less path): A here; the follow-up is filed as objectui#12902, together with the class c finding (Studio's "Add region" writes region_N, which the save door refuses on every template but dashboard), as one card for the two objectui positions of this family.
    • Open question 4 (the upstream migration text): A. The sentence is true until this PR lands, so the seat files the objectstack card with the ACCEPT, after the contract review.
    • The seat read the diff at 572fd84: 4 files, +304/−27, on the claimed surface (page.tsx, one new test, one moved pin in @object-ui/types' test tree, one changeset).
      • TEMPLATE_REGISTRY is typed by the spec's PageTemplate, so the set cannot drift from the spec silently; the lookup guards prototype keys (constructor is pinned).
      • @object-ui/components already imports runtime helpers from @objectstack/spec/ui (resolveI18nLabel), so the new import is not a new dependency edge. Its declared floor, ^18.0.0-next.1, predates PAGE_TEMPLATE_SLOTS (added in next.2); the lockfile resolves next.3, and the floor has stayed at next.1 across the next.2 and next.3 bumps. Recorded, not changed here.
      • The pageType dispatch is unchanged, and its control pins record, home, app and utility.
    • Clause-②: no (narrowing) owes one CONTRACT_REVIEW_TIER review. The seat runs it on this head once CI reports, then writes the ACCEPT.

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-17T16:49Z


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions