Repository navigation
Description
Slice 6 of #788. Depends on #795. It can land in parallel with the screen slices.
Make the audit log show when an assistant took an action, rather than a person typing it.
The shape
ActorUserId and ActorEmail stay the human. That is a requirement, not a style choice. AGENTS.md #500 states that ICurrentUser is "an authorization input, not a label", and FlockScopeGuard reads its roles. The person authorized the action and remains the actor.
What this adds is provenance, the application that acted.
Why first-class columns rather than DetailsJson
AuditEvent already has a DetailsJson column, and using it would be cheaper. It was rejected because:
- Provenance is not a detail. It is who acted, which belongs beside the actor fields.
- It must be filterable. "Show me everything assistants did last month" is the question this exists to answer, and a JSON blob is not indexable for it.
The slice therefore adds two new columns on AuditEvents (application id and display name), a migration, and regenerated docs/schema/ in the same PR (#417).
Care needed
AuditEvents is the table this repo is most careful about. #508 gave it a monotonic Sequence ordering key, and #505 deliberately decided not to time-partition it. Read both before altering it. Adding columns is compatible with each, but the change must not disturb the ordering guarantees.
Surfacing
The existing audit UI should show the application. Today a row shows only the person's name even when an assistant acted, so an Owner reviewing history cannot tell a human typo from an assistant misfiring. This slice closes that gap.
Related
#272 (GDPR). This new dimension inherits the existing ActorEmail tension between erasure and pseudonymisation, because AuditEvent stores immutable snapshots and offers no way to change them.
Done when
An action performed through an assistant records both the human and the application, the audit UI shows it, and a user can filter on it.
Activity
docs(auth): record the OAuth 2.1 decision for MCP authentication (#801)
mforce commentedon Oct 6, 2026
Amendment, 2026-10-06: what #514 changed for this slice
The body above stays as written. Paths were checked against
mainat8cb14e67.IInsightsModule.ListAuditEventsAsync, which returnsAuditEventRead. Add the application id and display name toAuditEventRead, and add the new filter to that contract method. Reading the columns from outside the contract is a CW1004 build error.AuditEventstays inCluckwork.Domain.Auditing, which is Platform, so any module may reference it. The fix(api): order same-instant audit events by a durable monotonic key, not a random Guid #508 and chore(infra): do not partition AuditEvents by time — record why, and what to do instead #505 cautions in the body still apply.docs/designs/822-mui-revamp.md.mforce commentedon Oct 8, 2026
Mockups for selection, 2026-10-08
Refreshed 2026-10-08: every label now says "Connected apps", the maintainer's chosen term. OAuth calls these "clients"; the UI does not.
Design directions for showing app provenance in the audit log, inside the chosen Audit composition. Nothing is chosen yet. The interactive lab and README are on branch
docs/788-oauth-screen-mockups(not pushed yet), indocs/designs/788-oauth-screens/.The agent recommends C: every row shows who acted on a second line, so an Owner can tell a person from a connected app without opening the row.
Audit log provenance
A, desktop 1280 and phone 390
B, desktop 1280 and phone 390
C, desktop 1280 and phone 390
test(api): re-anchor the authorize mutants on the subject claim
feat(web): show which connected app acted in the audit log
chore(web): raise the precache ceiling to 1,920 KiB for the OAuth mil…
chore(web): raise the precache ceiling to 1,920 KiB for the OAuth mil…
Merge origin/main (#800) into feat/798-oauth-consent