三只 skill 文件收口(队友写成,Lead 核后入库): · 新增 `stale-doc-count-sweep`:把今天做的「一个事实数变了之后全仓同步」钉成流程——从权威来源**实测**真值 → 全形态扫描并**逐条分类**(当前态改 / 变更记录历史行只加当日新行 / 同数不同义的误报不动 / 带日期戳的 测量只加「当时」锁口径)→ 逐条字面替换且每处断言命中数 → 被改文件全文通读核各小节 → 复扫残留归零 → 跑门禁分笔提交。这份流程的价值全在**分类**那步:今天有 5 处「27 → 40」是历史事实、1 处「< 40KB」是同数 不同义(绘制缓冲红线),一并替换就会毁掉它们。 · `mem-budget`:补上 `ram_baseline.py --update`(只往 tsv 追加趋势行)与 `--write`(才同 步台账受管区)的区别、 以及「提交前台账怎么回填」的动作——这个坑是 Lead 本人 05:0x 踩的(用错一枚参数造出一次真的 mem-budget FAIL),写下来比口头转告可靠。 · `task-worktree`:把文中 4 处**自伤**的裸形改成形态描述——该节讲的正是「单字母紧跟数字」这类形态怎么被 校验 2 计数,结果例子自己就是那种形态,等于技能文自己吃门禁余量。改完不可判定绝对数 **982 → 978** (余量 +4),叙述信息量不减:形态与属主都还写清。 ⚠ 这条教训值得单记:**文档在讲某个反模式时,自己不要用那个反模式的字面量**——否则每次读它的人都得替它 付余量。同批 `docs/编号规范.md` §4.4 也已登记这类误判面。 自查:`check_ids --strict` exit 0、不可判定绝对数 978 / 上限 1,166;三文件 noBOM / LF / U +FFFD=0 / 结尾换行齐。
9.1 KiB
name, description, whenToUse
| name | description | whenToUse |
|---|---|---|
| stale-doc-count-sweep | 全仓陈旧计数同步 playbook——某个事实数(黄金参考页数、菜单树叶数、钩子数等)变了之后,从权威来源实测真值 → 全形态扫描命中点并逐条分类(当前态改 / 变更记录历史行只加当日新行 / 同数不同义误报不动 / 带日期戳的测量只加「当时」锁口径)→ 逐条字面替换且每处断言命中数 → 被改文件全文通读核对各小节 → 复扫残留当前态命中归零 → 跑门禁分笔提交。 | 某个计数/数字变了要跨 md/yaml/py 同步、用户说「同步一下 / 全仓改一遍 / 这个页数(叶数、钩子数)不对」、发现文档数字与实测不符、或同一份文档两节数字/顺序对不上要先核口径时。 |
陈旧计数全仓同步
适用:一个事实数变了(黄金参考页数 27→40→47、菜单树叶数、钩子数…),仓库里多处引用它的当前态表述要跟着变,而历史记录、同数异义、带日期戳的测量不能跟着变。
同一流程在本仓已跑过两次(b24b2b5f 27→40、13 个文件;31ca4a1f 40→47、11 个文件)——照下面的序列逐字复跑,别临场重新发明分类。
Steps
-
实测真值,不抄任何二手数字(不抄用户口述、不抄另一处文档)。
cd "<repo>" ls simulator/tests/ref/*.bin | wc -l # 内容页黄金参考页数(唯一判据 = 入库的 shot_*.bin 实数)菜单树叶数这类来源自带口径规则的数,先读来源文件头再计数:
sed -n 1,12p ui_menu_tree.txt # 文件头写明「缩进即层级,每级 2 空格;# 开头为注释;空行忽略」叶子判据 = 不存在更深缩进后继行的行。把「节点行数」「叶子总数」「已绑」「未绑」四个数一次报全,并让
未绑 = 待做 + 不做与分类表逐项闭合。实测量到 42 个节点行、33 个叶子、已绑 21、未绑 12(= 待做 7 + 不做 5)。 -
全形态扫描,一个形态都不许只扫一种写法:
grep -rn --include=*.md --include=*.py --include=*.yaml --include=*.txt \ -E '40 *(页|张|帧|个页面)|内容页.{0,6}40|黄金.{0,6}40' .先列出
文件:行:全文,判定前必须看整行——| cut -c1-120会截掉后半句(那里常写着日期戳或口径)。 -
逐条分类,四类各走各的路(这是本 playbook 的核心,别用一条规则套全部命中):
类别 判定 动作 当前态陈述 描述「现在是多少」 改成实测真值 变更记录历史行 形如「27 → 40 页」的当日事实 原样保留;只在该文件 §变更记录顶部加一行当日的「40 → 47」(含判据与实测来源) 同数不同义 最坏路径 < 40KB这类内存/绘制缓冲红线不动,并在结论里写明「为什么不动」 带日期戳的测量 「2026-10-26 实跑 …覆盖 40 页中的」 不臆改新数,只补「当时」两字锁住口径;新数留待下次实跑回填 拿不准就回到第 2 步把整行打印出来再判;判错历史行 = 把当天事实改写成假账。
-
逐条字面替换,每处断言命中数(弃用整文件正则批处理)。脚本写成临时文件再跑(内嵌 heredoc/模板字符串里的反引号会截断整脚本),按字节替换以保 BOM 与行尾不动:
import pathlib, sys sys.stdout.reconfigure(encoding='utf-8', errors='replace') JOBS = [ # (文件, old, new, 期望命中数) ('AGENTS.md', '内容页 40 页黄金参考', '内容页 47 页黄金参考', 1), ('docs/UI设计/UI_自动化测试流程.md', '该集合现已扩至 40 页', '该集合现已扩至 47 页', 1), ('docs/UI设计/UI_自动化测试流程.md', '文本断言 **310 条**、覆盖 40 页中的', '文本断言 **310 条**、覆盖当时 40 页中的', 1), ] for path, old, new, expect in JOBS: p = pathlib.Path(path); raw = p.read_bytes() o, n = old.encode('utf-8'), new.encode('utf-8') got = raw.count(o) assert got == expect, f'{path}: 命中 {got},期望 {expect}(未写入)' p.write_bytes(raw.replace(o, n)) print(f'OK {path}: {old} -> {new} x{got}')每行打印
old -> new xN,收口时这串输出就是「改了哪几处」的账。脚本报错/没编译过,先git diff --stat确认零写入再换写法(不要在半落地状态上继续叠改)。 -
被改文件全文通读,核对其余小节——不是只看 diff。检查同一文档内互相引用的小节(典型:
docs/任务规划/README.md§1 当前执行表 vs §2 全项目顺序表;UI补齐.md§1 口径 vs §2 清单):顺序、计数、完成状态必须一致。若发现上一笔自己写进文档的数口径就错了(例如把 42 个节点行当叶子数写成「未绑 21 叶」),明确认错并改正,同时把可复核的重算方法写进文档(「按缩进判叶子:有更深缩进后继者即非叶子」),防止再错。 -
复扫残留,排除历史行与误报后,当前态命中必须为 0:
grep -rn --include=*.md --include=*.py --include=*.yaml -E '40 (页|张)|40 个内容页' \ AGENTS.md .pre-commit-config.yaml docs scripts | grep -v '27 → 40'剩下每一条都要能说出归属(历史行 / 误报 / 已加「当时」)。说不出来的就是漏改。
-
跑门禁,分笔提交(
git commit属 Ask first,须用户明确指示后再做):./.venv/Scripts/python.exe scripts/check_doc_links.py --all ./.venv/Scripts/python.exe scripts/ci_local.py # 或 pre-commit run --files <被改文件>PowerShell 形态把
./.venv/Scripts/python.exe换成& '.venv\Scripts\python.exe'。提交信息正文长,一律git commit -F <UTF-8 无 BOM 文件>,别用-m(中文长标题易超 100 字符、终端代码页会转码)。一笔只装一类事:计数同步一笔、口径/登记簿修正一笔。提交说明如实写(如「先认一笔自己的错:上一笔的未绑 21 叶是探针错」),别把口径修正写成「补充说明」。
Pitfalls
- 照抄用户给的数:用户说「从 40 扩到 47」也要自己数
ref/*.bin;数出来不一定是 47。真值只认权威来源实测。 - 把节点行当叶子数:42 是
ui_menu_tree.txt的节点行数,33 才是叶子;文件头写着「缩进即层级」,不读规则就数错(实测把错数写进两份文档,下一轮才自查出来)。 - 整文件正则批处理:第一次尝试的正则没编译过、整批零落地。改法 = 逐条字面替换 + 每处
assert count == expect,宁可慢也要每处可审计。 - 反引号截断:脚本里含
ui-golden、#page=这类反引号时,经 TS 模板字符串/内嵌 heredoc 传递会被截断,表现为「整批零落地」。把脚本落成文件再执行,或用chr(96)/String.fromCharCode(96)拼。 - 只改记得的那节:上一笔只改 §2 与开篇、漏改 §1,用户当场问出「§1 说 16 叶、§2 说剩 3 项,自相矛盾」。改完必须全文通读同一文档的所有小节。
- 历史行被当陈旧值改掉:变更记录里的「27 → 40」是当天事实,改了就是伪造历史;正确动作是另加当日新行。
- 误报跟着改:「< 40KB」是绘制缓冲红线,与页数无关,改了就是引入错误。
- 带日期戳的测量臆改新数:「2026-10-26 实跑取数 …覆盖 40 页」改成 47 就是把历史测量冒充现值;只加「当时」。
- 用截断的 grep 输出判定:
cut -c截掉的后半句常含日期戳/口径,据此分类必错。 - 新写文本撞编号门禁:新增的「单字母+数字」裸形(如
SD2506、CP56Time2a)会把id-check的不可判定引用绝对数推高(实测 1156 → 1161,上限只剩 5)。收尾看门禁输出的und计数,涨了先把自己这批文本逐处归因,别去放宽noise_literals。
Verification
提交前逐条打勾:
- 真值来自本轮实测命令的输出(
ref/*.bin计数 / 按来源规则重算的叶数),并在结论里贴出该数字 - 分类表逐条列出:改了哪些当前态、哪些历史行保留、哪些误报不动(附理由)、哪些只加「当时」
- 替换脚本打印了每处
old -> new xN,且每处assert通过(无半落地状态;报错时已确认零写入) - 被改文件已全文通读,同文档各小节(§1/§2)与配套 README/清单的顺序、计数一致;口径闭合(如
未绑 = 待做 + 不做) - 复扫输出中当前态残留 = 0,每条剩余命中都能归类
check_doc_links.py --all打印「文档路径检查通过(N 个文档)」;ci_local.py/pre-commit全绿(passed=N failed=0、RC=0)- 分笔提交完成,回报 commit 号 + 每笔改了哪些文件 + 没动的那几类及理由