朕喜技术(ZhenxiJS)
2026.09.20
1 分钟阅读

CNB 流水线 Solver「读不到本轮信息 / 没有题」怎么排查:scenario/.current-round.json 不存在、scenario/ 只有 .gitkeep、当天无 push→日期分支

日期:2026-09-20 08: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 交接、.current-round.json、孤儿分支、构建 pending、cnb build get-build-logs、cnb issues list-issues 一句话结论:Solver 报「读取不到本轮信息」时,先别急着解题 —— 用「状态文件 + 问题环境 + 远端分支 + 历史 Issue + 当天构建记录」做五要素判定; 全空时要如实记录诊断,而不是硬造一题刷成交。


一、问题背景

本仓库是「每天 3 个计算机实战问题」的自动化训练闭环。.cnb.yml 里一条定时流水线每天 3 次(00:00 / 08:00 / 16:00)触发:

main:
  "crontab: 0 0,8,16 * * *":
    - name: scenario-daily-round
      stages:
        - name: generate-scenario   # Stage 1:CodeBuddy-Creator 出题
          type: npc:go
        - name: solve-scenario      # Stage 2:CodeBuddy-Solver 解题
          type: npc:go

两个 stage 共享同一个工作目录。Creator 通过写一个不提交的状态文件把本轮信息交接给 Solver:

{"branch":"2026-09-20-0800","issue":70,"scenario_dir":"scenario/2026-09-20-0800","topic":"..."}
# 路径 scenario/.current-round.json,已在 .gitignore 中被忽略

2026-09-20 08:00 场轮到 Solver(solve-scenario)启动时,典型症状:

  • cat scenario/.current-round.json → No such file or directory
  • ls -A scenario/ → 只有 .gitkeep
  • git branch --show-current → main(不在任何日期分支上)
  • git ls-remote origin 'refs/heads/2026-09-20-0800' → 空

Solver 面对的是「空手接活」。先判断这是不是异常,再决定怎么做。


二、复现步骤(诊断命令,可原样照跑)

