feat(graph): add diagnosis routing skeleton
This commit is contained in:
+3
@@ -0,0 +1,3 @@
|
||||
ready_at: 2026-07-17
|
||||
devflow: devflow/projects/2026-07-17-chat-diagnosis-stategraph-routing-skeleton
|
||||
authorization: user-requested-per-stage-archive
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
committed_at: 2026-07-17
|
||||
scope: iss-011-stage-1-routing-skeleton
|
||||
validation: openspec-strict-pass
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
## Context
|
||||
|
||||
阶段 0 已归档 StateGraph 设计基线,当前仓库仍没有 Graph 实现。阶段 1 只引入可编译、可用 Fake Node 执行的内部骨架,不连接 Spring Bean、ChatService、真实 Agent 或数据库。
|
||||
|
||||
锁定依赖 `spring-ai-alibaba-graph-core:1.1.2.0` 已通过本地 JAR 验证:
|
||||
|
||||
- `StateGraph.addNode(... AsyncNodeActionWithConfig)`
|
||||
- `StateGraph.addConditionalEdges(... AsyncEdgeActionWithConfig, mappings)`
|
||||
- `CompileConfig.builder().recursionLimit(...)`
|
||||
- `KeyStrategyFactoryBuilder`、`ReplaceStrategy`、`AppendStrategy`
|
||||
- `CompiledGraph.invoke(input, RunnableConfig)`
|
||||
- `RunnableConfig.builder().threadId(...)`
|
||||
|
||||
阶段 2 将消费 Node action ports,阶段 3 将消费 compiled graph。阶段 1 自身没有生产调用方。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 建立明确的状态、状态枚举、节点、route 和 reason code 常量。
|
||||
- 建立 config-aware Node action ports 和可编译 Graph 工厂。
|
||||
- 以冻结计数和 guard 实现完整条件边。
|
||||
- 验证 AppendStrategy 和实际 CompiledGraph 行为。
|
||||
- 从有界 events 构造确定性的 orchestration trace。
|
||||
- 用 Fake Node 测试所有路由和终止边界。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不接 ReactAgent、Gatekeeper Service、ToolTrace 或 Prompt。
|
||||
- 不修改 ChatService、Hook、ThreadLocal 或生产 Spring 配置。
|
||||
- 不持久化 trace,不修改 DB/DTO/API。
|
||||
- 不删除旧 Sequential 实现或测试。
|
||||
- 不运行 Maven E2E。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Package and class boundaries
|
||||
|
||||
新代码位于 `com.superbiz.agent.graph.diagnosis`:
|
||||
|
||||
| 类型 | 职责 |
|
||||
|---|---|
|
||||
| `DiagnosisGraphState` | 26 个 state key、默认 Replace + events Append strategy、typed reads |
|
||||
| `DiagnosisGraphStatus` | Planner/Executor/Gatekeeper/Verifier/Composer status、Verdict、PlannerMode |
|
||||
| `DiagnosisGraphTopology` | Node id、route key、reason code 常量 |
|
||||
| `DiagnosisGraphActions` | 八个 `AsyncNodeActionWithConfig` ports |
|
||||
| `DiagnosisGraphRouter` | 纯确定性 edge guard,不修改 state |
|
||||
| `DiagnosisGraphFactory` | 注册 Node/Edge、retry wrapper、evidence retry wrapper、recursion limit |
|
||||
| `OrchestrationEvent` | node/outcome/reasonCode/attempt |
|
||||
| `OrchestrationTransition` | from/to/reasonCode/attempt |
|
||||
| `DiagnosisOrchestrationTrace` | version/transitions/finalNode/terminationReason/degraded/evidenceRetryCount |
|
||||
| `DiagnosisOrchestrationTraceBuilder` | events → transitions/summary |
|
||||
|
||||
Fake Node 和 script fixture 只存在于 test 源集。
|
||||
|
||||
替代方案:把 router 和状态读取放进 ChatService 或每个 Adapter。拒绝,因为会复制 guard 并阻碍 Fake Node 独立验证。
|
||||
|
||||
### 1.1 Direct dependency ownership
|
||||
|
||||
代码直接 import Graph Core API,因此 `pom.xml` 显式声明 `com.alibaba.cloud.ai:spring-ai-alibaba-graph-core`。版本继续由现有 Spring AI Alibaba BOM 管理为 1.1.2.0,不重复写版本。依赖 Agent Framework 的传递依赖虽可编译,但会让上游依赖图调整无意中破坏本模块,拒绝。
|
||||
|
||||
### 2. State strategy and typed reads
|
||||
|
||||
`KeyStrategyFactoryBuilder.defaultStrategy(new ReplaceStrategy())`,仅对 `orchestration_events` 使用 `new AppendStrategy()`。Node 每次返回 `List.of(event)`,Graph 合并后保持有序列表。
|
||||
|
||||
typed reads 对 absent、null、错误类型和未知 enum 返回安全默认,不抛出边路由异常。未知 status/verdict 的路由默认 Fallback。
|
||||
|
||||
### 3. Config-aware action ports
|
||||
|
||||
所有 port 使用 `AsyncNodeActionWithConfig`,即使 Fake Node 当前只需要 state。原因是阶段 2 必须读取 `RunnableConfig.threadId/metadata` 并向 Agent 传递 run context;现在锁定接口可以避免随后重写 Graph topology。
|
||||
|
||||
`DiagnosisGraphActions` 构造时对八个 action 做 non-null 校验。
|
||||
|
||||
### 4. Retry counter ownership
|
||||
|
||||
Edge 只选 route,不修改 state。Factory 用 wrapper 管理计数:
|
||||
|
||||
- Planner 重入前,如果上次 `planner_status` 是 INVALID_OUTPUT/RETRYABLE_FAILED,count + 1。
|
||||
- Verifier/Composer 同理。
|
||||
- 第一次失败后的 state count 为 0,允许 self-loop;重入执行后 count 为 1,再失败则 Fallback。
|
||||
- Evidence Retry Node 完成时将 `evidence_retry_count + 1`、`planner_retry_count=0`、`planner_mode=EVIDENCE_GAP_ONLY`。
|
||||
- Verified Input Node 完成时重置 `verifier_retry_count=0`,因为它产生新的 verified input。
|
||||
- 技术重试不修改 evidence count。
|
||||
|
||||
替代方案:由每个 Fake/real action 自行维护计数。拒绝,因为遗漏会造成无限 self-loop,骨架必须拥有控制计数。
|
||||
|
||||
### 5. Conditional routing
|
||||
|
||||
| Source | Route keys |
|
||||
|---|---|
|
||||
| Planner | executor / retry_planner / fallback |
|
||||
| Executor | gatekeeper / fallback |
|
||||
| Gatekeeper | verified_input / fallback |
|
||||
| Verifier | composer / retry_verifier / evidence_retry / fallback |
|
||||
| Composer | end / retry_composer / fallback |
|
||||
|
||||
Verified Input 固定到 Verifier,Evidence Retry 固定到 Planner,Fallback 固定到 END。
|
||||
|
||||
Verifier evidence-retry guard 同时要求:
|
||||
|
||||
- `verifier_status=COMPLETED`
|
||||
- `effective_verdict=LOW_CONFID`
|
||||
- `verifier_verdict_ceiling=PASS`
|
||||
- `verifier_output.facts_checked` 至少一项具有非空 fact 且 verification 为 `no_evidence` 或 `indirect_support`
|
||||
- `evidence_retry_count < 1`
|
||||
|
||||
否则 LOW_CONFID 到 Composer。router 只检查现有 Verifier 输出,不选择工具或构造 retry context;后者属于阶段 2 Evidence Retry Node。
|
||||
|
||||
### 6. Recursion limit
|
||||
|
||||
合法最坏路径低于 20 次 Node 执行;compile recursion limit 固定 32。测试断言 compiled graph 的 max iterations/compile config,并覆盖第二次技术失败和第二次 LOW_CONFID 均终止。
|
||||
|
||||
recursion limit 是最后保险,不替代业务 guard。
|
||||
|
||||
### 7. Event and trace contract
|
||||
|
||||
`OrchestrationEvent` 构造时拒绝 blank node/outcome/reason 或 attempt<1。每个 Fake/真实 Node attempt 返回一个 event;AppendStrategy 累积实际路径。
|
||||
|
||||
Builder:
|
||||
|
||||
1. 要求 events 非空且类型正确。
|
||||
2. 相邻 events 生成 transition,transition reason/attempt 取 source event。
|
||||
3. 最后 event 决定 finalNode 和 terminationReason。
|
||||
4. final node 为 Fallback 时 degraded=true;其他质量由 effective verdict 表达。
|
||||
5. evidence retry count 从 state 读取。
|
||||
6. `toMap()` 使用冻结 snake_case 字段,transition 同样提供 map。
|
||||
|
||||
不从应用日志推导路径,也不在 state 维护第二份 transitions。
|
||||
|
||||
### 8. Test architecture
|
||||
|
||||
`DiagnosisGraphRoutingTest` 使用真实 `CompiledGraph` + scriptable Fake actions:
|
||||
|
||||
- 每个 node 有 outcome 队列和调用计数。
|
||||
- Fake action 只输出本 node 的状态字段、必要 guard payload 和一个 event。
|
||||
- 每个用例使用唯一 `RunnableConfig.threadId`。
|
||||
- 断言 node sequence、调用次数、最终 state、events、trace transitions。
|
||||
- 参数化覆盖同类技术失败,独立用例覆盖 evidence retry/counter reset 和 unknown fail-closed。
|
||||
|
||||
`DiagnosisOrchestrationTraceBuilderTest` 覆盖空 events、非法 event、顺序、fallback degraded 和 map shape。
|
||||
|
||||
## Interface Impact
|
||||
|
||||
- 等级:L2 internal interface。
|
||||
- 新接口消费者:阶段 2 adapters、阶段 3 orchestrator、阶段 4 test suite。
|
||||
- 构建消费者:Maven 直接声明 Graph Core,版本仍由既有 BOM 统一管理。
|
||||
- 当前生产消费者:无。
|
||||
- 外部 API/DTO/数据库/状态:无变化。
|
||||
- 兼容策略:后续 actions 实现 ports;Graph State 不直接传给 Agent。
|
||||
- 回滚:revert 本阶段提交,无数据迁移。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Graph merge 行为与假设不同] → 使用真实 CompiledGraph 单元测试,不 mock StateGraph。
|
||||
- [计数 wrapper 与 action 更新冲突] → wrapper 最后写入控制计数,actions 不拥有 retry counters。
|
||||
- [Verifier gap 解析过早耦合] → router 只识别现有 facts_checked 最小字段,retry context 构造留到阶段 2。
|
||||
- [未接生产入口被误认为完成] → proposal/spec/acceptance 明确 skeleton-only,阶段 3 才切换。
|
||||
- [事件无限追加] → 所有业务循环有硬上限且 recursion limit=32。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 添加纯 Java 状态、router、actions、factory 和 trace types。
|
||||
2. 先用 Fake actions 编译和执行完整 Graph。
|
||||
3. 阶段 1 archive + commit 后,阶段 2 基于 ports 实现真实 nodes。
|
||||
4. 如需回滚,revert 阶段 1 commit;当前生产路径不受影响。
|
||||
|
||||
## Open Questions
|
||||
|
||||
无。
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
# Chat Diagnosis StateGraph Routing Skeleton
|
||||
|
||||
## Why
|
||||
|
||||
阶段 0 已归档 ISS-011 的 StateGraph 设计基线,但仓库尚无可编译的 StateGraph 实现,也没有证据证明锁定的 Graph Core `1.1.2.0` 能按冻结条件边、追加事件策略和循环上限工作。阶段 1 需要用 Fake Node 建立不接真实模型、不会进入生产入口的路由骨架,为后续真实 Node 接入提供稳定内部接口。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 新增 Diagnosis Graph State key、Node、route、status/verdict 常量和类型。
|
||||
- 在现有 Spring AI Alibaba BOM 管理下显式声明 Graph Core 直接依赖,避免依赖 Agent Framework 的传递关系。
|
||||
- 新增可注入 config-aware Node action ports 的 StateGraph 编译工厂。
|
||||
- 实现阶段 0 冻结的完整条件边、三类技术重试上限、一次 evidence retry 和 recursion limit。
|
||||
- 为 `orchestration_events` 配置 AppendStrategy,其余字段默认 ReplaceStrategy。
|
||||
- 新增有界 event、transition 和 orchestration trace builder。
|
||||
- 使用 Fake Node 单元测试覆盖正常、重试、失败、Gatekeeper、LOW_CONFID、Fallback、循环上限和 trace 顺序。
|
||||
|
||||
本 change 不接入 ChatService 或任何真实 Agent/Service。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `chat-diagnosis-stategraph-routing-skeleton`:提供未接生产入口的 StateGraph 状态、拓扑、路由、有限循环和编排 trace 构造能力。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- 无。阶段 0 设计基线保持不变;如果实现发现 API 冲突,必须先回写本 change,而不是静默改变基线语义。
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
|
||||
- 包 `com.superbiz.agent.graph.diagnosis` 下的纯 Java Graph 骨架。
|
||||
- `pom.xml` 中 Graph Core 的直接编译依赖;版本继续由现有 BOM 锁定为 1.1.2.0。
|
||||
- Planner、Executor、Gatekeeper、Verified Input、Verifier、Evidence Retry、Composer、Fallback Node action ports。
|
||||
- `orchestration_events` Append 策略和紧凑 trace builder。
|
||||
- Fake Node route tests,使用 `RunnableConfig.threadId` 执行。
|
||||
- recursion limit=32;业务计数仍是主要终止机制。
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- ReactAgent Adapter、Prompt、ToolCallback、Skill 或模型调用。
|
||||
- 调用 `ExecutorGatekeeperService` 或读取数据库 ToolInvocation。
|
||||
- 修改 `ChatService`、`VerifierInputHook`、`VerifierContextHolder`。
|
||||
- Flyway、`DiagnosisRun`、Trace DTO/API 或持久化。
|
||||
- 删除旧 Sequential 实现或测试。
|
||||
- Maven E2E、`logs/` 和数据库核验。
|
||||
|
||||
## Context Constraints
|
||||
|
||||
- 必须引用阶段 0 archive,不得改变其路由、安全或 run ownership 语义。
|
||||
- 使用本地已验证的 Graph Core `1.1.2.0` API,不依赖未锁定版本示例。
|
||||
- Graph action ports 使用 `AsyncNodeActionWithConfig`,为阶段 2 显式传递 run config 留出接口。
|
||||
- Executor 不重试;Planner/Verifier/Composer 各最多一次技术重试;整个 Run 最多一次 evidence retry。
|
||||
- Unknown/null status 必须 fail closed 到 Fallback。
|
||||
- Fake nodes 只存在于测试代码,生产骨架不得包含模拟业务输出。
|
||||
- 阶段 1 不改变任何外部 API 或当前生产路径。
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Graph 可编译,默认 Replace、events Append,recursion limit 为 32。
|
||||
- PASS 正常路径到 Composer/END,events 与 transitions 顺序一致。
|
||||
- Planner INVALID_OUTPUT/RETRYABLE_FAILED 首次自重试,第二次或 NON_RETRYABLE_FAILED Fallback。
|
||||
- Executor COMPLETED 进入 Gatekeeper;INVALID_OUTPUT/TOOL_BLOCKED/FAILED Fallback 且从不重试。
|
||||
- Gatekeeper PASS 和有 binding 的 LOW_CONFID 进入 Verified Input;REJECT、unknown、零 binding LOW_CONFID Fallback。
|
||||
- Verifier 技术失败首次自重试;PASS/REJECT 到 Composer;满足全部 guard 的 LOW_CONFID 只补证据一次;其余 LOW_CONFID 到 Composer。
|
||||
- Composer 技术失败首次自重试,耗尽或不可重试进入 Fallback。
|
||||
- Evidence retry 进入新 Planner 阶段时重置 planner retry count,且不影响其他技术计数。
|
||||
- 每个测试路径能构造 bounded orchestration trace,无未定义条件边或无限循环。
|
||||
- focused unit tests 和 Maven test-compile 通过;不运行 Maven E2E。
|
||||
|
||||
## Risks
|
||||
|
||||
- Graph Core 的 state merge/conditional-edge 细节可能与 API 签名表面不同;用真实 CompiledGraph Fake Node tests 验证。
|
||||
- Node action 若忘记写 status/event,路由必须 fail closed,测试覆盖 null/unknown。
|
||||
- 通用骨架若掺入真实 Agent 语义会污染阶段边界;本 change 只定义 ports 和确定性路由。
|
||||
- 32 次 recursion limit 是保险,不替代显式计数。
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Diagnosis Graph skeleton SHALL compile against the locked Graph API
|
||||
|
||||
The system SHALL provide an internal Diagnosis StateGraph skeleton using Graph Core 1.1.2.0 config-aware node actions, conditional edges, explicit key strategies, and a recursion limit of 32. The skeleton SHALL NOT be wired to the current production Chat path.
|
||||
|
||||
#### Scenario: Skeleton is compiled
|
||||
|
||||
- **WHEN** valid node action ports are supplied
|
||||
- **THEN** the Graph SHALL compile with all frozen nodes and conditional edges
|
||||
- **AND** `orchestration_events` SHALL use Append semantics while all other state uses Replace semantics
|
||||
- **AND** the compiled Graph SHALL enforce recursion limit 32
|
||||
|
||||
#### Scenario: Run config is supplied
|
||||
|
||||
- **WHEN** a Fake Node Graph is invoked with a `RunnableConfig.threadId`
|
||||
- **THEN** config-aware node ports SHALL receive that config
|
||||
- **AND** the final state SHALL remain scoped to that invocation
|
||||
|
||||
#### Scenario: Production path is inspected
|
||||
|
||||
- **WHEN** stage 1 is accepted
|
||||
- **THEN** ChatService, real Agents, Gatekeeper service, database, and Trace API SHALL NOT invoke the new skeleton
|
||||
|
||||
### Requirement: Planner routing SHALL allow one technical retry per Planner stage
|
||||
|
||||
The skeleton SHALL route Planner COMPLETED to Executor. INVALID_OUTPUT and RETRYABLE_FAILED SHALL self-retry only while `planner_retry_count=0`; NON_RETRYABLE_FAILED, unknown status, or a second technical failure SHALL route to Fallback.
|
||||
|
||||
#### Scenario: Planner first technical failure
|
||||
|
||||
- **WHEN** Planner first returns INVALID_OUTPUT or RETRYABLE_FAILED
|
||||
- **THEN** only Planner SHALL run again
|
||||
- **AND** the re-entered Planner state SHALL have `planner_retry_count=1`
|
||||
|
||||
#### Scenario: Planner retry is exhausted
|
||||
|
||||
- **WHEN** Planner returns a technical failure after retry count reaches 1
|
||||
- **THEN** the Graph SHALL route to Fallback
|
||||
- **AND** Executor SHALL NOT run
|
||||
|
||||
#### Scenario: Planner fails non-retryably
|
||||
|
||||
- **WHEN** Planner returns NON_RETRYABLE_FAILED or an unknown status
|
||||
- **THEN** the Graph SHALL route directly to Fallback
|
||||
|
||||
### Requirement: Executor and Gatekeeper routing SHALL fail closed
|
||||
|
||||
Executor SHALL route only COMPLETED output to Gatekeeper and SHALL never retry. Gatekeeper SHALL route PASS and LOW_CONFID with verified bindings to Verified Input; REJECT, unknown status, or LOW_CONFID with zero bindings SHALL route to Fallback.
|
||||
|
||||
#### Scenario: Executor completes legal output
|
||||
|
||||
- **WHEN** Executor returns COMPLETED, including a legal no-evidence output or legal output after tool errors
|
||||
- **THEN** Gatekeeper SHALL run exactly once
|
||||
|
||||
#### Scenario: Executor cannot complete contract
|
||||
|
||||
- **WHEN** Executor returns INVALID_OUTPUT, TOOL_BLOCKED, FAILED, or unknown status
|
||||
- **THEN** the Graph SHALL route directly to Fallback
|
||||
- **AND** Gatekeeper and Verifier SHALL NOT run
|
||||
|
||||
#### Scenario: Gatekeeper permits verification
|
||||
|
||||
- **WHEN** Gatekeeper returns PASS or LOW_CONFID with `verified_binding_count>0`
|
||||
- **THEN** Verified Input SHALL run before Verifier
|
||||
|
||||
#### Scenario: Gatekeeper blocks verification
|
||||
|
||||
- **WHEN** Gatekeeper returns REJECT, unknown status, or LOW_CONFID with zero verified bindings
|
||||
- **THEN** the Graph SHALL route to Fallback
|
||||
- **AND** Verifier SHALL NOT run
|
||||
|
||||
### Requirement: Verifier routing SHALL separate technical retry from evidence retry
|
||||
|
||||
Verifier INVALID_OUTPUT and RETRYABLE_FAILED SHALL self-retry once with the same verified input. COMPLETED PASS or REJECT SHALL route to Composer. COMPLETED LOW_CONFID SHALL route to one Evidence Retry only when all frozen guards are true; otherwise it SHALL route to Composer. Other outcomes SHALL fail closed.
|
||||
|
||||
#### Scenario: Verifier first technical failure
|
||||
|
||||
- **WHEN** Verifier first returns INVALID_OUTPUT or RETRYABLE_FAILED
|
||||
- **THEN** only Verifier SHALL run again
|
||||
- **AND** Gatekeeper, Executor, and tools SHALL NOT rerun
|
||||
|
||||
#### Scenario: Verifier retry is exhausted
|
||||
|
||||
- **WHEN** Verifier returns a technical failure after `verifier_retry_count=1`
|
||||
- **THEN** the Graph SHALL route to Fallback
|
||||
|
||||
#### Scenario: Verifier verdict reaches Composer
|
||||
|
||||
- **WHEN** Verifier completes with effective PASS or REJECT
|
||||
- **THEN** Composer SHALL run
|
||||
|
||||
#### Scenario: LOW_CONFID qualifies for evidence retry
|
||||
|
||||
- **WHEN** Verifier completes LOW_CONFID with ceiling PASS, valid no_evidence or indirect_support facts, and `evidence_retry_count=0`
|
||||
- **THEN** Evidence Retry SHALL run once and return to a new Planner stage
|
||||
- **AND** `planner_retry_count` SHALL reset to 0
|
||||
- **AND** `evidence_retry_count` SHALL become 1
|
||||
|
||||
#### Scenario: LOW_CONFID does not qualify for evidence retry
|
||||
|
||||
- **WHEN** ceiling is LOW_CONFID, facts contain no valid gap, or evidence retry count is already 1
|
||||
- **THEN** Composer SHALL run without another Planner cycle
|
||||
|
||||
### Requirement: Composer routing SHALL allow one technical retry and then terminate safely
|
||||
|
||||
Composer COMPLETED SHALL terminate at END. INVALID_OUTPUT and RETRYABLE_FAILED SHALL self-retry once; NON_RETRYABLE_FAILED, unknown status, or a second technical failure SHALL route to Fallback and then END.
|
||||
|
||||
#### Scenario: Composer first technical failure
|
||||
|
||||
- **WHEN** Composer first returns INVALID_OUTPUT or RETRYABLE_FAILED
|
||||
- **THEN** only Composer SHALL run again
|
||||
- **AND** Verifier and preceding nodes SHALL NOT rerun
|
||||
|
||||
#### Scenario: Composer retry is exhausted
|
||||
|
||||
- **WHEN** Composer fails technically after `composer_retry_count=1`
|
||||
- **THEN** Fallback SHALL run exactly once
|
||||
- **AND** the Graph SHALL terminate
|
||||
|
||||
#### Scenario: Composer succeeds
|
||||
|
||||
- **WHEN** Composer returns COMPLETED
|
||||
- **THEN** the Graph SHALL terminate without invoking Fallback
|
||||
|
||||
### Requirement: Orchestration events SHALL produce an exact bounded trace
|
||||
|
||||
Each node attempt SHALL append one terminal orchestration event. The trace builder SHALL derive transitions from adjacent events, final node and termination reason from the last event, degraded state from Fallback termination, and evidence retry count from state.
|
||||
|
||||
#### Scenario: Normal path trace is built
|
||||
|
||||
- **WHEN** Fake nodes execute Planner, Executor, Gatekeeper, Verified Input, Verifier, and Composer
|
||||
- **THEN** events and transitions SHALL preserve that exact order
|
||||
- **AND** the trace SHALL terminate at Composer without degradation
|
||||
|
||||
#### Scenario: Fallback path trace is built
|
||||
|
||||
- **WHEN** a route terminates through Fallback
|
||||
- **THEN** the trace final node SHALL be Fallback
|
||||
- **AND** `degraded` SHALL be true
|
||||
- **AND** its termination reason SHALL come from the Fallback event
|
||||
|
||||
#### Scenario: Trace input is invalid
|
||||
|
||||
- **WHEN** no events exist or an event has blank node, outcome, reason code, or attempt below 1
|
||||
- **THEN** trace construction SHALL fail explicitly rather than fabricate a path
|
||||
|
||||
#### Scenario: Event payload is inspected
|
||||
|
||||
- **WHEN** orchestration events and trace maps are produced
|
||||
- **THEN** they SHALL contain only routing metadata
|
||||
- **AND** they SHALL NOT contain Prompt, model reasoning, tool output, or Graph State snapshots
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
## 1. Define Graph State And Audit Types
|
||||
|
||||
- [x] 1.1 Declare the BOM-managed Graph Core direct dependency; add diagnosis state keys, typed status/verdict enums, node/route/reason constants, and Replace/Append key strategies.
|
||||
- [x] 1.2 Add validated orchestration event, transition, and trace value types with bounded routing-only map output.
|
||||
|
||||
## 2. Build The Deterministic Graph Skeleton
|
||||
|
||||
- [x] 2.1 Add non-null config-aware node action ports for Planner, Executor, Gatekeeper, Verified Input, Verifier, Evidence Retry, Composer, and Fallback.
|
||||
- [x] 2.2 Implement fail-closed deterministic routers for every frozen Planner, Executor, Gatekeeper, Verifier, and Composer outcome.
|
||||
- [x] 2.3 Build and compile the StateGraph with all nodes/edges, retry counter wrappers, evidence retry resets, Append events, and recursion limit 32.
|
||||
|
||||
## 3. Build The Trace Summary
|
||||
|
||||
- [x] 3.1 Implement orchestration trace construction from ordered events, including transitions, final reason, degraded flag, evidence retry count, and explicit invalid-input errors.
|
||||
|
||||
## 4. Verify With Fake Nodes
|
||||
|
||||
- [x] 4.1 Create reusable scriptable config-aware Fake Node fixtures that emit one terminal event per attempt and expose node order/call counts.
|
||||
- [x] 4.2 Add real CompiledGraph tests for normal, Planner, Executor, and Gatekeeper routes including unknown fail-closed behavior.
|
||||
- [x] 4.3 Add real CompiledGraph tests for Verifier, evidence retry, counter reset/independence, Composer, and recursion termination routes.
|
||||
- [x] 4.4 Add trace builder and AppendStrategy assertions for exact event/transition order, fallback degradation, map shape, and invalid events.
|
||||
|
||||
## 5. Validate The Stage
|
||||
|
||||
- [x] 5.1 Run focused routing/trace tests, Maven test compilation, strict OpenSpec validation, and diff checks; resolve all regressions.
|
||||
- [x] 5.2 Verify ChatService, real Agents, Gatekeeper service, database, and Trace API do not reference the skeleton; record that Maven E2E/log/DB checks are reserved for stage 5.
|
||||
@@ -0,0 +1,154 @@
|
||||
# chat-diagnosis-stategraph-routing-skeleton Specification
|
||||
|
||||
## Purpose
|
||||
提供未接生产入口的 Diagnosis StateGraph 状态、config-aware Node ports、确定性条件边、有限重试、编排事件和 trace 构造能力,并以 Fake Node 测试锁定 Graph Core 1.1.2.0 的实际行为。
|
||||
## Requirements
|
||||
### Requirement: Diagnosis Graph skeleton SHALL compile against the locked Graph API
|
||||
|
||||
The system SHALL provide an internal Diagnosis StateGraph skeleton using Graph Core 1.1.2.0 config-aware node actions, conditional edges, explicit key strategies, and a recursion limit of 32. The skeleton SHALL NOT be wired to the current production Chat path.
|
||||
|
||||
#### Scenario: Skeleton is compiled
|
||||
|
||||
- **WHEN** valid node action ports are supplied
|
||||
- **THEN** the Graph SHALL compile with all frozen nodes and conditional edges
|
||||
- **AND** `orchestration_events` SHALL use Append semantics while all other state uses Replace semantics
|
||||
- **AND** the compiled Graph SHALL enforce recursion limit 32
|
||||
|
||||
#### Scenario: Run config is supplied
|
||||
|
||||
- **WHEN** a Fake Node Graph is invoked with a `RunnableConfig.threadId`
|
||||
- **THEN** config-aware node ports SHALL receive that config
|
||||
- **AND** the final state SHALL remain scoped to that invocation
|
||||
|
||||
#### Scenario: Production path is inspected
|
||||
|
||||
- **WHEN** stage 1 is accepted
|
||||
- **THEN** ChatService, real Agents, Gatekeeper service, database, and Trace API SHALL NOT invoke the new skeleton
|
||||
|
||||
### Requirement: Planner routing SHALL allow one technical retry per Planner stage
|
||||
|
||||
The skeleton SHALL route Planner COMPLETED to Executor. INVALID_OUTPUT and RETRYABLE_FAILED SHALL self-retry only while `planner_retry_count=0`; NON_RETRYABLE_FAILED, unknown status, or a second technical failure SHALL route to Fallback.
|
||||
|
||||
#### Scenario: Planner first technical failure
|
||||
|
||||
- **WHEN** Planner first returns INVALID_OUTPUT or RETRYABLE_FAILED
|
||||
- **THEN** only Planner SHALL run again
|
||||
- **AND** the re-entered Planner state SHALL have `planner_retry_count=1`
|
||||
|
||||
#### Scenario: Planner retry is exhausted
|
||||
|
||||
- **WHEN** Planner returns a technical failure after retry count reaches 1
|
||||
- **THEN** the Graph SHALL route to Fallback
|
||||
- **AND** Executor SHALL NOT run
|
||||
|
||||
#### Scenario: Planner fails non-retryably
|
||||
|
||||
- **WHEN** Planner returns NON_RETRYABLE_FAILED or an unknown status
|
||||
- **THEN** the Graph SHALL route directly to Fallback
|
||||
|
||||
### Requirement: Executor and Gatekeeper routing SHALL fail closed
|
||||
|
||||
Executor SHALL route only COMPLETED output to Gatekeeper and SHALL never retry. Gatekeeper SHALL route PASS and LOW_CONFID with verified bindings to Verified Input; REJECT, unknown status, or LOW_CONFID with zero bindings SHALL route to Fallback.
|
||||
|
||||
#### Scenario: Executor completes legal output
|
||||
|
||||
- **WHEN** Executor returns COMPLETED, including a legal no-evidence output or legal output after tool errors
|
||||
- **THEN** Gatekeeper SHALL run exactly once
|
||||
|
||||
#### Scenario: Executor cannot complete contract
|
||||
|
||||
- **WHEN** Executor returns INVALID_OUTPUT, TOOL_BLOCKED, FAILED, or unknown status
|
||||
- **THEN** the Graph SHALL route directly to Fallback
|
||||
- **AND** Gatekeeper and Verifier SHALL NOT run
|
||||
|
||||
#### Scenario: Gatekeeper permits verification
|
||||
|
||||
- **WHEN** Gatekeeper returns PASS or LOW_CONFID with `verified_binding_count>0`
|
||||
- **THEN** Verified Input SHALL run before Verifier
|
||||
|
||||
#### Scenario: Gatekeeper blocks verification
|
||||
|
||||
- **WHEN** Gatekeeper returns REJECT, unknown status, or LOW_CONFID with zero verified bindings
|
||||
- **THEN** the Graph SHALL route to Fallback
|
||||
- **AND** Verifier SHALL NOT run
|
||||
|
||||
### Requirement: Verifier routing SHALL separate technical retry from evidence retry
|
||||
|
||||
Verifier INVALID_OUTPUT and RETRYABLE_FAILED SHALL self-retry once with the same verified input. COMPLETED PASS or REJECT SHALL route to Composer. COMPLETED LOW_CONFID SHALL route to one Evidence Retry only when all frozen guards are true; otherwise it SHALL route to Composer. Other outcomes SHALL fail closed.
|
||||
|
||||
#### Scenario: Verifier first technical failure
|
||||
|
||||
- **WHEN** Verifier first returns INVALID_OUTPUT or RETRYABLE_FAILED
|
||||
- **THEN** only Verifier SHALL run again
|
||||
- **AND** Gatekeeper, Executor, and tools SHALL NOT rerun
|
||||
|
||||
#### Scenario: Verifier retry is exhausted
|
||||
|
||||
- **WHEN** Verifier returns a technical failure after `verifier_retry_count=1`
|
||||
- **THEN** the Graph SHALL route to Fallback
|
||||
|
||||
#### Scenario: Verifier verdict reaches Composer
|
||||
|
||||
- **WHEN** Verifier completes with effective PASS or REJECT
|
||||
- **THEN** Composer SHALL run
|
||||
|
||||
#### Scenario: LOW_CONFID qualifies for evidence retry
|
||||
|
||||
- **WHEN** Verifier completes LOW_CONFID with ceiling PASS, valid no_evidence or indirect_support facts, and `evidence_retry_count=0`
|
||||
- **THEN** Evidence Retry SHALL run once and return to a new Planner stage
|
||||
- **AND** `planner_retry_count` SHALL reset to 0
|
||||
- **AND** `evidence_retry_count` SHALL become 1
|
||||
|
||||
#### Scenario: LOW_CONFID does not qualify for evidence retry
|
||||
|
||||
- **WHEN** ceiling is LOW_CONFID, facts contain no valid gap, or evidence retry count is already 1
|
||||
- **THEN** Composer SHALL run without another Planner cycle
|
||||
|
||||
### Requirement: Composer routing SHALL allow one technical retry and then terminate safely
|
||||
|
||||
Composer COMPLETED SHALL terminate at END. INVALID_OUTPUT and RETRYABLE_FAILED SHALL self-retry once; NON_RETRYABLE_FAILED, unknown status, or a second technical failure SHALL route to Fallback and then END.
|
||||
|
||||
#### Scenario: Composer first technical failure
|
||||
|
||||
- **WHEN** Composer first returns INVALID_OUTPUT or RETRYABLE_FAILED
|
||||
- **THEN** only Composer SHALL run again
|
||||
- **AND** Verifier and preceding nodes SHALL NOT rerun
|
||||
|
||||
#### Scenario: Composer retry is exhausted
|
||||
|
||||
- **WHEN** Composer fails technically after `composer_retry_count=1`
|
||||
- **THEN** Fallback SHALL run exactly once
|
||||
- **AND** the Graph SHALL terminate
|
||||
|
||||
#### Scenario: Composer succeeds
|
||||
|
||||
- **WHEN** Composer returns COMPLETED
|
||||
- **THEN** the Graph SHALL terminate without invoking Fallback
|
||||
|
||||
### Requirement: Orchestration events SHALL produce an exact bounded trace
|
||||
|
||||
Each node attempt SHALL append one terminal orchestration event. The trace builder SHALL derive transitions from adjacent events, final node and termination reason from the last event, degraded state from Fallback termination, and evidence retry count from state.
|
||||
|
||||
#### Scenario: Normal path trace is built
|
||||
|
||||
- **WHEN** Fake nodes execute Planner, Executor, Gatekeeper, Verified Input, Verifier, and Composer
|
||||
- **THEN** events and transitions SHALL preserve that exact order
|
||||
- **AND** the trace SHALL terminate at Composer without degradation
|
||||
|
||||
#### Scenario: Fallback path trace is built
|
||||
|
||||
- **WHEN** a route terminates through Fallback
|
||||
- **THEN** the trace final node SHALL be Fallback
|
||||
- **AND** `degraded` SHALL be true
|
||||
- **AND** its termination reason SHALL come from the Fallback event
|
||||
|
||||
#### Scenario: Trace input is invalid
|
||||
|
||||
- **WHEN** no events exist or an event has blank node, outcome, reason code, or attempt below 1
|
||||
- **THEN** trace construction SHALL fail explicitly rather than fabricate a path
|
||||
|
||||
#### Scenario: Event payload is inspected
|
||||
|
||||
- **WHEN** orchestration events and trace maps are produced
|
||||
- **THEN** they SHALL contain only routing metadata
|
||||
- **AND** they SHALL NOT contain Prompt, model reasoning, tool output, or Graph State snapshots
|
||||
Reference in New Issue
Block a user