Skip to content

feat(spec)!: retire action.aria — no action renderer ever applied it (ADR-0049) - #20398

Merged
objectstack-fleet[bot] merged 12 commits into
mainfrom
claude/issue-20323-retire-action-aria
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 12 commits into
mainfrom
claude/issue-20323-retire-action-aria

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #20323

Clause-②: yes

What this does

Retires action.aria under ADR-0049 enforce-or-remove, following the triage direction on the card (RETIRE, on the chart-config precedent 2bf6ef18d). No maintainer word reversed it to ENFORCE.

  • Schema. ActionSchema.aria becomes a retiredKey() tombstone. It is a tsc error (the input type is never) and a parse error that carries the prescription. The accessible name that IS applied is the action's required label, and the placing node's aria block (page.components[].aria or the list view aria) names the region. AriaPropsSchema is untouched: this is a key retirement, not a def retirement.
  • ADR-0087. The D2 conversion action-aria-removed (protocol 18, retiredFromLoadPath) strips the key from actions[] and objects[].actions[] as a lossless delete. The D3 semantic entry action-aria-retired is its own family, per the one-entry-per-family rule. The retired key ui/Action:aria is registered under 18, the major of the chart-config sibling.
  • Ledger. liveness/action.json regrades aria from live to dead. Its REMOVED note records that the uncited 「PARTIAL — honored by a few objectui renderers」 claim had no reader behind it. The undrilled-container row action/aria goes, and state-counts.md is regenerated.
  • Docs. Two hand-written pages taught aria on an action and are corrected: protocol/objectui/actions.mdx and widget-contract.mdx. The three reference pages that render ActionSchema are regenerated.
  • Changeset. minor, BREAKING, with Clause-②: yes, the FROM → TO table and the ADR-0087 registered marker.

Premise, re-measured on this checkout

  • objectui at the .objectui-sha pin f8a9d0fb05. A reader grep for an action's aria (action, actionDef, def, spec, btn, a, act, item followed by .aria) over packages/** and apps/** non-test sources hits 0 lines. The control, the same grep for .variant, hits 18 files. Every schema.aria reader there is a placing node: the record:* components, ListView, ObjectView and element:button's props.
  • Icon-only reversal condition. Triage named "icon-only actions have no accessible name" as the condition that would reverse this to ENFORCE. It does not hold. action-icon.tsx:243 renders aria-label={schema.label || schema.name}, action-menu.tsx:341 renders aria-label={schema.label || moreActionsLabel}, and action-button.tsx:346 renders {schema.label} as the visible text.
  • Framework. A grep for .aria over packages/** non-test TS outside packages/spec hits 0 lines. action.form.ts has 0 aria rows; its one hit is the variant substring.
  • Authors in this repo. Across examples/**, the published skills/** and packages/** fixtures, 0 actions author aria. The control is 15 variant: lines in examples/**.
  • Authors in HotCRM 2f7b2326. 0 actions author aria. Its 6 aria: blocks are all page-level page.aria, which stays live. The control: 7 files under src/**/actions/ declare locations:, 17 times.
  • Served schema. metadata-protocol drops a tombstone's { not: {} } node from the served JSON Schema, via stripUnauthorableProperties. So the Studio "More fields" form stops offering aria once this ships.
  • Pinned sibling. objectui's ActionRunner.ts:410 mirrors the key as aria?: SpecActionInput['aria']. A type probe against this branch's built dist compiles that mirror at exit 0, because it evaluates to undefined. An authored block on it is refused with TS2322, and the control leg without @ts-expect-error exits 2. So the Console Pin Gate's objectui build is not broken by this change.

Hand-over review (the stopped run's six commits, read hunk by hunk)

commit verdict
0c5dbbff sources, ledger, tests, changeset kept, with corrections. The prescription said "removed in @objectstack/spec 17"; it now says 17.5.0, the spelling every sibling retirement on this line uses. The refusal pin in action.test.ts now also asserts the tombstone's own issue kind (invalid_type at aria, and no root unrecognized_keys, which is what a bare deletion would answer instead). The changeset's BREAKING sentence now names the replacement. The HotCRM control is re-measured: 7 files and 17 lines, not "5 action files".
6334c137 regenerated artifacts kept, and re-derived after both merges
bfc86375 the stored-row pin uses a parseable script action kept
0f20c62f the action/aria undrilled-container row goes kept; check:liveness is green
8cbcfa46 merge of main kept
90b8fcdc regenerated state counts kept; superseded by the post-merge regeneration

Added in this round:

Verification

Head 7faf0e9f, on 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).
  • pnpm --filter @objectstack/spec check:generated: all 15 generated artifacts up to date, measured over a spec build made on this head.
  • Gates: node scripts/pm/dispatch-gates.mjs --commands derives 114 commands. All 114 exit 0, and --ran reconciles them as 114 derived, 114 run, 0 NOT-MEASURED, 0 UNRUN. The run covers every package's build closure, rebuilt on this head, so the gates that read dist measured it.