全部命令在 CNB 流水线容器内执行,cnb CLI 已登录(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 | grep 2026-09-20

实测输出:

23b0432369985fc60be5483555c117f90b02dd53    refs/heads/2026-09-20-0000

→ 当天只有 2026-09-20-0000(00:00 场,第69题,已完成)—— 没有 2026-09-20-0800。

3. 历史 Issue / 本轮 Issue、历史最大题号

# 本轮(0800)Issue 是否存在
cnb issues list-issues --repo zhenxijs/3dayTest/3day-test \
  --page-size 5 --order-by=-created_at --state open
# → total: 1(只有 #82 第66题 2026-09-19-0000,与本轮无关)

# 历史最大题号
cnb issues list-issues --repo zhenxijs/3dayTest/3day-test \
  --page-size 6 --order-by=-created_at --state closed

实测输出(截取):

total: 79
- number: "85"  title: 【实战题·第69题】…(2026-09-20-0000)  created_at: "2026-09-19T16:31:35Z"
- number: "84"  title: 【实战题·第68题】…(2026-09-19-1600)
- number: "83"  title: 【实战题·第67题】…(2026-09-19-0800)

→ 历史最大题号 = 69(#85)。没有 2026-09-20-0800 的 Issue,08:00 场的题从未发布。

4. 关键:当天的构建记录

cnb build get-build-logs --repo zhenxijs/3dayTest/3day-test \
  --createTime 2026-09-20 --endTime 2026-09-20 --page-size 30

实测输出(关键字段,快照 total: 5):

- sn: cnb-6h8-1k2u1ppcc
  createTime: "2026-09-20T00:00:06.000Z"      # = 本地 08:00:06
  status: pending  duration: 3207000          # ≈ 53.5 分钟(运行中)
  event: "crontab: 0 0,8,16 * * *"            # ★ 本场定时构建(就是当前这条)
  targetRef: main
- sn: cnb-mq4-1k2t8a2le
  createTime: "2026-09-19T16:34:36.000Z"  status: success  event: push  targetRef: main
- sn: cnb-eho-1k2t89fpl
  createTime: "2026-09-19T16:34:17.000Z"  status: success  event: push  targetRef: 2026-09-20-0000
- sn: cnb-unp-1k2t8463p
  createTime: "2026-09-19T16:31:23.000Z"  status: success  event: push  targetRef: 2026-09-20-0000
- sn: cnb-2ug-1k2t6bkqa
  createTime: "2026-09-19T16:00:31.000Z"  status: success  duration: 2126504   # ≈ 35.4 分钟
  event: "crontab: 0 0,8,16 * * *"            # ★ 00:00 场定时构建
  targetRef: main

读法(三个坑都在这):

  1. createTime 是 UTC,本地是 UTC+8:2026-09-20T00:00:06Z 实际是 08:00:06 CST,正是本场。
  2. 当天 total: 5 里只有两条 crontab 定时构建:cnb-2ug-1k2t6bkqa(00:00 场)与 cnb-6h8-1k2u1ppcc(08:00 场,当前);另三条是 push 触发的质检/文档构建。
  3. 所有 push 构建都指向 2026-09-20-0000 或 main,没有一条指向 2026-09-20-0800 —— 平台侧证明:08:00 场的 Creator 从未 push 过任何东西。

5. 交叉验证:正常一轮应留下 push→日期分支 痕迹

cnb build get-build-logs --repo zhenxijs/3dayTest/3day-test \
  --createTime 2026-09-19 --endTime 2026-09-19 --page-size 30
# → total: 12,可见每场次的三段式:crontab → push→<日期分支> → push→main

实测(截取):

2026-09-19T00:00:04Z  crontab  →  cnb-hoo-1k2rfd0fn(00:00 场)
2026-09-19T00:10:50Z  push     →  2026-09-19-0800
2026-09-19T00:15:52Z  push     →  2026-09-19-0800
2026-09-19T08:00:01Z  crontab  →  cnb-4sg-1k2sarqs7(08:00 场)
2026-09-19T08:58:41Z  push     →  2026-09-19-1600

→ 正常一轮必然留下 push→<日期分支> 的痕迹。今天 08:00 场完全没有,与「Creator 未产出」一致。

6. 顺带确认 Docker 可用(排除「环境没起来」)

docker version --format '{{.Client.Version}} / {{.Server.Version}}'
# → 29.6.2 / 29.6.2-7   正常

三、根本原因

本轮(2026-09-20-0800)的 Creator 阶段没有产出任何交接物。

五要素交叉验证:

检查项期望实测判定
scenario/.current-round.json存在且含 branch/issue不存在❌
scenario/2026-09-20-0800/README + Dockerfile + compose + 代码只有 .gitkeep❌
远端分支 2026-09-20-0800存在不存在❌
Issue「第70题(2026-09-20-0800)」已发布不存在(最大 #85 = 第69题/0000)❌
平台构建痕迹有 push→2026-09-20-0800无❌

机制推断(与前一轮 2026-09-15-0800 的「第58题位」同型):

两个 npc:go stage 共享同一工作目录,而 Creator 的交接物 (scenario/2026-09-20-0800/、.current-round.json)在 push 之前只活在这块目录里, 且 .current-round.json 还被 .gitignore 忽略、永远不进版本库。 一旦本场 Creator 未执行到「commit + push + 发 Issue」,或工作区被重置、被并发实例覆盖, 本轮的题、分支、Issue 就会同时归零且无任何残留 —— Solver 只能空手。

本场跑到 08:53(duration ≈ 53.5 min)仍未结束,00:00 场也跑了 35.4 分钟; 单轮耗时长,一旦某场超时,就会被后续场次追尾。

一句话:Solver 读到「空手」=「本轮 Creator 未产出」+「共享工作目录未留任何可查痕迹」的组合结果。

⚠️ 这不是某道题的解答,也不是「某道题挂了」,而是流水线 stage 交接机制的可靠性缺陷。


四、解决办法

1) 本轮处理方式(对工作负责的姿势)

  1. 不发明题号、不硬造题目、不改历史产物:
    • 不臆造「第70题」并编造一套假环境 —— 那样写出的 SOLUTION / 经验文档是脱离真实环境的伪证据, 会污染整个经验库的可信度;
    • 不动 2026-09-20-0000(第69题)的任何文件。
  2. 只沉淀「诊断过程本身」:可复现命令链 + 实测输出 + 判定表(就是本篇)。
  3. 给结论留落点:本轮 Issue 不存在,走「分支内文档 + commit message」通道(见第六节)。
  4. 指出缺陷位置,便于配置侧加固。

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:给交接文件加「新鲜度」字段,防跨场次串读

.current-round.json 增加 created_at / run_id,Solver 校验其是否等于本次运行, 避免读到上一场遗留的文件。

建议 3:加流水线互斥锁,消除并发撞车

lock:
  key: scenario-daily-round
  wait: false

建议 4:交接物双保险

状态文件不提交、极脆弱。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-20-0800                 # → 空
# 4) 无本轮 Issue(历史最大 #85 第69题)
cnb issues list-issues --repo zhenxijs/3dayTest/3day-test --page-size 5 --order-by=-created_at --state open
# → total: 1(仅 #82 第66题)
# 5) 当天两条 crontab 构建,无 push→2026-09-20-0800
cnb build get-build-logs --repo zhenxijs/3dayTest/3day-test --createTime 2026-09-20 --endTime 2026-09-20
# → total: 5(crontab×2 + push×3,push 均指向 2026-09-20-0000 / main)
# 6) 环境可用性反向验证
docker version --format '{{.Client.Version}} / {{.Server.Version}}' # → 29.6.2 / 29.6.2-7

结论:不是 Docker/网络问题,也不存在「已就绪但未被读取」的题; 本轮确实无题可解,已按实情记录而非伪造产出。


六、经验与避坑

  1. Solver 报「读不到本轮信息」时,先做五要素判定,再决定动作: 状态文件 → 问题环境目录 → 远端分支 → 历史 Issue → 当天构建记录。 全空 = 本轮无题,不要硬造。
  2. scenario/.current-round.json 是「不提交」的进程内交接物,生命周期只有「同一工作目录内的相邻 stage」。 任何 git checkout / git reset / 工作区重刷都可能让它蒸发;它不是可靠持久化载体。
  3. 别把「构建是新创建」当成「构建属于本场次」:createTime 是 UTC,本地 UTC+8。 2026-09-20T00:00:06Z 其实是 08:00:06 CST。时区看错一步,结论就反了。
  4. status: pending 不能当「已产出」的证据,也不能当「成功构建」引用。
  5. 别把 pipelineTotalCount 读成「当天构建条数」:它是单条构建内部的 pipeline 条数 (同一构建的多 job),与当天有多少条构建记录是两个维度。数当天条数看列表的 total。
  6. 「有没有 push→<日期分支> 构建」是判断 Creator 是否产出的强证据: 正常一轮必有「commit + push 分支」的动作。当天一条都没有 → Creator 根本没跑完。
  7. 时间线自相矛盾就是信号:当「上一场的产物时间」晚于「本场次的触发时间」, 基本可断定存在多实例撞车 / 前一场未结束。
  8. 共享工作目录的 NPC 流水线一定要做并发互斥(lock: { key: ... }), 否则「未提交的进程内状态」会被并发实例互相覆盖,产生「偶发莫名其妙的空手接活」。
  9. Issue 缺位时,结论要走「三级替代通道」,不能悬空: ① 分支上的 commit message → ② 分支内 SOLUTION.md / 经验文档 → ③ 分支评论 / 构建说明。 两条红线:不新建 Issue(题号序列属 Creator 职责,凭空造号会污染序列); 不把结论评论到上一场 Issue(会造成串场)。
  10. 文档要写「实情」而不是「战果」:本轮没有可解题的环境,就记录诊断链路与加固建议。 伪造一道题再写「修复前后 PASS 对比」,是最坏的做法——它会污染整个经验库的可信度。
  11. cnb CLI 的 --repo 必须是三段式(组织/仓库组/仓库), 写成两段会得到 status: 404 / errmsg: Resource not found.。
  12. Solver 侧不创建/不提交与本轮无关的残留目录:工作区若有未跟踪的一次性脚手架(如 .tmpimg/), 不要顺手提交,也不要据此推断题号;保持 git status 干净,便于后续排障。

附:本轮事实快照

项值
运行时间2026-09-20 08:53 CST
触发事件crontab: 0 0,8,16 * * *(08:00 场)
当前 stagesolve-scenario(CodeBuddy-Solver)
本场 crontab 构建cnb-6h8-1k2u1ppcc(2026-09-20T00:00:06Z = 本地 08:00:06;pending,≈53.5 min)
当天构建总数5:cnb-6h8-1k2u1ppcc(crontab 08:00) + cnb-2ug-1k2t6bkqa(crontab 00:00) + cnb-mq4-1k2t8a2le(push→main) + cnb-eho-1k2t89fpl/cnb-unp-1k2t8463p(push→2026-09-20-0000)
对照:00:00 场构建cnb-2ug-1k2t6bkqa(2026-09-19T16:00:31Z = 本地 00:00:31,success,≈35.4 min)
本轮 Issue不存在(--state open → 仅 #82 第66题)
构建地址https://cnb.cool/zhenxijs/3dayTest/3day-test/-/build/logs/cnb-6h8-1k2u1ppcc
当前分支2026-09-20-0800(承载诊断文档的孤儿分支)
历史最大题号69(Issue #85,分支 2026-09-20-0000,closed)
本轮状态无题可解(Creator 交接物缺失),仅产出诊断文档

版权声明

本文为博主原创文章,遵循 CC BY-NC-SA 4.0 许可协议。 转载请注明出处:http://localhost/blogs/2026-09-20-0800-cnbcreator-solver

分享这篇文章