12 KiB
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:
- Primary route B: in-process / sidecar connector that reuses the already logged-in
IMPlatformClient.exeruntime and its existing message/file send classes. - Fallback route A: constrained UI/RPA wrapper only if B cannot attach, load, or invoke safely.
- 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_messageisphere_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_keyand 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:
runs/offline-evidence-intake/zyl-qqfile-20260709/
Relevant extracted binaries:
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:
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:
IMPP.Client.Core.Plugins.Manager.AppContextManager.SendTxtMessageByJid(jid, chatType, content)
Observed behavior from IL:
- for direct/P2P chat, it gets a
P2PChatManagerfromIMPPManager.Instance; - it resolves a
Chatby 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:
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
chatvsgroupchat; - 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:
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:
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:
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:
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:
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.HTTPFileServerandFileTransferManager.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
fileIdand records metadata.
Native TCP file transfer
TcpFileTransfer.dll is native and exposes strings/exports indicating:
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
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
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:
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.exeprocess; - 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.exeexposesAppContextManagerandMessageSchedulingin the runtime module set; - confirm
smack.dllis loaded or loadable from the same install directory; - confirm
IMPP.Interface.dllandIMPP.Service*.dllare present.
Stop condition:
- app is not .NET Framework / cannot inspect CLR runtime safely;
- required assemblies are missing;
- only
SendP2PMessageis available butSendTxtMessageByJid/MessageSchedulingcannot be reached.
Gate B3: non-mutating dynamic observation
Pass condition:
- during one operator-approved manual test send, observe the expected chain:
SendTxtMessageByJidor 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:
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:
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:
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:
- Prepare or collect one operator-approved sandbox send evidence package.
- Use one explicit sandbox target, one content hash, and one idempotency key.
- Observe success/ack or local sent-record evidence.
- Prove duplicate retry with the same idempotency key is locally rejected before any second send.
- Capture method names, argument shape, IDs/hashes, status booleans, and refs only.
- Do not enable production
send_message_after_approvaluntil 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.