docs: add continuous execution plan

This commit is contained in:
zhaoyilun
2026-07-10 19:44:35 +08:00
parent 93112d6d99
commit 9eb7f382cc
2 changed files with 914 additions and 3 deletions

View File

@@ -58,9 +58,11 @@ N13/N14/N15 are pre-business validation results. They can help identify UI eleme
## Current loop
Current loop: `R6e sandbox-only send connector shell and idempotency audit hardening implemented; next R6f fake/sandbox connector contract or corrected full evidence intake`.
Current loop: `Planning gate complete for continuous execution; awaiting business review before starting R6f`.
Plan file: `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`.
Active continuous execution plan: `docs/superpowers/plans/2026-07-10-r6f-r14-continuous-execution-plan.md`.
Previous roadmap file: `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`.
Loop rule:
@@ -222,4 +224,10 @@ R6e sandbox-only send connector shell and idempotency audit hardening is complet
- Duplicate same-key/same-target/same-content preview calls return structured metadata with `duplicate_detected=true` and no side effects.
- Same idempotency key reused for different target/content returns `send_status="blocked"` with `conflict_detected=true` and no side effects.
- `scripts\verify-go-mcp.ps1` and `cmd\isphere-capability-smoke` use fresh per-run idempotency state to keep repeatable smoke deterministic.
- Next node: R6f fake/sandbox connector contract or corrected full evidence intake.
- Next node after user approval: R6f fake/sandbox connector contract.
Continuous execution plan R6f-R14 is drafted and awaiting user review:
- Plan file: `docs/superpowers/plans/2026-07-10-r6f-r14-continuous-execution-plan.md`.
- Scope: 15 ordered rounds covering send-message connector/gate hardening, send-file preview/idempotency/package, receive-file download preview, receive-message reconciliation, end-to-end business smoke, and release-candidate report.
- Execution rule after approval: one round at a time, status-card update, verification, commit, push, then continue automatically until an evidence-only blocker requires user action.

View File

