Skip to content

收口 Feishu projector card Operation builder #717

Description

@kxn

父 issue

背景

#713 的 A/B/C 已完成:daemon recovery pipeline、daemon async result contract、Feishu setup/autoconfig facade 都已收口。重新评估当前代码后,下一处仍值得优先治理的是 Feishu projector 的 Operation 构造边界。

当前 internal/adapter/feishu/projector.go 和相邻 projector 文件中仍有多处手写 Operation{...},重复组合这些跨切面规则:

  • GatewayID / SurfaceSessionID / ChatID 基础字段。
  • OperationSendCardOperationUpdateCard 的 message id 判定。
  • ReplyToMessageID reply lane 只应作用于新发送卡片/文本/图片。
  • CardUpdateMulticardEnvelopeV2rawCardDocument(...) / header subtitle。
  • temporary session header 注入。
  • theme fallback 与 card body/elements 同步。

这类重复不是视觉问题,而是 correctness / maintainability 问题:新增 payload 时容易漏 reply lane、temporary session header、patchable update_multi、card envelope 或 message id update 语义。

范围

本 issue 只覆盖 Feishu projector 把 eventcontract.Event 投影为 Operation 的 card operation construction 边界:

  • 普通卡片 payload 的 send/update 判定。
  • projector card operation 的基础字段填充。
  • reply lane、temporary session header、card envelope、theme/body/elements 同步。
  • 与这些规则直接相关的结构测试和现有 projector 回归。

不覆盖 gateway transport apply、callback payload 解析、card 视觉改版、业务 read model 生成或 final markdown normalize 语义变更。

相关文档

  • docs/general/feishu-card-api-constraints.md
  • docs/general/feishu-card-content-context-guidelines.md
  • docs/general/feishu-card-ui-state-machine.md
  • docs/general/issue-orchestration-workflow.md

涉及文件

