Repository navigation
fix(plugin-detail): name the actor of an activity row that carries only actor_id (objectui#12067) - #12070
Merged
Conversation
…ly actor_id (objectui#12067) On @objectstack/* 17.7.0 the audit writer fills sys_activity.actor_id and never actor_name, so record:history read every such entry as "Unknown user" and the activity feed (record:activity, and the console record page's merged feed) read it as "System". The three sys_activity reads now pass $expand: ['actor_id'], so the engine batch-loads the page's sys_user rows in the same request. One reader, activityActorName, names the actor: the actor_name snapshot when present, else the expanded actor_id's name, else the existing fallback. A bare id (a user the viewer may not read) is never shown. Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #12067
Clause-②: no
Implemented by the os-dev dispatched from seat
domain:ui#3, sessionhttps://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8.What changed
record:history(record-history.tsx): itssys_activityself-fetch now passes$expand: ['actor_id'], and the entry's user comes fromactivityActorName(row)instead ofactor_namealone.recordActivityFeed.ts: a new module-level reader,activityActorName, applies the card's rule. It returns theactor_namesnapshot when that is non-blank. Otherwise it returns the expandedactor_idrecord'sname(sys_user's declared name field). Otherwise it returnsnull, so the caller keeps its existing fallback.activityRowToFeedItemnow uses it in place ofrow.actor_name ?? systemActorLabel.sys_activityreads whose rows go throughactivityRowToFeedItempass the same expand: therecord:activityblock's self-fetch (record-activity.tsx) and the console record page's merged feed (RecordDetailView.tsx, app-shell).content/docs/plugins/plugin-detail.mdx(AGENTS.md Add automated testing infrastructure and CI/CD workflows #2)..changeset/12067-history-actor-id.md:patchfor@object-ui/plugin-detailand@object-ui/app-shell.No export, prop, type or pack key changes.
activityActorNameis not re-exported from the package index. In the builtpackages/plugin-detail/dist/index.d.tsit has 0 hits, against 3 hits for the controlactivityRowToFeedItem.SysActivityRowis unchanged too: the reader readsactor_idthrough its existing index signature.Measurements (the dispatch's three mechanism hypotheses)
sys_activity, and whether the read can expandactor_id: yes, in the same request.dataSource.find('sys_activity', { $filter: { object_name, record_id }, $orderby: { timestamp: 'desc' }, $top }).$expandis a declaredQueryParamsmember (@object-ui/typesdata.ts).ObjectStackAdapter.findsends any$expandtorawFindWithPopulate: oneGET /api/v1/data/sys_activity?populate=actor_id&.... Its filter conversion is the same as the SDK route's:translateFilterToASTcallsconvertFiltersToAST.6befe19c, spec 17.7.0),sys_activity.actor_idisField.lookup('sys_user'). It is the same at@objectstack/plugin-audit@17.0.0, so every 17.x server declares the field and the protocol's expand gate (assertExpandTargetsExist) admits it.expandRelatedRecordsloads the ids of the whole page with ONEfind(sys_user, id in [...])through the engine's own read path (CRUD gate, RLS, FLS). When that read is refused it keeps the bare id, and the parent read still succeeds.$expand=user_id, then readname.sys_userread door: ordinary viewers are not refused, so the stop clause does not fire.member_defaultgrantssys_userallowRead: true, row-scoped bysys_user_self(id == current_user.id) andsys_user_org_members(id in current_user.org_user_ids). The read-only set carries the same twoselectpolicies.recordActivityFeed.ts: the same gap.activityRowToFeedItemthrough two reads: therecord:activityself-fetch, andRecordDetailView's merged feed on the default console record page.actor: row.actor_name ?? systemActorLabelshowed those rows as made by "System", which credits the change to no person. Per the claim, the same rule now applies there.actor_id, so both of those reads now do.Surface beyond the claim's file list (stated, not silent)
The claim names
record-history.tsx,recordActivityFeed.ts(conditional), their tests and the changeset. This PR also touches:record-activity.tsxandRecordDetailView.tsx: one$expand: ['actor_id']line each. Without them, the rule the claim admits intorecordActivityFeed.tswould read an expanded record that never arrives. LeavingRecordDetailViewout would also make the console record page and therecord:activityblock disagree about the same row, a disagreement that file's own comment calls a bug.RecordDetailView.activityActorId-12067.test.tsx(that read's pin) and the docs paragraph.The seat may amend the claim's file surface.
Tests (all at
6b1a3ff64)New pins:
record-history.actorId-12067.test.tsx, the claim's four:actor_idshows the user's name;actor_name;find, onsys_activitywith$expand: ['actor_id'], and nosys_userread.recordActivityFeed.actorId-12067.test.tsx: the same three rules on the mapper, plus therecord:activityself-fetch (one read, expanded, both names shown, no "System").RecordDetailView.activityActorId-12067.test.tsx: the console page'ssys_activityread carries the expand, and the feed shows the user, not "System".Runs:
pnpm exec vitest run packages/plugin-detail/ --maxWorkers=2:Test Files 250 passed | 1 skipped (251),Tests 2433 passed | 8 skipped (2441).RecordDetailView(git grep -l RecordDetailViewover app-shell tests), run in two halves:56 passed (56)/495 passed, and55 passed (55)/394 passed. The full app-shell suite (1245 files) does not fit the foreground cap, so it is CI's.apps/console/src/__tests__/record-block-record-reach.test.tsx:13 passed (13).pnpm --filter @object-ui/plugin-detail type-checkandpnpm --filter @object-ui/app-shell type-check: both exit 0, after building each dependency closure.tsc -p tsconfig.test.json --listFilesOnlylists each new test file.pnpm exec eslinton the 7 touched TS/TSX files: 0 errors and 140 warnings (no-explicit-anyand the like; the repo has no warnings ratchet). This is a narrowed run, and three facts back it:eslint.config.js;--format json;parserOptions.projectorprojectService, and no custom rule ineslint-rules/reads the filesystem, so this diff cannot move a verdict on an untouched file.check:control-bytes,check:test-path-roots,check:changeset-claims,check:pending-changeset-literals,check:new-line-citations(0 new),check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:doc-typesandcheck:doc-fences: all exit 0. So docheck-changeset-presence.mjs(7 source files of 2 released packages, 1 changeset),check-changeset-no-major.mjs,check-changeset-fixed.mjsandcheck-changeset-overwrite.mjs.check-governed-queue-guard.mjs --testreports NOT GOVERNED for all 9 paths.check:doc-snippetsandcheck:doc-examples. Reason: prerequisite. The gate printed "THE GATE COULD NOT RUN" because the packages its examples import are not built. The docs diff adds 0 fenced blocks.Ablations (predictions written before each run)
Each run used
ablation-replace.mjsin wrap mode. Every anchor hit 1 time and went to 0 on disk. Every restore matched the HEAD blob, andgit diff HEADwas empty afterwards.$expand: ['actor_id']fromrecord-history.tsxTests 2 failed | 2 passed (4)user_name: activityActorName(r)back tor.actor_name ?? nullTests 2 failed | 2 passed (4)row.actor_name ?? systemActorLabelTests 4 failed | 1 passed (5)across both filesrecord-activity.tsxTests 1 failed | 3 passed (4)RecordDetailView.tsxTests 1 failed (1)Acceptance notes
$expandroute skips the adapter's missing-resource memo. On a deployment with nosys_activity(no audit plugin), each mount now repeats a 404 read instead of remembering the first one. What the user sees is unchanged: a 404 is not a refusal, so the history and the feed stay empty. Observation only, nothing filed; carrier: none.actor_avatar_urlis still the only avatar source. An id-only row shows initials from the resolved name. This is outside the card's acceptance.actor_name, which still wins. The expand then names only the older rows, at the cost of one batched server-sidesys_userread per page.Generated by Claude Code