Files

219 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Chat Diagnosis StateGraph Real Nodes Decisions
## Question Pool
| # | 维度 | 问题 | 模式 | 状态 |
|---|---|---|---|---|
| Q1 | 边界 | 阶段 2 是否切换 ChatService/DB/Trace? | user-interview(六阶段已确认) | 已解决 |
| Q2 | 复用 | 新 Nodes 如何避免复制 Hook/ChatService 解析与安全渲染? | evidence-driven | 已解决 |
| Q3 | Agent | Adapter 如何调用真实 ReactAgent 并保留 Hook/ToolCallback/run config? | evidence-driven | 已解决 |
| Q4 | Gatekeeper | 显式 Node 如何保证当前 run、单次调用和 fail-closed 标准化? | evidence-driven | 已解决 |
| Q5 | 安全 | passed checked bindings 如何投影为 verified output/evidence? | evidence-driven | 已解决 |
| Q6 | 补证据 | 哪些 facts 可触发 evidence retry,completed queries 如何表达? | evidence-driven | 已解决 |
| Q7 | Fallback | 前置验证失败与 Composer 后置失败可分别使用哪些材料? | evidence-driven | 已解决 |
| Q8 | Prompt | 阶段 2 是否立即修改共享 Verifier Prompt? | evidence-driven | 已解决 |
| Q9 | 验收 | 阶段 2 是否需要单元/集成测试与 E2E? | evidence-driven + user rule | 已解决 |
## Evidence-driven
| 结论 | 证据来源 | 是否已汇报用户 |
|---|---|---|
| ReactAgent.call(input, config) 返回 AssistantMessage,现有 AgentLoggingHook 从 config metadata 读取 sessionId/runId | 本地 1.1.2.0 javap、AgentLoggingHook | 已汇报 |
| Executor parser 当前在 VerifierInputHook,Verifier/Composer parser 与 renderer 当前在 ChatService | 定向源码阅读和 references | 已汇报 |
| checked_bindings 提供 claim_id/tool_name/source_invocation_id/raw_path/matched_text/status | ExecutorGatekeeperService | 已汇报 |
| Gatekeeper.validateRun 使用 run-scoped ToolInvocation repository | ExecutorGatekeeperService tests/code | 已汇报 |
| Graph path不能注册旧 VerifierInputHook,否则 Gatekeeper 会双执行且输入包含 full tool trace | 阶段 0 ADR、Hook 源码 | 已汇报 |
| evidence retry 只允许 critical no_evidence/indirect_support | 阶段 0 design/ISS-011 | 已汇报 |
| 阶段 1 router 未检查 is_critical,属于实现偏离 | Router 源码与阶段 0 baseline 对照 | 已汇报 |
| 共享 Prompt 暂时仍服务旧 Sequential path,本阶段直接修改会提前破坏生产 payload | ChatService agent builder + VerifierInputHook + prompt | 已汇报 |
| Node 输入/安全边界新增且旧解析会重构,单元和 focused regression 必要;E2E 不必要 | 阶段边界和用户规则 | 已汇报 |
## User-interview
| 问题原文 | 用户原话 | 确认状态 | OpenSpec 回写 |
|---|---|---|---|
| 阶段 2 是否独立 sm-flow? | “iss-011里每个阶段,都是一个sm-flow” | 已确认 | 独立 change |
| 是否可提前切生产入口? | “每个阶段需要归档完并提交才能进入下一个阶段” | 已确认不可提前阶段 3 | Out of Scope |
| 阶段 2 是否执行 E2E? | “端到端只在最后阶段全部完成后才验证” | 已确认不执行 | Acceptance |
| 是否添加单元测试? | “如果有必要添加单元测试验收的话,就加” | 已确认规则;本阶段判定必要 | Acceptance |
## Context And Handoff
- 阶段 0 archive/commit:design baseline / `581daff`
- 阶段 1 archive/commit:routing skeleton / `42ba204`
- 当前 change:`chat-diagnosis-stategraph-real-nodes`
- 后续 change:`chat-diagnosis-stategraph-chatservice-cutover`,只能在本阶段 archive + commit 后创建。
## Technical Decisions
### Shared protocol components
- 抽取 Executor、Verifier、Composer 解析器,旧 Hook/ChatService 委托新组件。
- 抽取 Composer safe input builder / renderer,旧 ChatService 保持相同输出。
- JSON sanitization 只存在一份共享实现,不在每个 Node copy。
- 抽取过程是行为保持 refactor;现有 focused tests 是回归门禁。
### Agent adapter boundary
- `DiagnosisAgentInvoker` 是最小 port:`invoke(String, RunnableConfig) -> String`。
- `ReactAgentDiagnosisInvoker` 只包装 `ReactAgent.call(...).getText()`。
- Planner/Executor/Verifier/Composer adapters 各自拥有白名单 input projector、parser 和 status event。
- tests 使用 fake invoker,另有 ReactAgent wrapper test。
### Legacy Hook coexistence
- 旧 Sequential path 在阶段 3 前仍通过 VerifierInputHook 执行 Gatekeeper。
- Graph Verifier Agent 不注册该 Hook;显式 Gatekeeper Node 是 Graph 中唯一 validation 入口。
- Parser/enricher 可共享,但 Hook 的 legacy payload/prompt 暂不改变。
- 阶段 3 切换生产入口并同步 Verifier Prompt;阶段 5 删除旧隐式结构。
### Gatekeeper normalization
- raw pass → PASS。
- raw fail + severity low_confid → LOW_CONFID。
- raw fail + severity reject → REJECT。
- 缺失、unknown、异常或不一致 → REJECT。
- verified_binding_count 只统计 checked_bindings.status=pass。
### Verified projection
- 通过项按 claim_id + source_invocation_id + tool_name + raw_path 与原 binding 精确匹配。
- verified_executor_output 只包含 answer_version 与至少一条 passed binding 的 filtered claims;合法零 claim 保持空列表。
- verified_evidence 只含 claim_id/source_invocation_id/tool_name/raw_path/matched_text。
- hypotheses、失败 binding、未引用 ToolInvocation、raw Executor output 不投影。
### Evidence retry
- extractor 要求 `is_critical=true` 且 verification 为 no_evidence/indirect_support。
- gap 字段:claim_id(从 `claim-id: text` 提取或空)、fact、verification、reason。
- completed queries 由 verified evidence 的 tool/invocation/path 去重生成。
- prior verified output/evidence 原样只读进入 retry_context。
- 约束固定:max_retry=1、do_not_repeat_successful_queries、only_execute_incremental_queries、preserve_prior_verified_claims。
- Executor 输入声明“增量执行、完整输出”,Java 不合并 claims。
### Interface impact
- 等级:L2 internal interface;共享 parser 委托保持旧行为。
- 新消费者:阶段 3 Graph orchestrator/Agent factory。
- 当前外部 API/DB/生产路由:无变化。
- 回滚:revert 本阶段提交;旧 Sequential path仍完整。
- 有意修正:Router 只允许 critical gap,属于对冻结基线的代码修复。
## Risks Accepted
- 真实模型尚未执行;Node contract 通过 fake invoker/real service tests证明,阶段 5 才 E2E。
- Prompt 输入说明与 Graph input 的最终同步推迟到阶段 3,避免当前旧生产 Hook 提前不兼容。
- 旧 Hook 暂时仍存在,但不进入 Graph action graph;阶段 5 必须删除。
## Architecture Audit
### Module and ownership map
`Diagnosis Context + RunnableConfig` → Agent adapters / deterministic Nodes → owned Graph State fields → `DiagnosisGraphRouter` → next Node or END → `final_answer + orchestration_events`。阶段 2 只提供这条可构造链,阶段 3 才由 `ChatService` 创建 Run、构造 Agent 实例并调用 Graph。
| 模块 | 数据所有权 | 允许依赖 |
|---|---|---|
| `diagnosis.protocol` | JSON contract、纯解析结果、安全 input/rendering | Jackson 与纯 DTO;不依赖 Graph/Hook/ChatService/ThreadLocal |
| `graph.diagnosis` Agent adapters | 白名单输入、Agent attempt status/event | protocol、注入的 invoker、Graph API |
| Gatekeeper Node | raw Gatekeeper result、normalized status/count | ExecutorGatekeeperService、当前 run config |
| Verified Input / Retry Prepare | verified projection、critical gaps、retry context | raw result 的只读投影与 protocol DTO |
| Router / Factory | 条件边、有限计数、调用次序 | Graph State;不解析 Agent raw output |
| legacy Hook / ChatService | 阶段 3 前的生产 Sequential 流程 | 只委托 protocol;不得消费真实 Graph action set |
### Lifecycle and coupling audit
Graph State 和 events 都是 invocation-scoped,runId 只从当前 RunnableConfig 获取,Nodes 不持有跨 Run 可变状态。旧路径与 Graph 路径阶段性共享的只有无状态 protocol 组件和 Gatekeeper service,不共享 ThreadLocal 或 Agent output。ReactAgent/invoker 必须构造注入,阶段 2 不复制 ChatService Prompt/Agent factory。唯一有意的阶段性耦合是 legacy consumers 改为委托 protocol,这由旧 focused tests 和完整 revert 保护。阶段 3 前生产入口、DB、Trace、Prompt 均保持隔离。
### Cross-artifact alignment
| 对齐链 | 结果 | 证据 |
|---|---|---|
| brief/proposal 目标、范围、非目标 → proposal | 已对齐 | 独立阶段边界、真实 Nodes、无生产切换均明确 |
| proposal 承诺与约束 → design | 已对齐 | invoker、共享组件、Gatekeeper、投影、retry、Fallback、L2 均有决策 |
| design 架构/接口结论 → specs/tasks | 已对齐 | 中立 protocol 包、构造注入、fail-closed 和生产隔离均有任务/行为 |
| specs 可观察行为 → tasks 可执行切片 | 已对齐 | 每个 requirement 至少由一个实现任务和一个测试/验收任务覆盖 |
### Audit result
审计发现共享协议组件包所有权与 Agent 实例装配边界需要显式化,已回写 design/tasks。未发现状态字段、路由计数、run 生命周期或阶段边界的新冲突。接口影响维持 L2,消费者都在本 change 与下一阶段明确范围内。剩余风险是共享抽取的旧行为漂移和 binding 投影泄漏,均有 focused regression 与 mixed-binding tests。架构风险可接受,无未解决问题。
## Commit Gate
- proposal/design/specs/tasks:全部存在,OpenSpec status `isComplete=true`。
- 当前 change strict validation:通过。
- 主 specs strict validation:13 passed,0 failed。
- 规格结构:9 requirements、22 scenarios;tasks:27 个 checkbox 切片。
- Cross-artifact:4/4 已对齐,gap=0。
- 接口影响:L2,已在 design 独立章节记录消费者、兼容和回滚。
- Question pool:所有 evidence-driven 已汇报;所有 user-interview 已确认;无未决项。
- Preflight scope:`git diff --check` 通过;Commit checkpoint 未修改业务代码。
- 结论:Draft OpenSpec 达到可执行状态,创建 `.committed`。
## Apply Authorization
- 用户原话:“直接实现吧,不用找我授权了”。
- 解释:阶段 2–5 后续 checkpoint 可在前置门禁通过后直接继续,不再因 Apply 或 Archive 授权暂停。
- 不扩大范围:每阶段仍须独立 OpenSpec、验收归档、Git commit;阶段 0–4 不做 E2E,阶段 5 才统一执行。
## Pre-apply Research
### Reference implementations read
- `src/main/java/com/superbiz/agent/hook/VerifierInputHook.java`:Executor JSON sanitization、parse status、tool-name normalization、唯一 invocation 回填与 legacy Gatekeeper payload。
- `src/main/java/com/superbiz/agent/service/ChatService.java`:Verifier claim/fact parser、Gatekeeper ceiling、Composer allowed-material builder、Composer parser/safe renderer、旧 retry context。
- `src/main/java/com/superbiz/agent/service/ExecutorGatekeeperService.java`:`validateRun`、severity normalization source、checked binding 与 matched_text 结构。
- `src/main/java/com/superbiz/agent/graph/diagnosis/DiagnosisGraphFactory.java`:config-aware action ports、technical retry/evidence retry counter 所有权和 recursion limit。
- `src/main/java/com/superbiz/agent/graph/diagnosis/OrchestrationEvent.java` 与 `src/test/java/com/superbiz/agent/graph/diagnosis/ScriptedDiagnosisGraphActions.java`:每 attempt 单 event 形态。
- `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`:RunnableConfig metadata 中 sessionId/runId 的审计读取方式。
- `src/test/java/com/superbiz/agent/hook/VerifierInputHookTest.java`、`ChatServiceSequentialAgentTest.java`、`DiagnosisGraphRoutingTest.java`:JUnit 5、Mockito 边界替身和 CompiledGraph observable behavior 测试风格。
- 本地 `1.1.2.0` JAR `javap`:`ReactAgent.call(String,RunnableConfig)` 与 `RunnableConfig.threadId/metadata` 公共 API。
### Technology inventory
| 类别 | 项目标准 / 本阶段使用 |
|---|---|
| JSON contract | Jackson `ObjectMapper`、`LinkedHashMap` 保持稳定字段顺序;共享 sanitization 只存在一份 |
| Graph Node | `AsyncNodeActionWithConfig` 返回 `CompletableFuture<Map<String,Object>>`;state 默认 Replace、events Append |
| Agent boundary | 构造注入的 `DiagnosisAgentInvoker`;ReactAgent wrapper 透传同一个 RunnableConfig |
| Run scope | `config.metadata("runId")` 为 Gatekeeper 唯一运行边界;缺失即 fail closed |
| Error handling | 合法 contract/invalid output/temporary/permanent 分离;unknown exception 不推断为可重试 |
| Tests | JUnit 5;只在 ReactAgent、repository 等系统边界使用 fake/mock;Node/CompiledGraph 走公开 action/graph 接口 |
| Request/response | 本阶段不改 Controller/DTO/API,不适用 |
| MQ/Consumer | 本阶段不涉及,不适用 |
| DB/Trace/Prompt | 本阶段禁止修改,阶段 3 处理 |
### Reuse and new infrastructure
- 新建中立 `com.superbiz.agent.diagnosis.protocol`:`JsonPayloadSupport`、Executor/Verifier/Composer protocol、safe input/rendering、`EvidenceGapExtractor`;不得依赖 Graph/Hook/ChatService/ThreadLocal。
- 新建 `graph.diagnosis` Node 层:invoker wrapper、failure classifier、四个 Agent adapters、Gatekeeper、Verified Input、Retry Prepare、Fallback 和 action assembly。
- 不新建 Prompt/Agent factory;阶段 3 通过构造注入已有 ReactAgent 实例。
- 不新增 Maven dependency、数据库迁移、配置项或生产 consumer。
### Pre-apply conclusion
参考实现、API 签名、异常和测试标准已足以指导实现;未发现 devflow/OpenSpec 冲突。进入 TDD tracer bullet,先锁定共享 Executor parser 的合法 no-evidence 与 malformed 行为。
## Apply Completion And Verification
### Assembly alignment
- 首个共享 protocol 模块与最终真实 Graph action assembly 均逐项对照 design/specs:invoker 显式透传 RunnableConfig,Gatekeeper 单次 fail-closed,Verified Input 精确投影,Verifier/Composer 固定输入重试,critical evidence retry 与两类 Fallback 边界全部落地。
- `DiagnosisGraphFactory` 继续独占技术重试计数、evidence retry 计数和 Planner mode/reset;Node 不重复拥有编排计数。
- 新增源码中无 `ThreadLocal`、`VerifierInputHook`、`tool_trace_summary`、`raw_executor`、TODO 或 FIXME;protocol 包无 Graph/Hook/ChatService 反向依赖。
- `ChatService` 无 Diagnosis Graph/CompiledGraph 引用,生产切换保持在阶段 3;DB migration、Trace DTO/entity/repository 和 prompts 均无 diff。
### Automated verification
- 新 protocol/Node/真实 CompiledGraph/Router/Trace focused suite:通过。
- 旧 `ChatServiceSequentialAgentTest`、`VerifierInputHookTest`、`ExecutorGatekeeperServiceTest` 回归:通过。
- 合计 100 tests,0 failures,0 errors,0 skipped。
- `mvn -q -DskipTests test-compile`:通过。
- `openspec validate chat-diagnosis-stategraph-real-nodes --strict`:通过。
- `openspec validate --specs --strict`:13 passed,0 failed。
- `git diff --check`:通过;仅报告 Git 既有 LF/CRLF 转换提示,无 whitespace error。
### Deferred final verification
- 阶段 2 按用户确认不运行 Maven live E2E,不启动应用,不检查 `logs/`,不查询数据库。
- 上述端到端、日志和 `scripts/query_mysql.py` 数据库核验统一保留到阶段 5 全部实现完成后执行。