dsh-cindy-host 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +462 -0
- package/LICENSE +21 -0
- package/README.md +178 -0
- package/cordis.patch.yml +6 -0
- package/doc/architecture.md +34 -0
- package/doc/cindy-android-verify.md +362 -0
- package/doc/cindy-mobile-freeze-handoff.md +124 -0
- package/doc/cindy-phone-link.md +2902 -0
- package/doc/desktop-runtime-fix-20260930.md +69 -0
- package/doc/development-plan.md +19 -0
- package/doc/file-peer-apply-recovery-20260921.md +35 -0
- package/doc/file-peer-installed-hotfix-20260921.md +53 -0
- package/doc/file-peer-minimal-apply-20260921.md +78 -0
- package/doc/file-peer-original-contract-alignment-20260921.md +119 -0
- package/doc/file-peer-phone-export-observation-20260921.md +75 -0
- package/doc/file-peer-product-contract-audit-20260921.md +106 -0
- package/doc/file-peer-root-cause-20260921.md +53 -0
- package/doc/file-transfer.md +50 -0
- package/doc/host-performance-20260930.md +91 -0
- package/doc/neonabyss-apk-file-peer-diagnosis-20260921.md +87 -0
- package/doc/new-session-sync-fix-20260930.md +59 -0
- package/doc/patches/cindy-peer-silence-probe.patch +1112 -0
- package/doc/projection-read-probe.md +77 -0
- package/doc/publishing.md +259 -0
- package/doc/releasing.md +149 -0
- package/doc/research.md +24 -0
- package/doc/session-discovery-2026-09-20.md +67 -0
- package/lib/client.js +763 -0
- package/package.json +84 -0
- package/src/auth-session.js +189 -0
- package/src/authorization-policy.js +59 -0
- package/src/cindy-channels.js +1707 -0
- package/src/cindy-login-flow.js +159 -0
- package/src/cindy-login.js +80 -0
- package/src/cindy-message-row.js +432 -0
- package/src/cindy-session-row.js +171 -0
- package/src/console-sink.js +6 -0
- package/src/contracts.js +26 -0
- package/src/credential-store.js +128 -0
- package/src/demo.js +9 -0
- package/src/dsh-active-sessions.js +59 -0
- package/src/dsh-host-source.js +62 -0
- package/src/dsh-message-fold.js +608 -0
- package/src/dsh-plugin.js +1932 -0
- package/src/dsh-session-source.js +529 -0
- package/src/file-peer-protocol.js +7 -0
- package/src/file-peer-rtc.js +41 -0
- package/src/fixture-source.js +13 -0
- package/src/host-approvals.js +329 -0
- package/src/host-attachments.js +249 -0
- package/src/host-authorization.js +51 -0
- package/src/host-demo.js +3 -0
- package/src/host-export-jobs.js +356 -0
- package/src/host-export-owner.js +62 -0
- package/src/host-file-browser.js +400 -0
- package/src/host-file-ice.js +63 -0
- package/src/host-file-peer.js +289 -0
- package/src/host-file-reference.js +16 -0
- package/src/host-files.js +148 -0
- package/src/host-frame-budget.js +310 -0
- package/src/host-goals.js +284 -0
- package/src/host-history-view-limits.js +22 -0
- package/src/host-history-view.js +417 -0
- package/src/host-input-queue.js +505 -0
- package/src/host-media-fetch.js +511 -0
- package/src/host-media.js +678 -0
- package/src/host-models.js +231 -0
- package/src/host-palette.js +111 -0
- package/src/host-push-channels.js +37 -0
- package/src/host-reconnect.js +54 -0
- package/src/host-routes.js +266 -0
- package/src/host-settings.js +41 -0
- package/src/host-status.js +216 -0
- package/src/host-transfer-diagnostics.js +50 -0
- package/src/host.js +2497 -0
- package/src/login.js +31 -0
- package/src/logout.js +3 -0
- package/src/projection-read-model-sink.js +6 -0
- package/src/projection.js +43 -0
- package/src/session-flags.js +160 -0
- package/src/session-publisher.js +123 -0
- package/src/session-read-model.js +6 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# 大文件 peer:已复现的 Host 协商截止缺陷
|
|
2
|
+
|
|
3
|
+
## 结论
|
|
4
|
+
|
|
5
|
+
找到并最小修复一个**确定的 Host 缺陷**:合法的慢 ICE 配置响应叠加 TURN UDP→TCP 重试,能超过旧 offer 的 15 秒截止,导致已有可用本地候选的连接被提前关闭。它足以触发“peer 失败 → 旧 OSS 512MiB 超限”。**尚未证明用户那次 1,315,101,941 字节 APK 就命中此条件**;如果当时几乎立即报错,而非等待约15秒以上,此候选不吻合。
|
|
6
|
+
|
|
7
|
+
本轮没有 Android 打包、手机更新、发布、部署、DSH 重启、游戏 APK 内容读取/重传或凭据提取,也没有新派诊断 agent。Cindy 未提交的产品修复未修改。
|
|
8
|
+
|
|
9
|
+
## 确定链路与触发条件
|
|
10
|
+
|
|
11
|
+
- `src/host-file-peer.js:179–209`:总 offer 计时先开始,再 loadIceServers,再 `await pc.setLocalDescription(answer)`,最后才调用 `gatherIce(c)`。旧总预算15秒。
|
|
12
|
+
- `node_modules/werift/lib/webrtc/src/peerConnection.js:714–725`:`setLocalDescription` 内部已经 **await gatherCandidates**;后置的4秒 gather 等待不能限制这一 await。
|
|
13
|
+
- `node_modules/werift/lib/ice/src/ice.js:701–702,881–920`:等待所有候选任务;UDP TURN 分配失败后再尝试同端点 TCP。即使 host candidates 已产生,也要等待这条重试链结束。
|
|
14
|
+
- `src/host-file-ice.js:28–52`:配置请求合法预算为3秒。
|
|
15
|
+
- `Cindy/packages/device-link/src/allowlist.ts:714`、`invokePolicy.ts:73–86`:file-peer RPC 实际给30秒,不是 mobile 默认15秒。Host 自己提前截断了这段合法预算。
|
|
16
|
+
|
|
17
|
+
复现仅使用本机 UDP/TCP 黑洞服务、模拟用户名/口令和 **2.75秒配置响应延迟**,不触达公网 TURN、不传文件内容。配置加载在依赖注入边界模拟;显式localhost STUN替代werift隐含的公网STUN,不更改其TURN串行重试逻辑:
|
|
18
|
+
|
|
19
|
+
| 场景 | 实测 |
|
|
20
|
+
|---|---|
|
|
21
|
+
| 对照:只有本机 STUN 超时,无 TURN | ~5.06秒得到 answer |
|
|
22
|
+
| 只有 UDP TURN 不响应、TCP立即拒绝 | ~6.47秒得到 answer;**这个更弱条件没有触发缺陷,不能笼统说 TURN 不通必超时** |
|
|
23
|
+
| UDP和TCP均不响应 + 配置2.75秒,旧15秒总截止 | **15.006秒 FILE_PEER_TIMEOUT**,已有2个 host candidates,仍在 gathering |
|
|
24
|
+
| 完全相同条件,25秒总预算 | **15.621秒得到 answer,随后本机 ICE/DTLS 连接 established** |
|
|
25
|
+
|
|
26
|
+
## 为什么旧手机版只显示大小超出
|
|
27
|
+
|
|
28
|
+
原 `peerFileTransport.tsx` 在 offer/answer 异常后 catch 返回 null → 原 shared `fileAccess.ts:43–54` 调 fallback → Host `src/host.js:285–286` 的旧导出 guard 拒绝 >536,870,912 字节。1,315,101,941 <2GiB,所以“超限”不是新协议的上限,而可能是覆盖原始协商错误的第二次失败。
|
|
29
|
+
|
|
30
|
+
当前 Cindy 未提交修复已在 `peerFileTransport.tsx:197–213,259–263` 保留 answer 阶段错误,shared fileAccess 防止大文件错误 fallback;它修复失因掩盖,**不修复 Host 的15秒提前截止**。无需先打完整 Android APK才能复现或修本 Host 点。
|
|
31
|
+
|
|
32
|
+
## 最小修复和验证
|
|
33
|
+
|
|
34
|
+
- 仅将 `src/host-file-peer.js:185–189` 的 offer 上限从15秒改为**25秒**,保留 RPC 回程5秒。没有提高文件大小、改框架、改60秒进度空闲截止或权限/并发约束。
|
|
35
|
+
- `test/host-file-peer.test.js:373–397`:新增16秒完成 gathering 的回归(修改前确实失败、修改后通过),并校验24.999秒尚未超时、25秒超时且迟到工厂资源仍关闭。
|
|
36
|
+
- 针对性 manager 测试 **53/53**;最终两项时间边界测试 **2/2**。未跑无关全量回归。
|
|
37
|
+
- `tools/file-peer-ice-deadline-probe.mjs`:真实 werift + 产品 manager + 本机黑洞的可重现验证;默认验证修复后,`--legacy-budget` 仅在隔离进程注入旧15秒截止。复现进程退出释放未结束的库内重试,无生产修改。
|
|
38
|
+
- `tools/file-peer-mobile-boundary-probe.mjs`:真实移动端 HTML/CSP/生成 runtime 在 Chromium 运行;发送65,540条有序小消息,再执行16KiB接收+EOF,共**81,924字节合成内容**,成功跨过相当于16KiB块传到1GiB处的SCTP序号回绕。排除“>1GiB序号回绕必坏”候选;这不是Android原生真机验收。
|
|
39
|
+
|
|
40
|
+
## 其他已核对边界
|
|
41
|
+
|
|
42
|
+
- 当前分享入口默认整文件,预览页下载显式 stream=false;没有发现把APK分享误作 stream 的代码错误。layout 挂载 PeerFileTransport;手机询问的是 **Host caps.fileRead**。
|
|
43
|
+
- Android Expo标准 file:// 的 File.open 默认读写,不是只读;16KiB分块刷新的是进展超时,并非整个1.3GB下载必须60秒完成。
|
|
44
|
+
- GitNexus:Host索引停在2026-09-18/205a24b;已用 context确认owner,但新功能以实际文件为准。登记的 Cindy-markdown-preview 是另一工作树,没有重建索引或把它当本分支事实。当前Cindy为 fix/mobile-peer-silence-probe / dc294b02ca,未提交修复按磁盘文件核对。
|
|
45
|
+
- 14:18实时状态显示3080已是 **PID40916,11:10:11启动**,不是上轮PID8932;这是本轮开始前的现场变化,本轮没重启。当前file-peer调用/拒绝计数为空,旧失败环已不可用于还原当次原因。
|
|
46
|
+
|
|
47
|
+
## 给主助手的最小后续
|
|
48
|
+
|
|
49
|
+
Host源码修复**尚未部署**。先交付这个已证修复,不把 Android 构建障碍当根因或前置。Cindy诊断改动继续由22890原会话持有,不覆盖其文件。
|
|
50
|
+
|
|
51
|
+
当次归因仍只缺一条:**同次 Host offer 的 FILE_PEER_TIMEOUT 及约15秒耗时**(而不是再拿一份APK)。旧记录已丢失时不能补造;以后经用户同意的正常操作可直接读取既有Host recentRefusals/counters配合请求时间,无需为此先重打Android。若签名不符,继续定位手机ready/空间/接收阶段,而不把本确定缺陷冒充唯一历史根因。
|
|
52
|
+
|
|
53
|
+
回传:指定 key `file-peer-original-owner-root-cause-report-20260921-01` 已成功提交一次;receiptId=`d22dbd766fa1082dcea18845f4f187811a5d3e1e0e022a81e53217e4f7608ea3`,requestId=`assistant-d10baf91-87f1-453b-921f-03ac3af25c04`,admission=accepted(仅入队,不冒充主助手已处理或手机成功接收)。
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# 手机文件直传(0.1.10 起)
|
|
2
|
+
|
|
3
|
+
## 能力与边界
|
|
4
|
+
|
|
5
|
+
DSH Host 对接 Cindy 已有 `device-link:file-peer` / `files-v1` 协议。手机端需要包含该能力的版本;无需开启远程桌面画面,文件通道也不复用视频/键鼠通道。
|
|
6
|
+
|
|
7
|
+
- **电脑 → 手机整文件下载**:最多 **2 GiB**。64 KiB 及以下(含空文件)经授权后内联;更大的文件优先走独立 WebRTC DataChannel。
|
|
8
|
+
- ICE 从现有 Cindy 认证接口获取短期 TURN 配置,尝试可用直连或中继;接口不可用时与 Cindy 一样回退公共 STUN。不是保证所有网络都能直连。werift 当前选择配置中的首个可解析 TURN,不具备浏览器完整的多服务器竞速策略。
|
|
9
|
+
- **0.1.11 起**,手机文件浏览器两阶段 OSS 导出兜底支持 **2 GiB(含边界)**及调用方更小的maxBytes。Host以64 KiB分块/背压上传,无10分钟总上传截断,但有阶段/无进展时限;手机原30分钟轮询预算不变。聊天媒体旧路径仍限25 MiB。OSS是云端中转,不是P2P直连。
|
|
10
|
+
- 手机上传附件仍为旧流程(默认 20 MiB)。本轮**没有新增上传方向、持久断点续传、嵌套 SSH 文件导出或 >2 GiB 支持**。
|
|
11
|
+
|
|
12
|
+
该能力随 0.1.10 发布;本地必须更新到此版本并重启原 DSH Web,不能以另开服务器代替生效。
|
|
13
|
+
|
|
14
|
+
## 数据流与安全
|
|
15
|
+
|
|
16
|
+
1. 手机 `remote-op caps.fileRead` → `fileUrl`;Host 只接受本机绝对 workdir 和相对 relPath。
|
|
17
|
+
2. `media:fetch prepareOnly` 与 peer `open` 共用本地文件 resolver:必需目录根、realpath containment、敏感路径 denylist、常规文件校验;URL 的 maxBytes 只能收紧上限。
|
|
18
|
+
3. Relay 认证的 `Envelope.src` 是唯一设备身份。`caps/offer/open/close` 仅传授权和信令;文件内容走 `files-v1` 的可靠有序二进制块。
|
|
19
|
+
4. Host 用连接绑定的随机 ticket,严格连续 offset 与每次 16 块信用。每块最多 16 KiB,按文件句柄读取,零长度二进制块作为 EOF;不将大文件整份读进内存。
|
|
20
|
+
5. 源文件 stat/句柄身份变化会终止;这是元数据变更检测,**不是密码学内容快照**。单连接同时一个文件,全 Host 最多四连接,60 秒无进展关闭。
|
|
21
|
+
6. 撤销设备、设备离线、link-close、Relay 断开、关闭手机连接、Host stop 都使相应连接立即失效,随后释放文件句柄/RTC/定时器;迟到的异步结果不得恢复连接。取消和授权拒绝不能通过其他入口绕过权限。
|
|
22
|
+
|
|
23
|
+
现有读取权限仍沿用本项目“同 Cindy 账号且未撤销的控制设备”合同;本次没有放宽成匿名下载接口,也不把 SSH 引用猜成本机路径。
|
|
24
|
+
|
|
25
|
+
## 运行时与维护门禁
|
|
26
|
+
|
|
27
|
+
运行依赖固定为 `werift@0.24.4`(纯 Node,Node >=22),仅请求 peer 时延迟加载,不引入 Electron。该版本直接发送空 Buffer 会消费 SCTP 序号却不发 DATA,使 Cindy EOF 和后续文件卡住。`src/file-peer-rtc.js` 对空包使用同一发送队列、PPID 57 和一个忽略字节,保持顺序及缓冲计数。
|
|
28
|
+
|
|
29
|
+
**这个小适配依赖固定版本的内部 API**。升级 werift 必须重新跑真实浏览器验收,尤其“EOF 后再传文件”;不能只凭模拟单测升级。`--native-empty` 可复现上游缺陷,不是通过型测试。
|
|
30
|
+
|
|
31
|
+
## 验证
|
|
32
|
+
|
|
33
|
+
```powershell
|
|
34
|
+
npm test
|
|
35
|
+
npm run test:file-peer
|
|
36
|
+
# 需要相邻 Cindy 源码、playwright-core 和已安装的 Chromium/Edge/Chrome:
|
|
37
|
+
# 可覆盖 CINDY_SOURCE_ROOT / PLAYWRIGHT_CORE_PATH / CHROMIUM_EXECUTABLE
|
|
38
|
+
npm run smoke:file-peer
|
|
39
|
+
npm pack --dry-run
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
真实 smoke 使用 Cindy 原始 `filePeerRuntime.ts` 接收器、产品 Host manager/resolver/RTC adapter 和临时磁盘 source/sink,不使用 Cindy 账号或用户文件。为避免 werift 对 `iceServers: []` 隐式回退 Google STUN,Node 测试端显式指定 localhost STUN。脚本有硬超时,结束清理浏览器、连接和临时文件。
|
|
43
|
+
|
|
44
|
+
已在 Node 24.12.0、werift 0.24.4、Edge Chromium 151.0.4129.59 验证:空文件、1B、16KiB、256KiB、跨批次文件以及两次 32MiB+37B,源文件与接收落盘 SHA-256 一致,同一个 peer 顺序复用。单测覆盖路由/身份伪造、越权路径、信用/偏移、文件变化、撤销/迟到结果、连接上限、闲置清理和旧 OSS 语义。
|
|
45
|
+
|
|
46
|
+
**0.1.11补充验收:**本地真实HTTP完成2 GiB以及约11分钟持续流式上传;真实约1.3 GB文件经OSS上传完成,用户确认手机下载成功。Host有界任务/账号归属/取消清理、显式登录与旧connect竞态已有定向回归。
|
|
47
|
+
|
|
48
|
+
**仍未确认:**实际手机P2P未建立的原因、前后台行为、跨NAT和公网TURN UDP/TCP/TLS、2 GiB手机整链路、手机端独立hash/安装/系统分享。本次不修P2P,不将OSS成功称为直传成功。
|
|
49
|
+
|
|
50
|
+
通道审计将当前未实现的远端模型收藏 get/apply/changed 和下一条输入预测明确分类为不支持;分类不代表实现这些功能。
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Host performance: native Cindy comparison and implementation
|
|
2
|
+
|
|
3
|
+
## Scope and evidence boundary
|
|
4
|
+
|
|
5
|
+
The earlier functional migration is complete: the user confirmed successful new-session retry. This separate plan addresses latency, not login or session-data recovery. No real create/prompt, credential reset, data deletion or process restart was performed by the agent.
|
|
6
|
+
|
|
7
|
+
Initial read-only loopback measurements on the running desktop (short session, warm caches):
|
|
8
|
+
|
|
9
|
+
| Channel | Samples |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| sessions:list | 38 / 7 / 18 ms |
|
|
12
|
+
| sessions:get | 3 / 1 / 1 ms |
|
|
13
|
+
| messages:view | 2 / 1 / 2 ms |
|
|
14
|
+
| input:get-projection | 1 / 1 ms |
|
|
15
|
+
| maker:list-active | **1757 / 3642 ms** |
|
|
16
|
+
|
|
17
|
+
A subsequent **pre-deployment** active-only probe measured 9770 / 8394 / 7578 ms while full regression tests were also running. Different load conditions mean these samples must not be mixed into a claimed speedup. Neither set measures relay/mobile round-trip latency, long histories, or cold startup.
|
|
18
|
+
|
|
19
|
+
Evidence: [initial samples](<G:/Projects/DSH-cindy-host/artifacts/desktop-runtime-inspect/performance-baseline-20260930.json>), [loaded pre-deployment samples](<G:/Projects/DSH-cindy-host/artifacts/desktop-runtime-inspect/performance-active-predeploy.json>).
|
|
20
|
+
|
|
21
|
+
## Comparison with native Cindy
|
|
22
|
+
|
|
23
|
+
- [Native subscription/dispatch](<G:/Projects/Cindy/apps/desktop/src/main/device-link/dispatch.ts#L3449-L3533>) updates subscription state and stages replay without waiting for a full corpus listing. Independent invokes do not share a global execution lock. Our existing Host is also concurrent; no imaginary global mutex was added or removed.
|
|
24
|
+
- [Native session queries](<G:/Projects/Cindy/apps/desktop/src/main/localDb/ipc/sessionQueries.ts#L139-L158>) limit selected IDs first and reuse persisted summary/count/preview projections. Exact get remains authoritative and is not served from a settled stale cache ([invoke policy](<G:/Projects/Cindy/packages/device-link/src/invokePolicy.ts#L145-L155>)). SQL indexes are evidence of architecture, not a proposal to add a second database to DSH.
|
|
25
|
+
- [Mobile device page](<G:/Projects/Cindy/apps/mobile/app/devices/index.tsx#L738-L797>) reads list and active in parallel but commits the combined result after both settle. A fast warm list cannot hide a slow active request. Existing conversation screens instead progressively commit some reads; not every mobile operation is serial.
|
|
26
|
+
- [Native history reader](<G:/Projects/Cindy/apps/desktop/src/main/localDb/ipc/historyViewReader.ts>) performs bounded cursor scans with complete-group and clear/rewind checks. This patch does not claim to reproduce that paging architecture or eliminate all long-history grouping CPU.
|
|
27
|
+
|
|
28
|
+
## Changes
|
|
29
|
+
|
|
30
|
+
### 1. Read authoritative live running state, not persisted discovery
|
|
31
|
+
|
|
32
|
+
The old active poll always called `source.listSessionStates → listItems → sessionController.list`, which queries the entire logical persisted corpus. Existing list singleflight only shared overlapping calls; sequential polls each paid again. Normal session-list SWR masked this cost on a different channel.
|
|
33
|
+
|
|
34
|
+
Verified current DSH Inspect contracts: `agents.list/get`, `sessions.get`, and `sessionProjections.snapshot(session, keys)`. Packaged [controller summary](<G:/Projects/DSH-cindy-host/artifacts/desktop-runtime-inspect/dsh-api-session-controller-index.js#L1870-L1905>) derives running from live Agent status; cold persisted summaries cannot be running.
|
|
35
|
+
|
|
36
|
+
The new [live reader](<../src/dsh-active-sessions.js>) enumerates the live registry, checks exact Agent/Session identity, filters subagents/parented/blank sessions, and reads current `sessionListMetadata` only for eligible running roots. It uses no running-state TTL, corpus read or log snapshot. Projection selection narrows output; missing in-memory cells may still materialize other registered units, so this is not a claim of zero CPU cost.
|
|
37
|
+
|
|
38
|
+
A successful empty registry is authoritative. The targeted watchdog receives explicit `running:false` when its ID is absent, preventing a stale push cache from resurrecting a disposed Agent. Archive/delete filtering remains at the Host/router boundary. Missing APIs or actual read failures retain the legacy fallback instead of inventing no running sessions.
|
|
39
|
+
|
|
40
|
+
Diagnostics now include `activeStateReads`, `activeStateFallbacks`, and `lastActiveStateError` under `listing`. These also distinguish a newly loaded module from a merely updated installation.
|
|
41
|
+
|
|
42
|
+
### 2. Reuse exact header metadata
|
|
43
|
+
|
|
44
|
+
The exact-ID observation already supplies immutable `createdAt` and `cwd`. Previously `projectItems` nevertheless asked `metaFor`, whose reader scanned every session header. Complete authoritative header fields now seed the metadata cache before that fallback. Legacy summaries missing fields retain their old metadata reader. Title/model/provider/effort/permission semantics are unchanged; exact observations are not replaced with a stale result cache.
|
|
45
|
+
|
|
46
|
+
### 3. Share concurrent transcript initialization
|
|
47
|
+
|
|
48
|
+
A per-session Promise flight replaces the old Set-only bookkeeping. Concurrent count/view/page cold reads share one full replay. Success/rejection releases the flight; a failed read never caches empty history. Live events dirty the owning flight; explicit invalidation detaches it so subsequent reads use a new generation. Old completion cannot cache over a newer generation or clear its dirty/flight state. Different sessions remain independent.
|
|
49
|
+
|
|
50
|
+
## Deterministic before/after work counts
|
|
51
|
+
|
|
52
|
+
[Probe script](<../tools/performance-path-probe.mjs>) imports the pre-deployment installed implementation and migration implementation with identical injected fixtures. These are **operation counts, not live latency estimates**:
|
|
53
|
+
|
|
54
|
+
| Scenario | Before | After |
|
|
55
|
+
| --- | ---: | ---: |
|
|
56
|
+
| 5 sequential active polls: corpus reads | 5 | 0 |
|
|
57
|
+
| 2 concurrent cold exact gets: extra metadata corpus reads | 2 | 0 |
|
|
58
|
+
| 3 concurrent transcript surfaces: complete log seeds | 3 | 1 |
|
|
59
|
+
|
|
60
|
+
[Recorded probe output](<G:/Projects/DSH-cindy-host/artifacts/desktop-runtime-inspect/performance-work-counts.json>).
|
|
61
|
+
|
|
62
|
+
## Verification and deployment
|
|
63
|
+
|
|
64
|
+
- Added 8 live-reader tests, 5 plugin/source/Host integration tests and 10 transcript concurrency/invalidation tests.
|
|
65
|
+
- Focused integration suites: 188 passed.
|
|
66
|
+
- Final full suite: **740 passed, 1 skipped, 0 failed (741 total)**. [Full log](<G:/Projects/DSH-cindy-host/artifacts/desktop-runtime-inspect/performance-tests-final.log>).
|
|
67
|
+
- Independent read-only review found no blocking regression. Retained limits: legacy fallback may still scan/stale-serve; live projection first-touch may cost CPU; long-history grouping/image hydration and mobile network latency are not eliminated by this patch.
|
|
68
|
+
- Six runtime files copied into the installed desktop package, with each source/installed SHA256 and syntax check verified. Original five files were backed up; the new helper's prior absence is recorded in [backup manifest](<C:/Users/chany/.dsh/profiles/desktop/cindy-performance-fix-backup-20260930/manifest.json>).
|
|
69
|
+
- Final read-only status: still connected/authenticated, but **`activeStateReads` is absent**, so the running module has **not** been verified to load the performance patch. No automatic restart was attempted.
|
|
70
|
+
|
|
71
|
+
## Post-restart live verification
|
|
72
|
+
|
|
73
|
+
The user confirmed a full restart. Read-only status at about 146 seconds uptime reports connected/authenticated and the new diagnostics fields, proving the performance module is now loaded. During the measurement, `activeStateReads` increased from 1 to 9, `activeStateFallbacks` stayed 0, `staleServes` stayed 0, and `handlerErrors` remained empty.
|
|
74
|
+
|
|
75
|
+
| Channel | Post-restart samples |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| maker:list-active | **10 / 2 / 1 / 1 / 1 ms** |
|
|
78
|
+
| maker:session-in-turn (known completed session) | 1 / 1 / 1 ms, all false |
|
|
79
|
+
| sessions:get (same known short session) | **1468 / 7 / 7 ms** |
|
|
80
|
+
| messages:view | 1 / 1 / 1 ms |
|
|
81
|
+
| sessions:list | 18 / 12 / 8 ms |
|
|
82
|
+
|
|
83
|
+
The initial active samples reported 3 running sessions. A later separate read reported 2; targeted watchdog checks for both returned true. The previously completed handset-created session returned false. This verifies current true and false paths without sending prompts or creating sessions; disposal/clear race behavior is covered by the deterministic regressions, not manufactured live transitions.
|
|
84
|
+
|
|
85
|
+
[Post-restart measurements and diagnostics](<G:/Projects/DSH-cindy-host/artifacts/desktop-runtime-inspect/performance-postrestart-20260930.json>).
|
|
86
|
+
|
|
87
|
+
The main active-poll bottleneck improved from the earlier 1757/3642 ms baseline to 1–10 ms in this local probe, with no legacy fallback. Samples are few and taken at different times; no universal percentile or phone round-trip speedup is claimed. **The first post-restart exact get still cost 1468 ms**, then warmed to 7 ms. Its title/projection/transcript initialization components were not individually timed, so its precise remaining cause is not yet established. Subsequent history samples follow that get and therefore do not establish cold-history performance.
|
|
88
|
+
|
|
89
|
+
## Remaining acceptance
|
|
90
|
+
|
|
91
|
+
Ask the user about actual phone device-page and session-opening responsiveness. Keep local service timing, remaining first-read cost, and phone end-to-end experience separate. Do not close user-experience acceptance solely because the local probe and unit suite pass.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# NeonAbyss2.apk 手机下载超限:功能开发者有限诊断
|
|
2
|
+
|
|
3
|
+
- 检查时间:2026-09-21 01:03–01:11(UTC+08)。
|
|
4
|
+
- 状态:**手机接收仍未成功;精确 peer 失败点尚未证实。** 本轮完成有限定位,不等于修复或端到端验收。
|
|
5
|
+
- 范围:只读既有运行诊断/源码、两份目标文件的路径授权与元数据准备;仅新写本报告。未发布、部署、改生产设置、重启、启动另一 DSH、改 Cindy 源码、发起 RTC offer/open/receive、重传 APK、访问 OSS 或读取/输出 token/凭据。旧“发布”动作未恢复,冻结的 session-bridge 升级未触碰。
|
|
6
|
+
|
|
7
|
+
## 结论先行
|
|
8
|
+
|
|
9
|
+
1. **不能再将“当前进程没重启,未加载文件 handler”当作首要结论或据此直接重启。** 现有 3080 运行实例已经实际响应 `caps.fileRead:true` 与 file-peer `{version:1,maxBytes:2147483648}`,并能对本次 1,315,101,941 字节 APK 完成新协议的 prepareOnly。
|
|
10
|
+
2. **文件大小在新通道范围内;工作区副本的正确 root/relPath 也可用。** NAS 原文件以它自身父目录为 workdir 时同样通过。不能推断历史手机请求用了这些正确参数,因为原请求未被日志保留。
|
|
11
|
+
3. 已将现阶段问题收窄为:历史客户端入口/构建是否走新读取流程,或 peer 在客户端注册、ICE/WebView、握手、手机磁盘/落盘等阶段放弃/失败,随后被旧 OSS 的大小错误覆盖。**目前不能单独断言手机过旧、TURN 故障或空间不足。**
|
|
12
|
+
4. 已证实一个诊断缺口:手机客户端的 peer 失败被 `catch → null` 吞掉;共享读取层随后进入 OSS fallback。1.315 GB 大于旧 512 MiB 上限,因此最终只见超限文案,与该失因链一致,但还缺同次完整错误和阶段证据确认本次确实如此。
|
|
13
|
+
|
|
14
|
+
## 实时证据
|
|
15
|
+
|
|
16
|
+
### 运行实例与磁盘版本
|
|
17
|
+
|
|
18
|
+
- `Get-NetTCPConnection -LocalPort 3080 -State Listen`:127.0.0.1:3080,PID **8932**。
|
|
19
|
+
- `Get-Process -Id 8932`:node,启动时间 **2026-09-20 19:27:34(UTC+08)**。
|
|
20
|
+
- `C:/Users/chany/.dsh/profiles/web/node_modules/dsh-cindy-host-demo/package.json:3`:磁盘版本 **0.1.10**。
|
|
21
|
+
- 上述信息不能精确证明整个内存模块树的包版本或解释期间如何重载;但以下实际响应足以证明**新文件能力目前已在运行**。不拿包版本标签替代功能探针。
|
|
22
|
+
|
|
23
|
+
### 既有安全入口与请求结果
|
|
24
|
+
|
|
25
|
+
使用项目既有 `GET /api/dsh-cindy-host/status` 和 `POST /api/dsh-cindy-host/selftest`,均为 127.0.0.1:3080;没有寻找 token 或绕过认证。`src/host-routes.js:179–200,225–250` 明确定义 selftest 的本地 loopback 信任边界;本轮只调用元数据操作。`src/host.js:2433–2436` 给该类请求标记 `src:selftest`,它不是手机发来的请求。
|
|
26
|
+
|
|
27
|
+
| 检查 | 实际响应 | 可证明的边界 |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| Host 状态 | connected,projectionRunning=true | Host 当时在线 |
|
|
30
|
+
| `file-browser:remote-op / caps` | `{ok:true,fileRead:true}` | **手机询问 Host** 的能力合同可用;不是手机声明该能力 |
|
|
31
|
+
| `device-link:file-peer / caps` | `{version:1,maxBytes:2147483648}` | 新 file-peer handler 已提供服务;尚未建立 RTC |
|
|
32
|
+
| workdir=`G:/Projects/助手`,relPath=`delivery/NeonAbyss2.apk`,`fileUrl` | `{ok:true,url:"xdt-file://open?..."}` | 工作区副本路径通过本机绝对根、相对路径和真实路径授权 |
|
|
33
|
+
| 对该引用 `media:fetch {prepareOnly:true}` | `{ossKey:"",size:1315101941,mimeType:"application/octet-stream",transferRequired:true}` | 大小可接受,要求后续传输;没有读取整文件或上传 |
|
|
34
|
+
| NAS workdir=`Z:/[3] Veewo游戏项目/NeonAbyss2/游戏包/Android/Feature/shop-entitlement/2026.9.20.99b5007f212`,relPath=`NeonAbyss2.apk` | fileUrl 成功;prepareOnly 返回同样大小和 transferRequired=true | NAS 在**这个明确的自身目录根**内可准备;不代表从助手 root 能越界读 Z: |
|
|
35
|
+
|
|
36
|
+
两份文件元数据准备发生在 01:07:36–01:07:37。工作区副本通过 Get-Item 独立确认大小为 1,315,101,941 字节。本轮未重新计算 1.3GB 哈希;此前交付报告记录两者 SHA-256 相同,本轮不将其写成独立重验。
|
|
37
|
+
|
|
38
|
+
### 运行诊断的已有信息与局限
|
|
39
|
+
|
|
40
|
+
在本轮 selftest **之前**,01:03:53 状态快照的累计调用数:file-browser:remote-op=25,media:fetch=2,file-peer=6。累计拒绝:file-browser=2;media/file-peer 没有拒绝计数。
|
|
41
|
+
|
|
42
|
+
- 这是所有设备及此前自测合计,不足以将 6 次 file-peer 归属本次手机、某个 action 或某个文件。不要据此声称手机已完成握手/传输。
|
|
43
|
+
- 读取时 recentRefusals 已没有文件类条目;其上限 30 条对外展示,invoke success 环也会被会话轮询挤掉。
|
|
44
|
+
- handlerErrors=11:10 项 `invoke:maker:list-active` 超时,1 项 `user-questions-request` 远端取消;未见文件类边界异常。这不证明 peer 无失败,预期错误可成为 RPC 错误、关闭连接或在手机客户端被吞掉。
|
|
45
|
+
- `src/host.js:1743–1801` 的 askOf 没有记录文件 op、peer action、root/relPath;`1662–1701` 仅有通道级计数和有限环。因此既有接口不能恢复本次的 caps → fileUrl → prepare → offer/open → fallback 完整链路,也没有可用的同次 ICE/连接事件记录。
|
|
46
|
+
|
|
47
|
+
## 源码确认的交互与失因路径
|
|
48
|
+
|
|
49
|
+
以下是现有 Cindy 源码合同,**不等同于证明手机安装包正是这份构建**:
|
|
50
|
+
|
|
51
|
+
1. `apps/mobile/app/files/[sessionId].tsx:465–503`:原“导出/分享”非图片分支调用 `exportRemoteFileToUrl`,不需要寻找新直连按钮。
|
|
52
|
+
2. `apps/mobile/src/session/fileBrowserExport.ts:43–49`:调用 `fileBrowser.readBytes`,普通分享默认不是 stream 模式。
|
|
53
|
+
3. `mobileMakerTransport.ts:1209–1225`:询问 **Host** `caps.fileRead`;为真则取 `fileUrl`,并把两阶段 `exportDeviceFile` 作为 fallback。
|
|
54
|
+
4. `mobileMakerTransport.ts:880–909`:media prepareOnly、`tryMobilePeerFile` 与 fallback 接到共享 `readDeviceFile`。
|
|
55
|
+
5. `packages/device-link/src/fileAccess.ts:43–54`:需要稳定播放 URL 的 stream 分支可能跳过 transient peer;普通分享则尝试 peer,返回 null 时进入 fallback。不能把预览流与整文件分享混为一谈。
|
|
56
|
+
6. `peerFileTransport.tsx:173–223,247–250`:caps → ICE 配置 → WebView offer → Host answer → WebView answer → Host open → 手机空间检查 → receive。忙碌、不可用、异常等可返回 null;异常在 catch 中丢失,除了取消不会保留原错误。
|
|
57
|
+
7. `peerFileRegistry.ts:67–71`:手机临时文件预算要求剩余空间至少 `2*size + 256MiB`。本 APK 对应 **2,898,639,338 字节(约2.70GiB)**,并受累计临时文件 4GiB 预算约束。空间不足只是一个待验证候选,不是本次已证实原因。
|
|
58
|
+
8. `src/host.js:208,255–286`:旧 exportFileStart 对超过 **536,870,912** 字节返回 `OVERSIZE`,消息为 `the file is 1315101941 bytes, over the 536870912 byte export limit`。本轮**未调用**该会启动上传的操作,仅核对源码的前置拒绝。若现有截图包含这个上限/文案,就能确认最后失败是旧 export guard。若是 26,214,400,则更像旧 media 路径,不能混同。
|
|
59
|
+
9. `remoteMediaDiskCacheExpo.ts:21–24,43–68`:peer 的 file:// 结果走本地复制,未发现另一个固定分享大小上限;复制失败映射一般下载失败,不能据此解释现有“超限”。
|
|
60
|
+
|
|
61
|
+
## 最小下一步(只提出,不在本轮实施)
|
|
62
|
+
|
|
63
|
+
### 主助手统一补充的最少信息
|
|
64
|
+
|
|
65
|
+
先取**已有失败**的完整错误文字/截图(尤其上限数字)与大致操作时间、手机 Cindy 版本/构建号。不让用户重复1.3GB下载,不让用户重做 Host 端基础检查。若这些已有于原对话/截图,直接复用,不重复问。
|
|
66
|
+
|
|
67
|
+
### 启用/修复分支
|
|
68
|
+
|
|
69
|
+
- **现在没有“必须重启才能启用新 handler”的证据。** 不把本问题与冻结的 session-bridge 升级合并,不直接重启或重装。
|
|
70
|
+
- 若手机构建确实不含这条 readBytes/file-peer 路径:由主助手交 Cindy 手机开发 agent 确认最小客户端更新,不由文件交付 agent 排障,也不在这里改 Cindy 项目。
|
|
71
|
+
- 若构建支持:由对应 agent 优先保留 peer 的**阶段+安全错误码**(注册/WebView/ICE/answer/open/空间/receive),同时避免把 >512MiB 文件的原始 peer 失败覆盖成泛化 OSS 超限。不要记录 SDP、TURN/账号凭据或文件内容。Host 侧可另案补有界 action/状态/字节数诊断;本轮未改生产或源码。
|
|
72
|
+
- 后续经授权可先用极小、非敏感文件验证同手机 peer;只有协议/存储/网络链路有明确证据后再决定大文件重试。不要通过提高旧 OSS 上限绕过问题,它仍是整缓冲上传路径。
|
|
73
|
+
|
|
74
|
+
## 本报告对前序有限报告的订正
|
|
75
|
+
|
|
76
|
+
`G:/Projects/助手/docs/neonabyss-apk-direct-download-diagnosis-20260921.md` 的能力方向应改为“手机询问 Host caps.fileRead”;并且本项目确有既有运行内诊断与 selftest 入口。本轮已补上运行 handler 和正确两种路径的实际证据。未改写前序报告以保留原调查边界;新事实以本报告为准。
|
|
77
|
+
|
|
78
|
+
**最终交付状态不变:文件副本存在,但手机未确认收到;故障未宣布修复。**
|
|
79
|
+
|
|
80
|
+
## 回报回执
|
|
81
|
+
|
|
82
|
+
已用 session_manage prompt 向 `session-b19a5c27-8bc6-4ba9-a2ea-4786ba88815f` 成功提交一次报告。
|
|
83
|
+
|
|
84
|
+
- idempotency_key:`host-file-peer-apk-diagnosis-report-20260921-01`
|
|
85
|
+
- receiptId:`9f3e92a8336512dbc66c105510a5fc67642e84d42c92aac05f6a6dd68b3bead7`
|
|
86
|
+
- requestId:`assistant-35514f14-dccc-46a7-a1bf-863a76d873a0`
|
|
87
|
+
- admission:accepted。仅证明主助手收件队列已接纳,不等于已处理、根因已修复或手机已接收。后续等待安排,不主动重传/重启。
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# New-session synchronization NOT_FOUND — 2026-09-30
|
|
2
|
+
|
|
3
|
+
## Evidence
|
|
4
|
+
|
|
5
|
+
After the desktop connection fixes, the real Host reports authenticated/connected and the user confirms existing running sessions synchronize. A newly created session `02df58ff-6ec6-43fd-bb74-b3c79e5d0efa` instead produced `[NOT_FOUND] No DSH session ...`.
|
|
6
|
+
|
|
7
|
+
- The ID has a real local session projection record, created at 2026-09-30 13:18:49 UTC, with a first user message recorded. No session data was deleted or recreated during diagnosis.
|
|
8
|
+
- Live refusal counters include `local-db:sessions:get` and `local-db:messages:view`. The user supplied the exact metadata NOT_FOUND message above; the bounded diagnostics window can evict individual earlier failures.
|
|
9
|
+
- Later **read-only** local selftest calls for that same ID return metadata successfully (active, 5 messages) and history successfully (4 history items). This proves the reported failure was not permanent absence. The reads do not create or resume a session and do not send a prompt.
|
|
10
|
+
|
|
11
|
+
## Phone contract
|
|
12
|
+
|
|
13
|
+
The handset preallocates an ID, mounts the screen/subscription, creates the DSH session, calls `local-db:sessions:get` **before the first enqueue**, then enqueues its initial message. Exact-ID probes also support idempotent creation retries. The normal full-sync guard does not prevent the independently mounted history-view hook from reading the preallocated ID before create finishes.
|
|
14
|
+
|
|
15
|
+
Relevant Cindy source: `apps/mobile/src/session/newSessionCreation.ts` (creation pipeline and exact-ID probe), `apps/mobile/app/sessions/[sessionId].tsx` (sync and independently mounted history view), `packages/maker-shared/src/historyViewController.ts` (initial refresh and unavailable fallback).
|
|
16
|
+
|
|
17
|
+
A real created blank session must be readable by ID; an unknown preallocated ID before successful create must remain NOT_FOUND. Never synthesize success from an arbitrary ID, disable subagent filtering, or globally convert history failures into empty success.
|
|
18
|
+
|
|
19
|
+
## Causes and changes
|
|
20
|
+
|
|
21
|
+
1. **Discovery was used as existence proof.** Router get searched the cached visible list; the source deliberately excludes blank drafts and subagents. An existing new blank session was therefore called missing. The real DSH `sessionQuery.observeSession(id, { projectionMode: 'all', signal })` contract can read a live or persisted identity without a listing preflight or Agent activation. The new exact read uses that contract, releases its lease, retains model/provider/effort/permission projections and creation metadata, excludes subagents/parented rows, and keeps archive/delete/pin flags. Only the explicit `SESSION_QUERY_SESSION_NOT_FOUND` code becomes absence; I/O/replay errors propagate.
|
|
22
|
+
2. **Pre-write list flights survived invalidation.** Clearing rowsCache did not clear/fence rowsRefresh, and the source had its own inFlightList. Create now invalidates both layers; old completions cannot overwrite the new cache. A legacy lookup without the exact port rechecks a cache miss instead of treating a stale page as absence.
|
|
23
|
+
3. **Failed history reads seeded a false empty cache.** ensureTranscript touched the transcript cache from finally even when the initial log read rejected. It now caches only successful seeds; a real empty transcript is still cacheable and a failed read remains retryable.
|
|
24
|
+
|
|
25
|
+
The discovery list continues to hide unprompted drafts. Exact-ID reads do not insert every draft into that list. Deleted/archived rows remain flagged, never revived by a get. No handset code changes are required.
|
|
26
|
+
|
|
27
|
+
## Verification
|
|
28
|
+
|
|
29
|
+
- New end-to-end seam/router/source regression file: `test/new-session-sync.test.js`, 9 tests passed (create→get→empty history before enqueue, exact observation disposal, unknown/subagent exclusions, applied selection metadata, both cache race layers, legacy miss recovery, actual Host flag projection).
|
|
30
|
+
- Transcript regression reproduces the previous false-empty cache before the fix, then verifies failed→successful retry, persistent unknown errors and legitimate empty caching.
|
|
31
|
+
- Full final suite: **714 passed, 1 skipped, 0 failed** (715 total), including review follow-ups for blank→titled transition and timestamp parity.
|
|
32
|
+
- Log: `G:\Projects\DSH-cindy-host\artifacts\desktop-runtime-inspect\new-session-tests-final.log`.
|
|
33
|
+
- Exact reads of an unnamed blank session no longer retain a negative title-cache entry for 60 seconds after its first prompt.
|
|
34
|
+
|
|
35
|
+
## Post-restart follow-up: creation prerequisite timeout
|
|
36
|
+
|
|
37
|
+
The user's next attempt reported `任务创建失败` / `invoke timeout`. Live diagnostics showed connected/authenticated, about 176 seconds uptime, phone subscription to draft ID `db4d802e-83bb-46ba-9d9b-5517f4089dbb`, **zero `maker:create-session` invokes**, and real listing TimeoutErrors at 13:48:14 UTC. Exact-ID selftest correctly returned NOT_FOUND for this uncreated draft. This is a separate pre-create failure, not proof that the create→get repair failed.
|
|
38
|
+
|
|
39
|
+
Confirmed blocking dependency: `device-link:subscribe` awaited `listSessions()` to announce turn state **even when subscribing only to `sessions` and no session ID needed a state announcement**. The handset pipeline awaits precisely that acknowledgement before sending create (`newSessionCreation.ts:911–917`). A slow cold listing therefore stalls creation before any create request reaches the Host. Three regressions failed against the deployed implementation: corpus-only subscription blocked on a deferred listing; targeted attachment performed a global list instead of an exact read; exact-read failure retried through the corpus rather than the runtime fallback.
|
|
40
|
+
|
|
41
|
+
Follow-up: sessions-only subscription now acknowledges without any corpus read; targeted session subscriptions use the exact-ID reader, preserving live/idle, input projection and history-repair pushes. Legacy sources without an exact read use the cheaper state listing. If an exact read fails, turn announcement uses the established runtime fallback instead of starting another global list. No timeout was merely increased; no unknown session was synthesized into existence. Post-reload handset validation is still required.
|
|
42
|
+
|
|
43
|
+
Follow-up validation: all 3 new regressions failed before the router change and passed afterward; focused suites 118/118 passed; full suite **717 passed, 1 skipped, 0 failed** (718 total), recorded in `G:\Projects\DSH-cindy-host\artifacts\desktop-runtime-inspect\subscribe-timeout-tests.log`. Only `src/cindy-channels.js` was deployed again, after backing up the installed file to `C:\Users\chany\.dsh\profiles\desktop\cindy-subscribe-fix-backup-20260930`. Source/installed SHA256 equality, syntax and diff whitespace checks passed. The agent did not restart the desktop or submit a real create/prompt; awaiting the user's restart and retry.
|
|
44
|
+
|
|
45
|
+
## Successful handset retry
|
|
46
|
+
|
|
47
|
+
The user confirmed `重试成功了`. Subsequent read-only Host diagnostics showed connected/authenticated, 1 create invoke and 1 enqueue invoke. Exact-ID get for the same draft `db4d802e-83bb-46ba-9d9b-5517f4089dbb` succeeded with 2 messages; recent history reads at 13:58 UTC succeeded. Only the older 13:48 listing timeout records remained in the bounded handler-error log. This confirms successful retry with preserved identity, not repeated cold-start latency or independent proof that the final router module reloaded. The user subsequently requested a serious performance comparison with Cindy's native implementation; that is follow-up work, not evidence that functional success establishes acceptable latency.
|
|
48
|
+
|
|
49
|
+
## Deployment boundary
|
|
50
|
+
|
|
51
|
+
Source is the migration worktree `G:\Projects\DSH-cindy-host-020`, not old main. Deployment includes only these changed runtime files, preserving the previous desktop settings/auth/client repair:
|
|
52
|
+
|
|
53
|
+
- `src/dsh-plugin.js`
|
|
54
|
+
- `src/dsh-session-source.js`
|
|
55
|
+
- `src/cindy-channels.js`
|
|
56
|
+
- `src/host.js`
|
|
57
|
+
- `src/dsh-message-fold.js`
|
|
58
|
+
|
|
59
|
+
All five runtime files were copied to the installed desktop package after backing up the originals to `C:\Users\chany\.dsh\profiles\desktop\cindy-sync-fix-backup-20260930`. Source/deployed SHA256 equality and `node --check` passed for each file. No process restart or plugin enable/disable was performed; the existing running module is not assumed to have reloaded. Tests use mocked services and sockets; they are not a claim of real post-reload handset acceptance. After the user restarts the desktop, verify a phone-created session can be opened immediately and its first message/history synchronizes without NOT_FOUND. Preserve existing session IDs and login credentials throughout.
|