You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Studio page-create never completes — the console PUTs recordChrome / items, which the server strictly rejects (ADR-0089 D3a) #4232
Creating a page in Studio never completes. The console issues a PUT whose body contains recordChrome and items; the server strictly rejects that body per ADR-0089 D3a, so no page is ever stored.
Observed: the create round-trip fails on every attempt; no page row exists afterwards. Reproduced 2×.
Expected: the create round-trips and the page is persisted.
Root cause
The default page schema the console synthesises carries properties the server's strict validator refuses.
packages/plugin-detail/src/synth/buildDefaultPageSchema.ts — the header synthesiser emits {type: 'page:header', recordChrome: true} (recordChrome: options.recordChrome !== false, ~line 414; the option is declared ~line 141 and threaded again ~line 730). items comes from the same synthesis path (page:tabs.items).
This is NOT a stale bundle — and the emission is pinned
The QA run is pinned to vendored console 09987b68, but the defect was re-verified against objectui origin/main at bb68488 (current at filing time), where the same emission is still present. Additionally:
packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts pins the emitted shape: expect(node).toEqual({ type: 'page:header', recordChrome: true }) (~line 677), plus page:header.recordChrome defaults to true and can be turned off (~line 240).
⚠️Whoever fixes this must change BOTH sides — the emitted shape AND the pin that currently locks it in place. A fixer who changes only one side will go red: change the emitter alone and the pin fails; change the pin alone and the server still rejects the PUT. Budget for both in the same change.
One more constraint on the fix shape: page:header.recordChrome is a declared registry property — packages/components/src/renderers/layout/containers.tsx declares it ({ name: 'recordChrome', type: 'boolean', ... defaultValue: true }, ~line 1644) and consumes it (~lines 1036 / 1510), and the spec-parity pin apps/console/src/__tests__/registry-inputs-spec-parity.test.ts lists ['page:header', 'recordChrome'] (~line 687). So the real decision is whether the property is stripped from the create payload or accepted by the server, not simply deleted from the renderer.
Open Studio and create a page bound to an object (the create path seeds regions from buildDefaultPageSchema(objectDef)).
Save.
Observed: the console PUTs a body containing recordChrome and items; the server rejects it strictly (ADR-0089 D3a); no page is stored. Reproduced 2×.
Dedup
Searched objectstack-ai/objectui for buildDefaultPageSchema, recordChrome, and Studio page-save/strict-rejection symptoms — no open or closed duplicate found.
Source
Extracted from the QA run objectstack-ai/objectstack#7514 (framework a86db175, vendored console 09987b6). Root-cause re-verification is against objectui origin/main @ bb68488.
Decision framing given to the dev (delegated, veto window open): the console complies with ADR-0089 D3a — "accept on server" is not on the table without an upstream ruling (that would be an objectstack-lane card). The deliverable is the synthesiser emitting a spec-canonical, server-accepted shape that preserves the semantics (header chrome on/off, tab items) in whatever spelling the ADR sanctions — measured against the ADR text and the server validator, not guessed. Blind-stripping that silently loses a user's persisted recordChrome: false choice is NOT an acceptable fix shape; if the ADR provides no spec-shaped carrier for that semantic, the dev stops and reports needs_decision instead of dropping semantics.
Both-sides warning from the card honored: the emitter and its own pin (buildDefaultPageSchema.test.ts) change together; the registry declaration in packages/components and the spec-parity pin are NOT to be deleted — the card is explicit that the decision is payload-shape, not renderer-property removal.
Surface constraints vs in-flight: packages/plugin-detail has been added to #4040's tranche-1 exclusion list (constraint update sent to its dev); no other in-flight agent holds this surface.
Two facts about this defect that the original card does not carry, measured in a later QA run — objectstack-ai/objectstack#7695 (record-page-roundtrip, framework 92f26f75, console 09987b6). Not re-filed; recorded here because they change what "fixed" has to mean.
This card was closed by PR #4290 after that run finished, so please read both facts as open questions against the merged fix, not as claims about current main.
1. The create form's Page type defaults to list. The item's steps as written therefore never produce a record page at all — the create path is exercised on a list page unless the type is changed by hand. The framework side corroborates it: packages/spec/src/kernel/metadata-create-seeds.ts seeds page as
(verified on objectstack origin/main00e9196). That also settles a sub-question the run raised: the list seed genuinely isregions: [] — that emptiness is declared, not a synthesis failure.
2. The record seed carries no record:highlights block, even before the rejection. So the 422 is not the only thing standing between the create path and a usable record page; the seed it rejects was already missing the highlight strip. Where that comes from is worth one check by whoever verifies #4290: on objectui origin/main (33c32bf) buildDefaultHighlightsdoes emit record:highlights when highlightFields.length > 0 (packages/plugin-detail/src/synth/buildDefaultPageSchema.ts:501, reached from the default-slot path ~line 798), so the observed absence means either deriveHighlightFields returned empty for the object under test or the create path did not route through that builder. Either answer is actionable; the run could not distinguish them because the PUT never landed.
3. #1541 is not regressed for a record page — the record seed is non-empty. Recording the negative so it is not re-investigated.
Activity
yinlianghui commentedon Aug 11, 2026
CLAIM — session
session_017Qqyix2QcnpUC9XeYVDzx3(objectui whole-repo PM seat), dispatching now.Branch:
claude/issue-4232-studio-page-create-strict. Worktree-first.Decision framing given to the dev (delegated, veto window open): the console complies with ADR-0089 D3a — "accept on server" is not on the table without an upstream ruling (that would be an objectstack-lane card). The deliverable is the synthesiser emitting a spec-canonical, server-accepted shape that preserves the semantics (header chrome on/off, tab items) in whatever spelling the ADR sanctions — measured against the ADR text and the server validator, not guessed. Blind-stripping that silently loses a user's persisted
recordChrome: falsechoice is NOT an acceptable fix shape; if the ADR provides no spec-shaped carrier for that semantic, the dev stops and reports needs_decision instead of dropping semantics.Both-sides warning from the card honored: the emitter and its own pin (
buildDefaultPageSchema.test.ts) change together; the registry declaration inpackages/componentsand the spec-parity pin are NOT to be deleted — the card is explicit that the decision is payload-shape, not renderer-property removal.Surface constraints vs in-flight:
packages/plugin-detailhas been added to #4040's tranche-1 exclusion list (constraint update sent to its dev); no other in-flight agent holds this surface.Generated by Claude Code
yinlianghui commentedon Aug 11, 2026
ACCEPT — PM review of record (session
session_017Qqyix2QcnpUC9XeYVDzx3)。PR #4290 按 emit-canonical 落地,验收要点:
.strict()翻转(DetailView「审批中已锁定」band 不读节点 lockRecord:lockRecord:false 的审批节点上照样显示锁定 + 撤回 #2902,spec 15.0.0)不给任何顶层拼写,但两个语义都有 spec 载体——节点自己的properties袋,且PageHeaderProps.recordChrome/PageTabsProps.items是 objectstack#6776 已声明的 props。语义三项全保(chrome 开/关、tabs 结构),零丢失,无需上报。载体核对用了 vendored spec 17.0.0-rc.6 的真 PageSchema 解析真实发射,不是只读 prose——正是派单要求的测量姿势。recordChrome+actions/fields/statusField+stages/items)。修复形状正确:13 类节点全部路由过唯一的componentNode(type, props)——"什么可以进 page 写载荷"只有一个答案,不是一处一个。slot-override 节点原样保留并钉住(canonicalize 自建的,不动手上递来的)。properties提升到节点上,且每条路径(RegionContent / renderChildren)都走它。registry 声明与 spec-parity pin 按卡片约束未动。unrecognized_keys @ regions.0.components.0 …);CI 20 项收敛全绿。pageType(objectui 本地 fork,parity 测试钉为 local,不进 PUT)与 asideclassName(无载体,create 路径不可达 → Synthesizedasideregion carriesclassName, whichPageRegionSchemarejects — a Reference Rail page has no persistable spelling #4286 finding)点名不并入,处理正确。上游路由:报告中"
PageHeaderProps.title必填 vs 平台默认 header 刻意无 title(渲染器从记录派生)"的矛盾属 objectstack spec 契约问题——本席已代为在 objectstack 立卡转交(见下条链接),不在本 repo 修。Flipping ready + auto-merge。#4232 落地后 plugin-detail 面释放,#4040 批次3 解锁该包。
Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
Two facts about this defect that the original card does not carry, measured in a later QA run — objectstack-ai/objectstack#7695 (
record-page-roundtrip, framework 92f26f75, console 09987b6). Not re-filed; recorded here because they change what "fixed" has to mean.This card was closed by PR #4290 after that run finished, so please read both facts as open questions against the merged fix, not as claims about current
main.1. The create form's Page type defaults to
list. The item's steps as written therefore never produce a record page at all — the create path is exercised on a list page unless the type is changed by hand. The framework side corroborates it:packages/spec/src/kernel/metadata-create-seeds.tsseedspageas(verified on objectstack
origin/main00e9196). That also settles a sub-question the run raised: the list seed genuinely isregions: []— that emptiness is declared, not a synthesis failure.2. The record seed carries no
record:highlightsblock, even before the rejection. So the 422 is not the only thing standing between the create path and a usable record page; the seed it rejects was already missing the highlight strip. Where that comes from is worth one check by whoever verifies #4290: on objectuiorigin/main(33c32bf)buildDefaultHighlightsdoes emitrecord:highlightswhenhighlightFields.length > 0(packages/plugin-detail/src/synth/buildDefaultPageSchema.ts:501, reached from the default-slot path ~line 798), so the observed absence means eitherderiveHighlightFieldsreturned empty for the object under test or the create path did not route through that builder. Either answer is actionable; the run could not distinguish them because the PUT never landed.3. #1541 is not regressed for a record page — the record seed is non-empty. Recording the negative so it is not re-investigated.
Generated by Claude Code
fix(plugin-detail): synthesize page components in the spec `propertie…