fix(scripts): rename_ref 搬整目录不再改脏目录内部内容,并补齐出链层级

2026-10-30 测试说明分层那次(28 个路径、209 文件)实测踩到两条,都是
「把不该改的东西改脏」,当时的补救全靠事后从 git 里捞原始字节:

B1 整目录搬迁会改写目录内部文件的内容。「相对引用文件所在目录」这条
    解析规则不检验目标是否存在,于是台架日志里不是路径的斜杠片段被当成
    「旧目录下的子路径」并插上目录名:`1/1 PASSED` → `test_data/1/1 PASSED`、
    `13639/32768`、日期占位 `[----/--/-- --:--:--]` 全中招,连有效的
    `see ../a.md` 也被换成指向不存在的 `see td/a.md`。23 个证据文件是
    用 `git show HEAD:<旧路径>` 逐字节还原才救回来的。
B2 目录内部文件指向外部的 `../` 出链不补层级。emit_dir 取的是
    `new_abs.parent`,整目录搬迁时少算一层,`../images/x.svg` 搬深一层后
    仍指旧层级;图片按文档目录相对(§3.2),check_doc_links 看不见 → 静默断链。

改法(尽量小面):
- resolve_token:按引用文件目录解析时要求目标真存在;根相对写法保持原宽松口径。
- rewrite_text:moved 文件的 emit_dir 改成「本文件搬完实际所在的目录」;
  单文件搬迁走原分支,一字未动。
- 整目录搬迁时目录内部互为相对的引用一律不改(两侧一起搬,改了必错);
  「旧路径是不是目录」必须在搬迁前记进 old_is_dir_global——--apply 是先
  git mv 再改写,那时旧路径已经不存在了。
- glob 形态改成看得见:搬目录时前缀整体跟着搬(本来就该改);搬单文件时
  一条 glob 可能同时盖住搬走与没搬走的两批文件,不猜,只点名列出。
  分层那次有 4 处这种引用是静默漏改、事后手改的。

回归:新增 `--selftest`(在一次性临时 git 仓里跑本脚本的副本,`.gitignore`
先排除 /scripts/ 免得脚本自己进扫描面)。案例 A 守整目录搬迁(证据文件
逐字节不变、出链补层、别人文件的入链照改、glob 前缀跟着搬),案例 B 守
单文件搬迁的层级换算与 glob 提示,18 项断言全绿。反向对照也做了:同一
夹具在改前版本上 B1/B2 都复现,所以断言不是凭空写的。

文档同步:docs/文档规范.md §3.6 第 4/5 条从「现存危害」改写成「已修 +
验收判据」,新增第 6 条 glob 提示,并加「改本体必须先跑 --selftest」;
docs/测试说明/README.md 第 3/5 节口径同步;scripts/README.md 补 --selftest
与任务树 --no-verify 的用法行。顺带修掉分层那笔里我写错的日期:
2026-11-01 → 2026-10-30(文档规范 4 处、测试说明 README 2 处,真值就是今天)。