Head 8dd3a2ce, before the second main merge, on origin/main 862b6ce8. The second merge touched none of these packages' interaction with this diff; the incoming commits retire other keys and touch no action surface.

package command Test Files Tests
@objectstack/lint vitest run 112 passed 4640 passed
@objectstack/cli vitest run --project unit 231 passed 3309 passed
@objectstack/runtime vitest run --project local 282 passed 4059 passed, 1 skipped
@objectstack/metadata-protocol vitest run 189 passed, 3 skipped 2736 passed, 19 skipped
@objectstack/metadata-core vitest run 16 passed 285 passed
@objectstack/objectql vitest run --project local 322 passed 5857 passed

pnpm --filter @objectstack/spec typecheck was green at the same head. The cli integration layer is declared to CI: this diff touches no spawn entry and no integration file.

Ablation, from the committed state at 8dd3a2ce. The blobs of action.zod.ts and of the three pin files are byte-identical at 7faf0e9f.

  • The mutation goes through scripts/ablation-replace.mjs: the anchor aria: retiredKey( becomes aria: z.any().optional().describe(, so the key is accepted again. The tool reports the anchor going from 1 to 0, the replacement from 0 to 1, and the blob from 2e0a17b14b06 to 45e6bd9b1156. The wrapper also arms a trap that restores the file.
  • The control leg runs the three pin files on the committed state: Tests 166 passed (166).
  • The mutant leg: Tests 4 failed | 162 passed (166). The four red tests:
    • action.test.ts · refuses an action carrying aria;
    • aria-carrier-tombstones.test.ts · the action tombstone fires and prescribes;
    • aria-carrier-tombstones.test.ts · the object-nested coordinate;
    • action-aria-removed.test.ts · the stored-row seam.
  • The restore is proven by content, not by an exit code. The file's blob equals HEAD's blob 2e0a17b14b06, git diff HEAD is empty, and the porcelain status has 0 lines.
  • The pins import ./action.zod and ../ui/action.zod.js relatively. They read src, not dist, so this ablation has no dist leg.

Acceptance notes


Generated by Claude Code

…urces, ledger, tests, changeset)

Claude-Session: https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ
Co-authored-by: Claude <noreply@anthropic.com>
check:liveness names it stale: the tombstone is no longer a container, so the
recorded gap no longer exists.

Claude-Session: https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ
Co-authored-by: Claude <noreply@anthropic.com>
…tire-action-aria

Conflicts resolved by stacking both intents: conversions/registry.ts and
migrations/registry.ts step18 conversionIds keep main's
form-layout-inline-grid-to-vertical and this branch's action-aria-removed;
step18's hand-written rationale carries main's form-layout paragraph and then
this branch's action.aria paragraph. Generated regions are regenerated in the
next commit.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
state-counts.md, and the three reference pages that render ActionSchema,
regenerated from the merged tree (gen:migration-registry, gen:liveness-counts,
gen:docs over a fresh spec build); check:generated reads all 15 up to date.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
…er issue; object-row replay pinned

- The prescription names the release that ships the refusal (17.5.0), the
  house spelling of every sibling retirement on this line.
- action.test.ts: the refusal pin asserts the tombstone's own issue kind
  (invalid_type at `aria`, and no root unrecognized_keys), which is what a bare
  deletion would answer instead.
- action-aria-removed.test.ts: the stored-row seam reaches an `object` row's
  nested action, the changeset's second at-rest coordinate.
- The changeset's BREAKING sentence names the replacement; its HotCRM control
  is re-measured at 2f7b2326.
- liveness/README.md: the action row's "dead set three" becomes four.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
…tire-action-aria

Conflicts resolved by stacking both intents: CONVERSIONS_BY_MAJOR[18] and
step18.conversionIds keep main's currency-config-precision-removed and
permission-rls-tags-removed, then this branch's action-aria-removed; step18's
hand-written rationale carries main's two paragraphs, then this branch's
action.aria paragraph. Generated regions are regenerated in the next commit.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
…rred

content/docs/references/data/object.mdx regenerated from the merged tree over
a fresh spec build; gen:migration-registry and gen:liveness-counts reproduce
the committed bytes, and check:generated reads all 15 up to date.

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 13 documentable anchor(s). ⚠️ 5 changed file(s) yielded no anchor (packages/spec/authorable-surface/ui.json, packages/spec/liveness/README.md, packages/spec/liveness/action.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/ai/tools.mdx (via escalate_case (literal, a string literal in fixture), support_case (literal, a string literal in fixture))
What this run could not see
  • 5 changed file(s) yielded no anchor (packages/spec/authorable-surface/ui.json, packages/spec/liveness/README.md, packages/spec/liveness/action.json, …) — pages documenting those are invisible to this run
  • 8 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 2f122b6e47dd01264d1a3c4d2fc7946fc31f3f2e → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8cb48e7e154d3b346abb2c6af1acb8cd8191992d — the merge of head 7faf0e9f63c7a37478b86af29f713f5697ea1970 into base 2f122b6e47dd01264d1a3c4d2fc7946fc31f3f2e, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 8cb48e7e154d3b346abb2c6af1acb8cd8191992d && git checkout 8cb48e7e154d3b346abb2c6af1acb8cd8191992d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2f122b6e47dd01264d1a3c4d2fc7946fc31f3f2e 7faf0e9f63c7a37478b86af29f713f5697ea1970 && git checkout -B drift-repro 2f122b6e47dd01264d1a3c4d2fc7946fc31f3f2e && git merge --no-ff 7faf0e9f63c7a37478b86af29f713f5697ea1970

node scripts/docs-audit/affected-docs.mjs --json 2f122b6e47dd01264d1a3c4d2fc7946fc31f3f2e

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 2f122b6e47dd01264d1a3c4d2fc7946fc31f3f2e → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 7faf0e9f63c7a37478b86af29f713f5697ea1970
Local-runs: none

Inputs: card #20323 (body and all five comments — triage 5860351140, claims 5861374979 / 5863199486, release 5862791758, dev report 5864933100); PR #20398 (body, 19-file list, net diff against main at merge-base 15bf186f); the 35 check-runs on the head (33 success; 2 skipped by design — Console Pin Gate, whose path filter is .objectui-sha plus the console scripts, none touched; Packed-tarball smoke, opt-in). Verification was read-only: git fetch / git show / git grep against refs in this checkout and against the objectui pin f8a9d0fb05 in the sibling checkout; nothing built, run or re-run.

① Derived judgments

Accept-set

  • ActionSchema.aria narrows from AriaPropsSchema.optional() to retiredKey(...), a never slot: any authored value is refused at parse with the prescription, and the input type is never for tsc. Both authored coordinates (actions[], objects[].actions[]) refuse through the same slot; pinned in action.test.ts and aria-carrier-tombstones.test.ts (object-nested case included). RIGHT. Premise re-verified at the objectui pin: 0 readers of an action's aria on any action surface (action:button/icon/menu/group/bar, the row and bulk menus, the quick-actions bar); the only schema.aria readers are placing nodes (record:* components, ListView); icon-only renderers name from schema.label (action-icon.tsx:243, action-menu.tsx:341), so triage's reversal condition does not hold. Direction is RETIRE per the triage record; no maintainer word reversed it.
  • Refusal shape: invalid_type at path aria, no root unrecognized_keys, message head pinned. RIGHT — that is the tombstone's own issue, and the anti-vacuity is real: a bare delete on this strictObject would answer unrecognized_keys without the prescription.
  • Tombstone on a strictObject rather than the guidance-map route. RIGHT — retired-key.ts's own docblock names closed shapes as a supported case (the prescription is the payload), the same schema already carries execute as a retiredKey tombstone, and the ledger discipline follows the tombstone route consistently (row kept and regraded; authorable-surface row marked [RETIRED], not deleted).
  • AriaPropsSchema untouched and still live on page.aria, page.components[].aria, the list view aria and element props; control pinned. RIGHT — a key retirement, not a def retirement.

ADR-0087

  • D2 action-aria-removed: toMajor: 18, retiredFromLoadPath: true, stripKeys via mapCollection over actions[] and objects[].actions[], one notice per stripped key, fixture with expectedNotices: 2, copy-on-write control and idempotence pinned. Replay sites: authored sources are NOT replayed (the loader skips retired entries; the tombstone refuses and the house sentence sends the author to os migrate meta --from 17, which replays the chain) — RIGHT; stored seams — applyConversionsToStoredItem pins includeRetired: true and wraps action / object rows into actions / objects, so both at-rest coordinates are reached, pinned by two tests — RIGHT; artifact door — applyArtifactForwardConversions replays with includeRetired: true over the whole stack shape, where actions live only at those two paths — RIGHT. The third ActionSchema embedding (MetadataTypeRegistryEntry.actions, plugin code, and its MetadataTypeInfoResponse projection) is neither a stack source nor a stored row; no walker reaches it and the tombstone (tsc plus parse) covers it; the conversion docblock states this boundary. RIGHT.
  • D3 action-aria-retired as its own family (ruling B on [Decision] 一次退役,要写一条记录还是两条?—— 迁移条目的 D2/D3 约定,两处成文相互矛盾 #17152), non-empty reason and acceptanceCriteria; step 18 conversionIds and rationale extended; RETIRED_KEYS_BY_MAJOR[18] gains ui/Action:aria, matching the authorable-surface spelling. Registered under protocol 18 while shipping on 17.5.0 is the chart sibling's convention and ADR-0087's amended two-axis rule. RIGHT. The generated migrations/registry.ts matches its entry files (Lint & Repo Gates carries that step; success).
  • D4 artifacts (spec-changes.json, upgrade guide) unchanged. RIGHT — both project protocol 16 to 17 only; every other 18-registered conversion (chart-config-aria, permission-rls-tags, currency-config-precision) is equally absent; check:spec-changes / check:upgrade-guide ran green.
  • Changeset marker: the adr-0087 registered marker names action-aria-removed and action-aria-retired; both ids resolve at the head (Check Changeset runs check-adr-0087-registration against the merge-base; success).

Ledger and baselines

  • liveness/action.json aria: live to dead, verifiedAt 2026-09-28, note in the house REMOVED template and recording the uncited PARTIAL claim. The row carried only status and note before (no authorWarn), so no advisory-lint non-warn pin is owed. RIGHT. state-counts.md (action live 46 to 45, dead 3 to 4; totals 939 / 163) is arithmetically consistent; the action/aria undrilled-container row goes (a never slot has nothing to drill); the README action row now says the dead set is four. Spec property liveness check-run: success.
  • authorable-surface/ui.json: ui/Action:aria [RETIRED]. api-surface and json-schema.manifest unchanged — correct for a key tombstone (both record def and export existence, not key sets).

Public surface and docs

  • No exported symbol removed; the Action input type's aria becomes undefined-only. objectui at the pin: ActionRunner.ts:410 mirrors SpecActionInput['aria'], which resolves to undefined and compiles; actionKeys.ts lists aria in the spec-owned key set, and the tombstone keeps the key in the shape. Console Pin Gate was skipped by its path filter, so the sibling compile is dev-probed rather than gate-measured; nothing the pinned sibling imports is removed by this diff. RIGHT.
  • Served schema: stripUnauthorableProperties drops { not: {} } property nodes structurally (acceptsNothing), so Studio's derived "More fields" stops offering aria once the release is pinned. RIGHT.
  • Docs: actions.mdx interface block loses aria?: AriaProps with corrective prose; widget-contract.mdx carrier sentence corrected; three reference tables regenerated (the nested Action.aria table gone). No remaining page teaches aria on an action (grep at head). RIGHT.
  • First-party authors of an action aria: 0 in this repository at the head (aria: over examples/**, skills/**, packages/**, apps/** outside spec src, tests and generated files hits only i18n locale bundles, the page and view form translations, and CHANGELOGs); the four Type Check check-runs are green, so no TS author survives the never type; objectui at the pin authors aria only on its own live carriers (record components, list views, chart configs), and its one action-shaped type test expects { aria: 'label' } refused, which still holds. HotCRM 2f7b2326 0-on-actions is dev-measured with a control (out of repo; not re-measured here).

Residual, advisory (no accept-set or surface effect): two published src/**/*.zod.ts comments now name the action as a live AriaProps carrier — i18n.zod.ts:8-11 (a dated measurement note that already lists ChartConfigSchema, retired by #17751 and left uncorrected there, so this PR is at parity with the precedent) and dashboard.zod.ts:1129 (the parenthetical saying action.aria carries the shape and the ledger grades it PARTIAL). Carry as a one-line follow-up beside the objectui sub-issue.

② Semver level

  • '@objectstack/spec': minor with the BREAKING banner, the FROM to TO table, the one-line fix, the house os migrate meta --from 17 sentence and the ADR-0087 registered marker. RIGHT: ADR-0087 (amended 2026-09-13, [Decision] 两条裁决援引同一个 launch-window convention,却给出相反的 changeset 等级(minor vs major)—— 退役一个可写键到底发哪一级? #18003) ships a pre-GA metadata-facing retirement as minor with the banner and its disposition entry; check-changeset-no-major (Check Changeset, success) refuses major in the launch window. Only @objectstack/spec publishes from this diff (src/**/*.zod.ts, liveness/, dist; content/docs is the docs site, not a package), so a single bump is correct. The tombstone's 17.5.0 is the next minor on the 17.4.0 line and matches the sibling spelling.
  • Clause-②: yes — declared identically in the PR body, the changeset and both claims. The arm is omitted, which the rule permits (at most one arm), and the BREAKING banner carries the breaking signal the registration gate reads. It is an accept-set narrowing, correctly declared, tombstoned and registered.

③ Boundary flags

Dev deviations (seven), each answered:

  1. Worktree created from the branch (dispatch-ordered RESUME), no empty-branch push — process; the six hand-over commits were re-read and corrected in 68b038ef; the net diff is what is judged. Answered.
  2. Two main merges through os-regen-merge.sh with deferred regenerations — the net three-dot diff is clean (19 files; the conversion, the D3 entry and the retired key each appear exactly once in their registries); the head's check-runs are green. Answered.
  3. liveness/README.md, one sentence outside the claim's surface — RIGHT to take: liveness is in @objectstack/spec files[], the row said the dead set was three, which this change made false, and the retirement playbook's ledger step names the README row; the PR body names the fix with evidence, as the os-dev in-place rule requires. The rule's second obligation — amending the claim's declared file surface in the same round — is not on the card (no amended claim comment). Escalated to the seat as an owed one-line claim amendment; not a diff defect.
  4. Consumer suites and spec typecheck measured at 8dd3a2ce, not the head — superseded by the check-runs on 7faf0e9f (Test Core 6/6, Type Check x4, Build Core, Dogfood, Temporal). Answered.
  5. One locked run cut by a timeout and a stray vitest child killed by PID — process hygiene with no diff content; the re-run was under the lock, and the head's check-runs are the verdict. Answered.
  6. Commit trailers follow AGENTS.md's model-free pair — verified on all eleven authored commits; the hand-over merge 8cbcfa46 carries no trailer (a merge commit; the pre-push hook accepted the push). Answered.
  7. Refusal pin asserts the Zod issue kind and message head rather than an ADR-0112 code plus status — RIGHT: ADR-0112 governs the API error envelope; a retiredKey() refusal is a Zod parse issue with no HTTP status, as the family docblock (aria-carrier-tombstones.test.ts:36-38) records; the invalid_type-at-aria-with-no-root-unrecognized_keys assertion is the correct anti-vacuity shape. Answered.

open_questions: none declared; none found.

Out-of-scope findings (two), correctly carried and not folded: objectui ActionDefaultInspector RETIRED_FIELDS plus the ActionRunner mirror (the seat's sub-issue after landing, per triage note 3); #19332's waiting item receives the disposition (the seat's write after landing). Add the advisory residual above to the same follow-up.

Console Pin Gate skipped (path filter) and Packed-tarball smoke skipped (opt-in) are by design, not gaps in this head's verdict.

Implemented-by: claude/issue-20323-retire-action-aria
Reviewed-by: session_01ARcDurZ5j34RdqsGgc4jgH

VERDICT: PASS


Generated by Claude Code

os-warren pushed a commit that referenced this pull request Sep 28, 2026
Landing lap: origin/main dcd3bce, 6 commits past 15bf186. #20398
(`dcd3bcea`) appended `action-aria-removed` to the same three step-18
tails this branch appends `flow-decision-mode-inclusive-explicit` to.
Resolved per the seat's answer B on #15429 (5865957805), and nowhere else:

- `CONVERSIONS_BY_MAJOR[18]` and step18 `conversionIds`: both kept,
  main's `actionAriaRemoved` / `action-aria-removed` first (landing
  order), this branch's entry after it;
- step18 `rationale`: main's sentence kept, this branch's sentence
  appended verbatim (the one string join: main's closing literal now
  ends in a space and the concatenation continues).

No other hand edit; generated regions are regenerated in the next commit.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
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 protocol:ui size/l tests tooling

Projects

None yet

2 participants