Skip to content

fix(plugin-audit,platform-objects): the audit log's default list shows what people did; the audit objects read in Chinese - #30620

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-crycwe
Nov 5, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-crycwe

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE

维护者速读

  • 改了什么:Setup「审计日志」打开时的默认列表(最近)只列人做的操作:登录时顺带写的「更新用户(最近登录时间)」行、设置变更顺带写的设置存储行和设置审计行、密钥存储、签名密钥、数据迁移台账都不再出现在默认列表;「平台设置」「平台设置审计记录」「评论表情回应」在中文界面显示中文名。
  • 为什么改:真实用户走查发现一次登录在审计日志里写好几行,设置改一次出现三四行,管理员找不到真正的操作;「Platform Setting Audit Entry」等对象名在中文界面是英文。
  • 风险与回滚:不少写任何一行,也不删数据,「全部」视图照旧列出每一行;登录戳那一行多带一个 metadata 标记 {"event":"auth.last_login_stamp"}。回滚即 revert 本 PR,已写入的标记无害。
  • 先看:packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts(默认视图 recent 的过滤与排除清单),packages/plugins/plugin-audit/src/sign-in-stamp.ts 与 audit-writers.ts 里打标记的两处,packages/platform-objects/scripts/i18n-extract.config.ts。
  • 两分钟验证:pnpm --filter @objectstack/plugin-audit exec vitest run src/sys-audit-log-default-view.integration.test.ts,预期 5 条全过:登录戳被标记且不进默认列表,管理员改用户仍在,设置变更行仍在,「全部」仍列出所有行。
  • 需要你做的:无,席位落地。

Refs #30209 (row 3)

Clause-②: no — no packages/spec change; the new constants are module-internal (not exported from the package entry)
Metadata-protocol: none
Skills-docs: none — git grep -n -i -E "audit log|last_login|sys_platform_setting|comment reaction" -- skills on ef370d07e answers two lines (skills/objectstack-ui/rules/list-views.md:222, an example grid labelled Audit Log; skills/objectstack-platform/references/plugin-development.md:211, a plugin's log line), neither about the shipped audit log's views or names, so this PR makes neither false.

What changes

Row 3, the audit log's default list. Measured on a fresh pnpm dev -- --fresh showcase boot (c23eafa8), one act wrote several ledger rows:

Act Rows on sys_audit_log
A sign-in login on sys_session, and update on the person's sys_user stamping last_login_at / last_login_ip (plugin-auth stampLastLogin, under the person's own id)
The first sign-in through the console the two above, and create on sys_jwks (the token-signing key)
A tenant setting change create/update on sys_setting, config_change naming sys_setting, create on sys_setting_audit
A global secret change create on sys_secret, create on sys_platform_setting, config_change naming sys_platform_setting, create on sys_platform_setting_audit
A boot rows on sys_migration
  • plugin-audit: the CRUD ledger writer marks the sign-in stamp. isSignInStamp (sign-in-stamp.ts) answers true for an update of sys_user whose changed fields (the writer's own diff) are last_login_at / last_login_ip and nothing else; the row then carries metadata: {"event":"auth.last_login_stamp"}, the place config_change rows already name their event (settings.set). An administrator's edit of a user, or any write that changes another field beside the stamp, carries no mark. The row is still written. A delegated write's performed_by / on_behalf_of keys are kept beside the mark when both apply.
  • sys_audit_log.listViews.recent (the first declared view, which Setup opens) gains a filter: rows on sys_secret, sys_setting_audit, sys_platform_setting_audit, sys_jwks, sys_migration and sys_migration_journal are left out; rows on sys_setting / sys_platform_setting are left out unless the action is config_change (that row names the store as its object); and a row whose metadata contains the stamp's event is left out (an any-of group with metadata is null, so rows without metadata stay). metadata is not one of the value-bearing columns parent-field-query-guard.ts refuses to filter on, so every reader can run the view. all_events is unchanged and lists every row. Object names are read from the definitions (@objectstack/platform-objects/system, SystemObjectName.JWKS), not a name prefix: sys_user, sys_member, sharing rules and the like stay in, because their writes are acts.

Row 3, the audit objects' names in Chinese. sys_platform_setting and sys_platform_setting_audit (registered by service-settings, defined in platform-objects) were in no extract config, so no bundle carried them in any locale. They join platform-objects' extract config (and its bundle-ownership list); the extract added them to every bundle, and zh-CN is written by hand (object, field, help, option and view names, following sys_setting / sys_setting_audit). sys_comment_reaction's zh-CN leaves in plugin-audit held the English fill and are translated; the regenerate dropped their fill records.

Tests

  • plugin-audit/src/sys-audit-log-default-view.integration.test.ts (new; real kernel, AuditPlugin, SQLite driver, the view's filter lowered the way the Console lowers it, or group included, and parsed by parseFilterAST): the stamp is marked and the two controls are not; recent keeps login, both config_change rows and the administrator's edits, and leaves out the stamp and every machinery row; recent reads newest first; all_events still lists all of them.
  • platform-objects/src/system/platform-setting-zh-cn.test.ts (new): served zh-CN (SetupAppTranslations) names both objects and every declared field and option in Chinese.
  • plugin-audit/src/translations/comment-reaction-zh-cn.test.ts (new): served zh-CN (AuditTranslations) names sys_comment_reaction, its fields and helps in Chinese.

Red first on main 2ffdb649 (pin commit ccb7a5f8): default view 2 failed / 3 passed (stamp unmarked; stamp in recent), platform settings zh-CN 4/4 failed, comment reaction zh-CN 2/2 failed.

Ablation (once, scripts/ablation-replace.mjs, anchor hit x1, restored blob equals HEAD, git diff HEAD empty): with signInStamp = isSignInStamp(…) replaced by false, the default-view file goes 2 failed / 3 passed (the mark pin and the recent pin).

Acceptance notes

  • Rows 4, 5 and 6 are not in this PR (Refs, not a closing keyword). Row 4 (config change old/new values) and row 5 (the sharing-rule object picker) are in the card report as decisions; row 6 (queue members) is a reading only.
  • ja-JP and es-ES carry the extract's English fill for the two settings objects, recorded in their source-hashes files; sys_comment_reaction in those locales is unchanged.
  • The sign-in stamp is recognised by its fields. A future write that changes only last_login_at / last_login_ip on sys_user for another reason would be marked too; today plugin-auth's stamp is the only writer of those two fields.
  • Other sys_* objects that still read English under zh-CN (approvals tokens and approvers, connector and flow credentials, metadata commit and activation, webhook, trusted key, identity email, automation run, assignment cursor, audience binding suggestion, migration journal) belong to other packages and are not touched.

Verification

Package suites and typechecks (head ef370d0, after merging origin/main with #30551)
  • pnpm --filter @objectstack/platform-objects --filter @objectstack/plugin-audit test under the verify lock: platform-objects 114 files / 1567 tests, plugin-audit 73 files / 1144 tests, VERDICT command-exit 0.
  • pnpm --filter @objectstack/plugin-audit --filter @objectstack/platform-objects typecheck: VERDICT command-exit 0.
  • node scripts/check-i18n-bundles.mjs --write after the merge: byte-identical (no file changed); pnpm check:i18n: all ten bundle sets in sync.
  • eslint --no-inline-config on the changed TypeScript files: exit 0.
Derived gate families

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on ef370d07e (after the origin/main merge) derived 64 commands. Each ran with its exit code captured before any pipe: all 64 exited 0. --ran: 64 derived, 64 run, 0 NOT-MEASURED, 0 UNRUN.

  • On the pre-merge tree (77f2050b) the same 64 ran green except node scripts/check-plugin-teardown-shape.mjs --self-test, exit 3 on the shallow clone; it exited 0 after git fetch of its fixture commit, and exited 0 on the merged head too.
  • pnpm lint (repository-wide, eslint . --no-inline-config) on ef370d07e: exit 0.

Generated by Claude Code

… and the audit objects' zh-CN names

Red on main: the sign-in stamp and the machinery rows reach the default
view, and three audit objects read English under zh-CN.

Claude-Session: https://claude.ai/code/session_01Utp6CbEH94Gqn2583kuuzH
Co-authored-by: Claude <[email protected]>
…es out machinery rows; audit objects read in Chinese

- The ledger writer marks the sign-in stamp (an update of sys_user that only
  stamps last_login_at / last_login_ip) with metadata.event
  auth.last_login_stamp; the row is still written.
- sys_audit_log's first view, recent, leaves out that row, the settings
  stores' mirrored writes beside a config_change, the settings trails, the
  secret store, the signing key and the migration ledger. all_events lists
  every row.
- sys_platform_setting and sys_platform_setting_audit join platform-objects'
  extract config and read in Chinese under zh-CN; sys_comment_reaction's
  zh-CN bundle is translated.

Claude-Session: https://claude.ai/code/session_01Utp6CbEH94Gqn2583kuuzH
Co-authored-by: Claude <[email protected]>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/platform-objects, @objectstack/plugin-audit, touching 27 documentable anchor(s).

25 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 1c5cee6736518291d86148cd69124542dfc0d021.

⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: sys_user (literal, 49 pages)
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 103 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 11 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1c5cee6736518291d86148cd69124542dfc0d021 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 70e0312b9a90cacb2a4db8beb745dd2503c10ef8 — the merge of head ef370d07ea841903f55a891f17791391f7263ddd into base 1c5cee6736518291d86148cd69124542dfc0d021, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 70e0312b9a90cacb2a4db8beb745dd2503c10ef8 && git checkout 70e0312b9a90cacb2a4db8beb745dd2503c10ef8
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 1c5cee6736518291d86148cd69124542dfc0d021 ef370d07ea841903f55a891f17791391f7263ddd && git checkout -B drift-repro 1c5cee6736518291d86148cd69124542dfc0d021 && git merge --no-ff ef370d07ea841903f55a891f17791391f7263ddd

node scripts/docs-audit/affected-docs.mjs --json 1c5cee6736518291d86148cd69124542dfc0d021

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 1c5cee6736518291d86148cd69124542dfc0d021 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE

席位记录 · 2026-11-05T18:41Z · Head-sha ef370d07 · ACCEPT

维护者速读(席位按 diff 校正)

  • 改了什么:Setup「审计日志」默认打开的「最近」列表只列人做的操作。登录时顺带写的「更新用户(最近登录时间/IP)」行、设置改动顺带写的设置存储行和设置审计行、密钥、签名密钥、数据迁移台账都不再出现在默认列表里。「平台设置」「平台设置审计记录」「评论表情回应」在中文界面显示中文名。
  • 为什么改:Setup: show what people can really do and what really changed, using names rather than ids #30209 第 3 行。一次登录在审计日志里写好几行,设置改一次出现三四行,管理员找不到真正的操作;几个审计相关对象在中文界面是英文。
  • 风险与回滚:一行都不少写,也不删数据,「全部」视图照旧列出每一行。登录戳那一行多带一个标记 {"event":"auth.last_login_stamp"}。回滚即 revert 本 PR,已写入的标记无害。
  • 先看:plugin-audit 的 sys-audit-log.object.ts(recent 视图的过滤与排除清单)、sign-in-stamp.ts、audit-writers.ts 打标记的一处。
  • 两分钟验证:pnpm --filter @objectstack/plugin-audit exec vitest run src/sys-audit-log-default-view.integration.test.ts,5 条全过。
  • 需要你做的:无。非受管面、非 BREAKING、Clause-②: no,四个复核面都不碰,按技能由 CI 加席位自读,席位落地。第 4、5 行要你裁定,交接给席位 2 后由它走裁定线程。

席位意见:同意落地。判定看的是改了哪些字段,不看写入上下文:只改 last_login_at / last_login_ip 的 sys_user 更新才打标记,管理员改用户、或同一次写入还改了别的字段,都不打。过滤只作用在默认视图上,存储和「全部」视图不变,合规取证不受影响。排除清单取自对象定义和协议常量,不用前缀匹配,成员角色、共享规则、封禁这类真操作都留在列表里。

席位核对

  1. 形态:draft→ready,目标 main,Refs #30209 (row 3),不带闭合关键词(第 4、5、6 行不在本 PR);作者 objectstack-fleet[bot](中继)。
  2. 前提实测:报告 6665615192 在 main 加钉的提交上红:默认视图 2 条、平台设置中文 4 条、表情回应中文 2 条。消融一次转红后已还原。两包测试 1567 / 1144 条全过,64 道派生门禁全过。
  3. 门禁 check-runs(钉 head ef370d07):全部 success 或 skipped,0 失败(落地前席位复读)。
  4. 接受的偏差:ja-JP / es-ES 只带抽取的英文兜底,已记入 source-hashes。登录戳按字段识别:将来如果别的写入也只改这两个字段,也会被打标记,PR 已写明,接受。plugin-audit 从 @objectstack/platform-objects/system 引对象定义,这个依赖原本就有(key-material-copy.ts 已在用)。
  5. 范围外去向:「共享规则建在未启用记录共享的对象上,保存成功但静默不生效」已立卡 A sharing rule on an object without record sharing saves and silently does nothing #30621(p3)。其余 17 个 sys_* 对象中文缺失分属其他包,不在此卡。第 4 行(配置变更新旧值)、第 5 行(共享规则对象选择器)是 needs_decision,第 6 行(队列成员)是实测结果,都交接给席位 2。Skills-docs: none 成立。changeset patch,Metadata-protocol: none。
  6. 落地条款:check-governed-merges --pr 30620 结果 NOT governed。1111 行里大部分是生成的翻译包,≤ 3000,非 Tier H。全部 check 绿后 ready + auto-merge。合并后席位在 Setup: show what people can really do and what really changed, using names rather than ids #30209 写落地(卡保持开,留给第 4、5、6 行),并结线程。

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 5, 2026 18:42
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 5, 2026 18:42
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 740edc5 Nov 5, 2026
49 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-crycwe branch November 5, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant