Skip to content

audit log: the actor column shows a truncated raw user id and the actor filter is free text, not a user lookup (split from objectui#11697) #11701

Closed

Description

@objectstack-fleet

Path: ② the capabilities an end user meets in the app — audit log | 缺项 | P2

Split by the triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U from objectui#11697, its audit half. Re-read on objectui main (c3623eb116). ⛔ Not a claim, ⛔ not a dispatch.

Triage: lands in apps/console/src/pages/system/AuditLogPage.tsx (truncate(r.user_id, 18) about :310; the free-text actor filter about :130 and :232) ⇒ domain:ui; rationale: the page shows the stored id where a person is meant to be named.

Done when

  • The audit list shows the actor's name, by populating user_id on the /data/sys_audit_log fetch (or the existing lookup display), with the id still available on hover or copy.
  • The actor filter is a user lookup.
  • Pin: an audited change by the seeded admin shows the admin's name in the actor column, and filtering by that user returns the row.

enhancement · priority:p3 · area:access · pm:queue.


Generated by Claude Code

Activity

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

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01FngvPpdrnhHMdHHq6vwwju
    Account: os-justin
    Branch: claude/issue-11701-audit-actor-name
    Worktree: objectui-issue-11701
    Domain: domain:ui
    Seat: domain:ui#2
    File surface:

    • apps/console/src/pages/system/AuditLogPage.tsx, in these places (as of 0cfe772):
      • the /data/sys_audit_log fetch (about :125–:168);
      • the actor filter (about :112, :130, :232–:238);
      • the actor column (about :310);
      • the drawer's actor row (about :363–:364).
    • A user picker or lookup display the console already ships, only consumed. The dev locates it. ⛔ No new export.
    • The tests beside the page (apps/console/src/pages/system/*.test.ts(x)) and .changeset/11701-*.md.

    Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui over the surface: no path-derived mandate; default tier)
    Clause-②: no
    Thread-read: none
    Ruling-ref: the card body's triage (split from objectui#11697): the list names the actor by populating user_id on the fetch, or by the existing lookup display, with the id still on hover or copy; the actor filter is a user lookup. Retrieved this round.
    Serial constraints cleared: none blocking.

    Read 2026-10-06T16:53Z.

    Why Clause-②: no:

    • The page lives in @object-ui/console, an app. It consumes published pieces and adds no export, prop, schema key or i18n key. Its labels are English literals today, and translating the page is not this card.
    • If the dev measures that a new i18n key or export is unavoidable, it reports the built-declaration delta. The seat then amends this line to yes and runs the at-tier contract review before enqueue.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 11701,
    "status": "done",
    "branch": "claude/issue-11701-audit-actor-name",
    "pr": "#11739",
    "session": "session_01FngvPpdrnhHMdHHq6vwwju",
    "premise_still_valid": true,
    "summary": "The Audit Log page's one /api/v1/data/sys_audit_log read now sends $expand=user_id. At objectstack 1fb274e61c, user_id is Field.lookup('sys_user'), and the engine's expandRelatedRecords batch-loads the users in place of their ids through the full sys_user read gate, keeping the bare id when a user is missing or refused. The actor column shows the name with the id as its title. An unresolved user shows the id, a null user_id reads 'System' with the actor principal on hover, and the drawer shows the name and the full id. The free-text actor box is now LookupField from @object-ui/fields with reference sys_user, already exported, so nothing new is exported. It writes the chosen id to filter.user_id, and removing the chip clears it. UserField was not used because it always adds a banned-not-true candidate filter, which would hide deactivated users from an audit search. No export, prop, type member or i18n key changed (Clause-2: no), and the changeset is '@object-ui/console': patch.",
    "tests": "All heavy runs went through os-verify-lock.sh with slot issue-11701, at HEAD 8e17dbf. (1) pnpm exec vitest run on the new AuditLogPage.actorName-11701.test.tsx and consoleFaces.displayLocale-9909.test.tsx: 'Test Files 2 passed (2) / Tests 19 passed (19)'. (2) pnpm exec vitest run apps/console/ from the repo root: 'Test Files 155 passed (155) / Tests 1806 passed (1806)'. (3) pnpm --workspace-concurrency=2 --filter '@object-ui/console^...' run build: exit 0, 35 packages. (4) pnpm --filter @object-ui/console run type-check (echoed 'tsc --noEmit && tsc -b tsconfig.node.json --force'): exit 0, and tsc --listFilesOnly lists both changed .tsx files. (5) pnpm --filter @object-ui/console run lint: exit 0, '0 errors, 219 warnings'. The 2 warnings on AuditLogPage.tsx (err: any, and the useEffect calling load) are on code already present at base. ABLATION, one leg, prediction written before the run (exactly 2 pins red): HEAD held the fix. node ablation-replace.mjs replaced the anchor in ActorCell's face.name return so it renders truncate(face.id, 18). Evidence: 'anchor x1 to x0', 'replace x0 to x1', 'blob 970a60a9c060 to f13067506aca', 'ok mutation landed'. Result: 'Tests 2 failed | 5 passed (7)'. The two failures were "shows the seeded admin's name in the actor column, with the id on hover" and "choosing the admin sends user_id equal to the admin's id, and lists the admin's row", each reading 'Expected Admin User, Received usr_admin_0001'. Restore: 'blob after restore 970a60a9c060 == blob at HEAD 970a60a9c060, git diff HEAD empty', DIFF_HEAD_BYTES=0, git status empty. The suite imports ./AuditLogPage by relative path, so the subject is src and needs no dist leg. Two earlier lock calls ended in queue-timeout (exit 99), recorded as NOT MEASURED and then re-run to the results above.",
    "mcp_calls": "0 — no MCP GitHub tool was called",
    "api_writes": "3 — (1) pr_create through the fleet relay: POST /repos/objectstack-ai/objectstack/dispatches executed POST /repos/objectstack-ai/objectui/pulls, giving draft #11739, read back byte-identical at 8729 bytes; (2) label-write.mjs --assign os-justin through the relay: POST /repos//issues/11739/assignees, read back as MATCHES, with zero label calls; (3) this os-dev-report comment through post-stamped.mjs: POST /repos//issues/11701/comments. Separately, 4 git pushes (the empty-branch probe and 3 commits), which are not REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted, not filed (Acceptance notes of #11739). When a sys_user lookup dropdown opens, LookupField previews the email column through EmailCellRenderer, whose copy control is a button nested inside the option button. React logs 'button cannot contain a nested button' in this suite's stderr on a failing run. The code is @object-ui/fields LookupField; no test fails, and no public-door measurement was taken, so it is outside classes a, b and c. Dedupe words: LookupField nested button, EmailCellRenderer copy button, lookup option preview email",
    "carrier: objectui#11739 (touches the file) · noted, not filed. AuditLogPage still reads through a raw fetch with credentials 'include' rather than the console adapter that AGENTS.md section 7 asks for. This predates the change, which kept the one fetch and added $expand. Read-only observation. Dedupe words: AuditLogPage raw fetch, audit log adapter, credentials include bearer"
    ],
    "gates": [
    {
    "cmd": "pnpm exec vitest run apps/console/src/pages/system/AuditLogPage.actorName-11701.test.tsx apps/console/src/pages/consoleFaces.displayLocale-9909.test.tsx",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm exec vitest run apps/console/",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm --workspace-concurrency=2 --filter '@object-ui/console^...' run build",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm --filter @object-ui/console run type-check",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm --filter @object-ui/console run lint",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "node ablation-replace.mjs (ActorCell name to raw id) -- vitest run the new suite",
    "exit": 1,
    "head": "8e17dbf",
    "note": "expected red: 2 failed / 5 passed as predicted; restore proven blob == HEAD, git diff HEAD empty"
    },
    {
    "cmd": "node scripts/check-changeset-presence.mjs",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "node scripts/check-changeset-no-major.mjs",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "node scripts/check-changeset-fixed.mjs",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:new-line-citations",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:control-bytes",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:changeset-claims",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:pending-changeset-literals",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "node scripts/check-governed-queue-guard.mjs --test (3 changed paths)",
    "exit": 0,
    "head": "8e17dbf",
    "note": "NOT GOVERNED"
    },
    {
    "cmd": "pnpm check:vi-mock-specifiers",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:vi-mock-inherit",
    "exit": 0,
    "head": "8e17dbf",
    "note": "red at 7569d75/f910b17 on the hand-listed app-shell factory; fixed in 8e17dbf"
    },
    {
    "cmd": "pnpm check:vi-mock-override-shape",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:test-path-roots",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:i18n-keys",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:phantom-deps",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:unused-deps",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:element-data-source-declaration",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:handler-key-reads",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:metadata-write-doors",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:unreferenced-sources",
    "exit": 0,
    "head": "8e17dbf"
    },
    {
    "cmd": "pnpm check:eager-closure",
    "exit": 2,
    "head": "8e17dbf",
    "note": "NOT MEASURED: prerequisite missing (apps/console/dist/eager-closure.json needs a console vite build, not run locally). Both mounts of the page are React lazy dynamic imports. CI owns it."
    }
    ],
    "line_budget": "n/a — no skills/** or line-ratcheted ledger touched. Diff: +333 / -13 across 3 files.",
    "deviations": [
    "Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and an emoji PR footer. I followed AGENTS.md's model-free trailer pair (Claude-Session + Co-authored-by: Claude) and os-dev.md's session-URL PR footer, which take precedence.",
    "Zone 2 assumption 3 named UserField or LookupField. Measured: UserField always appends a banned-not-true filter, so I mounted LookupField with reference sys_user, which matches sys_audit_log.user_id's declared lookup type. Both are already exported, and no new export or prop was added.",
    "Zone 2 assumption 2: I took the $expand path, not a batched sys_user read. The reason is in the summary and the PR body.",
    "Gate list: I ran the whole console package (155 files) instead of only pages/system. Root-level suites are not on the package graph and were not run, and the diff adds no root test or script.",
    "NOT MEASURED: check:eager-closure (prerequisite), a live backend and browser run (the objectstack checkout here is not installed or built), and repo-wide lint and pnpm test (CI's).",
    "No i18n key and no built en.d.ts delta. Clause-2 stays no."
    ],
    "files_changed": [
    {
    "path": ".changeset/11701-audit-actor-name.md",
    "added": 11,
    "removed": 0
    },
    {
    "path": "apps/console/src/pages/system/AuditLogPage.actorName-11701.test.tsx",
    "added": 215,
    "removed": 0
    },
    {
    "path": "apps/console/src/pages/system/AuditLogPage.tsx",
    "added": 107,
    "removed": 13
    }
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR objectui#11739 at 8e17dbf (Fixes #11701). No contract review is owed; it lands when CI is green

    domain:ui execution seat 2 · session_01FngvPpdrnhHMdHHq6vwwju (os-justin) · 2026-10-06T18:01Z. Dev report: os-dev-report on this card. Claim 6021171727.

    • Shape:

      • The PR is a draft on base main (merge-base 22b503c). Its first line is Fixes #11701, and Clause-②: no starts a line.
      • It has 3 files, +333/−13, all inside the claim's surface. git merge-tree against main at 5a2a6ab is clean. NOT GOVERNED. The assignee is os-justin.
      • The commits: 7569d75 (the fix), f910b17 (the changeset), and 8e17dbf. 8e17dbf makes the new suite inherit the real @object-ui/app-shell surface, after check:vi-mock-inherit went red on a hand-listed factory at the first two heads.
    • Measured by the dev at objectstack 1fb274e6:

      • sys_audit_log.user_id is Field.lookup('sys_user').
      • The engine's expandRelatedRecords batch-loads the referenced users through the full sys_user read gate.
      • It keeps the bare id when a user is gone or not readable.

      So $expand=user_id on the page's one read names the actors with no second request. This is the triage's first-named path.

    • Seat's own reading of the diff (AuditLogPage.tsx):

      • actorOf(row) maps the row to one face:
        • an expanded record gives its name and id;
        • a bare string gives the id;
        • a null user_id reads "System", with the actor principal (svc:NAME) on hover.
      • ActorCell shows the name with title set to the id, otherwise the truncated id in monospace, so it never shows a blank.
      • The drawer's ActorDetail shows the name with the full id below it, for copying.
      • The free-text actor box is LookupField from @object-ui/fields, already exported, with reference: 'sys_user' and the console's useAdapter(). The other apps/console pages under the same connected routes read that adapter too. It commits the chosen id to filter.user_id, and removing the chip, or "Clear filters", clears it.
      • UserField was not used, by measurement: it always adds a banned-not-true candidate filter, which would hide deactivated users from an audit search.
    • Clause-②: no, confirmed. @object-ui/console is an app. No export, prop, type member or i18n key is added. The page's labels stay English literals, and the lookup brings its existing translated strings.

    • Changeset (@object-ui/console: patch): the seat checked it sentence by sentence against the diff. It covers the expanded read, the name with the id on hover, the bare id for an unresolved user, "System" with the principal, the drawer row, and the lookup filter with its clear path. patch fits.

    • Tests and gates (dev, measured at 8e17dbf):

      • apps/console/: 155 files, 1806 tests, green, including the new AuditLogPage.actorName-11701.test.tsx.
      • The console closure build (35 packages), type-check and lint: 0 errors.
      • The check:* set, including the three vi-mock gates: all exit 0.
      • One ablation leg (the name face reverted to the raw id) went 2 red / 5 green as predicted, both reading Expected Admin User, Received usr_admin_0001. It was restored by blob.
      • Declared NOT MEASURED: check:eager-closure (a prerequisite was missing; both mounts of the page are lazy imports) and a live backend run. CI owns them.
    • Out-of-scope findings (2), Acceptance notes, not filed:

      • LookupField's option preview nests EmailCellRenderer's copy button inside the option button. It is a React DOM-nesting warning, and no test fails.
      • The page still reads through a raw fetch with credentials: 'include', not the console adapter. This predates the change, which kept the one read.
    • CI on 8e17dbf: in progress at this read (29 success, 3 skipped, 10 running, 0 failed).


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#11739 → main a526249, verified by content. Fixes closed this card

    domain:ui execution seat 2 · session_01FngvPpdrnhHMdHHq6vwwju (os-justin) · 2026-10-06T18:27Z.

    • The merge.

      • Squash a526249 went through the merge queue. It has one parent, 5a2a6ab, and is an ancestor of origin/main.
      • 3 files, +333/−13.
      • The landed tree equals git merge-tree of the parent and the reviewed head 8e17dbf (tree 88a3b795… on both).
      • The changed lines are identical (md5 3cdb6ecf… on both).
    • No contract review was owed: Clause-②: no (ACCEPT 6022351222).

    • Content check against the first parent:

      reading 5a2a6ab a526249
      $expand user_id on the AuditLogPage list read 0 1
      the actor filter's LookupField 0 1
      AuditLogPage.actorName-11701.test.tsx present 0 1
    • Closures. Fixes #11701 closed this card as completed at the merge. No other issue closed in the landing window. pm:dispatched comes off in this stroke.

    • Recorded, not filed:

      • LookupField's option preview nests a copy button inside the option button (a DOM-nesting warning).
      • The page still reads through a raw fetch, not the console adapter. This was already true before the change.

    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 guardsdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions