# Send Connector B-First Plan Date: 2026-07-10 Node: C29 / write-side connector route correction Decision owner: user/business manager ## Decision The selected send route is now: 1. **Primary route B: in-process / sidecar connector** that reuses the already logged-in `IMPlatformClient.exe` runtime and its existing message/file send classes. 2. **Fallback route A: constrained UI/RPA wrapper** only if B cannot attach, load, or invoke safely. 3. **Network replay/protocol reimplementation remains deferred** because it would require independently reproducing login/session/ack behavior. This document supersedes the previous C15/R5 conclusion for future send work. The old conclusion was correct for the evidence available at that time: no write connector had been selected. This node records the newly approved route and the evidence that makes B worth trying first. ## Business goal Expose controlled MCP actions for digital employees: - `isphere_send_message` - `isphere_send_file` The implementation must preserve these business controls: - target must be resolved from existing contact/group search results; - text/file content must be previewed before execution; - execution must use an `idempotency_key` and content hash; - every outbound attempt must produce an audit record; - early versions should support sandbox/test-target verification before normal production use. ## Static evidence summary Offline package evidence under: ```text runs/offline-evidence-intake/zyl-qqfile-20260709/ ``` Relevant extracted binaries: ```text zyl/Impp/IMPlatformClient.exe zyl/Impp/smack.dll zyl/Impp/IMPP.Interface.dll zyl/Impp/IMPP.ServiceBase.dll zyl/Impp/IMPP.Service.dll zyl/Impp/TcpFileTransfer.dll zyl/Impp/HYHC.IMPP.DAL.dll ``` Relevant IL snapshots: ```text runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPlatformClient.exe.il runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/smack.dll.il runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPP.Interface.dll.il runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPP.Service.dll.il runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPP.ServiceBase.dll.il ``` ## Text-send call chain ### Preferred sidecar candidate `IMPlatformClient.exe` contains a high-level helper: ```text IMPP.Client.Core.Plugins.Manager.AppContextManager.SendTxtMessageByJid(jid, chatType, content) ``` Observed behavior from IL: - for direct/P2P chat, it gets a `P2PChatManager` from `IMPPManager.Instance`; - it resolves a `Chat` by JID; - it finds or opens a chat form; - it calls `frmP2PChat.SendTxtMessage(content)`; - for temporary/reserved group chat, it calls the corresponding room form send method. This is the best B-route first target because it reuses the logged-in client's own state and UI/business rules. ### Central message construction candidate `IMPlatformClient.exe` also contains: ```text IMPP.Client.Core.MessageEngine.MessageScheduling.SendChatMessage(chat, msgText, toJid, messageType, isSaveMessage, msgGuid, IsReceipt) ``` Observed behavior from IL: - reads local font/style settings; - builds message body via `UtilsText.GetMessageStyleBodyText`; - decides `chat` vs `groupchat`; - creates `smack.packet.XmppMessage`; - sets body, subject, offline flag, receipt flag, time, and message type; - calls `chat.SendMessage(xmppMessage)`; - optionally persists/parses message through `MessageManager.MessageParsing`. This is the cleanest lower-level B candidate if the sidecar can obtain a valid `Chat` object from the running client context. ### Protocol bottom `smack.dll` provides the real wire-send chain: ```text com.vision.smack.Chat.SendMessage(XmppMessage) -> com.vision.smack.XMPPConnection.send(string) -> Sharp.Xmpp.Core.XmppCore.Send(string) -> stream.Write(...) ``` This proves that the send capability exists in the installed client binaries. It also shows why an external reimplementation is less attractive: it would need the same active connection, stanza format, message id, receipt, and session state. ## Important trap: plugin interface text send is not enough `IMPP.Interface.dll` declares: ```text IAppContextManager.SendP2PMessage(string pJid, string pMessage) IAppContextManager.SendP2PFiles(UserInfo[] pUserInfo, string[] pFiles) IAppContextManager.SendChatRoomMessage(string pRoomJid, string pMessage, string pluginID) IAppContextManager.SendPluginMessage(string pluginID, int command, string para) ``` But the implementation of: ```text IMPP.Client.Core.Plugins.Manager.AppContextManager.SendP2PMessage(...) ``` records the plugin call and then throws `NotImplementedException`. Therefore the B route must **not** choose `SendP2PMessage` as the text-send entry. The sidecar should prefer `SendTxtMessageByJid` or, if necessary, `MessageScheduling.SendChatMessage` with an existing `Chat` object. ## File-send call chain File sending appears split into upload plus file-message notification. ### Upload engine `IMPP.ServiceBase.dll` defines `IFileTransfer`. `IMPP.Service.dll` implements: ```text IMPP.Service.BLL.FileTransfer.FileUpload(...) IMPP.Service.BLL.FileTransfer.AsynFileUpload(...) IMPP.Service.BLL.FileTransfer.FileDownload(...) IMPP.Service.BLL.FileTransfer.SyncFileTransfer(...) ``` ### Offline file send `IMPlatformClient.exe` contains: ```text IMPP.Client.OffLineFileSend.sendFile() IMPP.Client.OffLineFileSend.trans_UploadCompleted(fileId) ``` Observed behavior: - builds a generated file GUID; - builds remote name as `filename____guid.ext`; - uses `Config.ServerInfo.HTTPFileServer` and `FileTransferManager.GetDomain`; - creates `FileUploadPara`; - calls `IMPPManager.Instance.Service.FileTransfer.FileUpload(uploadPara)`; - after upload completion, creates an `OFFLINE_FILE_TRANSFER;...` message body; - calls `Chat.sendFileMessage(...)`; - sets packet id to `fileId` and records metadata. ### Native TCP file transfer `TcpFileTransfer.dll` is native and exposes strings/exports indicating: ```text Send SendFile GetTcpFileMsgGuid _StartWaitForSendFileThread@8 _StartRecvFileThread@24 ``` This is a candidate for online/TCP file transfer, but the first B route should use the managed offline-file path because it is closer to the normal client business flow and already integrates upload metadata with XMPP file messages. ## Proposed sidecar architecture ```text Go MCP Server -> controlled action contract and audit -> C# WinHelper / Sidecar command -> B-route sidecar adapter -> running IMPlatformClient context -> existing AppContextManager / MessageScheduling / OffLineFileSend / smack.dll ``` The sidecar should be a narrow adapter, not a general-purpose remote code executor. ### Candidate sidecar operations ```text version self_check probe_client_runtime probe_send_entrypoints resolve_runtime_jid preview_send_message send_message_after_approval preview_send_file send_file_after_approval read_send_audit ``` The first implementation slice should stop before real production send: ```text version self_check probe_client_runtime probe_send_entrypoints ``` Then run a live sandbox observation before enabling `send_message_after_approval`. ## B-route validation gates ### Gate B1: runtime discovery Pass condition: - find a running `IMPlatformClient.exe` process; - record PID, bitness, install path, module list summary; - confirm the discovered path matches the extracted evidence family; - confirm whether the sidecar must be x86 or x64. Stop condition: - no logged-in process; - process bitness incompatible with available sidecar build; - module names differ too much from the extracted package. ### Gate B2: entrypoint availability Pass condition: - confirm `IMPlatformClient.exe` exposes `AppContextManager` and `MessageScheduling` in the runtime module set; - confirm `smack.dll` is loaded or loadable from the same install directory; - confirm `IMPP.Interface.dll` and `IMPP.Service*.dll` are present. Stop condition: - app is not .NET Framework / cannot inspect CLR runtime safely; - required assemblies are missing; - only `SendP2PMessage` is available but `SendTxtMessageByJid`/`MessageScheduling` cannot be reached. ### Gate B3: non-mutating dynamic observation Pass condition: - during one operator-approved manual test send, observe the expected chain: - `SendTxtMessageByJid` or UI send method; - `MessageScheduling.SendChatMessage`; - `Chat.SendMessage`; - `XMPPConnection.send`; - capture only redacted method names, argument shape, message id/hash, and success/ack indicator. Stop condition: - method chain differs from static evidence; - no success/ack indicator can be mapped; - message id/idempotency cannot be correlated. ### Gate B4: sidecar dry run Pass condition: - sidecar can resolve the target JID/chat type; - sidecar can build a preview object without sending; - preview contains target, content hash, connector, and proposed entrypoint; - audit event is appended. Stop condition: - no deterministic target resolution; - preview cannot distinguish direct vs group chat; - no auditable dry-run object. ### Gate B5: one sandbox send Pass condition: - one explicit test target only; - one idempotency key only; - one message content hash only; - success/ack or local sent-record evidence captured; - duplicate retry with same idempotency key is rejected locally. Stop condition: - duplicate send risk; - wrong target risk; - no post-send verification. ## A-route fallback A remains the backup route if B cannot be made reliable. A should not be arbitrary desktop control. It should expose only: ```text search_contact(query) open_conversation(target) write_draft(text) verify_draft(target, text_hash) send_after_approval(approval_id) upload_file(path) verify_send_result() ``` A-route fallback is activated when any of these happen: - B cannot attach/probe safely; - required runtime classes are unavailable in the logged-in process; - B can observe but cannot invoke without unstable side effects; - B cannot provide idempotency/audit guarantees; - sidecar bitness/runtime mismatch is too costly to resolve in the current cycle. ## MCP contract impact The MCP business tools should not expose B/A internals directly. They should keep the stable user-facing shape: ```text isphere_send_message(target_type, target_id, content_text, mode, idempotency_key, content_sha256) isphere_send_file(target_type, target_id, file_path, mode, idempotency_key, file_sha256) ``` Connector metadata should show the route: ```text connector = "implatform-sidecar" | "uia-rpa" connector_stage = "preview" | "sandbox_send" | "production" ``` ## Next implementation loop R6b B-route preview/dry-run contract is now complete. `isphere_send_message` is registered as preview/dry-run only, validates target/content-hash/idempotency input, appends redacted audit JSONL, and blocks production with all side-effect flags false. Next node should be **R6c online sandbox-send evidence gate**: 1. Prepare or collect one operator-approved sandbox send evidence package. 2. Use one explicit sandbox target, one content hash, and one idempotency key. 3. Observe success/ack or local sent-record evidence. 4. Prove duplicate retry with the same idempotency key is locally rejected before any second send. 5. Capture method names, argument shape, IDs/hashes, status booleans, and refs only. 6. Do not enable production `send_message_after_approval` until the evidence gate passes. ## Current status B is selected as the primary send/file-send route. Runtime discovery, entrypoint metadata preflight, and preview/dry-run audit are in place. A remains the fallback and now has concrete UIA selector/offline-blocker classifier support. Production send remains blocked until dynamic observation and one approved sandbox send prove success/ack behavior.