@@ -0,0 +1,903 @@
# R6f-R14 Continuous Execution Plan Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 用 15 个连续轮次把 iSphere MCP 的四个业务目标推进到可验收状态:搜索联系人、搜索群组、收发消息、收发文件;如果生产写入证据不足,则产出明确阻断和下一包采集材料。
**Architecture:** Go MCP server 是唯一对数字员工暴露的产品面C# WinHelper、MsgLibReadSidecar、录制包和本地脚本只作为证据采集、只读解析、或受控连接器边界。读能力优先走 PacketReader/MsgLib 已验证源;写能力先建立 fake/sandbox connector contract、审计/idempotency、生产门禁再根据在线沙箱证据决定是否开启真实连接器。
**Tech Stack:** Go 1.23.4, `github.com/modelcontextprotocol/go-sdk`, PowerShell, x86 .NET Framework sidecar, C# WinHelper, Windows iSphere/IMPlatformClient evidence packages.
## Global Constraints
- Repository root: `E:\coding\codex\isphere-ai-bridge`.
- Remote name: `gitea`; active branch: `main` unless the user explicitly asks for a new branch.
- Code search rule from `AGENTS.md`: use `git ls-files`, `ag`, `grep -R`, or PowerShell file commands; do not use `rg`.
- Local machine cannot currently log in to iSphere; do not attempt local live login as an acceptance gate.
- Production `isphere_send_message`, `isphere_send_file`, and real file download stay blocked unless the corresponding evidence gate passes in this plan.
- Committed docs and script output must not include raw message body, raw file content, credentials, or unredacted local operator paths.
- Standard deterministic smoke must keep optional real MsgLib env cleared unless a script name explicitly says it is an optional real-evidence smoke.
- Every round ends with status-card update, `git diff --check`, `go test ./...`, `go build ./cmd/isphere-mcp`, relevant PowerShell smoke, commit, and push.
- Generated packages and run outputs remain under ignored `runs/`; commit only package builders, validators, docs, and source code.
---
## Current Starting Point
- `isphere_search_contacts`: core search exists, with deterministic ranking/de-dup and optional MsgLib enrichment.
- `isphere_search_groups`: core search exists, with deterministic ranking/de-dup and optional MsgLib enrichment.
- `isphere_receive_messages`: PacketReader default exists; explicit `source_preference="msglib_readonly"` exists; default merge/reconciliation is not yet enabled.
- `isphere_receive_files`: list mode exists; real download mapping is blocked by missing cache/download evidence.
- `isphere_send_message`: preview/dry-run exists; production remains blocked; R6e added sandbox-only connector metadata and idempotency state.
- `isphere_send_file`: not yet registered as a product tool; file upload evidence exists only as UIA/menu and DLL metadata, not as a send connector.
## Continuous Execution Rules After Approval
1. Execute exactly one round at a time in the order below.
2. At the start of each round, mark that round as `in_progress` in `docs/current-status-card.md`.
3. Use TDD for code rounds: add failing tests first, run the focused failing test, implement the minimum, then run the full verification gate.
4. If a round is blocked only by missing online evidence, write the blocker into `docs/source-discovery/...`, keep production behavior blocked, and move to the next local-safe round.
5. If all remaining rounds require missing online evidence, stop and ask the user for the exact returned package listed by the most recent package builder.
6. After every round, commit and push only the intended source/docs/scripts:
```powershell
git status --short
git diff --check
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git status --short
Write-Host "Use the concrete git add and git commit commands listed inside the active round below."
git push gitea main
```
## Planned File Structure
- `internal/tools/isphere_send_message.go`: existing MCP tool; keeps request/response contract, idempotency use, audit use, and production gate decisions.
- `internal/tools/send_message_connector.go`: new focused connector interface, fake connector result types, and connector error mapping for message send.
- `internal/tools/send_message_gate.go`: new production gate loader and reason-code formatter for message send.
- `internal/tools/isphere_send_message_test.go`: message send tool contract tests for preview, fake accepted/failed, duplicate, conflict, gate blocked.
- `internal/tools/isphere_send_file.go`: new file-send preview MCP tool with allowed-directory validation and SHA256/size metadata.
- `internal/tools/isphere_send_file_test.go`: file-send preview, blocked production, path validation, idempotency tests.
- `internal/mcpserver/server.go` and `internal/mcpserver/server_test.go`: tool registration count and name coverage.
- `scripts/package-send-sandbox-gate.ps1`: existing package builder; will get v2 manifest/checklist coverage.
- `scripts/validate-returned-send-sandbox-package.ps1`: existing validator; will get strict v2 pass/fail fields.
- `scripts/package-send-file-sandbox-gate.ps1`: new package builder for upload/file-transfer evidence.
- `scripts/verify-file-cache-mapping.ps1`: existing diagnostic; will get v2 cache-root and fingerprint matching.
- `scripts/verify-business-goals-smoke.ps1`: new end-to-end MCP business smoke.
- `docs/current-status-card.md`: source of truth for active loop, blockers, and next round.
- `docs/go-mcp-runbook.md`: operator-facing run and env instructions.
- `docs/source-discovery/*.md`: evidence notes and decisions.
---
## Round Queue
### R6f: Fake/sandbox send connector contract
**Purpose:** 在不接真实发送入口的前提下把发送连接器接口、fake accepted、fake failed、审计映射、idempotency 映射一次性定型。
**Files:**
- Create: `internal/tools/send_message_connector.go`
- Modify: `internal/tools/isphere_send_message.go`
- Modify: `internal/tools/isphere_send_message_test.go`
- Modify: `docs/current-status-card.md`
- Modify: `docs/go-mcp-runbook.md`
**Interfaces:**
- Produces: `type SendMessageConnector interface { ExecuteSendMessage(context.Context, SendMessageConnectorRequest) (SendMessageConnectorResult, error) }`
- Produces: `type SendMessageConnectorRequest struct { TargetType string; TargetID string; TargetRef string; ContentSHA256 string; ContentLength int; IdempotencyKeySHA256 string; ExecutionMode string }`
- Produces: `type SendMessageConnectorResult struct { Accepted bool; Status string; AckRef string; ErrorCode string; ErrorMessage string; ConnectorMode string }`
- Produces: `RegisterISphereSendMessageToolWithStateAndConnector(server, auditStore, idempotencyStore, connector)` for tests only.
- [ ] **Step 1: Write failing fake-accepted test**
Add `TestISphereSendMessageFakeConnectorAcceptedAudit` to `internal/tools/isphere_send_message_test.go`:
```go
func TestISphereSendMessageFakeConnectorAcceptedAudit(t *testing.T) {
connector := fakeSendMessageConnector{result: SendMessageConnectorResult{
Accepted: true, Status: "accepted", AckRef: "fake-ack-1", ConnectorMode: "fake",
}}
response := callSendMessageWithInjectedConnector(t, connector, map[string]any{
"target_type": "contact", "target_id": "u1", "content_text": "hello",
"content_sha256": sha256Hex("hello"), "idempotency_key": "idem-1", "execution_mode": "production",
})
assertToolBool(t, response, "ok", true)
assertToolString(t, response, "send_status", "accepted")
assertToolString(t, response, "connector_mode", "fake")
assertAuditOmits(t, response, []string{"hello", "idem-1"})
}
```
Run:
```powershell
go test ./internal/tools -run TestISphereSendMessageFakeConnectorAcceptedAudit -v
```
Expected before implementation: FAIL because `RegisterISphereSendMessageToolWithStateAndConnector` and connector types do not exist.
- [ ] **Step 2: Write failing fake-failed test**
Add `TestISphereSendMessageFakeConnectorFailureAudit` asserting `ok=false`, `send_status="failed"`, `error_code="fake_rejected"`, and `side_effect_flags.real_send_attempted=false`.
- [ ] **Step 3: Implement connector contract**
Create `internal/tools/send_message_connector.go` with the interface, request/result structs, and result normalization. Keep the fake connector in the test file.
- [ ] **Step 4: Wire injected connector only for tests**
Modify `internal/tools/isphere_send_message.go` so default `RegisterISphereSendMessageTool` still blocks production, while `RegisterISphereSendMessageToolWithStateAndConnector` can execute a fake connector in tests.
- [ ] **Step 5: Verify and commit**
```powershell
git diff --check
go test ./internal/tools -run "TestISphereSendMessageFakeConnector|TestISphereSendMessageIdempotency" -v
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add internal\tools\send_message_connector.go internal\tools\isphere_send_message.go internal\tools\isphere_send_message_test.go docs\current-status-card.md docs\go-mcp-runbook.md
git commit -m "feat: add fake send connector contract"
git push gitea main
```
**Acceptance gate:** Default MCP still reports `production_send_enabled=false`; fake connector is reachable only through test injection.
---
### R6g: Send audit and idempotency replay diagnostics
**Purpose:** 让后续连接器接入前可以独立验证审计、重复请求、冲突请求、重放读取,不依赖登录环境。
**Files:**
- Create: `scripts/verify-send-audit-idempotency.ps1`
- Create: `scripts/test-verify-send-audit-idempotency.ps1`
- Modify: `internal/tools/isphere_send_message_test.go`
- Modify: `docs/go-mcp-runbook.md`
- Modify: `docs/current-status-card.md`
**Interfaces:**
- Consumes: `ISPHERE_SEND_AUDIT_PATH`, `ISPHERE_SEND_IDEMPOTENCY_PATH`.
- Produces script output keys: `audit_records`, `idempotency_records`, `duplicate_detected`, `conflict_detected`, `raw_body_present`, `raw_idempotency_key_present`.
- [ ] **Step 1: Write fixture test script**
`scripts/test-verify-send-audit-idempotency.ps1` creates temporary JSONL audit/idempotency files with one normal record, one duplicate, and one conflict.
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\test-verify-send-audit-idempotency.ps1
```
Expected before implementation: FAIL because `verify-send-audit-idempotency.ps1` does not exist.
- [ ] **Step 2: Implement diagnostic script**
`scripts/verify-send-audit-idempotency.ps1` accepts:
```powershell
param(
[Parameter(Mandatory=$true)][string]$AuditPath,
[Parameter(Mandatory=$true)][string]$IdempotencyPath
)
```
It prints sanitized JSON with counts and booleans only; it exits non-zero if raw `content_text` or raw `idempotency_key` appears.
- [ ] **Step 3: Add tool-level test for audit redaction regression**
Add `TestISphereSendMessageAuditRedactionIsStable` asserting JSONL audit files do not contain the submitted message body or raw idempotency key.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\test-verify-send-audit-idempotency.ps1
go test ./internal/tools -run TestISphereSendMessageAuditRedactionIsStable -v
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add scripts\verify-send-audit-idempotency.ps1 scripts\test-verify-send-audit-idempotency.ps1 internal\tools\isphere_send_message_test.go docs\go-mcp-runbook.md docs\current-status-card.md
git commit -m "test: add send audit idempotency diagnostics"
git push gitea main
```
**Acceptance gate:** Diagnostics can prove audit/idempotency shape without opening iSphere.
---
### R6h: Central production gate policy for send message
**Purpose:** 把“为什么不能生产发送”变成单独 gate 对象,避免后续连接器代码散落硬编码。
**Files:**
- Create: `internal/tools/send_message_gate.go`
- Create: `internal/tools/send_message_gate_test.go`
- Modify: `internal/tools/isphere_send_message.go`
- Modify: `docs/current-status-card.md`
- Modify: `docs/go-mcp-runbook.md`
**Interfaces:**
- Produces: `type SendMessageGatePolicy struct { ProductionAllowed bool; ReasonCode string; ReasonMessage string; EvidenceGatePass bool; ConnectorConfigured bool }`
- Produces: `LoadSendMessageGatePolicy(env map[string]string, evidenceGatePass bool, connectorConfigured bool) SendMessageGatePolicy`.
- Valid reason codes: `send_evidence_missing`, `send_connector_missing`, `send_disabled_by_default`, `send_gate_passed`.
- [ ] **Step 1: Write table tests**
Create `TestLoadSendMessageGatePolicy` with cases for default disabled, env set but evidence missing, evidence pass but connector missing, and all pass.
```powershell
go test ./internal/tools -run TestLoadSendMessageGatePolicy -v
```
Expected before implementation: FAIL because the gate type does not exist.
- [ ] **Step 2: Implement gate policy**
Create `send_message_gate.go` with the exact type/function and reason-code order from the test.
- [ ] **Step 3: Route blocked production through the gate**
Modify `isphere_send_message.go` so blocked production responses include `gate_reason_code` and `gate_reason_message` from `SendMessageGatePolicy`.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
go test ./internal/tools -run TestLoadSendMessageGatePolicy -v
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add internal\tools\send_message_gate.go internal\tools\send_message_gate_test.go internal\tools\isphere_send_message.go docs\current-status-card.md docs\go-mcp-runbook.md
git commit -m "feat: centralize send message production gate"
git push gitea main
```
**Acceptance gate:** The default runtime stays blocked, but the response explains the exact reason in machine-readable fields.
---
### R6i: B-route connector adapter shell
**Purpose:** 为后续 IMPlatformClient/B-route sidecar 接入定义请求/响应 JSON 边界,但本轮不执行真实发送。
**Files:**
- Create: `internal/tools/send_message_broute_adapter.go`
- Create: `internal/tools/send_message_broute_adapter_test.go`
- Modify: `docs/source-discovery/2026-07-10-send-connector-preflight.md`
- Modify: `docs/current-status-card.md`
**Interfaces:**
- Produces: `type BRouteSendAdapterConfig struct { SidecarPath string; TimeoutSeconds int; Mode string }`.
- Produces: `func NewBRouteSendMessageConnector(config BRouteSendAdapterConfig) SendMessageConnector`.
- In this round, accepted modes are `disabled` and `dry_run_contract`; any other mode returns `broute_mode_blocked`.
- [ ] **Step 1: Write disabled-mode test**
```go
func TestBRouteSendMessageConnectorDisabledMode(t *testing.T) {
connector := NewBRouteSendMessageConnector(BRouteSendAdapterConfig{Mode:"disabled"})
result, err := connector.ExecuteSendMessage(context.Background(), SendMessageConnectorRequest{
TargetType:"contact", TargetID:"u1", ContentSHA256:"abc", IdempotencyKeySHA256:"idem",
})
if err == nil { t.Fatalf("expected disabled error") }
if result.ErrorCode != "broute_mode_blocked" { t.Fatalf("unexpected error code: %s", result.ErrorCode) }
}
```
- [ ] **Step 2: Write dry-run contract test**
Add `TestBRouteSendMessageConnectorDryRunContract` asserting no external process starts and result contains `ConnectorMode="broute-dry-run-contract"` and `Accepted=false`.
- [ ] **Step 3: Implement adapter shell**
Implement a connector that validates request fields and returns contract-shaped blocked/dry-run results only. Do not call `Start-Process`, do not load DLLs, do not click/type.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
go test ./internal/tools -run TestBRouteSendMessageConnector -v
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add internal\tools\send_message_broute_adapter.go internal\tools\send_message_broute_adapter_test.go docs\source-discovery\2026-07-10-send-connector-preflight.md docs\current-status-card.md
git commit -m "feat: add b-route send adapter shell"
git push gitea main
```
**Acceptance gate:** B-route contract exists; no real send entrypoint is invoked.
---
### R6j: Online sandbox-send recording package v2
**Purpose:** 修正 R6d 缺失项,一次性要求 before/after recorder、人工时间戳、ack/sent-record、重复发送确认减少用户反复跑包。
**Files:**
- Modify: `scripts/package-send-sandbox-gate.ps1`
- Modify: `scripts/verify-send-sandbox-gate-package.ps1`
- Modify: `scripts/validate-returned-send-sandbox-package.ps1`
- Modify: `docs/source-discovery/2026-07-10-send-sandbox-gate.md`
- Modify: `docs/current-status-card.md`
**Required returned fields:**
- `operator_started_at_local`
- `operator_clicked_send_at_local`
- `operator_observed_success_at_local`
- `before_recorder_present=true`
- `after_recorder_present=true`
- `success_ack_or_sent_record_present=true`
- `duplicate_second_send_attempted=false`
- [ ] **Step 1: Add v2 manifest assertions to package verifier**
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-send-sandbox-gate-package.ps1
```
Expected before implementation: FAIL because v2 required returned fields are not enforced.
- [ ] **Step 2: Add v2 checklist to package builder**
Update package contents to include `RETURN-CHECKLIST-V2.md`, `SANDBOX-SEND-INPUTS.schema.json`, and a stricter `CREATE-RETURN-ZIP.ps1` that refuses to package if after-recorder output is missing.
- [ ] **Step 3: Add validator strict mode**
Add parameter:
```powershell
param([string]$ZipPath, [switch]$StrictV2)
```
`-StrictV2` exits non-zero if any required returned field is absent.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-send-sandbox-gate-package.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\test-validate-returned-send-sandbox-package.ps1
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add scripts\package-send-sandbox-gate.ps1 scripts\verify-send-sandbox-gate-package.ps1 scripts\validate-returned-send-sandbox-package.ps1 scripts\test-validate-returned-send-sandbox-package.ps1 docs\source-discovery\2026-07-10-send-sandbox-gate.md docs\current-status-card.md
git commit -m "chore: harden send sandbox evidence package v2"
git push gitea main
```
**Acceptance gate:** A generated package can no longer omit the R6d missing after-recorder/timestamp fields.
---
### R6k: Returned sandbox evidence intake v2
**Purpose:** 自动检查 Downloads 是否已有新返回包;有则按 strict v2 intake没则写清楚生产发送仍阻断并继续本地可推进工作。
**Files:**
- Create or modify: `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis-v2.md`
- Modify: `docs/current-status-card.md`
- Modify: `docs/source-discovery/capability-source-matrix.md`
- [ ] **Step 1: Look for a new returned package**
```powershell
Get-ChildItem C:\Users\zhaoy\Downloads -Filter *.zip | Sort-Object LastWriteTime -Descending | Select-Object -First 10 FullName,LastWriteTime,Length
```
Prefer a zip whose contents include `SANDBOX-SEND-INPUTS.json`, after-recorder output, and return manifest.
- [ ] **Step 2A: If a new candidate exists, validate strict v2**
```powershell
$candidate = Get-ChildItem C:\Users\zhaoy\Downloads -Filter *.zip | Sort-Object LastWriteTime -Descending | Select-Object -First 1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\validate-returned-send-sandbox-package.ps1 -ZipPath $candidate.FullName -StrictV2
```
Expected pass output must include `r6d_gate_pass=true` and `strict_v2_pass=true` before production send can move beyond blocked state.
- [ ] **Step 2B: If no candidate exists, document no-intake state**
Create `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis-v2.md` stating no strict-v2 returned package was found, `r6d_gate_pass=false`, and production `isphere_send_message` remains blocked.
- [ ] **Step 3: Verify and commit**
```powershell
git diff --check
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add docs\source-discovery\2026-07-10-returned-send-sandbox-analysis-v2.md docs\source-discovery\capability-source-matrix.md docs\current-status-card.md
git commit -m "docs: record send sandbox evidence v2 intake"
git push gitea main
```
**Acceptance gate:** The status card explicitly says whether production send is still blocked or evidence-gated for the next round.
---
### R6l: Send-message production path gate closure
**Purpose:** 根据 R6k 决策收口:如果 strict v2 通过,只打开 gated fake/sandbox connector path如果没通过保持生产阻断并让响应/文档完全一致。
**Files:**
- Modify: `internal/tools/isphere_send_message.go`
- Modify: `internal/tools/isphere_send_message_test.go`
- Modify: `scripts/verify-go-mcp.ps1`
- Modify: `docs/go-mcp-runbook.md`
- Modify: `docs/current-status-card.md`
**Branching rule:**
- If `r6d_gate_pass=false`: add regression tests proving production remains blocked with `gate_reason_code="send_evidence_missing"`.
- If `r6d_gate_pass=true`: add tests that production can only run through an injected connector with `ISPHERE_SEND_PRODUCTION_ENABLED=1`, evidence gate pass, and idempotency key present.
- [ ] **Step 1: Write default-blocked regression test**
Add `TestISphereSendMessageProductionGateBlockedWithoutStrictEvidence`, asserting `ok=false`, `send_status="blocked"`, `gate_reason_code` is not empty, `production_send_enabled=false`, and `real_send_attempted=false`.
- [ ] **Step 2: Write gated fake-production test if strict v2 passed**
Add `TestISphereSendMessageProductionRequiresEvidenceAndConnector`. If strict v2 did not pass, keep this test skipped with explicit skip reason: `strict v2 send evidence not present in this repository state`.
- [ ] **Step 3: Update verification smoke**
`verify-go-mcp.ps1` must continue printing `production_send_enabled=false` on the default path unless strict evidence and env gate are configured.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
go test ./internal/tools -run "TestISphereSendMessageProduction" -v
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add internal\tools\isphere_send_message.go internal\tools\isphere_send_message_test.go scripts\verify-go-mcp.ps1 docs\go-mcp-runbook.md docs\current-status-card.md
git commit -m "feat: close send message production gate behavior"
git push gitea main
```
**Acceptance gate:** No ambiguous state remains: send-message is either gated by validated evidence or explicitly blocked with a machine-readable reason.
---
### R7: `isphere_send_file` preview tool
**Purpose:** 补齐“发文件”的 MCP 产品面,先支持 preview/dry-run校验目标、文件存在性、允许目录、大小、SHA256不上传不点击。
**Files:**
- Create: `internal/tools/isphere_send_file.go`
- Create: `internal/tools/isphere_send_file_test.go`
- Modify: `internal/mcpserver/server.go`
- Modify: `internal/mcpserver/server_test.go`
- Modify: `scripts/verify-go-mcp.ps1`
- Modify: `cmd/isphere-capability-smoke/main.go`
- Modify: `docs/go-mcp-runbook.md`
- Modify: `docs/current-status-card.md`
**Interfaces:**
- Tool name: `isphere_send_file`.
- Args: `target_type`, `target_id`, `file_path`, `file_sha256`, `idempotency_key`, `execution_mode`, `preview`.
- Env: `ISPHERE_SEND_FILE_ALLOWED_DIR` required for previewing real local file paths.
- Response fields: `ok`, `send_status`, `file_sha256`, `file_size_bytes`, `target_ref`, `production_send_enabled`, `side_effect_flags`.
- [ ] **Step 1: Write file-preview test**
Add `TestISphereSendFilePreviewComputesHashAndSize`, creating a temp allowed directory and `hello.txt`, then asserting preview returns `ok=true`, `send_status="planned"`, `file_size_bytes=5`, and `real_send_attempted=false`.
- [ ] **Step 2: Write path rejection test**
Add `TestISphereSendFileRejectsPathOutsideAllowedDir` asserting paths outside `ISPHERE_SEND_FILE_ALLOWED_DIR` return `ok=false` and `send_status="blocked"`.
- [ ] **Step 3: Implement tool and registration**
Register the tenth MCP tool. Production execution returns blocked with `production_send_enabled=false`.
- [ ] **Step 4: Update smoke scripts**
`verify-go-mcp.ps1` and `isphere-capability-smoke` must assert tool count includes `isphere_send_file`, preview works with a temp fixture file, and production remains blocked.
- [ ] **Step 5: Verify and commit**
```powershell
git diff --check
go test ./internal/tools -run TestISphereSendFile -v
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add internal\tools\isphere_send_file.go internal\tools\isphere_send_file_test.go internal\mcpserver\server.go internal\mcpserver\server_test.go scripts\verify-go-mcp.ps1 cmd\isphere-capability-smoke\main.go docs\go-mcp-runbook.md docs\current-status-card.md
git commit -m "feat: add send file preview tool"
git push gitea main
```
**Acceptance gate:** 数字员工能看到“发文件”工具,但默认路径只做 preview不上传。
---
### R8: Send-file idempotency and audit hardening
**Purpose:** 把发文件的审计/idempotency 与发消息保持一致,后续接上传连接器时不再重做控制面。
**Files:**
- Modify: `internal/tools/isphere_send_file.go`
- Modify: `internal/tools/isphere_send_file_test.go`
- Modify: `scripts/verify-go-mcp.ps1`
- Modify: `docs/go-mcp-runbook.md`
- Modify: `docs/current-status-card.md`
**Interfaces:**
- Env: `ISPHERE_SEND_FILE_AUDIT_PATH`.
- Env: `ISPHERE_SEND_FILE_IDEMPOTENCY_PATH`.
- Duplicate same target/file/idempotency returns `duplicate_detected=true` with no second send.
- Reusing the same idempotency key for a different target or file hash returns `conflict_detected=true`.
- [ ] **Step 1: Write duplicate test**
Add `TestISphereSendFileDuplicateIdempotencyDetected`: same target, same file hash, same idempotency key called twice; second response has `duplicate_detected=true` and `real_send_attempted=false`.
- [ ] **Step 2: Write conflict test**
Add `TestISphereSendFileIdempotencyConflictBlocked`: same idempotency key with a different file hash returns `send_status="blocked"` and `conflict_detected=true`.
- [ ] **Step 3: Implement audit and idempotency state**
Reuse the message idempotency pattern or extract a shared small helper only if it reduces duplication without changing message behavior.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
go test ./internal/tools -run TestISphereSendFile -v
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add internal\tools\isphere_send_file.go internal\tools\isphere_send_file_test.go scripts\verify-go-mcp.ps1 docs\go-mcp-runbook.md docs\current-status-card.md
git commit -m "feat: harden send file idempotency audit"
git push gitea main
```
**Acceptance gate:** File upload remains blocked, but duplicate/conflict behavior is deterministic.
---
### R9: Send-file upload evidence package
**Purpose:** 为“真实发文件”采集一次性材料:文件菜单、上传路径、大小限制、发送确认、上传/文件传输 DLL 状态。
**Files:**
- Create: `scripts/package-send-file-sandbox-gate.ps1`
- Create: `scripts/verify-send-file-sandbox-gate-package.ps1`
- Create: `scripts/validate-returned-send-file-sandbox-package.ps1`
- Create: `docs/source-discovery/2026-07-10-send-file-sandbox-gate.md`
- Modify: `docs/current-status-card.md`
**Required package contents:**
- `RUN-FILE-RECORDING-SUITE.bat`
- `FILE-SEND-INPUTS.json`
- `RETURN-FILE-CHECKLIST.md`
- `CREATE-FILE-RETURN-ZIP.ps1`
- WinHelper recorder executable and dependencies
- Capability smoke executable if already built
- [ ] **Step 1: Build verifier first**
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-send-file-sandbox-gate-package.ps1
```
Expected before implementation: FAIL because package builder does not exist.
- [ ] **Step 2: Implement package builder**
The builder outputs `runs/send-file-sandbox-gate-package.zip` and includes only executables/scripts/docs needed by an online operator.
- [ ] **Step 3: Implement returned-package validator**
Validator requires file send attempt timestamps, before/after recorder output, file SHA256, observed upload/sent status, and duplicate-send confirmation.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-send-file-sandbox-gate-package.ps1
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add scripts\package-send-file-sandbox-gate.ps1 scripts\verify-send-file-sandbox-gate-package.ps1 scripts\validate-returned-send-file-sandbox-package.ps1 docs\source-discovery\2026-07-10-send-file-sandbox-gate.md docs\current-status-card.md
git commit -m "chore: add send file sandbox evidence package"
git push gitea main
```
**Acceptance gate:** 用户可以把一个包带到可登录环境采集发文件证据。
---
### R10: Receive-file download resolver v2 diagnostic
**Purpose:** 继续推进“收文件”的下载/落地问题,验证 MsgLib 记录、cache/archive 文件、文件名/source-id/大小/时间窗口是否能形成可信映射。
**Files:**
- Modify: `scripts/verify-file-cache-mapping.ps1`
- Create: `scripts/test-verify-file-cache-mapping.ps1`
- Create: `docs/source-discovery/2026-07-10-file-download-mapping-v2.md`
- Modify: `docs/current-status-card.md`
**Diagnostic inputs:**
- `-CacheRoot` accepts an absolute operator-local cache root selected at runtime; fixture tests create the cache root under `$env:TEMP`.
- `-MsgLibDb` and `-SQLiteDll` accept copied DB/runtime paths when real copied DB is available; fixture tests do not require real DB files.
- `-SanitizedOutputPath` writes committed-safe JSON summary to a caller-selected output file.
- [ ] **Step 1: Add fixture test for resolver scoring**
Fixture contains three DB-like file records and four cache-like file entries. Expected scoring:
```text
exact filename + exact size + close timestamp => score 100
exact size + source id in name/ref => score 80
filename only => score 40 and not accepted
```
- [ ] **Step 2: Implement scoring and sanitized output**
Output fields: `records_checked`, `cache_candidates_checked`, `accepted_matches`, `ambiguous_matches`, `raw_paths_printed=false`, `file_contents_read=false`.
- [ ] **Step 3: Write decision note**
`docs/source-discovery/2026-07-10-file-download-mapping-v2.md` records whether accepted matches exist. If not, download remains blocked and UI/client download connector becomes the next route.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\test-verify-file-cache-mapping.ps1
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add scripts\verify-file-cache-mapping.ps1 scripts\test-verify-file-cache-mapping.ps1 docs\source-discovery\2026-07-10-file-download-mapping-v2.md docs\current-status-card.md
git commit -m "test: add file download resolver v2 diagnostic"
git push gitea main
```
**Acceptance gate:** 文件下载要么得到可实现映射,要么得到明确阻断证据。
---
### R11: Receive-file download preview contract
**Purpose:** 即使真实下载还不能做,也让 `isphere_receive_files` 对 download 请求返回可机器解析的 preview/blocked 结果,而不是只有泛化拒绝。
**Files:**
- Modify: `internal/tools/isphere_receive_files.go`
- Modify: `internal/tools/isphere_receive_files_test.go`
- Modify: `scripts/verify-go-mcp.ps1`
- Modify: `docs/go-mcp-runbook.md`
- Modify: `docs/current-status-card.md`
**Interfaces:**
- Args accepted: `mode="download"`, `preview=true`, `file_ref`, `output_dir`.
- If resolver lacks accepted mapping, response: `ok=false`, `download_status="blocked"`, `blocked_reason_code="file_cache_mapping_missing"`.
- If resolver has accepted mapping in fixture tests, response: `ok=true`, `download_status="planned"`, no file copy during preview.
- [ ] **Step 1: Write blocked-preview test**
Add `TestISphereReceiveFilesDownloadPreviewBlockedWithoutMapping`, asserting `blocked_reason_code="file_cache_mapping_missing"` and `file_contents_read=false`.
- [ ] **Step 2: Write planned-preview fixture test**
Add `TestISphereReceiveFilesDownloadPreviewPlannedWithFixtureMapping`, using an injected fixture resolver and asserting `download_status="planned"`, `file_contents_read=false`, and `file_copied=false`.
- [ ] **Step 3: Implement preview contract**
Keep non-preview real download blocked unless R10 accepted mapping exists and a separate production-copy gate is added.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
go test ./internal/tools -run TestISphereReceiveFilesDownloadPreview -v
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add internal\tools\isphere_receive_files.go internal\tools\isphere_receive_files_test.go scripts\verify-go-mcp.ps1 docs\go-mcp-runbook.md docs\current-status-card.md
git commit -m "feat: add receive file download preview contract"
git push gitea main
```
**Acceptance gate:** 数字员工可以理解“为什么现在不能下载”,并在有映射时得到 planned preview。
---
### R12: Receive-message reconciliation helper
**Purpose:** 给收消息建立 PacketReader/MsgLib 对账能力,用于后续提升默认 `auto` 的可信度,但本轮不改变默认路由。
**Files:**
- Create: `internal/isphere/message_reconciliation.go`
- Create: `internal/isphere/message_reconciliation_test.go`
- Create: `scripts/verify-receive-source-reconciliation.ps1`
- Modify: `docs/source-discovery/2026-07-10-receive-message-reconciliation-precheck.md`
- Modify: `docs/current-status-card.md`
**Interfaces:**
- Produces: `type MessageReconciliationCandidate struct { Source string; MessageID string; ConversationID string; SenderID string; TimestampUnixMilli int64; BodyPresent bool; AttachmentPresent bool }`.
- Produces: `func ReconcileMessageSources(left, right []MessageReconciliationCandidate) MessageReconciliationSummary`.
- Summary fields: `strong_matches`, `medium_matches`, `unmatched_left`, `unmatched_right`, `auto_merge_recommended`.
- [ ] **Step 1: Write reconciliation tests**
Add `TestReconcileMessageSourcesStrongAndMediumMatches`: same message id is strong; same conversation/sender and timestamp within 3000ms is medium; auto merge remains false until a strong-ratio threshold is met.
- [ ] **Step 2: Implement pure Go helper**
No DB/log IO in the helper. It only compares sanitized candidates.
- [ ] **Step 3: Add script wrapper**
Script runs against fixture JSON first; optional real evidence mode prints counts and booleans only.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
go test ./internal/isphere -run TestReconcileMessageSources -v
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-receive-source-reconciliation.ps1 -UseFixture
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add internal\isphere\message_reconciliation.go internal\isphere\message_reconciliation_test.go scripts\verify-receive-source-reconciliation.ps1 docs\source-discovery\2026-07-10-receive-message-reconciliation-precheck.md docs\current-status-card.md
git commit -m "feat: add receive message reconciliation helper"
git push gitea main
```
**Acceptance gate:** 对账能力存在,但默认 receive routing 不改变。
---
### R13: End-to-end business goals smoke
**Purpose:** 用一个脚本从数字员工视角验证四个业务目标的当前状态:能搜联系人、搜群、收消息、列文件、预览发消息、预览发文件,并列出阻断项。
**Files:**
- Create: `scripts/verify-business-goals-smoke.ps1`
- Create: `docs/reports/2026-07-10-business-goals-smoke.md`
- Modify: `docs/current-status-card.md`
- Modify: `docs/go-mcp-runbook.md`
**Output keys:**
- `search_contacts_ready`
- `search_groups_ready`
- `receive_messages_ready`
- `send_message_preview_ready`
- `send_message_production_ready`
- `receive_files_list_ready`
- `receive_files_download_ready`
- `send_file_preview_ready`
- `send_file_production_ready`
- `remaining_business_blockers`
- [ ] **Step 1: Implement fixture-backed smoke**
The script starts `cmd/isphere-mcp` with temp fixture env and calls MCP requests using the same pattern as `verify-go-mcp.ps1`.
- [ ] **Step 2: Assert business booleans**
Default expected state after R12:
```text
search_contacts_ready=true
search_groups_ready=true
receive_messages_ready=true
send_message_preview_ready=true
receive_files_list_ready=true
send_file_preview_ready=true
send_message_production_ready=false unless strict send evidence passed
receive_files_download_ready=false unless R10 accepted mapping exists
send_file_production_ready=false unless file sandbox evidence passed
```
- [ ] **Step 3: Create report**
`docs/reports/2026-07-10-business-goals-smoke.md` summarizes the current business state in plain Chinese.
- [ ] **Step 4: Verify and commit**
```powershell
git diff --check
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-business-goals-smoke.ps1
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
git add scripts\verify-business-goals-smoke.ps1 docs\reports\2026-07-10-business-goals-smoke.md docs\current-status-card.md docs\go-mcp-runbook.md
git commit -m "test: add end-to-end business goals smoke"
git push gitea main
```
**Acceptance gate:** 业务目标完成度可以用脚本输出,而不是口头判断。
---
### R14: Operator packaging, runbook, and release-candidate report
**Purpose:** 把当前可交付能力、包、用法、阻断项整理成用户能执行、业务能审核、下一轮能继续的最终材料。
**Files:**
- Modify: `docs/go-mcp-runbook.md`
- Create: `docs/reports/2026-07-10-r6f-r14-release-candidate.md`
- Modify: `docs/source-discovery/capability-source-matrix.md`
- Modify: `docs/current-status-card.md`
- Modify: package scripts touched in earlier rounds only if packaging verification finds missing required files.
**Required report sections:**
- `## Business capability status`
- `## MCP tools available to digital employees`
- `## Packages generated under runs`
- `## Production blockers`
- `## Exact next evidence request if blocked`
- `## Verification commands and latest results`
- [ ] **Step 1: Rebuild local packages**
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\package-send-sandbox-gate.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-send-sandbox-gate-package.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\package-send-file-sandbox-gate.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-send-file-sandbox-gate-package.ps1
```
- [ ] **Step 2: Run full verification**
```powershell
git diff --check
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-business-goals-smoke.ps1
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
```
- [ ] **Step 3: Write release-candidate report**
The report must state the business status using these exact categories:
```text
已完成:可直接给数字员工用
可预览:数字员工可规划但不会真实发出/下载
阻断:需要在线可登录环境返回证据
```
- [ ] **Step 4: Commit and push**
```powershell
git status --short
git add docs\go-mcp-runbook.md docs\reports\2026-07-10-r6f-r14-release-candidate.md docs\source-discovery\capability-source-matrix.md docs\current-status-card.md scripts\package-send-sandbox-gate.ps1 scripts\verify-send-sandbox-gate-package.ps1 scripts\package-send-file-sandbox-gate.ps1 scripts\verify-send-file-sandbox-gate-package.ps1
git commit -m "docs: publish r6f r14 release candidate status"
git push gitea main
```
**Acceptance gate:** 用户可以审核一个清晰结论:哪些目标已经能给数字员工用,哪些只到 preview哪些必须回到在线环境采证。
---
## Expected Business State After R14
| Goal | Expected state after local-only rounds | If strict online evidence arrives during R6k/R9 |
| --- | --- | --- |
| 搜索联系人 | 已完成,可给数字员工用 | unchanged |
| 搜索群组 | 已完成,可给数字员工用 | unchanged |
| 收消息 | 已完成基础能力;增加对账辅助 | 可进一步判断是否切换 default auto merge |
| 发消息 | preview/idempotency/audit/gate 完整;生产默认阻断 | 可进入 gated connector production path |
| 收文件 | list 完整download preview 能解释阻断 | 若 R10 映射成立,可进入真实 download gate |
| 发文件 | preview/idempotency/audit/tool surface 完整;生产默认阻断 | 若 R9 返回包通过,可进入 upload connector path |
## Stop Conditions That Require User Input
- R6k strict-v2 returned send package missing, and remaining desired work is real production send.
- R9 returned send-file package missing, and remaining desired work is real upload/send file.
- R10 cannot map received-file metadata to cache/download and user wants real download rather than preview/blocked explanation.
- A future online package contains raw sensitive material that cannot be summarized into committed docs without user choosing a redaction policy.
## Self-Review
- Spec coverage: the plan covers search contacts, search groups, receive messages, send messages, receive files, and send files.
- Loop coverage: there are 15 ordered rounds from R6f through R14, each with files, commands, acceptance gates, commit messages, and push commands.
- Placeholder scan: the plan does not use placeholder markers; evidence-dependent branches have exact pass/fail behavior and concrete next actions.
- Type consistency: send-message connector types introduced in R6f are consumed by R6h, R6i, and R6l; file-send tool fields introduced in R7 are consumed by R8, R9, and R13.