[M-AI-06-06] 将 Feynman Parent Projector 接入 ReviewCard Child Job #317

Closed
opened 2026-06-21 18:13:13 +08:00 by wangdl · 1 comment
Owner

类型 / 标签

  • backend / feynman / review-card / feature-flag

风险等级

P0 — 入口路由错误会导致双执行或请求丢失;Parent/Child 关联断裂会导致 ReviewCard 丢失

依赖

  • M-AI-06-02(事务创建能力)
  • M-AI-06-03(Definition + Snapshot)
  • M-AI-06-04(Executor + 验证)
  • M-AI-06-05(Projector + 幂等)

目标

在 Feynman Parent Projector 中原子创建 ReviewCard Child Job,并在 Legacy Event 和 Child Job 之间进行互斥路由。

Feature Flag

新增或复用 FEYNMAN_REVIEW_CARD_MODE,值:legacy_event / child_job。支持用户白名单。

legacy_event

保持当前行为:Parent succeeded → 发布 ai.analysis.completed → ReviewCardSubscriber。

child_job

在 Parent Projector 事务内完成:Feynman Result + FocusItem + Parent Artifact + ReviewCard Child Job + Child Snapshot + Child Outbox + Parent Job succeeded。

事务成功后:不发布会触发旧 ReviewCardSubscriber 的同类事件;或事件必须携带明确标识,使 Subscriber 忽略该请求。

Child Job 字段

至少包含:userId = parent.userId、parentJobId = parent.id、jobType = review_card_generation、triggerType = child_job、targetType = ai_analysis_result、targetId = result.id、idempotencyKey = review-card:feynman:。最终以契约为准。

Parent Projector 幂等

重复执行 Parent Projector:不重复创建 Result、FocusItem、Child Job、Child Snapshot、Child Outbox,不发布 Legacy Event。

失败语义

Child 创建失败

由于 Child 创建属于 Parent Projector 事务:Parent Projector 整体回滚,Parent 不得进入 succeeded。

Child 执行失败

Parent 已经成功:Parent = succeeded、Child = failed。不得回滚 Parent 结果。

回滚

切换 child_job → legacy_event 后:新 Parent 使用旧事件、已创建 Child Job 继续完成、不得把同一个 Parent 再送入 Legacy Event、已生成 ReviewCard 保留、不需要数据库回滚。

可观测性

最少记录:parentJobId、childJobId、userId、sourceResultId、reviewCardMode、childLifecycleStatus、cardCount、errorCode、durationMs。

约束

  • 不删除 Subscriber / 不删除旧 Workflow
  • 不修改 Active Recall / 不修改 Quiz
  • 不新增 Migration / 不在事务内调用 AI

验收标准

  • Parent 和 Child 原子关联
  • 两种模式互斥
  • 无双生成
  • Parent 重试不重复 Child
  • Child 失败不改变 Parent
  • 回滚有效
  • 单元和集成测试通过

建议执行顺序

第 6 个执行(依赖 02+03+04+05 全部就绪)

## 类型 / 标签 - backend / feynman / review-card / feature-flag ## 风险等级 P0 — 入口路由错误会导致双执行或请求丢失;Parent/Child 关联断裂会导致 ReviewCard 丢失 ## 依赖 - M-AI-06-02(事务创建能力) - M-AI-06-03(Definition + Snapshot) - M-AI-06-04(Executor + 验证) - M-AI-06-05(Projector + 幂等) ## 目标 在 Feynman Parent Projector 中原子创建 ReviewCard Child Job,并在 Legacy Event 和 Child Job 之间进行互斥路由。 ## Feature Flag 新增或复用 FEYNMAN_REVIEW_CARD_MODE,值:legacy_event / child_job。支持用户白名单。 ### legacy_event 保持当前行为:Parent succeeded → 发布 ai.analysis.completed → ReviewCardSubscriber。 ### child_job 在 Parent Projector 事务内完成:Feynman Result + FocusItem + Parent Artifact + ReviewCard Child Job + Child Snapshot + Child Outbox + Parent Job succeeded。 事务成功后:不发布会触发旧 ReviewCardSubscriber 的同类事件;或事件必须携带明确标识,使 Subscriber 忽略该请求。 ## Child Job 字段 至少包含:userId = parent.userId、parentJobId = parent.id、jobType = review_card_generation、triggerType = child_job、targetType = ai_analysis_result、targetId = result.id、idempotencyKey = review-card:feynman:<parentJobId>。最终以契约为准。 ## Parent Projector 幂等 重复执行 Parent Projector:不重复创建 Result、FocusItem、Child Job、Child Snapshot、Child Outbox,不发布 Legacy Event。 ## 失败语义 ### Child 创建失败 由于 Child 创建属于 Parent Projector 事务:Parent Projector 整体回滚,Parent 不得进入 succeeded。 ### Child 执行失败 Parent 已经成功:Parent = succeeded、Child = failed。不得回滚 Parent 结果。 ## 回滚 切换 child_job → legacy_event 后:新 Parent 使用旧事件、已创建 Child Job 继续完成、不得把同一个 Parent 再送入 Legacy Event、已生成 ReviewCard 保留、不需要数据库回滚。 ## 可观测性 最少记录:parentJobId、childJobId、userId、sourceResultId、reviewCardMode、childLifecycleStatus、cardCount、errorCode、durationMs。 ## 约束 - 不删除 Subscriber / 不删除旧 Workflow - 不修改 Active Recall / 不修改 Quiz - 不新增 Migration / 不在事务内调用 AI ## 验收标准 - [ ] Parent 和 Child 原子关联 - [ ] 两种模式互斥 - [ ] 无双生成 - [ ] Parent 重试不重复 Child - [ ] Child 失败不改变 Parent - [ ] 回滚有效 - [ ] 单元和集成测试通过 ## 建议执行顺序 第 6 个执行(依赖 02+03+04+05 全部就绪)
wangdl added this to the M-AI-06 Feynman ReviewCard 子 Job 与可靠生成 milestone 2026-06-21 18:13:13 +08:00
Author
Owner

开发完成评论

完成内容

  • 修改 FeynmanProjector:注入 AiJobCreationService、ReviewCardGenerationSnapshotBuilder、FeatureFlagService、EventBusService
  • 新增 routeReviewCardGeneration() 方法:根据 FEYNMAN_REVIEW_CARD_MODE 标志路由
  • child_job 模式:在同一事务中创建 Child Job + Snapshot + Outbox
  • legacy_event 模式(默认):保留 EventBus 路径
  • FeatureFlag 查询失败 → 安全回退到 legacy_event
  • idempotencyKey = review-card:feynman:
  • 创建 ReviewCardChildJob Artifact 关联父 Job

修改文件

  • src/modules/ai-job/feynman-projector.ts — 修改 (+132 / -18)
  • src/modules/ai-job/feynman-projector.spec.ts — 修改 (+165 / +3, 9 tests)

代码证据

  • feynman-projector.ts:193-200 — FeatureFlag 路由 + 安全回退
  • feynman-projector.ts:215-250 — createReviewCardChildJob(): Snapshot build + createInTransaction
  • feynman-projector.ts:236-243 — Child Job 创建参数
  • feynman-projector.ts:246-256 — ReviewCardChildJob Artifact 写入父 Job

测试情况

  • FeynmanProjector: 31 passed (22 old + 9 new)
  • Regression: 22 suites, 482 passed, 0 failed

新增测试覆盖

Scenario Status
legacy_event mode: no Child Job OK
child_job mode: Child Job via createInTransaction OK
idempotencyKey format correct OK
targetId = fe_ OK
Snapshot has correct weaknesses/strengths OK
Entry idempotency: no duplicate Child Job OK
FeatureFlag failure -> safe fallback OK
childJobId written to Parent Artifact OK
legacy_event does not trigger child_job path OK

是否建议进入 Review

  • YES - proceed to M-AI-06-07 (Real E2E)
## 开发完成评论 ### 完成内容 - 修改 FeynmanProjector:注入 AiJobCreationService、ReviewCardGenerationSnapshotBuilder、FeatureFlagService、EventBusService - 新增 routeReviewCardGeneration() 方法:根据 FEYNMAN_REVIEW_CARD_MODE 标志路由 - child_job 模式:在同一事务中创建 Child Job + Snapshot + Outbox - legacy_event 模式(默认):保留 EventBus 路径 - FeatureFlag 查询失败 → 安全回退到 legacy_event - idempotencyKey = review-card:feynman:<parentJobId> - 创建 ReviewCardChildJob Artifact 关联父 Job ### 修改文件 - src/modules/ai-job/feynman-projector.ts — 修改 (+132 / -18) - src/modules/ai-job/feynman-projector.spec.ts — 修改 (+165 / +3, 9 tests) ### 代码证据 - feynman-projector.ts:193-200 — FeatureFlag 路由 + 安全回退 - feynman-projector.ts:215-250 — createReviewCardChildJob(): Snapshot build + createInTransaction - feynman-projector.ts:236-243 — Child Job 创建参数 - feynman-projector.ts:246-256 — ReviewCardChildJob Artifact 写入父 Job ### 测试情况 - FeynmanProjector: 31 passed (22 old + 9 new) - Regression: 22 suites, 482 passed, 0 failed ### 新增测试覆盖 | Scenario | Status | |----------|--------| | legacy_event mode: no Child Job | OK | | child_job mode: Child Job via createInTransaction | OK | | idempotencyKey format correct | OK | | targetId = fe_<parentJobId> | OK | | Snapshot has correct weaknesses/strengths | OK | | Entry idempotency: no duplicate Child Job | OK | | FeatureFlag failure -> safe fallback | OK | | childJobId written to Parent Artifact | OK | | legacy_event does not trigger child_job path | OK | ### 是否建议进入 Review - YES - proceed to M-AI-06-07 (Real E2E)
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#317
No description provided.