围栏腐坏是真 bug:@T3@ 是被误提交进仓的代码围栏占位符,Markdown 渲染出 来就是一行 @T3@ 加裸命令。git log -S 定位:842d711e(2026-10-28) SKILL.md 还有 18 个真三反引号围栏行、0 个占位符;21c68521(2026-10-29 插件桥接那笔)起变 0 围栏 / 34 个占位符。全仓只有本技能 6 个文件有此 病,draw-diagram / keil-build / ui-verify 等都用真围栏。本轮七个文件 占位符清零、围栏全部成对。 信息密度:SKILL.md 28,139 → 23,087 B(−18%,占插件写侧上限 65536 的 35%,给自进化留头量)。同一句外置理由在 C2/D/E/F/G/陷阱/验证 重复 7 次 → 0;frontmatter 与 F 节写了两遍的插件桥接说明收进 F 节;「这不是免费 的」「挡给你看的保护」这类修辞删掉。删掉的细节全部落进对应 reference 篇——skill-size 钩子会校验指针不悬空:现 26 处链接 / 8 篇目标 / 悬空 0, 每篇都有入口。 锚点未重排:节号 A–G/C2、各节步骤号、铁律编号被 reference/ 反向引用 (铁律 3/5/7/9 与 A 第 1、5 步,C 第 5~7 步,E 第 1~6 步均结构性存在)。 只在 SKILL.md 出现的 PIPESTATUS 教训保留(reference/ 里没有,删了就丢)。 门禁:check_skill_size.py rc=0(17 个 SKILL.md 全在写侧上限内、无悬空 指针);七文件均无 BOM / CR / U+FFFD、单个尾换行。
7.7 KiB
G. 任务树内跑门禁与审计:输出落点(ci-artifacts)与 SDL2 联接假红
三条硬规矩,全是 2026-10-29 实测付过失败成本的(两起 ENOENT + 一次假红误判):
- 门禁/审计输出只落
<tree>/ci-artifacts/,而新树里它不存在 → 落盘前先mkdir -p。ci-artifacts/被.gitignore忽略(不污染脏行数,E 第 4 步的备份同理),但也因此不会被检出——$TW new出来的树里没有这个 目录。直接fs.writeFileSync("<tree>/ci-artifacts/head-md.md", …)当场ENOENT: no such file or directory, 整段程序零执行(实测:那一轮的门禁体检与快照读取全没跑成,白重跑一次)。用 Node 写之前先fs.mkdirSync(dir, { recursive: true });用 bash 重定向就先单独敲一条mkdir -p ci-artifacts再落盘 ——重定向在命令执行之前解析,目录没建出来时是同一条命令直接失败,后面串着的grep跟着一起报No such file or directory,看着像「门禁没跑出结果」,其实是写错了地方。 cd进任务树之后,../_wt/x.txt不是你以为的地方:cd之后..=_wt,../_wt/x.txt落到_wt/_wt/x.txt(实测就是这么报的)。树内命令的输出一律用树内相对路径(ci-artifacts/xxx.txt); 要绝对路径就写完整绝对路径,跨树取文件用$MAIN/…、$WTROOT/…这种变量打头的全路径, 不靠cd之后的相对层级往上跳。- 任务树内文档门禁按单文件跑;全库
--all基线留到合并后在主树跑。任务树的simulator/SDL2是指向 主树同一份的目录联接(new的第 2/3 步建的),--all会把这份「仓库里的第二份仓库副本」一起扫: 实测任务树里check_doc_links.py --all打检查 222 个文档,35 处问题、RC=1,而 35 处全落在simulator/SDL2联接下、要改的文档一条都没有 → 判红纯属联接带来的假红。单文件检查不受影响 (扫描根就是那一个文件,联接目录不在面内)。主树本身没有 SDL2 时不产生这类假红(联接如实镜像主树, F 节那棵树连 SDL2 都没得联),但别据此认为--all在树内可信。
F="docs/<子目录>/<本次改动的文件>.md" # 本次改动的那一个文件
"$PY" scripts/check_doc_links.py "$F" > ci-artifacts/dl-<slug>.txt 2>&1; echo RC=$?
cat ci-artifacts/dl-<slug>.txt
逐文件跑的实测读数:需求文档 161 处章节引用 / 98% 机器可判定 / rc=0;方案文档 16 处 / 88% / rc=0。
确实要在树内跑 --all 时(例如怀疑主干基线本身),判红顺序固定三步,缺一步都不许下结论:
① 在主树跑同一条命令拿基线;② 过滤掉 simulator/SDL2 联接下的问题行;③ 剩下的与主树基线逐行比。
只跑 --all 见 RC=1 就回「文档门禁挂了」= 把基线噪声算成本任务的账;只跑「过滤后为空」就回「全绿」
= 会漏掉真红。全库 --all 的正解位置是合并后的主工作树:实测合入后在主树跑 check_doc_links.py --all
= 2,597 处章节引用 / 194 个文档 / rc=0 —— 这才证明「就地删叙述」没打断任何引用。
另:不因 --all 的既有假红跳过对本次改动文件的单文件复检(假红是基线的事,你的文件仍要逐个过)。
-
文档改动在树内提交前的固定体检(2026-10-29 实测):
lines / bytes / BOM / CR / U+FFFD / 三连续空行 / 行尾空格 / 末行单个 LF+ 一个自写的 Markdown 表格每行列数一致性检查(数格子前先把转义管道\|还原成占位符, 否则会把\|当成列边界数错)。为什么要自己数:doc-links只管链接与章节、no-mojibake只管编码面, 表格断列与删段留下的三连续空行没有任何钩子会报。 实测读数:需求文档lines=2665 bytes=196137 BOM=false CR=0 U+FFFD=0 tripleBlank=0 trailingWS=0 endLF=true, 表格体检另报两处坏表格(L988-992 counts=5/7、L2472-2486 counts=2/3)——与本次编辑无关的历史行。 所以体检要区分「本次改动 bad=0」与「整份文件 bad=0」:先定位归属再决定动不动手,顺手改别人的区域等于把 没打算提交的内容卷进这笔改动(报告里写「本次改动引入 0 处」,并点名那两处是存量)。 -
提交 / 合并信息一律
-F读文件;清退类任务还要做禁词自检(2026-10-29 两遍实测):消息文件写在ci-artifacts/(被忽略 → 不污染脏行数),UTF-8 无 BOM、CR=0、标题 ≤100 字符、正文每行 ≤80(实测标题 31 / 32 字符、 正文最长行 50 / 55)——-m会把中文按终端代码页转码搞坏,长中文标题还容易撞 gitlint。硬自检:
git log -1 --pretty=%B | grep -c '485' # 被清退主题的关键词:必须是 0
git log -1 --pretty=%B | grep -ci '\bDE\b' # 同主题的次要关键词:同样 0
关键词不许出现在标题、正文、合并信息任何一处(实测标题改写成「删除与本方案无关的其它串口通道对照内容」这种
语义短语替掉了它)——否则「别让我看到 X」这条要求在 git log 里当场破产。合并信息是另一份文件:
ci-artifacts/merge-msg-<slug>.txt 落盘后同样 grep 一遍再 git merge --no-ff --no-edit -F(C2 第 3 步)。
自审发现消息里的行数 / 统计算错而尚未推送 → git commit --amend -F <改好的文件> 就地修(实测就这么修掉一次
off-by-one);别追加一笔「更正」提交——那等于把禁词和被更正的错数一起写回历史。
6. 合并提交期 pre-commit 只查冲突文件(2026-10-29 实测):合并那一次提交的钩子日志首行是 [INFO] Checking merge-conflict files only.,其余钩子全打 (no files to check) Skipped —— 于是「合并提交通过了 30 项钩子」这句话只覆盖冲突文件,别拿它当全量绿。正解:合并落主干后立刻在主工作树跑全量 scripts/ci_local.py(静态 + 提交信息 + 主机侧单测 + manual 段),实测全量这一步才会抓到「表格断列」「章节引用悬空」这类跨文件问题。合并解冲突时若上游把 Markdown 表格重排过,注意单元格里的竖线必须写成反斜杠竖线(先例 docs/子系统设计/运行与自检记录设计说明.md 的 FA_WRITE\|FA_SEEKEND),否则 FA_WRITE|FA_OPEN_APPEND 会被当列分隔符打断,而 doc-links 不查表格列数——要自己数(第 4 条)。
7. 跨层改动拆不成「按层分笔」提交(2026-10-29 实测,四笔改一笔):钩子看到的世界 = HEAD + 本笔 staged——pre-commit 会 stash 已跟踪文件的未暂存改动,而未跟踪文件不在 git diff-index 里、不会被藏(git add -N 也救不了,pre-commit 会把它撤下索引、文件仍在盘上)。后果:把双端登记(MDK-ARM/*.uvprojx / simulator/CMakeLists.txt)、生成器产物、互锁引用的文档分到别的笔里,本笔必被 doc-links(引用了还没入册的小节)、registration-check(源文件登记在另一笔)、generated-fresh(#page= 找不到页面描述符、字库清单与源不一致)、mem-numbers(受管区还是旧 .map 的数)四道整仓门禁一起拦。判据:一笔提交必须自洽——互锁的改动(代码 + 登记 + 生成物 + 文档)走同一笔;机制与三条处置结论(半成品要么先落地要么先挪出工作树)→ docs/代码规范/pre-commit使用说明.md §2「stash 覆盖面」。