详细设计 4/4:异常处理、并发与测试

所有不可执行分支必须同时具备:用户可见原因、诊断事件、无部分副作用。

组件边界

Resolvers(只读)

ProjectResolver

WorktreeResolver

StoryContextResolver

TapdWorkflowResolver

Deciders(纯函数)

StartStoryDecision

ContextMergeDecision

TapdSyncSuggestion

CleanupDecision

Handlers(副作用)

保存资料

创建 worktree

启动 session

确认式 TAPD 回写

原子性与并发

资料编辑使用 context_revision 乐观锁:页面提交旧 revision 时返回 409 和最新数据,禁止静默覆盖 AI 或其他页面的更新。

同一 Story 的项目、文档、变更项批量保存与事件日志在一个 SQLite 写事务内完成。

创建 worktree 使用项目级进程内锁 + 文件锁,锁内再次解析 Git worktree 事实,防止两个 Story 同时抢同一路径或分支。

SQLite 同时只能有一个写事务,因此事务保持短小;Git 扫描和外部 API 调用不放在 DB 事务内。

失败处理

失败行为反馈码
项目路径不存在不创建 worktree,不启动 sessionproject_path_missing
Git 命令失败/超时保留原资料,不猜测状态git_command_failed / timeout
部分项目 worktree 创建失败本次启动失败;清理本次新建且 clean 的 worktree,原有 worktree 不动worktree_prepare_partial
资料 revision 冲突拒绝覆盖,返回最新快照和冲突字段context_revision_conflict
TAPD 拉取失败显示本地缓存为 stale;不改变本地执行状态tapd_fetch_failed
TAPD 回写失败建议保持 pending,允许重试tapd_writeback_failed
Session 启动失败worktree 保留;Story 不进入 activesession_start_failed

测试层次

单元测试:状态映射、资料合并、注入 Markdown、worktree 决策表、TAPD 回写建议。

DB 测试:迁移、外键/唯一约束、事务回滚、revision 冲突、级联清理。

Git 集成测试:临时仓库创建两个 Story worktree;分支占用、路径冲突、stale、dirty cleanup。

API 测试:Story 资料 CRUD、refresh、start、cleanup preview/confirm、TAPD suggestion/confirm。

Prompt 回归:新 session、恢复、重试都注入相同 revision;正文不被自动展开。

生命周期回归:sync 创建 candidate 且绝不调用 start_story_async;本地完成绝不直接调用 TAPD 更新。

本期范围

P0:结构化资料、Web/API 编辑、worktree 自动创建与校验、session 注入、单 Story 自动发现、TAPD 回写建议。

不在 P0:TAPD Webhook、生产部署平台探测、自动执行 DDL/Nacos、自动删除 worktree、跨机器路径同步。