预计涉及:

  • internal/adapter/feishu/projector.go
  • internal/adapter/feishu/projector_exec_command_progress.go
  • internal/adapter/feishu/projector_thread_history.go
  • internal/adapter/feishu/card_renderer.go
  • internal/adapter/feishu/card_header_context.go
  • internal/adapter/feishu/*projector*_test.go

默认不修改:

  • internal/adapter/feishu/gateway_runtime*.go
  • internal/core/orchestrator/**
  • internal/core/control/** 的 read model contract

建议范围

  1. 先补结构测试,锁定普通 card operation path 应通过统一 builder,而不是在多个 case 中重复设置 envelope/raw document/reply/update 组合。
  2. 增加 projector 内部 card operation spec/builder,覆盖 GatewayIDSurfaceSessionIDChatID、title/body/theme/elements、patchable message id、reply lane、temporary header。
  3. 逐步迁移 projectEventBase 中普通卡片 payload,以及 projectExecCommandProgress / projectThreadHistory 的同类路径。
  4. 对 final reply split、exec progress split 里的 transport-size probe 保持谨慎:只在不改变测量语义时复用 helper,否则保留手写临时 op 并写明理由。
  5. 跑目标 projector 测试、全量测试、文件长度检查和 Feishu card guardrail 复核。

目标

建立 projector 内部统一的 card Operation builder / factory,让常见卡片投影路径通过一个入口设置基础字段、send/update 判定、reply lane、temporary session header、card envelope 与 raw card document。

非目标

  • 不改变现有 Feishu 卡片视觉、文案或用户语义。
  • 不重写整个 projector 架构。
  • 不迁移到 CardKit streaming 或改变 message.patch 策略。
  • 不扩大到 gateway transport、callback parsing、menu/action payload schema。
  • 不改变 final reply markdown split、exec progress 分卡预算算法或 path/target picker read model。

完成标准

  • projectEventBase 中常见卡片 payload 不再各自手写完整 Operation{... cardEnvelope/card ...} 组合,而是复用统一 builder。
  • projectExecCommandProgressprojectThreadHistory 这类相邻 projector path 至少覆盖同一类 send/update + reply lane builder,避免继续形成第二套实现。
  • 需要保留手写 Operation 的路径必须有明确理由,例如 text/image/reaction/delete 或 transport-size probe 只构造临时 payload。
  • 现有卡片渲染输出行为保持等价,目标 projector 测试和全量测试通过。
  • Feishu card API constraints、card content context、Feishu card UI state-machine guardrail 已检查;若行为确实未变,文档无需更新,但需要在收尾中记录检查结论。

依赖

信息索引

当前重点代码:

  • internal/adapter/feishu/projector.go
  • internal/adapter/feishu/projector_exec_command_progress.go
  • internal/adapter/feishu/projector_thread_history.go
  • internal/adapter/feishu/projector_exec_command_progress_split.go
  • internal/adapter/feishu/projector_final_split.go
  • internal/adapter/feishu/card_renderer.go
  • internal/adapter/feishu/card_header_context.go

相关文档:

  • docs/general/feishu-card-api-constraints.md
  • docs/general/feishu-card-content-context-guidelines.md
  • docs/general/feishu-card-ui-state-machine.md

实现参考

建议先做一个内部 builder,优先覆盖普通 card operation,不碰非 card operation:

  • 输入:event、chat id、title/body/theme/elements、可选 message id、patchable/update_multi、temporary session label、subtitle/title tag。
  • 输出:完整 Operation,默认 OperationSendCard;有 message id 时转 OperationUpdateCard 并清空 reply lane;新发送时按 event delivery lane 应用 reply。
  • builder 内部统一设置 GatewayIDSurfaceSessionIDChatIDcardEnvelopeV2rawCardDocument(...)
  • 对 final reply / exec progress split 里的 transport-size probe,可以先保持手写临时 op,或只接入一个不带 event 的 render helper;不要为了统一而改变预算测量对象。
  • 对 text/image/reaction/delete operation 不强行纳入 card builder。

建议先用结构测试锁定:普通 projector path 不应再在 projectEventBase 内重复设置 cardEnvelope: cardEnvelopeV2card: rawCardDocument(...) 多次;允许 list 要明确。

检查参考

目标检查:

  • go test ./internal/adapter/feishu -run 'Projector|ExecCommandProgress|ThreadHistory|Final|PathPicker|TargetPicker|Request|Selection|Plan|Notice' -count=1
  • go test ./internal/adapter/feishu -count=1
  • go test ./...
  • bash scripts/check/go-file-length.sh && git diff --check

Guardrail 检查:

  • 对照 docs/general/feishu-card-api-constraints.md:确认没有增加卡片体积、更新频率或交互模式。
  • 对照 docs/general/feishu-card-content-context-guidelines.md:确认没有把动态文本新塞回 raw markdown。
  • 对照 docs/general/feishu-card-ui-state-machine.md:确认 callback payload、inline replace、old-card/freshness 语义未变化;若有变化必须同步文档。

收尾参考

执行决策

  • 是否拆分:不再拆。本 issue 是 调研核心大包与高耦合结构拆分方案 #713 的 D 子执行单元,范围单一,验证面集中在 Feishu projector/card projection。
  • 当前执行单元:Projector cross-cutting operation builder 收口。
  • verifier:需要。该 issue 改动 Feishu projector 结构,虽然目标是行为等价,但默认做独立 verifier。

执行快照

  • 当前阶段:plan
  • 当前执行点:issue body 已补齐执行闭包字段,等待 prepare/lint 后进入实现。
  • 已完成:从 调研核心大包与高耦合结构拆分方案 #713 复核 A/B/C 后确认 D 仍是下一优先级;识别 Operation 构造重复点。
  • 下一步:切换状态到 status:implementable-now,运行 issue workflow prepare/lint;通过后按 TDD/结构测试开始实现。
  • 当前阻塞:无产品决策阻塞。
  • 最后一致状态:master/origin/master 在 328f93fa,工作区干净。
  • 未完成尾项:prepare、lint、实现、验证、verifier、回卷 调研核心大包与高耦合结构拆分方案 #713、commit/push、close。
  • 恢复步骤:读取本 issue 与 调研核心大包与高耦合结构拆分方案 #713;重新确认 internal/adapter/feishu/projector*.go 的 Operation 构造现状;先补结构测试再实现 builder。

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:feishuFeishu/Lark integration, gateway, projector, or previewmaintainabilityRefactors, code structure, and long-term maintainability workstatus:implementable-nowReady to implement with current issue body and context

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions