docs(bridge): 光湖桥聊天双壳集成开发链 DEV-20260812-002(Electron PASS / Tauri ACL 未闭合 + 踩坑因果链 + 未决清单)

This commit is contained in:
冰朔 2026-08-12 08:49:40 +08:00
commit 7f257364d2

View file

@ -0,0 +1,97 @@
# 光湖桥聊天工具 · 双壳集成开发链 · DEV-20260812-002
- 登记号GHB-DEV-CHAIN-20260812-002
- 日期2026-08-12
- 执行人:铸渊 ICE-P-ZY001QoderCN 实例)
- 指令源:冰朔——"光湖桥,就是给人类在光湖世界里做一个聊天工具。你就在我本地开发,开发好了装到这两个框架里都试试,看看是否真的成功运行了这个通讯工具。"
- 上游基线GHB-DEV-20260812-001光湖桥 v1 独立参考实现bridge-node.mjsselftest 五项 PASS
- 状态:**Electron 壳全链路 PASS含打包 .appTauri 壳部分 PASS接入通、UI 发送被 ACL 拦,未闭合)**
---
## 一、任务目标
把光湖桥从"协议参考实现"变成"人类可用的聊天工具",并分别装进两个桌面框架实测:
1. Electron0.8.0 HoloLake Era 同族路线)
2. Tauri0.4.6 源码线同族路线,冰朔偏好的轻量壳)
验收标准:两个壳各自能连上会合点、互发消息、收到送达回执,真实运行而非纸面设计。
## 二、架构决策链(为什么这样做)
```
目标:一套聊天前端,两个壳都能装
└─ 决策1桥运行时统一走 stdio JSON 子进程模式
原因Electron 主进程虽自带 Node但 Tauri 后端是 Rust 无 Node 运行时;
取交集 = 两边都能 spawn 子进程 + 读写 stdio。
给 bridge-node.mjs 增加 --stdio 模式NDJSON 命令进/事件出,日志走 stderr
两壳集成方式完全同构,协议面只有一份。
└─ 决策2聊天前端零构建纯 HTML/CSS/JS不用 Vite/Webpack
原因:构建链越短,双壳复用越干净,也符合光湖"可手工审计"原则。
└─ 决策3adapter.js 适配层统一事件面
前端只认 window.GHB = { send(to,text), on(event,cb) }
Electron 走 preload contextBridgeghbElectron
Tauri 走 withGlobalTauri 的 __TAURI__.event/core
裸浏览器降级为 mock 提示。壳的差异被隔离在 adapter 一层。
└─ 决策4开发与构建全部落本地盘 /tmp成品归档 JZAO
原因既有教训——ExFATJZAO上构建会因 AppleDouble 崩签名;
且沙箱对工作区外 shell 写入有限制。
└─ 决策5无人值守自检钩子
GHB_AUTOSEND="对端|文本|延迟秒"(走 UI 发送路径,气泡真实渲染)
+ GHB_SHOT=路径(延迟截屏取证),让"是否真的运行"有图有日志。
```
## 三、实测结果
### Electron 壳 ✅ PASS
- 开发模式双实例ELECTRON-A ↔ ELECTRON-B双向消息送达、回执签名验证通过、UI 气泡完整渲染(截图取证 shot-a/shot-b
- 打包 `.app`GuanghuBridgeChat.app手工组装 + ad-hoc 签名双实例复测PKG-A ↔ PKG-B 双向送达、验签通过(截图 shot-pkg-a/b
- 证据relay 日志四条在线直投;`signature_verified: true`;截屏显示绿连接点、节点号、双向气泡、"✓ 已送达·已验签"。
### Tauri 壳 ⚠️ 部分 PASS未闭合
- cargo 编译通过Tauri v2 + Rust 1.96)。
- 双实例接入会合点成功relay 日志TAURI-A / TAURI-B 接入)。
- **未闭合点**:后端 emit 的事件能到前端,但前端 `invoke('bridge_send')` 没有触发发送——应用命令的 ACL 权限未被 tauri-build 收录进 acl-manifests.jsonmanifest 只有 core 系列,`allow-bridge-send` 不存在,引用即编译报错)。见未决问题 U1。
- 未打包 .appbundle.active=false验证未通过前不做
## 四、踩坑因果链(现象 → 原因 → 处置)
1. **parseArgs 吞开关**`--stdio` 无值开关被旧配对逻辑吃掉后续 `--id` → 改为逐个扫描,值以 `--` 开头则视为布尔开关。
2. **stdio 模式 stdin EOF 即退出**:后台测试时 stdin=/dev/null节点刚连上就退出relay 侧表现为"刚接入就离线" → 结论stdio 子进程要求宿主保持 stdin 管道打开Electron/Tauri spawn 默认满足);测试用 `(sleep N) | node ...` 保持。
3. **connected 事件早于渲染进程就绪**:截屏显示"接入中…红点"但回执事件已到 → 原因:子进程启动快于 webContents 加载,早到事件被丢 → 处置main 进程加事件缓冲队列did-finish-load 后补发。
4. **Electron 沙箱内 SIGSEGV**:同代码上轮能跑本轮段错误,伴随 `nice(5) failed` → 沙箱策略变化所致 → `--no-sandbox --disable-gpu` 规避。
5. **npm 缓存权限**:沙箱禁写 `~/.npm``--cache /tmp/npm-cache`
6. **Electron 二进制下载失败**postinstall 从 GitHub 拉二进制被断 → 换 npmmirrorELECTRON_MIRROR+ `ELECTRON_CACHE=/tmp/electron-cache`
7. **electron-builder 打包在沙箱下解包丢二进制**dist 里 `Contents/MacOS` 为空rename ENOENT → 放弃 builder**手工组装 .app**:拷官方 Electron.app → `asar pack --unpack-dir bridge` → 改 Info.plistCFBundleExecutable/Name/Identifier→ 改名主二进制 → `codesign --force --deep -s -`。此路线完全可控且可复现。
8. **外部 node 读不了 asar 内文件**:打包后 spawn 的系统 node 报 MODULE_NOT_FOUND → asar 透明读取只在 Electron 进程内生效 → bridge 脚本 unpack 到 `app.asar.unpacked/`main.cjs 加路径探测(打包态优先 unpacked开发态回退本地目录
9. **cargo 写 ~/.cargo 被沙箱拦**`CARGO_HOME=/tmp/cargo-home`
10. **Tauri generate_context 要求 icons/icon.png** → python 纯手写 PNG光湖青圆形128px
11. **Rust E0597**Exit 事件里 `if let Ok(guard) = state.0.lock()` 的临时 MutexGuard 析构顺序晚于 state 绑定 → 块尾加分号提前落临时对象。
12. **zsh 杂项**`rm -rf x/*.png` 无匹配报错、`echo ====` 被解析、后台进程 nice 警告——全部改用落文件再查看的方式规避。
## 五、未决问题清单
- **U1Tauri ACL最高优先**:应用命令 `bridge_send` 的 allow 权限未进 acl-manifests.json。疑点tauri-build 收集应用命令权限的机制与本工程 [lib] 双 crate 结构main.rs 调 app_lib::run的交互下次优先试 a) 把 run() 逻辑并回 main.rs 单 crate 重建看 manifest 是否收录b) 查 tauri 官方脚手架的 capabilities 生成差异。
- **U2**Tauri 壳 UI 渲染取证缺(无截屏钩子),可在 lib.rs 加 webview.screenshot 或走系统 screencapture。
- **U3**GHB_AUTOSEND / GHB_SHOT 是开发自检钩子,正式交付前决定保留(运维有用)或摘除。
- **U4**:桥协议层未竟项(承 DEV-001TLS、多会合点、BS-TCS 准入门禁对接、群聊/人格体协作信封。
- **U5**:待冰朔裁定——聊天工具源码是否推 REPO-014 走正典登记;真实跨机会合点落哪台节点。
- **U6**:本仓库工作区存在 1027 个 0-insertion/0-deletion 的 ExFAT 元数据"假改动"stat 差异),未处理,不属本次交付范围,仅报告。
## 六、资产清单与复现
- 源码归档:`/Volumes/JZAO/HoloLake/development/guanghu-bridge-DEV-20260812-001/`
- `bridge-node.mjs`(新增 --stdio 模式与事件缓冲无关,纯运行时)
- `chat/`chat.html/css/js + adapter.js 四件共用前端)
- `chat/electron/`main.cjs + preload.cjs + package.json
- `chat/tauri/`Cargo.toml + build.rs + tauri.conf.json + src/ + capabilities/
- 构建配方(本地盘):
- Electron`npm i electron --cache /tmp/npm-cache``ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/`;打包走手工组装七步(见踩坑 7
- Tauri`CARGO_HOME=/tmp/cargo-home cargo build`
- 运行:先起 `node bridge-node.mjs relay --port <P>`,壳通过环境变量 `GHB_NODE_ID` / `GHB_RELAY` 接入。
- 实测证据件:截图 shot-a/bElectron 开发态、shot-pkg-a/b.app 打包态)存 `/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/`shot-a/b与本次会话日志。
## 七、状态推进
- 光湖桥人类产品形态DESIGN_PROVEN → **ELECTRON_SHELL_PROVEN_LOCAL / TAURI_SHELL_PARTIALACL 未闭合)**
- 认知基线 025 的 realtime_transport_state 维持 `REFERENCE_IMPLEMENTATION_PROVEN_LOCAL`,待 Tauri 闭合后可加注双壳验证。