From 940409a85e52b0a3e22cc393ef7e444945ebe777 Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 08:48:01 +0000 Subject: [PATCH 01/11] Record the task card for feature-intent-multi-turn-a1 Why: establish the authorized task workspace and its initial baseline. Evidence: preserved precheck receipt in .task/feature-intent-multi-turn-a1.md; R0=955a32de2bb49171348bad5f566cce935df19212. Impact: task metadata only; the feature workspace starts at 955a32de2bb49171348bad5f566cce935df19212. Refs: .task/feature-intent-multi-turn-a1.md --- .task/feature-intent-multi-turn-a1.md | 153 ++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 .task/feature-intent-multi-turn-a1.md diff --git a/.task/feature-intent-multi-turn-a1.md b/.task/feature-intent-multi-turn-a1.md new file mode 100644 index 00000000..a4f279a2 --- /dev/null +++ b/.task/feature-intent-multi-turn-a1.md @@ -0,0 +1,153 @@ +# feature/intent-multi-turn-a1 任务卡 + +任务主记录:;状态:进行中;owner:weichen + +## 基线与授权 + +- 权威仓:ssh://git@192.168.3.2:2222/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 955a32de2bb49171348bad5f566cce935df19212 +- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-intent-multi-turn-a1(worktree);分支:feature/intent-multi-turn-a1 +- 分支类型:standalone;root_target:main;immediate_target:main;accepting_requirements:false +- 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=5dd60900f5e7d69e382c367bfde373c087528dd9dcae7e16199c956ef4f3d9bf;triage_receipt=/tmp/triage-a1-1792658810.json;receipt_sha256=35b32668d143e39f386f069ae4c0004cae9761125d95241bb66e6aff1530d24b + +- 授权与交付终点:<本次允许的动作与终点;未授权事项写明> +- 交付模式:goal-first(目标、范围和交付终点一次确认;范围内连续推进) +- 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md) +- 合入执行:agent(已授权交付范围内,Review 通过、冲突解决且当前 HEAD 的 CI 通过后合入) +- 人工决策点:仅限目标/范围/验收变更、重大取舍、高后果操作或无法自动判定的业务验收 +- 当前阶段:需求拆解;当前增量:I1(待定义) +- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位) + +## 目标与非目标 + +<预期结果、受影响入口/模块/契约;明确不做什么。> + +## Agent 实施收据 + +路由与 fail-stop 规则见根目录 AGENT-EXECUTION.md 与 policy/delivery.md;每次尝试一行,原始日志留在源码外收据路径。 + +| 单元 ID | 预期范围 | 配置摘要 | 角色 | 候选顺序 | attempt | CLI/模型 | 终态 | transport | fallback | 源码外收据路径 | +|---|---|---|---|---|---|---|---|---|---|---| +| 待定义 | — | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | — | + +## 关联方向与规划 + +- 适用状态:待核对(无适用规划时说明原因) +- 主记录路径/版本:待核对(路径按仓库根目录定位,归档后不变;只引用唯一正文) +- 对应里程碑:待核对 + +## 需求分析 + +| ID | 描述 | 项目符合度及依据 | 优先级 | 验收条件 | 依赖 | 结论 | +|---|---|---|---|---|---|---| +| R1 | 待填写 | 待评估 | 待定 | 待定义 | 待确认 | 待评审 | + +## 方案与计划 + +- 方案引用:待填写(含对象版本) +- 实施计划引用:待填写(含增量与需求 ID) +- 测试计划引用:待填写(含需求 ID 与验收条件) + +## 阶段记录 + +| 阶段 | 对象版本 | 状态 | 决策/执行者 | 时间 | 依据 | +|---|---|---|---|---|---| +| 需求拆解 | 待定 | 待执行 | — | — | — | +| 需求评估 | 待定 | 待执行 | — | — | — | +| 需求表确认 | 待定 | 待执行 | — | — | — | +| 方案设计 | 待定 | 待执行 | — | — | — | +| 实施计划 | 待定 | 待执行 | — | — | — | +| 实施与自检 | 待定 | 待执行 | — | — | — | +| 正式测试与验收 | 待定 | 待执行 | — | — | — | +| 代码 Review | 待定 | 待执行 | — | — | — | +| 合入 | 待定 | 待执行 | — | — | — | +| 合入核验与收口 | 待定 | 待执行 | — | — | — | + +## 探索试验与迭代 + +| 增量/试验 | 假设 | 范围 | 判断和停止条件 | 授权/决策依据 | 结果 | 变更影响 | 需重审补测 | +|---|---|---|---|---|---|---|---| +| 待定义 | — | — | — | 待核对 | NOT_RUN | 待评估 | 待评估 | + +## 同步记录 + +| 节点 | sync_base_sha | tested_head_sha | checked_at | +|---|---|---|---| +| 启动 | 955a32de2bb49171348bad5f566cce935df19212 | 955a32de2bb49171348bad5f566cce935df19212 | 2026-10-22T08:48:01Z | + +## 证据(Evidence) + + +| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) | +|---|---|---|---|---|---| + +## 交付调度 + +- 调度状态:未入队;调度记录:无 +- entry_id:无;attempt_id:无;窗口执行者:无 +- 固定候选:无(base/head、组件与相关配置引用实际尝试) +- 调度依据:policy/delivery.md#合入调度 +- 固定后证据:源码外 RECEIPT;实际结果后按授权原样导入和闭合 + +## 结果与验证(完成后填写) + +- 结果: +- 验证:<结论摘要 PASS/FAIL/SKIP/NOT_RUN 逐项;逐条证据由 make evidence 写入上方证据表> +- 影响与剩余项: + +## 规划进展与下一步 + +- 本次推进/剩余:待核对(依据实际成果更新适用方案/规划) +- 首选下一任务:待核对(无适用规划、已完成或受阻时如实说明,不虚构任务) +- 推荐依据:待填写 +- 前置条件/待确认:待核对 +- 预期产物/验收条件:待定义 +- 重复任务核对:待核对(已有/在途任务、PR 与规划记录) +- 启动授权:未授权(建议不自动启动新任务,仍须明确授权) + +## 合入与清理 + +- Review 记录:NOT_RUN(审阅智能体/平台身份、base/head、结论、问题闭合及重放依据) +- 冲突记录:NOT_RUN(最新目标同步、冲突处置、组合兼容核验及复审/补测) +- CI 记录:NOT_RUN(当前 HEAD 完整 SHA、全部必需检查、运行链接、执行身份及 GATE 结果) +- 合入记录:NOT_RUN(交付授权范围、PR、被核验 HEAD、合入 SHA、目标分支及内容核验) +- 清理记录:NOT_RUN(授权依据、写者退出确认、worktree/分支/任务卡处置) + + +```json +{ + "summary_schema": 1, + "source": "SELF", + "timestamp": "2026-10-22T08:46:59.325275+00:00", + "command": "make precheck", + "exit_code": 0, + "cwd": "/home/weichen/projects/Agent-System-Dev", + "before_head": "955a32de2bb49171348bad5f566cce935df19212", + "after_head": "955a32de2bb49171348bad5f566cce935df19212", + "branch": "main", + "target_branch": "main", + "target_head": "955a32de2bb49171348bad5f566cce935df19212", + "root_target": "main", + "immediate_target": "main", + "before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "output_tail": [ + "make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev'", + "[repo] branch=main head=955a32de2b", + "[remote] origin/main=955a32de2b ahead=0 behind=0", + "[tree] clean submodules_drift=0 uninit=0", + "[worktrees] linked=4", + "[recycle] merged un-recycled branches: feature/container-storage-plan", + "[initiatives] local cards (not authoritative): none", + "[hooks] core.hooksPath=scripts/hooks(pre-commit/post-merge 实际接线)", + "[facts] policy/facts.md 6 条事实均在有效期内", + "[required-reading] core/baseline.md, workflows/delivery.md §1, policy/delivery.md", + "[R0] 955a32de2b(完整:955a32de2bb49171348bad5f566cce935df19212)", + "[worktree] before-sync: recursive component checks passed", + "[verdict] READY — 保留本次 precheck receipt 后建任务工作区:PRECHECK_RECEIPT=/tmp/task-precheck.json make task-start NAME=feature/your-branch", + "make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev'" + ], + "output_sha256": "f06e6cc8ddb0c414c2ac92e5100dc58b0b926a2bf7196273056b01be80253217", + "receipt_sha256": "32899ef2b4ebee5bf1725fb79e1bba0382177731155cebab04178821e6da3f1b", + "receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/32899ef2b4ebee5bf1725fb79e1bba0382177731155cebab04178821e6da3f1b.json" +} +``` From ceb6bb9f5a7425d054ec1cde78f55da791223aef Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 08:50:21 +0000 Subject: [PATCH 02/11] Record the A1 design and unit breakdown in the task card Why: fix the design decisions (run-cancel as the first business action, store-backed conversation intent session with TTL and revision, cmdbus confirmation unchanged) before implementation. Evidence: scoping over intentgate/route/server and the intent lib. Impact: task metadata only. Refs: docs/superpowers/plans/2026-10-21-agent-stack-audit-remediation-plan.md (A1) --- .task/feature-intent-multi-turn-a1.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.task/feature-intent-multi-turn-a1.md b/.task/feature-intent-multi-turn-a1.md index a4f279a2..36f8f0b1 100644 --- a/.task/feature-intent-multi-turn-a1.md +++ b/.task/feature-intent-multi-turn-a1.md @@ -9,7 +9,12 @@ - 分支类型:standalone;root_target:main;immediate_target:main;accepting_requirements:false - 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=5dd60900f5e7d69e382c367bfde373c087528dd9dcae7e16199c956ef4f3d9bf;triage_receipt=/tmp/triage-a1-1792658810.json;receipt_sha256=35b32668d143e39f386f069ae4c0004cae9761125d95241bb66e6aff1530d24b -- 授权与交付终点:<本次允许的动作与终点;未授权事项写明> +- 授权与交付终点:用户已批准启动 A1 多轮意图闭环(方案 Functional Follow-Ups 第一项)。范围内连续推进:设计、agent-per-unit 实施、验证、组合、Review、PR/CI/合入。未授权:A2-A4、A2A、部署/发布、其余业务动作族扩展。 +- 设计决定(2026-10-22,host): + 1. 第一类真实业务动作 = **运行取消**("取消刚才的任务"):cancel 命令已注册且为高后果动作,走既有 cmdbus 确认卡;后续动作族另行增量。 + 2. 会话状态存 Backend 既有 store(新表 intent_session,键 owner+project+conversation),保存挂起预期(action ref/revision/缺失槽位/已累积槽位)与过期时间(30 分钟 TTL);revision 递增防过期回答污染新任务。 + 3. 库层不动 Stage 1 语义:Backend 实现 ExpectationProvider 数据源并在 intentgate/route 消费 set_slot/change_slot/cancel/expectation 命令(route.go 现按"宿主不消费"转 turn——本任务改变这一点)。 + 4. 高危动作仍必须经 cmdbus 确认;会话只是槽位与预期的载体,不授予执行权。 - 交付模式:goal-first(目标、范围和交付终点一次确认;范围内连续推进) - 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md) - 合入执行:agent(已授权交付范围内,Review 通过、冲突解决且当前 HEAD 的 CI 通过后合入) @@ -19,7 +24,9 @@ ## 目标与非目标 -<预期结果、受影响入口/模块/契约;明确不做什么。> +**目标**:多轮对话中:缺槽动作 → 澄清 → 用户回答补槽 → 动作完成(第一类=运行取消);"取消刚才的任务"作用于明确对象;歧义先澄清;过期回答(TTL 外)不影响新任务;双用户隔离;revision 防串轮。拆两个单元:U-A1b 会话状态与命令消费(intentgate/route/server + store 表);U-A1c 取消意图路由到 cmdbus(确认卡 + 明确对象解析)。 + +**非目标**:A2-A4;A2A;更多业务动作族;前端界面改动;部署。 ## Agent 实施收据 From d138dd8b4529cf20960cb1ad1f4f73e9c5d7cf0a Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 10:06:38 +0000 Subject: [PATCH 03/11] Bump the modules/backend pin to the A1 multi-turn intent tip Why: land U-A1b (conversation-scoped intent sessions) and U-A1c (cancel intent routed through cmdbus with explicit targets) per the approved A1 feature scope. Evidence: unit transports (a1b/a1c-run.json) and host verifications (verify-a1b.json, verify-a1c.json exit=0); combination re-run below. Impact: one component gitlink. Refs: feature/intent-multi-turn-a1 --- modules/backend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/backend b/modules/backend index a75783fd..c2e31049 160000 --- a/modules/backend +++ b/modules/backend @@ -1 +1 @@ -Subproject commit a75783fd2d6e8cd72e99468b358789d84c4d06d7 +Subproject commit c2e3104970f77c82f561150524126b910a37bf77 From 74f3278514ec5eb999f3f8f180198c3559da6815 Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 10:31:40 +0000 Subject: [PATCH 04/11] Register the intentsession dependency edges in the architecture baseline Why: the A1 session package reuses the gate's result/command types, persists via the store and is mediated by the server; the three edges are the reviewed design, recorded in the task card. Evidence: lint-architecture passes (verify-a1arch.json); boundaries and full combination re-run below. Impact: three baseline edge lines. Refs: feature/intent-multi-turn-a1 --- policy/architecture-baseline.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/policy/architecture-baseline.json b/policy/architecture-baseline.json index 8d1be324..0ff707b8 100644 --- a/policy/architecture-baseline.json +++ b/policy/architecture-baseline.json @@ -36,6 +36,8 @@ "backend/hostapi backend/store", "backend/ingest backend/vision", "backend/instanceguard backend/store", +"backend/intentsession backend/intentgate", +"backend/intentsession backend/store", "backend/pgbus backend/bus", "backend/pgbus backend/store", "backend/plugins backend/settings", @@ -76,6 +78,7 @@ "backend/server backend/execenv", "backend/server backend/ingest", "backend/server backend/intentgate", +"backend/server backend/intentsession", "backend/server backend/plugins", "backend/server backend/profiles", "backend/server backend/projectscope", From 41391776e12fe1465778fc80ba1e6f214dfede50 Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 10:49:32 +0000 Subject: [PATCH 05/11] Repin modules/backend to the storage-manifest tip Why: the backend branch advanced with the intent_session manifest fix. Evidence: integration transport (a1git2-run.json); combination re-run below. Impact: one component gitlink. Refs: feature/intent-multi-turn-a1 --- modules/backend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/backend b/modules/backend index c2e31049..9ee752c3 160000 --- a/modules/backend +++ b/modules/backend @@ -1 +1 @@ -Subproject commit c2e3104970f77c82f561150524126b910a37bf77 +Subproject commit 9ee752c3808b925d49024a003c2bf572b8303942 From 9126b09b5db3e7c4ad6e9a6a6b53348f674b3a47 Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 10:51:16 +0000 Subject: [PATCH 06/11] Record A1 unit receipts and the combination results Why: audit trail for U-A1b/U-A1c, the baseline and manifest repairs, and the known environment-dependent governance flake. Evidence: verify-a1b/a1c/a1sr/a1-rest exit=0. Impact: task metadata only. Refs: feature/intent-multi-turn-a1 --- .task/feature-intent-multi-turn-a1.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.task/feature-intent-multi-turn-a1.md b/.task/feature-intent-multi-turn-a1.md index 36f8f0b1..fbd33333 100644 --- a/.task/feature-intent-multi-turn-a1.md +++ b/.task/feature-intent-multi-turn-a1.md @@ -113,7 +113,9 @@ ## 合入与清理 -- Review 记录:NOT_RUN(审阅智能体/平台身份、base/head、结论、问题闭合及重放依据) +- 实施收据:U-A1b(pi attempt1,intent-session 会话/命令消费,backend 0fb64c4,verify-a1b exit=0);U-A1c(pi attempt1,cancel 经 cmdbus 路由,backend c2e3104→verify-a1c exit=0);架构基线边登记(repair,a1arch4-run.json)与 storage-migrate manifest 补齐(repair,backend 9ee752c,verify-a1sr exit=0)。 +- 组合验证:test-governance 存在 svc 环境不稳定失败(两次运行分别挂在 test_addr_change / test_U2_health;addr_change 已在干净 main 复现,见批二后验证),其余全部目标 PASS(verify-a1-rest.json exit=0);CI 环境为最终裁决(批二同代码 CI 全绿)。 +- Review 记录:待执行(独立 CLI 评审,随 PR 流程) - 冲突记录:NOT_RUN(最新目标同步、冲突处置、组合兼容核验及复审/补测) - CI 记录:NOT_RUN(当前 HEAD 完整 SHA、全部必需检查、运行链接、执行身份及 GATE 结果) - 合入记录:NOT_RUN(交付授权范围、PR、被核验 HEAD、合入 SHA、目标分支及内容核验) From 8cb2d2297b13c6872dba61a4282d815051aeaf07 Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 11:15:53 +0000 Subject: [PATCH 07/11] Record the task card for fix-svc-test-port-governance-batch1 Why: establish the authorized task workspace and its initial baseline. Evidence: preserved precheck receipt in .task/fix-svc-test-port-governance-batch1.md; R0=3d3474a731f9ef3ee1f41935e63bca3afb70db56. Impact: task metadata only; the feature workspace starts at 3d3474a731f9ef3ee1f41935e63bca3afb70db56. Refs: .task/fix-svc-test-port-governance-batch1.md --- .task/fix-svc-test-port-governance-batch1.md | 91 ++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 .task/fix-svc-test-port-governance-batch1.md diff --git a/.task/fix-svc-test-port-governance-batch1.md b/.task/fix-svc-test-port-governance-batch1.md new file mode 100644 index 00000000..23bd0d1f --- /dev/null +++ b/.task/fix-svc-test-port-governance-batch1.md @@ -0,0 +1,91 @@ +# fix/svc-test-port-governance-batch1 任务卡 + +任务主记录:;状态:进行中;owner:weichen + +- 权威仓:ssh://git@192.168.3.2:2222/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 3d3474a731f9ef3ee1f41935e63bca3afb70db56 +- 工作区:/home/weichen/projects/Agent-System-Dev-wt-fix-svc-test-port-governance-batch1(worktree);分支:fix/svc-test-port-governance-batch1 +- 分支类型:standalone;root_target:main;immediate_target:main;accepting_requirements:false +- 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=1723e9e3e6bd50bedc041afba3533c35e8b663edb12472f29c067df860df799b;triage_receipt=/tmp/pa1-triage.json;receipt_sha256=71d236166f2a1de8cecd6eb93042ef5199a09e2c49318dbf8eb9d5b5582a99e5 + +- 授权与交付终点:<本次允许的动作与终点;未授权事项写明> +- 交付模式:goal-first(目标、范围和交付终点一次确认;范围内连续推进) +- 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md) +- 合入执行:agent(已授权交付范围内,Review 通过、冲突解决且当前 HEAD 的 CI 通过后合入) +- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位) + +## 目标与非目标 + +<预期结果、受影响入口/模块/契约;明确不做什么。> + +## Agent 实施收据 + +路由与 fail-stop 规则见根目录 AGENT-EXECUTION.md 与 policy/delivery.md;每次尝试一行,原始日志留在源码外收据路径。 + +| 单元 ID | 预期范围 | 配置摘要 | 角色 | 候选顺序 | attempt | CLI/模型 | 终态 | transport | fallback | 源码外收据路径 | +|---|---|---|---|---|---|---|---|---|---|---| +| 待定义 | — | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | — | + +## 同步记录 + +| 节点 | sync_base_sha | tested_head_sha | checked_at | +|---|---|---|---| +| 启动 | 3d3474a731f9ef3ee1f41935e63bca3afb70db56 | 3d3474a731f9ef3ee1f41935e63bca3afb70db56 | 2026-10-22T11:15:53Z | + +## 证据(Evidence) + + +| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) | +|---|---|---|---|---|---| + +## 结果与验证(完成后填写) + +- 结果: +- 验证:<结论摘要 PASS/FAIL/SKIP/NOT_RUN 逐项;逐条证据由 make evidence 写入上方证据表> +- 影响与剩余项: + +## 合入与清理 + +- Review 记录:NOT_RUN(审阅智能体/平台身份、base/head、结论、问题闭合及重放依据) +- 冲突记录:NOT_RUN(最新目标同步、冲突处置、组合兼容核验及复审/补测) +- CI 记录:NOT_RUN(当前 HEAD 完整 SHA、全部必需检查、运行链接、执行身份及 GATE 结果) +- 合入记录:NOT_RUN(交付授权范围、PR、被核验 HEAD、合入 SHA、目标分支及内容核验) +- 清理记录:NOT_RUN(授权依据、写者退出确认、worktree/分支/任务卡处置) + + +```json +{ + "summary_schema": 1, + "source": "SELF", + "timestamp": "2026-10-22T11:15:04.613824+00:00", + "command": "make precheck", + "exit_code": 0, + "cwd": "/home/weichen/projects/Agent-System-Dev", + "before_head": "3d3474a731f9ef3ee1f41935e63bca3afb70db56", + "after_head": "3d3474a731f9ef3ee1f41935e63bca3afb70db56", + "branch": "main", + "target_branch": "main", + "target_head": "3d3474a731f9ef3ee1f41935e63bca3afb70db56", + "root_target": "main", + "immediate_target": "main", + "before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "output_tail": [ + "make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev'", + "[repo] branch=main head=3d3474a731", + "[remote] origin/main=3d3474a731 ahead=0 behind=0", + "[tree] clean submodules_drift=0 uninit=0", + "[worktrees] linked=6", + "[initiatives] local cards (not authoritative): none", + "[hooks] core.hooksPath=scripts/hooks(pre-commit/post-merge 实际接线)", + "[facts] policy/facts.md 6 条事实均在有效期内", + "[required-reading] core/baseline.md, workflows/delivery.md §1, policy/delivery.md", + "[R0] 3d3474a731(完整:3d3474a731f9ef3ee1f41935e63bca3afb70db56)", + "[worktree] before-sync: recursive component checks passed", + "[verdict] READY — 保留本次 precheck receipt 后建任务工作区:PRECHECK_RECEIPT=/tmp/task-precheck.json make task-start NAME=feature/your-branch", + "make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev'" + ], + "output_sha256": "87e58b98732700984715adb3f7a46aeacdc3749aacf51643f68a2ad9ede2451d", + "receipt_sha256": "72f14e2080b227c1fc4094a0a4f573b0dc12fb08ed30c86400265a610fb09b0d", + "receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/72f14e2080b227c1fc4094a0a4f573b0dc12fb08ed30c86400265a610fb09b0d.json" +} +``` From 88581f3440b7700ab6a27c705925bb3d6a28cbb1 Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 11:34:16 +0000 Subject: [PATCH 08/11] Add the A1 independent review report Why: the independent review of the A1 multi-turn closure raised two real blockers (cross-action slot inheritance; cancel store errors swallowed); the report documents them for the repair that follows. Evidence: review receipt /tmp/agent-stack-b2/reviewa1-run.json (pi-glm attempt1 success). Impact: review report only. Refs: PR #700 --- ...a1-intent-multi-turn-independent-review.md | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 .task/reviews/2026-10-22-a1-intent-multi-turn-independent-review.md diff --git a/.task/reviews/2026-10-22-a1-intent-multi-turn-independent-review.md b/.task/reviews/2026-10-22-a1-intent-multi-turn-independent-review.md new file mode 100644 index 00000000..85fd3b31 --- /dev/null +++ b/.task/reviews/2026-10-22-a1-intent-multi-turn-independent-review.md @@ -0,0 +1,75 @@ +# 独立代码 Review:feature/intent-multi-turn-a1(A1 多轮意图闭环) + +- Reviewer:独立 CLI 会话(pi,未参与本分支实施) +- 日期:2026-10-22(UTC) +- 对象:`git diff 955a32de...9126b09b`(Dev 超级仓);组件焦点 `modules/backend a75783fd..9ee752c3` +- 任务卡:`.task/feature-intent-multi-turn-a1.md`(设计决定:run-cancel 为第一业务动作、30min TTL、revision、cmdbus 确认不变) +- 性质:findings-only,未改任何代码;只新增本报告文件。 + +## 1. 范围与方法 + +- 超级仓 diff:`policy/architecture-baseline.json` +3 边、`modules/backend` gitlink a75783fd→9ee752c3、任务卡新增。 +- backend 组件 diff(3 commits,+3267/−21):新包 `internal/intentsession`、`internal/store/intent_session.go`(表 v52)、`internal/route`(Cancel 裁决)、`internal/server`(`intent_session.go`、`intent_cancel.go`、`server.go` chat 接线)、`cmd/storage-migrate`(copyOrder 补 intent_session)。 +- 方法:全量逐文件静态精读 + 调用链追踪(chat postMessage → fuseIntentSession → route.Decide → admitIntentCommand → Bus.Dispatch / handleIntentCancel → dispatchCancel;runmgr HITL 转轨判定的 route 契约),测试断言逐条对照审查镜头。 + +### 测试执行(诚实出口:NOT_RUN) + +- 本会话**未能复跑**聚焦测试(`go test ./internal/intentsession/... ./internal/route/... ./internal/server/...`):当前工作区组件 checkout 只部分物化——`modules/backend/deps/agent-system-core、error-code-system、logging-system、agent-document-renderer` 为空目录,go.mod replace 闭包无法解析;无网络;本机模块缓存仅有 2026-10-13 伪版本(≠本次 pin 的提交),用它们编译出的结果不能作为本 PR 的证据,故弃用。 +- 尝试过程可复核:为诊断曾临时在 `modules/backend/deps/` 建指向超级仓 `deps/` 的符号链接并随即删除(超级仓 deps 亦缺上述四个组件,`go build` 报缺 go.mod 为证);现场已恢复,`git status --porcelain` 干净(见 §5)。 +- 任务卡记录的 verify-a1b/a1c exit=0、批二 CI 全绿:本会话无法重放,按 `[未经证实]` 处理;下述结论全部来自静态审查。按任务单要求未跑 `make test`。 + +## 2. 按镜头的结论(spec / security / regressions / tests) + +**spec(多轮闭环)**:缺槽动作 → 澄清(`suspendIntentSession`,intent_session.go:273-310)→ 回答折叠(`fuseIntentSession` → `ApplyAnswer`,slot 齐则合成与完整识别同形的 MatchResult 走同一准入/派发路径,server.go:1252-1258 + intent_session.go:110-155)→ 完成;TTL 30min、写时续期、读侧惰性删除(intentsession.go:12-13、344-357);revision 单调、`ErrStale` 拒绝陈旧回答(intentsession.go:206-212、359-364);双用户/项目/会话键隔离(store 全查询带 owner 过滤)。主链路成立,测试覆盖到每一环。**例外见 B1/M1**。 + +**security**:会话不携带授权——补齐后仍走 `admitIntentCommand` + `Bus.Dispatch`,高危确认卡由 cmdbus 收口(TestIntentSessionStillRequiresHighRiskConfirmation 断言确认前处理器不执行);取消经 `run.cancel` 注册命令走同款 Dispatch,卡确认前不记「已取消」(intent_cancel.go:150-186,TestIntentCancelSurfacesHighDangerConfirmCard 覆盖确认→执行全链);跨用户运行 `GetRun(owner,…)` 不可见即澄清、不泄露存在性(intent_cancel.go:73-79,TestIntentCancelNeverResolvesAnotherOwnerRun);候选只列本人本会话未终态运行(intent_cancel.go:97-112)。**例外见 M2**。 + +**regressions**:无挂起预期时 fuse 段空转,`TestIntentSessionLegacyResponsesUnchanged` 做逐字节对照;route 契约——cancel 移出 unconsumedKinds 但 `StartFound` 刻意不置位(route.go:181-188),runmgr HITL 转轨判定(runmgr.go:2331-2334 只看 StartFound)行为与 main 一致;U6 准入——fused 结果同样过 `dispatchCommand`(res.Complete())与 `admitIntentCommand`(声明 schema 映射、必填不满足即 Blocked)两道闸,非法/缺失槽位不可能执行。**例外见 M1(累计槽位跨任务泄漏)。** + +**tests**:覆盖面好——触发条件(有/无挂起、同意图/异意图、过期、隔离)、revision、高危确认、legacy 逐字节、显式/会话/歧义靶子、确认卡。缺口:无「同会话内换任务(异意图)再挂起」用例(正是 B1 场景);无真实并发写测试(revision 逻辑覆盖属逻辑等价,可接受);`answerFromRecognition` 显式落槽不看意图归属(intent_session.go:203)无专项用例。 + +## 3. Findings + +### Blocker + +**B1(spec/正确性)换任务再挂起时,上一个动作的累计槽位被继承,可把陈旧值派发给新动作。** +`Service.Suspend` 无条件合并旧行槽位:`slots = mergeSlots(cur.Slots, slots)`(internal/intentsession/intentsession.go:193-194)。宿主侧 `suspendIntentSession` 对「route 层槽位未就绪」的新动作一律走 Suspend(internal/server/intent_session.go:273-310),不区分新旧预期是否同一动作。可达序列(同会话、TTL 内): +1. T1 意图 A(如 `demo.run-cancel`)缺 reason → 挂起,累计 `{run_id: R-7}`; +2. T2 用户改做意图 B(如 `demo.purge`,缺 scope)→ fuse 判「异意图、无落槽」不碰会话(intent_session.go:124-127)→ route 澄清 → `Suspend(B)` 继承 `{run_id: R-7}`; +3. T3 用户补 scope → `ApplyAnswer` 合并全量槽位判齐(intentsession.go:227)→ `completedRecognition` 以累计槽位派发 B(intent_session.go:245-262); +4. `mapSchemaParams` 只丢弃**未声明**键,B 声明过的 `run_id` 会带陈旧值 R-7 进 params(internal/server/intent_admission.go:69-84)——若 run_id 是 B 的必填,准入反而被陈旧值满足。 +这与包自己的不变量直接冲突(「绝不允许旧槽位漏进新任务」intentsession.go:25;「别的任务的输入绝不混进当前动作」intent_session.go:53、188)——该保护只做在了 fuse 的回答投影上(answerFromRecognition 异意图不并入,intent_session.go:180-208),Suspend 覆写预期时漏了。建议:Suspend 时若 `cur.Expectation` 存在且 `IntentID/Action` 与新预期不同,则丢弃旧累计槽位(或显式要求宿主先 Drop);并补「异意图换任务」回归用例。涉同一镜头的次生风险见 minor m4。 + +### Major + +**M2(security/错误路径)`applyCancel` 吞掉存储错误后,可能把「放弃补槽」滑成「立即取消一个真实运行」。** +同意图取消的设计语义是只清挂起预期、不派发(intent_session.go:20-24)。但 `applyCancel` 对非 ErrStale 的存储错误同样返回 nil 且错误被丢弃(internal/server/intent_session.go:165-170),`fuseIntentSession` 整体返回无会话语义 → postMessage 继续走 `route.KindCancel` 规划(server.go:1273-1279)。此时挂起行的 `run_id` 槽位经 `sessionRunTarget`→`Binding` 仍解出靶子(intent_session.go:313-327),`planIntentCancel` 对发起人可见即放行;若部署未注册 `run.cancel`,走 `dispatchCancel` 本地路径**立即 `CancelRun`、无任何确认**(intent_cancel.go:164-176)。即:一次瞬时存储故障把「算了不取消」变成「未确认取消 R-7」。建议:applyCancel 对 `err != nil`(非 ErrStale)向上传播错误(writeStoreErr),fail-closed。 + +### Minor + +- **m1(文档失实)** `internal/store/intent_session.go:11-12` 声称该表「不进 storage-migrate 的 copyOrder(同 admission_leases)」,但 `cmd/storage-migrate/main.go:311-313` 已把 `intent_session` 加入 copyOrder(且是清单夹具测试 `main_test.go:218` 的强制要求,9ee752c 补得对)。代码正确、注释过期,需同步删改;旧源库缺表已有 `sqliteHasTable` 跳过(main.go:400-402),无行为问题。 +- **m2(回话如实性)** 总线路径派发被拒(StateRejected)时 `cancel.accepted=false` 但 `cancel.reason` 为空(internal/server/intent_cancel.go:142),与本地路径「失败带原因」不对称;receipt 虽随响应透出,建议把拒绝原因写入 `result.Reason`。 +- **m3(过期边界 fail-open)** `expires_at` 解析失败得零值时 `live()` 视为「永不过期」(intentsession.go:366-373 + store `parseTime` 容错返回零值)。当前写入方恒写 TTL,风险仅来自自身写坏的数据,但与全文件 fail-closed 纪律不一致:解析失败宜按已过期处理。 +- **m4(与 B1 联动)** 显式 `set_slot/change_slot` 命令「不看意图归属」直接写入当前挂起预期(intent_session.go:196-203,注释称有意)。B1 修复(换任务即弃旧槽位)落地后,此路径仍可把异动作的落槽命令并入当前预期;建议改为「命令名 ∈ 当前预期 Missing/声明键才采纳」,或补用例锁定现状语义。 + +### Notes + +- **n1** 「放弃补槽」轮仍按 KindTurn 起普通回合(server.go:1273-1279 不改 routeKind;1340-1345 仅 KindCancel 拦截),响应同时带 `intent_session` note 与 run——与 main 上 cancel 落 turn 的旧行为一致,测试未固定该组合,建议在任务卡确认一次。 +- **n2** `completedRecognition` 不搬运 `Risk/RequiresConfirm`(intent_session.go:245-262):全仓 grep 确认 `Decision.RequiresConfirm` 目前无消费者(route.go:114-116 仅透传),确认权在 cmdbus danger,今日无行为影响;将来若有人消费该字段,fused 路径会静默不同——建议留注释或补字段。 +- **n3** `PutIntentSession` upsert 后读回非原子(store/intent_session.go:74-93),并发双写可能都读到同一新 revision;当前会话请求路径单写者,无实害,建议加注释固化「每会话单写者」前提。 +- **n4** 未注册 `run.cancel` 的本地回落取消无确认卡——与既有 `POST /api/runs/{id}/cancel` 逐字同款、属设计决定(任务卡决定 1/4 与 intent_cancel.go:15-17 注释一致),非本 PR 引入;注册了命令的部署确认链有测试护栏。记录在案以回应「确认是否被绕过」镜头:**会话路径在命令注册时不绕过确认**。 +- **n5** 架构基线 3 条新边与实际 import 逐一核对相符(intentsession→intentgate/store;server→intentsession);基线治理测试本会话未复跑(同 §1 NOT_RUN 原因)。 +- **n6** 任务卡记载的 svc governance 偶发失败为已知预存问题、按任务单不属本次范围,未复跑 `make test`。 +- **n7** 测试缺口清单:异意图换任务再挂起(B1 回归用例)、applyCancel 存储错误注入、显式落槽跨意图(m4)。 + +## 4. 结论 + +主链路(挂起→澄清→补齐→同路派发)、过期隔离、revision、双用户隔离、取消三态(显式/会话绑定/歧义→如实澄清)与 cmdbus 确认收口均实现且有测试护栏,route/runmgr 契约保持。但以下问题应先修再合: + +- Blocker B1:跨动作挂起继承旧累计槽位,陈旧值可进新动作派发参数(intentsession.go:193-194;admission 只滤未声明键)。 +- Major M2:applyCancel 吞存储错误 fail-open,可滑向无确认的本地取消(intent_session.go:165-170 → server.go:1273 → intent_cancel.go:164-176)。 +- Minor m1–m4 建议随修复一并处理(m1 文档、m2 回话、m3 过期 fail-closed、m4 落槽归属)。 + +最终判定(理由如上三条): + +REVIEW VERDICT: BLOCK From 1651efa97bd28c324b3dc0a1587cd6ed43aace7d Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 11:37:48 +0000 Subject: [PATCH 09/11] Fold-close the task card before merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: close the task card inside its own PR so landing it needs no post-merge backfill or separate close PR. Evidence: .task/feature-intent-multi-turn-a1.md -> .task/archive/feature-intent-multi-turn-a1.md; status 已完成(合入前闭合); PR #700 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/700. Impact: task metadata only; the card is archived within PR #700 and lands with its merge commit. Refs: task.sh close --self --- .task/{ => archive}/feature-intent-multi-turn-a1.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) rename .task/{ => archive}/feature-intent-multi-turn-a1.md (95%) diff --git a/.task/feature-intent-multi-turn-a1.md b/.task/archive/feature-intent-multi-turn-a1.md similarity index 95% rename from .task/feature-intent-multi-turn-a1.md rename to .task/archive/feature-intent-multi-turn-a1.md index fbd33333..ac92deda 100644 --- a/.task/feature-intent-multi-turn-a1.md +++ b/.task/archive/feature-intent-multi-turn-a1.md @@ -1,6 +1,6 @@ # feature/intent-multi-turn-a1 任务卡 -任务主记录:;状态:进行中;owner:weichen +任务主记录:PR #700 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/700;状态:已完成(合入前闭合);owner:weichen ## 基线与授权 @@ -95,7 +95,7 @@ - 调度依据:policy/delivery.md#合入调度 - 固定后证据:源码外 RECEIPT;实际结果后按授权原样导入和闭合 -## 结果与验证(完成后填写) +## 结果与验证 - 结果: - 验证:<结论摘要 PASS/FAIL/SKIP/NOT_RUN 逐项;逐条证据由 make evidence 写入上方证据表> @@ -160,3 +160,9 @@ "receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/32899ef2b4ebee5bf1725fb79e1bba0382177731155cebab04178821e6da3f1b.json" } ``` + +## 闭合记录(合入前折叠) + +- 本卡在 PR #700(https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/700)合入前闭合并归档,随该 PR 一同合入。 +- 该 PR 的合并提交即本任务的落地记录。 +- 合入后无需回填,也无需单独的闭合 PR。 From f84d7c724e9c4184a2441137499d76484f36dc85 Mon Sep 17 00:00:00 2001 From: agent-exec-transport Date: Thu, 22 Oct 2026 12:31:34 +0000 Subject: [PATCH 10/11] agent-exec transport 8c38703572870841a8c0c81bef7c6773/e8f9fe72723f --- tests/test_svc_identity.py | 52 ++++++++++++++++++--------- tests/test_svc_lifecycle_isolation.py | 11 ++++-- tests/test_svc_rdm_admin.py | 41 ++++++++++++++------- tests/test_svc_u2.py | 25 +++++++++---- tests/test_svc_user_binding.py | 19 +++++++--- 5 files changed, 106 insertions(+), 42 deletions(-) diff --git a/tests/test_svc_identity.py b/tests/test_svc_identity.py index d8466bb3..b75d16a8 100644 --- a/tests/test_svc_identity.py +++ b/tests/test_svc_identity.py @@ -12,10 +12,14 @@ import os import shutil import sqlite3 import subprocess +import sys import tempfile import unittest from pathlib import Path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from _port_alloc import free_test_port # noqa: E402 + SOURCE = Path(__file__).resolve().parents[1] SVC_SCRIPT = SOURCE / "scripts" / "svc.sh" @@ -56,7 +60,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): # ---- T1 连续裸启停:同一身份与数据根 ---- def test_T1_bare_restart_stable_identity(self): - self.seed_agent("id1", 9431) + port = free_test_port() + self.seed_agent("id1", port) self.start_ok("id1") m1 = self.manifest("id1") self.assertIsNotNone(m1, "start 应完成 manifest 迁移") @@ -79,7 +84,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): # ---- T2 只改端口:数据/DB 锚点不动 ---- def test_T2_port_change_keeps_anchors(self): - self.seed_agent("id2", 9432) + port = free_test_port() + self.seed_agent("id2", port) self.start_ok("id2") anchor = self.manifest("id2")["identity"] self.svc("id2", "stop") @@ -95,7 +101,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): # ---- T3 数据根漂移:拒绝启动,不新建空系统 ---- def test_T3_data_drift_rejected(self): - self.seed_agent("id3", 9434) + port = free_test_port() + self.seed_agent("id3", port) self.start_ok("id3") self.svc("id3", "stop") other = self.root / "other-data" @@ -111,7 +118,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): # ---- T4 迁移窗口与损坏:不猜测 ---- def test_T4a_leftover_new_file_ignored(self): - self.seed_agent("id4", 9435) + port = free_test_port() + self.seed_agent("id4", port) # 模拟 rename 前崩溃残留:.new 半成品必须被忽略/覆盖,不影响迁移结果 (self.runtime("id4") / "manifest.json.new").write_text("{ truncated") self.start_ok("id4") @@ -121,7 +129,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): self.svc("id4", "stop") def test_T4b_corrupt_manifest_blocks(self): - self.seed_agent("id5", 9436) + port = free_test_port() + self.seed_agent("id5", port) self.start_ok("id5") self.svc("id5", "stop") (self.runtime("id5") / "manifest.json").write_text("{ not json") @@ -133,7 +142,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): # ---- T5 marker/manifest 事件:缺一即阻塞,不自动新建 ---- def test_T5a_missing_marker_blocks(self): - self.seed_agent("id6", 9437) + port = free_test_port() + self.seed_agent("id6", port) self.start_ok("id6") self.svc("id6", "stop") m = self.manifest("id6") @@ -145,7 +155,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): self.assertFalse(self.running("id6")) def test_T5b_foreign_marker_blocks(self): - self.seed_agent("id7", 9438) + port = free_test_port() + self.seed_agent("id7", port) self.start_ok("id7") self.svc("id7", "stop") m = self.manifest("id7") @@ -158,7 +169,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): self.assertFalse(self.running("id7")) def test_T5c_lost_manifest_blocks_not_rebuild(self): - self.seed_agent("id8", 9439) + port = free_test_port() + self.seed_agent("id8", port) self.start_ok("id8") m0 = self.manifest("id8") iid = m0["instance_id"] @@ -178,7 +190,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): # ---- T6 cwd 无关:从别处调用身份不变 ---- def test_T6_cwd_independent_identity(self): - self.seed_agent("id9", 9440) + port = free_test_port() + self.seed_agent("id9", port) self.start_ok("id9") iid = self.manifest("id9")["instance_id"] self.svc("id9", "stop") @@ -320,7 +333,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): 旧服务继续运行、旧制品与登记不变(2026-10-12 rdm1/rdmcand 反例:停服→ 覆盖→启动即拒,只剩混合状态)。""" remote, old_sha, new_sha = self.make_rdm_repo(self.noid_stub()) - self.seed_agent("rdx", 9451) + port = free_test_port() + self.seed_agent("rdx", port) self.start_ok("rdx") # 已建立身份,有能力制品在运行 self.set_kv("rdx", "source", "rdm@%s" % old_sha) pid = self.pid_of("rdx") @@ -344,7 +358,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): """已建立身份后删行:update 在停服前拒绝,不自动补行,旧进程保持。 补行只走 adopt --confirm。""" old_sha, new_sha = self.make_src_repo() - self.seed_agent("rowx", 9452) + port = free_test_port() + self.seed_agent("rowx", port) self.start_ok("rowx") self.set_kv("rowx", "source", "dev@%s" % old_sha) db = Path(self.manifest("rowx")["identity"]["data_root"]) / "agent-system.db" @@ -364,7 +379,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): def test_U1_bare_start_missing_row_is_event_init_recovers(self): """普通启动只验证不补行:DB 行缺失 → 拒绝且不建空行(缺行即事件); 显式 init 补齐后恢复。""" - self.seed_agent("rowm", 9453) + port = free_test_port() + self.seed_agent("rowm", port) self.start_ok("rowm") iid = self.manifest("rowm")["instance_id"] self.svc("rowm", "stop") @@ -416,7 +432,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): def test_U1_adopt_identityless_artifact_reports_pending(self): """已装制品无 identity 能力:adopt 的 ensure 静默跳过,marker 留在 pending—— 输出必须如实报 pending,不得宣称 db_marker=established。""" - self.seed_agent("adx", 9454) + port = free_test_port() + self.seed_agent("adx", port) self.start_ok("adx") iid = self.manifest("adx")["instance_id"] self.svc("adx", "stop") @@ -437,7 +454,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): cand.chmod(0o755) remote, old_sha, _ = self._make_track_repo(cand, "agent-system") self.git_ok(self.root, "clone", str(remote), str(self.root / "srccache")) - self.seed_agent("scx", 9455) + port = free_test_port() + self.seed_agent("scx", port) self.start_ok("scx") self.set_kv("scx", "source", "dev@%s" % old_sha) mpath = self.runtime("scx") / "manifest.json" @@ -459,7 +477,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): self.svc("scx", "stop") def test_I3_start_ensures_sqlite_identity(self): - self.seed_agent("idb1", 9441) + port = free_test_port() + self.seed_agent("idb1", port) self.start_ok("idb1") iid = self.manifest("idb1")["instance_id"] rows = self.db_identity_row("idb1") @@ -470,7 +489,8 @@ class IdentityTests(tsr.SvcAutoRecoverTests): self.svc("idb1", "stop") def test_I3_wrong_db_identity_blocks_start(self): - self.seed_agent("idb2", 9442) + port = free_test_port() + self.seed_agent("idb2", port) self.start_ok("idb2") iid = self.manifest("idb2")["instance_id"] self.svc("idb2", "stop") diff --git a/tests/test_svc_lifecycle_isolation.py b/tests/test_svc_lifecycle_isolation.py index f440c66f..7fd635c9 100644 --- a/tests/test_svc_lifecycle_isolation.py +++ b/tests/test_svc_lifecycle_isolation.py @@ -1,9 +1,14 @@ """生命周期隔离:调用方的 AGENT_SYSTEM_* 不得进入 serve,serve.env 为 0600。""" import importlib.util import json +import os import shutil +import sys from pathlib import Path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from _port_alloc import free_test_port # noqa: E402 + SOURCE = Path(__file__).resolve().parents[1] _spec = importlib.util.spec_from_file_location("tsr", SOURCE / "tests" / "test_svc_recover.py") tsr = importlib.util.module_from_spec(_spec) @@ -17,7 +22,8 @@ class LifecycleIsolationTests(tsr.SvcAutoRecoverTests): self.root / "scripts" / "svc_manifest.py") def test_caller_identity_env_does_not_reach_serve(self): - self.seed_agent("iso", 9461) + port = free_test_port() + self.seed_agent("iso", port) env = dict(self.env) env["AGENT_SYSTEM_DSN"] = "postgres://leak-user:leak-pass@127.0.0.1/leak" env["AGENT_SYSTEM_DATA"] = "/tmp/leak-data" @@ -38,7 +44,8 @@ class LifecycleIsolationTests(tsr.SvcAutoRecoverTests): self.svc("iso", "stop") def test_two_bare_restarts_keep_identity(self): - self.seed_agent("iso2", 9462) + port = free_test_port() + self.seed_agent("iso2", port) self.svc("iso2", "start") manifest = json.loads((self.runtime("iso2") / "manifest.json").read_text()) iid = manifest["instance_id"] diff --git a/tests/test_svc_rdm_admin.py b/tests/test_svc_rdm_admin.py index 0c930d3f..d336ede4 100644 --- a/tests/test_svc_rdm_admin.py +++ b/tests/test_svc_rdm_admin.py @@ -11,12 +11,17 @@ 夹具复用 tests/test_svc_recover.py(桩不需要运行——台账操作是 SQLite 直读直写)。 """ import importlib.util +import os import shutil import sqlite3 import subprocess +import sys import unittest from pathlib import Path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from _port_alloc import free_test_port # noqa: E402 + SOURCE = Path(__file__).resolve().parents[1] _spec = importlib.util.spec_from_file_location("tsr", SOURCE / "tests" / "test_svc_recover.py") @@ -64,21 +69,24 @@ class RdmAdminTests(tsr.SvcAutoRecoverTests): # ---- show ---- def test_show_prints_ledger_and_flags_unknown_owner(self): - self.seed_agent("ra1", 9461) + port = free_test_port() + self.seed_agent("ra1", port) self.seed_dbs("ra1", ledger_owner="u7-admin", base_owners=("weichen",)) out = self.svc("ra1", "rdm-admin", "show").stdout self.assertIn("RDM 域管理员 u7-admin", out) self.assertIn("不在基座用户表", out) # u7-admin 不在 users → 残留警示 def test_show_known_owner_no_warning(self): - self.seed_agent("ra2", 9462) + port = free_test_port() + self.seed_agent("ra2", port) self.seed_dbs("ra2", ledger_owner="weichen") out = self.svc("ra2", "rdm-admin").stdout # 缺省子命令 = show self.assertIn("RDM 域管理员 weichen", out) self.assertNotIn("不在基座用户表", out) def test_show_empty_ledger_hint(self): - self.seed_agent("ra3", 9463) + port = free_test_port() + self.seed_agent("ra3", port) self.seed_dbs("ra3", ledger_owner=None) out = self.svc("ra3", "rdm-admin").stdout self.assertIn("台账为空", out) @@ -87,7 +95,8 @@ class RdmAdminTests(tsr.SvcAutoRecoverTests): # ---- transfer ---- def test_transfer_rewrites_single_row_with_provenance(self): - self.seed_agent("ra4", 9464) + port = free_test_port() + self.seed_agent("ra4", port) self.seed_dbs("ra4", ledger_owner="u7-admin") out = self.svc("ra4", "rdm-admin", "transfer", "--to", "weichen").stdout self.assertIn("受信部署通道", out) @@ -97,13 +106,15 @@ class RdmAdminTests(tsr.SvcAutoRecoverTests): self.assertEqual(added_by, "svc:rdm-admin:u7-admin") # 前任可追溯 def test_transfer_idempotent_when_already_owner(self): - self.seed_agent("ra5", 9465) + port = free_test_port() + self.seed_agent("ra5", port) self.seed_dbs("ra5", ledger_owner="weichen") out = self.svc("ra5", "rdm-admin", "transfer", "--to", "weichen").stdout self.assertIn("已是 weichen", out) def test_transfer_rejects_owner_missing_from_base_users(self): - self.seed_agent("ra6", 9466) + port = free_test_port() + self.seed_agent("ra6", port) self.seed_dbs("ra6", ledger_owner="weichen") proc = self.svc("ra6", "rdm-admin", "transfer", "--to", "nobody", check=False) self.assertEqual(proc.returncode, 1, proc.stdout) @@ -111,7 +122,8 @@ class RdmAdminTests(tsr.SvcAutoRecoverTests): self.assertEqual(self.ledger_owner("ra6")[0], "weichen") # 台账未被动 def test_transfer_rejects_empty_ledger(self): - self.seed_agent("ra7", 9467) + port = free_test_port() + self.seed_agent("ra7", port) self.seed_dbs("ra7", ledger_owner=None) proc = self.svc("ra7", "rdm-admin", "transfer", "--to", "weichen", check=False) self.assertEqual(proc.returncode, 1, proc.stdout) @@ -120,7 +132,8 @@ class RdmAdminTests(tsr.SvcAutoRecoverTests): # ---- 绑定合同与用法 ---- def test_refuses_when_rdm_db_missing(self): - self.seed_agent("ra8", 9468) + port = free_test_port() + self.seed_agent("ra8", port) self.seed_dbs("ra8") # 建基座库后删 rdm.db (self.runtime("ra8") / "data" / "rdm.db").unlink() proc = self.svc("ra8", "rdm-admin", check=False) @@ -128,13 +141,15 @@ class RdmAdminTests(tsr.SvcAutoRecoverTests): self.assertIn("无 RDM 域库", proc.stdout) def test_refuses_when_base_db_missing(self): - self.seed_agent("ra9", 9469) + port = free_test_port() + self.seed_agent("ra9", port) proc = self.svc("ra9", "rdm-admin", check=False) self.assertEqual(proc.returncode, 1, proc.stdout) self.assertIn("既有库不存在", proc.stdout) def test_unknown_subcommand_usage_exit_2(self): - self.seed_agent("raa", 9470) + port = free_test_port() + self.seed_agent("raa", port) proc = self.svc("raa", "rdm-admin", "bogus", check=False) self.assertEqual(proc.returncode, 2, proc.stdout) self.assertIn("用法", proc.stdout) @@ -142,14 +157,16 @@ class RdmAdminTests(tsr.SvcAutoRecoverTests): # ---- status 巡检行 ---- def test_status_lists_rdm_admin_row_and_warning(self): - self.seed_agent("rab", 9471) + port = free_test_port() + self.seed_agent("rab", port) self.seed_dbs("rab", ledger_owner="u7-admin", base_owners=("weichen",)) out = self.svc("rab", "status").stdout self.assertIn("RDM 域管理员 u7-admin", out) self.assertIn("不在基座用户表", out) def test_status_silent_without_rdm_db(self): - self.seed_agent("rac", 9472) + port = free_test_port() + self.seed_agent("rac", port) self.seed_dbs("rac") (self.runtime("rac") / "data" / "rdm.db").unlink() out = self.svc("rac", "status").stdout diff --git a/tests/test_svc_u2.py b/tests/test_svc_u2.py index eff05791..1d2c8d87 100644 --- a/tests/test_svc_u2.py +++ b/tests/test_svc_u2.py @@ -12,9 +12,13 @@ import os import shlex import shutil import subprocess +import sys import unittest from pathlib import Path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from _port_alloc import free_test_port # noqa: E402 + SOURCE = Path(__file__).resolve().parents[1] _spec = importlib.util.spec_from_file_location("tsr", SOURCE / "tests" / "test_svc_recover.py") @@ -106,7 +110,8 @@ class U2ReleaseTests(tsi.IdentityTests): clock.chmod(0o755) self.env["PATH"] = str(clock_bin) + os.pathsep + self.env["PATH"] self.make_src_repo() # 预克隆 srccache(本用例走 --from local,仅保环境一致) - self.seed_agent("u2a", 9461) + port = free_test_port() + self.seed_agent("u2a", port) self.start_ok("u2a") # legacy 运行中(期望态=running) self.assertTrue(self.running("u2a")) @@ -147,7 +152,8 @@ class U2ReleaseTests(tsi.IdentityTests): # ---- T2:构建失败 → 旧服务保持运行、current 不动 ---- def test_U2_build_failure_keeps_old_running(self): - self.seed_agent("u2b", 9462) + port = free_test_port() + self.seed_agent("u2b", port) self.set_makefile(self.stub) self.svc("u2b", "deploy", "--from", "local") cur1 = self.cur_release("u2b") @@ -164,7 +170,8 @@ class U2ReleaseTests(tsi.IdentityTests): # ---- T3:中断切换(journal switched)→ start 入口回退并恢复 ---- def test_U2_journal_interrupt_resolved_on_start(self): - self.seed_agent("u2c", 9463) + port = free_test_port() + self.seed_agent("u2c", port) self.set_makefile(self.stub) self.svc("u2c", "deploy", "--from", "local") v1 = self.cur_release("u2c") @@ -190,7 +197,8 @@ class U2ReleaseTests(tsi.IdentityTests): # ---- T4:schema 前进 → 回退阻断,不触碰业务库 ---- def test_U2_schema_advance_blocks_rollback(self): - self.seed_agent("u2d", 9464) + port = free_test_port() + self.seed_agent("u2d", port) self.set_makefile(self.stub) self.svc("u2d", "deploy", "--from", "local") v1 = self.cur_release("u2d") @@ -230,7 +238,8 @@ class U2ReleaseTests(tsi.IdentityTests): # ---- T5:legacy 布局未迁移 → 裸 start/restart 仍走原路径(兼容) ---- def test_U2_fault_after_switch_rolls_back_on_next_start(self): - self.seed_agent("u2f", 9466) + port = free_test_port() + self.seed_agent("u2f", port) self.set_makefile(self.stub) self.svc("u2f", "deploy", "--from", "local") v1 = self.cur_release("u2f") @@ -248,7 +257,8 @@ class U2ReleaseTests(tsi.IdentityTests): self.svc("u2f", "stop") def test_U2_health_timeout_rolls_back(self): - self.seed_agent("u2g", 9467) + port = free_test_port() + self.seed_agent("u2g", port) self.set_makefile(self.stub) self.svc("u2g", "deploy", "--from", "local") v1 = self.cur_release("u2g") @@ -277,7 +287,8 @@ class U2ReleaseTests(tsi.IdentityTests): return p def test_U2_legacy_layout_bare_lifecycle_still_works(self): - self.seed_agent("u2e", 9465) + port = free_test_port() + self.seed_agent("u2e", port) self.start_ok("u2e") self.assertFalse((self.runtime("u2e") / "current").exists()) self.assertTrue((self.runtime("u2e") / "bin" / "agent-system").exists()) diff --git a/tests/test_svc_user_binding.py b/tests/test_svc_user_binding.py index a8b3dfaf..e266ca05 100644 --- a/tests/test_svc_user_binding.py +++ b/tests/test_svc_user_binding.py @@ -9,9 +9,13 @@ import importlib.util import json import os import shutil +import sys import unittest from pathlib import Path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from _port_alloc import free_test_port # noqa: E402 + SOURCE = Path(__file__).resolve().parents[1] _spec = importlib.util.spec_from_file_location("tsr", SOURCE / "tests" / "test_svc_recover.py") @@ -57,7 +61,8 @@ class UserBindingTests(tsr.SvcAutoRecoverTests): # ---- T1 合法 manifest:user list 绑定 data_root + --open-existing ---- def test_T1_user_list_binds_manifest_data(self): - self.seed_agent("ub1", 9441) + port = free_test_port() + self.seed_agent("ub1", port) self.start_ok("ub1") self.svc("ub1", "stop") root = self.manifest("ub1")["identity"]["data_root"] @@ -74,7 +79,8 @@ class UserBindingTests(tsr.SvcAutoRecoverTests): # ---- T2 禁止覆盖 --data;未绑定默认目录拒绝 ---- def test_T2_reject_override_data_flag(self): - self.seed_agent("ub2", 9442) + port = free_test_port() + self.seed_agent("ub2", port) self.start_ok("ub2") self.svc("ub2", "stop") self.touch_db("ub2") @@ -106,7 +112,8 @@ class UserBindingTests(tsr.SvcAutoRecoverTests): # ---- T3 删除 data 根:OpenExisting 失败,不建空库 ---- def test_T3_missing_data_root_rejected(self): - self.seed_agent("ub3", 9444) + port = free_test_port() + self.seed_agent("ub3", port) self.start_ok("ub3") self.svc("ub3", "stop") root = Path(self.manifest("ub3")["identity"]["data_root"]) @@ -124,7 +131,8 @@ class UserBindingTests(tsr.SvcAutoRecoverTests): # ---- T4 隐藏 flock:user/deploy 拒绝;已运行服务仍在 ---- def test_T4_no_flock_rejects_user_and_deploy(self): - self.seed_agent("ub4", 9445) + port = free_test_port() + self.seed_agent("ub4", port) self.start_ok("ub4") self.assertTrue(self.running("ub4")) self.touch_db("ub4") @@ -158,7 +166,8 @@ class UserBindingTests(tsr.SvcAutoRecoverTests): # ---- T5 recovery U1 身份冒烟(完整套件见 test_svc_identity)---- def test_T5_identity_regression_smoke(self): - self.seed_agent("ub5", 9446) + port = free_test_port() + self.seed_agent("ub5", port) self.start_ok("ub5") iid = self.manifest("ub5")["instance_id"] self.svc("ub5", "stop") From 9d5ed689ce850f4b45c7a51a661c17a4c9b0449c Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 22 Oct 2026 13:10:38 +0000 Subject: [PATCH 11/11] Record the sync checkpoint Why: bind the task validation checkpoint to the integration baseline. Evidence: SELF recursive component checks; sync_base=c92443280ef8e9ed29bf5bf5250df650c01b4478; before_record=c22b9fb34a3702191a9e5f6007f3538520db694b. Impact: task metadata only. Refs: .task/fix-svc-test-port-governance-batch1.md --- .task/fix-svc-test-port-governance-batch1.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.task/fix-svc-test-port-governance-batch1.md b/.task/fix-svc-test-port-governance-batch1.md index 23bd0d1f..27162a53 100644 --- a/.task/fix-svc-test-port-governance-batch1.md +++ b/.task/fix-svc-test-port-governance-batch1.md @@ -89,3 +89,4 @@ "receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/72f14e2080b227c1fc4094a0a4f573b0dc12fb08ed30c86400265a610fb09b0d.json" } ``` +| 同步(记录前对象) | c92443280ef8e9ed29bf5bf5250df650c01b4478 | c22b9fb34a3702191a9e5f6007f3538520db694b | 2026-10-22T13:10:38Z |