Skip to content

fix(bridge,app): land the Wave-10 product fixes outside the plan scope - #205

Open
qiyuanhuakai wants to merge 10 commits into
feat/v090-task-47-docs-v090from
feat/wave10-product-fixes
Open

qiyuanhuakai wants to merge 10 commits into
feat/v090-task-47-docs-v090from
feat/wave10-product-fixes

Conversation

@qiyuanhuakai

Copy link
Copy Markdown
Owner

Independent — Wave-10 product fixes that landed outside the plan's task rows.

  • app/utils/nodeCrypto.ts + vite.config.ts: the node:crypto realm seam replacing the static node:module import that blanked pnpm dev (finding F3-P2-3).
  • bridge/runtime/runtimeServices.js + app/bridgeRuntimeWorkspaceProbe.test.ts: probe every granted workspace root so the catalog carries repoKey (finding F3-P2-2).
  • bridge/runtime/storage/runtimeStore.js (+ .d.ts) and the vis-bridge-runtime-staging.mjs / installer scripts: SEA store-worker sidecar resolution — stage the Node 24 sidecar beside the install.
  • bridge/visBridgeServer.js: log the runtime-host diagnosis instead of swallowing it.
  • app/runtime/migration/browserSourcePort.ts: delegate to the canonical describeLocalBinding describer. KEPT deliberately even though it duplicates already-merged PR fix(app): delegate legacy binding description to the canonical describer #185 — the stack must carry the fix for the tree to be coherent (the working tree's createBrowserLegacySourcePort binds through the canonical legacyBinding seam, so dropping the file would desynchronize it and make the stack depend on a merge order).
  • The six bridge/runtime/**/*.d.ts files: type declarations for services whose .js already exists (tasks 33/34/37/38/39); those tasks have no PR, so the declarations had never been committed anywhere. They land with this bucket per the plan.

Verification: bucket tests nodeCrypto, bridgeRuntimeWorkspaceProbe, browserSourcePort 3 files / 7 tests green; vue-tsc --noEmit exit 0; oxlint warnings-only.

qiyuanhuakai commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner Author

AI 辅助源码审查(独立源码核对;非作者自述,CI 日志另行标明)

Head:fbd2c8387f10a027c76c469a64724ac1d50ca367
Live base:f003d0a8f0119bf8f177d525e56dc104007d3e98
范围:本 PR 20 文件增量、crypto 接缝的消费者、workspace probe 授权链、store sidecar staging / resolver / 三平台 installer、现有打包测试。发布前重读 head 与评论:仍 open,未发现重复意见。

确定问题:

  1. [P1] Windows NSIS 将 sidecar 安装到错误目录,安装后的 /runtime 无法找到 store worker。
    package-vis-bridge-installer.mjs:151–153 在 $INSTDIR 下执行 File /r ".../bridge/" 和 ".../shared/"。按 NSIS File 语义,wildcard 前的目录是搜索根,其内部 runtime 目录会复制到 $INSTDIR/runtime,bridge/shared 这一级不会保留。实际 resolver 却只搜索 $INSTDIR/bridge/runtime,并在其下要求 runtime/runtimeDatabaseWorker.mjs 与 runtime/vis_bridge_node.exe(runtimeStore.js:16–29)。因此 Windows 安装后必然报 sidecar missing;shared 模块位置与卸载删除路径也不匹配。
    建议分别 SetOutPath "$INSTDIR\bridge"、"$INSTDIR\shared" 后复制各自内容,再复原 $INSTDIR;增加真实安装/解包布局断言和已安装 /runtime 握手测试,不能只测试 dist-bridge staging。

  2. [P2] 无条件启动时 Git probe 让合法只读 root 阻断整个 runtime。
    runtimeServices.js:87 对所有 workspace 调用 probeWorkspace;workspace grant 本来允许 permissions: ['read'],但链路 catalog.probe → git.probe → repository → command.authorize 的默认权限为 command(targetGitCommand.js:60–76)。一个不授予 command 的 root 就抛 unauthorized: git.permission,drivers.start 也不会执行;这不是代码注释所说的损坏仓库或真正 startup failure,而是正常的能力限制。
    用该 SHA 未修改的 targetGitCommand / gitService 模块和临时只读 grant,独立聚焦检查已观察到该错误;未宣称完整服务集成复现。建议仅探测有授权的 root,其余保留明确 unknown/unsupported 状态,不提升权限、不阻断无关来源;补只读 root 与混合权限 roots 的 startup 回归测试。

  3. [P1] 新 sidecar staging 没有同步现有 RPM 测试 fixture,Linux 打包必经 CI gate 已失败。
    vis-bridge-installer-posix.mjs:27–31 新增无条件 stageRuntimeWorkerSidecar,而 app/bridgeInstallerRpm.integration.test.ts 创建的 minimal root 仅含 bridge binary / node-pty,未提供 worker import closure。本 PR 未更新该 fixture。
    官方 Linux arm64 CI 日志 已在 Run RPM packaging inspection test 失败,报 Could not resolve "/tmp/vis-bridge-rpm-test-…/bridge/runtime/storage/runtimeDatabaseWorker.mjs",1 test / 1 failed,尚未执行真正 binary payload build。这里引用 CI 证据,不冒充我的独立完整测试运行。建议把 worker/shared 依赖和可控 sidecar 纳入 fixture,并断言新增 payload;不要为使旧测试变绿而让生产路径静默省略 sidecar。

继承 / 修复边界:

  • 本次确实新增 node:crypto 精确 alias 和六项服务 .d.ts,对应修补上游 browser crypto / TS7016 缺口;Node 与浏览器 helper 的 SHA-256 abc 向量在我的 Node 24 聚焦检查均与 builtin 一致。尚未独立运行 Vite 浏览器或完整 typecheck,不能据此宣称 UI 全面修复。
  • browserSourcePort 改用 canonical describeLocalBinding 的改动按当前 base 核对,没有把已合并其他分支上的同类修复误当成本分支自动具备。
  • App.vue 未在本 PR 改动,上游 delivery payload / acknowledgement 协议问题不列为本 PR 新增;test(qa): register the missing runtime case modules and evidence drivers #203 的 workflow 权限/跨 workflow artifact 问题亦是继承,不能由本次产品修复视为已解决。

验证限制:未执行真实 Windows/macOS 安装、SEA 全链路、完整 suite、live SSH/Slurm、并发压力或性能 benchmark;未恢复此前受限的安全复现。作者的 3 files / 7 tests 不作为我的运行结果。本次审查不保证没有其他缺陷。

CI 终态补充(2026-10-18 08:34 UTC,更新前重读 head/base,SHA 未变,仍 open):

  • Complete CI and Release #620 completed / failure。Validate 的 lint/typecheck 已通过,确认六个声明补齐了此前 TS7016;完整 suite 官方结果为 621 files(618 passed / 1 failed / 2 skipped)、6199 tests(6193 passed / 1 failed / 5 skipped)。唯一失败为上文 RPM fixture 缺 worker;web build 被跳过。三个 bucket 文件的 7 个测试在官方日志中通过,不是我的独立全套运行。
  • 两个 Linux Bridge installer 任务均在 RPM inspection gate 失败;其余 9 个 Electron / Bridge 构建安装任务成功,Publish draft release skipped。Windows installer 成功日志验证的是 PTY smoke,未覆盖已安装 /runtime store-worker 握手,因此不能否定上文 NSIS 布局问题。
  • Runtime Live QA #3 completed / failure;保留前述 test(qa): register the missing runtime case modules and evidence drivers #203 继承工作流缺口的归因,不视为本次新增。

…eview found

Three confirmed defects, each RED-first.

1. [P1] The Windows NSIS installer dropped the bridge/shared level. Per NSIS
File semantics the directory before the wildcard is the SEARCH ROOT, so
File /r ".../bridge/*" under $INSTDIR copied bridge/runtime/** to
$INSTDIR/runtime/** (both trees even collided there), while
installedStoreRootCandidates only searches $INSTDIR\bridge\runtime — an
installed Windows vis_bridge always reported its store sidecar missing, and
the uninstall paths no longer matched what install created. Each level now
gets its own SetOutPath and $INSTDIR is restored afterwards. The staging
module also named the sidecar after the HOST platform, so a Windows installer
packaged on Linux shipped vis_bridge_node while the installed resolver
demands vis_bridge_node.exe; the name now follows the staged platform.
New app/bridgeInstallerWindowsLayout.integration.test.ts composes the REAL
generated script with the REAL staging, reconstructs the installed tree under
the documented File semantics, asserts the layout and the uninstall symmetry,
and completes a REAL store round-trip by forking the installed worker through
the installed sidecar. makensis is unavailable on the Linux host, so the
install step is a faithful semantic reconstruction; every other step is the
production path. Both fixes were verified independently load-bearing.

2. [P2] The unconditional startup probe treated a legitimate read-only grant
as a startup failure. catalog.probe -> git.probe -> repository authorizes
with the default command permission, so a root granted permissions:['read']
threw unauthorized: git.permission and drivers.start never ran — a normal
capability limit, not a broken repository. The startup now distinguishes that
one rejection (recorded as an explicit unknown with no repoKey, never an
elevated permission) from genuine failures, which still fail fast; authorized
roots are probed exactly as before. Regression: read-only root plus
mixed-permission roots in app/bridgeRuntimeWorkspaceProbe.test.ts, asserting
the authorized root is still probed for real.

3. [P1] The RPM packaging fixture was not synchronized with the new sidecar
staging, so the Linux gate failed with Could not resolve
".../bridge/runtime/storage/runtimeDatabaseWorker.mjs". The fixture now
carries the REAL worker import closure (computed by the production module and
copied from the checkout, never re-implemented) and a controllable sidecar
marker threaded through a new optional sidecarSource packager option, and the
RPM assertions cover the new payload. New
app/bridgeInstallerDeb.integration.test.ts drives the same shared staging
path end to end with real dpkg-deb: build, unpack, layout assertion and an
installed-/runtime handshake.

qiyuanhuakai commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner Author

AI 辅助增量复核(dot)。

当前 head:32ca6b72e1c39da2b1ec3013a8fc497ccc3431d5;base:f003d0a8f0119bf8f177d525e56dc104007d3e98。相对上次 fbd2c8387f10a027c76c469a64724ac1d50ca367 是 1 个提交、11 个文件。发布前重读 head 与评论,仍 open、未合并。

上次三项结论更新:

  1. NSIS 目录层级 P1:源码已修正。 installer:161–165分别在 $INSTDIR\\bridge、$INSTDIR\\shared 下复制各树,再恢复输出目录,与 installed resolver:16–29所找目录一致。另一个相关修正是 staging:47–61按目标 platform 选择 sidecar 文件名。新增 Windows 测试覆盖脚本布局重建、卸载目录和 worker IPC;它不是 makensis 编译后在原生 Windows 上安装验证,不能以其通过声称 Windows 安装全链路已验证。

  2. 只读 root 阻断启动 P2:原控制流已修正。 runtimeServices:98–106仅捕获 unauthorized/git.permission,记录 unknown 后继续其他 root 与 drivers.start,其他错误仍抛出。workspaceCatalog:82–101保留 workspace/sources 等已有字段、清除 repoKey,使用 revision 条件写入并有界重试。新增混合权限测试检查授权 root 仍是真实 Git repo、只读 root 为 unknown,不提升权限。
    独立用精确 head 的原始 catalog/共享模块执行 5 个定向用例通过:unknown 清除旧 repoKey并保留字段、两次 conflict 后成功、八次 conflict 退出、非 conflict 立即传播、缺失 workspace 拒绝。存储端为 mock;这不是完整 createRuntimeServices 启动集成测试。

  3. RPM fixture 缺 worker P1:fixture 源码已补齐,当前两个 Linux CI 的原 RPM gate 均已通过;但同类缺口还漏了 updater fixture,见下。 RPM 测试:49–71从真实 checkout 计算并复制 worker import closure,传入可控 sidecar;后续检查 RPM 清单、解包 worker/shared 与 sidecar 字节/权限。生产 staging 仍强制包含 worker,未通过跳过它来掩盖失败。sidecarSource 经 Windows、POSIX 及 RPM 共用 staging 链路传递。

验证表述的边界: 新 DEB 测试虽然构建并解包真实 DEB,其 handshake:111–116明确使用 process.execPath,包里的 sidecar 是文字 marker。它验证解包后的 worker/import closure 与 IPC,不能证明包内 sidecar 可执行,也未经过 SEA 主程序或 HTTP/WebSocket /runtime 握手。Windows 测试使用本机解释器复制件和脚本语义模拟,也不能等同原生 Windows 安装。建议将这些精确边界保留在验收结论中;此处未据此新增一个生产故障结论。

本轮审阅实际增量、catalog/probe 授权调用链、installed resolver、三平台打包及新增测试;随后跟踪 CI 确认以下仍须修复的构建门禁缺口。未独立运行 esbuild staging、RPM/DEB/NSIS 套件、真实安装、完整 typecheck/build、live SSH/Slurm 或任何此前受限安全复现。现环境缺可用项目测试依赖与 RPM 工具;上述 5 个 Node 定向检查与作者/CI 结果分开计算。

#200 的 delivery/acknowledgement 与 #203 的 workflow 权限、跨 workflow artifact 缺口未由本次 11 文件增量修复,仍作为继承问题,不重复标成本次新增。Complete CI及 Live QA终态见下方补充。本评论限于已检查范围,不是无缺陷保证或正式 APPROVE/REQUEST_CHANGES。

03:34 UTC 补充:[P1,sidecar fixture 同类残余] 原生 updater 集成 fixture 仍缺 worker/import closure,两个 Linux Bridge 门禁继续必败。

bridgeUpdaterTransaction.integration.test.ts:67–86只创建 node-pty 链接与 bridge 目录,再写 binaryEntry.js 并调用 buildVisBridgeBinary;没有放入 runtimeDatabaseWorker.mjs 及依赖。build-vis-bridge.mjs:77–85又无条件运行同一 stageRuntimeWorkerSidecar。因此即使 RPM fixture 修好,此独立调用方仍在旧版本 fixture 的 SEA 构建后立即失败,尚未进入 updater Docker 事务。

已读本 head 对应合并树 662a1977cdff791e520693e596a1616a4656a3fd 的官方日志:Linux x64、Linux arm64均先通过 RPM inspection(1/1),随后在 Verify native terminal update transaction 报 Could not resolve "/tmp/vis-bridge-native-update-…/bridge/runtime/storage/runtimeDatabaseWorker.mjs",1 test / 1 failed。这不是旧 RPM 失败重复,也不是环境性 timeout;本次只同步 RPM fixture,没有同步 buildVisBridgeBinary 的这个 fixture 消费者。属于 #205 引入强制 sidecar 的同类残余,不归因于 #200/#203。

建议同样为 updater fixture 准备真实 worker import closure,并保证测试所构建安装包含可运行的目标解释器;同时覆盖 binary builder 与 installer 两条入口,不能让生产 staging 静默跳过 worker。上述结论来自源码与 CI 日志,未本地执行原生 updater/权限场景。完整 CI 终态见下方补充。

CI 终态(2026-10-19 03:40 UTC,head 未变)

  • Complete CI and Release #631:completed/failure。Validate 成功,官方日志为 621 files passed / 2 skipped,6197 tests passed / 5 skipped;新增 Windows 布局、DEB、混合 workspace probe、RPM 用例均通过。lint/type-check 和 web build 也成功。这些是 CI 证据,不是我的本地全套运行。
  • 失败仍为上述两个 Linux Bridge 的 native updater gate;其余 10 个主要 job 成功,Complete CI 汇总失败,发布跳过。普通 suite 中该 native updater 用例受 VIS_BRIDGE_NATIVE_UPDATE_QA 开关控制,Validate 通过不能覆盖这条专门门禁。
  • Live QA perf:优化文件树加载速度 #6:completed/failure。已读 SSH/Slurm 日志,两者均在 native lab 写 /etc/hosts 的 EACCES 预检退出;macOS arm64 packaged 日志从 Live QA 自身 run 下载到 0 个匹配 Bridge artifact 后拒绝。保持 test(qa): register the missing runtime case modules and evidence drivers #203 继承 workflow 问题的归因,没有据此声称真实 SSH/Slurm 或安装后 QA 已运行成功。

qiyuanhuakai added a commit that referenced this pull request Oct 19, 2026
This branch's App.vue composes the landed Thread / Handoff / collaboration
services through app/runtime/threadPorts.ts and app/runtime/collaborationPorts.ts,
but only the .js modules were inherited: the six sibling .d.ts files and the
node:crypto seam existed solely on #205's head, so `vue-tsc --noEmit` failed
here with 6x TS7016 ("Could not find a declaration file for module
'../../bridge/runtime/{threads,collaboration}/<service>.js'").

Bring the actual bytes from #205's head 32ca6b7
rather than re-deriving them:

- bridge/runtime/threads/checkpointService.d.ts, handoffService.d.ts
- bridge/runtime/collaboration/coordinator.d.ts, delegationService.d.ts,
  fanoutService.d.ts, mailbox.d.ts
- app/utils/nodeCrypto.ts (+ its test) and the vite.config.ts alias that maps
  `node:crypto` onto it, so a browser realm gets the browser primitives while a
  Node realm (bridge, SEA, workers, tests) keeps the real builtin

RED: 6 TS7016 at app/runtime/{threadPorts,collaborationPorts}.ts.
GREEN: vue-tsc --noEmit exit 0, vite build exit 0, nodeCrypto.test.ts 4 green.
…ixture

buildVisBridgeBinary unconditionally stages the runtime store worker plus
its import closure (stageRuntimeWorkerSidecar), but the native updater
fixture only staged node-pty and the bridge directory, so the SEA build
failed with:

  error: Could not resolve ".../bridge/runtime/storage/runtimeDatabaseWorker.mjs"

Both Linux Bridge installer gates failed on exactly this line (the RPM
fixture's identical gap was already fixed; this independent consumer of
buildVisBridgeBinary was missed). Copy the REAL worker import closure
computed from this checkout into the fixture root, mirroring the RPM/DEB
fixtures. The production staging still requires the worker; nothing is
skipped or weakened to go green.

RED -> GREEN locally (VIS_BRIDGE_NATIVE_UPDATE_QA=1, docker + dpkg-deb):
1 failed with the esbuild resolve error above -> 1 passed with the full
container transaction (OLD_VERSION=0.7.12, UID_MISMATCH=1,
UNREADABLE_ROOT_ANCESTOR=1, HOSTED_REJECTED=1, NEW_VERSION=0.8.0,
PACKAGE_VERSION=0.8.0, DAEMON_STOPPED=1, NO_RESTART=1).

qiyuanhuakai commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner Author

我是 OpenAI 的 AI 审查助手。本轮增量复核 head 0fed647bf71b481aa7714c875f715f0694677046;PR 元数据 base 为 f003d0a8f0119bf8f177d525e56dc104007d3e98。相对上轮 32ca6b72e1c39da2b1ec3013a8fc497ccc3431d5 只有 1 个提交、1 个测试文件(+14/-2)。发布前重新确认 head 未变、PR open / 未合并、评论无重复。

原 native updater fixture P1 已修复

测试:34–36现在等待准备完成后再构建两个版本;68–85由真实 checkout 计算 worker import closure,并保留相对路径复制到 fixture。生产 staging 仍强制要求 worker,没有放宽门槛。

当前 CI Linux x64 与 Linux arm64 的 bridgeUpdaterTransaction.integration.test.ts 均已 1/1 通过(约 84s / 65s)。原缺失 worker 的 updater 构建阻断已消除;这是 GitHub Actions 的实际执行证据,不是把作者本地结果当作我的复现。

[P1,同类残余] RPM lifecycle 的另一个升级 fixture 仍缺 worker closure,两个 Linux job 继续失败

定位:scripts/qa/vis-bridge-rpm-lifecycle.sh:27–42。该独立消费者建立 qa_root 时只复制已安装的 vis_bridge 与 node-pty,然后直接调用 packageVisBridgeInstaller(rootDirectory, version:9999.0.0);没有准备 bridge/runtime/storage/runtimeDatabaseWorker.mjs 及其 imports。installer:202–205会无条件 stageRuntimeWorkerSidecar,最终从这个空 fixture 源树解析 worker。

两项 Linux job 现在先通过原 RPM inspection、native updater 事务和实际 RPM normal install,随后在 Exercise RPM install, upgrade, and removal lifecycle 报 Could not resolve "/tmp/tmp.…/bridge/runtime/storage/runtimeDatabaseWorker.mjs"。日志已出现 RPM_NORMAL_INSTALL_OK,尚未出现 RPM_UPGRADE_LIFECYCLE_OK / RPM_REMOVE_LIFECYCLE_OK;升级包还没构建成功,生命周期验证便被阻断。后续 bridge-remove-lifecycle.json 缺失是前面退出后的连带现象,不能作为另外一个独立产品 bug。

这不是本次单文件修改新引入的错误,而是 #205 强制 sidecar 后仍漏同步的第三个 fixture 消费者:RPM inspection fixture 和 updater transaction fixture 已分别修复,shell lifecycle fixture 尚未修复。建议在这里也从可信 checkout 提供完整 worker closure,并提供适合目标架构的可运行 sidecar;在最终组合 tree 上跑完 RPM install → upgrade → remove,不能让生产 staging 静默跳过缺失 worker。

CI、堆叠与验证边界

CI checkout 日志实际使用 merge commit 88a8f6f32ae225edf00fd6a7789d93a132ece2a4,把当前 head 合入实时基底 5b95ef766e3eae38ba37da48cbe6cb14379d75c9。不能据此称 head 已回补全部基底修复,也不能把下游/其他 PR 变更归到此次测试增量。

主 CI 终态补记(2026-10-19 06:15 UTC,已重读 head 未变):39207761458 completed/failure。Validate 的 lint/type-check、web build 成功,官方日志 621 test files passed / 2 skipped,6197 tests passed / 5 skipped。两项 Linux Bridge 均因上文 RPM lifecycle fixture P1 失败,其余 10 个主要 job 成功,Complete CI failure,发布跳过。普通 Validate 与专门安装门禁的覆盖不能互相替代。Live QA 39207761394已 failure:重新读 SSH/Slurm 日志仍在 native lab 写 /etc/hosts 的 EACCES 预检退出,packaged lanes 未找到所需 Bridge artifact。它们是本分支继承的旧 workflow 配置,不是此次 closure 复制导致;#203 新 head 的 Live QA 成功没有自动进入这里。

本轮独立工作限于精确 SHA 的增量、调用链/准备顺序和官方 CI 日志核对;没有本地运行 Docker、安装/升级、权限边界、安全复现或完整测试。当前无需重跑此前受限场景就能从源码与两平台 CI 确认上述构建缺口。原 NSIS 布局、只读 workspace 和 RPM inspection 修复未被这一文件增量回退,但也未在本轮重新作原生安装验收。本评论不构成无缺陷保证或正式审查投票。

The Fedora lifecycle lane builds an upgrade RPM from a QA root holding only
the installed SEA binary and node-pty. packageVisBridgeInstaller re-stages
the runtime store worker plus its import closure from that root's
source-shaped tree, so the upgrade build died with:

  error: Could not resolve ".../bridge/runtime/storage/runtimeDatabaseWorker.mjs"

The same mandatory-staging contract the updater fixture just hit, in the
production QA lane: the installed tree keeps the closure under its staged
names (bridge/runtime/runtime/** and shared/runtime/**), so copy the REAL
installed closure back into the source-shaped locations and exclude the
sidecar. Production staging still requires the worker; nothing is skipped.

Locally reproduced on the shared staging path (deb build from an identical
QA root): RED = the same esbuild resolve error, GREEN = installer produced
containing runtimeDatabaseWorker.mjs, vis_bridge_node and shared/runtime/**.
qiyuanhuakai added a commit that referenced this pull request Oct 19, 2026
…am here too

The main CI's Validate gate fails on this branch with the six inherited ports
TS7016 errors: app/runtime/{threadPorts,collaborationPorts}.ts statically import
bridge/runtime/{threads,collaboration}/<service>.js, and only the .js modules are
in this branch's history.

The origin is the ancestor, not this PR: commit ccca97b ("feat(app): wire the
unified runtime tree, threads and collaboration into App.vue") introduced both
port modules on branch feat/v090-task-49-53-runtime-app-integration (PR #200)
without their declarations, and every branch stacked above it inherited the
gap. The fix landed on #200 first; a stacked branch does not auto-sync, so this
branch still fails on its own head and the fix cannot be claimed for it from
there.

Bring the same bytes in (from PR #205's head 32ca6b7,
verified byte-identical by git hash-object), so this PR is independently
buildable rather than waiting on an ancestor merge:

- bridge/runtime/threads/checkpointService.d.ts, handoffService.d.ts
- bridge/runtime/collaboration/coordinator.d.ts, delegationService.d.ts,
  fanoutService.d.ts, mailbox.d.ts
- app/utils/nodeCrypto.ts (+ its test) and the vite.config.ts alias mapping
  `node:crypto` onto it, so a browser realm gets the browser primitives while a
  Node realm (bridge, SEA, workers, tests) keeps the real builtin

RED: 6x TS7016 at app/runtime/{threadPorts,collaborationPorts}.ts.
GREEN: vue-tsc --noEmit exit 0, vite build exit 0, nodeCrypto.test.ts 4 green.
qiyuanhuakai added a commit that referenced this pull request Oct 19, 2026
This branch's App.vue composes the landed Thread / Handoff / collaboration
services through app/runtime/threadPorts.ts and app/runtime/collaborationPorts.ts,
but only the .js modules were inherited: the six sibling .d.ts files and the
node:crypto seam existed solely on #205's head, so `vue-tsc --noEmit` failed
here with 6x TS7016 ("Could not find a declaration file for module
'../../bridge/runtime/{threads,collaboration}/<service>.js'").

Bring the actual bytes from #205's head 32ca6b7
rather than re-deriving them:

- bridge/runtime/threads/checkpointService.d.ts, handoffService.d.ts
- bridge/runtime/collaboration/coordinator.d.ts, delegationService.d.ts,
  fanoutService.d.ts, mailbox.d.ts
- app/utils/nodeCrypto.ts (+ its test) and the vite.config.ts alias that maps
  `node:crypto` onto it, so a browser realm gets the browser primitives while a
  Node realm (bridge, SEA, workers, tests) keeps the real builtin

RED: 6 TS7016 at app/runtime/{threadPorts,collaborationPorts}.ts.
GREEN: vue-tsc --noEmit exit 0, vite build exit 0, nodeCrypto.test.ts 4 green.
qiyuanhuakai added a commit that referenced this pull request Oct 19, 2026
This branch's App.vue composes the landed Thread / Handoff / collaboration
services through app/runtime/threadPorts.ts and app/runtime/collaborationPorts.ts,
but only the .js modules were inherited: the six sibling .d.ts files and the
node:crypto seam existed solely on #205's head, so `vue-tsc --noEmit` failed
here with 6x TS7016 ("Could not find a declaration file for module
'../../bridge/runtime/{threads,collaboration}/<service>.js'").

Bring the actual bytes from #205's head 32ca6b7
rather than re-deriving them:

- bridge/runtime/threads/checkpointService.d.ts, handoffService.d.ts
- bridge/runtime/collaboration/coordinator.d.ts, delegationService.d.ts,
  fanoutService.d.ts, mailbox.d.ts
- app/utils/nodeCrypto.ts (+ its test) and the vite.config.ts alias that maps
  `node:crypto` onto it, so a browser realm gets the browser primitives while a
  Node realm (bridge, SEA, workers, tests) keeps the real builtin

RED: 6 TS7016 at app/runtime/{threadPorts,collaborationPorts}.ts.
GREEN: vue-tsc --noEmit exit 0, vite build exit 0, nodeCrypto.test.ts 4 green.
…owser kernel

Review findings on the task-56 QA workflow and its new drivers:

1. The cross-workflow artifact download named no producing run, so all four
   packaged-Bridge platforms downloaded 0 artifacts and stopped at "Locate the
   packaged Bridge" (CI: "Total of 0 artifact(s) downloaded"). Production and
   consumption now sit in the SAME run's dependency chain: build-electron.yml
   gains a packaged-bridge-qa job with needs:[bridge-installers] (the job that
   uploads bridge-<platform>-<arch>-artifacts), downloads that same-run
   artifact, locates and starts the real packaged Bridge, and is gated by
   complete-ci. runtime-v090-qa.yml no longer downloads across runs.

2. The native lab runtime needs root-only privileged initialisation (/etc/hosts,
   system packages, real network namespaces, cgroup v2 delegation) and the
   workflow ran it as the unprivileged runner user; an earlier sudo apt-get
   does not confer root on later steps, so both lanes died with EACCES. The lab
   lanes now run in the matched isolated environment — a --privileged
   ubuntu:24.04 container (--runtime docker) that owns the privileged init,
   runs every daemon as its dedicated user, and is discarded on teardown. A
   preflight proves the container can really create a network namespace before
   any lane, so a missing capability is never mistaken for a dependency
   problem, and an always() cleanup step discards a stale lab container.
   Verified on this host: slurm happy 39/39, slurm failure 48/48, ssh happy
   14/14, ssh failure 21/21, all real daemons in a real privileged container.

3. The system/faults drivers imported the browser kernel from a personal
   absolute path (an author-machine skill cache), so no clean checkout could
   run the browser legs and one machine's cache silently became the default
   contract. The kernel (not published to any registry) is now DELIVERED in
   the repository under scripts/qa/vendor/omowright with its manifest as the
   version pin, loaded through scripts/qa/runtime-v090-browser-kernel.mjs
   (VIS_BROWSER_KERNEL override -> vendored copy -> located prerequisite
   error), with per-file sha256 digest enforcement. A node:test smoke loads
   the kernel from an arbitrary temporary checkout, proves the override wins,
   and fails on a missing or digest-mismatched kernel with a located message.
   The vendored tree is excluded from oxlint like dist; its integrity is the
   digest pin's job, not the linter's.
Follow-up on the same-run artifact chain, from the first CI run's actual logs:

- The lab preflight ran `ip netns add` in a bare ubuntu:24.04 image, which has
  no iproute2 ("exec: ip: executable file not found in $PATH"). The preflight
  now installs iproute2 inside the privileged container first — the same
  privileged init the lab itself performs — so it proves package installation
  AND network-namespace creation before any lane, instead of failing on a
  missing binary that the lab would have installed anyway.

- The packaged-Bridge QA downloaded and located the artifact correctly ("Total
  of 1 artifact(s) downloaded", locate succeeded), but the shipped artifact is
  an INSTALLER (.pkg / .exe), so `[ -x ]` on it failed and the start test never
  ran. The start test now installs the real artifact and starts the installed
  binary: macOS runs `installer -pkg ... -target /` and then
  /usr/local/bin/vis_bridge --version (asserting a real version line), Windows
  runs the repo's existing installer QA (install, reinstall, PATH, --help,
  daemon lifecycle, uninstall). The artifact downloads to dist-bridge/installers,
  the layout that script expects. The graded surface stays the packaged product
  the release actually ships.
The QA drivers load the browser kernel delivered under
scripts/qa/vendor/omowright; run the node:test smoke in the Validate job so a
clean checkout that cannot load it — or a driver that hardcodes a personal
absolute path again — fails CI instead of failing at browser-leg runtime.
…ative failures propagate

Two findings from the review of head e2517a5, both pre-existing implementation
residue rather than new logic in the workflow files:

1. The Slurm lab reported "ready" before SSH was ready. awaitLabReady returned
   as soon as sinfo showed two idle nodes, but the setup script starts slurmd,
   sleeps 7, and only THEN starts the login namespace's sshd — its own
   SSH-listener wait was never part of the ready condition. The lane's
   "real sshd running" precondition used `sshd -V`, a version string that proves
   the binary exists and nothing about the port, and the store login followed
   immediately. CI reproduced it: all preconditions and nine checks passed, then
   the store login failed with a bare `false !== true`, and the failure detail
   had discarded the SSH stderr that would have said why.

   Fix: the setup script now writes a completion marker (/run/lab-setup-complete)
   only after it has proven both sshd listeners are listening and both compute
   nodes are idle, and awaitLabReady requires that marker alongside sinfo — so
   readiness is the setup's real end state, not a parallel weaker one. No extra
   fixed sleep. The precondition now observes the actual listener with ss, and a
   failed login reports both stdout and stderr.

   Verified in the real privileged container: happy lane 39/39 assertions,
   failure lane 48/48.

2. The Windows packaged-QA helper swallowed native failures. It ran vis_bridge
   and four `node ... assert-*` commands without checking each exit code;
   PowerShell's default native-error setting does not make a non-zero native
   exit throw, and GitHub's pwsh wrapper propagates only the FINAL exit code, so
   an earlier failing assertion followed by later successful steps reported the
   packaged acceptance lane green. Every native call now goes through an
   Invoke-Native wrapper that throws naming the command, and
   scripts/qa/vis-bridge-installer-windows.test.mjs guards the structure (no raw
   native statement survives; the wrapper checks $LASTEXITCODE and throws; every
   graded step label is a checked call). The negative control — re-adding a raw
   `vis_bridge --help` — fails the test. The behavioural negative control runs on
   the real Windows job, the only place a PowerShell runtime exists.

   Also archives the Windows lifecycle receipts: the helper writes them to
   RUNNER_TEMP while the artifact only collected .omo/evidence/vis-v090/task-46,
   so the install/reinstall/uninstall proof was being discarded. A staging step
   copies them into the evidence tree before the upload.

Both smokes are wired into the Validate job.
…he host

The review of head e2601cb found the readiness residue in the native
duplicate-start path: awaitLabReady accepted `test -f /run/lab-setup-complete`,
a FIXED path. The docker runtime gets a fresh container per run, so that file
was always this run's; the native runtime runs the setup script on the REUSED
isolated runner, where the previous run's marker and its idle slurm daemons
both survive. stopLab never removed the marker, and the setup script's own
`rm -f` sat at line 287, right next to its own `touch` — after a long apt
install — while awaitLabReady has polled since startLab returned. A native
host already holding `yes` plus two idle nodes therefore reported ready while
THIS round's setup had barely begun.

Four changes, all rooted in the marker's identity and ordering:

- the marker path carries a per-startup token (labSetupMarkerPath), so a
  leftover file from an earlier run is a DIFFERENT file and can never answer
  this run's readiness. startLab mints the token and records markerPath on the
  lab; awaitLabReady checks exactly that path.
- the setup script sweeps /run/lab-setup-complete* as step 0, before the
  install, so a dead marker does not linger on the reused host at all.
- the marker is written LAST, after the version record it certifies:
  readLabDescriptor reads /tmp/lab-versions.txt the instant readiness returns,
  and the previous ordering left a window where it observed an empty or partial
  record (the comment even claimed the version record was already written).
- stopLab removes this startup's marker, so teardown leaves nothing behind.

awaitLabReady takes an injectable probe (defaulting to the real execLab) so the
readiness decision is drivable on a host without a privileged lab; the new
scripts/qa/runtime-v090-slurm-lab.test.mjs asserts a stale marker REJECTS, this
startup's own marker ACCEPTS, the marker follows the version writes, the sweep
precedes the install, and teardown removes the marker — 5 green, wired into the
Validate job next to the other two QA smokes. The generated script still passes
`bash -n`. The privileged native lane itself is unchanged and still runs on the
isolated runner.
Ancestor e6bc962 added the `packaged-bridge-qa` matrix job (4 platforms,
`needs: [bridge-installers]`) and wired it into `complete-ci` — both into its
`needs` and into the gate's own env/loop as `PACKAGED_BRIDGE_QA_RESULT`. It did
not update `ciWorkflow.test.ts`, whose two lane-set assertions still expected
the previous 7 lanes, so `complete-ci needs exactly the lane set` and the
aggregate-check literal both failed.

The failure was LATENT until now: the `validate` job runs `pnpm lint`
(vue-tsc) at step 3 and `pnpm test` at step 6, so the six inherited ports
TS7016 errors failed the job at lint and `pnpm test` never executed. Landing the
six declarations on this head (previous commit) is what let the test phase run
and surface this.

Both assertions now expect the 8 lanes this branch's workflow actually has.
This is not a weakening: `complete-ci needs exactly the lane set` still asserts
`needs.length === laneSet.length` with the "no extras" message, so a lane added
to the workflow without being registered here still fails; and the
aggregate-check test still requires the single-line literal plus every lane's
individual `LANE_*` env line, so an unguarded lane still fails.

RED: 2 failed (`expected 'name: Complete CI and Release...' to contain
'needs: [validate, ..., bridge-installers]'`; `complete-ci needs exactly the
lane set`).
GREEN: 25/25 in ciWorkflow.test.ts; full suite 6192 passed / 6 skipped, exit 0;
vue-tsc --noEmit exit 0; oxlint exit 0.

qiyuanhuakai commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner Author

AI 辅助增量复核(dot;中文顶层评论,非 APPROVE / REQUEST_CHANGES)。

审查 head:a05a0e5bed21e16ced0c8467e8544c40dd71fbc8。
相对上轮 0fed647b 评论,实际为 7 提交、19 文件。逐文件核对:其中 18 文件与已审 #203 的 6b01ab8 完全一致,覆盖此前 workflow/live-lab/browser loader 修复;另一个变化是 RPM lifecycle fixture 增加 worker closure 准备。

原 RPM lifecycle fixture P1 已修复。
vis-bridge-rpm-lifecycle.sh L32–51从已安装包的 bridge/runtime/runtime 复制真实 worker 与同目录闭包到 fixture 的 bridge/runtime/storage,并复制 shared/runtime;显式检查入口存在后才构建升级包。此路径转换与 staging L64–88的 source→staged 映射互逆。生产 staging 仍强制计算闭包,没有跳过缺失 worker。
本轮独立核对复制/构建顺序与映射,精确脚本的 sh -n、bash -n 均通过,没有本地执行安装或容器。
当前 Linux x64 日志与 Linux arm64 日志均已完整出现:

  • RPM_NORMAL_INSTALL_OK
  • RPM_UPGRADE_LIFECYCLE_OK
  • RPM_REMOVE_LIFECYCLE_OK
    两项 job 已 success;native updater 专门测试也各 1/1 通过。升级 fixture 原先在 worker 解析处退出的阻断已消除,这些是本 head 对应 CI 合并树的实际结果。

#203 的修复此次已进入本 head,不再沿用旧 Live QA 失败。
18 文件内容与已审版本一致,包括同 run artifact 生产/消费、安装后定位真实 runtime、Docker 预检/SSH readiness、每次启动 marker、Windows native 失败传播及 ciWorkflow 八项依赖预期。Live QA 39221268017已 completed/success。上轮旧 native /etc/hosts EACCES 与跨 workflow 下载 0 artifact 不代表当前执行结果。
此前 #203 已说明的非阻塞限制仍适用:marker 测试 L70–80定位版本路径会先命中注释;Windows 静态 smoke 也不等同真实“前项失败、后项成功”的 PowerShell 行为负控。此次移入相同代码没有顺带修正这些测试说明/保护尾项,不另计新增 P1/P2。

RPM 升级样本的解释器范围请明确。
新增复制循环明确跳过原包的 vis_bridge_node,而 L53–63在 Fedora 容器用普通 node 调用 packager,没有传 sidecarSource;staging L92–94、L106–108默认复制 process.execPath。两平台日志显示 Fedora 安装的是 Node 22.22.0,因此本次 9999.0.0 升级样本重新打入的是容器 Node,而非复用发布包的 Node 24 sidecar。当前生命周期已成功,不把这点说成已复现产品安装失败;若验收目标包括保持发布包解释器一致,请显式传入已安装的目标架构 sidecar 并校验版本/运行能力,不能用这些绿色 marker 单独证明 Node 24 sidecar 的完整升级验收。

CI 与边界
终态补记(2026-10-19 08:25 UTC):当前主 39221268131 completed/success;Validate、11 个生产打包、4 个 Packaged Bridge QA 及 Complete CI 全部 success,Publish skipped。Validate 的 lint/type-check、web build 成功,官方日志 621 test files / 6197 tests passed,2 files / 5 tests skipped;browser kernel 7/7、Windows 静态 smoke 3/3、Slurm readiness 5/5 均实际执行并通过。本终态根据本次 head 最新 job 及 run 状态确认,没有沿用旧 attempt 或旧汇总失败。
日志检出测试合并提交 7e95ac9,合入实时 #204 base 718c54b;API 历史 base_sha f003d0a 不代表实际测试合并树。本次修复与移入的 #203 文件不等于其他所有 stack 问题已解决。
本轮独立验证为精确增量、十八文件比对、staging/fixture 调用与 shell 语法检查;没有本地运行 Docker、RPM/NSIS/DEB 安装、权限场景、安全复现、真实 live lab 或完整测试。以上平台执行结果均明确归于 GitHub Actions。

@qiyuanhuakai

Copy link
Copy Markdown
Owner Author

CI 修复:七个失败 gate 逐个定性,并落地祖先分支已合入的修复

结论:7 个失败 gate 全部转绿,本 PR 现有 0 个失败 check,mergeStateStatus = CLEAN。新 head a05a0e5bed21e16ced0c8467e8544c40dd71fbc8。

先更正两个事实

  1. 本 PR 并非独立分支,它是堆叠在 docs(release): record the v0.9.0-alpha runtime, migration and platform limits #204 之上的。 refs/pull/205/merge = 0a6a1a87c Merge adfd086de into 5b95ef766e,base 就是 docs(release): record the v0.9.0-alpha runtime, migration and platform limits #204 的 head 5b95ef766e。
  2. 这 7 个失败不是"test(qa): register the missing runtime case modules and evidence drivers #203 未合入的 workflow 变更造成的",恰恰相反——是本分支没有带上 test(qa): register the missing runtime case modules and evidence drivers #203 已经落地并通过的修复。test(qa): register the missing runtime case modules and evidence drivers #203 在 6b01ab804639 是 CLEAN 的。本分支与 test(qa): register the missing runtime case modules and evidence drivers #203 那条线的共同分叉点是 8c5cb2399,位置在 test(qa): register the missing runtime case modules and evidence drivers #203 四个 QA-lab / workflow 修复之前。

每个 gate 的实际失败日志行与定性

Gate 失败耗时 实际日志行 定性
Live SSH 31s native lab runtime cannot write /etc/hosts (EACCES): the native runtime installs system packages and edits /etc/hosts, so it must run as root on the isolated runner — use --runtime docker on a host without root (b) 陈旧基线产物
Live Slurm 38s 同上,逐字相同(--lab isolated --modes "tcp,relay" --runtime native) (b) 陈旧基线产物
Live QA complete 3s ##[error]live-slurm did not succeed (failure) / ##[error]live-ssh did not succeed (failure) / ##[error]cross-platform did not succeed (failure) 纯 fan-in 汇聚,非独立缺陷
Packaged Bridge/Electron on Windows arm64 3m6s Found 0 artifact(s) → Filtering artifacts by pattern 'bridge-windows-arm64-artifacts' → Total of 0 artifact(s) downloaded → ##[error]no packaged Bridge artifact was produced by task 45 for this platform (a) 本分支自身缺陷(自基线继承)
Packaged Bridge/Electron on Windows x64 1m16s 同上,pattern bridge-windows-x64-artifacts 同上
Packaged Bridge/Electron on macOS arm64 32s 同上,pattern bridge-macos-arm64-artifacts 同上
Packaged Bridge/Electron on macOS x64 1m29s 同上,pattern bridge-macos-x64-artifacts 同上

两个 3s / 31s / 38s 的失败是配置/环境前置失败(特权 lab 起不来、产物链断),不是真实测试失败;4 个 32s–3m6s 的是真实跑完了安装与 QA 前置之后才死在"找不到产物"。

根因

  • 两个 Live gate:runtime-v090-qa.yml 用 --runtime native 起 lab。GitHub runner 用户不是 root,而某一步里的 sudo apt-get 不会把 root 带给后续步骤;lab 要写 /etc/hosts、装系统包、建真实 network namespace,于是 EACCES。
  • 四个 Packaged gate:runtime-v090-qa.yml 的 cross-platform-packaged job 用 actions/download-artifact@v4 下载 bridge-<platform>-<arch>-artifacts,但没有指名生产它的 run,因此只能看到当前 run 的产物——而这个 run(39208967603,workflow Runtime v0.9.0 Live QA (task 46))里根本没有生产该产物的 job。生产它的是另一个 workflow(Complete CI and Release / build-electron.yml)里的 bridge-installers。所以 Found 0 artifact(s) 是必然,不是偶发。

修法:cherry-pick #203 已落地的修复区间,不重新推导

按 #203 自己的顺序把 8c5cb2399..6b01ab804639 摘到本分支:e6bc96255(same-run artifact chain + container lab runtime + delivered browser kernel)、5c5156166、e2517a5a6、e2601cb3b、a322281eb、6b01ab804。

  • cross-platform-packaged 被删除;产物生产与消费放进同一个 run 的依赖链:build-electron.yml 新增 packaged-bridge-qa(needs: [bridge-installers],4 平台),并被 complete-ci 纳入 needs 与逐 lane 检查。
  • lab 改为 --runtime docker:一个 --privileged ubuntu:24.04 容器承担全部特权初始化,跑真实 slurmctld / 两个 slurmd / munged / sshd,并在任何 lane 之前先证明该容器真能建 network namespace;另加 docker rm -f 清理步骤。

字节同一性证明:git diff 6b01ab804639 HEAD -- .github/workflows/ app/ciWorkflow.test.ts .oxlintrc.json 为空,即与 #203 的 head 逐字节相同。scripts/qa/ 下唯一残留差异是本分支自己的 vis-bridge-rpm-lifecycle.sh worker 闭包修复,已刻意保留。

为什么"对着当前基线重跑"救不了本 PR

本 PR 的基线是 #204 的 head 5b95ef766e,它自己也还带着坏掉的 cross-platform-packaged 和 --runtime native。重跑只会复现同样的失败。堆叠分支没有自动同步,所以只能把修复带进本分支——这正是本次做的事。

本地验证(推送前)

  • vue-tsc --noEmit exit 0,零输出;oxlint exit 0(仅存量 warning)
  • vitest run app/ciWorkflow.test.ts → 25 passed
  • node --test scripts/qa/runtime-v090-slurm-lab.test.mjs scripts/qa/vis-bridge-installer-windows.test.mjs scripts/qa/runtime-v090-browser-kernel.test.mjs → 15 passed / 0 failed

CI 结果(push 后)

Live SSH pass 2m12s、Live Slurm pass 4m46s、Live QA complete pass 3s、4 个 Packaged Bridge QA 全 pass、Validate pass 6m34s、Complete CI pass 4s —— 0 个失败 check。

如实声明

  • 本机没有 sshd、没有 Slurm、没有 munge、不能建 network namespace、也没有免密 root,没有在本机跑过任何真实 lab。上面每一条 Live / Packaged 结果都是 GitHub runner 真实执行出来的。
  • 没有削弱、收窄或删除任何断言;四个 Packaged gate 的断言(产物必须存在、必须可执行、--version 必须真的打印)原样保留,只是把产物链修对。
  • 没有 force-push、没有改写历史;除推送外对 GitHub 只做过一次单个 job 重跑(docs(release): record the v0.9.0-alpha runtime, migration and platform limits #204 的 Live Slurm,非本 PR)。

qiyuanhuakai added a commit that referenced this pull request Oct 19, 2026
This branch's App.vue composes the landed Thread / Handoff / collaboration
services through app/runtime/threadPorts.ts and app/runtime/collaborationPorts.ts,
but only the .js modules were inherited: the six sibling .d.ts files and the
node:crypto seam existed solely on #205's head, so `vue-tsc --noEmit` failed
here with 6x TS7016 ("Could not find a declaration file for module
'../../bridge/runtime/{threads,collaboration}/<service>.js'").

Bring the actual bytes from #205's head 32ca6b7
rather than re-deriving them:

- bridge/runtime/threads/checkpointService.d.ts, handoffService.d.ts
- bridge/runtime/collaboration/coordinator.d.ts, delegationService.d.ts,
  fanoutService.d.ts, mailbox.d.ts
- app/utils/nodeCrypto.ts (+ its test) and the vite.config.ts alias that maps
  `node:crypto` onto it, so a browser realm gets the browser primitives while a
  Node realm (bridge, SEA, workers, tests) keeps the real builtin

RED: 6 TS7016 at app/runtime/{threadPorts,collaborationPorts}.ts.
GREEN: vue-tsc --noEmit exit 0, vite build exit 0, nodeCrypto.test.ts 4 green.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant