feat: harden send preview idempotency
This commit is contained in:
@@ -30,7 +30,7 @@ Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-repor
|
||||
- `isphere_receive_messages` accepts the read-contract argument set for the current local-readonly path: `conversation_id`, `query`, `since`, `limit`, `include_attachment_metadata`, `source_preference`, `preview`, and empty `cursor`.
|
||||
- `isphere_search_contacts` and `isphere_search_groups` accept and validate the safe search-contract args for the current local-readonly path and can optionally enrich results from the env-configured C29 `MsgLib.db` display-entity reader; default behavior remains log/JID-backed when MsgLib env vars are absent.
|
||||
- `isphere_receive_files` list mode accepts and validates the safe file-list contract args for the current local-readonly path while keeping download blocked.
|
||||
- `isphere_send_message` accepts the R6b preview/dry-run contract (`target_type`, `target_id`, `content_text`, `content_sha256`, `idempotency_key`, `execution_mode`) and returns planned preview metadata plus redacted audit metadata; `execution_mode="production"` returns blocked status with all side-effect flags false.
|
||||
- `isphere_send_message` accepts the R6b/R6e preview/dry-run contract (`target_type`, `target_id`, `content_text`, `content_sha256`, `idempotency_key`, `execution_mode`) and returns planned preview metadata plus redacted audit/idempotency metadata; `execution_mode="production"` returns blocked status with all side-effect flags false.
|
||||
- `native/MsgLibReadSidecar` provides a bounded x86 .NET read-only boundary for `MsgLib.db` schema/display-source checks, bounded contact/group display-entity reads, message-source metadata, and sidecar-level bounded message listing; `internal/msglib` wraps it from Go, C30 wires display metadata as an optional MCP contact/group enrichment source, C39 adds a Go receive-source adapter around `ListMessages`, C40 adds tool-level explicit `msglib_readonly` source selection, and C41 wires it through env configuration without changing the MCP default source.
|
||||
- N12-pre and N12R documents define safe offline evidence intake and internal-sandbox live UIA capture procedures.
|
||||
- N13/N14/N15 produced selector catalog/report validation infrastructure, but those are supporting validation assets only.
|
||||
@@ -58,7 +58,7 @@ N13/N14/N15 are pre-business validation results. They can help identify UI eleme
|
||||
|
||||
## Current loop
|
||||
|
||||
Current loop: `R6d partial returned sandbox evidence intake accepted for limited use; next R6e sandbox-only send connector shell and idempotency audit hardening`.
|
||||
Current loop: `R6e sandbox-only send connector shell and idempotency audit hardening implemented; next R6f fake/sandbox connector contract or corrected full evidence intake`.
|
||||
|
||||
Plan file: `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`.
|
||||
|
||||
@@ -118,6 +118,7 @@ Current loop output so far:
|
||||
45. R6c: because the local machine cannot log in, prepared an online/internal sandbox evidence package instead of attempting local send. Added `scripts/package-send-sandbox-gate.ps1`, `scripts/verify-send-sandbox-gate-package.ps1`, and `docs/source-discovery/2026-07-10-send-sandbox-gate.md`; local verification generates `runs/send-sandbox-gate-package.zip` with the read-only recorder, before/after scripts, sandbox input template, SHA256 helper, expected-return checklist, and return-zip helper.
|
||||
46. R6c package consolidation: upgraded `runs/send-sandbox-gate-package.zip` into a one-pass operator recording suite with `RUN-RECORDING-SUITE.bat`, numbered `01/02/03` scripts, and `RECORDING-PACKAGE-MANIFEST.json`; added a second offline-safe `runs/send-capability-test-package.zip` with `isphere-capability-smoke.exe` plus packaged `ISphereWinHelper.exe` to verify the 9-tool MCP surface, receive/search/file-list fixture behavior, send preview, and `production_send_enabled=false`.
|
||||
47. R6d partial intake: accepted `C:\Users\zhaoy\Downloads\1631.zip` as partial evidence only. Added `scripts\validate-returned-send-sandbox-package.ps1`, `scripts\test-validate-returned-send-sandbox-package.ps1`, and `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis.md`. Validator reports `partial_evidence_usable=true` and `r6d_gate_pass=false`: capability test passed, content hash matched, idempotency key/success/no-second-send fields were present, but after-recorder output and manual send timestamps are missing. This can unblock sandbox-only connector-shell/idempotency work, not production send.
|
||||
48. R6e: hardened `isphere_send_message` with a sandbox-only connector shell marker and idempotency store. Preview remains no-send; production remains blocked. Duplicate idempotency keys for the same target/content are detected and reported; conflicting reuse of the same idempotency key for different content/target is blocked with all side-effect flags false. `ISPHERE_SEND_IDEMPOTENCY_PATH` can point to a JSONL state file; standard verification uses per-run temporary state.
|
||||
|
||||
## Recompiled business roadmap
|
||||
|
||||
@@ -213,3 +214,12 @@ R6d partial returned sandbox evidence intake is complete:
|
||||
- `partial_evidence_usable=true`: use it to continue sandbox-only send connector shell and idempotency/audit hardening.
|
||||
- `r6d_gate_pass=false`: do not enable production `isphere_send_message`, because after-recorder output and manual send timestamps are missing.
|
||||
- Next node: R6e sandbox-only send connector shell and idempotency audit hardening.
|
||||
|
||||
R6e sandbox-only send connector shell and idempotency audit hardening is complete:
|
||||
|
||||
- Added `SendMessageIdempotencyStore` and file-backed `ISPHERE_SEND_IDEMPOTENCY_PATH`.
|
||||
- `isphere_send_message` response now exposes `connector_mode="sandbox-only-shell"` and `production_send_enabled=false`.
|
||||
- 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.
|
||||
|
||||
@@ -100,6 +100,7 @@ The verification confirms:
|
||||
- `isphere_search_groups` is callable and returns JID-derived group candidates from the configured synthetic groupchat fixture; exact ID/display-name matches rank before prefix/substring matches and case-insensitive duplicates are collapsed.
|
||||
- `isphere_receive_files` is callable in list mode and returns one file metadata candidate from the configured synthetic file-transfer fixture.
|
||||
- `isphere_send_message` is callable in preview mode and returns `send_status="planned"` without raw content in the response; `execution_mode="production"` returns `send_status="blocked"` and `production_send_enabled=false`.
|
||||
- `isphere_send_message` also exposes sandbox-only connector metadata and idempotency state: duplicate reuse of the same key for the same target/content is detectable, while conflicting reuse of the same key for different content/target is blocked.
|
||||
- Verification uses synthetic/local helper checks and does not load raw N12-pre evidence.
|
||||
- The deterministic verification path clears MsgLib env variables, so it proves the default no-MsgLib behavior remains stable.
|
||||
- File download/cache mapping, send-file, and production send remain later-stage work.
|
||||
@@ -264,6 +265,15 @@ Allowed parameters:
|
||||
- `isphere_receive_files`: `conversation_id`, `message_id`, `file_id`, `name_contains`, `mode`, `output_dir`, `cursor`, `source_preference`, `preview`, `limit` only. C22 supports `mode` empty or `list`; `source_preference` currently supports empty/`auto`/`local_readonly`; `cursor` and `output_dir` must be empty in current list-only mode; download is deferred.
|
||||
- `isphere_send_message`: `target_type`, `target_id`, `content_text`, `content_sha256`, `idempotency_key`, `execution_mode` only. R6b supports `execution_mode` empty/`preview`/`dry_run` as planned preview. `execution_mode="production"` returns blocked status until sandbox-send evidence passes. The response and audit store `content_sha256` and `idempotency_key_sha256`, not raw message body or raw idempotency key.
|
||||
|
||||
Optional send audit/idempotency paths:
|
||||
|
||||
```powershell
|
||||
$env:ISPHERE_SEND_AUDIT_PATH = "E:\coding\codex\isphere-ai-bridge\runs\send-audit\send-message-preview.jsonl"
|
||||
$env:ISPHERE_SEND_IDEMPOTENCY_PATH = "E:\coding\codex\isphere-ai-bridge\runs\send-audit\send-message-idempotency.jsonl"
|
||||
```
|
||||
|
||||
If `ISPHERE_SEND_IDEMPOTENCY_PATH` is set, the send preview path records hashed idempotency state. Reusing the same idempotency key for the same target/content sets `duplicate_detected=true`; reusing it for different content or target returns blocked metadata with `conflict_detected=true`. Raw message body and raw idempotency key are not stored in the JSONL state.
|
||||
|
||||
## 10. Current tool surface and next-stage route
|
||||
|
||||
The current runbook verifies nine tools:
|
||||
@@ -278,7 +288,7 @@ The current runbook verifies nine tools:
|
||||
- `isphere_receive_files`
|
||||
- `isphere_send_message`
|
||||
|
||||
The current log-backed business read tools have parser/source/tool registration and an empty default server source. Raw N12-pre evidence remains under ignored `runs/` paths and is not committed. The current command entry point can read an operator-local encrypted PacketReader log-line file via `ISPHERE_PACKET_LOG_FILE` or a directory of `.log`/`.txt` files via `ISPHERE_PACKET_LOG_DIR`; this is still not a production ingestion claim because raw evidence remains local and uncommitted. `isphere_receive_messages` now exposes contract-facing fields for digital-employee consumption while preserving older aliases for compatibility, supports `conversation_id`, keyword `query`, and RFC3339 `since` filtering, and validates the remaining safe contract args without pretending unsupported connectors/pagination exist. Contact and group search also accept the safe local-readonly contract args, rank exact matches before prefix/substring matches, collapse case-insensitive duplicates across log-derived candidates and optional `MsgLibReadSidecar` display metadata, and preserve `source`/`raw_ref`; receive-message `sender_name` and `conversation.display_name` can use that same optional metadata when MsgLib env is configured. `isphere_receive_files` supports list mode with safe contract arg validation; download/cache mapping remains deferred. `isphere_send_message` supports preview/dry-run metadata and redacted audit only; production send remains blocked until dynamic observation, idempotency protection, and one approved sandbox send prove success/ack behavior.
|
||||
The current log-backed business read tools have parser/source/tool registration and an empty default server source. Raw N12-pre evidence remains under ignored `runs/` paths and is not committed. The current command entry point can read an operator-local encrypted PacketReader log-line file via `ISPHERE_PACKET_LOG_FILE` or a directory of `.log`/`.txt` files via `ISPHERE_PACKET_LOG_DIR`; this is still not a production ingestion claim because raw evidence remains local and uncommitted. `isphere_receive_messages` now exposes contract-facing fields for digital-employee consumption while preserving older aliases for compatibility, supports `conversation_id`, keyword `query`, and RFC3339 `since` filtering, and validates the remaining safe contract args without pretending unsupported connectors/pagination exist. Contact and group search also accept the safe local-readonly contract args, rank exact matches before prefix/substring matches, collapse case-insensitive duplicates across log-derived candidates and optional `MsgLibReadSidecar` display metadata, and preserve `source`/`raw_ref`; receive-message `sender_name` and `conversation.display_name` can use that same optional metadata when MsgLib env is configured. `isphere_receive_files` supports list mode with safe contract arg validation; download/cache mapping remains deferred. `isphere_send_message` supports preview/dry-run metadata, sandbox-only connector-shell metadata, duplicate/conflict idempotency detection, and redacted audit only; production send remains blocked until dynamic observation, a full send evidence gate, and a controlled sandbox connector pass prove success/ack behavior.
|
||||
|
||||
Core business tools for contacts, groups, messages, and files are defined in `docs/mcp-core-tools-contract.md`. Send-message preview metadata and audit records are now in place; production send still waits for the later online sandbox-send gate.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Returned send sandbox analysis: `docs/source-discovery/2026-07-10-returned-send-
|
||||
| `isphere_search_contacts` | bare sender/receiver JIDs extracted from normalized log-backed messages loaded from configured PacketReader file or directory source | validated copied `MsgLib.db` tables: `TD_Roster`, `TD_CustomEffigy`, `tblRecent`, `tblChatLevel`, `tblPersonMsg`; decrypted roster/contact stanzas from `Smark.SendReceive`; UIA helper source if display names are still missing | `docs/source-discovery/2026-07-10-msglib-readonly-schema-extraction.md`; `internal/isphere/contacts_test.go`; `internal/tools/isphere_contacts_test.go` | C34 documents optional MsgLib contact display enrichment; R2 adds deterministic exact-match-first ranking, case-insensitive de-duplication across log/MsgLib candidates, and preserves `source`/`raw_ref` | core contact search complete; optional richer fields later |
|
||||
| `isphere_search_groups` | decrypted `PacketReader.ProcessPacket` `type="groupchat"` stanzas and conference/MUC JIDs loaded from configured PacketReader file or directory source | validated copied `MsgLib.db` tables: `tblMsgGroupPersonMsg`, `TD_WorkGroupAuth`, `tblRecent`; UIA helper source if group display names are still missing | `docs/source-discovery/2026-07-10-msglib-readonly-schema-extraction.md`; `internal/isphere/groups_test.go`; `internal/tools/isphere_groups_test.go`; C9 ignored-log scan: PacketReader 86 groupchat/86 conference hits; Smark 24 groupchat/658 conference/631 muc hits | C34 documents optional MsgLib group display enrichment; R2 adds deterministic exact-match-first ranking, case-insensitive de-duplication across log/MsgLib candidates, and preserves `source`/`raw_ref` | core group search complete; optional member/owner hierarchy later |
|
||||
| `isphere_receive_files` | decrypted `PacketReader.ProcessPacket` file-transfer message stanzas via `internal/isphere.ListFilesFromMessages` and `isphere_receive_files` list mode; configured PacketReader file or directory source; `zyl\importal\<hash>` cache entries remain unlinked | MsgLib `TD_ReceiveFileRecord` safe metadata through explicit copied-DB path; decrypted `Smark.SendReceive` and `SaveToDB` traces for file-reference reconciliation; future UIA/client connector for download | `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md#c12-file-transfer-evidence-precheck`; `docs/source-discovery/2026-07-10-file-download-mapping-precheck.md`; `docs/source-discovery/2026-07-10-file-cache-mapping-diagnostic.md` | C22 verifies safe file-list contract args; R3 confirms list metadata is available; R3b diagnostic finds 0 current cache/archive matches, so R4 remains blocked | blocked pending better cache evidence or UI/client download connector |
|
||||
| `isphere_send_message` | B-route selected: running-client sidecar / in-process connector, preferring `AppContextManager.SendTxtMessageByJid(...)` or `MessageScheduling.SendChatMessage(...)` over the unimplemented `SendP2PMessage(...)` interface path; current MCP tool exposes preview/dry-run only | A-route fallback: constrained UI/RPA wrapper only if B cannot pass runtime probe, entrypoint availability, dynamic observation, and idempotent dry-run gates; network/protocol replay remains deferred | `docs/source-discovery/2026-07-10-send-message-source-precheck.md`; `docs/source-discovery/2026-07-10-send-message-connector-selection.md`; `docs/source-discovery/2026-07-10-send-sidecar-b-first-plan.md`; `docs/source-discovery/2026-07-10-returned-live-probe-analysis.md`; `docs/source-discovery/2026-07-10-send-connector-preflight.md`; `docs/source-discovery/2026-07-10-send-sandbox-gate.md`; `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis.md`; `internal/tools/isphere_send_message_test.go`; `cmd/isphere-capability-smoke/main.go` | R6d validates `C:\Users\zhaoy\Downloads\1631.zip` as partial evidence only: `partial_evidence_usable=true`, `r6d_gate_pass=false`, capability smoke passed, content hash matched, operator success/no-second-send fields were present, but after-recorder output and send timestamps were missing. This is enough for sandbox-only connector-shell/idempotency work, not enough for production send. | next: R6e sandbox-only connector shell and idempotency audit hardening |
|
||||
| `isphere_send_message` | B-route selected: running-client sidecar / in-process connector, preferring `AppContextManager.SendTxtMessageByJid(...)` or `MessageScheduling.SendChatMessage(...)` over the unimplemented `SendP2PMessage(...)` interface path; current MCP tool exposes preview/dry-run only | A-route fallback: constrained UI/RPA wrapper only if B cannot pass runtime probe, entrypoint availability, dynamic observation, and idempotent dry-run gates; network/protocol replay remains deferred | `docs/source-discovery/2026-07-10-send-message-source-precheck.md`; `docs/source-discovery/2026-07-10-send-message-connector-selection.md`; `docs/source-discovery/2026-07-10-send-sidecar-b-first-plan.md`; `docs/source-discovery/2026-07-10-returned-live-probe-analysis.md`; `docs/source-discovery/2026-07-10-send-connector-preflight.md`; `docs/source-discovery/2026-07-10-send-sandbox-gate.md`; `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis.md`; `internal/tools/isphere_send_message_test.go`; `cmd/isphere-capability-smoke/main.go` | R6e adds sandbox-only connector-shell metadata and JSONL-backed idempotency state. Duplicate same-key/same-target/same-content preview calls are detectable; conflicting key reuse is blocked. Production remains blocked because R6d was only partial evidence and no real connector has passed a controlled online sandbox test. | next: R6f fake/sandbox connector contract |
|
||||
| `isphere_send_file` | B-route selected after send-message probe: managed offline-file path through `OffLineFileSend.sendFile()`, `IMPP.Service*.dll` `IFileTransfer.FileUpload(...)`, and `Chat.sendFileMessage(...)` | A-route fallback: constrained UI/RPA upload/send-file flow; native `TcpFileTransfer.dll` is a later candidate only after managed path is rejected | `docs/source-discovery/2026-07-10-send-message-source-precheck.md`; `docs/source-discovery/2026-07-10-send-message-connector-selection.md`; `docs/source-discovery/2026-07-10-send-sidecar-b-first-plan.md`; `docs/source-discovery/2026-07-10-returned-live-probe-analysis.md`; `docs/source-discovery/2026-07-10-send-connector-preflight.md`; `docs/source-discovery/2026-07-10-send-sandbox-gate.md` | R6a/C31 metadata confirms `FileTransfer.FileUpload`, `FileTransfer.AsynFileUpload`, `OffLineFileSend.sendFile`, and `Chat.sendFileMessage` candidates. File-send remains blocked behind returned message-send sandbox evidence plus later upload/file-message dry-run evidence. | next: wait for R6d, then file-send upload preflight |
|
||||
|
||||
## Stage C entry rule
|
||||
@@ -44,4 +44,4 @@ Start Stage C with a narrow log-backed `isphere_receive_messages` source abstrac
|
||||
|
||||
## Deferred source work
|
||||
|
||||
`MsgLib.db` has a validated copied read-only open path through the bundled 32-bit `System.Data.SQLite.dll` and password `123`. C27 adds `MsgLibReadSidecar` as the bounded x86 .NET reader boundary, C28 adds the Go `internal/msglib` process client, C29 adds bounded `display_entities` extraction, C30 wires it as optional contact/group MCP enrichment, C31 proves real copied-DB MCP enrichment with sanitized output, C32 reuses it for receive-message display fields, C33 proves that receive display path through a real copied-DB MCP smoke without printing entity values, C34 documents the operator setup/verification path, C35 maps MsgLib message tables to receive-message contract fields without reading row values, C36 adds metadata-only `message_sources` readiness, C37 defines the bounded DB-backed receive-source design, C38 implements sidecar/Go-wrapper `list_messages` with sanitized verification, C39 adds a Go adapter from MsgLib list results to the receive-message domain model, C40 adds explicit tool-level `msglib_readonly` source selection, C41 wires env-configured explicit MsgLib receive with optional sanitized smoke, R1 documents source reconciliation keys, and R2 hardens contact/group search ranking and de-duplication. R6d partial evidence is now usable only for sandbox-only send connector shell and idempotency/audit hardening. The active roadmap is `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`; next step is R6e.
|
||||
`MsgLib.db` has a validated copied read-only open path through the bundled 32-bit `System.Data.SQLite.dll` and password `123`. C27 adds `MsgLibReadSidecar` as the bounded x86 .NET reader boundary, C28 adds the Go `internal/msglib` process client, C29 adds bounded `display_entities` extraction, C30 wires it as optional contact/group MCP enrichment, C31 proves real copied-DB MCP enrichment with sanitized output, C32 reuses it for receive-message display fields, C33 proves that receive display path through a real copied-DB MCP smoke without printing entity values, C34 documents the operator setup/verification path, C35 maps MsgLib message tables to receive-message contract fields without reading row values, C36 adds metadata-only `message_sources` readiness, C37 defines the bounded DB-backed receive-source design, C38 implements sidecar/Go-wrapper `list_messages` with sanitized verification, C39 adds a Go adapter from MsgLib list results to the receive-message domain model, C40 adds explicit tool-level `msglib_readonly` source selection, C41 wires env-configured explicit MsgLib receive with optional sanitized smoke, R1 documents source reconciliation keys, and R2 hardens contact/group search ranking and de-duplication. R6e has completed sandbox-only send connector shell and idempotency/audit hardening. The active roadmap is `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`; next step is R6f.
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
| Search contacts | Registered MCP tool; deterministic exact-match ranking and case-insensitive de-duplication across log/JID candidates and optional copied-DB MsgLib display enrichment. | Optional richer fields such as department/title remain future enrichment, not a core search blocker. | complete for core search; optional enrichment later |
|
||||
| Search groups | Registered MCP tool; deterministic exact-match ranking and case-insensitive de-duplication across groupchat/conference candidates and optional copied-DB MsgLib display enrichment. | Optional member count, owner refs, and nested/group hierarchy remain future enrichment, not a core search blocker. | complete for core search; optional enrichment later |
|
||||
| Receive messages | PacketReader source works; copied `MsgLib.db` explicit receive works with `source_preference="msglib_readonly"`; R1 precheck says default should remain PacketReader until a future reconciliation helper is implemented. | Future reconciliation helper, source confidence scoring, pagination policy. | future receive helper after R2/R3 |
|
||||
| Send messages | `isphere_send_message` preview/dry-run is registered; R6a confirms B-route entrypoint metadata; R6d partial returned package is usable for sandbox-only connector-shell/idempotency work. | Full production still needs after-recorder output and manual send timestamps, or a later complete returned package. | next R6e sandbox-only connector shell |
|
||||
| Send messages | `isphere_send_message` preview/dry-run is registered; R6a confirms B-route entrypoint metadata; R6e adds sandbox-only connector shell metadata and idempotency/audit state. | Full production still needs after-recorder output/manual timestamps or a controlled online sandbox connector pass. | next R6f fake/sandbox connector contract |
|
||||
| Receive files | List mode exists from message-derived file metadata; R3/R3b confirm DB file metadata exists but current cache/archive evidence does not map to local files. | R4 download is blocked until better cache evidence or a UI/client download connector is available. | blocked; continue R5 |
|
||||
| Send files | Contract exists; R6a/C31 metadata confirms file-upload/offline-file/file-message candidates and A-route file menu classifier support. | Blocked behind returned send-message sandbox evidence plus upload/file-transfer dry-run. | wait for R6d, then file-send upload preflight |
|
||||
|
||||
@@ -551,6 +551,41 @@ powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
|
||||
**Stop condition:**
|
||||
- Do not wire a real send entrypoint until a full returned package or controlled online sandbox connector test is available.
|
||||
|
||||
**R6e Result:**
|
||||
|
||||
- Added `SendMessageIdempotencyStore` plus file-backed `fileSendMessageIdempotencyStore`.
|
||||
- Added `ISPHERE_SEND_IDEMPOTENCY_PATH` for JSONL idempotency state.
|
||||
- Added `RegisterISphereSendMessageToolWithState` so tests and future connector work can inject fake audit/idempotency state.
|
||||
- `isphere_send_message` now returns `connector_mode="sandbox-only-shell"` and `production_send_enabled=false`.
|
||||
- Duplicate idempotency key reuse for the same target/content is reported with `duplicate_detected=true` and no side effects.
|
||||
- Conflicting idempotency key reuse for different content/target is blocked with `conflict_detected=true`, `send_status="blocked"`, and no side effects.
|
||||
- `scripts/verify-go-mcp.ps1` and `cmd/isphere-capability-smoke` now use fresh per-run send audit/idempotency state so repeated smokes remain deterministic.
|
||||
- Decision: next node is R6f fake/sandbox connector contract. Production send remains blocked.
|
||||
|
||||
---
|
||||
|
||||
### R6f: Fake/sandbox send connector contract
|
||||
|
||||
**Purpose:** Define the connector interface and fake connector behavior needed before any real B-route send entrypoint is attached.
|
||||
|
||||
**Files:**
|
||||
- Modify: `internal/tools/isphere_send_message.go`
|
||||
- Modify tests: `internal/tools/isphere_send_message_test.go`
|
||||
- Modify docs: this roadmap, `docs/current-status-card.md`, and `docs/go-mcp-runbook.md`
|
||||
|
||||
**Execution policy:**
|
||||
- The fake connector may simulate accepted/ack/failed outcomes only inside tests.
|
||||
- Runtime MCP `execution_mode="production"` remains blocked unless an explicit test-only/fake injection is used.
|
||||
- No real helper send op, no UI click/type, no network/protocol send, no upload.
|
||||
|
||||
**Acceptance gate:**
|
||||
- Fake connector tests cover accepted, failed, duplicate, and idempotency-conflict paths.
|
||||
- The production MCP server still reports `production_send_enabled=false`.
|
||||
- Audit records keep raw message body and raw idempotency key out of JSONL.
|
||||
|
||||
**Stop condition:**
|
||||
- If a real connector is introduced before fake/sandbox contract tests pass, stop and revert that part.
|
||||
|
||||
---
|
||||
|
||||
### R6: Send-message preview and production path
|
||||
|
||||
Reference in New Issue
Block a user