Files
Agent-System/.doc/ops/research/2026-09-15-module-decoupling-ipc-assessment.md
T
weichenandCursor 7647215513 docs(ops): land Phase 2 Track E/S/P plans onto a legal feature branch
Move the reviewed durable-event, HTTP envelope, and PI typed-result
designs off the docs/ prefix so Track E can start from latest dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 08:11:29 +00:00

9.9 KiB
Raw Blame History

title, status, created, updated, author, confidence
title status created updated author confidence
模块解耦与 IPC/RPC 交互现状评估(复核修订版) done 2026-09-15 2026-09-15 Cline high

调研:模块解耦与 IPC/RPC 交互现状评估

结论

  1. 系统采用模块化单体,不应把所有模块调用改成 IPC/RPC。当前已运行的外部传输边界有两条:Web 与 server 的 HTTP/SSE、Go server 与 PI Agent Runner 的 HTTP。cmd/events 和 FAV worker 是计划中的独立进程,不是已运行事实。
  2. 端口、组合根、事件信封、RunManifest、幂等键和 arch-check 提供了可执行的边界基础;import=0/event=0 只表示没有超出现有 allowlist/baseline 的新违规,不能证明语义解耦已经完成。
  3. 首要可靠性缺口是事件“部分生产、没有生产级消费闭环”。internal/events/pg.go 尚无原子 lease、ack/fail、retry/dead-letter 的完整实现;现有 dispatcher 测试覆盖 MemoryBus,不是 PostgreSQL 运行证据。
  4. 最大结构扩散源仍是 bizdev service locator。另有 docgov → docrevision 单向 canonical/hash 工具依赖、chat/coordinator 扇出和 intent → bizdev 依赖。此前“docgov↔docrevision 双向 import”的结论不成立。
  5. HTTP 错误信封与 PI Runner typed result 是独立协议债,不应阻塞持久事件链关闭。FAV 分支也不应成为 notify/projection 交付的前置条件。

1. 通信边界

边界 机制 当前状态
Web ↔ server /api/v1/* HTTP + SSE 已运行;错误信封仍未统一
Go ↔ PI Agent Runner HTTP + Bearer;health/run/cancel/search 已运行;结果仍依赖 legacy stdout/result.json 路径
单体内模块 消费者端口 + internal/app 组合根 已运行;bizdev locator 和部分直依赖仍扩大改动面
领域事件 PG envelope/delivery schema 写侧部分存在;生产 dispatcher 未闭环
cmd/events 计划中的独立 worker 尚未实现/部署
FAV worker 独立审计轨道 分支未整支合入;不得作为本轮验收前置

不建议把单体内端口改成 RPC。那会增加序列化、延迟、部分失败与运维成本,却不消除当前 locator、授权、幂等和事件消费缺口。

2. 已有契约与真实边界

已有且可校验

  • .doc/system-design/module-boundaries.yaml 与 internal/archtest 管理 import、SQL write、path 和 event 规则。
  • events.Envelope schema 1 包含 event/aggregate/correlation/causation/idempotency/digest/producer 等字段,并校验 digest 与敏感字段。
  • taskrun.RunManifest schema 1 使用 canonical JSON 与 SHA-256。
  • TaskRun 同 idempotency key 异 request digest 返回冲突;文档写使用 expected head/ETag。
  • backend 选择由服务端 allowlist 控制,出站数据经过 secret stripping。
  • module-boundaries.yaml 已有 event_producers 与 event_consumers 段。后续工作是补全并校验 runtime registry parity,不是新建段落。

尚未闭合

  • PGSink.Append/InsertEnvelope 已存在,但 ClaimIDs 仍是 SELECT-only claim;没有生产级 lease 获取、heartbeat、fenced ack/fail、retry、dead-letter 和 immutable attempt audit 闭环。
  • event_deliveries 每个 event/consumer 一行,只保存当前状态和累计 attempt;无法还原每次 lease/attempt 历史。
  • internal/events/replay.go 只检查 dry-run 与 consumer/operator/reason 等基础字段,尚未形成带认证主体、env/project/event scope、plan digest 和 apply 审计的应用用例。
  • docflow envelope 仍存在 Environment:"dev"、ProjectID:0,且 Fav.StageAgentCommit(ctx, 0, ...) 使用错误项目作用域。
  • 部分 server 路径临时构造 docflow.Commands,没有稳定注入 EventSink/UoW;不能假设 candidate-ready、downstream-impact、approved 三条链已经产生可供 shadow 的事件。
  • 闭包 hook 没有版本、重试、delivery 或 replay 记录。

3. 耦合点

3.1 bizdev service locator

bizdev.Service 暴露 Pool()/CAS()/DocGov()/DocRevision()/ProjectWorkflow()/FreeformDoc()/KB()/ContextManager()。调用方可以绕过端口取得数据库池和其他模块实现,令签名或构造变化向多包扩散。

整改应先加 no-new-callers 门禁,再逐调用方迁移,最后在一个 contract 提交删除 8 个 getter。门禁应禁止领域/用例 API 暴露或转发 pool/tx,同时允许 app/cmd 组合根向表属主构造器注入 pool,并允许登记属主从 opaque TxScope 解出 tx。

3.2 docgov 到 docrevision 的单向工具依赖

生产依赖方向是 docgov → docrevision。直接用途集中在 Markdown canonicalization 与 SHA helper;docrevision 不生产 import docgov。

目标不是“破双向环”,而是把 canonical Markdown + digest 提取为有行为、内聚、带 golden vectors 的共享模块,例如 internal/doccontent。它不应进入只放无行为值对象的 vocabulary。

3.3 chat、coordinator 与 intent

  • coordinator 仍以 bizdev.TaskRunRequest/Result 为词汇。
  • chat 编排跨多个模块,需按用例逐批迁入 chatflow。
  • intent 与 bizdev 的解绑是较小且独立的迁移,不应和 chat 大迁移绑成一个分支。

3.4 闭包桥与未接线事件

当前批准后的推进与通知仍可通过 docrevision.OnOutbox、docgov.AddOnApprovedHook 及组合根闭包执行。闭包在提交后的进程内调用不能提供 durable delivery、重试、dead-letter、replay 或 attempt audit。

不能直接删除闭包。正确顺序是:

  1. 证明生产入口在同一 UoW 写入领域变化、envelope 和目标 delivery。
  2. 对历史事件做 dry-run inventory,隔离 scope/schema/sequence 异常。
  3. 完成真实 PG dispatcher。
  4. shadow 只计算 intended outcome,不执行业务副作用。
  5. 以时间、样本和状态分支覆盖作为切换门。
  6. 按 notify、workflow advance、projection 独立切换和回滚。

4. 并发、数据与权限风险

并发

  • FOR UPDATE SKIP LOCKED 只有在 claim 事务同时更新 lease owner/token/until 并 RETURNING 时才完成所有权转移;当前 SELECT-only ClaimIDs 不够。
  • Fencing 不能只保护 ack。token 必须进入 consumer command,并在数据库副作用或 projection marker 的最终提交点校验。heartbeat 失败应取消 handler。
  • 同一 consumer/aggregate 最多一个 inflight;不同 aggregate 并行。领域版本可能稀疏,不能直接当无缺口事件序号。
  • at-least-once delivery 通过 inbox/唯一键/CAS/no-replace 得到 exactly-one visible outcome;不能声称 delivery 本身 exactly once。

历史数据

旧记录可能含 project 0、错误 environment、未知 consumer、未知 payload schema 或稀疏 aggregate version。启用 live claim 前必须生成 manifest,并分类 safe/repair/quarantine/expire。任何修复保留 old/new digest、operator、reason、approval;本计划不删历史数据。

权限

后台 consumer 使用按 env/consumer/action 约束的 service principal。处理事件时按 ProjectID/DocID 重读资源归属、成员/duty、workflow config revision、活动 stage 和当前状态。事件 actor 只用于审计,不能把历史用户权限带到延迟执行时。

Replay 必须是应用用例:管理员 capability、精确范围、reason/approval、dry-run plan digest、apply exact digest 和不可变审计。多项目或批量 apply 需要操作者与批准人分离。

日志、dead-letter 和 reconciliation 只能保存 ID、digest、typed error code 与字段 allowlist 生成的摘要,不能保存原始 payload、正文、SQL error、绝对路径、token 或 prompt。

5. 优先级建议

P0:Track E 持久事件交付

  1. 修正 docflow 生产入口、env/project 作用域和 UoW 原子写。
  2. 补全既有 event allowlist 与 runtime registry parity。
  3. 审计历史事件、sequence/checkpoint 模型和现有唯一约束。
  4. 实现 cmd/events 的 PG lease/heartbeat/fencing/attempt/dead-letter。
  5. notify、workflow advance、projection 逐个 shadow、live、回滚。
  6. 用真实 browser + PG + worker restart 证明刷新后正文恢复,无 projection-missing。

P1:Track S 结构解耦

  • D4:bizdev locator 调用方迁移与最终 getter 原子删除。
  • D5:stageflow 自有 use-case 类型,coordinator 解绑 bizdev DTO。
  • D6:提取 doccontent canonical 行为模块,移除单向工具依赖。
  • D7a:intent 单独解绑 bizdev。
  • D7b:chat 按用例迁入 chatflow。

这些单元分别 go/no-go,不作为事件可靠性 blocker 的关闭条件。

P2:Track P 独立协议

  • HTTP/SSE 错误信封另立 remediation;公开 details 必须按 code allowlist 并脱敏。
  • PI Runner 任务命名为 typed-result-v1 rollout,不混称“协议 v2”。typed 字段存在但无效时 fail closed;只有字段缺失且握手声明旧 Runner 时才允许 legacy。

6. 证据索引

事实 证据
模块化单体决策 .doc/adr/2026-09-14-modular-monolith-decoupling.md
PG delivery 当前实现 internal/events/pg.go、deploy/postgres/goose/00035_2026-09-14-durable-event-delivery.sql
MemoryBus 测试边界 internal/events/dispatcher_test.go、internal/events/bus.go
replay 当前校验 internal/events/replay.go
事件字段硬编码 internal/app/docflow/commands.go
闭包桥 internal/app/docnotify/subscriber.go、internal/docgov/engine.go、internal/app/app.go
bizdev locator internal/bizdev/service.go:229-260
单向 canonical 依赖 internal/docgov/lease.go、internal/docrevision canonical helper
allowlist 已存在 .doc/system-design/module-boundaries.yaml

建议动作

下一项只立 Track E 的 E0A:事件生产、契约与历史数据门。Dispatcher 必须保持 off,直到 PG 测试证明事件源和旧数据分类正确。完整执行计划见 Phase 2 持久事件交付与后续解耦路线。