- 审计注册表为可由系统任务、定时任务发起的动作声明落库策略(always/on_success/outcome/log_only/none),未声明按 log_only - 人工、开放接口、个人客户、外部系统发起的动作始终写审计表 - log_only 写所在服务 app.log(logger=audit),不含快照 - 对接日志不再补写 integration.attempt_started,无上游审计时 audit_event_id 为空 - 新增 audit.persist_overrides 按动作覆盖策略 - 审计覆盖扫描要求机器动作必须声明策略 - 新增 OpenSpec 提案 refactor-audit-log-persistence 与技术方案文档 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9.2 KiB
MODIFIED Requirements
Requirement: 审计时间线
系统 SHALL 支持按事件、操作者、资源、请求、关联标识和资金维度查询已记录的审计事实。新建的 tb_integration_log 在已取得稳定审计事件时 SHALL 写入其内部 ID 作为 audit_event_id;没有上游审计事件时 audit_event_id SHALL 为空,系统 MUST NOT 为补齐关联而另写审计事件,并且该日志的非空 integration_id SHALL 出现在对应事件列表和事件详情的 investigation_refs.integration_refs 中;关联生成失败时系统 MUST 保留 Integration Log 并记录可排查告警,且 MUST NOT 按名称、时间或摘要推断关联。历史 Integration Log 不在本要求的回填范围内。审计事件的构造、校验或持久化失败 MUST 记录可关联的结构化错误日志和二次失败记录,且 MUST NOT 改变已通过业务校验的业务操作结果或接口响应。尚无完成物理清理记录时,审计调查接口 MUST 继续查询在线审计事实,且返回的留存边界不得将数据标记为已归档。
Scenario: 审计时间线
- GIVEN 审计事实已存在
- WHEN 使用对应维度查询
- THEN 返回匹配的事实与稳定动作编码,不用访问日志替代
Scenario: 事件返回已关联外部交互引用
- GIVEN 一个在线审计事件有
tb_integration_log.audit_event_id指向其内部 ID 的外部交互记录 - WHEN 查询全局审计事件列表或该事件详情
- THEN 该事件的
investigation_refs.integration_refs返回该记录的integration_id
Scenario: 事件没有关联外部交互引用
- GIVEN 一个在线审计事件没有稳定关联的外部交互记录
- WHEN 查询全局审计事件列表或该事件详情
- THEN
investigation_refs.integration_refs返回空数组
Scenario: 新外部交互日志具有稳定审计关联
- GIVEN 系统即将记录一次新的外部调用、入站回调或未发送裁决,且该调用由一个已写入的审计事件发起
- WHEN 写入对应 Integration Log
- THEN 该记录保存非空
audit_event_id,且其目标 Audit Event 已存在
Scenario: 没有上游审计事件的外部交互日志
- GIVEN 一次系统任务发起的外部调用没有上游审计事件
- WHEN 写入对应 Integration Log
- THEN 该记录的
audit_event_id为空 - AND 审计事件表不新增
integration.attempt_started事件
Scenario: 缺少审计关联时保留外部交互日志
- GIVEN 一次新的外部交互日志没有稳定审计事件关联
- WHEN 系统尝试写入该 Integration Log
- THEN 系统持久化该 Integration Log、记录可排查告警,并返回空
integration_refs
Scenario: 审计写入失败不阻断业务
- GIVEN 一个业务操作已通过自身输入、权限和状态校验
- WHEN 该操作的审计事件构造、校验或持久化失败
- THEN 系统提交或返回该业务操作原本的结果,并以请求关联标识、动作编码和资源标识记录审计失败
Scenario: 尚无物理清理记录时查询在线审计
- GIVEN 审计或外部交互日志尚无完成物理清理的归档运行记录
- WHEN 调用任一依赖留存边界的审计调查接口
- THEN 系统返回当前在线数据或空列表
- AND 响应中的
archived_before为空 - AND 系统不得因空留存边界返回服务端错误
Requirement: 轮询审计事实保留边界
系统 SHALL 仅为人工触发的轮询操作,以及由轮询结果导致的资金或套餐生命周期变化(如套餐到期、激活、退款失效)持久化统一审计事件及资源快照。系统任务发起的轮询同步本身(流量同步、网络状态同步、流量扣减、停复机原因更新)MUST NOT 创建 tb_audit_event 或 tb_audit_event_resource,无论成功、失败或结果未知;其可查证据由采集记录、采集失败记录、停复机记录、日流量记录与应用日志提供。审计调查接口仅返回实际已保留的历史事实。
Scenario: 自动轮询成功但无业务变化
- GIVEN 一次自动轮询成功且没有改变任何业务状态、有效流量或风险结论
- WHEN 系统结束该轮询处理
- THEN 审计事件和审计资源表不新增该次轮询记录
Scenario: 自动轮询同步流量并扣减
- GIVEN 一次自动轮询读到有效增量并完成扣减
- WHEN 系统提交该变化
- THEN 审计事件表不新增流量同步或扣减事件
- AND 采集记录保存该次读数、扣减判定、增量与原始响应
Scenario: 自动轮询调用失败
- WHEN 一次自动轮询查流量超时或返回无效响应
- THEN 审计事件表不新增记录
- AND 采集失败记录保存该次失败的错误类别、上游返回与原始数据
Scenario: 轮询导致套餐到期
- GIVEN 轮询或定时任务判定一个套餐已到期
- WHEN 系统把套餐置为已过期
- THEN 系统保留套餐到期的审计事实与资源快照
Scenario: 人工触发刷新
- WHEN 后台账号手动刷新一张卡
- THEN 系统为该操作写审计事件
ADDED Requirements
Requirement: 审计动作落库策略
系统 SHALL 在统一审计注册表中为每个动作声明落库策略,取值为:总是写(always)、只写成功(on_success)、只写结论(outcome)、只写应用日志(log_only)、不写(none)。
- 操作者为后台账号、个人客户、OpenAPI 或外部系统时,系统 MUST 按"总是写"处理,不受动作策略限制。
- 操作者为系统任务或定时任务、且动作未声明策略时,系统 MUST 按"只写应用日志"处理。
- 审计覆盖扫描 MUST 在存在可由系统任务或定时任务发起、但未声明落库策略的动作时失败。
- 系统 SHALL 提供按动作编码覆盖落库策略的运行时配置;覆盖只作用于系统任务与定时任务操作者。
- 是否写入审计 MUST NOT 改变业务操作的结果或接口响应。
Scenario: 人工操作始终写审计
- GIVEN 动作
order.create对系统任务声明为只写应用日志 - WHEN 后台账号创建订单
- THEN 系统写入审计事件与资源快照
Scenario: 新增机器动作未声明策略
- WHEN 系统任务写一个未声明落库策略的动作
- THEN 审计事件表不新增记录,应用日志新增一行该动作的结构化日志
Scenario: 覆盖扫描发现未声明策略
- GIVEN 一个可由系统任务发起的动作没有声明落库策略
- WHEN 运行审计覆盖扫描
- THEN 扫描失败并列出该动作编码
Scenario: 运行时覆盖
- GIVEN 运行时配置把
package_usage.expire覆盖为只写应用日志 - WHEN 定时任务使一个套餐到期
- THEN 审计事件表不新增记录,应用日志新增一行
- AND 删除该覆盖后,下一次到期重新写审计事件
Requirement: 系统过程动作写应用日志
落库策略为"只写应用日志",或"只写成功"时的失败结果,系统 SHALL 在所在服务的应用日志中写一行结构化日志,并 MUST NOT 写入审计事件表与资源表。
- 日志行 MUST 带固定 logger 名
audit。 - 日志行 MUST 包含:动作编码、操作者类型与标识、来源、结果、资源类型与资源键、关联标识、请求标识、错误码、摘要。
- 日志行 MUST NOT 包含变更前后快照、主体数据、密钥、令牌或加密报文。
- 成功写 Info 级别,失败写 Warn 级别。
- 应用日志写入失败 MUST NOT 重试,也 MUST NOT 影响业务结果。
Scenario: 网络状态同步
- WHEN 系统任务同步一张卡的网络状态
- THEN 应用日志新增一行
logger=audit、动作编码为iot_card.worker_network_sync的记录 - AND 该行不含变更前后快照
Scenario: 不新增审计表数据
- WHEN 系统任务写任一只写应用日志的动作
- THEN
tb_audit_event与tb_audit_event_resource均无新增
Requirement: 自动重试动作只写结论
落库策略为"只写结论"的动作,系统 SHALL 只在最终结论产生时写一条审计事件。最终结论指最终成功,或重试用尽转人工处理。
- 中间失败 MUST NOT 写审计事件,只写应用日志;日志行 MUST 带尝试序号与对应尝试记录标识。
- 结论事件的元数据 MUST 包含总尝试次数、首次失败时间与最后错误码。
- 同一业务对象的同一结论 MUST 只有一条审计事件。
- 每一次尝试的细节 MUST 由对应业务尝试记录保存,并可分页查询。
Scenario: 重试后成功
- GIVEN 一张退款单的资产后处理前两次失败、第三次成功
- WHEN 第三次处理完成
- THEN 审计事件表只有一条结论为成功的事件,元数据中总尝试次数为 3
- AND 尝试记录中有三条记录
Scenario: 重试用尽转人工
- GIVEN 一张退款单的资产后处理连续失败达到上限
- WHEN 系统将其标记为需人工处理
- THEN 审计事件表写入一条结论为失败的事件,包含最后错误码
Scenario: 结论重复写入
- WHEN 同一退款单的成功结论被重复提交
- THEN 审计事件表仍只有一条该结论事件