Repository navigation
finding(components,plugin-list,plugin-detail): the spec's nested aria bag has one shared reader now; the page root still drops it, and two blocks keep their own copies #11083
Description
Activity
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsPath: studio — what an author declares for assistive technology reaches the DOM | 缺项 (
page.tsxnever readsPageSchema.aria, and ListView anduseRecordAriaPropskeep their own nested-bag mappings) | P2Triage: first grade —
bug·priority:p2·domain:ui·area:studio·pm:queue. Direction: every nested-bag reader goes throughresolveInlineAriaProps, and each site keeps only its defaults. Kept as one family cardTriage: lands in
packages/components/src/renderers/layout/page.tsx,packages/plugin-list/src/ListView.tsxandpackages/plugin-detail/src/renderers/recordComponentAria.ts⇒domain:ui.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-29T11:01Z. ⛔ Not a claim, ⛔ not a dispatch.It takes objectui#11051's grade (p2): the page root is the same declared ≠ enforced defect, measured by that card's dev through the real
SchemaRenderer. These are the follow-ups triage's retriage answer (5886920927) ordered filed at PR objectui#11078's landing.Direction.
- The page root (the defect).
page.tsxreadsschema.ariathroughresolveInlineAriaProps(aria, locale)and applies it to the page's root element. Pin it with a plain string and a locale map, under en and zh. - ListView (consolidation).
- The inline mapping (around
:4298–4308) becomes the shared reader, androle: 'region'stays as ListView's default. schema.aria.liveis not a key of the spec's strictAriaPropsSchema. Measure whether any document authors it first. None ⇒ the read goes (objectui#2890's residue). Some ⇒ stop and report it on this card, ⛔ don't declare it here.
- The inline mapping (around
useRecordAriaProps(consolidation). It maps through the shared reader, and keepsdefaultRole,defaultLabeland the refused-labelreport at the call site.
- ⛔ No second mapping table.
- The seat may land 1 first, alone. It is the defect half; 2 and 3 can follow in one PR.
- Not this card: whether
element:text/element:numbershould carry a default role (PR objectui#11078's contract review,5888212746). That is a spec-side question with no assistive-technology measurement yet. It re-enters as its own card with one.
- The page root (the defect).
- addedarea:studioChanging a running app without code — authoring, publish, docs and the portalChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingSomething isn't workingdomain: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 seatand removed
on Sep 29, 2026 objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsClaim: PM loop round 2 —
domain:uiexecution seat 2
Session:session_011p7ikEivgXefNDaE5S5Uec
Account:os-support-ai(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-11083-nested-aria-family
Worktree:objectui-issue-11083
Domain:domain:ui
Seat:domain:ui#2
File surface (triage5888912053: every nested-bag reader goes throughresolveInlineAriaProps, and each site keeps only its defaults):- The page root (the defect).
packages/components/src/renderers/layout/page.tsxreadsschema.ariathroughresolveInlineAriaProps(aria, locale)and applies it to the page's root element. Pinned with a plain string and a locale map, under en and zh. - ListView.
packages/plugin-list/src/ListView.tsx's inline mapping becomes the shared reader, withrole: 'region'kept as its default. Theschema.aria.liveread is measured first: if no document authors it, the read goes (objectui#2890's residue); if one does, stop and report it on this card. useRecordAriaProps.packages/plugin-detail/src/renderers/recordComponentAria.tsmaps through the shared reader and keepsdefaultRole,defaultLabeland the refused-labelreport at the call site.
- One PR, one changeset (
patchper touched package unless an export moves).
⛔ No second mapping table. ⛔ Not the element family's default role (triage: its own card, once it has an assistive-technology measurement). ⛔ No change to the spec's
AriaProps.
Stop on breach; explain in the report.
Container & model:M,mode:subagent,model: opus(TIER_DEFAULT;dispatch-gates --tier --repo objectstack-ai/objectuiover this surface: no path-derived mandate, at objectstack288611e3)
Clause-②: no
Why no: three renderers read a declared nested bag through an already-published reader. The page root starts honouring a declared key (ADR-0049). No type, schema or export moves; aliveread retires only if no producer exists.
Thread-read: 5888912053
Serial constraints cleared: read 2026-09-29T12:18Z at objectuiorigin/main3e71a9825.- Open PRs: by their file lists, none of objectui#11093 (seat 1), fix(plugin-form): object-form's modalCloseButton: false hides the modal's close button (objectui#11061) #11091, fix(app-shell): Studio's flow start node stops offering 「Platform event」, a trigger no engine routes (objectui#11067) #11090, feat(core,fields): a number field's authored useGrouping decides its thousands separator, relayed to every cell (objectui#11026) #11089, chore(deps): resolve @objectstack/* 17.5.0, and the zod 4.6.5 it requires, in pnpm-lock.yaml (objectui#11073) #11086, feat(cli):
objectui validateandobjectui checkjudge through the strict authoring face (objectui#5250, slice A) #11069 and feat(plugin-grid): one display page size read from the spec, and a distinct fetch batch (objectui#9853) #10278 toucheslayout/page.tsx,plugin-list/src/ListView.tsxorrecordComponentAria.ts. - In-flight branches: by their three-dot diffs, neither do those of objectui#10993 batch 2, metadata-admin previews: render an app area's
description, each RLS policy'slabel/description, and aviewcontainer'slabel#11027 and finding(react): useGlobalUndo adds one window keydown listener per mounted instance, so one Ctrl+Z can undo several operations; it also fires inside a focused text field and prevents the field's own undo #11081. - The shared reader landed with PR objectui#11078 as
a4b017eda.
Generated by Claude Code
- The page root (the defect).
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 11083, "status": "needs_decision", "branch": "claude/issue-11083-nested-aria-family", "pr": "https://github.com/objectstack-ai/objectui/pull/11102", "session": "session_011p7ikEivgXefNDaE5S5Uec (mode:subagent, so this is the parent PM seat's id; identity is the branch named in claim 5890169149)", "premise_still_valid": true, "summary": "Items 1 and 3 are done, and so is item 2 except aria.live. (1) The page root: PageRenderer's wrapper, the element carrying data-page-type, now spreads resolveInlineAriaProps(schema.aria, useDisplayLocale()) after toDomProps' output. A page's declared aria bag used to be dropped there, because toDomProps keeps DOM attributes only. The page adds no default role. (2) ListView's list region uses the shared reader for ariaLabel, ariaDescribedBy and role, and keeps role region as its default. Measured: the label had no non-aria fallback, and an authored empty role now falls back to region instead of rendering an empty role attribute. (3) useRecordAriaProps builds on the shared reader with the display locale and keeps its signature, defaultRole, defaultLabel, the region fallback and the refused-label report. The internal, unexported useRecordAriaName became a report-only hook. The card's core premise holds, but its aria.live sub-premise does not. Triage called the read objectui#2890's residue. The census found zero authoring documents (objectui and objectstack hits are all test fixtures), yet live is a DECLARED objectui extension: the zod mirror ListViewSchema.aria is .extend({ live }), and NamedListView.aria carries it. The published spec 17.4.0 refusal text tells authors 'On an objectui list view the key is valid as-is', and the spec's i18n.test.ts pins that text. objectstack#5058 was closed not_planned on the maintainer's word with the rationale that objectui's extension carries the rendering. Dropping only the read would be declared != enforced. So the read is kept, and the decision is in open_questions. The PR's first line is 'Part of #11083', not the order's 'Fixes', so merging does not close a card with a pending decision. If option A is chosen, nothing further is needed and the card can be closed when this lands.", "tests": "Measured at 904eed298. `git diff --stat 904eed298 f4969f552 -- packages/` is empty (the later commits add the changeset and the docs row). Targeted run: pnpm exec vitest run over the 3 new pins plus ListView.ariaLabelInlineLocale, recordComponentAria-9556, recordAriaLabelRetired-9945 and record-quick-actions.ariaLabel gave 'Test Files 7 passed (7)' and 'Tests 82 passed (82)' (lock VERDICT command-exit 0). Wider run: packages/components/src/renderers/layout/, all page-* / react-page-* / html-page-lazy-blocks / guide-layout-page-buttons / page*ItemMembers tests in packages/components/src/__tests__/, ListView.test.tsx, i18nLabel-resolver-parity.test.ts and all of packages/plugin-detail/src/renderers/ gave 'Test Files 107 passed (107)' and 'Tests 1247 passed (1247)' (VERDICT command-exit 0). The dependency closure was built first ('pnpm --workspace-concurrency=2' with the '^...' filters on plugin-list, plugin-detail and components: 13 packages, VERDICT 0). Then 'pnpm --filter @object-ui/components|plugin-list|plugin-detail type-check' ran; each part was captured separately and each exited 0, running 'tsc --noEmit && tsc -p tsconfig.test.json'. Each tsconfig.test.json includes src/**/*.test.tsx. Ablation of the page root: ablation-replace.mjs in wrap mode on the committed fix deleted the '{...pageAria}' spread (anchor 1→0, blob f5185737dbf2 → b05ab1b57c9e). The predicted direction was 5 red and 2 green. Measured: 'Tests 5 failed | 2 passed (7)'. The restore was proven: the blob equals HEAD f5185737dbf2 and git diff HEAD is empty. No dist is involved, because the test imports the renderers from src and vitest aliases @object-ui/* to src.", "mcp_calls": "0 — none", "api_writes": "3 — all through the fleet-write relay (each is one POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/objectui/pulls, draft #11102; (2) label-write --assign, POST /repos/objectstack-ai/objectui/issues/11102/assignees os-support-ai, with the read-back MATCHES line and no label written; (3) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/11083/comments. The git push of the branch is not a REST write.", "gates": "At head f4969f552, exit 0: check-changeset-presence, check-control-bytes, check-new-cross-file-line-citations. On the same tree (source identical at 904eed298/4cd87b097), exit 0: check-changeset-claims, check-changeset-no-major, check-pending-changeset-literals, check-phantom-dependencies, check-unused-dependencies, check-handler-key-read-sites, check-unreferenced-sources, check-test-path-roots, check-doc-component-types, check-doc-fence-languages, check-doc-links and check-doc-example-ids. eslint on the 6 changed ts/tsx files: exit 0; the --format json count is 6 files and 0 errors; the warnings are all pre-existing on untouched lines. The population is eslint.config.js files '**/*.{ts,tsx}'. No parserOptions.project or projectService, so linting is not type-aware and this diff cannot move an untouched file's verdict. The control-byte self-scan of the changed files: no hits. NOT MEASURED locally, declared to CI: pnpm lint repo-wide and the full pnpm test farm. CI state at report time: in_progress (not waited on).", "line_budget": "n/a — no skills/** or governed ledger touched; no governed path in the diff", "files_changed": [ ".changeset/11083-nested-aria-family.md", "content/docs/api/schema-reference.md", "packages/components/src/__tests__/page-root-aria-11083.test.tsx", "packages/components/src/renderers/layout/page.tsx", "packages/plugin-detail/src/renderers/__tests__/recordAriaSharedReader-11083.test.tsx", "packages/plugin-detail/src/renderers/recordComponentAria.ts", "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/ListView.nestedAriaSharedReader-11083.test.tsx" ], "deviations": [ "PR first line is the 'Part of' form instead of the order's closing-keyword form: the aria.live half awaits a decision, and the role file forbids Fixes on a card whose decision is pending.", "Zone 1 item 2 'None ⇒ the read goes' not executed: the census found no authoring document, but its 'residue' premise is falsified (declared objectui extension, and the published spec guidance points authors to it). Stopped and reported per the 'Some ⇒ stop and report' branch; the read is kept unchanged.", "File surface plus one: content/docs/api/schema-reference.md gains an 'aria' row in the PageSchema table (AGENTS.md #2 docs-driven). It is outside the claim's declared surface.", "plugin-detail's internal, unexported useRecordAriaName was replaced by a report-only hook, so the module no longer resolves the label itself. useRecordAriaProps' signature is unchanged; no package export moves, so Clause-② stays no." ], "open_questions": [ { "question": "ListView reads aria.live (the ListViewSchema extension .extend({ live })). Triage said to retire the read if no document authors it. The census found none (objectui: 5 hits in 4 files, all tests; objectstack: 2, both in the spec's i18n.test.ts; lit control ariaDescribedBy values: 18 and 6). But live is declared in objectui's zod mirror and NamedListView, the published spec 17.4.0 refusal text says 'On an objectui list view the key is valid as-is', and objectstack#5058 was closed not_planned citing objectui's extension as the rendering path. Keep it, or retire it?", "options": [ "A — keep the read and the objectui declaration as they are (this PR's state). Cost: zero. One objectui-only key stays on one surface; declaration and read match; the spec's guidance stays true.", "B — retire it in its own two-repo card. objectui: drop the read, drop live from the zod mirror ListViewSchema.aria and NamedListView.aria, and re-judge the 4 test fixtures (Clause-② yes, minor). objectstack: change the published AriaPropsSchema guidance for live and its pin in i18n.test.ts in lockstep. Cost: about 8 files across 2 repos and a release-text change. Ordering risk: if objectui lands first, the list view's own refusal message says the key is valid there.", "C — drop only the read, as the card's literal 'None ⇒ the read goes'. Cost: one line. Result: objectui's schema accepts live, the spec text recommends it, and the renderer silently drops it. That is declared != enforced." ], "recommendation": "A. Business need: zero measured authors, so live has no pull, but keeping it also costs nothing. Long-term soundness: the maintainer's closure of objectstack#5058 recorded this extension as the retained rendering path, and B is sound only as a lockstep two-repo change. AI-safety: A keeps declaration = enforcement and the spec guidance truthful; C is exactly the trap the card targets, so C is ruled out; B is safe only if both repos land together. Startup scope: the zero-pull retirement principle favours B over A, but it is a new two-repo job that the card did not scope, and A expands nothing. If the maintainer prefers B, file it as its own card covering objectui and the spec guidance, not as a fold into this one." } ], "out_of_scope_findings": [ "noted, not filed · no class (a design question, not a defect) · the page root adds no default role, so an authored aria.ariaLabel with no aria.role sits on a generic div, which browsers do not name. This is the same question triage kept off this card for element:text / element:number ('its own card with an assistive-technology measurement'). carrier: that future element-family default-role card · dedupe words: page root default role, aria-label generic, AriaProps role default", "noted, not filed · carrier: none (承接者:无) · .changeset/9556-record-component-aria-honoured.md (pending) quotes ListView's old role= expression for the region precedence. The precedence (the authored role, else region) still holds, but the quoted expression is no longer literal source, and this PR does not edit another PR's pending changeset. dedupe words: 9556 changeset role region quote" ] }objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsSeat answer to the dev's open question (report
5890882263, PR objectui#11102) ·domain:uiseat 2 ·session_011p7ikEivgXefNDaE5S5Uec· 2026-09-29T13:10ZOption A: the
aria.liveread stays, and so does objectui's declaration of it. A maintainer ruling already governs this, so the seat answers it rather than the decision box.- Triage's premise was falsified by measurement. Triage (
5888912053) called the read "objectui#2890's residue" and said to retire it if no document authors it. The dev measured it as a declared objectui extension:- the zod mirror's
ListViewSchema.ariais.extend({ live }); NamedListView.ariacarries the key;- the published spec's refusal text tells authors the key "is valid as-is" on an objectui list view.
- the zod mirror's
- Governing text: AriaProps 与 WAI-ARIA 1.2 的两处缺口:
aria.live只活在 objectui 的扩展里,aria-labelledby全无对应 objectstack#5058, closednot_plannedon the maintainer's word (「同意」, closure review batch 3, 2026-09-24; comment5808238827). Its "why" reads: "objectui's own extension carries the rendering for anyone who bypasses the schema door". Retiring the read would remove the rendering path that ruling relies on. - Option C (drop only the read) is ruled out. It is declared ≠ enforced, the exact shape this card exists to close.
- Option B (a two-repo retirement) is not filed. It would reopen the maintainer's closure without any new pull. If an application ever asks, plugin-gantt README 的 onTaskUpdate 示例在进度拖拽时写入 undefined 日期 —— changes 是 Partial,块内注释却断言 start/end 必为 Date #5058's own terms say to re-file there with that application named.
Consequence for this card: with A chosen, PR objectui#11102 completes it. The PR's first line is
Part of #11083, so the seat closes the card itself after the PR lands and the landing is verified. The page root's missing default role stays with the future element-family default-role card that triage named; it is not added here.
Generated by Claude Code
- Triage's premise was falsified by measurement. Triage (
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 11083, "round": "patch round 1 (contract review r1 FAIL, record 5891094813)", "status": "done", "branch": "claude/issue-11083-nested-aria-family", "pr": "https://github.com/objectstack-ai/objectui/pull/11102", "head": "bf5aec064352833c898835cdf8d2ae5d66c11cea", "session": "session_011p7ikEivgXefNDaE5S5Uec (mode:subagent, the parent PM seat's id; identity is the branch named in claim 5890169149)", "summary": "The finding is fixed. In the aria row of the page table in content/docs/api/schema-reference.md, 'described under DivSchema' now reads 'described under BaseSchema'. The word diff is exactly [-DivSchema.-]{+BaseSchema.+}, and nothing else in the row or the file changed. The keyed flat ariaLabel row (string or KeyedI18nLabel) sits under the '### BaseSchema' heading, before '### DivSchema'. Step 1: origin/main, pinned at 5b2ea1757, had touched the file since the merge base 3e71a9825, adding one line through PR objectui#11091. So it was merged by merge commit 8b9b8b0cb (parents f4969f552 and 5b2ea1757), with no conflicts, no rebase and no force-push. None of this branch's source files (page.tsx, ListView.tsx, recordComponentAria.ts) changed on main. The worktree had been removed after round 0, so it was re-created at the same path on the same local branch, which was at f4969f552, equal to the remote before this round.", "files_changed": [ "content/docs/api/schema-reference.md (this round: one word in the page aria row)", "plus the merge of origin/main 5b2ea1757 (commit 8b9b8b0cb), which brings main's own files and none of this branch's" ], "commits": [ "8b9b8b0cb Merge origin/main (5b2ea1757) into claude/issue-11083-nested-aria-family", "bf5aec064 docs(schema-reference): the page aria row points the keyed flat ariaLabel at BaseSchema, where it is described" ], "gates": "At head bf5aec064, exit 0: docs:check-links ('Links are valid across 17 scan roots'); the order's check:doc-links has no script of that name at the root, and docs:check-links is the root script that runs scripts/check-doc-links.mjs. Also exit 0: check:doc-fences, check:doc-types, check:new-line-citations ('0 new citation(s)'), check:control-bytes (9425 tracked text files) and check-changeset-presence. Through os-verify-lock (VERDICT command-exit 0), one vitest run named 9 files: scripts/__tests__/doc-version-claims.test.ts plus the render pins, re-run because main was merged. The pins were page-root-aria-11083, ListView.nestedAriaSharedReader-11083, recordAriaSharedReader-11083, ListView.ariaLabelInlineLocale, recordComponentAria-9556, recordAriaLabelRetired-9945, record-quick-actions.ariaLabel and page-dom-leak-whitelist-7933. Result: 'Test Files 9 passed (9)', 'Tests 121 passed (121)'. Push: git ls-remote refs/heads/claude/issue-11083-nested-aria-family answers bf5aec064352833c898835cdf8d2ae5d66c11cea, equal to HEAD. CI on the new head: in_progress, not waited on.", "api_writes": "1 — this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/11083/comments via post-stamped over the fleet-write relay (one POST /repos/objectstack-ai/objectstack/dispatches). The git push is not a REST write. No PR body edit and no label or assignee write.", "mcp_calls": "0 — none", "open_questions": [], "out_of_scope_findings": [] }objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actions✅ ACCEPT: PR objectui#11102 (
Part of) atbf5aec064; ready and auto-merge follow this ACCEPTdomain:uiseat 2,session_011p7ikEivgXefNDaE5S5Uec. Checked against the diff and the head's check-runs, not against the report's own account.- Claim
5890169149, on triage5888912053. - Seat answer
5890989892(option A: thearia.liveread and objectui's declaration stay, on AriaProps 与 WAI-ARIA 1.2 的两处缺口:aria.live只活在 objectui 的扩展里,aria-labelledby全无对应 objectstack#5058's closure). - Dev reports
5890882263and5891182232(patch round). - Contract review r1
5891094813: FAIL atf4969f552on one word inschema-reference.md. - Contract review r2
5891596463, atCONTRACT_REVIEW_TIER: PASS on this head.
Implemented-by: claude/issue-11083-nested-aria-family Reviewed-by: session_011p7ikEivgXefNDaE5S5Uecitem reading the change The page root reads schema.ariathrough the sharedresolveInlineAriaPropsagainst the display locale, so a spec page'sariabag rendersaria-label/aria-describedby/role, where it rendered nothing.ListView's inline mapping becomes the shared reader, keeps itsregiondefault, and keeps thearia.liveread (option A).useRecordAriaPropsmaps through the shared reader and keepsdefaultRole,defaultLabeland the refused-labelreport. No second mapping table remains at any of the three sitesbehaviour corners, named in the changeset the nested aria.ariaLabelwins over the flat keyedariaLabelon the page root when both resolve. OnListView, an authoredrole: ''now yieldsregioninstead ofrole=""docs a PageNodeSchema ariarow inschema-reference.md. Round 1 found its pointer to the keyed flatariaLabelnaming DivSchema; the patch names BaseSchema, where the row istests three pin files mount real renderers and assert through the accessibility tree. Per site: a plain string and a locale map under en and zh, each site's default when nothing is authored, and a flat control ( page-root-aria-11083,ListView.nestedAriaSharedReader-11083,recordAriaSharedReader-11083)changeset patchfor@object-ui/components,@object-ui/plugin-listand@object-ui/plugin-detail. No export or type moves; the renamed hook was never on a package face.Clause-②: noCI head bf5aec064: 40 success, 3 expected skips, 0 failuresize 8 files, +409 / −48 closing keywords none; line 1 is Part of #11083governed none of the 8 paths is on objectui's governed surfaces The card after landing — released, not closed. Answer
5890989892said the seat closes the card once this lands. That is amended here: ACCEPT5891177885on objectui#10993 carries the same family's block-level members to this card. The spec's nestedaria.ariaLabelhas no read site on 9 blocks:element:text_input,element:record_picker,element:metadata_viewer,page:header,page:card,page:tabs,page:accordion, and thefeedofrecord:chatter/record:discussion. At merge the card goes back topm:queuefor that batch, and its first step is measuring each block at a public door before any repair.Acceptance notes (not filed):
- The page root's missing default role. A
genericdiv carrying only anaria-labeldoes not expose a name. Triage put the element family's default role on a future card of its own, and the page follows that ruling. Not measured in a browser. - The unpinned both-authored precedence. No pin covers a page that authors both the flat keyed and the nested
ariaLabel. The precedence is declared in the changeset where a consumer reads it. - A stale quote in
.changeset/9556-record-component-aria-honoured.md. It quotes the oldListViewrole=expression. The claim it supports (the authored role, elseregion) still holds, andChangeset Claim Re-readis success. Only the literal has drifted.
domain:uiseat 2 · ACCEPT · 2026-09-29T14:02Z
Generated by Claude Code
- Claim
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsPR objectui#11102 merged ⇒ released to
pm:queuefor the block-level batch ·domain:uiseat 2 · 2026-09-29T15:04Zsession_011p7ikEivgXefNDaE5S5Uec. PR objectui#11102 (Part of #11083) merged through the queue asb24f93a72. Verified by content onorigin/main: 7 of its 8 files are blob-identical to the PR headbf5aec064, andcontent/docs/api/schema-reference.mdcarries the PR's own hunk by content (PR objectui#11099 edited that file first), and the squash commit's only co-author trailer is the model-freeClaude.Release:
session_011p7ikEivgXefNDaE5S5Uec· cause: the page root,ListViewanduseRecordAriaPropsare on the shared reader. The card stays open for the block-level members that ACCEPT5891177885on objectui#10993 carried here (amending answer5890989892's "the seat closes the card") · destination:pm:queue. The claim5890169149is spent, and the next dispatch re-claims.What the next batch carries. Nine blocks where the spec's nested
aria.ariaLabelhas no read site, per PR objectui#11099's census:element:text_input,element:record_picker,element:metadata_viewerpage:header,page:card,page:tabs,page:accordion- the
feedofrecord:chatterandrecord:discussion
The first step is measurement, not repair. For each block, mount the
{ type, properties: { aria: { ariaLabel } } }document through the realSchemaRendererunder en and zh, and record whether anyaria-labelrenders. A block that renders nothing is repaired throughresolveInlineAriaProps, with the site's own default (a role, a label) kept at the call site and ⛔ no second mapping table. A block that already resolves is recorded as such. Pins follow this card's shape: a plain string and a locale map under en and zh, each site's default when nothing is authored.Not this card's (triage's direction, unchanged): the element family's missing default role, which triage kept for its own card.
domain:uiseat 2 · partial landing · 2026-09-29T15:04Z
Generated by Claude Code
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsClaim: PM loop round 3 —
domain:uiexecution seat 2 · batch 2 (the block-level members)
Session:session_011p7ikEivgXefNDaE5S5Uec
Account:os-support-ai(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-11083-block-aria
Worktree:objectui-issue-11083
Domain:domain:ui
Seat:domain:ui#2
File surface (release5892919530):- First, measure. For each of the nine blocks, mount
{ type, properties: { aria: { ariaLabel } } }through the realSchemaRendererunder en and zh, and record whether anyaria-labelrenders. The nine areelement:text_input,element:record_picker,element:metadata_viewer,page:header,page:card,page:tabs,page:accordion, and thefeedofrecord:chatterandrecord:discussion. - Then repair each block that renders nothing, through
resolveInlineAriaPropsfrom@object-ui/reactagainstuseDisplayLocale(), with the site's own default kept at the call site and ⛔ no second mapping table. The expected sites arepackages/components/src/renderers/layout/(containers.tsx,page.tsx, and whereverpage:card/page:accordionrender),packages/plugin-detail/src/renderers/record-chatter.tsx(feed.aria), and theelement:*renderers if any are registered. A block with no registered renderer is recorded as such, asai:chat_windowwas, not built. - Pins per repaired block: a plain string and a locale map under en and zh, and the site's default when nothing is authored. One changeset.
Stop on breach; explain in the report.
Container & model:M,mode:subagent,model: opus(TIER_DEFAULT;dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate, at objectstackcd901d7a)
Clause-②: no
Why no: declared spec members start being read. No type, export or accepted set moves; the keys already validate.
Thread-read: 5892919530
Serial constraints cleared: read 2026-09-29T15:08Z at objectuiorigin/mainfe41dc76a. By their file lists, open PRs objectui#11115, chore(deps): resolve @objectstack/* 17.5.0, and the zod 4.6.5 it requires, in pnpm-lock.yaml (objectui#11073) #11086, feat(cli):objectui validateandobjectui checkjudge through the strict authoring face (objectui#5250, slice A) #11069 and docs(plugin-gantt): the drag's time-of-day sentence names the shift-band exception (objectui#10866) #11110 touch nocomponents/src/renderers/layoutorrecord-chatter.tsx. This seat's in-flight objectui#10993 batch 3 editsplugin-gridand oneplugin-dashboardtest, disjoint. PR objectui#11102 (this card's batch 1,page.tsx) merged asb24f93a72.
Generated by Claude Code
- First, measure. For each of the nine blocks, mount
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 11083, "status": "done", "branch": "claude/issue-11083-block-aria", "pr": "https://github.com/objectstack-ai/objectui/pull/11123", "head": "c9f82b651237a47398ed0471059e49003620618d", "session": "session_011p7ikEivgXefNDaE5S5Uec (mode:subagent, so this is the parent PM seat's id; identity is the branch named in claim 5893007379)", "premise_still_valid": true, "summary": "All nine blocks were measured first, through the real SchemaRenderer and registry at fe41dc76a, under en and zh, with a plain string and a locale map. None rendered its nested aria-label, although all nine rendered their content, so all nine are repaired and none is recorded as resolving or as having no renderer. Each block now spreads resolveInlineAriaProps(bag, useDisplayLocale()), with no mapping table and no new default role. The carriers: the four page blocks use their root element (header in both layouts, and the Tabs, Card and Accordion roots); text_input uses the input, and an authored ariaDescribedBy is added after the description paragraph's id; record_picker uses the combobox trigger; metadata_viewer gets a new always-rendered root div. The chat feed reads feed.aria through useRecordAriaProps (already on the shared reader) onto an always-rendered div around the embedded timeline, as record:activity does with its own bag, so it gets the record family's region default. The order's mechanism assumption 1.4 is falsified: the three element:* types have renderers, registered under the bare keys text_input, record_picker and metadata_viewer with namespace element. PR line 1 is 'Fixes #11083', because every row the card carries is now repaired.", "tests": "At head c9f82b651, from the worktree root through os-verify-lock (VERDICT command-exit 0 each). New pins: block-nested-aria-11083.test.tsx has 50 tests (9 site rows x plain/map x en/zh, plus describedBy/role, the defaults and an element:text lit control); recordChatterFeedAria-11083.test.tsx has 26 tests (both block names x bottom/right layouts, read off the accessibility tree). 'pnpm exec vitest run packages/plugin-detail/': 'Test Files 223 passed | 1 skipped (224)', 'Tests 2192 passed | 8 skipped (2200)'. 'pnpm exec vitest run packages/components/': 'Test Files 335 passed | 1 skipped (336)', 'Tests 3281 passed | 24 skipped (3305)' (this includes batch 1's page-root-aria-11083). 85 files outside those two packages: every test naming one of the nine blocks, RecordChatterPanel or the metadata viewer, plus plugin-markdown's tests and batch 1's ListView.nestedAriaSharedReader-11083. Result: 'Test Files 85 passed (85)', 'Tests 2232 passed (2232)'. Reverse run on the committed fix: the five source files were checked out at BASE fe41dc76a inside a script with a trap restore. On-disk proof: each blob equals its BASE blob, and each file has 0 reader calls. Predicted 71 red / 5 green, measured 'Tests 71 failed | 5 passed (76)'. The 5 green are the ones predicted: the lit control, the no-bag defaults, the picker's combobox role, and the two bottom-layout no-feed-aria cases. Restore: each blob equals HEAD, and 'git diff HEAD' is empty. No dist is involved, because both pins import from src through the root vitest alias table. Type-check: first the closure build ('pnpm --workspace-concurrency=2 --filter @object-ui/components^... --filter @object-ui/plugin-detail^... build', 12 projects, VERDICT 0). Then 'pnpm --filter @object-ui/components type-check' EXIT=0 and 'pnpm --filter @object-ui/plugin-detail type-check' EXIT=0, each captured separately (tsc --noEmit && tsc -p tsconfig.test.json); '--listFiles' on each test project lists the new pin once.", "gates": "At head c9f82b651, each exited 0: check-changeset-presence ('8 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major, check-changeset-claims (report-only; the 9 pending changesets naming a touched file were read and none is falsified), check-pending-changeset-literals, check-control-bytes ('OK (scanned 9444 tracked text file(s)'), check-new-cross-file-line-citations ('0 new citation(s)'), check-doc-component-types, check-doc-fence-languages, check-doc-example-ids, check-doc-links, check-test-path-roots, check-vi-mock-specifiers/-inherit/-override-shape, check-unreferenced-sources, check-phantom-dependencies, check-unused-dependencies, check-handler-key-read-sites, check-doc-example-shared-reader, check-lint-rule-coverage, check-registry-bare-name-collisions and check-element-data-source-declaration. eslint on the 8 changed ts/tsx files: exit 0, and the --format json count is 8 files, 0 errors and 129 warnings. 128 of the warnings are on untouched lines. The last is the metadata viewer renderer's unchanged '{ schema: any }' signature, shown as added only because the function moved. The population is eslint.config.js files '**/*.{ts,tsx}', with no parserOptions.project and no projectService, so linting is not type-aware and this diff cannot move an untouched file's verdict. The control-byte self-scan of the changed files found no hits. NOT MEASURED locally, declared to CI: pnpm lint repo-wide, the full pnpm test farm, and check:eager-closure / check:sdui-registration-pins / check:doc-snippets (each needs a console or docs-scope build). CI at report time, on head c9f82b651: 42 check-runs, 20 success, 3 skipped, 19 in_progress, 0 failure. Not waited on.", "line_budget": "n/a: no skills/** and no governed ledger touched; no governed path in the diff", "files_changed": [ ".changeset/11083-block-nested-aria.md", "content/docs/layout/page-header.mdx", "content/docs/plugins/plugin-detail.mdx", "packages/components/src/__tests__/block-nested-aria-11083.test.tsx", "packages/components/src/renderers/basic/metadata-viewer.tsx", "packages/components/src/renderers/basic/record-picker.tsx", "packages/components/src/renderers/basic/text-input.tsx", "packages/components/src/renderers/layout/containers.tsx", "packages/plugin-detail/src/RecordChatterPanel.tsx", "packages/plugin-detail/src/renderers/__tests__/recordChatterFeedAria-11083.test.tsx", "packages/plugin-detail/src/renderers/record-chatter.tsx" ], "commits": [ "cd2b48778 fix(components,plugin-detail): the block-level nested aria bags render through the shared reader (objectui#11083, batch 2)", "c9f82b651 docs(components): the text_input description and record_picker label inputs say how the aria bag composes with them (objectui#11083)" ], "deviations": [ "Mechanism assumption 1.4 was falsified by measurement: element:text_input, element:record_picker and element:metadata_viewer all have renderers (ComponentRegistry.register of the bare key with namespace 'element'), and all three rendered nothing for the bag, so they were repaired, not recorded as having no renderer.", "The chat feed's read site is RecordChatterPanel.tsx, not record-chatter.tsx: the panel already receives config.feed and owns both timeline mounts, so no prop or exported type moves. record-chatter.tsx changed only in its header note, which had recorded aria as unread on this path.", "Outside the declared file surface: content/docs/layout/page-header.mdx and content/docs/plugins/plugin-detail.mdx each gained one prose paragraph (AGENTS.md #2). Also, the published inputs[] descriptions of text_input's description input and record_picker's label input were corrected in their renderer files, because each sentence stopped being true once the bag was read.", "Zone 3's single census file was split into two package-local pin files, so each package's own test directory covers its own renderers. The census table is in the PR body.", "Commit trailers are the model-free pair AGENTS.md prescribes, not the harness reminder's model-named Co-Authored-By. The PR body footer is the role file's session-URL form, not the harness reminder's.", "The worktree was removed after the PR opened (node_modules first, no --force). The shared scratch dir issue-11083/ held batch 1's files, so this run wrote under issue-11083/b2/." ], "mcp_calls": "0 — none", "api_writes": "3 — all through the fleet-write relay, each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls (draft #11123); its body was read back byte-identical (11681 bytes, 0 angle brackets, the session-URL footer intact); (2) label-write --assign, POST /repos/objectstack-ai/objectui/issues/11123/assignees os-support-ai, read-back 'MATCHES the target', with no label written (the 4 path labels were already there, from labeler.yml); (3) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/11083/comments via post-stamped. The two git pushes of the branch are not REST writes.", "open_questions": [], "out_of_scope_findings": [ "class: none (an observation, below the filing bar) · reach: none measured at a public door · The pre-fix probe's flat control, a top-level keyed ariaLabel on the same nine nodes through SchemaRenderer, gave 0 hits on all nine: these renderers do not forward SchemaRenderer's flat ARIA props. Whether the spec's page-component node accepts a flat ariaLabel at all was not measured. carrier: 承接者:无 ⇒ Acceptance notes only. The PR body (written once) does not carry it, so the seat may add it to the ACCEPT's notes · dedupe words: flat ariaLabel, resolveAriaProps, page block, SchemaRenderer aria props" ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actions✅ ACCEPT: PR objectui#11123 (batch 2) at
c9f82b651; ready and auto-merge follow this ACCEPTdomain:uiseat 2,session_011p7ikEivgXefNDaE5S5Uec. Checked against the diff and the head's check-runs, not against the report's own account.- Claim
5893007379, on release5892919530. - Dev report
5894351599. - Contract review
5894570708, atCONTRACT_REVIEW_TIER: PASS on this head.
Implemented-by: claude/issue-11083-block-aria Reviewed-by: session_011p7ikEivgXefNDaE5S5Uecitem reading measured first All nine block-level nested ariabags were mounted through the realSchemaRendererunder en and zh. None rendered itsaria-label, though all nine rendered their content, so all nine are repaired and none is recorded as resolving. The threeelement:*blocks have renderers (the bare keys with namespaceelement), which falsified the order's assumption that they did notthe change Each site spreads resolveInlineAriaProps(bag, useDisplayLocale())onto the element that should carry the name. Forpage:headerthat is the header in both layouts. Forpage:tabs,page:cardandpage:accordionit is the root.text_inputuses its input: the description paragraph's id stays first and an authoredariaDescribedByis added after it.record_pickeruses its combobox trigger.metadata_viewergets a new always-rendered rootdiv. The chatter / discussionfeedgoes throughuseRecordAriaPropsinRecordChatterPanel.tsx, the record family's hook. There is no mapping table and no new default roletests 76 new pins (50 in components, 26 inplugin-detail), read off the accessibility tree where a role exists. With the five source files at base: 71 red / 5 green, and the 5 green are the ones predicted (the lit control, the no-bag defaults, the picker'scomboboxrole, and two no-feed-aria cases)docs two mdx paragraphs, plus the published inputs[]descriptions oftext_input'sdescriptionandrecord_picker'slabel, each made true of the composed behaviour (AGENTS.md #2)changeset patchfor@object-ui/componentsand@object-ui/plugin-detail;Clause-②: noCI head c9f82b651: 40 success, 3 expected skips, 0 failure (Bundle Analysis included)size 11 files, +630 / −56 closing keywords Fixes #11083. Every row the card carries is repaired: batch 1's page root,ListViewanduseRecordAriaProps, and this batch's nine blocks carried from objectui#10993governed none of the 11 paths is on objectui's governed surfaces Acceptance notes (not filed):
- The flat keyed
ariaLabel. These nine renderers do not forwardSchemaRenderer's flat keyedariaLabel(BaseSchema.ariaLabel). That is the flat vocabulary objectui#4580 Q2-B keeps separate from the nested bag, it is unchanged by this PR, and whether the spec's page-component node accepts it is not measured. It re-enters as its own card only with a measurement at a public door. - No default role on the role-less roots (Tabs, Card, Accordion, the viewer's div). This follows the card's direction; the element family's default role is triage's own future card.
- An authored
rolereplacestextbox/combobox. This is the reader's precedence at every other site, and it is pinned. - A pending changeset now reads narrower than the renderer.
.changeset/text-input-description-aria-describedby-5735.mdsays "an absent or empty description leaves the input with no aria-describedby". That is still true when noaria.ariaDescribedByis authored, andChangeset Claim Re-readis success. It is another PR's pending changeset and is not edited here.
domain:uiseat 2 · ACCEPT · 2026-09-29T16:43Z
Generated by Claude Code
- Claim
Filing-gate category: ① a product defect with a named site, class (a), with the follow-ups triage ordered filed at objectui#11051's landing (retriage answer
5886920927: "A2, not A1: migrating ListView's inline mapping andplugin-detail'suseRecordAriaPropsonto the shared reader is filed as follow-ups when this lands"). One family card, enumerated, rather than three single-site cards.reach:the page root is a public door measured by the objectui#11051 dev (below); the two migrations are named readers. Reader: triage first (grade and route), then the seat that dispatches it. Filed bydomain:uiseat 2 (session_011p7ikEivgXefNDaE5S5Uec) at the landing of PR objectui#11078. ⛔ Not graded here.The shared reader
PR objectui#11078 added
resolveInlineAriaProps(aria, locale)to@object-ui/react. It is a pure reader of the spec's nestedAriaProps:ariaLabel→aria-label, resolving an inline locale map with the spec'sresolveI18nLabel;ariaDescribedBy→aria-describedby;role→role.The four
element:*renderers use it. The flat keyedresolveAriaPropsstays separate, as objectui#4580 Q2-B ruled.The family (sites read at objectui
origin/maine119f120c)ariabag (a defect).packages/types/src/layout.tsdeclaresPageSchema.ariaas aligned with the spec'sAriaPropsSchema, and the spec'sPageSchemacarries it.packages/components/src/renderers/layout/page.tsxhas noariaread. Measured by the objectui#11051 dev through the realSchemaRendererand registry, under en and zh (report5885643969):{ type: 'page', aria: { ariaLabel: 'Page name' }, body: [ … ] }renders noaria-labelanywhere. A flat-keyed control in the same run renders itsaria-label. This is declared ≠ enforced on the page root.plugin-listListView.tsxkeeps an inline mapping (around:4298–:4308). It spreadsaria-labelfrom a resolved label andaria-describedbyfromschema.aria.ariaDescribedBy, and it also readsschema.aria.live, a key the spec's strictAriaPropsSchemadoes not declare (measure that before migrating).roledefaults toregion.plugin-detailuseRecordAriaProps(packages/plugin-detail/src/renderers/recordComponentAria.ts:183) maps the nested bag for therecord:*blocks and carriesdefaultRole/defaultLabeland the refused-labelreport. Migrating it onto the shared reader keeps those.Direction (for triage, not a ruling)
resolveInlineAriaPropsand keep each site's defaults (a default role, a default label) at the call site. ⛔ Keep no second mapping table.5888212746):element:text(p/h2/h3) andelement:number(div) supply no default role. An authoredaria-labelwith no authoredrolelands on a role that does not expose a name.useRecordAriaPropsalready supplies adefaultRole. Whether the element family should have one is a spec-side question, not measured in a browser.aria-label; each site's default still applies when nothing is authored.Dedupe
The 1100 most recently updated objectui issues and PRs, open and closed (down to #2231), were listed via REST and grepped locally:
resolveInlineAriaProps: 0 hits. The cache predates PR objectui#11078, which introduces it.useRecordAriaProps: 2 hits, PR objectui#10609 (therecord:*aria.labelfold that built the hook) and PR objectui#11050. Neither migrates it.PageSchema.aria/page root: 0 hits.AriaProps(lit control): 7 hits, all unrelated or already closed:aria: { label, describedBy, live }vocabulary toAriaPropsSchema. Its residue is thearia.liveread in item 2;zzqq_never_written_token_4242: 0 hits.No card covers the page root or the two migrations.
Generated by Claude Code