diff --git a/docs/architecture/adr-003-unified-ai-job-engine.md b/docs/architecture/adr-003-unified-ai-job-engine.md index 42c7094..395252a 100644 --- a/docs/architecture/adr-003-unified-ai-job-engine.md +++ b/docs/architecture/adr-003-unified-ai-job-engine.md @@ -115,7 +115,27 @@ export class AiJobLifecycleRepository { } ``` -**禁止**:业务代码直接调用 `prisma.aiJob.update({ where: { id }, data: { lifecycleStatus: '...' } })` 或 `this.repository.updateJobStatus()` 写入 `lifecycleStatus`。 +**禁止**:**新 Engine 创建的新 Job** 的业务代码直接调用 `prisma.aiJob.update()` 写入 `lifecycleStatus`。 + +#### 1.4.1 过渡期双写路径 + +M-AI-03 期间存在两条 lifecycleStatus 写入路径: + +| 路径 | 写入方 | 适用 Job | 生命周期 | +|------|--------|---------|---------| +| **新** | `AiJobLifecycleRepository` | 通过 `AiJobService.createJob()` 创建的新 Job(ai-interactive / ai-background 队列) | M-AI-03 起永久 | +| **旧** | `AiAnalysisRepository.updateJobStatus()`(`ai-analysis.repository.ts:35-46`) | 通过旧 `AiAnalysisService` 创建的旧 Job(ai-analysis 队列) | M-AI-04/M-AI-05 迁移完成后删除 | + +**不冲突的原因**:两条路径操作的 Job 实例互斥——旧路径的 Job 由 `AiAnalysisService` 创建并路由到 `ai-analysis` 队列,新路径的 Job 由 `AiJobService` 创建并路由到 `ai-interactive` / `ai-background` 队列。§12 声明 M-AI-03 不修改 `AiAnalysisWorker`,因此旧路径保持原样,新路径独立运作。ADB"唯一入口"指新 Engine 范围内。 + +**迁移计划**: + +``` +M-AI-03: AiJobLifecycleRepository 就绪,仅 Synthetic Job 使用 +M-AI-04: active-recall 生产者切换到 AiJobService → 走新路径 +M-AI-05: feynman-evaluation 生产者切换 → 旧路径完全停用 +M-AI-05 末: 删除 AiAnalysisRepository.updateJobStatus() 中的 lifecycleStatus 写入 +``` #### 1.5 Legacy `status` Shadow Write @@ -447,8 +467,10 @@ interface AiJobPayload { createdAt: string; } -// BullMQ jobId 格式: "{queueName}:{jobType}:{idempotencyKey}" -// 例如: "ai-interactive:active-recall:user123_20260620_001" +// BullMQ jobId 格式: "{queueName}:{userId}:{jobType}:{idempotencyKey}" +// 例如: "ai-interactive:user123:active-recall:user123_20260620_001" +// userId 必须包含:不同用户使用相同 idempotencyKey 时,BullMQ 层面不会误判为重复 +// (Outbox dedupeKey 已包含 userId,BullMQ jobId 对齐此设计) ``` #### 3.3 Worker 进程注册边界