# Decisions ## 核心决策 | 决策 | 选择 | 理由 | |---|---|---| | 领域拆分 | 新增 `chat_session` 和 `diagnosis_run` | 会话元数据和一次诊断执行的生命周期不同,继续塞在一张表会导致上下文膨胀和边界混淆 | | Trace 明细 | 复用 `agent_step` / `tool_invocation`,增加 `run_id` | 现有明细表已经能表达 Trace,隔离需要 run key,不需要新事件模型 | | API 身份 | `runId = "run-" + UUID` | 外部 ID 不依赖数据库自增 ID,碰撞风险低 | | Trace 兼容 | 缺少 `runId` 时按 `created_at DESC, id DESC` 解析 latest run | 保留旧客户端兼容性,避免 feedback/eval 更新 `updated_at` 后改变 latest 判定 | | 历史迁移 | 每条旧 `diagnosis_session` 生成一条 compatibility run | 旧混合数据没有真实轮次边界,不能伪造多 run 历史 | | Feedback fallback | 缺少 `runId` 时短期绑定 latest run 并返回 `fallbackToLatestRun=true` | 老客户端可继续工作,同时让歧义可观测 | | Case provenance | 新自动案例写 `case_library.diagnosis_id = run_id` | 保留旧列,文档声明过渡语义 | | AIOps 范围 | 同一个 change 内完成 AIOps run isolation | AIOps 是一等 Trace 入口,不能留下同类混合 trace bug | | 所有权校验 | 服务层校验 run/session ownership,暂不加 DB 外键 | 兼容历史 orphan rows 和回滚窗口 | ## 用户确认 - 选择拆 `chat_session` 和 `diagnosis_run`,不只是在旧表加字段。 - `chat_session` 第一阶段只保存元数据,不保存完整对话正文。 - 完整多轮对话历史继续放在 Redis `SessionContext.messageHistory`。 - `runId` 是正式 API 字段。 - Trace 缺少 `runId` 时短期默认查 latest run。 - Feedback 缺少 `runId` 时短期 fallback,长期可再收紧。 - 每次有效 Chat/AIOps 都创建 run。 - 不新增 `diagnosis_trace` / `trace_event` 主表。 - 旧 `diagnosis_session` 保留用于历史和回滚,新代码不再写新执行态。 - demo 脚本和 Trace UI 做最小 `runId` 支持。 ## 接口影响 级别:L4。 - 新 API 响应字段:`runId`。 - Trace API 新 query 参数:`runId`。 - 新 API:`GET /api/chat/session/{sessionId}/runs`。 - Feedback request 新增 optional/preferred `runId`。 - Feedback response 新增 bound `runId` 和 `fallbackToLatestRun`。 - `/api/ai_ops` SSE 保持 event name `message`,新增 `type=metadata` 消息。 - DB contract 新增两张表和两个 `run_id` 列。 - 旧 `sessionId` only 调用仍兼容,但 fallback 必须可观测。 ## 风险接受 - 历史混合 trace 无法真实拆分,只能作为 compatibility run。 - 上下文传播同时依赖 `RunnableConfig.metadata` 和 `SessionContextHolder`,后续改动必须注意 `sessionId/runId` 同步。 - `case_library.diagnosis_id` 在过渡期存在 `session_id` 和 `run_id` 两种语义。 - 缺少 `runId` 的 Feedback 仍有歧义,后续客户端迁移完成后可收紧为参数错误。