Add repairable INVALID_PROGRESS_PROTOCOL observations, independent PROGRESS_PROTOCOL_VIOLATED saturation, and controlled release paths. Archive the OpenSpec change after syncing main specs and devflow.
18 KiB
18 KiB
Diagnosis 信息增益停止契约 Decisions
Discover Status
- Checkpoint:Discover。
- Capability source:
sm-flow内置 Discover 协议;grill 使用grill-with-docs,代码可证问题通过源码、测试和引用搜索处理。 - Scale:
complex。变更跨越 Agent、Tool 协议、Run 生命周期、Release、Guard、配置、Trace 和 E2E。 - 接口影响:L3。模型可见 Tool Schema 发生有意协议变更,公开 HTTP/SSE 和业务 Tool backend 协议不变。
- 工具降级:当前没有
codebase-retrieval和 LSP 工具;以rg、源码和测试引用核查替代。用户已明确“可以忽略gitnexus”。
Question Pool
| # | 维度 | 问题 | 模式 | 状态 |
|---|---|---|---|---|
| Q1 | 术语 | Tool 客观状态、信息增益、收集状态、停止原因和最终发布状态是否应合并为一个枚举? | user-interview | 已解决 |
| Q2 | 语义 | Tool 返回价值由谁判断,是否需要多级质量分数? | user-interview | 已解决 |
| Q3 | 协议 | 模型继续调用 Tool 时如何回传上一轮信息增益,是否需要 next_action? |
user-interview | 已解决 |
| Q4 | 边界 | Tool Schema 应来自 Prompt 还是服务端原生 Tool Calling 注册? | user-interview | 已解决 |
| Q5 | 边界 | Harness 能确定性判定哪些 NO_GAIN,RAG REFERENCE 由谁判定? |
user-interview | 已解决 |
| Q6 | 范围 | 首版是否需要 new_count 或自然语言语义去重? |
user-interview | 已解决 |
| Q7 | 配置 | 连续无增益阈值是否可配置,默认值与生效时机是什么? | user-interview | 已解决 |
| Q8 | 发布 | 信息饱和、预算终止和 conclusion=null 由谁转换为用户可见结果? |
user-interview | 已解决 |
| Q9 | 验收 | 如何证明未知问题不再以通用内部错误结束,同时不放过无证据结论? | evidence-driven | 已解决 |
| Q10 | 技术 | 当前 Tool schema 是否能直接容纳 previous_observation? |
evidence-driven | 已解决 |
| Q11 | 技术 | 进展控制状态应扩展 Redis Store 还是放入 RunContext handle? | evidence-driven | 已解决 |
| Q12 | 技术 | RAG relevance_level 在哪一层丢失,前端是否已有过程展示能力? |
evidence-driven | 已解决 |
Evidence-driven
| 结论 | 证据来源 | 是否已汇报用户 |
|---|---|---|
当前三个 Agent-facing Tool 直接使用 RagToolRequest、QueryLogsRequest、MysqlToolRequest 生成 Schema;要增加 previous_observation + input 必须显式演进 Tool Schema,不能只改 interceptor。 |
HarnessEvidenceTools、三个 request records、DiagnosisAgentFactory |
已汇报 |
HarnessToolInterceptor 当前把完整 agentResult 放入 ToolCallResponse.content,控制视图与模型观察尚未分离。 |
HarnessToolInterceptor |
已汇报 |
RunContext 已采用结构不可变、可变状态存在线程安全 handle 的模式;进展 tracker 放入 RunContext 比扩展 Redis 按 Run 枚举更符合现有所有权。 |
RunContext、DiagnosisHarnessCore.startRun |
已汇报 |
CanonicalInvocationStore 只有 begin/find/markReady/markError,扩展按 Run 枚举会影响 Redis 实现和多组 fake store;首版可由 tracker 保存完成调用 key,在结束时按 key 读取 canonical 记录。 |
CanonicalInvocationStore 及其引用测试 |
已汇报 |
RagResultProjector 只按 evidence 是否为空生成 EVIDENCE_FOUND / NO_EVIDENCE,没有读取上游 relevanceLevel / relevance_level。 |
RagResultProjector、LookupResult、KnowledgeEvidencePostProcessor |
已汇报 |
DiagnosisReleaseUseCase.execute 当前强制 draft 非空并对所有 Draft 运行 EvidenceGuard;EvidenceGuard 又把空 analysis 判为 ANALYSIS_MISSING,与合法无结论结果冲突。 |
DiagnosisReleaseUseCase、EvidenceGuard |
已汇报 |
ChatApplicationUseCase.recoverBudgetExhaustion 已有未提交预算 Fallback,但它绕过 Diagnosis Release,需迁移而不是丢弃用户价值。 |
ChatApplicationUseCase、SafeFallbackFactory、现有测试 diff |
已汇报 |
前端已渲染 observed_facts / verified_sources / limitations / next_steps,不需要新增公开展示协议。 |
src/main/resources/static/app.js |
已汇报 |
| 验收必须同时覆盖主动无结论、Harness 饱和、预算终止、无证据结论被 Guard 拦截,以及原始未知 Query 的 live SSE、日志和 exact run 数据。 | 当前事故现象、ISS-016 验收项、现有 E2E 工具 | 已汇报 |
User-interview
| 问题原文 | 用户原话 | 确认状态 | OpenSpec 回写 |
|---|---|---|---|
| 是否精简状态而不建立第二套生命周期? | “这里我觉得设计得太混乱了,怎么简化”以及对最终简化架构“我觉得可以” | 已确认 | 已回写 |
是否只保留 GAINED / NO_GAIN? |
“质量状态只要 information_gain = GAINED | NO_GAIN 就够了?”后确认“我觉得可以” | 已确认 | 已回写 |
是否需要 new_count? |
“好那就去掉new_count” | 已确认 | 已回写 |
是否需要 next_action? |
“那就去掉next_action,我觉得由llm自己去判断就好了,不用显示的指定” | 已确认 | 已回写 |
| Tool 如何注入? | “首先 tool注入,由服务端注入,而不是写死在提示词中” | 已确认 | 已回写 |
| Prompt 是否强调合法放弃和正确但无用的内容? | “需要说明 模型不必须要给出一个答案”以及“如果你发现工具返回的是正确但对推导无用的废话,请停止调用” | 已确认 | 已回写 |
| 阈值是否可配置? | “我觉得这个可以暴露出一个配置来控制” | 已确认 | 已回写 |
| 首版重复检测做到什么程度? | “也就是说这一版只是做参数的去重校验”后确认“可以” | 已确认 | 已回写 |
| 是否按当前简化方案进入实施? | “可以用更简单的方式”“可以。修正一下文档”“用sm-flow开始实施把” | 已确认 | 已回写,并授权完成 Commit 后进入 Apply |
关键取舍
- 决策:停止权归 Harness,语义价值判断由模型与确定性规则共同产生。
- 原因:Tool 只能知道客观返回,模型才能判断内容是否推进当前假设;但空结果和完全重复 scope 可由代码零 Token 判定。
- 影响:Harness 只消费二值信息增益,不引入独立 Judge 或质量分数。
- 决策:使用下一次 Tool Call Envelope 回传上一轮模型评价。
- 原因:模型只有看到 Tool Observation 后才能评价,下一次真实行为正好提供受 Schema 约束的回传边界。
- 影响:这是 L3 Agent-facing Tool Schema 变更,业务 request 在 interceptor 内解包后保持不变。
- 决策:进展 tracker 是 RunContext handle,Canonical Store 保持 Tool 真相源。
- 原因:停止决策需要低延迟 Run 内状态,完整证据仍应由 canonical 记录提供;两者职责不同。
- 影响:tracker 保存计数、scope、待评价调用和 canonical keys,不复制 raw payload。
- 决策:不创建 ADR。
- 原因:这些是 ISS-016 范围内可通过 OpenSpec 回滚的内部协议演进,已有架构文档详细记录取舍,尚不满足独立 ADR 的必要性。
OpenSpec 回写
- 必须进入 proposal/design/spec/tasks:Tool Envelope、L3 影响、Run tracker、确定性
NO_GAIN、RAGrelevance_level、双视图、STOP_REQUIRED、ProgressSnapshot、统一 Release、Prompt、配置和 E2E。 - 必须保留非目标:无
new_count、无next_action、无 Judge、无语义去重、无第二套诊断生命周期、无公开 SSE 协议新增。 - 当前没有未确认的 user-interview 问题,也没有 devflow/OpenSpec 冲突。
Cross-Artifact 对齐检查
| 上游 → 下游 | 检查内容 | 状态 |
|---|---|---|
| ISS-016/架构文档 → proposal | 未知问题、合法放弃、信息增益、饱和停止、双视图、统一 Release、非目标和 E2E | 已对齐 |
| proposal → design | L3 Envelope、Run tracker、scope、STOP_REQUIRED、ProgressSnapshot、预算终态、Prompt 和迁移方案 | 已对齐 |
| design → specs/tasks | 状态机、Tool 门禁、RAG relevance、无结论 Guard、Release 所有权、Trace 和兼容边界 | 已对齐 |
| specs → tasks | 每个可观察行为均有 contract/state/loop/release/config/E2E 可执行切片 | 已对齐 |
Gap 详情
- 无。
Architecture Audit
- Capability source:
zoom-out。按 glossary 的 Diagnosis Agent、Diagnosis Harness、RunContext、Evidence Status、Invocation Status、Release Outcome 术语审计。 - 顶层链路:
ChatApplicationUseCase -> DiagnosisChatExecutor -> DiagnosisAgentUseCase -> ReactAgent/interceptors -> ToolBoundary/canonical store -> ProgressSnapshot -> DiagnosisReleaseUseCase -> SSE/persistence。 - 所有权:Agent 负责诊断语义;Tool/Projector 负责客观结果;Run tracker 负责停止控制;Canonical Store 负责 Tool 真相;Guard 负责引用与结论安全;Release 负责用户可见 SUCCESS/FALLBACK;Application 只负责编排和持久化。
RunContext的生产代码构造点只有DiagnosisHarnessCore.startRun,大量测试通过该工厂获取;新增 tracker 不需要扩散手工构造。DiagnosisAgentUseCase、HarnessToolInterceptor、HarnessEvidenceTools和DiagnosisReleaseUseCase的直接消费者均已由配置类和 focused tests 覆盖,任务清单包含所有构造调用更新。FallbackType新语义只通过通用 SafeFallback JSON/前端渲染消费,没有前端枚举 switch;公开协议不新增字段。- 最大框架风险是 Tool Envelope Schema 和 STOP_REQUIRED 后异常传播;design 要求三个具体 record、真实 callback schema 测试和 scripted framework-loop 测试在 Release 迁移前锁定行为。
- 最大生命周期风险是预算已把 RunLifecycle 置为
BUDGET_EXHAUSTED后 Application 再次checkActive;design 将其限制为“Diagnosis Release 已处理的预算 Fallback”窄分支,并禁止 Application 重建业务内容。 - 审计结论:模块职责没有形成新的循环依赖或第二真相源;L3 风险已进入 specs 和 tasks,可进入 commit gate。
Commit Gate Preflight
proposal.md、design.md、六份 capability delta specs 和tasks.md均存在。openspec status --change diagnosis-information-gain-stop-contract --json返回isComplete=true。openspec validate diagnosis-information-gain-stop-contract --strict通过。- question pool 全部已解决;evidence-driven 结论已汇报;user-interview 决策均有用户原话和确认状态。
- 接口影响已判为 L3,并有独立 Interface Impact、兼容、迁移、回滚和验收说明。
- Cross-artifact 检查无 gap;架构风险均已进入 design/tasks。
- 用户已通过“用sm-flow开始实施把”明确授权 Commit 后进入 Apply。
Pre-apply Research
参考实现
HarnessEvidenceTools:现有三类FunctionToolCallback注册点和 adapter bridge,继续作为 Agent-facing Schema 唯一入口。HarnessToolInterceptor:可获得 exact framework Tool Call ID,适合消费 Envelope 和执行 progress gate。ToolBoundary:Tool 预算、Run 校验、canonical 写入和安全错误的单点,不在 interceptor 重复 reserve。RunContext/DiagnosisHarnessCore.startRun:结构不可变 + 可变 handle 模式和唯一生产构造点。RagResultProjector/QueryLogsResultProjector/MysqlResultProjector:bounded canonical agent result 的现有标准化模式。EvidenceGuard/DiagnosisReleaseUseCase:当前结论验证链和无结论冲突位置。ChatApplicationUseCase.recoverBudgetExhaustion:保留用户价值、需要迁移所有权的临时预算 Fallback。DiagnosisAgentUseCaseTest.ScriptedChatModel:真实框架 model -> Tool -> model loop 回归模式。
技术栈清单
- Tool Schema:三个具体 record 交给 Spring AI
FunctionToolCallback.inputType,共享PreviousObservation,不使用泛型擦除或 JsonNode Schema。 - JSON:继续使用项目
ObjectMapper严格解析/序列化;控制字段在 interceptor 消费后只传业务 input。 - Run 状态:新增线程安全 tracker handle,由
DiagnosisHarnessCore.startRun创建,不使用 ThreadLocal。 - Canonical 真相:继续使用
ToolCallKeyFactory + CanonicalInvocationStore.find;tracker 只记录 identity。 - 视图:从 bounded canonical
agent_result白名单投影 Model Observation,不读取 raw response。 - 异常:受控停止使用专用异常和 cause-chain 分类;未知异常保持 fail closed。
- 测试:JUnit 5、scripted ChatModel、现有 fake store/adapter fixture;不增加 Maven 依赖。
新建基础设施
harness.progress:信息增益、收集状态、停止原因、tracker、scope、snapshot/projector。harness.agent:三个 Agent-facing Envelope、白名单 observation projector、受控停止异常和执行结果。- 不新增数据库表、Redis 数据结构、HTTP DTO、SSE event 或外部依赖。
Apply 期间设计补充:Draft 合同失败
- 真实 E2E
runId=4e667111-524e-4407-87ab-b4b262952017已完成一次 READY RAG 调用,第二轮模型返回文本后在 Draft/Release 边界失败;后续三次同 Query 均走零 Tool 的MISSING_REQUIRED_CONTEXT,证明模型输出存在随机分支。 - 用户确认采用窄化降级:非法 Draft 自身不被接受;已有当前 Run 的安全 ProgressSnapshot 时发布
INSUFFICIENT_EVIDENCE,没有安全过程时继续FAILED。 - 这是有意行为变更:从“所有非法 Draft 都发布技术失败”调整为“非法 Draft + 已验真过程可发布过程型 Fallback”;公开 SSE 字段、Tool 协议和最终生命周期枚举不变。
- 不新增 stop reason,不把 Draft 解析失败伪装成
INFORMATION_SATURATED或BUDGET_LIMIT_REACHED;使用 Agent 输出异常携带有界 snapshot,并以脱敏 Trace 区分输出合同失败。
Apply Verification
- Focused tests:
DiagnosisAgentUseCaseTest、DiagnosisReleaseUseCaseTest、DiagnosisChatExecutorTest、HarnessChatConfigurationTest通过。 - 完整回归:
mvn -q -Dtest='!MilvusConnectionTest' test退出码为0;本轮 Surefire 报告汇总Tests=292, Failures=0, Errors=0, Skipped=3。 - 外部凭据边界:未排除时唯一失败为
MilvusConnectionTest.connect,原因是当前测试进程未设置MILVUS_TOKEN;这不是本变更回归。 - OpenSpec:
openspec.cmd validate diagnosis-information-gain-stop-contract --strict通过。 - 格式与清理:
git diff --check通过;未发现临时 E2E JSON、DEBUG 或 tmp 文件。 - named SSE E2E:Query
诊断切换企业失败的问题,sessionId=iss016-final-20260726-a,runId=3ab22ed7-d0ed-45d8-b928-dce5790c0542;SSE 返回SAFE_FALLBACK、type=MISSING_REQUIRED_CONTEXT、done.outcome=FALLBACK。 - 数据库核对:
status=SUCCESS、intent=DIAGNOSIS、release_outcome=FALLBACK、tool_call_count=0、total_token_count=2890、answer 非空。 - Trace 核对:
RUN_STARTED -> ROUTING_ATTEMPT -> ROUTING_DECISION -> AGENT_MODEL_STEP -> EVIDENCE_GUARD_INITIAL -> RELEASE_DECISION/FALLBACK -> RUN_FINISHED/FALLBACK。 - 兼容性:公开 HTTP/SSE 字段、前端 SafeFallback 消费结构、数据库表和业务 Tool request 均未新增字段;模型侧 Tool Envelope 是本变更已确认的 L3 协议变更。
Apply Continuation: Task 8 Protocol Repair + Bounded Stop
- Checkpoint:Apply。
- Capability source:
openspec-apply-change+ sm-flow apply 协议。 - 背景:tasks 1–7 已完成;真实 E2E 暴露连续
INVALID_PROGRESS_PROTOCOL不会累计NO_GAIN,可能在硬预算前空转。Task 8 补齐协议修复反馈与独立兜底停止。 - 实现事实(代码已在工作区,本轮补齐测试与收口):
ProgressProtocolViolationType/ProgressProtocolViolationException覆盖 MISSING_PREVIOUS_OBSERVATION、OUT_OF_ORDER、UNEXPECTED、MISSING_INPUT、INVALID_ENVELOPE。DiagnosisProgressTracker独立累计连续协议错误,默认阈值 2,达到后stop_reason=PROGRESS_PROTOCOL_VIOLATED。HarnessToolInterceptor返回可修正 observation(repair_required、violation_type、missing_field、expected_previous_tool_call_id、allowed_information_gain);达阈一次 STOP_REQUIRED,再请求抛DiagnosisCollectionStoppedException。DiagnosisReleaseUseCase支持PROGRESS_PROTOCOL_VIOLATED:有安全 ProgressSnapshot 发INSUFFICIENT_EVIDENCE,无进展 fail closed。TOOL_REQUEST_REJECTED记录 violation_type、repair_prompt_delivered、consecutive_protocol_violations、stop_reason,不记录参数/观察正文/异常。
- 验证:
- Focused:
DiagnosisProgressTrackerTest、HarnessToolInterceptorTest、DiagnosisReleaseUseCaseTest、DiagnosisAgentUseCaseTest、HarnessChatConfigurationTest通过。 - OpenSpec strict validate 通过。
- Focused:
- 文档:ISS-016 剩余协议停止项勾选完成;ISS-015 阶段 1 标记已完成;架构文档同步协议错误独立停止语义。
- OpenSpec tasks 8.1–8.6 全部完成。剩余 Apply 工作:无。可进入 Archive checkpoint(需用户确认是否归档 OpenSpec)。
Archive
- Checkpoint:Archive。
- Capability source:
sm-flowarchive 协议 +openspec-archive-change。 - 用户确认:明确要求“执行(archive),完后提交推送”。
- devflow 档案:
brief.md、evidence.md、decisions.md、acceptance.md- 更新
devflow/index.md、devflow/glossary/CONTEXT.md
- OpenSpec:
- delta specs 已同步到 main specs(含新建
diagnosis-information-gain-stop-contract) - change 归档至
openspec/changes/archive/2026-07-27-diagnosis-information-gain-stop-contract/
- delta specs 已同步到 main specs(含新建
- 不创建独立 ADR:决策已由 OpenSpec/ISS/架构文档承载,且可通过 OpenSpec 回滚。
- 状态:archived。