You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Audit Log filters have no accessible name: the visible Action, Actor, From and To labels are not tied to their controls #13224
Filing gate ① a user-visible defect with a named landing point and a reproduction. Found by the os-dev working objectui#13175 for the domain:ui seat 3 (session_01GL347th7aWQUnY2k8diSLG), outside that card's scope; the seat measured the whole family. ⛔ Not a claim. Grade and lane: triage's.
Reader who acts: objectui triage routes it; the suspected landing is the domain:ui lane owning apps/console/src/pages/system/AuditLogPage.tsx (the filter row).
Measured
reach: Setup → Audit Log (/system/audit-log), shipped to every admin.
Actual: in the filter row, four of the five filters draw a bare <Label> with no htmlFor and no aria-labelledby on the control: Action (a Select trigger), Actor (a LookupField), From and To (<Input type="date">). Code read at objectui 7084cff, AuditLogPage.tsx lines 475, 504, 521 and 525; the Object filter's label (line 487) is wired with htmlFor={objectFilterId}. Live on that tree (Chromium, the console against an objectstack 9d13b5fc8 backend): getByLabel(name, { exact: true }) counts Action 0, Object 1, Actor 0, From 0, To 0.
Expected: each filter control is named by its visible label, as the Object filter already is.
Who reaches it: every screen-reader and voice-control user of the Audit Log; the four controls announce as an unnamed combobox, lookup and two date fields.
Family pin (all locations): the Action, Actor, From and To controls of AuditLogPage.tsx's filter row. The open fix for objectui#13175 (objectui#13212) changes the Action select's options, not its label wiring; it does not cover this.
Dedupe
Semantic search_issues on objectstack-ai/objectui, closed included, "Audit Log page filter labels not associated with controls accessible name Action Actor date": 5 hits (objectui#13175, objectui#11701, objectui#13165, objectui#11697, objectui#4476). None covers the labels' wiring.
Claim: PM loop round 3 (priority:p3, bug)
Session: session_014MXhk1yjWh37d634hLy3p7
Account: huangyiirene (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-13224-audit-filter-labels
Worktree: objectui-issue-13224
Domain: domain:ui
Seat: domain:ui#1
File surface: apps/console/src/pages/system/AuditLogPage.tsx, the filter row, read at objectui mainab4e4d7. The Action (:475), Actor (:504), From (:521) and To (:525) labels are bare <Label>s with no htmlFor and no aria-labelledby on their controls, while Object (:487) is wired with htmlFor={objectFilterId}. Also tests beside it, and a changeset only if objectui's changeset gates ask for one. Not the filters' options or query (objectui#13212 landed the Action options; objectui#13229 is changing the shared Combobox). Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui over this surface reads no path-derived mandate)
Clause-②: no
Responsibility: the risk is produced by objectui's own Audit Log page, whose four filter labels name nothing, so assistive tech announces unnamed controls; the platform path that covers it: none; who reaches it: every screen-reader and voice-control admin on Setup › Audit Log.
Thread-read: none
The card had no comment at this claim.
Serial constraints cleared: objectui#13212 (another seat, the same file) has merged; no open objectui PR and no in-flight claim touches AuditLogPage.tsx. This seat's objectui#13229 changes packages/components/src/custom/combobox.tsx, which this page uses but this claim does not edit.
Why Clause-②: no: apps/console is the console app, not a published package, so no export, prop or accept set moves.
{
"issue": 13224,
"status": "done",
"branch": "claude/issue-13224-audit-filter-labels",
"pr": "https://github.com/objectstack-ai/objectui/pull/13256",
"session": "session_014MXhk1yjWh37d634hLy3p7 — subagent = parent's (the PM seat's) session id",
"premise_still_valid": true,
"summary": "Premise held at origin/main 878a4af38: in AuditLogPage.tsx's filter row the Action, Actor, From and To labels were bare Labels over controls with no id or aria-labelledby; only Object was wired (htmlFor={objectFilterId}). Each label now names its own control through useId + htmlFor + the control's id, exactly as the Object filter does. H1 measured per control: the Radix SelectTrigger spreads id onto its trigger button, and Radix sets no aria-labelledby on the trigger. LookupField forwards id ('id' is in DOM_PASS_THROUGH_KEYS, applied by toDomProps) onto the trigger Button that both of its render paths mount, but does not forward aria-labelledby. Input spreads id. H2: the id route works for all four, so no aria-labelledby was needed and @object-ui/fields is untouched (no published prop). H3: options, query and row markup/classes are unchanged, and the five existing AuditLogPage suites stay green; layout was not browser-measured. H4: the new pin goes red with the fix reverted. PR #13256 is draft, base main, first line the closing keyword on this card, with the 'Clause-②: no' line copied and assignee huangyiirene. Changeset .changeset/13224-audit-filter-labels.md (@object-ui/console patch), added because check-changeset-presence asked for one. Per the PM's 12:10Z message, both relay writes used the default write budget (no OS_PM_WRITE_HOURLY_MAX prefix). Worktree /home/user/objectui-issue-13224 removed after the PR opened (node_modules first, no --force).",
"tests": "New apps/console/src/pages/system/AuditLogPage.filterLabels-13224.test.tsx, 3 tests. (1) For each of Action, Object, Actor, From and To, queryAllByLabelText(label, {exact:true}) has length 1, and the element is that filter's own control: Action/Object are role=combobox reading 'All actions'/'Any object', Actor is getByTestId('lookup-trigger-user_id'), From/To are type=date, 5 distinct; getByRole combobox Action/Object and button Actor resolve to the same elements. (2) The Action control found by its label sends {action:'update'}. (3) The From/To fields found by their labels send created_at $gte/$lte as before. Final run at HEAD a00e6154f, clean tree, under os-verify-lock: 'pnpm exec vitest run --maxWorkers=2 apps/console/src/pages/system/AuditLogPage apps/console/src/pages/system/auditLogActions.test.ts' to 'Test Files 7 passed (7)', 'Tests 42 passed (42)' (5 existing AuditLogPage suites + new + auditLogActions). The lock printed 'VERDICT batch-last-exit 0' because a git-status probe in the && chain was piped; vitest was the last command and its summary is quoted. ABLATION, fix committed first (5bf9258e4): objectstack scripts/ablation-replace.mjs, wrap mode, inside the lock, replaced the HEAD filter-row region with its 878a4af38 text: 'anchor hits 1 time(s), as declared', 'ok mutation landed: anchor 1 to 0, blob 3d71fbd1744b to 3f69af83817c'. New suite: 'Tests 3 failed (3)' with 'the \"Action\" label names exactly one control: expected [] to have a length of 1 but got +0' (the date test on the From label). Restore: 'ok restored: blob == HEAD (3d71fbd1744b) and `git diff HEAD` is empty'; post-restore grep -c of htmlFor={actionFilterId} = 1. Direction observed: red, as predicted. No dist build was needed for the ablation: the suite imports ./AuditLogPage from source.",
"gates": "Hand-derived (dispatch-gates.mjs refuses objectui); exit codes captured before any pipe; all local runs at a00e6154f. Under the lock: turbo build of '@object-ui/console^...' (34/34 successful, 14 cached; needed because console type-check reads @object-ui/* dist). 'pnpm --filter @object-ui/console lint' exit 0: 0 errors, 220 warnings, 2 of them in AuditLogPage.tsx on lines this diff does not touch (no-explicit-any in the load path, set-state-in-effect on the effect calling load()). 'pnpm --filter @object-ui/console type-check' exit 0; 'tsc --noEmit --listFiles' in apps/console counts the new test file once. Unlocked: check-changeset-presence exit 0 ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'); check-changeset-no-major exit 0; check:new-line-citations exit 0 ('VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only to exit 0'); check:control-bytes exit 0. Families read on the new test file, the changeset and the page, each exit 0: check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots, check:changeset-claims, check:pending-changeset-literals, check:i18n-keys, check:shell-escape-residue, check:unreferenced-sources, check:handler-key-reads. check-governed-queue-guard --test over the 3 paths: NOT GOVERNED. No --ran reconciliation (objectui has no dispatch-gates). test:repo-style full shards and the check:* farm are declared to CI. CI on PR #13256 head a00e6154f at 12:42Z: total_count 35 = array 35; 3 success (Changeset Fixed Group Check, label, Changeset Bump Policy), 3 skipped, 29 in_progress. Status in_progress; not waited on per contract.",
"mcp_calls": "0",
"api_writes": "2 — relay strokes via scripts/pm/fleet-write/dispatch.mjs (each one POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create, executed as POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/13256/assignees, read-back 5358 bytes sent = stored, assignee huangyiirene; (2) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/13224/comments. Not REST writes: 3 git pushes of the branch (empty probe, fix 5bf9258e4, changeset a00e6154f).",
"open_questions": [],
"out_of_scope_findings": []
}
#13256 merged through the merge queue at 2026-10-20T13:06Z. The squash commit 039e0b9 has one parent (e077b8a), and git merge-base --is-ancestor places it on origin/main (exit 0)
queue
no gh-readonly-queue/main/pr-13256-* branch remains
landed content
on origin/main, AuditLogPage.tsx wires htmlFor={actionFilterId}, {actorFilterId}, {fromDateId} and {toDateId} (1 each). Positive control: the Object filter's htmlFor={objectFilterId} is kept (1)
records
claim 6289713449, dev report 6291115408 on this card, ACCEPT 6291137243 on PR #13256 (no contract-review face hit)
closing
closed completed at 2026-10-20T13:06Z through the PR's Fixes #13224; pm:dispatched is removed in this act
Each Audit Log filter control is named by its visible label (Action, Object, Actor, From, To), so assistive tech announces it by name. The query and the layout are unchanged.
Activity
objectstack-fleet commentedon Oct 20, 2026
Claim: PM loop round 3 (
priority:p3,bug)Session:
session_014MXhk1yjWh37d634hLy3p7Account:
huangyiirene(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13224-audit-filter-labelsWorktree:
objectui-issue-13224Domain:
domain:uiSeat:
domain:ui#1File surface:
apps/console/src/pages/system/AuditLogPage.tsx, the filter row, read at objectuimainab4e4d7. The Action (:475), Actor (:504), From (:521) and To (:525) labels are bare<Label>s with nohtmlForand noaria-labelledbyon their controls, while Object (:487) is wired withhtmlFor={objectFilterId}. Also tests beside it, and a changeset only if objectui's changeset gates ask for one. Not the filters' options or query (objectui#13212 landed the Action options; objectui#13229 is changing the sharedCombobox). Stop on breach; explain in the report.Container & model:
S,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuiover this surface reads no path-derived mandate)Clause-②: no
Responsibility: the risk is produced by objectui's own Audit Log page, whose four filter labels name nothing, so assistive tech announces unnamed controls; the platform path that covers it: none; who reaches it: every screen-reader and voice-control admin on Setup › Audit Log.
Thread-read: none
The card had no comment at this claim.
Serial constraints cleared: objectui#13212 (another seat, the same file) has merged; no open objectui PR and no in-flight claim touches
AuditLogPage.tsx. This seat's objectui#13229 changespackages/components/src/custom/combobox.tsx, which this page uses but this claim does not edit.Why
Clause-②: no:apps/consoleis the console app, not a published package, so no export, prop or accept set moves.Claimed at: 2026-10-20T11:21Z
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{ "issue": 13224, "status": "done", "branch": "claude/issue-13224-audit-filter-labels", "pr": "https://github.com/objectstack-ai/objectui/pull/13256", "session": "session_014MXhk1yjWh37d634hLy3p7 — subagent = parent's (the PM seat's) session id", "premise_still_valid": true, "summary": "Premise held at origin/main 878a4af38: in AuditLogPage.tsx's filter row the Action, Actor, From and To labels were bare Labels over controls with no id or aria-labelledby; only Object was wired (htmlFor={objectFilterId}). Each label now names its own control through useId + htmlFor + the control's id, exactly as the Object filter does. H1 measured per control: the Radix SelectTrigger spreads id onto its trigger button, and Radix sets no aria-labelledby on the trigger. LookupField forwards id ('id' is in DOM_PASS_THROUGH_KEYS, applied by toDomProps) onto the trigger Button that both of its render paths mount, but does not forward aria-labelledby. Input spreads id. H2: the id route works for all four, so no aria-labelledby was needed and @object-ui/fields is untouched (no published prop). H3: options, query and row markup/classes are unchanged, and the five existing AuditLogPage suites stay green; layout was not browser-measured. H4: the new pin goes red with the fix reverted. PR #13256 is draft, base main, first line the closing keyword on this card, with the 'Clause-②: no' line copied and assignee huangyiirene. Changeset .changeset/13224-audit-filter-labels.md (@object-ui/console patch), added because check-changeset-presence asked for one. Per the PM's 12:10Z message, both relay writes used the default write budget (no OS_PM_WRITE_HOURLY_MAX prefix). Worktree /home/user/objectui-issue-13224 removed after the PR opened (node_modules first, no --force).", "tests": "New apps/console/src/pages/system/AuditLogPage.filterLabels-13224.test.tsx, 3 tests. (1) For each of Action, Object, Actor, From and To, queryAllByLabelText(label, {exact:true}) has length 1, and the element is that filter's own control: Action/Object are role=combobox reading 'All actions'/'Any object', Actor is getByTestId('lookup-trigger-user_id'), From/To are type=date, 5 distinct; getByRole combobox Action/Object and button Actor resolve to the same elements. (2) The Action control found by its label sends {action:'update'}. (3) The From/To fields found by their labels send created_at $gte/$lte as before. Final run at HEAD a00e6154f, clean tree, under os-verify-lock: 'pnpm exec vitest run --maxWorkers=2 apps/console/src/pages/system/AuditLogPage apps/console/src/pages/system/auditLogActions.test.ts' to 'Test Files 7 passed (7)', 'Tests 42 passed (42)' (5 existing AuditLogPage suites + new + auditLogActions). The lock printed 'VERDICT batch-last-exit 0' because a git-status probe in the && chain was piped; vitest was the last command and its summary is quoted. ABLATION, fix committed first (5bf9258e4): objectstack scripts/ablation-replace.mjs, wrap mode, inside the lock, replaced the HEAD filter-row region with its 878a4af38 text: 'anchor hits 1 time(s), as declared', 'ok mutation landed: anchor 1 to 0, blob 3d71fbd1744b to 3f69af83817c'. New suite: 'Tests 3 failed (3)' with 'the \"Action\" label names exactly one control: expected [] to have a length of 1 but got +0' (the date test on the From label). Restore: 'ok restored: blob == HEAD (3d71fbd1744b) and `git diff HEAD` is empty'; post-restore grep -c of htmlFor={actionFilterId} = 1. Direction observed: red, as predicted. No dist build was needed for the ablation: the suite imports ./AuditLogPage from source.", "gates": "Hand-derived (dispatch-gates.mjs refuses objectui); exit codes captured before any pipe; all local runs at a00e6154f. Under the lock: turbo build of '@object-ui/console^...' (34/34 successful, 14 cached; needed because console type-check reads @object-ui/* dist). 'pnpm --filter @object-ui/console lint' exit 0: 0 errors, 220 warnings, 2 of them in AuditLogPage.tsx on lines this diff does not touch (no-explicit-any in the load path, set-state-in-effect on the effect calling load()). 'pnpm --filter @object-ui/console type-check' exit 0; 'tsc --noEmit --listFiles' in apps/console counts the new test file once. Unlocked: check-changeset-presence exit 0 ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'); check-changeset-no-major exit 0; check:new-line-citations exit 0 ('VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only to exit 0'); check:control-bytes exit 0. Families read on the new test file, the changeset and the page, each exit 0: check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots, check:changeset-claims, check:pending-changeset-literals, check:i18n-keys, check:shell-escape-residue, check:unreferenced-sources, check:handler-key-reads. check-governed-queue-guard --test over the 3 paths: NOT GOVERNED. No --ran reconciliation (objectui has no dispatch-gates). test:repo-style full shards and the check:* farm are declared to CI. CI on PR #13256 head a00e6154f at 12:42Z: total_count 35 = array 35; 3 success (Changeset Fixed Group Check, label, Changeset Bump Policy), 3 skipped, 29 in_progress. Status in_progress; not waited on per contract.", "mcp_calls": "0", "api_writes": "2 — relay strokes via scripts/pm/fleet-write/dispatch.mjs (each one POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create, executed as POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/13256/assignees, read-back 5358 bytes sent = stored, assignee huangyiirene; (2) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/13224/comments. Not REST writes: 3 git pushes of the branch (empty probe, fix 5bf9258e4, changeset a00e6154f).", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
LANDED ·
domain:uiseat 1 ·session_014MXhk1yjWh37d634hLy3p7· 2026-10-20T13:06Z ·pm:dispatchedcleared039e0b9has one parent (e077b8a), andgit merge-base --is-ancestorplaces it onorigin/main(exit 0)gh-readonly-queue/main/pr-13256-*branch remainsorigin/main,AuditLogPage.tsxwireshtmlFor={actionFilterId},{actorFilterId},{fromDateId}and{toDateId}(1 each). Positive control: the Object filter'shtmlFor={objectFilterId}is kept (1)6289713449, dev report6291115408on this card, ACCEPT6291137243on PR #13256 (no contract-review face hit)completedat 2026-10-20T13:06Z through the PR'sFixes #13224;pm:dispatchedis removed in this actEach Audit Log filter control is named by its visible label (Action, Object, Actor, From, To), so assistive tech announces it by name. The query and the layout are unchanged.
fix(console): Audit Log filter labels name their controls (objectui#1…