7 Commits

Author SHA1 Message Date
zhaoyilun
a9e692a574 feat: add in-process adapter research contract 2026-07-12 11:15:07 +08:00
zhaoyilun
a4242c12be docs: add offline b-route reverse decision 2026-07-12 02:36:59 +08:00
zhaoyilun
485d5ea766 docs: plan offline b-route reverse work 2026-07-12 01:44:01 +08:00
zhaoyilun
eb399853e6 docs: plan b-route bridge next steps 2026-07-12 01:36:28 +08:00
zhaoyilun
0bb07c7754 docs: clarify rpa fallback priority 2026-07-12 01:29:07 +08:00
zhaoyilun
341f08b7be docs: correct main send status and plan 2026-07-12 01:22:56 +08:00
zhaoyilun
3b01d94088 merge: a-route real chat window 2026-07-12 01:13:24 +08:00
28 changed files with 3927 additions and 29 deletions

View File

@@ -1,6 +1,6 @@
# Current Status Card # Current Status Card
Date: 2026-07-10 Date: 2026-07-12
Branch: `main` Branch: `main`
Loop base: `e993ce1 docs: trim safety constraints from mcp roadmap` Loop base: `e993ce1 docs: trim safety constraints from mcp roadmap`
Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-report-hardening'` Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-report-hardening'`
@@ -11,10 +11,16 @@ Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-repor
后续研发主线切换为 MCP 核心通信能力:搜索联系人、搜索群组、收发消息、收发文件。现有 UIA/selector/report 只作为底层辅助和证据,不再作为主线继续扩展。 后续研发主线切换为 MCP 核心通信能力:搜索联系人、搜索群组、收发消息、收发文件。现有 UIA/selector/report 只作为底层辅助和证据,不再作为主线继续扩展。
Route priority is explicit:
1. Primary route: B-route running-client sidecar / in-process connector / existing API that reuses the logged-in `IMPlatformClient.exe` runtime.
2. Secondary route: existing bridge, local service, local data, log, cache, or database source where it can satisfy the MCP contract.
3. Backup route only: A-route/RPA/UIA. Use it to keep the product moving when the B-route is blocked or temporarily untestable, but do not promote it above B-route as the default product architecture.
## Current completed state ## Current completed state
- Go MCP foundation exists: `cmd/isphere-mcp`, `internal/mcpserver`, `internal/helperclient`, and `internal/tools` build a stdio MCP server. - Go MCP foundation exists: `cmd/isphere-mcp`, `internal/mcpserver`, `internal/helperclient`, and `internal/tools` build a stdio MCP server.
- The current MCP surface exposes ten tools: four WinHelper observation tools, four read-oriented business tools, one send-message preview-only tool, and one send-file preview-only tool: - The current MCP surface exposes ten tools: four WinHelper observation tools, four read-oriented business tools, one send-message tool that is preview by default and can use explicit A-route UIA action config, and one send-file preview-only tool:
- `win_helper_version` - `win_helper_version`
- `win_helper_self_check` - `win_helper_self_check`
- `win_helper_scan_windows` - `win_helper_scan_windows`
@@ -23,15 +29,17 @@ Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-repor
- `isphere_search_contacts` - `isphere_search_contacts`
- `isphere_search_groups` - `isphere_search_groups`
- `isphere_receive_files` - `isphere_receive_files`
- `isphere_send_message` preview/dry-run only; production is blocked - `isphere_send_message` preview/dry-run by default; explicit `uia_rpa` config can perform UI write/click, but business delivery remains unverified
- `isphere_send_file` preview/dry-run only; production file upload is blocked - `isphere_send_file` preview/dry-run only; production file upload is blocked
- C# `ISphereWinHelper` exists under `native/ISphereWinHelper` and uses the `isphere.helper.v1` stdin/stdout JSON contract. Helper `0.4.0` adds read-only `probe_send_entrypoints` and `probe_send_uia_controls` for R6a/C31 send connector preflight. - C# `ISphereWinHelper` exists under `native/ISphereWinHelper` and uses the `isphere.helper.v1` stdin/stdout JSON contract. Helper `0.5.0` includes read-only `probe_send_entrypoints` / `probe_send_uia_controls` plus `uia_send_message` for configured UI Automation write/click.
- `scripts/verify-win-helper.ps1` and `scripts/verify-go-mcp.ps1` provide repeatable local checks for the helper, ten-tool MCP surface, default empty-source receive/contact/group/file calls, send-message preview/production-blocked behavior, send-file preview/production-blocked behavior, synthetic configured-file receive/contact/group/file smoke, and synthetic configured-directory receive/contact/group/file smoke. - `scripts/verify-win-helper.ps1` and `scripts/verify-go-mcp.ps1` provide repeatable local checks for the helper, ten-tool MCP surface, default empty-source receive/contact/group/file calls, standard send-message preview/production-blocked behavior when A-route env is not configured, send-file preview/production-blocked behavior, synthetic configured-file receive/contact/group/file smoke, and synthetic configured-directory receive/contact/group/file smoke.
- `isphere_receive_messages` now returns the contract-facing `ok`, `conversation`, `messages`, `next_cursor`, and `audit` envelope while retaining legacy parser-native message fields for compatibility. - `isphere_receive_messages` now returns the contract-facing `ok`, `conversation`, `messages`, `next_cursor`, and `audit` envelope while retaining legacy parser-native message fields for compatibility.
- `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_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_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_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/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. - `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.
- A-route fallback can now be explicitly enabled with `ISPHERE_SEND_CONNECTOR_MODE=uia_rpa` and a real/synthetic chat HWND. In that mode the helper can write text to `rtbSendMessage` and click `btnSend`; this is a UI action capability, not proof of business delivery.
- Offline/unlogged real-window work can open the real `frmP2PChat` and confirm UIA root `frmP2PChat`, editor `rtbSendMessage`, button `btnSend`, and receive area `rtbRecvMessage`. The local offline client still reports that messages cannot be sent while offline.
- `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. - `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. - 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. - N13/N14/N15 produced selector catalog/report validation infrastructure, but those are supporting validation assets only.
@@ -41,7 +49,7 @@ Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-repor
- The project has not yet implemented production message sending, file download, or production file sending; `isphere_receive_messages`, `isphere_search_contacts`, `isphere_search_groups`, and `isphere_receive_files` list mode have operator-local encrypted log-file/log-directory support but not a production ingestion path. - The project has not yet implemented production message sending, file download, or production file sending; `isphere_receive_messages`, `isphere_search_contacts`, `isphere_search_groups`, and `isphere_receive_files` list mode have operator-local encrypted log-file/log-directory support but not a production ingestion path.
- The project has not completed production iSphere integration. - The project has not completed production iSphere integration.
- The project has not proven a stable real message source for the full business workflow beyond decrypted PacketReader log evidence and synthetic/redacted tests. - The project has not proven a stable real message source for the full business workflow beyond decrypted PacketReader log evidence and synthetic/redacted tests.
- The project has not implemented real message sending or real file upload. R6b adds preview/dry-run only; it does not prove send invocation, success/ack, or idempotent production behavior. - The project has not proven business-level message delivery or real file upload. A-route can perform UI write/click when explicitly configured, but local offline clicks do not prove server send, receiver delivery, success/ack, or sent-record evidence.
- N12-pre offline evidence is not N12 pass. - N12-pre offline evidence is not N12 pass.
- N13/N14/N15 selector/report work is pre-business evidence, not finished contact/message/file capability. - N13/N14/N15 selector/report work is pre-business evidence, not finished contact/message/file capability.
@@ -59,12 +67,14 @@ N13/N14/N15 are pre-business validation results. They can help identify UI eleme
## Current loop ## Current loop
Current loop: `R14 release-candidate report complete`; next step is evidence-driven production gate review. Current loop: `A-route real chat window merged to main`; next step is evidence-driven B-route send/file production verification, with A-route/RPA kept as backup readiness.
Active continuous execution plan: `docs/superpowers/plans/2026-07-10-r6f-r14-continuous-execution-plan.md`. Active continuous execution plan: `docs/superpowers/plans/2026-07-11-a-route-rpa-send.md`.
Previous roadmap file: `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`. Previous roadmap file: `docs/superpowers/plans/2026-07-10-core-business-capabilities-roadmap.md`.
Current business status correction: `docs/reports/2026-07-12-main-business-status-correction.md`.
Loop rule: Loop rule:
1. Write or update the plan before coding. 1. Write or update the plan before coding.
@@ -387,12 +397,23 @@ R14 release-candidate report is complete:
## A-route UIA send branch ## A-route UIA send branch
A-route UIA send branch is in progress on `codex/a-route-rpa-send`: A-route UIA send work has been merged into `main`:
- Route positioning: A-route/RPA is a fallback, not the primary product route. B-route sidecar/API connector evidence remains the preferred path for real send/file capability.
- User direction: do not add a product approval gate; implement function first and let the digital employee layer decide when to call it. - User direction: do not add a product approval gate; implement function first and let the digital employee layer decide when to call it.
- Added plan `docs\superpowers\plans\2026-07-11-a-route-rpa-send.md`. - Added plan `docs\superpowers\plans\2026-07-11-a-route-rpa-send.md`.
- Go connector request now carries raw `ContentText` only to the action connector; response and audit remain redacted. - Go connector request now carries raw `ContentText` only to the action connector; response and audit remain redacted.
- Added Go `uia-rpa` send connector adapter and env loader. - Added Go `uia-rpa` send connector adapter and env loader.
- Added C# helper op `uia_send_message` that sets the send editor text and invokes the send button through UI Automation. - Added C# helper op `uia_send_message` that sets the send editor text and invokes the send button through UI Automation.
- Synthetic local verification in `scripts\verify-win-helper.ps1` proves the helper can write to a WinForms send box and trigger a send button marker. - Synthetic local verification in `scripts\verify-win-helper.ps1` proves the helper can write to a WinForms send box and trigger a send button marker.
- Added `scripts\open-offline-real-frmP2PChat.ps1`, which opens a real offline/unlogged `frmP2PChat` and confirms `rtbSendMessage` / `btnSend` selectors.
- Visual real-window demo proved the local UI can accept text and receive a send-button click, but the client remains offline and reports that the message cannot be sent.
- Default MCP smoke still clears A-route env and remains preview/blocked unless explicitly configured. - Default MCP smoke still clears A-route env and remains preview/blocked unless explicitly configured.
2026-07-12 business correction:
- `isphere_send_message` now has two different readiness levels:
- preview/dry-run: stable MCP contract, no send.
- A-route UI action: configured UI write/click works against synthetic and real offline windows.
- It does **not** yet have verified online business delivery. Do not describe `clicked_ui=true` or helper `sent_message=true` as “消息已送达”.
- `isphere_send_file` remains preview-only for production file upload. The real offline UIA dump did not expose `btnSendFile` as a stable automation id, so file upload needs a separate toolbar/menu locator node.

View File

@@ -2,7 +2,7 @@
This runbook is for the first Go MCP phase of `isphere-ai-bridge`. It lets an operator build and verify the Windows helper and the Go MCP server without reading the source code. This runbook is for the first Go MCP phase of `isphere-ai-bridge`. It lets an operator build and verify the Windows helper and the Go MCP server without reading the source code.
Current scope: expose four WinHelper observation operations, four business read tools, and two preview-only send tools through Go MCP. Read tools are `isphere_receive_messages`, `isphere_search_contacts`, `isphere_search_groups`, and `isphere_receive_files` list mode plus download preview/blocked status. Send tools are `isphere_send_message` and `isphere_send_file` preview/dry-run only; production send/file upload is blocked. Read tools use an empty default message source unless `ISPHERE_PACKET_LOG_FILE` points to an operator-local encrypted PacketReader log-line file or `ISPHERE_PACKET_LOG_DIR` points to an operator-local directory of encrypted PacketReader `.log`/`.txt` files. Contact/group display names can also be optionally enriched from an operator-local copied `MsgLib.db` through the bounded read-only `MsgLibReadSidecar`; receive messages can use copied DB rows only when the caller explicitly passes `source_preference="msglib_readonly"`. Current scope: expose four WinHelper observation operations, four business read tools, one message-send tool, and one preview-only file-send tool through Go MCP. Read tools are `isphere_receive_messages`, `isphere_search_contacts`, `isphere_search_groups`, and `isphere_receive_files` list mode plus download preview/blocked status. `isphere_send_message` is preview/dry-run by default; when explicitly configured with `ISPHERE_SEND_CONNECTOR_MODE=uia_rpa` it can perform a UI write/click action against a configured chat HWND, but online business delivery is still unverified. `isphere_send_file` remains preview/dry-run only and production file upload is blocked. Read tools use an empty default message source unless `ISPHERE_PACKET_LOG_FILE` points to an operator-local encrypted PacketReader log-line file or `ISPHERE_PACKET_LOG_DIR` points to an operator-local directory of encrypted PacketReader `.log`/`.txt` files. Contact/group display names can also be optionally enriched from an operator-local copied `MsgLib.db` through the bounded read-only `MsgLibReadSidecar`; receive messages can use copied DB rows only when the caller explicitly passes `source_preference="msglib_readonly"`.
## 1. Prerequisites ## 1. Prerequisites
@@ -563,7 +563,9 @@ Current short answer:
- 已完成:搜索联系人、搜索群组、收消息基础读取、收文件列表。 - 已完成:搜索联系人、搜索群组、收消息基础读取、收文件列表。
- 可预览:发消息 preview、发文件 preview。 - 可预览:发消息 preview、发文件 preview。
- 阻断:生产发消息、真实文件下载、生产发文件 - A-route/RPA 是备选兜底,不是主线;主线仍是 B-route running-client sidecar / in-process connector / existing API
- A-route 已具备 UI 动作能力:显式配置后可以对聊天窗口写入文本并点击发送按钮;本地还可打开真实离线 `frmP2PChat` 验证窗口/输入框/按钮定位。
- 阻断:在线业务送达、真实文件下载、生产发文件。离线点击不等于服务端发送成功。
The two online evidence packages to send to an internal/logged-in operator are: The two online evidence packages to send to an internal/logged-in operator are:
@@ -576,7 +578,7 @@ They are generated under ignored `runs\` and are not committed.
## 18. A-route UIA send connector ## 18. A-route UIA send connector
A-route is the UI Automation fallback for text sending when the B-route sidecar cannot be tested. It is function-first: there is no human approval ID gate inside the connector. The digital employee layer is responsible for deciding when to call production mode. A-route is the UI Automation fallback for text sending when the B-route sidecar cannot be tested. It is function-first, but it is not the primary architecture. Prefer B-route running-client sidecar / in-process connector / existing API evidence whenever that route is available. There is no human approval ID gate inside the connector; the digital employee layer is responsible for deciding when to call production mode.
Local verification uses a synthetic WinForms window: Local verification uses a synthetic WinForms window:
@@ -590,6 +592,17 @@ Expected output includes helper version `0.5.0` and:
{"synthetic_uia_send_action":"uia_send_message"} {"synthetic_uia_send_action":"uia_send_message"}
``` ```
The project also has a real offline chat-window opener:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\open-offline-real-frmP2PChat.ps1 -RuntimeMode Deps -ShowWindow -HoldSeconds 1
```
That script opens the real `frmP2PChat` without login and confirms the key UIA
ids `frmP2PChat`, `rtbSendMessage`, `btnSend`, and `rtbRecvMessage`. The window
is still offline and will show the client-side “cannot send while offline”
message.
To enable A-route in a logged-in desktop session, configure the MCP server environment before startup: To enable A-route in a logged-in desktop session, configure the MCP server environment before startup:
```powershell ```powershell
@@ -603,6 +616,11 @@ $env:ISPHERE_SEND_UIA_HELPER_PATH = "E:\coding\codex\isphere-ai-bridge\runs\win-
Then call `isphere_send_message` with `execution_mode="production"`. The connector will set the send editor text and invoke the send button through UI Automation. Response metadata uses `connector_mode="uia-rpa"`; the audit still stores hashes and metadata, not the raw message body or raw idempotency key. Then call `isphere_send_message` with `execution_mode="production"`. The connector will set the send editor text and invoke the send button through UI Automation. Response metadata uses `connector_mode="uia-rpa"`; the audit still stores hashes and metadata, not the raw message body or raw idempotency key.
Important status boundary: helper fields such as `clicked_ui=true` or
`sent_message=true` mean the UI action ran. They do not prove server acceptance,
receiver delivery, or a sent-record match. Online/logged-in evidence is still
required before this can be called business-level send.
Standard `scripts\verify-go-mcp.ps1` clears all A-route env vars so the deterministic smoke remains preview/blocked by default. Standard `scripts\verify-go-mcp.ps1` clears all A-route env vars so the deterministic smoke remains preview/blocked by default.
## 19. Troubleshooting ## 19. Troubleshooting

View File

@@ -1,5 +1,9 @@
# Business Goals Smoke - 2026-07-10 # Business Goals Smoke - 2026-07-10
> 2026-07-12 校准A-route 已合并到 `main``isphere_send_message`
> 在显式 `uia_rpa` 配置下可以执行 UI 写入/点击;但业务送达仍未验证。
> 当前主状态见 `docs/reports/2026-07-12-main-business-status-correction.md`。
## 业务目标状态 ## 业务目标状态
| 目标 | 当前状态 | 说明 | | 目标 | 当前状态 | 说明 |

View File

@@ -1,5 +1,9 @@
# R6f-R14 Release Candidate Status - 2026-07-10 # R6f-R14 Release Candidate Status - 2026-07-10
> 2026-07-12 校准:本报告是 A-route 前的 R14 状态。后续 `main`
> 已具备显式配置下的发消息 UI 写入/点击能力,但在线业务送达仍未验证。
> 当前主状态见 `docs/reports/2026-07-12-main-business-status-correction.md`。
本报告是 R6f-R14 连续轮次的业务验收材料。结论先讲清楚:数字员工现在可以用搜索、收消息基础读取、收文件列表,以及发消息/发文件 preview生产发消息、真实下载文件、生产发文件仍然需要在线可登录环境返回证据。 本报告是 R6f-R14 连续轮次的业务验收材料。结论先讲清楚:数字员工现在可以用搜索、收消息基础读取、收文件列表,以及发消息/发文件 preview生产发消息、真实下载文件、生产发文件仍然需要在线可登录环境返回证据。
## Business capability status ## Business capability status

View File

@@ -0,0 +1,34 @@
# Main Business Status Correction - 2026-07-12
本报告校准 `main` 合并 A-route 后的业务状态避免把“UI 输入/点击”误写成“业务送达”。
## 四个目标当前状态
| 目标 | 当前业务状态 | 已有能力 | 剩余卡点 |
| --- | --- | --- | --- |
| 搜索联系人 | 基础可用 | `isphere_search_contacts` 支持 log-backed 候选和可选 MsgLib enrichment。 | 更丰富字段、成员层级属于后续增强。 |
| 搜索群组 | 基础可用 | `isphere_search_groups` 支持 groupchat/conference 候选、排序、去重和可选 MsgLib enrichment。 | 群成员/管理员层级属于后续增强。 |
| 收发消息 | 收消息基础可用;发消息 UI action ready在线业务送达未验证 | `isphere_receive_messages` 可从 PacketReader/log-backed 或显式 MsgLib readonly 读取;`isphere_send_message` preview 稳定A-route `uia_rpa` 可对真实/合成聊天窗口写入 `rtbSendMessage` 并点击 `btnSend`。 | 需要在线登录环境证明 server ack、接收方送达或 sent-record/content-hash after 证据。 |
| 收发文件 | 收文件 list 可用;发文件 preview 可用;真实下载/真实上传未完成 | `isphere_receive_files` 可列文件元数据并给出 download preview blocked/planned`isphere_send_file` 可做 allowed-dir SHA256/size preview。 | 真实下载需要 cache mapping/copy gate真实发文件需要文件按钮/菜单定位、上传 connector 和在线发送证据。 |
## A-route 合并后的精确定义
- 路线定位B-route/运行客户端 sidecar/API connector 仍是主线A-route/RPA 只是备选兜底,不作为默认产品架构。
- 已实现:打开真实离线 `frmP2PChat`,识别 `rtbSendMessage``btnSend``rtbRecvMessage`
- 已实现:`uia_send_message` 可以写入发送框并触发发送按钮。
- 未证明:在线登录态下消息被服务端接受、对方收到、或本地 sent-record 产生。
- 未实现:真实文件上传。真实离线 UIA dump 没有稳定暴露 `btnSendFile` automation id。
## 后续计划
1. 主线优先:继续验证 B-route running-client sidecar / in-process connector / existing API 的真实发送和文件能力。
2. 备选保持:把真实 `frmP2PChat` HWND 接入 `isphere_send_message``uia_rpa` connector形成可重复 UI action smoke但只作为 B-route 卡住时的兜底。
3. 在线消息验证:在可登录环境采集 before/after sent-record、content hash、ack/成功提示、idempotency 不重复发送证据。
4. 文件发送节点:优先找 B-route 上传/发送 connector如果继续卡住再单独定位真实工具栏/菜单里的文件按钮,做 RPA 上传动作和在线 evidence package。
5. 更新业务 smoke`send_message_ui_action_ready``send_message_business_delivery_ready` 拆成两个字段。
## 对外口径
可以说:数字员工已经具备联系人/群组搜索、收消息基础读取、收文件列表、发消息 preview、发消息 UI 操作能力。
不要说:数字员工已经能稳定在线发送消息或发送文件。当前还缺在线业务证据。

View File

@@ -3,6 +3,10 @@
日期2026-07-11 日期2026-07-11
分支:`codex/a-route-rpa-send` 分支:`codex/a-route-rpa-send`
> 2026-07-12 校准:本文记录的是 synthetic 离线探针阶段和当时的真实窗体构造阻塞。后续已经通过
> `scripts\open-offline-real-frmP2PChat.ps1` 在未登录/离线环境打开真实 `frmP2PChat`。
> 当前以 `docs/source-discovery/2026-07-11-a-route-open-real-chat-window.md` 为准。
## 本轮目标 ## 本轮目标
用户明确当前先不要求真实发送消息,只要求“打开那个会话窗口”,用来验证数字员工是否能: 用户明确当前先不要求真实发送消息,只要求“打开那个会话窗口”,用来验证数字员工是否能:
@@ -86,7 +90,7 @@ frmP2PChat(com.vision.smack.Chat chat, string pluginInfo, string extendTabJson)
- `ConfigSystemManager.config` - `ConfigSystemManager.config`
- `P2PChat.OtherJid` - `P2PChat.OtherJid`
仍未成功打开真实窗体。当前阻塞不再是脚本能力,而是构造函数内部把窗体初始化、登录态、连接态、名册状态、消息中心事件、配置状态混在一起。IL 证据显示构造函数中直接访问: 本节以下内容是当时的中间判断。后续 Task 7 已经补齐更多离线依赖并成功打开真实窗体,因此这里不再作为当前阻塞。它仍保留为风险索引:构造函数内部确实把窗体初始化、登录态、连接态、名册状态、消息中心事件、配置状态混在一起。IL 证据显示构造函数中直接访问:
- `IMPPManager.Instance.Connection.add_OnConnectError` - `IMPPManager.Instance.Connection.add_OnConnectError`
- `IMPPManager.Instance.Connection.add_OnReConnectOk` - `IMPPManager.Instance.Connection.add_OnReConnectOk`
@@ -98,7 +102,7 @@ frmP2PChat(com.vision.smack.Chat chat, string pluginInfo, string extendTabJson)
- `IMPPManager.Instance.RosterManager.UpdateStrangerStatus` - `IMPPManager.Instance.RosterManager.UpdateStrangerStatus`
- `Config.BaseConfig.VisualPhoneEnable` - `Config.BaseConfig.VisualPhoneEnable`
这说明真实 `frmP2PChat` 不是独立窗口类;它要求完整登录运行态。没有服务端/登录态时继续硬构造,投入会越来越像“重建一个假客户端运行时” 后续解决方式不是走正常登录链路,而是建立更完整的离线依赖 harness并在构造完成后补齐关键用户/JID/配置缓存。当前结论已变更为:真实 `frmP2PChat` 可以离线打开,但真实发送仍会被客户端离线状态阻断
## 当前业务结论 ## 当前业务结论
@@ -111,10 +115,10 @@ frmP2PChat(com.vision.smack.Chat chat, string pluginInfo, string extendTabJson)
- 点击结果可留本地审计 marker。 - 点击结果可留本地审计 marker。
- 全程不发真实消息、不上传真实文件。 - 全程不发真实消息、不上传真实文件。
从“真实 iSphere 会话窗口”的目标看,仍需要在线登录环境或继续补完整客户端运行态 从“真实 iSphere 会话窗口”的目标看,后续已完成离线打开真实 `frmP2PChat`。从“真实业务发送”的目标看,仍需要在线登录环境。
## 下一步建议 ## 下一步建议
1. 当前分支先使用 `open-offline-chat-window-probe.ps1` 验证 RPA 识别/定位/点击效果 1. synthetic 探针只作为回归兜底;真实窗口验证优先使用 `open-offline-real-frmP2PChat.ps1`
2. 在线环境拿到真实登录后的 `frmP2PChat` HWND 后,用同一套 WinHelper 选择器直接验证真实窗口 2. 把真实离线 `frmP2PChat` HWND 接入 `isphere_send_message``uia_rpa` connector做可重复 UI 写入/点击 smoke
3. 如果必须离线打开真实窗体,再继续走“补完整 IMPPManager/SmarkManager/Config/BaseConfig/MessageCenter 运行态”的破解路线 3. 在线环境拿到真实登录后的 `frmP2PChat` HWND 后,用同一套 WinHelper 选择器验证业务发送

View File

@@ -155,11 +155,23 @@ powershell -NoProfile -ExecutionPolicy Bypass -File scripts\open-offline-real-fr
- 本轮没有处理真实发送、真实上传、真实登录态。 - 本轮没有处理真实发送、真实上传、真实登录态。
- `btnSendFile` 在这次真实离线 UIA dump 中没有以 `btnSendFile` automation id 暴露;后续如果 RPA 需要上传文件,需要另开节点定位真实工具栏按钮或菜单路径。 - `btnSendFile` 在这次真实离线 UIA dump 中没有以 `btnSendFile` automation id 暴露;后续如果 RPA 需要上传文件,需要另开节点定位真实工具栏按钮或菜单路径。
## 2026-07-12 主分支状态校准
该能力已经随 A-route 分支合并到 `main`。业务含义如下:
- 已完成:真实离线 `frmP2PChat` 打开、UIA 识别、发送框定位、发送按钮定位。
- 已演示:在真实离线窗口内写入文本并点击 `btnSend`,可用于验证数字员工的窗口识别、定位和点击链路。
- 未完成:在线登录态下的真实发送、服务端 ack、接收方送达、发送记录匹配。
- 未完成:真实文件上传/发送。当前真实 UIA dump 没有稳定暴露 `btnSendFile`,文件发送要单独做工具栏/菜单定位。
因此,文档里出现的 helper `sent_message=true` 只能解释为“UI 发送动作已触发”,不能解释为“业务消息已送达”。
## 下一轮建议 ## 下一轮建议
1. 把 A-route RPA 的窗口定位目标从 synthetic probe 切到真实 `frmP2PChat` 1. 把 A-route RPA 的窗口定位目标从 synthetic probe 切到真实 `frmP2PChat`
- root `automation_id=frmP2PChat` - root `automation_id=frmP2PChat`
- send box `automation_id=rtbSendMessage` - send box `automation_id=rtbSendMessage`
- send button `automation_id=btnSend` - send button `automation_id=btnSend`
2. 如果弹出“企业信息获取失败”影响自动化,单独加一个非阻塞关闭弹窗步骤 2. 把真实窗口 HWND 接入 `isphere_send_message``uia_rpa` connector形成可重复的本地 UI 动作 smoke
3. 如果后续需要文件按钮,再专门分析真实工具栏图标按钮、菜单项和 `ToolStrip` 命中路径。 3. 在线登录环境中补一次业务发送验证发送前后记录、content hash、ack/发送记录、idempotency 不重复发送。
4. 如果后续需要文件按钮,再专门分析真实工具栏图标按钮、菜单项和 `ToolStrip` 命中路径。

View File

@@ -1,7 +1,7 @@
# A-route UIA Send Implementation Note # A-route UIA Send Implementation Note
Date: 2026-07-11 Date: 2026-07-11
Branch: `codex/a-route-rpa-send` Branch: implemented on `codex/a-route-rpa-send`, merged to `main`
## Decision ## Decision
@@ -25,6 +25,28 @@ $env:ISPHERE_SEND_UIA_BUTTON_AUTOMATION_ID = "btnSend"
Then call `isphere_send_message` with `execution_mode="production"`. Then call `isphere_send_message` with `execution_mode="production"`.
## Status correction after real-window work
`uia_send_message` is a UI action connector. Its helper result fields such as
`typed_text=true`, `clicked_ui=true`, and `sent_message=true` mean the editor was
written and the send button was invoked/clicked. They do not mean the server
accepted the message, the receiver got it, or a sent record was written.
After this note was first written, the project also opened a real offline
`frmP2PChat` window locally and confirmed:
- root: `frmP2PChat`
- editor: `rtbSendMessage`
- send button: `btnSend`
- receive area: `rtbRecvMessage`
The real offline window still shows the client-side offline-send blocker, so it
is useful for UI positioning and click verification, not for business delivery
verification.
## Remaining real-environment work ## Remaining real-environment work
The local environment still cannot log in to iSphere. The code path is implemented and locally proven against synthetic UIA, but real iSphere success still needs a logged-in window handle and one real run in the online environment. The local environment still cannot log in to iSphere. The code path is
implemented and locally proven against synthetic UIA plus the real offline chat
window, but real iSphere success still needs a logged-in window handle and one
online run with success/ack or sent-record evidence.

View File

@@ -0,0 +1,309 @@
# B-Route Bridge/IPC/Plugin Static Map
Date: 2026-07-12
## Scope
This report uses offline IL, binary string metadata, reflection metadata for `HttpServerLib.dll`, and returned live-probe JSON. It does not log in, open sockets, attach hooks, inject into a process, replay traffic, or mutate client binaries.
Machine-readable evidence: `runs/offline-broute-reverse/bridge-map.json`
Reflection metadata: `runs/offline-broute-reverse/httpserverlib-reflection.json`
## Recommendation
| Question | Answer |
| --- | --- |
| Should B-route pursue existing IPC/plugin before an in-process adapter? | **No** |
| Offline decision | `in_process_adapter_research` |
| External sidecar boundary | `external_sidecar_preview_only_until_bridge_exists` |
| Reason | Offline static evidence found no existing local IPC/plugin route that exposes send-message or send-file. HttpServerLib and plugin surfaces either require logged-in runtime state or are UI/framework-only; the named-pipe stub is empty. |
## Sources
### Text/IL sources
| Source | Role | Exists | Lines | Size bytes |
| --- | --- | --- | ---: | ---: |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il` | main client IL; login, plugin manager, local HTTP starter, chat/runtime | yes | 1360035 | 74148460 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il` | common helpers; WinCommand, ProcessComm, DTOs | yes | 118343 | 5703293 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ISphere.exe.il` | ISphere companion app IL; CEF and command helpers | yes | 81273 | 5679074 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.UI.dll.il` | UI/browser support IL | yes | 242314 | 13545362 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il` | file service implementation IL | yes | 3351 | 207786 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il` | XMPP/socks5/network IL | yes | 87425 | 5019807 |
### Binary/string sources
| Source | Role | Exists | Strings | Size bytes |
| --- | --- | --- | ---: | ---: |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll` | local HTTP server framework binary | yes | 555 | 26624 |
| `runs\offline-real-client-window\full\zyl\Impp\IMPlatformClient.Web.exe` | CEF/web helper process binary | yes | 185 | 9216 |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll` | native network abstraction | yes | 563 | 87552 |
| `runs\offline-real-client-window\full\zyl\Impp\IOClientNetwork.dll` | native network implementation | yes | 870 | 145920 |
| `runs\offline-real-client-window\full\zyl\Impp\IMPlatformClient.exe` | main client binary | yes | 76877 | 8366592 |
## Candidate classification
| Candidate | Category | Classification | Usable for B-route send | Recommendation | Matches |
| --- | --- | --- | --- | --- | ---: |
| `frmLogin.StartWinServer / HttpServerLib.HttpService` | `localhost_http` | `requires_logged_in_process` | no | `do_not_pursue_before_in_process_adapter` | 31 |
| `HttpServerLib route/module framework` | `localhost_http` | `static_only_unknown` | no | `no_existing_ipc_first` | 8 |
| `PluginLightAppMulProcessCommunication NamedPipeServerStream` | `named_pipe` | `not_a_bridge` | no | `do_not_use` | 17 |
| `IMPP.Common.Helper.ProcessComm WM_COPYDATA helper` | `window_message` | `static_only_unknown` | no | `not_a_send_bridge` | 164 |
| `PluginManager / IMPlugin command surface` | `plugin` | `requires_logged_in_process` | no | `plugin_extension_not_first` | 2696 |
| `IMPlatformClient.Web / CEF helper` | `child_process` | `requires_logged_in_process` | no | `preview_only_not_send` | 343 |
| `INetwork / IOClientNetwork native stack` | `native_network` | `not_a_bridge` | no | `do_not_pursue_as_ipc` | 72 |
| `returned live-probe named pipe inventory` | `named_pipe` | `static_only_unknown` | no | `do_not_assume_isphere_api` | 49 |
| `local TcpListener candidates` | `tcp_listener` | `not_a_bridge` | no | `not_existing_ipc` | 145 |
## Verified facts
- `frmLogin.StartWinServer` constructs `HTTPServerLib.HttpService` on `0.0.0.0` and starts `HttpServer.Start` in a thread, but it depends on `IMPPManager.UserInfo` and `ServiceManager.UnifiedAuthentication` state.
- `HttpServerLib.dll` exposes route/module primitives such as `HttpService.RegisterModule`, `ServiceModule`, `ServiceRoute`, `RouteAttribute`, `OnGet`, and `OnPost`.
- Main client IL does not show a concrete `RegisterModule` call or send-message/send-file HTTP route registration.
- `PluginLightAppMulProcessCommunication` declares a `NamedPipeServerStream` field, but `StartLightAppMultProssCommunication` returns immediately.
- Returned live probe showed one remote TCP connection to port `10088` and a named pipe `\\.\\pipe\\zfpinject-msg-server`; neither proves an iSphere send API.
- `PluginManager`/`IMPlugin` evidence is UI/app-store/context-menu oriented; no local assembly-load plugin bridge or send route was confirmed.
## Candidate evidence
### frmLogin.StartWinServer / HttpServerLib.HttpService
Classification: `requires_logged_in_process`; usable for B-route send: `False`; matches: 31.
Reason: Static IL builds a local HTTP service from logged-in user/auth state, but no send route or active live local listener was confirmed.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:223` | `reference` | `.assembly extern HttpServerLib` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:888716` | `reference` | `RepairDatabase() cil managed` | `L888715: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:888818` | `string_literal` | `IL_00f8: ldstr "{0}/ifim/messageAuth\?version={1}&user={2}&resource"` | `L888715: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:888944` | `string_literal` | `IL_0287: ldstr "RepairDatabase.exe"` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889041` | `method_end` | `} // end of method frmLogin::RepairDatabase` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889166` | `callsite` | `IL_004d: call instance void IMPP.Client.frmLogin::RepairDatabase()` | `L889120: .method private hidebysig instance bool` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889253` | `signature_continuation` | `StartWinServer() cil managed` | `L889252: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889272` | `reference` | `class [HttpServerLib]HTTPServerLib.HttpService V_15,` | `L889252: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889518` | `callsite` | `IL_0276: call instance int32 IMPP.Client.frmLogin::GetFreePort(int32[])` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889551` | `string_literal` | `IL_02d3: ldstr "0.0.0.0"` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889554` | `constructor_call` | `IL_02dc: newobj instance void [HttpServerLib]HTTPServerLib.HttpService::.ctor(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889559` | `reference` | `IL_02e5: ldftn instance void [HttpServerLib]HTTPServerLib.HttpServer::Start()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889677` | `method_end` | `} // end of method frmLogin::StartWinServer` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889680` | `signature_continuation` | `GetFreePort(int32[] portArray) cil managed` | `L889679: .method private hidebysig instance int32` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889798` | `method_end` | `} // end of method frmLogin::GetFreePort` | `L889679: .method private hidebysig instance int32` |
| `runs\offline-broute-reverse\httpserverlib-reflection.json` | `reflection_metadata` | `HttpServerLib reflection exposes matching types/methods; see httpserverlib-reflection.json` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str10` | `binary_string` | `HttpServerLib.dll` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str12` | `binary_string` | `HTTPServerLib` | `` |
### HttpServerLib route/module framework
Classification: `static_only_unknown`; usable for B-route send: `False`; matches: 8.
Reason: HttpServerLib has ServiceModule/RouteAttribute primitives, but client IL does not show RegisterModule or send-message routes.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-broute-reverse\httpserverlib-reflection.json` | `reflection_metadata` | `HttpServerLib reflection exposes matching types/methods; see httpserverlib-reflection.json` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str21` | `binary_string` | `RouteAttribute` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str22` | `binary_string` | `RouteMethod` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str23` | `binary_string` | `ServiceModule` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str24` | `binary_string` | `ServiceRoute` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str292` | `binary_string` | `RegisterModule` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str302` | `binary_string` | `SearchRoute` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\HttpServerLib.dll#str303` | `binary_string` | `ExecuteRoute` | `` |
### PluginLightAppMulProcessCommunication NamedPipeServerStream
Classification: `not_a_bridge`; usable for B-route send: `False`; matches: 17.
Reason: A NamedPipeServerStream field exists, but StartLightAppMultProssCommunication has a one-instruction ret body.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9039` | `type_definition` | `.class private auto ansi beforefieldinit IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication` | `L9012: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9042` | `reference` | `.field private static class IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication _instance` | `L9012: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9043` | `reference` | `.field private class [System.Core]System.IO.Pipes.NamedPipeServerStream _pipeServer` | `L9012: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9052` | `method_end` | `} // end of method PluginLightAppMulProcessCommunication::.ctor` | `L9044: .method private hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9058` | `constructor_call` | `IL_0000: newobj instance void IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::.ctor()` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9059` | `reference` | `IL_0005: stsfld class IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::_instance` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9060` | `reference` | `IL_000a: ldsfld class IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::_instance` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9061` | `callsite` | `IL_000f: callvirt instance void IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::StartLightAppMultProssCommunication()` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9063` | `method_end` | `} // end of method PluginLightAppMulProcessCommunication::Init` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9066` | `reference` | `StartLightAppMultProssCommunication() cil managed` | `L9065: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9071` | `method_end` | `} // end of method PluginLightAppMulProcessCommunication::StartLightAppMultProssCommunication` | `L9065: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9079` | `method_end` | `} // end of method PluginLightAppMulProcessCommunication::.cctor` | `L9073: .method private hidebysig specialname rtspecialname static` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9081` | `reference` | `} // end of class IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication` | `L9073: .method private hidebysig specialname rtspecialname static` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:217833` | `callsite` | `IL_0071: call void IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::Init()` | `L217793: .method private hidebysig specialname rtspecialname` |
| `runs\offline-real-client-window\full\zyl\Impp\IMPlatformClient.exe#str2852` | `binary_string` | `NamedPipeServerStream` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\IMPlatformClient.exe#str6922` | `binary_string` | `PluginLightAppMulProcessCommunication` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\IMPlatformClient.exe#str8523` | `binary_string` | `StartLightAppMultProssCommunication` | `` |
### IMPP.Common.Helper.ProcessComm WM_COPYDATA helper
Classification: `static_only_unknown`; usable for B-route send: `False`; matches: 164.
Reason: ProcessComm can send WM_COPYDATA to a foreground or titled window, but no receive handler or send-command contract is confirmed.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:271124` | `reference` | `native int GetForegroundWindow() cil managed preservesig` | `L271123: .method public hidebysig static pinvokeimpl("user32.dll" winapi)` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:278221` | `type_definition` | `.class sequential ansi sealed nested private beforefieldinit COPYDATASTRUCT` | `L278204: .method private hidebysig static object` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:278227` | `reference` | `} // end of class COPYDATASTRUCT` | `L278204: .method private hidebysig static object` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:279144` | `reference` | `.field private static literal int32 WM_COPYDATA = int32(0x0000004A)` | `L279026: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:282985` | `reference` | `int32 FindWindow(string lpClassName,` | `L282984: .method private hidebysig static pinvokeimpl("user32.dll" winapi)` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:317869` | `callsite` | `IL_3827: call native int IMPP.Client.utils.Utils::GetForegroundWindow()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:412102` | `callsite` | `IL_3613: call native int IMPP.Client.utils.Utils::GetForegroundWindow()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:543733` | `reference` | `.field public static literal int32 WM_COPYDATA = int32(0x0000004A)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:660716` | `reference` | `.locals init (valuetype IMPP.Client.Business.Logon.Native/COPYDATASTRUCT V_0,` | `L660712: .method public hidebysig static bool DefWndProc(valuetype [System.Windows.Forms]System.Windows.Forms.Message& m) cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:660731` | `reference` | `valuetype IMPP.Client.Business.Logon.Native/COPYDATASTRUCT V_15,` | `L660712: .method public hidebysig static bool DefWndProc(valuetype [System.Windows.Forms]System.Windows.Forms.Message& m) cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:660735` | `reference` | `valuetype IMPP.Client.Business.Logon.Native/COPYDATASTRUCT V_19,` | `L660712: .method public hidebysig static bool DefWndProc(valuetype [System.Windows.Forms]System.Windows.Forms.Message& m) cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:660746` | `reference` | `valuetype IMPP.Client.Business.Logon.Native/COPYDATASTRUCT V_30,` | `L660712: .method public hidebysig static bool DefWndProc(valuetype [System.Windows.Forms]System.Windows.Forms.Message& m) cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:661348` | `reference` | `IL_06b6: initobj IMPP.Client.Business.Logon.Native/COPYDATASTRUCT` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:661350` | `reference` | `IL_06bd: ldtoken IMPP.Client.Business.Logon.Native/COPYDATASTRUCT` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:661353` | `reference` | `IL_06cc: unbox.any IMPP.Client.Business.Logon.Native/COPYDATASTRUCT` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:661356` | `reference` | `IL_06d5: ldfld int32 IMPP.Client.Business.Logon.Native/COPYDATASTRUCT::cbData` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:661360` | `reference` | `IL_06e3: ldfld native int IMPP.Client.Business.Logon.Native/COPYDATASTRUCT::lpData` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:661446` | `reference` | `IL_07e8: stfld native int IMPP.Client.Business.Logon.Native/COPYDATASTRUCT::dwData` | `` |
### PluginManager / IMPlugin command surface
Classification: `requires_logged_in_process`; usable for B-route send: `False`; matches: 2696.
Reason: Plugin evidence is UI/app-store/context-menu oriented and depends on logged-in PluginManager state; no Assembly.Load/LoadFrom or send API bridge was confirmed.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1048` | `reference` | `.mresource public IMPP.Client.Core.Plugins.Manager.FrmAppStore.resources` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1051` | `reference` | `// 警告: 创建了托管资源文件 IMPP.Client.Core.Plugins.Manager.FrmAppStore.resources` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1063` | `reference` | `.mresource public IMPP.Client.Core.Plugins.Manager.WindowForm.FrmCefHomePage.resources` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1066` | `reference` | `// 警告: 创建了托管资源文件 IMPP.Client.Core.Plugins.Manager.WindowForm.FrmCefHomePage.resources` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:82622` | `callsite` | `IL_0156: call class IMPP.Client.Core.Plugins.Manager.PluginManager IMPP.Client.Core.Plugins.Manager.PluginManager::GetInstance()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:82623` | `callsite` | `IL_015b: callvirt instance class [mscorlib]System.Collections.Generic.List`1<class IMPP.Client.Core.Plugins.Manager.IMPlugin> IMPP.Client.Core.Plugins.Manager.PluginManager::GetPluginList()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:85884` | `callsite` | `IL_0157: call class IMPP.Client.Core.Plugins.Manager.PluginManager IMPP.Client.Core.Plugins.Manager.PluginManager::GetInstance()` | `L85783: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:85890` | `callsite` | `IL_0168: callvirt instance void IMPP.Client.Core.Plugins.Manager.PluginManager::add_PluginMessageNotify(class [IMPP.Interface]IMPP.Interface.PluginMessageEventHandler)` | `L85783: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:88002` | `callsite` | `IL_045d: call class IMPP.Client.Core.Plugins.Manager.PluginManager IMPP.Client.Core.Plugins.Manager.PluginManager::GetInstance()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:88007` | `callsite` | `IL_0470: callvirt instance void IMPP.Client.Core.Plugins.Manager.PluginManager::DoNotifyAction(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:90512` | `callsite` | `IL_0111: call void IMPP.Client.Core.Plugins.Manager.PluginUtils::LoadPluginContextMenu(class [System.Windows.Forms]System.Windows.Forms.ContextMenuStrip,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:90677` | `callsite` | `IL_016d: call void IMPP.Client.Core.Plugins.Manager.PluginUtils::LoadPluginContextMenu(class [System.Windows.Forms]System.Windows.Forms.ContextMenuStrip,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:91111` | `callsite` | `IL_00f8: call void IMPP.Client.Core.Plugins.Manager.PluginUtils::LoadPluginContextMenu(class [System.Windows.Forms]System.Windows.Forms.ContextMenuStrip,` | `L91000: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:91274` | `callsite` | `IL_00cb: call void IMPP.Client.Core.Plugins.Manager.PluginUtils::LoadPluginContextMenu(class [System.Windows.Forms]System.Windows.Forms.ContextMenuStrip,` | `L91188: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:105364` | `callsite` | `IL_03c1: callvirt instance string IMPP.Client.Core.Plugins.Manager.IMPlugin::get_Command()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:105401` | `callsite` | `IL_042d: call class IMPP.Client.Core.Plugins.Manager.PluginManager IMPP.Client.Core.Plugins.Manager.PluginManager::GetInstance()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:105402` | `callsite` | `IL_0432: callvirt instance class [mscorlib]System.Collections.Generic.List`1<class IMPP.Client.Core.Plugins.Manager.IMPlugin> IMPP.Client.Core.Plugins.Manager.PluginManager::GetPluginList()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:217227` | `reference` | `class IMPP.Client.Core.Plugins.Manager.PluginManager V_3,` | `L217219: .method public hidebysig newslot virtual final` |
### IMPlatformClient.Web / CEF helper
Classification: `requires_logged_in_process`; usable for B-route send: `False`; matches: 343.
Reason: The web helper/CEF surface exists, but static evidence points to UI/plugin browser support, not an external send/file API.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:278553` | `reference` | `.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `L278527: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300455` | `reference` | `IL_0428: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300465` | `string_literal` | `IL_0442: ldstr "NavigateTo"` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300492` | `callsite` | `IL_0477: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.Compi...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300493` | `reference` | `IL_047c: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300500` | `reference` | `IL_048f: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300501` | `reference` | `IL_0494: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300502` | `reference` | `IL_0499: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300504` | `callsite` | `IL_04a0: callvirt instance class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.WinCefBrowser IMPP.Client.Core.Plugins.Manager.WindowForm.frmPluginTabCtrl::get_CefBrowser()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:300506` | `callsite` | `IL_04a6: callvirt instance void class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.WinCefBrowser,object>::Invoke(!0,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:388726` | `reference` | `.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `L388681: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:413211` | `callsite` | `IL_0266: callvirt instance class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.WinCefBrowser IMPP.Client.Business.ISphereAssistant.frmExtendTabCtrl::get_CefBrowser()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:413215` | `callsite` | `IL_0277: callvirt instance void [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.WinCefBrowser::NavigateTo(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:414754` | `reference` | `IL_0b96: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:414764` | `string_literal` | `IL_0bb0: ldstr "NavigateTo"` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:414791` | `callsite` | `IL_0be5: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.Compi...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:414792` | `reference` | `IL_0bea: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:414799` | `reference` | `IL_0bfd: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite,class [IMPP.Cef4CSharp]IMPP.Cef4CSharp.Win.Wi...` | `` |
### INetwork / IOClientNetwork native stack
Classification: `not_a_bridge`; usable for B-route send: `False`; matches: 72.
Reason: Native NETIO send/recv symbols are low-level transport, not a local command bridge into logged-in chat objects.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str249` | `binary_string` | `D:\work\me\sourcecode\app_project\Network_node\bin\release\INetwork.pdb` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str314` | `binary_string` | `INetwork.dll` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str317` | `binary_string` | `??0StreamClientBase@@QAE@ABV0@@Z` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str318` | `binary_string` | `??0StreamClientBase@@QAE@XZ` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str319` | `binary_string` | `??0StreamClientChannel@@QAE@ABV0@@Z` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str320` | `binary_string` | `??0StreamClientChannel@@QAE@XZ` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str321` | `binary_string` | `??0StreamClientFrameSink@@QAE@ABV0@@Z` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str322` | `binary_string` | `??0StreamClientFrameSink@@QAE@XZ` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str323` | `binary_string` | `??0StreamClientMsg@@QAE@ABV0@@Z` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str324` | `binary_string` | `??0StreamClientMsg@@QAE@XZ` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str325` | `binary_string` | `??0StreamClientMsgSink@@QAE@ABV0@@Z` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str326` | `binary_string` | `??0StreamClientMsgSink@@QAE@XZ` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str327` | `binary_string` | `??0StreamClientNetEventSink@@QAE@ABV0@@Z` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str328` | `binary_string` | `??0StreamClientNetEventSink@@QAE@XZ` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str329` | `binary_string` | `??0StreamClientRecverEventSink@@QAE@ABV0@@Z` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str330` | `binary_string` | `??0StreamClientRecverEventSink@@QAE@XZ` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str331` | `binary_string` | `??0StreamClientSenderEventSink@@QAE@ABV0@@Z` | `` |
| `runs\offline-real-client-window\full\zyl\Impp\INetwork.dll#str332` | `binary_string` | `??0StreamClientSenderEventSink@@QAE@XZ` | `` |
### returned live-probe named pipe inventory
Classification: `static_only_unknown`; usable for B-route send: `False`; matches: 49.
Reason: Live probe saw \\.\\pipe\\zfpinject-msg-server, but no matching iSphere static string or send contract was found in the configured samples.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:905746` | `reference` | `frmMain_OnReConnectionSucceed(object sender,` | `L905745: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:905814` | `reference` | `IL_0081: ldftn void IMPP.Client.frmMain::'<frmMain_OnReConnectionSucceed>b__4'()` | `L905745: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:905828` | `method_end` | `} // end of method frmMain::frmMain_OnReConnectionSucceed` | `L905745: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:919019` | `reference` | `IL_006e: ldftn instance void IMPP.Client.frmMain::frmMain_OnReConnectionSucceed(object,` | `L918967: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:919023` | `callsite` | `IL_0079: callvirt instance void [smack]com.vision.smack.XMPPConnection::add_OnReConnectionSucceed(class [mscorlib]System.EventHandler)` | `L918967: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:928079` | `method_header` | `.method private hidebysig static void '<frmMain_OnReConnectionSucceed>b__4'() cil managed` | `L928079: .method private hidebysig static void '<frmMain_OnReConnectionSucceed>b__4'() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:928087` | `method_end` | `} // end of method frmMain::'<frmMain_OnReConnectionSucceed>b__4'` | `L928079: .method private hidebysig static void '<frmMain_OnReConnectionSucceed>b__4'() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1126866` | `reference` | `IL_00e2: ldftn instance void IMPP.Client.Business.ReConnection.WindowForm.FrmReConnection::OnReConnectionSucceed(object,` | `L1126773: .method private hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1126870` | `callsite` | `IL_00ed: callvirt instance void [smack]com.vision.smack.XMPPConnection::add_OnReConnectionSucceed(class [mscorlib]System.EventHandler)` | `L1126773: .method private hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1127782` | `reference` | `OnReConnectionSucceed(object sender,` | `L1127781: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1127841` | `reference` | `IL_0069: ldftn instance void IMPP.Client.Business.ReConnection.WindowForm.FrmReConnection::'<OnReConnectionSucceed>b__0'()` | `L1127781: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1127855` | `method_end` | `} // end of method FrmReConnection::OnReConnectionSucceed` | `L1127781: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1127979` | `reference` | `'<OnReConnectionSucceed>b__0'() cil managed` | `L1127978: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1127987` | `method_end` | `} // end of method FrmReConnection::'<OnReConnectionSucceed>b__0'` | `L1127978: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ISphere.exe.il:33510` | `reference` | `IL_00e2: ldftn instance void IMPP.ISphere.IMPPManage.FrmReConnection::OnReConnectionSucceed(object,` | `L33417: .method private hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ISphere.exe.il:33514` | `callsite` | `IL_00ed: callvirt instance void [smack]com.vision.smack.XMPPConnection::add_OnReConnectionSucceed(class [mscorlib]System.EventHandler)` | `L33417: .method private hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ISphere.exe.il:34155` | `reference` | `OnReConnectionSucceed(object sender,` | `L34154: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ISphere.exe.il:34182` | `reference` | `IL_0031: ldftn instance void IMPP.ISphere.IMPPManage.FrmReConnection::'<OnReConnectionSucceed>b__0'()` | `L34154: .method private hidebysig instance void` |
### local TcpListener candidates
Classification: `not_a_bridge`; usable for B-route send: `False`; matches: 145.
Reason: TcpListener evidence is tied to TCP file manage or smack socks5, not a command API for text/file send. Returned live probe had only one remote XMPP connection.
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889833` | `callsite` | `IL_003c: callvirt instance class [System]System.Net.IPEndPoint[] [System]System.Net.NetworkInformation.IPGlobalProperties::GetActiveTcpListeners()` | `L889800: .method private hidebysig instance bool` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1117108` | `reference` | `.field private static class [System]System.Net.Sockets.TcpListener _listener` | `L1117034: .method public hidebysig instance bool` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1118022` | `reference` | `IL_0058: ldsfld class [System]System.Net.Sockets.TcpListener IMPP.Client.Business.TCPFileManage.TCPFileManager::_listener` | `L1117985: .method public hidebysig static class [System]System.Net.IPEndPoint` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1118096` | `reference` | `IL_011e: ldsfld class [System]System.Net.Sockets.TcpListener IMPP.Client.Business.TCPFileManage.TCPFileManager::_listener` | `L1117985: .method public hidebysig static class [System]System.Net.IPEndPoint` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1118097` | `callsite` | `IL_0123: callvirt instance class [System]System.Net.EndPoint [System]System.Net.Sockets.TcpListener::get_LocalEndpoint()` | `L1117985: .method public hidebysig static class [System]System.Net.IPEndPoint` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1118817` | `callsite` | `IL_0091: callvirt instance class [System]System.Net.IPEndPoint[] [System]System.Net.NetworkInformation.IPGlobalProperties::GetActiveTcpListeners()` | `L1118746: .method public hidebysig static int32 FindFreeTCPPort([opt] int32 startPort) cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1119636` | `reference` | `IL_0009: stsfld class [System]System.Net.Sockets.TcpListener IMPP.Client.Business.TCPFileManage.TCPFileManager::_listener` | `L1119622: .method private hidebysig specialname rtspecialname static` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:64917` | `reference` | `.field private class com.vision.smack.socks5.TCPSocks5Server '<Server>k__BackingField'` | `L64879: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:64926` | `signature_continuation` | `instance void .ctor(class com.vision.smack.socks5.TCPSocks5Server server,` | `L64925: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:64935` | `callsite` | `IL_0008: call instance void com.vision.smack.socks5.TCPSocks5Connection::set_Server(class com.vision.smack.socks5.TCPSocks5Server)` | `L64925: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:64942` | `method_header` | `.method private hidebysig specialname instance class com.vision.smack.socks5.TCPSocks5Server` | `L64942: .method private hidebysig specialname instance class com.vision.smack.socks5.TCPSocks5Server` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:64949` | `reference` | `IL_0001: ldfld class com.vision.smack.socks5.TCPSocks5Server com.vision.smack.socks5.TCPSocks5Connection::'<Server>k__BackingField'` | `L64942: .method private hidebysig specialname instance class com.vision.smack.socks5.TCPSocks5Server` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:64954` | `reference` | `set_Server(class com.vision.smack.socks5.TCPSocks5Server 'value') cil managed` | `L64953: .method private hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:64961` | `reference` | `IL_0002: stfld class com.vision.smack.socks5.TCPSocks5Server com.vision.smack.socks5.TCPSocks5Connection::'<Server>k__BackingField'` | `L64953: .method private hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:65018` | `callsite` | `IL_0001: call instance class com.vision.smack.socks5.TCPSocks5Server com.vision.smack.socks5.TCPSocks5Connection::get_Server()` | `L65012: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:65019` | `callsite` | `IL_0006: callvirt instance bool com.vision.smack.socks5.TCPSocks5Server::get_IsStarting()` | `L65012: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:65027` | `callsite` | `IL_0016: call instance class com.vision.smack.socks5.TCPSocks5Server com.vision.smack.socks5.TCPSocks5Connection::get_Server()` | `L65012: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:65028` | `callsite` | `IL_001b: callvirt instance bool com.vision.smack.socks5.TCPSocks5Server::get_RequireValidate()` | `L65012: .method private hidebysig instance void` |
## Decision
No existing IPC/plugin/local HTTP bridge is confirmed usable for B-route text send or file send. The next B-route branch should be `in_process_adapter_research`. Until that exists, an external sidecar can only do preview/probe work, while A-route/RPA remains backup-only.
## Next work
1. Update the B-route next plan and capability source matrix with `in_process_adapter_research` as the offline decision.
2. Create a separate plan before implementing any in-process adapter work.
3. Do not promote RPA beyond backup in this branch.

View File

@@ -0,0 +1,230 @@
# B-Route File Send Static Map
Date: 2026-07-12
## Scope
This report uses offline IL only. It does not upload files, send file messages, replay traffic, inject into a process, or mutate the original iSphere binaries.
Machine-readable evidence: `runs/offline-broute-reverse/file-send-map.json`
## Sources
| Source | Role | Exists | Lines | Size bytes |
| --- | --- | --- | ---: | ---: |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il` | main client IL; UC_FileSend, OffLineFileSend, MessageScheduling | yes | 1360035 | 74148460 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il` | file transfer service implementation | yes | 3351 | 207786 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il` | file transfer contracts, parameters, and result DTOs | yes | 1641 | 93585 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Interface.dll.il` | transport/event interface contracts | yes | 4429 | 227335 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il` | Chat.sendFileMessage and XMPP message construction | yes | 87425 | 5019807 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\TcpFileTransfer.dll.il` | native TCP transfer candidate; IL may be unavailable | yes | 5 | 241 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Model.dll.il` | chat record models if extracted | no | 0 | |
## Target classification
| Target | Phase | Intent | Classification | Matches |
| --- | --- | --- | --- | ---: |
| `IMPP.Client.OffLineFileSend.sendFile` | `upload` | offline file upload orchestration from UI file sender | `confirmed_signature` | 3 |
| `IMPP.Client.OffLineFileSend.trans_UploadCompleted` | `upload_to_message_boundary` | upload-completed handler that converts FileUploadResult.FileID into a chat file message | `confirmed_signature` | 3 |
| `IMPP.Service.BLL.FileTransfer.FileUpload` | `upload` | synchronous service upload entry returning FileUploadResult | `confirmed_signature` | 17 |
| `IMPP.Service.BLL.FileTransfer.AsynFileUpload` | `upload` | asynchronous upload queue entry | `confirmed_signature` | 3 |
| `FileUploadPara` | `upload_parameters` | host/port/domain/local file path/cache/timeout/upload flags | `confirmed_signature` | 66 |
| `FileUploadResult.FileID` | `upload_result` | server-side file id and URL returned by upload | `confirmed_signature` | 75 |
| `MessageScheduling.SendFileMessage` | `message` | scheduled/file-message finalization path using RosterContactsArgs and FileTransferArgs | `confirmed_signature` | 3 |
| `Chat.sendFileMessage` | `message` | smack API that sends the XMPP file message after upload metadata is known | `confirmed_signature` | 8 |
| `Required values: path id size target jid` | `requirements` | static evidence for local file path, remote folder/file id, file size/name, target JID/chat, and server auth | `confirmed_signature` | 550 |
## Upload step vs chat-message step
| Step | Static evidence | Business meaning |
| --- | --- | --- |
| 1. Upload | `IMPP.Client.OffLineFileSend.sendFile` constructs `FileUploadPara` and calls `IFileTransfer.FileUpload`; `IMPP.Service.BLL.FileTransfer.FileUpload` delegates to `SyncFileTransfer` and private `Upload`. | The local file must be uploaded to the HTTP file service first. |
| 2. Upload result | `FileUploadResult.FileID` is read; upload notification calls `IMPP.Client.OffLineFileSend.trans_UploadCompleted(fileId)`. | The server-issued file id becomes the durable reference. |
| 3. Chat file message | `trans_UploadCompleted` and `MessageScheduling.SendFileMessage` build `OFFLINE_FILE_TRANSFER;...` payloads and call `Chat.sendFileMessage`. | The chat send step publishes metadata/reference, not raw file bytes. |
Conclusion: file send is upload-first, chat-message-second. A direct chat message is insufficient without a valid uploaded file id or remote folder reference.
## Required values
| Value | Status | Evidence |
| --- | --- | --- |
| local file path | `required_confirmed` | OffLineFileSend constructor receives localFilePath; sendFile uses get__localFilePath; MessageScheduling.SendFileMessage uses FileTransferArgs.get_LocalFilePath. |
| server file id / remote folder | `required_confirmed` | Upload returns FileUploadResult.FileID; trans_UploadCompleted(fileId) passes it to Chat.sendFileMessage and Packet.set_id. MessageScheduling path uses FileTransferArgs.get_RemoteFolder. |
| file name and file size | `required_confirmed` | SendFileMessage builds OFFLINE_FILE_TRANSFER payload from FileInfo/FileSystemInfo name and length; OffLineFileSend keeps _fileSize. |
| target JID / chat object | `required_confirmed` | UC_FileSend and MessageScheduling both require a live smack Chat; scheduled path derives it from RosterContactsArgs.get_RosterJid + UtilsChat.GetChat. |
| HTTP file server and auth | `required_confirmed` | FileUploadPara construction uses Config.ServerInfo.HTTPFileServer IP/Port/domain; service upload builds /FS/auth/resource/upload URL with UnifiedAuthentication token/app key/client secret/time/user id. |
| file hash | `not_confirmed_in_file_send_path` | No file-transfer-path MD5/SHA/checksum requirement was confirmed in the configured IL. MD5 hits belong to image/RTF or auth digest areas, not the offline file-send path. |
## Evidence excerpts
### IMPP.Client.OffLineFileSend.sendFile
Classification: `confirmed_signature`; phase: `upload`; matches: 3.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826149` | `signature_continuation` | `sendFile() cil managed` | `L826148: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826572` | `method_end` | `} // end of method OffLineFileSend::sendFile` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:824164` | `callsite` | `IL_026b: callvirt instance void IMPP.Client.OffLineFileSend::sendFile()` | `` |
### IMPP.Client.OffLineFileSend.trans_UploadCompleted
Classification: `confirmed_signature`; phase: `upload_to_message_boundary`; matches: 3.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826888` | `signature_continuation` | `trans_UploadCompleted(string fileId) cil managed` | `L826887: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:827241` | `method_end` | `} // end of method OffLineFileSend::trans_UploadCompleted` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826670` | `callsite` | `IL_0104: call instance void IMPP.Client.OffLineFileSend::trans_UploadCompleted(string)` | `L826574: .method private hidebysig instance void` |
### IMPP.Service.BLL.FileTransfer.FileUpload
Classification: `confirmed_signature`; phase: `upload`; matches: 17.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:851` | `signature_continuation` | `FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara para) cil managed` | `L849: .method public hidebysig newslot virtual final` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:870` | `method_end` | `} // end of method FileTransfer::FileUpload` | `L849: .method public hidebysig newslot virtual final` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:873` | `signature_continuation` | `instance void AsynFileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara para) cil managed` | `L872: .method public hidebysig newslot virtual final` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:164` | `method_end` | `} // end of method IFileTransfer::FileUpload` | `L160: .method public hidebysig newslot abstract virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512182` | `callsite` | `IL_01d9: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608800` | `callsite` | `IL_00b2: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608921` | `callsite` | `IL_00c5: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L608836: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:679721` | `callsite` | `IL_00bf: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L679642: .method public hidebysig static void UploadGroupImage(string jid,` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:699952` | `callsite` | `IL_024c: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:738959` | `callsite` | `IL_00bf: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L738869: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:739560` | `callsite` | `IL_00bf: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L739470: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:790010` | `callsite` | `IL_018b: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826414` | `callsite` | `IL_02b6: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:2852` | `reference` | `} // end of property FileTransfer::FileUploadMaxCount` | `L2825: .method family hidebysig newslot virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:2861` | `reference` | `} // end of property FileTransfer::FileUploadCount` | `L2825: .method family hidebysig newslot virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:186` | `reference` | `} // end of property IFileTransfer::FileUploadMaxCount` | `L177: .method public hidebysig newslot abstract virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:205` | `reference` | `} // end of property IFileTransfer::FileUploadCount` | `L177: .method public hidebysig newslot abstract virtual` |
### IMPP.Service.BLL.FileTransfer.AsynFileUpload
Classification: `confirmed_signature`; phase: `upload`; matches: 3.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:873` | `signature_continuation` | `instance void AsynFileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara para) cil managed` | `L872: .method public hidebysig newslot virtual final` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:883` | `method_end` | `} // end of method FileTransfer::AsynFileUpload` | `L872: .method public hidebysig newslot virtual final` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:169` | `method_end` | `} // end of method IFileTransfer::AsynFileUpload` | `L166: .method public hidebysig newslot abstract virtual` |
### FileUploadPara
Classification: `confirmed_signature`; phase: `upload_parameters`; matches: 66.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:851` | `signature_continuation` | `FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara para) cil managed` | `L849: .method public hidebysig newslot virtual final` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:873` | `signature_continuation` | `instance void AsynFileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara para) cil managed` | `L872: .method public hidebysig newslot virtual final` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:162` | `signature_continuation` | `FileUpload(class IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara para) cil managed` | `L160: .method public hidebysig newslot abstract virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:167` | `signature_continuation` | `instance void AsynFileUpload(class IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara para) cil managed` | `L166: .method public hidebysig newslot abstract virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1139` | `type_definition` | `.class public auto ansi serializable beforefieldinit IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara` | `L1086: .method family hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1155` | `method_end` | `} // end of method FileUploadPara::get_IsImg` | `L1146: .method public hidebysig specialname instance bool` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1167` | `method_end` | `} // end of method FileUploadPara::set_IsImg` | `L1157: .method private hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1178` | `method_end` | `} // end of method FileUploadPara::get_IsPublic` | `L1169: .method public hidebysig specialname instance bool` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1190` | `method_end` | `} // end of method FileUploadPara::set_IsPublic` | `L1180: .method public hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1234` | `method_end` | `} // end of method FileUploadPara::.ctor` | `L1192: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1263` | `method_end` | `} // end of method FileUploadPara::.ctor` | `L1236: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512182` | `callsite` | `IL_01d9: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512459` | `constructor_call` | `IL_04a3: newobj instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::.ctor(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608787` | `constructor_call` | `IL_0092: newobj instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::.ctor(string,` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608795` | `callsite` | `IL_009c: callvirt instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::set_IsPublic(bool)` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608800` | `callsite` | `IL_00b2: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608908` | `constructor_call` | `IL_00a5: newobj instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::.ctor(string,` | `L608836: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608916` | `callsite` | `IL_00af: callvirt instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::set_IsPublic(bool)` | `L608836: .method private hidebysig instance void` |
### FileUploadResult.FileID
Classification: `confirmed_signature`; phase: `upload_result`; matches: 75.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il:982` | `method_header` | `.method private hidebysig instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult` | `L982: .method private hidebysig instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1277` | `type_definition` | `.class public auto ansi serializable beforefieldinit IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult` | `L1236: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1307` | `method_end` | `} // end of method FileUploadResult::.ctor` | `L1284: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1318` | `method_end` | `} // end of method FileUploadResult::get_FileID` | `L1309: .method public hidebysig specialname instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1330` | `method_end` | `} // end of method FileUploadResult::set_FileID` | `L1320: .method private hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1341` | `method_end` | `} // end of method FileUploadResult::get_Url` | `L1332: .method public hidebysig specialname instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:1353` | `method_end` | `} // end of method FileUploadResult::set_Url` | `L1343: .method private hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512182` | `callsite` | `IL_01d9: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512315` | `callsite` | `IL_0322: callvirt instance string [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult::get_FileID()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608800` | `callsite` | `IL_00b2: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608819` | `callsite` | `IL_00e0: callvirt instance string [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult::get_FileID()` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608921` | `callsite` | `IL_00c5: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L608836: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608940` | `callsite` | `IL_00f3: callvirt instance string [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult::get_FileID()` | `L608836: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:679721` | `callsite` | `IL_00bf: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L679642: .method public hidebysig static void UploadGroupImage(string jid,` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:679747` | `callsite` | `IL_00f4: callvirt instance string [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult::get_FileID()` | `L679642: .method public hidebysig static void UploadGroupImage(string jid,` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:699952` | `callsite` | `IL_024c: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:699993` | `callsite` | `IL_02bf: callvirt instance string [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult::get_FileID()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:738959` | `callsite` | `IL_00bf: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara)` | `L738869: .method private hidebysig instance void` |
### MessageScheduling.SendFileMessage
Classification: `confirmed_signature`; phase: `message`; matches: 3.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153803` | `signature_continuation` | `SendFileMessage(class IMPP.Client.Business.RosterContacts.RosterContactsArgs rosterArgs,` | `L1153802: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1154125` | `method_end` | `} // end of method MessageScheduling::SendFileMessage` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:728711` | `callsite` | `IL_01fb: call class [smack]com.vision.smack.packet.XmppMessage IMPP.Client.Core.MessageEngine.MessageScheduling::SendFileMessage(class IMPP.Client.Business.RosterContacts.RosterContactsArgs,` | `` |
### Chat.sendFileMessage
Classification: `confirmed_signature`; phase: `message`; matches: 8.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1235` | `signature_continuation` | `sendFileMessage(string p_message,` | `L1233: .method public hidebysig newslot abstract virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1244` | `method_end` | `} // end of method Chat::sendFileMessage` | `L1233: .method public hidebysig newslot abstract virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:21442` | `signature_continuation` | `sendFileMessage(string p_message,` | `L21441: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:21490` | `method_end` | `} // end of method P2PChat::sendFileMessage` | `L21441: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30070` | `signature_continuation` | `sendFileMessage(string p_message,` | `L30069: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30119` | `method_end` | `} // end of method ChatRoom::sendFileMessage` | `L30069: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:827225` | `callsite` | `IL_034d: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::sendFileMessage(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153922` | `callsite` | `IL_00f1: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::sendFileMessage(string,` | `L1153802: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
### Required values: path id size target jid
Classification: `confirmed_signature`; phase: `requirements`; matches: 550.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:611789` | `method_end` | `} // end of method RosterContactsArgs::get_RosterJid` | `L611780: .method public hidebysig specialname instance class [smack]com.vision.smack.Jid` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:670956` | `type_definition` | `.class public auto ansi beforefieldinit IMPP.Client.Business.Authentication.UnifiedAuthenticationCenter` | `L670876: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:671260` | `method_end` | `} // end of method UnifiedAuthenticationCenter::Authentication` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:671331` | `method_end` | `} // end of method UnifiedAuthenticationCenter::GetServerTimeSpan` | `L671262: .method public hidebysig instance valuetype [mscorlib]System.TimeSpan` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:671390` | `method_end` | `} // end of method UnifiedAuthenticationCenter::ConvertStringToDateTime` | `L671333: .method private hidebysig instance valuetype [mscorlib]System.DateTime` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:671406` | `method_end` | `} // end of method UnifiedAuthenticationCenter::InitServiceManager` | `L671392: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:671416` | `method_end` | `} // end of method UnifiedAuthenticationCenter::.ctor` | `L671408: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:723604` | `method_end` | `} // end of method FileTransferArgs::get_LocalFilePath` | `L723595: .method public hidebysig specialname instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:723650` | `method_end` | `} // end of method FileTransferArgs::get_RemoteFolder` | `L723641: .method public hidebysig specialname instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:723876` | `method_end` | `} // end of method RosterContactsGroupArgs::get_RosterJid` | `L723867: .method public hidebysig specialname instance class [smack]com.vision.smack.Jid` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:767951` | `method_end` | `} // end of method ServerInfo::set_HTTPFileServer` | `L767941: .method public hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:767962` | `method_end` | `} // end of method ServerInfo::get_HTTPFileServer` | `L767953: .method public hidebysig specialname instance class IMPP.Client.Server` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:768272` | `method_end` | `} // end of method BaseConfig::UnifiedAuthenticationAddress` | `L768241: .method public hidebysig instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826017` | `method_end` | `} // end of method OffLineFileSend::get__localFilePath` | `L826008: .method private hidebysig specialname instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826109` | `method_end` | `} // end of method OffLineFileSend::get__fileSize` | `L826100: .method private hidebysig specialname instance int64` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1339551` | `method_end` | `} // end of method OffLineFileRecv::get__fileSize` | `L1339542: .method private hidebysig specialname instance int64` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il:477` | `method_end` | `} // end of method FileTransferParaBase::get_LocalFilePath` | `L468: .method public hidebysig specialname instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:13688` | `callsite` | `IL_0179: callvirt instance class [smack]com.vision.smack.Chat [smack]com.vision.smack.ChatManager::GetChat(class [smack]com.vision.smack.XMPPConnection,` | `` |
## Inference
- High confidence: upload and file-message finalization are separate steps.
- High confidence: `FileUploadPara` needs HTTP file server host/port/domain plus local file path and upload options.
- High confidence: `Chat.sendFileMessage` produces the XMPP file-message envelope after file metadata is available.
- Medium confidence: B-route file send must either call the same logged-in service/runtime or reproduce the authenticated HTTP upload plus XMPP file-message sequence.
- Low confidence until bridge evidence: an external sidecar can obtain the same service/auth/chat objects without being inside the logged-in client process.
## Decision
Offline static evidence supports B-route research, but file sending needs more than one method call: upload first, then chat file-message finalization. The next blocker is reachability: whether an IPC/plugin/in-process bridge can access the logged-in `IFileTransfer` service and smack `Chat` object.
## Next work
1. Extract bridge/IPC/plugin candidates before coding any file-send adapter.
2. If a bridge exists, prototype non-mutating discovery first: service availability, chat object lookup, and upload endpoint metadata only.
3. Keep A-route/RPA backup-only.

View File

@@ -0,0 +1,149 @@
# B-Route Text Send Static Map
Date: 2026-07-12
## Scope
This report uses offline IL only. It does not log in, send messages, replay traffic, inject into a process, or mutate the original iSphere binaries.
Machine-readable evidence: `runs/offline-broute-reverse/text-send-map.json`
## Sources
| Source | Role | Exists | Lines | Size bytes |
| --- | --- | --- | ---: | ---: |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il` | main managed client IL; chat UI, AppContextManager, scheduling call sites | yes | 1360035 | 74148460 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il` | XMPP/smack managed IL; Chat and XMPPConnection implementation | yes | 87425 | 5019807 |
## Target classification
| Target | Intent | Classification | Matches |
| --- | --- | --- | ---: |
| `AppContextManager.SendTxtMessageByJid` | high-level text send entry exposed by AppContextManager | `confirmed_signature` | 4 |
| `MessageScheduling.SendChatMessage` | message scheduling text/chat send helper | `confirmed_signature` | 6 |
| `Chat.SendMessage` | smack Chat send API used by chat/UI code | `confirmed_signature` | 16 |
| `XMPPConnection.send` | lowest-level XMPP connection send primitive | `confirmed_signature` | 105 |
| `MessageCenter send-related callbacks` | MessageCenter or IMPPManager message-center callbacks touching send/message flow | `confirmed_signature` | 962 |
## Verified facts
- `AppContextManager.SendTxtMessageByJid` appears in the offline client IL and is not just a UIA/RPA artifact.
- `MessageScheduling.SendChatMessage` appears in the offline client IL and has call-site evidence around chat-message flow.
- `Chat.SendMessage` / `Chat.sendMessage` appears as a smack chat API used by client code.
- `XMPPConnection.send` appears as a lower-level connection send primitive in offline IL.
- `MessageCenter send-related callbacks` appear as MessageCenter/GetMessageCenter references, but offline static evidence alone does not prove an external bridge can call them.
## Evidence excerpts
### AppContextManager.SendTxtMessageByJid
Classification: `confirmed_signature`; matches: 4.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:585987` | `signature_continuation` | `instance void SendTxtMessageByJid(string jid,` | `L585986: .method public hidebysig newslot virtual final` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:586197` | `method_end` | `} // end of method AppContextManager::SendTxtMessageByJid` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:542112` | `string_literal` | `IL_09bf: ldstr "SendTxtMessageByJid"` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1358068` | `string_literal` | `IL_0c3f: ldstr "SendTxtMessageByJid"` | `` |
### MessageScheduling.SendChatMessage
Classification: `confirmed_signature`; matches: 6.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153800` | `method_end` | `} // end of method MessageScheduling::SendChatMessage` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1154225` | `method_end` | `} // end of method MessageScheduling::SendChatMessage` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:728720` | `callsite` | `IL_0213: call class [smack]com.vision.smack.packet.XmppMessage IMPP.Client.Core.MessageEngine.MessageScheduling::SendChatMessage(class IMPP.Client.Business.RosterContacts.RosterContactsArgs,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1154187` | `callsite` | `IL_006e: call class [smack]com.vision.smack.packet.XmppMessage IMPP.Client.Core.MessageEngine.MessageScheduling::SendChatMessage(class [smack]com.vision.smack.Chat,` | `L1154127: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153541` | `reference` | `SendChatMessage(class [smack]com.vision.smack.Chat chat,` | `L1153540: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1154128` | `reference` | `SendChatMessage(class IMPP.Client.Business.RosterContacts.RosterContactsArgs rosterArgs,` | `L1154127: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
### Chat.SendMessage
Classification: `confirmed_signature`; matches: 16.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1220` | `method_end` | `} // end of method Chat::sendMessage` | `L1217: .method public hidebysig newslot abstract virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1231` | `method_end` | `} // end of method Chat::sendMessage` | `L1222: .method public hidebysig newslot abstract virtual` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1425` | `method_end` | `} // end of method Chat::SendMessage` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1266` | `callsite` | `IL_0021: call instance class com.vision.smack.packet.XmppMessage com.vision.smack.Chat::SendMessage(class com.vision.smack.packet.XmppMessage)` | `L1246: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:21393` | `callsite` | `IL_0047: call instance class com.vision.smack.packet.XmppMessage com.vision.smack.Chat::SendMessage(class com.vision.smack.packet.XmppMessage)` | `L21362: .method public hidebysig virtual instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:21431` | `callsite` | `IL_002b: call instance class com.vision.smack.packet.XmppMessage com.vision.smack.Chat::SendMessage(class com.vision.smack.packet.XmppMessage)` | `L21398: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:21482` | `callsite` | `IL_003a: call instance class com.vision.smack.packet.XmppMessage com.vision.smack.Chat::SendMessage(class com.vision.smack.packet.XmppMessage)` | `L21441: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:29958` | `callsite` | `IL_0047: call instance class com.vision.smack.packet.XmppMessage com.vision.smack.Chat::SendMessage(class com.vision.smack.packet.XmppMessage)` | `L29927: .method public hidebysig virtual instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30063` | `callsite` | `IL_0064: call instance class com.vision.smack.packet.XmppMessage com.vision.smack.Chat::SendMessage(class com.vision.smack.packet.XmppMessage)` | `L30012: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30115` | `callsite` | `IL_0056: call instance class com.vision.smack.packet.XmppMessage com.vision.smack.Chat::SendMessage(class com.vision.smack.packet.XmppMessage)` | `L30069: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:299997` | `callsite` | `IL_0096: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::SendMessage(class [smack]com.vision.smack.packet.XmppMessage)` | `L299937: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:412929` | `callsite` | `IL_00d2: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::SendMessage(class [smack]com.vision.smack.packet.XmppMessage)` | `L412858: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:430535` | `callsite` | `IL_0357: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::SendMessage(class [smack]com.vision.smack.packet.XmppMessage)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:739211` | `callsite` | `IL_012c: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::sendMessage(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:739789` | `callsite` | `IL_012c: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::sendMessage(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153743` | `callsite` | `IL_01d0: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::SendMessage(class [smack]com.vision.smack.packet.XmppMessage)` | `` |
### XMPPConnection.send
Classification: `confirmed_signature`; matches: 105.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:86319` | `method_end` | `} // end of method XMPPConnection::send` | `L86263: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1378` | `callsite` | `IL_00bc: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:17710` | `callsite` | `IL_004a: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L17649: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:23187` | `callsite` | `IL_004b: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L23150: .method public hidebysig instance class com.vision.smack.disco.DiscoInfoResponse` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:23248` | `callsite` | `IL_002c: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L23220: .method public hidebysig virtual instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:23962` | `callsite` | `IL_0110: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:26786` | `callsite` | `IL_004e: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L26752: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:26855` | `callsite` | `IL_008b: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L26790: .method public hidebysig instance class [mscorlib]System.Collections.Generic.IList`1<class com.vision.smack.muc.BookMarkConfenerce>` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:26980` | `callsite` | `IL_008a: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L26919: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:29230` | `callsite` | `IL_00a2: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L29148: .method public hidebysig instance bool` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:29470` | `callsite` | `IL_007d: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L29404: .method public hidebysig instance bool` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:29690` | `callsite` | `IL_0053: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L29646: .method public hidebysig instance bool` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:29841` | `callsite` | `IL_00b2: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L29766: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:29918` | `callsite` | `IL_0033: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L29894: .method public hidebysig virtual instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30152` | `callsite` | `IL_003c: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L30121: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30178` | `callsite` | `IL_0023: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L30159: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30221` | `callsite` | `IL_0046: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L30182: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30268` | `callsite` | `IL_004d: callvirt instance void com.vision.smack.XMPPConnection::send(string)` | `L30225: .method public hidebysig instance void` |
### MessageCenter send-related callbacks
Classification: `confirmed_signature`; matches: 962.
| Source line | Kind | Snippet | Method context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:74199` | `method_end` | `} // end of method MessageCenter::add_OnMessageSended` | `L74135: .method public hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:74265` | `method_end` | `} // end of method MessageCenter::remove_OnMessageSended` | `L74201: .method public hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:75658` | `method_end` | `} // end of method MessageCenter::pChat_OnMessageSended` | `L75587: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:82645` | `method_end` | `} // end of method MessageCenter::SendPluginsOffLineMessage` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:206380` | `method_end` | `} // end of method AVRoomMessageCenter::Send` | `L206369: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:945209` | `method_header` | `.method public hidebysig instance class IMPP.Client.control.MessageCenter` | `L945209: .method public hidebysig instance class IMPP.Client.control.MessageCenter` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:945695` | `method_header` | `.method public hidebysig specialname instance class IMPP.Client.control.MessageCenter` | `L945695: .method public hidebysig specialname instance class IMPP.Client.control.MessageCenter` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72786` | `callsite` | `IL_0005: callvirt instance class IMPP.Client.control.MessageCenter IMPP.Client.IMPPManager::GetMessageCenter()` | `L72779: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72787` | `callsite` | `IL_000a: callvirt instance int32 IMPP.Client.control.MessageCenter::GetChatMessageCount()` | `L72779: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72814` | `callsite` | `IL_000b: callvirt instance class IMPP.Client.control.MessageCenter IMPP.Client.IMPPManager::GetMessageCenter()` | `L72806: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72820` | `callsite` | `IL_001c: callvirt instance void IMPP.Client.control.MessageCenter::add_OnMessageArrived(class IMPP.Client.control.MessageCenter/MessageArrivedHandler)` | `L72806: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72822` | `callsite` | `IL_0026: callvirt instance class IMPP.Client.control.MessageCenter IMPP.Client.IMPPManager::GetMessageCenter()` | `L72806: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72827` | `callsite` | `IL_0037: callvirt instance void IMPP.Client.control.MessageCenter::add_OnMessageConsumed(class IMPP.Client.control.MessageCenter/MessageConsumedHandler)` | `L72806: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72829` | `callsite` | `IL_0041: callvirt instance class IMPP.Client.control.MessageCenter IMPP.Client.IMPPManager::GetMessageCenter()` | `L72806: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72835` | `callsite` | `IL_0052: callvirt instance void IMPP.Client.control.MessageCenter::add_UpdateUnreadMessageCount(class IMPP.Client.control.MessageCenter/UpdateUnreadMessageCountHandler)` | `L72806: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72837` | `callsite` | `IL_005c: callvirt instance class IMPP.Client.control.MessageCenter IMPP.Client.IMPPManager::GetMessageCenter()` | `L72806: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72842` | `callsite` | `IL_006d: callvirt instance void IMPP.Client.control.MessageCenter::add_TcpFileToOffline(class [mscorlib]System.Action`1<class [smack]com.vision.smack.packet.XmppMessage>)` | `L72806: .method public hidebysig specialname rtspecialname` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:72844` | `callsite` | `IL_0077: callvirt instance class IMPP.Client.control.MessageCenter IMPP.Client.IMPPManager::GetMessageCenter()` | `L72806: .method public hidebysig specialname rtspecialname` |
## Inference
- High confidence: text sending has an internal managed call path that reaches smack chat/connection send APIs.
- Medium confidence: the likely chain is high-level AppContextManager or UI chat code -> MessageScheduling/frmP2PChat -> smack Chat.SendMessage/sendMessage -> XMPPConnection.send.
- Low confidence until live/runtime evidence: an external sidecar can invoke this path without being inside the logged-in process.
## Decision
B-route text send remains plausible only if a bridge can enter the logged-in runtime or an existing IPC/API exposes the same call. Offline IL confirms call shape, but not runtime invocability.
## Next work
1. Extract file-send/upload call graph and separate upload from chat-message finalization.
2. Extract bridge/IPC/plugin candidates to see whether the send call path is reachable without RPA.
3. Keep A-route/RPA as backup-only; do not promote it unless B-route bridge evidence fails.

View File

@@ -0,0 +1,277 @@
# In-Process Adapter Static Map
Date: 2026-07-12
## Scope
This report uses offline IL/static evidence only. It does not log in, attach hooks, inject into a process, modify client binaries, upload files, send messages, or open network connections.
Machine-readable evidence: `runs\inprocess-adapter-research\inprocess-adapter-map.json`
## Decision
| Question | Answer |
| --- | --- |
| Selected next B-route branch | managed_in_process_adapter_contract_first |
| Can offline branch enable production send? | **No** |
| Go connector mode to expose now | in_process_contract |
| Required online proof later | logged-in adapter reachability plus sent-record/content-hash/ack evidence |
## Sources
| Source | Role | Exists | Lines | Size bytes |
| --- | --- | --- | ---: | ---: |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il` | main managed client; UI, AppContextManager, MessageScheduling, frmMain, login runtime | True | 1360035 | 74148460 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il` | XMPP/smack managed library; Chat and XMPPConnection send primitives | True | 87425 | 5019807 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Service.dll.il` | file transfer service implementation | True | 3351 | 207786 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.ServiceBase.dll.il` | file transfer DTOs and FileUploadPara/FileUploadResult contracts | True | 1641 | 93585 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Interface.dll.il` | service and network interface contracts | True | 4429 | 227335 |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il` | common helper and runtime DTO evidence | True | 118343 | 5703293 |
## Command contract for future in-process adapter
| Op | Current status | Purpose | Required evidence before production |
| --- | --- | --- | --- |
| `probe_runtime` | `contract_only` | report whether adapter is inside logged-in IMPP runtime and can see required types/singletons | process identity; loaded assemblies; IMPPManager.UserInfo presence; XMPP connection state |
| `send_text` | `blocked_until_logged_in_adapter` | invoke high-level text send path after target JID and content hash are validated | AppContextManager or MessageScheduling reachability; target JID; sent record or ack containing content hash/correlation |
| `upload_file` | `blocked_until_logged_in_adapter` | call file upload service and return server FileID/remote folder metadata | FileUploadPara values; HTTP file server/auth; FileUploadResult.FileID |
| `send_file_message` | `blocked_until_upload_evidence` | finalize file message after upload returns server id | uploaded FileID; file name/size; target JID/Chat; sent record/ack |
## Anchor summary
| Anchor | Command | Classification | Confidence | Evidence | Required runtime |
| --- | --- | --- | --- | ---: | --- |
| `AppContextManager.SendTxtMessageByJid` | `send_text` | `in_process_candidate_static_only` | `high_static` | 6 | logged-in IMPPManager/UserInfo; target JID; initialized AppContextManager; live XMPP connection |
| `MessageScheduling.SendChatMessage` | `send_text` | `in_process_candidate_static_only` | `high_static` | 16 | MessageScheduling instance or static caller; RosterContactsArgs/contact context; Chat object; live XMPP connection |
| `com.vision.smack.Chat.SendMessage / XMPPConnection.send` | `send_text` | `in_process_candidate_static_only` | `high_static` | 16 | Chat instance; XMPPConnection authenticated session; message payload format |
| `IMPP.Client.OffLineFileSend.sendFile` | `upload_file_then_send_file` | `in_process_candidate_static_only` | `high_static` | 6 | local file path; HTTP file server/auth state; target roster/chat args; upload completion callback |
| `IFileTransfer/FileTransfer.FileUpload + FileUploadPara` | `upload_file` | `in_process_candidate_static_only` | `high_static` | 16 | FileUploadPara host/port/domain; localFilePath; token/auth; FileUploadResult.FileID |
| `MessageScheduling.SendFileMessage / Chat.sendFileMessage` | `send_file_message` | `in_process_candidate_static_only` | `high_static` | 13 | uploaded file id; remote folder metadata; file name/size; target Chat/JID |
| `IMPPManager.UserInfo / UnifiedAuthentication / Auth token` | `runtime_context` | `runtime_dependency` | `medium_static` | 16 | UserInfo; UnifiedAuthentication; Auth token; HTTPFileServer; server resource/domain |
| `frmMain / MessageCenter / chat runtime ownership` | `runtime_context` | `runtime_dependency` | `medium_static` | 16 | running frmMain; initialized message center; contact/session state |
| `frmLogin.StartWinServer / HttpServerLib` | `not_selected_bridge` | `not_a_send_bridge` | `high_static_negative` | 6 | logged-in state; route module registration not found; send route not found |
## Verified facts
- Text send has static in-process candidates, but all require logged-in runtime objects and a live XMPP/Chat path.
- File send is split into upload and message-finalization; FileUploadResult.FileID is a required boundary value before Chat.sendFileMessage is meaningful.
- The earlier IPC/plugin/local HTTP scan did not find a confirmed external send bridge, so this branch must stay at in_process_contract until online reachability exists.
- in_process_contract is a Go-side contract and audit mode only; it must return blocked/no-side-effect metadata in this offline branch.
## Required runtime state
- logged-in IMPlatformClient.exe process
- loaded IMPP.Client/AppContextManager/MessageScheduling types
- initialized IMPPManager.UserInfo and UnifiedAuthentication/Auth token
- live XMPPConnection/Chat session
- target JID or group JID resolved by existing search tools
- file upload service parameters and FileUploadResult.FileID for file sends
## Anchor evidence
### AppContextManager.SendTxtMessageByJid
Classification: `in_process_candidate_static_only`; command: `send_text`; evidence count: 6.
Adapter role: preferred high-level managed entry if an in-process adapter can reach AppContextManager
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:542112` | `string_literal` | `IL_09bf: ldstr "SendTxtMessageByJid"` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:585987` | `signature_continuation` | `instance void SendTxtMessageByJid(string jid,` | `L585986: .method public hidebysig newslot virtual final instance void SendTxtMessageByJid(string jid,` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:586197` | `method_end` | `} // end of method AppContextManager::SendTxtMessageByJid` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1358068` | `string_literal` | `IL_0c3f: ldstr "SendTxtMessageByJid"` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Interface.dll.il:1920` | `signature_continuation` | `instance void SendTxtMessageByJid(string jid,` | `L1919: .method public hidebysig newslot abstract virtual instance void SendTxtMessageByJid(string jid,` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Interface.dll.il:1924` | `method_end` | `} // end of method IAppContextManager::SendTxtMessageByJid` | `L1919: .method public hidebysig newslot abstract virtual instance void SendTxtMessageByJid(string jid,` |
### MessageScheduling.SendChatMessage
Classification: `in_process_candidate_static_only`; command: `send_text`; evidence count: 16.
Adapter role: fallback managed entry when scheduling layer has chat and contact args
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:728720` | `callsite` | `IL_0213: call class [smack]com.vision.smack.packet.XmppMessage IMPP.Client.Core.MessageEngine.MessageScheduling::SendChatMessage(class IMPP.Client.Business.RosterContacts.RosterContactsArgs,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153541` | `reference` | `SendChatMessage(class [smack]com.vision.smack.Chat chat,` | `L1153540: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153800` | `method_end` | `} // end of method MessageScheduling::SendChatMessage` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1154128` | `reference` | `SendChatMessage(class IMPP.Client.Business.RosterContacts.RosterContactsArgs rosterArgs,` | `L1154127: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1154187` | `callsite` | `IL_006e: call class [smack]com.vision.smack.packet.XmppMessage IMPP.Client.Core.MessageEngine.MessageScheduling::SendChatMessage(class [smack]com.vision.smack.Chat,` | `L1154127: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1154225` | `method_end` | `} // end of method MessageScheduling::SendChatMessage` | `L1154127: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:99274` | `reference` | `get_issendchatmessage() cil managed` | `L99273: .method public hidebysig specialname instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:99284` | `reference` | `set_issendchatmessage(string 'value') cil managed` | `L99283: .method public hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:99582` | `reference` | `.property instance string issendchatmessage()` | `L99546: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:99586` | `reference` | `.set instance void Schedule::set_issendchatmessage(string)` | `L99546: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:99587` | `reference` | `.get instance string Schedule::get_issendchatmessage()` | `L99546: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:100662` | `reference` | `get_issendchatmessage() cil managed` | `L100661: .method public hidebysig specialname instance string` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:100672` | `reference` | `set_issendchatmessage(string 'value') cil managed` | `L100671: .method public hidebysig specialname instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:101019` | `reference` | `.property instance string issendchatmessage()` | `L100976: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:101023` | `reference` | `.get instance string ScheduleTaskDetailsDTO::get_issendchatmessage()` | `L100976: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPP.Common.dll.il:101024` | `reference` | `.set instance void ScheduleTaskDetailsDTO::set_issendchatmessage(string)` | `L100976: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed` |
### com.vision.smack.Chat.SendMessage / XMPPConnection.send
Classification: `in_process_candidate_static_only`; command: `send_text`; evidence count: 16.
Adapter role: lowest-level send target; requires already resolved Chat/XMPPConnection
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:80284` | `callsite` | `IL_34d2: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:206378` | `callsite` | `IL_0010: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `L206369: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:249554` | `callsite` | `IL_0c1e: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:249857` | `callsite` | `IL_0f27: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:299997` | `callsite` | `IL_0096: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::SendMessage(class [smack]com.vision.smack.packet.XmppMessage)` | `L299937: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:410318` | `callsite` | `IL_2257: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:412929` | `callsite` | `IL_00d2: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::SendMessage(class [smack]com.vision.smack.packet.XmppMessage)` | `L412858: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:430535` | `callsite` | `IL_0357: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::SendMessage(class [smack]com.vision.smack.packet.XmppMessage)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:451786` | `callsite` | `IL_00b1: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `L451702: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:451858` | `callsite` | `IL_018f: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:454073` | `callsite` | `IL_0179: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:454206` | `callsite` | `IL_00b9: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `L454118: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:454298` | `callsite` | `IL_00b9: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `L454210: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:520831` | `callsite` | `IL_017a: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:521914` | `callsite` | `IL_007a: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `L521860: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:521970` | `callsite` | `IL_0075: callvirt instance void [smack]com.vision.smack.XMPPConnection::send(string)` | `L521918: .method public hidebysig instance void` |
### IMPP.Client.OffLineFileSend.sendFile
Classification: `in_process_candidate_static_only`; command: `upload_file_then_send_file`; evidence count: 6.
Adapter role: UI-side upload orchestration and transition into chat file message
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:821640` | `reference` | `_tcpRecvInfo_RecvCancelSendFile() cil managed` | `L821639: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:824164` | `callsite` | `IL_026b: callvirt instance void IMPP.Client.OffLineFileSend::sendFile()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826149` | `reference` | `sendFile() cil managed` | `L826148: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826572` | `method_end` | `} // end of method OffLineFileSend::sendFile` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:826670` | `callsite` | `IL_0104: call instance void IMPP.Client.OffLineFileSend::trans_UploadCompleted(string)` | `L826574: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:827241` | `method_end` | `} // end of method OffLineFileSend::trans_UploadCompleted` | `` |
### IFileTransfer/FileTransfer.FileUpload + FileUploadPara
Classification: `in_process_candidate_static_only`; command: `upload_file`; evidence count: 16.
Adapter role: service upload entry that must return FileUploadResult before chat file finalization
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:511999` | `reference` | `class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara V_11,` | `L511981: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512002` | `reference` | `class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult V_14,` | `L511981: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512182` | `callsite` | `IL_01d9: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.Ser...` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512315` | `callsite` | `IL_0322: callvirt instance string [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult::get_FileID()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:512459` | `constructor_call` | `IL_04a3: newobj instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::.ctor(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608732` | `reference` | `class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara V_4,` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608733` | `reference` | `class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult V_5,` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608787` | `constructor_call` | `IL_0092: newobj instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::.ctor(string,` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608795` | `callsite` | `IL_009c: callvirt instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::set_IsPublic(bool)` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608800` | `callsite` | `IL_00b2: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.Ser...` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608819` | `callsite` | `IL_00e0: callvirt instance string [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult::get_FileID()` | `L608722: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608847` | `reference` | `class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara V_5,` | `L608836: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608848` | `reference` | `class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult V_6,` | `L608836: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608908` | `constructor_call` | `IL_00a5: newobj instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::.ctor(string,` | `L608836: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608916` | `callsite` | `IL_00af: callvirt instance void [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadPara::set_IsPublic(bool)` | `L608836: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:608921` | `callsite` | `IL_00c5: callvirt instance class [IMPP.ServiceBase]IMPP.ServiceBase.ModelBase.FileServiceBase.FileUploadResult [IMPP.ServiceBase]IMPP.ServiceBase.Interface.IFileTransfer::FileUpload(class [IMPP.ServiceBase]IMPP.Ser...` | `L608836: .method private hidebysig instance void` |
### MessageScheduling.SendFileMessage / Chat.sendFileMessage
Classification: `in_process_candidate_static_only`; command: `send_file_message`; evidence count: 13.
Adapter role: chat file-message finalization after FileID/remote folder exists
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:728711` | `callsite` | `IL_01fb: call class [smack]com.vision.smack.packet.XmppMessage IMPP.Client.Core.MessageEngine.MessageScheduling::SendFileMessage(class IMPP.Client.Business.RosterContacts.RosterContactsArgs,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:827225` | `callsite` | `IL_034d: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::sendFileMessage(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1144766` | `callsite` | `IL_03e8: callvirt instance void [HYHC.IMPP.DAL]HYHC.IMPP.DAL.IMPPDAL::AddSendFileMessage(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1146020` | `callsite` | `IL_0237: callvirt instance void [HYHC.IMPP.DAL]HYHC.IMPP.DAL.IMPPDAL::AddSendFileMessage(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1150833` | `callsite` | `IL_14e8: callvirt instance void [HYHC.IMPP.DAL]HYHC.IMPP.DAL.IMPPDAL::AddSendFileMessage(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153803` | `reference` | `SendFileMessage(class IMPP.Client.Business.RosterContacts.RosterContactsArgs rosterArgs,` | `L1153802: .method public hidebysig static class [smack]com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1153922` | `callsite` | `IL_00f1: callvirt instance class [smack]com.vision.smack.packet.XmppMessage [smack]com.vision.smack.Chat::sendFileMessage(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1154125` | `method_end` | `} // end of method MessageScheduling::SendFileMessage` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1235` | `reference` | `sendFileMessage(string p_message,` | `L1233: .method public hidebysig newslot abstract virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:1244` | `method_end` | `} // end of method Chat::sendFileMessage` | `L1233: .method public hidebysig newslot abstract virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:21442` | `reference` | `sendFileMessage(string p_message,` | `L21441: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:21490` | `method_end` | `} // end of method P2PChat::sendFileMessage` | `L21441: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\smack.dll.il:30070` | `reference` | `sendFileMessage(string p_message,` | `L30069: .method public hidebysig virtual instance class com.vision.smack.packet.XmppMessage` |
### IMPPManager.UserInfo / UnifiedAuthentication / Auth token
Classification: `runtime_dependency`; command: `runtime_context`; evidence count: 16.
Adapter role: runtime state required before any production send/upload can be meaningful
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:3533` | `callsite` | `IL_004c: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `L3492: .method public hidebysig static void FillDataToDataGridView(class [IMPP.UI]IMPP.UI.SkinControl.SkinDataGridView dgv,` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:4359` | `callsite` | `IL_01ba: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:4393` | `callsite` | `IL_021a: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:4403` | `callsite` | `IL_0236: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:5267` | `callsite` | `IL_02ea: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:5752` | `callsite` | `IL_08ac: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:5772` | `callsite` | `IL_08ee: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:6283` | `callsite` | `IL_0ea6: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:6329` | `callsite` | `IL_0f2f: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:6399` | `callsite` | `IL_1006: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:7402` | `callsite` | `IL_0141: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:7504` | `callsite` | `IL_024f: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:7855` | `callsite` | `IL_00bf: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `L7780: .method public hidebysig static void AddLinkID(class CSharpWin.ChatRichTextBox textBox,` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:7997` | `callsite` | `IL_023a: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:8222` | `callsite` | `IL_047a: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:8309` | `callsite` | `IL_0557: callvirt instance class [IMPP.Common]IMPP.Common.UserInfo IMPP.Client.IMPPManager::get_UserInfo()` | `` |
### frmMain / MessageCenter / chat runtime ownership
Classification: `runtime_dependency`; command: `runtime_context`; evidence count: 16.
Adapter role: likely object owner for initialized chat, reconnect, message center, and plugin runtime state
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1714` | `field` | `.field family class IMPP.Client.frmMain mainWin` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1744` | `reference` | `IL_001d: ldfld class IMPP.Client.frmMain IMPP.Client.VideoChat.SingleAVDispatcher::mainWin` | `L1721: .method family hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:1789` | `reference` | `IL_002a: ldfld class IMPP.Client.frmMain IMPP.Client.VideoChat.SingleAVDispatcher::mainWin` | `L1761: .method family hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:2777` | `reference` | `Init(class IMPP.Client.frmMain frmMain) cil managed` | `L2776: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:2791` | `reference` | `IL_000a: stfld class IMPP.Client.frmMain IMPP.Client.VideoChat.SingleAVDispatcher::mainWin` | `L2776: .method public hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:3005` | `reference` | `IL_001d: ldfld class IMPP.Client.frmMain IMPP.Client.VideoChat.SingleAVDispatcher::mainWin` | `L2981: .method family hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9039` | `type_definition` | `.class private auto ansi beforefieldinit IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication` | `L9012: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9042` | `field` | `.field private static class IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication _instance` | `L9012: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9058` | `constructor_call` | `IL_0000: newobj instance void IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::.ctor()` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9059` | `reference` | `IL_0005: stsfld class IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::_instance` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9060` | `reference` | `IL_000a: ldsfld class IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::_instance` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9061` | `callsite` | `IL_000f: callvirt instance void IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication::StartLightAppMultProssCommunication()` | `L9054: .method public hidebysig static void Init() cil managed` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:9081` | `reference` | `} // end of class IMPP.Client.Core.Plugins.MessageCenter.Classes.PluginLightAppMulProcessCommunication` | `L9073: .method private hidebysig specialname rtspecialname static` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:13688` | `callsite` | `IL_0179: callvirt instance class [smack]com.vision.smack.Chat [smack]com.vision.smack.ChatManager::GetChat(class [smack]com.vision.smack.XMPPConnection,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:14269` | `callsite` | `IL_00be: callvirt instance class [smack]com.vision.smack.Chat [smack]com.vision.smack.ChatManager::GetChat(class [smack]com.vision.smack.XMPPConnection,` | `L14190: .method public hidebysig static void OpenSetRoamMessageForm(valuetype [IMPP.Model]IMPP.Model.ChatRecord.MsgType msgSource,` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:15179` | `callsite` | `IL_0074: callvirt instance class [smack]com.vision.smack.Chat [smack]com.vision.smack.ChatManager::GetChat(class [smack]com.vision.smack.XMPPConnection,` | `L15134: .method public hidebysig static class [IMPP.Model]IMPP.Model.ChatRecord.tblMsgGroupPersonMsg` |
### frmLogin.StartWinServer / HttpServerLib
Classification: `not_a_send_bridge`; command: `not_selected_bridge`; evidence count: 6.
Adapter role: known local HTTP framework, but not a confirmed send bridge
| Source | Kind | Snippet | Context |
| --- | --- | --- | --- |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:223` | `reference` | `.assembly extern HttpServerLib` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889253` | `reference` | `StartWinServer() cil managed` | `L889252: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889272` | `reference` | `class [HttpServerLib]HTTPServerLib.HttpService V_15,` | `L889252: .method private hidebysig instance void` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889554` | `constructor_call` | `IL_02dc: newobj instance void [HttpServerLib]HTTPServerLib.HttpService::.ctor(string,` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889559` | `reference` | `IL_02e5: ldftn instance void [HttpServerLib]HTTPServerLib.HttpServer::Start()` | `` |
| `runs\offline-evidence-intake\zyl-qqfile-20260709\metadata\c28-il\IMPlatformClient.exe.il:889677` | `method_end` | `} // end of method frmLogin::StartWinServer` | `` |
## Stop conditions
- No logged-in process is available for runtime reachability validation.
- Adapter cannot see AppContextManager, MessageScheduling, Chat, or IFileTransfer in process.
- Every viable path requires unsupported binary patching instead of a replaceable managed adapter/harness.
- Online evidence cannot produce sent-record/content-hash/ack correlation for text send.
- File upload cannot return FileUploadResult.FileID or equivalent remote folder metadata.
## Next work
1. Add Go connector mode in_process_contract that validates request shape and returns blocked/no-side-effect metadata.
2. In a logged-in environment, build a recorder/probe that only checks reachability of the listed runtime objects before attempting any send.
3. Promote text send only after sent-record/content-hash/ack evidence exists.
4. Promote file send only after upload returns FileUploadResult.FileID and file-message finalization is proven online.

View File

@@ -0,0 +1,65 @@
# Offline B-Route Reverse Decision
Date: 2026-07-12
Branch: `codex/offline-broute-reverse`
## Current phase / 当前阶段
Offline reverse engineering for the primary B-route is complete for the current evidence set. The goal was to decide whether B-route can continue through an existing IPC/plugin/local API, or whether it must move to an in-process adapter research branch.
## Inputs / 输入证据
| Evidence | Path |
| --- | --- |
| Offline sample index | `docs/source-discovery/2026-07-12-offline-broute-reverse-index.md` |
| Text send static map | `docs/source-discovery/2026-07-12-broute-text-send-static-map.md` |
| File send static map | `docs/source-discovery/2026-07-12-broute-file-send-static-map.md` |
| Bridge/IPC/plugin static map | `docs/source-discovery/2026-07-12-broute-bridge-static-map.md` |
| Machine JSON outputs | `runs/offline-broute-reverse/*.json` |
## Verified facts / 已验证事实
1. The offline sample set is present and hash-matched against the recorded plan list; the analyzer scripts only read metadata/IL and did not copy or modify binaries.
2. Text send has confirmed static call-path evidence:
- `AppContextManager.SendTxtMessageByJid`
- `MessageScheduling.SendChatMessage`
- `Chat.SendMessage` / `Chat.sendMessage`
- `XMPPConnection.send`
3. File send has confirmed two-step evidence:
- upload first through `OffLineFileSend.sendFile`, `FileUploadPara`, and `IFileTransfer.FileUpload` / `IMPP.Service.BLL.FileTransfer.FileUpload`;
- then chat file-message finalization through `trans_UploadCompleted(fileId)`, `MessageScheduling.SendFileMessage`, and `Chat.sendFileMessage`.
4. `FileUploadResult.FileID` / remote-folder metadata is required before the chat file message is meaningful.
5. The static bridge scan found no confirmed existing IPC/plugin/local HTTP route that exposes text-send or file-send.
6. `HttpServerLib` exists, but the discovered `frmLogin.StartWinServer` path depends on logged-in runtime state and no send route was found.
7. `PluginLightAppMulProcessCommunication` declares a `NamedPipeServerStream`, but its start method returns immediately.
8. Returned live probe saw `\\.\pipe\zfpinject-msg-server`, but no matching iSphere static send contract was found.
## Decision / 决策
| Candidate | Decision | Reason |
| --- | --- | --- |
| `existing_ipc_first` | rejected for now | No concrete local HTTP/named-pipe/service send API was confirmed. |
| `plugin_extension_first` | rejected for now | Plugin evidence is UI/app-store/context-menu oriented; no local plugin load/send bridge is confirmed. |
| `in_process_adapter_research` | selected | The send and file-send call paths exist, but they need access to the logged-in `IMPlatformClient.exe` runtime objects. |
| `external_sidecar_preview_only` | allowed | External sidecar can validate contracts/probes, but cannot reuse logged-in static runtime by itself. |
| `fallback_rpa_only` | not selected | A-route/RPA remains backup-only; do not promote it unless B-route is explicitly blocked by a later decision. |
Final offline decision: **B-route stays primary, but the next real branch is `in_process_adapter_research`, not existing IPC/plugin and not production send.**
## Business impact / 业务影响
- Message receiving, file receiving/listing, contact search, and group search stay on the existing data/log-backed roadmap.
- Text send is technically mapped but not business-complete: the missing piece is a bridge into logged-in runtime state and later online ack/sent-record validation.
- File send is harder than text send: upload and chat-message finalization are separate, and upload needs HTTP file-service auth plus server-issued file id.
- RPA remains a practical backup for UI smoke, but it is not the product architecture.
## Next implementation slice / 下一轮
1. Create a dedicated in-process adapter research plan.
2. Keep any sidecar work preview/probe-only until an adapter path is selected.
3. Do not implement real `send_message`, `send_file`, or `upload_file` in this offline branch.
4. Online evidence later must prove sent-record/content-hash/ack before production send can be called complete.
## Stop conditions / 停止条件
Stop and ask for business decision if the next in-process research shows that every viable bridge requires invasive process mutation, unsupported injection, or cannot be validated without a logged-in test environment.

View File

@@ -0,0 +1,45 @@
# Offline B-Route Reverse Index
Date: 2026-07-12
## Scope
This index records the read-only offline samples for B-route reverse engineering. The script reads metadata and SHA256 hashes only; it does not copy or modify the original binaries.
## Summary
- Samples total: 12
- Samples present: 12
- Hash matches: 12
- Originals copied: false
- Originals modified: false
- Machine JSON: `runs/offline-broute-reverse/index.json`
## Sample table
| Sample | Role | Size | SHA256 match | SHA256 |
| --- | --- | ---: | --- | --- |
| `runs/offline-real-client-window/full/zyl/Impp/IMPlatformClient.exe` | main managed client; text send, chat window, plugin/IPC candidates | 8366592 | yes | `E2966E58360DAEEBF178410A961E2DC52748C63E9CCBD94BD6EC8434A1A09CB7` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Service.dll` | file upload service candidates | 21504 | yes | `F859DE2F34E024B5F372D95F22CBF8A018C780F24203E7A76D392E52BD90CADD` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Interface.dll` | service/interface contract candidates | 33792 | yes | `DD093CF61FAE85C2D2581F289B01AA477546712E098FEF81272FDD989E50D12D` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Model.dll` | model/parameter types | 35328 | yes | `7CBABDD23A7234D15E294C549EEEC78EFBAD6E957CD45A6E8A85309349A624A5` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.UI.dll` | UI/plugin helpers and possible send controls | 2401792 | yes | `4C61212519C01D1B731ED4F20DF3411C491616F4ADA98A4529722A6AA3689E6D` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Common.dll` | shared utility and message types | 479744 | yes | `02A47C99C27C9BFE2BADC438389300C92220B07609BD87C48B4B5E1B4EE6AEB4` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Helper.dll` | helper abstractions | 53248 | yes | `30932D082B6678699C832C63F923E01EAD84674FAEDB613D631E034E03742FB9` |
| `runs/offline-real-client-window/full/zyl/Impp/smack.dll` | XMPP chat/send layer | 370688 | yes | `BAD0BB0591765DB153B17CECC1112B0BBDBF3B1D3370DDF973F91974E92CEC66` |
| `runs/offline-real-client-window/full/zyl/Impp/TcpFileTransfer.dll` | native/transfer candidate | 45056 | yes | `6C4874B46D1E7DC04C9B6784180603452400B881E04509D464A0D58814EFEDA7` |
| `runs/offline-real-client-window/full/zyl/Impp/HttpServerLib.dll` | local API/IPC candidate | 26624 | yes | `FFDB633216AE332B8EDFFC83E2AE546B7A80144C659FF4053FDFE4FE382A8D12` |
| `runs/offline-real-client-window/full/zyl/Impp/INetwork.dll` | network abstraction candidate | 87552 | yes | `E40BE4EE2439E4280461F4D2BADB318A5F4572428F069AB6D17B4C4F0E8CFAC9` |
| `runs/offline-real-client-window/full/zyl/Impp/IOClientNetwork.dll` | network implementation candidate | 145920 | yes | `64CA231A614771325741A5F098E52EBF20F7190E339B64962DE2EDEDCFFFF904` |
## Verified facts
- All metadata came from local filesystem reads under the repository workspace.
- The expected primary B-route samples are present if Samples present equals Samples total.
- Hash matching only proves local file identity against this plan's recorded sample list; it does not prove runtime invocability.
## Next reverse targets
1. Text-send static call graph: SendTxtMessageByJid, MessageScheduling.SendChatMessage, Chat.SendMessage, XMPPConnection.send.
2. File-send/upload static call graph: OffLineFileSend.sendFile, FileTransfer.FileUpload, AsynFileUpload, sendFileMessage.
3. Bridge/IPC/plugin map: HttpServerLib, plugin loaders, local HTTP, named pipes, command-line switches, services.

View File

@@ -1,6 +1,6 @@
# Capability Source Matrix # Capability Source Matrix
Date: 2026-07-10 Date: 2026-07-12
Stage: Core business capability roadmap Stage: Core business capability roadmap
Evidence index: `docs/source-discovery/2026-07-09-n12-pre-zyl-index.md` Evidence index: `docs/source-discovery/2026-07-09-n12-pre-zyl-index.md`
Schema notes: `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md` Schema notes: `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md`
@@ -14,6 +14,15 @@ File download mapping v2: `docs/source-discovery/2026-07-10-file-download-mappin
Send-file sandbox gate: `docs/source-discovery/2026-07-10-send-file-sandbox-gate.md` Send-file sandbox gate: `docs/source-discovery/2026-07-10-send-file-sandbox-gate.md`
Business goals smoke: `docs/reports/2026-07-10-business-goals-smoke.md` Business goals smoke: `docs/reports/2026-07-10-business-goals-smoke.md`
R14 release candidate: `docs/reports/2026-07-10-r6f-r14-release-candidate.md` R14 release candidate: `docs/reports/2026-07-10-r6f-r14-release-candidate.md`
Main status correction: `docs/reports/2026-07-12-main-business-status-correction.md`
A-route UIA send: `docs/source-discovery/2026-07-11-a-route-uia-send.md`
A-route real offline chat window: `docs/source-discovery/2026-07-11-a-route-open-real-chat-window.md`
Offline B-route reverse index: `docs/source-discovery/2026-07-12-offline-broute-reverse-index.md`
Offline B-route text-send map: `docs/source-discovery/2026-07-12-broute-text-send-static-map.md`
Offline B-route file-send map: `docs/source-discovery/2026-07-12-broute-file-send-static-map.md`
Offline B-route bridge map: `docs/source-discovery/2026-07-12-broute-bridge-static-map.md`
Offline B-route decision: `docs/source-discovery/2026-07-12-offline-broute-reverse-decision.md`
In-process adapter static map: `docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md`
## Source priority ## Source priority
@@ -24,6 +33,8 @@ R14 release candidate: `docs/reports/2026-07-10-r6f-r14-release-candidate.md`
5. Network/protocol source. 5. Network/protocol source.
6. Mock source for tests only. 6. Mock source for tests only.
Route rule: UIA helper / A-route / RPA is a backup route only. It can preserve delivery momentum while B-route is blocked or untestable, but B-route sidecar/API evidence remains the preferred path for production send and file capability.
## Matrix ## Matrix
| MCP tool | Primary source | Fallback source | Evidence file | Decision status | Next implementation slice | | MCP tool | Primary source | Fallback source | Evidence file | Decision status | Next implementation slice |
@@ -32,8 +43,8 @@ R14 release candidate: `docs/reports/2026-07-10-r6f-r14-release-candidate.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`; `docs/source-discovery/2026-07-10-file-download-mapping-v2.md`; `docs/reports/2026-07-10-business-goals-smoke.md` | C22 verifies safe file-list contract args; R10 proves resolver scoring with fixture accepted matches; R11 adds structured download preview with `blocked`/`planned` status and side-effect flags false; R13/R14 confirms list is ready but real download is still blocked. | blocked for real download pending accepted real cache mapping and copy gate; list mode is complete | | `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`; `docs/source-discovery/2026-07-10-file-download-mapping-v2.md`; `docs/reports/2026-07-10-business-goals-smoke.md` | C22 verifies safe file-list contract args; R10 proves resolver scoring with fixture accepted matches; R11 adds structured download preview with `blocked`/`planned` status and side-effect flags false; R13/R14 confirms list is ready but real download is still blocked. | blocked for real download pending accepted real cache mapping and copy gate; list mode is complete |
| `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`; `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis-v2.md`; `docs/source-discovery/2026-07-10-returned-send-sent-record-diagnostic.md`; `internal/tools/isphere_send_message_test.go`; `cmd/isphere-capability-smoke/main.go`; `docs/reports/2026-07-10-business-goals-smoke.md` | R6f-R6l define connector contract, audit/idempotency replay, production gate, B-route shell, strict-v2 package, and explicit production closure. R10a validates two returned sent-record packages as manual-only evidence: `operator_observed_success=true`, but `exact_content_seen_after=false`, `content_sha256_seen_after=false`, `after_offline_blocked=true`, and `production_send_unlock_recommended=false`. Preview is complete; production remains blocked. | blocked until strict machine sent-record/content-hash after evidence passes and a connector is configured | | `isphere_send_message` | B-route selected: `in_process_adapter_research` after offline reverse. Static call path is confirmed through `AppContextManager.SendTxtMessageByJid(...)`, `MessageScheduling.SendChatMessage(...)`, `Chat.SendMessage`, and `XMPPConnection.send`, but no existing IPC/plugin/local HTTP send bridge is confirmed; default MCP tool still exposes preview/dry-run unless an explicit connector mode is configured | A-route fallback is now implemented for UI action: `ISPHERE_SEND_CONNECTOR_MODE=uia_rpa` calls WinHelper `uia_send_message` against a configured HWND, writes `rtbSendMessage`, and clicks `btnSend`; this stays backup-only and 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`; `docs/source-discovery/2026-07-10-returned-send-sandbox-analysis-v2.md`; `docs/source-discovery/2026-07-10-returned-send-sent-record-diagnostic.md`; `docs/source-discovery/2026-07-11-a-route-uia-send.md`; `docs/source-discovery/2026-07-11-a-route-open-real-chat-window.md`; `docs/source-discovery/2026-07-12-broute-text-send-static-map.md`; `docs/source-discovery/2026-07-12-broute-bridge-static-map.md`; `docs/source-discovery/2026-07-12-offline-broute-reverse-decision.md`; `docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md`; `internal/tools/isphere_send_message_test.go`; `cmd/isphere-capability-smoke/main.go`; `docs/reports/2026-07-10-business-goals-smoke.md` | R6f-R6l define connector contract, audit/idempotency replay, production gate, B-route shell, strict-v2 package, and explicit production closure. R10a validates two returned sent-record packages as manual-only evidence. A-route adds local UI action readiness: synthetic window proof plus real offline `frmP2PChat` open/write/click target proof. Offline B-route reverse confirms the send call path but rejects existing IPC/plugin-first for this evidence set; business delivery is still not verified because local runtime is offline and no success/ack or sent-record hash evidence has passed. | B-route now exposes only the `in_process_contract` connector mode for request-shape/audit validation; keep external sidecar preview/probe-only and A-route UI action backup-only; production remains blocked until logged-in adapter reachability plus online sent-record/content-hash/ack evidence passes |
| `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(...)`; current MCP tool exposes preview/dry-run only | 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-file-sandbox-gate.md`; `internal/tools/isphere_files_test.go`; `docs/reports/2026-07-10-business-goals-smoke.md` | R7 registers send-file preview as the tenth MCP tool; R8 adds audit/idempotency duplicate/conflict hardening without raw file paths/content; R9 builds and verifies the online send-file evidence package; R13/R14 confirms preview is ready and production upload remains blocked. | blocked until returned file-send package proves upload/sent evidence and an upload connector is gated | | `isphere_send_file` | B-route selected after offline reverse: managed file send is upload-first through `OffLineFileSend.sendFile()`, `FileUploadPara`, `IMPP.Service*.dll` `IFileTransfer.FileUpload(...)`, then chat file-message finalization through `trans_UploadCompleted(fileId)`, `MessageScheduling.SendFileMessage`, and `Chat.sendFileMessage(...)`; current MCP tool exposes preview/dry-run only | A-route file fallback is not implemented yet; real offline UIA dump did not expose stable `btnSendFile`, so the fallback slice remains toolbar/menu locator discovery; native `TcpFileTransfer.dll` is not the first B-route bridge because managed upload/message flow is now mapped | `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-file-sandbox-gate.md`; `docs/source-discovery/2026-07-11-a-route-open-real-chat-window.md`; `docs/source-discovery/2026-07-12-broute-file-send-static-map.md`; `docs/source-discovery/2026-07-12-broute-bridge-static-map.md`; `docs/source-discovery/2026-07-12-offline-broute-reverse-decision.md`; `docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md`; `internal/tools/isphere_files_test.go`; `docs/reports/2026-07-10-business-goals-smoke.md` | R7 registers send-file preview as the tenth MCP tool; R8 adds audit/idempotency duplicate/conflict hardening without raw file paths/content; R9 builds and verifies the online send-file evidence package; R13/R14 confirms preview is ready and production upload remains blocked. Offline B-route reverse confirms upload-first/file-message-second and shows file id/auth/runtime reachability are the blockers. A-route real-window work confirms file-button automation still needs a separate locator node. | blocked until B-route in-process adapter research proves logged-in access to `IFileTransfer.FileUpload`, returned `FileUploadResult.FileID`, and `Chat.sendFileMessage` finalization; production file upload/send remains blocked until online evidence exists; A-route locator remains backup-only |
## Stage C entry rule ## Stage C entry rule
@@ -50,4 +61,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. R6j/R6k confirm the send-message strict-v2 production gate is still not passed; R10a confirms the returned sent-record packages are manual-only evidence and do not unlock production send; R10/R11 define file-download resolver/preview behavior while keeping real copy blocked; R12 adds receive-source reconciliation without changing default routing; R13/R14 publish business-goals smoke and the release-candidate status. The active continuous execution plan `docs/superpowers/plans/2026-07-10-r6f-r14-continuous-execution-plan.md` is complete through R14; next work is evidence-driven, not local login-dependent. `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. R6j/R6k confirm the send-message strict-v2 production gate is still not passed; R10a confirms the returned sent-record packages are manual-only evidence and do not unlock production send; R10/R11 define file-download resolver/preview behavior while keeping real copy blocked; R12 adds receive-source reconciliation without changing default routing; R13/R14 publish business-goals smoke and the release-candidate status. A-route now proves UI write/click readiness against synthetic and real offline chat windows, but not online delivery. The active B-route follow-up is now the in-process contract path in `docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md`: validate logged-in adapter reachability before production send/file work. A-route RPA remains backup-only under `docs/superpowers/plans/2026-07-11-a-route-rpa-send.md`.

View File

@@ -2,7 +2,7 @@
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:**`codex/a-route-rpa-send` 分支实现 A 方案:通过受控 UI Automation 路线让 `isphere_send_message` 能配置为真实 UI 写入并点击发送。 **Goal:**`codex/a-route-rpa-send` 分支实现 A 方案,并在合并到 `main` 后继续校准计划:通过受控 UI Automation 路线让 `isphere_send_message` 能配置为真实 UI 写入并点击发送;同时明确这只证明 UI 动作,不等于业务送达,而且 A-route/RPA 是备选兜底,不是主线
**Architecture:** Go MCP 继续保留稳定 `isphere_send_message` 接口、hash、idempotency、audit。新增 A-route connector 调用 C# `ISphereWinHelper` 的 UIA action opC# helper 根据窗口句柄、发送框 AutomationId、发送按钮 AutomationId 写入文本并点击。B-route sidecar 仍是主路线,但当前不可测时先实现 A-route 功能兜底。 **Architecture:** Go MCP 继续保留稳定 `isphere_send_message` 接口、hash、idempotency、audit。新增 A-route connector 调用 C# `ISphereWinHelper` 的 UIA action opC# helper 根据窗口句柄、发送框 AutomationId、发送按钮 AutomationId 写入文本并点击。B-route sidecar 仍是主路线,但当前不可测时先实现 A-route 功能兜底。
@@ -11,12 +11,14 @@
## Global Constraints ## Global Constraints
- Repository root: `E:\coding\codex\isphere-ai-bridge`. - Repository root: `E:\coding\codex\isphere-ai-bridge`.
- Active branch: `codex/a-route-rpa-send`. - Original implementation branch: `codex/a-route-rpa-send`; merged branch for follow-up documentation and plan correction: `main`.
- Do not use `rg`; use `git ls-files`, `ag`, `grep -R`, or PowerShell commands. - Do not use `rg`; use `git ls-files`, `ag`, `grep -R`, or PowerShell commands.
- Local machine cannot log in; use synthetic WinForms/UIA verification for local tests. - Local machine cannot log in; use synthetic WinForms/UIA verification for local tests.
- User explicitly removed human approval as a product gate for A-route; do not add approval IDs or approval queues in this plan. - User explicitly removed human approval as a product gate for A-route; do not add approval IDs or approval queues in this plan.
- Keep audit redaction: do not store raw message body or raw idempotency key in committed docs/audit tests. - Keep audit redaction: do not store raw message body or raw idempotency key in committed docs/audit tests.
- Real UI action requires explicit env configuration; default MCP behavior remains preview/blocked. - Real UI action requires explicit env configuration; default MCP behavior remains preview/blocked.
- Route priority must stay B-route first: running-client sidecar / in-process connector / existing API is the primary product route; A-route/RPA only keeps a fallback path alive while B-route is blocked or untestable.
- Helper fields `clicked_ui=true` and `sent_message=true` mean the helper wrote the editor and invoked/clicked the send button. They must not be interpreted as server acceptance, receiver delivery, or sent-record proof.
--- ---
@@ -112,4 +114,43 @@ adds a no-network WinForms probe using the real selector names
- [x] Verify UIA classification finds send editor, send button, and file button. - [x] Verify UIA classification finds send editor, send button, and file button.
- [x] Verify `-ProbeClick` writes text and clicks `btnSend`. - [x] Verify `-ProbeClick` writes text and clicks `btnSend`.
- [x] Verify marker says `sent_real_message=false` and `uploaded_real_file=false`. - [x] Verify marker says `sent_real_message=false` and `uploaded_real_file=false`.
- [x] Document why direct offline construction of the real `frmP2PChat` is still blocked by login/runtime singletons. - [x] Document the then-current direct-construction blocker; Task 7 supersedes this by opening the real `frmP2PChat` with a fuller offline dependency harness.
## Task 7: Replace synthetic-only proof with real offline `frmP2PChat`
**Files:**
- Create: `scripts/open-offline-real-frmP2PChat.ps1`
- Create: `scripts/extract-frmP2PChat-il-risk.ps1`
- Create: `scripts/test-extract-frmP2PChat-il-risk.ps1`
- Create: `scripts/test-open-offline-real-frmP2PChat-contract.ps1`
- Create: `docs/source-discovery/2026-07-11-a-route-open-real-chat-window.md`
**Purpose:** local machine still cannot log in, but RPA validation should run
against a real client chat form instead of only a synthetic WinForms probe.
- [x] Extract constructor/load IL risks for `frmP2PChat`.
- [x] Build an offline dependency harness that can construct and show the real `frmP2PChat`.
- [x] Confirm UIA root `automation_id=frmP2PChat`.
- [x] Confirm send editor `automation_id=rtbSendMessage`.
- [x] Confirm send button `automation_id=btnSend`.
- [x] Confirm receive area `automation_id=rtbRecvMessage`.
- [x] Record that the real offline window shows the expected offline-send blocker.
- [x] Merge and push the real-window branch to `main`.
## Task 8: Corrected next loop after main merge
**Business status after Task 7:**
- Message send: UI write/click path exists; online delivery is not verified.
- File send: preview-only; no real upload path is implemented.
- Receive/search: unchanged from R14; basic digital-employee read/search remains usable through local-readonly evidence paths.
**Next implementation slices:**
- [ ] Re-check B-route sidecar / in-process connector / existing API feasibility before promoting any RPA path.
- [ ] Add a real-window A-route smoke that opens `frmP2PChat`, passes its HWND into the MCP `uia_rpa` connector, writes a unique text, clicks `btnSend`, and records sanitized UI evidence; treat this as backup readiness only.
- [ ] Add an online/logged-in verification package for message send: first target B-route evidence; include A-route evidence only as a fallback comparison path.
- [ ] Keep default `verify-go-mcp.ps1` preview/blocked unless explicit A-route env is set, so CI does not depend on a desktop login.
- [ ] Start a separate file-send RPA locator node: identify the real toolbar/menu path for file attach because `btnSendFile` was not exposed in the real offline UIA dump.
- [ ] Only after file locator proof, add file upload action and online file-send evidence package.
- [x] Create `docs/reports/2026-07-12-main-business-status-correction.md` separating “UI action ready” from “business delivery ready”.

View File

@@ -0,0 +1,335 @@
# B-Route Bridge Next Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Push the primary B-route from offline reverse evidence into the selected `in_process_adapter_research` branch, while keeping any external sidecar work preview/probe-only and not enabling real send.
**Architecture:** Keep the Go MCP tool contracts stable. B-route remains the primary product route: reuse the logged-in `IMPlatformClient.exe` runtime through a narrow bridge. Offline reverse now rules out existing IPC/plugin as the next first step, so a dedicated in-process adapter research plan is required before any production send. External sidecars may only do self-check/probe/preview. A-route/RPA remains backup-only and should be used only for UI action smoke or when B-route is proven blocked.
**Tech Stack:** Go 1.23.4, github.com/modelcontextprotocol/go-sdk, Windows PowerShell, .NET Framework C# helper/sidecar, stdin/stdout JSON protocols, Windows UI Automation only as fallback.
## Global Constraints
- Repository root: `E:\coding\codex\isphere-ai-bridge`.
- Active branch for execution should be a new `codex/` branch, not `main` directly.
- Do not use `rg`; use `git ls-files`, `ag`, `grep -R`, or PowerShell commands.
- Local machine cannot log in to iSphere; local work must use static analysis, fake sidecar processes, synthetic fixtures, or offline real-window UI only.
- B-route is primary: running-client sidecar / in-process connector / existing API comes before A-route/RPA.
- A-route/RPA is backup-only: keep it runnable, but do not make it the default product architecture.
- No real send/file upload in this plan. Stop at bridge feasibility, self_check, runtime probe, and dry-run preview.
- Keep audit redaction: do not store raw message body, raw idempotency key, raw file contents, or raw local file paths in committed outputs.
---
## Offline reverse result amendment
`docs/superpowers/plans/2026-07-12-offline-broute-reverse-plan.md` has now produced the offline reverse decision set:
- `docs/source-discovery/2026-07-12-offline-broute-reverse-index.md`
- `docs/source-discovery/2026-07-12-broute-text-send-static-map.md`
- `docs/source-discovery/2026-07-12-broute-file-send-static-map.md`
- `docs/source-discovery/2026-07-12-broute-bridge-static-map.md`
- `docs/source-discovery/2026-07-12-offline-broute-reverse-decision.md`
Decision correction: B-route remains primary, but **existing IPC/local service** and **plugin extension** are not confirmed usable. The selected next branch is `in_process_adapter_research`. External sidecar work is allowed only as preview/probe plumbing until an in-process bridge is selected. A-route/RPA remains backup-only.
## Current evidence summary
The current `main` state already has:
- `isphere_send_message` MCP contract, preview/dry-run metadata, audit, idempotency, and connector abstraction.
- `internal/tools/send_message_broute_adapter.go` with B-route `disabled` and `dry_run_contract` modes only.
- `internal/tools/send_message_uia_adapter.go` wired from env only for `ISPHERE_SEND_CONNECTOR_MODE=uia_rpa`.
- C# WinHelper `probe_client_runtime`, `probe_send_entrypoints`, `probe_send_uia_controls`, and `uia_send_message`.
- Offline real `frmP2PChat` opener for RPA backup validation.
- No B-route env wiring, no process-backed B-route sidecar client, no in-process bridge transport decision, and no real send/file-upload connector.
Important technical conclusion: an external C# process cannot automatically reuse the logged-in static runtime of `IMPlatformClient.exe`. Offline reverse has now made the transport decision for this evidence set: existing API/IPC and plugin extension are not confirmed; the next B-route node is a separate `in_process_adapter_research` plan. Do not build production send/file upload in this plan.
---
## Task 1: B-route bridge transport feasibility report
**Files:**
- Create: `docs/source-discovery/2026-07-12-b-route-bridge-feasibility.md`
- Modify: `docs/source-discovery/capability-source-matrix.md`
**Interfaces:**
- Consumes: existing docs `docs/source-discovery/2026-07-10-send-sidecar-b-first-plan.md`, `docs/source-discovery/2026-07-10-send-connector-preflight.md`, and current Go/C# connector files.
- Produces: a route decision table with exact choices: `existing_ipc`, `plugin_extension`, `in_process_adapter`, `external_dry_run_only`, or `fallback_rpa`.
- [ ] Re-read current B-route evidence.
Run:
```powershell
Get-Content -LiteralPath docs\source-discovery\2026-07-10-send-sidecar-b-first-plan.md
Get-Content -LiteralPath docs\source-discovery\2026-07-10-send-connector-preflight.md
Get-Content -LiteralPath internal\tools\send_message_broute_adapter.go
Get-Content -LiteralPath internal\tools\send_message_uia_adapter.go
```
Expected: confirm B-route entrypoint names exist, but no bridge transport is implemented.
- [ ] Write the feasibility report with this required conclusion block:
```markdown
## Decision
B-route remains primary. The immediate next implementation is not production send; it is bridge transport selection plus dry-run sidecar plumbing.
| Candidate | Can reuse logged-in runtime? | Local feasibility | Next action |
| --- | --- | --- | --- |
| existing_ipc/local_service | not confirmed | offline bridge map found no send/file API | park unless new online evidence appears |
| plugin_extension | not confirmed | plugin evidence is UI/app-store/context-menu oriented | park unless a concrete local load contract appears |
| in_process_adapter | possible but requires explicit bridge mechanism | selected by offline decision | create dedicated research plan before coding |
| external_dry_run_only | cannot reuse logged-in static runtime | useful for protocol/client tests only | keep preview/probe-only boundary |
| fallback_rpa | can drive UI only | backup-ready for UI action smoke | keep as backup, not primary |
```
- [ ] Update `capability-source-matrix.md` so the next slice says: “B-route bridge transport feasibility and dry-run sidecar boundary”, not “RPA send”.
- [ ] Verify docs.
Run:
```powershell
git diff --check
```
Expected: exit 0.
### 2026-07-12 plan correction
Task 1 is now satisfied by the offline reverse reports listed above. Before executing Tasks 2-5, create or approve a new `in_process_adapter_research` plan. Tasks 2-4 may still be used later for non-mutating sidecar preview plumbing, but they do not solve production send by themselves.
## Task 2: Add B-route connector env selection without starting real send
**Files:**
- Modify: `internal/tools/send_message_uia_adapter.go` or split env loading into `internal/tools/send_message_connector_env.go`
- Modify: `internal/tools/send_message_uia_adapter_test.go` or create `internal/tools/send_message_connector_env_test.go`
- Modify: `docs/go-mcp-runbook.md`
**Interfaces:**
- Consumes: `NewBRouteSendMessageConnector(BRouteSendAdapterConfig)`.
- Produces: `NewSendMessageConnectorFromEnv()` supports:
- `ISPHERE_SEND_CONNECTOR_MODE=broute_dry_run`
- `ISPHERE_SEND_CONNECTOR_MODE=broute_sidecar`
- `ISPHERE_SEND_BROUTE_MODE=disabled|dry_run_contract|sidecar_preview`
- `ISPHERE_SEND_BROUTE_SIDECAR_EXE=<path>`
- `ISPHERE_SEND_BROUTE_TIMEOUT_SECONDS=<positive int>`
- [ ] Write failing env-loader tests.
Test cases:
```text
mode empty -> nil connector
mode uia_rpa -> existing UIA connector
mode broute_dry_run -> B-route connector mode dry_run_contract
mode broute_sidecar without sidecar exe -> connector returns blocked sidecar config error, not panic
```
Run:
```powershell
go test ./internal/tools -run "TestNewSendMessageConnectorFromEnv" -count=1
```
Expected before implementation: fail for B-route modes.
- [ ] Implement env parsing with no real send.
Required behavior:
```text
broute_dry_run -> NewBRouteSendMessageConnector(BRouteSendAdapterConfig{Mode:"dry_run_contract"})
broute_sidecar -> NewBRouteSendMessageConnector(BRouteSendAdapterConfig{Mode:"sidecar_preview", SidecarPath: env path, TimeoutSeconds: parsed timeout})
```
- [ ] Run focused tests.
```powershell
go test ./internal/tools -run "TestNewSendMessageConnectorFromEnv|TestBRoute" -count=1
```
Expected: pass.
## Task 3: Process-backed B-route sidecar client boundary
**Files:**
- Create: `internal/broute/send_sidecar_client.go`
- Create: `internal/broute/send_sidecar_client_test.go`
- Modify: `internal/tools/send_message_broute_adapter.go`
- Modify: `internal/tools/send_message_broute_adapter_test.go`
**Interfaces:**
- Produces protocol: `isphere.broute.send.v1`.
- Produces sidecar ops:
- `self_check`
- `probe_runtime`
- `preview_send_message`
- No op named `send_message` in this task.
- [ ] Write fake-process tests for `internal/broute`.
The fake sidecar must accept stdin JSON and return:
```json
{"protocol":"isphere.broute.send.v1","request_id":"...","op":"preview_send_message","ok":true,"data":{"connector_mode":"broute-sidecar-preview","would_send":false,"entrypoint":"AppContextManager.SendTxtMessageByJid","target_ref":"direct:demo","content_sha256":"..."}}
```
- [ ] Implement the client with timeout, stderr capture, protocol/op/request_id validation, and structured sidecar errors.
Use `internal/msglib/sidecar_client.go` as the pattern, but keep the package separate as `internal/broute`.
- [ ] Update `send_message_broute_adapter.go` so `Mode="sidecar_preview"` calls `preview_send_message` and returns:
```text
Accepted=false
Status=blocked
ErrorCode=broute_sidecar_preview_only
ConnectorMode=broute-sidecar-preview
ProductionEnabled=false
SideEffects all false
```
- [ ] Verify no accidental production send path exists.
Run:
```powershell
go test ./internal/broute ./internal/tools -run "BRoute|Sidecar" -count=1
```
Expected: pass; no test should require iSphere login.
## Task 4: Native B-route sidecar skeleton, preview-only
**Files:**
- Create: `native/ISphereSendSidecar/Program.cs`
- Create: `native/ISphereSendSidecar/SidecarProtocol.cs`
- Create: `scripts/build-send-sidecar.ps1`
- Create: `scripts/verify-send-sidecar.ps1`
- Create: `docs/broute-send-sidecar-contract.md`
**Interfaces:**
- Native executable accepts stdin JSON and writes stdout JSON.
- Protocol: `isphere.broute.send.v1`.
- Ops implemented:
- `self_check`
- `probe_runtime`
- `preview_send_message`
- Explicitly not implemented:
- `send_message`
- `send_file`
- `upload_file`
- hooks/injection/network replay.
- [ ] Implement `self_check` returning sidecar name, version, process bitness, and `mutates_client=false`.
- [ ] Implement `probe_runtime` by reusing safe process/module discovery logic from WinHelper where possible.
- [ ] Implement `preview_send_message` as contract validation only; it must echo hashes/target refs and `would_send=false`.
- [ ] Build and verify.
Run:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\build-send-sidecar.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-send-sidecar.ps1
go test ./...
```
Expected: all pass; sidecar verification prints only booleans/counts and no message body.
## Task 5: Online B-route evidence package v3
**Files:**
- Create: `scripts/package-broute-bridge-probe.ps1`
- Create: `scripts/verify-broute-bridge-probe-package.ps1`
- Create: `scripts/validate-returned-broute-bridge-probe.ps1`
- Create: `docs/source-discovery/2026-07-12-broute-bridge-probe-package.md`
**Interfaces:**
- Package includes:
- live probe recorder;
- send sidecar preview executable;
- `RUN-BROUTE-BRIDGE-PROBE.bat`;
- `BROUTE-BRIDGE-INPUTS.template.json`;
- return zip helper.
- [ ] Package only non-mutating probes.
- [ ] Require operator to be logged in before running.
- [ ] Validate returned package for:
- running client present;
- module availability;
- sidecar self_check passed;
- sidecar preview returned `would_send=false`;
- no real send attempted.
Run:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\package-broute-bridge-probe.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-broute-bridge-probe-package.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\validate-returned-broute-bridge-probe.ps1 -UseFixture
```
Expected: package builds and fixture validation passes.
## Task 6: Business smoke split for send readiness
**Files:**
- Modify: `scripts/verify-business-goals-smoke.ps1`
- Modify: `docs/reports/2026-07-12-main-business-status-correction.md`
- Create or modify: `docs/reports/2026-07-12-broute-next-smoke.md`
**Interfaces:**
- Produces separate booleans:
- `send_message_preview_ready`
- `send_message_broute_bridge_preview_ready`
- `send_message_ui_action_ready`
- `send_message_business_delivery_ready`
- `send_file_preview_ready`
- `send_file_business_delivery_ready`
- [ ] Update smoke script to avoid one ambiguous `send_message_production_ready` field.
- [ ] Ensure current expected state is:
```json
{
"send_message_preview_ready": true,
"send_message_broute_bridge_preview_ready": true,
"send_message_ui_action_ready": true,
"send_message_business_delivery_ready": false,
"send_file_preview_ready": true,
"send_file_business_delivery_ready": false
}
```
- [ ] Verify.
Run:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify-business-goals-smoke.ps1
git diff --check
go test ./...
```
Expected: pass.
---
## Stop conditions
Stop and ask the business owner if any of these occur:
1. B-route bridge transport requires invasive in-process loading and no plugin/IPC path exists.
2. Online probe shows the logged-in client does not expose the expected modules/entrypoints.
3. B-route preview cannot distinguish direct contact vs group target.
4. Any step would perform real send/upload before explicit online evidence gates are ready.
5. A-route becomes the only viable path; this requires an explicit business decision because RPA is backup-only.
## Recommended next action
Start with Task 1 and Task 2 only. That creates a clear B-route bridge feasibility decision and lets the MCP server select a B-route dry-run connector from env without touching real send.

View File

@@ -0,0 +1,285 @@
# In-Process Adapter Research Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Convert the offline B-route decision into a reproducible in-process adapter research slice that identifies reachable runtime objects, defines the minimum helper contract, and keeps production send blocked until logged-in evidence exists.
**Architecture:** This branch does not mutate the iSphere client and does not claim production send. It adds deterministic IL/static analysis for in-process anchors, then updates the Go connector with an explicit `in_process_contract` mode that validates the future bridge request/response shape while returning a blocked/no-side-effect result. Later online work can replace the contract stub with a logged-in managed adapter.
**Tech Stack:** PowerShell static analyzers over IL/text evidence, Markdown reports under `docs/source-discovery`, Go MCP tool connector code under `internal/tools`, and `go test ./...` for regression verification.
## Global Constraints
- Do not use ripgrep (`rg`); use `git ls-files`, `ag`, `grep -R`, PowerShell, or `Select-String`.
- Do not stage or commit `.codex-remote-attachments/`.
- Do not copy, patch, or modify original iSphere binaries.
- Do not enable real text send, file upload, or file send in this offline branch.
- A-route/RPA remains backup-only; do not promote it as the product path.
- B-route primary path for this branch is `in_process_adapter_research`.
- Every claimed completion must be backed by fresh command output.
---
## File Structure
- Create `scripts/extract-inprocess-adapter-map.ps1`: deterministic static analyzer for in-process anchors, object ownership, method accessibility, required runtime state, and stop conditions.
- Create `docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md`: human-readable report generated by the script.
- Create ignored runtime JSON at `runs/inprocess-adapter-research/inprocess-adapter-map.json`: machine-readable evidence generated by the script; not committed unless the repo already tracks runs output.
- Modify `internal/tools/send_message_broute_adapter.go`: add `in_process_contract` mode that validates request shape and returns blocked/no-side-effect contract metadata.
- Modify `internal/tools/send_message_broute_adapter_test.go`: add tests for `in_process_contract` mode, including no accepted send and no side effects.
- Modify `internal/tools/send_message_uia_adapter.go`: extend the existing send connector env factory to route `ISPHERE_SEND_CONNECTOR_MODE=in_process_contract` to the B-route contract connector.
- Modify `internal/tools/send_message_uia_adapter_test.go`: prove the env factory builds the in-process contract connector.
- Modify `docs/source-discovery/capability-source-matrix.md`: point send-message/send-file next slices to the generated static map and keep production blocked.
---
### Task 1: Static In-Process Anchor Map
**Files:**
- Create: `scripts/extract-inprocess-adapter-map.ps1`
- Create: `docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md`
**Interfaces:**
- Consumes: IL files under `runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/` and offline B-route reports.
- Produces: Markdown report and JSON with these top-level keys: `ok`, `decision`, `anchors`, `commands`, `required_runtime_state`, `stop_conditions`, `originals_modified`.
- [ ] **Step 1: Create the analyzer script**
Create `scripts/extract-inprocess-adapter-map.ps1` with these behaviors:
```powershell
param(
[string]$OutDir = "runs/inprocess-adapter-research",
[string]$ReportPath = "docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md"
)
$ErrorActionPreference = 'Stop'
# Resolve repository root from the script location, not caller cwd.
# Read IL files only; never write into the sample directories.
# Extract anchors for AppContextManager, MessageScheduling, Chat, XMPPConnection,
# OffLineFileSend, FileUploadPara, FileUploadResult, FileTransfer, frmMain, and logged-in user/auth state.
# Emit JSON to $OutDir and Markdown to $ReportPath.
```
- [ ] **Step 2: Run the analyzer**
Run:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\extract-inprocess-adapter-map.ps1
```
Expected output contains:
```json
{
"ok": true,
"decision": "managed_in_process_adapter_contract_first",
"originals_modified": false
}
```
- [ ] **Step 3: Verify report content**
Run:
```powershell
Get-Content docs\source-discovery\2026-07-12-inprocess-adapter-static-map.md -Raw | Select-String -Pattern 'AppContextManager|MessageScheduling|Chat|FileUploadResult|in_process_contract|Stop conditions'
```
Expected: all listed terms are present.
---
### Task 2: Go Connector In-Process Contract Mode
**Files:**
- Modify: `internal/tools/send_message_broute_adapter.go`
- Modify: `internal/tools/send_message_broute_adapter_test.go`
- Modify: `internal/tools/send_message_uia_adapter.go`
- Modify: `internal/tools/send_message_uia_adapter_test.go`
**Interfaces:**
- Consumes: `SendMessageConnectorRequest` from `internal/tools/send_message_connector.go`.
- Produces: new connector mode string `in_process_contract` with blocked result:
- `Accepted: false`
- `Status: "blocked"`
- `ErrorCode: "broute_in_process_contract_only"`
- `ConnectorMode: "broute-in-process-contract"`
- `ProductionEnabled: false`
- `SideEffects["attached_hook"] == false`
- `SideEffects["sent_message"] == false`
- [ ] **Step 1: Add a failing test for contract mode**
Add this test to `internal/tools/send_message_broute_adapter_test.go`:
```go
func TestBRouteSendMessageConnectorInProcessContract(t *testing.T) {
connector := NewBRouteSendMessageConnector(BRouteSendAdapterConfig{Mode: "in_process_contract"})
result, err := connector.ExecuteSendMessage(context.Background(), SendMessageConnectorRequest{
TargetType: "direct",
TargetID: "u1",
TargetRef: "contact:u1",
ContentText: "hello",
ContentSHA256: strings.Repeat("a", 64),
ContentLength: 5,
IdempotencyKeySHA256: strings.Repeat("b", 64),
ExecutionMode: "production",
})
if err != nil {
t.Fatalf("in_process_contract should be a structured blocked result, not process error: %v", err)
}
if result.Accepted || result.ProductionEnabled {
t.Fatalf("contract mode must not accept production send: %+v", result)
}
if result.Status != "blocked" || result.ErrorCode != "broute_in_process_contract_only" {
t.Fatalf("unexpected contract result: %+v", result)
}
if result.ConnectorMode != "broute-in-process-contract" {
t.Fatalf("connector mode = %q", result.ConnectorMode)
}
if result.SideEffects["sent_message"] != false || result.SideEffects["attached_hook"] != false {
t.Fatalf("contract mode must report no side effects: %#v", result.SideEffects)
}
}
```
- [ ] **Step 2: Run the failing test**
Run:
```powershell
go test ./internal/tools -run TestBRouteSendMessageConnectorInProcessContract -count=1
```
Expected before implementation: FAIL because `in_process_contract` is not handled.
- [ ] **Step 3: Implement minimal mode branch**
In `internal/tools/send_message_broute_adapter.go`, add a `case "in_process_contract"` branch that calls `validateBRouteSendMessageRequest(request)` and returns a structured blocked result with no side effects.
- [ ] **Step 4: Add and run env factory coverage**
Add `TestSendMessageConnectorFromEnvBuildsInProcessContractConnector` to `internal/tools/send_message_uia_adapter_test.go` and update `NewSendMessageConnectorFromEnv()` so `ISPHERE_SEND_CONNECTOR_MODE=in_process_contract` returns `NewBRouteSendMessageConnector(BRouteSendAdapterConfig{Mode: "in_process_contract"})`.
Run:
```powershell
go test ./internal/tools -run 'Test(BRouteSendMessageConnector|SendMessageConnectorFromEnv)' -count=1
```
Expected: PASS.
- [ ] **Step 5: Run the targeted test again**
Run:
```powershell
go test ./internal/tools -run TestBRouteSendMessageConnectorInProcessContract -count=1
```
Expected: PASS.
---
### Task 3: Capability Matrix Correction
**Files:**
- Modify: `docs/source-discovery/capability-source-matrix.md`
**Interfaces:**
- Consumes: `docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md`.
- Produces: updated business-facing capability status showing B-route next step is contract/in-process reachability, not production send.
- [ ] **Step 1: Update send-message and send-file rows**
Add the new report path to the evidence references and update next-slice language:
```markdown
- In-process adapter static map: `docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md`
```
For send-message, state:
```markdown
Next slice: validate `in_process_contract` reachability in a logged-in runtime; production remains blocked until adapter invocation plus sent-record/content-hash/ack evidence exists.
```
For send-file, state:
```markdown
Next slice: validate logged-in access to `IFileTransfer.FileUpload` and returned `FileUploadResult.FileID`; production file upload/send remains blocked until online evidence exists.
```
- [ ] **Step 2: Verify diff contains no RPA promotion**
Run:
```powershell
git diff -- docs\source-discovery\capability-source-matrix.md | Select-String -Pattern 'RPA|in_process|production remains blocked|FileUploadResult'
```
Expected: in-process language appears and RPA remains backup-only.
---
### Task 4: Verification and Branch Closure
**Files:**
- All files from Tasks 1-3.
**Interfaces:**
- Consumes: scripts and tests from previous tasks.
- Produces: committed and pushed branch `codex/in-process-adapter-research`.
- [ ] **Step 1: Run static analyzer**
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\extract-inprocess-adapter-map.ps1
```
Expected: `ok=true`, `decision=managed_in_process_adapter_contract_first`, `originals_modified=false`.
- [ ] **Step 2: Run targeted tests**
```powershell
go test ./internal/tools -run TestBRouteSendMessageConnector -count=1
```
Expected: PASS.
- [ ] **Step 3: Run full tests**
```powershell
go test ./...
```
Expected: PASS.
- [ ] **Step 4: Run diff hygiene**
```powershell
git diff --check
git diff --cached --check
```
Expected: no output and exit code 0 after staging.
- [ ] **Step 5: Commit and push**
```powershell
git add scripts\extract-inprocess-adapter-map.ps1 docs\source-discovery\2026-07-12-inprocess-adapter-static-map.md docs\source-discovery\capability-source-matrix.md internal\tools\send_message_broute_adapter.go internal\tools\send_message_broute_adapter_test.go docs\superpowers\plans\2026-07-12-in-process-adapter-research.md
git commit -m "feat: add in-process adapter research contract"
git push -u gitea codex/in-process-adapter-research
```
Expected: branch pushed to `gitea/codex/in-process-adapter-research`.
---
## Self-Review
- Spec coverage: The plan covers B-route in-process research, static evidence, Go connector contract, capability matrix, verification, commit, and push.
- Placeholder scan: No task uses TBD/TODO/fill-in-later language; every implementation task names exact files and commands.
- Type consistency: `in_process_contract` maps to `broute-in-process-contract`; `SendMessageConnectorResult.SideEffects` reuses the existing `sendMessageNoSideEffects()` shape.

View File

@@ -0,0 +1,212 @@
# Offline B-Route Reverse Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Use offline reverse engineering to advance the primary B-route when no logged-in iSphere environment is available.
**Architecture:** Treat the available iSphere/IMPlatformClient binaries as read-only samples. Recover the send-message, send-file, plugin/IPC, and bridge-transport evidence needed to decide whether B-route can be implemented without relying on RPA. Keep A-route/RPA as backup-only and do not execute real send or upload in this plan.
**Tech Stack:** Windows PowerShell, .NET Framework IL tools, existing extracted IL files, Go 1.23.4 for repeatable analyzers, Markdown evidence reports.
## Global Constraints
- Repository root: `E:\coding\codex\isphere-ai-bridge`.
- Active branch for execution should be a new `codex/` branch, not `main` directly.
- Do not use `rg`; use `git ls-files`, `ag`, `grep -R`, or PowerShell commands.
- Tomorrow has no logged-in iSphere environment; do not wait for online evidence.
- Preserve original binaries read-only. Any extraction output must go under ignored `runs/` or committed sanitized docs/scripts only.
- B-route remains primary. A-route/RPA remains backup-only.
- No real message send, no file upload, no network replay, no process injection, and no client mutation in this plan.
- Outputs must separate verified facts from reverse-engineering hypotheses.
---
## Available offline samples
Use these local samples first:
| Sample | Purpose | SHA256 |
| --- | --- | --- |
| `runs/offline-real-client-window/full/zyl/Impp/IMPlatformClient.exe` | main managed client; text send, chat window, plugin/IPC candidates | `E2966E58360DAEEBF178410A961E2DC52748C63E9CCBD94BD6EC8434A1A09CB7` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Service.dll` | file upload service candidates | `F859DE2F34E024B5F372D95F22CBF8A018C780F24203E7A76D392E52BD90CADD` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Interface.dll` | service/interface contract candidates | `DD093CF61FAE85C2D2581F289B01AA477546712E098FEF81272FDD989E50D12D` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Model.dll` | model/parameter types | `7CBABDD23A7234D15E294C549EEEC78EFBAD6E957CD45A6E8A85309349A624A5` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.UI.dll` | UI/plugin helpers and possible send controls | `4C61212519C01D1B731ED4F20DF3411C491616F4ADA98A4529722A6AA3689E6D` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Common.dll` | shared utility and message types | `02A47C99C27C9BFE2BADC438389300C92220B07609BD87C48B4B5E1B4EE6AEB4` |
| `runs/offline-real-client-window/full/zyl/Impp/IMPP.Helper.dll` | helper abstractions | `30932D082B6678699C832C63F923E01EAD84674FAEDB613D631E034E03742FB9` |
| `runs/offline-real-client-window/full/zyl/Impp/smack.dll` | XMPP chat/send layer | `BAD0BB0591765DB153B17CECC1112B0BBDBF3B1D3370DDF973F91974E92CEC66` |
| `runs/offline-real-client-window/full/zyl/Impp/TcpFileTransfer.dll` | native/transfer candidate | `6C4874B46D1E7DC04C9B6784180603452400B881E04509D464A0D58814EFEDA7` |
| `runs/offline-real-client-window/full/zyl/Impp/HttpServerLib.dll` | local API/IPC candidate | `FFDB633216AE332B8EDFFC83E2AE546B7A80144C659FF4053FDFE4FE382A8D12` |
| `runs/offline-real-client-window/full/zyl/Impp/INetwork.dll` | network abstraction candidate | `E40BE4EE2439E4280461F4D2BADB318A5F4572428F069AB6D17B4C4F0E8CFAC9` |
| `runs/offline-real-client-window/full/zyl/Impp/IOClientNetwork.dll` | network implementation candidate | `64CA231A614771325741A5F098E52EBF20F7190E339B64962DE2EDEDCFFFF904` |
Existing IL evidence to reuse:
- `runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPlatformClient.exe.il`
- `runs/offline-chat-window/frmP2PChat-ctor.il.txt`
- `runs/offline-chat-window/frmP2PChat-ctor-null-risk.md`
---
## Task 1: Offline reverse case index
**Files:**
- Create: `docs/source-discovery/2026-07-12-offline-broute-reverse-index.md`
- Create: `scripts/build-offline-broute-reverse-index.ps1`
**Interfaces:**
- Produces: a sanitized Markdown/JSON index of sample paths, SHA256, size, timestamp, and role.
- Consumes: the sample paths listed above.
- [ ] Write `scripts/build-offline-broute-reverse-index.ps1` to hash the sample list and emit `runs/offline-broute-reverse/index.json` plus `docs/source-discovery/2026-07-12-offline-broute-reverse-index.md`.
The script must not copy or modify binaries. It should only read metadata and hashes.
- [ ] Run:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\build-offline-broute-reverse-index.ps1
```
Expected: JSON and Markdown index generated; no binary copied.
## Task 2: Text-send static call graph
**Files:**
- Create: `scripts/extract-broute-text-send-map.ps1`
- Create: `docs/source-discovery/2026-07-12-broute-text-send-static-map.md`
**Interfaces:**
- Consumes: `IMPlatformClient.exe.il`, `smack.dll`, and related managed assemblies.
- Produces: function map for:
- `AppContextManager.SendTxtMessageByJid`
- `MessageScheduling.SendChatMessage`
- `Chat.SendMessage`
- `XMPPConnection.send`
- `MessageCenter` send-related callbacks
- [ ] Extract method headers, signatures, call sites, and surrounding IL windows.
- [ ] Mark each function as one of: `confirmed_signature`, `confirmed_callsite`, `string_only`, or `not_found`.
- [ ] Write the report with a conclusion section:
```markdown
## Decision
B-route text send remains plausible only if a bridge can enter the logged-in runtime or an existing IPC/API exposes the same call. Offline IL confirms call shape, but not runtime invocability.
```
- [ ] Verify:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\extract-broute-text-send-map.ps1
git diff --check
```
Expected: exit 0 and report contains all target function names.
## Task 3: File-send/static upload call graph
**Files:**
- Create: `scripts/extract-broute-file-send-map.ps1`
- Create: `docs/source-discovery/2026-07-12-broute-file-send-static-map.md`
**Interfaces:**
- Consumes: `IMPlatformClient.exe`, `IMPP.Service.dll`, `IMPP.Interface.dll`, `IMPP.Model.dll`, `TcpFileTransfer.dll`.
- Produces: function/type map for:
- `IMPP.Client.OffLineFileSend.sendFile`
- `IMPP.Client.OffLineFileSend.trans_UploadCompleted`
- `IMPP.Service.BLL.FileTransfer.FileUpload`
- `IMPP.Service.BLL.FileTransfer.AsynFileUpload`
- `FileUploadPara`
- chat/file message send method names such as `sendFileMessage`
- [ ] Extract signatures and parameter types.
- [ ] Identify whether file send is direct upload first or chat-message first.
- [ ] Identify what local file path, server file id, file hash, and target JID values are required.
- [ ] Verify:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\extract-broute-file-send-map.ps1
git diff --check
```
Expected: report separates upload step from chat message step.
## Task 4: Bridge/IPC/plugin reverse map
**Files:**
- Create: `scripts/extract-broute-bridge-map.ps1`
- Create: `docs/source-discovery/2026-07-12-broute-bridge-static-map.md`
**Interfaces:**
- Consumes: `IMPlatformClient.exe`, `HttpServerLib.dll`, `IMPlatformClient.Web.exe`, `INetwork.dll`, `IOClientNetwork.dll`, config files, and existing live-probe `services_registry_shortcuts.json` / `network_inventory.json`.
- Produces: static evidence table for:
- localhost HTTP server routes or ports;
- named pipe strings;
- plugin loader classes or directories;
- command-line switches;
- COM/service candidates;
- update/patch extension points.
- [ ] Search strings and IL for `HttpListener`, `TcpListener`, `NamedPipe`, `Pipe`, `Plugin`, `LoadFrom`, `Assembly.Load`, `localhost`, `127.0.0.1`, `http://`, `net.pipe`, `Register`, `Route`, and `Command`.
- [ ] Report exact methods/classes where bridge candidates appear.
- [ ] Classify each candidate:
- `usable_without_login`
- `requires_logged_in_process`
- `static_only_unknown`
- `not_a_bridge`
- [ ] Verify:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\extract-broute-bridge-map.ps1
git diff --check
```
Expected: report gives a yes/no recommendation for whether B-route should pursue IPC/plugin before in-process adapter.
## Task 5: Offline bridge decision update
**Files:**
- Modify: `docs/superpowers/plans/2026-07-12-b-route-bridge-next-plan.md`
- Modify: `docs/source-discovery/capability-source-matrix.md`
- Create: `docs/source-discovery/2026-07-12-offline-broute-reverse-decision.md`
**Interfaces:**
- Consumes: reports from Tasks 1-4.
- Produces: next implementation decision:
- `existing_ipc_first`
- `plugin_extension_first`
- `in_process_adapter_research`
- `external_sidecar_preview_only`
- `fallback_rpa_only`
- [ ] Write decision using only offline evidence.
- [ ] If no bridge is found, state clearly that external sidecar can only do preview/probe unless an in-process bridge is added.
- [ ] Keep RPA marked backup-only.
## Task 6: Optional offline prototype only after decision
**Files:**
- To be added only after Task 5 decision.
**Rules:**
- If decision is `existing_ipc_first`, prototype a non-mutating client call to the local API only.
- If decision is `plugin_extension_first`, prototype plugin discovery only, not send.
- If decision is `in_process_adapter_research`, create a new explicit plan before coding.
- If decision is `external_sidecar_preview_only`, continue with the already planned preview-only B-route sidecar boundary.
- If decision is `fallback_rpa_only`, ask the user before promoting RPA beyond backup.
---
## Stop conditions
Stop and report if:
1. Static evidence shows all B-route send functions require live-only objects with no reachable bridge.
2. Bridge/plugin evidence implies invasive in-process loading and no safer IPC/API path exists.
3. File send requires server-issued upload tokens that cannot be derived offline.
4. Any next step would send a real message, upload a real file, mutate the client, attach a hook, or replay network traffic.
## Recommended immediate execution
Run Task 1 through Task 4 while offline. Do not wait for tomorrow's login evidence. After those reports exist, decide whether B-route can continue through IPC/plugin/static sidecar preview or whether RPA remains the only near-term operational path.

View File

@@ -52,6 +52,26 @@ func (c bRouteSendMessageConnector) ExecuteSendMessage(_ context.Context, reques
ErrorMessage: "B-route adapter dry_run_contract mode validates request shape only and does not start a sidecar", ErrorMessage: "B-route adapter dry_run_contract mode validates request shape only and does not start a sidecar",
ConnectorMode: "broute-dry-run-contract", ConnectorMode: "broute-dry-run-contract",
}, nil }, nil
case "in_process_contract":
if err := validateBRouteSendMessageRequest(request); err != nil {
return SendMessageConnectorResult{
Accepted: false,
Status: "failed",
ErrorCode: "broute_invalid_request",
ErrorMessage: err.Error(),
ConnectorMode: "broute-in-process-contract",
SideEffects: sendMessageNoSideEffects(),
}, nil
}
return SendMessageConnectorResult{
Accepted: false,
Status: "blocked",
ErrorCode: "broute_in_process_contract_only",
ErrorMessage: "B-route in_process_contract mode validates the future in-process adapter contract only; logged-in runtime reachability and sent-record evidence are still required",
ConnectorMode: "broute-in-process-contract",
ProductionEnabled: false,
SideEffects: sendMessageNoSideEffects(),
}, nil
default: default:
result := SendMessageConnectorResult{ result := SendMessageConnectorResult{
Accepted: false, Accepted: false,

View File

@@ -53,3 +53,32 @@ func TestBRouteSendMessageConnectorDryRunContract(t *testing.T) {
t.Fatalf("unexpected dry-run result: %+v", result) t.Fatalf("unexpected dry-run result: %+v", result)
} }
} }
func TestBRouteSendMessageConnectorInProcessContract(t *testing.T) {
connector := NewBRouteSendMessageConnector(BRouteSendAdapterConfig{Mode: "in_process_contract"})
result, err := connector.ExecuteSendMessage(context.Background(), SendMessageConnectorRequest{
TargetType: "direct",
TargetID: "u1",
TargetRef: "contact:u1",
ContentText: "hello",
ContentSHA256: strings.Repeat("a", 64),
ContentLength: 5,
IdempotencyKeySHA256: strings.Repeat("b", 64),
ExecutionMode: "production",
})
if err != nil {
t.Fatalf("in_process_contract should be a structured blocked result, not process error: %v", err)
}
if result.Accepted || result.ProductionEnabled {
t.Fatalf("contract mode must not accept production send: %+v", result)
}
if result.Status != "blocked" || result.ErrorCode != "broute_in_process_contract_only" {
t.Fatalf("unexpected contract result: %+v", result)
}
if result.ConnectorMode != "broute-in-process-contract" {
t.Fatalf("connector mode = %q", result.ConnectorMode)
}
if result.SideEffects["sent_message"] != false || result.SideEffects["attached_hook"] != false {
t.Fatalf("contract mode must report no side effects: %#v", result.SideEffects)
}
}

View File

@@ -53,6 +53,9 @@ type uiaSendMessageConnector struct {
func NewSendMessageConnectorFromEnv() SendMessageConnector { func NewSendMessageConnectorFromEnv() SendMessageConnector {
mode := strings.TrimSpace(strings.ToLower(os.Getenv(EnvSendConnectorMode))) mode := strings.TrimSpace(strings.ToLower(os.Getenv(EnvSendConnectorMode)))
if mode == "in_process_contract" || mode == "in-process-contract" {
return NewBRouteSendMessageConnector(BRouteSendAdapterConfig{Mode: "in_process_contract"})
}
if mode != "uia_rpa" && mode != "uia-rpa" { if mode != "uia_rpa" && mode != "uia-rpa" {
return nil return nil
} }

View File

@@ -2,6 +2,7 @@ package tools
import ( import (
"context" "context"
"strings"
"testing" "testing"
) )
@@ -103,6 +104,31 @@ func TestSendMessageConnectorFromEnvBuildsUiaRPAConnector(t *testing.T) {
} }
} }
func TestSendMessageConnectorFromEnvBuildsInProcessContractConnector(t *testing.T) {
t.Setenv(EnvSendConnectorMode, "in_process_contract")
connector := NewSendMessageConnectorFromEnv()
if connector == nil {
t.Fatalf("NewSendMessageConnectorFromEnv returned nil for in_process_contract config")
}
result, err := connector.ExecuteSendMessage(context.Background(), SendMessageConnectorRequest{
TargetType: "direct",
TargetID: "u1",
TargetRef: "contact:u1",
ContentText: "hello",
ContentSHA256: strings.Repeat("a", 64),
ContentLength: 5,
IdempotencyKeySHA256: strings.Repeat("b", 64),
ExecutionMode: sendMessageProductionMode,
})
if err != nil {
t.Fatalf("in_process_contract should return structured blocked result, got err=%v", err)
}
if result.Accepted || result.ProductionEnabled || result.ErrorCode != "broute_in_process_contract_only" {
t.Fatalf("unexpected in-process contract result: %+v", result)
}
}
type fakeUiaHelperCaller struct { type fakeUiaHelperCaller struct {
response uiaHelperResponse response uiaHelperResponse
err error err error

View File

@@ -0,0 +1,168 @@
param(
[string]$OutputDir = "runs/offline-broute-reverse",
[string]$ReportPath = "docs/source-discovery/2026-07-12-offline-broute-reverse-index.md"
)
$ErrorActionPreference = "Stop"
$repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path
$outDir = Join-Path $repo $OutputDir
$reportFullPath = Join-Path $repo $ReportPath
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $reportFullPath) | Out-Null
$samples = @(
@{
path = "runs/offline-real-client-window/full/zyl/Impp/IMPlatformClient.exe"
role = "main managed client; text send, chat window, plugin/IPC candidates"
expected_sha256 = "E2966E58360DAEEBF178410A961E2DC52748C63E9CCBD94BD6EC8434A1A09CB7"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Service.dll"
role = "file upload service candidates"
expected_sha256 = "F859DE2F34E024B5F372D95F22CBF8A018C780F24203E7A76D392E52BD90CADD"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Interface.dll"
role = "service/interface contract candidates"
expected_sha256 = "DD093CF61FAE85C2D2581F289B01AA477546712E098FEF81272FDD989E50D12D"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Model.dll"
role = "model/parameter types"
expected_sha256 = "7CBABDD23A7234D15E294C549EEEC78EFBAD6E957CD45A6E8A85309349A624A5"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.UI.dll"
role = "UI/plugin helpers and possible send controls"
expected_sha256 = "4C61212519C01D1B731ED4F20DF3411C491616F4ADA98A4529722A6AA3689E6D"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Common.dll"
role = "shared utility and message types"
expected_sha256 = "02A47C99C27C9BFE2BADC438389300C92220B07609BD87C48B4B5E1B4EE6AEB4"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Helper.dll"
role = "helper abstractions"
expected_sha256 = "30932D082B6678699C832C63F923E01EAD84674FAEDB613D631E034E03742FB9"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/smack.dll"
role = "XMPP chat/send layer"
expected_sha256 = "BAD0BB0591765DB153B17CECC1112B0BBDBF3B1D3370DDF973F91974E92CEC66"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/TcpFileTransfer.dll"
role = "native/transfer candidate"
expected_sha256 = "6C4874B46D1E7DC04C9B6784180603452400B881E04509D464A0D58814EFEDA7"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/HttpServerLib.dll"
role = "local API/IPC candidate"
expected_sha256 = "FFDB633216AE332B8EDFFC83E2AE546B7A80144C659FF4053FDFE4FE382A8D12"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/INetwork.dll"
role = "network abstraction candidate"
expected_sha256 = "E40BE4EE2439E4280461F4D2BADB318A5F4572428F069AB6D17B4C4F0E8CFAC9"
},
@{
path = "runs/offline-real-client-window/full/zyl/Impp/IOClientNetwork.dll"
role = "network implementation candidate"
expected_sha256 = "64CA231A614771325741A5F098E52EBF20F7190E339B64962DE2EDEDCFFFF904"
}
)
$entries = foreach ($sample in $samples) {
$fullPath = Join-Path $repo $sample.path
$exists = Test-Path -LiteralPath $fullPath -PathType Leaf
$item = $null
$sha256 = ""
$matches = $false
if ($exists) {
$item = Get-Item -LiteralPath $fullPath
$sha256 = (Get-FileHash -LiteralPath $fullPath -Algorithm SHA256).Hash.ToUpperInvariant()
$matches = ($sha256 -eq $sample.expected_sha256)
}
[pscustomobject]@{
path = $sample.path
file_name = Split-Path -Leaf $sample.path
role = $sample.role
exists = $exists
size_bytes = if ($item) { $item.Length } else { $null }
last_write_time = if ($item) { $item.LastWriteTime.ToString("o") } else { $null }
sha256 = $sha256
expected_sha256 = $sample.expected_sha256
sha256_matches_expected = $matches
}
}
$summary = [pscustomobject]@{
generated_at = (Get-Date).ToUniversalTime().ToString("o")
repository = $repo
output_dir = $OutputDir
samples_total = @($entries).Count
samples_present = @($entries | Where-Object { $_.exists }).Count
hash_matches = @($entries | Where-Object { $_.sha256_matches_expected }).Count
originals_copied = $false
originals_modified = $false
entries = $entries
}
$jsonPath = Join-Path $outDir "index.json"
$summary | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $jsonPath -Encoding UTF8
$lines = New-Object System.Collections.Generic.List[string]
$lines.Add("# Offline B-Route Reverse Index")
$lines.Add("")
$lines.Add("Date: 2026-07-12")
$lines.Add("")
$lines.Add("## Scope")
$lines.Add("")
$lines.Add("This index records the read-only offline samples for B-route reverse engineering. The script reads metadata and SHA256 hashes only; it does not copy or modify the original binaries.")
$lines.Add("")
$lines.Add("## Summary")
$lines.Add("")
$lines.Add("- Samples total: $($summary.samples_total)")
$lines.Add("- Samples present: $($summary.samples_present)")
$lines.Add("- Hash matches: $($summary.hash_matches)")
$lines.Add("- Originals copied: false")
$lines.Add("- Originals modified: false")
$lines.Add("- Machine JSON: ``$OutputDir/index.json``")
$lines.Add("")
$lines.Add("## Sample table")
$lines.Add("")
$lines.Add("| Sample | Role | Size | SHA256 match | SHA256 |")
$lines.Add("| --- | --- | ---: | --- | --- |")
foreach ($entry in $entries) {
$size = if ($null -ne $entry.size_bytes) { [string]$entry.size_bytes } else { "missing" }
$match = if ($entry.sha256_matches_expected) { "yes" } else { "no" }
$sha = if ($entry.sha256) { $entry.sha256 } else { "missing" }
$lines.Add("| ``$($entry.path)`` | $($entry.role) | $size | $match | ``$sha`` |")
}
$lines.Add("")
$lines.Add("## Verified facts")
$lines.Add("")
$lines.Add("- All metadata came from local filesystem reads under the repository workspace.")
$lines.Add("- The expected primary B-route samples are present if `Samples present` equals `Samples total`.")
$lines.Add("- Hash matching only proves local file identity against this plan's recorded sample list; it does not prove runtime invocability.")
$lines.Add("")
$lines.Add("## Next reverse targets")
$lines.Add("")
$lines.Add("1. Text-send static call graph: `SendTxtMessageByJid`, `MessageScheduling.SendChatMessage`, `Chat.SendMessage`, `XMPPConnection.send`.")
$lines.Add("2. File-send/upload static call graph: `OffLineFileSend.sendFile`, `FileTransfer.FileUpload`, `AsynFileUpload`, `sendFileMessage`.")
$lines.Add("3. Bridge/IPC/plugin map: `HttpServerLib`, plugin loaders, local HTTP, named pipes, command-line switches, services.")
($lines -join "`n") + "`n" | Set-Content -LiteralPath $reportFullPath -Encoding UTF8
[pscustomobject]@{
ok = $true
json_path = $jsonPath
report_path = $reportFullPath
samples_total = $summary.samples_total
samples_present = $summary.samples_present
hash_matches = $summary.hash_matches
originals_copied = $false
originals_modified = $false
} | ConvertTo-Json -Depth 4

View File

@@ -0,0 +1,537 @@
param(
[string]$IlDir = "runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il",
[string]$BinaryDir = "runs/offline-real-client-window/full/zyl/Impp",
[string]$OutputDir = "runs/offline-broute-reverse",
[string]$ReportPath = "docs/source-discovery/2026-07-12-broute-bridge-static-map.md",
[int]$WindowRadius = 4,
[int]$MaxEvidencePerCandidate = 18
)
$ErrorActionPreference = "Stop"
$repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path
$ilDirFull = Join-Path $repo $IlDir
$binaryDirFull = Join-Path $repo $BinaryDir
$outDir = Join-Path $repo $OutputDir
$reportFullPath = Join-Path $repo $ReportPath
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $reportFullPath) | Out-Null
$textSources = @(
@{ path = "IMPlatformClient.exe.il"; role = "main client IL; login, plugin manager, local HTTP starter, chat/runtime" },
@{ path = "IMPP.Common.dll.il"; role = "common helpers; WinCommand, ProcessComm, DTOs" },
@{ path = "IMPP.ISphere.exe.il"; role = "ISphere companion app IL; CEF and command helpers" },
@{ path = "IMPP.UI.dll.il"; role = "UI/browser support IL" },
@{ path = "IMPP.Service.dll.il"; role = "file service implementation IL" },
@{ path = "smack.dll.il"; role = "XMPP/socks5/network IL" }
)
$binarySources = @(
@{ path = "HttpServerLib.dll"; role = "local HTTP server framework binary" },
@{ path = "IMPlatformClient.Web.exe"; role = "CEF/web helper process binary" },
@{ path = "INetwork.dll"; role = "native network abstraction" },
@{ path = "IOClientNetwork.dll"; role = "native network implementation" },
@{ path = "IMPlatformClient.exe"; role = "main client binary" }
)
$liveProbeSources = @(
"runs/returned-live-probe/isphere-live-probe-20260710-121958/isphere-live-probe-20260710-121958/services_registry_shortcuts.json",
"runs/returned-live-probe/isphere-live-probe-20260710-121958/isphere-live-probe-20260710-121958/network_inventory.json"
)
$candidates = @(
@{
key = "local_http_win_server"
display = "frmLogin.StartWinServer / HttpServerLib.HttpService"
category = "localhost_http"
classification = "requires_logged_in_process"
usable_for_broute_send = $false
recommendation = "do_not_pursue_before_in_process_adapter"
reason = "Static IL builds a local HTTP service from logged-in user/auth state, but no send route or active live local listener was confirmed."
patterns = @("StartWinServer", "HttpServerLib", "HttpService::\.ctor", "HttpServer::Start", "GetFreePort", "0\.0\.0\.0", "messageAuth", "RepairDatabase")
},
@{
key = "http_route_framework"
display = "HttpServerLib route/module framework"
category = "localhost_http"
classification = "static_only_unknown"
usable_for_broute_send = $false
recommendation = "no_existing_ipc_first"
reason = "HttpServerLib has ServiceModule/RouteAttribute primitives, but client IL does not show RegisterModule or send-message routes."
patterns = @("RouteAttribute", "RouteMethod", "ServiceModule", "ServiceRoute", "RegisterModule", "OnGet\s*\(", "OnPost\s*\(", "ExecuteRoute", "SearchRoute")
},
@{
key = "plugin_named_pipe_stub"
display = "PluginLightAppMulProcessCommunication NamedPipeServerStream"
category = "named_pipe"
classification = "not_a_bridge"
usable_for_broute_send = $false
recommendation = "do_not_use"
reason = "A NamedPipeServerStream field exists, but StartLightAppMultProssCommunication has a one-instruction ret body."
patterns = @("NamedPipeServerStream", "PluginLightAppMulProcessCommunication", "StartLightAppMultProssCommunication", "MulProcess", "LightApp")
},
@{
key = "process_comm_wm_copydata"
display = "IMPP.Common.Helper.ProcessComm WM_COPYDATA helper"
category = "window_message"
classification = "static_only_unknown"
usable_for_broute_send = $false
recommendation = "not_a_send_bridge"
reason = "ProcessComm can send WM_COPYDATA to a foreground or titled window, but no receive handler or send-command contract is confirmed."
patterns = @("IMPP\.Common\.Helper\.ProcessComm", "\bProcessComm\b", "COPYDATASTRUCT", "WM_COPYDATA", "SendMessageToTargetWindow", "FindWindow\(string lpClassName", "GetForegroundWindow\(\)")
},
@{
key = "plugin_manager_command_surface"
display = "PluginManager / IMPlugin command surface"
category = "plugin"
classification = "requires_logged_in_process"
usable_for_broute_send = $false
recommendation = "plugin_extension_not_first"
reason = "Plugin evidence is UI/app-store/context-menu oriented and depends on logged-in PluginManager state; no Assembly.Load/LoadFrom or send API bridge was confirmed."
patterns = @("PluginManager", "IMPlugin::get_Command", "LoadPluginContextMenu", "FrmAppStore", "FrmCefHomePage", "ShowPlugins", "Assembly\.Load", "LoadFrom", "AddPluginInfo")
},
@{
key = "cef_web_helper"
display = "IMPlatformClient.Web / CEF helper"
category = "child_process"
classification = "requires_logged_in_process"
usable_for_broute_send = $false
recommendation = "preview_only_not_send"
reason = "The web helper/CEF surface exists, but static evidence points to UI/plugin browser support, not an external send/file API."
patterns = @("IMPlatformClient\.Web", "CefProcessName", "CefRuntime", "WinCefBrowser", "NavigateTo", "SendProcessMessage", "V8Context")
},
@{
key = "native_network_stack"
display = "INetwork / IOClientNetwork native stack"
category = "native_network"
classification = "not_a_bridge"
usable_for_broute_send = $false
recommendation = "do_not_pursue_as_ipc"
reason = "Native NETIO send/recv symbols are low-level transport, not a local command bridge into logged-in chat objects."
patterns = @("INetwork", "IOClientNetwork", "NETIO_", "NETIO_C_", "StreamClient", "RegistRecvCallback", "SendPacket", "BasePipe")
},
@{
key = "live_probe_named_pipe"
display = "returned live-probe named pipe inventory"
category = "named_pipe"
classification = "static_only_unknown"
usable_for_broute_send = $false
recommendation = "do_not_assume_isphere_api"
reason = "Live probe saw \\.\\pipe\\zfpinject-msg-server, but no matching iSphere static string or send contract was found in the configured samples."
patterns = @("zfpinject-msg-server", "named_pipes", "connections", "remote_port", "10088")
},
@{
key = "local_tcp_listener_candidates"
display = "local TcpListener candidates"
category = "tcp_listener"
classification = "not_a_bridge"
usable_for_broute_send = $false
recommendation = "not_existing_ipc"
reason = "TcpListener evidence is tied to TCP file manage or smack socks5, not a command API for text/file send. Returned live probe had only one remote XMPP connection."
patterns = @("TcpListener", "TCPFileManager::_listener", "TCPSocks5Server", "GetActiveTcpListeners", "BeginAcceptSocket", "remote_port")
}
)
function Get-RelativePath([string]$Path) {
if ($Path.StartsWith($repo, [System.StringComparison]::OrdinalIgnoreCase)) {
return $Path.Substring($repo.Length).TrimStart('\', '/')
}
return $Path
}
function Get-TextEvidenceKind([string]$Line) {
if ($Line -match "^\s*\.class\b") { return "type_definition" }
if ($Line -match "^\s*\.method\b") { return "method_header" }
if ($Line -match "\bend of method\b") { return "method_end" }
if ($Line -match "\bcall(?:virt)?\b") { return "callsite" }
if ($Line -match "\bnewobj\b") { return "constructor_call" }
if ($Line -match "\bldstr\b") { return "string_literal" }
if ($Line -match "^\s*(instance|static|StartWinServer|GetFreePort|SendMessageToTargetWindow)\b.*\(") { return "signature_continuation" }
return "reference"
}
function Get-MethodContext($Lines, [int]$Index) {
$start = [Math]::Max(0, $Index - 120)
$methodHeader = $null
$classHeader = $null
for ($i = $Index; $i -ge $start; $i--) {
$line = $Lines[$i]
if ($null -eq $methodHeader -and $line -match "^\s*\.method\b") {
$methodHeader = [pscustomobject]@{ line_number = $i + 1; text = $line.Trim() }
}
if ($null -eq $classHeader -and $line -match "^\s*\.class\b") {
$classHeader = [pscustomobject]@{ line_number = $i + 1; text = $line.Trim() }
}
if ($methodHeader -and $classHeader) { break }
}
[pscustomobject]@{ method_header = $methodHeader; class_header = $classHeader }
}
function New-TextEvidence($Lines, [int]$Index, [string]$SourceRel) {
$from = [Math]::Max(0, $Index - $WindowRadius)
$to = [Math]::Min($Lines.Count - 1, $Index + $WindowRadius)
$window = New-Object System.Collections.Generic.List[object]
for ($i = $from; $i -le $to; $i++) {
$window.Add([pscustomobject]@{ line_number = $i + 1; text = $Lines[$i].TrimEnd() })
}
$context = Get-MethodContext -Lines $Lines -Index $Index
[pscustomobject]@{
source = $SourceRel
source_type = "text_il"
line_number = $Index + 1
string_index = $null
kind = Get-TextEvidenceKind -Line $Lines[$Index]
text = $Lines[$Index].Trim()
method_header = $context.method_header
class_header = $context.class_header
window = $window
}
}
function Get-PrintableStrings([string]$Path, [int]$MinLength = 4) {
$bytes = [System.IO.File]::ReadAllBytes($Path)
$strings = New-Object System.Collections.Generic.List[string]
$sb = New-Object System.Text.StringBuilder
foreach ($b in $bytes) {
if ($b -ge 32 -and $b -le 126) {
[void]$sb.Append([char]$b)
} else {
if ($sb.Length -ge $MinLength) { $strings.Add($sb.ToString()) }
$sb.Clear() | Out-Null
}
}
if ($sb.Length -ge $MinLength) { $strings.Add($sb.ToString()) }
$sb = New-Object System.Text.StringBuilder
for ($i = 0; $i -lt ($bytes.Length - 1); $i += 2) {
$b = $bytes[$i]
$z = $bytes[$i + 1]
if ($z -eq 0 -and $b -ge 32 -and $b -le 126) {
[void]$sb.Append([char]$b)
} else {
if ($sb.Length -ge $MinLength) { $strings.Add($sb.ToString()) }
$sb.Clear() | Out-Null
}
}
if ($sb.Length -ge $MinLength) { $strings.Add($sb.ToString()) }
return $strings.ToArray()
}
function Get-HttpServerReflection([string]$Path) {
$result = [ordered]@{ path = Get-RelativePath -Path $Path; ok = $false; error = ""; types = @() }
try {
$asm = [System.Reflection.Assembly]::LoadFile($Path)
$types = New-Object System.Collections.Generic.List[object]
foreach ($type in $asm.GetTypes()) {
if ($type.FullName -notmatch "HTTPServerLib\.(HttpServer|HttpService|ServiceModule|ServiceRoute|RouteAttribute|IServer|ActionResult)") { continue }
$ctors = @($type.GetConstructors([System.Reflection.BindingFlags]'Public,NonPublic,Instance') | ForEach-Object {
$params = @($_.GetParameters() | ForEach-Object { $_.ParameterType.Name + " " + $_.Name })
[pscustomobject]@{ is_public = $_.IsPublic; signature = "$($type.Name)($([string]::Join(', ', $params)))" }
})
$methods = @($type.GetMethods([System.Reflection.BindingFlags]'Public,NonPublic,Instance,Static,DeclaredOnly') | ForEach-Object {
$params = @($_.GetParameters() | ForEach-Object { $_.ParameterType.Name + " " + $_.Name })
[pscustomobject]@{ name = $_.Name; signature = "$($_.ReturnType.Name) $($_.Name)($([string]::Join(', ', $params)))" }
})
$types.Add([pscustomobject]@{ full_name = $type.FullName; constructors = $ctors; methods = $methods })
}
$result.ok = $true
$result.types = $types.ToArray()
} catch {
$result.error = $_.Exception.Message
}
return [pscustomobject]$result
}
$textSourceResults = New-Object System.Collections.Generic.List[object]
$binarySourceResults = New-Object System.Collections.Generic.List[object]
$candidateBuckets = @{}
foreach ($candidate in $candidates) {
$candidateBuckets[[string]$candidate['key']] = New-Object System.Collections.Generic.List[object]
}
foreach ($source in $textSources) {
$sourceFullPath = Join-Path $ilDirFull ([string]$source['path'])
$sourceRel = Get-RelativePath -Path $sourceFullPath
if (-not (Test-Path -LiteralPath $sourceFullPath -PathType Leaf)) {
$textSourceResults.Add([pscustomobject]@{ path = $sourceRel; role = $source['role']; exists = $false; line_count = 0; size_bytes = $null })
continue
}
$item = Get-Item -LiteralPath $sourceFullPath
$lines = [System.IO.File]::ReadAllLines($sourceFullPath)
$textSourceResults.Add([pscustomobject]@{ path = $sourceRel; role = $source['role']; exists = $true; line_count = $lines.Count; size_bytes = $item.Length })
foreach ($candidate in $candidates) {
$key = [string]$candidate['key']
$compiled = @($candidate['patterns'] | ForEach-Object { [regex]::new($_, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) })
for ($i = 0; $i -lt $lines.Count; $i++) {
$line = $lines[$i]
foreach ($rx in $compiled) {
if ($rx.IsMatch($line)) {
$candidateBuckets[$key].Add((New-TextEvidence -Lines $lines -Index $i -SourceRel $sourceRel))
break
}
}
}
}
}
foreach ($source in $binarySources) {
$sourceFullPath = Join-Path $binaryDirFull ([string]$source['path'])
$sourceRel = Get-RelativePath -Path $sourceFullPath
if (-not (Test-Path -LiteralPath $sourceFullPath -PathType Leaf)) {
$binarySourceResults.Add([pscustomobject]@{ path = $sourceRel; role = $source['role']; exists = $false; string_count = 0; size_bytes = $null })
continue
}
$item = Get-Item -LiteralPath $sourceFullPath
$strings = Get-PrintableStrings -Path $sourceFullPath -MinLength 4
$binarySourceResults.Add([pscustomobject]@{ path = $sourceRel; role = $source['role']; exists = $true; string_count = $strings.Count; size_bytes = $item.Length })
foreach ($candidate in $candidates) {
$key = [string]$candidate['key']
$compiled = @($candidate['patterns'] | ForEach-Object { [regex]::new($_, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) })
for ($i = 0; $i -lt $strings.Count; $i++) {
$s = $strings[$i]
foreach ($rx in $compiled) {
if ($rx.IsMatch($s)) {
$candidateBuckets[$key].Add([pscustomobject]@{
source = $sourceRel
source_type = "binary_string"
line_number = $null
string_index = $i
kind = "binary_string"
text = $s
method_header = $null
class_header = $null
window = @()
})
break
}
}
}
}
}
$liveProbe = New-Object System.Collections.Generic.List[object]
foreach ($relPath in $liveProbeSources) {
$fullPath = Join-Path $repo $relPath
if (Test-Path -LiteralPath $fullPath -PathType Leaf) {
$raw = Get-Content -LiteralPath $fullPath -Raw
$liveProbe.Add([pscustomobject]@{ path = $relPath; exists = $true; length = $raw.Length; data = ($raw | ConvertFrom-Json) })
foreach ($candidate in $candidates) {
$key = [string]$candidate['key']
$compiled = @($candidate['patterns'] | ForEach-Object { [regex]::new($_, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) })
foreach ($rx in $compiled) {
if ($rx.IsMatch($raw)) {
$candidateBuckets[$key].Add([pscustomobject]@{
source = $relPath
source_type = "live_probe_json"
line_number = $null
string_index = $null
kind = "live_probe_json"
text = ($raw -replace "\s+", " ").Trim()
method_header = $null
class_header = $null
window = @()
})
break
}
}
}
} else {
$liveProbe.Add([pscustomobject]@{ path = $relPath; exists = $false; length = 0; data = $null })
}
}
$httpServerPath = Join-Path $binaryDirFull "HttpServerLib.dll"
$httpReflection = if (Test-Path -LiteralPath $httpServerPath -PathType Leaf) { Get-HttpServerReflection -Path $httpServerPath } else { [pscustomobject]@{ path = Get-RelativePath -Path $httpServerPath; ok = $false; error = "missing"; types = @() } }
$httpReflectionPath = Join-Path $outDir "httpserverlib-reflection.json"
$httpReflection | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $httpReflectionPath -Encoding UTF8
if ($httpReflection.ok) {
$reflectionText = ($httpReflection.types | ConvertTo-Json -Depth 8 -Compress)
foreach ($candidate in $candidates) {
$key = [string]$candidate['key']
$compiled = @($candidate['patterns'] | ForEach-Object { [regex]::new($_, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) })
foreach ($rx in $compiled) {
if ($rx.IsMatch($reflectionText)) {
$candidateBuckets[$key].Add([pscustomobject]@{
source = Get-RelativePath -Path $httpReflectionPath
source_type = "reflection"
line_number = $null
string_index = $null
kind = "reflection_metadata"
text = "HttpServerLib reflection exposes matching types/methods; see httpserverlib-reflection.json"
method_header = $null
class_header = $null
window = @()
})
break
}
}
}
}
$candidateResults = New-Object System.Collections.Generic.List[object]
foreach ($candidate in $candidates) {
$key = [string]$candidate['key']
$allEvidence = $candidateBuckets[$key].ToArray()
$evidenceForReport = @(
$allEvidence |
Sort-Object @{ Expression = { if ($_.source_type -eq "text_il") { 0 } elseif ($_.source_type -eq "reflection") { 1 } elseif ($_.source_type -eq "live_probe_json") { 2 } else { 3 } } }, source, line_number, string_index |
Select-Object -First $MaxEvidencePerCandidate
)
$classification = if ($allEvidence.Count -eq 0) { "not_found" } else { [string]$candidate['classification'] }
$candidateResults.Add([pscustomobject]@{
key = $key
display = $candidate['display']
category = $candidate['category']
classification = $classification
usable_for_broute_send = [bool]$candidate['usable_for_broute_send']
recommendation = $candidate['recommendation']
reason = $candidate['reason']
match_count = $allEvidence.Count
evidence = $evidenceForReport
})
}
$recommendation = [pscustomobject]@{
pursue_existing_ipc_or_plugin_first = $false
decision = "in_process_adapter_research"
fallback_boundary = "external_sidecar_preview_only_until_bridge_exists"
rationale = "Offline static evidence found no existing local IPC/plugin route that exposes send-message or send-file. HttpServerLib and plugin surfaces either require logged-in runtime state or are UI/framework-only; the named-pipe stub is empty."
}
$summary = [pscustomobject]@{
generated_at = (Get-Date).ToUniversalTime().ToString("o")
repository = $repo
il_dir = $IlDir
binary_dir = $BinaryDir
text_sources = $textSourceResults
binary_sources = $binarySourceResults
live_probe = $liveProbe
httpserverlib_reflection = Get-RelativePath -Path $httpReflectionPath
candidates = $candidateResults
recommendation = $recommendation
originals_copied = $false
originals_modified = $false
}
$jsonPath = Join-Path $outDir "bridge-map.json"
$summary | ConvertTo-Json -Depth 14 | Set-Content -LiteralPath $jsonPath -Encoding UTF8
$linesOut = New-Object System.Collections.Generic.List[string]
$linesOut.Add("# B-Route Bridge/IPC/Plugin Static Map")
$linesOut.Add("")
$linesOut.Add("Date: 2026-07-12")
$linesOut.Add("")
$linesOut.Add("## Scope")
$linesOut.Add("")
$linesOut.Add("This report uses offline IL, binary string metadata, reflection metadata for ``HttpServerLib.dll``, and returned live-probe JSON. It does not log in, open sockets, attach hooks, inject into a process, replay traffic, or mutate client binaries.")
$linesOut.Add("")
$linesOut.Add("Machine-readable evidence: ``$OutputDir/bridge-map.json``")
$linesOut.Add("Reflection metadata: ``$OutputDir/httpserverlib-reflection.json``")
$linesOut.Add("")
$linesOut.Add("## Recommendation")
$linesOut.Add("")
$linesOut.Add("| Question | Answer |")
$linesOut.Add("| --- | --- |")
$linesOut.Add("| Should B-route pursue existing IPC/plugin before an in-process adapter? | **No** |")
$linesOut.Add("| Offline decision | ``$($recommendation.decision)`` |")
$linesOut.Add("| External sidecar boundary | ``$($recommendation.fallback_boundary)`` |")
$linesOut.Add("| Reason | $($recommendation.rationale) |")
$linesOut.Add("")
$linesOut.Add("## Sources")
$linesOut.Add("")
$linesOut.Add("### Text/IL sources")
$linesOut.Add("")
$linesOut.Add("| Source | Role | Exists | Lines | Size bytes |")
$linesOut.Add("| --- | --- | --- | ---: | ---: |")
foreach ($sourceResult in $textSourceResults) {
$exists = if ($sourceResult.exists) { "yes" } else { "no" }
$sizeText = if ($null -ne $sourceResult.size_bytes) { [string]$sourceResult.size_bytes } else { "" }
$linesOut.Add("| ``$($sourceResult.path)`` | $($sourceResult.role) | $exists | $($sourceResult.line_count) | $sizeText |")
}
$linesOut.Add("")
$linesOut.Add("### Binary/string sources")
$linesOut.Add("")
$linesOut.Add("| Source | Role | Exists | Strings | Size bytes |")
$linesOut.Add("| --- | --- | --- | ---: | ---: |")
foreach ($sourceResult in $binarySourceResults) {
$exists = if ($sourceResult.exists) { "yes" } else { "no" }
$sizeText = if ($null -ne $sourceResult.size_bytes) { [string]$sourceResult.size_bytes } else { "" }
$linesOut.Add("| ``$($sourceResult.path)`` | $($sourceResult.role) | $exists | $($sourceResult.string_count) | $sizeText |")
}
$linesOut.Add("")
$linesOut.Add("## Candidate classification")
$linesOut.Add("")
$linesOut.Add("| Candidate | Category | Classification | Usable for B-route send | Recommendation | Matches |")
$linesOut.Add("| --- | --- | --- | --- | --- | ---: |")
foreach ($candidateResult in $candidateResults) {
$usable = if ($candidateResult.usable_for_broute_send) { "yes" } else { "no" }
$linesOut.Add("| ``$($candidateResult.display)`` | ``$($candidateResult.category)`` | ``$($candidateResult.classification)`` | $usable | ``$($candidateResult.recommendation)`` | $($candidateResult.match_count) |")
}
$linesOut.Add("")
$linesOut.Add("## Verified facts")
$linesOut.Add("")
$linesOut.Add("- ``frmLogin.StartWinServer`` constructs ``HTTPServerLib.HttpService`` on ``0.0.0.0`` and starts ``HttpServer.Start`` in a thread, but it depends on ``IMPPManager.UserInfo`` and ``ServiceManager.UnifiedAuthentication`` state.")
$linesOut.Add("- ``HttpServerLib.dll`` exposes route/module primitives such as ``HttpService.RegisterModule``, ``ServiceModule``, ``ServiceRoute``, ``RouteAttribute``, ``OnGet``, and ``OnPost``.")
$linesOut.Add("- Main client IL does not show a concrete ``RegisterModule`` call or send-message/send-file HTTP route registration.")
$linesOut.Add("- ``PluginLightAppMulProcessCommunication`` declares a ``NamedPipeServerStream`` field, but ``StartLightAppMultProssCommunication`` returns immediately.")
$linesOut.Add("- Returned live probe showed one remote TCP connection to port ``10088`` and a named pipe ``\\.\\pipe\\zfpinject-msg-server``; neither proves an iSphere send API.")
$linesOut.Add("- ``PluginManager``/``IMPlugin`` evidence is UI/app-store/context-menu oriented; no local assembly-load plugin bridge or send route was confirmed.")
$linesOut.Add("")
$linesOut.Add("## Candidate evidence")
foreach ($candidateResult in $candidateResults) {
$linesOut.Add("")
$linesOut.Add("### $($candidateResult.display)")
$linesOut.Add("")
$linesOut.Add("Classification: ``$($candidateResult.classification)``; usable for B-route send: ``$($candidateResult.usable_for_broute_send)``; matches: $($candidateResult.match_count).")
$linesOut.Add("")
$linesOut.Add("Reason: $($candidateResult.reason)")
if (@($candidateResult.evidence).Count -eq 0) {
$linesOut.Add("")
$linesOut.Add("No evidence found in configured offline sources.")
continue
}
$linesOut.Add("")
$linesOut.Add("| Source | Kind | Snippet | Context |")
$linesOut.Add("| --- | --- | --- | --- |")
foreach ($evidence in $candidateResult.evidence) {
$sourceLoc = if ($evidence.line_number) { "$($evidence.source):$($evidence.line_number)" } elseif ($null -ne $evidence.string_index) { "$($evidence.source)#str$($evidence.string_index)" } else { $evidence.source }
$method = if ($evidence.method_header) { "L$($evidence.method_header.line_number): $($evidence.method_header.text)" } else { "" }
$snippet = (($evidence.text -replace "\|", "\\|") -replace "`r?`n", " ")
if ($snippet.Length -gt 220) { $snippet = $snippet.Substring(0, 220) + "..." }
$method = ($method -replace "\|", "\\|")
$linesOut.Add("| ``$sourceLoc`` | ``$($evidence.kind)`` | ``$snippet`` | ``$method`` |")
}
}
$linesOut.Add("")
$linesOut.Add("## Decision")
$linesOut.Add("")
$linesOut.Add("No existing IPC/plugin/local HTTP bridge is confirmed usable for B-route text send or file send. The next B-route branch should be ``in_process_adapter_research``. Until that exists, an external sidecar can only do preview/probe work, while A-route/RPA remains backup-only.")
$linesOut.Add("")
$linesOut.Add("## Next work")
$linesOut.Add("")
$linesOut.Add("1. Update the B-route next plan and capability source matrix with ``in_process_adapter_research`` as the offline decision.")
$linesOut.Add("2. Create a separate plan before implementing any in-process adapter work.")
$linesOut.Add("3. Do not promote RPA beyond backup in this branch.")
($linesOut -join "`n") + "`n" | Set-Content -LiteralPath $reportFullPath -Encoding UTF8
$requiredNames = @("HttpServerLib", "NamedPipe", "Plugin", "IMPlatformClient.Web", "ProcessComm", "INetwork", "IOClientNetwork", "in_process_adapter_research")
$reportText = Get-Content -LiteralPath $reportFullPath -Raw
$missing = @($requiredNames | Where-Object { $reportText -notlike "*$_*" })
if ($missing.Count -gt 0) {
throw "Report missing required names: $($missing -join ', ')"
}
[pscustomobject]@{
ok = $true
json_path = $jsonPath
report_path = $reportFullPath
reflection_path = $httpReflectionPath
candidates = $candidateResults.Count
decision = $recommendation.decision
pursue_existing_ipc_or_plugin_first = $false
originals_copied = $false
originals_modified = $false
} | ConvertTo-Json -Depth 6

View File

@@ -0,0 +1,342 @@
param(
[string]$IlDir = "runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il",
[string]$OutputDir = "runs/offline-broute-reverse",
[string]$ReportPath = "docs/source-discovery/2026-07-12-broute-file-send-static-map.md",
[int]$WindowRadius = 5,
[int]$MaxEvidencePerTarget = 18
)
$ErrorActionPreference = "Stop"
$repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path
$ilDirFull = Join-Path $repo $IlDir
$outDir = Join-Path $repo $OutputDir
$reportFullPath = Join-Path $repo $ReportPath
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $reportFullPath) | Out-Null
$sources = @(
@{ path = "IMPlatformClient.exe.il"; role = "main client IL; UC_FileSend, OffLineFileSend, MessageScheduling" },
@{ path = "IMPP.Service.dll.il"; role = "file transfer service implementation" },
@{ path = "IMPP.ServiceBase.dll.il"; role = "file transfer contracts, parameters, and result DTOs" },
@{ path = "IMPP.Interface.dll.il"; role = "transport/event interface contracts" },
@{ path = "smack.dll.il"; role = "Chat.sendFileMessage and XMPP message construction" },
@{ path = "TcpFileTransfer.dll.il"; role = "native TCP transfer candidate; IL may be unavailable" },
@{ path = "IMPP.Model.dll.il"; role = "chat record models if extracted" }
)
$targets = @(
@{
key = "IMPP.Client.OffLineFileSend.sendFile"
display = "IMPP.Client.OffLineFileSend.sendFile"
phase = "upload"
intent = "offline file upload orchestration from UI file sender"
patterns = @("OffLineFileSend::sendFile", "^\s*sendFile\(\) cil managed")
},
@{
key = "IMPP.Client.OffLineFileSend.trans_UploadCompleted"
display = "IMPP.Client.OffLineFileSend.trans_UploadCompleted"
phase = "upload_to_message_boundary"
intent = "upload-completed handler that converts FileUploadResult.FileID into a chat file message"
patterns = @("OffLineFileSend::trans_UploadCompleted", "trans_UploadCompleted\(string fileId\)")
},
@{
key = "IMPP.Service.BLL.FileTransfer.FileUpload"
display = "IMPP.Service.BLL.FileTransfer.FileUpload"
phase = "upload"
intent = "synchronous service upload entry returning FileUploadResult"
patterns = @("FileTransfer::FileUpload", "FileUpload\(class \[IMPP\.ServiceBase\].*FileUploadPara")
},
@{
key = "IMPP.Service.BLL.FileTransfer.AsynFileUpload"
display = "IMPP.Service.BLL.FileTransfer.AsynFileUpload"
phase = "upload"
intent = "asynchronous upload queue entry"
patterns = @("FileTransfer::AsynFileUpload", "AsynFileUpload\(class \[IMPP\.ServiceBase\].*FileUploadPara")
},
@{
key = "FileUploadPara"
display = "FileUploadPara"
phase = "upload_parameters"
intent = "host/port/domain/local file path/cache/timeout/upload flags"
patterns = @("FileUploadPara", "FileUploadPara::\.ctor")
},
@{
key = "FileUploadResult.FileID"
display = "FileUploadResult.FileID"
phase = "upload_result"
intent = "server-side file id and URL returned by upload"
patterns = @("FileUploadResult::get_FileID", "FileUploadResult::set_FileID", "FileUploadResult", "get_FileID\(\) cil managed")
},
@{
key = "MessageScheduling.SendFileMessage"
display = "MessageScheduling.SendFileMessage"
phase = "message"
intent = "scheduled/file-message finalization path using RosterContactsArgs and FileTransferArgs"
patterns = @("MessageScheduling::SendFileMessage", "SendFileMessage\(class IMPP\.Client\.Business\.RosterContacts\.RosterContactsArgs")
},
@{
key = "Chat.sendFileMessage"
display = "Chat.sendFileMessage"
phase = "message"
intent = "smack API that sends the XMPP file message after upload metadata is known"
patterns = @("Chat::sendFileMessage", "P2PChat::sendFileMessage", "ChatRoom::sendFileMessage", "sendFileMessage\(string p_message")
},
@{
key = "Required values: path id size target jid"
display = "Required values: path id size target jid"
phase = "requirements"
intent = "static evidence for local file path, remote folder/file id, file size/name, target JID/chat, and server auth"
patterns = @("get_LocalFilePath", "get_RemoteFolder", "get__localFilePath", "get__fileSize", "FileInfo::get_Length", "FileSystemInfo::get_Name", "get_RosterJid", "GetChat\(", "HTTPFileServer", "UnifiedAuthentication", "Auth::get_token")
}
)
function Get-RelativePath([string]$Path) {
if ($Path.StartsWith($repo, [System.StringComparison]::OrdinalIgnoreCase)) {
return $Path.Substring($repo.Length).TrimStart('\', '/')
}
return $Path
}
function Get-EvidenceKind([string]$Line) {
if ($Line -match "^\s*\.class\b") { return "type_definition" }
if ($Line -match "^\s*\.method\b") { return "method_header" }
if ($Line -match "\bend of method\b") { return "method_end" }
if ($Line -match "\bcall(?:virt)?\b") { return "callsite" }
if ($Line -match "\bnewobj\b") { return "constructor_call" }
if ($Line -match "\bldstr\b") { return "string_literal" }
if ($Line -match "^\s*(instance|static|FileUpload|SendFileMessage|sendFileMessage|sendFile|trans_UploadCompleted)\b.*\(") { return "signature_continuation" }
return "reference"
}
function Get-MethodContext($Lines, [int]$Index) {
$start = [Math]::Max(0, $Index - 120)
$methodHeader = $null
$classHeader = $null
for ($i = $Index; $i -ge $start; $i--) {
$line = $Lines[$i]
if ($null -eq $methodHeader -and $line -match "^\s*\.method\b") {
$methodHeader = [pscustomobject]@{ line_number = $i + 1; text = $line.Trim() }
}
if ($null -eq $classHeader -and $line -match "^\s*\.class\b") {
$classHeader = [pscustomobject]@{ line_number = $i + 1; text = $line.Trim() }
}
if ($methodHeader -and $classHeader) { break }
}
[pscustomobject]@{ method_header = $methodHeader; class_header = $classHeader }
}
function New-Evidence($Lines, [int]$Index, [string]$SourceRel) {
$from = [Math]::Max(0, $Index - $WindowRadius)
$to = [Math]::Min($Lines.Count - 1, $Index + $WindowRadius)
$window = New-Object System.Collections.Generic.List[object]
for ($i = $from; $i -le $to; $i++) {
$window.Add([pscustomobject]@{ line_number = $i + 1; text = $Lines[$i].TrimEnd() })
}
$context = Get-MethodContext -Lines $Lines -Index $Index
[pscustomobject]@{
source = $SourceRel
line_number = $Index + 1
kind = Get-EvidenceKind -Line $Lines[$Index]
text = $Lines[$Index].Trim()
method_header = $context.method_header
class_header = $context.class_header
window = $window
}
}
function Get-Classification($Evidence) {
$kinds = @($Evidence | ForEach-Object { $_.kind })
if ($kinds -contains "type_definition" -or $kinds -contains "method_header" -or $kinds -contains "signature_continuation" -or $kinds -contains "method_end") { return "confirmed_signature" }
if ($kinds -contains "callsite" -or $kinds -contains "constructor_call") { return "confirmed_callsite" }
if ($kinds.Count -gt 0 -and @($kinds | Where-Object { $_ -ne "string_literal" }).Count -eq 0) { return "string_only" }
if ($kinds.Count -gt 0) { return "confirmed_callsite" }
return "not_found"
}
$sourceResults = New-Object System.Collections.Generic.List[object]
$targetBuckets = @{}
foreach ($target in $targets) {
$targetKey = [string]$target['key']
$targetBuckets[$targetKey] = New-Object System.Collections.Generic.List[object]
}
foreach ($source in $sources) {
$sourcePath = [string]$source['path']
$sourceFullPath = Join-Path $ilDirFull $sourcePath
$sourceRel = Get-RelativePath -Path $sourceFullPath
if (-not (Test-Path -LiteralPath $sourceFullPath -PathType Leaf)) {
$sourceResults.Add([pscustomobject]@{ path = $sourceRel; role = $source['role']; exists = $false; line_count = 0; size_bytes = $null })
continue
}
$item = Get-Item -LiteralPath $sourceFullPath
$lines = [System.IO.File]::ReadAllLines($sourceFullPath)
$sourceResults.Add([pscustomobject]@{ path = $sourceRel; role = $source['role']; exists = $true; line_count = $lines.Count; size_bytes = $item.Length })
foreach ($target in $targets) {
$targetKey = [string]$target['key']
$compiled = @($target['patterns'] | ForEach-Object { [regex]::new($_, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) })
for ($i = 0; $i -lt $lines.Count; $i++) {
$line = $lines[$i]
foreach ($rx in $compiled) {
if ($rx.IsMatch($line)) {
$targetBuckets[$targetKey].Add((New-Evidence -Lines $lines -Index $i -SourceRel $sourceRel))
break
}
}
}
}
}
$targetResults = New-Object System.Collections.Generic.List[object]
foreach ($target in $targets) {
$targetKey = [string]$target['key']
$allEvidence = $targetBuckets[$targetKey].ToArray()
$evidenceForReport = @(
$allEvidence |
Sort-Object @{ Expression = { if ($_.kind -in @("type_definition", "method_header", "signature_continuation", "method_end")) { 0 } elseif ($_.kind -in @("callsite", "constructor_call")) { 1 } elseif ($_.kind -eq "string_literal") { 2 } else { 3 } } }, source, line_number |
Select-Object -First $MaxEvidencePerTarget
)
$targetResults.Add([pscustomobject]@{
key = $targetKey
display = $target['display']
phase = $target['phase']
intent = $target['intent']
classification = Get-Classification -Evidence $allEvidence
match_count = $allEvidence.Count
evidence = $evidenceForReport
})
}
$requirements = @(
[pscustomobject]@{ value = "local file path"; evidence = "OffLineFileSend constructor receives localFilePath; sendFile uses get__localFilePath; MessageScheduling.SendFileMessage uses FileTransferArgs.get_LocalFilePath."; status = "required_confirmed" },
[pscustomobject]@{ value = "server file id / remote folder"; evidence = "Upload returns FileUploadResult.FileID; trans_UploadCompleted(fileId) passes it to Chat.sendFileMessage and Packet.set_id. MessageScheduling path uses FileTransferArgs.get_RemoteFolder."; status = "required_confirmed" },
[pscustomobject]@{ value = "file name and file size"; evidence = "SendFileMessage builds OFFLINE_FILE_TRANSFER payload from FileInfo/FileSystemInfo name and length; OffLineFileSend keeps _fileSize."; status = "required_confirmed" },
[pscustomobject]@{ value = "target JID / chat object"; evidence = "UC_FileSend and MessageScheduling both require a live smack Chat; scheduled path derives it from RosterContactsArgs.get_RosterJid + UtilsChat.GetChat."; status = "required_confirmed" },
[pscustomobject]@{ value = "HTTP file server and auth"; evidence = "FileUploadPara construction uses Config.ServerInfo.HTTPFileServer IP/Port/domain; service upload builds /FS/auth/resource/upload URL with UnifiedAuthentication token/app key/client secret/time/user id."; status = "required_confirmed" },
[pscustomobject]@{ value = "file hash"; evidence = "No file-transfer-path MD5/SHA/checksum requirement was confirmed in the configured IL. MD5 hits belong to image/RTF or auth digest areas, not the offline file-send path."; status = "not_confirmed_in_file_send_path" }
)
$summary = [pscustomobject]@{
generated_at = (Get-Date).ToUniversalTime().ToString("o")
repository = $repo
il_dir = $IlDir
sources = $sourceResults
targets = $targetResults
phase_decision = "Offline static evidence shows upload first, then chat file-message finalization. Direct Chat.sendFileMessage alone is not enough unless a valid uploaded file id/remote folder already exists."
requirements = $requirements
originals_copied = $false
originals_modified = $false
}
$jsonPath = Join-Path $outDir "file-send-map.json"
$summary | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $jsonPath -Encoding UTF8
$linesOut = New-Object System.Collections.Generic.List[string]
$linesOut.Add("# B-Route File Send Static Map")
$linesOut.Add("")
$linesOut.Add("Date: 2026-07-12")
$linesOut.Add("")
$linesOut.Add("## Scope")
$linesOut.Add("")
$linesOut.Add("This report uses offline IL only. It does not upload files, send file messages, replay traffic, inject into a process, or mutate the original iSphere binaries.")
$linesOut.Add("")
$linesOut.Add("Machine-readable evidence: ``$OutputDir/file-send-map.json``")
$linesOut.Add("")
$linesOut.Add("## Sources")
$linesOut.Add("")
$linesOut.Add("| Source | Role | Exists | Lines | Size bytes |")
$linesOut.Add("| --- | --- | --- | ---: | ---: |")
foreach ($sourceResult in $sourceResults) {
$exists = if ($sourceResult.exists) { "yes" } else { "no" }
$sizeText = if ($null -ne $sourceResult.size_bytes) { [string]$sourceResult.size_bytes } else { "" }
$linesOut.Add("| ``$($sourceResult.path)`` | $($sourceResult.role) | $exists | $($sourceResult.line_count) | $sizeText |")
}
$linesOut.Add("")
$linesOut.Add("## Target classification")
$linesOut.Add("")
$linesOut.Add("| Target | Phase | Intent | Classification | Matches |")
$linesOut.Add("| --- | --- | --- | --- | ---: |")
foreach ($targetResult in $targetResults) {
$linesOut.Add("| ``$($targetResult.display)`` | ``$($targetResult.phase)`` | $($targetResult.intent) | ``$($targetResult.classification)`` | $($targetResult.match_count) |")
}
$linesOut.Add("")
$linesOut.Add("## Upload step vs chat-message step")
$linesOut.Add("")
$linesOut.Add("| Step | Static evidence | Business meaning |")
$linesOut.Add("| --- | --- | --- |")
$linesOut.Add("| 1. Upload | ``IMPP.Client.OffLineFileSend.sendFile`` constructs ``FileUploadPara`` and calls ``IFileTransfer.FileUpload``; ``IMPP.Service.BLL.FileTransfer.FileUpload`` delegates to ``SyncFileTransfer`` and private ``Upload``. | The local file must be uploaded to the HTTP file service first. |")
$linesOut.Add("| 2. Upload result | ``FileUploadResult.FileID`` is read; upload notification calls ``IMPP.Client.OffLineFileSend.trans_UploadCompleted(fileId)``. | The server-issued file id becomes the durable reference. |")
$linesOut.Add("| 3. Chat file message | ``trans_UploadCompleted`` and ``MessageScheduling.SendFileMessage`` build ``OFFLINE_FILE_TRANSFER;...`` payloads and call ``Chat.sendFileMessage``. | The chat send step publishes metadata/reference, not raw file bytes. |")
$linesOut.Add("")
$linesOut.Add("Conclusion: file send is upload-first, chat-message-second. A direct chat message is insufficient without a valid uploaded file id or remote folder reference.")
$linesOut.Add("")
$linesOut.Add("## Required values")
$linesOut.Add("")
$linesOut.Add("| Value | Status | Evidence |")
$linesOut.Add("| --- | --- | --- |")
foreach ($req in $requirements) {
$linesOut.Add("| $($req.value) | ``$($req.status)`` | $($req.evidence) |")
}
$linesOut.Add("")
$linesOut.Add("## Evidence excerpts")
foreach ($targetResult in $targetResults) {
$linesOut.Add("")
$linesOut.Add("### $($targetResult.display)")
$linesOut.Add("")
$linesOut.Add("Classification: ``$($targetResult.classification)``; phase: ``$($targetResult.phase)``; matches: $($targetResult.match_count).")
if (@($targetResult.evidence).Count -eq 0) {
$linesOut.Add("")
$linesOut.Add("No evidence found in configured offline IL sources.")
continue
}
$linesOut.Add("")
$linesOut.Add("| Source line | Kind | Snippet | Method context |")
$linesOut.Add("| --- | --- | --- | --- |")
foreach ($evidence in $targetResult.evidence) {
$method = if ($evidence.method_header) { "L$($evidence.method_header.line_number): $($evidence.method_header.text)" } else { "" }
$snippet = ($evidence.text -replace "\|", "\\|")
$method = ($method -replace "\|", "\\|")
$linesOut.Add("| ``$($evidence.source):$($evidence.line_number)`` | ``$($evidence.kind)`` | ``$snippet`` | ``$method`` |")
}
}
$linesOut.Add("")
$linesOut.Add("## Inference")
$linesOut.Add("")
$linesOut.Add("- High confidence: upload and file-message finalization are separate steps.")
$linesOut.Add("- High confidence: ``FileUploadPara`` needs HTTP file server host/port/domain plus local file path and upload options.")
$linesOut.Add("- High confidence: ``Chat.sendFileMessage`` produces the XMPP file-message envelope after file metadata is available.")
$linesOut.Add("- Medium confidence: B-route file send must either call the same logged-in service/runtime or reproduce the authenticated HTTP upload plus XMPP file-message sequence.")
$linesOut.Add("- Low confidence until bridge evidence: an external sidecar can obtain the same service/auth/chat objects without being inside the logged-in client process.")
$linesOut.Add("")
$linesOut.Add("## Decision")
$linesOut.Add("")
$linesOut.Add("Offline static evidence supports B-route research, but file sending needs more than one method call: upload first, then chat file-message finalization. The next blocker is reachability: whether an IPC/plugin/in-process bridge can access the logged-in ``IFileTransfer`` service and smack ``Chat`` object.")
$linesOut.Add("")
$linesOut.Add("## Next work")
$linesOut.Add("")
$linesOut.Add("1. Extract bridge/IPC/plugin candidates before coding any file-send adapter.")
$linesOut.Add("2. If a bridge exists, prototype non-mutating discovery first: service availability, chat object lookup, and upload endpoint metadata only.")
$linesOut.Add("3. Keep A-route/RPA backup-only.")
($linesOut -join "`n") + "`n" | Set-Content -LiteralPath $reportFullPath -Encoding UTF8
$requiredNames = @("IMPP.Client.OffLineFileSend.sendFile", "IMPP.Client.OffLineFileSend.trans_UploadCompleted", "IMPP.Service.BLL.FileTransfer.FileUpload", "IMPP.Service.BLL.FileTransfer.AsynFileUpload", "FileUploadPara", "sendFileMessage", "Upload step vs chat-message step")
$reportText = Get-Content -LiteralPath $reportFullPath -Raw
$missing = @($requiredNames | Where-Object { $reportText -notlike "*$_*" })
if ($missing.Count -gt 0) {
throw "Report missing required names: $($missing -join ', ')"
}
[pscustomobject]@{
ok = $true
json_path = $jsonPath
report_path = $reportFullPath
sources = $sourceResults.Count
targets = $targetResults.Count
classifications = @($targetResults | ForEach-Object { "$($_.display)=$($_.classification)" })
phase_decision = $summary.phase_decision
originals_copied = $false
originals_modified = $false
} | ConvertTo-Json -Depth 6

View File

@@ -0,0 +1,285 @@
param(
[string]$IlDir = "runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il",
[string]$OutputDir = "runs/offline-broute-reverse",
[string]$ReportPath = "docs/source-discovery/2026-07-12-broute-text-send-static-map.md",
[int]$WindowRadius = 4,
[int]$MaxEvidencePerTarget = 18
)
$ErrorActionPreference = "Stop"
$repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path
$ilDirFull = Join-Path $repo $IlDir
$outDir = Join-Path $repo $OutputDir
$reportFullPath = Join-Path $repo $ReportPath
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $reportFullPath) | Out-Null
$sources = @(
@{
path = "IMPlatformClient.exe.il"
role = "main managed client IL; chat UI, AppContextManager, scheduling call sites"
},
@{
path = "smack.dll.il"
role = "XMPP/smack managed IL; Chat and XMPPConnection implementation"
}
)
$targets = @(
@{
key = "AppContextManager.SendTxtMessageByJid"
display = "AppContextManager.SendTxtMessageByJid"
intent = "high-level text send entry exposed by AppContextManager"
patterns = @("AppContextManager::SendTxtMessageByJid", "\bSendTxtMessageByJid\b")
},
@{
key = "MessageScheduling.SendChatMessage"
display = "MessageScheduling.SendChatMessage"
intent = "message scheduling text/chat send helper"
patterns = @("MessageScheduling::SendChatMessage", "\bSendChatMessage\s*\(")
},
@{
key = "Chat.SendMessage"
display = "Chat.SendMessage"
intent = "smack Chat send API used by chat/UI code"
patterns = @("com\.vision\.smack\.Chat::SendMessage", "com\.vision\.smack\.Chat::sendMessage", "\bChat::SendMessage\b", "\bChat::sendMessage\b")
},
@{
key = "XMPPConnection.send"
display = "XMPPConnection.send"
intent = "lowest-level XMPP connection send primitive"
patterns = @("XMPPConnection::send\b", "\bXMPPConnection\.send\b")
},
@{
key = "MessageCenter send-related callbacks"
display = "MessageCenter send-related callbacks"
intent = "MessageCenter or IMPPManager message-center callbacks touching send/message flow"
patterns = @("GetMessageCenter\s*\(\)", "MessageCenter::.*Send", "MessageCenter.*Send", "class IMPP\.Client\.control\.MessageCenter", "IMPP\.Client\.control\.MessageCenter")
}
)
function Get-RelativePath([string]$Path) {
if ($Path.StartsWith($repo, [System.StringComparison]::OrdinalIgnoreCase)) {
return $Path.Substring($repo.Length).TrimStart('\', '/')
}
return $Path
}
function Get-EvidenceKind([string]$Line) {
if ($Line -match "^\s*\.class\b") { return "type_definition" }
if ($Line -match "^\s*\.method\b") { return "method_header" }
if ($Line -match "\bend of method\b") { return "method_end" }
if ($Line -match "\bcall(?:virt)?\b") { return "callsite" }
if ($Line -match "\bldstr\b") { return "string_literal" }
if ($Line -match "^\s*(instance|static)\b.*\(") { return "signature_continuation" }
return "reference"
}
function Get-MethodContext($Lines, [int]$Index) {
$start = [Math]::Max(0, $Index - 90)
$methodHeader = $null
$classHeader = $null
for ($i = $Index; $i -ge $start; $i--) {
$line = $Lines[$i]
if ($null -eq $methodHeader -and $line -match "^\s*\.method\b") {
$methodHeader = [pscustomobject]@{ line_number = $i + 1; text = $line.Trim() }
}
if ($null -eq $classHeader -and $line -match "^\s*\.class\b") {
$classHeader = [pscustomobject]@{ line_number = $i + 1; text = $line.Trim() }
}
if ($methodHeader -and $classHeader) { break }
}
[pscustomobject]@{ method_header = $methodHeader; class_header = $classHeader }
}
function New-Evidence($Lines, [int]$Index, [string]$SourceRel) {
$from = [Math]::Max(0, $Index - $WindowRadius)
$to = [Math]::Min($Lines.Count - 1, $Index + $WindowRadius)
$window = New-Object System.Collections.Generic.List[object]
for ($i = $from; $i -le $to; $i++) {
$window.Add([pscustomobject]@{ line_number = $i + 1; text = $Lines[$i].TrimEnd() })
}
$context = Get-MethodContext -Lines $Lines -Index $Index
[pscustomobject]@{
source = $SourceRel
line_number = $Index + 1
kind = Get-EvidenceKind -Line $Lines[$Index]
text = $Lines[$Index].Trim()
method_header = $context.method_header
class_header = $context.class_header
window = $window
}
}
function Get-Classification($Evidence) {
$kinds = @($Evidence | ForEach-Object { $_.kind })
if ($kinds -contains "method_header" -or $kinds -contains "signature_continuation" -or $kinds -contains "method_end") { return "confirmed_signature" }
if ($kinds -contains "callsite") { return "confirmed_callsite" }
if ($kinds.Count -gt 0 -and @($kinds | Where-Object { $_ -ne "string_literal" }).Count -eq 0) { return "string_only" }
if ($kinds.Count -gt 0) { return "confirmed_callsite" }
return "not_found"
}
$sourceResults = New-Object System.Collections.Generic.List[object]
$targetBuckets = @{}
foreach ($target in $targets) {
$targetKey = [string]$target['key']
$targetBuckets[$targetKey] = New-Object System.Collections.Generic.List[object]
}
foreach ($source in $sources) {
$sourcePath = [string]$source['path']
$sourceFullPath = Join-Path $ilDirFull $sourcePath
$sourceRel = Get-RelativePath -Path $sourceFullPath
if (-not (Test-Path -LiteralPath $sourceFullPath -PathType Leaf)) {
$sourceResults.Add([pscustomobject]@{ path = $sourceRel; role = $source['role']; exists = $false; line_count = 0; size_bytes = $null })
continue
}
$item = Get-Item -LiteralPath $sourceFullPath
$lines = [System.IO.File]::ReadAllLines($sourceFullPath)
$sourceResults.Add([pscustomobject]@{ path = $sourceRel; role = $source['role']; exists = $true; line_count = $lines.Count; size_bytes = $item.Length })
foreach ($target in $targets) {
$targetKey = [string]$target['key']
$compiled = @($target['patterns'] | ForEach-Object { [regex]::new($_, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) })
for ($i = 0; $i -lt $lines.Count; $i++) {
$line = $lines[$i]
foreach ($rx in $compiled) {
if ($rx.IsMatch($line)) {
$targetBuckets[$targetKey].Add((New-Evidence -Lines $lines -Index $i -SourceRel $sourceRel))
break
}
}
}
}
}
$targetResults = New-Object System.Collections.Generic.List[object]
foreach ($target in $targets) {
$targetKey = [string]$target['key']
$allEvidence = $targetBuckets[$targetKey].ToArray()
$evidenceForReport = @(
$allEvidence |
Sort-Object @{ Expression = { if ($_.kind -in @("method_header", "signature_continuation", "method_end")) { 0 } elseif ($_.kind -eq "callsite") { 1 } elseif ($_.kind -eq "string_literal") { 2 } else { 3 } } }, line_number |
Select-Object -First $MaxEvidencePerTarget
)
$targetResults.Add([pscustomobject]@{
key = $targetKey
display = $target['display']
intent = $target['intent']
classification = Get-Classification -Evidence $allEvidence
match_count = $allEvidence.Count
evidence = $evidenceForReport
})
}
$summary = [pscustomobject]@{
generated_at = (Get-Date).ToUniversalTime().ToString("o")
repository = $repo
il_dir = $IlDir
sources = $sourceResults
targets = $targetResults
decision = "B-route text send remains plausible only if a bridge can enter the logged-in runtime or an existing IPC/API exposes the same call. Offline IL confirms call shape, but not runtime invocability."
originals_copied = $false
originals_modified = $false
}
$jsonPath = Join-Path $outDir "text-send-map.json"
$summary | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $jsonPath -Encoding UTF8
$linesOut = New-Object System.Collections.Generic.List[string]
$linesOut.Add("# B-Route Text Send Static Map")
$linesOut.Add("")
$linesOut.Add("Date: 2026-07-12")
$linesOut.Add("")
$linesOut.Add("## Scope")
$linesOut.Add("")
$linesOut.Add("This report uses offline IL only. It does not log in, send messages, replay traffic, inject into a process, or mutate the original iSphere binaries.")
$linesOut.Add("")
$linesOut.Add("Machine-readable evidence: ``$OutputDir/text-send-map.json``")
$linesOut.Add("")
$linesOut.Add("## Sources")
$linesOut.Add("")
$linesOut.Add("| Source | Role | Exists | Lines | Size bytes |")
$linesOut.Add("| --- | --- | --- | ---: | ---: |")
foreach ($sourceResult in $sourceResults) {
$exists = if ($sourceResult.exists) { "yes" } else { "no" }
$sizeText = if ($null -ne $sourceResult.size_bytes) { [string]$sourceResult.size_bytes } else { "" }
$linesOut.Add("| ``$($sourceResult.path)`` | $($sourceResult.role) | $exists | $($sourceResult.line_count) | $sizeText |")
}
$linesOut.Add("")
$linesOut.Add("## Target classification")
$linesOut.Add("")
$linesOut.Add("| Target | Intent | Classification | Matches |")
$linesOut.Add("| --- | --- | --- | ---: |")
foreach ($targetResult in $targetResults) {
$linesOut.Add("| ``$($targetResult.display)`` | $($targetResult.intent) | ``$($targetResult.classification)`` | $($targetResult.match_count) |")
}
$linesOut.Add("")
$linesOut.Add("## Verified facts")
$linesOut.Add("")
$linesOut.Add("- ``AppContextManager.SendTxtMessageByJid`` appears in the offline client IL and is not just a UIA/RPA artifact.")
$linesOut.Add("- ``MessageScheduling.SendChatMessage`` appears in the offline client IL and has call-site evidence around chat-message flow.")
$linesOut.Add("- ``Chat.SendMessage`` / ``Chat.sendMessage`` appears as a smack chat API used by client code.")
$linesOut.Add("- ``XMPPConnection.send`` appears as a lower-level connection send primitive in offline IL.")
$linesOut.Add("- ``MessageCenter send-related callbacks`` appear as MessageCenter/GetMessageCenter references, but offline static evidence alone does not prove an external bridge can call them.")
$linesOut.Add("")
$linesOut.Add("## Evidence excerpts")
foreach ($targetResult in $targetResults) {
$linesOut.Add("")
$linesOut.Add("### $($targetResult.display)")
$linesOut.Add("")
$linesOut.Add("Classification: ``$($targetResult.classification)``; matches: $($targetResult.match_count).")
if (@($targetResult.evidence).Count -eq 0) {
$linesOut.Add("")
$linesOut.Add("No evidence found in configured offline IL sources.")
continue
}
$linesOut.Add("")
$linesOut.Add("| Source line | Kind | Snippet | Method context |")
$linesOut.Add("| --- | --- | --- | --- |")
foreach ($evidence in $targetResult.evidence) {
$method = if ($evidence.method_header) { "L$($evidence.method_header.line_number): $($evidence.method_header.text)" } else { "" }
$snippet = ($evidence.text -replace "\|", "\\|")
$method = ($method -replace "\|", "\\|")
$linesOut.Add("| ``$($evidence.source):$($evidence.line_number)`` | ``$($evidence.kind)`` | ``$snippet`` | ``$method`` |")
}
}
$linesOut.Add("")
$linesOut.Add("## Inference")
$linesOut.Add("")
$linesOut.Add("- High confidence: text sending has an internal managed call path that reaches smack chat/connection send APIs.")
$linesOut.Add("- Medium confidence: the likely chain is high-level AppContextManager or UI chat code -> MessageScheduling/frmP2PChat -> smack Chat.SendMessage/sendMessage -> XMPPConnection.send.")
$linesOut.Add("- Low confidence until live/runtime evidence: an external sidecar can invoke this path without being inside the logged-in process.")
$linesOut.Add("")
$linesOut.Add("## Decision")
$linesOut.Add("")
$linesOut.Add("B-route text send remains plausible only if a bridge can enter the logged-in runtime or an existing IPC/API exposes the same call. Offline IL confirms call shape, but not runtime invocability.")
$linesOut.Add("")
$linesOut.Add("## Next work")
$linesOut.Add("")
$linesOut.Add("1. Extract file-send/upload call graph and separate upload from chat-message finalization.")
$linesOut.Add("2. Extract bridge/IPC/plugin candidates to see whether the send call path is reachable without RPA.")
$linesOut.Add("3. Keep A-route/RPA as backup-only; do not promote it unless B-route bridge evidence fails.")
($linesOut -join "`n") + "`n" | Set-Content -LiteralPath $reportFullPath -Encoding UTF8
$requiredNames = @("AppContextManager.SendTxtMessageByJid", "MessageScheduling.SendChatMessage", "Chat.SendMessage", "XMPPConnection.send", "MessageCenter send-related callbacks")
$reportText = Get-Content -LiteralPath $reportFullPath -Raw
$missing = @($requiredNames | Where-Object { $reportText -notlike "*$_*" })
if ($missing.Count -gt 0) {
throw "Report missing required target names: $($missing -join ', ')"
}
[pscustomobject]@{
ok = $true
json_path = $jsonPath
report_path = $reportFullPath
sources = $sourceResults.Count
targets = $targetResults.Count
classifications = @($targetResults | ForEach-Object { "$($_.display)=$($_.classification)" })
originals_copied = $false
originals_modified = $false
} | ConvertTo-Json -Depth 6

View File

@@ -0,0 +1,410 @@
param(
[string]$IlDir = "runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il",
[string]$OutputDir = "runs/inprocess-adapter-research",
[string]$ReportPath = "docs/source-discovery/2026-07-12-inprocess-adapter-static-map.md",
[int]$WindowRadius = 4,
[int]$MaxEvidencePerAnchor = 16
)
$ErrorActionPreference = "Stop"
$repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path
$ilDirFull = Join-Path $repo $IlDir
$outDir = Join-Path $repo $OutputDir
$reportFullPath = Join-Path $repo $ReportPath
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $reportFullPath) | Out-Null
$sources = @(
@{ path = "IMPlatformClient.exe.il"; role = "main managed client; UI, AppContextManager, MessageScheduling, frmMain, login runtime" },
@{ path = "smack.dll.il"; role = "XMPP/smack managed library; Chat and XMPPConnection send primitives" },
@{ path = "IMPP.Service.dll.il"; role = "file transfer service implementation" },
@{ path = "IMPP.ServiceBase.dll.il"; role = "file transfer DTOs and FileUploadPara/FileUploadResult contracts" },
@{ path = "IMPP.Interface.dll.il"; role = "service and network interface contracts" },
@{ path = "IMPP.Common.dll.il"; role = "common helper and runtime DTO evidence" }
)
$anchors = @(
@{
key = "text_high_level_entry"
display = "AppContextManager.SendTxtMessageByJid"
command = "send_text"
adapter_role = "preferred high-level managed entry if an in-process adapter can reach AppContextManager"
confidence = "high_static"
usable_offline = $false
required_runtime = @("logged-in IMPPManager/UserInfo", "target JID", "initialized AppContextManager", "live XMPP connection")
patterns = @("AppContextManager::SendTxtMessageByJid", "\bSendTxtMessageByJid\b")
},
@{
key = "text_scheduling_entry"
display = "MessageScheduling.SendChatMessage"
command = "send_text"
adapter_role = "fallback managed entry when scheduling layer has chat and contact args"
confidence = "high_static"
usable_offline = $false
required_runtime = @("MessageScheduling instance or static caller", "RosterContactsArgs/contact context", "Chat object", "live XMPP connection")
patterns = @("MessageScheduling::SendChatMessage", "SendChatMessage\(", "SendChatMessage\(class IMPP\.Client")
},
@{
key = "text_low_level_chat"
display = "com.vision.smack.Chat.SendMessage / XMPPConnection.send"
command = "send_text"
adapter_role = "lowest-level send target; requires already resolved Chat/XMPPConnection"
confidence = "high_static"
usable_offline = $false
required_runtime = @("Chat instance", "XMPPConnection authenticated session", "message payload format")
patterns = @("com\.vision\.smack\.Chat::SendMessage", "com\.vision\.smack\.Chat::sendMessage", "XMPPConnection::send\b")
},
@{
key = "file_upload_orchestrator"
display = "IMPP.Client.OffLineFileSend.sendFile"
command = "upload_file_then_send_file"
adapter_role = "UI-side upload orchestration and transition into chat file message"
confidence = "high_static"
usable_offline = $false
required_runtime = @("local file path", "HTTP file server/auth state", "target roster/chat args", "upload completion callback")
patterns = @("OffLineFileSend::sendFile", "sendFile\(\) cil managed", "OffLineFileSend::trans_UploadCompleted")
},
@{
key = "file_upload_service"
display = "IFileTransfer/FileTransfer.FileUpload + FileUploadPara"
command = "upload_file"
adapter_role = "service upload entry that must return FileUploadResult before chat file finalization"
confidence = "high_static"
usable_offline = $false
required_runtime = @("FileUploadPara host/port/domain", "localFilePath", "token/auth", "FileUploadResult.FileID")
patterns = @("FileTransfer::FileUpload", "FileUploadPara", "FileUploadResult::get_FileID", "FileUploadResult")
},
@{
key = "file_message_finalizer"
display = "MessageScheduling.SendFileMessage / Chat.sendFileMessage"
command = "send_file_message"
adapter_role = "chat file-message finalization after FileID/remote folder exists"
confidence = "high_static"
usable_offline = $false
required_runtime = @("uploaded file id", "remote folder metadata", "file name/size", "target Chat/JID")
patterns = @("MessageScheduling::SendFileMessage", "Chat::sendFileMessage", "sendFileMessage\(")
},
@{
key = "logged_in_identity_auth"
display = "IMPPManager.UserInfo / UnifiedAuthentication / Auth token"
command = "runtime_context"
adapter_role = "runtime state required before any production send/upload can be meaningful"
confidence = "medium_static"
usable_offline = $false
required_runtime = @("UserInfo", "UnifiedAuthentication", "Auth token", "HTTPFileServer", "server resource/domain")
patterns = @("IMPPManager::get_UserInfo", "IMPPManager.UserInfo", "UnifiedAuthentication", "HTTPFileServer", "Auth::get_token", "get_token")
},
@{
key = "main_window_runtime_owner"
display = "frmMain / MessageCenter / chat runtime ownership"
command = "runtime_context"
adapter_role = "likely object owner for initialized chat, reconnect, message center, and plugin runtime state"
confidence = "medium_static"
usable_offline = $false
required_runtime = @("running frmMain", "initialized message center", "contact/session state")
patterns = @("class IMPP\.Client\.frmMain", "frmMain::", "GetMessageCenter\(\)", "MessageCenter", "OnReConnectionSucceed", "GetChat\(")
},
@{
key = "existing_http_not_bridge"
display = "frmLogin.StartWinServer / HttpServerLib"
command = "not_selected_bridge"
adapter_role = "known local HTTP framework, but not a confirmed send bridge"
confidence = "high_static_negative"
usable_offline = $false
required_runtime = @("logged-in state", "route module registration not found", "send route not found")
patterns = @("StartWinServer", "HttpServerLib", "HttpService::\.ctor", "RegisterModule", "RouteAttribute")
}
)
function Get-RelativePath([string]$Path) {
if ($Path.StartsWith($repo, [System.StringComparison]::OrdinalIgnoreCase)) {
return $Path.Substring($repo.Length).TrimStart([char[]]@('\', '/'))
}
return $Path
}
function Write-Utf8NoBomLf([string]$Path, [string]$Text) {
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
$normalized = $Text -replace "`r`n", "`n"
$normalized = $normalized -replace "`r", "`n"
$normalized = $normalized.TrimEnd() + "`n"
[System.IO.File]::WriteAllText($Path, $normalized, $utf8NoBom)
}
function Get-EvidenceKind([string]$Line) {
if ($Line -match "^\s*\.class\b") { return "type_definition" }
if ($Line -match "^\s*\.method\b") { return "method_header" }
if ($Line -match "\bend of method\b") { return "method_end" }
if ($Line -match "\bnewobj\b") { return "constructor_call" }
if ($Line -match "\bcall(?:virt)?\b") { return "callsite" }
if ($Line -match "\bldstr\b") { return "string_literal" }
if ($Line -match "^\s*(instance|static)\b.*\(") { return "signature_continuation" }
if ($Line -match "^\s*\.field\b") { return "field" }
return "reference"
}
function Get-MethodContext($Lines, [int]$Index) {
$start = [Math]::Max(0, $Index - 100)
for ($i = $Index; $i -ge $start; $i--) {
if ($Lines[$i] -match "^\s*\.method\b") {
$header = $Lines[$i].Trim()
if (($i + 1) -lt $Lines.Count -and $Lines[$i + 1] -match "^\s+(instance|static|default)\b") {
$header = ($header + " " + $Lines[$i + 1].Trim())
}
return "L$($i + 1): $header"
}
}
return ""
}
function Get-WindowSnippet($Lines, [int]$Index, [int]$Radius) {
$start = [Math]::Max(0, $Index - $Radius)
$end = [Math]::Min($Lines.Count - 1, $Index + $Radius)
$parts = New-Object System.Collections.Generic.List[string]
for ($i = $start; $i -le $end; $i++) {
$parts.Add(("L{0}: {1}" -f ($i + 1), $Lines[$i].Trim()))
}
return ($parts -join "`n")
}
function Find-AnchorEvidence($Anchor) {
$items = New-Object System.Collections.Generic.List[object]
foreach ($source in $sources) {
$sourcePath = Join-Path $ilDirFull $source.path
if (-not (Test-Path -LiteralPath $sourcePath)) { continue }
$lines = [System.IO.File]::ReadAllLines($sourcePath)
for ($i = 0; $i -lt $lines.Count; $i++) {
$line = $lines[$i]
foreach ($pattern in $Anchor.patterns) {
if ($line -match $pattern) {
$items.Add([pscustomobject]@{
source = Get-RelativePath $sourcePath
source_role = $source.role
line = $i + 1
kind = Get-EvidenceKind $line
pattern = $pattern
snippet = $line.Trim()
context = Get-MethodContext $lines $i
window = Get-WindowSnippet $lines $i $WindowRadius
})
break
}
}
if ($items.Count -ge $MaxEvidencePerAnchor) { break }
}
if ($items.Count -ge $MaxEvidencePerAnchor) { break }
}
return $items.ToArray()
}
function Classify-Anchor($Anchor, $Evidence) {
if ($Evidence.Count -eq 0) { return "missing_static_evidence" }
if ($Anchor.command -eq "not_selected_bridge") { return "not_a_send_bridge" }
if ($Anchor.command -eq "runtime_context") { return "runtime_dependency" }
return "in_process_candidate_static_only"
}
$sourceSummary = foreach ($source in $sources) {
$path = Join-Path $ilDirFull $source.path
$exists = Test-Path -LiteralPath $path
$lineCount = 0
$size = 0
if ($exists) {
$item = Get-Item -LiteralPath $path
$size = $item.Length
$lineCount = ([System.IO.File]::ReadLines($path) | Measure-Object).Count
}
[pscustomobject]@{
path = Get-RelativePath $path
role = $source.role
exists = $exists
lines = $lineCount
size_bytes = $size
}
}
$anchorResults = foreach ($anchor in $anchors) {
$evidence = Find-AnchorEvidence $anchor
[pscustomobject]@{
key = $anchor.key
display = $anchor.display
command = $anchor.command
adapter_role = $anchor.adapter_role
classification = Classify-Anchor $anchor $evidence
confidence = $anchor.confidence
usable_offline = $anchor.usable_offline
required_runtime = $anchor.required_runtime
evidence_count = $evidence.Count
evidence = $evidence
}
}
$commands = @(
[pscustomobject]@{
op = "probe_runtime"
status = "contract_only"
purpose = "report whether adapter is inside logged-in IMPP runtime and can see required types/singletons"
required_evidence = @("process identity", "loaded assemblies", "IMPPManager.UserInfo presence", "XMPP connection state")
},
[pscustomobject]@{
op = "send_text"
status = "blocked_until_logged_in_adapter"
purpose = "invoke high-level text send path after target JID and content hash are validated"
required_evidence = @("AppContextManager or MessageScheduling reachability", "target JID", "sent record or ack containing content hash/correlation")
},
[pscustomobject]@{
op = "upload_file"
status = "blocked_until_logged_in_adapter"
purpose = "call file upload service and return server FileID/remote folder metadata"
required_evidence = @("FileUploadPara values", "HTTP file server/auth", "FileUploadResult.FileID")
},
[pscustomobject]@{
op = "send_file_message"
status = "blocked_until_upload_evidence"
purpose = "finalize file message after upload returns server id"
required_evidence = @("uploaded FileID", "file name/size", "target JID/Chat", "sent record/ack")
}
)
$requiredRuntimeState = @(
"logged-in IMPlatformClient.exe process",
"loaded IMPP.Client/AppContextManager/MessageScheduling types",
"initialized IMPPManager.UserInfo and UnifiedAuthentication/Auth token",
"live XMPPConnection/Chat session",
"target JID or group JID resolved by existing search tools",
"file upload service parameters and FileUploadResult.FileID for file sends"
)
$stopConditions = @(
"No logged-in process is available for runtime reachability validation.",
"Adapter cannot see AppContextManager, MessageScheduling, Chat, or IFileTransfer in process.",
"Every viable path requires unsupported binary patching instead of a replaceable managed adapter/harness.",
"Online evidence cannot produce sent-record/content-hash/ack correlation for text send.",
"File upload cannot return FileUploadResult.FileID or equivalent remote folder metadata."
)
$result = [pscustomobject]@{
ok = $true
generated_at = (Get-Date).ToUniversalTime().ToString("o")
decision = "managed_in_process_adapter_contract_first"
sources = $sourceSummary
anchors = $anchorResults
commands = $commands
required_runtime_state = $requiredRuntimeState
stop_conditions = $stopConditions
originals_copied = $false
originals_modified = $false
}
$jsonPath = Join-Path $outDir "inprocess-adapter-map.json"
$jsonText = $result | ConvertTo-Json -Depth 8
Write-Utf8NoBomLf $jsonPath $jsonText
$md = New-Object System.Collections.Generic.List[string]
$md.Add("# In-Process Adapter Static Map")
$md.Add("")
$md.Add("Date: 2026-07-12")
$md.Add("")
$md.Add("## Scope")
$md.Add("")
$md.Add("This report uses offline IL/static evidence only. It does not log in, attach hooks, inject into a process, modify client binaries, upload files, send messages, or open network connections.")
$md.Add("")
$md.Add("Machine-readable evidence: ``$(Get-RelativePath $jsonPath)``")
$md.Add("")
$md.Add("## Decision")
$md.Add("")
$md.Add("| Question | Answer |")
$md.Add("| --- | --- |")
$md.Add("| Selected next B-route branch | `managed_in_process_adapter_contract_first` |")
$md.Add("| Can offline branch enable production send? | **No** |")
$md.Add("| Go connector mode to expose now | `in_process_contract` |")
$md.Add("| Required online proof later | logged-in adapter reachability plus sent-record/content-hash/ack evidence |")
$md.Add("")
$md.Add("## Sources")
$md.Add("")
$md.Add("| Source | Role | Exists | Lines | Size bytes |")
$md.Add("| --- | --- | --- | ---: | ---: |")
foreach ($source in $sourceSummary) {
$md.Add("| ``$($source.path)`` | $($source.role) | $($source.exists) | $($source.lines) | $($source.size_bytes) |")
}
$md.Add("")
$md.Add("## Command contract for future in-process adapter")
$md.Add("")
$md.Add("| Op | Current status | Purpose | Required evidence before production |")
$md.Add("| --- | --- | --- | --- |")
foreach ($cmd in $commands) {
$required = ($cmd.required_evidence -join "; ")
$md.Add("| ``$($cmd.op)`` | ``$($cmd.status)`` | $($cmd.purpose) | $required |")
}
$md.Add("")
$md.Add("## Anchor summary")
$md.Add("")
$md.Add("| Anchor | Command | Classification | Confidence | Evidence | Required runtime |")
$md.Add("| --- | --- | --- | --- | ---: | --- |")
foreach ($anchor in $anchorResults) {
$required = ($anchor.required_runtime -join "; ")
$md.Add("| ``$($anchor.display)`` | ``$($anchor.command)`` | ``$($anchor.classification)`` | ``$($anchor.confidence)`` | $($anchor.evidence_count) | $required |")
}
$md.Add("")
$md.Add("## Verified facts")
$md.Add("")
$md.Add("- Text send has static in-process candidates, but all require logged-in runtime objects and a live XMPP/Chat path.")
$md.Add("- File send is split into upload and message-finalization; `FileUploadResult.FileID` is a required boundary value before `Chat.sendFileMessage` is meaningful.")
$md.Add("- The earlier IPC/plugin/local HTTP scan did not find a confirmed external send bridge, so this branch must stay at `in_process_contract` until online reachability exists.")
$md.Add("- `in_process_contract` is a Go-side contract and audit mode only; it must return blocked/no-side-effect metadata in this offline branch.")
$md.Add("")
$md.Add("## Required runtime state")
$md.Add("")
foreach ($state in $requiredRuntimeState) {
$md.Add("- $state")
}
$md.Add("")
$md.Add("## Anchor evidence")
foreach ($anchor in $anchorResults) {
$md.Add("")
$md.Add("### $($anchor.display)")
$md.Add("")
$md.Add("Classification: ``$($anchor.classification)``; command: ``$($anchor.command)``; evidence count: $($anchor.evidence_count).")
$md.Add("")
$md.Add("Adapter role: $($anchor.adapter_role)")
$md.Add("")
if ($anchor.evidence_count -eq 0) {
$md.Add("No static evidence found for this anchor in the configured IL set.")
continue
}
$md.Add("| Source | Kind | Snippet | Context |")
$md.Add("| --- | --- | --- | --- |")
foreach ($e in $anchor.evidence) {
$snippet = ($e.snippet -replace "\|", "\\|" )
if ($snippet.Length -gt 220) { $snippet = $snippet.Substring(0, 217) + "..." }
$context = ($e.context -replace "\|", "\\|" )
if ($context.Length -gt 180) { $context = $context.Substring(0, 177) + "..." }
$md.Add("| ``$($e.source):$($e.line)`` | ``$($e.kind)`` | ``$snippet`` | ``$context`` |")
}
}
$md.Add("")
$md.Add("## Stop conditions")
$md.Add("")
foreach ($condition in $stopConditions) {
$md.Add("- $condition")
}
$md.Add("")
$md.Add("## Next work")
$md.Add("")
$md.Add("1. Add Go connector mode `in_process_contract` that validates request shape and returns blocked/no-side-effect metadata.")
$md.Add("2. In a logged-in environment, build a recorder/probe that only checks reachability of the listed runtime objects before attempting any send.")
$md.Add("3. Promote text send only after sent-record/content-hash/ack evidence exists.")
$md.Add("4. Promote file send only after upload returns `FileUploadResult.FileID` and file-message finalization is proven online.")
Write-Utf8NoBomLf $reportFullPath ($md -join "`n")
[pscustomobject]@{
ok = $true
json_path = $jsonPath
report_path = $reportFullPath
anchors = $anchorResults.Count
decision = $result.decision
originals_copied = $false
originals_modified = $false
} | ConvertTo-Json -Depth 5