Skip to content

plugin-audit: an activity summary is rendered once, at write time, in the workspace locale — store it as a key and render it in the reader's language #26167

Closed

Description

@objectstack-fleet

Filing class: ③ maintainer-directed — the maintainer, replying to this suggestion in the hotclm regression thread on 2026-10-26: 「同意,立卡」. Reach: public door, measured on 18.1.0 with objectstack-ai/hotclm main (pnpm demo:zh, Console in zh-CN). Reader: the plugin-audit lane (audit-writers.ts summary writer) and the record feed renderer in objectui.

Business reason

A record's Discussion feed is read by everyone who works on the record, in their own language. Today its system rows are frozen in whatever language the workspace default was at the moment of each write: an English-default workspace shows Created Contract "…" to a Chinese reader forever, a workspace that switches language keeps every older row in the old one, and two colleagues with different languages see the same row in one of them. Without the change, every multi-language deployment has a half-translated feed that no translation pack can fix after the fact.

Measured

hotclm, pnpm demo:zh (workspace locale left at its default en), Console in zh-CN: the 讨论 tab of a contract shows Created Contract "回归测试 NDA — 已有相对方" and eight Updated Contract "…" rows, although @objectstack/plugin-audit 18.1.0 ships activityCreated: '创建了 {{object}} "{{label}}"'. (The app-side half — the demo should set its workspace locale — is objectstack-ai/hotclm#142.)

Why

audit-writers.ts resolves resolveWriteLocale(tenantId, userId) (ADR-0053 localization.locale, framework#3039) and stores the interpolated sentence in sys_activity.summary; the object label is translated at the same moment.

Proposal

Store the summary as its message key plus params (messages.activityCreated, {object: <object name>, label}), keep the English sentence as the fallback text, and render it per reader — the shape plugin-approvals already took for the admin_rescue timeline note (#25627, "store … as a code and render it in the reader's language") and for flow/step labels (#24977). Existing rows keep their stored text.

Dedupe: objectstack and objectui issues (2,000 most recently updated each, all states) grepped for activity … locale|language|i18n|render, activityCreated, reader … locale — neighbours #24235/#24261 (the write-time locale cache, closed), #25627 and #24977 (reader-locale precedents in approvals), none proposes this for activity summaries.


Filed from the hotclm browser regression thread (2026-10-26).

Activity

  1. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — enhancement · priority:p2 · domain:server · area:i18n · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-26T14:55Z

    ⛔ Not a claim, ⛔ not a dispatch.

    • The maintainer's 「同意,立卡」. Store the audit summary as a message key plus its parameters, and render it in the reader's locale. Rows written before the change keep their frozen text: the PR states whether they stay as-is or get a one-time re-render, and does not silently drop them.
    • Two lanes: the plugin-audit writer (server) and the record feed renderer (ui/). One PR in this tree.

    Generated by Claude Code

  2. added
    area:i18nThe customer's own language, across UI, metadata and notifications
    domain:serverDomain lane — seat card indexed by label:pm:seat
    enhancementNew feature or request
    and removed on Oct 26, 2026
  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 8 · card thread
    Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01UBPXQdapfjkjYdQck9dtTa
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-xshjzo (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#1
    Ruling-ref: the maintainer's 「同意,立卡」, quoted on the card, and triage first grade (2026-10-26T14:55Z). Store the activity summary as its message key plus params, keep the English sentence as the fallback summary, and render in the reader's locale. Rows written before the change keep their text unless the PR gives a measured reason otherwise; they are never dropped silently. One PR.
    File surface: packages/plugins/plugin-audit/** plus the read path the measurement picks (server render on read preferred). ui/ only if needed, and ⛔ not the files of open PR #26055 while it is open. ⛔ No packages/spec/** (stop on breach; explain in the report)
    Container & model: S, mode:thread, default model and effort (set at thread open)
    Clause-②: no — provisional; the dev measures it on the diff (a stored field on sys_activity may be a schema change) and the PR body carries the measured value
    Metadata-protocol: none — provisional; the dev measures it on the diff
    Responsibility: a record's Discussion feed shows system rows frozen in the write-time workspace locale (audit-writers.ts stores the interpolated sentence)
    Thread-read: none
    Premise: holds (read 2026-10-26T15:54Z at origin/main fbb75998ba: card open, unassigned, pm:queue, no claim; audit-writers.ts still interpolates messages.activityCreated at write time)
    Serial constraints cleared: PR #26055 (domain:ui, #25959) edits the ui activity renderer and the locales, so this claim stays off those files while it is open; no other open PR touches plugin-audit/src/audit-writers.ts; the dev re-measures before pr_create

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26167,
      "status": "done",
      "branch": "claude/project-thread-xshjzo",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26258",
      "session": "session_01UBPXQdapfjkjYdQck9dtTa",
      "premise_still_valid": true,
      "summary": "Each CRUD mirror row in sys_activity now stores the English sentence in summary as the fallback, and the message key plus params in metadata.summary_message. The params carry the object name, the record label, the field names, and from/to values with option values. A new sys_activity find/findOne middleware in plugin-audit (installActivitySummaryLocale) negotiates the caller's locale against the held packs, composes the summary with that reader's object, field and option labels, and drops the code for non-system callers. Hypothesis A held: the Discussion feed reads dataSource.find('sys_activity') and shows row.summary, and the authed fetch sends Accept-Language, so no ui file changed and the serial rule with #26055 holds. Rows written before the change have no code and stay as written, with no migration or backfill (pinned by a test). File surface: plugin-audit/** plus one docs row, content/docs/permissions/system-context.mdx row 45, which check-system-context-census requires for the new read site. Please amend the claim's file surface to include it.",
      "tests": "Red first, commit cb6b6af2: src/activity-summary-reader-locale.integration.test.ts on main fbb75998 failed 4 and passed 3, with Expected '创建了 合同 \"NDA\"' and Received 'Created Contract \"NDA\"' (lock VERDICT command-exit 1). Green at fa1d3912: pnpm --filter @objectstack/plugin-audit exec vitest run gave Test Files 62 passed (62) and Tests 1013 passed (1013), exit 0. The two files edited after that run were re-run, 8/8 passed, exit 0. pnpm --filter @objectstack/plugin-audit typecheck (which includes check:test-typecheck) exited 0, and eslint on packages/plugins/plugin-audit exited 0. Ablation: ablation-replace.mjs disabled the installActivitySummaryLocale registration in audit-plugin.ts, the mutation was verified on disk (blob ad14d3cc to dc00e279), and the integration test failed 4 and passed 3. The restore matched the HEAD blob and git diff HEAD was empty. No dist step applies, because the suite imports src.",
      "gates": "dispatch-gates --commands on the final diff derives 102 families. All 102 ran with exit 0, each code captured before any pipe. --ran reconciles 102 derived, 102 run, 0 NOT-MEASURED, 0 UNRUN. First-pass reds were re-run to green: check-system-context-census exited 1 for a missing anchor, fixed by the docs row. check:query-options-erasure exited 1 because the test surface went from 236 to 237, fixed by typing the new tests' options, and it is back to 236. check-plugin-teardown-shape --self-test exited 3 on a shallow clone and passed after unshallowing. check:i18n exited 3 until its build closure was built, then reported all 10 packages in sync. check:dual-build-cjs-loads exited 3 until a full pnpm build, then exited 0. check:nul-bytes exited 0. CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 relay strokes. (1) The pr_create dispatch fw-20261026T172240Z-57c06e: POST /repos/objectstack-ai/objectstack/dispatches, which the relay executed as POST /pulls (draft) and POST /issues/26258/assignees [os-project-manager]. The body read back as 7171 of 7171 bytes, identical. (2) This os-dev-report comment, through post-stamped.mjs: POST /issues/26167/comments. git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": [
        "Acceptance note, not filed: summary is searchable, and its stored text is now English, so full-text search over summary in a zh-CN workspace matches English words for new rows. This follows the ruling that English is the fallback text. carrier: none (承接者:无)",
        "Not measured: the hotclm pnpm demo:zh Console check. hotcrm/hotclm is outside this run; the read path was measured from code and is pinned end to end by the integration test."
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment: PM loop round 8 · card thread (supersedes 6420565917 by widening the file surface by one docs file; everything else stands)
    Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01UBPXQdapfjkjYdQck9dtTa
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-xshjzo (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#1
    Ruling-ref: the maintainer's 「同意,立卡」, quoted on the card, and triage first grade (2026-10-26T14:55Z). Store the activity summary as its message key plus params, keep the English sentence as the fallback summary, and render in the reader's locale. Rows written before the change keep their text unless the PR gives a measured reason otherwise; they are never dropped silently. One PR.
    File surface: packages/plugins/plugin-audit/** plus the read path the measurement picks (server render on read preferred). ui/ only if needed, and ⛔ not the files of open PR #26055 while it is open. Also content/docs/permissions/system-context.mdx: row 45 gains the new read-site anchor that check-system-context-census requires (the seat agreed 2026-10-26T17:26Z). ⛔ No packages/spec/** (stop on breach; explain in the report)
    Container & model: S, mode:thread, default model and effort (set at thread open)
    Clause-②: no — provisional; the dev measures it on the diff (a stored field on sys_activity may be a schema change) and the PR body carries the measured value
    Metadata-protocol: none — provisional; the dev measures it on the diff
    Responsibility: a record's Discussion feed shows system rows frozen in the write-time workspace locale (audit-writers.ts stores the interpolated sentence)
    Thread-read: none
    Premise: holds (read 2026-10-26T17:26Z at origin/main 1eebbc08ba: card open, pm:dispatched, assignee os-project-manager, this seat's claim the newest; the dev reproduced red first on main)
    Serial constraints cleared: PR #26055 (domain:ui, #25959) edits the ui activity renderer and the locales, so this claim stays off those files while it is open; no other open PR touches plugin-audit/src/audit-writers.ts; the dev re-measures before pr_create

  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed

    PR #26258 merged at 2026-10-26T18:52Z by the merge queue as c49688601d on main (Fixes #26167; ACCEPT 6423361244).

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-26258-*' 0 refs
    origin/main by content git cat-file -e origin/main:packages/plugins/plugin-audit/src/activity-summary-message.ts present
    Ancestry git merge-base --is-ancestor c49688601d origin/main holds

    State: this card closed by Fixes (completed); pm:dispatched removed.


    Generated by Claude Code

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

Metadata

Metadata

Labels

area:i18nThe customer's own language, across UI, metadata and notificationsdomain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions