Task Pipeline Architecture Addendum

Historical design input(2026-07-23 校准):本文保留 2026-05 的问题发现和 Task Orchestrator 思路,但不是现行 implementation specification。当前 Task V2 parity 和 Task V2+ 工程路线见 工程审计与实施基线;V3 proposal 不能自动覆盖本文记录的 V2 行为。

日期: 2026-05-31
用途: 对 Task Pipeline 设计产出 的补充说明。
背景: 2026-05-30 的 task pipeline 设计方向基本成立;2026-05-31 做了全系统 pipeline 调研后,需要把 task 放回 contacts / calls / messages / leads / contact_timeline / future AI tools 的整体架构里看。


结论

Task V2 的主方向没有问题,但它不能作为一个孤立 feature 落地。

应该保留的核心判断:

  • Task 是 actual work object。
  • Task lifecycle 应该是 open / closed,当前 DB pending / closed 可作为 implementation mapping。
  • no_answerleft_voicemailcallback_later 这类值是 progress,不是 final outcome。
  • AI 可以提出 task action proposal,但状态转换、幂等、权限、DNC、audit 必须由 code 执行。
  • Task Orchestrator 是必要的。

需要补强的地方:

Task Orchestrator 不是 task feature 内部的小 helper,而是 unified pipeline architecture 里的 shared mutation module。

也就是说,它应该服务:

  • contacts-analyzer
  • lead-processor
  • studio-api
  • SMS meaningful reply flow
  • retry / reprocess / onboarding backfill
  • future AI agent / tool calling

Task V2 和 Unified Pipeline 的关系

旧理解

Task Pipeline Design
  -> Task Orchestrator
  -> tasks / task_progress_events / contact_timeline

现在应该升级为

Unified Pipeline Architecture
  -> Shared Mutation Layer
      -> Task Orchestrator
      -> Contact Writer
      -> Timeline Writer
      -> Policy Guard

Task Orchestrator 是 shared mutation layer 的一部分,不是单独为 Tasks 页面服务的后端逻辑。


Task V2 需要修正/强调的点

1. task_progress_eventscontact_timeline 的关系

Task deliverable 里说 task_progress_events 是 progress source of truth,这个判断仍然成立。

需要更明确:

职责
task_progress_eventstask-level progress source of truth
contact_timelinecontact-level audit/feed projection

它们可以同时写,但不能互相替代。

原因:

  • contact_timeline 是用户可见的 contact feed。
  • task detail / attempt count / retry history 更适合从 task-level events 重建。
  • 现在 tasks/list.ts 用 closed sibling tasks 推 attempt_count,这是当前 schema 不足的表现。

2. closeResult 的 current state 和 target state 要分开写

当前代码事实:

TASK_CLOSE_RESULT 有 18 个值,其中包括 progress-like 值:

  • attempted
  • no_answer
  • left_voicemail
  • callback_later

Target architecture:

  • 这些值不应该继续作为 final outcome 使用。
  • 新 API 应该用 record_progress 表达。
  • 旧 API / 旧数据可以 compatibility 保留一段时间。

因此 task-enums.md 应继续记录 current code truth;task design doc 负责说明 target semantics。

3. contacts.actionNeededtasks.actionNeeded 要定义 source of truth

调研后更明确:

tasks = actual work object source of truth
contacts.actionNeeded / suggestedActions = contact-level summary or compatibility projection

否则 contacts-analyzer prompt 会同时生成 contact-level action 和 task-level action,长期会让 UI/API 不知道谁说了算。

Task V2 应该显式要求:

  • 任何需要前台执行的 human work 都必须变成 task。
  • contact-level action 只用于 summary / ranking / legacy compatibility。
  • 后续设计要决定是否 deprecate contact-level action fields。

4. Task Orchestrator 应该接受 code-only action

不要把 Task Orchestrator 理解成“AI taskDecisions 的执行器”。

它也应该处理 deterministic action:

来源示例
lead-processorcreate lead_outreach task
studio-apistaff close / record progress
SMS STOPDNC cascade close
retry/backfillidempotent re-application
future tool APIcreate_task / record_task_progress / close_task

也就是说:

AI proposal is one caller.
Code/system/manual actions are also callers.

5. Studio API close behavior 是 Phase 1 必查点

当前 PATCH /v2/tasks/closecloseResult = no_answer / left_voicemail 时:

  1. close 当前 task。
  2. 自动创建一个 follow-up task。

这和 Task V2 target model 冲突。

Target:

No Answer / Left Voicemail -> record_progress
Task remains open
dueAt may be updated
attemptCount increments from progress events

这个不一定第一步就改代码,但 Phase 1 design 必须把 API contract 改清楚。

6. Lead retry / backfill 必须走同一个 task contract

lead happy path 通过 LeadCreated event 创建 contact/task/timeline 是合理的。

但 retry/backfill path 不能只补 leads,漏掉 downstream task。

Task Orchestrator 的价值之一就是让这些入口可以 idempotently 调同一套 task creation contract。


Phase 1 推荐顺序

Phase 1A: Task Orchestrator contract

先不急着改所有代码,先把 contract 写清楚:

applyTaskAction({
  action: 'create' | 'update' | 'close' | 'record_progress',
  identity,
  actor,
  payload,
  idempotencyKey,
})

必须定义:

  • identity: contactPhone + storeId + franchiseId + accountId
  • actor: staff | contact_analysis | lead_webhook | system | ai_agent
  • action: mutation type
  • payload: typed per action
  • idempotencyKey: retry/backfill/tool safety
  • side effects: tasks + task_progress_events + contact_timeline

Phase 1B: Progress vs close API

定义两个不同 API:

POST /tasks/{taskId}/progress
POST /tasks/{taskId}/close

不要再用 close API 承担 progress update。

Phase 1C: contacts-analyzer prompt output cleanup

当前 taskDecisions[] 只有:

  • create
  • update
  • close

Target 应该补:

  • record_progress
  • create_closed 或等价 outcome action

但这个要在 Orchestrator contract 定下来之后再改 prompt。

Phase 1D: timeline projection

每个 task action 都应该生成 contact-level timeline projection,但 source of truth 不一定是 contact_timeline

建议:

task_progress_events -> task detail / attempt count
contact_timeline -> contact feed / audit

文档处理建议

保留

文档处理
../task-pipeline-deliverable-codex.md保留为 task target architecture
task-pipeline-design-brief.md保留为 task 设计思路来源
task-enums.md保留为 current code enum truth

新增/使用

文档处理
task-pipeline-architecture-addendum.md本文件,解释 task V2 如何接入 unified architecture
../../../unified-pipeline/research/unified-pipeline-reference-checklist.md下一轮调研/执行入口
../../../unified-pipeline/research/unified-pipeline-research-appendix.md代码调研结论和 Phase 1 判断

不建议现在做

不要直接把 task-enums.md 改成 future enum。

原因:

  • 它是 current code source-of-truth doc。
  • 当前 DB 仍然允许 18 个 closeResult
  • 如果在这里直接删/改 progress-like close results,会让工程读者误以为代码已经改了。

正确做法:

Current docs record current code.
Design docs describe target semantics.
Implementation plan tracks migration.