Skip to content

Lift channel-runtime delivery target to typed OutboundTarget sub-message (oneof per platform) #408

@eanzhao

Description

@eanzhao

Background

Per PR #403 review comment, the typed Lark receive-target landed in PR #403 as flat lark_receive_id + lark_receive_id_type fields directly on platform-agnostic state messages:

  • UserAgentCatalogEntry
  • UserAgentCatalogUpsertCommand
  • UserAgentCatalogDocument
  • WorkflowAgentState / WorkflowAgentInitializedEvent / InitializeWorkflowAgentCommand
  • SkillRunnerOutboundConfig

These messages all also carry a platform field. Today only api-lark-bot reaches them, so the Lark coupling is fine in practice — but if Telegram / Discord / Slack are added the natural extension is per-platform field bolt-ons (telegram_chat_id, discord_channel_id, …) which violate CLAUDE.md's "核心语义强类型 / 命名语义优先" guidance.

Proposed shape

Lift the per-platform receive-target into a typed sub-message with a oneof:

message OutboundTarget {
  oneof target {
    LarkReceiveTarget lark = 1;
    TelegramChatTarget telegram = 2;
    // ...
  }
}

message LarkReceiveTarget {
  string receive_id = 1;
  string receive_id_type = 2; // open_id / chat_id / union_id / email / user_id
}

message TelegramChatTarget {
  string chat_id = 1; // ...
}

Wire as a single OutboundTarget outbound_target = N; field on each of the messages listed above; deprecate / migrate the flat lark_receive_id* fields in a follow-up cycle.

Migration considerations

  • Both UserAgentCatalogEntry.platform and the new oneof discriminator carry the platform — pick one and remove the redundancy at the same time.
  • UserAgentCatalogProjector.Materialize and UserAgentCatalogQueryPort.ToEntry need to round-trip the sub-message through the projection.
  • Existing persisted state (Lark-only) must continue to deserialize: keep the flat fields as reserved / sub-message-only after migration, with a one-time backfill from the flat pair.
  • Trigger: do this when the second platform's actual delivery code lands (it shouldn't be added speculatively).

Out of scope

Reference

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions