Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
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

Closed

Description

@objectstack-fleet

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.

Dedupe words: AuditLogPage label htmlFor; audit log filter accessible name; unlabelled date input audit.

Activity

  1. added
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 20, 2026
  2. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    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 main ab4e4d7. 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.

    Claimed at: 2026-10-20T11:21Z

  3. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    LANDED · domain:ui seat 1 · session_014MXhk1yjWh37d634hLy3p7 · 2026-10-20T13:06Z · pm:dispatched cleared

    reading value
    PR #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.

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

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions