Skip to Content
SpikesS8 · ABC implementation gaps

Spike S8 · 实施期 must-have gap 验证(A + B + C)

状态:✅ 全部通过(2026-05-18)

S7 完成后用户 review 时识别出 3 个”实施期 must-have”缺口,本次集中验证:

验证项优先级工作量
AOpenSpec CLI 在容器内正确装载🔴 高30 min
BmicroVM 内 git commit + push 真 PR🔴 高1-2 h
CFly 真启动 microVM(公有云路径)🔴 高2-4 h

A · OpenSpec CLI 容器内装载

问题

S7 时 npm install -g openspecwhich openspec 不在 PATH,agent 手动 mkdir + mv 模拟 archive 绕开了——但这不能作为生产路径。

根因

npm 上的 openspec 是空占位包

$ npm view openspec name version name = 'openspec' version = '0.0.0' # ← 空包,bin 字段为空

真实的 CLI 包是 scoped

$ npm view @fission-ai/openspec name version bin name = '@fission-ai/openspec' version = '1.3.1' bin = { openspec: 'bin/openspec.js' }

主仓库 host 上的 openspec 也是软链到 @fission-ai/openspec

$ readlink /Users/tanghehui/.nvm/versions/node/v22.22.0/bin/openspec ../lib/node_modules/@fission-ai/openspec/bin/openspec.js

验证

box 内(node:22-alpine + apk add ca-certificates bash):

npm install -g @fission-ai/openspec --silent --no-audit which openspec # /usr/local/bin/openspec openspec --version # 1.3.1

✅ binary 装到 /usr/local/bin/openspec,默认 PATH 可见。

实施期落地

task-runner Dockerfile(或 prep 脚本)必须用正确包名

# ✗ 错: npm install -g openspec # 装空包 # ✓ 对: RUN npm install -g @fission-ai/openspec

B · microVM 内 git commit + push 真 PR

验证流程

box 内端到端走完整 git workflow + 创 PR:

box (node:22-alpine) ↓ apk add git ca-certs curl ↓ git clone https://x-access-token:$TOKEN@github.com/Xeonice/openspec-spike-poc.git ↓ git checkout -b spike/b-validate-1779091853 ↓ printf ">> README.md ↓ git commit ↓ git push origin spike/b-validate-1779091853 ✓ ↓ curl POST /repos/.../pulls + Authorization: Bearer $TOKEN ↓ → https://github.com/Xeonice/openspec-spike-poc/pull/2 ✓

实际产物PR #2 

关键技巧 · x-access-token URL 注入

git HTTPS clone 的 credential helper 在容器里很复杂(要么 keyring、要么环境变量)。最简单做法:

git clone https://x-access-token:$GH_TOKEN@github.com/owner/repo.git /workspace

x-access-token 是 GitHub 的固定用户名占位,密码位放 token——git 自动注入 Authorization header,0 配置。clone 完成后后续 git push 也复用这条 remote。

实施期落地

  • 真实场景 token 来源是 GitHub App installation token(D11 已设计),而不是用户 PAT
  • token 由主 API 在 dispatch 时调 /internal/tasks/:taskId/token 续期接口提供给 box
  • box 内启动脚本注入 GH_TOKEN env var,task-runner agent 用 https://x-access-token:$GH_TOKEN@... clone

用户视图


C · Fly 真启动 microVM

环境

  • Fly app: spike-runner-poc(用户预创建,验证后清理)
  • token: PAT (fm2_...)
  • sandbank: @sandbank.dev/flyio v0.2.0

实测数据

指标
启动耗时7.7s · image=node:22-slim · cpu=1 · memory=256MB
kernelLinux 6.12.87-fly x86_64 GNU/Linux
CPUAMD EPYC 2499 MHz (shared)
memory212 MB(256 配置 - kernel reserve)
nodev22.22.3(image 自带)
exec round-trip0.2-0.5s
destroy1.6s
box → subapi RTTavg 239ms / median 211ms(公网 HTTPS)

关键 blocker · 镜像必须自带 bash

Sandbank flyio adapter 内部用 bash -c "<command>" 包装 exec:

// @sandbank.dev/flyio/dist/client.js async exec(machineId, command) { return request(`/machines/${machineId}/exec`, { method: 'POST', body: JSON.stringify({ cmd: `bash -c ${JSON.stringify(command)}` }), }); }

alpine 默认没装 bash(busybox 提供 sh),首次实验所有 exec 都返回:

stderr: No such file or directory (os error 2) exit: 0 stdout: (空)

切到 node:22-slim(Debian-based 自带 bash)后全部 exec 正常。

公有云 vs 私有路径对比(spike 实测)

指标BoxLite (macmini Hypervisor)Fly (AMD EPYC cloud)差异
启动时间1.5s7.7s5x(cloud overhead 合理)
callback RTT to subapi35ms (S6 LAN)239ms (公网)7x(跨 ocean)
capabilityexec.stream + sleep + snapshot + …terminal + volumes + port.exposeFly 不支持 exec.stream(之前 S2.a 已验)
资源256 MB / aarch64256 MB / x86_64架构不同
成本(单次任务 ~10 min)0(自家硬件)$0.03-0.05 (shared 1 CPU + 256MB)

印证 D2 双轨设计

  • 私有化路径(BoxLite):硬件门槛低 + 启动快 + LAN 内 callback 几乎零延迟
  • 公有云路径(Fly):弹性好 + 无需自己硬件 + 全球 region 可调

实施期落地

  • task-runner D11 选择 provider:dispatch 时按 task config 决定 flyio or boxlite
  • Fly base image 必须含 bash(node:22-slim 或 Dockerfile 显式 apt-get install bash
  • Fly machine 启动时间 7-10s,dispatch UI 需要给”准备中”占位状态
  • 公网 callback RTT 200-300ms,HTTPS SSE keep-alive 长任务时需要 retry/重连机制

累积新发现(写进 design.md)

1. openspec 包必须用 scoped 名 @fission-ai/openspec

  • Dockerfile / box prep 脚本写 npm install -g @fission-ai/openspec
  • 不要写 npm install -g openspec(空包)

2. git push 用 x-access-token:$TOKEN URL 注入

  • 替代复杂 credential helper
  • token 由 D11 容器内续期 InstallationsService 续期机制提供

3. Fly base image 必须含 bash

  • sandbank flyio 内部 bash -c 包装
  • 推荐 base:node:22-slim 或 Dockerfile 显式装 bash
  • 不要alpine 默认(无 bash)

4. 公有云 vs 私有 callback 延迟差 7x

  • 私有 LAN: ~35ms
  • 公网 HTTPS: ~200-300ms
  • 不影响 task 完成(人类感知阈值 100ms 但 callback 是后台异步)
  • 影响”实时进度条”的视觉流畅度——UI 端做平滑

文件存档

  • /tmp/spike-a-openspec-cli.py(macmini 上 box 内验证 openspec 安装)
  • /tmp/spike-b-git-push.py(box 内端到端 git push + PR)
  • /tmp/openspec-spike-s1/spike-c-fly.mjs(Fly machine 真启动)
  • spike B 产物:PR #2 
  • Fly app spike-runner-poc:machine 已 destroy,app 残留,建议 host 上 fly apps destroy spike-runner-poc --yes 手动清理

POC 验证阶段宣告完成

8 个 spike 全部通过(S1 / S1.5 / S2 / S3+S4 / S5 / S6 / S7 / S8)。每个 spike 的”未覆盖”项要么已被后续 spike 补齐(S6→S3+S4 出口、S7→S5 长时、S8→S7 缺口),要么显式 defer 到实施期 §7(真 backend 跑通后观察长 SSE 等)。

可以开始 task-runner 真实施了。