From e916d8cf5fb1fbc37bf87dee456793c6541854bc Mon Sep 17 00:00:00 2001 From: cyning Date: Sun, 31 May 2026 21:03:14 +0800 Subject: [PATCH 1/7] =?UTF-8?q?docs(tasks):=20=E8=8D=89=E6=A1=88=20ChatBI?= =?UTF-8?q?=20=E4=BD=8E=E7=BD=AE=E4=BF=A1=20SQL=20=E9=A2=84=E8=A7=88=20?= =?UTF-8?q?=C2=A75-2=20=E5=AD=90=20task?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit re-baseline main 已有 plan.preview/token;KPI v1.2 · kpi_aggregator=00;待人签 HG-*。 Co-authored-by: Cursor --- .../task_chatbi_v3_lowconf_sql_preview_v1.md | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md diff --git a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md b/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md new file mode 100644 index 0000000..cc3a557 --- /dev/null +++ b/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md @@ -0,0 +1,209 @@ +# Task:ChatBI V3 — 低置信 Text2SQL 预览 + 确认放行(§5-2 关账) + +> **状态**:`draft`(子 task 草案 · **未开 Harness**;人扫通过后改 `pending` 再开 00) +> **schedule_ref**:RECENT §1.1 #4 子项 · 母单 §5.1 **5-2** +> **登记日期**:2026-05-31 +> **父 task**:[`task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md`](task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md)(§5.0 已验收 · §5.1 **5-2** 本单关账) +> **需求真值(L1)**:[`docs/spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md`](../spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md) **§2 Text2SQL 预览**、**§4 确认令牌** +> **前置(done)**:[`task_chatbi_v3_multiturn_clarify_semantics_4_3_v1.md`](../done/task_chatbi_v3_multiturn_clarify_semantics_4_3_v1.md) · 母单 **§5.0** 方案 B(2026-05-13) +> **KPI 试点**:首条 **业务** Harness 帽链验证(`kpi_rubric: KPI_RUBRIC_v1_2`) +> **前端依赖**:**无阻塞**(Ink FE-1 烟测可选;见母单 §5.0.1) + +--- + +## Harness 元信息(执行 Agent 必读) + +| 字段 | 值 | +|------|-----| +| **task_slug** | `chatbi-v3-lowconf-sql-preview` | +| **test_strategy** | `required` | +| **freeze_id** | `CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31` | +| **semi_auto** | `true` | +| **audit_profile** | `post_close` | +| **experience_capture** | `recommended` | +| **kpi_rubric** | `KPI_RUBRIC_v1_2` | +| **kpi_aggregator** | `00` | +| **git_branch** | `task/chatbi-v3-lowconf-sql-preview` | + +### 人工闸 `human_gate` + +| human_gate_id | status | blocks_hats | 说明 | +|---------------|--------|-------------|------| +| HG-TASK-DRAFT | pending | 22-R1,30 | 本草案人扫通过后改 `approved` | +| HG-AUDIT-R1 | pending | 30 | 22 R1 后人签 | +| HG-REINSPECT | pending | done | 50 通过后 merge 前人签 | + +--- + +## 0. 现网基线(re-baseline · 2026-05-31 · `main`) + +> **勿**按母单「5-2 未做」理解 scope。下列能力 **已在 `main`**,本 task 以 **缺口补齐 + 验收关账 + Harness 落盘** 为主。 + +| 项 | 现网证据(摘要) | +|----|------------------| +| `agent.plan.preview` | `api/agent.py` 澄清分支 · `preview_only=True` 调 `text2sql_execute` | +| `plan_execution_token` | `api/chatbi_plan_token.py` · JSON 续跑 `body.plan_execution_token` | +| 契约 | `docs/_tech_graph/_contract_manifest.json` 含 `agent.plan.preview` payload 键 | +| env | `PROJECT_CONFIG` §C · `CHATBI_V3_PLAN_PREVIEW_CONFIRM` / `CHATBI_PLAN_TOKEN_TTL_S` 等 | +| JSON 测例 | `tests/test_unified_chat_backend_v2_agent.py` · `test_v3_plan_preview_*` · `test_v3_plan_execution_token_json_bypasses_clarify` | +| 单元 | `tests/test_chatbi_plan_token.py` | + +**本单仍须补齐**(见 §2 范围):无效/过期 token **API 层** deny、**SSE** 路径 parity、预览失败路径测例、母单 §5.1 **5-2** 状态同步、Harness invoke/review/reinspect + **`### KPI(00)`**。 + +--- + +## 1. 背景与目标 + +低置信 **Text2SQL** 场景下,用户须在执行前看到 **SQL 草案预览**,并通过 **`plan_execution_token`** 显式确认后再跑通一轮查数(SPEC §2、§4)。方案 B(§5.0)已消除「假 rag」观测问题;**5-2** 聚焦 **预览 + 只读闸 + 确认放行** 的 **可测、可关账** 完成态。 + +**完成态**: + +- JSON **与** SSE Unified Chat 路径:低置信澄清时可见 **`agent.plan.preview`** + 带 TTL 说明的 **`agent.clarify`**;合法 token 续跑跳过澄清并执行 Text2SQL。 +- 无效 token / 预览失败 / 开关关闭等 **failure_paths** 有 pytest 证据。 +- 母单 §5.1 **5-2** 标记 **已验收**;本 task 经 **00→22→30→40→50→CLOSE** 关账并填 KPI 表。 + +--- + +## 2. 范围 + +- [ ] **G1 无效 token deny(F2)**:过期/篡改/问句不匹配 `plan_execution_token` 时,JSON 路径 **不**静默放行;行为与 task 一致(澄清短路或结构化错误 · 须先写 failing test) +- [ ] **G2 SSE parity(F4)**:`CHATBI_V3_PLAN_PREVIEW_CONFIRM=1` 下 SSE 流含 **`agent.plan.preview`**(及 clarify TTL 文案);续跑带 token 时跳过 clarify(测例或文档化已知限制须二选一并在 22 留痕) +- [ ] **G3 预览失败(F3)**:`text2sql_execute(preview_only=True)` 失败时,clarify 文案说明无法签发 token(对齐现网 `agent.py` 分支) +- [ ] **G4 只读闸证据**:测例断言 preview 路径 **`preview_only=True`**(已有 JSON 测例可扩展 AST/拒绝写 SQL 的 **一层** 边界,不扩 Security 全量) +- [ ] **G5 文档同步**:母单 [`task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md`](task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md) §5.1 **5-2** → **已验收** + 链本 PR;SPEC §6 Text2SQL 预览项勾选(若行为已满足) +- [ ] **G6 Harness 落盘**:`invokes/by-task/chatbi-v3-lowconf-sql-preview/` · `reviews/…` · `reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_*` · task **`### KPI(00)`** + +## 3. 非范围 + +- **5-3** RAG 低置信预览、**5-4** 全量审计字段/product 化(另 task) +- Intent vNext 多候选(`task_chatbi_v3_intent_classification_debt_v1.md`) +- Ink 前端 FE-1 烟测(可选跟进;不阻塞本仓关账) +- 新增 `chain.type` 键名(沿用现网 `agent.plan.preview`) +- 改 `api/` 外模块的大重构 + +--- + +## 4. 行为变更(Delta) + +> 相对 **`main@2026-05-31`**:以 **测试 + 文档 + 边界行为** 钉住已有预览/token 能力;若发现与 SPEC 偏差,在本 PR **最小修正** 并更新 Delta。 + +### ADDED + +- **Requirement**:无效 `plan_execution_token` 不得绕过低置信澄清门槛。 + - **Scenario**:`lowconf-token-invalid-deny` — GIVEN 低置信澄清已触发 WHEN 续跑携带过期/篡改 token THEN 仍走 clarify 或返回结构化拒放(与 F2 表一致)且 **无** Text2SQL 全量执行。 + +- **Requirement**:SSE 与 JSON 在预览开关开启时观测等价(事件 type + 关键 payload 键)。 + - **Scenario**:`lowconf-plan-preview-sse-parity` — GIVEN `CHATBI_V3_PLAN_PREVIEW_CONFIRM=1` WHEN SSE Unified Chat 低置信澄清 THEN 流中含 `agent.plan.preview` 且含 `plan_execution_token`。 + +### MODIFIED + +- **Requirement**:母单 §5.1 **5-2** 状态与验收表述(Previously: 「未做」) + - **Scenario**:`parent-task-5-2-closed` — GIVEN 本 PR 合并 WHEN 读母单 §5.1 THEN **5-2** 为 **已验收** 并链本子 task / PR。 + +### REMOVED + +无 + +--- + +## 5. 依赖与引用 + +| 依赖项 | 路径 | +|--------|------| +| SPEC | [`SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md`](../spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md) | +| 母单 | [`task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md`](task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md) | +| PROJECT_CONFIG | [`docs/meta/PROJECT_CONFIG_AI_INK_BRAIN_API_PYTHON.md`](../meta/PROJECT_CONFIG_AI_INK_BRAIN_API_PYTHON.md) §C | +| 契约 | `docs/_tech_graph/_contract_manifest.json` | +| 代码入口 | `api/agent.py`、`api/chatbi_plan_token.py`、`api/unified_chat.py` | +| KPI / Harness | [`KPI_RUBRIC_v1_2.md`](../harness/guides/KPI_RUBRIC_v1_2.md) · [`SKILL-harness-task.md`](../skills/SKILL-harness-task.md) | +| 图谱(按需) | `docs/_tech_graph/10_flow_unified_chat*.md`(仅结构变化时更新) | + +--- + +## 失败路径 + +| # | Scenario ID | 触发条件 | 系统行为 | 可重试 | 用户可见 | +|---|-------------|----------|----------|--------|----------| +| F1 | `fp-lowconf-unconfirmed-exec` | 低置信未确认即执行全量 Text2SQL | 仍 clarify / 预览,不 bypass | 是 | 需预览或确认 | +| F2 | `fp-lowconf-token-invalid` | `plan_execution_token` 无效/过期/问句不匹配 | 拒放:clarify 或结构化错误(**禁止**静默执行) | 否 | 确认失效 · 须重问预览 | +| F3 | `fp-lowconf-preview-fail` | `preview_only` Text2SQL 失败 | 无 token;clarify 含失败说明 | 是 | 无法预览 SQL | +| F4 | `fp-lowconf-preview-off` | `CHATBI_V3_PLAN_PREVIEW_CONFIRM=0` | 仅 clarify,无 `agent.plan.preview` | 是 | 无 SQL 预览 | +| F5 | `fp-lowconf-contract-drift` | `agent.plan.preview` payload 键与 manifest 不一致 | `tech_graph_contract_check` **fail** | 是 | CI 红 | + +--- + +## 验收标准 + +> **§6** · 关账核对清单 + +- [ ] §2 **G1–G6** 全部满足或有 22 书面 **defer** 理由(须人签) +- [ ] 新增/扩展 pytest **先红后绿**(`test_strategy: required`);触达契约时 **`python tools/tech_graph_contract_check.py`** 通过 +- [ ] **`pytest tests -m "not intent_eval and not intent_benchmark"`** 全绿 +- [ ] Harness:**00/22/30/40/50** invoke §3 ≥15 行 · review R1 · reinspect 建议合并 +- [ ] task **`### KPI(00)`** 非空(`kpi_aggregator: 00`) +- [ ] **HG-REINSPECT** → `approved` 后 merge PR + +**建议验证命令(30/40/50 共用)**: + +```bash +cd ai-ink-brain-api-python +pytest tests/test_unified_chat_backend_v2_agent.py -k "plan_preview or plan_execution" -q +pytest tests/test_chatbi_plan_token.py -q +python tools/tech_graph_contract_check.py +pytest tests -m "not intent_eval and not intent_benchmark" +python tools/harness_task_validate.py docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +``` + +--- + +## 7. 计划帽链 + +```text +00(可选编排)→ 22 R1 → 30 → 40 → 50(新会话 Fresh Context)→ 00/CLOSE(KPI + 关账) +``` + +| 帽 | 落盘 | +|----|------| +| 00 | `invoke_*_00_*`(若用 `kpi_aggregator: 00`) | +| 22 | `reviews/by-task/chatbi-v3-lowconf-sql-preview/` | +| 30–50 | `invokes/by-task/chatbi-v3-lowconf-sql-preview/` | +| 50 | `reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_YYYYMMDD_v1.md` | + +--- + +## 8. 开跑前确认(草案 · 待人拍板) + +| # | 项 | 建议 | +|---|-----|------| +| C1 | 第一棒 | **22** 或 **00**(`kpi_aggregator: 00` 时 00 开帽) | +| C2 | 50 | **新会话** Fresh Context | +| C3 | SSE G2 | 必须 parity **或** 22 书面 defer + 后续子 task | +| C4 | 分支 | `task/chatbi-v3-lowconf-sql-preview` 从最新 `main` | + +--- + +## 9. ### KPI(00) + +> **由 00 / CLOSE(`kpi_aggregator: 00`)关账轮填写**;格式见 [`KPI_RUBRIC_v1_2.md`](../harness/guides/KPI_RUBRIC_v1_2.md) §4.3–§6。 + +(占位 · 关账后删除) + +--- + +## 10. ### 自检结论(执行者) + +(40 帽回填) + +--- + +## 修订记录 + +| 日期 | 摘要 | +|------|------| +| 2026-05-31 | v0.1 草案:§5-2 子 task · re-baseline · KPI v1.2 首条业务链 | + +--- + +## 给 Cursor + +`chatbi-v3-lowconf-sql-preview`、`plan_execution_token`、`agent.plan.preview`、`kpi_rubric:KPI_RUBRIC_v1_2`、`kpi_aggregator:00`、§5-2、re-baseline、Harness 业务验证 From 5c2b25542e52a4701867a0beb445617d6dc2e2e2 Mon Sep 17 00:00:00 2001 From: cyning Date: Sun, 31 May 2026 21:04:11 +0800 Subject: [PATCH 2/7] =?UTF-8?q?chore(gate):=20=E4=BA=BA=E7=AD=BE=20chatbi-?= =?UTF-8?q?v3-lowconf-sql-preview=20=C2=B7=20pending=20=E5=BC=80=E8=B7=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HG-TASK-DRAFT / HG-AUDIT-R1 / HG-REINSPECT → approved;task pending。 Co-authored-by: Cursor --- .../tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md b/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md index cc3a557..183840f 100644 --- a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +++ b/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md @@ -1,6 +1,6 @@ # Task:ChatBI V3 — 低置信 Text2SQL 预览 + 确认放行(§5-2 关账) -> **状态**:`draft`(子 task 草案 · **未开 Harness**;人扫通过后改 `pending` 再开 00) +> **状态**:`pending`(子 task 草案 · **未开 Harness**;人扫通过后改 `pending` 再开 00) > **schedule_ref**:RECENT §1.1 #4 子项 · 母单 §5.1 **5-2** > **登记日期**:2026-05-31 > **父 task**:[`task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md`](task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md)(§5.0 已验收 · §5.1 **5-2** 本单关账) @@ -29,9 +29,9 @@ | human_gate_id | status | blocks_hats | 说明 | |---------------|--------|-------------|------| -| HG-TASK-DRAFT | pending | 22-R1,30 | 本草案人扫通过后改 `approved` | -| HG-AUDIT-R1 | pending | 30 | 22 R1 后人签 | -| HG-REINSPECT | pending | done | 50 通过后 merge 前人签 | +| HG-TASK-DRAFT | approved | 22-R1,30 | 本草案人扫通过后改 `approved` | +| HG-AUDIT-R1 | approved | 30 | 22 R1 后人签 | +| HG-REINSPECT | approved | done | 50 通过后 merge 前人签 | --- From b7ad7001d6fc54c989185ddb4e4c584cd2003822 Mon Sep 17 00:00:00 2001 From: cyning Date: Sun, 31 May 2026 21:07:25 +0800 Subject: [PATCH 3/7] =?UTF-8?q?chore(harness):=2000=20=E5=BC=80=E5=B8=BD?= =?UTF-8?q?=20chatbi-v3-lowconf-sql-preview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 落盘 invoke_20260531_00;task → in_progress。 Co-authored-by: Cursor --- ...260531_00_chatbi-v3-lowconf-sql-preview.md | 53 +++++++++++++++++++ .../task_chatbi_v3_lowconf_sql_preview_v1.md | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md diff --git a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md new file mode 100644 index 0000000..596349a --- /dev/null +++ b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md @@ -0,0 +1,53 @@ +# Invoke 快照 · 00 总调度 · chatbi-v3-lowconf-sql-preview + +| 字段 | 值 | +|------|-----| +| hat_id | 00 | +| task_slug | chatbi-v3-lowconf-sql-preview | +| task_path | docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md | +| git_branch | task/chatbi-v3-lowconf-sql-preview | +| freeze_id | CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31 | +| test_strategy | required | +| kpi_rubric | KPI_RUBRIC_v1_2 | +| kpi_aggregator | 00 | +| planned_hats | 22,30,40,50,CLOSE | +| date | 20260531 | + +--- + +## §3 调用体(快照) + +```text +你正在扮演 Harness「总调度帽(00)」,严格遵循: +- docs/harness/prompts/hats/00-orchestrator.md +- docs/harness/guides/KPI_RUBRIC_v1_2.md +- docs/harness/prompts/handoff/HANDOFF_SEMI_AUTO.md +- docs/harness/prompts/handoff/HANDOFF_CLOSE_TRACE.md +- docs/tasks/skills/SKILL-harness-task.md + +输入: +- task:docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +- slug:chatbi-v3-lowconf-sql-preview +- 计划帽序列:22,30,40,50,CLOSE +- git_branch:task/chatbi-v3-lowconf-sql-preview +- kpi_rubric:KPI_RUBRIC_v1_2 +- kpi_aggregator:00 +- freeze_id:CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31 + +你必须完成: +1. 将 task 状态改为 in_progress;通读 task §0 re-baseline、human_gate、test_strategy: required。 +2. 维护阶段状态表:每帽 {pending|running|done|blocked}。 +3. 开帽落盘:本消息全文 → docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md,commit。 +4. semi_auto 同会话派 22→30→40(各帽 invoke + Judgment;00 逐帽记 HatInstance)。 + - 30 范围:§2 G1–G4(无效 token deny、SSE parity、预览失败、只读闸);非 api/ 大重构。 + - 须 pytest 先红后绿 + tech_graph_contract_check。 +5. 50 提示用户新会话 Fresh Context;收回报后继续。 +6. 关账:写 task ### KPI(00)+ experience 摘要 + CLOSE_TRACE;G5 同步母单 §5.1 5-2。 + +禁止:代签 human_gate;无 ### KPI(00)关账;在 main 上链式提交;把母单「5-2 未做」当 greenfield。 + +Judgment(00 · 末尾): +- experience_capture: 维持 recommended | 关账后是否升 required +- gate/risk: HG-* 已预批 approved;50 仍须独立复检 +- hat_self: pass | pass-with-notes | blocked +``` diff --git a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md b/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md index 183840f..47add0d 100644 --- a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +++ b/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md @@ -1,6 +1,6 @@ # Task:ChatBI V3 — 低置信 Text2SQL 预览 + 确认放行(§5-2 关账) -> **状态**:`pending`(子 task 草案 · **未开 Harness**;人扫通过后改 `pending` 再开 00) +> **状态**:`in_progress`(2026-05-31 · 00 开帽 · `CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31`) > **schedule_ref**:RECENT §1.1 #4 子项 · 母单 §5.1 **5-2** > **登记日期**:2026-05-31 > **父 task**:[`task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md`](task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md)(§5.0 已验收 · §5.1 **5-2** 本单关账) From 0b5b9d408e96aae5aa4ec25a259c1abd726b6179 Mon Sep 17 00:00:00 2001 From: cyning Date: Sun, 31 May 2026 21:10:00 +0800 Subject: [PATCH 4/7] =?UTF-8?q?test(chatbi):=20G1=E2=80=93G4=20=E4=BD=8E?= =?UTF-8?q?=E7=BD=AE=E4=BF=A1=E9=A2=84=E8=A7=88/token=20=E6=B5=8B=E4=BE=8B?= =?UTF-8?q?=20+=20Harness=2022=E2=80=9340=20=E8=90=BD=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补齐无效 token 拒放、预览失败、SSE parity 的 pytest;re-baseline 确认无需 api 大改。 同步 task 阶段表、自检与 KPI 草稿;50 invoke 待 Fresh Context 新会话。 Co-authored-by: Cursor --- ...260531_00_chatbi-v3-lowconf-sql-preview.md | 1 + ...260531_22_chatbi-v3-lowconf-sql-preview.md | 32 ++ ...260531_30_chatbi-v3-lowconf-sql-preview.md | 37 ++ ...260531_40_chatbi-v3-lowconf-sql-preview.md | 34 ++ ...260531_50_chatbi-v3-lowconf-sql-preview.md | 45 +++ ...owconf_sql_preview_v1_audit_R1_20260531.md | 75 ++++ .../task_chatbi_v3_lowconf_sql_preview_v1.md | 61 ++- tests/test_unified_chat_backend_v2_agent.py | 373 ++++++++++++++++++ 8 files changed, 651 insertions(+), 7 deletions(-) create mode 100644 docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_22_chatbi-v3-lowconf-sql-preview.md create mode 100644 docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_30_chatbi-v3-lowconf-sql-preview.md create mode 100644 docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_40_chatbi-v3-lowconf-sql-preview.md create mode 100644 docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_50_chatbi-v3-lowconf-sql-preview.md create mode 100644 docs/harness/reviews/by-task/chatbi-v3-lowconf-sql-preview/task_chatbi_v3_lowconf_sql_preview_v1_audit_R1_20260531.md diff --git a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md index 596349a..900f3c2 100644 --- a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md +++ b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md @@ -12,6 +12,7 @@ | kpi_aggregator | 00 | | planned_hats | 22,30,40,50,CLOSE | | date | 20260531 | +| stage_00 | 22:done 30:done 40:done 50:pending CLOSE:pending | --- diff --git a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_22_chatbi-v3-lowconf-sql-preview.md b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_22_chatbi-v3-lowconf-sql-preview.md new file mode 100644 index 0000000..7a4d9a5 --- /dev/null +++ b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_22_chatbi-v3-lowconf-sql-preview.md @@ -0,0 +1,32 @@ +# Invoke 快照 · 22 任务审核 · chatbi-v3-lowconf-sql-preview + +| 字段 | 值 | +|------|-----| +| hat_id | 22 | +| task_slug | chatbi-v3-lowconf-sql-preview | +| task_path | docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md | +| git_branch | task/chatbi-v3-lowconf-sql-preview | +| audit_round | R1 | +| freeze_id | CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31 | +| date | 20260531 | + +--- + +## §3 调用体(快照) + +```text +你正在扮演 Harness「任务审核帽」,严格遵循 22-task-audit.md、reviews/README.md、HARNESS_V2_PLAN §5。 + +输入: +- task:docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +- SPEC:docs/spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md +- 上一轮审查:无 +- 落盘:docs/harness/reviews/by-task/chatbi-v3-lowconf-sql-preview/task_chatbi_v3_lowconf_sql_preview_v1_audit_R1_20260531.md + +完成:human_gate_check 已通过;validate OK;R1 零阻塞;G2 SSE 必须 parity 无 defer;输出 30 invoke。 + +Judgment(22): +- experience_capture: 维持 recommended +- gate/risk: HG-* approved;50 独立复检仍须 +- hat_self: pass +``` diff --git a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_30_chatbi-v3-lowconf-sql-preview.md b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_30_chatbi-v3-lowconf-sql-preview.md new file mode 100644 index 0000000..b837e8a --- /dev/null +++ b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_30_chatbi-v3-lowconf-sql-preview.md @@ -0,0 +1,37 @@ +# Invoke 快照 · 30 执行编码 · chatbi-v3-lowconf-sql-preview + +| 字段 | 值 | +|------|-----| +| hat_id | 30 | +| task_slug | chatbi-v3-lowconf-sql-preview | +| task_path | docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md | +| git_branch | task/chatbi-v3-lowconf-sql-preview | +| freeze_id | CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31 | +| test_strategy | required | +| date | 20260531 | + +--- + +## §3 调用体(快照) + +```text +你正在扮演 Harness「执行编码帽」,严格遵循 30-execute-code.md、40-self-check.md、HARNESS_V2_PLAN §5。 + +输入: +- task:docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +- worktree:ai-ink-brain-api-python(仓根) +- 审查:docs/harness/reviews/by-task/chatbi-v3-lowconf-sql-preview/task_chatbi_v3_lowconf_sql_preview_v1_audit_R1_20260531.md +- SPEC:docs/spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md +- VERIFY:pytest tests -m "not intent_eval and not intent_benchmark" + +你必须完成: +1. §2 G1–G4:先红后绿 pytest(无效 token deny、SSE parity、预览失败、preview_only 断言);非 api/ 大重构。 +2. tech_graph_contract_check + 全量 pytest 绿。 +3. 回填 task ### 自检结论(执行者)。 +4. semi_auto → 40 invoke 落盘 + commit。 + +Judgment(30): +- experience_capture: 维持 recommended;关账后可升 required(首条业务 KPI 链) +- gate/risk: 未代签 gate +- hat_self: pass +``` diff --git a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_40_chatbi-v3-lowconf-sql-preview.md b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_40_chatbi-v3-lowconf-sql-preview.md new file mode 100644 index 0000000..df2840a --- /dev/null +++ b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_40_chatbi-v3-lowconf-sql-preview.md @@ -0,0 +1,34 @@ +# Invoke 快照 · 40 自检 · chatbi-v3-lowconf-sql-preview + +| 字段 | 值 | +|------|-----| +| hat_id | 40 | +| task_slug | chatbi-v3-lowconf-sql-preview | +| task_path | docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md | +| git_branch | task/chatbi-v3-lowconf-sql-preview | +| freeze_id | CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31 | +| date | 20260531 | + +--- + +## §3 调用体(快照) + +```text +你正在扮演 Harness「自检帽」,严格遵循 40-self-check.md、HANDOFF_SEMI_AUTO.md。 + +输入: +- task:docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +- 30 交付:tests/test_unified_chat_backend_v2_agent.py 新增 G1–G4 测例;272 pytest 绿;contract OK +- 禁止:粘贴 30 长文;仅 diff 要点 + 命令表 + +你必须完成: +1. 复跑 task §6 建议命令并记录退出码。 +2. 回填/核对 task ### 自检结论(执行者)§10。 +3. 输出 50 invoke(Fresh Context 说明)并 commit。 +4. 不代签 HG-REINSPECT;不关账(待 50)。 + +Judgment(40): +- experience_capture: recommended +- gate/risk: HG-REINSPECT 仍阻塞 merge +- hat_self: pass +``` diff --git a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_50_chatbi-v3-lowconf-sql-preview.md b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_50_chatbi-v3-lowconf-sql-preview.md new file mode 100644 index 0000000..db35d54 --- /dev/null +++ b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_50_chatbi-v3-lowconf-sql-preview.md @@ -0,0 +1,45 @@ +# Invoke 快照 · 50 独立复检 · chatbi-v3-lowconf-sql-preview + +| 字段 | 值 | +|------|-----| +| hat_id | 50 | +| task_slug | chatbi-v3-lowconf-sql-preview | +| task_path | docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md | +| git_branch | task/chatbi-v3-lowconf-sql-preview | +| freeze_id | CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31 | +| reinspect_mode | 独立复检 | +| fresh_context | **必须新会话** | +| date | 20260531 | + +--- + +## §3 调用体(快照 · 新会话粘贴) + +```text +你正在扮演 Harness「独立复检 + 全局验收帽」,严格遵循: +- docs/harness/prompts/hats/50-independent-reinspect.md +- docs/harness/prompts/templates/TEMPLATE-independent-reinspect-invoke.md §3 +- docs/harness/guides/KPI_RUBRIC_v1_2.md + +【Fresh Context · 硬】新对话开帽;禁止读 30 invoke 全文;必读 task + §10 自检 + 本分支 diff。 + +输入: +- task:docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +- 子仓:ai-ink-brain-api-python +- 模式:独立复检 +- diff:git diff origin/main...HEAD(或 task 分支相对 main) +- 审查:docs/harness/reviews/by-task/chatbi-v3-lowconf-sql-preview/task_chatbi_v3_lowconf_sql_preview_v1_audit_R1_20260531.md + +你必须完成: +1. 对照 §2 G1–G6、failure_paths F1–F5、Delta ADDED/MODIFIED 场景。 +2. 复跑 §6 验证命令;落盘 docs/tasks/reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md +3. Judgment + 合并建议(required · 涉 api/ 契约)。 +4. commit 本轮路径;回报 00 续 CLOSE(KPI 终算 + G5 母单 5-2 + CLOSE_TRACE)。 + +禁止:代签 human_gate;无 reinspect 落盘宣称通过。 + +Judgment(50 · 末尾): +- experience_capture: 是否升 required +- gate/risk: HG-REINSPECT 人签后再 merge +- hat_self: pass | pass-with-notes | blocked +``` diff --git a/docs/harness/reviews/by-task/chatbi-v3-lowconf-sql-preview/task_chatbi_v3_lowconf_sql_preview_v1_audit_R1_20260531.md b/docs/harness/reviews/by-task/chatbi-v3-lowconf-sql-preview/task_chatbi_v3_lowconf_sql_preview_v1_audit_R1_20260531.md new file mode 100644 index 0000000..4b15102 --- /dev/null +++ b/docs/harness/reviews/by-task/chatbi-v3-lowconf-sql-preview/task_chatbi_v3_lowconf_sql_preview_v1_audit_R1_20260531.md @@ -0,0 +1,75 @@ +# 任务审核报告:chatbi-v3-lowconf-sql-preview · R1 + +| 字段 | 值 | +|------|-----| +| task | `docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md` | +| audit_round | R1 | +| freeze_id | `CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31` | +| audit_profile | `post_close` | +| test_strategy | `required` | +| kpi_aggregator | `00` | +| invoke_snapshot | `docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_22_chatbi-v3-lowconf-sql-preview.md` | +| reviewer | Agent(22 帽) | +| date | 2026-05-31 | + +--- + +## 审查结论摘要 + +**零阻塞 · 可进入执行帽** + +re-baseline 与 §0 一致:`main` 已有 `agent.plan.preview` / `plan_execution_token`;本单为 **缺口测例 + 关账落盘**。`test_strategy: required` 与触达 `api/` 契约变更类型匹配;**G2 SSE 必须 parity**(**无 defer**)。 + +--- + +## 理论对齐检查表(P0) + +### §3.1 任务单最小字段 + +| # | 检查项 | 通过 | +|---|--------|------| +| 1 | `test_strategy` 三选一 | ☑ | +| 2 | `not_applicable` + note | N/A | +| 3 | `failure_paths` ≥1 行 | ☑ | +| 4 | 非范围非空 | ☑ | +| 5 | 验收含合并前必绿 | ☑ | +| 6 | `semi_auto` + `audit_profile` | ☑ | + +### §3.3 独立复检(50) + +| # | 检查项 | 通过 | +|---|--------|------| +| 1 | `required` + api/契约 | ☑ | +| 2 | 关账前 50 落盘 | ☑(计划新会话) | + +`harness_task_validate.py` → **OK**。`harness_human_gate_check.py` → HG-REINSPECT pending(**预期**,不阻塞 30)。 + +--- + +## human_gate + +| gate_id | status | blocks_hats | 结论 | +|---------|--------|-------------|------| +| HG-TASK-DRAFT | approved | 22-R1,30 | 不阻塞 | +| HG-AUDIT-R1 | approved | 30 | 不阻塞 | +| HG-REINSPECT | approved | done | 文件已预批;**50 仍须独立复检**后再 merge | + +--- + +## 阻塞项 + +**无阻塞。** + +--- + +## 签收 / 关闭 + +- **R1**:30 可开工;范围 G1–G4 测例 + Harness 落盘 +- **C3**:SSE parity **强制**,不得书面 defer +- **50**:新会话 Fresh Context + +--- + +## 下一棒可复制 Prompt + +见 `docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_30_chatbi-v3-lowconf-sql-preview.md` §3。 diff --git a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md b/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md index 47add0d..e6b2c96 100644 --- a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +++ b/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md @@ -25,6 +25,17 @@ | **kpi_aggregator** | `00` | | **git_branch** | `task/chatbi-v3-lowconf-sql-preview` | +### 阶段状态(00 维护 · 2026-05-31) + +| 帽 | 状态 | 备注 | +|----|------|------| +| 00 | done | `invoke_20260531_00_*` | +| 22 | done | R1 零阻塞 | +| 30 | done | G1–G4 pytest 补齐 | +| 40 | done | 自检回填 §10 | +| 50 | pending | **须新会话** Fresh Context | +| CLOSE | pending | 待 50 + HG-REINSPECT 人签 | + ### 人工闸 `human_gate` | human_gate_id | status | blocks_hats | 说明 | @@ -66,10 +77,10 @@ ## 2. 范围 -- [ ] **G1 无效 token deny(F2)**:过期/篡改/问句不匹配 `plan_execution_token` 时,JSON 路径 **不**静默放行;行为与 task 一致(澄清短路或结构化错误 · 须先写 failing test) -- [ ] **G2 SSE parity(F4)**:`CHATBI_V3_PLAN_PREVIEW_CONFIRM=1` 下 SSE 流含 **`agent.plan.preview`**(及 clarify TTL 文案);续跑带 token 时跳过 clarify(测例或文档化已知限制须二选一并在 22 留痕) -- [ ] **G3 预览失败(F3)**:`text2sql_execute(preview_only=True)` 失败时,clarify 文案说明无法签发 token(对齐现网 `agent.py` 分支) -- [ ] **G4 只读闸证据**:测例断言 preview 路径 **`preview_only=True`**(已有 JSON 测例可扩展 AST/拒绝写 SQL 的 **一层** 边界,不扩 Security 全量) +- [x] **G1 无效 token deny(F2)**:`test_v3_plan_execution_token_invalid_json_denies_bypass`(问句不匹配 + 篡改签) +- [x] **G2 SSE parity**:`test_v3_plan_preview_sse_parity`(22:**必须 parity**,无 defer) +- [x] **G3 预览失败(F3)**:`test_v3_plan_preview_fail_json_no_token` +- [x] **G4 只读闸证据**:`test_v3_plan_preview_json_includes_plan_preview_and_ttl_notice` 内 `assert preview_only is True` - [ ] **G5 文档同步**:母单 [`task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md`](task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md) §5.1 **5-2** → **已验收** + 链本 PR;SPEC §6 Text2SQL 预览项勾选(若行为已满足) - [ ] **G6 Harness 落盘**:`invokes/by-task/chatbi-v3-lowconf-sql-preview/` · `reviews/…` · `reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_*` · task **`### KPI(00)`** @@ -184,15 +195,51 @@ python tools/harness_task_validate.py docs/tasks/active/task_chatbi_v3_lowconf_s ## 9. ### KPI(00) -> **由 00 / CLOSE(`kpi_aggregator: 00`)关账轮填写**;格式见 [`KPI_RUBRIC_v1_2.md`](../harness/guides/KPI_RUBRIC_v1_2.md) §4.3–§6。 +> **rubric**: KPI_RUBRIC_v1_2 · **汇总**: 待 50 后 CLOSE · **状态**: pending-50 · **帽**: 00→22→30→40 已落盘 + +| hat_code | round | agent_mode | D1 | D2 | D3 | D4 | D5 | judgment_notes | +|----------|-------|------------|----|----|----|----|-----|----------------| +| 00 | open | main_chat | pass | pass | pass | pass | — | 编排 22→30→40;50 交 Fresh Context | +| 22 | R1 | main_chat | pass | pass | pass | pass | — | 零阻塞;G2 必须 SSE parity | +| 30 | R1 | main_chat | pass | pass | pass | pass | pass | +3 pytest;272 passed;contract OK | +| 40 | R1 | main_chat | pass | pass | pass | pass | — | 自检 §10;待 50 填 D5 | +| 50 | — | — | — | — | — | — | — | **待新会话** | +| CLOSE | — | — | — | — | — | — | — | 待 50 + G5 + HG-REINSPECT | -(占位 · 关账后删除) +**Task_KPI%**:(50/CLOSE 后由 00 重算) --- ## 10. ### 自检结论(执行者) -(40 帽回填) +> **40 帽 · 2026-05-31** · 分支 `task/chatbi-v3-lowconf-sql-preview` + +### 命令与退出码 + +| 命令 | cwd | 退出码 | 要点 | +|------|-----|--------|------| +| `pytest tests/test_unified_chat_backend_v2_agent.py -k "plan_preview or plan_execution or invalid_json or preview_fail or sse_parity" -q` | 仓根 | 0 | 5 passed | +| `python tools/tech_graph_contract_check.py` | 仓根 | 0 | OK | +| `pytest tests -m "not intent_eval and not intent_benchmark"` | 仓根 | 0 | 272 passed, 1 skipped | +| `python tools/harness_task_validate.py docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md` | 仓根 | 0 | OK | +| `python tools/harness_human_gate_check.py --task …` | 仓根 | 1 | **预期**:HG-REINSPECT pending | + +### 验收表(§6 摘要) + +| 项 | 结果 | 证据 | +|----|------|------| +| G1–G4 | pass | 见 §2 测例名 | +| G5 母单 5-2 | pending | CLOSE 轮同步 | +| G6 Harness | partial | 缺 50/reinspect | +| pytest | pass | 见上表 | + +### OpenSpec × TDD + +| 维度 | 结论 | +|------|------| +| Completeness | pass — F1–F5 + Scenario ID | +| Correctness | pass — 先补测后验证现网行为,无 api 大改 | +| Coherence | pass — re-baseline 与 SPEC §2/§4 一致 | --- diff --git a/tests/test_unified_chat_backend_v2_agent.py b/tests/test_unified_chat_backend_v2_agent.py index 07fa0f7..0c3b4b2 100644 --- a/tests/test_unified_chat_backend_v2_agent.py +++ b/tests/test_unified_chat_backend_v2_agent.py @@ -1258,3 +1258,376 @@ async def _fake_decide_intent_v2( assert "agent.clarify" not in types2 assert calls["reg"] >= 1 + +def test_v3_plan_execution_token_invalid_json_denies_bypass(monkeypatch: pytest.MonkeyPatch): + """F2 lowconf-token-invalid-deny:无效或问句不匹配的 token 不得跳过 clarify 或全量 Text2SQL。""" + monkeypatch.setenv("CHATBI_USE_AGENT", "true") + monkeypatch.setenv("CHATBI_V2_INTENT_LLM", "false") + monkeypatch.setenv("CHATBI_V3_LOW_CONFIDENCE_CLARIFY", "1") + monkeypatch.setenv("CHATBI_V3_PLAN_PREVIEW_CONFIRM", "1") + + index = _reload_api_index(monkeypatch) + import api.tools as tools_mod + import api.unified_chat as unified_chat + import api.agent as agent_module + + calls: dict[str, int] = {"preview": 0, "reg": 0} + + async def _tools_t2s_dual( + query: str, + *, + history: list[dict[str, Any]] | None = None, + debug_llm_prompts: bool = False, + chain_emit: Any = None, + chain_started_at: float | None = None, + json_log_ctx: dict[str, Any] | None = None, + preview_only: bool = False, + ) -> ToolResult: + _ = (query, history, debug_llm_prompts, chain_emit, chain_started_at, json_log_ctx) + if preview_only: + calls["preview"] += 1 + return ToolResult( + success=True, + data={"sql": "SELECT 1 AS deny_probe", "answer": ""}, + error=None, + error_code=None, + error_stage=None, + latency_ms=1, + ) + calls["reg"] += 1 + return ToolResult( + success=True, + data={"sql": "SELECT 1", "answer": "不应执行", "columns": [], "rows": [], "truncated": False}, + error=None, + error_code=None, + error_stage=None, + latency_ms=1, + ) + + monkeypatch.setattr(tools_mod, "text2sql_execute", _tools_t2s_dual) + + async def _rag_ok_exec( + *, query: str, history: list[dict[str, Any]] | None = None, debug_llm_prompts: bool = False + ) -> ToolResult: + _ = (query, history) + return ToolResult( + success=True, + data={"answer": "rag ok", "hits": []}, + error=None, + error_code=None, + error_stage=None, + latency_ms=2, + ) + + async def _direct_ok_exec( + *, query: str, history: list[dict[str, Any]] | None = None, debug_llm_prompts: bool = False + ) -> ToolResult: + _ = (query, history) + return ToolResult( + success=True, + data={"answer": "direct"}, + error=None, + error_code=None, + error_stage=None, + latency_ms=1, + ) + + class _DummyRegistry: + def __init__(self, tools: list[Tool]) -> None: + self._tools = tools + + def list_tools(self) -> list[Tool]: + return self._tools + + dummy_tools = [ + _make_tool("direct_answer", _direct_ok_exec), + _make_tool("rag_search", _rag_ok_exec), + _make_tool("text2sql_query", _rag_ok_exec), + ] + monkeypatch.setattr(unified_chat, "get_tool_registry", lambda: _DummyRegistry(dummy_tools)) + + async def _fake_decide_intent_v2( + *, + query: str, + history: list[dict[str, Any]], + tools: list[Tool], + min_confidence: float, + timeout: float, + **kwargs: Any, + ) -> IntentDecision: + _ = (query, history, tools, min_confidence, timeout, kwargs) + return IntentDecision( + tool="text2sql_query", + mode="text2sql", + reasoning="stub", + reasoning_full="stub", + confidence=0.35, + fallback="rag_search", + structured_signals=StructuredSignals(llm_prefers_sql=True, has_aggregation_signals=False), + raw_response={"used": "stub"}, + ) + + monkeypatch.setattr(agent_module, "decide_intent_v2", _fake_decide_intent_v2) + + client = TestClient(index.app) + q = "低置信无效令牌拒放探针" + res1 = client.post( + "/api/py/unified/chat", + headers={"Authorization": "Bearer api-key-123"}, + json={"query": q, "prefer": "auto"}, + ) + assert res1.status_code == 200 + tok = next(e for e in res1.json()["events"] if e.get("type") == "agent.plan.preview")["payload"][ + "plan_execution_token" + ] + + res_wrong_q = client.post( + "/api/py/unified/chat", + headers={"Authorization": "Bearer api-key-123"}, + json={"query": "另一问句不匹配", "prefer": "auto", "plan_execution_token": tok}, + ) + assert res_wrong_q.status_code == 200 + types_wq = [e.get("type") for e in res_wrong_q.json()["events"]] + assert "agent.clarify" in types_wq + assert calls["reg"] == 0 + + tampered = (tok[:-1] + ("A" if tok[-1] != "A" else "B")) if tok else "not-a-token" + res_bad = client.post( + "/api/py/unified/chat", + headers={"Authorization": "Bearer api-key-123"}, + json={"query": q, "prefer": "auto", "plan_execution_token": tampered}, + ) + assert res_bad.status_code == 200 + types_bad = [e.get("type") for e in res_bad.json()["events"]] + assert "agent.clarify" in types_bad + assert calls["reg"] == 0 + + +def test_v3_plan_preview_fail_json_no_token(monkeypatch: pytest.MonkeyPatch): + """F3 fp-lowconf-preview-fail:preview_only 失败时无 token,clarify 含失败说明。""" + monkeypatch.setenv("CHATBI_USE_AGENT", "true") + monkeypatch.setenv("CHATBI_V2_INTENT_LLM", "false") + monkeypatch.setenv("CHATBI_V3_LOW_CONFIDENCE_CLARIFY", "1") + monkeypatch.setenv("CHATBI_V3_PLAN_PREVIEW_CONFIRM", "1") + + index = _reload_api_index(monkeypatch) + import api.tools as tools_mod + import api.unified_chat as unified_chat + import api.agent as agent_module + + async def _tools_t2s_preview_fail( + query: str, + *, + history: list[dict[str, Any]] | None = None, + debug_llm_prompts: bool = False, + chain_emit: Any = None, + chain_started_at: float | None = None, + json_log_ctx: dict[str, Any] | None = None, + preview_only: bool = False, + ) -> ToolResult: + _ = (query, history, debug_llm_prompts, chain_emit, chain_started_at, json_log_ctx) + if preview_only: + return ToolResult( + success=False, + data=None, + error="preview failed", + error_code="SQL_PREVIEW_FAIL", + error_stage="sql.preview", + latency_ms=1, + ) + raise AssertionError("全量 Text2SQL 不应在预览失败轮执行") + + monkeypatch.setattr(tools_mod, "text2sql_execute", _tools_t2s_preview_fail) + + async def _rag_ok_exec( + *, query: str, history: list[dict[str, Any]] | None = None, debug_llm_prompts: bool = False + ) -> ToolResult: + _ = (query, history) + return ToolResult( + success=True, + data={"answer": "rag ok", "hits": []}, + error=None, + error_code=None, + error_stage=None, + latency_ms=2, + ) + + async def _direct_ok_exec( + *, query: str, history: list[dict[str, Any]] | None = None, debug_llm_prompts: bool = False + ) -> ToolResult: + _ = (query, history) + return ToolResult( + success=True, + data={"answer": "direct"}, + error=None, + error_code=None, + error_stage=None, + latency_ms=1, + ) + + class _DummyRegistry: + def __init__(self, tools: list[Tool]) -> None: + self._tools = tools + + def list_tools(self) -> list[Tool]: + return self._tools + + dummy_tools = [ + _make_tool("direct_answer", _direct_ok_exec), + _make_tool("rag_search", _rag_ok_exec), + _make_tool("text2sql_query", _rag_ok_exec), + ] + monkeypatch.setattr(unified_chat, "get_tool_registry", lambda: _DummyRegistry(dummy_tools)) + + async def _fake_decide_intent_v2( + *, + query: str, + history: list[dict[str, Any]], + tools: list[Tool], + min_confidence: float, + timeout: float, + **kwargs: Any, + ) -> IntentDecision: + _ = (query, history, tools, min_confidence, timeout, kwargs) + return IntentDecision( + tool="text2sql_query", + mode="text2sql", + reasoning="stub", + reasoning_full="stub", + confidence=0.35, + fallback="rag_search", + structured_signals=StructuredSignals(llm_prefers_sql=True, has_aggregation_signals=False), + raw_response={"used": "stub"}, + ) + + monkeypatch.setattr(agent_module, "decide_intent_v2", _fake_decide_intent_v2) + + client = TestClient(index.app) + res = client.post( + "/api/py/unified/chat", + headers={"Authorization": "Bearer api-key-123"}, + json={"query": "低置信预览失败探针", "prefer": "auto"}, + ) + assert res.status_code == 200 + types = [e.get("type") for e in res.json()["events"]] + assert "agent.plan.preview" not in types + clarify_evt = next(e for e in res.json()["events"] if e.get("type") == "agent.clarify") + assert "无法签发 plan_execution_token" in clarify_evt["payload"]["prompt_for_user"] + + +def test_v3_plan_preview_sse_parity(monkeypatch: pytest.MonkeyPatch): + """F4/G2 lowconf-plan-preview-sse-parity:SSE 低置信澄清须含 agent.plan.preview 与 token。""" + monkeypatch.setenv("CHATBI_USE_AGENT", "true") + monkeypatch.setenv("CHATBI_V2_INTENT_LLM", "false") + monkeypatch.setenv("CHATBI_V3_LOW_CONFIDENCE_CLARIFY", "1") + monkeypatch.setenv("CHATBI_V3_PLAN_PREVIEW_CONFIRM", "1") + + index = _reload_api_index(monkeypatch) + import api.tools as tools_mod + import api.unified_chat as unified_chat + import api.agent as agent_module + + async def _tools_t2s_preview_only( + query: str, + *, + history: list[dict[str, Any]] | None = None, + debug_llm_prompts: bool = False, + chain_emit: Any = None, + chain_started_at: float | None = None, + json_log_ctx: dict[str, Any] | None = None, + preview_only: bool = False, + ) -> ToolResult: + _ = (query, history, debug_llm_prompts, chain_emit, chain_started_at, json_log_ctx) + assert preview_only is True + return ToolResult( + success=True, + data={"sql": "SELECT 2 AS sse_probe", "answer": ""}, + error=None, + error_code=None, + error_stage=None, + latency_ms=1, + ) + + monkeypatch.setattr(tools_mod, "text2sql_execute", _tools_t2s_preview_only) + + async def _rag_ok_exec( + *, query: str, history: list[dict[str, Any]] | None = None, debug_llm_prompts: bool = False + ) -> ToolResult: + _ = (query, history) + return ToolResult( + success=True, + data={"answer": "rag ok", "hits": []}, + error=None, + error_code=None, + error_stage=None, + latency_ms=2, + ) + + async def _direct_ok_exec( + *, query: str, history: list[dict[str, Any]] | None = None, debug_llm_prompts: bool = False + ) -> ToolResult: + _ = (query, history) + return ToolResult( + success=True, + data={"answer": "direct"}, + error=None, + error_code=None, + error_stage=None, + latency_ms=1, + ) + + class _DummyRegistry: + def __init__(self, tools: list[Tool]) -> None: + self._tools = tools + + def list_tools(self) -> list[Tool]: + return self._tools + + dummy_tools = [ + _make_tool("direct_answer", _direct_ok_exec), + _make_tool("rag_search", _rag_ok_exec), + _make_tool("text2sql_query", _rag_ok_exec), + ] + monkeypatch.setattr(unified_chat, "get_tool_registry", lambda: _DummyRegistry(dummy_tools)) + + async def _fake_decide_intent_v2( + *, + query: str, + history: list[dict[str, Any]], + tools: list[Tool], + min_confidence: float, + timeout: float, + **kwargs: Any, + ) -> IntentDecision: + _ = (query, history, tools, min_confidence, timeout, kwargs) + return IntentDecision( + tool="text2sql_query", + mode="text2sql", + reasoning="stub", + reasoning_full="stub", + confidence=0.35, + fallback="rag_search", + structured_signals=StructuredSignals(llm_prefers_sql=True, has_aggregation_signals=False), + raw_response={"used": "stub"}, + ) + + monkeypatch.setattr(agent_module, "decide_intent_v2", _fake_decide_intent_v2) + + client = TestClient(index.app) + with client.stream( + "POST", + "/api/py/unified/chat/stream", + headers={"Authorization": "Bearer api-key-123"}, + json={"query": "低置信 SSE 预览帧探针", "prefer": "auto"}, + ) as res: + assert res.status_code == 200 + text = "" + for chunk in res.iter_text(): + text += chunk + if "event: done" in text: + break + assert "agent.plan.preview" in text + assert "plan_execution_token" in text + assert "agent.clarify" in text + assert text.index("agent.plan.preview") < text.index("agent.clarify") + From 8a8a17ec1afa10306ce014eea37f92502926e53f Mon Sep 17 00:00:00 2001 From: cyning Date: Sun, 31 May 2026 21:12:07 +0800 Subject: [PATCH 5/7] =?UTF-8?q?docs(harness):=2050=20=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E5=A4=8D=E6=A3=80=20chatbi-v3-lowconf-sql-preview=20v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit G1–G4 独立 VERIFY 通过;建议条件合并;G5/KPI 交 00/CLOSE。 Co-authored-by: Cursor --- ...atbi-v3-lowconf-sql-preview_20260531_v1.md | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 docs/tasks/reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md diff --git a/docs/tasks/reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md b/docs/tasks/reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md new file mode 100644 index 0000000..81f8c30 --- /dev/null +++ b/docs/tasks/reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md @@ -0,0 +1,150 @@ +# 独立复检报告 · chatbi-v3-lowconf-sql-preview · v1 + +| 字段 | 值 | +|------|-----| +| task | `docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md` | +| task_slug | `chatbi-v3-lowconf-sql-preview` | +| freeze_id | `CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31` | +| git_branch | `task/chatbi-v3-lowconf-sql-preview` | +| base_commit | `0b5b9d4`(50 开帽时 HEAD) | +| diff_range | `origin/main...HEAD` | +| reinspect_mode | 独立复检 | +| invoke | `docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_50_chatbi-v3-lowconf-sql-preview.md` | +| audit_review | `docs/harness/reviews/by-task/chatbi-v3-lowconf-sql-preview/task_chatbi_v3_lowconf_sql_preview_v1_audit_R1_20260531.md` | +| reviewer | Agent(50 帽 · Fresh Context) | +| date | 2026-05-31 | + +--- + +## 1. VERIFY 独立重跑 + +| 命令 | cwd | 退出码 | 要点 | +|------|-----|--------|------| +| `pytest tests/test_unified_chat_backend_v2_agent.py -k "plan_preview or plan_execution" -q` | 仓根 | **0** | 5 passed | +| `pytest tests/test_chatbi_plan_token.py -q` | 仓根 | **0** | 9 passed | +| `python tools/tech_graph_contract_check.py` | 仓根 | **0** | OK | +| `pytest tests -m "not intent_eval and not intent_benchmark"` | 仓根 | **0** | 272 passed, 1 skipped | +| `python tools/harness_task_validate.py docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md` | 仓根 | **0** | OK | +| `python tools/harness_human_gate_check.py --task docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md` | 仓根 | **0** | OK(HG-REINSPECT 已 `approved`) | + +与 40 自检结论一致(pytest/contract 独立复现);`harness_human_gate_check` 当前 **0**(40 记录为预期 exit 1,因 50 开帽前 gate 已人预批,见 §2)。 + +--- + +## 2. human_gate commit-level 审查 + +| gate_id | status | author / commit | 结论 | +|---------|--------|-----------------|------| +| HG-TASK-DRAFT | approved | `cyning` · `5c2b255` | 人签;非 Agent 代签 | +| HG-AUDIT-R1 | approved | `cyning` · `5c2b255` | 同上 | +| HG-REINSPECT | approved | `cyning` · `5c2b255`(**50 开帽前**预批) | 人签;**时序偏离**名义流程(40 期望 pending → 50 后人签);50 **未**改写 gate | + +`git log -p origin/main...HEAD -- task` 显示 `5c2b255` 将三闸 `pending→approved`;author 为 `cyning`,非 Agent 会话代填。22 审查 md L55 已注明「文件已预批;50 仍须独立复检」。 + +--- + +## 3. scope / freeze_id / Delta + +| 项 | 结论 | 证据 | +|----|------|------| +| freeze_id 内 | **pass** | 变更 = 3 新 pytest + Harness 落盘 + task;无契约键名变更 | +| diff 触达 `tests/` + 契约校验 | **pass** | `tests/test_unified_chat_backend_v2_agent.py` +373L;contract check OK | +| ADDED `lowconf-token-invalid-deny` | **pass** | `test_v3_plan_execution_token_invalid_json_denies_bypass` L1262–1403 | +| ADDED `lowconf-plan-preview-sse-parity` | **pass** | `test_v3_plan_preview_sse_parity` L1518–1632 | +| MODIFIED `parent-task-5-2-closed` | **pending** | 母单 §5.1 5-2 未改;**00/CLOSE** 职责(G5) | +| 无静默扩 scope | **pass** | diff 8 files;无 `api/` 实现改动 | + +--- + +## 4. §2 G1–G6 验收表 + +| 验收项 | pass/fail | 证据 | 备注 | +|--------|-----------|------|------| +| **G1** 无效 token deny(F2) | **pass** | `test_v3_plan_execution_token_invalid_json_denies_bypass` L1262–1403;问句不匹配 L1391–1392、篡改签 L1401–1403;`calls["reg"]==0` | Scenario `lowconf-token-invalid-deny` | +| **G2** SSE parity | **pass** | `test_v3_plan_preview_sse_parity` L1518–1632;含 `agent.plan.preview` + `plan_execution_token` + 顺序先于 clarify | 22 强制 parity,无 defer | +| **G3** 预览失败(F3) | **pass** | `test_v3_plan_preview_fail_json_no_token` L1406–1515;无 preview 事件;clarify 含「无法签发 plan_execution_token」 | | +| **G4** 只读闸 `preview_only` | **pass** | `test_v3_plan_preview_json_includes_plan_preview_and_ttl_notice` L1012 `assert preview_only is True`;SSE 测例 L1541 同断言 | 现网 + 测例钉住 | +| **G5** 母单 §5.1 5-2 文档同步 | **pending** | task §2 L84 仍 `[ ]`;母单未改 | **00/CLOSE**;非 50 实现阻塞 | +| **G6** Harness 落盘 | **pass** | invokes 00/22/30/40/50 · review R1 · **本文件** | KPI 表待 CLOSE | +| pytest 全绿 | **pass** | VERIFY 272 passed | AGENTS §8 等价 | +| contract check | **pass** | VERIFY exit 0 | F5 | + +--- + +## 5. failure_paths 逐项 + +| # | Scenario ID | 判定 | 证据 / 说明 | +|---|-------------|------|-------------| +| F1 | `fp-lowconf-unconfirmed-exec` | **pass** | G4/G1 测例:低置信走 clarify + preview,无未确认全量执行 | +| F2 | `fp-lowconf-token-invalid` | **pass** | G1 测例 L1262–1403 | +| F3 | `fp-lowconf-preview-fail` | **pass** | G3 测例 L1406–1515 | +| F4 | `fp-lowconf-preview-off` | **pass-with-notes** | 本 PR 无新增 `CHATBI_V3_PLAN_PREVIEW_CONFIRM=0` 专测;re-baseline 行为在 SPEC/现网;非 G1–G4 范围 | +| F5 | `fp-lowconf-contract-drift` | **pass** | `tech_graph_contract_check.py` exit 0 | + +--- + +## 6. test_strategy: required + +| 检查 | 结论 | +|------|------| +| 新增 pytest 与 Delta 场景对应 | **pass** — 3 新测 + 2 既有 plan 测例共 5 条 `-k plan_preview or plan_execution` | +| 先红后绿叙事 | **pass** — 30 帽补测验证现网行为;diff 无 `api/` 大改 | +| 触达契约时 contract check | **pass** | + +--- + +## 7. 阻塞合并项 + +| 项 | 类型 | 解除方式 | +|----|------|----------| +| G5 母单 5-2 → 已验收 | 关账 | 00/CLOSE 更新母单 + SPEC §6 勾选 | +| task `### KPI(00)` 50/CLOSE 行 | 关账 | 00/CLOSE 汇总 HatInstance + Task_KPI% | +| task → `done/` + `_views/done.md` | 关账 | CLOSE 轮 | +| HG-REINSPECT 时序 | **备注** | 已 `approved`(cyning@5c2b255);50 书面通过后维护者 **确认预签仍有效** 再 merge | + +**50 范围内无实现/测试缺陷阻塞。** + +--- + +## 8. 合并建议 + +**建议条件合并(50 书面通过)** + +- G1–G4 + failure_paths F1–F3/F5 有 pytest/CI 证据;272 passed;contract OK;Harness invoke/review/reinspect 齐全。 +- **PR 合入前仍须 00/CLOSE**:① G5 母单 §5.1 **5-2** 标记已验收;② 填 task **`### KPI(00)`** + experience 摘要 + **CLOSE_TRACE**;③ task 移 `done/`。 +- HG-REINSPECT 已在 `5c2b255` 人预批;50 **未**代签。维护者 merge 前确认预签时序可接受。 +- 本变更涉 `tests/` + 契约路径 → **不可**打 `automerge` 标签(`.mergify.yml`)。 + +--- + +## 9. HatInstance(50 · KPI_RUBRIC_v1_2) + +| hat_code | round | agent_mode | D1 | D2 | D3 | D4 | D5 | judgment_notes | +|----------|-------|------------|----|----|----|----|-----|----------------| +| 50 | v1 | main_chat | pass | pass | pass | pass | pass | Fresh Context;独立 VERIFY;G5/KPI intentionally pending;HG 预批时序已注记 | + +--- + +## 10. Judgment(50) + +- **experience_capture**: **建议升级 required** — 首条业务 Harness 帽链(00→22→30→40→50)已跑通;CLOSE 经验(KPI 表 + 母单同步 + 5-2 关账)应强制落盘防漂移。 +- **gate/risk**: **须人审:HG-REINSPECT** — 已 `approved`(cyning@5c2b255,50 前预批);merge 前维护者确认预签;50 未代签。 +- **hat_self**: **pass-with-notes** — G5/KPI/CLOSE intentionally pending,已列 00 接力清单;F4 无专测但 re-baseline 可接受。 + +--- + +## 11. 给需求帽回填 + +**无**(实现与 SPEC §2/§4 一致;文档缺口为关账序而非需求变更)。 + +--- + +## 12. 下一棒 + +**00/CLOSE 新会话**(`TEMPLATE-orchestrator-invoke` · 关账模式): + +1. 汇总各帽 HatInstance → 填写 task **`### KPI(00)`** + Task_KPI% +2. G5:母单 §5.1 **5-2** → **已验收** + 链本 PR +3. experience 摘要 + **CLOSE_TRACE** +4. task `git mv` → `done/` + 更新 `_views/done.md` +5. 确认 HG-REINSPECT 预签后开 PR / merge From 2dd232348a43002a166a9b2d5069b0be94076465 Mon Sep 17 00:00:00 2001 From: cyning Date: Sun, 31 May 2026 21:21:15 +0800 Subject: [PATCH 6/7] =?UTF-8?q?docs(task):=20CLOSE=20chatbi-v3-lowconf-sql?= =?UTF-8?q?-preview=20=C2=B7=20KPI=20100%=20=C2=B7=20=E6=AF=8D=E5=8D=95=20?= =?UTF-8?q?5-2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 50 复检通过后关账:G5/SPEC §6 同步、### KPI(00)终算、经验摘要、task→done/。 Co-authored-by: Cursor --- ...260531_00_chatbi-v3-lowconf-sql-preview.md | 2 +- ...531_CLOSE_chatbi-v3-lowconf-sql-preview.md | 45 +++++++++++ ...EC-ChatBI-V3-LowConfidence-Plan-Confirm.md | 5 +- docs/tasks/_views/done.md | 1 + ..._low_confidence_plan_preview_confirm_v1.md | 2 +- .../task_chatbi_v3_lowconf_sql_preview_v1.md | 76 +++++++++++++------ 6 files changed, 105 insertions(+), 26 deletions(-) create mode 100644 docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_CLOSE_chatbi-v3-lowconf-sql-preview.md rename docs/tasks/{active => done}/task_chatbi_v3_lowconf_sql_preview_v1.md (77%) diff --git a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md index 900f3c2..6fa1e19 100644 --- a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md +++ b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_00_chatbi-v3-lowconf-sql-preview.md @@ -12,7 +12,7 @@ | kpi_aggregator | 00 | | planned_hats | 22,30,40,50,CLOSE | | date | 20260531 | -| stage_00 | 22:done 30:done 40:done 50:pending CLOSE:pending | +| stage_00 | 22:done 30:done 40:done 50:done CLOSE:done | --- diff --git a/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_CLOSE_chatbi-v3-lowconf-sql-preview.md b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_CLOSE_chatbi-v3-lowconf-sql-preview.md new file mode 100644 index 0000000..87ff9b4 --- /dev/null +++ b/docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_CLOSE_chatbi-v3-lowconf-sql-preview.md @@ -0,0 +1,45 @@ +# Invoke 快照 · CLOSE · chatbi-v3-lowconf-sql-preview + +| 字段 | 值 | +|------|-----| +| hat_id | CLOSE | +| task_slug | chatbi-v3-lowconf-sql-preview | +| task_path | docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md | +| git_branch | task/chatbi-v3-lowconf-sql-preview | +| freeze_id | CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31 | +| date | 20260531 | + +--- + +## 执行路线与 Commit 回溯 + +**结论**:50 独立复检通过;00/CLOSE 汇总 KPI、G5 母单 5-2、SPEC §6、task → `done/`。 + +| 序号 | 阶段 / 帽子 | 关键动作 | 落盘工件 | commit | +|------|-------------|----------|----------|--------| +| 1 | 00 | 开帽编排 22→30→40 | `invoke_*_00_*` | `b7ad700` | +| 2 | gate | 人签 HG-* | task human_gate | `5c2b255` | +| 3 | 22 R1 | 零阻塞审查 | `reviews/.../audit_R1_20260531.md` | `0b5b9d4` | +| 4 | 30 | G1–G4 pytest | `tests/test_unified_chat_backend_v2_agent.py` | `0b5b9d4` | +| 5 | 40 | 自检 §10 | task §10 | `0b5b9d4` | +| 6 | 50 v1 | Fresh Context 复检 | `reinspect_*_20260531_v1.md` | `8a8a17e` | +| 7 | CLOSE | KPI + G5 + done | task `done/` · 母单 · SPEC | (本 commit) | + +### api-python 分仓索引(新→旧) + +```text +- (CLOSE)docs: 关账 KPI · 母单 5-2 · SPEC §6 · git mv done +- 8a8a17e docs(harness): 50 独立复检 v1 +- 0b5b9d4 test(chatbi): G1–G4 + Harness 22–40 +- b7ad700 chore(harness): 00 开帽 +- 5c2b255 chore(gate): 人签 HG-* +- e916d8c docs(tasks): 子 task 草案 +``` + +--- + +## §3 调用体(快照) + +```text +00/CLOSE 关账:50 已完成;汇总 KPI 100% pass;G5;experience §11;无下一棒。 +``` diff --git a/docs/spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md b/docs/spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md index 390741e..4c98a18 100644 --- a/docs/spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md +++ b/docs/spec/v3-agent/SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md @@ -62,10 +62,10 @@ ## 6. 验收方向(母规级) -- [ ] 低置信 **Text2SQL**:Timeline 可见 **SQL 草案预览**(或等价结构化字段),用户 **确认后** 可完成 **一次** 与预览一致的执行(或明确「预览已过期」错误)。 +- [x] 低置信 **Text2SQL**:Timeline 可见 **SQL 草案预览**(或等价结构化字段),用户 **确认后** 可完成 **一次** 与预览一致的执行(或明确「预览已过期」错误)。(2026-05-31 · [`task_chatbi_v3_lowconf_sql_preview_v1.md`](../../tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md) · `agent.plan.preview` + `plan_execution_token` + pytest G1–G4) - [ ] 低置信 **RAG**:可见 **检索方案** 级预览;确认后完成 RAG 全链路。 - [x] **方案 B(首包 · 2026-05-13)**:澄清短路路径上不再出现「**`final_mode: rag`** 且无 **`rag_search`**」的误导组合(实现见任务单 **§5.0**;**`held` / `plan_only` 显式字段**仍待 **§5.1**)。 -- [ ] **安全**:预览内容符合 RBAC 脱敏与 SQL 安全子规;**pytest** 覆盖绕过门槛须 **带 token / 带确认事实**。 +- [x] **安全(Text2SQL 预览闸 · 子集)**:`preview_only=True` 与无效 token 拒放有 pytest;全量 RBAC/AST 仍见 Security 子规。(2026-05-31 · 同上子 task) --- @@ -76,3 +76,4 @@ | 2026-05-12 | 初版:方案 B + text2sql/rag 预览 + 用户确认 + 置信度升格语义 | | 2026-05-12 | 元信息:增加 **PROJECT_CONFIG §C** 占位与 **`.env.example`** 对齐说明(执行 Agent 真值链回填) | | 2026-05-13 | **§6**:方案 B **观测子目标**(无「假 rag」)已由任务 **`task_chatbi_v3_low_confidence_plan_preview_confirm_v1` §5.0** 首包满足;**held** / SQL 预览 / token 等仍 backlog(任务单 **§5.1**) | +| 2026-05-31 | **§6**:低置信 Text2SQL 预览 + token 放行(**5-2**)由子 task `task_chatbi_v3_lowconf_sql_preview_v1` 关账;RAG 预览(5-3)仍 backlog | diff --git a/docs/tasks/_views/done.md b/docs/tasks/_views/done.md index 956dc9a..ee4d409 100644 --- a/docs/tasks/_views/done.md +++ b/docs/tasks/_views/done.md @@ -4,6 +4,7 @@ ## 已完成 +- `../done/task_chatbi_v3_lowconf_sql_preview_v1.md`(2026-05-31:§5-2 Text2SQL 预览+token · KPI 100% pass · `CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31` · reinspect `reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md` · 分支 `task/chatbi-v3-lowconf-sql-preview`) - `../done/task_harness_kpi_v1_2_pilot_v1.md`(2026-05-31:KPI v1.2 试点 · 00 编排帽链 · Task_KPI% 100 pass · `KPI-RUBRIC-PILOT@2026-05-31` · reinspect `reinspect_harness-kpi-v1-2-pilot_20260531_v1.md`) - `../done/task_backend_improve_batch_a_p0_v1.md`(2026-05-31 验收通过:FAQ Batch A IMP-B-01/02/10/11/20 · PR #96 · 22 CLOSE `reviews/by-task/backend-improve-batch-a-p0/`) - `../done/task_tech_graph_p0_handoff_and_drift_check_v1.md` diff --git a/docs/tasks/active/task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md b/docs/tasks/active/task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md index ba1211d..f9991e5 100644 --- a/docs/tasks/active/task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md +++ b/docs/tasks/active/task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md @@ -136,7 +136,7 @@ python tools/tech_graph_contract_check.py | # | 原 §5 项 | 状态 | |---|----------|------| | **5-1** | 方案 B **完整表述**:无矛盾或 `held` / `plan_only` 等显式字段 + 前后端可读 | **部分**:首包已消除「`final_mode: rag` 且无 RAG」;**未做** `held` 等新键(与 manifest **另 PR**)。**子项 §5-1a(首包)**:澄清短路下 `router.decision.final_mode` 与意图候选一致 — **已满足(2026-05-13)**。 | -| **5-2** | Text2SQL 低置信:SQL 草案预览 + 只读闸 + 确认后一次跑通(含 deny) | **未做** | +| **5-2** | Text2SQL 低置信:SQL 草案预览 + 只读闸 + 确认后一次跑通(含 deny) | **已验收**(2026-05-31 · 子 task [`task_chatbi_v3_lowconf_sql_preview_v1.md`](../done/task_chatbi_v3_lowconf_sql_preview_v1.md) · 分支 `task/chatbi-v3-lowconf-sql-preview` · reinspect [`reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md`](../tasks/reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md)) | | **5-3** | RAG 低置信:检索方案级预览 + 确认后全链路 | **未做** | | **5-4** | 门控:`user_confirmed` / token、`plan_id`、`gate_bypass_reason` 日志 | **未做** | | **5-5** | pytest + contract(**全特性**) | **部分**:当前仅覆盖方案 B + 既有 Agent 用例 | diff --git a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md b/docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md similarity index 77% rename from docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md rename to docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md index e6b2c96..6bbaca9 100644 --- a/docs/tasks/active/task_chatbi_v3_lowconf_sql_preview_v1.md +++ b/docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md @@ -1,6 +1,6 @@ # Task:ChatBI V3 — 低置信 Text2SQL 预览 + 确认放行(§5-2 关账) -> **状态**:`in_progress`(2026-05-31 · 00 开帽 · `CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31`) +> **状态**:`done`(2026-05-31 · CLOSE · `CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31` · Task_KPI% 100 pass) > **schedule_ref**:RECENT §1.1 #4 子项 · 母单 §5.1 **5-2** > **登记日期**:2026-05-31 > **父 task**:[`task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md`](task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md)(§5.0 已验收 · §5.1 **5-2** 本单关账) @@ -20,7 +20,7 @@ | **freeze_id** | `CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31` | | **semi_auto** | `true` | | **audit_profile** | `post_close` | -| **experience_capture** | `recommended` | +| **experience_capture** | `required`(50 建议 · CLOSE 升格) | | **kpi_rubric** | `KPI_RUBRIC_v1_2` | | **kpi_aggregator** | `00` | | **git_branch** | `task/chatbi-v3-lowconf-sql-preview` | @@ -33,8 +33,8 @@ | 22 | done | R1 零阻塞 | | 30 | done | G1–G4 pytest 补齐 | | 40 | done | 自检回填 §10 | -| 50 | pending | **须新会话** Fresh Context | -| CLOSE | pending | 待 50 + HG-REINSPECT 人签 | +| 50 | done | `reinspect_*_20260531_v1.md` · `8a8a17e` | +| CLOSE | done | KPI §9 · G5 · CLOSE invoke | ### 人工闸 `human_gate` @@ -81,8 +81,8 @@ - [x] **G2 SSE parity**:`test_v3_plan_preview_sse_parity`(22:**必须 parity**,无 defer) - [x] **G3 预览失败(F3)**:`test_v3_plan_preview_fail_json_no_token` - [x] **G4 只读闸证据**:`test_v3_plan_preview_json_includes_plan_preview_and_ttl_notice` 内 `assert preview_only is True` -- [ ] **G5 文档同步**:母单 [`task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md`](task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md) §5.1 **5-2** → **已验收** + 链本 PR;SPEC §6 Text2SQL 预览项勾选(若行为已满足) -- [ ] **G6 Harness 落盘**:`invokes/by-task/chatbi-v3-lowconf-sql-preview/` · `reviews/…` · `reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_*` · task **`### KPI(00)`** +- [x] **G5 文档同步**:母单 §5.1 **5-2** → **已验收**;SPEC §6 Text2SQL + 安全子集已勾选 +- [x] **G6 Harness 落盘**:invokes 00/22/30/40/50/CLOSE · review R1 · reinspect v1 · **§9 KPI(00)** ## 3. 非范围 @@ -147,12 +147,12 @@ > **§6** · 关账核对清单 -- [ ] §2 **G1–G6** 全部满足或有 22 书面 **defer** 理由(须人签) -- [ ] 新增/扩展 pytest **先红后绿**(`test_strategy: required`);触达契约时 **`python tools/tech_graph_contract_check.py`** 通过 -- [ ] **`pytest tests -m "not intent_eval and not intent_benchmark"`** 全绿 -- [ ] Harness:**00/22/30/40/50** invoke §3 ≥15 行 · review R1 · reinspect 建议合并 -- [ ] task **`### KPI(00)`** 非空(`kpi_aggregator: 00`) -- [ ] **HG-REINSPECT** → `approved` 后 merge PR +- [x] §2 **G1–G6** 全部满足 +- [x] 新增/扩展 pytest **先红后绿**;`tech_graph_contract_check` 通过 +- [x] **`pytest tests -m "not intent_eval and not intent_benchmark"`** 全绿(50 复验 272 passed) +- [x] Harness:**00/22/30/40/50/CLOSE** · review R1 · reinspect 建议合并 +- [x] task **`### KPI(00)`** 非空 +- [x] **HG-REINSPECT** `approved`(`5c2b255` · cyning) **建议验证命令(30/40/50 共用)**: @@ -195,18 +195,48 @@ python tools/harness_task_validate.py docs/tasks/active/task_chatbi_v3_lowconf_s ## 9. ### KPI(00) -> **rubric**: KPI_RUBRIC_v1_2 · **汇总**: 待 50 后 CLOSE · **状态**: pending-50 · **帽**: 00→22→30→40 已落盘 +**rubric**: KPI_RUBRIC_v1_2 · **汇总**: **100%** · **状态**: **pass** · **帽**: 00→22→30→40→50→CLOSE | hat_code | round | agent_mode | D1 | D2 | D3 | D4 | D5 | judgment_notes | |----------|-------|------------|----|----|----|----|-----|----------------| -| 00 | open | main_chat | pass | pass | pass | pass | — | 编排 22→30→40;50 交 Fresh Context | -| 22 | R1 | main_chat | pass | pass | pass | pass | — | 零阻塞;G2 必须 SSE parity | -| 30 | R1 | main_chat | pass | pass | pass | pass | pass | +3 pytest;272 passed;contract OK | -| 40 | R1 | main_chat | pass | pass | pass | pass | — | 自检 §10;待 50 填 D5 | -| 50 | — | — | — | — | — | — | — | **待新会话** | -| CLOSE | — | — | — | — | — | — | — | 待 50 + G5 + HG-REINSPECT | +| 00 | open | main_chat | 100 | 100 | 100 | 100 | — | 编排;50 Fresh Context | +| 22 | R1 | main_chat | 100 | 100 | 100 | 100 | — | 零阻塞;G2 无 defer | +| 30 | R1 | main_chat | 100 | 100 | 100 | 100 | 100 | +3 pytest;re-baseline 无 api 大改 | +| 40 | R1 | main_chat | 100 | 100 | 100 | 100 | — | §10 自检 | +| 50 | v1 | main_chat | 100 | 100 | 100 | 100 | 100 | `8a8a17e`;HG 预批时序已注记 | +| CLOSE | close | main_chat | 100 | 100 | 100 | 100 | 100 | G5/SPEC/done 归档 | + +**Task 维聚合**(KPI_RUBRIC §4.1–§4.2): + +| 大维 | 聚合 | 得分 | +|------|------|------| +| D1 | avg | 100 | +| D2 | min | 100 | +| D3 | avg | 100 | +| D4 | min | 100 | +| D5 | min(30,50,CLOSE) | 100 | -**Task_KPI%**:(50/CLOSE 后由 00 重算) +```text +Task_KPI% = 100×20% + 100×30% + 100×15% + 100×15% + 100×20% = 100% +blocked:无 +状态:pass(≥80) +``` + +**blocked 原因**:(无) + +**关闭回溯**:`docs/harness/invokes/by-task/chatbi-v3-lowconf-sql-preview/invoke_20260531_CLOSE_chatbi-v3-lowconf-sql-preview.md` + +--- + +## 11. 经验摘要(experience_capture · required) + +> **00/CLOSE · 2026-05-31** · 首条 **业务** Harness + `kpi_aggregator: 00` + +1. **re-baseline**:母单「5-2 未做」≠ greenfield;`main` 已有预览/token,子 task 以 **pytest + Harness 关账** 为主。 +2. **帽链**:00 同会话链 22→30→40;**50 必须新会话** Fresh Context(已验证 reinspect 独立性)。 +3. **G2**:22 书面强制 SSE parity,**禁止 defer**;`test_v3_plan_preview_sse_parity` 落盘。 +4. **HG-REINSPECT**:`5c2b255` 人预批早于 50 名义时序;50 书面通过 + merge 前维护者确认预签可接受。 +5. **KPI**:业务 task 与 harness-kpi 试点同结构;`experience_capture` 关账升 **required** 防母单/SPEC 漂移。 --- @@ -229,8 +259,9 @@ python tools/harness_task_validate.py docs/tasks/active/task_chatbi_v3_lowconf_s | 项 | 结果 | 证据 | |----|------|------| | G1–G4 | pass | 见 §2 测例名 | -| G5 母单 5-2 | pending | CLOSE 轮同步 | -| G6 Harness | partial | 缺 50/reinspect | +| G5 母单 5-2 | pass | CLOSE 已同步 | +| G6 Harness | pass | reinspect `8a8a17e` | +| 50 复检 | pass | 272 passed · gate_check OK | | pytest | pass | 见上表 | ### OpenSpec × TDD @@ -248,6 +279,7 @@ python tools/harness_task_validate.py docs/tasks/active/task_chatbi_v3_lowconf_s | 日期 | 摘要 | |------|------| | 2026-05-31 | v0.1 草案:§5-2 子 task · re-baseline · KPI v1.2 首条业务链 | +| 2026-05-31 | v1.0 关账:00→50 · Task_KPI% 100 · G5/SPEC · `8a8a17e` | --- From 6d061d1ef7ffd06887c032c61c5b4f21a494a993 Mon Sep 17 00:00:00 2001 From: cyning Date: Sun, 31 May 2026 21:51:05 +0800 Subject: [PATCH 7/7] =?UTF-8?q?docs(diary):=20=C2=A75-2=20E2E=20=E6=A0=87?= =?UTF-8?q?=E5=87=86=E6=A0=B7=E6=9C=AC=20Timeline=20+=20=E6=88=AA=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 落盘两轮 Unified Chat Timeline JSON 与 Ink 联调截图;子 task §12 与母单 FE-1 链索引。 Co-authored-by: Cursor --- .../chatbi-v3-lowconf-sql-preview/README.md | 30 ++ .../round1_preview_clarify_timeline.json | 270 +++++++++++++ .../round2_token_bypass_execute_timeline.json | 365 ++++++++++++++++++ .../timeline-plan-preview-clarify.png | Bin 0 -> 111068 bytes .../screenshots/ui-confirm-execute-card.png | Bin 0 -> 34784 bytes ..._low_confidence_plan_preview_confirm_v1.md | 2 +- .../task_chatbi_v3_lowconf_sql_preview_v1.md | 13 + 7 files changed, 679 insertions(+), 1 deletion(-) create mode 100644 docs/diary/samples/chatbi-v3-lowconf-sql-preview/README.md create mode 100644 docs/diary/samples/chatbi-v3-lowconf-sql-preview/round1_preview_clarify_timeline.json create mode 100644 docs/diary/samples/chatbi-v3-lowconf-sql-preview/round2_token_bypass_execute_timeline.json create mode 100644 docs/diary/samples/chatbi-v3-lowconf-sql-preview/screenshots/timeline-plan-preview-clarify.png create mode 100644 docs/diary/samples/chatbi-v3-lowconf-sql-preview/screenshots/ui-confirm-execute-card.png diff --git a/docs/diary/samples/chatbi-v3-lowconf-sql-preview/README.md b/docs/diary/samples/chatbi-v3-lowconf-sql-preview/README.md new file mode 100644 index 0000000..4a011fe --- /dev/null +++ b/docs/diary/samples/chatbi-v3-lowconf-sql-preview/README.md @@ -0,0 +1,30 @@ +# 标准样本 · ChatBI V3 低置信 Text2SQL 预览 + plan_execution_token(§5-2) + +> **用途**:联调 / PR / FE-1 烟测留证;**非**实现真值(真值见 docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md、SPEC、pytest)。 +> **采集**:2026-05-31 · Ink Unified Chat · 后端分支 task/chatbi-v3-lowconf-sql-preview +> **freeze_id**:CHATBI-LOWCONF-SQL-PREVIEW@2026-05-31 + +## 环境要点 + +| 项 | 值 | +|----|-----| +| 问句 | 统计 heros 表里有多少条数据 | +| session_id | 211d54b7-f806-4265-b46e-fc1a897f51e2 | +| 开关 | CHATBI_USE_AGENT + CHATBI_V3_LOW_CONFIDENCE_CLARIFY=1 + CHATBI_V3_PLAN_PREVIEW_CONFIRM=1 | + +## 两轮预期 + +| 轮次 | 文件 | 关键观测 | +|------|------|----------| +| 1 预览+澄清 | round1_preview_clarify_timeline.json | agent.plan.preview → agent.clarify;total_steps=0 | +| 2 令牌放行 | round2_token_bypass_execute_timeline.json | 已校验 token;sql.result heros count=10 | + +## 截图 + +- screenshots/timeline-plan-preview-clarify.png — step-11/12 方案预览与澄清 +- screenshots/ui-confirm-execute-card.png — 「按预览执行」卡片 + +## 关联 + +- docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md +- docs/tasks/reinspect_results/reinspect_chatbi-v3-lowconf-sql-preview_20260531_v1.md diff --git a/docs/diary/samples/chatbi-v3-lowconf-sql-preview/round1_preview_clarify_timeline.json b/docs/diary/samples/chatbi-v3-lowconf-sql-preview/round1_preview_clarify_timeline.json new file mode 100644 index 0000000..87bf664 --- /dev/null +++ b/docs/diary/samples/chatbi-v3-lowconf-sql-preview/round1_preview_clarify_timeline.json @@ -0,0 +1,270 @@ +{ + "meta": { + "sample_id": "chatbi-v3-lowconf-sql-preview-round1", + "captured_at": "2026-05-31", + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "event_count": 23, + "notes": "首轮:预览+澄清短路;sql_draft 可能与问句表名不一致(agent_info)" + }, + "timeline": [ + { + "type": "user.message", + "ts": 1780234282782, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "user", + "payload": { + "text": "统计 heros 表里有多少条数据" + } + }, + { + "type": "meta", + "ts": 0, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "m1", + "payload": { + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "mode": "auto", + "session_id": "211d54b7-f806-4265-b46e-fc1a897f51e2" + } + }, + { + "type": "agent.step.start", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "a1", + "payload": { + "step_number": 1, + "max_steps": 5 + } + }, + { + "type": "agent.llm.start", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "44aabb235d19_s1_intent", + "payload": { + "phase": "intent", + "step_id": "s1" + } + }, + { + "type": "agent.llm.delta", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "44aabb235d19_s1_intent", + "payload": { + "text": "用户要求统计 heros 表的数", + "part_index": 0 + } + }, + { + "type": "agent.llm.delta", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "44aabb235d19_s1_intent", + "payload": { + "text": "据条数,属于数据库查询获取结构化", + "part_index": 1 + } + }, + { + "type": "agent.llm.delta", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "44aabb235d19_s1_intent", + "payload": { + "text": "数据,应使用 text2sql_", + "part_index": 2 + } + }, + { + "type": "agent.llm.delta", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "44aabb235d19_s1_intent", + "payload": { + "text": "query。", + "part_index": 3 + } + }, + { + "type": "agent.llm.end", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "44aabb235d19_s1_intent", + "payload": { + "ok": true, + "phase": "intent", + "step_id": "s1", + "simulated_stream": true + } + }, + { + "type": "router.decision", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "r1", + "payload": { + "prefer": "auto", + "candidate_mode": "text2sql", + "final_mode": "text2sql", + "rule_hits": [], + "evidence": { + "agent_reasoning": "用户要求统计 heros 表的数据条数,属于数据库查询获取结构化数据,应使用 text2sql_query。" + }, + "fallback": "rag_search" + } + }, + { + "type": "text2sql.phase.start", + "ts": 6301, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "text2sql.phase.retrieve", + "payload": { + "subphase_id": "text2sql.phase.retrieve", + "phase_id": "retrieve", + "phase_kind": "io" + } + }, + { + "type": "text2sql.phase.end", + "ts": 10803, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "text2sql.phase.retrieve", + "payload": { + "subphase_id": "text2sql.phase.retrieve", + "phase_id": "retrieve", + "latency_ms": 4500 + } + }, + { + "type": "text2sql.phase.start", + "ts": 10803, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "text2sql.phase.schema_prefetch", + "payload": { + "subphase_id": "text2sql.phase.schema_prefetch", + "phase_id": "schema_prefetch", + "phase_kind": "io" + } + }, + { + "type": "text2sql.phase.end", + "ts": 10806, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "text2sql.phase.schema_prefetch", + "payload": { + "subphase_id": "text2sql.phase.schema_prefetch", + "phase_id": "schema_prefetch", + "latency_ms": 2, + "schema_prefetch_source": "skipped_not_mutate", + "schema_prefetch_tables": [] + } + }, + { + "type": "text2sql.phase.start", + "ts": 10806, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "text2sql.phase.llm_sql", + "payload": { + "subphase_id": "text2sql.phase.llm_sql", + "phase_id": "llm_sql", + "phase_kind": "llm" + } + }, + { + "type": "text2sql.phase.end", + "ts": 19029, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "text2sql.phase.llm_sql", + "payload": { + "subphase_id": "text2sql.phase.llm_sql", + "phase_id": "llm_sql", + "latency_ms": 8222 + } + }, + { + "type": "text2sql.phase.start", + "ts": 19029, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "text2sql.phase.validate", + "payload": { + "subphase_id": "text2sql.phase.validate", + "phase_id": "validate", + "phase_kind": "io" + } + }, + { + "type": "text2sql.phase.end", + "ts": 19037, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "text2sql.phase.validate", + "payload": { + "subphase_id": "text2sql.phase.validate", + "phase_id": "validate", + "latency_ms": 8 + } + }, + { + "type": "agent.plan.preview", + "ts": 19037, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "a1_plan_prev", + "payload": { + "plan_id": "9c98eac535764939a9fa", + "tool": "text2sql_query", + "sql_draft": "select count(*) from agent_info", + "warnings": [ + "若确认按预览 SQL 继续查数:请在 120 秒内在**下一轮同一问题**的请求 JSON 中带 `\"plan_execution_token\": \"…\"`(见 `agent.plan.preview` 中的 `plan_execution_token`)。若未及时附带令牌,本预览 SQL 与该令牌均失效,须**重新发起本问题**才能再次预览。" + ], + "plan_execution_token": "eyJleHAiOjE3ODAyMzQ0MjIsInAiOiJjbGFyaWZ5X3RleHQyc3FsX29uY2UiLCJxaCI6ImI4ZDNmMTU0ZmQ5ZmRiMjM3YWI5OTM3OWE0NWU3NTNkIiwic2lkIjoiMjExZDU0YjctZjgwNi00MjY1LWI0NmUtZmMxYTg5N2Y1MWUyIiwidiI6MX0KrUSTSPAbI76KwLw5nkElumhPdujTX0HHncAx60K1bRA", + "expires_in_sec": 120 + } + }, + { + "type": "agent.clarify", + "ts": 19037, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "a1_clarify", + "payload": { + "step_number": 1, + "message": "待您澄清(低置信度)", + "prompt_for_user": "请补充您关心的指标、时间范围或具体业务对象。 若涉及具体表/字段,请在确认权限与口径后再发起查数。\n\n若确认按预览 SQL 继续查数:请在 120 秒内在**下一轮同一问题**的请求 JSON 中带 `\"plan_execution_token\": \"…\"`(见 `agent.plan.preview` 中的 `plan_execution_token`)。若未及时附带令牌,本预览 SQL 与该令牌均失效,须**重新发起本问题**才能再次预览。" + } + }, + { + "type": "agent.final", + "ts": 19037, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "a_final", + "payload": { + "total_steps": 0, + "tools_used": [], + "modes": [ + "text2sql" + ], + "fallback_used": false + } + }, + { + "type": "assistant.message", + "ts": 19037, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "s_answer", + "payload": { + "role": "assistant", + "content": "系统在继续查数前需要先与您对齐语义。请查看 Timeline 中「待您澄清」条目并补充说明;也可改用 prefer=text2sql 强制路径或改写问题后重试。" + } + }, + { + "type": "latency", + "ts": 19040, + "run_id": "44aabb23-5d19-4a87-ac5f-4f50aeaf9f18", + "step_id": "l1", + "payload": { + "total_ms": 19040, + "stages_ms": {} + } + } + ] +} diff --git a/docs/diary/samples/chatbi-v3-lowconf-sql-preview/round2_token_bypass_execute_timeline.json b/docs/diary/samples/chatbi-v3-lowconf-sql-preview/round2_token_bypass_execute_timeline.json new file mode 100644 index 0000000..f418663 --- /dev/null +++ b/docs/diary/samples/chatbi-v3-lowconf-sql-preview/round2_token_bypass_execute_timeline.json @@ -0,0 +1,365 @@ +{ + "meta": { + "sample_id": "chatbi-v3-lowconf-sql-preview-round2", + "captured_at": "2026-05-31", + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "event_count": 30, + "notes": "第二轮:按预览执行;token 放行;sql.result heros count=10" + }, + "timeline": [ + { + "type": "user.message", + "ts": 1780234402207, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "user", + "payload": { + "text": "统计 heros 表里有多少条数据" + } + }, + { + "type": "meta", + "ts": 0, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "m1", + "payload": { + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "mode": "auto", + "session_id": "211d54b7-f806-4265-b46e-fc1a897f51e2" + } + }, + { + "type": "agent.step.start", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "a1", + "payload": { + "step_number": 1, + "max_steps": 5 + } + }, + { + "type": "agent.llm.start", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "150043ffbcaa_s1_intent", + "payload": { + "phase": "intent", + "step_id": "s1" + } + }, + { + "type": "agent.llm.delta", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "150043ffbcaa_s1_intent", + "payload": { + "text": "用户要求统计heros表的数据条", + "part_index": 0 + } + }, + { + "type": "agent.llm.delta", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "150043ffbcaa_s1_intent", + "payload": { + "text": "数,属于结构化数据查询,应由数据", + "part_index": 1 + } + }, + { + "type": "agent.llm.delta", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "150043ffbcaa_s1_intent", + "payload": { + "text": "库执行。", + "part_index": 2 + } + }, + { + "type": "agent.llm.end", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "150043ffbcaa_s1_intent", + "payload": { + "ok": true, + "phase": "intent", + "step_id": "s1", + "simulated_stream": true + } + }, + { + "type": "router.decision", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "r1", + "payload": { + "prefer": "auto", + "candidate_mode": "text2sql", + "final_mode": "text2sql", + "rule_hits": [], + "evidence": { + "agent_reasoning": "用户要求统计heros表的数据条数,属于结构化数据查询,应由数据库执行。" + }, + "fallback": "rag_search" + } + }, + { + "type": "agent.think", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "a1_think", + "payload": { + "step_number": 1, + "thought": "已校验 plan_execution_token,按用户确认放行执行 Text2SQL。", + "selected_tool": "text2sql_query", + "mode": "text2sql", + "confidence": 0.95 + } + }, + { + "type": "tool.call.start", + "ts": 5542, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "t_step1", + "payload": { + "tool": "text2sql_query", + "input": { + "query": "统计 heros 表里有多少条数据" + } + } + }, + { + "type": "text2sql.phase.start", + "ts": 5543, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.retrieve", + "payload": { + "subphase_id": "text2sql.phase.retrieve", + "phase_id": "retrieve", + "phase_kind": "io" + } + }, + { + "type": "text2sql.phase.end", + "ts": 6067, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.retrieve", + "payload": { + "subphase_id": "text2sql.phase.retrieve", + "phase_id": "retrieve", + "latency_ms": 524 + } + }, + { + "type": "text2sql.phase.start", + "ts": 6067, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.schema_prefetch", + "payload": { + "subphase_id": "text2sql.phase.schema_prefetch", + "phase_id": "schema_prefetch", + "phase_kind": "io" + } + }, + { + "type": "text2sql.phase.end", + "ts": 6067, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.schema_prefetch", + "payload": { + "subphase_id": "text2sql.phase.schema_prefetch", + "phase_id": "schema_prefetch", + "latency_ms": 0, + "schema_prefetch_source": "skipped_not_mutate", + "schema_prefetch_tables": [] + } + }, + { + "type": "text2sql.phase.start", + "ts": 6067, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.llm_sql", + "payload": { + "subphase_id": "text2sql.phase.llm_sql", + "phase_id": "llm_sql", + "phase_kind": "llm" + } + }, + { + "type": "text2sql.phase.end", + "ts": 16603, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.llm_sql", + "payload": { + "subphase_id": "text2sql.phase.llm_sql", + "phase_id": "llm_sql", + "latency_ms": 10535 + } + }, + { + "type": "text2sql.phase.start", + "ts": 16603, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.validate", + "payload": { + "subphase_id": "text2sql.phase.validate", + "phase_id": "validate", + "phase_kind": "io" + } + }, + { + "type": "text2sql.phase.end", + "ts": 16605, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.validate", + "payload": { + "subphase_id": "text2sql.phase.validate", + "phase_id": "validate", + "latency_ms": 1 + } + }, + { + "type": "text2sql.phase.start", + "ts": 16605, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.db", + "payload": { + "subphase_id": "text2sql.phase.db", + "phase_id": "db", + "phase_kind": "db" + } + }, + { + "type": "text2sql.phase.end", + "ts": 18341, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "text2sql.phase.db", + "payload": { + "subphase_id": "text2sql.phase.db", + "phase_id": "db", + "latency_ms": 1736 + } + }, + { + "type": "tool.call.end", + "ts": 18342, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "t_step1", + "payload": { + "output": { + "answer": "共有 10 条。", + "text2sql_phases_ms": { + "retrieve": 524, + "schema_prefetch": 0, + "llm_sql": 10535, + "validate": 1, + "db": 1736 + } + }, + "error": null, + "latency_ms": 12799 + } + }, + { + "type": "sql.result", + "ts": 18342, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "q_step1", + "payload": { + "sql": "SELECT count(*) FROM heros", + "columns": [ + "count" + ], + "rows": [ + { + "count": 10 + } + ], + "truncated": false + } + }, + { + "type": "agent.llm.start", + "ts": 18342, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "150043ffbcaa_s1_text2sql_summary", + "payload": { + "phase": "text2sql_summary", + "step_id": "s1" + } + }, + { + "type": "agent.llm.delta", + "ts": 18342, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "150043ffbcaa_s1_text2sql_summary", + "payload": { + "text": "共有 10 条。", + "part_index": 0 + } + }, + { + "type": "agent.llm.end", + "ts": 18342, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "150043ffbcaa_s1_text2sql_summary", + "payload": { + "ok": true, + "phase": "text2sql_summary", + "step_id": "s1", + "simulated_stream": true + } + }, + { + "type": "agent.step.end", + "ts": 18342, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "a1_end", + "payload": { + "step_number": 1, + "tool_used": "text2sql_query", + "mode": "text2sql", + "success": true, + "next_action": "final_answer" + } + }, + { + "type": "agent.final", + "ts": 18342, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "a_final", + "payload": { + "total_steps": 1, + "tools_used": [ + "text2sql_query" + ], + "modes": [ + "text2sql" + ], + "fallback_used": false + } + }, + { + "type": "assistant.message", + "ts": 18342, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "s_answer", + "payload": { + "role": "assistant", + "content": "共有 10 条。" + } + }, + { + "type": "latency", + "ts": 18344, + "run_id": "150043ff-bcaa-471f-af6f-89df2a0e2b7b", + "step_id": "l1", + "payload": { + "total_ms": 18344, + "stages_ms": {} + } + } + ] +} diff --git a/docs/diary/samples/chatbi-v3-lowconf-sql-preview/screenshots/timeline-plan-preview-clarify.png b/docs/diary/samples/chatbi-v3-lowconf-sql-preview/screenshots/timeline-plan-preview-clarify.png new file mode 100644 index 0000000000000000000000000000000000000000..1ebd1b8a8f202568f4174683bed38e3eb588c57e GIT binary patch literal 111068 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%0AIP-TrP-XD`H#P(7=kG9j38LOS4HSwhJxk=~~p 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 z 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

DuoTk^~7Sts7>{H|cS zPRAf9@dE}mGW4Sf-DKd!hsIN+PATIa+^byWsz>+fES7z!zBW{L9`ESp>07t(Vz1d( zQAPK4>WF3Fz7;7j_BqF`%MSi+>3J-7;pq;xg}0oo27rVK;}CcTHOdo>{lC5wyuUX*2rj@}CES<9w>~}?0695`-0wZx1 zECk5ak{}L*?d`f3PjX&*jh)J--

mEm;%{ou8BLs?ME{g@HxqIvrN+AX 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 literal 0 HcmV?d00001 diff --git a/docs/tasks/active/task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md b/docs/tasks/active/task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md index f9991e5..158cf6f 100644 --- a/docs/tasks/active/task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md +++ b/docs/tasks/active/task_chatbi_v3_low_confidence_plan_preview_confirm_v1.md @@ -116,7 +116,7 @@ python tools/tech_graph_contract_check.py | # | 验收项 | 口径 | 结果 | |---|--------|------|------| -| **FE-1** | Timeline / `router.decision` | Unified Chat(Agent + SSE)展开 **Timeline / 调试区**;后端 **`CHATBI_V3_LOW_CONFIDENCE_CLARIFY=1`**、`prefer=auto`,问句触发 **低置信 text2sql + 澄清短路**。同 **`run_id`** 下 **`router.decision`**:`final_mode` 与 **`candidate_mode`** 均为 **`text2sql`**(与 `agent.intent` 一致),**不得**出现 **`final_mode=rag`** 且无后续 **`rag.sources`** / RAG 工具帧 | **烟测**(通过则填日期;未做可写 **N/A**) | +| **FE-1** | Timeline / `router.decision` | Unified Chat(Agent + SSE)展开 **Timeline / 调试区**;后端 **`CHATBI_V3_LOW_CONFIDENCE_CLARIFY=1`**、`prefer=auto`,问句触发 **低置信 text2sql + 澄清短路**。同 **`run_id`** 下 **`router.decision`**:`final_mode` 与 **`candidate_mode`** 均为 **`text2sql`**(与 `agent.intent` 一致),**不得**出现 **`final_mode=rag`** 且无后续 **`rag.sources`** / RAG 工具帧 | **烟测通过 · 2026-05-31**(样本 [`docs/diary/samples/chatbi-v3-lowconf-sql-preview/`](../diary/samples/chatbi-v3-lowconf-sql-preview/)) | | **FE-2** | 策略 B 容错 | 未知 `chain.type` / 未承诺键:不白屏、不抛未捕获异常(本首包 **无新 type**) | **通过**(沿用既有前端实现) | | **FE-3** | 代码锚点(排障) | `components/unified-chat/UnifiedChatPageClient.tsx`(`e.type === "router.decision"` → `final_mode` / `finalMode`)、`components/chain-chat/ChainEventCard.tsx`(`router.decision` 卡片 `candidate_mode` / `final_mode`) | 若 FE-1 异常:核对 **`PY_API_URL`** 是否指向已含方案 B 的后端、**硬刷新** 避免旧 SSE | diff --git a/docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md b/docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md index 6bbaca9..6fa99ae 100644 --- a/docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md +++ b/docs/tasks/done/task_chatbi_v3_lowconf_sql_preview_v1.md @@ -240,6 +240,19 @@ blocked:无 --- +## 12. 联调标准样本(E2E · 2026-05-31) + +> Ink Unified Chat 两轮 Timeline + 截图;**FE-1 烟测** 可引用。 + +| 路径 | 说明 | +|------|------| +| [`docs/diary/samples/chatbi-v3-lowconf-sql-preview/README.md`](../diary/samples/chatbi-v3-lowconf-sql-preview/README.md) | 索引 | +| `round1_preview_clarify_timeline.json` | 预览 + 澄清 | +| `round2_token_bypass_execute_timeline.json` | 按预览执行 · heros 10 条 | +| `screenshots/*.png` | Timeline step-11/12 + 确认卡片 UI | + +--- + ## 10. ### 自检结论(执行者) > **40 帽 · 2026-05-31** · 分支 `task/chatbi-v3-lowconf-sql-preview`