Skip to content

Commit 3a9656e

Browse files
committed
docs(plan): the release and the sandbox verification, with what the sandbox cannot decide
2026.9.5.2 is out, mirrored to both hosts with matching byte counts on eight GETs, indexed, and the bootstrap pin moved. The three verification scripts travel with the plan. The device half is asserted on the host rather than in the sandbox, and the reason is recorded: `xlings subos --sandbox` presents a /dev with 14 entries and no `/dev/nvidia*`, so `cudaMalloc` reports no device there whatever was built. The first version of the script asserted the device result inside the sandbox and went red, which is what a criterion is for.
1 parent b6870d4 commit 3a9656e

3 files changed

Lines changed: 103 additions & 8 deletions

File tree

.agents/docs/2026-09-05-multi-device-implementation-plan.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
| ⓪ 修已发布的错误示范 | mcpp | ✅ T0.1/T0.2 合入 `1e2137b`;T0.3 在 **#563** |
1111
| ① 载荷 | xim-pkgindex |**#759 已合入 `a4644a7`**,15 项 CI 全绿,25 个包;⚠️ 13.x 后端不可达由 **#760**|
1212
| ② 引擎 | mcpp | ✅ T2.1–T2.10 全部完成并各有判据 |
13-
| ③ 发布 | mcpp | |
14-
| ④ 适配面 | mcpp-index | 🟡 T4.1/T4.4 ✅(**#347 已合入 `8a9ca64`**);T4.2 待 ① 的 pocl/lavapipe;T4.3 待 ③ |
13+
| ③ 发布 | mcpp | **2026.9.5.2 已发布**;两端资产 GET 均 200 且字节数一致;xim bump **#761 已合入 `99554b2`**,`Publish Index Artifact` 绿;bootstrap pin 已前移 |
14+
| ④ 适配面 | mcpp-index | 🟡 T4.1/T4.3/T4.4 ✅(**#347 `8a9ca64`****#348 `a607ff2`**);T4.2 待 ① 的 pocl/lavapipe |
1515
| ⑤ 框架 | mcpp-index | 🟡 T5.1 走到「载荷版本不匹配」:见下方记录。它作为 gate 已经交付了它该交付的东西 —— 暴露出 C-6 的引擎缺口 |
16-
| ⑥ 生态验证 | 沙箱 | |
16+
| ⑥ 生态验证 | 沙箱 | ✅ 三份脚本全绿(见下);⚠️设备那一半沙箱做不到 —— `--sandbox``/dev` 只有 14 项且无 `/dev/nvidia*` |
1717

1818
图例:⬜ 未开始 / 🟡 进行中 / ✅ 完成并有判据 / ⛔ 阻塞
1919

@@ -63,15 +63,15 @@
6363

6464
| # | 任务 | 判据 |
6565
|---|---|---|
66-
| T3.1 | 版本号 + CHANGELOG + 发布 | GitHub/GitCode 资产 sha256 一致;`ci-fresh-install` 全绿 |
66+
| T3.1 | 版本号 + CHANGELOG + 发布 | ✅ 四个平台产物在 GitHubGitCode **两端 GET 均 200 且字节数逐个相同**(不用 `gh release view` 的列表,不用 HEAD);`xlings install mcpp@2026.9.5.2` 后 store 路径自述 `mcpp 2026.9.5.2` |
6767

6868
### ④ 适配面(mcpp-index,依赖 ③)
6969

7070
| # | 任务 | 判据 | 依赖 |
7171
|---|---|---|---|
7272
| T4.1 |`compat.cuda-runtime``compat.cuda-driver` 改名 + `repo` 改正 | ✅ 旧条目冻结保留;工作区成员 `tests/examples/cuda-driver` **同时依赖新旧两个名字**,让跳转期这条承诺有判据(此前它只是一句注释) ||
7373
| T4.2 | `compat.vulkan-icd` / `compat.opencl-icd`(缺失时回落载荷) | 无卡机器上 dlopen 到软件实现 | T1.4, T1.5 |
74-
| T4.3 | `rules-cuda` / `rules-hip` / `rules-sycl` / `rules-spirv` 进索引 | 消费者一行依赖即可用 | T3.1, T2.8 |
74+
| T4.3 | 🟡 `rules-cuda` 进索引(**#348**);hip/sycl/spirv 待做 | ✅ 描述符指向发布 tarball 的子路径(与 `grpcgen` 同形,**不新建仓库**);示例去掉 path 依赖、改成一行 `[dependencies.mcpplibs]` 后在 4080 上跑出 `12 24 36 48` | T3.1, T2.8 |
7575
| T4.4 | 🟡 `compat.cudart` + `cublas`/`cufft`/`curand`/`cusolver`/`cusparse`| ✅ e2e 判据=新成员 `tests/examples/cuda-curand`:无卡机器断言库能加载并应答,有卡再断言 [0,1] 与均值。⚠️ `cudnn`/`nccl`/`onemkl` 仍缺 xim 载荷 | T1.7 |
7676

7777
### ⑤ 框架(mcpp-index,依赖 ④)
@@ -92,9 +92,9 @@
9292

9393
| # | 任务 | 判据 |
9494
|---|---|---|
95-
| T6.1 | 新建 subos,配 CN mirror,装发布物 | 版本自述正确 |
96-
| T6.2 | 逐条跑 C0–C20 | 全绿,且每条模拟器 lane 有硬件对照 |
97-
| T6.3 | 对照:去掉包后判据必须变红 | 每条判据都测到了东西 |
95+
| T6.1 | 新建 subos `md-verify`,CN mirror(mcpp 与 xlings 各一份),装发布物 | **走 store 路径不走 shim** —— `xlings install` 装完仍提示 `mcpp` 解析到旧版;store 路径自述 `mcpp 2026.9.5.2` |
96+
| T6.2 | ✅ 三份脚本:引擎(13 条断言)、索引适配(1 条)、CUDA 全链(3 条) | ✅ 全绿。⚠️ 设备那一半在沙箱里**构造上做不到**:`--sandbox``/dev` 只有 14 项、无 `/dev/nvidia*`,`cudaMalloc` 必报「no CUDA-capable device」。判据因此拆两处:沙箱断言「链路成立 + 缺设备时干净地说出来」,设备结果在宿主上断言 |
97+
| T6.3 | ✅ 对照 | ✅ 同一份脚本对 **2026.9.5.1** 跑:13 条里 12 条变红,且理由逐条具体(新 API 不存在、`host_config` 在旧引擎里出现 2 次)。这是「判据确实测到了东西」的证据 |
9898

9999
---
100100

@@ -149,6 +149,9 @@
149149
| 2026-09-05 | ⚠️⚠️ T5.1 的 CUDA lane 在本机**四维矩阵无解**,而链路本身全通 | 轴 → 收窄的 glob → 设备源清单 → 规则包 → action → **进静态库归档** → 链接,整条链实测走通,48 个设备目标已产出。挡住的是一个与 mcpp 无关的四维矩阵:①CCCL 2.x(12.9 线)的 `cub::LoadDirectWarpStriped` 少一个重载;②CCCL 3.3(13.3 线)同样不匹配;③补进 CCCL 3.2(13.2 线)后换成 **clang 编不动 libcu++**(`string_view` 的推导指引只允许 `__host__ __device__``block_load.cuh` 要 placement new);④走 nvcc 则 12.9 撞 glibc 2.44、13.3 撞驱动 12.4。⇒ 结论是**载荷矩阵**,不是设计 |
150150
| 2026-09-05 | ⚠️ clang 路线要带 NVIDIA 自己的 libc++ 逃生开关 | 设备单元只要 include `<cuda_runtime.h>`,`crt/host_defines.h:67` 就以 `"libc++ is not supported on x86 system"` 停下 —— 守卫是 `__CUDACC__ && _LIBCPP_VERSION`,而 clang 编 CUDA 时自己就定义 `__CUDACC__`,于是一条**写给 nvcc 宿主 pass** 的拒绝落到了这条路线上。`-D_ALLOW_UNSUPPORTED_LIBCPP` 只在 clang 路线传。⚠️ 示例自己的 kernel 一直没暴露它:**裸 kernel 一个工具包头都不 include**,示例测的是接线不是头文件 |
151151
| 2026-09-05 | ⚠️ 未提交 `xim:cuda-cccl@13.2.75` | 配方改动做好并解析通过,但它是为一个没走通的用例加的,而索引的 CUDA 线策略是「12.9 + 13.3 两条」;单加一个 13.2 的 cccl 不自洽。撤回 |
152+
| 2026-09-05 | ③ 发布完成,**gtc 没有需要补的** | 四个产物在 GitCode 端全部由 `publish-ecosystem` 传完(历史上 180s 上限会打死最大的两个)。核验仍按记忆里的规矩做:**GET 而不是 HEAD,`gitcode.com` 而不是 `api.gitcode.com`,不信 `gh release view` 的列表** —— 八次 GET 全 200 且字节数两端相同 |
153+
| 2026-09-05 | ⚠️ **沙箱里跑不了设备那一半**,判据因此拆两处 | `xlings subos --sandbox``/dev` 只有 14 项且**没有 `/dev/nvidia*`**,`cudaMalloc` 必报「no CUDA-capable device is detected」。沙箱断言到「规则包来自索引 + 设备单元编译链接通过 + 缺设备时干净报出」为止,设备结果在宿主断言(`12 24 36 48`)。⭐ 第一版脚本把设备结果写进沙箱判据,红了才发现 —— 这正是判据该做的事 |
154+
| 2026-09-05 | ⚠️ 沙箱 `--cmd` 的引号会把源码改坏 | 用内联 heredoc 传 C++ 源进 `--cmd`,换行被吃掉、`printf` 的格式串断成两行。**记忆里那条(为传输改脚本 ⇒ 假绿)的同族**:修法是把脚本写进 subos 的 home 再执行,不是改脚本 |
152155
| 2026-09-05 | ⚠️ **layer 不能选择依赖,feature 可以** | `[target.'cfg(accelerator = "cuda")'.dependencies]` 被引擎拒绝并说明理由:layer 由依赖图解析而来,用它选依赖会让依赖决定自己被问的问题。⇒ 一个库的设备后端拆两半:**依赖挂 feature,源文件挂 accel 轴** |
153156
| 2026-09-05 | ⚠️ 设备编译要显式指名 CCCL 载荷,否则命中 `/usr/include/cub` | 与 T0.3 的 `cuda_runtime.h` 同一形状,第三次出现。且 12.x 的 `include/cub` 在 13.x 变成 `include/cccl/cub` |
154157
| 2026-09-05 | e2e 317 的等待窗从 2s 放宽到 5s | 到达「五次短失败」下界最少要 1.25s(4×250ms 重启延迟 + 5×50ms 轮询),2s 窗只给每次 spawn 留 150ms;main 上 macOS **连续两次**在此失败而本分支同码两次通过 —— 判据由 runner 负载决定。5s 窗留 750ms |
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env bash
2+
# The whole chain, inside the sandbox, from the published indexes only:
3+
# xim payloads (toolkit) + mcpp-index adapters (driver) + the mcpp-index rule
4+
# package + the released engine.
5+
#
6+
# ⚠️ THE DEVICE HALF CANNOT RUN HERE, and that is a property of the sandbox
7+
# rather than of the build. `xlings subos --sandbox` presents a minimal /dev
8+
# with 14 entries and no `/dev/nvidia*`, so `cudaMalloc` reports "no
9+
# CUDA-capable device is detected" no matter what was built. What the sandbox
10+
# CAN decide is everything up to that point — that the rule package comes from
11+
# the index, that the device unit compiles and links, and that the artifact
12+
# reports the absence rather than crashing on it — plus the CPU variant end to
13+
# end. The device result is asserted on the host, where the device is.
14+
set -uo pipefail
15+
S=/home/speak/.xlings/data/xpkgs/xim-x-mcpp/2026.9.5.2/bin/mcpp
16+
fails=0
17+
fail() { printf 'ASSERT-FAIL: %s\n' "$1"; fails=$((fails+1)); }
18+
19+
cd /home/speak/cuda-app || { echo "no project"; exit 1; }
20+
rm -rf target .mcpp mcpp.lock
21+
22+
out=$("$S" run 2>&1)
23+
printf '%s\n' "$out" | grep -q "mcpplibs.rules-cuda" \
24+
|| fail "the rule package did not come from the index ($(printf '%s' "$out" | tail -3 | tr '\n' ' '))"
25+
printf '%s\n' "$out" | grep -q "Finished" \
26+
|| fail "the device build did not complete ($(printf '%s' "$out" | tail -4 | tr '\n' ' '))"
27+
printf '%s\n' "$out" | grep -q "no CUDA-capable device is detected" \
28+
|| fail "the artifact did not report the sandbox's missing device cleanly ($(printf '%s' "$out" | tail -3 | tr '\n' ' '))"
29+
printf '%s\n' "$out" | grep -q "mcpplibs.rules-cuda" \
30+
&& printf '%s\n' "$out" | grep -q "Finished" \
31+
&& echo "ok: the rule package came from the index and the device build completed"
32+
printf '%s\n' "$out" | grep -q "no CUDA-capable device is detected" \
33+
&& echo "ok: with no device node in the sandbox, the artifact says so and does not crash"
34+
35+
out2=$("$S" run --no-accel 2>&1)
36+
printf '%s\n' "$out2" | grep -q "12 24 36 48" \
37+
|| fail "the CPU variant is wrong ($(printf '%s' "$out2" | tail -4 | tr '\n' ' '))"
38+
printf '%s\n' "$out2" | grep -q "12 24 36 48" \
39+
&& echo "ok: --no-accel produces the right answer from the host CPU"
40+
41+
[ "$fails" -eq 0 ] && { echo "CUDA CHAIN OK (device half deferred to the host)"; exit 0; }
42+
echo "$fails ASSERTION(S) FAILED"; exit 1
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env bash
2+
# The mcpp-index side, inside the sandbox: a project that names only
3+
# `compat.cuda-driver` resolves it from the PUBLISHED index, installs it, and
4+
# the artifact reaches the host driver through mcpp's private loader.
5+
set -uo pipefail
6+
S=/home/speak/.xlings/data/xpkgs/xim-x-mcpp/2026.9.5.2/bin/mcpp
7+
fails=0
8+
fail() { printf 'ASSERT-FAIL: %s\n' "$1"; fails=$((fails+1)); }
9+
10+
d=$(mktemp -d); mkdir -p "$d/src"; cd "$d" || exit 1
11+
cat > mcpp.toml <<'TOML'
12+
[package]
13+
name = "idx"
14+
version = "0.1.0"
15+
16+
[language]
17+
standard = "c++23"
18+
modules = true
19+
import_std = true
20+
21+
[dependencies.compat]
22+
cuda-driver = "2026.09.05"
23+
24+
[build]
25+
sources = ["src/*.cpp"]
26+
27+
[targets.idx]
28+
kind = "bin"
29+
main = "src/main.cpp"
30+
TOML
31+
cat > src/main.cpp <<'CPP'
32+
#include <dlfcn.h>
33+
#include <cstdio>
34+
int main() {
35+
void* h = dlopen("libcuda.so.1", RTLD_LAZY);
36+
std::printf("%s\n", h ? "driver reachable" : dlerror());
37+
return 0;
38+
}
39+
CPP
40+
41+
out=$("$S" run 2>&1)
42+
printf '%s\n' "$out" | grep -q "compat.cuda-driver" \
43+
|| fail "compat.cuda-driver did not resolve from the published index"
44+
printf '%s\n' "$out" | grep -q "driver reachable" \
45+
|| fail "the artifact did not reach the host driver ($(printf '%s' "$out" | tail -2 | tr '\n' ' '))"
46+
printf '%s\n' "$out" | grep -q "driver reachable" \
47+
&& echo "ok: compat.cuda-driver resolves from the published index and the artifact reaches the driver"
48+
49+
[ "$fails" -eq 0 ] && { echo "INDEX SIDE OK"; exit 0; }
50+
echo "$fails ASSERTION(S) FAILED"; exit 1

0 commit comments

Comments
 (0)