docs: accept partial send sandbox evidence

This commit is contained in:
zhaoyilun
2026-07-10 19:11:52 +08:00
parent 89d7f65b45
commit 138615a29c
7 changed files with 446 additions and 6 deletions

View File

@@ -58,7 +58,7 @@ N13/N14/N15 are pre-business validation results. They can help identify UI eleme
## Current loop ## Current loop
Current loop: `R6c local online-sandbox evidence package consolidated plus offline capability-test package prepared; next R6d returned sandbox evidence intake after package is run and returned`. Current loop: `R6d partial returned sandbox evidence intake accepted for limited use; next R6e sandbox-only send connector shell and idempotency audit hardening`.
Plan file: `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`. Plan file: `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`.
@@ -117,6 +117,7 @@ Current loop output so far:
44. R6b: added `isphere_send_message` preview/dry-run only. The tool validates `target_type`, `target_id`, `content_sha256`, and `idempotency_key`, returns connector metadata `implatform-sidecar`/`preview`, appends redacted JSONL audit events without raw message body or raw idempotency key, and returns `send_status="blocked"` for production with all side-effect flags false. `verify-go-mcp.ps1` now verifies the 9-tool surface and proves `send_preview_tool_present=true` and `production_send_enabled=false`. 44. R6b: added `isphere_send_message` preview/dry-run only. The tool validates `target_type`, `target_id`, `content_sha256`, and `idempotency_key`, returns connector metadata `implatform-sidecar`/`preview`, appends redacted JSONL audit events without raw message body or raw idempotency key, and returns `send_status="blocked"` for production with all side-effect flags false. `verify-go-mcp.ps1` now verifies the 9-tool surface and proves `send_preview_tool_present=true` and `production_send_enabled=false`.
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. 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`. 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.
## Recompiled business roadmap ## Recompiled business roadmap
@@ -201,3 +202,14 @@ R6c local preparation for online sandbox-send evidence is complete:
- The capability-test package is offline-safe and confirms 9 MCP tools, fixture-backed receive/search/file-list behavior, send preview, no real send, and `production_send_enabled=false`. - The capability-test package is offline-safe and confirms 9 MCP tools, fixture-backed receive/search/file-list behavior, send preview, no real send, and `production_send_enabled=false`.
- Production `isphere_send_message` and `isphere_send_file` remain blocked until the returned package proves success/ack or sent-record evidence and no second send. - Production `isphere_send_message` and `isphere_send_file` remain blocked until the returned package proves success/ack or sent-record evidence and no second send.
- Next node: R6d returned sandbox evidence intake after the package is run and returned. - Next node: R6d returned sandbox evidence intake after the package is run and returned.
R6d partial returned sandbox evidence intake is complete:
- Local intake source: `C:\Users\zhaoy\Downloads\1631.zip`.
- Added repeatable validator: `scripts\validate-returned-send-sandbox-package.ps1`.
- Added fixture test: `scripts\test-validate-returned-send-sandbox-package.ps1`.
- Created `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis.md`.
- Validator decision: `partial_use_only`.
- `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.

View File

@@ -401,7 +401,34 @@ The package also contains `RECORDING-PACKAGE-MANIFEST.json`, `run-before-recorde
Production `isphere_send_message` remains blocked until the returned package is analyzed. Production `isphere_send_message` remains blocked until the returned package is analyzed.
## 14. Offline capability-test package ## 14. Returned sandbox package validation
When a returned package comes back, validate it before treating it as evidence:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\validate-returned-send-sandbox-package.ps1 -PackagePath C:\Users\zhaoy\Downloads\1631.zip
```
The current partial returned package `C:\Users\zhaoy\Downloads\1631.zip` validates as:
```json
{
"partial_evidence_usable": true,
"r6d_gate_pass": false,
"production_send_enabled": false,
"decision": "partial_use_only"
}
```
Use `partial_use_only` to continue local sandbox-only connector-shell and idempotency/audit work. Do not enable production send from a partial package. Full pass still requires after-recorder output and manual send timestamps.
The fixture test for the current partial package is:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\test-validate-returned-send-sandbox-package.ps1
```
## 15. Offline capability-test package
Use this second package when you want to test the current capability surface without logging in and without any real send. Use this second package when you want to test the current capability surface without logging in and without any real send.
@@ -440,7 +467,7 @@ Expected final JSON includes:
This package includes `isphere-capability-smoke.exe` and `runs\win-helper\ISphereWinHelper.exe`. It verifies the nine-tool MCP surface, fixture-backed receive/search/file-list behavior, send preview, and the production-send block. It does not log in, click, type, upload, hook, inject, or send. This package includes `isphere-capability-smoke.exe` and `runs\win-helper\ISphereWinHelper.exe`. It verifies the nine-tool MCP surface, fixture-backed receive/search/file-list behavior, send preview, and the production-send block. It does not log in, click, type, upload, hook, inject, or send.
## 15. Troubleshooting ## 16. Troubleshooting
- If C# helper build fails, run `scripts\build-win-helper.ps1` directly and check for missing .NET Framework reference assemblies. - If C# helper build fails, run `scripts\build-win-helper.ps1` directly and check for missing .NET Framework reference assemblies.
- If `win_helper_version` fails, rerun `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-win-helper.ps1` first. - If `win_helper_version` fails, rerun `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-win-helper.ps1` first.

View File

@@ -0,0 +1,133 @@
# Returned Send Sandbox Analysis
Date: 2026-07-10
Node: R6d returned sandbox evidence intake
Returned package: `C:\Users\zhaoy\Downloads\1631.zip`
Local intake copy: `runs/returned-send-sandbox/1631/`
## Decision
Use this return package as **partial R6d evidence** only.
Business interpretation:
- It is enough to continue the next engineering loop with a sandbox-only send connector shell, idempotency/audit hardening, and stricter returned-package validation.
- It is not enough to enable production `isphere_send_message`.
- It is not enough to start `isphere_send_file` production work.
Repository behavior remains:
```text
production_send_enabled=false
```
## Validator
Repeatable validation command:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\validate-returned-send-sandbox-package.ps1 -PackagePath C:\Users\zhaoy\Downloads\1631.zip
```
Fixture test:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\test-validate-returned-send-sandbox-package.ps1
```
Observed validator result:
```json
{
"partial_evidence_usable": true,
"r6d_gate_pass": false,
"capability_test_ok": true,
"capability_tool_count": 9,
"production_send_enabled": false,
"content_hash_matches": true,
"operator_observed_success": true,
"do_not_send_second_time_confirmed": true,
"has_before_probe": true,
"has_after_probe": false,
"missing_for_full_gate": [
"manual_send_started_at_local",
"manual_send_finished_at_local",
"after_recorder_output"
],
"decision": "partial_use_only"
}
```
## Evidence received
The returned zip contains:
```text
isphere-live-probe-20260710-162555.zip
RUN-RECORDING-SUITE.txt
SANDBOX-SEND-INPUTS..json
send-capability-test-package.txt
```
Notes:
- `SANDBOX-SEND-INPUTS..json` has a double dot in the filename, but the validator accepts this pattern.
- The target id is present but should stay redacted in committed docs.
- The raw message body is not needed in committed docs; the validator checks the supplied SHA256 against the local returned JSON.
- The capability-test transcript proves the offline-safe 9-tool package ran successfully and kept production send disabled.
## Evidence that is usable now
Usable for next engineering loop:
- explicit sandbox target fields are present;
- content SHA256 matches the supplied test content;
- idempotency key is present;
- operator recorded observed success/sent-record text;
- operator confirmed no second send;
- one read-only live probe package was returned;
- capability smoke passed with 9 tools and `production_send_enabled=false`.
This is enough to justify moving from "waiting for any returned send evidence" to:
1. returned-package validator hardening;
2. sandbox-only connector shell design;
3. idempotency/audit persistence design;
4. fake/sandbox connector tests.
## Missing for full R6d pass
Missing:
- `manual_send_started_at_local`;
- `manual_send_finished_at_local`;
- after-send recorder output;
- standard `return-evidence/before` and `return-evidence/after` shape from `make-return-zip.ps1`.
Because these are missing, the full gate does **not** pass.
## Current route decision
Proceed with "partial use" only:
```text
R6d partial_use_only -> R6e sandbox-only send connector shell and idempotency audit hardening
```
Do not change the current MCP production-send response:
```text
execution_mode="production" -> send_status="blocked"
```
## What would make it full pass later
Ask the operator to return a corrected package only when convenient:
1. run `02-run-after-recorder.bat`;
2. fill `manual_send_started_at_local`;
3. fill `manual_send_finished_at_local`;
4. run `03-make-return-zip.bat`;
5. return the generated `isphere-send-sandbox-return-*.zip`.
The current partial package can still be used for the next local development loop.

View File

@@ -7,6 +7,7 @@ Schema notes: `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md`
Returned live probe: `docs/source-discovery/2026-07-10-returned-live-probe-analysis.md` Returned live probe: `docs/source-discovery/2026-07-10-returned-live-probe-analysis.md`
Send connector preflight: `docs/source-discovery/2026-07-10-send-connector-preflight.md` Send connector preflight: `docs/source-discovery/2026-07-10-send-connector-preflight.md`
Send sandbox gate: `docs/source-discovery/2026-07-10-send-sandbox-gate.md` Send sandbox gate: `docs/source-discovery/2026-07-10-send-sandbox-gate.md`
Returned send sandbox analysis: `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis.md`
## Source priority ## Source priority
@@ -25,7 +26,7 @@ Send sandbox gate: `docs/source-discovery/2026-07-10-send-sandbox-gate.md`
| `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_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_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_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`; `internal/tools/isphere_send_message_test.go`; `cmd/isphere-capability-smoke/main.go` | R6c prepares the online sandbox evidence package because local login is unavailable. `runs/send-sandbox-gate-package.zip` now contains a consolidated recording suite for one manual sandbox send; `runs/send-capability-test-package.zip` separately verifies the offline-safe 9-tool surface, fixture-backed receive/search/file-list behavior, send preview, and `production_send_enabled=false`. No returned online send evidence has been analyzed yet. Production remains blocked. | next: R6d returned sandbox evidence intake after user returns the package | | `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_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 | | `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 ## Stage C entry rule
@@ -43,4 +44,4 @@ Start Stage C with a narrow log-backed `isphere_receive_messages` source abstrac
## Deferred source work ## 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. R6c now has both the consolidated online recording package and the offline capability-test package. The active roadmap is `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`; next step is R6d returned sandbox evidence intake after the online package is returned. `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.

View File

@@ -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 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 | | 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 | | 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; R6c has a consolidated online sandbox recording package plus a separate offline capability-test package. | Need returned online sandbox evidence proving success/ack and no duplicate send before production. | next R6d returned sandbox evidence intake | | 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 |
| 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 | | 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 | | 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 |
@@ -510,6 +510,47 @@ powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-go-mcp.ps1
**Stop condition:** **Stop condition:**
- Do not infer success from screenshots or vague operator notes alone. Require the structured returned package fields and before/after recorder output. - Do not infer success from screenshots or vague operator notes alone. Require the structured returned package fields and before/after recorder output.
**R6d Result:**
- Added `scripts/validate-returned-send-sandbox-package.ps1`.
- Added `scripts/test-validate-returned-send-sandbox-package.ps1`.
- Created `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis.md`.
- Validated `C:\Users\zhaoy\Downloads\1631.zip` as partial evidence:
- `partial_evidence_usable=true`;
- `r6d_gate_pass=false`;
- capability test passed with 9 tools;
- production send remained disabled;
- content hash matched;
- idempotency key, operator observed success, success record, and no-second-send confirmation were present;
- after-recorder output and manual send timestamps were missing.
- Decision: use the returned package to proceed with sandbox-only connector shell and idempotency/audit hardening, but keep production `isphere_send_message` blocked.
---
### R6e: Sandbox-only send connector shell and idempotency audit hardening
**Purpose:** Use R6d partial evidence to build the non-production connector control plane before any real send connector is enabled.
**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:**
- `execution_mode="preview"` remains no-send.
- `execution_mode="production"` remains blocked.
- Add or harden idempotency/audit state so duplicate idempotency keys can be detected before any future production connector is attached.
- If a connector interface is introduced, tests must use a fake connector only.
- No helper click/type/send op, no upload, no hook, no network replay.
**Acceptance gate:**
- Duplicate idempotency-key behavior is tested.
- Audit records remain redacted and do not store raw message body.
- Standard MCP smoke still reports `production_send_enabled=false`.
**Stop condition:**
- Do not wire a real send entrypoint until a full returned package or controlled online sandbox connector test is available.
--- ---
### R6: Send-message preview and production path ### R6: Send-message preview and production path

View File

@@ -0,0 +1,61 @@
param(
[string]$FixtureZip = "C:\Users\zhaoy\Downloads\1631.zip"
)
$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
$repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path
$validator = Join-Path $repo "scripts\validate-returned-send-sandbox-package.ps1"
if (-not (Test-Path -LiteralPath $validator)) {
throw "missing validator script: $validator"
}
if (-not (Test-Path -LiteralPath $FixtureZip)) {
throw "missing fixture zip: $FixtureZip"
}
$output = & powershell -NoProfile -ExecutionPolicy Bypass -File $validator -PackagePath $FixtureZip
if ($LASTEXITCODE -ne 0) {
throw "validator failed with exit code $LASTEXITCODE"
}
$output | ForEach-Object { Write-Host $_ }
$lastLine = @($output | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) | Select-Object -Last 1
$result = $lastLine | ConvertFrom-Json
if ($result.ok -ne $true) {
throw "validator ok mismatch: $($result.ok)"
}
if ($result.partial_evidence_usable -ne $true) {
throw "partial_evidence_usable mismatch: $($result.partial_evidence_usable)"
}
if ($result.r6d_gate_pass -ne $false) {
throw "r6d_gate_pass mismatch: $($result.r6d_gate_pass)"
}
if ($result.capability_test_ok -ne $true) {
throw "capability_test_ok mismatch: $($result.capability_test_ok)"
}
if ($result.capability_tool_count -ne 9) {
throw "capability_tool_count mismatch: $($result.capability_tool_count)"
}
if ($result.content_hash_matches -ne $true) {
throw "content_hash_matches mismatch: $($result.content_hash_matches)"
}
if ($result.operator_observed_success -ne $true) {
throw "operator_observed_success mismatch: $($result.operator_observed_success)"
}
if ($result.has_after_probe -ne $false) {
throw "has_after_probe mismatch: $($result.has_after_probe)"
}
if ($result.production_send_enabled -ne $false) {
throw "production_send_enabled mismatch: $($result.production_send_enabled)"
}
[ordered]@{
ok = $true
fixture = $FixtureZip
partial_evidence_usable = $result.partial_evidence_usable
r6d_gate_pass = $result.r6d_gate_pass
capability_tool_count = $result.capability_tool_count
production_send_enabled = $result.production_send_enabled
} | ConvertTo-Json -Depth 4 -Compress

View File

@@ -0,0 +1,165 @@
param(
[Parameter(Mandatory=$true)]
[string]$PackagePath,
[string]$WorkDir = ""
)
$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
function ConvertTo-Sha256Hex([string]$Text) {
$bytes = [System.Text.Encoding]::UTF8.GetBytes($Text)
$sha = [System.Security.Cryptography.SHA256]::Create()
try {
return -join ($sha.ComputeHash($bytes) | ForEach-Object { $_.ToString("x2") })
}
finally {
$sha.Dispose()
}
}
function Read-FirstJsonLine([string]$Path) {
if (-not (Test-Path -LiteralPath $Path)) {
return $null
}
foreach ($line in Get-Content -LiteralPath $Path) {
$trimmed = $line.Trim()
if ($trimmed.StartsWith("{") -and $trimmed.EndsWith("}")) {
return ($trimmed | ConvertFrom-Json)
}
}
return $null
}
function Test-NonEmptyString($Value) {
if ($null -eq $Value) {
return $false
}
return -not [string]::IsNullOrWhiteSpace([string]$Value)
}
if (-not (Test-Path -LiteralPath $PackagePath)) {
throw "package not found: $PackagePath"
}
$resolvedPackage = (Resolve-Path -LiteralPath $PackagePath).Path
$cleanup = $false
if ([string]::IsNullOrWhiteSpace($WorkDir)) {
$WorkDir = Join-Path ([System.IO.Path]::GetTempPath()) ("isphere-returned-send-sandbox-" + [guid]::NewGuid().ToString("N"))
$cleanup = $true
}
if (Test-Path -LiteralPath $WorkDir) {
Remove-Item -LiteralPath $WorkDir -Recurse -Force
}
New-Item -ItemType Directory -Force -Path $WorkDir | Out-Null
try {
if ($resolvedPackage.EndsWith(".zip", [System.StringComparison]::OrdinalIgnoreCase)) {
Expand-Archive -LiteralPath $resolvedPackage -DestinationPath $WorkDir -Force
$root = $WorkDir
}
else {
$root = $resolvedPackage
}
$allFiles = Get-ChildItem -LiteralPath $root -Recurse -File
$inputsFile = $allFiles | Where-Object { $_.Name -like "SANDBOX-SEND-INPUTS*.json" } | Sort-Object FullName | Select-Object -First 1
if (-not $inputsFile) {
throw "missing SANDBOX-SEND-INPUTS json"
}
$inputs = Get-Content -LiteralPath $inputsFile.FullName -Raw | ConvertFrom-Json
$capabilityLog = $allFiles | Where-Object { $_.Name -like "*capability-test*.txt" -or $_.Name -like "*capability*.log" } | Sort-Object FullName | Select-Object -First 1
$capability = $null
if ($capabilityLog) {
$capability = Read-FirstJsonLine $capabilityLog.FullName
}
$liveProbeZips = @($allFiles | Where-Object { $_.Name -like "isphere-live-probe-*.zip" })
$beforeMarkers = @($allFiles | Where-Object { $_.FullName -match "\\before\\" -or $_.FullName -match "/before/" -or $_.Name -like "*before*" })
$afterMarkers = @($allFiles | Where-Object { $_.FullName -match "\\after\\" -or $_.FullName -match "/after/" -or $_.Name -like "*after*" })
$contentText = [string]$inputs.content_text_to_send
$expectedHash = [string]$inputs.content_sha256
$actualHash = ConvertTo-Sha256Hex $contentText
$contentHashMatches = ($actualHash -eq $expectedHash)
$capabilityOK = $false
$capabilityToolCount = 0
$productionSendEnabled = $false
if ($null -ne $capability) {
$capabilityOK = ($capability.ok -eq $true)
if ($null -ne $capability.tool_count) {
$capabilityToolCount = [int]$capability.tool_count
}
if ($null -ne $capability.production_send_enabled) {
$productionSendEnabled = [bool]$capability.production_send_enabled
}
}
$hasExplicitTarget = (Test-NonEmptyString $inputs.sandbox_target_type) -and (Test-NonEmptyString $inputs.sandbox_target_id)
$hasIdempotencyKey = Test-NonEmptyString $inputs.idempotency_key
$hasSuccessRecord = Test-NonEmptyString $inputs.success_ack_or_sent_record
$manualStartPresent = Test-NonEmptyString $inputs.manual_send_started_at_local
$manualFinishPresent = Test-NonEmptyString $inputs.manual_send_finished_at_local
$operatorSuccess = ($inputs.operator_observed_success -eq $true)
$noSecondSend = ($inputs.do_not_send_second_time_confirmed -eq $true)
$hasBeforeProbe = ($liveProbeZips.Count -gt 0 -or $beforeMarkers.Count -gt 0)
$hasAfterProbe = ($afterMarkers.Count -gt 0)
$partialUsable = (
$capabilityOK -and
$capabilityToolCount -eq 9 -and
-not $productionSendEnabled -and
$hasExplicitTarget -and
$contentHashMatches -and
$hasIdempotencyKey -and
$operatorSuccess -and
$hasSuccessRecord -and
$noSecondSend -and
$hasBeforeProbe
)
$r6dGatePass = (
$partialUsable -and
$manualStartPresent -and
$manualFinishPresent -and
$hasAfterProbe
)
$missing = New-Object System.Collections.Generic.List[string]
if (-not $manualStartPresent) { $missing.Add("manual_send_started_at_local") }
if (-not $manualFinishPresent) { $missing.Add("manual_send_finished_at_local") }
if (-not $hasAfterProbe) { $missing.Add("after_recorder_output") }
[ordered]@{
ok = $true
package = $resolvedPackage
input_file_name = $inputsFile.Name
partial_evidence_usable = $partialUsable
r6d_gate_pass = $r6dGatePass
target_type_present = Test-NonEmptyString $inputs.sandbox_target_type
target_id_present = Test-NonEmptyString $inputs.sandbox_target_id
content_hash_matches = $contentHashMatches
idempotency_key_present = $hasIdempotencyKey
operator_observed_success = $operatorSuccess
success_ack_or_sent_record_present = $hasSuccessRecord
do_not_send_second_time_confirmed = $noSecondSend
manual_send_started_at_local_present = $manualStartPresent
manual_send_finished_at_local_present = $manualFinishPresent
capability_test_ok = $capabilityOK
capability_tool_count = $capabilityToolCount
production_send_enabled = $productionSendEnabled
has_before_probe = $hasBeforeProbe
has_after_probe = $hasAfterProbe
live_probe_zip_count = $liveProbeZips.Count
missing_for_full_gate = @($missing)
decision = if ($r6dGatePass) { "full_gate_pass" } elseif ($partialUsable) { "partial_use_only" } else { "not_usable" }
} | ConvertTo-Json -Depth 6 -Compress
}
finally {
if ($cleanup -and (Test-Path -LiteralPath $WorkDir)) {
Remove-Item -LiteralPath $WorkDir -Recurse -Force
}
}