在 #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) 组对一遍,只剩两张表在豁免外:
| 对象 |
lifecycle.class |
在 SKIP_OBJECTS? |
判断 |
sys_upload_session(packages/services/service-storage/src/objects/system-upload-session.object.ts:132) |
transient |
❌ |
本单 |
sys_file(.../system-file.object.ts:179) |
transient |
❌ |
不算漏 —— 其自身注释即写 “sys_file rows are mostly permanent business truth”,transient 只为收墓碑行/未完成上传;审计有合规价值 |
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_value diff 也跟着变大;
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 的差别(为什么单独立单而不是并进去)
建议修法
与 #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)
在 #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)