[M-AI-04-02] 注册 Active Recall Job Definition 与输入 Snapshot #297

Closed
opened 2026-06-21 12:48:13 +08:00 by wangdl · 3 comments
Owner

类型 / 标签

  • backend
  • active-recall
  • registry
  • snapshot

风险等级

P0

依赖

  • M-AI-04-01(审计与冻结契约)

背景

按照迁移契约注册 Active Recall Definition,使其成为统一 Job Engine 可识别的真实业务 Job Type,并实现输入 Schema、Snapshot Builder 和注册校验。此 Issue 不切换生产入口,仅完成注册与验证。

目标

  1. 向 JobDefinitionRegistry 注册 Active Recall Definition
  2. 实现 ActiveRecallSnapshotBuilder,生成稳定、版本化、脱敏的输入 Snapshot

非目标

  • 不修改原 Controller
  • 不修改原 ActiveRecallService.submit
  • 不创建真实 Job
  • 不调用模型
  • 不写业务结果
  • 不新增 Migration
  • 不在 Feature Flag 开启前接收真实流量

影响范围

  • JobDefinitionRegistry(新增 Definition)
  • ActiveRecallSnapshotBuilder(新增)
  • AiJobSnapshot 表
  • 输入 Schema 定义

Definition 冻结字段

jobType, queueName, priority, attempts, timeoutMs, inputSchemaVersion, outputSchemaVersion, promptKey, promptVersion, modelTier, inputSchema, outputSchema, executor, businessValidator, referenceValidator, projector

队列原则:ai-interactive(除非审计证明属于后台任务)

Snapshot Builder 职责

  1. 加载并验证 Active Recall
  2. 验证记录属于当前用户
  3. 加载模型所需最小业务上下文
  4. 生成稳定、版本化输入
  5. 脱敏处理
  6. 计算 contentHash

禁止存储

JWT / Authorization Header / 模型 API Key / Cookie / 数据库连接信息 / 无关用户画像 / 未脱敏 Credential

验收标准

  • Registry 注册成功
  • 重复注册失败(幂等注册)
  • 非法输入被拒绝
  • Snapshot 生成稳定(相同输入→相同 contentHash)
  • Snapshot 不含敏感字段
  • Definition 元数据来自 M-AI-04-01 冻结契约
  • 输入 Schema 版本化
  • 单元测试通过

建议执行顺序

第 2 个执行(依赖 M-AI-04-01)

## 类型 / 标签 - backend - active-recall - registry - snapshot ## 风险等级 P0 ## 依赖 - M-AI-04-01(审计与冻结契约) ## 背景 按照迁移契约注册 Active Recall Definition,使其成为统一 Job Engine 可识别的真实业务 Job Type,并实现输入 Schema、Snapshot Builder 和注册校验。此 Issue 不切换生产入口,仅完成注册与验证。 ## 目标 1. 向 JobDefinitionRegistry 注册 Active Recall Definition 2. 实现 ActiveRecallSnapshotBuilder,生成稳定、版本化、脱敏的输入 Snapshot ## 非目标 - 不修改原 Controller - 不修改原 ActiveRecallService.submit - 不创建真实 Job - 不调用模型 - 不写业务结果 - 不新增 Migration - 不在 Feature Flag 开启前接收真实流量 ## 影响范围 - JobDefinitionRegistry(新增 Definition) - ActiveRecallSnapshotBuilder(新增) - AiJobSnapshot 表 - 输入 Schema 定义 ## Definition 冻结字段 jobType, queueName, priority, attempts, timeoutMs, inputSchemaVersion, outputSchemaVersion, promptKey, promptVersion, modelTier, inputSchema, outputSchema, executor, businessValidator, referenceValidator, projector 队列原则:ai-interactive(除非审计证明属于后台任务) ## Snapshot Builder 职责 1. 加载并验证 Active Recall 2. 验证记录属于当前用户 3. 加载模型所需最小业务上下文 4. 生成稳定、版本化输入 5. 脱敏处理 6. 计算 contentHash ## 禁止存储 JWT / Authorization Header / 模型 API Key / Cookie / 数据库连接信息 / 无关用户画像 / 未脱敏 Credential ## 验收标准 - [ ] Registry 注册成功 - [ ] 重复注册失败(幂等注册) - [ ] 非法输入被拒绝 - [ ] Snapshot 生成稳定(相同输入→相同 contentHash) - [ ] Snapshot 不含敏感字段 - [ ] Definition 元数据来自 M-AI-04-01 冻结契约 - [ ] 输入 Schema 版本化 - [ ] 单元测试通过 ## 建议执行顺序 第 2 个执行(依赖 M-AI-04-01)
wangdl added this to the M-AI-04 Active Recall 端到端迁移 milestone 2026-06-21 12:48:13 +08:00
Author
Owner

开发完成评论

完成内容

  • 创建 ActiveRecallJobDefinition 冻结常量 — 所有字段源自 M-AI-04-01 迁移契约
  • 创建 ActiveRecallSnapshotBuilder — 加载答案+问题、所有权校验、构建版本化脱敏快照、计算 contentHash
  • 创建 ActiveRecallRegistrationService — OnModuleInit 向 Registry 注册 Definition
  • AiJobModule 注册以上两个新 Provider
  • 24 个单元测试全部通过

修改/新增文件

  • src/modules/ai-job/active-recall-job-definition.ts — 新增, ActiveRecall JobDefinition 常量
  • src/modules/ai-job/active-recall-snapshot-builder.ts — 新增, 快照构建器
  • src/modules/ai-job/active-recall-registration.service.ts — 新增, 注册服务
  • src/modules/ai-job/active-recall-registration.service.spec.ts — 新增, 24 tests
  • src/modules/ai-job/ai-job.module.ts — 修改, 注册 2 个新 Provider

代码证据

  • active-recall-job-definition.ts:13-75:Definition 冻结常量,全部字段映射自契约
  • active-recall-snapshot-builder.ts:53-101:build() 方法 — findUnique 加载 → 所有权校验 → 构建快照
  • active-recall-snapshot-builder.ts:64answer.userId !== userId → ForbiddenException(P0 跨用户所有权修复)
  • active-recall-snapshot-builder.ts:114-120:computeHash() — SHA256 前 16 字符
  • active-recall-registration.service.ts:17-25:onModuleInit 注册 Definition
  • ai-job.module.ts:18-19:import 新服务
  • ai-job.module.ts:34-35:providers 注册
  • active-recall-registration.service.spec.ts:24 tests 覆盖 Registration + SnapshotBuilder

测试情况

  • 已运行命令:
    • npm run build
    • npx jest --testPathPatterns="active-recall-registration"
    • npx jest --testPathPatterns="ai-job"
  • 结果:
    • 构建通过
    • 新测试:1 suite, 24 passed, 0 failed
    • 全量 ai-job:10 suites, 188 passed, 18 skipped, 0 failed(无回归)

验收标准对照

  • Registry 注册成功 — active-recall-registration.service.spec.ts:36-47
  • 重复注册失败(幂等注册)— active-recall-registration.service.spec.ts:49-62
  • 非法输入被拒绝 — 4 个场景:答案不存在/用户不匹配/无关联问题/问题不存在
  • Snapshot 生成稳定 — active-recall-registration.service.spec.ts:193-203
  • Snapshot 不含敏感字段 — active-recall-registration.service.spec.ts:175-191
  • Definition 元数据来自 M-AI-04-01 冻结契约 — §3 §4 §6 §7 §8
  • 输入 Schema 版本化 — schemaVersion: 'active-recall-v1'
  • 单元测试通过 — 24/24

未完成 / 风险

  • 不创建真实 Job(目标限定)— 待 M-AI-04-05 集成
  • SnapshotBuilder 尚未集成到 AiJobCreationService — 待 M-AI-04-05 添加路由逻辑
  • 无 Migration(目标限定)

是否建议进入 Review

  • 是 — Definition 已注册、SnapshotBuilder 已实现且测试通过,可以进入 Review
