立卡门 ① — a defect with a named producer and a now-satisfied unblocker.
finding — filed by the domain:spec execution seat on objectstack-ai/objectstack (session session_013RDBh5DqXd2xnLwvHLgLFr, seat 1), under the multi-repo rule that the seat accepting an upstream PR files the consumer-side follow-up. ⛔ Ungraded and unrouted — domain:*, type and priority belong to this repo's triage. Not claimed.
Blocked-by: objectstack-ai/objectstack#19736
⚠️ That blocker is already satisfied — which is the whole point of this card, and why it is filed now rather than held.
⛔ The line above is deliberately bare and line-leading. It is a machine-greppable reverse index, and the repo's own ratchet reads it as /^\s*(?:>\s*)?(?:[-*+]\s+)??(?:Blocked-by|…):/— leading space, a blockquote, a bullet or a backtick are allowed, **bold is not**. This card was filed with the key wrapped in…` and mid-sentence, which matches nothing; the unlock scan would never have seen it. Corrected in place by the filing seat.
The defect, measured on this repo's current main
main at 0cf2d6644bdb, which is newer than the objectstack pin (.objectui-sha = 87af769e9a3ee28ace099fdd653d3ebd79fe82e2), so this is ⛔ not an artifact of pin lag:
| file |
line |
behaviour |
packages/plugin-form/src/DrawerForm.tsx |
:645, :713 |
pushes collapsible: section.collapsible alone |
packages/plugin-form/src/ObjectForm.tsx |
:1554 |
Boolean(section.collapsible) || Boolean(section.collapsed) — applies the ruling |
⇒ On the drawer arms, a section authored collapsed: true with no collapsible beside it renders permanently closed with nothing on the page that reopens it — the exact defect objectui#9780 measured, still live on this surface while ObjectForm honours the ruling.
⚠️ This is NOT a duplicate of objectui#9780 — that card is closed, and its fix was deliberately scoped
objectui#9780 is closed as completed, by merged PR objectui#9968 («a section declared collapsed installs its disclosure control»). That fix landed on the ObjectForm default arm and deliberately left the drawer arms alone. DrawerForm.tsx:632-635 says so in its own words and names its unblocker verbatim:
push reads section.collapsible alone, so objectui#9780's «collapsed implies collapsible» — applied on the default arm — [is unchanged] on purpose; converging it is the collapsed / collapsible decision.
⭐ That decision is now published, which is what makes this actionable today
The maintainer ruled it on objectui#9780 (comment 5729750150, 2026-09-18, letter A, 「其他同意」): «collapsible: false with collapsed: true is the same contradiction and resolves the same way (collapsed wins, toggle present)». Letters B (refuse the combination at the declaration face) and C (a console.warn) were REFUSED, which is why the remedy is renderer-side and why no lint rule exists.
objectstack-ai/objectstack#19736 publishes that ruling as contract text on FormSectionSchema (packages/spec/src/ui/view.zod.ts), describing both keys and stating explicitly that the implication is a renderer rule and ⛔ not a parse fold — measured: {collapsed: true} parses to {collapsible: false, collapsed: true} verbatim, safeParseAsync agreeing. So the renderer cannot delegate this to parse; each arm resolves it from the declaration itself, exactly as ObjectForm.tsx:1554 does.
That PR carries an at-tier contract-review PASS and is armed for the merge queue. ⇒ the fence this card sits behind is discharged.
Producer
Any hand-authored drawer form view, plus the metadata designer. ⭐ And it is the shape an AI writing metadata hits most easily: «collapsed by default» is a natural intent, collapsed: true is its most natural spelling, and written alone it is exactly the broken one.
Dedupe — query and hit counts, including closed
Suggested shape, ⛔ not a ruling
Converge the two drawer arms onto the same resolution ObjectForm.tsx:1554 uses. ⚠️ Note :689 (const isCollapsed = section.collapsible ? … : …) reads the pair a second time on the same arm — re-derive both sites rather than patching the push alone, and ⚠️ re-read the line numbers above against main before editing: they are this seat's reading of 0cf2d6644bdb and this repo moves.
Generated by Claude Code
立卡门 ① — a defect with a named producer and a now-satisfied unblocker.
finding— filed by thedomain:specexecution seat onobjectstack-ai/objectstack(sessionsession_013RDBh5DqXd2xnLwvHLgLFr, seat 1), under the multi-repo rule that the seat accepting an upstream PR files the consumer-side follow-up. ⛔ Ungraded and unrouted —domain:*,typeandprioritybelong to this repo's triage. Not claimed.Blocked-by: objectstack-ai/objectstack#19736
⛔ The line above is deliberately bare and line-leading. It is a machine-greppable reverse index, and the repo's own ratchet reads it as
/^\s*(?:>\s*)?(?:[-*+]\s+)??(?:Blocked-by|…):/— leading space, a blockquote, a bullet or a backtick are allowed, **bold is not**. This card was filed with the key wrapped in…` and mid-sentence, which matches nothing; the unlock scan would never have seen it. Corrected in place by the filing seat.The defect, measured on this repo's current
mainmainat0cf2d6644bdb, which is newer than the objectstack pin (.objectui-sha=87af769e9a3ee28ace099fdd653d3ebd79fe82e2), so this is ⛔ not an artifact of pin lag:packages/plugin-form/src/DrawerForm.tsx:645,:713collapsible: section.collapsiblealonepackages/plugin-form/src/ObjectForm.tsx:1554Boolean(section.collapsible) || Boolean(section.collapsed)— applies the ruling⇒ On the drawer arms, a section authored
collapsed: truewith nocollapsiblebeside it renders permanently closed with nothing on the page that reopens it — the exact defect objectui#9780 measured, still live on this surface whileObjectFormhonours the ruling.objectui#9780 is closed as completed, by merged PR objectui#9968 («a section declared
collapsedinstalls its disclosure control»). That fix landed on theObjectFormdefault arm and deliberately left the drawer arms alone.DrawerForm.tsx:632-635says so in its own words and names its unblocker verbatim:⭐ That decision is now published, which is what makes this actionable today
The maintainer ruled it on objectui#9780 (comment 5729750150, 2026-09-18, letter A, 「其他同意」): «
collapsible: falsewithcollapsed: trueis the same contradiction and resolves the same way (collapsed wins, toggle present)». Letters B (refuse the combination at the declaration face) and C (aconsole.warn) were REFUSED, which is why the remedy is renderer-side and why no lint rule exists.objectstack-ai/objectstack#19736publishes that ruling as contract text onFormSectionSchema(packages/spec/src/ui/view.zod.ts), describing both keys and stating explicitly that the implication is a renderer rule and ⛔ not a parse fold — measured:{collapsed: true}parses to{collapsible: false, collapsed: true}verbatim,safeParseAsyncagreeing. So the renderer cannot delegate this to parse; each arm resolves it from the declaration itself, exactly asObjectForm.tsx:1554does.That PR carries an at-tier contract-review PASS and is armed for the merge queue. ⇒ the fence this card sits behind is discharged.
Producer
Any hand-authored drawer form view, plus the metadata designer. ⭐ And it is the shape an AI writing metadata hits most easily: «collapsed by default» is a natural intent,
collapsed: trueis its most natural spelling, and written alone it is exactly the broken one.Dedupe — query and hit counts, including closed
mcp__github__search_issuesonobjectstack-ai/objectui, query drawer form section collapsed implies collapsible unopenable disclosure control →total_count4, all closed: DrawerForm's no-sections field builder dropsvisibleWhen/readonlyWhen/requiredWhen(andgroup) — ModalForm's identical builder carries them #4755, DrawerForm never calls deriveFieldGroupSections — a drawer form ignores the object's declared fieldGroups that ObjectForm and ModalForm both honour #4774, finding(docs):collapsible.mdx's schema block names a requiredchildrenrow the renderer never reads, and omits the requiredcontentthe renderer does read #8197, ModalForm 显式多 section 表单:每个 section 独立 <form>,提交时丢弃第 2+ 个 section 的值 #2153 — none about this pair on the drawer arms.closed_by_pull_requests= objectui#9968 (MERGED)./search/issueswas not used: it is refused for this session with a body carrying nototal_count, so a naive parse prints zero hits and reads exactly like a clean dedupe.Suggested shape, ⛔ not a ruling
Converge the two drawer arms onto the same resolution⚠️ Note ⚠️ re-read the line numbers above against
ObjectForm.tsx:1554uses.:689(const isCollapsed = section.collapsible ? … : …) reads the pair a second time on the same arm — re-derive both sites rather than patching thepushalone, andmainbefore editing: they are this seat's reading of0cf2d6644bdband this repo moves.Generated by Claude Code