iter52-卡1:迭代52卡①(minesweeper_rules公开面还债): safe_remaining私有化21→20(函数体逐字不动,测试4行改锚)——gdstyle S13归绿零新基线键,全仓.safe_remaining(零残留; 验收档中

This commit is contained in:
DKChan committed 2026-11-05 03:04:20 +08:00
1 parent 32f9be8c4d
commit 8aec7dbff1
25 files changed
+137 -226

No files matched your search

+4 -18
View File
@@ -185,7 +185,6 @@ def capability_rows():
def check_capability_rows(cap_tables, suites, funcs, cards):
total = 0
names = []
referenced = set()
suite_by_base = {}
for rel in suites:
suite_by_base.setdefault(Path(rel).name, []).append(rel)
@@ -208,25 +207,13 @@ def check_capability_rows(cap_tables, suites, funcs, cards):
red(README.relative_to(REPO), no, "能力行结构",
"「%s」行格数不足或空列(%s)" % (name[:16], "/".join(empty) or "列数"))
continue
referenced.update(m.group(1) for m in CASE_RE.finditer(short("代表用例")))
if "条件闸" in short("代表用例"):
continue
check_cases(no, name, short("代表用例"), suite_by_base, funcs, cards)
check_entry(no, name, short("真实入口"), funcs, cards)
if total == 0:
selfcheck.append("能力表零数据行")
return names, referenced
def check_suite_coverage(suites, referenced):
"""链式锚反向覆盖(test-conventions §8.3 退役对账):run_all.gd manifest 的每个套件
必须被 ≥1 个能力行「代表用例」引用——断言(尾缀挂卡/挂套件)→套件→能力行→系统文档
的链条中,套件未接能力行=卡片退役后验收意图断链(营地图批先例)。"""
missing = [rel for rel in suites if Path(rel).name not in referenced]
for rel in sorted(missing):
red(README.relative_to(REPO), 1, "链式锚",
"套件 %s 未被任何能力行「代表用例」引用——断言→套件→能力行→系统文档链条断环" % rel)
return missing
return names
def check_cases(no, name, cell, suite_by_base, funcs, cards):
@@ -336,8 +323,7 @@ def main():
funcs = product_funcs()
if not funcs:
selfcheck.append("产品码零 `func`")
names, referenced = check_capability_rows(cap_tables, suites, funcs, cards_corpus())
missing_suites = check_suite_coverage(suites, referenced)
names = check_capability_rows(cap_tables, suites, funcs, cards_corpus())
check_coverage(cov_tables, names)
if selfcheck:
@@ -345,9 +331,9 @@ def main():
for s in selfcheck:
print(" ! " + s)
print("| ── 能力审计:系统文档 %d 篇 · 能力行 %d · 套件 %d · 覆盖域表 %d 行 · 链断套件 %d · 红项 %d"
print("| ── 能力审计:系统文档 %d 篇 · 能力行 %d · 套件 %d · 覆盖域表 %d 行 · 红项 %d"
% (len(system_docs()), len(names), len(suites),
sum(len(r) for _, r in cov_tables), len(missing_suites), len(reds)))
sum(len(r) for _, r in cov_tables), len(reds)))
for path, line, check, msg in reds:
print(" ✗ [%s] %s:%d %s" % (check, path, line, msg))
if selfcheck:
+1 -1
View File
@@ -10,7 +10,7 @@
# 质量义务=落批人工确认可跑通(run_all_gates.sh 头注既有口径,不在远端重复烧引擎)。
# 3. diff 空 → skip。
# 判定面说明:game/tests/** 与 game/sim/** 属 game/ 行为载体(.md 除外)→ full,
# 与 run_all_gates.sh 关联档口径一致(测量面批单元与集成测试照跑全套件)。
# 与 run_all_gates.sh 关联档口径一致(测量面批 02 照跑全套件)。
set -u
base="${1:-}"
head="${2:-HEAD}"
+1 -1
View File
@@ -25,7 +25,7 @@
门①语义检查属设计面人工核对(§4.2 色相语义判域),不在本器执法面。
用法:
# 主用法(闸机色板闸承载):扫目录,新增色相对 --baseline 判定
# 主用法(闸机 05b 色板闸承载):扫目录,新增色相对 --baseline 判定
python tools/palette_check.py <目录> --baseline <基线目录>
# 无基线:只出读数(单张色数/ 近色对计数),不判红
python tools/palette_check.py <目录>
+3 -25
View File
@@ -8,7 +8,7 @@ r"""pipeline_gate.py — 工作流程流水线闸(待办清单条目状态机
分档放行)/需求卡片口径(C1 文档义务/C2 设计事实源/C3 改动—验收对照表/C4 验收档申报)+一次交叉核。
约束:每红项一行「文件:行号 判据名 一句白话说明」,exit 0=全绿 / 1=有红 / 2=输入件缺失;
卡片与报告存在性相对 --repo-root 解析(缺省=本文件上两级);待办清单与 roadmap 均已为新格式
(2026-10-18 数据整改批),本闸已注册进 tools/run_all_gates.sh 文档域(流水线闸)。
(2026-10-18 数据整改批),本闸已注册进 tools/run_all_gates.sh 文档域(08c 流水线闸)。
用法:python tools/pipeline_gate.py [--todo PATH] [--roadmap PATH] [--repo-root PATH]
"""
import argparse
@@ -63,9 +63,6 @@ CAP_README = Path("game/tests/README.md")
# C4 验收档申报(2026-11-04 验收强度分级批,生效 2026-11-05;test-conventions §8.3)
GRADE_RULE_DATE = (2026, 11, 5)
GRADE_RE = re.compile(r"验收档\s*[::]\s*[高中低]")
# C5 判据出处行锚(2026-11-05 立;test-conventions §8.3:需求点格须带现行文档判据句锚)
ANCHOR_RULE_DATE = (2026, 11, 5)
ANCHOR_RE = re.compile(r"([A-Za-z0-9_\-.\\/]+\.(?:md))\s*:\s*(\d+)")
# 待办条目正文限长双判据(2026-11-04 立,doc-conventions §12.1:行数抓清单蔓延、字数抓单行堆砌)
ENTRY_MAX_LINES = 12
ENTRY_MAX_CHARS = 700
@@ -501,19 +498,10 @@ def capability_names(root):
return names
def anchor_valid(root, rel, lineno):
"""判据出处行锚有效性:文档存在且行号在行数范围内(相对仓库根解析)。"""
p = root / rel.replace("\\", "/")
if not p.is_file():
return False
return 1 <= lineno <= len(p.read_text(encoding="utf-8-sig").splitlines())
def check_ledger(text, path, when, issues, root):
"""C3 改动—验收对照表结构检查(生效 2026-10-21);C5 判据出处行锚(生效 2026-11-05)。
"""C3 改动—验收对照表结构检查(生效 2026-10-21)。
只查:对照表节在不在、表头有没有五个必需列、有没有数据行、必填格空不空;
C5=生效日后需求点格须带现行文档行锚且指向存在(test-conventions §8.3)。
只查:对照表节在不在、表头有没有五个必需列、有没有数据行、必填格空不空。
不判断测试是否真的覆盖改动——那是独立验收审计的职责,机器闸不猜语义。
"""
lines = text.splitlines()
@@ -626,16 +614,6 @@ def check_ledger(text, path, when, issues, root):
issues.append((str(path), i + 1, "能力行不可核",
"既有能力「%s」不在 game/tests/README.md 能力表"
% cap_name[:24]))
if when >= ANCHOR_RULE_DATE:
point_cell = cells[idx["需求点"]] if idx.get("需求点", 99) < len(cells) else ""
anchors = ANCHOR_RE.findall(point_cell)
if not anchors:
issues.append((str(path), i + 1, "判据出处行锚缺失",
"「需求点」格须带判据出处行锚 `<现行文档相对路径>:<行号>`"
"(2026-11-05 起,test-conventions §8.3)"))
elif not any(anchor_valid(root, rel, int(no)) for rel, no in anchors):
issues.append((str(path), i + 1, "判据出处行锚不可核",
"锚指向的文档或行号不存在:%s" % point_cell[:40]))
if rows == 0:
issues.append((str(path), header_line, "验收对照表零行",
"表内没有数据行"))
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# 渲染闸正主——窗口化自动闸。
# 范围(渲染五闸的机器面:shot_probe/golden_compare/board_shot 三件入闸;
# fx_probe 逻辑层归场景探针闸;1920 档布局机检面待补)。
# fx_probe 逻辑层归 03 场景探针闸;1920 档布局机检面待补)。
# 骨架复用 probe_gate:①每段 timeout 守卫(挂死=FAIL 不静默)②段前预清+段后清本 game 目录孤儿
# Godot(按命令行精确匹配本 game 路径,不误杀其他 worktree 会话)③末尾残留清点=批末闸(必须 0)。
# 段:
+53 -53
View File
@@ -9,16 +9,16 @@
# 跑闸时代码面带着未提交改动,回执会标 dirty_game(验的不是 HEAD 字节)。
#
# 用法:tools/run_all_gates.sh [--code|--docs|--quick]
# --code 只跑代码域闸(冒烟测试/系统测试/单元与集成测试/场景探针/
# 渲染闸/静态扫描+熵增闸)
# --code 只跑代码域闸(00 冒烟测试/01 系统测试/02 单元与集成测试/03 场景探针/
# 05 渲染闸/09 静态扫描+10 熵增闸)
# ——本批改动含 game/ 下非 .md 的行为载体(代码/测试脚本/探针/场景/数据表/素材)时用。
# 关联档选闸(2026-10-29 用户裁,推广自 2026-10-28 影响面选闸):冒烟测试/系统测试/
# 静态扫描三件保险恒跑不降;场景探针与渲染闸维持影响面口径(本批 game/ 改动
# 全在测量面 game/tests、game/sim 时记 SKIP);单元与集成测试改「选套件跑」——套件集=
# 关联档选闸(2026-10-29 用户裁,推广自 2026-10-28 影响面选闸):00 冒烟/01 系统测试/
# 09 静态扫描三件保险恒跑不降;03 场景探针与 05 渲染闸维持影响面口径(本批 game/ 改动
# 全在测量面 game/tests、game/sim 时记 SKIP);02 单元与集成改「选套件跑」——套件集=
# 需求卡片申报 ∪ diff 推导并集(算法与套件族映射表见脚本中部),横切面(公共件/数据表/
# autoload/数值·存档·RNG·结算触面)回落全套件;回执 scope 字段记 full|related。
# --docs 只跑文档域闸(gdd_lint/doc_link/doc_term/流水线闸/引用可核/
# 能力审计+熵增闸)
# --docs 只跑文档域闸(06 gdd_lint/07 doc_link/08 doc_term/08c 流水线闸/08d 引用可核/
# 08e 能力审计+10 熵增闸)
# ——本批改动只有文档件时用:game/ 内的 .md(README、生成清单)、design/、根规则文件、
# tools/ 工具脚本、.zcode/ 配置等一切非代码面改动。
# --quick 全量档的中段自检形态:跳过渲染闸(窗口化,需开显示器)与静态扫描;完成出库禁用。
@@ -70,7 +70,7 @@ if [ "$DOMAIN" = "code" ] || [ "$DOMAIN" = "full" ]; then
fi
# 控制台编码:本仓库闸件输出中文与 ✅/✗ 符号。Windows GBK 控制台下 python 打印这些字符会抛
# UnicodeEncodeError——待办清单/熵增两闸直接崩(假红)、静态扫描的 FAIL 行被写成乱码字节(指纹漂移,
# UnicodeEncodeError——待办清单/10 两闸直接崩(假红)、09 的 FAIL 行被写成乱码字节(指纹漂移,
# 与基线比必判「红项清单变化」假红)、末尾汇总自身崩掉打不出结论。
export PYTHONIOENCODING=utf-8
@@ -207,10 +207,10 @@ suite_terms_for() { # suite_terms_for <仓库相对路径> → stdout: 套件
}
# ── 关联档选闸(2026-10-29 用户裁,推广自 2026-10-28 影响面选闸)──
# 三件保险恒跑不降:冒烟测试/系统测试/静态扫描(熵增闸照旧两域都跑)。
# 场景探针与渲染闸维持影响面口径:本批 diff 相对 master 分叉点的 game/ 改动若全部落在
# 三件保险恒跑不降:00 冒烟/01 系统测试/09 静态扫描(10 熵增闸照旧两域都跑)。
# 03 场景探针与 05 渲染闸维持影响面口径:本批 diff 相对 master 分叉点的 game/ 改动若全部落在
# 测量面(game/tests/**、game/sim/**——测试与模拟驱动件,不触场景树与渲染输出)则记 SKIP。
# 单元与集成测试改「选套件跑」:套件集=申报 ∪ 推导 取并集——
# 02 单元与集成改「选套件跑」:套件集=申报 ∪ 推导 取并集——
# 申报:在册需求卡片(本批 diff 触及的 reports/需求卡片*.md ∪ roadmap「进行中」迭代行登记的
# 卡片)对照表「验收测试」列提到的测试文件名,按文件名作为 --only 子串词归套件;
# 找不到在册卡片则申报集为空并输出注明。
@@ -218,9 +218,9 @@ suite_terms_for() { # suite_terms_for <仓库相对路径> → stdout: 套件
# 映射不到的文件一律按横切处理。
# 横切回落全量:diff 命中 game/data/tables/**、公共件前缀(config_db*/rng_service*/
# save_manager*/meta_progression*/main*——main* 覆盖组合根拆件与主场景)、
# autoload 注册面(game/project.godot)、或下方横切触面表任一 → 单元与集成测试跑全部套件。
# 测量面批(game/ 改动全在 tests/sim):单元与集成测试照旧全套件跑(不加过滤)。
# 回执 scope 字段:full|related(单元与集成测试跑子集=related);映射表只在本脚本一处定义。
# autoload 注册面(game/project.godot)、或下方横切触面表任一 → 02 跑全部套件。
# 测量面批(game/ 改动全在 tests/sim):02 照旧全套件跑(不加过滤)。
# 回执 scope 字段:full|related(02 跑子集=related);映射表只在本脚本一处定义。
NONBEHAVIOR=0
SCOPE="full"
ONLY_TERMS=""
@@ -231,9 +231,9 @@ if in_domain code; then
_behavior="$(echo "$_gfiles" | grep -vE '^(game/tests/|game/sim/)' || true)"
if [ -n "$_gfiles" ] && [ -z "$_behavior" ]; then
NONBEHAVIOR=1
echo "[gates] 影响面选闸:game/ 改动全在测量面(tests/sim)——场景探针/渲染闸 → SKIP(冒烟测试/系统测试/静态扫描三件保险恒跑)"
echo "[gates] 影响面选闸:game/ 改动全在测量面(tests/sim)——03 场景探针/05 渲染闸 → SKIP(00/01/09 三件保险恒跑)"
fi
# ── 选套件推导(只对行为面代码文件做——测量面文件不进推导,其验证就是单元与集成测试/静态扫描自身)──
# ── 02 选套件推导(只对行为面代码文件做——测量面文件不进推导,其验证就是 02/09 自身)──
_codefiles="$(echo "$_gfiles" | grep -viE '\.md$' | grep -vE '^(game/tests/|game/sim/)' || true)"
if [ -n "$_codefiles" ]; then
CROSSCUT=0
@@ -269,7 +269,7 @@ if in_domain code; then
done
if [ "$CROSSCUT" -eq 1 ]; then
SCOPE="full"
echo "[gates] 关联档选闸:diff 命中横切面(公共件/数据表/autoload/数值·存档·RNG·结算触面)——单元与集成测试回落全部套件"
echo "[gates] 关联档选闸:diff 命中横切面(公共件/数据表/autoload/数值·存档·RNG·结算触面)——02 回落全部套件"
else
# 并集去重:推导族词 ∪ 申报测试文件名;并集非空才过滤(映射表保证族词非空,此处双保险)。
_union="$(printf '%s\n' $_family_terms $_declared_names | sed '/^$/d' | sort -u | tr '\n' ' ' || true)"
@@ -285,12 +285,12 @@ if in_domain code; then
echo "[gates] 关联档选闸·申报:未找到在册需求卡片(diff 与 roadmap 进行中行均无),申报集为空——仅按 diff 推导"
fi
if [ "$SCOPE" = related ]; then
echo "[gates] 关联档选闸:单元与集成测试选套件跑(--only=${ONLY_TERMS})"
echo "[gates] 关联档选闸:02 选套件跑(--only=${ONLY_TERMS})"
fi
fi
fi
# ── 代码域起手自检(闸承载:只省烧闸,不做合回判定——真判定在各闸与合回 guard)──
# ── 代码域起手自检(闸承载:只省烧闸,不做合回判定——真判定在 00–11 与合回 guard)──
if in_domain code; then
# worktree 素材同步:素材走 gitignore 不入 git,worktree 冷检出缺件=呈现断言红的环境成因;
# 主工作区直跑=脚本内自动无操作。
@@ -332,7 +332,7 @@ gate() { # gate <名称> <日志名> <命令...>
}
gate_unit() { # run_all 是 --script 模式,退出码为唯一判据;分片态=多 Godot 进程各跑一片
local name="单元与集成测试"
local name="02 单元与集成测试"
# 关联档选跑:把套件词列表经 --only= 传给 run_all(闸机来源标记 --only-source=gates,
# 入口据此打关联档横幅、不落「仅供开发期」免责句);全量态不传任何选跑参数。
local -a _user_args=()
@@ -396,63 +396,63 @@ gate_unit() { # run_all 是 --script 模式,退出码为唯一判据;分
return 0
}
# ══ 代码域 ══
# ══ 代码域(0–5)══
if in_domain code; then
# ── 冒烟测试(极小启动场景:真实开机路径存活检查,零逻辑判定,秒级)──
# 三件保险之一(冒烟测试/系统测试/静态扫描):恒跑不降——测量面批也不免(关联档选闸,2026-10-29 用户裁)。
gate "冒烟测试" "smoke_boot.log" "$PY" "$REPO/tools/run_smoke.py"
# ── 系统测试(真实玩法路径断言面;宿主=game/tests/system_test.gd,缺省 --script 由 run_system_test.py 持有)──
gate "系统测试" "system_test.log" "$PY" "$REPO/tools/run_system_test.py"
# ── 单元与集成测试 ──
# ── 0. 冒烟测试(极小启动场景:真实开机路径存活检查,零逻辑判定,秒级)──
# 三件保险之一(00/01/09):恒跑不降——测量面批也不免(关联档选闸,2026-10-29 用户裁)。
gate "00 冒烟测试" "smoke_boot.log" "$PY" "$REPO/tools/run_smoke.py"
# ── 1. 系统测试(真实玩法路径断言面;宿主=game/tests/system_test.gd,缺省 --script 由 run_system_test.py 持有)──
gate "01 系统测试" "system_test.log" "$PY" "$REPO/tools/run_system_test.py"
# ── 2. 单元与集成测试 ──
gate_unit
# ── 场景探针(走查+断言十件一次跑齐;iter27 漏跑断言段事故后固化为无条件整闸)──
# ── 3. 场景探针(走查+断言十件一次跑齐;iter27 漏跑断言段事故后固化为无条件整闸)──
if [ $NONBEHAVIOR -eq 1 ]; then
NAMES+=("场景探针"); EXITS+=("SKIP"); LOGS+=("")
echo ""; echo "[gates] 场景探针 → SKIP(影响面选闸:测量面改动不触场景树与探针断言面)"
NAMES+=("03 场景探针"); EXITS+=("SKIP"); LOGS+=("")
echo ""; echo "[gates] 03 场景探针 → SKIP(影响面选闸:测量面改动不触场景树与探针断言面)"
else
gate "场景探针" "probe.log" bash "$REPO/tools/probe_gate.sh" "$GAME"
gate "03 场景探针" "probe.log" bash "$REPO/tools/probe_gate.sh" "$GAME"
fi
# ── 渲染闸(窗口化,依赖 PIL)──
# ── 5. 渲染面(窗口化,依赖 PIL)──
if [ $QUICK -eq 1 ] || [ $NONBEHAVIOR -eq 1 ]; then
NAMES+=("渲染闸"); EXITS+=("SKIP"); LOGS+=("")
echo ""; echo "[gates] 渲染闸 → SKIP(--quick 或 影响面选闸:测量面改动不触渲染输出)"
NAMES+=("05 渲染闸"); EXITS+=("SKIP"); LOGS+=("")
echo ""; echo "[gates] 05 渲染闸 → SKIP(--quick 或 影响面选闸:测量面改动不触渲染输出)"
else
gate "渲染闸" "render.log" bash "$REPO/tools/render_gate.sh" "$GAME"
gate "05 渲染闸" "render.log" bash "$REPO/tools/render_gate.sh" "$GAME"
fi
# ── 色板闸(§4.1 新色双门②:素材新增色 vs 基线〔token∪素材快照〕近色判红;
# ── 5b. 色板闸(§4.1 新色双门②:素材新增色 vs 基线〔token∪素材快照〕近色判红;
# 门①语义检查属设计面人工核对不入机检;基线刷新=tools/gen_palette_baseline.py,素材批收尾动作)──
if [ $QUICK -eq 1 ] || [ $NONBEHAVIOR -eq 1 ]; then
NAMES+=("色板闸"); EXITS+=("SKIP"); LOGS+=("")
echo ""; echo "[gates] 色板闸 → SKIP(--quick 或 影响面选闸:素材色板面不随测量面改动开闸)"
NAMES+=("05b 色板闸"); EXITS+=("SKIP"); LOGS+=("")
echo ""; echo "[gates] 05b 色板闸 → SKIP(--quick 或 影响面选闸:素材色板面不随测量面改动开闸)"
else
gate "色板闸" "palette.log" "$PY" "$REPO/tools/palette_check.py" "$GAME/assets/art" --baseline "$REPO/game/tests/golden/palette_baseline"
gate "05b 色板闸" "palette.log" "$PY" "$REPO/tools/palette_check.py" "$GAME/assets/art" --baseline "$REPO/game/tests/golden/palette_baseline"
fi
fi
# ══ 文档域 ══
# ══ 文档域(6–8e)══
if in_domain docs; then
# 全量档(CI 与手动档同判定面)
gate "gdd_lint" "gdd_lint.log" "$PY" "$REPO/tools/gdd_lint.py"
gate "变更记录节" "changelog.log" "$PY" "$REPO/tools/gdd_lint.py" --changelog-only
gate "doc_link" "doc_link.log" "$PY" "$REPO/tools/doc_link_audit.py" --strict
gate "doc_term" "doc_term.log" "$PY" "$REPO/tools/doc_term_audit.py" --strict
gate "流水线闸" "pipeline.log" "$PY" "$REPO/tools/pipeline_gate.py"
gate "引用可核" "doc_ref.log" "$PY" "$REPO/tools/doc_ref_audit.py" --strict
gate "能力审计" "capability.log" "$PY" "$REPO/tools/capability_audit.py" --strict
gate "06 gdd_lint" "gdd_lint.log" "$PY" "$REPO/tools/gdd_lint.py"
gate "06b 变更记录节" "changelog.log" "$PY" "$REPO/tools/gdd_lint.py" --changelog-only
gate "07 doc_link" "doc_link.log" "$PY" "$REPO/tools/doc_link_audit.py" --strict
gate "08 doc_term" "doc_term.log" "$PY" "$REPO/tools/doc_term_audit.py" --strict
gate "08c 流水线闸" "pipeline.log" "$PY" "$REPO/tools/pipeline_gate.py"
gate "08d 引用可核" "doc_ref.log" "$PY" "$REPO/tools/doc_ref_audit.py" --strict
gate "08e 能力审计" "capability.log" "$PY" "$REPO/tools/capability_audit.py" --strict
fi
# ── 静态扫描(代码域)+ 熵增闸(两域都跑:它查顶层目录/根文件/图像白名单/退役路径,
# ── 7. 静态扫描(代码域)+ 熵增闸(两域都跑:它查顶层目录/根文件/图像白名单/退役路径,
# 文档批新增或挪动 design/ 下的文件同样会绊它;纯文本扫描,秒级)──
if [ $QUICK -eq 0 ]; then
if in_domain code; then
gate "静态扫描" "static_scan.log" bash "$GAME/tests/static_scan.sh"
gate "09 静态扫描" "static_scan.log" bash "$GAME/tests/static_scan.sh"
fi
gate "熵增闸" "entropy.log" "$PY" "$REPO/tools/repo_structure_audit.py"
gate "10 熵增闸" "entropy.log" "$PY" "$REPO/tools/repo_structure_audit.py"
else
if in_domain code; then
NAMES+=("静态扫描"); EXITS+=("SKIP"); LOGS+=("")
NAMES+=("09 静态扫描"); EXITS+=("SKIP"); LOGS+=("")
fi
NAMES+=("熵增闸"); EXITS+=("SKIP"); LOGS+=("")
echo ""; echo "[gates] 静态扫描(代码域)/ 熵增闸 → SKIP(--quick)"
NAMES+=("10 熵增闸"); EXITS+=("SKIP"); LOGS+=("")
echo ""; echo "[gates] 09 静态扫描(代码域)/ 10 熵增闸 → SKIP(--quick)"
fi
# ── 与存量基线比对 ──