## 开发完成评论 ### 完成内容 - 创建 `ActiveRecallJobDefinition` 冻结常量 — 所有字段源自 M-AI-04-01 迁移契约 - 创建 `ActiveRecallSnapshotBuilder` — 加载答案+问题、所有权校验、构建版本化脱敏快照、计算 contentHash - 创建 `ActiveRecallRegistrationService` — OnModuleInit 向 Registry 注册 Definition - 在 `AiJobModule` 注册以上两个新 Provider - 24 个单元测试全部通过 ### 修改/新增文件 - `src/modules/ai-job/active-recall-job-definition.ts` — 新增, ActiveRecall JobDefinition 常量 - `src/modules/ai-job/active-recall-snapshot-builder.ts` — 新增, 快照构建器 - `src/modules/ai-job/active-recall-registration.service.ts` — 新增, 注册服务 - `src/modules/ai-job/active-recall-registration.service.spec.ts` — 新增, 24 tests - `src/modules/ai-job/ai-job.module.ts` — 修改, 注册 2 个新 Provider ### 代码证据 - `active-recall-job-definition.ts:13-75`:Definition 冻结常量,全部字段映射自契约 - `active-recall-snapshot-builder.ts:53-101`:build() 方法 — findUnique 加载 → 所有权校验 → 构建快照 - `active-recall-snapshot-builder.ts:64`:`answer.userId !== userId` → ForbiddenException(P0 跨用户所有权修复) - `active-recall-snapshot-builder.ts:114-120`:computeHash() — SHA256 前 16 字符 - `active-recall-registration.service.ts:17-25`:onModuleInit 注册 Definition - `ai-job.module.ts:18-19`:import 新服务 - `ai-job.module.ts:34-35`:providers 注册 - `active-recall-registration.service.spec.ts`:24 tests 覆盖 Registration + SnapshotBuilder ### 测试情况 - 已运行命令: - `npm run build` - `npx jest --testPathPatterns="active-recall-registration"` - `npx jest --testPathPatterns="ai-job"` - 结果: - 构建通过 - 新测试:1 suite, 24 passed, 0 failed - 全量 ai-job:10 suites, 188 passed, 18 skipped, 0 failed(无回归) ### 验收标准对照 - [x] Registry 注册成功 — `active-recall-registration.service.spec.ts:36-47` - [x] 重复注册失败(幂等注册)— `active-recall-registration.service.spec.ts:49-62` - [x] 非法输入被拒绝 — 4 个场景:答案不存在/用户不匹配/无关联问题/问题不存在 - [x] Snapshot 生成稳定 — `active-recall-registration.service.spec.ts:193-203` - [x] Snapshot 不含敏感字段 — `active-recall-registration.service.spec.ts:175-191` - [x] Definition 元数据来自 M-AI-04-01 冻结契约 — §3 §4 §6 §7 §8 - [x] 输入 Schema 版本化 — `schemaVersion: 'active-recall-v1'` - [x] 单元测试通过 — 24/24 ### 未完成 / 风险 - 不创建真实 Job(目标限定)— 待 M-AI-04-05 集成 - SnapshotBuilder 尚未集成到 AiJobCreationService — 待 M-AI-04-05 添加路由逻辑 - 无 Migration(目标限定) ### 是否建议进入 Review - 是 — Definition 已注册、SnapshotBuilder 已实现且测试通过,可以进入 Review
Author
Owner

Non-blocking 问题修复

1. SnapshotBuilder 孤儿类 + 2. 接口签名不兼容 已修复

问题: ActiveRecallSnapshotBuilder.build(userId, answerId) 2 参数 vs SnapshotBuilderService.buildSnapshot(userId, targetType, targetId) 3 参数。且 AiJobCreationService 无 jobType 分派机制。

修复(不扩大 M-AI-04-02 范围):

  • 新增 buildSnapshot(userId, targetType, targetId) 方法 — 签名与 SnapshotBuilderService.buildSnapshot() 完全兼容
  • targetType='active_recall_answer' + targetId=answerId → 委托 build(userId, targetId)
  • 非法 targetType → BadRequestException
  • 代码头部增加 M-AI-04-05 集成说明注释

M-AI-04-05 集成方案(文档化):

// AiJobCreationService.createJob() 中按 jobType 分派:
const snapshot = input.jobType === 'active_recall'
  ? await this.activeRecallSnapshotBuilder.buildSnapshot(input.userId, input.targetType, input.targetId)
  : await this.snapshotBuilder.buildSnapshot(input.userId, input.targetType, input.targetId);
// targetType='active_recall_answer', targetId=answerId

修改文件:

  • active-recall-snapshot-builder.ts:+BadRequestException import, +集成说明注释, +buildSnapshot() 方法
  • active-recall-registration.service.spec.ts:+BadRequestException import, +3 tests (buildSnapshot 正常/非法 targetType/签名兼容)

测试: 27/27 passed (原 24 + 新增 3)

## Non-blocking 问题修复 ### 1. SnapshotBuilder 孤儿类 + 2. 接口签名不兼容 ✅ 已修复 **问题**: `ActiveRecallSnapshotBuilder.build(userId, answerId)` 2 参数 vs `SnapshotBuilderService.buildSnapshot(userId, targetType, targetId)` 3 参数。且 `AiJobCreationService` 无 jobType 分派机制。 **修复**(不扩大 M-AI-04-02 范围): - 新增 `buildSnapshot(userId, targetType, targetId)` 方法 — 签名与 `SnapshotBuilderService.buildSnapshot()` 完全兼容 - `targetType='active_recall_answer'` + `targetId=answerId` → 委托 `build(userId, targetId)` - 非法 targetType → `BadRequestException` - 代码头部增加 M-AI-04-05 集成说明注释 **M-AI-04-05 集成方案**(文档化): ```typescript // AiJobCreationService.createJob() 中按 jobType 分派: const snapshot = input.jobType === 'active_recall' ? await this.activeRecallSnapshotBuilder.buildSnapshot(input.userId, input.targetType, input.targetId) : await this.snapshotBuilder.buildSnapshot(input.userId, input.targetType, input.targetId); // targetType='active_recall_answer', targetId=answerId ``` **修改文件**: - `active-recall-snapshot-builder.ts`:+BadRequestException import, +集成说明注释, +`buildSnapshot()` 方法 - `active-recall-registration.service.spec.ts`:+BadRequestException import, +3 tests (buildSnapshot 正常/非法 targetType/签名兼容) **测试**: 27/27 passed (原 24 + 新增 3)
Author
Owner

