diff --git a/client/DESIGN.md b/client/DESIGN.md index 38bfb646..b7c16bf9 100644 --- a/client/DESIGN.md +++ b/client/DESIGN.md @@ -313,10 +313,11 @@ v1 设计选择:优先支持 `--control-stdin`,即 stdin 一行一个 JSON 3. `skills:list` 4. `status:get` -当前仍未纳入 Slice C 基线: +Slice D 设计基线: -1. `actions:list` -2. capability discovery / startup handshake +1. v1 capability discovery 优先走显式 `actions:list`,继续复用 `client-control-stdin.v1` +2. unsolicited startup handshake 不纳入当前宿主协议基线,避免在 stdout 多路复用流上引入额外隐式帧 +3. 能力发现返回当前 session 可用的 canonical action ids,不要求首版附带额外元数据矩阵 #### 8.3.5 错误处理与安全边界(Slice C landed baseline) @@ -352,7 +353,7 @@ v1 设计选择:优先支持 `--control-stdin`,即 stdin 一行一个 JSON 4. `script` 模式(注释/空行/失败中断)。 5. headless 协议稳定性(事件 envelope、schema version、error path)。 6. `control-stdin` 往返控制(approvals / MCP / skills / status)。 -7. capability discovery(`actions:list` / 启动握手)与宿主降级策略。 +7. capability discovery(显式 `actions:list`)与宿主降级策略。 ## 11. 分阶段落地计划 @@ -381,7 +382,8 @@ v1 设计选择:优先支持 `--control-stdin`,即 stdin 一行一个 JSON 1. `--headless` 明确模式边界 2. versioned event envelope v1 3. `--control-stdin` 最小外部控制面 -4. capability discovery / handshake +4. 显式 capability discovery(`actions:list`) +5. 启动握手若要引入,需作为后续独立 slice 明确多路复用与兼容策略 ## 12. 风险与缓解 diff --git a/client/README.md b/client/README.md index 033d249e..507cd391 100644 --- a/client/README.md +++ b/client/README.md @@ -347,19 +347,20 @@ Issue #135 对应的宿主编排能力目前分成“已落地”和“未落地 仍未落地: -- `actions:list` / 启动握手式能力发现 +- `actions:list` 显式能力发现 当前推荐边界是: 1. 自动化脚本仍使用 `run/script --output json`。 2. 宿主事件流接入使用 `run/script --headless`。 -3. 运行中控制当前优先使用 `--control-stdin` 做 `status:get`、approvals、MCP 与 `skills:list`;`actions:list` / 启动握手仍在后续 Slice 中。 +3. 运行中控制当前优先使用 `--control-stdin` 做 `status:get`、approvals、MCP 与 `skills:list`;`actions:list` 作为下一 Slice 的显式能力发现入口继续推进。 4. 不要把当前 `log/event/result` 三类 JSON 行当作长期稳定的宿主协议。 补充说明: - `script --headless` 与 `run --headless` 一样支持审批超时控制。 - `script` 可显式传入 `--approval-timeout-seconds `;未显式传入时,headless 脚本默认使用 `120s` 超时,避免无头会话无限等待审批。 +- 启动即发送的 capability handshake 当前不属于 v1 计划;宿主应通过显式 discovery action 获取支持矩阵。 退出码约定: diff --git a/docs/features/client-external-control-plane-v1.md b/docs/features/archive/client-external-control-plane-v1.md similarity index 87% rename from docs/features/client-external-control-plane-v1.md rename to docs/features/archive/client-external-control-plane-v1.md index d93bb89b..d6b95f39 100644 --- a/docs/features/client-external-control-plane-v1.md +++ b/docs/features/archive/client-external-control-plane-v1.md @@ -5,7 +5,7 @@ topics: ["client-cli", "host-orchestration", "control-plane", "issue-135"] todo_ids: ["CCLI-005", "CCLI-006"] created: 2026-03-02 updated: 2026-03-02 -status: active +status: archived mode: openspec --- @@ -17,11 +17,11 @@ mode: openspec ## OpenSpec Artifacts -- Proposal: `openspec/changes/client-external-control-plane-v1/proposal.md` -- Design: `openspec/changes/client-external-control-plane-v1/design.md` +- Proposal: `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/proposal.md` +- Design: `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/design.md` - Specs: - - `openspec/changes/client-external-control-plane-v1/specs/client-host-orchestration/spec.md` -- Tasks: `openspec/changes/client-external-control-plane-v1/tasks.md` + - `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/specs/client-host-orchestration/spec.md` +- Tasks: `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/tasks.md` ## TODO Coverage @@ -46,6 +46,7 @@ mode: openspec - `../../.venv/bin/python -m pytest tests/integration/test_client_cli_flow.py -q` - `openspec list` - `openspec validate client-external-control-plane-v1 --type change --strict --json --no-interactive` +- `openspec archive client-external-control-plane-v1 -y` - `./scripts/ci/check_governance_evidence_truth.sh` ### Results @@ -60,10 +61,11 @@ mode: openspec - `../../.venv/bin/python -m pytest tests/integration/test_client_cli_flow.py -q -k 'status_get_reports_pending_approvals'`: failed before the review fix because `run --headless --control-stdin` only updated the approval timeout watch, leaving `status:get` snapshots blind to pending runtime approvals; passed after wiring run-mode approval pending/resolved events into `CLISessionState.pending_runtime_approvals`. - `../../.venv/bin/python -m pytest tests/integration/test_client_cli_flow.py -q -k 'surfaces_action_handler_failure or rejects_unsupported_action or bridges_approvals_list or control_stdin_status_get_emits_structured_result or script_headless_control_stdin_status_get_reports_active_task'`: passed (`5` tests), covering happy path plus unsupported-action and handler-failure branches. - `../../.venv/bin/python -m pytest tests/unit/test_client_cli.py -q -k 'cancellation_does_not_block_default_executor_shutdown'`: failed before the review fix because cancelling the control task still left a blocking `stdin.readline()` worker pinned in the default executor; passed after moving `control-stdin` reads onto a daemon thread + asyncio queue bridge. -- `../../.venv/bin/python -m pytest tests/unit/test_client_cli.py -q`: passed (`44` tests, `0` failures). -- `../../.venv/bin/python -m pytest tests/integration/test_client_cli_flow.py -q`: passed (`20` tests, `0` failures). +- `../../.venv/bin/python -m pytest tests/unit/test_client_cli.py -q`: passed (`45` tests, `0` failures) after the final `pending_approvals` status snapshot regression fix. +- `../../.venv/bin/python -m pytest tests/integration/test_client_cli_flow.py -q`: passed (`21` tests, `0` failures) after the final `status:get` pending-approval coverage landed. - `openspec list`: confirms Slice A / Slice B have been archived out of the active change list, and the active Slice C change now shows `✓ Complete`. - `openspec validate client-external-control-plane-v1 --type change --strict --json --no-interactive`: passed (`1/1` change valid, `0` issues). +- `openspec archive client-external-control-plane-v1 -y`: archived the completed change to `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/` and synced the landed control-plane deltas back into `openspec/specs/client-host-orchestration/spec.md`. - `./scripts/ci/check_governance_evidence_truth.sh`: passed after the Slice C feature evidence block and prior-slice archive moves were synchronized. ### Behavior Verification @@ -83,7 +85,8 @@ mode: openspec - Slice A intent gate (merged): `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/141` - Slice B implementation gate (merged): `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/145` - Slice C docs-only intent PR (merged): `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/148` -- Slice C implementation PR (open): `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/151` +- Slice C implementation PR (merged): `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/151` - Slice C spec-fold review thread: `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/148#discussion_r2872038646` - Slice C implementation review thread: `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/151#discussion_r2872629793` - Slice C implementation review thread: `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/151#discussion_r2872876273` +- Archive target: `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/` diff --git a/docs/features/client-capability-discovery-and-host-tests.md b/docs/features/client-capability-discovery-and-host-tests.md new file mode 100644 index 00000000..82cb2236 --- /dev/null +++ b/docs/features/client-capability-discovery-and-host-tests.md @@ -0,0 +1,71 @@ +--- +change_ids: ["client-capability-discovery-and-host-tests"] +doc_kind: feature +topics: ["client-cli", "host-orchestration", "capability-discovery", "issue-135"] +todo_ids: ["CCLI-007", "CCLI-008"] +created: 2026-03-02 +updated: 2026-03-02 +status: active +mode: openspec +--- + +# Feature: client-capability-discovery-and-host-tests + +## Scope + +落实 Issue #135 的 Slice D:为 `client/` 的宿主协议面补上显式 capability discovery(`actions:list`),并建立覆盖 headless event envelope、control plane 与 discovery 的宿主级回归测试。 + +## OpenSpec Artifacts + +- Proposal: `openspec/changes/client-capability-discovery-and-host-tests/proposal.md` +- Design: `openspec/changes/client-capability-discovery-and-host-tests/design.md` +- Specs: + - `openspec/changes/client-capability-discovery-and-host-tests/specs/client-host-orchestration/spec.md` +- Tasks: `openspec/changes/client-capability-discovery-and-host-tests/tasks.md` + +## TODO Coverage + +- `CCLI-007` +- `CCLI-008` + +## Evidence + +### Commands + +- `git fetch origin` +- `git worktree add .worktrees/client-capability-discovery-and-host-tests -b codex/client-capability-discovery-and-host-tests origin/main` +- `openspec archive client-external-control-plane-v1 -y` +- `../../.venv/bin/python -m pytest tests/unit/test_client_cli.py -q` +- `../../.venv/bin/python -m pytest tests/integration/test_client_cli_flow.py -q` +- `openspec list` +- `openspec show client-capability-discovery-and-host-tests --type change --json --no-interactive` +- `openspec validate client-capability-discovery-and-host-tests --type change --strict --json --no-interactive` +- `./scripts/ci/check_governance_evidence_truth.sh` + +### Results + +- `git fetch origin`: confirmed `origin/main` has merged Slice C via PR `#151`. +- `git worktree add .worktrees/client-capability-discovery-and-host-tests -b codex/client-capability-discovery-and-host-tests origin/main`: created an isolated Slice D workspace from merged `main` at commit `cce6e4d`. +- `openspec archive client-external-control-plane-v1 -y`: archived the completed Slice C change to `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/` and synced the landed control-plane deltas back into the main `client-host-orchestration` spec. +- `../../.venv/bin/python -m pytest tests/unit/test_client_cli.py -q`: passed (`45` tests, `0` failures) as the Slice D kickoff baseline in the new worktree. +- `../../.venv/bin/python -m pytest tests/integration/test_client_cli_flow.py -q`: passed (`21` tests, `0` failures) as the Slice D kickoff baseline in the new worktree. +- `openspec list`: shows the new change as `client-capability-discovery-and-host-tests 0/7 tasks`. +- `openspec show client-capability-discovery-and-host-tests --type change --json --no-interactive`: confirms the change exposes `1` `MODIFIED` delta under `client-host-orchestration`. +- `openspec validate client-capability-discovery-and-host-tests --type change --strict --json --no-interactive`: passed (`1/1` change valid, `0` issues). +- `./scripts/ci/check_governance_evidence_truth.sh`: passed after the Slice C archive moves and Slice D kickoff evidence were synchronized. + +### Behavior Verification + +- Happy path: Slice C is now archived on top of merged `main`, and Slice D design chooses explicit `actions:list` discovery on `--control-stdin` rather than adding startup chatter to the host protocol. +- Error branch: unsolicited startup capability handshake remains out of scope for v1, preventing hosts from depending on implicit frames before explicit discovery semantics are finalized. + +### Risks and Rollback + +- Risk: until Slice D implementation lands, hosts still need a hardcoded discovery matrix even though the design baseline now prefers explicit `actions:list`. +- Rollback: drop the Slice D kickoff change and keep the repository at the archived Slice C baseline where control is available but capability discovery remains planned-only. + +### Review and Merge Gate Links + +- Slice C implementation gate (merged): `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/151` +- Slice C archive target: `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/` +- Slice D intent PR: `https://github.com/zts212653/Deterministic-Agent-Runtime-Engine/pull/156` diff --git a/docs/todos/2026-03-02_client_cli_host_orchestration_master_todo.md b/docs/todos/2026-03-02_client_cli_host_orchestration_master_todo.md index f740efa3..c00e5e43 100644 --- a/docs/todos/2026-03-02_client_cli_host_orchestration_master_todo.md +++ b/docs/todos/2026-03-02_client_cli_host_orchestration_master_todo.md @@ -16,14 +16,15 @@ mode: openspec ## 认领声明(Claim Ledger) -> 当前状态:Slice A / Slice B 已于 2026-03-02 完成并合入 `main`;Slice C 的 docs-only intent PR `#148` 已合入,当前实现已覆盖 approvals / MCP / skills / status 的 `control-stdin` 基线,待进入实现 PR / review gate。 -> Slice C 负责外部 control plane v1;Slice D 继续承担 capability discovery 与宿主级回归测试。 +> 当前状态:Slice A / Slice B / Slice C 已于 2026-03-02 完成并合入 `main`;Slice C 已归档到 `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/`。 +> Slice D 当前进入 docs-first kickoff:先建立 capability discovery 与宿主协议回归测试的设计基线、OpenSpec change 和 intent PR payload,再进入实现。 | Claim ID | TODO Scope | Owner | Status | Declared At | Expires At | OpenSpec Change | Notes | |---|---|---|---|---|---|---|---| -| CLM-20260302-CCLI-A | CCLI-001~CCLI-002 | bouillipx | done | 2026-03-02 | 2026-03-09 | `client-host-orchestration-doc-baseline` | Slice A: docs baseline 已随 PR `#141` 合入 `main`,待归档到 `openspec/changes/archive/2026-03-02-client-host-orchestration-doc-baseline/`。 | -| CLM-20260302-CCLI-B | CCLI-003~CCLI-004 | bouillipx | done | 2026-03-02 | 2026-03-09 | `client-headless-event-envelope-v1` | Slice B: headless event envelope v1 已随 PR `#145` 合入 `main`,待归档到 `openspec/changes/archive/2026-03-02-client-headless-event-envelope-v1/`。 | -| CLM-20260302-CCLI-C | CCLI-005~CCLI-006 | bouillipx | active | 2026-03-02 | 2026-03-09 | `client-external-control-plane-v1` | Slice C: docs-only intent PR `#148` 已合入;当前已落地 `--control-stdin` 最小基线,以及 `status:get`、approvals、`mcp:list/reload/show-tool`、`skills:list` host bridge;`actions:list` 仍留给 Slice D。 | +| CLM-20260302-CCLI-A | CCLI-001~CCLI-002 | bouillipx | done | 2026-03-02 | 2026-03-09 | `client-host-orchestration-doc-baseline` | Slice A: docs baseline 已随 PR `#141` 合入 `main`,并已归档到 `openspec/changes/archive/2026-03-02-client-host-orchestration-doc-baseline/`。 | +| CLM-20260302-CCLI-B | CCLI-003~CCLI-004 | bouillipx | done | 2026-03-02 | 2026-03-09 | `client-headless-event-envelope-v1` | Slice B: headless event envelope v1 已随 PR `#145` 合入 `main`,并已归档到 `openspec/changes/archive/2026-03-02-client-headless-event-envelope-v1/`。 | +| CLM-20260302-CCLI-C | CCLI-005~CCLI-006 | bouillipx | done | 2026-03-02 | 2026-03-09 | `client-external-control-plane-v1` | Slice C: docs-only intent PR `#148` 与实现 PR `#151` 已合入;change 已归档到 `openspec/changes/archive/2026-03-02-client-external-control-plane-v1/`,feature evidence 已迁移到 `docs/features/archive/client-external-control-plane-v1.md`。 | +| CLM-20260302-CCLI-D | CCLI-007~CCLI-008 | bouillipx | active | 2026-03-02 | 2026-03-09 | `client-capability-discovery-and-host-tests` | Slice D: 建立显式 `actions:list` 能力发现与宿主协议回归测试的 docs baseline、OpenSpec artifacts 与 intent PR payload。 | ## 切片规划 @@ -42,10 +43,10 @@ mode: openspec | CCLI-002 | P0 | done | CCLI-GAP-006 | `client-host-orchestration-doc-baseline` | 更新 `client/README.md`,明确当前 `--output json` 是 legacy automation schema,补充后续宿主协议模式的兼容说明。 | bouillipx | `client/README.md`;`docs/features/archive/client-host-orchestration-doc-baseline.md` | 2026-03-02 | | CCLI-003 | P1 | done | CCLI-GAP-001 | `client-headless-event-envelope-v1` | 为 `client` 设计并实现显式 headless 模式,定义禁止 prompt / 禁止内联审批 / 只输出协议帧的行为边界。 | bouillipx | `client/main.py`;`client/session.py`;`tests/integration/test_client_cli_flow.py`;`docs/features/archive/client-headless-event-envelope-v1.md` | 2026-03-02 | | CCLI-004 | P1 | done | CCLI-GAP-002 | `client-headless-event-envelope-v1` | 设计并实现 versioned event envelope(至少含 `schema_version`、`run_id`、`seq`、`event`、`data`),并定义与现有 JSON 输出的兼容策略。 | bouillipx | `client/render/headless.py`;`tests/unit/test_client_cli.py`;`tests/integration/test_client_cli_flow.py`;`docs/features/archive/client-headless-event-envelope-v1.md` | 2026-03-02 | -| CCLI-005 | P1 | doing | CCLI-GAP-003 | `client-external-control-plane-v1` | 设计外部控制协议入口(如 `control-stdin` 或 loopback RPC),覆盖 approvals / MCP / skills / status 的结构化控制。 | bouillipx | `client/main.py`;`client/render/control.py`;`tests/unit/test_client_cli.py`;`tests/integration/test_client_cli_flow.py`;相关 OpenSpec design/specs/tasks | 2026-03-02 | -| CCLI-006 | P2 | doing | CCLI-GAP-005 | `client-external-control-plane-v1` | 将当前 canonical MCP actions(首批为 `mcp:list/reload/show-tool`)接入外部 control plane,并明确运行中生效与错误处理语义。CLI 层 `unload` 待后续补 canonical action 后再纳入宿主协议面。 | bouillipx | `client/main.py`;`tests/integration/test_client_cli_flow.py`;`docs/features/client-external-control-plane-v1.md` | 2026-03-02 | -| CCLI-007 | P2 | todo | CCLI-GAP-004 | `client-capability-discovery-and-host-tests` | 将 `actions:list` 提升到 CLI 宿主协议面,并定义启动握手或显式查询命令。 | TBD | `dare_framework/transport/interaction/resource_action.py`;`client/main.py`;相关文档 | 2026-03-02 | -| CCLI-008 | P1 | todo | CCLI-GAP-006 | `client-capability-discovery-and-host-tests` | 新增 headless 协议稳定性、外部控制、能力发现三组集成测试,并回写 README / 设计文档中的验证锚点。 | TBD | `tests/integration/test_client_cli_flow.py`;新增协议测试文件 | 2026-03-02 | +| CCLI-005 | P1 | done | CCLI-GAP-003 | `client-external-control-plane-v1` | 设计外部控制协议入口(如 `control-stdin` 或 loopback RPC),覆盖 approvals / MCP / skills / status 的结构化控制。 | bouillipx | `client/main.py`;`client/render/control.py`;`tests/unit/test_client_cli.py`;`tests/integration/test_client_cli_flow.py`;`docs/features/archive/client-external-control-plane-v1.md`;`openspec/changes/archive/2026-03-02-client-external-control-plane-v1/` | 2026-03-02 | +| CCLI-006 | P2 | done | CCLI-GAP-005 | `client-external-control-plane-v1` | 将当前 canonical MCP actions(首批为 `mcp:list/reload/show-tool`)接入外部 control plane,并明确运行中生效与错误处理语义。CLI 层 `unload` 待后续补 canonical action 后再纳入宿主协议面。 | bouillipx | `client/main.py`;`tests/integration/test_client_cli_flow.py`;`docs/features/archive/client-external-control-plane-v1.md`;`openspec/changes/archive/2026-03-02-client-external-control-plane-v1/` | 2026-03-02 | +| CCLI-007 | P2 | doing | CCLI-GAP-004 | `client-capability-discovery-and-host-tests` | 将 `actions:list` 提升到 CLI 宿主协议面,并收敛为显式 discovery action;启动握手不纳入当前 v1 scope。 | bouillipx | `client/DESIGN.md`;`client/README.md`;`docs/features/client-capability-discovery-and-host-tests.md`;相关 OpenSpec design/specs/tasks | 2026-03-02 | +| CCLI-008 | P1 | doing | CCLI-GAP-006 | `client-capability-discovery-and-host-tests` | 新增 headless 协议稳定性、外部控制、能力发现三组集成测试,并回写 README / 设计文档中的验证锚点。 | bouillipx | `tests/integration/test_client_cli_flow.py`;`docs/features/client-capability-discovery-and-host-tests.md`;相关 OpenSpec design/specs/tasks | 2026-03-02 | --- diff --git a/openspec/changes/client-external-control-plane-v1/.openspec.yaml b/openspec/changes/archive/2026-03-02-client-external-control-plane-v1/.openspec.yaml similarity index 100% rename from openspec/changes/client-external-control-plane-v1/.openspec.yaml rename to openspec/changes/archive/2026-03-02-client-external-control-plane-v1/.openspec.yaml diff --git a/openspec/changes/client-external-control-plane-v1/design.md b/openspec/changes/archive/2026-03-02-client-external-control-plane-v1/design.md similarity index 100% rename from openspec/changes/client-external-control-plane-v1/design.md rename to openspec/changes/archive/2026-03-02-client-external-control-plane-v1/design.md diff --git a/openspec/changes/client-external-control-plane-v1/proposal.md b/openspec/changes/archive/2026-03-02-client-external-control-plane-v1/proposal.md similarity index 100% rename from openspec/changes/client-external-control-plane-v1/proposal.md rename to openspec/changes/archive/2026-03-02-client-external-control-plane-v1/proposal.md diff --git a/openspec/changes/client-external-control-plane-v1/specs/client-host-orchestration/spec.md b/openspec/changes/archive/2026-03-02-client-external-control-plane-v1/specs/client-host-orchestration/spec.md similarity index 100% rename from openspec/changes/client-external-control-plane-v1/specs/client-host-orchestration/spec.md rename to openspec/changes/archive/2026-03-02-client-external-control-plane-v1/specs/client-host-orchestration/spec.md diff --git a/openspec/changes/client-external-control-plane-v1/tasks.md b/openspec/changes/archive/2026-03-02-client-external-control-plane-v1/tasks.md similarity index 100% rename from openspec/changes/client-external-control-plane-v1/tasks.md rename to openspec/changes/archive/2026-03-02-client-external-control-plane-v1/tasks.md diff --git a/openspec/changes/client-capability-discovery-and-host-tests/.openspec.yaml b/openspec/changes/client-capability-discovery-and-host-tests/.openspec.yaml new file mode 100644 index 00000000..fd79bfc5 --- /dev/null +++ b/openspec/changes/client-capability-discovery-and-host-tests/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-03-02 diff --git a/openspec/changes/client-capability-discovery-and-host-tests/design.md b/openspec/changes/client-capability-discovery-and-host-tests/design.md new file mode 100644 index 00000000..c7343673 --- /dev/null +++ b/openspec/changes/client-capability-discovery-and-host-tests/design.md @@ -0,0 +1,71 @@ +## Context + +`client/` 在 Slice C 之后已经具备了可写的本地 control plane,但 capability discovery 仍然缺位: + +- transport runtime 内部已经支持 `actions:list`,并返回当前注册的 canonical `resource:action` ids; +- CLI 宿主协议桥接目前只暴露 approvals / MCP / skills / status,未把 `actions:list` 暴露给外部宿主; +- 现有集成测试主要按功能面分段验证,还没有把 headless event envelope、control plane 和 capability discovery 作为统一协议面冻结。 + +Issue #135 的最后一片因此不需要再扩 transport 语义,而是要把已有 discovery surface 提升到 CLI 宿主协议面,并为协议稳定性建立联合回归。 + +## Goals / Non-Goals + +**Goals:** + +- 通过现有 `client-control-stdin.v1` 暴露显式 `actions:list` 能力发现。 +- 明确 v1 discovery baseline:显式请求、结构化响应、无 startup handshake。 +- 为宿主协议补齐 capability discovery happy path 与回归测试。 +- 把 Slice D 的设计选择回写到 canonical docs 与 feature evidence。 + +**Non-Goals:** + +- 本次不引入启动即发送的 capability handshake。 +- 本次不为 action discovery 设计 richer metadata schema。 +- 本次不引入新的控制通道(例如 loopback RPC / websocket)。 +- 本次不改变 Slice B / Slice C 已落地的 envelope schema。 + +## Decisions + +### Decision 1: v1 capability discovery 采用显式 `actions:list` + +- 宿主通过已存在的 `--control-stdin` 通道显式发送 `actions:list`。 +- CLI 不会在 session 启动时自动发送 discovery frame。 +- 这一选择避免了在 headless event envelope 与 control result 多路复用流上再引入第三类“隐式 handshake”启动帧。 + +### Decision 2: discovery payload 继续复用 transport canonical shape + +- `actions:list` 的返回结果继续使用现有 transport payload 形状:`{"actions": ["resource:action", ...]}`。 +- 首版只承诺 canonical action id 列表,不额外附带 capability metadata。 +- 返回动作必须与当前 session 真实可调用的 CLI host bridge surface 一致,而不是静态文档枚举。 + +### Decision 3: Slice D 把宿主协议作为联合回归面冻结 + +- 集成测试至少覆盖: + - headless event envelope 基线仍可稳定输出; + - `control-stdin` 在 `actions:list` 加入后不破坏现有 approvals / MCP / skills / status; + - capability discovery 结果可被宿主直接消费,无需解析 help 文本或启动 chatter。 +- 错误路径至少覆盖: + - 不支持的 action 仍返回结构化错误; + - 未请求 discovery 时不会出现 unsolicited startup handshake frame。 + +## Risks / Trade-offs + +- [Risk] `actions:list` 可能暴露 runtime 内部尚未桥接的 action id。 + → Mitigation: Slice D 需要明确 discovery 返回的是 CLI host bridge 当前 surface,而不是底层 transport 的全部潜在动作。 + +- [Risk] 把 startup handshake 推迟可能要求宿主多发一次 discovery 请求。 + → Mitigation: 显式请求比隐式帧更容易做多路复用和兼容控制,首版优先稳定性而不是减少一个往返。 + +- [Risk] 回归测试过度绑定当前 action 列表,降低未来扩展空间。 + → Mitigation: 测试以“至少包含 / error contract 稳定”为主,避免把列表顺序或未来扩展动作硬编码成脆弱断言。 + +## Migration Plan + +1. 在 canonical docs 中把 Slice D 设计基线收敛到显式 `actions:list`,并明确 startup handshake 延后。 +2. 在 CLI host bridge 中暴露 `actions:list`。 +3. 增加 capability discovery 与宿主协议联合回归测试。 +4. 回写 feature evidence、master TODO、review links 和最终归档记录。 + +## Open Questions + +- `actions:list` 是否应只返回 action id 列表,还是需要在后续 slice 中增加 category / mutability / docs link 等 metadata? diff --git a/openspec/changes/client-capability-discovery-and-host-tests/proposal.md b/openspec/changes/client-capability-discovery-and-host-tests/proposal.md new file mode 100644 index 00000000..bd1fd81c --- /dev/null +++ b/openspec/changes/client-capability-discovery-and-host-tests/proposal.md @@ -0,0 +1,39 @@ +## Why + +Slice C 已经让宿主可以通过 `--control-stdin` 对活跃 headless run 发送 approvals / MCP / skills / status 控制,但宿主仍然必须硬编码“当前 CLI 支持哪些动作”。Issue #135 剩余的协议缺口因此不再是控制写路径,而是显式能力发现与宿主级回归冻结。 + +当前 `main` 的剩余问题有两类: + +1. CLI 宿主协议面还没有暴露 `actions:list`,宿主无法在运行时查询当前 session 的 canonical action surface。 +2. headless event envelope、control-stdin 和 capability discovery 还没有被同一组宿主协议回归测试一起冻结,后续演进容易在一个面上修复时回退另一个面。 + +Slice D 收敛到两件事:把 `actions:list` 提升为宿主协议动作,并补齐宿主级协议回归测试。启动即发送的 capability handshake 不纳入这一版基线,避免在 stdout 多路复用流里额外引入隐式协议帧。 + +## What Changes + +- 为 `run/script --headless --control-stdin` 暴露显式 `actions:list` capability discovery。 +- 定义 Slice D 的 v1 discovery baseline:显式请求、结构化返回、无 unsolicited startup handshake。 +- 增加宿主协议集成测试,覆盖 headless event envelope、control plane 和 capability discovery 的联合回归面。 +- 回写 `client/DESIGN.md`、`client/README.md`、master TODO 和 feature evidence,作为实现前的 docs-first 基线。 + +## Capabilities + +### Modified Capabilities + +- `client-host-orchestration`: 把“planned capability discovery”推进为显式 `actions:list` 宿主协议动作,并补齐协议回归锚点。 + +## Impact + +- 影响文件: + - `client/main.py` + - `client/DESIGN.md` + - `client/README.md` + - `tests/unit/test_client_cli.py` + - `tests/integration/test_client_cli_flow.py` + - `docs/todos/2026-03-02_client_cli_host_orchestration_master_todo.md` + - `docs/features/client-capability-discovery-and-host-tests.md` + - `openspec/changes/client-capability-discovery-and-host-tests/**` +- 不包含: + - 启动即发送的 capability handshake + - 更丰富的 capability metadata schema(标签、权限、分类矩阵) + - 新的网络控制入口或 `--control-port` diff --git a/openspec/changes/client-capability-discovery-and-host-tests/specs/client-host-orchestration/spec.md b/openspec/changes/client-capability-discovery-and-host-tests/specs/client-host-orchestration/spec.md new file mode 100644 index 00000000..31a119b1 --- /dev/null +++ b/openspec/changes/client-capability-discovery-and-host-tests/specs/client-host-orchestration/spec.md @@ -0,0 +1,20 @@ +## MODIFIED Requirements + +### Requirement: Host capabilities are discoverable without hardcoded matrices +The system SHALL provide a deterministic capability discovery surface for host orchestration. + +- v1 capability discovery MUST be exposed as an explicit `actions:list` request over the structured local control plane. +- The discovery response MUST return the currently supported canonical action ids as structured data. +- v1 MUST NOT require an unsolicited startup handshake before a host can interact with the session. + +#### Scenario: Host queries supported actions over control plane +- **GIVEN** a host is attached to a running headless session through `--control-stdin` +- **WHEN** it sends action `actions:list` +- **THEN** the client returns a structured list of currently supported canonical action ids +- **AND** the host does not need to infer support by parsing help text or natural-language output + +#### Scenario: Startup does not emit unsolicited capability handshake +- **GIVEN** a host starts a headless session and has not sent a discovery request +- **WHEN** the session begins running +- **THEN** the client does not emit an unsolicited capability handshake frame +- **AND** capability discovery remains available through an explicit structured request diff --git a/openspec/changes/client-capability-discovery-and-host-tests/tasks.md b/openspec/changes/client-capability-discovery-and-host-tests/tasks.md new file mode 100644 index 00000000..65dddfc1 --- /dev/null +++ b/openspec/changes/client-capability-discovery-and-host-tests/tasks.md @@ -0,0 +1,15 @@ +## 1. Capability Discovery Bridge + +- [ ] 1.1 将 `actions:list` 暴露到 `run/script --headless --control-stdin` 的 host bridge。 +- [ ] 1.2 明确并验证 discovery 返回的是当前 CLI host protocol surface,而不是 unsolicited startup handshake。 + +## 2. Host Protocol Regression Coverage + +- [ ] 2.1 增加 `actions:list` 的宿主协议 happy path 集成测试。 +- [ ] 2.2 增加 capability discovery 与现有 approvals / MCP / skills / status 共存的回归测试。 +- [ ] 2.3 覆盖 discovery 相关 error branch 和“无 startup handshake”约束。 + +## 3. Docs And Evidence + +- [ ] 3.1 更新 `client/DESIGN.md` 与 `client/README.md`,锁定显式 discovery baseline 和 handshake 延后策略。 +- [ ] 3.2 回写 `docs/features/client-capability-discovery-and-host-tests.md`、master TODO 与 review/merge-gate evidence。 diff --git a/openspec/specs/client-host-orchestration/spec.md b/openspec/specs/client-host-orchestration/spec.md index 6fa7f695..168dd1b0 100644 --- a/openspec/specs/client-host-orchestration/spec.md +++ b/openspec/specs/client-host-orchestration/spec.md @@ -2,9 +2,7 @@ ## Purpose Define the stable host-orchestration contract for `client/`, including explicit mode separation, headless event semantics, the planned structured local control plane, and capability discovery boundaries. - ## Requirements - ### Requirement: Client host orchestration modes are explicitly separated The system SHALL distinguish between interactive CLI behavior, legacy automation JSON output, and host-orchestrated headless execution. @@ -55,8 +53,9 @@ The system SHALL emit a versioned event envelope for headless mode that is disti ### Requirement: Host control is provided through a structured local control plane The system SHALL provide a structured local control plane for host-orchestrated sessions. +- v1 MUST support a local `--control-stdin` entry for headless `run/script`. - The control plane MUST accept deterministic actions for approvals, MCP management, skills discovery, and session status. -- Control responses MUST use structured success/error payloads. +- Control responses MUST use structured success/error payloads with request correlation. - The control plane MUST preserve existing approval and action semantics rather than bypassing them. #### Scenario: Host grants approval through structured control @@ -65,6 +64,12 @@ The system SHALL provide a structured local control plane for host-orchestrated - **THEN** the client resolves the approval through the deterministic approval action path - **AND** the result is returned as a structured control response +#### Scenario: Unknown control action fails structurally +- **GIVEN** a host sends a control command with an unsupported action id +- **WHEN** the client validates the command frame +- **THEN** the client returns a structured error response +- **AND** it does not fall back to prompt-oriented or natural-language command parsing + ### Requirement: Host capabilities are discoverable without hardcoded matrices The system SHALL provide a deterministic capability discovery surface for host orchestration. @@ -76,3 +81,23 @@ The system SHALL provide a deterministic capability discovery surface for host o - **WHEN** it requests capability discovery - **THEN** the client returns a structured list of supported actions - **AND** the host does not need to infer support by parsing help text or natural-language output + +### Requirement: Control plane v1 reuses canonical action identifiers +The system SHALL expose control-plane actions using canonical stable identifiers. + +- MCP control in v1 MUST be limited to `mcp:list`, `mcp:reload`, and `mcp:show-tool`. +- CLI-only verbs without canonical actions, including `mcp:unload`, MUST NOT be advertised as v1 host protocol actions. +- Approvals and skills actions MUST reuse their existing `resource:action` identifiers. + +#### Scenario: Host reloads MCP providers through canonical action id +- **GIVEN** the host needs to refresh MCP provider paths for a running headless session +- **WHEN** it sends action `mcp:reload` through the control plane +- **THEN** the client reuses the current MCP reload runtime path +- **AND** the response is returned as a structured control result + +#### Scenario: Host requests CLI session status +- **GIVEN** a headless session is running under the CLI host protocol +- **WHEN** the host sends action `status:get` +- **THEN** the client returns a structured snapshot of current session state +- **AND** the response is correlated to the request id +