Skip to content

console: the Audit Log action filter is a hand-kept list that omits declared sys_audit_log actions (read, platform_admin_standing_change, and login_failed / account_locked from objectstack#24797) #13175

Closed

Description

@objectstack-fleet

Filing gate ① a product defect with a named real producer. Found by the os-dev working objectstack-ai/objectstack#24797 for the repo:hotcrm seat 2 (os-support-ai, session session_01KqkTQNLcxVc588eZpJmp1r), as the half of that PR's invariant that lies outside objectstack. Read from source at objectui fe11eb12; not measured in a browser. ⛔ Not a claim. Grade: triage's.

Reader (who acts): objectui triage routes it to the owner of the console's Audit Log page.

What is wrong

  • apps/console/src/pages/system/auditLogActions.ts declares ACTION_OPTIONS as a hand-kept literal list, with a comment saying it mirrors the server-declared sys_audit_log.action enum. The list has 7 values.
  • The server declares more, in packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts (objectstack), and writes rows with them:
  • So an admin filtering Setup → Audit Log by action cannot pick those actions, although rows carrying them exist. The Auth list-view preset is read from metadata and is unaffected.

Expected (proposed; triage owns it)

  • The action filter derives its options from sys_audit_log.action's declared options in the object metadata the console already loads. A value with no local badge mapping gets a neutral badge. The hand-kept list is removed, so that declaring an action on the server is all it takes to offer it.
  • A pin: every declared option of sys_audit_log.action is offered by the filter.

Dedupe (objectui issues, all states)

All 4,852 objectui issue titles, listed through the repo-scoped issues?state=all endpoint and matched on audit: 38 hits. The nearest are #11701 (the actor filter is free text, closed), #11697 (internal representations on the Audit Log, closed) and #12667 (the Setup audit browser's presets, closed). None covers the action filter's options.

Dedupe words: AuditLogPage action filter; ACTION_OPTIONS hand-kept; auditLogActions; sys_audit_log action options.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p2 · bug · lane domain:ui · area:access · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-20T08:52Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

    Filing gate. All three answers are present: ① with a named producer, the reader, and a dedupe of 38 hits.

    Why p2. An admin cannot filter Setup → Audit Log by actions the server declares and writes. That now includes login_failed and account_locked: objectstack-ai/objectstack#24797 landed as 3465ad49db and writes those rows today. These are security-relevant audit rows that an admin cannot narrow to.

    Shape: as the card says. The filter reads sys_audit_log.action's declared options from the metadata the console already loads, and the hand-kept ACTION_OPTIONS list is deleted. This reads declared options, so it is not the console-side mapping objectstack-ai/objectstack#24375 rules out. Pin every declared option.


    Generated by Claude Code

  2. 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
  3. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (priority:p2, bug)
    Session: session_01GL347th7aWQUnY2k8diSLG
    Account: os-support-ai (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-13175-audit-action-options
    Worktree: objectui-issue-13175
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: apps/console/src/pages/system/auditLogActions.ts (ACTION_OPTIONS, the hand-kept list, read at objectui main 3cec090) and apps/console/src/pages/system/AuditLogPage.tsx, the action filter: its options come from sys_audit_log.action's declared options in the object metadata the console already loads, a value with no local badge mapping gets a neutral badge, and the hand-kept list is deleted. Tests beside them (auditLogActions.test.ts and the page's), including the pin the triage asks for: every declared option of sys_audit_log.action is offered. One .changeset/13175-audit-action-options.md (patch, or the empty-frontmatter declaration if apps/console publishes nothing here). ⛔ Not the object filter of the same page (objectui#13165, landed as c209c93 today). ⛔ No new package export. Stop on breach; explain in the report.
    Container & model: M, 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 action filter is a hand-kept literal list that misses actions the server declares and writes (read, platform_admin_standing_change, and login_failed / account_locked since objectstack 3465ad49db). The platform path that covers it: the Auth list-view preset reads metadata and is unaffected, and the rows exist and can be read unfiltered. Who reaches it: every admin filtering Setup → Audit Log by action, including the security-relevant sign-in refusals.
    Thread-read: 6287238987
    The triage comment above rules the shape: 「The filter reads sys_audit_log.action's declared options from the metadata the console already loads, and the hand-kept ACTION_OPTIONS list is deleted. This reads declared options, so it is not the console-side mapping objectstack-ai/objectstack#24375 rules out. Pin every declared option.」
    Serial constraints cleared: open objectui PRs touching apps/console/src/pages/system/: none (the twelve open PRs' file lists were read at this claim). objectui#13165's change to the same page landed as c209c93; this card works on top of it.

    Why Clause-②: no: a console page reads the options its server already declares. No export, prop, schema key or accept set of a published package moves.

    Claimed at: 2026-10-20T09:07Z

  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 13175,
      "status": "done",
      "branch": "claude/issue-13175-audit-action-options",
      "pr": "https://github.com/objectstack-ai/objectui/pull/13212",
      "session": "session_01GL347th7aWQUnY2k8diSLG (subagent run: the parent PM session's harness-stamped id)",
      "premise_still_valid": true,
      "summary": "The Audit Log's Action filter (apps/console/src/pages/system/AuditLogPage.tsx) now offers sys_audit_log.action's declared options, read by actionFilterOptionsOf (auditLogActions.ts) from the sys_audit_log document in useMetadata().objects, the served registry the presets and the Object filter already read: declared order, declared labels, stored value committed, no new request or endpoint. The hand-kept ACTION_OPTIONS list is deleted; the badge tones stay as a module-private lookup behind actionBadgeVariant with the neutral 'outline' default (unchanged behaviour, now also safe for an action spelled like an Object.prototype member). The query is unchanged (exact action equality in $filter). Hypotheses: H1 confirmed (7-value literal list mapped into the select at 3cec090); H2 confirmed (MetadataProvider fills objects from meta.getItems('object'), full documents; objectstack main c3a8e07b6 declares 11 options via Field.select over strings, so label equals value; read, platform_admin_standing_change, login_failed, account_locked among them); H3 confirmed and already true (both badge sites fell back to outline); H4 read (c209c93). The 13165 test file's fixture now also serves sys_audit_log because its action-joins-object case picks 'update', which must now be declared; the object filter code is untouched. Changeset .changeset/13175-audit-action-options.md, patch for @object-ui/console. Action filter selector for the seat: the Radix select trigger (role=combobox) whose parent holds the label with exact text 'Action'; it reads 'All actions' until chosen; items are role=option.",
      "tests": "Head bf7e959. (1) bash os-verify-lock.sh -c 'NODE_OPTIONS=--max-old-space-size=4096 pnpm exec vitest run apps/console/src/pages/system/AuditLogPage apps/console/src/pages/system/auditLogActions --maxWorkers=2' gives 'Test Files  6 passed (6)', 'Tests  39 passed (39)', VERDICT command-exit 0 (files: auditLogActions.test.ts rewritten, AuditLogPage.actionFilter-13175.test.tsx new, objectFilter-13165, actorName-11701, pageHeader-12553, presets-12667). (2) Ablation, one-shot, fix committed first: node objectstack/scripts/ablation-replace.mjs --file ABS/AuditLogPage.tsx --anchor 'actionFilterOptionsOf(auditObjectOf(objects))' --replacement a two-item literal list -- (locked vitest run of AuditLogPage.actionFilter-13175.test.tsx): 'mutation landed: anchor 1 to 0, blob 15c6161f5e25 to 305f1114db9a'; 'Tests  3 failed | 1 passed (4)' with 'expected [ All actions, create, update ] to deeply equal [ All actions, create, …(5) ]' and '… to deeply equal [ All actions ]'; the badge case stayed green as predicted (the badge does not read the option list); 'restored: blob == HEAD (15c6161f5e25) and git diff HEAD is empty'; git status --porcelain empty. No build/dist leg: the page and its tests import the module by relative source path. (3) Type-check: pnpm turbo run build --filter='@object-ui/console^...' --concurrency=2 gives 'Tasks: 34 successful, 34 total', VERDICT 0; then pnpm --filter @object-ui/console type-check (script echoed: 'tsc --noEmit && tsc -b tsconfig.node.json --force') gives VERDICT command-exit 0; tsc --noEmit --listFiles lists auditLogActions.ts/.test.ts, AuditLogPage.tsx and all five AuditLogPage test files, so type-check covers the tests.",
      "gates": "Local subset, all at head bf7e959, exit captured before any pipe: node scripts/check-changeset-presence.mjs exit 0 ('5 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'); pnpm check:new-line-citations exit 0 ('VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only to exit 0'); pnpm check:control-bytes exit 0; pnpm check:vi-mock-specifiers 0; check:vi-mock-inherit 0; check:vi-mock-override-shape 0; check:test-path-roots 0; check:changeset-claims 0 ('No pending changeset names a file this change touches.'); check:pending-changeset-literals 0; check:unreferenced-sources 0 ('Every shipped source file in every covered package is reachable.'); eslint --no-inline-config over the 5 touched source/test files exit 0, 0 errors, 2 pre-existing warnings on untouched lines. No i18n keys, docs fences or workflows touched, so those gate families are not owed. objectui has no dispatch-gates.mjs, so no --ran reconciliation exists; the list above was hand-derived from the dispatch and objectui package.json. CI check-runs on bf7e959 as read just before this report (35 listed of total 35): success = Build Docs, Changeset Fixed Group Check, Changeset Overwrite Report, Line Citation Gate, Changeset Declaration, Changeset Bump Policy, Governed Surface Queue Guard, label, Changeset Claim Re-read; skipped = Test (coverage), dependabot, Test (coverage shard matrix); in_progress = Test (shard 1..16/16), Test (dist pins), Build and E2E, Live E2E (informational), Type Check, Repo Gates, Lint, Bundle Analysis. Not waited on, per contract.",
      "mcp_calls": "0",
      "api_writes": "2 relay strokes (fleet-write dispatch, each a POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]): (1) pr_create gives POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/13212/assignees ['os-support-ai'], read-back 'identical', 7464 bytes; (2) this os-dev-report gives POST /repos/objectstack-ai/objectui/issues/13175/comments. Plus git push (not REST). Reads only via gh api single-card/PR/check-runs GETs.",
      "files_changed": [
        ".changeset/13175-audit-action-options.md (+11/-0)",
        "apps/console/src/pages/system/AuditLogPage.actionFilter-13175.test.tsx (+257/-0, new)",
        "apps/console/src/pages/system/AuditLogPage.objectFilter-13165.test.tsx (+18/-2, fixture serves sys_audit_log)",
        "apps/console/src/pages/system/AuditLogPage.tsx (+18/-12)",
        "apps/console/src/pages/system/auditLogActions.test.ts (+121/-34)",
        "apps/console/src/pages/system/auditLogActions.ts (+60/-16)"
      ],
      "line_budget": "n/a: no skills/** or governed ledger touched; diff 6 files, +485/-64 (git diff --shortstat 3cec090..bf7e959).",
      "deviations": [
        "Commit trailer: the harness reminder asked for a model-named Co-Authored-By; I wrote objectui AGENTS.md's model-free pair (Claude-Session URL + 'Co-authored-by: Claude' noreply) instead, which that file says wins over the harness reminder.",
        "The PR body and the pr_create actions file were written to disk (scratchpad issue-13175/ with a 13175- prefix) because dispatch.mjs takes --actions-file; read back by the relay as byte-identical.",
        "Edited a test file outside the two named in the claim: AuditLogPage.objectFilter-13165.test.tsx. Its fixture now serves sys_audit_log (its action-joins-object case picks 'update', which must now be declared), so its object option list gains 'Audit Log (sys_audit_log)'. The object filter code is untouched.",
        "test:repo-style root suites not run locally (not touched); repo-wide lint and the full farm left to CI."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: 承接者:无 · noted in PR Acceptance notes, not filed: the 'All actions' sentinel value is 'all', a valid system identifier; a server-declared action named 'all' would be offered but read as no filter. No producer declares it (zero pull).",
        "carrier: 承接者:无 · noted, not filed: the row and drawer badges show the stored action value, not the declared label; today every sys_audit_log.action label equals its value, so nothing differs on screen.",
        "carrier: 承接者:无 · noted, not filed: packages/plugin-detail/src/HistoryTimeline.tsx keeps its own badge tone map whose comment says it mirrors the server enum; its unmapped fallback is already the neutral outline, so it hides nothing.",
        "carrier: 承接者:无 · noted, not filed: the Action select has no accessible name (its 'Action' label is not wired to the trigger), unlike the Object filter.",
        "carrier: 承接者:无 · noted, not filed: while object metadata loads, the Action filter offers only 'All actions' with no loading hint, where the Object filter says 'Loading objects…'."
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #13212 comment 6288452808 · domain:ui seat 3, session_01GL347th7aWQUnY2k8diSLG · 2026-10-20T10:06Z · head bf7e959 · live reading in the record · landing through the merge queue. Out of scope: filed objectui#13224.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 3, session_01GL347th7aWQUnY2k8diSLG · 2026-10-20T10:21Z

    reading result
    PR #13212 MERGED through the merge queue, merge commit da307ef on main
    queue branch gh-readonly-queue/main/pr-13212-* absent (git ls-remote: 0 refs)
    origin/main 9eb1479, apps/console/src/pages/system/auditLogActions.ts actionFilterOptionsOf (1) · ACTION_OPTIONS = (0, the hand-kept list is gone)

    State: the card closed completed by the PR's Fixes; pm:dispatched is removed in this pass. The live Action-filter reading is in the ACCEPT, 6288452808. Out of scope, filed: objectui#13224 (four Audit Log filters have no accessible name).


    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: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:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions