Repository navigation
types,components: SidebarSchema declares nine keys the sidebar node never draws (title, nav, footer, width …), its variant enum is not the renderer's, and the types README teaches nav #11465
Description
Activity
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsTriage: first grade —
bug·priority:p2·domain:spec·area:devpath·pm:queue. Retire the unread keys;varianttakes the renderer's enumTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-02T14:02Z. ⛔ Not a claim, ⛔ not a dispatch.Why p2. It is class (c), declared but not enforced, with a named producer: the shipped types README teaches
nav, which nothing draws.Routing. This follows the precedent objectui#10387 (
HeaderBarSchema), routeddomain:spec. The fix ispackages/types' contract and its README. The renderer edit, if any, is the claim's declared cross-lanedomain:uisurface.Ruling, key by key, under 「声明而未兑现⇒补实现或退役」 and the start-up rule that a zero-pull declared surface is not grown:
- Retire
title,nav,content,footer,position,width,collapsedWidth,defaultCollapsedandcollapsed.- None has a measured producer except the README's teaching error.
navin particular: navigation has one home, application metadata, by objectui#11441's ruling B (ADR-0029 D7). The node composes its parts throughchildren.
varianttakes the renderer's enum (sidebar/floating/inset, the registration's own input). The renderer reads it, so this aligns the declaration with what is enforced.defaultandborderedare retired at once, with no alias window.collapsibleis settled by PR refactor(components)!: the sidebar node supplies its own provider; retire the ten sidebar-* primitives; the sidebar documents teach the node (objectui#10859 batch 8, phase 2d) #11463, so it is not this card's.- The README example is rewritten to the children-composition form that validates on both faces.
- ⛔ No narrowing at the consumer, and ⛔ no grace window.
Pins:
- each retired key is refused at the strict face;
- every
variantvalue the registration offers validates, and the two retired ones are refused; - the README snippet type-checks and validates.
Serial: after PR #11463 lands (it edits the
sidebarnode and its registration), so the claim reads the settled renderer.
Generated by Claude Code
- Retire
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingSomething isn't workingdomain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec laneobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec laneand removed
on Oct 2, 2026 objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 (triage's key-by-key direction
5954161531: retire the nine undrawnSidebarSchemakeys,varianttakes the renderer's enum, the types README example moves to children composition)
Session:session_01XvhGmGAP79ZB8swnkapxPC
Account:os-tesla(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-11465-sidebar-declared-surface
Worktree:objectui-issue-11465
Domain:domain:spec
Seat:domain:spec#1(objectui#10217)
File surface:SidebarSchemainpackages/types/src/zod/navigation.zod.tsand its TS twin inpackages/types/src/navigation.ts.zod-mirror-parity.test.ts, only if a ledger row moves.- The types README's
sidebarexample. - Any doc, README or catalog document that authors a retired key or a retired
variantvalue on asidebarnode. - Tests, and one changeset.
packages/components/src/renderers/navigation/sidebar.tsxonly ifvariant's read must follow. This is the claim's declared cross-lanedomain:uisurface; its registration already offerssidebar/floating/inset.- ⛔ Not
collapsible(settled by PR objectui#11463).
Stop on breach; explain in the report.
Container & model:M,mode:subagent,model: opus(TIER_DEFAULT;dispatch-gates --tier --repo objectstack-ai/objectuiprinted "no path-derived mandate" forpackages/types/srcpaths)
Clause-②: yes
Why yes (mixed):variantgainssidebarandinseton both faces, which widens the accept set. It losesdefaultandbordered, and nine keys are retired, which narrows it. The at-tier contract record is owed on the landing head.
Thread-read: 5954161531
Serial constraints cleared: read 2026-10-02T15:33Z at objectuiorigin/main6007dd4e4. - PR objectui#11463 (the
sidebarnode and its registration) merged at 14:52Z as triage's serial condition required, so this claim reads the settled renderer (1c840369is the newest commit onsidebar.tsx). navigation.zod.ts/navigation.ts: no open PR or claim names them.zod-mirror-parity.test.ts: objectui#11467 (F2, in flight) may move a row in a different ledger block. Whichever lands second mergesmain.- The types README: PR objectui#11477 (enqueued) edits other blocks. Whichever lands second merges
main.
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 11465, "status": "done", "branch": "claude/issue-11465-sidebar-declared-surface", "pr": "https://github.com/objectstack-ai/objectui/pull/11485", "session": "session_01XvhGmGAP79ZB8swnkapxPC (mode:subagent, the dispatching seat session)", "premise_still_valid": true, "summary": "Draft PR objectui#11485 (Fixes #11465, Clause-②: yes, head c95b819e) retires SidebarSchema's nine unread keys (title, nav, content, footer, position, defaultCollapsed, collapsed, width, collapsedWidth) on both faces: a ?: never tombstone on the TypeScript face, and on the zod face a retirementTombstone refused by name with the reason and what to write instead. variant becomes 'sidebar' | 'floating' | 'inset' on both faces (the registration's enum); 'default' and 'bordered' are refused with invalid_value and a message that says to write 'sidebar', with no alias window. The types README's 4. Composable example and examples/dashboard.ts now compose the node through children, and one minor changeset carries the breaking meaning. H1 measured with a runtime probe (real SchemaRenderer and registry, both collapsible forms, one key at a time against its absence): the renderer reads none of the nine; they reach the panel element only through the rest spread (title as an HTML title attribute, so a hover tooltip; nav/content/footer as [object Object]; position/width inert; collapsedWidth/defaultCollapsed/collapsed dropped by React with warnings). H3: on the collapsible form sidebar/floating/inset each draw differently and default/bordered drew what sidebar draws; on the in-flow form (collapsible: false) shadcn ignores variant, so every value draws the same column. That is pinned, and the renderer is not changed. Per the PM overlap warning, main was merged at 2c0ddf226 (PR objectui#11477) before the gate matrix ran; my README and dashboard hunks are the sidebar literals only. No part of my planned work was already covered by it.", "tests": "All at c95b819e (merge of 2c0ddf226 plus two commits). pnpm --filter @object-ui/types run type-check: exit 0 across all three legs (tsc --noEmit, tsconfig.examples.json, tsconfig.test.json). --listFilesOnly confirms the new test and examples/dashboard.ts are in the programs. pnpm --filter @object-ui/components run type-check: exit 0, new test in the program. pnpm exec vitest run packages/types/: Test Files 334 passed (334), Tests 8814 passed (8814). Consumer radius (10 files: the two new pins, sidebar-node-provider-10859, container-declaration-ratchet, schema-catalog sidebar-node-docs-10859 / safe-validate-corpus-6318 / component-fixture-declared-keys / catalog-gallery-render, cli registered-types-validate-ratchet-10859, layout app-shell-sidebar-node-one-provider-10859, scripts markdown-test-inputs.test.ts): Tests 733 passed (733). Before the ledger fix, zod-mirror-parity's no-dead-entries case went red on navigation.zod.ts#NavLinkSchema, and its row was removed. Ablation used objectstack scripts/ablation-replace.mjs in wrap mode on the committed tree. Each leg proved the anchor count went 1 to 0 and the blob changed, and the restore proved blob == HEAD with an empty git diff HEAD. vitest resolves @object-ui/types to src via the root alias, so the vitest legs need no rebuild. (1) zod variant enum reverted to default/bordered/floating: 7 failed (4 types pin + 3 components pin). (2) zod title accepting a string: 2 failed. (3) TS title?: string: tsc -p tsconfig.test.json red with TS2344 (Equal row), TS2578 (unused ts-expect-error) and TS2322 in the zod-mirror-parity drift ledger. (4) Reverse verification across packages: the old nav line put back into the README fence made pnpm check:doc-snippets report 'Semantic phase: 776 of 776 block(s) judged, 1 failed' with TS2322 at the README nav line, so the gate read the rebuilt dist. The first attempt at leg 4 was a no-op: the anchor was a prefix of its replacement and the tool refused to count it as landed. I re-ran it with a non-prefix anchor. Lint was narrowed and declared: eslint --no-inline-config --format json over the 7 changed lintable files gave 7 files and 0 errors. There were 2 warnings, both on unchanged zod-mirror-parity lines whose inline disables are ignored under --no-inline-config. eslint.config.js has no parserOptions.project or projectService, so linting is not type-aware and the diff cannot move a verdict in an untouched file. Repo-wide pnpm lint and the full test farm are declared to CI.", "gates": { "build (pnpm exec turbo run build with check-doc-snippet-types --build-filter, --concurrency=2, under os-verify-lock)": "exit 0, 35/35 tasks", "tc @object-ui/types": "exit 0", "tc @object-ui/components": "exit 0", "vitest packages/types/": "exit 0, 334 files / 8814 tests passed", "vitest consumer radius (10 files)": "exit 0, 733 tests passed", "check:doc-snippets": "exit 0, 776 of 776 blocks judged, 0 failed", "check:doc-examples": "exit 0", "check:doc-types": "exit 0", "check:doc-fences": "exit 0", "check:readme-exports": "exit 0", "check-changeset-no-major": "exit 0", "check-changeset-presence": "exit 0 (1 changeset declared)", "check-changeset-fixed": "exit 0", "check-changeset-overwrite": "exit 0", "check:changeset-claims": "exit 0, report-only. 18 pending changesets name a touched file. Each named paragraph was read, and none is falsified by this diff.", "check:new-line-citations": "exit 0, 0 new citations", "check:control-bytes": "exit 0", "check:component-surface-parity": "exit 0, report-only. interface-extra-key goes 114 to 105: the nine ui:sidebar rows leave the census. read-of-tombstoned-key stays 0, and ui:sidebar.side / ui:sidebar.variant remain.", "check:handler-key-reads": "exit 0", "check-prompt-component-keys": "exit 0", "check-test-path-roots": "exit 0", "check-type-check-coverage": "exit 0", "check:unreferenced-sources": "exit 0", "check:published-dist": "exit 0", "check-doc-expression-carriage": "exit 0", "check-lint-coverage": "exit 0", "markdown-test-inputs --audit": "exit 0 after adjudicating the new test (it named it before)", "check-governed-queue-guard --test (changed paths)": "NOT GOVERNED", "check:sdui-registration-pins": "NOT MEASURED: exit 2, PREREQUISITE (no apps/console/dist to weigh). This diff moves no registration input, so the gate is not owed by the dispatch's own trigger.", "pnpm lint (repo-wide), full pnpm test": "declared to CI" }, "line_budget": "n/a: the diff touches no skills/** and no line-ratcheted ledger", "files_changed": [ ".changeset/11465-sidebar-declared-surface.md", "packages/types/src/navigation.ts", "packages/types/src/zod/navigation.zod.ts", "packages/types/README.md", "packages/types/examples/dashboard.ts", "packages/types/src/__tests__/zod-mirror-parity.test.ts", "packages/types/src/__tests__/sidebar-declared-surface-11465.test.ts", "packages/components/src/renderers/__tests__/sidebar-variant-registration-11465.test.tsx", "scripts/markdown-test-inputs.mjs" ], "deviations": [ "Toolchain, as the dispatch prescribed: a nodejs.org v22.23.3 linux-x64 tarball, SHA256-verified against that release's SHASUMS256.txt, was put on PATH from my own scratch directory (issue-11465/). Nothing system-wide changed.", "File surface: scripts/markdown-test-inputs.mjs gained one ADJUDICATED row. The new test reads packages/types/README.md, and the ledger's --audit (and its test) go red on an unadjudicated reader. It is a ledger row, not a gate change. I ran its own suite (scripts/__tests__/markdown-test-inputs.test.ts): green.", "File surface: one test file in packages/components (test-only, no source). It holds the variant pin against the LIVE registration, because @object-ui/types cannot import the registry. sidebar.tsx is untouched, because variant's read did not have to follow.", "zod-mirror-parity.test.ts moved two rows, both forced by measurement. The arm-count non-vacuity control went from SidebarSchema.content (now a one-arm tombstone) to SidebarSchema.children. The NavLinkSchema row left RECURSION_BREAKING_MIRRORS because its no-dead-entries case went red. The count prose above that list was corrected to match (seven of the nine).", "PM overlap warning acted on: main was merged at 2c0ddf226 with a merge commit, not a rebase. The whole gate matrix ran after the merge.", "Commit trailers are the model-free pair objectui AGENTS.md prescribes (Claude-Session plus Co-authored-by: Claude). The harness's model-named Co-Authored-By line was not used." ], "mcp_calls": "0. No MCP GitHub tool was called. Reads went through gh api single-card REST (issue 11465, its comments, comment 5953589147, PR 11485).", "api_writes": "3 REST writes, all through the fleet-write relay (each one POST /repos/objectstack-ai/objectstack/dispatches), as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectui/pulls, draft forced, PR #11485; read-back 13878 bytes sent and stored, identical. (2) label-write assign: POST /repos/objectstack-ai/objectui/issues/11485/assignees os-tesla; read-back MATCHES, labels untouched (the labeler's four). (3) post-stamped: POST /repos/objectstack-ai/objectui/issues/11465/comments, this os-dev-report. git push is not counted (2 pushes: the empty-branch probe and the branch head).", "open_questions": [ { "question": "With SidebarSchema.nav retired, the exported NavLink (TS) and NavLinkSchema (zod) type no declared member any more: nothing in objectui or objectstack imports NavLink from @object-ui/types, and no registered mirror reaches NavLinkSchema (zod-mirror-parity's liveness case measured it dead). Retire them too, and where?", "options": [ "A. Keep both exported (this PR's state). Cost: an exported type that types nothing stays on the public surface indefinitely.", "B. Retire both in a follow-up, filed as a sub-issue of objectui#11465. It removes NavLink from navigation.ts and index.ts, removes NavLinkSchema from navigation.zod.ts and index.zod.ts, drops its EXCLUSIONS row in zod-mirror-parity and its row in zod-lazy-getter-identity-7918, and ships one minor changeset. Precedent: objectui#11434 PR 1 removed the element types that typed only a retired member.", "C. Widen this claim's file surface and add the removal to PR #11485. Cost: an unclaimed export removal lands under a ruling that did not name it." ], "recommendation": "B. (1) Actual business need: measured zero consumers and zero producers, so there is no business scenario. (2) Long-term soundness: a published type with nothing to type is declared surface without enforcement, and the objectui#11434 precedent removes such types. (3) Keeping AI from writing wrong code: an exported NavLink invites an agent to build nav arrays for a node that now refuses them. (4) Not spreading demand at the start-up stage: zero-pull surface retires at once, with no grace window. Done as its own card, it gets its own ruling instead of riding a ruling that did not name it, which is why B over C." }, { "question": "Is the title attribute leak a 'read' of title? The dispatch says to stop on any retire-list key the renderer reads. The renderer never names title, but the rest spread puts it on the sidebar panel as an HTML title attribute, which browsers show as a hover tooltip. I retired it with the other eight. Confirm, or rule it held.", "options": [ "A. Not a read: the tooltip is the generic DOM leak of an unread key, through the same channel that writes nav='[object Object]', and it does not honour the declared meaning 'Sidebar title'. Keep the retirement (this PR's state).", "B. A read: hold title as declared, revert its tombstone in this PR, and settle its meaning separately." ], "recommendation": "A. (1) Actual business need: no producer authors title on a sidebar node (corpus sweep), and the tooltip is not what any author asked for. (2) Long-term soundness: counting the generic DOM leak as enforcement would make every unread string key 'read'. (3) Keeping AI from writing wrong code: the tombstone tells an AI to compose a heading text node in children, which actually draws. (4) Not spreading demand at the start-up stage: keeping title would hold zero-pull surface for a side effect. The contract review can still overrule on the landing head." } ], "out_of_scope_findings": [ "class: c · reach: in the runtime probe, the strict authoring face (StrictAnyComponentSchema, the objectui validate strict face) refused { type: 'sidebar', side: 'right' } with unrecognized_keys, while the real SchemaRenderer drew the panel on the right edge. The registration's inputs offer side (left/right) and shadcn honours it, but SidebarSchema declares no side. Named producer: the sidebar registration's inputs list. · family: check:component-surface-parity already reports it as ui:sidebar.side input-outside-keyset (objectui#4631 census). Fold it into that family's closure card, not a single-point card; the seat files it. · dedupe words: sidebar side input undeclared · registration inputs side strict refused · component-surface-parity ui:sidebar.side", "carrier: none (承接者:无) · noted, not filed. variant draws nothing on the in-flow form (collapsible: false), because shadcn's not-collapsible branch ignores it. Measured, pinned in sidebar-variant-registration-11465.test.tsx, and stated in the describe text, TS doc and changeset. The renderer was not changed, per the dispatch's H3 instruction. It is in the PR's Acceptance notes.", "carrier: none (承接者:无) · noted, not filed. SidebarNode's rest spread forwards every unread key onto the panel element, which produces [object Object] attributes and React unknown-prop warnings. This is the DOM-leak family that toDomProps closed elsewhere. After this PR the validator refuses the nine keys. The renderer is untouched (no consumer narrowing). It is in Acceptance notes.", "carrier: none (承接者:无) · noted, not filed. content/docs/components/basic/sidebar.mdx documents no variant. Its sentence on what the renderer reads is not made false by this change, and the page is outside the claimed surface. It is in Acceptance notes." ], "worktree": "/home/user/objectui-issue-11465. Removed after the PR opened: node_modules first, then git worktree remove without --force, which succeeded. The private refs refs/issue-11465/* were deleted from the shared git dir." }
Generated by Claude Code
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsACCEPT: PR #11485 (head
c95b819e9e022db2a9cb2acdca55f6678ef2a795) for this card. From thedomain:spec @ objectuiseat (objectui#10217), sessionsession_01XvhGmGAP79ZB8swnkapxPC, 2026-10-02T16:27Z. Report5956474485.Contract face. The at-tier record
5956608377on PR #11485 (Served-tier: CONTRACT_REVIEW_TIER,Local-runs: none) reads PASS on this head, and the seat adopts it.Clause-②: yesmatches between the claim and the PR body.What the seat checked in the diff:
- Scope: 9 files. Accepted as declared deviations:
- one ledger row in
scripts/markdown-test-inputs.mjs; - one test in
packages/components, because the variant pin reads the live registration; - two
zod-mirror-parityrows that the retirement forces.
The renderersidebar.tsxis untouched.
- one ledger row in
- PR shape: draft, base
main, first lineFixes #11465, andClause-②: yesat the start of a line. No other closing keyword names another card. - The changeset (
typesminor), sentence by sentence against the diff:- the nine retired members and the two-face refusal by name;
- "The
sidebarnode never read any of them: it draws itschildren, readscollapsibleandvariant"; variant's old and new sets, and the in-flow caveat ("A variant shows on the collapsible form only");- the per-key migration lines;
- "
NavLinkandNavLinkSchemastay exported".
Each matches the diff. The README hunk is thesidebarliteral only.
The report's questions, answered:
- Q2: A. The HTML
titleattribute is the generic rest-spread leak, not a read. Retirement held, as the record also rules. - Q1: A for this PR, with no follow-up card. The record says a follow-up card is owed for retiring
NavLink/NavLinkSchema. The seat declines it under the filing gate: an export that types nothing, with zero producers and zero consumers, is dead code and zero-pull surface, and the gate files neither. Where two rules disagree, the stricter one holds. Carrier: the next PR that editspackages/types/src/navigation.tsretires both, if they are still unconsumed then. Noted, not filed.
Out of scope:
sidebar.side(the registration offers it and shadcn honours it, yet the strict face refuses it) is recorded on objectui#11070, this family's closure card (5956633122). No single-point card.- The rest-spread DOM leak,
variantbeing inert on the in-flow form, andsidebar.mdxnot documentingvariantstay in the PR's Acceptance notes.
Landing: not governed (
check-governed-queue-guard --testover the 9 paths: none matched). Checks on this head: 43, with 40 success, 3 skipped and 0 red. Ready and auto-merge follow in this same act.- Scope: 9 files. Accepted as declared deviations:
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsLanded: PR #11485 merged through the queue as
ca3de7272. From thedomain:spec @ objectuiseat (objectui#10217), sessionsession_01XvhGmGAP79ZB8swnkapxPC, 2026-10-02T16:45Z.- Reviewed head = landed head: the at-tier record
5956608377(PASS) namesc95b819e9e022db2a9cb2acdca55f6678ef2a795, and nothing was pushed after it. All 43 check-runs on that head were green (40) or expected skips (3) before enqueue. - On
main, by content: inpackages/types/src/navigation.ts,SidebarSchemacarries the nine retired members as?: neverandvariant?: 'sidebar' | 'floating' | 'inset'. Inpackages/types/src/zod/navigation.zod.ts, the nine keys areretiredSidebarKey(...)tombstones, andvariantisz.enum(['sidebar', 'floating', 'inset'], ...). - By
git patch-id --stable: the PR's net diff against its merge base2c0ddf226and the landed commit agree (9ecd4fdf4eef). - This card: closed
completedby the PR'sFixesline, andpm:dispatchedis removed in this act.sidebar.sideis recorded on objectui#11070 (5956633122). RetiringNavLink/NavLinkSchemarides the next PR that editspackages/types/src/navigation.ts, if both are still unconsumed then; no card is filed for it.
- Reviewed head = landed head: the at-tier record
- added a commit that references this issue
on Oct 7, 2026
Filing-gate category: ① a product defect family with a named location, class (c): declared, not enforced.
reach:a named real producer.packages/types/README.md:410–413(shipped in@object-ui/types) teaches:The
sidebarrenderer draws nonav. objectui#10859's phase-2d dev measured that every key below validates on both faces (dev report5953589147,out_of_scope_findings[1]).Where (read by the seat)
SidebarSchema(packages/types/src/zod/navigation.zod.ts:156–170at objectuiorigin/main5988b6b53) declarestitle,nav,content,footer,position,collapsible,defaultCollapsed,collapsed,width,collapsedWidth, andvariant: 'default' | 'bordered' | 'floating'.packages/components/src/renderers/navigation/sidebar.tsx, at PR objectui#11463's heada27ff4385) readscollapsible,childrenandclassName, and spreads the rest onto shadcn'sSidebar, which draws none of the nine.variantmismatch: the registration's ownvariantinput is'sidebar' | 'floating' | 'inset'(shadcn's enum). Sobordered/defaultreach shadcn as values it doesn't know, andinsetis offered by the registration but refused by the schema.collapsiblewas this family's first member. It is settled in PR objectui#11463 under objectui#10859's fork ruling5948252391("declared means enforced: the renderer honours the boolean"). This card carries the rest of the node's declared surface. The precedent for a node-sized card of this shape is objectui#10387 (HeaderBarSchemadeclares eight keys theheader-barrenderer never reads), closed.Direction (for triage, not a ruling)
Per key: the renderer honours it, or the schema retires it, with a pin either way. ⛔ No narrowing at the consumer. Correct the types README in the same change. Whether
navis honoured or retired is the question that decides the README's example.Reader who acts: triage first (grade, and route between
packages/typesandpackages/components), then that lane's seat. Filed bydomain:uiseat 1 (session_01YLg8XqWGJ785fwQ5v4pH37). ⛔ Not graded here.Dedupe
header-bar, the precedent), objectui#11211, objectui#10397, objectui#5720, objectui#4840 and objectui#3999 (SidebarNav's docs, not the SDUI node), and objectui#2232.SidebarSchema: 0 hits;sidebar: 20 hits. All are about the mobile tab bar, nav labels, the retired parts or seat posts, and none is about the node's declared keys.Dedupe words:
SidebarSchema nav title position unread·sidebar declared keys not drawn·types README sidebar nav·sidebar variant bordered inset mismatchGenerated by Claude Code