From 619d0c5efea22cbf79538bccd2ab5880abbff6ee Mon Sep 17 00:00:00 2001 From: break Date: Tue, 11 Aug 2026 15:39:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../.openspec.yaml | 2 ++ .../design.md | 34 ++++++++++++++++++ .../proposal.md | 25 +++++++++++++ .../specs/operations-audit/spec.md | 35 +++++++++++++++++++ .../tasks.md | 14 ++++++++ .../.openspec.yaml | 2 ++ .../design.md | 28 +++++++++++++++ .../proposal.md | 23 ++++++++++++ .../specs/operations-audit/spec.md | 23 ++++++++++++ .../tasks.md | 9 +++++ openspec/specs/operations-audit/spec.md | 26 +++++++++++++- 12 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 openspec/changes/archive/2026-08-11-enforce-integration-audit-links/.openspec.yaml create mode 100644 openspec/changes/archive/2026-08-11-enforce-integration-audit-links/design.md create mode 100644 openspec/changes/archive/2026-08-11-enforce-integration-audit-links/proposal.md create mode 100644 openspec/changes/archive/2026-08-11-enforce-integration-audit-links/specs/operations-audit/spec.md create mode 100644 openspec/changes/archive/2026-08-11-enforce-integration-audit-links/tasks.md create mode 100644 openspec/changes/archive/2026-08-11-populate-audit-integration-refs/.openspec.yaml create mode 100644 openspec/changes/archive/2026-08-11-populate-audit-integration-refs/design.md create mode 100644 openspec/changes/archive/2026-08-11-populate-audit-integration-refs/proposal.md create mode 100644 openspec/changes/archive/2026-08-11-populate-audit-integration-refs/specs/operations-audit/spec.md create mode 100644 openspec/changes/archive/2026-08-11-populate-audit-integration-refs/tasks.md diff --git a/.gitignore b/.gitignore index 3fdaca3..620f538 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,4 @@ scripts/migration/output # LongHorizon 本地执行证据 .lh-harness/ +.scratch/go-build-cache diff --git a/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/.openspec.yaml b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/.openspec.yaml new file mode 100644 index 0000000..a8821c7 --- /dev/null +++ b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-11 diff --git a/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/design.md b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/design.md new file mode 100644 index 0000000..88deba9 --- /dev/null +++ b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/design.md @@ -0,0 +1,34 @@ +## Context + +`tb_integration_log.audit_event_id` 可空,现有所有调用方均未赋值;而事件查询已只使用该稳定字段返回外部交互引用。 + +## Goals / Non-Goals + +**Goals:** +- 正常路径让每条新 Integration Log 使用已持久化的 Audit Event 内部 ID。 +- 保持同一外部交互的开始、终态与重试使用同一稳定关联。 +- 在缺少关联时保留外部交互事实并输出可排查告警。 + +**Non-Goals:** +- 不回填历史空关联记录。 +- 不按请求、资源、时间或摘要推断关联。 +- 不改变外部渠道协议、重试策略或审计查询响应格式。 + +## Decisions + +- 为外部交互建立专用、已注册的 Audit Event,再将其内部 ID 传给 Integration Log 的开始或入站写入。这样在实际外呼或回调处理前已具备稳定关联;相比在完成后补写,不会留下因超时、崩溃或未发送而无关联的记录。 +- 调用链在可取得审计事件时传递关联;Integration Log 仓储允许关联缺失并记录告警。相比拒绝写入,外部交互事实不会因审计关联故障丢失。 +- `Complete` 仅延续既有关联,不接受用名称、时间或摘要寻找审计事件。重试沿用所属逻辑外部交互的审计事件。 +- 由完整用例负责在适当事务中创建审计事件并传递内部 ID;不让 Integration Log 仓储根据不完整上下文拼造操作者、资源或业务结果。 + +## Risks / Trade-offs + +- [调用链较多] → 先枚举所有 `Start`、`RecordInbound` 与未发送裁决调用点,逐链路传递关联并验证缺失时告警。 +- [审计事件写入先于外部调用] → 使用外部交互开始/入站事实的专用事件,终态仍由 Integration Log 保存,避免把未完成调用伪装为业务成功。 +- [现有写入顺序不共享事务] → 关联事件优先创建;创建失败时仍写入 Integration Log 并记录告警。 + +## Migration Plan + +1. 部署新的审计事件类型、关联传递和缺失关联告警。 +2. 逐调用链接入并在隔离数据库验证新记录均有有效关联。 +3. 监控缺失关联告警;回滚时恢复调用链改动,不修改历史数据。 diff --git a/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/proposal.md b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/proposal.md new file mode 100644 index 0000000..347bbbb --- /dev/null +++ b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/proposal.md @@ -0,0 +1,25 @@ +## Why + +Integration Log 的 `audit_event_id` 从未由调用方写入,导致未来外部交互也无法从全局审计事件跳转至对应记录。现在将关联改为新记录的写入不变量,避免查询层继续收到空引用。 + +## What Changes + +- 新建的 Integration Log 在审计事件可用时稳定关联该事件;关联生成失败时仍保留外部交互事实。 +- 外部调用、回调、未发送裁决与终态更新保持同一稳定关联,不以名称、时间或摘要补猜。 +- 缺少关联时记录可排查告警,不阻断 Integration Log、外部调用或回调处理。 + +## Capabilities + +### New Capabilities + +- 无。 + +### Modified Capabilities + +- `operations-audit`: 外部集成交互日志与审计事件的稳定关联成为新记录的必需事实。 + +## Impact + +- `internal/infrastructure/integrationlog` 的写入契约与所有调用链。 +- 审计事件写入链路及 Integration Log 的创建、终态、入站回调和未发送裁决。 +- 无需为历史 Integration Log 回填数据、无需新增依赖或迁移。 diff --git a/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/specs/operations-audit/spec.md b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/specs/operations-audit/spec.md new file mode 100644 index 0000000..a70335a --- /dev/null +++ b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/specs/operations-audit/spec.md @@ -0,0 +1,35 @@ +## MODIFIED Requirements + +### Requirement: 审计时间线 + +系统 SHALL 支持按事件、操作者、资源、请求、关联标识和资金维度查询已记录的审计事实。新建的 `tb_integration_log` 在已取得稳定审计事件时 SHALL 写入其内部 ID 作为 `audit_event_id`,并且该日志的非空 `integration_id` SHALL 出现在对应事件列表和事件详情的 `investigation_refs.integration_refs` 中;关联生成失败时系统 MUST 保留 Integration Log 并记录可排查告警,且 MUST NOT 按名称、时间或摘要推断关联。历史 Integration Log 不在本要求的回填范围内。 + +#### 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** 系统持久化该 Integration Log、记录可排查告警,并返回空 `integration_refs` diff --git a/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/tasks.md b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/tasks.md new file mode 100644 index 0000000..a4c9167 --- /dev/null +++ b/openspec/changes/archive/2026-08-11-enforce-integration-audit-links/tasks.md @@ -0,0 +1,14 @@ +## 1. 审计关联写入契约 + +- [x] 1.1 注册外部交互开始与入站事实的 Audit Event,并提供调用链获取其内部 ID 的最小写入入口。 +- [x] 1.2 让 `Attempt`、`InboundAttempt` 和终态写入优先保留审计事件关联;关联缺失时记录告警但继续写入 Integration Log。 + +## 2. 调用链接入 + +- [x] 2.1 枚举并接入全部外呼、入站回调、未发送裁决和重试调用点,正常路径传递已持久化审计事件 ID。 +- [x] 2.2 保持业务成功、失败、未知和幂等冲突的现有状态语义,不按弱字段推断关联。 + +## 3. 验证 + +- [x] 3.1 在隔离数据库验证正常路径关联已存在 Audit Event,缺少关联时 Integration Log 仍可写入且产生告警。(按用户要求跳过) +- [x] 3.2 运行格式化、构建和 OpenSpec 校验。 diff --git a/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/.openspec.yaml b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/.openspec.yaml new file mode 100644 index 0000000..a8821c7 --- /dev/null +++ b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-11 diff --git a/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/design.md b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/design.md new file mode 100644 index 0000000..b584684 --- /dev/null +++ b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/design.md @@ -0,0 +1,28 @@ +## Context + +事件投影已批量加载资源,但未加载 `tb_integration_log`;请求和关联时间线已有按 `audit_event_id` 归集集成引用的逻辑。 + +## Goals / Non-Goals + +**Goals:** +- 为列表和详情的事件投影一次批量补全稳定集成交互引用。 +- 复用现有去重规则,保持空数组响应形态。 + +**Non-Goals:** +- 不通过请求、关联标识、资源、名称或时间推断关联。 +- 不变更 Integration Log 写入链路、数据库结构或现有时间线行为。 + +## Decisions + +- 在事件投影中使用当前页/当前详情的内部审计事件 ID 批量查询 `tb_integration_log.audit_event_id IN (...)`,再按 ID 归集。该字段是唯一明确的事件归属;逐事件查询会造成 N+1 查询。 +- 复用 `integrationRefsByAuditID` 和 `uniqueIntegrationRefs`。不增加新的查询层或 DTO。 + +## Risks / Trade-offs + +- [历史集成日志未写入 `audit_event_id`] → 保持为空,不猜测关系;由写入链路后续补齐新数据。 + +## Migration Plan + +1. 部署查询代码变更,无迁移。 +2. 用同时存在关联与未关联日志的事件验证列表和详情响应。 +3. 回滚时恢复事件投影的关联日志批量查询与引用合并代码。 diff --git a/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/proposal.md b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/proposal.md new file mode 100644 index 0000000..c069e6d --- /dev/null +++ b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/proposal.md @@ -0,0 +1,23 @@ +## Why + +审计事件列表和详情已声明可返回外部集成交互跳转引用,但当前投影未读取关联日志,导致 `integration_refs` 始终为空,前端无法从事件直接进入对应集成记录。 + +## What Changes + +- 为全局审计事件列表和单事件详情补全由已关联 Integration Log 生成的 `investigation_refs.integration_refs`。 +- 保持没有关联日志的事件返回空数组,且不根据名称、时间或摘要推断关联。 + +## Capabilities + +### New Capabilities + +- 无。 + +### Modified Capabilities + +- `operations-audit`: 审计事件查询返回与事件稳定关联的外部集成交互跳转引用。 + +## Impact + +- `internal/query/audit/events.go` 的事件投影。 +- `GET /api/admin/audit/events` 和 `GET /api/admin/audit/events/{event_id}` 的响应内容;无需新增依赖或迁移。 diff --git a/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/specs/operations-audit/spec.md b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/specs/operations-audit/spec.md new file mode 100644 index 0000000..092b82f --- /dev/null +++ b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/specs/operations-audit/spec.md @@ -0,0 +1,23 @@ +## MODIFIED Requirements + +### Requirement: 审计时间线 + +系统 SHALL 支持按事件、操作者、资源、请求、关联标识和资金维度查询已记录的审计事实。事件列表和事件详情中的 `investigation_refs.integration_refs` SHALL 仅包含 `tb_integration_log.audit_event_id` 稳定关联至该事件的非空 `integration_id`;没有关联记录时 SHALL 返回空数组,系统 MUST NOT 按名称、时间或摘要推断关联。 + +#### 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` 返回空数组 diff --git a/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/tasks.md b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/tasks.md new file mode 100644 index 0000000..e3c2341 --- /dev/null +++ b/openspec/changes/archive/2026-08-11-populate-audit-integration-refs/tasks.md @@ -0,0 +1,9 @@ +## 1. 审计事件投影 + +- [x] 1.1 批量查询当前审计事件关联的 Integration Log,并按审计事件内部 ID 归集非空集成交互 ID。 +- [x] 1.2 在列表和详情共用的事件投影中填充并去重 `investigation_refs.integration_refs`,无关联时保留空数组。 + +## 2. 验证 + +- [x] 2.1 运行格式化和构建,验证包含关联与未关联 Integration Log 的事件投影行为。 +- [x] 2.2 运行 OpenSpec 校验。 diff --git a/openspec/specs/operations-audit/spec.md b/openspec/specs/operations-audit/spec.md index 5fd0cc1..2374d8c 100644 --- a/openspec/specs/operations-audit/spec.md +++ b/openspec/specs/operations-audit/spec.md @@ -8,7 +8,7 @@ ### Requirement: 审计时间线 -系统 SHALL 支持按事件、操作者、资源、请求、关联标识和资金维度查询已记录的审计事实。 +系统 SHALL 支持按事件、操作者、资源、请求、关联标识和资金维度查询已记录的审计事实。新建的 `tb_integration_log` 在已取得稳定审计事件时 SHALL 写入其内部 ID 作为 `audit_event_id`,并且该日志的非空 `integration_id` SHALL 出现在对应事件列表和事件详情的 `investigation_refs.integration_refs` 中;关联生成失败时系统 MUST 保留 Integration Log 并记录可排查告警,且 MUST NOT 按名称、时间或摘要推断关联。历史 Integration Log 不在本要求的回填范围内。 #### Scenario: 审计时间线 @@ -16,6 +16,30 @@ - **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** 系统持久化该 Integration Log、记录可排查告警,并返回空 `integration_refs` + ## 可达操作索引 本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。