Non-blocking 问题修复(第 2 轮)

3. Definition 与 SnapshotBuilder 的值重复硬编码 已修复

修复: SnapshotBuilder 注入 JobDefinitionRegistry,在 build() 中通过 this.registry.get('active_recall') 读取 prompt/model 配置。全部值来自 Definition,零重复硬编码。

修改:

  • active-recall-snapshot-builder.ts:构造函数新增 JobDefinitionRegistry 参数,build() 第 1 步调用 this.registry.get('active_recall') 读取配置
  • 测试新增 single-source-of-truth 用例:修改 Registry 返回的 Definition → Snapshot 自动跟随

4. temperature 不在 JobDefinition 类型中 已修复(文档化)

分析: JobDefinition 接口已冻结(ADR-003 §2.1,不得自行扩展),temperature 不在其中。AiGatewayService.generate() 硬编码 temperature: 0.3ai-gateway.service.ts:62)。

修复:

  • 新增常量 AI_GATEWAY_DEFAULT_TEMPERATURE = 0.3,附注释说明来源(ai-gateway.service.ts:62
  • 注释明确:"Snapshot 必须记录 Executor 实际将使用的 temperature 以保证重放一致性"
  • 若未来 AiGateway 的 temperature 变更,只需修改此常量一处

5. projectorKey 指向不存在的实现 已确认(增量开发正常状态)

  • active_recall_projector 预计在 M-AI-04-04 实现
  • 测试 projectorKey 已设置 验证 Definition 中的 key 为 'active_recall_projector'
  • M-AI-04-04 必须:实现 Projector → 注册到 RESULT_PROJECTORS multi-provider(ai-job.module.ts:38

测试结果

  • 本次修复:28/28 passed(新增 1 test: 单一事实来源验证)
  • 全量 ai-job:192 passed, 0 failed(无回归)
## Non-blocking 问题修复(第 2 轮) ### 3. Definition 与 SnapshotBuilder 的值重复硬编码 ✅ 已修复 **修复**: SnapshotBuilder 注入 `JobDefinitionRegistry`,在 `build()` 中通过 `this.registry.get('active_recall')` 读取 prompt/model 配置。全部值来自 Definition,零重复硬编码。 **修改**: - `active-recall-snapshot-builder.ts`:构造函数新增 `JobDefinitionRegistry` 参数,`build()` 第 1 步调用 `this.registry.get('active_recall')` 读取配置 - 测试新增 `single-source-of-truth` 用例:修改 Registry 返回的 Definition → Snapshot 自动跟随 ### 4. temperature 不在 JobDefinition 类型中 ✅ 已修复(文档化) **分析**: `JobDefinition` 接口已冻结(ADR-003 §2.1,不得自行扩展),`temperature` 不在其中。`AiGatewayService.generate()` 硬编码 `temperature: 0.3`(`ai-gateway.service.ts:62`)。 **修复**: - 新增常量 `AI_GATEWAY_DEFAULT_TEMPERATURE = 0.3`,附注释说明来源(`ai-gateway.service.ts:62`) - 注释明确:"Snapshot 必须记录 Executor 实际将使用的 temperature 以保证重放一致性" - 若未来 AiGateway 的 temperature 变更,只需修改此常量一处 ### 5. projectorKey 指向不存在的实现 ✅ 已确认(增量开发正常状态) - `active_recall_projector` 预计在 M-AI-04-04 实现 - 测试 `projectorKey 已设置` 验证 Definition 中的 key 为 `'active_recall_projector'` - M-AI-04-04 必须:实现 Projector → 注册到 `RESULT_PROJECTORS` multi-provider(`ai-job.module.ts:38`) ### 测试结果 - 本次修复:28/28 passed(新增 1 test: 单一事实来源验证) - 全量 ai-job:192 passed, 0 failed(无回归)
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/api-server#297
No description provided.