DSH / Atlas
2026-07-20implementedarchitecturearchived 2026-09-04

todo event types belong to their producer

todo 事件类型归其生产方所有

`SessionEventMap` is merge-extensible so each plugin can add durable records without making the core session package depend on every event producer. `todo/write` and its `TodoItem` payload are produced and interpreted by the todo domain, while core session only provides the generic append, replay, surface, and invariant extension mechanisms. Declaring todo-specific types or relationships in core would make the sessio

English

Problem

SessionEventMap is merge-extensible so each plugin can add durable records without making the core session package depend on every event producer. todo/write and its TodoItem payload are produced and interpreted by the todo domain, while core session only provides the generic append, replay, surface, and invariant extension mechanisms. Declaring todo-specific types or relationships in core would make the session spine own a plugin vocabulary it cannot produce or validate completely.

Decision

@deepseek-ai/dsh-tool-todo declares TodoItem and merges todo/write into @deepseek-ai/dsh-session/types from its type-only outlet. The package root and /client entrypoint re-export TodoItem, so host and browser consumers share one declaration without loading the todo plugin.

Consumers that inspect todo records use type-only imports plus explicit package dependencies and TypeScript project references. The emitted JavaScript has no todo import, and a composition does not need to mount the todo tool merely to search, transmit, or render a log that may contain todo/write.

The todo invariant companion owns both the payload rules and the event's relationship to an open turn. Core session's merge-extensible switch falls through for todo/write, while the todo companion rejects malformed snapshots and snapshots outside an open turn before append. It validates existing and newly announced sessions in one pass and advances a committed per-session turn trace for later events. Todo-specific append, replay, projection, and enclosure tests live with the todo package. The model-facing behavior remains owned by the todo_write feature decision.

Verification

Focused todo tool, invariant, projection, integration, and Loader-composition tests exercise the producer and its companion. Session-query extraction and client runtime/connection tests prove type-only consumers retain semantic todo handling. Workspace typecheck proves declaration merging through the explicit project graph; generated event, persistence, API, and module catalogs record the declaration site and dependency edges.

Alternatives considered

  • Keep the payload type in core as shared UI vocabulary — rejected because rendering reuse does not make core the producer or semantic owner of the durable event.
  • Narrow todo/write structurally in each consumer — rejected because duplicate payload declarations can drift and bypass the merge-extensible event map.
  • Require every consumer to mount the todo plugin — rejected because reading a durable record is a type and data dependency, not authorization to install a model-facing tool.

Consequences

The core session package does not export TodoItem or enforce todo relationships. A package that names or narrows todo/write declares a type-only dependency on dsh-tool-todo; consumers that treat unknown merged events generically need no dependency. The todo package is the single source for the event payload, client type, runtime validation, and open-turn rule.

中文

问题

SessionEventMap 可通过声明合并扩展,使每个插件都能添加持久记录,而无需让核心会话包依赖所有事件生产方。todo/write 及其 TodoItem payload 由 todo 领域生产和解释;核心会话只提供通用的追加、回放、surface 与不变量扩展机制。在核心中声明 todo 专属类型或关系,会让会话主干拥有一个它既不生产、也无法完整校验的插件词汇。

决策

@deepseek-ai/dsh-tool-todo 在其仅类型出口中声明 TodoItem,并通过 @deepseek-ai/dsh-session/types 的声明合并加入 todo/write。包根入口和 /client 入口重新导出 TodoItem,使 host 与浏览器消费方共享同一处声明,而无需加载 todo 插件。

检查 todo 记录的消费方使用仅类型导入,并声明显式包依赖与 TypeScript 项目引用。产出的 JavaScript 不含 todo 导入;组合仅为了搜索、传输或渲染可能含有 todo/write 的日志时,无需挂载 todo 工具。

todo 不变量配套插件同时拥有 payload 规则和事件必须位于开放轮次内的关系。核心会话的可合并扩展 switch 对 todo/write 走默认分支;todo 配套插件会在追加前拒绝格式错误或位于开放轮次之外的快照。它会单次校验现有会话与新发布的会话,并为后续事件推进逐会话的已提交轮次追踪状态。todo 专属的追加、回放、投影和轮次封闭测试与 todo 包放在一起。面向模型的行为仍由 todo_write 功能决策负责。

验证

聚焦的 todo 工具、不变量、投影、集成和 Loader 组合测试覆盖生产方及其配套插件。session-query 提取与客户端 runtime/connection 测试证明仅类型消费方仍能保留 todo 的语义处理。全工作区类型检查证明声明合并通过显式项目图生效;重新生成的事件、持久化、API 与模块目录记录声明位置和依赖边。

曾考虑的替代方案

  • 把 payload 类型留在核心中作为共享 UI 词汇——拒绝:渲染复用并不会让核心成为持久事件的生产方或语义所有方。
  • 让每个消费方各自按结构收窄 todo/write——拒绝:重复的 payload 声明会漂移,并绕过可合并扩展的事件表。
  • 要求每个消费方都挂载 todo 插件——拒绝:读取持久记录是类型和数据依赖,并不构成安装面向模型工具的授权。

后果

核心会话包不导出 TodoItem,也不强制 todo 关系。命名或收窄 todo/write 的包声明对 dsh-tool-todo 的仅类型依赖;只把未知合并事件作通用处理的消费方无需依赖它。todo 包是事件 payload、客户端类型、运行时校验和开放轮次规则的唯一来源。