feat(harness): add canonical tool invocation boundary
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
| 日期 | slug | 说明 | 领域 | 关键词 | 关联 OpenSpec | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 2026-07-21 | single-react-tool-invocation-store | 建立统一 ToolBoundary 与 Redis canonical invocation store,集中生命周期、证据状态、TTL、容量和 Run 所有权。 | Harness/Tool boundary/Canonical store | ISS-014, ToolBoundary, canonical invocation, PROJECTING, READY, ERROR, TTL, RESULT_TOO_LARGE | openspec/changes/archive/2026-07-21-single-react-tool-invocation-store | archived |
|
||||
| 2026-07-21 | single-react-harness-run-context | 建立显式 RunContext、Harness Core、预算、取消、类型化重试和 Tool Store 基础。 | Harness/Run lifecycle/Budget | ISS-014, RunContext, deadline, cancellation, budget, retry, ToolCallKey | openspec/changes/archive/2026-07-21-single-react-harness-run-context | archived |
|
||||
| 2026-07-21 | single-react-aci-tool-contracts | 冻结 RAG、日志和 MySQL evidence Tool 的 Agent-facing ACI Schema、状态、框架调用引用和描述边界。 | Harness/Agent Tool contract | ISS-014, ACI, tool_call_id, evidence_status, RAG, query_logs, query_mysql, MOCK | openspec/changes/archive/2026-07-21-single-react-aci-tool-contracts | archived |
|
||||
| 2026-07-21 | single-react-design-freeze | 冻结单体 Diagnosis Agent、Harness、Guard、工具证据与阶段门禁契约。 | Chat/Harness/Agent contract | ISS-014, single ReactAgent, Harness, EvidenceGuard, SemanticGuard, tool_call_id, evidence_status | openspec/changes/archive/2026-07-21-single-react-design-freeze | archived |
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Acceptance: single-react-tool-invocation-store
|
||||
|
||||
## 实现结果
|
||||
|
||||
- 新增 canonical record/limits/exceptions/store interface/Redis JSON adapter。
|
||||
- 新增 ToolBoundary envelope/result、executor/projector interfaces 和稳定错误码。
|
||||
- 实现 preflight、Run/Tool budget、Run capacity、PROJECTING、READY/ERROR、evidence semantics、TTL 和 UTF-8 limits。
|
||||
- 旧 ToolInvocationRecorder、JPA、Chat/AIOps、Controller、Repository 和公开协议未修改。
|
||||
|
||||
## 静态验证
|
||||
|
||||
- `openspec validate single-react-tool-invocation-store --strict`:通过。
|
||||
- 新 Harness 包 Redis 引用仅为 `RedisCanonicalInvocationStore`。
|
||||
- legacy recorder/JPA/Chat/AIOps/Controller/repository/resources diff:为空。
|
||||
- staged diff check 与 Secret scan:提交前执行并通过。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
- `mvn -q -DskipTests compile`:通过。
|
||||
- `mvn -q '-Dtest=CanonicalInvocationStoreTest,ToolBoundaryTest' test`:通过。
|
||||
- 综合阶段 0/1/2/3A suite(含 Harness/ACI/Core/retry/key/config/ChatController):通过。
|
||||
|
||||
## 浏览器/人工验证
|
||||
|
||||
- 不适用。本阶段没有 UI、Controller、SSE 或公开协议变化。
|
||||
|
||||
## 未验证
|
||||
|
||||
- 未连接真实 Redis,未做 ACL/network/TTL live 验证;最终 E2E 阶段执行。
|
||||
- 未接入 Alibaba ToolInterceptor,真实框架 ID 传播留给后续 Agent/application stage。
|
||||
- 未实现 RAG/log/MySQL projector,留给 3B/3C。
|
||||
- canonical update 的 read-TTL-write 并发窗口已记录为风险,尚未 Lua/CAS 化。
|
||||
|
||||
## 剩余风险与后续门禁
|
||||
|
||||
- 新旧 JPA audit 与 canonical store 短期并存,后续 projector 必须只以新 boundary 的 READY record 作为引用来源。
|
||||
- 下一阶段 3B/3C 必须复用本 ToolBoundary,不复制 Redis 状态机。
|
||||
|
||||
## 状态
|
||||
|
||||
- Stage acceptance: accepted
|
||||
- OpenSpec archive: archived at `openspec/changes/archive/2026-07-21-single-react-tool-invocation-store`
|
||||
- Main spec sync: `openspec/specs/canonical-tool-invocation-store/spec.md`(7 added requirements)
|
||||
@@ -0,0 +1,29 @@
|
||||
# Brief: single-react-tool-invocation-store
|
||||
|
||||
## 背景
|
||||
|
||||
旧 `ToolInvocationRecorder` 依赖 ThreadLocal 和 JPA preview,不能证明完整 Tool 结果、生命周期和当前 Run 所有权。阶段 2 已提供 RunContext/Key/Capacity,需要统一 canonical ToolBoundary 和 Redis store 供后续 projector 复用。
|
||||
|
||||
## 目标
|
||||
|
||||
- 统一 Pre-Tool 门禁、PROJECTING/READY/ERROR 状态和 evidence semantics。
|
||||
- 在同一 Redis record 保存 request/raw_response/agent_result、框架 ID、Run、时间和错误。
|
||||
- 固定 TTL 不续期、容量/结果大小 fail-closed、raw 不静默截断。
|
||||
- 用 Fake Tool/Projector/Store 覆盖 duplicate、cross-run、no-evidence、error、TTL 和 oversize。
|
||||
|
||||
## 范围
|
||||
|
||||
- Canonical invocation model/store、Redis JSON adapter、ToolBoundary 和 focused tests。
|
||||
- 复用阶段 2 Core、budget、capacity、ToolCallKeyFactory。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不实现 RAG/log/MySQL projector。
|
||||
- 不修改旧 recorder/JPA、Chat/AIOps、Controller/SSE 或公开协议。
|
||||
|
||||
## 元数据
|
||||
|
||||
- 分档:complex
|
||||
- 接口影响:L2 内部 Harness boundary/store
|
||||
- 关联 Issue:ISS-014 阶段 3A
|
||||
- 关联 OpenSpec:`openspec/changes/single-react-tool-invocation-store`
|
||||
@@ -0,0 +1,106 @@
|
||||
# Decisions: single-react-tool-invocation-store
|
||||
|
||||
## 规模与入口
|
||||
|
||||
- 分档:complex。
|
||||
- 入口:ISS-014 阶段 3A;阶段 0/1/2 已 Archive 并由 `58c3910`、`4274f33`、`6b74990` 提交。
|
||||
- 目标:统一 ToolBoundary 和 Redis canonical invocation store,不实现 Tool-specific projection。
|
||||
|
||||
## Context
|
||||
|
||||
- 阶段 1 主规格已冻结 RAG/log/MySQL Agent-facing Request/Result 和 `EvidenceStatus`。
|
||||
- 阶段 2 主规格已冻结 `RunContext`、预算、取消、Key Factory 和 strict retry。
|
||||
- 旧 `ToolInvocationRecorder` 依赖 `SessionContextHolder`、JPA `ToolInvocation` 和 500 字符 preview,属于 durable audit 兼容路径,不是 canonical store。
|
||||
- 既有 `SessionConfiguration` 提供 `RedisTemplate<String,Object>` + JSON serializer;新 store 复用 bean,不新增连接配置。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| 维度 | 问题 | 模式 | 证据与结论 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| 术语 | canonical invocation 与旧 JPA ToolInvocation 是否同一记录? | evidence-driven | ISS-014 数据分层明确 Redis canonical 保存完整 request/raw/agent,JPA 只做 durable audit;两者分离。 | 已解决并汇报 |
|
||||
| 术语 | `PROJECTING/READY/ERROR` 与 evidence status 如何组合? | evidence-driven | 阶段 0/1 规格:只有 READY 可为 FOUND/NO_EVIDENCE,ERROR 不可引用;PROJECTING 是内部暂态。 | 已解决并汇报 |
|
||||
| 边界 | 阶段 3A 是否实现 RAG/log projector? | evidence-driven | ISS-014 3A 明确不实现 Tool-specific projection,3B/3C 单独接入。 | 已解决并汇报 |
|
||||
| 边界 | Redis 读取是否刷新 TTL? | evidence-driven | ISS-014 固定“创建设置、读取/更新不续期”;更新采用当前剩余 TTL,不恢复初始 TTL。 | 已解决并汇报 |
|
||||
| 验收 | raw 超限是否静默截断? | evidence-driven | ISS-014 明确 `RESULT_TOO_LARGE` ERROR,raw 不静默截断;agent projection 才可按 projector 预算截断并标记。 | 已解决并汇报 |
|
||||
| 验收 | 缺失/重复/cross-run ID 如何处理? | evidence-driven | 阶段 3A 任务明确覆盖;Key Factory 保留框架 ID,ToolBoundary 在 store 创建前校验 Run/ID 和 duplicate。 | 已解决并汇报 |
|
||||
| 技术 | Redis 如何避免 update 重置 TTL? | evidence-driven | 既有 RedisTemplate;begin 使用 setIfAbsent + TTL,update 先读取剩余 TTL 再写回相同/更短 TTL,get 不调用 expire。 | 已解决并汇报 |
|
||||
| 技术 | 是否修改旧 recorder 以复用新 store? | evidence-driven | 旧链路大量测试依赖 JPA preview/evidence_refs;本阶段零消费者,保持旧 recorder 不变,避免行为回归。 | 已解决并汇报 |
|
||||
|
||||
## Grill 结论
|
||||
|
||||
- 所有术语、边界、验收和技术问题均由 ISS、阶段规格、旧代码和 Redis 配置事实证明。
|
||||
- 没有新增产品偏好或兼容性取舍需要 user-interview;并发更新窗口作为已接受风险记录。
|
||||
- `grill-with-docs` 的代码可证结论已回写 proposal;没有未确认问题。
|
||||
|
||||
## 能力与工具限制
|
||||
|
||||
- Discover 能力来源:`sm-flow` + `grill-with-docs`。
|
||||
- 当前无 `codebase-retrieval`/LSP;使用 `rg`、源码、既有测试、本地 Redis 配置和 focused fake tests 进行等价核对。
|
||||
|
||||
## Cross-artifact 对齐
|
||||
|
||||
| 链路 | 状态 | 结论 |
|
||||
|---|---|---|
|
||||
| brief 目标/范围/非目标 -> proposal | 已对齐 | Boundary、canonical record、TTL/size、Fake tests 和 legacy isolation 全部覆盖。 |
|
||||
| proposal 范围/约束/承诺 -> design | 已对齐 | Redis value、状态机、preflight 顺序、raw/projection 和失败处理均已设计。 |
|
||||
| design 决策/接口影响/风险 -> specs/tasks | 已对齐 | L2 boundary、TTL 更新窗口、oversize/error、ID/Run 所有权有对应要求和任务。 |
|
||||
| specs 可观察行为 -> tasks | 已对齐 | 7 条 requirements 分解为 store、boundary、limits/failure 和隔离验证纵向切片。 |
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
- 能力来源:`zoom-out`,按 RunContext、Invocation Status、Evidence Status、canonical invocation 和 durable audit 术语审计。
|
||||
- ToolBoundary 只编排一次调用;CanonicalInvocationStore 独占 Redis 状态转换;DiagnosisHarnessCore 独占 Run budget/cancellation;旧 recorder 只写 JPA audit。
|
||||
- request/raw/agent result 归同一 canonical record,Agent 只获得 ToolBoundaryResult,不存在 raw 旁路。
|
||||
- Redis adapter 是唯一 Redis 访问点,接口/Fake 不依赖 Redis;后续 3B/3C 可直接复用而不复制状态机。
|
||||
- 风险集中在 read-TTL-write 并发窗口和 canonical raw 敏感性,已进入 design/spec/limits,无架构或 ADR 冲突。
|
||||
|
||||
## Commit Gate Preflight
|
||||
|
||||
- proposal、design、specs、tasks 完整,OpenSpec status complete,strict validation 通过。
|
||||
- question pool 无未汇报 evidence-driven 或未确认 user-interview 项。
|
||||
- L2 内部接口影响已记录;旧 JPA/Chat/Controller/协议不改。
|
||||
- cross-artifact 无 gap,所有错误、TTL、size、ID/Run 所有权和隔离要求可由 Fake tests 验证。
|
||||
- Apply 已获持续授权,范围只包括新 store/boundary 与 focused tests。
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
### 参考实现与复用
|
||||
|
||||
- 复用 `DiagnosisHarnessCore` 的 active/deadline/Tool budget/Run bytes 门禁。
|
||||
- 复用 `ToolCallKeyFactory` 精确保留框架 Tool Call ID 并隔离 Run key。
|
||||
- 复用阶段 0 `InvocationStatus` / `EvidenceStatus`,不创建字符串状态副本。
|
||||
- 复用 `SessionConfiguration` 提供的 `RedisTemplate<String,Object>` 和 Spring Boot ObjectMapper。
|
||||
- 旧 `ToolInvocationRecorder`/JPA preview 仅作为 durable audit 反例,本阶段不修改或调用。
|
||||
|
||||
### 技术栈清单
|
||||
|
||||
- canonical record:Java 17 record + Jackson JSON String,所有状态组合在 record transition 方法中校验。
|
||||
- Redis create:`ValueOperations.setIfAbsent` + TTL;update:读取当前 remaining TTL 后写回;get 不调用 expire。
|
||||
- 大小:UTF-8 bytes;record/agent result/store limits 与 RunContext 累计 capacity 双重门禁。
|
||||
- 测试:Mockito RedisTemplate/ValueOperations 验证 TTL API;In-memory fake store + Fake Tool/Projector 验证 boundary,不连接外部 Redis。
|
||||
|
||||
### 新建类型
|
||||
|
||||
- canonical model/limits/store/exceptions/Redis adapter。
|
||||
- ToolCallRequestEnvelope、ToolBoundaryResult、ProjectedToolResult、ToolExecutor、ToolResultProjector、ToolBoundary 和稳定 error codes。
|
||||
- Redis adapter tests 与 boundary fake tests。
|
||||
|
||||
### 影响半径
|
||||
|
||||
- 新 package 在阶段 3A 保持零现有消费者。
|
||||
- Redis 访问只允许出现在 `RedisCanonicalInvocationStore`;旧 Chat/AIOps/Controller/JPA/Recorder 不修改。
|
||||
|
||||
## Apply 结果
|
||||
|
||||
- 冲突分类:一次 focused test 断言错误(duplicate 场景应调用 `setIfAbsent` 两次)已修正并复跑通过;无规格偏离。
|
||||
- 新增 canonical record/limits/store exceptions、Redis JSON adapter、ToolBoundary envelope/result/interfaces 和 stable error codes。
|
||||
- ToolBoundary 已实现 preflight、Core budget/capacity、PROJECTING、raw/projection size、READY/ERROR 和安全返回边界;未接具体 projector。
|
||||
- 首模块对齐:store/boundary/limits/failure 与 design/tasks 全部完成;RAG/log/MySQL adapters 仍留给后续阶段。
|
||||
|
||||
## Apply 验证
|
||||
|
||||
- 编译:`mvn -q -DskipTests compile`:通过。
|
||||
- Store/Boundary focused:`mvn -q '-Dtest=CanonicalInvocationStoreTest,ToolBoundaryTest' test`:通过。
|
||||
- 综合回归:`mvn -q '-Dtest=CanonicalInvocationStoreTest,ToolBoundaryTest,HarnessContractTest,RagToolContractTest,QueryLogsToolContractTest,MysqlToolContractTest,RunContextTest,RunBudgetTest,DiagnosisHarnessCoreTest,HarnessRetryExecutorTest,ToolCallKeyFactoryTest,SpringAiRetryConfigurationTest,ChatControllerTest' test`:通过。
|
||||
- 静态隔离:新 Harness 包仅 `RedisCanonicalInvocationStore` 引用 Redis;legacy recorder/JPA/Chat/AIOps/Controller/repository/resources diff 为空。
|
||||
- OpenSpec:`openspec validate single-react-tool-invocation-store --strict`:通过。
|
||||
@@ -0,0 +1,20 @@
|
||||
# Evidence: single-react-tool-invocation-store
|
||||
|
||||
## 文档与代码证据
|
||||
|
||||
- ISS-014 阶段 3A 明确要求统一 ToolBoundary、canonical invocation、PROJECTING/READY/ERROR、TTL/容量、ID/Run 所有权,且不实现 3B/3C projector。
|
||||
- 阶段 2 已提供 `RunContext`、Run bytes capacity 和 `ToolCallKeyFactory`,本阶段直接复用。
|
||||
- 旧 `ToolInvocationRecorder` 使用 JPA preview 和 ThreadLocal fallback;新 canonical record 独立保存完整 request/raw/agent,不修改旧 recorder/JPA。
|
||||
- 既有 `SessionConfiguration` 提供 `RedisTemplate<String,Object>` JSON bean;`RedisCanonicalInvocationStore` 是新 Harness 包唯一 Redis 引用。
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- `setIfAbsent` 确保同一 `runId+toolCallId` 不覆盖;读取不调用 expire;更新使用剩余 TTL。
|
||||
- canonical record transition 只允许 PROJECTING -> READY/ERROR;READY 只接受 FOUND/NO_EVIDENCE,ERROR 不可引用。
|
||||
- ToolBoundary 在执行前校验 Run、ID、JSON、授权、只读和预算;raw 只在可信 store 保存,不返回 Agent。
|
||||
- UTF-8 record/Agent limits 与 Run capacity 双门禁;raw oversize 跳过 projector,Agent oversize 不返回,均产生 RESULT_TOO_LARGE。
|
||||
- Fake store/Redis mock tests 已覆盖 duplicate、cross-run、unauthorized、writable、execution/projection error、NO_EVIDENCE、TTL、raw/agent oversize。
|
||||
|
||||
## 工具限制
|
||||
|
||||
- 当前无 `codebase-retrieval`/LSP;使用 `rg`、源码、Maven 编译、Mockito Redis API 和 in-memory fake 完成等价验证。
|
||||
Reference in New Issue
Block a user