Repository navigation
spec(ui): the ComponentPropsMap rows still type renderer-read members as z.unknown() — navigation on object-map / object-gantt / object-tree and conditionalFormatting on object-kanban accept 42 — the family close-out after #21445 #21464
Description
Activity
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsTriage: first grade —
bug·priority:p2·domain:spec·area:records·pm:queue. Everyz.unknown()inComponentPropsMapis typed, or carries its reason; one enumeration pin holds the familyTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-02T20:52Z. ⛔ Not a claim, ⛔ not a dispatch.Why p2. It matches #21445 (p2), the family's object-grid row. It is class (c), measured on the published 17.6.0: renderer-read members accept any value, and the renderer drops or substitutes them.
Routing.
packages/spec/src/ui/component.zod.tsisdomain:spec.Direction: the card's, accepted as the family close-out.
- Each renderer-read
z.unknown()member is typed by reference where a schema already declares it. Examples areNavigationConfigSchemaon map, gantt and tree, and the list view'sconditionalFormattingon kanban. Otherwise it is typed to the renderer's read at the.objectui-shapin. - A member forwarded verbatim to a runner keeps
z.unknown()only with its reason in the.describe(). - A census of authored writers at the pin precedes each narrowing, as finding(spec):
ComponentPropsMap['object-grid']keepsresizableColumnsas a live alias ofresizable, and types six membersObjectGridreads with fixed shapes asz.unknown()(rowHeight: 42passes every door) #21445's did. A narrowing that would refuse a measured writer is reported, not shipped silently. - Enumeration pin: every
z.unknown()member acrossComponentPropsMapis either typed or listed with its recorded reason. A new one fails until it carries one. - It is a narrowing. The claim states the changeset level and
Clause-②.
Serial: after PR #21463 (#21445) lands, in the same file.
Generated by Claude Code
- Each renderer-read
- addedarea:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3and removed
on Oct 2, 2026 objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsClaim: PM loop round 1
Session:session_01YDt3PzwfrkuFzUBF89WPmM
Account:os-tesla(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-21464-component-props-unknown-closeout
Worktree:objectstack-issue-21464
Domain:domain:spec
Seat:domain:spec#2
File surface (ataa4632235b):packages/spec/src/ui/component.zod.ts, everyz.unknown()member acrossComponentPropsMap, per triage5961300594:- A member a renderer reads with a fixed shape is typed: by reference where a schema already declares it (for example
NavigationConfigSchemaon object-map, object-gantt and object-tree, and the list view'sconditionalFormattingon object-kanban), and otherwise to the renderer's read at the.objectui-shapin, as PR feat(spec)!: an object-grid page block types the seven members the grid reads, and resizableColumns retires for resizable (#21445) #21463 did for object-grid. - A member forwarded verbatim to a runner keeps
z.unknown(), with its reason in the.describe(). - A census of authored writers at the pin precedes each narrowing. A narrowing that would refuse a measured writer is reported, not shipped.
- One enumeration pin: every
z.unknown()member is typed or listed with its recorded reason, so a new one fails until it carries one. - Plus the regenerated artifacts (
authorable-surface, the references page, the strictness counts), the ADR-0087 semantic entry for the narrowing, and one changeset. - ⛔ No objectui edit, and no renderer change.
- Size: if the family cannot land as one reviewable PR, the dev stops after the census and returns a staging proposal before building past the first group.
- Stop on breach and explain in the report.
Container & model:
L,mode:subagent,model: opus(dispatch-gates --tierataa4632235b: no path-derived mandate; floor sonnet · default opus · ceilingCONTRACT_REVIEW_TIER).packages/spec/src/**, so the at-tier contract review runs as a separate isolated subagent after the PR opens.
Clause-②: yes (narrowing)
Thread-read: 5961300594
Serial constraints cleared:- Triage's serial condition holds: PR feat(spec)!: an object-grid page block types the seven members the grid reads, and resizableColumns retires for resizable (#21445) #21463 (finding(spec):
ComponentPropsMap['object-grid']keepsresizableColumnsas a live alias ofresizable, and types six membersObjectGridreads with fixed shapes asz.unknown()(rowHeight: 42passes every door) #21445) landed at 2026-10-02T21:49Z. - At 2026-10-02T22:20Z, no open PR touches
ui/component.zod.ts, its pins or its regenerated rows.
Seat terms: p2, ordered ahead of this seat's p3 work under the maintainer's terms (「只处理 p0 p1 p2」, widened by
5952442849),batch 3. The PR isFixes objectstack-ai/objectstack#21464, unless the dev stages it.
Generated by Claude Code
- A member a renderer reads with a fixed shape is typed: by reference where a schema already declares it (for example
- added 4 commits that reference this issue
on Oct 2, 2026 objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 21464,
"status": "done",
"branch": "claude/issue-21464-component-props-unknown-closeout",
"pr": "#21502",
"session": "session_01YDt3PzwfrkuFzUBF89WPmM — the parent session (mode:subagent), from the Claude-Session line this run commits under",
"premise_still_valid": true,
"summary": "Stage 1 of the ComponentPropsMap z.unknown() close-out, delivered as Part of #21464 under the size rule (A7). The census holds 107 z.unknown() members over 56 rows, 31 of them renderer-read; at the precedent PR #21463 rate (about 140 non-generated lines per member) the 28 still untyped project to about 3,900 lines, over the 2,500 ceiling. This PR types navigation on object-map, object-gantt and object-tree as the list view NavigationConfigSchema by reference, with no measured writer refused (36 of 36 authored literals parse). It adds one enumeration pin that lists every other z.unknown() member with a recorded reason (28 staged with a reader at the pin and a named stage, one of them held for a ruling) and fails on a new or a stale one. The rest of the kit: the ADR-0087 D3 entry, the step-18 rationale fragment, the regenerated references page and a minor BREAKING changeset. The staging proposal and two A2/A3 decisions are in open_questions.",
"resume": {
"found_done": [
"c7bb62ae6f: navigation typed by reference on the three rows; the enumeration pin (427 lines) with its ledger, STAGES table and §1-§4",
"527957de24 (wip): D3 entry 18.ui-object-map-gantt-tree-navigation-typed, rationale fragment order 64, changeset; content complete except as finished below",
"9a8037abbe: regenerated content/docs/references/ui/component.mdx",
"the lost run had already chosen A7 staging: the pin header and STAGES say so, and 28 staged lines each cite a reader"
],
"finished_here": [
"settled the open question: staging holds — 31 renderer-read members is over A7 (about 30), and the projected lines are over 2,500; every staged reader citation was re-read at 89cad75d55 and holds",
"merged origin/main 100c394 through scripts/pm/os-regen-merge.sh (merge commit 58b235e): check:generated reported all 15 artifacts current, so no regeneration was owed; sibling entries (agent-lifecycle-retired, ui-object-grid-row-members-typed) intact",
"re-measured the navigation writer census on the merged head and the kanban refusal (A3)",
"d3431deed3: finished the changeset (measured section re-anchored to the merged head with controls; summary now matches the ledger, 27 staged plus 1 held) and corrected two STAGES reasons that named a wrong or incomplete candidate (object-metric: chart aggregate/drillDown and dashboard compareTo, trend none; objectui-held: UIActionSchema is an objectui interface)",
"every gate rerun on d3431de; the lost run readings were discarded as not measured on the final head",
"opened draft PR #21502, assigned os-tesla, removed the worktree"
]
},
"tests": "All on d3431de, under scripts/pm/os-verify-lock.sh, with exit codes written to disk first. (1) pnpm --filter @objectstack/spec test: Test Files 602 passed, 1 skipped (603); Tests 17832 passed. (2) pnpm --filter @objectstack/spec typecheck: exit 0, with check:test-typecheck: OK — the test layer compiles under packages/spec/tsconfig.test.json (tsconfig.json excludes /*.test.ts, so this is what covers the pin). (3) The pin by name (--project local): Tests 51 passed (51). (4) scripts/step18-rationale-merge.test.ts (--project repo): Tests 9 passed (9). (5) Ablation via node scripts/ablation-replace.mjs in WRAP mode: object-map navigation reverted to z.unknown() with no ledger line. It landed: anchor x1 to x0, replace x0 to x1, blob 58b6e27fbc to 7e3b411604. The run went red: Tests 8 failed, 43 passed (51); §1 received ["object-map navigation"]; census expected 108 to be 107; six object-map §4 cases failed. Restore: blob after restore 58b6e27fbc == blob at HEAD, git diff HEAD empty. Green rerun: Tests 51 passed (51). The pin imports ./component.zod from source, so no build sits between mutation and run. (6) A narrowed eslint run over the 4 changed TS files: 4 files, 0 errors, 0 warnings. The population is from eslint itself (each resolves a config with --print-config); the count is from --format json; invariance holds because eslint.config.mjs never enables type-aware linting (lines 326-328). The full pnpm lint is CI's.",
"gates": {
"derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths): 114 commands, merge base 100c394, 6 changed paths, 649 changed lines (under the 5000 threshold)",
"reconcile": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran r-ran.list: exit 0 — Run reconciliation: 114 derived, 114 run, 0 NOT-MEASURED, 0 UNRUN",
"all_114": "exit 0. Six spec gates (check:api-surface, check:browser-reachable-entries, check:dual-source-exports, check:entry-nameability, check:exported-any, check:skill-examples) first answered PREREQUISITE NOT MET (exit 3), because dist predated the final pin edit. After pnpm --filter @objectstack/spec build at d3431de they and the whole spec family (#44-#67) were rerun: exit 0. The exit-3 lines are kept apart, not counted.",
"named": [
"pnpm --filter @objectstack/spec build :: exit 0",
"pnpm --filter @objectstack/spec run check:generated :: exit 0 — ✓ All 15 generated artifacts are up to date",
"pnpm --filter @objectstack/spec run check:liveness :: exit 0 — ✓ packages/spec/liveness/state-counts/ is current",
"pnpm --filter @objectstack/spec run check:migration-registry :: exit 0 — ✓ src/migrations/registry.ts is current (353 semantic, 246 retired-key, 217 retired-def)",
"pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0 — counts current, unmoved",
"pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0 — authorable-surface/ui.json unmoved",
"pnpm --filter @objectstack/spec test :: exit 0; pnpm --filter @objectstack/spec typecheck :: exit 0",
"node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0 — ✓ 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition (registered ui-object-map-gantt-tree-navigation-typed)",
"node scripts/check-changeset-no-major.mjs --base 100c394 --event event.json (the PR body as the payload) :: exit 0 — ✓ LEVEL AXIS: this PR declares clause-② yes (narrowing), and no package whose packages//src/** it moves is graded patch · direction arm: narrowing — a BREAKING change; during the launch window it ships minor",
"node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
"pnpm check:doc-authoring :: exit 0 — ✓ doc authoring guard: 17287 customer-facing string(s) across 1247 spec sources clean",
"pnpm check:nul-bytes :: exit 0 — check-nul-bytes: OK (scanned 9839 text file(s), no raw ASCII control bytes)",
"pnpm check:dual-build-cjs-loads :: exit 0 — 105 published require entry point(s) across 66 package(s) load (the lost run got PREREQUISITE NOT MET here; this run found every dist present)"
],
"not_measured": "NOT MEASURED: the Console Pin Gate, Dogfood and the full pnpm lint, reason: CI-owned. NOT MEASURED: the derivation against origin/main 5555047, reason: --ran printed STALE TREE — one family input, scripts/engine-double-contract.pinned.json, changed on main after the merge base; the diff touches none of its subjects, and the only other overlap since is a comment-only edit in ui/view.zod.ts"
},
"line_budget": "649 changed lines (+637/-12, 6 files) vs merge base 100c394. Before generated files: 573 (component.zod.ts +50/-9, pin +427, D3 entry +41, rationale fragment +13, changeset +33). Generated: component.mdx +36/-3 and registry.ts generated region +37. The A7 ceiling is about 2,500; the remaining 28 members project to about 3,900.",
"files_changed": [
"packages/spec/src/ui/component.zod.ts",
"packages/spec/src/ui/component-props-unknown-members.pin.test.ts",
"packages/spec/src/migrations/entries/semantic/18.ui-object-map-gantt-tree-navigation-typed.ts",
"packages/spec/src/migrations/registry.ts (rationale fragment hand-written; semantic region generated)",
"content/docs/references/ui/component.mdx (generated)",
".changeset/21464-component-props-navigation-typed.md"
],
"semver": "@objectstack/spec minor, BREAKING banner, Clause-②: yes (narrowing), ADR-0087 marker registered ui-object-map-gantt-tree-navigation-typed; judged by the level-axis and adr-0087 lines quoted in gates.named",
"census": {
"scope": "107 z.unknown() members over 56 rows on the merged head (unchanged from aa46322 minus the 3 typed). Readers: objectui at 89cad75d55, every citation re-read. Writers are file co-mentions (type plus authored KEY:) with a control key, written os N/M (ctl) | ou N/M (ctl). os was counted by the lost run on its aa46322-based tree, except navigation, which was re-measured on the merged head.",
"renderer_read": [
"object-map/gantt/tree · navigation · ObjectMap.tsx:1189, ObjectGantt.tsx:1960/2025, ObjectTree.tsx:1054, hook useNavigationOverlay.ts:364 · NavigationConfigSchema · os 0 on the row (ctl objectName 4/5) | ou 88/98/59 files (ctl 55/70/40), 36/36 literals parse · TYPED (this PR)",
"object-metric · aggregate · ObjectMetricWidget.tsx:250, :404 · chart aggregate (chart.zod.ts:644) · os 7/8 (7) | ou 17/36 (20) · staged object-metric",
"object-metric · trend · ObjectMetricWidget.tsx:254 (:176) · none · os 0/8 | ou 1/36 · staged object-metric",
"object-metric · drillDown · ObjectMetricWidget.tsx:265 (:218) · chart drillDown (chart.zod.ts:663) · os 0/8 | ou 7/36 · staged object-metric",
"object-metric · compareTo · ObjectMetricWidget.tsx:267 (:241) · dashboard widget compareTo (dashboard.zod.ts:1205) · os 1/8 | ou 4/36 · staged object-metric",
"object-form · fields[] · ObjectForm.tsx:961 · none · os 11/14 (12) | ou 178/210 (188) · staged object-form",
"object-form · customFields · ObjectForm.tsx:755, :1180 · none · os 0/14 | ou 21/210 · staged object-form",
"object-form · sections[] · ObjectForm.tsx:364, :1518 · FormViewSchema.sections · os 3/14 | ou 78/210 · staged object-form",
"object-form · contentLayout · ModalForm.tsx:854 (:151) · none · os 0/14 | ou 7/210 · staged object-form",
"object-form · submitBehavior · ObjectForm.tsx:1312-1313 · FormViewSchema.submitBehavior · os 2/14 | ou 12/210 · staged object-form",
"object-form · navigateOnSuccess · ObjectForm.tsx:1373, :1412 · none · os 0/14 | ou 5/210 · staged object-form",
"object-form · mobile · ObjectForm.tsx:1857 · none · os 0/14 | ou 7/210 · staged object-form",
"object-master-detail-form · sections[], fields[] · MasterDetailForm.tsx:1692-1693 · as object-form · os 2/4, 4/4 (4) | ou 9/29, 18/29 (21) · staged object-form",
"object-grid · columns[] · ObjectGrid.tsx:2158 · ListViewSchema.columns · os 7/21 (16) | ou 198/292 (248) · staged list-family",
"object-grid · fields[] · ObjectGrid.tsx:1946 · none · os 7/21 | ou 191/292 · staged list-family",
"object-grid · selection · ObjectGrid.tsx:4799-4810 · ListViewSchema.selection · os 1/21 | ou 19/292 · staged list-family",
"object-grid · selectable · ObjectGrid.tsx:4813-4815 · none · os 0/21 | ou 7/292 · staged list-family",
"object-grid · rowActions[] · ObjectGrid.tsx:1834-1835 · ListViewSchema.rowActions · os 1/21 | ou 19/292 · staged list-family",
"object-grid · bulkActions[], batchActions[] · ObjectGrid.tsx:4763 · ListViewSchema.bulkActions · os 2/21, 0/21 | ou 27/292, 7/292 · staged list-family",
"object-kanban · columns[] · KanbanBoardCore.tsx:95 · none · os 4/12 (9) | ou 87/152 (99) · staged list-family",
"object-calendar · calendar · ObjectCalendar.tsx:296-297 · ListViewSchema.calendar · os 1/6 (6) | ou 50/83 (62) · staged list-family",
"object-gantt · markers[] · ObjectGantt.tsx:2497 (GanttMarker) · none in spec · os 0/5 (4) | ou 6/98 (70) · staged objectui-held",
"object-timeline · items[] · ObjectTimeline.tsx:587 · none in spec · os 3/3 (3) | ou 12/45 (34) · staged objectui-held",
"object-timeline · mapping · ObjectTimeline.tsx:551, :576-579 (TimelineMappingSchema) · none in spec · os 2/3 | ou 2/45 · staged objectui-held",
"action:group · actions[]{} · action-group.tsx:303 (UIActionSchema, objectui interface) · none in spec · os 2/3 (label 3) | ou 23/36 (26) · staged objectui-held",
"action:menu · actions[]{} · action-menu.tsx:339 · none in spec · os 2/4 (3) | ou 23/38 (28) · staged objectui-held",
"object-kanban · conditionalFormatting · KanbanBoardCore.tsx:114, KanbanImpl.tsx:179 · ListViewSchema.conditionalFormatting · os 1/12 | ou 9/152 · HELD for a ruling (A3, open_questions[1])"
],
"recorded_reason": [
"slot (7) · page:tabs/page:accordion items[].children[], page:card children[]/footer[], page:footer/page:sidebar/page:section children[] · declared slot positions, judged at their own node (§2 checks)",
"runner (16) · action:button and action:icon params, bodyExtra, bodyShape, operation, patch, toast, resultDialog, onSuccess · forwarded verbatim to the action runner; each .describe() says so (§2 checks)",
"records (18) · staticData[] (grid/map/gantt/tree), data[] (kanban/timeline/calendar), calendar staticData[], data.items[] (grid/map/gantt/tree), initialValues{}/initialData{} (form/master-detail), grid bulkActionDefs[].patch{} and params[].default · record rows and field values shaped by the bound object",
"shared (35) · expression AST .ast beside every source (14) · HttpRequestSchema params{}/body on data.read/data.write (16) · inline JSON Schema data.schema{} (4) · bulk-action option entry params[].options[].* (1) · owned and judged by another file",
"any-value (1) · element:definition-list items[].description · shown as-is, data-list.tsx:68 toText",
"open-bag (1) · object-grid pagination.* · z.looseObject on purpose, named members typed",
"no-reader (1) · ai:chat_window context{} · objectui registers no ai:chat_window renderer (placeholders.tsx:109-113) — A2 open question, open_questions[2]"
]
},
"a2_decisions": "Typed: 3 (navigation x3, by reference). Runner-forwarded and kept z.unknown() with the reason in .describe(): 16. Recorded non-renderer reasons: 76 (slot 7, records 18, shared 35, runner 16). Plus one each of any-value, open-bag and no-reader. Staged: 27 renderer-read members, each with its reader at the pin and a named stage. Held: 1 (kanban conditionalFormatting, A3). Not guessed: ai:chat_window context{} has no reader and is listed as an open question, not a verdict.",
"a3": "navigation: no measured writer refused — objectstack 0 writers on the three rows; objectui 77 navigation lines in 190 files, 36/36 distinct authored literals parse on all three rows; the refused values are probes that already expect refusal (both-faces parity anything, a @ts-expect-error drawer, mode sideways). kanban conditionalFormatting: the by-reference shape refuses objectui fixtures — native rule: unrecognized_keys plus invalid_type@style; flat CEL rule: invalid_type@style plus unrecognized_keys[backgroundColor] — so it was NOT shipped.",
"a4_red_then_green": "Red: one member reverted (object-map navigation to z.unknown(), no ledger line), Tests 8 failed, 43 passed (51), §1 names exactly object-map navigation. Green: Tests 51 passed (51) before the ablation and again after the blob-proven restore. Both directions of §1 are live: an unlisted member reds, and a ledger line outliving its member reds.",
"a8": "No open PR touches ui/component.zod.ts, component.mdx, migrations/registry.ts, authorable-surface/ui.json or the pin (8 open PRs read via REST at 2026-10-03; #21352, the bot Version Packages PR, was read only to page 1 because the proxy refused its pagination link).",
"deviations": [
"Merged origin/main 100c394 into the branch (58b235e) through os-regen-merge.sh, per AGENTS.md multi-agent §10, before opening the PR; not named in the dispatch.",
"The wip commit 527957d keeps its wip subject in history; it was finished by d3431de instead of a history rewrite (no force-push). Squash landing collapses it.",
"The PR footer and commit trailers follow AGENTS.md (session-URL footer; model-free trailer pair), not the harness reminder that names a model and a different footer.",
"dispatch-gates --ran printed STALE TREE against origin/main 5555047 (one family input changed after the merge base); not re-derived, declared under gates.not_measured."
],
"mcp_calls": "0 — no MCP GitHub tool called",
"api_writes": "3 — each through the fleet-write relay as one repository_dispatch (POST /repos/objectstack-ai/objectstack/dispatches, 204), executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, draft #21502 (body read back byte-identical, 15559 bytes); (2) the label-write assign op on #21502, assignee os-tesla (read back matches); (3) this os-dev-report comment via post-stamped.mjs --comment=21464. Plus 2 git pushes (58b235e, d3431de), which are not REST.",
"open_questions": [
{
"question": "Staging proposal (A7): how do the 28 untyped renderer-read members land? The pin names four stages plus one held item.",
"options": [
"A — Four stages under #21464, each a Part-of PR that runs its own value census first: S-list (9: grid columns, fields, selection, selectable, rowActions, bulkActions, batchActions; kanban columns; calendar calendar — 5 by reference to ListViewSchema); S-form (9: form fields, customFields, sections, contentLayout, submitBehavior, navigateOnSuccess, mobile; master-detail sections, fields — FormViewSchema sections and submitBehavior by reference); S-metric (4: aggregate and drillDown by reference to the chart, compareTo to the dashboard widget, trend to the renderer read); S-objectui-held (5: gantt markers, timeline items and mapping, action:group and action:menu actions — the spec declares each contract first). The last stage carries the closing line once the held item is ruled.",
"B — Same four groups, filed as sub-issues of #21464 so separate seats can take them in parallel.",
"C — One PR for all of them: about 3,900 lines at the precedent rate, over A7."
],
"recommendation": "A, in the order S-list, S-form, S-metric, S-objectui-held. Business need, measured: the list and form rows carry the largest authored populations (objectui grid columns in 198 of 292 files, form fields in 178 of 210), so that is where an off-shape value is most likely to be authored. Long-term soundness: each stage types by reference where the spec already declares the shape, and the objectui-held contracts get declared in the spec first, contract-first, before any row takes them. Preventing AI authoring errors: every stage is a loud narrowing, and the pin keeps the remaining debt visible and shrink-only, so no new silent member can enter. Startup focus: staging answers size only; it keeps no alias or dual spelling and adds no gate beyond the pin triage named. B is equally sound if the PM wants parallel seats; C fails A7."
},
{
"question": "object-kanban conditionalFormatting (A3): the list view shape (the grid shape since PR #21463) refuses two rule dialects that objectui authors in its own fixtures and asserts in its own kanban schema test. How should it be typed?",
"options": [
"A — Narrow to ListViewSchema.conditionalFormatting, and pair it with an objectui change: respell its fixtures from the native rule to { condition: CEL, style: { backgroundColor } }, and retire the native dialect from objectui ObjectKanbanSchema in the same landing, with the pin bump (AGENTS.md Post-Task 4).",
"B — Widen the spec: the list view conditionalFormatting also accepts the native { field, operator, value, backgroundColor } rule, on every list carrier.",
"C — Keep z.unknown() with a recorded two-dialect reason."
],
"recommendation": "A. Business need: the measured writers are objectui test fixtures (9 of 152 files at the pin), not authored apps, and the grid already ships the single CEL dialect. Long-term soundness: one strict contract beats two dialects, and B widens every list carrier to tolerate a legacy spelling. Preventing AI authoring errors: one dialect is the one an AI cannot write wrong, while B and C keep a second spelling and C keeps the silent accept. Startup focus: retire the alias dialect at once, with no staged window. Cost: an objectui-side change outside this card (no objectui edit was allowed here), so it is its own card."
},
{
"question": "ai:chat_window (A2): the row has no renderer at the pin. objectui omits it on purpose, a referencing page gets a loud Unknown component type, and its palette excludes it. So context{} has no reader. Should the row retire?",
"options": [
"A — Retire ai:chat_window from ComponentPropsMap and the page component type list (page.zod.ts:164) under ADR-0049 enforce-or-remove, with the retirement kit (tombstone, D3 entry, changeset).",
"B — Keep the row and have objectui implement an inline renderer.",
"C — Keep it as is, with context{} recorded as no-reader (today’s pin line)."
],
"recommendation": "A, as its own card. Business need: zero authored writers in either repository; the objectstack hits are spec tests and type lists, and the objectui hits are tests asserting the absence, a palette exclusion and a tombstone list in check-prompt-component-keys. Long-term soundness: a declared component nothing renders is declared but not enforced, and the floating chat overlay is objectui canonical entry. Preventing AI authoring errors: today the spec accepts a block the console refuses to draw, and retiring makes the refusal loud at authoring. Startup focus: a zero-pull declared surface retires now, with no sunk-cost exemption."
}
],
"out_of_scope_findings": [
"carrier: open_questions[2] (PM) · ai:chat_window is declared in ComponentPropsMap and page.zod.ts:164, but objectui registers no renderer (placeholders.tsx:109-113) and zero writers author it in either repository · noted, not filed (no public-door reach measured in this run) · dedupe words: ai:chat_window renderer retire · chat_window ComponentPropsMap no reader · page component type no renderer",
"carrier: open_questions[1] (PM) · object-kanban conditionalFormatting is held under A3; objectui fixtures author two dialects the list view refuses · noted, not filed · dedupe words: kanban conditionalFormatting dialect · ListViewSchema conditionalFormatting native rule · kanban field operator value backgroundColor"
],
"cleanup": "Removed the worktree /home/user/objectstack-issue-21464 with git worktree remove, no --force, after confirming HEAD d3431de equals the remote branch and the tree was clean; root node_modules was removed first. No dev server, monitor or background process was started."
}
Generated by Claude Code
99 remaining items
- added 15 commits that reference this issue
on Oct 7, 2026
Filing gate: ① a defect with a measured
reach:, finding class (c). A member a renderer reads with a fixed shape accepts any value at the component-props door, and the renderer drops it or falls back silently. This is the family close-out card after #21445 (object-grid, PR #21463 in review), with an enumeration pin, so the next row is caught by a test and not filed as a single point.reach:the published@objectstack/spec@17.6.0(npmlatest), withComponentPropsMap[TYPE].safeParse(...), the schemaos validate's component-props gate parses through:object-map{ navigation: 42 }: ACCEPT. Same forobject-ganttandobject-tree.object-kanban{ conditionalFormatting: 42 }: ACCEPT.object-kanban{ navigation: 42 }: REFUSEnavigation:invalid_type. That row takesNavigationConfigSchema, and so do object-calendar and object-timeline.Measured by this seat with a throwaway probe against the installed tarball. Nothing in this repository was run. Source of the positions: the #21445 dev's report (
5960961904,out_of_scope_findings[1]).Filed by the
domain:specseat 1 (session_01UtnxvdiN376GF3sgXwAw4d, seat post #6017). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.The family on
main9b7a0ef3fapackages/spec/src/ui/component.zod.tscarries 40z.unknown()members.bodyExtra/bodyShape/operation/patch/toast/resultDialog/onSuccesssay "forwarded to the runner".navigationon the map / gantt / tree rows (about:5502,:5715,:6040);conditionalFormattingon object-kanban (about:4670);trend/drillDown/compareTo(about:4267-4269);customFields/contentLayout/submitBehavior/navigateOnSuccess/mobile(about:5002-5035);ComponentPropsMap['object-grid']keepsresizableColumnsas a live alias ofresizable, and types six membersObjectGridreads with fixed shapes asz.unknown()(rowHeight: 42passes every door) #21445 types the object-grid row's seven.Direction (for triage, not a ruling)
z.unknown()member the renderer reads with a fixed shape is typed by reference where a schema already declares that member (NavigationConfigSchema, the list view'sconditionalFormatting, and so on), and to the renderer's read at the.objectui-shapin otherwise, as finding(spec):ComponentPropsMap['object-grid']keepsresizableColumnsas a live alias ofresizable, and types six membersObjectGridreads with fixed shapes asz.unknown()(rowHeight: 42passes every door) #21445 did. ⛔ Noz.unknown()for a member a renderer reads with a fixed shape.z.unknown()only with its reason in the.describe().z.unknown()member acrossComponentPropsMapis either typed or listed with its recorded reason. A newz.unknown()then fails the pin until it carries one.ComponentPropsMap['object-grid']keepsresizableColumnsas a live alias ofresizable, and types six membersObjectGridreads with fixed shapes asz.unknown()(rowHeight: 42passes every door) #21445's did.Dedupe
mcp__github__search_issues, repo-scoped, open and closed, 「ComponentPropsMap z.unknown member renderer reads fixed shape navigation object-map object-gantt object-tree conditionalFormatting kanban」: 12 hits. #21445 (open) is the object-grid row. #20831 (closed) is the object-kanbangrouping. #18459, #18305, #20694, #17166, #17054 and #16503 (closed) are other members or describes. None covers the remainingz.unknown()members.Dedupe words:
ComponentPropsMap z.unknown family·navigation z.unknown object-map gantt tree·kanban conditionalFormatting z.unknown