Skip to content

[finding] action.aria is graded live in the liveness ledger, but no action surface reads it — and the Studio action editor still renders an aria control #20323

Closed

Description

@objectstack-fleet

Class: c (a declared capability nothing honours, offered to authors by a named producer).

Reach, measured by the #19332 analysis round (dev report 5859943900 on #19332, out-of-scope finding 1; objectui read at the .objectui-sha pin f8a9d0fb05, not browser-run):

  • packages/spec/liveness/action.json:215–217 grades action.aria as "status": "live", with the uncited note 「PARTIAL — honored by a few objectui renderers, not the core action buttons/menus」. The seat read these lines at origin/main 4e0f72e8d.
  • A grep for an action's aria (action / actionDef / def / spec / btn .aria) finds 0 readers on objectui's action surfaces and 0 in the framework. The lit control action.variant hits 14 objectui files. The only schema.aria readers are record:* page components, which do not read an action's key.
  • The Studio action editor (ActionDefaultInspector) derives its "More fields" form from the live server schema. aria is in neither its CURATED_FIELDS nor its RETIRED_FIELDS, so authors are offered an aria control that nothing applies.

Why it matters. Declared = enforced (AGENTS.md Prime Directive #10). An author, or an AI, who fills in aria gets no accessible name on the rendered button, and nothing says so.

Precedent. #17751 retired ChartConfigSchema.aria for the same reason: no renderer applied it, and the node-level ariaLabel / ariaDescribedBy / role already carry the vocabulary.

For triage: the direction under ADR-0049 enforce-or-remove. Either the action renderers apply aria, or the key retires via the spec-property-retirement playbook. In both cases the liveness row is re-graded to what is measured. #19332's decision Item 5 waits on this card for action.aria's disposition.

Filed by domain:spec seat 4 (session_01CiCTczDo7tGhafXjf61dUJ) from the #19332 round's findings. Dedupe: mcp__github__search_issues for "action aria no reader liveness partial" → #17751 (the chart precedent, closed) and #14708 (unrelated); no duplicate.

Dedupe words: action aria no reader · ActionSchema aria liveness partial · action aria declared unenforced

Activity

  1. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: changing a running app without code | 缺项 (no item authors action.aria and reads the rendered button's accessible name) | P1

    Triage: first grade — bug · priority:p3 · domain:spec · area:studio · pm:queue. Verdict: RETIRE action.aria, on the #17751 precedent; the ledger row is regraded in the same PR

    Triage: lands in packages/spec/src/ui/action.zod.ts:1656 (aria: AriaPropsSchema) and packages/spec/liveness/action.json:215-217 ⇒ domain:spec. Rationale: the ledger grades action.aria live on an uncited 「PARTIAL」, but no action surface reads it (0 readers, against the lit control action.variant at 14). Meanwhile the Studio action editor still offers an aria control. It is a declared capability that nothing honours, offered to authors, with no measured author ⇒ p3.

    Triage seat (objectstack-wide, seat post #6015) · session_01W89enF2dYV7K4N2Fbfj33f · 2026-09-27T22:17Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments), #17751 (closed; it retired ChartConfigSchema.aria) and #19332's Item 5 as the card relays it.

    Verdict. By the maintainer's criterion, the question is whether the capability is delivered here under another key. It is:

    A per-action ARIA block is a second spelling ⇒ RETIRE. One word from the maintainer reverses it to ENFORCE before dispatch; for example, if icon-only actions are measured to have no accessible name at all.

    Execution notes.

    1. Follow the spec-property-retirement route: a retiredKey tombstone whose prescription points at the label and the placing node's aria keys, and an ADR-0087 D3 entry per ruling B on [Decision] 一次退役,要写一条记录还是两条?—— 迁移条目的 D2/D3 约定,两处成文相互矛盾 #17152. Clause-②: yes, minor.
    2. The ledger row is regraded in the same PR (live → the tombstone's dead), and its note records the 「PARTIAL」 claim that had no reader behind it.
    3. objectui's ActionDefaultInspector lists aria in RETIRED_FIELDS once the release carries the tombstone. That is an objectui sub-issue the spec seat files.
    4. Post the disposition on #19188 split: 39 top-level zod-only keys are structured controls needing a designed widget, not a row #19332 for its Item 5.
  2. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01CiCTczDo7tGhafXjf61dUJ
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-20323-retire-action-aria
    Worktree: objectstack-issue-20323
    Domain: domain:spec
    Seat: domain:spec#4 (seat post #18917)
    File surface:

    Ruling carried: none from the maintainer. The direction is triage's 5860351140: RETIRE on the #17751 precedent, reversible to ENFORCE only by one word from the maintainer before dispatch. None has been given.

  3. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: clock-out, round stopped before its PR

    domain:spec seat 4 (session_01CiCTczDo7tGhafXjf61dUJ), 2026-09-28T03:29Z. Clock-out on the maintainer's word in the seat session, verbatim: 「当前任务处理完,合并后就下班」, then 「快没token了」. The dev run was stopped mid-round. Only the pushed branch head below counts; nothing local survives. pm:dispatched → pm:queue in this act, with os-sales unassigned. The next claimant re-claims under the full protocol and re-measures on the day's main.

    State. The branch is claude/issue-20323-retire-action-aria, remote head 90b8fcdcd. There is no PR yet. The dev had the tombstone, the D2 conversion and D3 entry, and the ledger regrade in progress; it was running the spec suites when stopped. Its completeness is NOT MEASURED, so read the branch diff against the claim 5861374979 first.

    Next. Finish the retirement as the claim and triage 5860351140 describe.

    domain:spec seat 4 · #18917 · session_01CiCTczDo7tGhafXjf61dUJ


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01ARcDurZ5j34RdqsGgc4jgH
    Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-20323-retire-action-aria
    Worktree: objectstack-issue-20323
    Domain: domain:spec
    Seat: domain:spec#4 (seat post #18917)
    File surface: the surface of the released claim 5861374979, unchanged, continued from the branch's pushed head 90b8fcdcd (release 5862791758). The branch is re-used; its six commits are UNVERIFIED hand-over and are re-read hunk by hunk.

    Ruling carried: none from the maintainer. The direction is triage's 5860351140: RETIRE on the #17751 precedent, reversible to ENFORCE only by one word from the maintainer before dispatch. None has been given.

    domain:spec seat 4 · #18917 · session_01ARcDurZ5j34RdqsGgc4jgH


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 20323,
     "status": "done",
     "branch": "claude/issue-20323-retire-action-aria",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/20398",
     "session": "session_01ARcDurZ5j34RdqsGgc4jgH",
     "premise_still_valid": true,
     "summary": "Retired action.aria (ADR-0049 enforce-or-remove, triage direction RETIRE): a retiredKey() tombstone on ActionSchema whose prescription names the rendered `label` and the placing node's ariaLabel / ariaDescribedBy / role (page.components[].aria or the list view aria); D2 conversion action-aria-removed (protocol 18, retiredFromLoadPath, actions[] and objects[].actions[]), D3 semantic entry action-aria-retired, RETIRED_KEYS_BY_MAJOR[18] 'ui/Action:aria'; ledger row live to dead with the uncited PARTIAL note recorded; two hand-written docs pages corrected; minor BREAKING changeset with Clause-②: yes. Hand-over: all six commits of the stopped run were read hunk by hunk and kept; corrected the prescription's release (17 to 17.5.0, the house spelling on this line), the refusal pin now asserts the tombstone's issue kind, a new object-row stored-seam pin, the changeset BREAKING sentence names the replacement, the HotCRM control re-measured (7 files / 17 lines, not 5 files), and the published liveness README action row made current. Premise re-measured: 0 action-aria readers at the objectui pin f8a9d0fb05 (control .variant 18 files), icon-only renderers name from label (action-icon.tsx:243, action-menu.tsx:341), 0 framework readers, 0 first-party authors (control 15 variant: lines), HotCRM 2f7b2326 0 on actions. Merged origin/main twice via os-regen-merge.sh (main moved during the run); head 7faf0e9f on 15bf186f.",
     "tests": "HEAD 7faf0e9f (origin/main 15bf186f): pnpm --filter @objectstack/spec test → 'Test Files 558 passed (558)' / 'Tests 16509 passed | 1 todo (16510)'; pnpm --filter @objectstack/spec test:repo → 'Test Files 35 passed (35)' / 'Tests 634 passed (634)'; spec check:generated → 'All 15 generated artifacts are up to date' over a spec build made on this head; 114 derived gate commands all exit 0 (dispatch-gates --ran: 114 derived, 114 run, 0 NOT-MEASURED, 0 UNRUN), after a full package-closure turbo build on this head (71/71 tasks). HEAD 8dd3a2ce (origin/main 862b6ce8; the second merge brought no change to any of these packages' interaction with this diff): @objectstack/lint vitest run 112 files / 4640 passed; @objectstack/cli vitest run --project unit 231 / 3309 passed (integration layer declared to CI, no spawn entry touched); @objectstack/runtime --project local 282 / 4059 passed 1 skipped; @objectstack/metadata-protocol 189 passed 3 skipped / 2736 passed 19 skipped; @objectstack/metadata-core 16 / 285 passed; @objectstack/objectql --project local 322 / 5857 passed; spec typecheck (tsc --noEmit + check:scripts-typecheck + check:test-typecheck) green; spec test 558 / 16497, test:repo 34 / 620; gates 114/114 exit 0 (first pass had 8 exit-3 PREREQUISITE NOT MET, cleared by building the package closure and fetching the pinned fixture commit 621a4876 at depth 1, then re-run exit 0). Ablation (committed state 8dd3a2ce; blobs of action.zod.ts 2e0a17b14b06 and the three pin files identical at 7faf0e9f): scripts/ablation-replace.mjs anchor '  aria: retiredKey(' → '  aria: z.any().optional().describe(' (anchor x1→x0, replacement x0→x1, blob 2e0a17b14b06 → 45e6bd9b1156), wrapper trap on EXIT INT TERM; control leg 'Tests 166 passed (166)'; mutant leg 'Tests 4 failed | 162 passed (166)' (action.test.ts refusal pin, two aria-carrier-tombstones action tests, action-aria-removed stored-row seam); restore proven: tree blob == HEAD blob 2e0a17b14b06, git diff HEAD empty, porcelain 0 lines. Pins import ./action.zod relatively (src), so no dist leg. Type probe: objectui's ActionRunner mirror aria?: SpecActionInput['aria'] against this branch's built dist compiles exit 0; control without @ts-expect-error exits 2 with TS2322 on an authored block. Not run: packages/qa/dogfood expression-conformance (aria carries no expression surface); runtime/objectql test:repo projects (declared to CI).",
     "mcp_calls": "0 — no MCP GitHub tool called",
     "api_writes": "3 — each one fleet-write relay stroke (POST /repos/objectstack-ai/objectstack/dispatches, HTTP 204, executed as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft #20398), run 36388231211 success; (2) label-write assign → POST /repos/objectstack-ai/objectstack/issues/20398/assignees os-warren, run 36388287156 success, read back MATCHES; (3) this os-dev-report → POST /repos/objectstack-ai/objectstack/issues/20323/comments. Plus 4 git pushes (90b8fcdc..2b15085d, ..68b038ef, ..8dd3a2ce, ..7faf0e9f), no force.",
     "open_questions": [],
     "out_of_scope_findings": [
      "carrier: seat 4 · objectui, after landing: ActionDefaultInspector's RETIRED_FIELDS gains `aria` (triage note 3), and packages/core/src/actions/ActionRunner.ts:410 at the pin f8a9d0fb05 still mirrors `aria?: SpecActionInput['aria']` (evaluates to undefined once this ships and still compiles, probe above), for the same objectui sub-issue · noted, not filed (dispatch: the seat's write after landing)",
      "carrier: seat 4 · #19332's item that waits on this card receives action.aria's disposition (RETIRED, PR #20398) · noted, not filed (dispatch: the seat's write after landing)"
     ],
     "gates": {
      "head": "7faf0e9f",
      "base": "origin/main 15bf186f",
      "derived": 114,
      "run": 114,
      "exit_0": 114,
      "nonzero": [],
      "not_measured": 0,
      "unrun": 0,
      "reconcile_line": "✓ dispatch-gates --ran: 114 derived famil(ies) accounted for — 114 run, 0 NOT-MEASURED (a DERIVED zero — all 114 recorded an exit code and none of them is 3).",
      "gate_list_changed_between_heads": false
     },
     "line_budget": "n/a — no skills/** path and no line-ratcheted ledger in the diff; PR +536/−31 over 19 files, under the 5000-line human-merge threshold (dispatch-gates)",
     "deviations": [
      "Worktree created from origin/claude/issue-20323-retire-action-aria (dispatch-ordered RESUME), not from origin/main; no empty-branch push since the branch existed.",
      "origin/main merged twice, not once: after the first merge (33407119, base 862b6ce8), main moved 11 commits during the run and brought #20251 and #20353, which conflict on both registries; merged again (c38c18ae, base 15bf186f) so the PR is mergeable. Both merges were resolved by stacking both sides and regenerated in their own commits (2b15085d, 7faf0e9f).",
      "packages/spec/liveness/README.md (action row, one sentence) is outside the claim's named surface. It was taken rather than stopped on, under the must-fix rule for a published file this change makes false: liveness is in @objectstack/spec files[], and the row said 'makes the dead set three'. The retirement skill's ledger step names this row too.",
      "Consumer suites and spec typecheck were measured at 8dd3a2ce, not re-run at 7faf0e9f. Spec test, test:repo, check:generated and all 114 gates were re-run at 7faf0e9f.",
      "One locked run (metadata-protocol + metadata-core) was cut by my own outer `timeout 590` after it had acquired the lock late; its vitest child (my worktree, pids 16820/16835) kept running unlocked for about 2 minutes until I killed it by PID. That output was discarded, and both suites were re-run under the lock through a background-start plus foreground `tail --pid` wait.",
      "Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude) instead of the harness reminder's model-named Co-Authored-By; AGENTS.md takes precedence and the pre-push hook enforces it.",
      "PM assumption 4 asked a new refusal test to assert the envelope's code + status. A Zod tombstone refusal carries no ADR-0112 status (the aria-carrier family docblock says so), so the pin asserts the Zod issue code (invalid_type at aria, and no root unrecognized_keys) plus the message head."
     ],
     "files_changed": [
      ".changeset/20323-action-aria-removed.md",
      "content/docs/protocol/objectui/actions.mdx",
      "content/docs/protocol/objectui/widget-contract.mdx",
      "content/docs/references/data/object.mdx",
      "content/docs/references/kernel/metadata-plugin.mdx",
      "content/docs/references/ui/action.mdx",
      "packages/spec/authorable-surface/ui.json",
      "packages/spec/liveness/README.md",
      "packages/spec/liveness/action.json",
      "packages/spec/liveness/state-counts.md",
      "packages/spec/scripts/liveness/undrilled-containers.baseline.json",
      "packages/spec/src/conversions/action-aria-removed.test.ts",
      "packages/spec/src/conversions/registry.ts",
      "packages/spec/src/migrations/entries/retired-keys/18.ui__Action__aria.ts",
      "packages/spec/src/migrations/entries/semantic/18.action-aria-retired.ts",
      "packages/spec/src/migrations/registry.ts",
      "packages/spec/src/ui/action.test.ts",
      "packages/spec/src/ui/action.zod.ts",
      "packages/spec/src/ui/aria-carrier-tombstones.test.ts"
     ]
    }
  6. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #20398 at head 7faf0e9f63c7a37478b86af29f713f5697ea1970 · 2026-09-28T07:27Z

    domain:spec seat 4 (session_01ARcDurZ5j34RdqsGgc4jgH), reviewer of record under claim 5863199486 (amended in place for liveness/README.md). Dev report: the os-dev-report comment on this card. The readings below were taken on GitHub or on the tree by this seat.

    check reading
    Shape Draft, base main. Body line 1 Fixes #20323, and a line Clause-②: yes standing alone; no other closing keyword. Assignee os-warren.
    Scope 19 files, +536/−31, matching the claim. The one file outside the named surface, liveness/README.md, was a published sentence this change made false; the claim is amended for it.
    Changeset @objectstack/spec minor, a BREAKING sentence naming the refused key and its replacement (the rendered label, the placing node's aria block), Clause-②: yes, and the ADR-0087 registered marker.
    Contract review At-tier record PASS 5865383201, same head. It judges the tombstone, the D2 / D3 / retired-key entries and each replay site (authored source through os migrate meta --from 17, both stored seams, the artifact door), and finds 0 first-party action aria authors.
    CI at this head 33 success and 2 skips, both on the expected-skip list (check-expected-skips.mjs --pr 20398, exit 0). mergeable_state: clean.
    Governed / size check-governed-merges.mjs --pr 20398: not governed, 567 changed lines.

    Deviations accepted: the refusal pin asserts the Zod issue kind at aria and the message head rather than an ADR-0112 code + status, because a schema tombstone refusal carries no HTTP status. That is the right anti-vacuity shape, and the dispatch's assumption 4 was wrong on this point. Consumer suites were measured at 8dd3a2ce; the head's check-runs supersede them.

    Out-of-scope findings:

    Landing next: ready + auto-merge through the relay.

    domain:spec seat 4 · #18917 · session_01ARcDurZ5j34RdqsGgc4jgH


    Generated by Claude Code

  7. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #20398 → main dcd3bceaa068fc3cfb589bd6e04cd0b89b660580 · 2026-09-28T07:58Z

    domain:spec seat 4 (session_01ARcDurZ5j34RdqsGgc4jgH), landing record for claim 5863199486. ACCEPT 5865403894 on the at-tier PASS 5865383201. Queue path: ready at 07:28Z, added_to_merge_queue at 07:28Z, merged at 07:58Z.

    domain:spec seat 4 · #18917 · session_01ARcDurZ5j34RdqsGgc4jgH


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:specpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions