Compare commits

...
Author SHA1 Message Date
weichen b9560c7e21 Merge authoritative main into the task branch
ci / svc-realcombo (pull_request) Successful in 3m52s
ci / test (pull_request) Successful in 11m7s
ci / test-pg (pull_request) Successful in 12m54s
Why: include the current integration baseline before merge.

Evidence: fetched origin/main=c3fc389b.

Impact: integrate upstream changes without rewriting task history.

Refs: task-sync
2026-10-22 15:25:57 +00:00
weichen 9a6ae6c571 Repin modules/backend with the intent-test hardening
ci / svc-realcombo (pull_request) Successful in 3m43s
ci / test (pull_request) Successful in 10m49s
ci / test-pg (pull_request) Successful in 14m3s
Why: the intent-session tests were load-sensitive in CI (409 races
against the prior run settling); the hardening rides the A2 pin.
Evidence: repair receipt (a1ff-run.json) and 3x race verification
(verify-a1ff.json exit=0) on the merged tip; full make test green
(verify-a2-combo3.json exit=0).
Impact: one component gitlink.
Refs: PR #704
2026-10-22 15:05:35 +00:00
weichen c3fc389b9f Merge pull request 'Close the merged deploy-txn port card' (#708) from feature/card-close-20261022-144302Z into main
ci / svc-realcombo (push) Successful in 3m56s
ci / test (push) Successful in 10m59s
ci / test-pg (push) Successful in 14m41s
2026-10-22 14:59:52 +00:00
weichen 9eeba5afa2 Close 1 merged task card(s) and archive them
ci / svc-realcombo (pull_request) Successful in 4m51s
ci / test (pull_request) Successful in 12m5s
ci / test-pg (pull_request) Successful in 15m55s
Why: branches merged into their immediate or root target had left their task cards open; backfill status and archive to prevent bookkeeping debt.
Evidence: fix-svc-test-port-governance-deploy-txn.md(PR#705 into main) — merges verified via git log --merges plus Gitea API squash lookup against each card's origin target.
Impact: .task/*.md moved to .task/archive/ with status backfilled; no code or submodule change.
Refs: task.sh close (card-autoclose-r1)
2026-10-22 14:43:02 +00:00
weichen 66e2c98060 Merge pull request 'Close the merged port governance cards' (#707) from feature/card-close-20261022-140925Z into main
ci / svc-realcombo (push) Successful in 3m52s
ci / test (push) Successful in 12m43s
ci / test-pg (push) Failing after 15m27s
2026-10-22 14:42:50 +00:00
weichen b58caf2d99 Fold-close the task card before merge
ci / svc-realcombo (pull_request) Successful in 4m1s
ci / test-pg (pull_request) Failing after 6m48s
ci / test (pull_request) Successful in 12m15s
Why: close the task card inside its own PR so landing it needs no post-merge backfill or separate close PR.
Evidence: .task/feature-exec-recovery-diagnostics-a2.md -> .task/archive/feature-exec-recovery-diagnostics-a2.md; status 已完成(合入前闭合); PR #704 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/704.
Impact: task metadata only; the card is archived within PR #704 and lands with its merge commit.
Refs: task.sh close --self
2026-10-22 14:20:42 +00:00
weichen ade7083c57 Close 1 merged task card(s) and archive them
ci / svc-realcombo (pull_request) Successful in 4m48s
ci / test (pull_request) Successful in 12m43s
ci / test-pg (pull_request) Successful in 16m39s
Why: branches merged into their immediate or root target had left their task cards open; backfill status and archive to prevent bookkeeping debt.
Evidence: fix-svc-test-port-governance-batch1.md(PR#702 into main) — merges verified via git log --merges plus Gitea API squash lookup against each card's origin target.
Impact: .task/*.md moved to .task/archive/ with status backfilled; no code or submodule change.
Refs: task.sh close (card-autoclose-r1)
2026-10-22 14:09:25 +00:00
weichen f673c2a15a Merge pull request 'Use a dynamic port in the last hardcoded test binding' (#705) from fix/svc-test-port-governance-deploy-txn into main
ci / svc-realcombo (push) Successful in 6m16s
ci / test (push) Successful in 13m30s
ci / test-pg (push) Successful in 20m15s
2026-10-22 14:09:13 +00:00
weichen b0d481e91e Record the A2 review approval in the task card
ci / svc-realcombo (pull_request) Successful in 4m31s
ci / test (pull_request) Successful in 10m36s
ci / test-pg (pull_request) Successful in 19m1s
Why: independent review approved the diagnostics endpoint (0 blockers,
0 majors).
Evidence: review receipt /tmp/agent-stack-b2/reviewa2b-run.json.
Impact: task metadata + review report.
Refs: PR #704
2026-10-22 14:01:07 +00:00
agent-exec-transport c4bd492230 agent-exec transport d7614ba632456b193fd4f78809d020e6/61190ee81e4f 2026-10-22 14:00:52 +00:00
agent-exec-transport 2739dcbfcc agent-exec transport 2e46101738c303455c7fb4f286176c0e/4e605887db1b
ci / svc-realcombo (pull_request) Successful in 4m4s
ci / test (pull_request) Successful in 11m18s
ci / test-pg (pull_request) Successful in 14m34s
2026-10-22 13:46:27 +00:00
weichen 03ed068408 Record the task card for fix-svc-test-port-governance-deploy-txn
Why: establish the authorized task workspace and its initial baseline.

Evidence: preserved precheck receipt in .task/fix-svc-test-port-governance-deploy-txn.md; R0=cb36b59accd0418c5ca952912d7c181b83038a4c.

Impact: task metadata only; the feature workspace starts at cb36b59acc.

Refs: .task/fix-svc-test-port-governance-deploy-txn.md
2026-10-22 13:39:46 +00:00
weichen d0b2bde9b0 Record the A2 implementation and combination results
ci / svc-realcombo (pull_request) Successful in 3m50s
ci / test (pull_request) Successful in 9m42s
ci / test-pg (pull_request) Successful in 14m45s
Why: audit trail for the diagnostics endpoint unit, the baseline edge
registration and the green full combination run.
Evidence: verify-a2b.json and verify-a2-combo2.json exit=0.
Impact: task metadata only.
Refs: feature/exec-recovery-diagnostics-a2
2026-10-22 13:32:43 +00:00
weichen cb36b59acc Merge pull request 'Use dynamic ports across the five test files that shared hardcoded bindings' (#702) from fix/svc-test-port-governance-batch1 into main
ci / svc-realcombo (push) Successful in 3m24s
ci / test (push) Successful in 11m9s
ci / test-pg (push) Successful in 18m29s
2026-10-22 13:26:12 +00:00
weichen 826398c969 Register the rundiag dependency edges in the architecture baseline
Why: the A2 diagnostics package reuses the cmdbus operation query and
store reads, mediated by the server; the three edges are the reviewed
design, recorded in the task card.
Evidence: lint-architecture passes (verify-a2arch.json); boundaries
and full combination re-run below.
Impact: three baseline edge lines.
Refs: feature/exec-recovery-diagnostics-a2
2026-10-22 13:24:34 +00:00
weichen 9d5ed689ce Record the sync checkpoint
ci / svc-realcombo (pull_request) Successful in 3m53s
ci / test (pull_request) Successful in 9m55s
ci / test-pg (pull_request) Successful in 14m38s
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
2026-10-22 13:10:38 +00:00
weichen c22b9fb34a Merge authoritative main into the task branch
Why: include the current integration baseline before verification.

Evidence: fetched origin/main=c92443280ef8e9ed29bf5bf5250df650c01b4478.

Impact: integrate upstream changes without rewriting task history.

Refs: task-sync
2026-10-22 13:09:54 +00:00
weichen 7f23ed9ed1 Bump the modules/backend pin to the A2 diagnostics tip
Why: land the read-only run diagnostics endpoint (A2) per the approved
feature scope.
Evidence: integration transport (a2git2-run.json); unit tests green
(verify-a2b.json exit=0); combination re-run below.
Impact: one component gitlink.
Refs: feature/exec-recovery-diagnostics-a2
2026-10-22 13:09:53 +00:00
weichen abf4c27736 Record the A2 design in the task card
Why: fix the read-only diagnostics contract (single GET endpoint,
aggregated responsibility/wait-reason/checkpoint/side-effects/next-step,
no write endpoints) before implementation.
Evidence: scoping over server routes, store recovery/HITL methods and
cmdbus audit records.
Impact: task metadata only.
Refs: docs/superpowers/plans/2026-10-21-agent-stack-audit-remediation-plan.md (A2)
2026-10-22 12:41:32 +00:00
weichen a14752bf1e Record the task card for feature-exec-recovery-diagnostics-a2
Why: establish the authorized task workspace and its initial baseline.

Evidence: preserved precheck receipt in .task/feature-exec-recovery-diagnostics-a2.md; R0=c92443280ef8e9ed29bf5bf5250df650c01b4478.

Impact: task metadata only; the feature workspace starts at c92443280e.

Refs: .task/feature-exec-recovery-diagnostics-a2.md
2026-10-22 12:37:28 +00:00
agent-exec-transport f84d7c724e agent-exec transport 8c38703572870841a8c0c81bef7c6773/e8f9fe72723f
ci / svc-realcombo (pull_request) Successful in 2m55s
ci / test (pull_request) Successful in 9m8s
ci / test-pg (pull_request) Successful in 20m53s
2026-10-22 12:31:34 +00:00
weichen c92443280e Merge pull request 'A1 multi-turn intent closure (sessions and cancel routing)' (#700) from feature/intent-multi-turn-a1 into main
ci / svc-realcombo (push) Successful in 3m4s
ci / test (push) Successful in 9m35s
ci / test-pg (push) Successful in 18m50s
2026-10-22 12:25:13 +00:00
weichen ce7b0d9c44 Merge authoritative main into the task branch
ci / svc-realcombo (pull_request) Successful in 3m59s
ci / test (pull_request) Successful in 10m59s
ci / test-pg (pull_request) Successful in 14m51s
Why: include the current integration baseline before merge.

Evidence: fetched origin/main=3d3474a7.

Impact: integrate upstream changes without rewriting task history.

Refs: task-sync
2026-10-22 12:09:38 +00:00
weichen 1651efa97b Fold-close the task card before merge
ci / test (pull_request) Successful in 9m36s
ci / svc-realcombo (pull_request) Successful in 3m56s
ci / test-pg (pull_request) Successful in 15m50s
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
2026-10-22 11:37:48 +00:00
weichen 88581f3440 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
2026-10-22 11:34:16 +00:00
weichen 8cb2d2297b 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 3d3474a731.

Refs: .task/fix-svc-test-port-governance-batch1.md
2026-10-22 11:15:53 +00:00
weichen 3d3474a731 Merge pull request 'Fold the archived port-governance card into main' (#699) from fix/svc-test-port-governance-final into main
ci / svc-realcombo (push) Successful in 3m39s
ci / test (push) Successful in 10m26s
ci / test-pg (push) Successful in 13m41s
ci / svc-realcombo (pull_request) Successful in 3m15s
ci / test (pull_request) Successful in 9m39s
ci / test-pg (pull_request) Successful in 15m14s
2026-10-22 10:55:45 +00:00
weichen 9126b09b5d Record A1 unit receipts and the combination results
ci / svc-realcombo (pull_request) Successful in 3m12s
ci / test (pull_request) Successful in 10m52s
ci / test-pg (pull_request) Successful in 15m3s
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
2026-10-22 10:51:16 +00:00
weichen 41391776e1 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
2026-10-22 10:49:32 +00:00
weichen 74f3278514 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
2026-10-22 10:31:40 +00:00
weichen d138dd8b45 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
2026-10-22 10:06:38 +00:00
weichen c88cb95654 Record the sync checkpoint
ci / svc-realcombo (pull_request) Successful in 2m55s
ci / test (pull_request) Successful in 8m44s
ci / test-pg (pull_request) Successful in 15m56s
Why: bind the task validation checkpoint to the integration baseline.

Evidence: SELF recursive component checks; sync_base=98ee59c477785b2d5094fcbea3e67a4dc864c388; before_record=a29562ef8315c6cbe71bf531720ce5ffa5ca2717.

Impact: task metadata only.

Refs: .task/archive/fix-svc-test-port-governance-final.md
2026-10-22 09:35:11 +00:00
weichen a29562ef83 Merge authoritative main into the task branch
Why: include the current integration baseline before verification.

Evidence: fetched origin/main=98ee59c477785b2d5094fcbea3e67a4dc864c388.

Impact: integrate upstream changes without rewriting task history.

Refs: task-sync
2026-10-22 09:34:18 +00:00
weichen b63685d7b5 Fold-close the task card before merge
Why: close the task card inside its own PR so landing it needs no post-merge backfill or separate close PR.
Evidence: .task/fix-svc-test-port-governance-final.md -> .task/archive/fix-svc-test-port-governance-final.md; status 已完成(合入前闭合); PR #698 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/698.
Impact: task metadata only; the card is archived within PR #698 and lands with its merge commit.
Refs: task.sh close --self
2026-10-22 09:33:42 +00:00
weichen 98ee59c477 Merge pull request 'Use dynamic ports in the last three hardcoded test bindings' (#698) from fix/svc-test-port-governance-final into main
ci / svc-realcombo (push) Successful in 2m30s
ci / test (push) Successful in 8m55s
ci / test-pg (push) Successful in 12m22s
2026-10-22 09:33:12 +00:00
agent-exec-transport 60bd1bedb4 agent-exec transport 848ba0b1bdee6617e7757143cdffa2e9/e0b4b463efec
ci / svc-realcombo (pull_request) Successful in 2m53s
ci / test (pull_request) Successful in 8m57s
ci / test-pg (pull_request) Successful in 12m24s
2026-10-22 09:08:33 +00:00
weichen 10b751f159 Record the task card for fix-svc-test-port-governance-final
Why: establish the authorized task workspace and its initial baseline.

Evidence: preserved precheck receipt in .task/fix-svc-test-port-governance-final.md; R0=955a32de2bb49171348bad5f566cce935df19212.

Impact: task metadata only; the feature workspace starts at 955a32de2b.

Refs: .task/fix-svc-test-port-governance-final.md
2026-10-22 08:55:33 +00:00
weichen ceb6bb9f5a 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)
2026-10-22 08:50:21 +00:00
weichen 940409a85e 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 955a32de2b.

Refs: .task/feature-intent-multi-turn-a1.md
2026-10-22 08:48:01 +00:00
16 changed files with 907 additions and 70 deletions
@@ -0,0 +1,167 @@
# feature/exec-recovery-diagnostics-a2 任务卡
任务主记录:PR #704 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/704;状态:已完成(合入前闭合);owner:weichen
## 基线与授权
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= c92443280ef8e9ed29bf5bf5250df650c01b4478
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-exec-recovery-diagnostics-a2(worktree);分支:feature/exec-recovery-diagnostics-a2
- 分支类型:standalone;root_target:main;immediate_target:main;accepting_requirements:false
- 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=34e72676959d0e970f1a3cb0e90ac2067dfb31f3c2e7a6650b5de9f3f77923c7;triage_receipt=/tmp/triage-a2-1792672248.json;receipt_sha256=7924fdbaeba41d98994c2e11bc96026d4db3cdbd0b28a9d1e381400eae9a6de4
- 授权与交付终点:用户已批准启动 A2 执行与恢复诊断(方案 Functional Follow-Ups 第二项)。范围内连续推进:设计、agent-per-unit 实施、验证、组合、Review、PR/CI/合入。未授权:控制台/前端界面、A3/A4、部署。
- 设计决定(2026-10-22,host):
1. 只读诊断 API:GET /api/runs/{id}/diagnostics(owner/project 授权,复用既有 run 鉴权),响应聚合:状态、当前责任方与等待原因(running / waiting_hitl / confirmation_pending / recovery_hold(原因+created_at) / reconciling / failed+reason / completed)、最后稳定 checkpoint(如可得)、已知副作用与关联 operation 记录(复用 cmdbus 审计信封查询)、下一步动作建议(确认卡片 / 解除 hold / 可安全重试 / 需人工核对 / 无)。
2. 纯读聚合,不改任何执行/恢复行为;复用既有 store 方法(GetRun/RecoveryHold/ListInterruptedSubagentRuns/审计查询)与 U7b 的 operation 查询。
3. 不建控制台、不加写接口;批量列表走既有会话 run 列表。
- 交付模式:goal-first(目标、范围和交付终点一次确认;范围内连续推进)
- 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md)
- 合入执行:agent(已授权交付范围内,Review 通过、冲突解决且当前 HEAD 的 CI 通过后合入)
- 人工决策点:仅限目标/范围/验收变更、重大取舍、高后果操作或无法自动判定的业务验收
- 当前阶段:需求拆解;当前增量:I1(待定义)
- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位)
## 目标与非目标
**目标**:单只读端点聚合"卡在哪里/谁在等/为何等/最后 checkpoint/已知副作用/下一步",覆盖 HITL 等待、确认等待、恢复 hold(批二 needs-reconciliation)、失败原因等全部可诊断状态。
**非目标**:控制台/UI;任何写操作或状态变更端点;A3/A4; squad sqlite 协作层的跨库聚合(只读后端 store 与审计)。
## 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 |
|---|---|---|---|
| 启动 | c92443280ef8e9ed29bf5bf5250df650c01b4478 | c92443280ef8e9ed29bf5bf5250df650c01b4478 | 2026-10-22T12:37:28Z |
## 证据(Evidence)
<!-- CMD="<命令>" make evidence 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->
| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) |
|---|---|---|---|---|---|
## 交付调度
- 调度状态:未入队;调度记录:无
- entry_id:无;attempt_id:无;窗口执行者:无
- 固定候选:无(base/head、组件与相关配置引用实际尝试)
- 调度依据:policy/delivery.md#合入调度
- 固定后证据:源码外 RECEIPT;实际结果后按授权原样导入和闭合
## 结果与验证
- 结果:
- 验证:<结论摘要 PASS/FAIL/SKIP/NOT_RUN 逐项;逐条证据由 make evidence 写入上方证据表>
- 影响与剩余项:
## 规划进展与下一步
- 本次推进/剩余:待核对(依据实际成果更新适用方案/规划)
- 首选下一任务:待核对(无适用规划、已完成或受阻时如实说明,不虚构任务)
- 推荐依据:待填写
- 前置条件/待确认:待核对
- 预期产物/验收条件:待定义
- 重复任务核对:待核对(已有/在途任务、PR 与规划记录)
- 启动授权:未授权(建议不自动启动新任务,仍须明确授权)
## 合入与清理
- 实施收据:a2-diagnostics-api(pi attempt1,rundiag 聚合 + GET /api/runs/{id}/diagnostics,backend 06b0c9f,verify-a2b exit=0);架构基线边登记(repair,a2arch-run.json);backend pin 集成(a2git2-run.json,cursor 配额间歇故障重试一次后成功)。
- 组合验证:全量 make test PASS(verify-a2-combo2.json exit=0,本轮 svc 既有 flake 未复现)。
- Review 记录:独立 CLI 评审单元 a2-independent-review(第 2 次派发 success;首轮 pi-glm 终态记录不可解码,现场保留);结论 APPROVE(0 blocker / 0 major);报告 .task/reviews/2026-10-22-a2-diagnostics-independent-review.md;被审对象合并基线 vs main
- 冲突记录:NOT_RUN(最新目标同步、冲突处置、组合兼容核验及复审/补测)
- CI 记录:NOT_RUN(当前 HEAD 完整 SHA、全部必需检查、运行链接、执行身份及 GATE 结果)
- 合入记录:NOT_RUN(交付授权范围、PR、被核验 HEAD、合入 SHA、目标分支及内容核验)
- 清理记录:NOT_RUN(授权依据、写者退出确认、worktree/分支/任务卡处置)
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"summary_schema": 1,
"source": "SELF",
"timestamp": "2026-10-22T12:30:58.698213+00:00",
"command": "make precheck",
"exit_code": 0,
"cwd": "/home/weichen/projects/Agent-System-Dev",
"before_head": "c92443280ef8e9ed29bf5bf5250df650c01b4478",
"after_head": "c92443280ef8e9ed29bf5bf5250df650c01b4478",
"branch": "fix/gitea-address-migration",
"target_branch": "main",
"target_head": "c92443280ef8e9ed29bf5bf5250df650c01b4478",
"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=fix/gitea-address-migration head=c92443280e",
"[remote] origin/main=c92443280e ahead=0 behind=0",
"[tree] clean submodules_drift=0 uninit=0",
"[worktrees] linked=7",
"[recycle] merged un-recycled branches: fix/gitea-endpoint-facts",
"[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] c92443280e(完整:c92443280ef8e9ed29bf5bf5250df650c01b4478)",
"[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": "d670ed210b367c72f877fb63bbbeb5b28411e95cb56fab782f27172fa481ed89",
"receipt_sha256": "2829e17065c329449fac8ef2690d50babf82015a1f546dcbfd3f27f67789dd0c",
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/2829e17065c329449fac8ef2690d50babf82015a1f546dcbfd3f27f67789dd0c.json"
}
```
## 闭合记录(合入前折叠)
- 本卡在 PR #704(https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/704)合入前闭合并归档,随该 PR 一同合入。
- 该 PR 的合并提交即本任务的落地记录。
- 合入后无需回填,也无需单独的闭合 PR。
@@ -0,0 +1,168 @@
# feature/intent-multi-turn-a1 任务卡
任务主记录:PR #700 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/700;状态:已完成(合入前闭合);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
- 授权与交付终点:用户已批准启动 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 通过后合入)
- 人工决策点:仅限目标/范围/验收变更、重大取舍、高后果操作或无法自动判定的业务验收
- 当前阶段:需求拆解;当前增量:I1(待定义)
- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位)
## 目标与非目标
**目标**:多轮对话中:缺槽动作 → 澄清 → 用户回答补槽 → 动作完成(第一类=运行取消);"取消刚才的任务"作用于明确对象;歧义先澄清;过期回答(TTL 外)不影响新任务;双用户隔离;revision 防串轮。拆两个单元:U-A1b 会话状态与命令消费(intentgate/route/server + store 表);U-A1c 取消意图路由到 cmdbus(确认卡 + 明确对象解析)。
**非目标**:A2-A4;A2A;更多业务动作族;前端界面改动;部署。
## 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)
<!-- CMD="<命令>" make evidence 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->
| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) |
|---|---|---|---|---|---|
## 交付调度
- 调度状态:未入队;调度记录:无
- entry_id:无;attempt_id:无;窗口执行者:无
- 固定候选:无(base/head、组件与相关配置引用实际尝试)
- 调度依据:policy/delivery.md#合入调度
- 固定后证据:源码外 RECEIPT;实际结果后按授权原样导入和闭合
## 结果与验证
- 结果:
- 验证:<结论摘要 PASS/FAIL/SKIP/NOT_RUN 逐项;逐条证据由 make evidence 写入上方证据表>
- 影响与剩余项:
## 规划进展与下一步
- 本次推进/剩余:待核对(依据实际成果更新适用方案/规划)
- 首选下一任务:待核对(无适用规划、已完成或受阻时如实说明,不虚构任务)
- 推荐依据:待填写
- 前置条件/待确认:待核对
- 预期产物/验收条件:待定义
- 重复任务核对:待核对(已有/在途任务、PR 与规划记录)
- 启动授权:未授权(建议不自动启动新任务,仍须明确授权)
## 合入与清理
- 实施收据: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、目标分支及内容核验)
- 清理记录:NOT_RUN(授权依据、写者退出确认、worktree/分支/任务卡处置)
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```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"
}
```
## 闭合记录(合入前折叠)
- 本卡在 PR #700(https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/700)合入前闭合并归档,随该 PR 一同合入。
- 该 PR 的合并提交即本任务的落地记录。
- 合入后无需回填,也无需单独的闭合 PR。
@@ -0,0 +1,98 @@
# fix/svc-test-port-governance-batch1 任务卡
任务主记录:PR #702 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/702(merge cb36b59acc);状态:已完成(回填);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)
<!-- CMD="<命令>" make evidence 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->
| 时间(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/分支/任务卡处置)
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```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"
}
```
| 同步(记录前对象) | c92443280ef8e9ed29bf5bf5250df650c01b4478 | c22b9fb34a3702191a9e5f6007f3538520db694b | 2026-10-22T13:10:38Z |
## 闭合记录(card-autoclose 回填)
- 依据:merge cb36b59accd0418c5ca952912d7c181b83038a4c(PR #702)已包含于 origin/main,分支成果已落盘;本段为合入后回填。
- 合并主题:Merge pull request 'Use dynamic ports across the five test files that shared hardcoded bindings' (#702) from fix/svc-test-port-governance-batch1 into main
- 归档:随闭合移入 .task/archive/;任务执行期的过程证据见原任务记录与 PR。
@@ -0,0 +1,99 @@
# fix/svc-test-port-governance-deploy-txn 任务卡
任务主记录:PR #705 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/705(merge f673c2a15a);状态:已完成(回填);owner:weichen
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= cb36b59accd0418c5ca952912d7c181b83038a4c
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-fix-svc-test-port-governance-deploy-txn(worktree);分支:fix/svc-test-port-governance-deploy-txn
- 分支类型:standalone;root_target:main;immediate_target:main;accepting_requirements:false
- 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=37c57479990e37eb048ba81763fe402e1e679a822679f315a4be18e4b965c333;triage_receipt=/tmp/plast-triage.json;receipt_sha256=d403df8b2564bf4e1fe16fb12ecc48cf31c25be4f7472e6b27bce6da3ecd93e0
- 授权与交付终点:<本次允许的动作与终点;未授权事项写明>
- 交付模式: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 |
|---|---|---|---|
| 启动 | cb36b59accd0418c5ca952912d7c181b83038a4c | cb36b59accd0418c5ca952912d7c181b83038a4c | 2026-10-22T13:39:45Z |
## 证据(Evidence)
<!-- CMD="<命令>" make evidence 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->
| 时间(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/分支/任务卡处置)
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"summary_schema": 1,
"source": "SELF",
"timestamp": "2026-10-22T13:28:41.022157+00:00",
"command": "make precheck",
"exit_code": 0,
"cwd": "/home/weichen/projects/Agent-System-Dev",
"before_head": "cb36b59accd0418c5ca952912d7c181b83038a4c",
"after_head": "cb36b59accd0418c5ca952912d7c181b83038a4c",
"branch": "main",
"target_branch": "main",
"target_head": "cb36b59accd0418c5ca952912d7c181b83038a4c",
"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=cb36b59acc",
"[remote] origin/main=cb36b59acc ahead=0 behind=0",
"[tree] clean submodules_drift=0 uninit=0",
"[worktrees] linked=9",
"[recycle] merged un-recycled branches: fix/gitea-address-migration fix/svc-test-port-governance-batch1",
"[cards] 已合入未闭合任务卡:fix-svc-test-port-governance-batch1.md——make task-close 回填归档(主检出运行)",
"[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] cb36b59acc(完整:cb36b59accd0418c5ca952912d7c181b83038a4c)",
"[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": "9f6260af81b0761dbb20afc5d145a9cb310303d426f655840a50f0879d81a49e",
"receipt_sha256": "eeb4f9ac9bdc0e30a0a7bbaa49176626bb8aca54a20f152b1771e1df8fd855d3",
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/eeb4f9ac9bdc0e30a0a7bbaa49176626bb8aca54a20f152b1771e1df8fd855d3.json"
}
```
## 闭合记录(card-autoclose 回填)
- 依据:merge f673c2a15a50bef2c55f2c79a17d7601f82c8a07(PR #705)已包含于 origin/main,分支成果已落盘;本段为合入后回填。
- 合并主题:Merge pull request 'Use a dynamic port in the last hardcoded test binding' (#705) from fix/svc-test-port-governance-deploy-txn into main
- 归档:随闭合移入 .task/archive/;任务执行期的过程证据见原任务记录与 PR。
@@ -0,0 +1,99 @@
# fix/svc-test-port-governance-final 任务卡
任务主记录:PR #698 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/698;状态:已完成(合入前闭合);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-fix-svc-test-port-governance-final(worktree);分支:fix/svc-test-port-governance-final
- 分支类型:standalone;root_target:main;immediate_target:main;accepting_requirements:false
- 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=04cbe9df900a03163aeadb42fd22e5a86ddeced179901b50ac0f4642ce7f6881;triage_receipt=/tmp/pg3-triage.json;receipt_sha256=aca390790027841efaefe2082123780b1ec8d775f9ca0be80262a80f7121bde9
- 授权与交付终点:<本次允许的动作与终点;未授权事项写明>
- 交付模式: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 |
|---|---|---|---|
| 启动 | 955a32de2bb49171348bad5f566cce935df19212 | 955a32de2bb49171348bad5f566cce935df19212 | 2026-10-22T08:55:33Z |
## 证据(Evidence)
<!-- CMD="<命令>" make evidence 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->
| 时间(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/分支/任务卡处置)
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"summary_schema": 1,
"source": "SELF",
"timestamp": "2026-10-22T08:54:47.013779+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=5",
"[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": "b63c0d5c11be0292024cc972eee78fbcef7349381ee3bdecb432815b903373e6",
"receipt_sha256": "3ee914c56ff0e9cf2a4d11db1ec0a2e6c74cf745cceb7eff1cefd2f9d938ee89",
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/3ee914c56ff0e9cf2a4d11db1ec0a2e6c74cf745cceb7eff1cefd2f9d938ee89.json"
}
```
## 闭合记录(合入前折叠)
- 本卡在 PR #698(https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/698)合入前闭合并归档,随该 PR 一同合入。
- 该 PR 的合并提交即本任务的落地记录。
- 合入后无需回填,也无需单独的闭合 PR。
| 同步(记录前对象) | 98ee59c477785b2d5094fcbea3e67a4dc864c388 | a29562ef8315c6cbe71bf531720ce5ffa5ca2717 | 2026-10-22T09:35:11Z |
@@ -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
@@ -0,0 +1,44 @@
# Independent Code Review — feature/exec-recovery-diagnostics-a2 (A2 run diagnostics)
- Reviewer: independent CLI review session (`a2-independent-review` unit; fresh session, not the implementer)
- Date: 2026-10-22
- Review object: this checkout @ `d0b2bde9` (branch `feature/exec-recovery-diagnostics-a2`) versus authoritative main. No `origin/*` refs exist in this sandbox; task card R0 = `c9244328` (= `d0b2bde9~5`, the merged main tip `c92443280ef8e9ed29bf5bf5250df650c01b4478`), so `git diff c9244328...d0b2bde9` ≡ `git diff origin/main...HEAD`.
- Dev-level scope: task card `.task/feature-exec-recovery-diagnostics-a2.md` (new), `modules/backend` gitlink `9ee752c3` → `06b0c9f1`, `policy/architecture-baseline.json` +3 edges. Verified: dev diff is exactly these 3 files; the three edges (`backend/rundiag backend/cmdbus`, `backend/rundiag backend/store`, `backend/server backend/rundiag`) sit in correct sorted positions and match the actual import graph (see N5).
- Backend scope: `git -C modules/backend diff 9ee752c..06b0c9f` — 7 files, +1418/−0: `internal/rundiag/rundiag.go` (488), `internal/rundiag/rundiag_test.go` (440), `internal/server/run_diagnostics.go` (32), `internal/server/run_diagnostics_test.go` (226), `internal/server/server.go` (+2), `internal/store/run_diagnostics.go` (110), `internal/store/run_diagnostics_test.go` (120).
- Method: read-only review of the full diff plus the neighboring run-read/cancel routes, the pre-existing store methods the aggregator reuses, and the cmdbus pending-confirm write path. No code changed; the only write is this report.
## Findings
### Blockers
None.
### Major
None.
### Minor
- **MI1 — Evidence-driven wait states outrank terminal run statuses; a completed/failed run can be reported as `waiting_hitl`.** In the responsibility switch the HITL arm `case ev.Run.Status == core.RunWaitingHITL || card != nil || decision != nil` (`modules/backend/internal/rundiag/rundiag.go:252`) is evaluated before `failed` (:281) and `completed` (:296). A run that ended while a decision card scoped only by owner+conversation (human_decisions has no run column; attributed by the time-window inference at :432-448) remained `pending`, or with a leftover unresolved run-scoped HITL card, yields `state=waiting_hitl`, `role=human`, `next_step.action=confirm_card` for a terminal run. This is exactly the fixed precedence the task card approved and the documented bounded attribution (`rundiag.go:15-19`), and `run.status` stays visible in the report — but a follow-up that suppresses evidence-driven wait mapping (or adds a note) when the run is terminal would remove the confusing "confirm card" advice on finished runs. Not blocking: matches the approved design; purely advisory output.
- **MI2 — Silent truncation of side-effect evidence contradicts the package's own honesty contract.** `sideEffects` stops appending at `maxSideEffects = 50` with no note (`rundiag.go:342-366`, cap at :57), and `Gather` fetches only the 200 newest audit envelopes (`maxAuditScan`, `rundiag.go:175` → `ListAudits` orders `time DESC`, `internal/store/audit.go:147-152`), so a busy conversation can under-report a run's operations without any indication. Every other evidence gap in the package adds a note (even "absence of records is not proof of no effect", :313-315); a "side effects truncated" note would complete that contract. Diagnostic-only impact; recorded evidence is still correct as far as it goes.
- **MI3 — Precedence is tested only at the top of the chain.** Of the ordered arms at `rundiag.go:224-310`, only "unreleased recovery hold wins over everything" (`rundiag_test.go:81-89`) exercises interleaved evidence; combinations such as released-hold+interrupted+open-HITL-card (→ `reconciling`) or decision+pending-confirm (→ `waiting_hitl`) are untested and rest on the switch order alone. Low risk because the order is literal and table-covered per state; suggesting coverage only because precedence is the stated spec center of this unit.
### Notes
- **N1 — Per-state derivation and precedence are complete and match the task-card contract.** All eight states are derivable: `unknown` fail-closed on unreadable hold (:226-233), `recovery_hold` on an open hold row (:234-240), `reconciling` for released-hold+`RunInterrupted` residue (:241-251, predicate at :402-403), `waiting_hitl` from status/run-scoped card/time-windowed decision (:252-273), `confirmation_pending` from an owner-scoped pending confirm parsed out of the dispatch payload (:274-280, :453-471), `failed` with retry-safety gated on unknown receipts (:281-295), `completed` (:296-298), `running` for running+pending (:299-303), `unknown` default for unmapped statuses (cancelled; interrupted without hold; :304-310). Precedence order is exactly `recovery_hold > reconciling > waiting_hitl > confirmation_pending > failed > completed > running > unknown`, with the fail-closed `HoldUnknown` degradation deliberately first.
- **N2 — Security: scoping is byte-for-byte the neighboring run-read pattern; no cross-owner leakage path exists.** The handler resolves the run via `s.st.GetRun(s.owner(r), r.PathValue("id"))` (`internal/server/run_diagnostics.go:25`) — identical to `getRun` (`server.go:1592`) — where `owner` comes only from the auth context (`auth.go:220-225`), `GetRun` filters `WHERE id=? AND owner=?` with cross-tenant = `ErrNotFound` (`messages.go:307-316`), and `writeStoreErr` maps it to 404 indistinguishable from a missing run (`server.go:2617-2620`). Every follow-on query is keyed on the already-authorized run's own fields, never on request parameters: `GetRecoveryHold(run.ID)` (`recovery_holds.go:36`), `ActiveHITLCardsByRun(run.ID)` (`recovery.go:156`), `PendingHumanDecisionsByConversation(run.Owner, run.ConversationID)` with empty-owner defense (`store/run_diagnostics.go:51-53`), `ListOwnerPendingConfirms(run.Owner)` (:88-90), `LastRunCheckpoint(run.ConversationID, run.ID)` (:28-30), `ListAudits(run.Owner, run.ConversationID)` (`audit.go:134-140`). The `pending_confirms` payload is parsed only to extract command/owner/conversation identity; the raw payload is never echoed (`rundiag.go:453-471`).
- **N3 — Read-only holds end to end.** All six store entry points the aggregator uses are SELECT-only (verified by reading each); `Build` is a pure function; the handler path contains no store write and the mux registers only the GET pattern (`server.go:396`). The author's `TestRunDiagnosticsIsReadOnly` additionally asserts the run row and hold are unchanged after a GET and that POST/PUT/DELETE/PATCH are not served (`run_diagnostics_test.go:153-193`).
- **N4 — No route-registration conflicts.** `GET /api/runs/{id}/diagnostics` differs from `GET /api/runs/{id}` (:394) and `POST /api/runs/{id}/cancel` (:393) by a literal extra segment / method; ServeMux precedence is specificity-based, single registration, no duplicate pattern anywhere in the diff.
- **N5 — Architecture-baseline edges are correct and validated.** `internal/rundiag` imports exactly `cmdbus` and `store` within the backend module (`rundiag.go:21-24`); the `agent-command` import is intentionally untracked — the baseline records only intra-repo package edges and has no deps-module edges anywhere (same precedent as `backend/cmdbus`, which also imports agent-command without an edge). `backend/server backend/rundiag` matches the handler import. Sorted positions are correct (`route < rundiag`; `ratelimit < rundiag < runmgr`), and `scripts/lint-architecture.go` compares this file against the collected import graph, so the edges are machine-checked in CI.
- **N6 — Go tests NOT_RUN in this review workspace (environment, not code).** The backend's nested dependency checkouts (`modules/backend/deps/agent-command`, `deps/agent-system-core`, …) are empty gitlinks here and no `.git/modules` gitdirs exist; `git submodule init/update` is forbidden for this unit and network is off, so `go build ./internal/rundiag/ …` fails at module setup (`agent-command@v0.0.0 (replaced by ./deps/agent-command): reading deps/agent-command/go.mod: no such file or directory`), before any code compiles. Fallbacks applied: every changed file was fully line-read; all `core.Run*`/phase/event symbols referenced are used by pre-existing compiling backend code; `cmdbus.Request` carries `ID/Owner/ConversationID` (`cmdbus.go:163-177`) and the pending-confirm payload is the marshaled dispatch request (`cmdbus.go:522-523`), so `waitingConfirm`'s parsing is sound; the `events` table has `run_id`/`seq`/`ts`/`type` in both dialects (`migrate.go:47,71`) and the checkpoint query is served by `idx_events_conv(conversation_id, seq)`. Author-recorded receipts were reviewed and are internally consistent with the task card: `/tmp/agent-stack-b2/verify-a2b.json` (`go build ./... && go test -count=1 ./internal/server/... ./internal/rundiag/... ./internal/store/... && go vet …`, exit=0, `ok agent-system-backend/internal/{server,rundiag,store}`) and `/tmp/agent-stack-b2/verify-a2-combo2.json` (`make test`, exit=0) — author-claimed (SELF), not independently re-executed in this session.
- **N7 — Attribution boundaries are documented and bounded; one sibling-run overlap remains.** Audit envelopes carry no runId today (host bus doesn't write it), so `belongsToRun` (`rundiag.go:371-383`) attributes by conversation + "not issued before run start". Concurrent sibling runs (subagents) in the same conversation have overlapping windows, so until the bus persists `runId`, an envelope from a sibling can appear in both runs' `side_effects`. The limitation is stated in the package doc (:17-19) and the report surfaces `operation_id`/`command_id` so a human can disambiguate; when the bus starts writing `env.RunID` the strict branch (:372-373) takes over automatically. Acceptable for a diagnostic surface.
- **N8 — "No records ≠ no effect" honesty contract is consistently enforced** (unrecorded checkpoints → null + note at :311-312, tested at `rundiag_test.go:280-302`; empty side effects → note :313-315; unreadable hold → fail-closed unknown that can never yield `safe_retry` :226-233, tested :304-339). Only the truncation gap of MI2 falls short of it.
## Lens summaries
1. **Spec** — pass. State derivation and precedence are complete and per-state correct (N1); the JSON contract (snake_case, `last_checkpoint` explicit null, `side_effects` always an array, `next_step` never reason-less) is pinned by `TestReportJSONContract` (`rundiag_test.go:341-389`). Dev-level artifacts (task card, 3 baseline edges, gitlink `06b0c9f`) are exactly as claimed.
2. **Security** — pass. Auth-context-only owner, tenant-filtered run fetch, 404 on cross-owner/missing (tested `run_diagnostics_test.go:62-97`), all downstream reads anchored on the authorized run, strictly read-only (N2/N3), no payload echo, empty-owner fail-closed store helpers.
3. **Regressions** — pass. The diff is additive: 7 new files plus a 2-line route registration; no execution/recovery/runmgr path touched, no existing signature changed, no route conflicts (N4), no migration/schema/index change.
4. **Tests** — pass with minor gaps. Per-state table of 12 cases covering all eight states plus degradation (`rundiag_test.go:78-225`), scoping at both server and store layers including cross-owner/cross-conversation/empty-owner (`run_diagnostics_test.go:62-97`, `store/run_diagnostics_test.go:13-120`), unknown-degradation at three levels (unreadable source, unmapped status, fail-closed hold; `run_diagnostics_test.go:195-226`), read-only and write-method rejection (`:153-193`), pre-run evidence exclusion (`rundiag_test.go:391-406`). Gaps: MI3 (chain precedence below the top arm), MI2 (truncation without note). Focused tests could not be re-run here (N6); author receipts for `go test ./internal/rundiag/... ./internal/server/... ./internal/store/...` and full `make test` are on record and uncontradicted.
REVIEW VERDICT: APPROVE
+6
View File
@@ -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",
@@ -49,6 +51,8 @@
"backend/rag backend/settings",
"backend/rag backend/store",
"backend/route backend/intentgate",
"backend/rundiag backend/cmdbus",
"backend/rundiag backend/store",
"backend/runmgr backend/bus",
"backend/runmgr backend/cardsvc",
"backend/runmgr backend/docgen",
@@ -76,12 +80,14 @@
"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",
"backend/server backend/prompts",
"backend/server backend/ratelimit",
"backend/server backend/route",
"backend/server backend/rundiag",
"backend/server backend/runmgr",
"backend/server backend/settings",
"backend/server backend/store",
+38 -25
View File
@@ -296,12 +296,14 @@ class SvcDbRecoveryTests(unittest.TestCase):
# ---- 1. 存量 exec= DSN:连续启动两次均恢复,进程参数无秘密 ----
def test_legacy_exec_dsn_survives_consecutive_restarts(self):
self.register_pg("pg1", 18890, password="legacy-pw-1")
dsn = "postgresql://agent:legacy-pw-1@127.0.0.1:18890/agent"
pg_port = free_test_port()
self.register_pg("pg1", pg_port, password="legacy-pw-1")
dsn = "postgresql://agent:legacy-pw-1@127.0.0.1:%d/agent" % pg_port
d = self.runtime("dev")
self.seed_agent("dev", 18791,
"--addr 127.0.0.1:18791 --data %s --plugins %s --auth auto --dsn %s"
% (d / "data", d / "plugins", dsn))
port = free_test_port()
self.seed_agent("dev", port,
"--addr 127.0.0.1:%d --data %s --plugins %s --auth auto --dsn %s"
% (port, d / "data", d / "plugins", dsn))
for _ in range(2):
self.clear_serve_record()
self.svc("dev", "restart")
@@ -322,12 +324,14 @@ class SvcDbRecoveryTests(unittest.TestCase):
# ---- 2. 仅 dbref:裸 restart 与重新部署均保留绑定 ----
def test_dbref_binding_survives_bare_restart_and_redeploy(self):
self.register_pg("pg1", 18891, password="bind-pw-2")
dsn = "postgresql://agent:bind-pw-2@127.0.0.1:18891/agent"
pg_port = free_test_port()
self.register_pg("pg1", pg_port, password="bind-pw-2")
dsn = "postgresql://agent:bind-pw-2@127.0.0.1:%d/agent" % pg_port
d = self.runtime("dev")
self.seed_agent("dev", 18792,
"--addr 127.0.0.1:18792 --data %s --plugins %s --auth auto"
% (d / "data", d / "plugins"),
port = free_test_port()
self.seed_agent("dev", port,
"--addr 127.0.0.1:%d --data %s --plugins %s --auth auto"
% (port, d / "data", d / "plugins"),
extra_rows=[("dbref", "pg1/agent"), ("db", "pg")])
self.clear_serve_record()
self.svc("dev", "restart")
@@ -413,9 +417,10 @@ class SvcDbRecoveryTests(unittest.TestCase):
def test_refusals_keep_registration_without_sqlite_fallback(self):
d = self.runtime("a1")
self.seed_agent("a1", 18796,
"--addr 127.0.0.1:18796 --data %s --plugins %s --auth auto"
% (d / "data", d / "plugins"),
port = free_test_port()
self.seed_agent("a1", port,
"--addr 127.0.0.1:%d --data %s --plugins %s --auth auto"
% (port, d / "data", d / "plugins"),
extra_rows=[("dbref", "pgmissing/agent"), ("db", "pg")])
self.clear_serve_record()
result = self.svc("a1", "restart", check=False)
@@ -425,33 +430,41 @@ class SvcDbRecoveryTests(unittest.TestCase):
self.assertEqual(self.kv("a1", "dbref"), "pgmissing/agent") # 可恢复配置保留
# 实例登记不全(缺 password)→ 拒启。
self.register_pg("pginc", 18895, complete=False)
self.register_pg("pginc", free_test_port(), complete=False)
d = self.runtime("a2")
self.seed_agent("a2", 18797,
"--addr 127.0.0.1:18797 --data %s --plugins %s --auth auto"
% (d / "data", d / "plugins"),
port = free_test_port()
self.seed_agent("a2", port,
"--addr 127.0.0.1:%d --data %s --plugins %s --auth auto"
% (port, d / "data", d / "plugins"),
extra_rows=[("dbref", "pginc/agent"), ("db", "pg")])
result = self.svc("a2", "restart", check=False)
self.assertNotEqual(result.returncode, 0)
self.assertIn("拒绝", result.stdout)
# dbref 与 dsn= 指向不同库 → 配置冲突拒启。
self.register_pg("pg1", 18896, password="clash-pw")
pg_port = free_test_port()
self.register_pg("pg1", pg_port, password="clash-pw")
other_pg_port = free_test_port()
while other_pg_port == pg_port:
other_pg_port = free_test_port()
d = self.runtime("a3")
self.seed_agent("a3", 18798,
"--addr 127.0.0.1:18798 --data %s --plugins %s --auth auto"
% (d / "data", d / "plugins"),
port = free_test_port()
self.seed_agent("a3", port,
"--addr 127.0.0.1:%d --data %s --plugins %s --auth auto"
% (port, d / "data", d / "plugins"),
extra_rows=[("dbref", "pg1/agent"), ("db", "pg"),
("dsn", "postgresql://u:p@127.0.0.1:18999/otherdb")])
("dsn", "postgresql://u:p@127.0.0.1:%d/otherdb"
% other_pg_port)])
result = self.svc("a3", "restart", check=False)
self.assertNotEqual(result.returncode, 0)
self.assertIn("拒绝", result.stdout)
# db=pg 但无可恢复 DSN → 拒启。
d = self.runtime("a4")
self.seed_agent("a4", 18799,
"--addr 127.0.0.1:18799 --data %s --plugins %s --auth auto"
% (d / "data", d / "plugins"),
port = free_test_port()
self.seed_agent("a4", port,
"--addr 127.0.0.1:%d --data %s --plugins %s --auth auto"
% (port, d / "data", d / "plugins"),
extra_rows=[("db", "pg")])
result = self.svc("a4", "restart", check=False)
self.assertNotEqual(result.returncode, 0)
+6 -2
View File
@@ -2,9 +2,13 @@
import importlib.util
import json
import os
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(
"tsi", SOURCE / "tests" / "test_svc_identity.py")
@@ -46,7 +50,7 @@ class DeployTxnTests(unittest.TestCase):
new.chmod(0o755)
fx.stub.write_text(old.read_text())
fx.stub.chmod(0o755)
fx.seed_agent("txn", 9471)
fx.seed_agent("txn", free_test_port())
fx.start_ok("txn")
pid = fx.pid_of("txn")
script = fx.root / "scripts" / "svc.sh"
@@ -68,7 +72,7 @@ class DeployTxnTests(unittest.TestCase):
def test_forward_only_requires_confirm_and_backup(self):
fx = self.fx
fx.seed_agent("fwd", 9472)
fx.seed_agent("fwd", free_test_port())
fx.start_ok("fwd")
iid = json.loads((fx.runtime("fwd") / "manifest.json").read_text())["instance_id"]
base = fx.stub.read_text()
+36 -16
View File
@@ -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")
+9 -2
View File
@@ -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"]
+29 -12
View File
@@ -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
+18 -7
View File
@@ -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())
+14 -5
View File
@@ -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")