Repository navigation
finding(components+): family D — the ~60 registrations that read NEITHER body nor children, measured across all 25 registering packages #9256
Description
Activity
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Sep 12, 2026 Dispatching —
domain:uiPM seat (os-tesla), R16, 2026-09-12T06:4xZClaimed:
os-devseat, by thedomain:uiPM seat (os-tesla), R16.Clause-②: yes
Clause-②
yes, mechanically and not on the "not sure" rule: the deliverable narrows published authoring types (?: neveron the TypeScript face) and refuses keys by name on the zod mirror.The ruling this inherits — ⛔ not re-opened
Summon #17, decision batch #2, maintainer 「同意」 (objectui#8284 comment 5572150897), executed for family A+B by PR objectui#9254. The shape to copy is settled:
?: neveron the TS face,aliasKeyRefusalon the zod mirror, and ⭐ the tombstone kept a MEMBER sozod-mirror-parity's key sets stay equal.⭐ Read objectui#9254 before planning — it is the template AND the warning
Its seat corrected the ruling's own cardinal by measuring: 114 registrations, not 34; 13 reading one channel, not 17/17. The old figures were grep artifacts — a docblock and a prefix match — and it proved that with lit controls in both directions. ⇒ your family-D verdict is a claim of ABSENCE across 25 packages, which is the most fragile kind of reading there is. ⛔ Do not produce it with grep.
⛔ Out of scope — ruled, do not drift into them
Family C (the 9 live
children || bodyfallbacks) is with the maintainer. Family E (sidebar-*, theany-typed registrations) is frozen — giving those a declaration is new published surface. The dev-time warning slice is severed. If your work starts needing any of these, stop and report.
Generated by Claude Code
Extended measured table — all 24 registering packages, not one (ruling execution step 1, family D)
Posted before any declaration moves, as the objectui#8284 ruling requires and as PR objectui#9254 did for families A+B. This continues the table on objectui#8284 comment 5643712599; every figure below is re-derived on this branch, and the two that moved are called out.
Instrument
The same TypeScript type checker instrument, extended from one package to 46 programs: every workspace package (40),
apps/console,apps/siteand the fourexamples/*. Eachbody/childrenread is an AST property access, element access or binding element whose OBJECT expression is asked for its TYPE, and the read is filed under that type. Comments and docblocks are not AST nodes, so they cannot score. 1,604 source files entered the programs (tests,dist,node_modulesexcluded).Two instrument defects were found and fixed while extending it. Both produced WRONG answers silently, so they are reported rather than quietly corrected:
- Attribution by bare type NAME pools unrelated types.
__typeis the symbol name of EVERY anonymous object type literal andRecordof every mapped-type instantiation. Filing reads under bare names put 20 registrations into "reads BOTH" that read nothing — sixapp-shellrenderers whose props type is an inline literal, theplugin-chartsarms,plugin-detail,plugin-markdown,plugin-editor,layout. Identity is now NAME plus the file and line of the type's own declaration. - An unbuilt tree answers
any, andanyreads as NEITHER.@object-ui/typesresolves throughdist/*.d.ts; beforeturbo run build,GridSchemainrenderers/layout/grid.tsxresolved toanyandgridscored NEITHER — it readschildren. The reading of record is taken on a fully built tree (43 of 43 build tasks green) and the module-resolution probe reports 0 unresolved-module diagnostics.
Lit controls, both directions (the instrument is proven able to miss and able to hit):
- grep-hit / checker-non-hit, inherited: the
schema.bodydocblock inrenderers/layout/box.tsx;schema.bodyExtra/schema.bodyShapeinaction/action-button.tsxandaction/action-icon.tsx(prefix match). - grep-hit / checker-non-hit, new in family D — four kinds the one-package sweep never met:
packages/plugin-chatbot/src/renderer.tsxwritesbody: schema.requestBody— an HTTP request body, three times, in the three registrations family D is about to narrow.packages/components/src/renderers/complex/carousel.tsxandcomplex/resizable.tsxcarrybody:inside EXAMPLE schema literals in their own registration metadata (defaultProps) — authored documents, not reads.packages/plugin-view/src/index.tsxrenders a bare{children}from its React props.SchemaRendererSTRIPSchildrenandbodyfrom the props bag it spreads, so that expression can never receive the authored channel.packages/layout/src/index.tssaysschema.childrenfour times in prose.
- Positive control: the same instrument scores 36 schema-attributed reads filed under the 18 published declarations (families A, B, C below), including two the one-package sweep could not see.
Population
measured here objectui#8284's reading registering packages 24 "25" registrations 219 114 distinct registered typenames199 — ⚠️ 24, not 25.apps/consoleregisters nothing throughComponentRegistry.register— it holds 21registerLazyaliases pointing at plugin packages, and the declarations those resolve to live inside the plugin. That is the likeliest source of the card's 25; it is named here rather than counted, because a lazy alias contributes no declaration to narrow.Summary — the whole population, by what its renderer READS
disposition registrations note reads childrenonly9 family A — unchanged from the one-package table reads bodyonly6 family B — two new, both outside packages/componentsreads BOTH (live fallback) 15 family C — 9 published declarations + 6 inline types reads NEITHER, published declaration 77 family D — this card reads NEITHER, local or inline declaration 23 no published face to narrow renderer prop typed any77 family E — frozen renderer prop typed bare BaseSchema9 family E — the sidebar-*buckettotal 219 ⚠️ The ~60 figure is superseded: 77. It was one package's reading. Family D reaches 12 packages:components57,plugin-dashboard4,plugin-ai3,plugin-chatbot3,plugin-view3, and one each inplugin-detail,plugin-designer,plugin-calendar,plugin-list,plugin-report,plugin-timeline,layout. 20 of the 77 are outsidepackages/components— the truncated sweep could not have seen them.Family B gained two rows the one-package sweep could not see
registered typedeclaration read site package listListViewRuntimePropsthe schema.bodyread inplugin-list/src/index.tsxpackages/plugin-listlist-viewListViewRuntimePropssame packages/plugin-list⚠️ Notelist:packages/componentsregisterslistwithListSchema, which reads NEITHER, andplugin-listregisterslistwith a declaration that readsbody. That is the collision hazard below, and it is whylistis held out.The generic traversers — the readers no per-component sweep sees
reader what it reads verdict for family D packages/react/src/SchemaRenderer.tsxdestructures childrenandbodyOUT of the props bag⭐ it renders NEITHER generically — it hands the node to the registered component and strips both keys, so "the renderer reads neither" means the content is dropped, full stop packages/core/src/validation/schema-validator.tsschema.childrenelseschema.bodyVALIDATION recursion only — it descends into authored content to validate it; it renders nothing packages/components/src/renderers/layout/semantic.tsxschema.childrenelseschema.bodya DYNAMIC-tag factory, 7 tag names: aside main header nav footer section articlepackages/components/src/renderers/basic/html-elements.tsxschema.childrenelseschema.bodya DYNAMIC-tag factory, 37 HTML tag names packages/components/src/renderers/layout/containers.tsxschema?.body/schema?.children, 16 sitesthe any-typed page-container registrations:tabs card accordion section header footer sidebarpackages/cli/src/commands/validate.ts,packages/runner/src/LayoutRenderer.tsx,packages/vscode-extension/src/providers/SchemaValidator.tsdata.children/item.childrenvalidators and nav-item trees, not the node content channel ⭐ The two dynamic-tag factories DO read the channel, and they were the real risk to a NEITHER verdict. Their 44 tag names were enumerated and intersected with the family-D type names: the intersection is empty.
containers.tsxis the one that does collide —accordionandtabsare family-D names it also claims — and both are held out below.The hazard is bigger than nine: 19
typenames carry 2+ registrationsComponentRegistry.registerwrites the namespaced key AND a bare-name fallback, and the bare-name write is last-one-wins (the method's own comment says so). Which declaration governs an authored node of such a type therefore depends on module import order.menu text image icon button form calendar card tabs grid accordion sidebar alert list timeline chartplus the two dynamic-tag registrations and the two dynamicfieldTyperegistrations.Eight of these are cross-PACKAGE collisions the one-package sweep could not see:
form(components + plugin-form),calendar(components + plugin-calendar),grid(components + plugin-grid),list(components + plugin-list),alert(components + plugin-detail),menu(components + app-shell),chartandtimeline(inside their own plugin).Family D — 77 registrations, of which 66 are narrowable and 11 are held out
Held out, with the specific measurement each still needs:
held why accordion,button(UIActionSchemaarm),calendar,icon(both arms),image,list,tabs,text,timelinethe typename carries 2+ registrations with DIFFERENT declarations; which one governs is unmeasured — the same reasonsidebarwas held out of family Binput(InputSchema)InputShorthandSchemais declared asOmitof it, so a tombstone here propagates onto theemail/passwordshorthand face, whose registrations areany-typed — family E, frozenchatbotfamily,bodychannel onlythe parity ledger already records this key: "TS declares a rendered slot; the mirror declares Recordof unknown — two different meanings of one key, a naming collision to rule on". Theirchildrenchannel is clean and is narrowedThe remaining 66 registrations over 64 published declarations are narrowed: both channels tombstoned,
?: neveron the TypeScript face and a by-name refusal on the zod mirror, the tombstone kept a MEMBER sozod-mirror-parity's key sets stay equal.⚠️ Real authored usage of the channels about to be refused — NON-ZERO, and it is in PUBLISHED material againA brace-matched object-literal census over 7,182 files (positive control: the same scan finds 431 documents authoring the channel those renderers DO read, so the query is live). It found 11 hits; the false-positive guard matters, since
"pageType": "detail"matched as a node of typedetailuntil the key name was anchored.Seven are real documents, and every one renders an EMPTY element today:
document node authored what the renderer reads examples/schema-catalog/src/schemas/components-overlay-dialog/dialog-trigger.jsondialogchildrencontentexamples/schema-catalog/src/schemas/components-overlay-drawer/basic-drawer.jsondrawerchildrencontentexamples/schema-catalog/src/schemas/components-overlay-popover/basic-popover.jsonpopoverchildrencontentexamples/schema-catalog/src/schemas/components-disclosure-collapsible/basic-collapsible.jsoncollapsiblechildrentrigger+contentcontent/docs/components/overlay/dialog.mdxDialogSchemadocuments childrenas the content channelcontentcontent/docs/components/overlay/drawer.mdxDrawerSchemadocuments childrencontentcontent/docs/components/overlay/popover.mdxPopoverSchemadocuments childrencontent⭐ The four catalog documents are the demo gallery — the rendered showcase — and the three docs pages are the published component reference, which is where an author learns the spelling. The docs page and the catalog document agree with each other and disagree with the renderer: the reference TEACHES the dead channel, so this is not seven authors slipping, it is the documentation manufacturing the defect.
collapsibleis objectui#8197, found for the third time.The four remaining hits are
packages/typesfixtures and the chatbot mirror's own declaration line; they are triaged in the PR, not migrated silently.
Generated by Claude Code
- Attribution by bare type NAME pools unrelated types.
os-dev-report
{ "issue": 9256, "status": "done", "branch": "claude/issue-9256-family-d-content-channel", "pr": "https://github.com/objectstack-ai/objectui/pull/9261", "premise_still_valid": true, "summary": "Extended objectui#8284's compiler-API read-site instrument from one package to 46 programs (every workspace package plus the apps and examples, 1,604 source files) and posted the measured table on the card before any declaration moved (comment 5644340762). The population is 219 registrations in 24 registering packages, not 25: apps/console registers nothing directly, it holds 21 registerLazy aliases. Family D is 77 registrations, not the card's ~60, and 20 of them are outside packages/components. 64 registrations over 62 published declarations are narrowed: body and children become `?: never` on the TypeScript face and a by-name retirementTombstone refusal on the zod mirror, kept a MEMBER so zod-mirror-parity's key sets stay equal; each tombstone's guidance names the keys that declaration's renderer DOES read, derived from the same instrument. Eleven registrations are held out and named with the measurement each still needs. Two instrument defects were found and fixed while extending it, both of which answered wrong SILENTLY: attribution by bare type NAME pools `__type` and `Record` across unrelated inline types (it put 20 registrations in 'reads BOTH' that read nothing), and on an unbuilt tree `@object-ui/types` resolves to `any`, which reads as NEITHER (grid scored NEITHER that way; it reads children). Assignee was empty on arrival, as dispatched; I never set it.", "tests": "ALL on 7bde46114, the branch head, from the committed tree, every heavy command through scripts/pm/os-verify-lock.sh and read from its VERDICT line. BUILD: turbo run build --filter='!@object-ui/site' --concurrency=2 -> 43 successful, 43 total. TSC (downstream direction, the one a contract narrowing lands on): turbo run type-check --filter='...@object-ui/types' -> 77 successful, 77 total. VITEST: packages/types/ -> 180 files / 4101 tests passed; packages/components/ + packages/types/ -> 446 files / 6539 tests passed; examples/schema-catalog/ -> 31 files / 2151 tests passed; examples/schema-catalog/ + packages/core/ + packages/react/ -> 262 files / 6336 tests (green after the objectui#9254 live control this PR supersedes was updated). GATES (each exit code captured by redirect-then-capture, never through a pipe): check:doc-snippets, check:doc-examples, check:doc-types (188 docs / 1107 blocks / 897 type literals judged), check:doc-fences, check:doc-example-ids, check-changeset-presence (25 source files of 1 released package, 1 changeset), changeset:check (no changeset declares major), check:control-bytes (7,449 tracked text files), check:new-line-citations (0 new cross-file line citations), check:handler-key-reads, check:spec-symbols, check:action-forward-parity, check:designer-field-key-parity, check:readme-exports, check:sdui-registration-pins, check:dist-completeness, check-governed-queue-guard --test (NOT GOVERNED, 35 paths, 0 matched) -- all exit 0. One gate name in my dispatch does not exist here: `check:changeset-no-major` exits 254 with 'Command not found' (MODULE_NOT_FOUND class = NOT MEASURED, not a red gate); this repo spells it `changeset:check`, which I ran instead and which reports the same verdict. LINT: whole population read, no narrowing argument needed -- eslint . --no-inline-config --format json selected 4,877 files by eslint's own config; the 35 files this branch touches carry 0 errors and 98 warnings, every one @typescript-eslint/no-explicit-any and NONE on a line this branch added (checked against the diff's added-line set); repo totals 95 errors / 13,008 warnings, all outside this diff. ABLATION -- both faces, both readers, from the committed tree, each leg prechecking git hash-object against the HEAD blob, proving the mutation on disk by marker count, and restoring under trap ... EXIT INT TERM with absolute paths, proved by an empty git diff HEAD and never by an exit code: BASELINE both files == HEAD blob, vitest GREEN 631/631, tsc exit 0. LEG 1 (delete DialogSchema's children refusal arm from the ZOD face; markers 18 -> 17, 8 lines removed): vitest RED 4 failed / 627 passed AND tsc RED, 2x TS2322 in zod-mirror-parity.test.ts's TYPED ledger -- a second, independent reader. LEG 2 (delete DialogSchema's `children?: never` from the TYPESCRIPT face; occurrences 9 -> 8): vitest GREEN 631 passed (631) and tsc RED with TS2578 Unused '@ts-expect-error' directive plus a TS2322 ledger error -- reporting only vitest would have recorded NOT MEASURED as green, which is exactly objectui#9254's lesson. RESTORE: git diff HEAD empty for both files, vitest GREEN 631/631, tsc exit 0. CROSS-PACKAGE REVERSE VALIDATION (proving the consumer reads the rebuilt .d.ts and not a cache): a temporary probe in packages/components authoring { type: 'dialog', children: [...] } as DialogSchema turned pnpm --filter @object-ui/components type-check RED with TS2322 'Type ... is not assignable to type undefined'; removing it returned exit 0 and git status is empty. AUTHORED-USAGE CENSUS: 7,182 files scanned, positive control 431 documents authoring the channel those renderers DO read; 11 hits, of which 7 are real documents rendering empty today and are fixed in this PR. NOT MEASURED and declared to CI: the full pnpm test, turbo run type-check across all 41 packages (only the 77-task downstream closure of @object-ui/types ran here), and the rest of the lint.yml gate farm.", "mcp_calls": "1 - one search_issues for dedup, which FAILED with 'API rate limit already exceeded for user ID 327383522'. Everything else went over repo-scoped REST (probe returned HTTP 200 at the start) plus git.", "open_questions": [ { "question": "The `body` key of the three chatbot faces is held out of this card. `zod-mirror-parity.test.ts`'s ledger already records it verbatim: the TypeScript face inherits `body` as a content channel (SchemaNode or SchemaNode[]) while the mirror declares it as Record of unknown, 'additional API body params' -- 'Two different meanings of one key -- a naming collision to rule on, not a widening.' The renderer reads neither: it reads `schema.requestBody`. So the key is dead on BOTH readings, but tombstoning it would silently pick one of the two declared meanings.", "options": [ "A - rule that the mirror's `body` is the stray spelling: refuse `body` on both faces (the family-D tombstone) and keep `requestBody`, which is the key the renderer actually reads and which the enhanced/floating faces already mirror alone", "B - rule that `body` is the canonical API-params spelling and `requestBody` is the alias: fold or alias-refuse `requestBody` instead, and leave `body` live as a record", "C - leave both declared as they are and record the collision as accepted drift" ], "recommendation": "A, because it is the only option consistent with what was measured rather than with declaration history: no renderer read consumes `body` under any meaning (the three registrations read `schema.requestBody`), the two sibling faces ChatbotEnhancedSchema and ChatbotFloatingSchema already mirror `requestBody` alone and declare no `body` at all, and B would newly invite a key nothing reads. But it changes a key the ledger flags for a RULING, so it is not mine to take under this card." } ], "out_of_scope_findings": [ "noted, NOT FILED (dedup channel unavailable, handing to PM to file): two published declarations declare a component `type` literal that a DIFFERENT registration serves -- `AppComponentSchema` declares `app`, and `app` is rendered by `PageNodeSchema` (family C, reads both channels); `DetailViewSchema` declares `detail-view`, and that name is registered in plugin-detail with an `any`-typed renderer while `DetailViewSchema` itself is the declaration of the `detail` registration. An author type-checking against either face is authoring keys for a renderer that is not the one their node reaches. Both were measured here (that is why both are held out of the narrowing), but I could not run the required duplicate search: REST /search/* is refused by the egress proxy by design, and the one targeted MCP search_issues call returned 'API rate limit already exceeded for user ID 327383522'. Filing unchecked is a forbidden shape, so the finding goes to PM with its evidence.", "noted, not filed: the multi-registration hazard is 19 `type` names, not the card's nine -- eight of them cross-PACKAGE collisions a one-package sweep cannot see (`form`, `calendar`, `grid`, `list`, `alert`, `menu`, `chart`, `timeline`). The mechanism is measured: ComponentRegistry.register writes a bare-name fallback LAST-ONE-WINS, so which declaration governs depends on import order. Successor: this card itself -- it is published in the table comment and in the PR, and it is the reason for nine of the eleven hold-outs.", "noted, not filed: the chatbot `body` collision above is already recorded in-repo, verbatim, in zod-mirror-parity.test.ts's KnownDrift ledger. A new card would duplicate an existing record; successor is whoever answers the open question.", "noted, not filed: `content/docs/components/overlay/{dialog,drawer,popover}.mdx` documented `children` as the content channel for renderers that read `content` -- the published reference was manufacturing the defect this card exists to close, not merely failing to mention it. FIXED IN THIS PR as an instance of the card, together with the four schema-catalog documents that followed it.", "noted, not filed: the instrument defects this run found (bare-name type attribution pooling `__type`/`Record`; an unbuilt tree resolving published declarations to `any`) are properties of the ad-hoc sweep, not of the repo. Nothing in the tree carries them today. Successor: whoever runs the next family (C or E) -- both are written up in the table comment so the next sweep starts from a correct instrument." ] }
Generated by Claude Code
Answer to the open question on the chatbot
bodykey — ⛔ route, do not ruleYour recommendation (option A) is consistent with everything measurable here, and I verified the load-bearing half of it independently:
fact measurement the renderer reads requestBody, notbodypackages/plugin-chatbot/src/renderer.tsx:85,:274,:412— all three spellbody: schema.requestBody, i.e.requestBodyis what gets sent as the HTTP bodythe rename already happened on the declaration side packages/types/src/zod/base.zod.ts:123— "declaration renamed the key torequestBody…"the mirror's omission is deliberate, not an oversight packages/types/src/zod/complex.zod.ts:656— "requestBodyis deliberately NOT in this pick."the two sibling faces carry requestBodycomplex.zod.ts:707,:745—requestBody: chatbotRequestBodyArm()⇒ nothing reads
bodyunder either meaning, exactly as you reported.⭐ But the ruling is already someone else's, and the card already exists
objectui#8572 —
ChatbotSchema.body accepts more than the declared contract— is open, labelleddomain:spec, and is this same key, this same collision, already measured with a live control:complex.zod.ts#ChatbotSchemamirrors the chat API's body params asz.record(z.string(), z.unknown()).optional(). That is WIDER thanBaseSchemaCore.body, which is the single-or-list node slot. It is the only wider redeclaration among the 109 base-key redeclarations across the component union's arms — the other 108 are equal or narrower.and it carries the reachability measurement your question implies but does not have:
document main objectui#8501 head chatbot node at the ROOT ACCEPTED ACCEPTED same node inside card.body[]REFUSED ACCEPTED same node inside div.children[]REFUSED ACCEPTED control — nested off-spec iconACCEPTED REFUSED ⇒ ⛔ Keep the three chatbot faces held out of objectui#9261, exactly as you did. Do not tombstone
bodythere. Deciding it inside a family-D narrowing would pick one of two declared meanings silently — which is the precise thing objectui#8572 exists to prevent, and it is adomain:speccontract call, not adomain:uione.I am not ruling A here, and I am not filing a new card: filing would duplicate objectui#8572. Your evidence — the three
schema.requestBodyread sites and the two sibling faces — is carried onto objectui#8572 as the read-site half it was missing, since its own table measures acceptance width but not what the renderer consumes.Two notes on your report
check:changeset-no-majordoes not exist in this repo. You were right to classify the254/Command not foundas NOT MEASURED rather than a red gate, and right to runchangeset:checkinstead. That wrong gate name came from my dispatch; the dispatch template is being corrected, not your run.- Your
search_issuesfailure was environmental, not yours: the MCP GitHub server is rate-limited on its own identity (user ID327383522), independently of the repo token. ⭐ Refusing to file unchecked was the right call. I ran the dedup by enumerating all 452 open issues (complete: 464 items = 100+100+100+100+64, page 6 empty, matchingopen_issues_count) and filed what survived:- objectui#9264 — the bare-name
last-one-winsregistry hazard.⚠️ Filed with your counts marked explicitly unverified by me: I re-read and confirmed the mechanism (Registry.ts:179,:185,:833;public-blocks.ts:47) but did not re-derive the 19 names or the eight cross-package ones. Since both instrument defects you found answered wrong silently, an unreplicated count from that run is a lead, not a result — the card says so. - objectui#9263 — the
app/PageRenderer/PageNodeSchemacollision.⚠️ Your second example did not survive re-measurement and is not in the card:detail-viewregistersDetailViewRenderer(plugin-detail/src/index.tsx:284), which isReact.FC<{…}>at:241, notany, and its wrapper casts toDetailViewSchemaat:275— declaration and registration agree there, by documented design. Theapphalf held and got sharper:PageRendereris typedschema: PageNodeSchema(page.tsx:475) and is registered under five names (page/app/utility/home/record), of which onlyappis measured.
- objectui#9264 — the bare-name
Generated by Claude Code
os-dev-report
{ "issue": 9256, "status": "done", "branch": "claude/issue-9256-family-d-content-channel", "pr": "https://github.com/objectstack-ai/objectui/pull/9261", "premise_still_valid": true, "summary": "MERGE FOLLOW-UP on the earlier report, which stands unchanged otherwise. `origin/main` moved to 20b507aff0 while this branch was in flight; merged with `git merge origin/main` into merge commit 502660a19 and pushed to the same branch -- never rebased, never amended, never force-pushed, and the branch's earlier history is byte-identical. PR 9261 is `mergeable: true` again; `mergeable_state` is now `blocked`, which is the draft-plus-checks-running state, not `dirty`. Exactly ONE conflict, and it is the one this PR's body predicted in advance: `examples/schema-catalog/test/overlay-trigger-mirror-6939.test.tsx`, where objectui#9254 rewrote the `tooltip` half of one `it` block and this card rewrote the `context-menu` half. Resolved by keeping BOTH refusals -- objectui#9254's live control ended on its own written terms ('that verdict needs a cross-package sweep before it can be acted on', and this card IS that sweep), and the reading about `tooltip` is now kept honest by the key-scoped control instead. Nothing else conflicted: the two cards narrow DISJOINT declarations, so the four shared `packages/types` files auto-merged and the `tombstone.zod.ts` import lists merged into their union. On @object-ui/core's export surface, which the coordinator flagged as the likely second conflict site: this diff changes no file under `packages/core` at all, so objectui#9258's new `optionDisplayLabel` export never met it -- verified by the merge output and by `git diff --name-only`. Nothing generated needed regenerating: `pnpm-lock.yaml` is byte-identical across the merge (empty `git diff` over it); `pnpm install` was re-run anyway and exited 0. A duplicate-member scan over every edited interface reports 0 duplicated `body` / `children` declarations.", "tests": "ALL RE-RUN on the merge commit 502660a19, from the committed tree, each heavy command through scripts/pm/os-verify-lock.sh and read from its VERDICT line. BUILD: turbo run build --filter='!@object-ui/site' --concurrency=2 -> 43 successful, 43 total. TSC: turbo run type-check --filter='...@object-ui/types' (the downstream closure) -> 77 successful, 77 total, 0 `error TS` lines. VITEST: pnpm exec vitest run packages/types/ packages/components/ examples/schema-catalog/ -> Test Files 478 passed (478) / Tests 8778 passed (8778). GATES, all exit 0: check:doc-snippets, check:doc-examples, check:doc-types, check:doc-fences, check:doc-example-ids, check:control-bytes, check:new-line-citations, check:handler-key-reads, check:spec-symbols, check-changeset-presence, changeset:check; check-governed-queue-guard --test -> NOT GOVERNED, 35 paths, 0 matched. LINT, whole population re-read on the merge commit: eslint . --no-inline-config --format json selected 4,879 files by eslint's own config; the 35 files this branch touches carry 0 errors and 98 warnings, every one @typescript-eslint/no-explicit-any and NONE on a line this branch added; repo totals 95 errors / 13,006 warnings, all outside this diff. ABLATION RE-RUN IN FULL, because the merge touched both files its legs mutate: baseline both files == HEAD blob, vitest GREEN 631/631, tsc exit 0; LEG 1 (delete DialogSchema's children arm from the ZOD face, markers 18 -> 17, 8 lines removed) vitest RED 4 failed / 627 passed AND tsc RED with 2x TS2322 in the parity ledger; LEG 2 (delete DialogSchema's `children?: never` from the TS face) vitest GREEN 631 passed and tsc RED with TS2578 plus a TS2322 ledger error; restore proved by an empty `git diff HEAD` on both files, then GREEN/exit 0 again. The one number that moved is itself proof the merge landed: the baseline count of `children?: never` in packages/types/src/overlay.ts is now 10, not 9 -- objectui#9254's TooltipSchema tombstone is the tenth. CI ON THE PUSHED HEAD 502660a19: it has started -- 36 check runs, of which 28 success, 3 skipped, 5 still in progress (Test shards 1-4 of 4, and Type Check) and ZERO failures at the time of this report. That is `in_progress`, not green: I am reporting the count and the conclusions as read, and I am NOT waiting for the remaining five, per the coordinator's instruction. The previous head 7bde46114 indeed had zero check runs; it no longer matters, since the branch head is now the merge commit.", "mcp_calls": "1 for the whole run - the one dedup search_issues that failed with 'API rate limit already exceeded for user ID 327383522'. The merge round added none: branch, PR, label, comment and check-run reads all went over repo-scoped REST plus git.", "open_questions": [ { "question": "Unchanged from the first report, and the coordinator has said they will rule on it separately: the `body` key of the three chatbot faces is held out. The TypeScript face inherits `body` as a content channel while the mirror declares it as `Record` of unknown, 'additional API body params'; zod-mirror-parity's ledger already records this verbatim as 'two different meanings of one key -- a naming collision to rule on, not a widening'. The renderer reads neither spelling of it: it reads `schema.requestBody`.", "options": [ "A - refuse `body` on both faces (the family-D tombstone) and keep `requestBody`, the key the renderer reads and the only one the enhanced/floating faces mirror", "B - treat `body` as the canonical API-params spelling and alias-refuse `requestBody` instead", "C - record the collision as accepted drift and change nothing" ], "recommendation": "A, on the measurement rather than on declaration history: no renderer read consumes `body` under either meaning, and the two sibling faces already mirror `requestBody` alone. Still not mine to take under this card -- it is a key the ledger flags for a ruling." } ], "out_of_scope_findings": [ "filed by the PM with my evidence (per their message, so NOT re-filed here): the two declarations whose own `type` literal is served by a different registration -- `AppComponentSchema` declares `app` while `PageNodeSchema` renders it, and `DetailViewSchema` declares `detail-view` while that name is registered with an `any`-typed renderer.", "noted, not filed: the multi-registration hazard is 19 `type` names, not the card's nine, eight of them cross-PACKAGE (`form`, `calendar`, `grid`, `list`, `alert`, `menu`, `chart`, `timeline`); ComponentRegistry.register's bare-name fallback is last-one-wins, so which declaration governs depends on import order. Published in the table comment and the PR; it is the reason for nine of the eleven hold-outs.", "noted, not filed: the chatbot `body` collision is already recorded in-repo, verbatim, in zod-mirror-parity.test.ts's KnownDrift ledger; a new card would duplicate it, and the coordinator is ruling on it.", "noted, not filed: `content/docs/components/overlay/{dialog,drawer,popover}.mdx` documented `children` as the content channel for renderers that read `content` -- the published reference was manufacturing this card's defect. FIXED IN THIS PR with the four schema-catalog documents that followed it.", "noted, not filed: the merge conflict this PR predicted is itself a reading worth keeping -- two cards executing one ruling in per-family PRs will collide in any test that carries a cross-family live control. The resolution pattern (keep both refusals, replace the cross-family control with a key-scoped one) is written into the merge commit message for whoever lands families C or E." ] }
Generated by Claude Code
os-dev-report
{ "issue": 9256, "status": "done", "branch": "claude/issue-9256-family-d-content-channel", "pr": "https://github.com/objectstack-ai/objectui/pull/9261", "premise_still_valid": true, "summary": "RED-CI FOLLOW-UP; the two earlier reports stand. The failure was mine and was exactly what the coordinator diagnosed: narrowing CalendarViewSchema added `body` and `children` as declared members, so the interface went from 13 own keys to 15, and `packages/plugin-calendar/src/readme-calendar-view-schema.test.ts` holds the README's prose figure to the interface. Fixed at the prose, not at the pin. ⛔ NOT a bare number swap: 15 counts two members an author can never write, so the README now states both halves -- 13 authorable keys, which are the ones its listing carries, plus two REFUSALS counted because the interface declares them and omitted from the listing because the listing is the authorable surface, with the reason (no renderer read consumes either channel for a calendar-view node; it renders events computed from `data`) and the card number. SECOND STALE CLAIM FOUND BY THE SAME STANDARD, which a bare number swap would have missed: `content/docs/api/schema-reference.md`'s shared BaseSchema table described `children` as 'Alias for `body`'. Nothing folds one into the other at any point -- that sentence is the belief objectui#8284 exists to correct, on the reference page an author reads before writing either key. Both rows now say their types are BaseSchema's and point at a new note stating the real rule: two channels, which one a node renders is per component and measured, the other tombstoned (naming objectui#9254 and objectui#9256). ENUMERATED, NOT INFERRED, per the coordinator's warning: every .md / .mdx under packages/, content/, docs/, apps/ and examples/ was scanned for count-shaped prose (`declares N keys`, `N keys of its own`, `N declared keys`, `N members`, `N properties`, and the word-number forms) and for exhaustiveness-shaped prose (`all/every/complete/exhaustive ... keys`) within the 337 doc lines that mention any of the 62 narrowed declarations. Exactly two live claims move, both fixed here. Two near-misses checked and cleared: `packages/plugin-form/README.md` and `content/docs/plugins/plugin-form.mdx` state 23 keys for `FormField`, an interface this card does not touch; `docs/audits/2026-08-zod-to-json-schema-fidelity.md` counts `AnyComponentSchema` union ARMS, and this card adds and removes none. The 23 per-type tables in schema-reference.md make no exhaustiveness claim -- only the BaseSchema table does, and BaseSchema is untouched. I also re-checked `packages/plugin-dashboard/README.md`, which main changed after my enumeration: 14 mentions of `DashboardComponentSchema`, no key count, no exhaustiveness claim.", "tests": "CI IS GREEN on the pushed head 44e3eb2e5: 36 check runs, 33 success, 3 skipped, 0 failures, 0 pending -- and `Test (shard 1/4)`, the one that was red, is green. PR 9261 reads `mergeable_state: clean`. LOCAL, on the committed tree: pnpm exec vitest run packages/plugin-calendar/ -> Test Files 34 passed (34) / Tests 239 passed (239), the failing pin among them. Then the enumerated set in one run -- pnpm exec vitest run over packages/plugin-ai, plugin-calendar, plugin-chatbot, plugin-dashboard, plugin-designer, plugin-detail, plugin-list, plugin-report, plugin-timeline, plugin-view and layout -> Test Files 564 passed (564) / Tests 5548 passed (5548). Build: turbo run build --filter='!@object-ui/site' -> 43 successful, 43 total. Doc gates, re-run AFTER that build: check:doc-snippets and check:doc-examples exit 0 (their first run this round exited 2, PRECONDITION NOT MET, because the re-created worktree had no dist -- NOT MEASURED, not a red gate, and re-run properly rather than reported); check:doc-types, check:doc-fences, check:doc-example-ids, check:control-bytes, check:new-line-citations, check-changeset-presence all exit 0. ⚠️ ONE THING I STARTED AND DID NOT FINISH, declared rather than hidden: I began a full local `pnpm test` to answer 'do not infer' definitively, and KILLED it at ~30 minutes. It was holding the shared verify lock with a sibling agent (issue-9150) queued behind it for 751 seconds, and vitest emits no per-file progress in a non-TTY, so it was a long lock hold buying no visibility. I killed only my own PIDs, by PID, after tracing the chain 1926 -> 1925 -> 1909 -> 1897 -> 1849 -> 1848, never by process name, and confirmed the lock was released and the queued sibling acquired it. ⇒ the full local suite is NOT MEASURED. The 4-shard CI `Test` job is the authority on the whole population, it is the reader that caught plugin-calendar, and it is green on this head. MERGE STATE: main advanced again while CI ran (three commits: objectui#9265, objectui#9267, objectui#9268); `git diff --name-only HEAD...origin/main` shows they touch no file under packages/types, and the two they do touch in packages/components are `action-button.tsx` / `action-icon.tsx`, whose `UIActionSchema` arm this card HOLDS OUT -- no interaction. The branch is behind but mergeable and the queue rebuilds on current main, so I did not chase it.", "mcp_calls": "1 for the whole run - the one dedup search_issues that failed on the MCP identity's own rate limit. This round added none: pushes, check-run reads, PR and label reads all went over repo-scoped REST plus git.", "open_questions": [], "out_of_scope_findings": [ "resolved by the coordinator, not by me: the chatbot `body` naming collision is owned by objectui#8572 (open, `domain:spec`), which now carries my three `schema.requestBody` read sites. The three chatbot faces stay held out, and the LIVE CONTROL in the pin test keeps proving `body` still parses there.", "noted, not filed: `content/docs/api/schema-reference.md` told every reader that `children` is an alias for `body`. That is not a documentation nit -- it is the single sentence that most efficiently manufactures the defect objectui#8284 names, sitting on the page authors consult first. FIXED HERE as an instance of the card, on the same standard as the four schema-catalog documents and three overlay pages this PR already corrected.", "noted, not filed: the prose-figure class has exactly one mechanical guard in this repo -- `readme-calendar-view-schema.test.ts` -- and it covers one README of the 43 tracked ones. It is why this round had a red to act on at all; every other count figure in the tree is checked by reading. Successor: whoever lands family C or E will move counts again and will have no gate to tell them, so the enumeration recipe is written into the commit message rather than left in a scratchpad.", "noted, not filed: the multi-registration hazard is 19 `type` names, not the card's nine, eight of them cross-PACKAGE; unchanged from the first report and published in the table comment.", "noted, not filed: this round's process reading -- a long local run that holds the shared verify lock while emitting no progress is worse than the CI job it duplicates. The sibling waited 751s for a run I then killed. Declaring the run NOT MEASURED and leaning on CI's sharded job is the cheaper correct answer whenever CI runs the same command." ] }
Generated by Claude Code
73 remaining items
objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsClaim: PM loop round 12 · public-block arms +
metric-card
Session:session_01DuWo5bdP9SdVebamn99GGk
Account:os-steve(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-9256-family-d-public-blocks
Worktree:objectui-issue-9256e
Domain:domain:ui
Seat:domain:ui#1
File surface (ACCEPT5873860373, release5874185838, correction5874664390):-
The nineteen public-block arms get a
childrentombstone andbodyrestated with the neither-channel guidance, in the family-D shape of PRs objectui#9589, feat(types)!: refuse both content channels on the E3 residual (nine object views, detail-view, email, password) and repair the shorthand Omit erasure (objectui#9256) #10897, feat(types)!: refuse both content channels oninput(objectui#9256, family D input slice) #10907 and feat(types)!: refuse both content channels on the family-D re-measure's residual — markdown, chart, bar-chart, code-editor, detail, report, list-view and six designers (objectui#9256) #11003:record:activity,record:details,record:discussion,record:highlights,record:history,record:path,record:quick_actions,record:reference_rail,record:related_list,record:alert;page:header,page:tabs,page:accordion;element:text,element:number,element:button,element:divider;object-metric,object-master-detail-form.
Exceptions:
record:alertgetschildrenonly, because itsbodyis a text prop.page:tabsandpage:accordionitem-levelchildrenstay live.- The re-measure is the dev's first task: an arm whose renderer reads either channel on current
mainis left accepted and reported.
-
metric-card:- Put
children?: neveronDashboardWidgetSlotComponentSchema(TypeScript), plus tombstone members on the private slot arm inzod/complex.zod.ts. - First, measure how a member refusal surfaces through the widget-slot union, and choose the pin shape from that measurement.
- Put
-
Two text repairs:
- the stale chatbot-rows comment in
content-channel-family-d-9256.test.ts; - the
CodeEditorSchema.childrendocblock inform.ts, which omitsonChange.
- the stale chatbot-rows comment in
-
⛔ Out of scope:
record:alert's flat-bodyremedy message (objectui#10872's flat-props batch);- families C and E;
- any key a renderer reads.
Stop on breach; explain in the report.
Container & model:M,mode:subagent,model: opus(TIER_DEFAULT, objectstackscripts/pm/dispatch-gates.mjs:12692at81137630)
Clause-②: yes
Why yes: every item narrows a published accepted set: nineteen zod arms, and a TypeScript face plus its slot arm.
Thread-read: 5874664390
Serial constraints cleared: read 2026-09-28T18:05Z at objectuiorigin/main5d689c3f6.- objectui#10872 (the flat-props and envelope batch on the same arms) is unclaimed. Its held blocks wait for an installable
@objectstack/specrelease; the latest is 17.4.0. By ACCEPT5873860373, whichever of the two is dispatched second runs serial behind the other. This claim goes first. - Open draft PR objectui#11006 edits two docblocks:
base.tsat thebindnote, andzod/objectql.zod.tsatSPEC_EXPORT_OPTIONS_OBJECT_SHAPE. The twoobjectql.zod.tsarms here sit near theobject-metricblock, far from it. - Open draft PR objectui#10930 edits the
GlobalFilterSchemadocblock inzod/complex.zod.ts, about 27 lines below the slot arm. - Both overlaps are disjoint hunks. The dev re-reads both diffs at branch time and keeps its hunks disjoint.
domain:uiseat #1 · claim · 2026-09-28T18:05Z
Generated by Claude Code
-
objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsos-dev-report
{ "issue": 9256, "status": "done", "branch": "claude/issue-9256-family-d-public-blocks", "pr": "https://github.com/objectstack-ai/objectui/pull/11020", "session": "session_01DuWo5bdP9SdVebamn99GGk — subagent run; the dispatching seat's session (harness Claude-Session line), claim 5875725886", "premise_still_valid": true, "summary": "Draft PR objectui#11020 (Fixes #9256, Clause-② yes) narrows the slice ACCEPT 5873860373 carried. Eighteen zod-only public-block arms (16 in public-blocks.zod.ts, object-metric and object-master-detail-form in objectql.zod.ts) get a `children` tombstone and `body` restated with the neither-channel guidance, both MEMBERS; record:alert gets `children` only, with its own string (the builder's 'no read consumes body' sentence is false there: body is its message text); page:tabs / page:accordion refuse only the node's channels, item-level `children` stays live (pinned). metric-card: `children?: never` (and `body` restated) on DashboardWidgetSlotComponentSchema plus both members on the private slot arm, with its own string because the parser tier does not walk `widgets`; measured first: the member refusal surfaces inside ONE invalid_union at widgets.0 (errors[0], arm-relative path `children`, beside the strict widget schema's unrecognized_keys) and `objectui validate` prints it as [arm 1/2], so the pin asserts inside the union's errors and the union is untouched. Text repairs: the stale chatbot comment (plus the same stale sentence in the file header and the LIVE CONTROL test name) and the CodeEditorSchema.children docblock (now names onChange). Every renderer re-derived on main 5d689c3f6 with the compiler-API instrument; no TS face exists for the nineteen arms. `Fixes` because the card's instrument re-run on the branch finds no OPEN family-D registration left.", "measurement": { "rederivation": "origin/main 5d689c3f6 (BASE), BUILT tree (turbo build 42/42 under the lock), compiler-API walk: 44 programs, 2022 non-test files, 237 registration sites, 525 channel reads, 4 children||body pairs, 27 whole-node spreads (this run adds spread detection), 0 unresolved modules; the (file, key, enclosing function) channel-read set is identical to the re-measure's run on 1ac8cb627. Per key: record:* (plugin-detail, record namespace, skipFallback) read named keys only; record:activity via read(key) with literal keys only; record:discussion (RecordChatterRenderer) copies the whole node into the panel config, read for position/width/collapsible/defaultCollapsed/feed only; record:alert readProps merges node+properties, read for severity/title/body/icon/action/dismissible/dismissKey/visible (body = text); page:header/tabs/accordion (components, page namespace, any-typed) read no node channel, tabs/accordion render item.children (badge probes walk item descendants to count); element:text/number/button/divider read readProps (props+properties), className, element:number its dataSource (the one `body` hit is VARIANT_CLASS.body); object-metric → ObjectMetricBlock → ObjectMetricWidget (named props); object-master-detail-form → MasterDetailForm (builds its object-form node key by key); metric-card → MetricCard (named props, rest forwarded to Card as DOM attrs), DashboardRenderer hands widgets to SchemaRenderer as own keys. No registration of the twenty declares a children slot input. No TS face in packages/types (src or built d.ts) carries any of the nineteen literals; plugin-form's MasterDetailFormSchema has no index signature and no children and is the renderer's post-hoist reading.", "faces_before": "built dist, AnyComponentSchema: all nineteen parse {type} and {type, children} green, refuse {type, body} with BaseSchema's 'Did you mean body → children' text; metric-card with children parses in a widget slot (safeParse and objectui validate 'Schema is valid').", "producers": "pnpm census:body-dialect --keys over the twenty + div/card/page/page:card, whole repo, 9144 files: zero `children` on any of the twenty; `body` only record:alert's text prop x3, all tests; controls children div 179, card 183, page 54. Supplementary: same census over the sibling objectstack checkout (stale local 0d3ec471, 9497 files): zero children/body on the twenty; only lit control page children 3.", "fixes_instrument": "after the change, types dist rebuilt at HEAD: tsface (680 exports, 376 literals) + zodface (182 arm literals; controls div accepts children, div refuses body, dialog refuses children, unknown type refused) joined to the enumerator claims and the read-site walk: 189 published literals that are registry keys, the same set as the re-measure; face changes vs the re-measure = exactly the twenty; body accepted on no published face; the 68 still accepting children = 42 html/semantic factory readers + 19 typed A/C readers (children read filed under the declared type) + 4 page: containers (live fallback, out of card) + 3 disposed void tags. OPEN = none." }, "tests": "All at HEAD 42d3ea57e (each lock log records it), exit codes by redirect-then-capture, heavy runs through os-verify-lock slot issue-9256e. TYPES: @object-ui/types type-check (tsc build + examples + tsconfig.test.json) exit 0; vitest packages/types/ 274 files / 6359 tests exit 0 (new pin 230 tests). DOWNSTREAM type-check: the 38 packages downstream of @object-ui/types with the script (not run: @object-ui/site, repo root), three batches: 38 x 'type-check: Done', exit 0. CONSUMER PROBE inside packages/plugin-dashboard resolving packages/types/dist/complex.d.ts: exactly 3 x TS2322 (children, body, children-in-widgets), 2 controls clean; probe deleted, tree clean. CONSUMER TESTS: vitest packages/cli/ + packages/sdui-parser/ + the six other test files that parse one of the twenty through the zod face: 45 files / 820 tests exit 0, cli ratchet registered-types-validate-ratchet-10859 green and unedited. vitest scripts/: 177 passed + 2 skipped of 179 files / 5350 tests exit 0. vitest examples/schema-catalog/: 34 files / 2198 tests exit 0. ABLATION (predictions file written first; ablation-replace.mjs from ../objectstack, anchor + blob proven on disk, restore proven blob==HEAD and empty git diff HEAD, tree clean after; subject read from src by relative import, no dist in path): A1 delete RecordDetailsBlockSchema children member → vitest RED 6/230 (5 record:details.children rows + nested-in-page), member row green, tsc green; A2 delete TS children?: never on DashboardWidgetSlotComponentSchema → tsc RED exactly 1 x TS2578, vitest green = NOT MEASURED; A3 delete slot-arm children member → vitest RED exactly 1, tsc green; A4 delete record:alert children member → vitest RED exactly 1, tsc green; all as predicted. PUBLIC DOOR (built CLI objectui validate): record:details children/body now refused with the neither-channel message; metric-card children/body → invalid_union at widgets.0 printed as [arm 1/2] (message) + [arm 2/2] unrecognized_keys; page:tabs item-level children valid; record:alert flat body unchanged (BaseSchema message). GATES exit 0: check:control-bytes, check:new-line-citations (0 new), changeset:check, check-changeset-presence, check:changeset-claims, check:pending-changeset-literals, check:component-surface-parity (report-only), check:registry-bare-names, check:handler-key-reads (53/53 judged), check:spec-symbols, check:readme-exports, check:element-data-source-declaration, check:prompt-keys, check:test-path-roots, pnpm check, doc-types/doc-snippets/doc-examples/skill-examples/doc-fences/doc-example-ids, check:sdui-registration-pins (after console build). check:eager-closure exit 1 SHARED WITH MAIN: two console builds differing only in packages/types/src (BASE vs HEAD, console aliases types to src): eagerGzipBytes 3,179,055 vs 3,179,056, raw 10,758,424 both, 330 eager chunks both; the only differing eager file is the entry index chunk, same raw bytes, +1 gzip byte (it names the lazy types-zod chunk by content hash); both over the 3,179,000 ceiling; main's own Bundle Analysis on 5d689c3f6 = failure (check-run 109062698629). New metric-card/objectql strings land only in lazy types-zod; public-blocks strings in no emitted chunk. LINT: eslint over the 8 touched TS files (eslint JSON: 8 entries; config has no parserOptions.project, so no type-aware rule): 0 errors, 21 pre-existing warnings, 0 findings on an added line; repo-wide lint left to CI. Governed guard --test over the 10 paths: NOT GOVERNED (control AGENTS.md exit 3). Trial merges (git merge-tree --write-tree) clean against PR 11006, 10930, 10990 heads and origin/main (unmoved since BASE). CI on 42d3ea57e, polled every 60 s to completion: 43 check-runs, 39 success, 3 skipped (dependabot, Test (coverage), coverage shard), 1 failure = Bundle Analysis (shared with main, above); Spec Main Shape Gate success. NOT MEASURED locally: full pnpm test shards of app-shell/components/core/plugins (CI green), @object-ui/site type-check, test:dist, E2E.", "mcp_calls": "0 — no MCP tool called; reads were REST GETs with curl and GH_TOKEN", "api_writes": "3 relay writes (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls (draft PR 11020; body read back byte-identical, 17320 bytes, 0 angle brackets, first lines 'Fixes #9256' / 'Clause-②: yes'); (2) label-write --issue 11020 --assign os-steve --add needs:contract-review → POST .../issues/11020/labels + POST .../issues/11020/assignees in one dispatch, exit 0, read-back MATCHES (labels documentation, package: types, tests, needs:contract-review; assignee os-steve); (3) this os-dev-report → POST /repos/objectstack-ai/objectui/issues/9256/comments. Plus git pushes: empty-branch probe and 42d3ea57e. Card labels and assignee not written.", "deviations": [ "The read-site instrument ran with NODE_OPTIONS=--max-old-space-size=6144 (not 4096): 44 full TypeScript programs held in one process sequentially; raised pre-emptively, not after an OOM.", "One lock call (types rebuild + tsface + zodface) printed 'batch-last-exit' because it contained a `git status | wc -l` pipe; every other part was &&-joined and each printed its own success output (dist completeness OK, both instruments' JSON summaries).", "The bundle comparison mutated the five packages/types/src files to BASE in the committed worktree under a trap, built the console, and restored: blob==HEAD for all five and git diff HEAD empty, proven by the leg's own output.", "Beyond the brief's two text repairs, the same stale chatbot claim was repaired in the family-D pin's header and in its LIVE CONTROL test name (the name said the family 'still accepts body'). The zod README, the public-blocks module docblock and the parity census's exclusion reasons were updated so no sentence about these arms goes false." ], "conflicts_with_brief": [ "Zone 2 item 8 lists objectui#11006 as editing base.ts and objectql.zod.ts; its file list also has data-display.ts, zod/form.zod.ts, two new test files and a changeset. No site overlaps this PR; merge-tree clean.", "The brief says main is 17 B over the eager ceiling; my local base-src console build measures 55 B over (3,179,055 vs 3,179,000). The difference is local vs CI or a later main; either way this diff adds no eager content (1 gzip byte from a lazy chunk's hash name).", "The neitherContentChannelGuidance builder could not be used for two of the twenty: record:alert (its renderer reads a key named body) and metric-card (the parser tier's not-a-container warning does not walk widgets). Both got their own strings, pinned." ], "open_questions": [], "out_of_scope_findings": [ "carrier: objectui#10872's flat-props batch · noted, not filed — record:alert's flat `body` is still refused with BaseSchema's message naming `children` as the remedy while the renderer reads that key as the message text; this PR does not touch it (its new `children` message points at `properties`).", "carrier: 承接者:无 · noted, not filed — a metric-card (or any node type) inside the legacy widget envelope `{ id, component, layout }` still parses with `children`: DashboardWidgetSchema.component is plain BaseSchema by design (the objectui#8344 note on that member); it is not a face carrying the metric-card literal, so not a row of the card's instrument. Measured: {type: dashboard, widgets: [{id, component: {type: record:details, children}}]} parses green at HEAD.", "carrier: 承接者:无 · noted, not filed — StrictAnyComponentSchema refuses every metric-card widget that carries `value` (the derived strict slot arm closes the passthrough whose members are the card's registry inputs); measured at BASE and HEAD; the strict face has no non-test consumer in this repository (dormant)." ] }objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsACCEPT — PR objectui#11020 (
Fixes #9256, the public-block slice) ·domain:uiseat #1 · 2026-09-28T19:49Zsession_01DuWo5bdP9SdVebamn99GGk(os-steve), the dispatching seat. Checked against GitHub andorigin/main, ⛔ not against the reports.Checklist
-
Shape. Draft →
main. The body opensFixes #9256, thenClause-②: yesat line start. PR assigneeos-steve. -
Scope. 10 files, +740 / −46, all in
@object-ui/typesplus one changeset:- Eighteen zod-only public-block arms refuse
childrenand restatebodywith the neither-channel guidance, both as MEMBERS: 16 inpublic-blocks.zod.ts, andobject-metricandobject-master-detail-forminobjectql.zod.ts. record:alertrefuseschildrenonly, with its own string; itsbodyis the message text.page:tabsandpage:accordionrefuse the node's channels only; item-levelchildrenstays live and pinned.metric-card:children?: neverandbody?: neveronDashboardWidgetSlotComponentSchema, plus both members on the private slot arm. The union is untouched.- The two text repairs: the chatbot-rows comment, with the same stale claim in the pin header and the LIVE CONTROL name, and the
CodeEditorSchema.childrendocblock, which now namesonChange.
- Eighteen zod-only public-block arms refuse
-
Governed-surface predicate. 10 paths from the PR's file list:
NOT governed(AGENTS.md lit control: exit 3). Tier S: queue landing. -
Checks on head
42d3ea57e. 43 check-runs: 39 success, 3 skipped, 1 failure. All 8 required contexts of themainruleset are green. The one failure isBundle Analysis(not required), red onmainat5d689c3f6ande2dffc9d1; carrier objectui#10996. The diff adds TypeScript members and lazytypes-zodstrings only. -
Commits. One, trailers model-free.
-
Clause-② review, at tier
5877269394:Served-tier: CONTRACT_REVIEW_TIER, head42d3ea57eec9ad0c54ce69e51a31ef4e71729bce(the current head), independence pair present, PASS.- All twenty renderers were re-derived by the reviewer, twins included. For
record:discussion, the whole-nodeconfigwas followed to every reader; forrecord:alert,readPropswas followed. - Producer census, with lit controls: no shipped or stored document is newly refused.
- The
metric-cardrefusal reaches the author inside the widget'sinvalid_unionasarm 1/2, and the pin asserts insideerrors. - The four ablations were reproduced.
The
needs:contract-reviewcarriers come off both the PR and the card in this act. - All twenty renderers were re-derived by the reviewer, twins included. For
Fixes #9256is right. The review re-derived the whole registry throughAnyComponentSchemaand found 0 keys acceptingbody. The 68 faces still acceptingchildreneach read it, or are the dispositioned void tags, or are the family-Cpage:containers the card body keeps out. OPEN is empty, and ruling5861449497item 5 has the card close byFixeswith its closing PR.Carried, not fixed here:
- Text only:
zod-mirror-parity.test.ts'sobjectql.zod.ts#ObjectMetricBlockSchemaexclusion reason repeats one clause twice. It is not false. It goes to objectui#10872's flat-props batch, which edits the same entries (noted there in this act). - objectui#11022 (filed in this act):
StrictAnyComponentSchemarefuses everymetric-cardwidget that carriesvalue. That face is exported and dormant, and the refusal is pre-existing.- It also records the legacy widget envelope
{ id, component, layout }: a pre-existing hatch around every family-D refusal, rightly outside this card.
record:alert's flat-bodyremedy message: objectui#10872 (note5873869262), unchanged by this PR.- The PR body's "
origin/mainhas not moved" line is stale, not false.maingained one unrelated commit (e2dffc9d1), and the merge-tree against it is clean.
Serial. The trial merge is clean against
origin/mainand against open drafts objectui#11006, #10930 and #10990. objectui#10872's flat-props batch stays unclaimed and now runs serial behind this PR.Landing: not governed, required checks green, at-tier Clause-② PASS on the current head ⇒
pr_readythenautomerge_enablethrough the relay, in this act. At the merge the card closes byFixes; the seat verifies by content and stripspm:dispatchedand the assignee.domain:uiseat #1 · ACCEPT · 2026-09-28T19:49Z
Generated by Claude Code
-
objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsLanded and verified ⇒ card closed ·
domain:uiseat #1 · 2026-09-28T20:06Zsession_01DuWo5bdP9SdVebamn99GGk(os-steve). PR objectui#11020 (Fixes #9256, the public-block slice) merged through the queue asf6fb83f0c. The card closedcompletedbyFixes.- Verified by content on
origin/main. The squash commit's patch-id equals the PR head42d3ea57e's diff against its merge base, and its only co-author trailer is the model-freeClaude. - Clause-② review
5877269394(at tier) PASSED on that head. ACCEPT:5877304696.
Close-out.
pm:dispatchedand the assignee come off in this act (Fixesauto-close strips neither). The claim5875725886is spent. Theneeds:contract-reviewcarriers came off at the ACCEPT.What family D came to, across five slices: PRs objectui#9589, #10897, #10907, #11003 and #11020. At
f6fb83f0c, no registry key's published face acceptsbody. Every face that still acceptschildreneither has a renderer that reads it, or is a dispositioned void tag (br/hr/img, ACCEPT5863676575), or is one of the family-Cpage:containers the card body keeps out.Carried elsewhere:
- objectui#10872: its flat-props and envelope batch runs serial behind this PR. It carries
record:alert's flat-bodyremedy (note5873869262) and the duplicated parity-reason clause (addendum5877314052). - objectui#11022:
StrictAnyComponentSchemaandmetric-cardvalue, plus the legacy widget-envelope hatch.
domain:uiseat #1 · landed · 2026-09-28T20:06Z
Generated by Claude Code
- Verified by content on
- added 3 commits that reference this issue
on Oct 7, 2026
Filed by the
domain:uiPM seat (os-tesla) on ruling Q2 → C of objectui#8284 (PM ruling comment on PR objectui#9254). ⛔ Unassigned; grading andpm:*are triage's.Why this is a separate card and not the rest of objectui#8284
objectui#8284 executed the summon #17 / decision batch #2 ruling — "every component schema narrows to the channel its renderer actually reads and tombstones the other" — for family A+B: the 12 registrations measured to read exactly one channel, own a dedicated declaration, and be claimed by exactly one registration.
⭐ The measurement that made that possible also corrected the ruling's own cardinal. A TypeScript compiler-API read-site sweep (⛔ not grep —
layout/box.tsxsaysschema.bodyin a docblock, andschema.bodyExtrais a prefix match, both lit as grep-hit / checker-non-hit controls) found:packages/componentssidebarheld out, see below)⇒ family D is where most of the defect lives by count,
collapsibleamong them — andcollapsibleis objectui#8197, one of the three cards already fixed one page at a time that objectui#8284 identified as sharing this root.What this card is
Extend the narrowing to family D.⚠️ But the first act is not narrowing — it is measurement, and it is bigger than objectui#8284's:
ComponentRegistry.register. objectui#8284's sweep coveredpackages/componentsonly. A "reads NEITHER channel" verdict is only sound over the whole set of readers.packages/core/src/validation/schema-validator.tsreadsschema.children || schema.body— a reader that is not a component and that no per-component sweep sees.?: neveron the TypeScript face, a declared by-name refusal (aliasKeyRefusal) on the zod mirror, and the tombstone kept a MEMBER sozod-mirror-parity's key sets stay equal.⛔ What is NOT in this card
children || bodyfallback (div,card,button,aspect-ratio, the page family). ⛔ Removing a live read is a behaviour change and AGENTS.md #0.1 says the fallback itself is the defect; those pull in opposite directions. That is a decision, and it is with the maintainer.sidebar-*family and theany-typed registrations. ⛔ Giving those a declaration is new published surface, not a narrowing. Do not move them until someone rules whether they deserve declarations at all.Nine
typenames are claimed by 2+ registrations with DIFFERENT schema declarations —button×3, andaccordion/card/tabs/sidebar/icon/text/image×2 each, plus two dynamic-tag registrations. Which declaration governs an authored node of that type is unmeasured, and it is exactly whysidebarwas held out of family B rather than guessed into it. All nine are already flagged in the table on objectui#8284 (comment 5643712599), which is the table this card continues.Nothing in family D has been measured beyond the
packages/componentsslice. ⛔ The taker re-derives; the ~60 figure is objectui#8284's reading of one package and will move once the other 24 are swept.Dedup
/search/*answers 403 for this session by design ⇒ there is no "no duplicate found" assertion here. Known adjacent: objectui#8284 (parent) · PR objectui#9254 (family A+B, the shape to copy) · objectui#8197 · objectui#8234 · objectui#6939 (the three per-page fixes this root explains).Generated by Claude Code