Skip to content

fix(components,plugin-list,plugin-detail): the page root reads its nested aria bag, and ListView and useRecordAriaProps map through the shared reader (objectui#11083) - #11102

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-11083-nested-aria-family
Sep 29, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-11083-nested-aria-family

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #11083
Clause-②: no

The page root now renders the aria bag the spec declares on it, and the two blocks that kept their own mapping of that bag (ListView's list region, plugin-detail's useRecordAriaProps) now go through resolveInlineAriaProps, the shared reader PR objectui#11078 added to @object-ui/react. There is no second mapping table.

Why Part of and not the order's Fixes. One sub-item needs a decision and is reported on the card, not done here: whether ListView stops reading aria.live. The measurements are in the section on it below. This PR keeps that read exactly as it was. The card's other items are all in this PR.

What changed

  1. Page root (the defect). PageRenderer gives its wrapper toDomProps(props), which keeps only DOM attributes, so the aria object was dropped and { type: 'page', aria: { ariaLabel: 'Page name' } } rendered no aria-label anywhere. The wrapper (the element carrying data-page-type) now also spreads resolveInlineAriaProps(schema.aria, useDisplayLocale()). It is spread after pageProps, so when a flat key and the nested bag name the same attribute, the page's own declared slot wins. The page adds no default role, and a page with no aria renders the same DOM as before.
  2. ListView (consolidation). The inline mapping (label, described-by, role) is replaced by const regionAria = resolveInlineAriaProps(schema.aria, displayLocale), spread on the region, plus role={regionAria.role ?? 'region'} as ListView's default. Measured: the label had no non-aria fallback. It came only from schema.aria.ariaLabel, so there was nothing else to keep. One visible difference: an authored role: '' used to render an empty role attribute, and now falls back to region (pinned). The aria.live read is kept unchanged (see below).
  3. useRecordAriaProps (consolidation). Built on the shared reader and the display locale. It keeps its signature, the caller's defaultRole and defaultLabel, the region fallback, and the refused-aria.label report. The report stays in an effect keyed on the message. The internal useRecordAriaName (one caller, never exported from the package) became a report-only hook, so this module no longer resolves the label itself.
  4. Docs. content/docs/api/schema-reference.md, the PageSchema table, gains an aria row (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2). This file is outside the claim's declared surface, and the report says so.

aria.live: measured, the read is kept, and a decision is needed

Triage direction 2: "Measure whether any document authors it first. None ⇒ the read goes (objectui#2890's residue). Some ⇒ stop and report it on this card."

Census. The pattern is the value form live followed by polite, assertive or off (any quoting), which also catches a multi-line bag.

  • objectui at base 3e71a9825: 5 hits in 4 files, all test fixtures: normalize-list-view.test.ts, ListView.test.tsx, inlineAria.test.ts and p1-spec-alignment.test.ts.
  • objectstack at origin/main cd901d7a: 2 hits, both in packages/spec/src/ui/i18n.test.ts.
  • There are 0 in examples, apps, seeds or docs.
  • The lit control is the value form of ariaDescribedBy over the same trees: 18 lines in objectui and 6 in objectstack.

So no document authors it. But the premise that it is "residue" does not hold, because live is a declared key with a named producer of guidance:

  • objectui declares it. The zod mirror's ListViewSchema.aria is stripImportedDefaults(SpecAriaPropsSchema).extend({ live }), described as "objectui-only — promote rather than grow this extension". The NamedListView.aria interface also carries live. objectui#2890's changeset kept it on purpose: "aria.live stays as a documented local extension — it has no spec counterpart, and dropping it would silently disable a shipped capability."
  • The published spec, @objectstack/spec 17.4.0 as installed here, refuses live on every other surface with this guidance: "On an objectui list view the key is valid as-is; anywhere else, drop it." The spec pins that text in i18n.test.ts, together with a reconstruction of objectui's .extend({ live }) that accepts it.
  • objectstack#5058, the promotion question, was closed not_planned on 2026-09-24 on the maintainer's word. Its rationale names "objectui's own extension carries the rendering".

Dropping only the read would leave live accepted by objectui's own schema and recommended by the spec's refusal text, then silently dropped at render. That is declared ≠ enforced, the trap this card exists to remove. Retiring it properly also moves a type (@object-ui/types, so Clause-② becomes yes) and changes the spec's published guidance text in the other repo. So this PR stops on that half and reports it on the card, with options.

Tests

The runs are from the worktree root with root-relative paths. They were measured at 904eed298. git diff --stat 904eed298 f4969f552 -- packages/ is empty, so the packages/ tree is byte-identical to head f4969f552 (the later commits add the changeset and the docs row).

  • New pins:
    • page-root-aria-11083.test.tsx: real SchemaRenderer and registry, under I18nProvider. A plain string under en and zh, a locale map under en and zh, described-by and role, no bag adds nothing, and a flat-ariaLabel control. 7 tests.
    • ListView.nestedAriaSharedReader-11083.test.tsx: described-by, an authored role, the region default, an empty role falling back to region, a zh locale map, and live kept. 6 tests.
    • recordAriaSharedReader-11083.test.tsx: a plain string and a locale map under zh, a locale map under en, and record:path's default role carrying a zh name. 4 tests.
  • Targeted run, new pins plus the existing aria pins (ListView.ariaLabelInlineLocale, recordComponentAria-9556, recordAriaLabelRetired-9945, record-quick-actions.ariaLabel): Test Files 7 passed (7), Tests 82 passed (82).
  • Wider run: packages/components/src/renderers/layout/, every page-* / react-page-* / html-page-lazy-blocks / guide-layout-page-buttons / page*ItemMembers test in packages/components/src/__tests__/, ListView.test.tsx, i18nLabel-resolver-parity.test.ts, and all of packages/plugin-detail/src/renderers/. Result: Test Files 107 passed (107), Tests 1247 passed (1247).
  • Type-check, after building the dependency closure (--filter with the ^... suffix on the three packages, 13 packages): pnpm --filter @object-ui/components type-check, @object-ui/plugin-list and @object-ui/plugin-detail. Each exited 0, and each ran tsc --noEmit && tsc -p tsconfig.test.json. Each package's tsconfig.test.json includes src/**/*.test.tsx, so the new pins are type-checked.
  • Ablation (page root). This used ablation-replace.mjs in wrap mode on the committed fix. It deleted the {...pageAria} spread (anchor 1 → 0, blob f5185737dbf2 → b05ab1b57c9e) and ran the page pin. The predicted direction was 5 red and 2 green (the no-bag case and the flat control). Measured: Tests 5 failed | 2 passed (7), exactly those five. After the restore, the blob equals HEAD and git diff HEAD is empty. The same file on the restored tree: 7 passed.

Gates

  • eslint on the 6 changed .ts/.tsx files: exit 0, and the JSON output lists 6 files with 0 errors. The warnings are all on lines this diff does not touch. The linted population comes from eslint's own config (files: ['**/*.{ts,tsx}']). The config has no parserOptions.project and no projectService, so linting is not type-aware and this diff cannot move the verdict on an untouched file. pnpm lint over the whole repo belongs to CI.
  • Exit 0 on the tree at head f4969f552:
    • check-changeset-presence, check-control-bytes, check-new-cross-file-line-citations;
    • 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, check-doc-example-ids.
  • Self-scan for control bytes over the changed files: no hits.

Acceptance notes

These are out of scope and noted only, not filed.

  • The page root has no default role. An authored aria.ariaLabel with no aria.role lands on the wrapper div, which is generic, and browsers expose no name on it. This is the same question triage kept off this card for element:text / element:number (its own card, once there is an assistive-technology measurement). The page follows that ruling and adds no default. Carrier: that future card. No other carrier.
  • A pending changeset quotes the old ListView source. .changeset/9556-record-component-aria-honoured.md quotes ListView's old role= expression for the region's precedence. The precedence (the authored role, else region) still holds, but the quoted expression is no longer literal source. This PR does not edit another PR's pending changeset. Carrier: none.

Generated by Claude Code

…sted aria bag, and ListView and useRecordAriaProps map through the shared reader

The page renderer hands its wrapper toDomProps, which drops the `aria`
object, so a page's declared accessible name reached no element. The
wrapper now spreads resolveInlineAriaProps(schema.aria, locale).

ListView's list region and useRecordAriaProps map the three declared
keys through the same reader and keep only their own defaults (the
region role; defaultRole, defaultLabel and the refused-label report).
ListView keeps its aria.live read, the ListViewSchema extension.

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…seRecordAriaProps on the shared reader

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation package: components plugin tests labels Sep 29, 2026
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 25 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/3917-retire-action-condition-branch.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    • ActionCondition is removed from @object-ui/types (and from the barrel export). - ActionSchema.condition is retyped to the predicate the runtime actually honours: boolean | string | { dialect?: string; source: string } — the same three arms ActionRunner's own ActionDef.condition carries, and the same vocabulary visible and disabled use. - ActionConditionSchema is removed from @object-ui/types/zod (and from the zod barrel); the condition key now validates against that predicate union. - The two teaching sites (content/docs/core/enhanced-actions.mdx Conditional Execution, content/docs/api/schema-reference.md ActionSchema table) are rewritten to the live vocabulary: condition is a gate; a branch is expressed as separate actions with mutually exclusive conditions.

.changeset/6170-retire-timeline-dead-keys.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Also in this change: the in-repo example packages/types/examples/data-display-examples.json (its timeline node authored all three) is migrated to items / variant; the two content/docs/api/schema-reference.md snippets that authored events: [] now author items: []; and the plugin-timeline docs callout says retired rather than deprecated.

.changeset/6896-retire-chart-inline-data.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ One correction to the record the ruling rests on. The ruling states zero authorship of a populated series[].data outside tests across packages/ / apps/ / examples/. The re-measurement finds one such site inside those roots — packages/types/examples/data-display-examples.json (2 series) — plus four outside them, in documentation: content/docs/api/schema-reference.md (3) and content/docs/core/report-schema.mdx (1).

.changeset/6939-kanban-column-cards.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Breaking, deliberately. KanbanColumn declared its card list as items in complex.ts and in the zod mirror complex.zod.ts. Every board reads cards. Measured on origin/main 78a3cc238: KanbanImpl.tsx reads .cards on 12 lines, KanbanEnhanced.tsx on 8, and bucketCardsIntoColumns twice more as col.cards || []; .items had zero read sites in either board (a same-shaped .title control on the same two files returns 8 and 3, so those zeros are readings and not a mis-shaped probe). Both catalog entries, the plugin docs and content/docs/api/schema-reference.md all author cards.

.changeset/6951-tree-view-data-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was measured, on this branch's base. TreeViewSchema declared two spellings for its one inline-nodes slot — nodes (read second) and data (read third: boundData || schema.nodes || schema.data || [] at renderers/data-display/tree-view.tsx:105), both declared by objectui#6150. data had been REQUIRED until 777e5c6f4 (PR fix(types): tree-view mirror stops requiring the limb it reads third (group 2 of objectui#6939) #7533) made it optional, so this retirement starts from a declared-and-optional member on both faces. The in-repo corpus at the retirement: seven tree-view nodes under examples/schema-catalog and packages/types/examples plus one content/docs fence — six on nodes, two on data (packages/types/examples/data-display-examples.json and content/docs/api/schema-reference.md), both rewritten; no package source authored either spelling.

.changeset/7070-no-invented-gantt-date-fields.md

  • names plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    • app-shell/src/views/ObjectView.tsx — the console object page. The inline branch becomes ganttViewOptions, the sibling of calendarViewOptions and timelineViewOptions: the declared block spread whole, title floored at 'name', no date field invented. - plugin-list/src/ListView.tsx — the render branch AND the capability gate. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

.changeset/7499-gantt-non-axis-floors-omitted.md

  • names plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    • plugin-list/src/ListView.tsx — the object-gantt render branch. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

.changeset/7664-kanban-arm-plugin-dialect.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Migration. Author boards in the plugin dialect — objectName + groupBy for an object-bound board, or columns[].cards[] with badges for a static one. Replace DeclarativeKanbanSchema imports with KanbanSchema (from @object-ui/types, or the Zod KanbanSchema from @object-ui/types/zod; @object-ui/plugin-kanban re-exports the same KanbanSchema type). Delete draggable (drag-and-drop is always on) and column color (style a lane through className). content/docs/api/schema-reference.md's kanban section now documents this dialect.

.changeset/7773-kanban-adapter-groupfield-write.md

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    Who is NOT affected — the boundary is node-local. Every VIEW-LEVEL groupField read is untouched and still live: it is a legacy alias of the spec's groupByField on the kanban view config, mapped by normalize-list-view.ts, and both adapters still resolve lanes through it (ObjectView.tsx's kanbanCfg.groupField ||, ListView.tsx's groupByField || groupField). Authoring options.kanban.groupField on a list-view or object-view keeps working exactly as documented in packages/plugin-list/README.md. groupField is dead only on the generated object-kanban NODE.

.changeset/7780-object-kanban-record-source.md

.changeset/7926-page-node-refuses-actions.md

  • names packages/components/src/renderers/layout/page.tsx → packages/components/src/renderers/layout/page.tsx — edited by this change

    Accept-set change, deliberately. A page document carrying actions used to parse GREEN and render nothing. PageNodeSchema never declared the key and PageRenderer never read it — git grep -ni action on packages/components/src/renderers/layout/page.tsx returns only the PageVariableActionBridge import and its render — so the array survived purely through BaseSchema's .passthrough(). Measured through the real SchemaRenderer: a page node with actions: [{type:'button',label:'Add Product'}, …] drew 0 buttons and the label appeared nowhere in the DOM, while the SAME two buttons in the page's child list drew 2. Until objectui#7933 the array also reached the wrapper element as actions="[object Object],[object Object]".

.changeset/7997-detail-view-related-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Documentation. packages/plugin-detail/README.md and content/docs/api/schema-reference.md stop teaching the retired array and gain a migration block each.

.changeset/8268-testid-emitted-as-data-testid.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    The other direction — retiring the promise — was considered and declined. It is what c1fe272ad did for BaseSchema.hidden, but that key had a working behaviour to describe and zero named consumers, and the ruling's decline turned on exactly that. This promise already has carriers outside the type declaration: content/docs/api/schema-reference.md states it as a table row and authors testId in that page's own base-schema example, @object-ui/cli's OBJECTUI_STRUCTURAL_KEYS identifies a file as an ObjectUI schema node by this key, at this change ObjectGridSlotKey / ObjectFormSlotKey pin it, SchemaBuilder.testId() writes it, and ADR-0054 C4 — shipped — reads "the renderer emits data-testid … derived from metadata".

.changeset/8653-listview-title-retired-rowactiondefs-pinned.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    title — retired. ListView resolved its export filename through schema.label || (schema as any).title. @objectstack/spec/ui's ListViewSchema refuses title by name (unrecognized_keys: ['title']) while ObjectGridPropsSchema accepts it; packages/types mirrors the platform contract rather than ruling over it, so declaring title on ListViewSchema would have made this repo accept what the platform save gate rejects. That asymmetry is also why objectui#6639 could take the declare branch for ObjectGridSchema.title one package over and this site could not. A parse-based census of apps/ examples/ content/ and packages/ found zero list-view nodes authoring title, so the retirement costs no author a filename. Over that same corpus the instrument reports three object-grid nodes carrying the key: two authored ones, both in content/docs/api/schema-reference.md, plus one that is not authored at all — packages/plugin-view/src/ObjectView.tsx composes title: schema.table?.title onto a grid node it builds, so it is a producer writing the key rather than an author declaring it. ObjectGrid's own title reads are untouched — they remain declared, ruled and read.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8990-object-kanban-groupby-optional.md

  • names packages/plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    • packages/plugin-list/src/ListView.tsx generates the node as groupBy: laneField. objectDef loads asynchronously, so laneField is undefined on every load until it lands, and stays undefined whenever the object offers no stageField hint and none of status / stage / state / phase. The renderer serves that node; both published faces refused it. - content/docs/utilities/data-objectstack.mdx documents an object-kanban node that is exactly { type, dataSource }, with no groupBy. ⚠️ This one is weaker and is cited for what it is: that fragment is still refused after this change, at RECORD_SOURCE_REQUIRED, because dataSource is not a rung of the record-source ladder. It shows a lane-less board is a documented authoring; it is not a document this change admits.

.changeset/9187-record-highlights-layout-two-values.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ The census behind this narrowing covers this repository only, and it found no in-repo authoring to migrate: every in-tree layout: 'grid' belongs to a different component (detail-view in content/docs/api/schema-reference.md and phase2-schemas.test.ts, ai-recommendations in packages/plugin-ai/README.md), and the one in-repo consumer of this interface that writes a layout (p1-spec-alignment.test.ts) writes 'horizontal'. So no document in this repository stops type-checking. A TypeScript consumer outside this repo that wrote grid is not observable from here and gets a compile error (TS2322) naming the key — which is why the FROM/TO is spelled out above.

.changeset/9556-record-component-aria-honoured.md

  • names renderers/recordComponentAria.ts → packages/plugin-detail/src/renderers/recordComponentAria.ts — edited by this change

    • @object-ui/types — RecordComponentAriaProps.ariaLabel is now string | I18nLabel. AriaPropsSchema.ariaLabel is z.union([z.string(), InlineLocaleMapSchema]), so the bare string was a narrowing: a map-valued name like { en: 'Deal stages', 'zh-CN': '阶段' } parsed at publish and tsc refused it here. This is a fourth site of objectui#9092's Group A, missed there because it is reached through a shared interface rather than restated inline. For a .d.ts consumer: writing aria.ariaLabel gains the map arm and no existing write breaks; a consumer that reads the member into a string position now sees string | I18nLabel | undefined and is named by the compiler — which is the audit the widening exists to produce, and is why this is minor rather than patch. Every in-repo reader of the six interfaces lives in @object-ui/plugin-detail, and both packages type-check clean. - @object-ui/plugin-detail — no new published symbol. The shared read point (renderers/recordComponentAria.ts) is internal; it is not added to the package barrel, so dist/index.d.ts gains nothing. What changes is behaviour. record:quick_actions' own props interface keeps its aria member and is retyped from an inline { ariaLabel?, label? } to the family's bag, which widens ariaLabel there the same way.

.changeset/calendar-view-schema-converge.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Runtime renderer behaviour is unchanged. @object-ui/plugin-calendar's README and content/docs/api/schema-reference.md are repaired to the converged surface in the same change, so no copy of the old contradiction survives.

.changeset/issue-5373-retire-crud-schema.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    crud had four declaration faces and no registered renderer, for the whole life of the key: the TS interface (packages/types/src/crud.ts), the zod mirror (packages/types/src/zod/crud.zod.ts), a dedicated branch in validateSchema that affirmatively PASSED it, and CRUDBuilder in @object-ui/core. A node spelling it painted the OBJUI-001 "Unknown component type" panel, and content/docs/api/schema-reference.md published it as reference material — so a reader (or an AI author) who copied the page got a red panel.

  • names api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Authoring crud is now REFUSED BY NAME rather than passed or silently ignored. validateSchema returns an error with code: 'RETIRED_TYPE' on schema.type — at any depth, since it is what validateChildren recurses with — so assertValidSchema throws and isValidSchema answers false. The message names the migration: object-grid for the record table with its toolbar, filters, pagination and row/batch actions, object-form for the create/edit form, and detail for the record view. api/schema-reference.md is rewritten around those shapes.

.changeset/list-user-actions-collision-5398.md

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    The harvest now reads the object block only. Both userActions read sites in ListView.tsx carry a comment naming the collision, and __tests__/ListView.userActionsCollision.test.tsx pins each clause of it: the two shapes, a producer that manufactures the view one, the harvest's blindness to it, and the projection that must keep the object's operand with a toolbar block — or an empty block — present on the view.

.changeset/listview-comment-pair-4559.md

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    Two comment corrections in ListView.tsx (objectui#4559, objectui#4966). No runtime behaviour changes and the emitted bundle is byte-identical; the published .d.ts does change, which is why this is a patch rather than an empty frontmatter.

.changeset/object-view-unmirrored-keys-7779.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    listViews stays unmirrored, on the ruling's own fallback clause. The declaration's value is the local NamedListView — 64 declared top-level members (⚠️ re-taken at objectui#8980, which added the seventeen the protocol declares on this surface to the 47 this entry first measured), of which the renderer reads 21 off a named view. data is one of the 21 now: it used to reach the renderer through an as any cast on the named-view config in packages/plugin-view/src/ObjectView.tsx and be declared nowhere, and the objectui#8980 ruling declared it by name — objectui#7928's open half, answered. The spec's ViewSchema.listViews is a record of the STRICT ObjectListViewSchema, which requires columns and refuses options, ObjectQL tuple filters and default — that is, it refused the named views this package's own README and content/docs/api/schema-reference.md taught when this entry was written ({ label: 'All Users' } fails at columns; filter: [["owner", "=", "..."]] fails at filter.0), and objectui#8255 has since rewritten them in the spec shape. Mirroring the spec value would have lost documented behaviour; mirroring the local value would enforce 43 unread members (64 declared, minus the 21 that are both declared and read) into the contract — the very thing ruling B refused for the six local keys. The key therefore stays in the parity ledger with that measurement, pinned, until the maintainer decides its value type. It is not papered over with z.any().

.changeset/page-source-tailwind-prose-retraction-5469.md

  • names src/renderers/layout/page.tsx → packages/components/src/renderers/layout/page.tsx — edited by this change

    • @object-ui/react-runtime: README.md is published to npm (npm includes README.md in the tarball regardless of files). Its "no sandbox" callout is the paragraph that routes untrusted-author work to the html tier, and it carried the retracted framing line-wrapped across :17-18. It also gains the §Styling section it was missing — the absence is why the framing survived here. - @object-ui/sdui-parser: the corrected header of src/types.ts projects verbatim into the published dist/types.d.ts. - @object-ui/components: the corrected header of src/renderers/basic/html-elements.tsx projects verbatim into the published dist/renderers/basic/html-elements.d.ts. The kind === 'html' dispatch-arm comment in src/renderers/layout/page.tsx does not project (it is inside a function body) and is included here only because the same package already owes an entry.

.changeset/table-renderer-declared-column-contract-5350.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What makes this site different from its three siblings is that the alias was not merely tolerated, it was published. content/docs/api/schema-reference.md §TableSchema shipped a copyable { "name": "id", "label": "#" } example and a property row reading "Column definitions with name, label, …", while packages/types declared the opposite pair. Docs and type disagreed about one type they both call TableColumn, each internally consistent. Retiring the alias without correcting the page would have turned a documented, working example into a silently broken one, so both halves land together: the page now authors accessorKey/header. The same row also advertised a render property that TableColumn has never declared — the renderer's hook is cell — and that claim is dropped rather than re-spelled.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with 5b2ea1757 (merge-base with origin/main): 7 file(s) changed outside .changeset/, read against 1750 pending declaration(s) that publish a body (2354 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3108.8 KB 3149.4 KB
Main entry chunk (gzip) 149.3 KB 350 KB
Entry file index-lDUY2KbV.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.84KB 133.94KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.11KB 66.33KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.68KB 36.71KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.59KB 61.84KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 169.69KB 43.37KB
plugin-gantt (index.js) 171.88KB 42.61KB
plugin-grid (index.js) 228.51KB 62.64KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.82KB 28.67KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 90.43KB 22.76KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 8.61KB 3.45KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.17KB 2.73KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 22.61KB 7.40KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f4969f5521c48a440d98a48e7c00f89c435bbd30
Local-runs: none

Inputs: card #11083 (body; comments 5888912053 triage, 5890169149 claim, 5890882263 os-dev-report, 5890989892 the seat's answer), PR #11102 (body, the 8-file list, the net diff against main at the head), the head's check-runs (filter=latest), and context reads at the base 88fbd793d or the head of packages/react/src/utils/inlineAria.ts, packages/plugin-detail/src/index.tsx, packages/plugin-detail/package.json, packages/components/package.json, packages/types/src/layout.ts, packages/types/src/objectql.ts, packages/types/src/zod/objectql.zod.ts, content/docs/api/schema-reference.md, .changeset/9556-record-component-aria-honoured.md and the three touched modules in full. Binding direction: triage 5888912053 as answered by the seat on the dev's open question (5890989892) — option A, the aria.live read and objectui's declaration of it stay, on the maintainer's closure of objectstack-ai/objectstack#5058.

Check-runs on the head: 43 latest runs, all completed by 2026-09-29T13:16Z — 40 success, 3 skipped (dependabot and the two coverage jobs, which do not run on a PR head), 0 failed. Among the successes: Test shards 1 to 8, Test (dist pins), Type Check, Lint, Spec Main Shape Gate, Build and E2E, Build Docs, Pre-Install Import Graph Check, the four changeset gates, Line Citation Gate, Control Byte Scan, Doc Component Type Check, Doc Example Id Check, Doc Fence Language Check, Internal Docs Link Check and Doc Snippet Type Check. Those conclusions are the gate verdicts; nothing was run locally.

① Derived judgments

  1. The page root reads schema.aria through the shared reader — right. page.tsx:582-583 calls useDisplayLocale() and then resolveInlineAriaProps(schema.aria, locale), unconditionally, after toDomProps(props) and before the first useMemo; no early return precedes it (:529-583), so the hook order is stable. The result is spread on the wrapper carrying data-page-type (:680). PageNodeSchema.aria is declared at types/layout.ts:1599-1603 (ariaLabel: string | I18nLabel, ariaDescribedBy, role), and the reader takes AriaProps | null | undefined and answers {} for a missing bag (inlineAria.ts:60-73), so a page with no bag renders the same DOM — pinned (page-root-aria-11083.test.tsx, 7 cases: plain string en and zh, locale map en and zh, described-by with role, no bag, flat control). No mapping table in the file. @object-ui/components already depends on @object-ui/i18n.
  2. Spread order on the page root — right, with one unpinned corner. {...pageAria} after {...pageProps} means the nested bag wins when the flat keyed ariaLabel and the nested ariaLabel both resolve. Triage did not rule on the precedence; the changeset states it. No pin covers the both-authored case (the flat control is authored alone). Not a finding: the precedence is declared where a consumer reads it.
  3. No default role on the page — right. Triage kept the element family's default role off this card, and the page follows that ruling. The generic div carrying only an aria-label is named as an acceptance note with the same carrier (the future card).
  4. ListView's inline mapping becomes the shared reader with region kept — right. ListView.tsx:4273 reads const regionAria = resolveInlineAriaProps(schema.aria, displayLocale); :4304-4306 spreads it, then role={regionAria.role ?? 'region'}, then the aria.live read unchanged. The three one-key spreads and the resolveInlineI18nLabel(schema.aria?.ariaLabel, …) read are gone; resolveInlineI18nLabel stays imported for schema.label (:3047, :4100). The attribute set is identical for every authored value except role: '' (old: role=""; new: region, because the reader leaves an empty role out, inlineAria.ts:71). That change is named in the changeset and pinned. The label had no non-aria fallback at the base (the diff's removed lines show the one aria-label spread), so nothing else was there to keep. No second mapping table.
  5. The aria.live read stays — right under the seat's option A. live is a declared objectui extension: zod/objectql.zod.ts:1798-1799 (stripImportedDefaults(SpecAriaPropsSchema).extend({ live })) and objectql.ts:2677 (NamedListView.aria). The shared reader does not read it, so the one-key spread at :4306 is the site's own key, not a mapping table. Pinned (ListView.nestedAriaSharedReader-11083.test.tsx, the live case).
  6. useRecordAriaProps maps through the shared reader and keeps its defaults — right. recordComponentAria.ts:184-204: useDisplayLocale(), useRefusedAriaLabelReport(block, aria) (the useEffect keyed on the message), resolveInlineAriaProps(aria, locale), then label = authored['aria-label'] || defaultLabel, describedBy = authored['aria-describedby'], role = authored.role || defaultRole || (label || describedBy ? 'region' : undefined). Limb for limb this equals the old name || defaultLabel, aria?.ariaDescribedBy || undefined and aria?.role || defaultRole || …, because the reader drops empty strings; the hook order (locale, then the effect) is unchanged. The reader reads the three declared keys only, so the refused aria.label spelling stays report-only. Signature unchanged: (aria: AuthoredRecordAria | undefined, { defaultRole?, defaultLabel?, block? }) returning RecordAriaDomProps. Pinned under zh and en (recordAriaSharedReader-11083.test.tsx, 4 cases, read off the accessibility tree).
  7. useRecordAriaName becomes the unexported useRefusedAriaLabelReport — right, and not a public-surface change. The package entry packages/plugin-detail/src/index.tsx (911 lines) exports nothing from renderers/recordComponentAria, the head tree has no renderers/index barrel, and the 9556 changeset records the read point as internal. Type Check on the head is success, so no in-repo importer of the removed name remains.
  8. Dependencies — right. @object-ui/react is a peerDependency (workspace:^) and a devDependency of @object-ui/plugin-detail; @object-ui/i18n is a dependency of @object-ui/components. Pre-Install Import Graph Check is success.
  9. The docs row on the PageNodeSchema table — the substance is right, one clause is wrong. schema-reference.md:142: aria typed AriaProps, the three renderings, "resolved for the display locale" and "the page adds no default role" all match the code. ⛔ "not the keyed flat ariaLabel described under DivSchema" is false: the keyed flat ariaLabel is a BaseSchema member, described in the BaseSchema table (:91, string | KeyedI18nLabel, resolved by resolveKeyedI18nLabel); the DivSchema section (:148-167) declares one property, children, and never mentions ariaLabel. A reader sent to DivSchema finds nothing. This is finding 1.
  10. The pins test the ruling, not the diff's shape — right. All three files mount real renderers (SchemaRenderer with the registry for the page; ListView under SchemaRendererProvider; RecordHighlightsRenderer and RecordPathRenderer under RecordContextProvider), assert through the accessibility tree wherever a role is present, and cover a plain string and a locale map under en and zh per site, which is the card's pin.

② Semver level

.changeset/11083-nested-aria-family.md: patch for @object-ui/components, @object-ui/plugin-list and @object-ui/plugin-detail — matches what the diff publishes. Components: a declared key starts rendering (a fix); no type or export moves. plugin-list: the same attributes, one corrected corner (role: ''), stated in the text. plugin-detail: an internal refactor with no visible change (judgment 6) and no published symbol added or removed (judgment 7). @object-ui/types and @object-ui/react are untouched, so no entry for them is right. The changeset's claims (PageNodeSchema mirrors aria; nested wins over flat; ListViewSchema declares live) each check against the sources above. Changeset Bump Policy, Changeset Declaration, Changeset Claim Re-read and Changeset Fixed Group Check are success.

Clause-②: no — right. The PR body carries the line; useRecordAriaProps's signature and the RecordAriaDomProps and AuthoredRecordAria types are unchanged; the plugin-detail, react and components package exports are unchanged.

③ Boundary flags

  • Part of #11083 instead of Fixes — accepted. The aria.live half was reported for a decision; the seat closes the card after landing, and the seat has answered (option A), so this PR owes nothing further on that item.
  • Zone 1 item 2 not executed as "None ⇒ the read goes" — accepted, answered. The dev stopped on a falsified premise (the read is a declared extension, not residue; judgment 5) and reported with options. The seat's answer is A, and the diff is in state A. Escalation closed.
  • The docs row outside the claim's surface — accepted as a surface addition (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2: a declared member gets its row), refused as written — finding 1.
  • useRecordAriaName becomes a report-only hook — accepted. Internal, never on the package face (judgment 7); Clause-② stays no.
  • Open question (aria.live: A, B or C) — answered by the seat (5890989892): A. This record judges the diff against A; the diff keeps the read, the declaration and the pin. Nothing to escalate.
  • Out-of-scope note, page root default role — accepted; the carrier is the future element-family card, as triage set.
  • Out-of-scope note, .changeset/9556-record-component-aria-honoured.md:71 quotes the old ListView role= expression — accepted, not a finding. The claim it supports (the authored role, else region) still holds after this PR; only the literal has drifted. That file already carries a dated note from objectui#9945 (:97-105), so a dated note is the precedent if the seat wants the quote refreshed at landing; Changeset Claim Re-read is success on the head.

Findings (the FAIL):

  1. content/docs/api/schema-reference.md:142 — the new aria row says the keyed flat ariaLabel is "described under DivSchema". It is described under BaseSchema (:91); DivSchema (:148-167) declares only children. Point the clause at BaseSchema. One word; everything else in the row, and everything else in the diff, is right.

Implemented-by: claude/issue-11083-nested-aria-family
Reviewed-by: session_011p7ikEivgXefNDaE5S5Uec

VERDICT: FAIL


Generated by Claude Code

…abel at BaseSchema, where it is described

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3109.3 KB 3149.4 KB
Main entry chunk (gzip) 149.3 KB 350 KB
Entry file index-nvy_ABcM.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.84KB 133.94KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.11KB 66.33KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.68KB 36.71KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.59KB 61.84KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 169.69KB 43.37KB
plugin-gantt (index.js) 171.88KB 42.61KB
plugin-grid (index.js) 228.51KB 62.64KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.82KB 28.67KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 90.43KB 22.76KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 8.61KB 3.45KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.17KB 2.73KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 22.61KB 7.40KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: bf5aec064352833c898835cdf8d2ae5d66c11cea
Local-runs: none

Round 2, the delta since r1. r1 is record 5891094813 on this PR: FAIL at f4969f552 on one finding — the aria row of the PageNodeSchema table in content/docs/api/schema-reference.md pointed the keyed flat ariaLabel at DivSchema, where it is not described. Every other judgment in r1 (① items 1 to 8 and 10, ② in full, ③ in full) stands unless this delta moves it, and it does not; those judgments are adopted here by reference and not restated.

Inputs: the PR at the new head (body unchanged, first line Part of #11083, Clause-②: no; the 8-file list; the net diff against main), the compare f4969f552...bf5aec064 and its two branch commits, the dev's patch-round report on the card (5891182232), and the head's check-runs (filter=latest). Same brief as r1; nothing built, run or re-run locally.

Check-runs on the head: 43 latest runs, all completed by 2026-09-29T13:36Z — 40 success, 3 skipped (dependabot and the two coverage jobs, which do not run on a PR head), 0 failed. Among the successes: Test shards 1 to 8, Test (dist pins), Type Check, Lint, Spec Main Shape Gate, Build and E2E, Build Docs, Pre-Install Import Graph Check, the four changeset gates, Line Citation Gate, Control Byte Scan, Doc Component Type Check, Doc Example Id Check, Doc Fence Language Check, Internal Docs Link Check, Doc Snippet Type Check, README Export Check and Skill Example Check. Those conclusions are the gate verdicts for the merged tree as well as for the one-word fix; nothing was run locally.

① Derived judgments

  1. The finding is fixed — right. Commit bf5aec064 changes one word in one file: the row now reads "not the keyed flat ariaLabel described under BaseSchema". At the head, the keyed flat ariaLabel row (string | KeyedI18nLabel, resolveKeyedI18nLabel) sits under ### BaseSchema at schema-reference.md:91, and the aria row is :142, under ### PageNodeSchema; DivSchema (:148 onward) is no longer named by the row. The pointer is now true.
  2. The delta moves no source hunk — right. The net diff at bf5aec064 differs from r1's net diff at f4969f552 in exactly two lines: the schema-reference.md blob index (main had touched the file) and the one-word row. The seven other files carry the same blobs as at r1 (page.tsx f5185737dbf2, ListView.tsx a6bab8af4ba3, recordComponentAria.ts 17b045e2debe, the three pins and the changeset unchanged), so ① items 1 to 8 and 10 of r1 are judgments of byte-identical hunks.
  3. The merge brought in only main's own files — right. 8b9b8b0cb has parents f4969f552 and 5b2ea1757; against its first parent it lists the 40 files of main's five commits since the old base (ae582b70a, 559a2e207, 17fc68873, 88fbd793d, 5b2ea1757: PRs objectui#11089, 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, fix(app-shell): the console dashboard refreshes on its authored refreshIntervalSeconds (objectui#11062) #11093, feat(app-shell): Studio's app, permission and view previews show the authored area descriptions, RLS policy labels and view label (objectui#11027) #11098), and none of them is a file of this branch except schema-reference.md, which main touched by one added line (PR objectui#11091) outside the PageNodeSchema table — the branch's hunk header is unchanged at @@ -139,6 +139,7 @@. No conflict, no rebase, no force-push; the branch's three source modules and its pins are the same blobs on both sides of the merge.
  4. The docs row as a whole — right. With the pointer corrected, every clause of the row (AriaProps, the three renderings, "resolved for the display locale", the inline-versus-keyed distinction, "the page adds no default role") matches the code judged in r1.

② Semver level

Unchanged from r1: .changeset/11083-nested-aria-family.md is the same blob (333c8d6c200e), patch for @object-ui/components, @object-ui/plugin-list and @object-ui/plugin-detail, matching what the diff publishes; the merge adds main's own changesets and no entry of this branch's. Clause-②: no — right; no signature, type or package export moved between f4969f552 and bf5aec064.

③ Boundary flags

  • The dev's patch-round report (5891182232): open_questions empty, out_of_scope_findings empty — accepted. Its claims check: the word diff is exactly DivSchema to BaseSchema; the merge is a plain merge of 5b2ea1757; the branch's source files did not change on main.
  • r1's flags stand: Part of #11083 (the seat closes the card after landing, per the seat's answer 5890989892); the aria.live read stays under option A; useRecordAriaName internal; the page-root default role with the future element-family card; the 9556 changeset's drifted literal not a finding.
  • Nothing new to escalate.

Implemented-by: claude/issue-11083-nested-aria-family
Reviewed-by: session_011p7ikEivgXefNDaE5S5Uec

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 29, 2026 14:03
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit b24f93a Sep 29, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11083-nested-aria-family branch September 29, 2026 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: components plugin tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants