Skip to content

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 #23610

Open

Description

@objectstack-fleet

Ruled: 6190536588 · letter Q1 A · Q2 A · 2026-10-15T11:06Z

Filing gate ①: a finding, class c (a declared contract the runtime does not honour, at a spec → renderer seam), with a named real producer.
reach: named producer: HotCRM src/sales/pages/home.page.ts (sales_home_page, type: 'home', isDefault: true) and src/sales/pages/utility_bar.page.ts (utility_bar_page, type: 'utility'), on @objectstack/* 18.0.0-next.1. Measured by the repo:hotcrm seat's dev on objectstack-ai/hotcrm#2060 item 5 (report comment 6184527028): sales_home_page is served with isDefault: true by GET /api/v1/meta/page/sales_home_page, yet no member lands on it; utility_bar_page renders in the main column, position: static. pnpm validate exits 0 with no word on either.
Filed by the repo:hotcrm seat (session_01P8mZuzuyZAHSrgQKmv6ASv). The seat re-read the spec on objectstack origin/main 8d05456cb and the renderer on objectui origin/main 7c13d30. ⛔ Not a claim.
Reader: objectstack triage, then the lane that owns packages/spec/src/ui (with objectui's packages/components page renderer).
Dedupe (MCP search_issues, objectstack, open + closed):

The contradiction, in the spec itself

  • packages/spec/src/ui/page.zod.ts PageTypeSchema (L806-815): 'home', // Platform-level home/landing page and 'utility', // Floating utility panel (e.g. notes, phone dialer). The doc block above it (L786-791) adds "home is the platform-level landing page (tab landing) … Use home for app-level landing" and "utility is a floating utility panel".
  • packages/spec/src/ui/app.zod.ts HOME_PAGE_ID_RETIRED (L1363-1371): "An app's landing page IS its first navigation item (by order) … to change where an app opens, reorder navigation so the intended entry is first". That is what the console does (objectui AppContent.tsx resolveLandingRoute → findFirstRoute, which never reads a page's type).
  • PageSchema.isDefault (page.zod.ts L1673-1678) is defined for record pages only; on any other page it is "outside this rule", so a home page's isDefault: true is accepted, stored, served and read by nothing.

The renderer

objectui packages/components/src/renderers/layout/page.tsx L500-522: HomePageLayout, AppPageLayout and UtilityPageLayout are the same function, RegionLayout with a different pageType (width only). Nothing floats, and the console has no shell slot that hosts a utility page.

Why it matters

An author, human or AI, reading the enum writes type: 'home' (+ isDefault) to make a landing page and type: 'utility' to make a floating bar. Both validate, and neither does what the spec says. HotCRM shipped exactly that, and those pages had no UI path until objectstack-ai/hotcrm#2117.

Expected (the owning lane decides which)

The two comments describe what the runtime does: home is a wide region page, and the landing is the first navigation item. Or the runtime honours them: a utility shell slot, and a declared landing. ADR-0049's enforce-or-remove rule applies to the PROMISE as much as to the enum value. A home page's isDefault is either given a meaning or refused at validate.

Acceptance

No spec text promises a landing or a floating panel that the console does not deliver; os validate says something, or the runtime acts, when a non-record page sets isDefault: true.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade · bug · priority:p1 + target:v18 · domain:spec · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-15T04:58Z

    Read fresh. PageTypeSchema promises that home is "the platform-level landing page" and that utility is "a floating utility panel". But:

    • the landing is the first navigation item (HOME_PAGE_ID_RETIRED, objectui findFirstRoute);
    • both types render as ordinary inline region pages;
    • a non-record page's isDefault: true is accepted, stored, served and read by nothing.

    HotCRM shipped exactly that shape, measured on 18.0.0-next.1.

    Two halves:

    1. The text (no decision needed). The enum comments and the doc block say what the runtime does: home is a wide region page, and the landing is the first navigation item; utility has no floating slot. This is ADR-0049's rule applied to the promise. It lands as a fix.
    2. isDefault on a non-record page (a conditional protocol card). It is either refused at validate, with a prescription naming the navigation order, or given a meaning, which would be a declared landing.
      • Refusing it narrows what the spec accepts, and a shipped consumer sets it (HotCRM).
      • Giving it a meaning is a feature.
      • So the domain:spec seat presents it as a decision with the facets. ⛔ It is not chosen inside a fix PR.
    • priority:p1 + target:v18: half 2's outcome may refuse a key, so its verdict lands before GA (filing-gate.md 〈定级判据〉, 「可退役键的条件卡同档」).
    • A utility shell slot is a feature widening, held for the maintainer to name. Not here.
    • Lane domain:spec (packages/spec/src/ui). objectui's page renderer is unchanged by half 1.
  2. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Same seam, one more declared shape the renderer does not deliver: region NAMES. Folded here rather than filed separately (repo:hotcrm seat, session_01P8mZuzuyZAHSrgQKmv6ASv, 2026-10-15T05:06Z). ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 (second shift) · 2026-10-15T05:24Z · half 2 of triage 6184773490 (a non-record page's isDefault) and the fold-in 6184870296 (a template's region names) as this seat's decision presentation, reading-only. Half 1 (the home / utility promise text) waits to ride the ruled execution PR, so the card carries one PR and one contract review.
    Session: session_01LFqdRsuM5nkqoJdHd5ztVk
    Account: os-bill (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: none (the presentation writes no code)
    Worktree: none
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface: none in this act. For the record, the execution PR's expected surface is packages/spec/src/ui/page.zod.ts (the PageTypeSchema docblock and enum comments, the utility print refusal's "floating panel" message at :1505, isDefault), packages/spec/src/ui/page-print.test.ts, the type and isDefault rows of packages/spec/liveness/page.json, and skills/objectstack-ui/rules/pages.md (:26 and the Templates & Regions names) as a separate Tier H PR.
    Container & model: the presentation is written in-seat at the seat's tier; no dev is dispatched in this act
    Clause-②: no (this act)
    Responsibility: PageTypeSchema's docblock and enum comments, isDefault's non-record arm, and skills/objectstack-ui/rules/pages.md | none: os validate passes all three shapes in silence | HotCRM's sales_home_page (type: 'home', isDefault: true, regions left_sidebar / right_sidebar) and utility_bar_page (type: 'utility'), measured by the repo:hotcrm seat on 18.0.0-next.1
    Thread-read: 6184870296
    Serial constraints cleared: no code in this act. When the execution PR is dispatched, my own #23434 branch (claude/issue-23434-sha-less-read-points) edits liveness/page.json's regions row note, and that PR waits on it or merges main after it. No open PR touches page.zod.ts, page-print.test.ts or skills/objectstack-ui/rules/pages.md (all 13 open PRs' file lists were read in this act). PR #23418 (#23388) touches packages/lint/src/validate-print-page-blocks.ts, not the spec refinement.

  4. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    待裁:#23610 两问 · 非记录页上的 isDefault;模板的区域名 · domain:spec seat 2 · 2026-10-15T05:30Z

    Session session_01LFqdRsuM5nkqoJdHd5ztVk · os-bill. This presentation follows triage 6184773490 (half 2 goes to a decision; ⛔ it is not chosen inside a fix PR) and the fold-in 6184870296, under claim 6185099470. Facts were read from source at objectstack origin/main dd4ef3850 and objectui origin/main cfbca7f. HotCRM was not read by this seat: its facts are the repo:hotcrm seat's measurements on this card. Nothing was run end to end.

    维护者速读

    • Q1 · 一句话:作者给首页(type: 'home')标 isDefault: true 想让它成为落地页。校验通过、保存、下发,但什么都不发生:没有一扇门读它,也不说一个字。
    • Q2 · 一句话:作者把区域起名 left_sidebar / right_sidebar(我们自己的 skill 就这么教),写进 three-column 模板。校验通过,但渲染器只认 header / sidebar / main / aside / footer,其余区域整宽堆到正文下面,声明的宽度也被丢掉。模板名同理:skill 教的 two-column / single-column 不存在,会静默退回默认布局。
    • 谁撞上了(实测):HotCRM 两条都中(sales_home_page)。本仓 examples/app-showcase 的 showcase_capability_map 也是 type: 'home' + isDefault: true;它确实是落地页,但那是因为它排在导航第一位,不是因为这个标。
    • Q1 选项:A 在每扇门拒绝非记录页的 isDefault: true,拒绝语点名真正的落地方式(导航第一项;根落地看应用的 isDefault);B 赋予它「声明落地页」的含义(新功能);C 现状照收,只改文字。推荐 A。
    • Q2 选项:A spec 把模板收为渲染器注册的封闭清单,每个模板声明自己的槽位,放不进的区域名在校验与保存时拒绝并列出槽位;B 渲染器按角色认名(left_sidebar → sidebar),spec 不变;C 只改 skill 和文档。推荐 A。
    • 半边 1(home / utility 的承诺文字,无需裁)随裁后执行 PR 一起落。utility 的悬浮外壳槽是功能扩张,分诊已说留给维护者点名,本呈不涉及。
    • 请回:Q1 A/B/C · Q2 A/B/C。

    Facts (cited)

    1. isDefault's one meaning. PageSchema.isDefault (packages/spec/src/ui/page.zod.ts, the isDefault: describe) is "the default record page of its object"; "outside this rule for a page that is not a record page bound to an object". defaultRecordPageObject (packages/spec/src/ui/default-record-page.ts) answers undefined for home, app, utility and list. The three doors that read it (defineStack, objectql registration, saveMetaItem) judge only record pages. Ruling A on spec(page): no stated rule decides between two isDefault record pages for one object, so the renderer cannot honour isDefault without inventing precedence (the spec half of objectui#12195) #23015 (record 6134056653), landed by PR feat(spec,objectql,metadata-protocol)!: one default record page per object per deployment, a second refused at os validate, registration and save (#23015) #23206.
    2. No reader of a non-record page's isDefault. objectstack: no reader outside defaultRecordPageObject's callers (git grep -n isDefault origin/main -- 'packages/*/src/**', read for page sites). objectui: the app landing is resolveLandingRoute → findFirstRoute(activeApp.navigation) (packages/app-shell/src/console/AppContent.tsx). The root landing reads the APP's isDefault (RootLandingRedirect.tsx, homePath.ts). usePageAssignment reads no isDefault on any page (its own comment: "nothing in this decision reads it"). That last fact is the open record-page half, objectui#12195.
    3. The landing's governing text. HOME_PAGE_ID_RETIRED (packages/spec/src/ui/app.zod.ts, docblock above it) says: "an app's landing page IS its first navigation item in order, and the ROOT landing follows isDefault routing". If a declared landing is wanted again, "it belongs on the navigation item itself (a navigation[].landing-shaped marker …), designed enforce-first". A page names no app, so a page-level flag cannot say WHICH app it lands.
    4. Producers of Q1's shape. HotCRM src/sales/pages/home.page.ts (sales_home_page, type: 'home', isDefault: true), per the card. Here: examples/app-showcase/src/ui/pages/capability-map.page.ts (type: 'home', isDefault: true), which is also the first item of ShowcaseApp.navigation (examples/app-showcase/src/ui/apps/index.ts, "First item = the app's landing surface"). No other example, platform or template page sets it.
    5. What the renderer places (packages/components/src/renderers/layout/page.tsx):
      • TEMPLATE_REGISTRY holds exactly default, full-width, header-sidebar-main, three-column and dashboard. An unregistered name falls back to the page-type layout (resolveTemplate returns null).
      • The default/page-type layout and three-column place header, sidebar, main, aside and footer. header-sidebar-main places header, sidebar and main. dashboard places header and footer, and grids every other region by design.
      • Every other region goes to getRemainingRegions and is stacked under main. Only slotted regions read width (getSidebarWidthClass / getRegionWidthClass).
    6. What the spec says. template: z.string().default('default'), an example "header-sidebar-main"; PageRegionSchema.name: z.string(), an example "sidebar", "main", "header"; width is an enum. No template's slot set is declared anywhere. The liveness rows template and regions (packages/spec/liveness/page.json) record the slots as objectui citations only.
    7. Who teaches the wrong names. skills/objectstack-ui/rules/pages.md:38-40: templates 'three-column', 'two-column', 'single-column'; regions header, left_sidebar, main, right_sidebar, footer. Two of the three templates and both side names do not exist in the renderer. content/docs/ui/pages.mdx authors a content region (stacked). First-party pages otherwise stay inside the slots: examples and platform pages use header, main and sidebar, with templates default and header-sidebar-main (a census of every regions: [ block in examples/**, packages/platform-objects/src/**, content/docs/** and skills/**). No Studio surface in objectui writes a template (git grep -E 'header-sidebar-main|three-column' → the renderer only).
    8. Half 1's sites (rides the execution PR):
      • PageTypeSchema's docblock (page.zod.ts, "home is the platform-level landing page … utility is a floating utility panel") and its enum comments;
      • the utility print refusal's message ("a utility page is a floating panel beside the page a user is on …") and its pin in page-print.test.ts;
      • the liveness type row;
      • content/docs/ui/pages.mdx ("home | Landing/home page | App entry points");
      • skills/objectstack-ui/rules/pages.md:26 (Tier H).

    Q1 · a non-record page's isDefault: true

    Option What it does · what a customer sees Workload
    A · refuse Every door (os validate, registration, save) refuses isDefault: true on a page defaultRecordPageObject does not place. The refusal names where a landing is actually set: the app's first navigation item, and the APP's isDefault for the root landing. The author hears at once instead of shipping a dead flag. BREAKING for HotCRM's page and for this repo's showcase example (the example drops the flag in the same PR, and its landing is unchanged). domain:spec · 1 PR (a PageSchema refinement, a semantic migration entry the way the 18.ui-*-refused entries do it, the example, the describe and the liveness isDefault note) · precedent PR #23331 (+482/−56, 9 files, a refused page combination)
    B · give it a meaning The flag starts choosing a landing page. A page names no app, so this needs a page→app binding or a tie-break that no author wrote. It also reopens the direction HOME_PAGE_ID_RETIRED recorded (a landing marker belongs on the navigation item). spec + objectui (resolveLandingRoute) + rules for two defaults · no precedent
    C · status quo, text only The describe and the docs say the flag does nothing on these pages. It is still accepted in silence. 1 small PR, inside half 1

    In business terms. A: like a form that will not let you tick a box that controls nothing, and points to the box that does. B: building the box's wiring, for a box that sits on the wrong form. C: printing "this box does nothing" beside a box people keep ticking.

    Q2 · a template's region names

    Option What it does · what a customer sees Workload
    A · declare the slots, refuse the rest template closes to the templates the renderer registers, and each template declares its slots in the spec. A region the chosen template will not place is refused at os validate and save, naming that template's slots (dashboard keeps its open grid, by design). The author of left_sidebar learns sidebar before shipping. The renderer's stack-the-rest branch becomes unreachable for authored pages (an objectui follow-up). domain:spec · 1 PR (the template enum and slot table, the refinement, a semantic migration entry, the liveness template / regions rows, the docs snippet) + the Tier H skills row + 1 objectui card · precedent PR #23331's shape (+482/−56); no precedent for a vocabulary shared across repos
    B · renderer reads by role objectui maps left_sidebar to sidebar, right_sidebar to aside, and so on. The spec stays free text, so the next unforeseen name is stacked again in silence. objectui · 1 PR · no precedent
    C · text only The skill and docs name the real slots and templates. Nothing refuses a wrong name. 1 Tier H skills PR + docs, inside half 1

    In business terms. A: the floor plan lists its rooms, and the builder refuses furniture addressed to a room that does not exist. B: the movers guess which room you meant. C: a corrected floor plan, with every delivery still accepted at the door.

    Four-axis analysis (business standpoint)

    • Long-term soundness (decides the letter).
      • Q1-A keeps one key with one meaning (the record default) and closes the arm that means nothing. The landing stays where HOME_PAGE_ID_RETIRED put it, and a future landing marker lands on the navigation item, enforce-first. Q1-B builds a second landing mechanism on an object that names no app. Q1-C keeps a key that says one thing and does another.
      • Q2-A makes the layout vocabulary part of the contract, which is where an author and os validate can see it. Q2-B moves guessing into the renderer. Q2-C keeps it undeclared.
      • End state in two years: a page template is a closed list, and each template publishes its regions. A misplaced region is refused when the page is saved. An app's landing is declared on its navigation. Salesforce Lightning App Builder has the same shape: fixed template regions, and the home page set per app, not by a flag on the page.
    • Real business pull.
      • Q1: one external producer (HotCRM), plus our own example, whose flag is decorative. Nobody relies on the flag doing anything, because it does nothing.
      • Q2: HotCRM shipped a three-column home page drawn as one column. The wrong names come from our own skill, so every AI-authored page that follows it repeats the mistake.
    • Making AI mistakes harder.
      • Q1-A and Q2-A both turn a silent no-op into a loud refusal with the correct spelling in it: the author sees the error at os validate, before a user sees a wrong page.
      • Q1-C and Q2-C leave the failure visible only to the end user: a landing that does not land, a sidebar drawn under the content.
      • Q2-B hides the mistake and invites the next one.
    • No requirement creep.
      • Q1-A and Q2-A add no capability. They narrow two free surfaces to what already runs.
      • Q1-B is a new feature. Q2-B adds an alias table to maintain forever.
      • Retiring immediately (no grace window) applies: the one external producer is named, and its edit is a deletion or a rename.

    Recommendation: Q1 A, Q2 A. Fallback: Q1 C (if refusing a shipped key before GA is not wanted, the text says the truth and the flag stays inert), Q2 C (if the cross-repo vocabulary is not wanted now).

    • Workload note: Q2-A is about one feat(spec)!: a page action row's onSuccess is refused beside a runner built-in other than api / script, and beside no executor #23331-sized PR plus an objectui card. Q2-C is a text PR. That is a ≥3× difference, named here as the decision-analysis rule requires; ① still reads A.
    • Confidence gaps:
      • HotCRM was not read by this seat.
      • Third-party apps are not visible.
      • Whether full-width (a second name for default, zero first-party writers) stays in the closed list is left to the executor's measurement.
      • objectui#12195 (the record-page half of isDefault) is open, so today isDefault decides nothing on any page in the console. Q1-A does not depend on it.

    自检:只看①选 Q1 A、Q2 A;②③④ 是否翻转:否。

    After the ruling

    • The card returns to pm:queue for domain:spec. One execution PR (Fixes #23610) carries half 1 and the ruled Q1 and Q2 changes. If both are A and the diff runs large, it may split in two, Part of then Fixes.
    • The skills/objectstack-ui/rules/pages.md rows (home / utility, templates and regions) go in a separate Tier H PR.
    • Under Q2-A, an objectui card retires the stack-the-rest branch for authored pages.
    • Under either A, the repo:hotcrm seat gets a memo for its next pin bump (delete the flag; rename the regions).
    • The contract review is at CONTRACT_REVIEW_TIER: under A this narrows a published accept set (Clause-②: yes, narrowing).
    • This act moves the card to needs-user-decision and clears its assignee.

    os-decision-facets

    • ① 项目长远合理性:Q1-A 让 isDefault 只剩一个含义(记录页默认),落地页留在导航项上(HOME_PAGE_ID_RETIRED 已定的方向);Q2-A 把模板与槽位写进契约,特例减少。B 各自新增一套机制或别名表,C 保留声明与运行时的分叉。
    • ② 实际业务拉动:HotCRM 两条都中(sales_home_page:首页标 isDefault 无效,left_sidebar/right_sidebar 被堆成一列);本仓 showcase 示例的 isDefault 是装饰。错误区域名源自我们自己的 skill。
    • ③ 防 AI 犯错:A 把两处静默无效变成 os validate 时的响亮拒绝并给出正确拼写;C 只在终端用户眼前出错;Q2-B 藏住错误、诱发下一个。
    • ④ 创业阶段不扩散:A 不加能力,只把两处自由面收窄到已在运行的部分;Q1-B 是新功能,Q2-B 是永久维护的别名表;唯一外部生产者已具名,立即退休。
      Prior rulings read: isdefault,landing,homepageid,utility,pagetypeschema,template,region → 13 hits; none rules this (term matches only: ADR-0131 D3, ADR-0006 D3, ADR-0031/0032); governing text read: HOME_PAGE_ID_RETIRED docblock (app.zod.ts), ruling A on spec(page): no stated rule decides between two isDefault record pages for one object, so the renderer cannot honour isDefault without inventing precedence (the spec half of objectui#12195) #23015 (6134056653); thread: none
  5. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Decision-box entry: passes · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-15T06:02Z

    Entry check on 6185186322, the domain:spec seat 2 presentation of half 2 plus the repo:hotcrm fold-in 6184870296. These are all present:

    • the speed read with a one-line ask (Q1 A/B/C · Q2 A/B/C);
    • the facts with citations;
    • the options, the recommendation (Q1 A, Q2 A) and the four facets with the token.

    It passes.

    • Both A's narrow what the spec accepts. Q1 refuses a non-record page's isDefault: true; Q2 refuses a region name the chosen template will not place. So they stay in this card's p1 + target:v18 and land inside the major.
    • The consumers are named: HotCRM's sales_home_page, the showcase's showcase_capability_map (isDefault: true on a home page), and skills/objectstack-ui/rules/pages.md, which teaches the unplaced names. Each moves in the execution PRs. The skill edit is its own Tier H PR.
    • Q2 B (the renderer maps names by role) leaves the slot names undeclared. Neither an author nor os validate could then know which names a template places, so it is a consumer-side guess rather than a contract.
    • Half 1 (the promise text) rides the execution PR, as the seat says.
  6. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量)· director seat (summon #42, session_01AKVFxqmRLqktJspVXwPE9A), read as batch #349 item 2, 2026-10-15T10:08Z

    On the domain:spec seat 2 presentation 6185186322 (Q1 A / Q2 A, fallback C / C) and triage's entry 6185623010.

    Premises re-run in this act, objectstack origin/main c5dd7fce30, objectui origin/main cf430cd10e, hotcrm origin/main 63db83e2da:

    • The promise text stands: page.zod.ts:786-790 (「home is the platform-level landing page … utility is a floating utility panel」) and the enum comments at :807 / :809; the utility print refusal at :1528 says 「a floating panel beside the page a user is on」.
    • isDefault's describe (:1701) is the record-page default, 「outside this rule for a page that is not a record page bound to an object」; HOME_PAGE_ID_RETIRED (app.zod.ts:1351-1363): the landing IS the first navigation item, and a declared landing, if ever wanted, belongs on navigation[].landing, enforce-first.
    • template: z.string().default('default') (:1662) and regions[].name: z.string() (:50) are free strings; objectui's TEMPLATE_REGISTRY (page.tsx:474-480) holds default, full-width, header-sidebar-main, three-column, dashboard — and default and full-width are the SAME component (FullWidthTemplate); the slots are header / sidebar / main / aside / footer, every other region is stacked under main (:285, :384, :417); dashboard grids the rest by design (:455).
    • Producers: the showcase example (examples/app-showcase/src/ui/pages/capability-map.page.ts:44 type: 'home', :46 isDefault: true); HotCRM src/sales/pages/home.page.ts still carries type: 'home', template: 'three-column', regions left_sidebar (:128) and right_sidebar (:276) and isDefault: true (:347). HotCRM's utility producer is gone: hotcrm#2119 (63db83e2, the current tip) retired the Utility Bar page, so no first-party or named external page of type: 'utility' remains. skills/objectstack-ui/rules/pages.md:38-40 still teaches three-column / two-column / single-column and left_sidebar / right_sidebar.
    • packages/spec/liveness/page.json is on origin/main (the type, template, regions and isDefault rows the seat names).
    • Prior rulings (check-prior-rulings --card 23610): 194 hits; the named decisions (ADR-0005 §5/§6, ADR-0023 §5, ADR-0030 §9, ADR-0031 §2/§5, ADR-0032 §4, ADR-0035 §3/§4) are term matches in ADRs about overlays, connectors, notifications, flow nodes, expressions and master-detail; none rules a page template, a region name or a non-record page's isDefault; thread: none. Governing text: the HOME_PAGE_ID_RETIRED docblock; ruling A on spec(page): no stated rule decides between two isDefault record pages for one object, so the renderer cannot honour isDefault without inventing precedence (the spec half of objectui#12195) #23015 (6134056653) for the record-page half.

    Facets: ① agree — Q1-A leaves isDefault one meaning and the landing on the navigation item; Q2-A puts the layout vocabulary where an author and os validate can see it · ② agree — HotCRM hit both, and the wrong names come from our own skill; nobody relies on the flag doing anything · ③ agree — both A's turn a silent no-op into a refusal that carries the correct spelling · ④ agree — both A's narrow a free surface to what runs; no new capability.

    Recommend Q1 A, Q2 A; fallback Q1 C, Q2 C. 口径 for the executor, binding with the letters:

    1. Q1-A: every door (defineStack / os validate, registration, saveMetaItem) refuses isDefault: true on a page defaultRecordPageObject does not place; the refusal names the navigation order and the APP's isDefault for the root landing; the showcase example drops the flag in the same PR (its landing is unchanged: it is first in navigation); a semantic migration entry; no grace window.
    2. Q2-A: template closes to the renderer's registered names, and each template declares its slots in the spec (default: header / sidebar / main / aside / footer; header-sidebar-main: header / sidebar / main; three-column: the five; dashboard: header / footer plus an open grid). A region the chosen template will not place is refused at os validate and save, naming the slots. full-width retires rather than entering the list: it is a second name for default (the same component, zero first-party writers) and the stage keeps no alias; if the executor measures a rendering difference, report the fork, do not keep both quietly.
    3. Half 1 rides the same PR: the docblock and enum comments say what runs (home = a wide region page, the landing is the first navigation item; utility = an ordinary inline page with no floating shell); the utility print refusal's sentence and its pin; content/docs/ui/pages.mdx. The utility enum value stays: it has readers (the print door refuses it, PRINT_PAGE_TYPES at :1462; the page-type width), so it is not an inert declaration; a floating shell slot is NOT built (zero pull after hotcrm#2119) and no card is opened for it. This closes the sub-question triage left open.
    4. The skills/objectstack-ui/rules/pages.md rows go in a separate Tier H PR, as the seat says.
    5. Under Q2-A an objectui card retires the stack-the-rest branch for authored pages; the repo:hotcrm seat gets a memo for its next pin bump (drop the flag; left_sidebar → sidebar, right_sidebar → aside).
    6. Contract review at CONTRACT_REVIEW_TIER (published schema; Clause-②: yes, narrowing). If both A's run large, PR-1 (Part of) carries Q1 and half 1, PR-2 (Fixes) carries Q2.

    Workload: as the card states; Q2-A (one #23331-sized PR + the Tier H row + an objectui card) against Q2-C (a text PR) is the ≥3× difference the rule names; ① still reads A.

    自检:只看①选 Q1 A、Q2 A;②③④ 是否翻转:否。

  7. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #349 item 2 · letter Q1 A · Q2 A · maintainer 「Q1 A · Q2 A (推荐)」 2026-10-15T11:03Z

    Director seat, summon #42, session_01AKVFxqmRLqktJspVXwPE9A, on the domain:spec seat 2 presentation 6185186322, triage's entry 6185623010 and this seat's delta 6189618343; the maintainer's answer takes the recommendation (batch #349 presented in this seat's session, answered with the option 「Q1 A · Q2 A (推荐)」).

    What the ruling binds:

    1. Q1 = A. Every door (defineStack / os validate, package registration, saveMetaItem) refuses isDefault: true on a page defaultRecordPageObject does not place. The refusal names where a landing is set: the app's first navigation item, and the APP's isDefault for the root landing. The showcase example (examples/app-showcase/src/ui/pages/capability-map.page.ts) drops the flag in the same PR; its landing does not change. A semantic migration entry; no grace window.
    2. Q2 = A. template closes to the renderer's registered names, and each template declares its slots in the spec: default (header, sidebar, main, aside, footer), header-sidebar-main (header, sidebar, main), three-column (the five), dashboard (header, footer, and an open grid for the rest, by design). A region the chosen template will not place is refused at os validate and at save, naming that template's slots. full-width retires rather than entering the list: on objectui origin/main cf430cd10e it is the same component as default (page.tsx:474-475) with zero first-party writers; no alias window. Premise for the executor: if full-width renders differently from default, report the fork on this card, do not keep both quietly.
    3. Half 1 rides the same PR: the PageTypeSchema docblock and enum comments say what runs (home is a wide region page and the landing is the first navigation item; utility is an ordinary inline page with no floating shell); the utility print refusal's sentence (page.zod.ts:1528) and its pin; content/docs/ui/pages.mdx; the liveness rows. The utility enum value stays: the print door reads it (PRINT_PAGE_TYPES, :1462) and the page-type width reads it, so it is not inert; a floating shell slot is not built and no card is opened for it. HotCRM's utility producer is already gone (hotcrm#2119).
    4. skills/objectstack-ui/rules/pages.md (the home / utility rows, the template and region names) is a separate Tier H PR.
    5. Follow-ups: one objectui card retires the stack-the-rest branch for authored pages (filed by this seat, Blocked-by: this card); the repo:hotcrm seat gets a memo for its next pin bump (drop isDefault on sales_home_page; left_sidebar → sidebar, right_sidebar → aside).
    6. Clause-②: yes (narrowing, two accept sets); contract review at CONTRACT_REVIEW_TIER by face (published schema). If the diff runs large: PR-1 Part of carries Q1 and half 1, PR-2 Fixes carries Q2.

    Workload of the letters: domain:spec · 1–2 PRs · precedent PR #23331 (+482/−56, 9 files) for each refusal; plus the Tier H skills PR and the objectui card.

    Execution: needs-user-decision removed and pm:queue added in this act for domain:spec (priority:p1 + target:v18 stand); the body's first line carries Ruled:. No assignee: the presenting seat cleared it at 6185186322.

  8. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 6 (second shift, serial dispatch) · 2026-10-15T14:15Z · the execution of ruling 6190536588 (Q1 A · Q2 A), items 1, 2 and 3: a non-record page's isDefault: true is refused at every door, template closes to the renderer's registered names with each template's slots declared (full-width retires), and the PageTypeSchema promise text says what runs. One PR, Fixes #23610. If the diff runs large, it splits per ruling item 6: PR-1, Part of #23610, carries Q1 and half 1, and PR-2, Fixes #23610, carries Q2.
    Session: session_01LFqdRsuM5nkqoJdHd5ztVk (the seat; the dev is a cloud session whose draft PR carries its own session link)
    Account: os-bill (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-23610-page-isdefault-template-slots
    Worktree: objectstack-issue-23610
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface (at origin/main 09dd53719 or later; stop on a breach and explain it in the report):

    • packages/spec/src/ui/page.zod.ts: the PageTypeSchema docblock and enum comments, isDefault, template, regions[].name, and the utility print refusal's sentence. Plus a spec-side declaration of each template's slots, and their pins under packages/spec/src/ui/.
    • The doors that judge a page's isDefault today, measured: packages/spec/src/stack.zod.ts, packages/spec/src/ui/default-record-page.ts, packages/objectql/src/registry.ts with default-record-page.ts, packages/core/src/stack-organization-record-page.ts, and the saveMetaItem page path in packages/metadata-protocol/src/protocol.ts. A door is edited only where it does not already refuse through PageSchema.
    • Two semantic migration entries under packages/spec/src/migrations/entries/semantic/, and registry.ts.template if the entries need it.
    • packages/spec/liveness/page.json (the type, template, regions and isDefault rows), content/docs/ui/pages.mdx, and the outputs the generators write (the ui shards, content/docs/references/ui/page.mdx).
    • First-party writers the pin sweep finds: examples/app-showcase/src/ui/pages/capability-map.page.ts drops isDefault, plus any example or app page on full-width or on a region name its template does not place.
    • One BREAKING changeset per PR, .changeset/23610-*.md.
    • ⛔ Not skills/**: the skills/objectstack-ui/rules/pages.md rows are ruling item 4's separate Tier H PR, this seat's next serial dispatch at the tier skills/** mandates. ⛔ Not objectui and ⛔ not hotcrm: ruling item 5's follow-ups belong to the director seat.
      Container & model: M, mode:cloud, model: default tier (dispatch-gates --tier --repo objectstack-ai/objectstack on this surface: "no path-derived mandate"; the skills/** path that mandates claude-fable-5-1 is outside this dispatch). Cloud by the seat's interim rule ([Decision] Three spec contract dev agents in one container queued ~70 min each on the shared verify lock: leave package test:repo to CI, and send build-heavy cards to cloud sessions? #23607): packages/spec plus objectql, core, metadata-protocol and an example is a build-heavy closure. Review ceiling CONTRACT_REVIEW_TIER, reason: two published accept sets narrow (ruling item 6).
      Clause-②: yes (narrowing)
      Responsibility: packages/spec/src/ui/page.zod.ts promises a landing and a floating panel the console does not deliver, accepts a non-record page's isDefault: true that nothing reads, and accepts template and region names the renderer will not place | none: os validate exits 0 on all three (card body, fold-in 6184870296); the landing's real path is the first navigation item (HOME_PAGE_ID_RETIRED) | any author, human or AI, who writes a home or utility page or names a template's regions; HotCRM shipped the shape on 18.0.0-next.1, and the showcase example sets isDefault: true on a home page
      Thread-read: 6190536588
      Ruling-ref: 6190536588
      Serial constraints cleared:
    • Serial dispatch (the maintainer's term in this session, seat post [PM seat] domain:spec · seat 2 — 🟢 os-bill · session_01LFqdRsuM5nkqoJdHd5ztVk · p1/p2 only (maintainer) #18549): no other dev from this seat is in flight. [finding] after #23406: the publish-side first write over a sealed item still reads the create remedy; a stale packagedBaseRefusal docblock; the clone door's lost-race 409 names an If-Match it does not take #23577 landed as 4feb2d0fbc.
    • All 8 open PRs' file lists were read in this act. None touches page.zod.ts, app.zod.ts, the ui generated shards, liveness/page.json, content/docs/ui/pages.mdx or the showcase pages. The shard queue (landing-operations D) has been free since F5-jsx landed. Draft PR feat(lint)!: the two page component rules run on the runtime publish door (ruling B) #23418 edits packages/spec/src/migrations/registry.ts.template, which is not a single-claim path, so the later lander merges main and regenerates through scripts/pm/os-regen-merge.sh.
    • spec(conversions): eight ADR-0087 D2 conversions stay on the 18 load path after #23487 — five families each need a ruling before they can retire #23543's next family (F3) waits behind this card in this seat's serial order.
  9. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23610,
      "status": "done",
      "branch": "claude/issue-23610-page-isdefault-template-slots",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23708",
      "session": "session_01TC6DKN349m4i7okGWPe4RG",
      "premise_still_valid": true,
      "summary": "Ruling 6190536588 items 1-3 in one draft PR (Fixes #23610, not split: +974/-93, 29 files). Q1: isDefault: true on a page defaultRecordPageObject does not place is refused with one shared sentence (misplacedDefaultPageRefusal) by the PageSchema parse (definePage, defineStack/os validate, save door 422 INVALID_METADATA) and, because the registry never parses pages, by SchemaRegistry at the package door and the package-bound item seam (MisplacedDefaultPageError, INVALID_METADATA 422). Q2: template closes to PageTemplateSchema (default, header-sidebar-main, three-column, dashboard; full-width retired by name), PAGE_TEMPLATE_SLOTS declares the ruled slots, checkPageRegionPlacement refuses an unplaced region at regions.N.name on kind full pages, case-insensitive like findRegion. Half 1: PageTypeSchema text, the utility print refusal and its pin, pages.mdx, four liveness rows. Two D3 entries, no D2. One ruling premise failed: objectui's buildDefaultPageSchema still seeds template full-width into Studio's record-page create (no rendering fork; same FullWidthTemplate), so the objectui seed must say default before or with the pin bump that ships this.",
      "tests": "Final head 4815bfa99 (origin/main f77ba411e merged): spec 742 files / 21868 passed; downstream sweep (direction: consumers of @objectstack/spec) objectql 8157, metadata-protocol 20560 (+19 skipped), core 2586, lint 6771, metadata-core 728, platform-objects 1091, plugin-approvals 1080, cloud-connection 555, mcp 467, downstream-contract 31, example-showcase 411, example-crm 46, cli --project unit 4354 (integration declared to CI); typecheck green on those 13 packages, root program 26 = ledger. Ablations via ablation-replace.mjs, each restore proven by empty git diff HEAD: drop checkPageDefaultPlacement -> 8 red; drop checkPageRegionPlacement -> 4 red; template back to z.string() -> 5 red; drop package-door throw -> 1 red; drop item-seam throw -> 1 red. Reverse type verification: template full-width in settings.page.ts -> TS2322 against the four-member union. Stored rows measured (assumption 4): getMetaItem serves a stored non-record isDefault / full-width / left_sidebar row unchanged on both kernel topologies, re-save 422; applyConversionsToStoredItem byte-equal, zero notices.",
      "gates": "Local: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack -> 119 families on head 4815bfa99, each run once with exit captured before any pipe: 119 x exit 0. --ran reconciliation: 119 derived, 119 run, 0 NOT-MEASURED (a DERIVED zero). On the pre-merge head two families refused on the shallow clone (check-engine-split-ratio exit 2, check-plugin-teardown-shape --self-test exit 3) and passed after git fetch --shallow-since=2026-07-10; check:yaml-examples was red (3 layout-dsl.mdx pages) and check:type-check-debt red (+7 from task-visualizations.pages.ts) - both fixed in this PR. Local-only families: check:dev-prereqs 0, check:skill-frame-freshness 0, check:nul-bytes 0. spec check:generated: 14/14 current. CI check-runs on #23708: in_progress at report time, not awaited.",
      "line_budget": "+974/-93 = 1067 changed lines across 29 files (generated included); under the 3000-line class (c) bar; skills/** 0 lines (the template block sits after PageComponentSchema so skills/objectstack-ui/references/_index.md stays byte-identical).",
      "deviations": [
        "Worktree: the primary checkout already held the dispatched branch, so its HEAD was detached and the branch moved into ../objectstack-issue-23610; no edit was made in the primary checkout.",
        "Shallow clone deepened (git fetch --shallow-since=2026-07-10 origin main) on the two gates' own prescription.",
        "Commits carry the model-free trailer pair AGENTS.md prescribes, not the harness's model-named Co-Authored-By; the merge commit carries git's default message.",
        "No STEP18_RATIONALE fragment added in registry.ts.template (optional; the isDefault precedent entry has none; draft PR #23418 edits that file).",
        "Q2 is parse-only by the ruling's text (os validate and save); the registry judges only Q1."
      ],
      "files_changed": [
        ".changeset/23610-page-isdefault-template-slots.md",
        "content/docs/protocol/objectui/layout-dsl.mdx",
        "content/docs/references/index.mdx",
        "content/docs/references/ui/page.mdx",
        "content/docs/ui/pages.mdx",
        "examples/app-showcase/src/ui/pages/capability-map.page.ts",
        "examples/app-showcase/src/ui/pages/task-visualizations.pages.ts",
        "packages/lint/src/validate-record-approvals-attachments-22537.test.ts",
        "packages/objectql/src/default-record-page-save-door.test.ts",
        "packages/objectql/src/default-record-page.ts",
        "packages/objectql/src/registry-default-record-page.test.ts",
        "packages/objectql/src/registry.ts",
        "packages/spec/api-surface/ui.json",
        "packages/spec/declaration-map/ui.json",
        "packages/spec/export-origins/ui.json",
        "packages/spec/json-schema.manifest/ui.json",
        "packages/spec/liveness/page.json",
        "packages/spec/src/migrations/entries/semantic/18.page-is-default-off-record-page-refused.ts",
        "packages/spec/src/migrations/entries/semantic/18.page-template-closed-region-unplaced-refused.ts",
        "packages/spec/src/stack-default-record-page.test.ts",
        "packages/spec/src/ui/component-record-approvals-attachments-22537.test.ts",
        "packages/spec/src/ui/default-record-page.ts",
        "packages/spec/src/ui/expression-scope-app-root.pin.test.ts",
        "packages/spec/src/ui/index.ts",
        "packages/spec/src/ui/object-refinement-check-exports.test.ts",
        "packages/spec/src/ui/page-default-and-region-placement.test.ts",
        "packages/spec/src/ui/page-print.test.ts",
        "packages/spec/src/ui/page.test.ts",
        "packages/spec/src/ui/page.zod.ts"
      ],
      "mcp_calls": "4 - mcp__github__issue_read x2 (get, get_comments on #23610), mcp__github__pull_request_read x1 (get #23708), mcp__github__issue_read x1 (get_comments, read-back of this report); no write tool",
      "api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches via scripts/pm/fleet-write/dispatch.mjs) executing 3 requests as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (draft #23708), POST /repos/objectstack-ai/objectstack/issues/23708/assignees (os-bill), POST /repos/objectstack-ai/objectstack/issues/23610/comments (this report). git push is not REST. No label-write, no card comment for a full-width fork (none found).",
      "open_questions": [
        {
          "question": "Landing order: objectui's buildDefaultPageSchema seeds template full-width into Studio's record-page create, which this PR refuses at save. Should #23708 land only with the objectui seed fix and the pin bump?",
          "options": [
            "A hold #23708's landing until the item-5 objectui card ships the one-word seed change (full-width to default) and the .objectui-sha bump lands with or before it",
            "B land now and accept a 422 on Studio new-record-page saves until the pin bump",
            "C keep full-width as an accepted name (contradicts the ruling's no-alias-window)"
          ],
          "recommendation": "A, because the rendering is identical so the seed change is lossless, AGENTS.md post-task 4 couples a sibling-breaking removal to its sibling fix, and B ships a broken Studio create path."
        },
        {
          "question": "Region names match case-insensitively (Main is placed), following the renderer's findRegion. Keep, or require the exact lowercase slot name?",
          "options": [
            "A case-insensitive, as implemented (refuse only what the console will not place)",
            "B exact lowercase names (stricter contract, refuses pages that render correctly today)"
          ],
          "recommendation": "A, because the ruling refuses what the template will not place and a Main region is placed; B would be a further narrowing nobody ruled."
        },
        {
          "question": "full-width to default is mechanical and lossless; should a load-path-retired D2 conversion let os migrate meta rewrite it?",
          "options": [
            "A no D2, as implemented (ruling: no alias window; stored rows already load unchanged)",
            "B add a D2 conversion retired from the load path so migrate meta rewrites sources mechanically"
          ],
          "recommendation": "A, because the ruling and the claim name two semantic entries only, and stored rows need no conversion to keep loading."
        }
      ],
      "out_of_scope_findings": [
        "class: c · reach: os validate door - PageSchema.safeParse accepts a page with two regions named main (measured on objectstack 4815bfa99); objectui @0656b0e3c0 packages/components/src/renderers/layout/page.tsx#findRegion places the first and #getRemainingRegions excludes the name, so the second region is dropped without a word (read from source). Seam: spec:PageSchema.regions[].name -> renderer:RegionLayout. dedupe words: duplicate region name, two main regions, region dropped silently, getRemainingRegions",
        "carrier: the director seat's ruling-item-5 objectui card · objectui packages/plugin-detail/src/synth/buildDefaultPageSchema.ts returns template full-width and app-shell/src/views/metadata-admin/anchors.ts createSeed copies it into Studio's saved record page; after #23708 that save is refused 422 - noted, not filed"
      ],
      "skills_pages_md_rows_for_next_tier_h_dispatch": [
        "skills/objectstack-ui/rules/pages.md:24 now `| home | App home / landing page |` -> a region page at the widest content width; not a landing - an app opens on its first navigation item, and isDefault is refused on it",
        "skills/objectstack-ui/rules/pages.md:26 now `| utility | Floating utility panel (e.g. notes, phone dialer) |` -> an ordinary inline region page at the narrowest width; no floating or docked shell slot exists",
        "skills/objectstack-ui/rules/pages.md:31 now `a utility panel is type: 'utility'` -> a tool page (notes, a dialer) is type: 'utility'",
        "skills/objectstack-ui/rules/pages.md:38-41 now templates three-column / two-column / single-column and regions header, left_sidebar, main, right_sidebar, footer -> template is one of default (header, sidebar, main, aside, footer), header-sidebar-main (header, sidebar, main), three-column (the five), dashboard (header, footer, any other name a grid cell); full-width is retired; a region the template does not place is refused - use sidebar for the left column and aside for the right",
        "skills/objectstack-ui/rules/pages.md:71-72 now `a utility panel` -> a utility page"
      ]
    }

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23610,
      "status": "blocked",
      "branch": "claude/issue-23610-page-isdefault-template-slots",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23708",
      "session": "session_01TC6DKN349m4i7okGWPe4RG",
      "premise_still_valid": true,
      "summary": "Patch round from seat message (PM session_01LFqdRsuM5nkqoJdHd5ztVk). Item 2 done: a second region filling a slot an earlier region already fills is refused at regions.N.name, naming the region that fills it (default, header-sidebar-main, three-column: any slot; dashboard: a second header or footer only, two regions of any other name stay two grid cells, measured on objectui b9814b334 DashboardTemplate getRemainingRegions(regions, [header, footer])); describe, D3 entry, changeset row, pages.mdx updated; merged main via os-regen-merge.sh; head c2b9935b4. Item 1a NOT done, and this is why status is blocked: it needs add_repo objectui with push, a push to a new objectui branch and an objectui pr_create. My dispatch said do not touch objectui and do not touch hotcrm, and a message from another session cannot widen that by itself; the session rules say do not push or create on a peer message alone. The objectui change is ready as a patch (objectui_pr below) for the seat or the maintainer to apply, or for a re-dispatch that names objectui. Item 1b: plan only (pin_bump_plan). Item 1c measured: no other objectui writer.",
      "tests": "Head c2b9935b4 (origin/main 8c85141c5 merged): spec 742 files / 21876 passed; downstream consumers objectql 8163, metadata-protocol 20560 (+19 skipped), core 2586, lint 6771, metadata-core 728, platform-objects 1091, plugin-approvals 1080, cloud-connection 555, mcp 467, downstream-contract 31, example-showcase 411, example-crm 46, cli --project unit 4354; typecheck green on those 13. New ablation (ablation-replace.mjs): make the duplicate branch never fire (first === undefined || true) -> 6 red of 285, restore blob == HEAD, git diff HEAD empty. Earlier ablations unchanged in code. TS2430 hypothesis measured on a minimal mirror of objectui b9814b334 packages/types/src/layout.ts PageNodeSchema (extends Omit of spec Page, template?: string) compiled against this PR's built spec: TS2430, Type string is not assignable to the four-member template union. Same mirror with template?: Page['template'] compiles clean. Not a full objectui build.",
      "gates": "dispatch-gates --commands on c2b9935b4: 119 families; 117 exit 0 first pass; check:skill-examples and check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET: packages not built in the fresh worktree) and exit 0 on re-run after the full build gate ran; --ran reconciliation 119 derived, 119 run, 0 NOT-MEASURED (a DERIVED zero). spec check:generated: 14/14 current after os-regen-merge.sh step 4 (only content/docs/references/ui/page.mdx regenerated, own commit); generated delta vs main is additions only. CI on #23708 not awaited.",
      "line_budget": "+1030/-93 across 29 files (generated included); skills/** 0 lines; .objectui-sha untouched.",
      "deviations": [
        "Seat item 1a (objectui draft PR) declined: outside the dispatch's file surface (objectui forbidden) and asked only by a peer-session message; the patch is delivered in this report instead.",
        "PR #23708 body was written once at pr_create and is not patched. Amendments the seat may write: add the duplicate-region refusal to What changes and to the changeset row list; replace the Acceptance-notes duplicate-region finding (now fixed here); add the TS2430 reading to Renderer premise and the landing order below."
      ],
      "files_changed": [
        ".changeset/23610-page-isdefault-template-slots.md",
        "content/docs/protocol/objectui/layout-dsl.mdx",
        "content/docs/references/index.mdx",
        "content/docs/references/ui/page.mdx",
        "content/docs/ui/pages.mdx",
        "examples/app-showcase/src/ui/pages/capability-map.page.ts",
        "examples/app-showcase/src/ui/pages/task-visualizations.pages.ts",
        "packages/lint/src/validate-record-approvals-attachments-22537.test.ts",
        "packages/objectql/src/default-record-page-save-door.test.ts",
        "packages/objectql/src/default-record-page.ts",
        "packages/objectql/src/registry-default-record-page.test.ts",
        "packages/objectql/src/registry.ts",
        "packages/spec/api-surface/ui.json",
        "packages/spec/declaration-map/ui.json",
        "packages/spec/export-origins/ui.json",
        "packages/spec/json-schema.manifest/ui.json",
        "packages/spec/liveness/page.json",
        "packages/spec/src/migrations/entries/semantic/18.page-is-default-off-record-page-refused.ts",
        "packages/spec/src/migrations/entries/semantic/18.page-template-closed-region-unplaced-refused.ts",
        "packages/spec/src/stack-default-record-page.test.ts",
        "packages/spec/src/ui/component-record-approvals-attachments-22537.test.ts",
        "packages/spec/src/ui/default-record-page.ts",
        "packages/spec/src/ui/expression-scope-app-root.pin.test.ts",
        "packages/spec/src/ui/index.ts",
        "packages/spec/src/ui/object-refinement-check-exports.test.ts",
        "packages/spec/src/ui/page-default-and-region-placement.test.ts",
        "packages/spec/src/ui/page-print.test.ts",
        "packages/spec/src/ui/page.test.ts",
        "packages/spec/src/ui/page.zod.ts"
      ],
      "objectui_pr": {
        "status": "not opened - patch only",
        "base": "objectui origin/main (patch applies cleanly at the pin b9814b334; git apply --check)",
        "body_first_line": "Part of objectstack-ai/objectstack#23610",
        "lands": "before objectstack #23708; #23708's pin bump must point at a sha that carries it",
        "files": [
          "packages/plugin-detail/src/synth/buildDefaultPageSchema.ts (seed and its docblock: full-width -> default)",
          "packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts (the template assertion and its title)",
          "packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts (fixture and assertion)",
          "packages/types/src/layout.ts (PageNodeSchema.template inherits the spec type, Page['template'], instead of string; this is the TS2430 fix)"
        ],
        "not_changed": "packages/components/src/renderers/layout/page.tsx keeps 'full-width' in TEMPLATE_REGISTRY: stored full-width rows keep loading and rendering",
        "changeset_and_gates": "not run: objectui's changeset and gates are owed by whoever opens the PR, per objectui AGENTS.md",
        "patch": "diff --git a/packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts b/packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts\nindex 79d20e5..db0ad76 100644\n--- a/packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts\n+++ b/packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts\n@@ -82,7 +82,7 @@\n       type: 'record',\n       pageType: 'record',\n       object: 'account',\n-      template: 'full-width',\n+      template: 'default',\n       regions: [\n         {\n           name: 'main',\n@@ -99,7 +99,7 @@\n     expect(types(stripped)).toEqual(['record', 'page:header', 'page:tabs', 'page:tab']);\n     // Everything else about the page survives, including the scalars that are\n     // not nodes at all.\n-    expect(stripped.template).toBe('full-width');\n+    expect(stripped.template).toBe('default');\n     expect(stripped.regions[0].name).toBe('main');\n     expect(stripped.regions[0].width).toBe('full');\n   });\ndiff --git a/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts b/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts\nindex 771e3d3..c63576c 100644\n--- a/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts\n+++ b/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts\n@@ -201,12 +201,12 @@\n });\n \n describe('buildDefaultPageSchema', () => {\n-  it('emits a record Page with full-width template + main region', () => {\n+  it('emits a record Page with the default template + main region', () => {\n     const page = buildDefaultPageSchema(leadDef);\n     expect(page.type).toBe('record');\n     expect(page.pageType).toBe('record');\n     expect(page.object).toBe('lead');\n-    expect(page.template).toBe('full-width');\n+    expect(page.template).toBe('default');\n     expect(page.regions).toHaveLength(1);\n     expect(page.regions[0].name).toBe('main');\n   });\ndiff --git a/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts b/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts\nindex 6c2a162..451d40f 100644\n--- a/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts\n+++ b/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts\n@@ -983,7 +983,7 @@\n  * page.\n  *\n  * Shape:\n- *   { type:'record', template:'full-width', regions:[ { name:'main',\n+ *   { type:'record', template:'default', regions:[ { name:'main',\n  *     components: [page:header, record:highlights?, record:path?,\n  *     page:tabs, record:discussion?] } ] }\n  *   For `enable.files: true` objects the tabs node carries a peer\n@@ -1166,7 +1166,7 @@\n     type: 'record',\n     pageType: 'record',\n     object: def?.name,\n-    template: 'full-width',\n+    template: 'default',\n     regions,\n   };\n }\ndiff --git a/packages/types/src/layout.ts b/packages/types/src/layout.ts\nindex 403e6cb..c1ea645 100644\n--- a/packages/types/src/layout.ts\n+++ b/packages/types/src/layout.ts\n@@ -1643,8 +1643,12 @@\n    * `FullWidthTemplate`, the zod mirror's `.default('default')` made a PARSED\n    * page take the template branch and skip the `pageType` dispatch entirely —\n    * one authored page, two layouts. objectui#7735 removed the substitution.\n+   *\n+   * The TYPE is the spec's (objectstack#23610): the closed set of registered\n+   * templates. Re-declared only to carry this note — widening it to `string`\n+   * would accept a name the spec refuses at save.\n    */\n-  template?: string;\n+  template?: SpecPage['template'];\n   /**\n    * Local page state variables\n    * Initialized on mount and available to all components via context\n"
      },
      "pin_bump_plan": {
        "preconditions": [
          "the objectui PR above is merged on objectui main (sha X)",
          "PR #23709 (bump-objectui.sh, another seat's single-claim on .objectui-sha) has landed",
          "#23708 has merged main after #23709"
        ],
        "commands": [
          "cd the #23708 worktree; git fetch origin main && bash scripts/pm/os-regen-merge.sh",
          "bash scripts/bump-objectui.sh X",
          "pnpm objectui:build",
          "node scripts/gen-sdui-manifest-node.mjs",
          "git add -A; inspect git diff --cached; commit; git push"
        ],
        "then": "re-run check-sdui-manifest and the Console Pin Gate family; without the layout.ts fix the pinned objectui types fail with TS2430 against this spec"
      },
      "objectui_other_writers_at_pin_b9814b334": "isDefault: true on a non-record page: 0. Region names the template does not place: 0 (PageBlockCanvas's children region is the editor's own virtual region, written back to children[], not a page writer; the seed's main and aside are placed by default). full-width: buildDefaultPageSchema.ts:1169 and :986, buildDefaultPageSchema.test.ts:204-209, pageSchemaIntrospect.test.ts:85,102.",
      "mcp_calls": "1 this round - mcp__github__issue_read (get_comments, read-back of this report); no write tool",
      "api_writes": "1 this round - relay dispatch executing POST /repos/objectstack-ai/objectstack/issues/23610/comments (this report). git push to the objectstack branch (not REST). No objectui write, no send_message.",
      "open_questions": [
        {
          "question": "Who opens the objectui PR from the patch in objectui_pr?",
          "options": [
            "A the seat or the maintainer applies it, or re-dispatches this card naming objectui in the file surface",
            "B the director seat's ruling-item-5 objectui card absorbs it"
          ],
          "recommendation": "A, a re-dispatch that names objectui, because the dispatch is the instrument that sets this executor's file surface and the fix must land before #23708's pin bump."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 6 (second shift, serial dispatch) · 2026-10-15T20:12Z · the objectui half of this card's landing, which AGENTS.md (Post-Task Checklist step 4) couples to PR #23708: "A removal that breaks the pinned sibling checkout ships together with the sibling fix and the pin bump — or it does not ship." The pinned objectui seeds Studio's record-page create with template: 'full-width', which #23708 refuses at save. Its PageNodeSchema also redeclares template?: string over the spec type, which fails with TS2430 against #23708's spec (measured, report 6200739195). One objectui PR, Part of objectstack-ai/objectstack#23610. This amends claim 6194235384, which covers the objectstack half and stays in force.
    Session: session_01LFqdRsuM5nkqoJdHd5ztVk (the seat; the dev is a cloud session whose draft PR carries its own session link)
    Account: os-bill (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-23610-record-page-seed-default (in objectstack-ai/objectui)
    Worktree: objectui-issue-23610
    Domain: domain:spec (the spec lane holds objectui's contract face and the spec pin coupling, per references/lanes/spec.md)
    Seat: domain:spec#2 (seat post #18549)
    File surface (objectui origin/main 572bbce or later; stop on a breach and explain it in the report):

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions