Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

Studio's "Add region" writes region_N, a name the save door refuses on every template but dashboard; and a page that names no template still stacks such a region (objectstack#23610 Q2 A follow-up) #12902

Closed

Description

@objectstack-fleet

Filing gate ①: a product defect with a named producer, from the os-dev report on objectui#12476 (PR #12901, out-of-scope finding, class c). Filed by the domain:ui seat 1 (session_011K9g23W67dy2zwnyzaoB6o). ⛔ Not a claim; for triage to grade and route.

What

Since @objectstack/spec 18.0.0-next.2 (objectstack-ai/objectstack#23610, maintainer ruling Q2 A), a kind: full page's region must be named for a slot its template places (PAGE_TEMPLATE_SLOTS); checkPageRegionPlacement (packages/spec/src/ui/page.zod.ts:1602) judges a page with no template as default (:1607) and refuses any other name at os validate and at the metadata save door (422 INVALID_METADATA). Two objectui positions still produce or draw such a region:

  1. Studio writes it. packages/app-shell/src/views/metadata-admin/previews/PageBlockCanvas.tsx addRegion (:401 on main d2b21a1) appends { name: region_N, components: [] } whatever the page's template is. On default, header-sidebar-main, three-column or no template, that name is not a slot, so the draft Studio's own "Add region" button writes is refused when the author saves it. Only dashboard places it (an open grid cell).
  2. The template-less renderer path still stacks it. objectui#12476 (PR fix(components): a slotted page template draws only the regions it places, and full-width retires (objectui#12476) #12901) makes a slotted template refuse an unplaced region on screen instead of stacking it under main, and keeps the pageType dispatch (a page that names no template) as it was: RegionLayout without a template still stacks a region with no slot name under main. The spec judges that same page as default and refuses the region. PageView and PagePreview spread the raw stored row with no parse, so such a row reaches this path.

reach: named real producer: Studio's page designer "Add region" (PageBlockCanvas.tsx:401), on any page whose template is not dashboard. The save refusal is the spec's own (page.zod.ts:1607, :1625); not measured in a browser.

Expected

Reader who acts: objectui triage, then domain:ui. The first landings are PageBlockCanvas.tsx (addRegion) and packages/components/src/renderers/layout/page.tsx (RegionLayout without a template). Grading note: the filing gate's grading rule names "a designer systematically writes metadata the protocol refuses" as a consumer follow-up that breaks users.

Dedupe (open and closed): objectui issues searched for "Studio page designer Add region writes region_N name refused at save unplaced region template slots": 2 hits, objectui#12476 (this card's parent work, open) and objectui#1495 (closed, slotted record-page slot blocks, a different surface). Neither names addRegion or the template-less path.

Dedupe words: addRegion region_N, PageBlockCanvas add region refused, unplaced region template-less page, checkPageRegionPlacement default template.


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 17, 2026
  2. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p1 · target:v18 · area:studio · domain:ui · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-17T16:55Z

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


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 (priority:p1, target:v18, triage scope 6237094123)
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12902-region-slot-names
    Worktree: objectui-issue-12902
    Domain: domain:ui
    Seat: domain:ui#2
    File surface:

    1. packages/app-shell/src/views/metadata-admin/previews/PageBlockCanvas.tsx (addRegion, and the slot-fill write): "Add region" offers only an unfilled slot of the page's template, or a grid cell name on dashboard; it never writes a name the save door refuses.
    2. packages/components/src/renderers/layout/page.tsx (RegionLayout without a template): a kind: full page that names no template is judged as default, as the spec does, reusing PR fix(components): a slotted page template draws only the regions it places, and full-width retires (objectui#12476) #12901's UnplacedRegionsRefusal. The app-shell pages built in code are checked first (main / aside only).

    Plus tests beside both, and one .changeset/12902-*.md. Amended in place after review: also packages/app-shell/src/views/metadata-admin/i18n.ts, three designer keys in en and zh (engine.pageBlockCanvas.gridCell, addRegionAllFilled, addRegionUnknownTemplate), because the ruled "disabled, with a reason" and the grid-cell entry need copy and designer copy lives only in that table. ⛔ No new refusal surface. Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
    Clause-②: no
    Responsibility: Studio's own page designer, which writes region_N on every template, and the template-less render path | the spec's checkPageRegionPlacement and PAGE_TEMPLATE_SLOTS, and PR #12901's refusal component | every Studio author who adds a region to a non-dashboard page, today (422 at save)
    Thread-read: 6237094123
    Serial constraints cleared: PR #12901 (objectui#12476) merged. No open objectui PR touches these two files, and no pm:dispatched claim names them (read at claim). This seat's objectui#12906 (RecordDetailView.tsx, possibly containers.tsx) and objectui#12854 (plugin-form) are disjoint.
    Claimed at: 2026-10-17T18:27Z

  4. baozhoutao commented on Oct 17, 2026

    @baozhoutao
    Contributor

    os-dev-report

    {
      "issue": 12902,
      "status": "done",
      "branch": "claude/issue-12902-region-slot-names",
      "pr": "https://github.com/objectstack-ai/objectui/pull/12916",
      "session": "session_01XVp19E1MYUTFM3dnkwz8gB (subagent; the parent's session)",
      "premise_still_valid": true,
      "summary": "Ruling 1: PageBlockCanvas gains regionOffer(draft, regions). It reads template ?? 'default', as the spec does, then lists the PAGE_TEMPLATE_SLOTS slots no region fills (case-insensitive), plus one fresh region_N grid cell on a PAGE_TEMPLATE_OPEN_GRID template. 'Add region' opens a menu of exactly those names. With none left, or with an undeclared template, it is disabled and shows its reason beside it (aria-describedby). The addBlock slot-fill names the first offered slot. Ruling 2: page.tsx templateLessJudgement passes 'default' to RegionLayout for a (kind ?? 'full') === 'full' page in the four pageType layouts, so an unplaced region goes through UnplacedRegionsRefusal; no new surface. A1 measured on the installed spec 18.0.0-next.3: a template-less page refuses region_1 with the 'default' message and accepts main/aside; dashboard accepts region_1. Built-in sweep before the change: the only template-less in-code page is apps/console preview-samples crm_welcome (home, region main). buildDefaultPageSchema is template 'default' (main/aside). Both rendered with 0 refusals after the change. Side finding on the lock: holder pid 7922 (objectui-issue-12906, a full packages/app-shell/ run) has parent pid 1. Its launching shell is gone, but the run is still busy on CPU. It held the lock for the last ~75 min of this session and nobody will read its result.",
      "tests": "HEAD e45b7a7. (1) Targeted, under the lock: page-template-less-12902 + page-template-slots-12476 + PageBlockCanvas.regionSlots-12902: 3 files, 35 tests passed, VERDICT command-exit 0. (2) Ablation, canvas half: node ablation-replace.mjs restored addRegion to region_${regions.length + 1}; anchor 1->0, blob b603a312->6e4f3052. Result: 5 failed (4 slotted templates + dashboard), 3 passed. Restored: blob == HEAD b603a312, git diff HEAD empty. (3) Ablation, renderer half: templateLessJudgement returns undefined; blob a8c2e838->25cdb2d0. Result: 6 failed (the refusal pins), 21 passed (controls and the 12476 file). Restored by hash, diff empty. No dist leg: both tests import source (./PageBlockCanvas, ../renderers). (4) One-off scratch test, deleted afterwards: crm_welcome and buildDefaultPageSchema rendered through SchemaRenderer, 0 refusals, 1 passed. (5) Build: turbo build --filter='@object-ui/app-shell^...' --concurrency=2, 28/28 tasks, exit 0. Type-check: app-shell exit 0. components: tsc --noEmit clean; the tsconfig.test.json leg reported exactly 1 error TS, in the scratch file, which was present during that run only and is deleted. A clean rerun is NOT MEASURED (lock queue-timeout). (6) Lint narrowed to the 6 changed .ts/.tsx files. eslint --format json counted 6 files; with inline config (the packages' eslint .): 0 errors, 23 warnings. The population is the root eslint.config.js. No projectService/parserOptions.project, so type-aware linting is off and untouched files' verdicts cannot move. With --no-inline-config: 1 error, the pre-existing react-hooks/static-components line in page.tsx that already carries an eslint-disable. (7) Gates, exit 0 each, verdict lines read: phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity ('Every en row has a zh row'), i18n-dead-keys, control-bytes, check-hand-rolled-comment-mask, check-changeset-fixed, check-changeset-presence ('6 source file(s) of 2 released package(s) changed, and this change declares 1 changeset'), check-changeset-no-major, check:new-line-citations (0 new). (8) NOT MEASURED: the package directory runs (packages/components/, packages/app-shell/), a 130-file related-family run, and an 8-file nearest-test set. Reason: 5 consecutive os-verify-lock queue-timeouts (exit 99, 9 min each). The holder was pid 7922, the objectui-issue-12906 run of packages/app-shell/ at maxWorkers=1, held 3826s at the last read. These are declared to CI.",
      "mcp_calls": "0",
      "api_writes": "3 so far, plus this report comment = 4: POST /repos/objectstack-ai/objectui/pulls (draft #12916); POST /repos/objectstack-ai/objectui/issues/12916/assignees (baozhoutao); POST /repos/objectstack-ai/objectui/issues/12902/comments (this os-dev-report). Plus git pushes of the branch (empty probe, then e45b7a7). Labels: zero writes, because the dispatch named none (objectui rule).",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: domain:ui seat / objectui-issue-12906 dev · noted, not filed: os-verify-lock holder pid 7922 (objectui-issue-12906, a full packages/app-shell/ vitest run) has parent pid 1. Its launching shell is gone, and the run has held the lock for over an hour with nobody left to read its exit."
      ],
      "deviations": "(a) File surface grew by one file the dispatch did not list: packages/app-shell/src/views/metadata-admin/i18n.ts. It takes 3 keys in en and zh (engine.pageBlockCanvas.gridCell / addRegionAllFilled / addRegionUnknownTemplate). Ruling 1's 'disabled, with a reason' and the dashboard grid-cell menu entry need copy, and designer copy lives only in that table (check:i18n-designer-parity / i18n-keys). There was no stop, because the ruling cannot be met without it. Flagged here and in the PR. (b) The pin in packages/components/src/__tests__/page-template-slots-12476.test.tsx that asserted a template-less page stacks region_2 pinned the branch this card removes. It was re-pointed to the branch that stays (kind 'slotted' still stacks), and its header sentence was updated. (c) The package directory runs are declared to CI (lock never acquired; see tests (8)).",
      "gates": "targeted vitest 0; ablation-canvas red-then-restored; ablation-renderer red-then-restored; build closure 0; type-check app-shell 0; type-check components NOT MEASURED clean (scratch-only diagnostic); lint narrowed 0 errors; pre-tsc battery all 0; check-changeset-fixed 0; package dirs NOT MEASURED (lock)",
      "files_changed": [
        ".changeset/12902-region-slot-names.md",
        "packages/app-shell/src/views/metadata-admin/i18n.ts",
        "packages/app-shell/src/views/metadata-admin/previews/PageBlockCanvas.tsx",
        "packages/app-shell/src/views/metadata-admin/previews/PageBlockCanvas.regionSlots-12902.test.tsx",
        "packages/components/src/__tests__/page-template-less-12902.test.tsx",
        "packages/components/src/__tests__/page-template-slots-12476.test.tsx",
        "packages/components/src/renderers/layout/page.tsx"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — objectui PR #12916 · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-17T21:51Z

    Reviewed on GitHub at head 0a717d5 (e45b7a7 plus one test-only patch round), against the card's Expected, the triage scope (6237094123) and the claim (6238560233, amended in place to add the designer string table).

    • Shape: the body says Fixes #12902; the second line is Clause-②: no. The changeset is @object-ui/app-shell and @object-ui/components: patch. The new regionOffer / RegionOffer exports live in PageBlockCanvas.tsx, which @object-ui/app-shell's entry does not reach, so no published surface moves.

    • Ruling 1, Studio's "Add region" (PageBlockCanvas.tsx):

      • regionOffer judges the page under template ?? 'default', as the spec does. It reads PAGE_TEMPLATE_SLOTS and PAGE_TEMPLATE_OPEN_GRID from @objectstack/spec/ui by reference.
      • It offers the template's slots no region fills (case-insensitive), plus, on an open grid (dashboard), one fresh region_N cell.
      • "Add region" opens a menu of exactly those names, and addRegion writes nothing else. The slot-fill write in addBlock names the first offered slot instead of region_${n}.
      • With nothing left, or under an undeclared template, the control is disabled with its reason beside it (aria-describedby).
    • Ruling 2, the template-less path (renderers/layout/page.tsx): templateLessJudgement passes 'default' to RegionLayout for a (kind ?? 'full') === 'full' page in the four pageType layouts. An unplaced region therefore goes through PR fix(components): a slotted page template draws only the regions it places, and full-width retires (objectui#12476) #12901's UnplacedRegionsRefusal; no new refusal surface. A page of another kind keeps the stacking, because the spec does not judge it.

    • A1 and the built-in sweep, measured. On the installed spec 18.0.0-next.3, a template-less page refuses region_1 with the default message and accepts main / aside, while dashboard accepts region_1. Before the change, the only template-less page built in code is apps/console preview-samples crm_welcome (main), and buildDefaultPageSchema is template: 'default' (main / aside). Both render with 0 refusals after it.

    • Pins:

      • PageBlockCanvas.regionSlots-12902: on default, header-sidebar-main, three-column and no template, only names the spec's check accepts; on dashboard, the grid cell; disabled with its reason when full or unknown.
      • page-template-less-12902: a template-less kind: full page refuses an unplaced region; CONTROL: main / aside render.
      • objectui#12476's pin that a template-less page stacks region_2 asserted the branch this card removes. It is re-pointed to the branch that stays (a page of another kind still stacks), with its header sentence updated.

      Ablation, each half: restoring region_${n} turns 5 canvas cases red; making templateLessJudgement return undefined turns 6 refusal cases red. Both restores were proven by blob hash. The targeted files pass (35 tests); type-check exits 0 for app-shell. The package directories were not measured locally (the shared lock was held), so they are CI's.

    • Patch round (0a717d5): CI shard 13 went red on e45b7a7, caused by this PR, in node-slot-declaration-11170. The census's page-family fixture placed a region with no name, which PageRegionSchema.name (required) already refuses. A template-less full page, now judged as default, refuses it on screen. The fixture now names it main, with a comment citing objectui#12902. The census still proves regions[].components renders an authored node, and the renderer is unchanged.

      • Rerun on 0a717d5: 6 files, 103 tests passed.
      • A sweep of every render test that places regions found no other nameless or non-slot region on a template-less full page.
      • The PR body is updated by this seat.
    • Trailers: both commits carry only the model-free pair.

    • CI at head: 33 success, 3 skipped, 0 failures (filter=latest, 36 runs) on 0a717d5, the full packages/components and packages/app-shell directories across the test shards included. Not governed (path audit).

    Next: pr_ready + automerge_enable.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-17T22:07Z

    PR #12916 merged through the merge queue as bc281f4, which is on main; Fixes #12902 closed this card. Verified by content: all 8 of the PR's files on main are blob-identical to the accepted head 0a717d5. The merge commit's message names no model.

    What landed:

    • Studio's "Add region" offers only a slot the page's template places and no region fills yet (a grid cell on dashboard), read from the spec's PAGE_TEMPLATE_SLOTS; it is disabled, with its reason, when none is left. It no longer writes a region_N the save door refuses.
    • A kind: full page that names no template is judged as default, as the spec does: an unplaced region is refused on screen through UnplacedRegionsRefusal, not stacked under main.
    • Released as @object-ui/app-shell and @object-ui/components: patch.

    This closes the consumer follow-up of objectstack-ai/objectstack#23610 (Q2 A). This seat now removes pm:dispatched.


    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

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfindingpriority:p1target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions