Repository navigation
fix(bridge,app): land the Wave-10 product fixes outside the plan scope - #205
qiyuanhuakai wants to merge 10 commits into
Conversation
|
AI 辅助源码审查(独立源码核对;非作者自述,CI 日志另行标明) Head:fbd2c8387f10a027c76c469a64724ac1d50ca367 确定问题:
继承 / 修复边界:
验证限制:未执行真实 Windows/macOS 安装、SEA 全链路、完整 suite、live SSH/Slurm、并发压力或性能 benchmark;未恢复此前受限的安全复现。作者的 3 files / 7 tests 不作为我的运行结果。本次审查不保证没有其他缺陷。 CI 终态补充(2026-10-18 08:34 UTC,更新前重读 head/base,SHA 未变,仍 open):
|
…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.
|
AI 辅助增量复核(dot)。 当前 head: 上次三项结论更新:
验证表述的边界: 新 DEB 测试虽然构建并解包真实 DEB,其 handshake:111–116明确使用 本轮审阅实际增量、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 对应合并树 建议同样为 updater fixture 准备真实 worker import closure,并保证测试所构建安装包含可运行的目标解释器;同时覆盖 binary builder 与 installer 两条入口,不能让生产 staging 静默跳过 worker。上述结论来自源码与 CI 日志,未本地执行原生 updater/权限场景。完整 CI 终态见下方补充。 CI 终态(2026-10-19 03:40 UTC,head 未变)
|
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).
|
我是 OpenAI 的 AI 审查助手。本轮增量复核 head 原 native updater fixture P1 已修复测试:34–36现在等待准备完成后再构建两个版本;68–85由真实 checkout 计算 worker import closure,并保留相对路径复制到 fixture。生产 staging 仍强制要求 worker,没有放宽门槛。 当前 CI Linux x64 与 Linux arm64 的 [P1,同类残余] RPM lifecycle 的另一个升级 fixture 仍缺 worker closure,两个 Linux job 继续失败定位:scripts/qa/vis-bridge-rpm-lifecycle.sh:27–42。该独立消费者建立 qa_root 时只复制已安装的 vis_bridge 与 node-pty,然后直接调用 两项 Linux job 现在先通过原 RPM inspection、native updater 事务和实际 RPM normal install,随后在 这不是本次单文件修改新引入的错误,而是 #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 主 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/**.
…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.
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'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.
|
AI 辅助增量复核(dot;中文顶层评论,非 APPROVE / REQUEST_CHANGES)。 审查 head:a05a0e5bed21e16ced0c8467e8544c40dd71fbc8。 原 RPM lifecycle fixture P1 已修复。
#203 的修复此次已进入本 head,不再沿用旧 Live QA 失败。 RPM 升级样本的解释器范围请明确。 CI 与边界 |
CI 修复:七个失败 gate 逐个定性,并落地祖先分支已合入的修复结论:7 个失败 gate 全部转绿,本 PR 现有 0 个失败 check,mergeStateStatus = CLEAN。新 head 先更正两个事实
每个 gate 的实际失败日志行与定性
两个 3s / 31s / 38s 的失败是配置/环境前置失败(特权 lab 起不来、产物链断),不是真实测试失败;4 个 32s–3m6s 的是真实跑完了安装与 QA 前置之后才死在"找不到产物"。 根因
修法:cherry-pick #203 已落地的修复区间,不重新推导按 #203 自己的顺序把
字节同一性证明: 为什么"对着当前基线重跑"救不了本 PR本 PR 的基线是 #204 的 head 本地验证(推送前)
CI 结果(push 后)
如实声明
|
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.
Independent — Wave-10 product fixes that landed outside the plan's task rows.
app/utils/nodeCrypto.ts+vite.config.ts: thenode:cryptorealm seam replacing the staticnode:moduleimport that blankedpnpm dev(finding F3-P2-3).bridge/runtime/runtimeServices.js+app/bridgeRuntimeWorkspaceProbe.test.ts: probe every granted workspace root so the catalog carriesrepoKey(finding F3-P2-2).bridge/runtime/storage/runtimeStore.js(+.d.ts) and thevis-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 canonicaldescribeLocalBindingdescriber. 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'screateBrowserLegacySourcePortbinds through the canonicallegacyBindingseam, so dropping the file would desynchronize it and make the stack depend on a merge order).bridge/runtime/**/*.d.tsfiles: type declarations for services whose.jsalready 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,browserSourcePort3 files / 7 tests green;vue-tsc --noEmitexit 0; oxlint warnings-only.