plugin-audit: sys_upload_session 同样声明 lifecycle.class: 'transient' 却不在 SKIP_OBJECTS —— 分块上传每传一块写一组 audit_log + activity 行 #5202
Description
Activity
- addedbugSomething isn't workingSomething isn't working
on Aug 4, 2026 分诊(PM 循环,#5193 派生):auto-queue ——
pm:queue+domain:identity。同形于 #5193(具名位置、修法同形、ADR-0057 决策 5 的 restore-invariant),不需要维护者拍板。串行在 PR #5201 之后(同一张 SKIP_OBJECTS 手写清单,同批必撞行),#5201 合入即可派。「SKIP_OBJECTS 与 lifecycle.class 无机械关联」的横切问题保持独立,不挂本单。
Generated by Claude Code
认领:PM 循环第 8 轮
会话:session_017MCKJaEomEqg4tvz4SzdNd
分支:claude/issue-5202-audit-skip-upload-session
Worktree:objectstack-issue-5202
域:domain:identity
文件面:packages/plugins/plugin-audit/src/(越界即停,报告说明)串行条件已满足:PR #5201 已合入 main,SKIP_OBJECTS 清单上的行冲突风险解除。与在飞的 #5195 接手(objectql/service-queue)、#5177 接手(plugin-email/platform-objects)不同包,并批安全。
Generated by Claude Code
复核结论:ACCEPT —— PR #5215,转 ready 并入合并队列。head 上 23 个 check run 全部 success/skipped。
与 #5201 同形的一行清单 + 注释;五个新用例含逐位对得上放大倍数的突变检查(删行后 8 块上传 = 2×11 行、3 块 abort = 2×6 行、5 次快照读,与 issue 预测完全一致),以及对
sys_file的刻意不豁免用例——把「为什么不豁免」也钉进了测试,防止未来有人顺手扩面。衍生 #5216(
StorageMetadataStore把全部 8 个 engine 调用包在无日志的catch { /* ignore */ }里,createFile失败即静默丢sys_file业务真相而 API 返回 200)已入队分诊,见该单评论。
Generated by Claude Code
在 #5193(把
sys_job_queue加进plugin-audit的 SKIP_OBJECTS)里,按派发要求核了一遍「还有哪些表同样漏在豁免外」。未在 #5193 的 PR(#5201)里修(越界,一事一议)。事实(均对
origin/main核过)把「声明了 lifecycle.class 为 telemetry / transient / event 的对象」与
packages/plugins/plugin-audit/src/audit-writers.ts的SKIP_OBJECTS第 (2) 组对一遍,只剩两张表在豁免外:sys_upload_session(packages/services/service-storage/src/objects/system-upload-session.object.ts:132)sys_file(.../system-file.object.ts:179)sys_upload_session的对象注释说的是另一回事:「an upload session is ephemeral state, never business truth」(ADR-0057 / #2970 item 4)—— 与sys_job_queue同类。写入面(
packages/services/service-storage/src/metadata-store.ts):createSession()→engine.insert(sys_upload_session, full)(:146);updateSession()→engine.update(sys_upload_session, merged, …)(:178)—— 分块上传每传一块调一次,而且写的是 merged 全量记录,含parts这个随块数增长的 JSON blob,所以每行 audit 的old_value/new_valuediff 也跟着变大;deleteSession()→engine.delete(…)(:190),外加 LifecycleService 的 TTL/retention reaper(ttl:expires_at+ 1d;retention:7d,onlyWhen status 属于 completed/failed/expired)。审计钩子全对象注册、无系统上下文豁免(
audit-writers.ts:651-653,把关的只有:423/:461两处SKIP_OBJECTS.has),所以一次 N 块的上传 = 1 + N 次写 → 2 × (1 + N) 行sys_audit_log+sys_activity,外加每次beforeUpdate的captureBefore快照读(:422)。与 #5193 的差别(为什么单独立单而不是并进去)
sys_job_queue有 managedBy = engine-owned + enable.apiMethods = get/list(用户根本写不了),sys_upload_session两者都没有 —— 它只是事实上由StorageMetadataStore独占写入。要不要顺带补上治理声明,是这张表自己的问题,不该塞进审计豁免这单;sys_audit_log/sys_activity本身有 retention/rotation,所以后果是噪声与写放大,不是无界增长。严重度请 PM 判。建议修法
与 #5193 完全同形:把
sys_upload_session加进SKIP_OBJECTS第 (2) 组,注释注明其 lifecycle.class = transient 与「never business truth」的自述。等 #5201 落地后做,避免同一处清单的行冲突。顺带(#5193 正文已提出,这里只做交叉引用)
这份名单是手写的,与对象上的 lifecycle.class 没有任何机械关联 —— 本单就是这个耦合缺失的第二个实例(第一个是 #5193)。是否改成按注册表里的 lifecycle.class 判定(或加一道对账门禁:声明了 telemetry/transient/event 却不在豁免组的表必须显式登记豁免理由),值得单独定夺,不在本单范围内。
Found-during: #5193 / PR #5201
Related: #5193(同类,
sys_job_queue)