CNB 流水线 Creator 交接物缺失导致 Solver 无题可解:stage 显示 success 却什么都没产出,怎么定位?
日期:2026-09-21 16:00(CST,UTC+8) 环境:CNB(cnb.cool)默认 NPC 镜像
cnbcool/default-npc:latest,services: docker(DinD) 技术栈关键词:CNB 流水线、cnb.yml、crontab: 0 0,8,16 * * *、npc:go、CodeBuddy-Creator / CodeBuddy-Solver、 stage 交接、scenario/.current-round.json、孤儿分支、cnb build get-build-status、cnb build get-build-stage、cnb build build-runner-download-log、agent bootstrap 重启、stage success 但不产出 一句话结论:stage success≠ 交接物存在 —— Creator 只跑了 61 秒、状态success、error为空, 却一个交接物都没产出(无分支 / 无环境 / 无 Issue / 无状态文件);Solver 报「读不到本轮信息」时, 用「状态文件 + 问题环境 + 远端分支 + 历史 Issue + 当天构建记录/ stage 日志」做五要素判定, 全空时要如实记录诊断,而不是硬造一题刷成交。
一、问题背景
本仓库是「每天 3 个计算机实战问题」的自动化训练闭环。.cnb.yml 里一条定时流水线每天 3 次
(00:00 / 08:00 / 16:00)触发,两个 npc:go stage 在同一个 Job 内、共享同一工作目录:
main:
"crontab: 0 0,8,16 * * *":
- name: scenario-daily-round
stages:
- name: generate-scenario # Stage 1:CodeBuddy-Creator 出题(timeout: 40m)
type: npc:go
- name: solve-scenario # Stage 2:CodeBuddy-Solver 解题(timeout: 60m)
type: npc:go
Creator 要留下三样交接物:
- 孤儿分支
YYYY-MM-DD-HHMM(含scenario/<分支>/复现环境)—— push 才留痕; - Issue「【实战题·第N题】…(YYYY-MM-DD-HHMM)」;
- 状态文件
scenario/.current-round.json(不提交,只活在共享工作目录里)。
{"branch":"2026-09-21-1600","issue":73,"scenario_dir":"scenario/2026-09-21-1600","topic":"..."}
# 路径 scenario/.current-round.json,已在 .gitignore 中被忽略
2026-09-21 16:00 场轮到 Solver(solve-scenario)启动时,典型症状:
cat scenario/.current-round.json→ No such file or directoryls -A scenario/→ 只有.gitkeepgit branch --show-current→ main(不在任何日期分支上)git ls-remote origin 'refs/heads/2026-09-21-1600'→ 空
Solver 面对的是「空手接活」。先判断这是不是异常,再决定怎么做。
二、复现步骤(诊断命令,可原样照跑)
全部命令在 CNB 流水线容器内执行,
cnbCLI 已登录(cnb status→✅ 已登录。)。
1. 看有没有交接文件、工作区有没有本轮环境
test -f scenario/.current-round.json && cat scenario/.current-round.json || echo "NO_STATE_FILE"
ls -A scenario/
git branch --show-current
实测输出:
NO_STATE_FILE
.gitkeep
main
2. 远端有没有本轮分支
git fetch origin --prune
git ls-remote --heads origin | awk '{print $2}' | sed 's#refs/heads/##' | sort | tail -6
实测输出:
2026-09-19-1600
2026-09-20-0000
2026-09-20-0800
2026-09-21-0000
2026-09-21-0800 ← 当天最新只到 08:00 场
main
→ 没有 2026-09-21-1600。
3. 历史 Issue / 本轮 Issue、历史最大题号
cnb issues list-issues --repo zhenxijs/3dayTest/3day-test --page-size 100
实测输出:
total: 1
- number: "82" state: open
title: 【实战题·第66题】内网 DNS「UDP 能查、TCP 不通」…(2026-09-19-0000)
created_at: "2026-09-18T16:17:13Z"
→ --state open 只有 1 条(#82 第66题,与本轮无关);没有 2026-09-21-1600 的 Issue。
(历史已关闭 Issue 的最大题号 = 72,分支 2026-09-21-0800,见 experience/README.md 索引末行。)
4. 关键:当天的构建记录
cnb build get-build-logs --repo zhenxijs/3dayTest/3day-test \
--createTime 2026-09-21 --endTime 2026-09-21 --page-size 40
实测输出(total: 9;createTime 是 UTC,+8 才是本地):
| sn | createTime (UTC) | 本地 (CST) | event | targetRef | status |
|---|---|---|---|---|---|
cnb-228-1k2vonj4m | 2026-09-20T16:00:05Z | 09-21 00:00:05 | crontab | main | success |
cnb-bvo-1k2vp7b68 | 2026-09-20T16:08:42Z | 09-21 00:08:42 | push | 2026-09-21-0000 | success |
cnb-nt8-1k2vpcn4f | 2026-09-20T16:11:38Z | 09-21 00:11:38 | push | 2026-09-21-0000 | success |
cnb-05g-1k2vpd8tl | 2026-09-20T16:11:56Z | 09-21 00:11:56 | push | main | success |
cnb-1pg-1k30k6c21 | 2026-09-21T00:00:01Z | 09-21 08:00:01 | crontab | main | success |
cnb-k7o-1k30kn228 | 2026-09-21T00:09:08Z | 09-21 08:09:08 | push | 2026-09-21-0800 | success |
cnb-gkg-1k30krvjo | 2026-09-21T00:11:49Z | 09-21 08:11:49 | push | 2026-09-21-0800 | success |
cnb-r5o-1k30kseja | 2026-09-21T00:12:05Z | 09-21 00:12:05 | push | main | error |
cnb-qu8-1k31flaoe | 2026-09-21T08:00:04Z | 09-21 16:00:04 | crontab | main | pending ← 本场 |
读法:
- 当天有 3 条
crontab构建(00:00 场 / 08:00 场 / 16:00 场),本场是cnb-qu8-1k31flaoe。 - 08:00 场留下了
push→2026-09-21-0800(第72题),这是正常一轮的样子。 - 全天 9 条构建中没有任何一条
push→2026-09-21-1600→ 平台侧证明 Creator 从未 push 过任何东西。
5. 决定性证据:stage 级「success 却没产出」
cnb build get-build-status --repo zhenxijs/3dayTest/3day-test --sn cnb-qu8-1k31flaoe
实测输出(关键部分):
pipelinesStatus:
"cnb-qu8-1k31flaoe-001":
name: scenario-daily-round
stages[6]{status,duration,name,id}:
success,25201,Prepare,prepare
success,60731,generate-scenario,stage-0 ← ★ Creator 阶段
start,0,solve-scenario,stage-1 ← ★ 本 stage
pending,0,BeforeEnd,beforeEnd
pending,0,DebugDetection,debugDetection
pending,0,End,end
cnb build get-build-stage --repo zhenxijs/3dayTest/3day-test \
--sn cnb-qu8-1k31flaoe --pipelineId cnb-qu8-1k31flaoe-001 --stageId stage-0
实测输出:
status: success
name: generate-scenario
startTime: 1789977628801 → 本地 2026-09-21 16:00:28
endTime: 1789977689533 → 本地 2026-09-21 16:01:29
error: ""
→ Creator 阶段只跑了 60.7 秒,状态 success,error 为空 —— 但它一个交接物都没产出。
这是本轮最值得记的一条:stage success 不等于交接物存在。
6. 决定性的第二步:Runner 日志里 Creator 到底干了什么
cnb build build-runner-download-log --repo zhenxijs/3dayTest/3day-test \
--pipelineId cnb-qu8-1k31flaoe-001
# → data: /tmp/cnb-api/<ts>-<rand>.bin
清洗后过滤出 Creator 阶段(16:00:26→16:01:29)执行的命令:
sed 's/\x1b\[[0-9;]*m//g' /tmp/cnb-api/<file>.bin | tr -d '\000' > /tmp/log.txt
awk '/^\[00:00:2[2-9]/,/^\[00:01:29/' /tmp/log.txt | grep -E '^\[[0-9:]+\s+[+-]?[0-9.]+m?s\] \$ '
实测输出:
[00:00:26] $ echo ~ / pwd / cat AGENTS.md / cat CODEBUDDY.md / cnb skills list … / node -v ← 启动 bootstrap
[00:00:28] $ pwd && ls -la && git log --oneline -5 && git remote -v
[00:00:30] $ cat experience/README.md | head -120
[00:00:30] $ git ls-remote --heads origin | head -80; ls template/ .devcontainer/ .cnb/ scenario/
[00:00:32] $ sed -n 120,200p experience/README.md
[00:00:32] $ cnb issues --help; cnb issues list --help
[00:00:34] $ cnb issues list-issues --help; cnb issues create-issue --help
[00:00:34] $ cat .cnb/settings.yml; cat template/README.md; cat template/docker-compose.yml
[00:00:36] $ cnb issues list-issues --page-size 100 --order-by=-created_at
[00:00:36] $ date +%Y-%m-%d-%H%M; date; cat .gitignore; cat .devcontainer/Dockerfile
[00:00:38] $ cnb issues list-issues … --state closed | grep -E 'number|title' ← 查重:捞历史题号
[00:00:40] $ …(同一命令分页)
[00:00:43] $ …(同一命令分页)
[00:00:45] $ …(同一命令计数)
[00:00:47] $ …(同一命令分页)
[00:00:50] $ cat MIGRATION.md; cat README.md
[00:00:51] $ ls -a scenario/; ls experience/ | head -80; ls experience/ | wc -l
[00:00:53] $ find experience -name '*第66题*' -o -name '*dns*'; grep -n "第6[567]题" experience/README.md
[00:00:53] $ cnb issues get --number 82 ← 最后一条有实质产出的命令
─────────── ★ 静默 32.6 秒(00:00:54 → 00:01:26)───────────
[00:01:26] $ echo ~
[00:01:26] $ pwd
[00:01:27] $ cat AGENTS.md
[00:01:27] $ cat CODEBUDDY.md
[00:01:27] $ cnb skills list -g -a codebuddy --json
[00:01:27] $ cnb skills list -p -a codebuddy --json
[00:01:27] $ node -v
[00:01:29] $(stage 结束)
根本原因一目了然:
00:00:26–00:00:54(约 28 秒):Creator 只做了查重调研 —— 读experience/README.md索引、git ls-remote列分支、cnb issues list-issues翻历史 Issue、cnb issues get --number 82读第66题详情。 它停在了「调研完、还没开始动手」的边界上。00:00:54 → 00:01:26:静默 32.6 秒(无任何 shell 命令,模型侧思考/上下文重建)。00:01:26–00:01:29:命令序列变回echo ~→pwd→cat AGENTS.md→cat CODEBUDDY.md→cnb skills list×2 →node -v—— 和00:00:26stage 启动时的 bootstrap 序列逐条一致。 说明 agent 丢掉了已有进度、从头重启了自己的启动流程。- 重启后还没来得及重新读题,stage 到点结束(总时长 60.7 秒),
于是「分支 / 环境 / Issue / 状态文件」四样全空,而 stage 状态仍是
success。
7. 交叉验证:正常一轮长什么样
2026-09-21T00:00:01Z crontab → cnb-1pg-1k30k6c21 (08:00:01 本地,success)
2026-09-21T00:09:08Z push → 2026-09-21-0800 "feat(第72题): 配置加载器静默跳过所有配置…"
2026-09-21T00:11:49Z push → 2026-09-21-0800 "fix(第72题): 修复配置加载器静默跳过所有配置"
2026-09-21T00:12:05Z push → main "docs(第72题): 沉淀…经验 + 更新索引"
→ 正常一轮 = crontab(触发)+ push→<日期分支> + push→main。
本轮 一条 push→2026-09-21-1600 都没有,与「Creator 未产出」完全吻合。
8. 确认 Docker 可用(排除「环境本身没起来」)
docker version --format '{{.Client.Version}} / {{.Server.Version}}'
# → 29.6.2 / 29.6.2-7 正常
三、根本原因
本轮(2026-09-21-1600)Creator 阶段在查重环节耗尽预算并中途重启,未产出任何交接物;
且它的失败对流水线完全不可见(stage 记 success、error: ""),Solver 因此空手接活。
五要素交叉验证:
| 检查项 | 期望 | 实测 | 判定 |
|---|---|---|---|
scenario/.current-round.json | 存在且含 branch/issue | 不存在 | ❌ |
scenario/2026-09-21-1600/ | README + Dockerfile + compose + 代码 | 只有 .gitkeep | ❌ |
远端分支 2026-09-21-1600 | 存在 | 不存在(最新 2026-09-21-0800) | ❌ |
| Issue「第73题(2026-09-21-1600)」 | 已发布 | 不存在(历史最大 72) | ❌ |
| 平台构建痕迹 | 有 push→2026-09-21-1600 | 无(当天 9 条全无) | ❌ |
机制推断(本轮首次拿到 stage 内部证据):
两个
npc:gostage 共享同一工作目录。Creator 的三样交接物里,scenario/与 Issue 必须先 push 才留痕,而.current-round.json被.gitignore忽略、 只活在共享工作目录里,且是进程内的。 本轮 Creator 在「查重调研」阶段就用掉了自己的预算(连续 5 次分页捞历史题号), 随后 agent 中途重启 bootstrap,stage 到点结束 —— 三样交接物一样都没有,且没有任何地方报错。
这是本仓库第 3 次同型事故:2026-09-15-0800(第58题位)、2026-09-20-0800(第70题位)、
2026-09-21-1600(本轮)。前两次只看到「结果为空」,
本轮第一次看到「Creator stage 内部到底发生了什么」:它不是没跑,而是跑了、只跑了查重、就重启并结束了,还被记成 success。
⚠️ 这不是某道题的解答,也不是「某道题挂了」,而是流水线 stage 交接机制的可靠性缺陷。
四、解决办法
1) 本轮处理方式(对工作负责的姿势)
- 不发明题号、不硬造题目、不改历史产物:
- 不臆造「第73题」并编造一套假环境 —— 那样写出的 SOLUTION / 经验文档是脱离真实环境的伪证据, 会污染整个经验库的可信度;
- 不动
2026-09-21-0800(第72题)的任何文件。
- 只沉淀「诊断过程本身」:可复现命令链 + 实测输出 + 判定表(就是本篇)。
- 给结论留落点:本轮 Issue 不存在,走「分支内文档 + commit message」通道。
- 把「stage success ≠ 交接物存在」写下来,供配置侧加固。
2. 流水线侧加固建议(改 .cnb.yml)
建议 1(最高优先级):Solver 开头做「交接物」硬校验,缺料即快速失败
# solve-scenario stage 开头(示意)
test -f scenario/.current-round.json \
|| { echo "FATAL: Creator 未留下 scenario/.current-round.json,本轮无题可解"; exit 1; }
BRANCH=$(python3 -c "import json;print(json.load(open('scenario/.current-round.json'))['branch'])")
git rev-parse --verify "origin/$BRANCH" >/dev/null \
|| { echo "FATAL: 远端不存在分支 $BRANCH"; exit 1; }
test -d "scenario/$BRANCH" \
|| { echo "FATAL: 缺少问题环境 scenario/$BRANCH/"; exit 1; }
建议 2(本轮新发现,针对 Creator 侧):给 Creator 加「产出断言」 ——
Creator stage 结束前必须自检「分支已 push + Issue 已建 + 状态文件已写」,
任一条不满足就 exit 1,让「静默成功」变成「构建失败」。
建议 3(本轮新发现):把「查重」与「出题」拆成两个 task/stage ——
本轮 Creator 的预算几乎全耗在翻历史 Issue 找题号上(00:00:38–00:00:47 连续 5 次分页)。
把查重结果落成缓存(如 experience/dedup-index.json),出题阶段直接读缓存,可显著省预算。
建议 4:给交接文件加「新鲜度」字段,防跨场次串读 ——
.current-round.json 增加 created_at / run_id,Solver 校验其是否等于本次运行。
建议 5:加流水线互斥锁,消除并发撞车
lock:
key: scenario-daily-round
wait: false
建议 6:交接物双保险 —— Creator 同时把轮次信息落到 Issue 正文 与 commit message; Solver 在状态文件缺失时按「当天日期查最近 Issue + 远端分支」兜底。
五、验证
# 1) 无交接文件
test -f scenario/.current-round.json || echo "NO_STATE_FILE" # → NO_STATE_FILE
# 2) 无本轮环境
ls -A scenario/ # → .gitkeep
# 3) 无本轮分支
git ls-remote --heads origin | grep 2026-09-21-1600 # → 空
# 4) 无本轮 Issue
cnb issues list-issues --repo zhenxijs/3dayTest/3day-test --page-size 100
# → total: 1(仅 #82 第66题)
# 5) stage 级:Creator「成功」但无产出
cnb build get-build-status --repo zhenxijs/3dayTest/3day-test --sn cnb-qu8-1k31flaoe
# → generate-scenario: success, 60731ms / solve-scenario: start
# 6) 当天无 push→2026-09-21-1600
cnb build get-build-logs --repo zhenxijs/3dayTest/3day-test \
--createTime 2026-09-21 --endTime 2026-09-21 --page-size 40
# → total: 9,targetRef 只出现 main / 2026-09-21-0000 / 2026-09-21-0800
# 7) 环境可用性反向验证
docker version --format '{{.Client.Version}} / {{.Server.Version}}' # → 29.6.2 / 29.6.2-7
结论:不是 Docker/网络问题,也不存在「已就绪但未被读取」的题; 本轮确实无题可解,已按实情记录而非伪造产出。
六、经验与避坑
stage success≠ 交接物存在(本轮最重要的一条)。 Creator stage 显示success, 60731ms, error: "",但它一个交接物都没产出。 判断「上一 stage 是否真的干活了」,要看产物的可验证痕迹(远端分支、Issue、状态文件), 不能只看 stage 状态。- Solver 报「读不到本轮信息」时,先做五要素判定,再决定动作: 状态文件 → 问题环境目录 → 远端分支 → 历史 Issue → 当天构建记录 / stage 日志。 全空 = 本轮无题,不要硬造。
cnb build get-build-status+cnb build get-build-stage是排查 NPC 流水线的关键工具: 前者给出每个 stage 的status/duration,后者给出精确的startTime/endTime/error。 本轮正是靠它们把 Creator 定位到「61 秒就结束」。cnb build build-runner-download-log能拿到含 NPC 全部 shell 命令的原始日志:--pipelineId <sn>-001(注意是-001这种带 pipeline 序号的 id)。 下载回来是带 ANSI 转义的二进制/文本混合体,用sed 's/\x1b\[[0-9;]*m//g' | tr -d '\000'清洗后再 grep。 这道工序是本轮找到根因的唯一途径。- 「命令序列重复出现」是 agent 重启的指纹:
echo ~ / pwd / cat AGENTS.md / cnb skills list / node -v在00:00:26与00:01:26各出现一次 —— 同一条 bootstrap 序列出现两遍 = 上下文丢失、agent 从头开始。 排查 NPC 异常结束时应优先找这个信号。 scenario/.current-round.json是「不提交」的进程内交接物,生命周期只有「同一工作目录内的相邻 stage」。 任何git checkout/git reset/ 工作区重刷都可能让它蒸发;它不是可靠持久化载体。- 别把「构建是新创建」当成「构建属于本场次」:
createTime是 UTC,本地 UTC+8。2026-09-21T08:00:04Z其实是 16:00:04 CST(本场);2026-09-21T00:00:01Z是 08:00:01 CST。 时区看错一步,结论就反了。 status: pending不能当「已产出」的证据,也不能当「成功构建」引用。- 别把
pipelineTotalCount读成「当天构建条数」:它是单条构建内部的 pipeline 条数 (同一构建的多 job)。数当天条数看列表的total。 - 「有没有
push→<日期分支>构建」是判断 Creator 是否产出的强证据: 正常一轮必有「commit + push 分支」的动作。当天一条都没有 → Creator 根本没跑完。 - Issue 缺位时,结论要走「三级替代通道」,不能悬空: ① 分支上的 commit message → ② 分支内 SOLUTION.md / 经验文档 → ③ 分支评论 / 构建说明。 两条红线:不新建 Issue(题号序列属 Creator 职责,凭空造号会污染序列); 不把结论评论到上一场 Issue(会造成串场)。
- 文档要写「实情」而不是「战果」:本轮没有可解题的环境,就记录诊断链路与加固建议。 伪造一道题再写「修复前后 PASS 对比」,是最坏的做法——它会污染整个经验库的可信度。
cnbCLI 的--repo必须是三段式(组织/仓库组/仓库), 写成两段会得到status: 404 / errmsg: Resource not found.。- Solver 侧不创建/不提交与本轮无关的残留目录:保持
git status干净,便于后续排障。
附:本轮事实快照
| 项 | 值 |
|---|---|
| 运行时间 | 2026-09-21 16:01 CST |
| 触发事件 | crontab: 0 0,8,16 * * *(16:00 场) |
| 当前 stage | solve-scenario(CodeBuddy-Solver) |
| 本场 crontab 构建 | cnb-qu8-1k31flaoe(2026-09-21T08:00:04Z = 本地 16:00:04;pending) |
| Creator stage | generate-scenario:success,60731 ms(≈60.7s),error: ""(16:00:28→16:01:29) |
| Creator 实际动作 | 仅查重调研(28s)→ 静默 32.6s → bootstrap 重启 → 结束;未建分支/环境/Issue |
| 当天构建总数 | 9(3 条 crontab:00:00 / 08:00 / 16:00 场) |
当天 push→2026-09-21-1600 | 0 条 |
| 对照:08:00 场(第72题) | cnb-1pg-1k30k6c21(crontab, success) + push→2026-09-21-0800 ×2 + push→main |
| 本轮 Issue | 不存在(--state open → 仅 #82 第66题) |
| 历史最大题号 | 72(分支 2026-09-21-0800,已完成) |
| 构建地址 | https://cnb.cool/zhenxijs/3dayTest/3day-test/-/build/logs/cnb-qu8-1k31flaoe |
| 当前分支 | 2026-09-21-1600(承载诊断文档的孤儿分支) |
| 本轮状态 | 无题可解(Creator 交接物缺失),仅产出诊断文档 |
| 同型历史 | 2026-09-15-0800(第58题位)、2026-09-20-0800(第70题位),本轮为第 3 次 |
