feat(门禁): 新增 mermaid-syntax 钩子,围栏内确定性语法提交前必拦
- scripts/check_mermaid.py(纯标准库):R0 围栏未闭合 / R1 图类型头缺 错 / R2 -. 后直接跟管道(确定性语法错误形态)/ R3 subgraph 与 sequence 块的 end 计数配对;--all / --selftest(5 形态)/ --prune; 排除面与 doc-links 同口径;零语料空基线 - 接线 .pre-commit-config.yaml(doc-links 后),docs/门禁说明/ mermaid-syntax.md 专篇(八段结构含限制与盲区),README 索引与 AGENTS.md 计数 51→52、提交期实跑 48→49 - 门禁说明 README 顺带修正两处历史矛盾:gitlint 实际就在本配置 (commit-msg 阶段),旧文「52−3−gitlint」与「gitlint 不在配置里」 均过时——锚定口径 52 = 47 pre-commit + 3 manual + 1 commit-msg, 加钩后 48 + 1 = 49;三处 grep 争执例句改抽象表述(例句里的数字 自己会过时) - docs/子系统设计/屏板链路设计说明.md:38 修复触发本钩子的坏图: -. 后直接跟管道不是合法边 operator,改为 -.->|label| 形态 实测:YAML 解析 52 / commit 阶段枚举 48 行全 Passed(含新钩子)/ check_mermaid --all 29 文件 60 块围栏 0 命中 rc=0 / check_doc_links --all rc=0(215 文档)/ 六文件无 BOM/CR/U+FFFD。
This commit is contained in:
@@ -35,7 +35,7 @@ flowchart TB
|
||||
A -->|无条件| A2["重挂 ReceiveToIdle_IT"]
|
||||
end
|
||||
S -.-> D
|
||||
S -.|"组帧 OK 且本拍注过键 → 交凭据"| T
|
||||
S -.->|"组帧 OK 且本拍注过键 → 交凭据"| T
|
||||
KQ -.-> K
|
||||
D --> TC["DMA2_Stream7 传完中断"] --> C["清 busy(攒了 dirty → 下一拍补组)"]
|
||||
```
|
||||
|
||||
+21
-13
@@ -1,7 +1,7 @@
|
||||
# 门禁逐项说明(每种门禁一篇)
|
||||
|
||||
> 本目录逐项说明各门禁:**声明的 51 个钩子到底在干什么、拦谁、放谁、什么时候会骗人**——其中 3 根慢钩子带
|
||||
> `stages: [manual]`,一次 `git commit` 只实跑 48 根(口径见下条)。
|
||||
> 本目录逐项说明各门禁:**声明的 52 个钩子到底在干什么、拦谁、放谁、什么时候会骗人**——其中 3 根慢钩子带
|
||||
> `stages: [manual]`,一次 `git commit` 只实跑 49 根(口径见下条)。
|
||||
> 每个门禁一篇,八段固定结构:查什么 / 为什么要它 / 触发面 / 报错怎么读 / 好处 /
|
||||
> **限制与盲区** / 豁免与基线 / 改门禁本身要注意什么。**最后一节是这套文档存在的理由**——
|
||||
> 一份只看"拦了什么"的门禁文档,会让人以为绿就是对的。
|
||||
@@ -12,41 +12,48 @@
|
||||
→ **51**(2026-10-26:49 → 50 加 `generated-fresh`;2026-10-27:50 → 51 加 `nested-comment`;
|
||||
2026-10-28:51 → 52 加 `id-check-new`、随即 52 → 51 摘掉 `id-check`(退役全库语料审计);2026-10-29:51 → 52 加 `skill-size`(SKILL.md 写侧上限与 reference 指针,详见 [`skill-size.md`](skill-size.md));
|
||||
同日 52 → **51** 退役 `id-check-new`——只查新增行的编号门禁整体退场,脚本与白名单移入
|
||||
`scripts/archive/id_gate/`,此后**编号形态没有机器面**(留档 [`id-check-new.md`](id-check-new.md)))。
|
||||
`scripts/archive/id_gate/`,此后**编号形态没有机器面**(留档 [`id-check-new.md`](id-check-new.md));
|
||||
2026-10-30:51 → **52** 加 `mermaid-syntax`(mermaid 围栏内确定性语法:坏图渲染失败靠肉眼才逮过,
|
||||
详见 [`mermaid-syntax.md`](mermaid-syntax.md)))。
|
||||
⚠ **别用 `grep -c` 去数配置里的声明行**:该文件里有一条**注释掉的**候选钩子(clang-format,第 65 行),
|
||||
文本 grep 会多算 1(当前口径 51 会数成 52)——「声明 52 / 文档 51 / 实跑 51」这种三个数不同源的争执就是这么来的。真要 grep,
|
||||
用**锚定行首缩进**的模式(它天然跳过以 # 开头的注释行)2026-10-28 实测直接得 **51**(当时口径),与 YAML 口径一致;
|
||||
文本 grep 会多算 1(当前口径 52 会数成 53)——「声明比文档多 1 / 实跑又少一档」这种三个数不同源的争执就是这么来的。真要 grep,
|
||||
用**锚定行首缩进**的模式(它天然跳过以 # 开头的注释行)2026-10-28 实测直接得 **51**(当时口径)、
|
||||
2026-10-30 复测得 **52**,均与 YAML 口径一致;
|
||||
会多算 1(比口径多 1)的是**不锚定行首、按子串**匹配声明行的写法(那条被注释掉的候选也被它算进去)。
|
||||
⚠ 反过来的坑也真踩过(2026-10-27):在配置**注释里复述那个 grep 字面量**,会让文本 grep 再虚高 1——
|
||||
数数只认 YAML 解析,注释与文档里都别写出那个字面量(`docs/门禁说明/nested-comment.md` §8 记了现场)。
|
||||
实跑侧口径:`scripts/ci_local.py` 的静态门禁汇总行 `[SUMMARY] …: pre-commit hooks -- passed=A failed=B skipped=C`(方括号里那一段是**层级名**,脚本输出与文档层的语义名正分头迁移 → 抓这行**按 `passed=` 字段匹配**,别把层级名前缀写死进字面量,否则会 grep 不到而误判「没有实跑数」),
|
||||
`A+B+C` = **commit 阶段**的钩子数(48 = 52 − 3 根 `stages: [manual]` − `gitlint`),再加 `gitlint` 1 条(它的
|
||||
commit-msg 阶段声明写在**上游**仓库自带的钩子清单里,本配置文件里查不到,见 `scripts/ci_local.py` 文件头)
|
||||
→ 48 + 1 = **49 = 一次 `git commit` 实跑的钩子数**;再加 3 根 manual 阶段的慢钩子才是声明数 52,三数同源(2026-10-29 加 `skill-size` 之前这四个数是 51 / 47 / 48)。
|
||||
`A+B+C` = **pre-commit 阶段**的钩子数(48 = 52 − 3 根 `stages: [manual]` − `gitlint`;2026-10-30 加
|
||||
`mermaid-syntax` 前该式子右侧是 51/47),再加 `gitlint` 1 条(它声明在本配置的 `repo: jorisroovers/gitlint`
|
||||
条目、`stages: [commit-msg]`(第 70 行),`--hook-stage commit` 的枚举不含它——2026-10-30 实测:
|
||||
`--hook-stage commit` 枚举 **47 行** / `manual` 枚举 **50 行** / YAML 解析声明 **51**(加本钩后 48/51/52),
|
||||
47 + 3 + 1 = 51,差的那个就是 `gitlint`;旧说法「gitlint 声明在上游清单、本配置里查不到」已于当日随
|
||||
`stages:` 接线作废)
|
||||
→ 48 + 1 = **49 = 一次 `git commit` 实跑的钩子数**;再加 3 根 manual 阶段的慢钩子才是声明数 52,三数同源(2026-10-29 加 `skill-size` 之前这四个数是 51 / 47 / 48;2026-10-30 加 `mermaid-syntax` 后是 52 / 48 / 49)。
|
||||
枚举自查(不执行任何钩子,`SKIP` 列全部 id):`SKIP=<全部 id> -m pre_commit run --all-files --hook-stage commit`
|
||||
输出 47 行、`--hook-stage manual` 输出 50 行(47 常规 + 3 慢的)。
|
||||
- **三根慢钩子在 manual 阶段**:`cppcheck`、`test-cppcheck`、`test-coverage` 带 `stages: [manual]` → `git commit`
|
||||
阶段**不跑**(实测三根合计约 165 s,占一次带代码提交耗时的约三分之二),只在**远端 CI 的「手动阶段门禁」步**
|
||||
(`.gitea/workflows/ci.yml`,逐根 `--hook-stage manual`)与 `scripts/ci_local.py` 的 **manual 段**里跑。
|
||||
本地手工复跑:`& '.venv\Scripts\python.exe' -m pre_commit run --all-files --hook-stage manual <hook-id>`
|
||||
(**一次只能给一个 id**,多 id 实测报 `unrecognized arguments`)。声明数仍是 51,变的是「提交期实跑几根」。
|
||||
(**一次只能给一个 id**,多 id 实测报 `unrecognized arguments`)。声明数仍是 52,变的是「提交期实跑几根」。
|
||||
- 通用机制(三个阶段 = `pre-commit` / `commit-msg` / `manual`、stash 陷阱、`always` 已废、增量拦截三段式、旧 §2.x 查号表):
|
||||
`docs/代码规范/pre-commit使用说明.md` §2。
|
||||
- 快速自查(不等提交):`& '.venv\Scripts\python.exe' scripts/ci_local.py`(静态段 47 根 + manual 段三根 + 提交信息门禁 + 体积门禁 + 主机侧纯逻辑单测;manual 段默认跑)。
|
||||
- 快速自查(不等提交):`& '.venv\Scripts\python.exe' scripts/ci_local.py`(静态段 48 根 + manual 段三根 + 提交信息门禁 + 体积门禁 + 主机侧纯逻辑单测;manual 段默认跑)。
|
||||
|
||||
## 1. 三种拦截姿态(先分清这个,报错时才知道该干什么)
|
||||
|
||||
| 姿态 | 含义 | 有哪些 | 失败时该做什么 |
|
||||
|---|---|---|---|
|
||||
| **改写型** | 不报错,直接改你的文件 | `trailing-whitespace`、`end-of-file-fixer` | 重新 `git add` 被改的文件再提交(它改的是工作区,不是索引) |
|
||||
| **硬拦截** | 违反即失败,没有存量豁免 | `cppcheck`、`coding-standard`、`doc-links`、`no-mojibake`、`mem-budget`、`ui-golden`、`font-charset`、`lv-conf-sync`、`task-table`、`mem-numbers`、`registration-check`、`cubemx-survival`、`test-suite-switch`、22 个主机单测、官方 5 个、`gitlint` | 只能改代码或改文档;**不要**找豁免开关 |
|
||||
| **硬拦截** | 违反即失败,没有存量豁免 | `cppcheck`、`coding-standard`、`doc-links`、`no-mojibake`、`mem-budget`、`ui-golden`、`font-charset`、`lv-conf-sync`、`task-table`、`mem-numbers`、`registration-check`、`cubemx-survival`、`test-suite-switch`、`mermaid-syntax`(基线为空,先例是已退役的 `id-check-new`「零语料」;唯一排除面 = 外部资料目录,见其专篇 §7)、22 个主机单测、官方 5 个、`gitlint` | 只能改代码或改文档;**不要**找豁免开关 |
|
||||
| **增量拦截** | 规则恒生效,但存量钉在基线/台账里,只许减不许增 | `layer-deps`(3 条,2026-10-25 还清 UI 记录 3 条)、`bsp-err`(38 条)、`generated-fresh`(5 处 `docs/images/` 配图存量,脚本内 `BASELINE`)、`nested-comment`(2 处主机侧假件头,`test/host/common/`,脚本内 `BASELINE`) | 报错先分清是**新增**还是**存量搬家**:`--verbose` 看归类,`--prune` 看已还清 |
|
||||
| **只查新增** | 只看本次改动的增量,没有存量基线,也没有台账 | ~~`id-check-new`~~(**2026-10-29 退役**,脚本在 `scripts/archive/id_gate/`;这一姿态已无现役门禁) | 手工复查时才谈得上:改成语义短语(门禁不再跑,行内 `[编号豁免]` 也随之失效) |
|
||||
|
||||
⚠ 增量拦截最容易误会的一点:**绿灯不等于没问题**,只等于"没有比上次更差"。
|
||||
每个增量拦截门禁的基线数字都写进它自己的文档,读那篇时第一眼看的就是"现在在册多少条"。
|
||||
|
||||
## 2. 索引(51 个 hook → 29 篇,其中 2 篇是已退役门禁的留档 + 1 根只有本表指针(专篇待补)+ 1 根详解在 docs/测试说明/)
|
||||
## 2. 索引(52 个 hook → 30 篇,其中 2 篇是已退役门禁的留档 + 1 根只有本表指针(专篇待补)+ 1 根详解在 docs/测试说明/)
|
||||
|
||||
> 带 `stages: [manual]` 的三根(`cppcheck` / `test-cppcheck` / `test-coverage`)**提交期不跑**,只在远端 CI 的
|
||||
> 「手动阶段门禁」步与 `scripts/ci_local.py` 的 manual 段跑;下表对应两行的「文档」列已标注。
|
||||
@@ -58,6 +65,7 @@
|
||||
| [`id-check.md`](id-check.md) | ~~`id-check`~ | **已退役(2026-10-28)**:全库语料的八项校验,留档备查;接班件也在下一行 | 在时有:几乎所有文本文件 | 已写(退役留档) |
|
||||
| [`id-check-new.md`](id-check-new.md) | ~~`id-check-new`~ | **已退役(2026-10-29,用户裁定)**:只查新增行的编号门禁,留档备查(含退役理由与手工跑法);**编号形态此后无机器面** | 在时有:任意 md/c/h/py/yaml/txt | 已写(退役留档) |
|
||||
| [`doc-links.md`](doc-links.md) | `doc-links` | 文档里的路径引用是否存在;`--sections-strict` 另查章节号是否还存在 | 任意 `.md` | 已写 |
|
||||
| [`mermaid-syntax.md`](mermaid-syntax.md) | `mermaid-syntax` | ` ```mermaid ` 围栏内确定性语法:图类型头 / `-.` 直接跟管道 / subgraph 与 sequence 块的 `end` 配对 | 任意 `.md`(`docs/芯片手册/` 等与 doc-links 同排除面) | 已写 |
|
||||
| [`cppcheck.md`](cppcheck.md) | `cppcheck`、`test-cppcheck` | 静态分析(真机侧与 `test/` 侧两套范围与抑制项) | C/H 源文件 | 已写(`stages: [manual]`) |
|
||||
| [`coding-standard.md`](coding-standard.md) | `coding-standard` | 编码规范 V1.0 的可机械检查子集(命名、头文件保护宏、模块头注释块…) | C/H 源文件 | 已写 |
|
||||
| [`no-mojibake.md`](no-mojibake.md) | `no-mojibake` | 禁 `U+FFFD`——中文被按错误编码重解码后不可逆损坏的痕迹 | 全部文本 | 已写 |
|
||||
@@ -98,7 +106,7 @@
|
||||
|
||||
## 4. 现状与下一步
|
||||
|
||||
- **本目录 29 篇已全部成文**(2026-10-29 加 `skill-size` 一篇 → 29;2026-10-27 实测当时 27 篇;2026-10-28 当时复核:`docs/门禁说明/` 下除 README 外 28 篇,与上表「文档」列
|
||||
- **本目录 30 篇已全部成文**(2026-10-30 加 `mermaid-syntax` 一篇 → 30;2026-10-29 加 `skill-size` 一篇 → 29;2026-10-27 实测当时 27 篇;2026-10-28 当时复核:`docs/门禁说明/` 下除 README 外 28 篇,与上表「文档」列
|
||||
**一一对应**——「有页无行」与「有行无页」两个差集都是空集;一行覆盖多个 hook 的行(`cppcheck`+`test-cppcheck`、
|
||||
22 个 `*-unit-test`)按行内列举计。上一句写「23 篇」是存量误差:2026-10-25 连加 `bom-guard` /
|
||||
`setview-check` / `uinav-selftest` 三根、本轮加 `generated-fresh` 都没同步它(本轮前实有 25 篇)。
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# mermaid 围栏语法预检(mermaid-syntax)— 围栏里的图坏了必在提交时响
|
||||
|
||||
> 一句话:` ```mermaid ` 代码块是**渲染期才报错**的内容——md 链接与章节门禁全绿也拦不住一张
|
||||
> 语法坏的图。本闸只查「错了必渲染失败」的三条确定性形态,不重造 mermaid 解析器。
|
||||
> 脚本 `scripts/check_mermaid.py`(纯标准库、只读,2026-10-30 接线)。
|
||||
|
||||
## 1. 它在查什么
|
||||
|
||||
对每个 md 提取 ` ```mermaid ` 围栏块(排除面见 §3),逐块查:
|
||||
|
||||
| 判定 | 形态 | 说明 |
|
||||
|---|---|---|
|
||||
| **R0 算** | 围栏未闭合 | 有 ` ```mermaid ` 开栏找不到闭栏 |
|
||||
| **R1 算** | 块内首个非空非注释行不以已知图类型关键字开头(`flowchart`/`graph`/`sequenceDiagram`/`stateDiagram`/`classDiagram`/`erDiagram`/`gantt`/`journey`/`pie`/`mindmap`/`timeline`/`quadrantChart`/`gitGraph`/`C4Context`… 全表见脚本 `DIAGRAM_HEADS`) | 没有头 = 100% `Syntax error in text`;`flowChat` 这类拼错也算 |
|
||||
| **R2 算** | `-.` 后(允许空白)直接出现管道 `\|`,即 `-.|"文字"\|` 形态 | 接线当日逮到的**真事原形**(§2);带文字点线的合法形态只有 `-.->\|t\|` 与 `-. 文字 .->`,selftest 证明两者不误伤 |
|
||||
| **R3 算** | flowchart/graph 的 `subgraph` 行数 ≠ 独占行 `end` 行数;sequenceDiagram 的行首块起点(`alt`/`opt`/`loop`/`par`/`critical`/`rect`/`break`)行数 ≠ 行首 `end` 行数 | 缺 `end`(或多 `end`)必渲染失败;`else`/`and`/`option` 是分支不消费 end,不误伤 |
|
||||
| 不算 | `%%` 注释行、`rem` 行 | 与渲染一致地跳过 |
|
||||
| 不算 | 标签内出现 `end`/管道/引号(如 `E["end 事件"]`、`-"x"|-`在合法箭头内) | 判定只看行首 token 与 `-.`+`\|` 邻接,不碰引号内文本 |
|
||||
|
||||
## 2. 为什么要它
|
||||
|
||||
2026-10-29 落库的 `docs/子系统设计/屏板链路设计说明.md` §1 flowchart 里,一行带文字点线写成:
|
||||
|
||||
```
|
||||
S -.|"组帧 OK 且本拍注过键 → 交凭据"| T ← 坏:`-.` 后直接跟管道,`-.|` 不是箭头 token
|
||||
S -.->|"组帧 OK 且本拍注过键 → 交凭据"| T ← 修复:补 `>`,`-.->|t|` 是合法形态
|
||||
```
|
||||
|
||||
mermaid 10.9.8 对前者整图渲染 `Syntax error in text`(headless Edge 截图实证,图旁红炸弹图标),
|
||||
对后者渲染完整正确。**该坏图从落库到 2026-10-30 被用户肉眼发现期间,doc-links 等文档门禁全绿**
|
||||
——它们查链接、章节、表格断裂,**没有任何一根查围栏内图表语法**;芯片手册转录目录之外,全仓
|
||||
自有围栏 60 块,全靠人眼守。
|
||||
|
||||
### 2.1 接线当日实测(都可复现)
|
||||
|
||||
| 测项 | 结果 |
|
||||
|---|---|
|
||||
| 全仓 `--all` 实扫 | **29 个自有文件共 60 块围栏:新发 0、基线 0**,退出码 0 ⇒ 空基线零语料 |
|
||||
| `--selftest` 五条 | **5/5**:正例(三种合法点线 + 配对 subgraph)0 命中 / 本坑形态 R2 必响 / subgraph 缺 end 必响 / 假图类型头必响且 sequence `alt-else-end` 不误伤 / 基线吞得下且清空后同命中算新发 |
|
||||
| 钩子端到端 | 暂存一个复刻本坑的坏 md → `mermaid-syntax Failed`、定位到 `文件:38 [R2-dot-pipe]` 原行;修复形态 `--all-files` Passed |
|
||||
| 原图渲染对照 | 坏版 `Syntax error in text`、好版完整渲染,两 PNG 见当日会话(mermaid 10.9.8 CDN + headless Edge) |
|
||||
|
||||
## 3. 触发面
|
||||
|
||||
钩子 `files: \.md$` + exclude 与 `doc-links` **同口径**(`.opencode/node_modules/`、`Lib/lvgl/`、
|
||||
`MDK-ARM/RTE/`、`docs/芯片手册/`)——芯片手册是外部转录,围栏形态不受控,与 doc-links 一样整体
|
||||
不进语料。`scripts/check_mermaid.py --all` 的文件集与钩子实际喂入**刻意同口径**。
|
||||
|
||||
单独自查:`& .venv\Scripts\python.exe scripts/check_mermaid.py --all`
|
||||
|
||||
## 4. 报错怎么读
|
||||
|
||||
```
|
||||
docs/子系统设计/xxx.md:38 [R2-dot-pipe] dotpipe:S -.|"组帧 OK 且本拍注过键 → 交凭据"| T
|
||||
```
|
||||
|
||||
行号是 **md 文件绝对行号**(不是块内偏移),直接跳。四条判读打印在输出尾行:
|
||||
R1 改图类型头;R2 改 `-.->|t|` 或 `-. t .->`;R3 补/删 `end`(打印里带 `pair:sg=N,end=M`
|
||||
两个计数,谁多谁少一眼可见);R0 补闭栏。
|
||||
|
||||
## 5. 好处
|
||||
|
||||
- 把「肉眼盯渲染」变成机器兜底:围栏内坏图在**提交时**响,不用等 GitWeb/IDE 预览点亮红块。
|
||||
- 空基线零语料:今天起任何新坏图都拦得住,不背历史债。
|
||||
- 毫秒级、纯标准库、只读——不需要网络、不需要 node、不需要浏览器。
|
||||
|
||||
## 6. 限制与盲区(绿 ≠ 图对)
|
||||
|
||||
- **不是解析器**:只覆盖三条「必炸」形态。大量仍会漏——引号不平衡、非法节点字符(中文引号
|
||||
包标签)、sequence 消息语法错、`style`/`classDef` 目标不存在、layout 指令错等。最终权威
|
||||
仍是**真实渲染**(mermaid CDN + headless Edge 截图回读,`draw-diagram` skill 载有流程)。
|
||||
- **R2 只钉 `-.`+`|` 本坑形态**:其它非法箭头变体(如 `==|`、`-.->x`)不响;出现新形态时
|
||||
加判据(本闸按「增量长牙」演进,与 `nested-comment` 同哲学)。
|
||||
- **R3 是计数配对**:subgraph 多一个**且** end 也恰好多一个(两处错互相抵消)测不出;
|
||||
也不校验 `end` 是否配对在正确的嵌套层级(只数总量)。
|
||||
- `%%` 注释行里的坏形态不响(与渲染行为一致);围栏缩进嵌在列表项里的块同样被扫(无盲区),
|
||||
但 **indented code block 里的 mermaid 不会被识别**(GFM 本也不渲染它,一致)。
|
||||
- 只扫 ` ```mermaid `;` ~~~mermaid ` 波浪围栏全仓未用,未支持。
|
||||
|
||||
## 7. 豁免与基线
|
||||
|
||||
- **基线为空**(2026-10-30 接线实扫 0 命中,先例 = 已退役的 `id-check-new`「零语料」形态),
|
||||
脚本内 `BASELINE = ()`。若将来被迫登记存量:必须写「文件 + 规则 + 上下文指纹 + 为什么不改」,
|
||||
`--prune` 打台账、只减不增。
|
||||
- 唯一排除面是 §3 的目录前缀(外部资料),**自有文档零豁免**。
|
||||
|
||||
## 8. 改门禁本身要注意什么
|
||||
|
||||
- **加判定必带正例自测**:往 `hits_for_block` 加任何新形态前,先在 `--selftest` T1 的正例里
|
||||
放入该形态的**合法**写法——没有正例守卫的新判据就是给自己造误报机(`nested-comment` §8 同训)。
|
||||
- **排除面两处同步**:`.pre-commit-config.yaml` 本钩的 `exclude` 与脚本 `EXCLUDE_PREFIXES`
|
||||
是两份字面拷贝,改一处必改另一处——手跑面与提交面不一致就会变成「两个数」。
|
||||
- 判定用「行首 token / 邻接字符」这类保守形态学,**不要**用「看起来像标签」的启发式——
|
||||
本仓围栏里混排中英文、全角符号、`µ`/`≠`/`→` 等字符,启发式必误伤。
|
||||
- 本条钩子使 YAML 解析口径 **51 → 52**、提交期实跑 **48 → 49**;加/摘钩子按
|
||||
`docs/门禁说明/README.md` §2 首条的自查命令三数同核(AGENTS 与索引两处计数同批改)。
|
||||
Reference in New Issue
Block a user