994 lines
50 KiB
Markdown
994 lines
50 KiB
Markdown
# 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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **Step 2: Write failing fake-failed test**
|
||
|
||
Add `TestISphereSendMessageFakeConnectorFailureAudit` asserting `ok=false`, `send_status="failed"`, `error_code="fake_rejected"`, and no real side-effect flags such as `sent_message` or `typed_text`.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
**R6f Result:**
|
||
|
||
- Added `internal/tools/send_message_connector.go` with `SendMessageConnector`, `SendMessageConnectorRequest`, `SendMessageConnectorResult`, and result normalization.
|
||
- Added `RegisterISphereSendMessageToolWithStateAndConnector` for injected test-only connector execution.
|
||
- Added fake connector accepted/failed tests proving accepted/failed connector outcomes map into structured response and redacted audit metadata.
|
||
- Default server registration still uses no connector; `execution_mode="production"` remains blocked with `production_send_enabled=false`.
|
||
- No helper send operation, UI click/type, network replay, hook, upload, or real production send was introduced.
|
||
|
||
---
|
||
|
||
### 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`.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
**R6g Result:**
|
||
|
||
- Added `scripts/test-verify-send-audit-idempotency.ps1` and confirmed the red test failed before the verifier existed.
|
||
- Added `scripts/verify-send-audit-idempotency.ps1` to summarize redacted audit/idempotency JSONL files with sanitized counts and booleans.
|
||
- Diagnostic detects duplicate same-key/same-target/content replay, conflict same-key/different-content replay, and raw field leaks.
|
||
- Added `TestISphereSendMessageAuditRedactionIsStable` to prove file-backed audit JSONL does not store raw message body or raw idempotency key.
|
||
- No iSphere login, real send, helper action, hook, upload, or network replay was introduced.
|
||
|
||
---
|
||
|
||
### 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`.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **Step 2: Implement gate policy**
|
||
|
||
Create `send_message_gate.go` with the exact type/function and reason-code order from the test.
|
||
|
||
- [x] **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`.
|
||
|
||
- [x] **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.
|
||
|
||
**R6h Result:**
|
||
|
||
- Added `internal/tools/send_message_gate.go` with `SendMessageGatePolicy` and `LoadSendMessageGatePolicy`.
|
||
- Added table tests for `send_disabled_by_default`, `send_evidence_missing`, `send_connector_missing`, and `send_gate_passed`.
|
||
- Default `isphere_send_message` production-blocked responses and audit events now include `gate_reason_code` and `gate_reason_message`.
|
||
- `ISPHERE_SEND_PRODUCTION_ENABLED=1` is recognized by policy tests, but the default MCP runtime still has no real connector and reports `production_send_enabled=false`.
|
||
|
||
---
|
||
|
||
### 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`.
|
||
|
||
- [x] **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) }
|
||
}
|
||
```
|
||
|
||
- [x] **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`.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
**R6i Result:**
|
||
|
||
- Added `internal/tools/send_message_broute_adapter.go` with `BRouteSendAdapterConfig` and `NewBRouteSendMessageConnector`.
|
||
- Added disabled-mode and dry-run-contract tests.
|
||
- `disabled` returns `broute_mode_blocked`; `dry_run_contract` validates request shape and returns `broute_dry_run_only`.
|
||
- The adapter shell does not start a sidecar, load DLLs, click/type UI, replay network traffic, or upload files.
|
||
- Production `isphere_send_message` remains blocked in the default MCP runtime.
|
||
|
||
---
|
||
|
||
### 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`
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
**R6j Result:**
|
||
|
||
- `scripts\verify-send-sandbox-gate-package.ps1` first failed against the old package because `RETURN-CHECKLIST-V2.md` was missing.
|
||
- `scripts\package-send-sandbox-gate.ps1` now emits `RETURN-CHECKLIST-V2.md`, `SANDBOX-SEND-INPUTS.schema.json`, `CREATE-RETURN-ZIP.ps1`, and strict-v2 fields in `SANDBOX-SEND-INPUTS.template.json`.
|
||
- `CREATE-RETURN-ZIP.ps1` refuses to build a return zip when after-recorder output, strict-v2 timestamps, success evidence, or no-duplicate confirmation are missing.
|
||
- `scripts\validate-returned-send-sandbox-package.ps1` now supports `-ZipPath` and `-StrictV2`.
|
||
- Existing partial package validation remains `partial_use_only`; strict-v2 validation exits non-zero for that partial package.
|
||
|
||
---
|
||
|
||
### 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`
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
**R6k Result:**
|
||
|
||
- Scanned `C:\Users\zhaoy\Downloads` for recent zip files.
|
||
- No new strict-v2 returned send-sandbox package was found.
|
||
- Re-validated `C:\Users\zhaoy\Downloads\1631.zip` with `-ZipPath` and `-StrictV2`; strict-v2 failed as expected.
|
||
- Created `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis-v2.md`.
|
||
- Decision: `r6d_gate_pass=false`, `strict_v2_pass=false`; default production send remains blocked.
|
||
|
||
---
|
||
|
||
### 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.
|
||
|
||
- [x] **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`.
|
||
|
||
- [x] **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`.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
**R6l Result:**
|
||
|
||
- R6k found `strict_v2_pass=false`, so R6l used the blocked branch.
|
||
- Added `TestISphereSendMessageProductionGateBlockedWithoutStrictEvidence`, proving production remains blocked with `gate_reason_code="send_evidence_missing"` when `ISPHERE_SEND_PRODUCTION_ENABLED=1` but strict evidence is missing.
|
||
- Added `TestISphereSendMessageProductionRequiresEvidenceAndConnector` as an explicit skipped test with reason `strict v2 send evidence not present in this repository state`.
|
||
- Standard MCP smoke continues to report `production_send_enabled=false`.
|
||
|
||
---
|
||
|
||
### 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`.
|
||
|
||
- [x] **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`.
|
||
|
||
- [x] **Step 2: Write path rejection test**
|
||
|
||
Add `TestISphereSendFileRejectsPathOutsideAllowedDir` asserting paths outside `ISPHERE_SEND_FILE_ALLOWED_DIR` return `ok=false` and `send_status="blocked"`.
|
||
|
||
- [x] **Step 3: Implement tool and registration**
|
||
|
||
Register the tenth MCP tool. Production execution returns blocked with `production_send_enabled=false`.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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,不上传。
|
||
|
||
**R7 Result:**
|
||
|
||
- Added `internal/tools/isphere_send_file.go` and `internal/tools/isphere_send_file_test.go`.
|
||
- Registered `isphere_send_file` as the tenth MCP tool.
|
||
- Preview requires `ISPHERE_SEND_FILE_ALLOWED_DIR`, validates target/idempotency/file existence/path boundary/SHA256/size, and returns `send_status="planned"` with `real_send_attempted=false`.
|
||
- Production `execution_mode="production"` remains structured blocked with `production_send_enabled=false` and all send/upload/UI/network side-effect flags false.
|
||
- Updated `scripts/verify-go-mcp.ps1` and `cmd/isphere-capability-smoke` to assert 10 tools, send-file preview readiness, and send-file production disabled.
|
||
- Verification passed: `git diff --check`, focused send-file tests, 10-tool registration test, `go test ./...`, `go build ./cmd/isphere-mcp`, `scripts\verify-go-mcp.ps1`, and `go run ./cmd/isphere-capability-smoke`.
|
||
|
||
---
|
||
|
||
### 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`.
|
||
|
||
- [x] **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`.
|
||
|
||
- [x] **Step 2: Write conflict test**
|
||
|
||
Add `TestISphereSendFileIdempotencyConflictBlocked`: same idempotency key with a different file hash returns `send_status="blocked"` and `conflict_detected=true`.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
**R8 Result:**
|
||
|
||
- Added send-file audit and idempotency state with `ISPHERE_SEND_FILE_AUDIT_PATH` and `ISPHERE_SEND_FILE_IDEMPOTENCY_PATH`.
|
||
- Duplicate same target/file/idempotency key now returns `duplicate_detected=true` and remains planned/no-send.
|
||
- Reusing the same idempotency key for a different target or file hash returns `send_status="blocked"` and `conflict_detected=true`.
|
||
- Send-file audit/idempotency JSONL stores file hash, size, target ref, result, side-effect flags, and hashed idempotency key; it does not store raw file content, raw local file path, or raw idempotency key.
|
||
- `scripts/verify-go-mcp.ps1` now asserts `send_file_duplicate_detected=true` and `send_file_conflict_blocked=true` while keeping `send_file_production_enabled=false`.
|
||
- Verification passed: `git diff --check`, `go test ./internal/tools -run TestISphereSendFile -v`, `go test ./...`, `go build ./cmd/isphere-mcp`, `scripts\verify-go-mcp.ps1`, and `go run ./cmd/isphere-capability-smoke`.
|
||
|
||
---
|
||
|
||
### 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
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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:** 用户可以把一个包带到可登录环境采集发文件证据。
|
||
|
||
**R9 Result:**
|
||
|
||
- Added `scripts/package-send-file-sandbox-gate.ps1`, which builds `runs/send-file-sandbox-gate-package.zip`.
|
||
- Added `scripts/verify-send-file-sandbox-gate-package.ps1`; the first run failed before the builder existed, then passed after implementation.
|
||
- Added `scripts/validate-returned-send-file-sandbox-package.ps1` for future returned online/internal sandbox packages.
|
||
- Added `docs/source-discovery/2026-07-10-send-file-sandbox-gate.md`.
|
||
- The package includes recorder binaries, capability smoke executable, `FILE-SEND-INPUTS.template.json`, operator instructions, `CREATE-FILE-RETURN-ZIP.ps1`, and `RUN-FILE-RECORDING-SUITE.bat`.
|
||
- Local verifier generated and validated the package; production `isphere_send_file` remains blocked.
|
||
- Returned-package validator was checked with a temporary strict-pass fixture.
|
||
|
||
---
|
||
|
||
### 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.
|
||
|
||
- [x] **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
|
||
```
|
||
|
||
- [x] **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`.
|
||
|
||
- [x] **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.
|
||
|
||
- [x] **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:** 文件下载要么得到可实现映射,要么得到明确阻断证据。
|
||
|
||
**R10 Result:**
|
||
|
||
- Added v2 fixture scoring to `scripts/verify-file-cache-mapping.ps1`.
|
||
- Updated `scripts/test-verify-file-cache-mapping.ps1` to prove exact filename/size/time gets score 100, source-id/size gets score 80, and filename-only gets score 40 without acceptance.
|
||
- Fixture verification produced `records_checked=3`, `cache_candidates_checked=4`, `accepted_matches=2`, `ambiguous_matches=0`, `score_100_matches=1`, `score_80_matches=1`, `score_40_only_matches=1`, `raw_paths_printed=false`, and `file_contents_read=false`.
|
||
- Created `docs/source-discovery/2026-07-10-file-download-mapping-v2.md`.
|
||
- Real production file download remains blocked because this proves resolver logic, not a real iSphere cache mapping from an online package.
|
||
|
||
---
|
||
|
||
### 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.
|