feat: add log-backed receive message source

This commit is contained in:
zhaoyilun
2026-07-09 23:00:27 +08:00
parent 4d5b314f83
commit fe2a1947f3
3 changed files with 227 additions and 8 deletions

View File

@@ -402,7 +402,7 @@ Implemented and verified in this loop:
- Consumes: `packetlog.ParseMessageLog(plaintext string) (packetlog.Message, error)`.
- Produces: `EncryptedPacketLogSource.ReceiveMessages(ctx context.Context, query ReceiveMessagesQuery) (ReceiveMessagesResult, error)`.
- [ ] **Step 1: Write failing source abstraction test**
- [x] **Step 1: Write failing source abstraction test**
Create `internal/isphere/source_test.go`:
@@ -482,7 +482,7 @@ go test ./internal/isphere -run TestEncryptedPacketLogSourceReturnsNormalizedMes
Expected: FAIL because `EncryptedPacketLogSource`, `ReceiveMessagesQuery`, and related types do not exist.
- [ ] **Step 2: Implement source abstraction**
- [x] **Step 2: Implement source abstraction**
Create `internal/isphere/source.go`:
@@ -584,7 +584,7 @@ func conversationID(sender string, receiver string) string {
}
```
- [ ] **Step 3: Verify source abstraction test passes**
- [x] **Step 3: Verify source abstraction test passes**
Run:
@@ -594,7 +594,7 @@ go test ./internal/isphere -run TestEncryptedPacketLogSourceReturnsNormalizedMes
Expected: PASS.
- [ ] **Step 4: Run full verification**
- [x] **Step 4: Run full verification**
Run:
@@ -605,7 +605,7 @@ go build ./cmd/isphere-mcp
Expected: both exit 0.
- [ ] **Step 5: Commit Loop C2**
- [x] **Step 5: Commit Loop C2**
Run:
@@ -617,23 +617,82 @@ git commit -m "feat: add log-backed receive message source"
Expected: commit succeeds.
- [ ] **Step 6: Rewrite Loop C3 before continuing**
- [x] **Step 6: Rewrite Loop C3 before continuing**
After Loop C2 passes, update `Loop C3` with the exact source interface and MCP response shape from the committed implementation.
---
## Loop C2 Result
Implemented and verified in this loop:
- `internal/isphere.EncryptedPacketLogSource.ReceiveMessages(ctx, query)` decrypts encrypted PacketReader log lines, parses XMPP `<message>` stanzas, normalizes bare sender/receiver JIDs, and returns C2 `isphere.Message` records.
- `ReceiveMessagesQuery{Limit: n}` limits returned messages when `n > 0`; zero or negative limit returns all available lines.
- The source checks context cancellation before each decrypt/parse operation and returns `ctx.Err()` when canceled.
- Tests use synthetic/redacted encrypted PacketReader fixture data only; no raw N12-pre evidence was committed.
- Verification completed for C2 with `git diff --check`, `go test ./...`, and `go build ./cmd/isphere-mcp`; the generated `isphere-mcp.exe` build artifact was removed.
- Loop C3 was rewritten around the actual C2 interface and the planned MCP response shape before continuing.
---
## Loop C3: Register `isphere_receive_messages` MCP tool
**Current draft goal:** Add the first business MCP tool after the source abstraction passes tests.
**Goal:** Register the first business read MCP tool on top of the C2 source abstraction, while keeping helper tools read-only and leaving send/search/file operations out of scope.
**Planned files:**
- Create: `internal/tools/isphere_read.go`
- Create: `internal/tools/isphere_read_test.go`
- Modify: `internal/mcpserver/server.go`
- Modify: `internal/mcpserver/server_test.go`
- Modify: `internal/tools/winhelper_test.go`
- Modify: `docs/source-discovery/capability-source-matrix.md`
- Modify: `docs/superpowers/plans/2026-07-09-stage-c-log-backed-receive-messages-loop.md`
**Rewrite rule before implementation:** Update existing tests that currently assert only four helper tools. The new expected surface should be four helper tools plus `isphere_receive_messages`.
**Interfaces from Loop C2:**
- Tool name: `isphere_receive_messages`.
- Tool input: `limit` only.
- Tool source: `isphere.EncryptedPacketLogSource.ReceiveMessages(ctx, isphere.ReceiveMessagesQuery{Limit: input.Limit})`.
- Tool output shape: a map/object with `messages`, where each message carries `id`, `conversation_id`, `conversation_type`, `sender_id`, `receiver_id`, `text`, `timestamp`, `subject`, `receipt_id`, and `read`.
- [ ] **Step 1: Write failing tool registration tests**
Add or update tests so they fail before implementation:
```powershell
go test ./internal/tools -run TestISphereReceiveMessagesToolReturnsSourceMessages -v
go test ./internal/mcpserver -run TestNewServerRegistersN8WinHelperToolsWithoutCallingHelper -v
```
Expected initial failures: `isphere_receive_messages` is not registered and the server/tool lists still expose only the four helper tools.
- [ ] **Step 2: Implement `internal/tools/isphere_read.go`**
Register `isphere_receive_messages` with `mcp.AddTool`, convert the C2 `isphere.Message` slice into the explicit JSON/map output shape, and keep the only public input parameter as `limit`. Use a source interface so tests can inject a synthetic C2 source without raw evidence files.
- [ ] **Step 3: Register business read tool in `mcpserver.NewServer`**
Register the helper tools plus `isphere_receive_messages`. If no live log-line loader exists yet, wire an empty `isphere.EncryptedPacketLogSource{}` as the default so registration is testable without committing raw logs.
- [ ] **Step 4: Update existing helper-tool guard tests**
Rename or adjust the old “exactly four” helper test so it still blocks forbidden write/sending tool names but explicitly allows `isphere_receive_messages`. Update `internal/mcpserver/server_test.go` to expect five tools: four helper tools plus `isphere_receive_messages`.
- [ ] **Step 5: Run full verification**
Run:
```powershell
git diff --check
go test ./...
go build ./cmd/isphere-mcp
```
Expected: all exit 0.
- [ ] **Step 6: Commit Loop C3 and rewrite Loop C4**
Commit exact C3 paths only. Rewrite Loop C4 around the actual MCP tool output shape and the fact that default server wiring has no raw evidence loader yet.
---