树内验证:AST OK;--selftest PASS;改动的 3 个 .md 单文件
check_doc_links --sections-strict RC=0(36 处章节引用、可判定 34、无法判定 0);
字节体检干净。未跑 @build(无 .c/.h 改动)。
This commit is contained in:
2026-10-30 09:34:21 +08:00
parent 2b478588a7
commit 1221676272
4 changed files with 244 additions and 17 deletions
+25 -9
View File
@@ -14,7 +14,7 @@
|---|---|
| **目录名一律不含空格** | 空格迫使脚本/链接/CI 处处加引号,且 URL 编码形态(`UI%20设计`)极易被漏改(2026-09-25 起强制;全库已无含空格目录) |
| **按领域归入子目录** | 顶层不放散落 `.md`;新领域先建无空格子目录,再在 [`README.md`](README.md) 登记 |
| **子目录内文件过多时再分一层(只多分一层)** | `docs/测试说明/` 2026-11-01 起按用途分 `流程与规范/` `单元测试/` `板级测试/` `专项验证/` `测试工具/` `测试数据/` 六个子目录,**归层判据 → `docs/测试说明/README.md` §2**。再往下分不会让引用更短,只会让按目录递归的门禁 glob 更难核对 |
| **子目录内文件过多时再分一层(只多分一层)** | `docs/测试说明/` 2026-10-30 起按用途分 `流程与规范/` `单元测试/` `板级测试/` `专项验证/` `测试工具/` `测试数据/` 六个子目录,**归层判据 → `docs/测试说明/README.md` §2**。再往下分不会让引用更短,只会让按目录递归的门禁 glob 更难核对 |
| 现有目录 | `架构设计/` `子系统设计/` `算法/` `网络/` `测试说明/` `代码规范/` `内存管理/` `问题记录/` `环境与部署/` `UI设计/` `硬件平台/` `芯片手册/` `images/` |
### 1.1b 代码目录的 README.md
@@ -161,24 +161,40 @@
它覆盖的引用形态:反引号根相对引用、Markdown 链接(根相对与文档相对都按原风格改写)、**图片链接的 `../` 层级换算**(§3.2 那条实证坑由它兜住)、`#include "x.h"` 裸文件名、`MDK-ARM/*.uvprojx` 的 `<FilePath>`、`simulator/CMakeLists.txt` 的 `${PROJECT_ROOT}/…` 与 `${VAR}/…`、以及 skill / 脚本 / 配置里的路径串。
**它管不到的五件事**(脚本会在结尾提示):
**它管不到的事**(1–3 一直是手工活;4–5 曾是真会把东西改坏的坑,2026-10-30 已修并进了 `--selftest` 回归;6 由脚本主动点名):
1. **昵称式引用**(「内存方案 §2.1」)与正文里的裸文件名散文 → 落盘后 `git grep -n '<旧文件名>'` 扫一遍;
2. **生成物**(`docs/images/引用关系图.*`)不改写 → 重跑 `& 'tools\refgraph\gen_refgraph.bat'`;
3. 改的是 `.c/.h` 且**新增了目录** → 还要把目录加进 `uvprojx` 的 `<IncludePath>`(→ `new-source-file` skill),随后 `@build` 验证。
4. ⚠ **搬整目录时会改写目录内部文件的内容**(2026-11-01 `docs/测试说明/` 分层实测):脚本把内部文件里"不是路径的斜杠片段"
当成旧目录前缀的引用 —— `1/1 PASSED` 被改成 `test_data/1/1 PASSED`、日志日期占位 `[----/--/-- --:--:--]` 也被插前缀。
**一手证据与测试数据不接受这种改写** → 落盘后用 `git show HEAD:<旧路径>` 的原始字节逐文件还原,并核对
`git diff --stat` 里**不该出现**"数据目录内容变更"(只该有改名)。
5. ⚠ **搬整目录时,目录内部文件指向外部的 `../` 出链不补层级**(目录变深一层 → 静默断链;搬**单个**文件不受此影响,
出链会正确加一层)→ 落盘后逐条核对数据目录内部 README 的出链。
4. ~~搬整目录时会改写目录内部文件的内容~~ **已修**(2026-10-30,回归见 `--selftest` 案例 A):根因是
「相对引用文件所在目录」那条解析规则不检验目标是否存在,于是内部文件里**不是路径的斜杠片段**被
当成旧目录下的子路径并插上目录名 —— 分层那次 `1/1 PASSED` 改成 `test_data/1/1 PASSED`、日志日期占位
`[----/--/-- --:--:--]` 同样中招,连有效的 `see ../a.md` 都被换成指向不存在文件的 `see td/a.md`。
**修法**:该解析路径要求目标**真存在**(根相对写法保持原来的宽松口径),并且整目录搬迁时目录**内部**
互为相对的引用一律不改(两侧一起搬,改了必错)。
⚠ **仍要做的验收**:搬完看 `git diff --stat`,数据目录里**不该出现内容变更**、只该有改名 ——
一手证据与台架日志不接受任何改写,这条从"补救动作"降级成"核对判据"。
5. ~~搬整目录时目录内部文件指向外部的 `../` 出链不补层级~~ **已修**(同一 `--selftest` 案例 A):根因是
改写时把「本文件的新目录」取成了 `new_abs.parent`,整目录搬迁时少算一层,于是 `../images/x.svg`
搬深一层后仍指旧层级(**静默断链**:图片按 §3.2 是文档目录相对,`check_doc_links` 看不见)。
**修法**:按「`new_abs` / 相对旧目录的子路径」的父目录来算,出链层级自动补对;搬**单个**文件的换算
一字未动,由 `--selftest` 案例 B 专门守着。
6. **glob 形态引用**(如 `` `docs/td/*.md` ``):搬**目录**时前缀整体跟着搬(正确,不用管);搬**单个文件**时
一条 glob 可能同时盖住搬走和没搬走的两批文件,脚本不猜 → 但会把它**点名列出**(`⚠ 通配符形态引用 N 处`)。
分层那次有 4 处这种引用是**静默漏改**、事后靠人工补的,现在至少看得见。
> 同批实测的另两条工具侧事实:新路径**以 `/` 结尾**才是"挪进该目录并保留文件名"(见上例注释);`--apply` 收尾会自动跑
> `check_doc_links.py --all`,在带 junction 联接(`.venv`、`simulator/SDL2`)的任务工作树里会把联接目录扫成**假红**,
> 所以树内批量搬迁要加 `--no-verify`,全库 `--all` 复核留到主工作树跑(→ `docs/环境与部署/并行任务工作树方案.md`)。
> 另:脚本结尾的 `ℹ` 提示在 GBK 代码页会抛 `UnicodeEncodeError` 让进程**以退出码 1 收场**(此时 `git mv` 与改写**已经落盘**,
> RC 与真实结果相反)→ 2026-11-01 已在 `scripts/rename_ref.py` 内把 stdout/stderr `reconfigure(encoding="utf-8")`,
> RC 与真实结果相反)→ 2026-10-30 已在 `scripts/rename_ref.py` 内把 stdout/stderr `reconfigure(encoding="utf-8")`,
> 与 `check_ids.py` / `check_doc_links.py` / `check_test_traceability.py` 同法。
>
> **改 `scripts/rename_ref.py` 本体必须先跑 `--selftest`**(`& '.venv\Scripts\python.exe' scripts/rename_ref.py --selftest`):
> 它在一次性临时 git 仓里跑**本脚本的副本**——案例 A 守整目录搬迁那两条(目录内证据文件逐字节不变、出链 `../`
> 补对层级、别人文件的入链照改、glob 前缀跟着搬走),案例 B 守单文件搬迁的层级换算与 glob 提示。
> 反向对照也留了记录:同一夹具在改前版本上两条 bug **都复现**(`1/1 PASSED` → `td/1/1 PASSED`、
> `![img](../img/x.svg)` 不补层),所以这些断言不是凭空写的。
---
+6 -5
View File
@@ -1,6 +1,6 @@
# 测试说明目录导航
> 本目录放**测试文档与测试采集数据**,2026-11-01 起按**用途**分六个子目录(原先 25 篇文档
> 本目录放**测试文档与测试采集数据**,2026-10-30 起按**用途**分六个子目录(原先 25 篇文档
> 与 3 个数据目录平铺在一层,找文档靠记忆、命名靠约定)。
> **全量索引与每篇文档的内容说明在 [`docs/README.md`](../README.md) §6**(同一事实只在一处详述,
> 本文件不重复那些描述),这里只回答两件事:**东西该放哪一层**、**每层现在有什么**。
@@ -58,14 +58,15 @@ docs/测试说明/
根往下找 `*_Test_Guide.md` 与 `*单元测试说明.md`):模块指南落 `板级测试/`、单测说明落
`单元测试/`,**换层等于让追溯门禁看不见它**。
3. **改名 / 挪目录一律走 `scripts/rename_ref.py`**(先 dry-run 再 `--apply`),它会同步改写
全库引用;手工扫引用既慢又漏 → `docs/文档规范.md` §3.6。⚠ 该脚本目前有两个已实测的坑,见
下面第 5 节。
全库引用;手工扫引用既慢又漏 → `docs/文档规范.md` §3.6。它搬目录时原有两个会改坏内容的坑
**已修**(同日加了 `--selftest` 回归),本目录当时的处置见下面第 5 节。
4. 引用本目录文档时用**仓库根相对路径**(形如 `docs/测试说明/<子目录>/<文件名>.md`);只有图片用
文档所在目录相对 → `docs/文档规范.md` §3.1 / §3.2。
## 5. 本次分层的处置记录(2026-11-01)
## 5. 本次分层的处置记录(2026-10-30)
`scripts/rename_ref.py` 搬目录时有两个坑(**权威记录在 `docs/文档规范.md` §3.6 第 4/5 条**,这里只留本目录的处置):
`scripts/rename_ref.py` 当时搬目录有两个坑(**权威记录在 `docs/文档规范.md` §3.6 第 4/5 条**,两处已于
同日修复并加 `--selftest` 回归;这里只留本目录的处置):
- `测试数据/` 下 23 个证据文件的**内容**曾被脚本误改 → 已用 `git show HEAD:<旧路径>` 的原始字节逐字节还原,
现在这三个目录是**纯改名**(内容与 HEAD 逐字节一致)。