docs(skills): 收录陈旧计数同步流程 + 补台账回填动作 + 去掉技能文里自伤门禁的裸形

三只 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 / 结尾换行齐。
This commit is contained in:
2026-10-27 09:11:18 +08:00
parent c457da0210
commit 251268992e
3 changed files with 289 additions and 7 deletions
+87 -3
View File
@@ -1,7 +1,7 @@
---
name: task-worktree
description: 多任务并行开发的空间管理(git worktree 生命周期):new 开一棵工作树 + 任务分支、目录联接共享 .venv 与模拟器 SDK、活跃任务硬上限 3 与腾位、build/bench 两类独占锁(含非登记任务占锁后「缺台账」释放不掉的正解)、done 预演合并回主干、门禁未全绿的补基线收尾、并集合并残留审计。规格见 docs/环境与部署/并行任务工作树方案.md。
whenToUse: 要同时推进多个任务、担心同分支同文档互相冲突;要为新任务开一个隔离空间;要把任务合并回主干;或遇到 `new` 报「已有 3 个活跃任务(上限 3)」、`lock release` 报「任务 X 不存在(缺台账)」、`done` 报「门禁未全绿:工作树与分支保留,未清场」、两个任务抢 COM6 / UV4、"改了文档被覆盖"、并集合并残留时。
description: 多任务并行开发的空间管理(git worktree 生命周期):new 开一棵工作树 + 任务分支、目录联接共享 .venv 与模拟器 SDK、活跃任务硬上限 3 与腾位、build/bench 两类独占锁(含非登记任务占锁后「缺台账」释放不掉的正解)、done 预演合并回主干、门禁未全绿的补基线收尾、并集合并残留审计,以及**把仓外 detached worktree 当净室测量仪**——门禁指标异常增长时一次只注入一份在飞文件、与基线差分做逐文件归因。规格见 docs/环境与部署/并行任务工作树方案.md。
whenToUse: 要同时推进多个任务、担心同分支同文档互相冲突;要为新任务开一个隔离空间;要把任务合并回主干;或遇到 `new` 报「已有 3 个活跃任务(上限 3)」、`lock release` 报「任务 X 不存在(缺台账)」、`done` 报「门禁未全绿:工作树与分支保留,未清场」、两个任务抢 COM6 / UV4、"改了文档被覆盖"、并集合并残留时;或**门禁指标异常增长(如 id-check 的不可判定数从 1,162 涨到 1,178、+16)却查不出是哪个文件 / 哪条任务道造成的**、主工作树压着多条在飞改动而不许 stash / 提交 / 改门禁脚本、要按 HEAD 基线只读出像验收时。
---
# task-worktree — 多任务并行开发空间(短命令 `@task`)
@@ -75,7 +75,7 @@ PY=".venv/Scripts/python.exe"; TW=".dsh/skills/task-worktree/scripts/task_worktr
`conflict` 字样的片段 → 据此误判「有冲突」。实测:`tail -2` 误读成 conflict,放宽到 `tail -10` 才看到
`[ok] 无冲突,预演结果树 <sha>`。dry-run 全文只有 5~8 行,直接读全量。
## 分步操作(三条运行时机制)
## 分步操作(四条运行时机制)
### A. `new` 被拒「已有 3 个活跃任务(上限 3)」——怎么腾位
@@ -179,6 +179,65 @@ git commit -F <UTF-8 无 BOM 的正文文件> # 提交属 Ask first(AGENTS.m
7. 清场完成后再敲一次 `done <ID>` 会得到 `前置/环境错误:任务 <ID> 不存在(缺台账 …json)`(exit 2)——
**这不是失败**:清场的最后一步 unlink 了台账。判完成以 `git log` 为准。
### D. 门禁指标异常增长 → 逐文件归因(把净室工作树当**测量仪**,主树全程只读)
**场景**(2026-10-27 实测):`id-check` 突然 FAIL「不可判定 1,178 > 上限 1,166」——比上一轮量到的 1,162 又涨了 **+16**,
而主工作树里同时压着 4 条在飞任务道的未提交改动。**不许 stash / checkout / reset**(那是搬动甚至丢弃别人未提交的工作,
项目级 Never;`git status` 一乱,整条道的现场就没了),**不许改门禁脚本本身**(它就是那把尺子,改了数字就不可信),
**也别在脏主树里跑门禁**(那测的是 4 条道 + 未跟踪文件的混合体,永远分不出谁)。正解:**在仓库之外另起一棵
detached HEAD 的干净工作树当净室,一次只往里注入一份在飞文件**,与基线差分即得每个文件的独立贡献。两步:
**净室建树 → 单文件注入测量**。
1. **建净室 + 先落基线数**(路径必须**在仓库目录之外**;铁律 7 对临时树同样成立——放仓内就污染 `git status` /
`pre-commit --all-files` / 全库搜索):
```bash
MAIN="D:/Code/DTU Code/STM32F4-Base" # 主工作树绝对路径(含空格 → 变量整体加引号)
WT="$MAIN/../_wt/und-attr" # 仓外同级 _wt/ 下;一次测量固定用同一个名字
rm -rf "$WT" 2>/dev/null
git -C "$MAIN" worktree add --detach "$WT" HEAD >/dev/null 2>&1 || { echo WT_FAIL; exit 9; }
git -C "$WT" status --porcelain # 应为空
"$PY" "$WT/scripts/check_ids.py" 2>&1 | tail -25 # ← TODO 口径:以 .pre-commit-config.yaml 里 id-check 钩子的 entry/args 为准;基线与注入用**同一条命令**
```
- `--detach`(**不要 `-b`**):净室没有分支、不写 `_wt/.state/<ID>.json` 台账 → **不占 `MAX_CONCURRENT = 3`
名额、不出现在 `$TW list`**,也没人会被误指去对它跑 `done`(建与拆都不走 `$TW new` / `$TW done`)。
- 能这么量的前提:该门禁**只读仓库内文本**。依赖本树构建产物的门禁(`mem-numbers` / `mem-budget` 要 `.map`)
在净室里必然报「找不到 .map 事实源」(见陷阱「新建工作树从未构建过」)——**那类指标不能这么归因**。
- `git status --porcelain` 非空 = 有别人的未跟踪文件被带进净室 → 先 `git clean -xdn` **干扫**(别去 `n`)
看清会删什么,只挪走多出来的那些再测;语料被污染出来的数字与 CI 不可比。
2. **一次只注入一份在飞文件 → 跑同一个扫描器 → 与基线差分**(得到的是每个文件的**独立**贡献,不是合计):
```bash
for f in "App/log/sys_log_mcu.c" "test/host/sys_log_mcu/sys_log_mcu_test.c" "docs/子系统设计/运行与自检记录设计说明.md"; do
mkdir -p "$WT/$(dirname "$f")"
cp "$MAIN/$f" "$WT/$f" # 拷进净室;主树那份只读、一字节不动
echo "== $f =="; "$PY" "$WT/scripts/check_ids.py" 2>&1 | tail -25 # ← 与第 1 步同一条命令
git -C "$WT" checkout -- "$f" # 只还原净室里自己刚拷进来的那份
done
```
实测:`run_par.c` / `board_ui_nav.py` / `check_nested_comment.py` / keil `SKILL.md` **各 +0**,
而 log 道那三个文件 **+6 / +8 / +2**,合计**正好 +16**。**Σ(逐文件增量) ≠ 观察到的涨幅 → 还有没被注入的
在飞文件,或存在文件间交互项**,不许就此交卷。
3. **定性增量是哪一类字面量**(只有「谁」没有「为什么」= 给不出可执行的改法):同一计数器在 **HEAD 版**与
**在飞版**各数一遍,**差值才是新增行带来的**(存量的不算这条道的账);再对新增行直接 grep。本次 16 处全是
**裸形 「字母 T 累进数字 4」**(`T` 在 `scripts/id_registry.json` 的 `bare_check_letters` 里,规范形态是连字符形),
全部落进 `skip_bare_unmanaged` —— 到这一步结论才配发给属主。
4. **闭合 + 复验主树一个字节没被污染**:
```bash
git -C "$MAIN" worktree remove --force "$WT" # 净室里只有自己的拷贝、没有原件,--force 安全
git -C "$MAIN" worktree list # 不该再有 und-attr
git -C "$MAIN" status --porcelain | sort # 与测量前**逐行一致**(测量前先存一份基线清单)
```
「增量 + 字面量类别 + 属主」三者齐了才算归因完成。**同一条道自己「我自查过不是我们」的结论别直接采信**
→ 陷阱「队友的自查结论要复核」。
**同一棵净室树的第二种用法**:按指定 commit **只读**构建出像 / 烧录验收——不搬动任何在飞改动,也不为台架
提前抢发一笔提交;构建与烧录都在这棵树里做(不在主树),仍受 `bench` / `build` 锁串行(铁律 3)。
## 铁律
1. **`done` 只能在主工作树执行**——主干分支检出在主工作树,git 不允许同一分支在两处检出。
@@ -247,6 +306,28 @@ git commit -F <UTF-8 无 BOM 的正文文件> # 提交属 Ask first(AGENTS.m
可能留下指向已删目录的死规则或重复条目。脚本会自动报「双方都改过」的文件清单 +
连续重复行;**权威判据是 base / 两个 tip 三方对比**(`git show <ref>:<file>` 逐项 `grep -F`),
别用 `tail -N` 目测。
- **⚠ 别用 heredoc 打补丁改门禁脚本造探针**(2026-10-27 实测三连败,白烧一整轮):heredoc 里的 python
把门禁脚本改坏——`patched 3` 之后 `PROBE_RC=1`、`SyntaxError: unterminated string literal (detected at
line 882)`,而它**正是被测对象**,改完的数不可信;另一处 `replace('\\', '/')`(想把 Windows 反斜杠换成正斜杠)里的反斜杠被多层引号吞掉
→ `SyntaxError (detected at line 16)`。**正解**:探针落成**独立 `.py` 文件**(写文件的工具,UTF-8 无 BOM)
再 `"$PY" probe.py`;非用 heredoc 不可就用单引号定界 `<<'PY'`(防变量展开),且**路径一律 `as_posix()`、
一个反斜杠都不写**——反斜杠字面量要穿「JS 模板串 → bash → shell 引号 → python」四层,必被吞。
- **取门禁数字:import 门禁模块,别猜输出、别打补丁**(2026-10-27;grep 源码 / 手抄正则 / 解析 stdout 三种姿势
都拿不到可复核的数,换成这句立刻拿到):先读门禁脚本的 `main()`(直读末尾那几十行)看它怎么装配检查器,
把**那几行照抄**进探针——`sys.path.insert(0, 'scripts')` → `import check_ids as ci` →
`ci.load_json(ci.REGISTRY_FILE, 'reg')` + `ci.load_json(ci.ALIASES_FILE, 'alias')` →
`ck = ci.Checker(reg, al, verbose=False)` → `ck.run()` → `print(ck.stats)`。别猜键名:先
`print(sorted(ck.stats))` 列出全量计数项,再按精确键取数(顺带 `git diff` 确认门禁脚本自己**没被改过**)。
- **别把「不可判定」当成一个数**(2026-10-27):`id-check` 有两种口径——检查器自己算的**硬不可判定**实测只有
**2** 处,而门禁红线(`scripts/id_registry.json` 的 `undecidable_total_ceiling`)量的是**派生值**
`refs_total - decidable`(实测 8,744 - 7,582 = **1,162**,拆开 = `skip_bare_unmanaged` 834 +
`noise_allowed` 326 + 硬不可判定 2,**三数精确闭合**)。所以**带属主登记处的族(TC-XXX 这类)加多少引用都算
「可判定」、一点不吃这条余量**,真正吃余量的是**裸形字母+数字**字面量;反过来「把可判定引用改写成散文」才是
**稀释比值**的动作,那才是绝对数红线要防的。口径混用会当场给整条道下错指令(本次就下错过、量完立刻撤回)。
- **队友的自查结论要复核,小心它测的是错变量**(2026-10-27):log 道做过受控实验、结论是「我们没推高这个数」——
他们改的是 TC 号、盯的是 `skip_bare_unmanaged`,那个组合当然不动;而 +16 走的是另一条路(新增裸形 「字母 T 累进数字 4」)。
定责用 D 节:逐文件注入 + HEAD/在飞两版同一计数器相减 + 对新增行 grep;闭合后 +16 = 16 处裸形 「字母 T 累进数字 4」,
**推翻**了自查结论。口头自查与 `--note` 都不是证据,**可复核的差分数字才是**。
- **`.workbuddy-ai/` 刻意不共享**:记忆不随任务分叉,也不给联接递归删除的机会。
任务工作树自己的记忆由 `done` / `abort` 在清场前归并回主工作树。
- **`--lean` 只省磁盘不省时间**:实测全量 smudge 7.25 s / 83 MB,跳过 smudge 7.05 s / 45 MB,
@@ -273,6 +354,9 @@ git commit -F <UTF-8 无 BOM 的正文文件> # 提交属 Ask first(AGENTS.m
- `git log --oneline -3`:能看到 `merge: task/<ID>-<slug> 合入 <base>` 与其后的补基线提交;
`git status --porcelain` 为空(补链改动已提交,才谈得上重跑 `done`)。
- `ls _wt/.state/`:该 ID 的台账已无(清场最后一步 unlink);重复 `done` 报「任务不存在」不必再追。
- D 节归因:测量前后 `git -C "$MAIN" status --porcelain` **逐行一致**(主树全程只读);
`git worktree list` 里净室路径已消失;逐文件增量之和 **等于**观察到的涨幅(实测 +6+8+2 = +16),且每处增量
都指到具体字面量类别(裸形 「字母 T 累进数字 4」)与属主;取数走 `import check_ids` 读 `ck.stats`,且门禁脚本自身 `git diff` 为空。
- 补绿链的每一条都自己 `echo RC=$?` 看到 0,最后以重跑 `done` 打出的**清场日志**(`已摘除联接` /
`已删除分支` / `完成(分支此前已合入)`)为成功判据,而不是 `tail` 出来的最后一行。