Files
STM32F4-Base/.dsh/skills/id-family-semantic-migration/reference/steps-alpha-numeric-family.md
T
wandering1 20617a33f7 docs(编号规范): 编号一律停发——§4.1 五族也不再发新号,只读存量
用户裁定(2026-10-29):「啥号都不发」= 任何族都不再新增编号,
含 §4.1 那五个原本"有脚本按字面量匹配"的存量族;既有号只读引用,
族里新增内容一律写语义行名。

规范本体:
- §1 由「先问三句」改成「默认答案:不发号」,三问表换成场景对照表;
- §4.1 由「允许用号的族」改成「存量族」,第四列改「既有号被谁读 /
  新写怎么办」,逐行写明新写怎么做(TRAP 写语义行名、FR 用 §5 行名、
  CODE-RULE / MENU-STATE 先问用户、P-n 只读存量页号);
- 末框四条对照 + 唯一例外入口(确需机器按字面量匹配 → 先问用户);
- 新增族 = 一律不许;批准后顺序:本文 §4.1 → 属主文档 → 才动 registry。

跨文件同步(12 份):门禁说明 id-check-new / id-check / host-unit-tests
(把"校验 5/3 拦新号"这类现状叙述历史化)、两份 TRAP 记录的编号口径、
开机账本用例号说明、AGENTS 两处、id-family 技能与其 steps-alpha 模板、
归档 README 与两份归档脚本 docstring。

AGENTS 主题表那行原写「允许用号的 7 个族」,与规范的 5 行本就对不上,
旧计数一并消掉。

未做:pre-commit 的 default_stages 一行——用户对该项未置可否。

验证:py_compile 与 check_ids_new.py --self-test 均 rc=0;逐篇
check_doc_links.py --sections-strict rc=0(编号规范 70 处引用 /
68 可判定 / 无法判定 0);13 份改动文件表列数与字节体检相对基线零新增。
2026-10-29 21:31:42 +08:00

11 KiB
Raw Blame History

Steps(字母+数字族:门禁看得见的那一路)(自 SKILL.md 外置)

本文由 id-family-semantic-migration 的 SKILL.md「Steps(字母+数字族:门禁看得见的那一路)」一节逐字外置而来(渐进展开:主文件只留索引与指针)。步骤号沿用原文,未重编。

  1. 确认范围与定调:先按开头的表判识别面(无识别面 → 走下一节);再读 docs/编号规范.md §4.1(族总表,穷举)、§4.1.1(已停发栏),存量与批次见 scripts/archive/id_gate/编号治理历史.md §9,明确本族属主登记处(owner_docs_glob);旧判据「有脚本按字面量匹配它」自 2026-10-29 起作废——全族一律停发。清退 = 全仓改语义;停发 = 在规范表里写死不再新增引用(id_registry.json 的游标冻结只是裁定留痕,2026-10-29 起无机器读者)。
  2. 按族实测三口径(字面量 / 站点 / 文件),不用 grep 估数。Checker.refs 是 dict(字面量 → 文件集合)不是方法,ck.refs(fam) 这种写法会 TypeError;站点数门禁不直接给,用族正则重扫它自己的语料:
    import sys; sys.path.insert(0, "scripts")
    import check_ids as ci
    reg = ci.load_json(ci.REGISTRY_FILE, "r"); al = ci.load_json(ci.ALIASES_FILE, "a")
    ck = ci.Checker(reg, al); ck.run()            # run() 填充 refs / stats / findings
    for name in ("N", "S-LDG", "TC", "FEAT"):     # 族名以 id_registry.json 的 "name" 为准
        rx = next(f for f in ck.families if f["name"] == name)["_re"]
        lits  = {l for l in ck.refs if rx.fullmatch(l)}        # 字面量(属主文档之外)
        files = {r for l in lits for r in ck.refs[l]}          # 文件
        sites = sum(len(rx.findall(line))
                    for rel in ck.iter_files()                 # 与门禁同一语料
                    for line in ck.read(rel).splitlines())     # 含属主文档定义行
        print(name, "literals", len(lits), "sites", sites, "files", len(files))
    
    全库扫一遍不便宜(数十秒量级):可丢后台 job,不要和别的长活串在同一个 120s 预算里。把活族清单与每族数字记下来作为动手前基线(拆批次与派单依据)。新测试套件发号导致 id-check 校验 3 报悬空引用时,先按号前缀聚合定位是哪个套件/哪个族(check_ids.py 2>&1 | grep -a '悬空引用' | ... 前缀计数),别逐条读。
  3. 逐族先分类再动手——不是每个命中的裸形都是编号,四类分治(实测 T1/T2/T3 的 41 处里只有部分是编号):
    • 真编号 → 语义短语 / 功能名;
    • 硬件位号(变压器 T1~T3 等)→ 把目录整目录登记进 check_ids 的 excluded_paths(如 excluded_paths += tools/netlist_semantics/),不逐处改位号名;
    • Mermaid 流程图节点名 → 改语义名但节点数与连线关系不变,图结构不动;
    • 数学记号 → 进噪声表;门禁自身的规则名(gitlint T2 Title has trailing whitespace)→ 不改。 分类前先把剩余每处原文打出来看(grep -F 逐文件),否则会把硬件资料改坏。
  4. 映射表由属主文档生成:从属主文档取「编号 → 功能名/语义短语」全表(实测 42 个定义 / 28 个在用),改名走 scripts/rename_ids.py(映射表驱动 + 显式 scope + 默认干跑 + 自动往 scripts/archive/id_gate/id_aliases.json 写 scoped 旧号→新号条目,状态 renamed / retired-to-phrase / void)。绝不全局查找替换:同一裸形字面量可能同时属多个族(实测 S3 三义),全局替换等于造新撞号。
  5. 按写域拆道并行派单(代码与测试半 / 文档半 / 某功能面各一条道),同笔用 send_message 下发统一改写口径(措辞、是否动字符串字面量、生成器归属、冻结历史行怎么处理),避免各道自定措辞;口径长就先落成 spec 文件(中文族一节第 5 步的做法同样适用)。看板任务只认 team_task_update 的 task_id / expected_revision / action=reassign / owner 四个字段。
  6. 门禁配置注释也是本族写入面:.pre-commit-config.yaml 的注释里会挂着功能号(实测 7h) ADC 采样有效性校验(语义取数与有效性层)、7i) 保护定值模型(P1 / 动作留痕层载体)、规划 §3.3 保护判据层)。配置属 Lead 写域,Lead 自己改(注释不占钩子行为、不影响 51 条钩子口径),但必须计入批次范围并在提交正文写清是 Lead 改的 config。
  7. 每处替换断言命中数,不做整文件正则批量改写(批量改写会静默漏改):
    def sub(path, pairs):
        p = pathlib.Path(path); t = p.read_text(encoding='utf-8')
        for old, new, want in pairs:
            got = t.count(old); assert got == want, (path, old, got, want)
            t = t.replace(old, new)
        p.write_text(t, encoding='utf-8')
    
    token 取最小形态:文档里被反引号/加粗包住的号,替换单位取反引号形(T4)而不含 ** 标记(第 225 行是 **裸形 T4**,按「裸形 T4」替就命中 0)。讲编号的文档改成形态描述(如「字母 T 紧跟数字 4」)能把不可判定绝对数还回余量:实测 4 处 → 982 降到 978,且 lesson 不丢。
  8. 同步更新归档扫描器的配置:check_ids 的 excluded_paths 与噪声表按第 3 步的分类结果改,使剩余命中不再是「假编号」;新测试套件发号的悬空引用要先定定义位:
    • 定义位只能落一处——注册表族(scripts/archive/id_gate/id_registry.json)或该套件说明文档,两处并存比没有定义位更坏;文档真写出来了(含判据与上板清单)就以文档为准、撤族;
    • 要建族就照现有同类族克隆(pattern / digit_width / owner_docs_glob / scope / cursor),别自造字段;
    • 抬游标前先确认游标是字符串形态('cursor': 'TC-UIDATA-026')——整型比较会静默不生效(实测踩坑),用字符串解析或正则取序号再比。
  9. 生成器文本改动必须同笔重跑产物:tools/arch_diagram/gen_*.py 里的 docstring/文案会进产物,generated-fresh 把生成器拷到临时目录重跑逐字节比对,只改源不改产物必红。这类站点整包转给生成器属主,「谁改谁跑生成器」,脚本 + 全部 svg 产物同一笔:
    ./.venv/Scripts/python.exe tools/arch_diagram/gen_net_instability_svg.py 2>&1 | tail -3
    pre-commit run generated-fresh --all-files   # 单钩子复跑必须带 --all-files 或 --files
    
    ⚠ 不带这两个参数的裸 pre-commit run 会进 staged_files_only 上下文并 stash 别道在飞的改动(docs/门禁说明/generated-fresh.md §2);pre-commit 不在 PATH 时改用 & '.venv\Scripts\python.exe' -m pre_commit run generated-fresh --all-files。PASS 后再目检 diff:只应文字变长、框宽自适应(526→551、右缘未越界、画布不变)。不把该站点从批次里悄悄丢掉:登记为「待未完成半批」,收口时核对。
  10. 核队友交付(按写域并行后必做):
    • 文件清单先展开真实路径再比:按简称匹配会误报丢失(作者列 phasor.py/adc_health.py 等 8 个,实为 test/host/<模块>/run_unit_test.py);用 git -c core.quotepath=false diff --name-only 取全路径做集合差。
    • 合并指纹对不上先问口径:作者按自定义顺序算的数 Lead 侧复现不了(d0a289b7 vs 报的 a45e7e2b)。改建 Lead 自有逐文件 16 位基线存 ci-artifacts/lead_lane_b_files.json,并把跨道文件单列(实测 App/algo/README.md)——autostash 后按逐文件比对,不假称对上别人的合并数。
  11. 分笔提交走真实 pre-commit 钩子:git add 用显式清单。坑:git add -- App/algo 把文档道的 App/algo/README.md(26 处)带上车,正文按 48 只文件写就不准了 → 该笔未 push 时 --amend 挪到文档笔并补一句归属说明;git add -A 会把别道在飞文件卷进来(覆盖率钩子在他编译不过的半成品上报红)→ 撤出他人域后重跑。提交正文每行 ≤80(gitlint B1),别把 ASCII 双引号写成正文首字符。
  12. 收口只认门禁自身计数(仅限语料内的族;无识别面族见下一节第 8~9 步),并核只减不增:
    ./.venv/Scripts/python.exe scripts/archive/id_gate/check_ids.py 2>&1 | grep -aE '扫描|可判定 |不可判定引用' | head -4
    ./.venv/Scripts/python.exe scripts/archive/id_gate/check_ids.py --strict 2>&1 | tail -1   # [OK] 校验 1~6 无错误
    
    报告「字面量 8787→8299→7828」「不可判定绝对数 1161→984→982→978(上限 1166)」「可判定比例 88.14%(基线 86.0%,容差 0.1pp)」。绝对数与比例两根线都要报:把可判定引用改成散文会稀释比值,所以另有不可判定绝对数上限。涨点归因见「净室归因」一节。
  13. 回写 docs/编号规范.md:§4.1 族表(停发/待清栏)、§4.1.1 已停发栏;存量表与批次结果表在 scripts/archive/id_gate/编号治理历史.md §9(只减不增、清点数字按最终实测同步);表格若保留动手前的清点数,明确标注「不是当前存量,是动手前基线」,否则就是拿旧数当现状。用户裁定原文与理由直接写进对应节(§4.1.1 停发行 + 该族的批次结论段落)——2026-10-28 起不再往变更记录写流水(docs/文档规范.md §5.1)。
  14. 裁定「不做」也要写成可执行硬口径入档(不是只划掉一行——「不做」最容易被读成「那还可以继续发号」):
    • §4.1.1「已停发」栏新增该族一行:游标冻结、现存号只减不增、新用例改用语义化测试函数名 + 文档表格行名,并写清与 §4.1 存量族栏的关系(那五族 2026-10-29 起也一律停发);
    • 批次段落写明裁定原文与理由(归档 scripts/archive/id_gate/编号治理历史.md §9.1——§9 一族的事实源已在归档篇,规范正文只留口径)(该族是唯一真被脚本按字面量匹配的族:C 断言标签 + 测试函数名 + 文档用例表三处同一号),并给出将来真要清退的前置条件:追溯器(check_test_traceability.py)先同时认新旧两种形态、并行核对通过,不许先改文档再改代码;
    • 全文核「等你裁定 / 需你裁定」悬空表述残留数归 0;
    • 无机器识别面的族落地面不同(docs/编号规范.md §4.1.1 一行 + 归档 编号治理历史.md §9.3 换算表 + 叙述同步三处),见下一节第 7 步。