# Comply

> 对任意项目文件（gene、spec、skill、script、wiki页面等）执行三类语义检查：过时错误（不再符合项目现状）、逻辑错误（文件内部自相矛盾）、违宪违法（违反CONSTITUTION.md或LAW.md）。wiki页面额外执行N1–N7结构检查+C1–C9内容检查（共16项）。默认只报告，不修改文件；指定 --fix 时自动修复可修复的机械性问题。当用户说 /comply <文件路径> 时触发。

- Skill: `orangeviolin/comply` (Agent Skill)
- Install (CLI): `npx skillmds@latest add orangeviolin/comply`
- Raw SKILL.md: https://api.skillmd.com/api/skills/orangeviolin/comply/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: OrangeViolin (https://skillmd.com/u/orangeviolin)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/orangeviolin/comply

---


# /comply — 项目文件合规检查

## 用法

```
/comply skills/gene/PRE6-corpus-linebreak-repair.md
/comply ref/spec/workflow-pdf-to-md.md
/comply wiki/scripts/build_chapter_pages.py
/comply docs/wiki/pages/turing.md
/comply docs/wiki/pages/turing.md --fix   # 检查并自动修复
```

## 概述

对任意项目文件（gene、spec、skill、**script**、wiki 页面等）执行三类语义检查，检查依据 `ref/spec/sys-norm-hierarchy.md` 定义的六层法源体系。**默认只报告，不修改文件**；指定 `--fix` 时自动修复可修复的机械性问题。若目标是 `docs/wiki/pages/` 下的 wiki 页面，额外执行 C1–C9 格式检查。

| 检查层 | 适用对象 | 对应基因 |
|--------|---------|---------|
| T 过时 / L 逻辑 / V 违宪 | 所有文件（含 Python 脚本） | **CHK5** genome-compliance（T/L/V 组） |
| GS1–GS3 配套脚本检查 | gene 文件（`skills/gene/*.md`） | **CHK5** GS 组 |
| SC1–SC3 调用基因上位法 | Python 脚本（`wiki/scripts/*.py` 等） | **CHK5** SC 组 |
| C1–C9 格式 | 仅 wiki 页面 | **CHK6** wiki-page-compliance |

**法源体系**：六层法源体系定义于 `ref/spec/sys-norm-hierarchy.md`（L1 宪法 > L2 本地法律 > L3 实施条例 > L4 技术规范 > L5 基因/技能 > L6 配置/规则/脚本）。其中 SC 组适用 L5（基因）是 L6（脚本）上位法的原则。

**Script 上位法规则**：对 Python 脚本执行合规检查时，调用该脚本的 gene（L5）即为其上位法。执行前在 `skills/gene/` 中 grep 脚本文件名，找出所有调用基因，再对照其描述检查脚本的函数签名（SC1）、输入输出格式（SC2）、调用约定（SC3）。若无调用基因则 SC 组跳过。

非 wiki 文件按 CHK5 的 T/L/V 组执行（详见 `skills/gene/CHK5-genome-compliance.md`）；wiki 页面在此基础上额外执行以下 C1–C9。

---

## PCF Phase Content Fidelity（BIRTH.md / GROW.md spec-instance 文件专属）

仅当目标文件为 `BIRTH.md` 或 `GROW.md` 且命令包含 `phase N` 参数时，在 CHK5 之后附加执行。
从对应的 `BIRTH.spec.md` / `GROW.spec.md` 提取 Phase N 节与实例文件逐项对比。

### PCF1 — 代码块完整性

统计 spec 和实例文件中 Phase N 节的代码块（```）数量：

```python
import re, sys
spec_path = sys.argv[1]   # BIRTH.spec.md / GROW.spec.md
inst_path = sys.argv[2]   # BIRTH.md / GROW.md
phase_n   = int(sys.argv[3])

def count_code_blocks(text, phase_n):
    pat = re.compile(rf'^##\s+Phase\s+{phase_n}[\s：]', re.M)
    nxt = re.compile(rf'^##\s+Phase\s+{phase_n + 1}[\s：]', re.M)
    m = pat.search(text)
    if not m: return 0
    start = m.start()
    m2 = nxt.search(text, start + 1)
    end = m2.start() if m2 else len(text)
    return len(re.findall(r'^```', text[start:end], re.M))

spec_cnt = count_code_blocks(open(spec_path).read(), phase_n)
inst_cnt = count_code_blocks(open(inst_path).read(), phase_n)
ratio = inst_cnt / spec_cnt * 100 if spec_cnt else 100
if inst_cnt < spec_cnt:
    print(f'✗ PCF1 代码块完整性: spec {spec_cnt} 个，实例 {inst_cnt} 个（{ratio:.0f}%）— 缺失 {spec_cnt - inst_cnt} 个')
elif inst_cnt > spec_cnt:
    print(f'○ PCF1 代码块完整性: spec {spec_cnt} 个，实例 {inst_cnt} 个（{ratio:.0f}%）— 多出 {inst_cnt - spec_cnt} 个（疑为专有扩展）')
else:
    print(f'✓ PCF1 代码块完整性: spec {spec_cnt} 个，实例 {inst_cnt} 个（100%）')
```

### PCF2 — 复选框完整性

统计 spec 和实例文件中 Phase N 节的复选框（`[ ]`）数量，含代码块内的：

```python
import re, sys
spec_path = sys.argv[1]
inst_path = sys.argv[2]
phase_n   = int(sys.argv[3])

def count_checkboxes(text, phase_n):
    pat = re.compile(rf'^##\s+Phase\s+{phase_n}[\s：]', re.M)
    nxt = re.compile(rf'^##\s+Phase\s+{phase_n + 1}[\s：]', re.M)
    m = pat.search(text)
    if not m: return 0
    start = m.start()
    m2 = nxt.search(text, start + 1)
    end = m2.start() if m2 else len(text)
    return len(re.findall(r'\[[\sx]\]', text[start:end]))

spec_cnt = count_checkboxes(open(spec_path).read(), phase_n)
inst_cnt = count_checkboxes(open(inst_path).read(), phase_n)
# spec 中为 [ ]，实例中可能已有 [x]
inst_all = inst_cnt  # 实例中 [ ] + [x] 的总数
if inst_all < spec_cnt:
    ratio = inst_all / spec_cnt * 100
    print(f'✗ PCF2 复选框完整性: spec {spec_cnt} 个，实例 {inst_all} 个（{ratio:.0f}%）— 缺失 {spec_cnt - inst_all} 个')
elif inst_all > spec_cnt * 1.2:
    print(f'○ PCF2 复选框完整性: spec {spec_cnt} 个，实例 {inst_all} 个 — 数量显著多于 spec，疑为专有扩展')
else:
    print(f'✓ PCF2 复选框完整性: spec {spec_cnt} 个，实例 {inst_all} 个（含已勾选）')
```

### PCF3 — 内容体量偏差检测

比较 spec 和实例文件中 Phase N 节的行数，偏差阈值 50%：

```python
import re, sys
spec_path = sys.argv[1]
inst_path = sys.argv[2]
phase_n   = int(sys.argv[3])

def section_line_count(text, phase_n):
    pat = re.compile(rf'^##\s+Phase\s+{phase_n}[\s：]', re.M)
    nxt = re.compile(rf'^##\s+Phase\s+{phase_n + 1}[\s：]', re.M)
    m = pat.search(text)
    if not m: return 0
    start = m.start()
    m2 = nxt.search(text, start + 1)
    end = m2.start() if m2 else len(text)
    return len(text[start:end].splitlines())

spec_lines = section_line_count(open(spec_path).read(), phase_n)
inst_lines = section_line_count(open(inst_path).read(), phase_n)
ratio = inst_lines / spec_lines * 100 if spec_lines else 100
if ratio < 50:
    print(f'✗ PCF3 内容体量偏差: spec {spec_lines} 行 → 实例 {inst_lines} 行（{ratio:.0f}%）— 疑似摘要而非实例化')
    print(f'  阈值 50%，当前 {ratio:.0f}% < 50%，建议检查是否存在批量遗漏。')
    print(f'  例外：若本节实际情况与通用模板差异大，可在节开头注明偏离以跳过体量检查。')
else:
    status = '✓' if ratio >= 80 else '○'
    print(f'{status} PCF3 内容体量偏差: spec {spec_lines} 行 → 实例 {inst_lines} 行（{ratio:.0f}%）— 正常')
```

### PCF4 — 占位符残留检测

在实例文件的 Phase N 节中搜索 `{{...}}` 模式：

```python
import re, sys
inst_path = sys.argv[1]
phase_n   = int(sys.argv[2])

pat = re.compile(rf'^##\s+Phase\s+{phase_n}[\s：]', re.M)
nxt = re.compile(rf'^##\s+Phase\s+{phase_n + 1}[\s：]', re.M)
txt = open(inst_path).read()
m = pat.search(txt)
if not m:
    print(f'✓ PCF4 占位符残留: Phase {phase_n} 在实例中未找到，跳过')
else:
    start = m.start()
    m2 = nxt.search(txt, start + 1)
    end = m2.start() if m2 else len(txt)
    section = txt[start:end]
    placeholders = re.findall(r'\{\{[^}]*\}\}', section)
    if placeholders:
        print(f'✗ PCF4 占位符残留: 发现 {len(placeholders)} 个未替换的占位符')
        for ph in placeholders[:10]:
            print(f'  {ph}')
        if len(placeholders) > 10:
            print(f'  …及 {len(placeholders) - 10} 个更多')
    else:
        print('✓ PCF4 占位符残留: 无')
```

### PCF5 — 结构性节缺失检测

从 spec 提取 Phase N 的完整结构树（标题下的第一级结构元素类型），与实例对比：

```python
import re, sys
spec_path = sys.argv[1]
inst_path = sys.argv[2]
phase_n   = int(sys.argv[3])

def extract_structure(text, phase_n):
    pat = re.compile(rf'^##\s+Phase\s+{phase_n}[\s：]', re.M)
    nxt = re.compile(rf'^##\s+Phase\s+{phase_n + 1}[\s：]', re.M)
    m = pat.search(text)
    if not m: return {}, 0
    start = m.start()
    m2 = nxt.search(text, start + 1)
    end = m2.start() if m2 else len(text)
    section = text[start:end]
    struct = {}  # heading → [element_types]
    current_h = None
    for line in section.splitlines():
        h = re.match(r'^(#{2,4})\s+(.+)', line)
        if h:
            current_h = h.group(2).strip()
            struct[current_h] = []
            continue
        if current_h and line.strip():
            if line.startswith('```'):
                struct[current_h].append('codeblock')
            elif line.startswith('|'):
                struct[current_h].append('table')
            elif line.startswith('- [') or line.startswith('* ['):
                struct[current_h].append('checkbox')
            elif line.startswith('>'):
                struct[current_h].append('blockquote')
            elif re.match(r'^-\s', line) or re.match(r'^\*\s', line):
                struct[current_h].append('list')
    return struct, len(section.splitlines())

spec_struct, _ = extract_structure(open(spec_path).read(), phase_n)
inst_struct, _ = extract_structure(open(inst_path).read(), phase_n)

missing = {}
for h, elems in spec_struct.items():
    if h not in inst_struct:
        missing[h] = elems
    else:
        # 检查必需结构元素是否存在
        spec_types = set(elems)
        inst_types = set(inst_struct[h])
        missing_types = spec_types - inst_types
        if missing_types:
            missing[h] = list(missing_types)

if missing:
    print(f'✗ PCF5 结构性节缺失: {len(missing)} 处结构不完整')
    for h, elems in list(missing.items())[:10]:
        print(f'  节 "{h}": 缺少 {elems}')
    if len(missing) > 10:
        print(f'  …及 {len(missing) - 10} 个更多')
else:
    print('✓ PCF5 结构性节缺失: 全部结构元素存在')
```
### PCF6 — 逐节实例化深度检查（防偷懒）

对 Phase N 下每个 `###`/`####` 小节，分别计算 spec→instance 的体量偏差和内容一致性。
这是 PCF3（全局体量）的补充——防止个别小节骨架化被其他小节掩盖。

```python
import re, sys
spec_path = sys.argv[1]
inst_path = sys.argv[2]
phase_n   = int(sys.argv[3])

def get_subsections(text, phase_n):
    """Extract all ###/#### subsections under Phase N, return {heading: (start, end, content)}"""
    pat = re.compile(rf'^##\s+Phase\s+{phase_n}[\s：]', re.M)
    nxt = re.compile(rf'^##\s+Phase\s+{phase_n + 1}[\s：]', re.M)
    m = pat.search(text)
    if not m: return {}
    start = m.start()
    m2 = nxt.search(text, start + 1)
    end = m2.start() if m2 else len(text)
    lines = text[start:end].splitlines()
    subs = {}
    current_h = None
    current_start = 0
    for i, line in enumerate(lines):
        h = re.match(r'^(#{3,4})\s+(.+)', line)
        if h:
            if current_h:
                subs[current_h] = (current_start, i, '\n'.join(lines[current_start:i]))
            current_h = h.group(2).strip()
            current_start = i
    if current_h:
        subs[current_h] = (current_start, len(lines), '\n'.join(lines[current_start:]))
    return subs

spec_subs = get_subsections(open(spec_path).read(), phase_n)
inst_subs = get_subsections(open(inst_path).read(), phase_n)
all_headings = sorted(set(list(spec_subs.keys()) + list(inst_subs.keys())))
issues = []

for h in all_headings:
    in_spec = h in spec_subs
    in_inst = h in inst_subs
    if not in_inst:
        issues.append(f'  ✗ "{h}": 实例中缺失（spec 有此小节）')
        continue
    if not in_spec:
        issues.append(f'  ○ "{h}": 实例额外小节（专有扩展）')
        continue
    spec_lines = spec_subs[h][2].count('\n') + 1
    inst_lines = inst_subs[h][2].count('\n') + 1
    ratio = inst_lines / spec_lines * 100 if spec_lines else 100
    if ratio < 50:
        issues.append(f'  ✗ "{h}": 体量 {ratio:.0f}%（{spec_lines}→{inst_lines} 行）— 疑似骨架未实例化')
    elif ratio < 70:
        issues.append(f'  △ "{h}": 体量 {ratio:.0f}%（{spec_lines}→{inst_lines} 行）— 偏薄，建议核查')
    spec_body = spec_subs[h][2].split('\n', 1)[-1].strip() if '\n' in spec_subs[h][2] else ''
    inst_body = inst_subs[h][2].split('\n', 1)[-1].strip() if '\n' in inst_subs[h][2] else ''
    if spec_body and spec_body == inst_body:
        issues.append(f'  ⚠ "{h}": 内容与 spec 完全一致（逐字复制，未实例化）')

missing = len([i for i in issues if i.startswith('  ✗')])
warn = len([i for i in issues if i.startswith('  △')])
copy = len([i for i in issues if i.startswith('  ⚠')])
extra = len([i for i in issues if i.startswith('  ○')])
total_spec = len([h for h in all_headings if h in spec_subs])

if issues:
    print(f'PCF6 逐节实例化验证: spec {total_spec} 小节 → 实例 {len(inst_subs)} 小节')
    if missing or warn or copy or extra:
        print(f'  ✗ 缺失 {missing}   △ 偏薄 {warn}   ⚠ 未实例化 {copy}   ○ 扩展 {extra}')
    for i in issues[:20]:
        print(i)
    if len(issues) > 20:
        print(f'  …及 {len(issues) - 20} 个更多')
else:
    print(f'✓ PCF6 逐节实例化验证: 全部 {total_spec} 小节正常实例化，无骨架或复制')
```

---

## C1–C9 格式检查（仅限 wiki 页面）

仅当目标文件位于 `docs/wiki/pages/` 目录下时执行，按 `skills/gene/CHK6-wiki-page-compliance.md` 定义。

### C1 破折号滥用（CONSTITUTION §11.1）

```python
import re, sys
txt = open(sys.argv[1]).read()
body = txt.split('---', 2)[-1] if txt.startswith('---') else txt
issues = []
for i, line in enumerate(body.splitlines(), 1):
    dashes = [m.start() for m in re.finditer('——', line)]
    if len(dashes) >= 2:
        issues.append(f'  - line {i}: 同行 {len(dashes)} 个破折号，疑似链式文风: {line.strip()[:80]!r}')
    for m in re.finditer(r'[^\s「」『』…。，、]——[^\s「」『』…]', line):
        ctx = line[max(0,m.start()-10):m.end()+10]
        issues.append(f'  - line {i}: 破折号疑似句间连接符: {ctx.strip()!r}')
        break
print('\n'.join(issues) if issues else 'OK')
```

### C2 巨型段落（CONSTITUTION §11.2）

```python
import re, sys
txt = open(sys.argv[1]).read()
body = txt.split('---', 2)[-1] if txt.startswith('---') else txt
issues = []
for i, para in enumerate(re.split(r'\n{2,}', body)):
    s = para.strip()
    if not s or s.startswith(('>', '```', '|', ':::', '#')):
        continue
    n = len(re.findall(r'[。！？.!?]', s))
    if n > 6:
        issues.append(f'  - 段落{i+1}: 约 {n} 句，超 6 句建议拆分: {s[:60]!r}…')
print('\n'.join(issues) if issues else 'OK')
```

### C3 AI 链式表达（CONSTITUTION §11.1）

```python
import re, sys
txt = open(sys.argv[1]).read()
body = txt.split('---', 2)[-1] if txt.startswith('---') else txt
PATTERNS = [
    (r'对.{2,10}产生了(深远|重要|深刻|重大|积极|广泛)的?(影响|意义|作用)', '空洞评价短语'),
    (r'不仅.{2,20}而且.{2,20}还.{2,20}', '「不仅…而且…还…」三重串联'),
    (r'(具有|拥有).{0,5}(重要|深远|深刻|积极)的?(意义|价值|作用)', '「具有重要意义」类套话'),
    (r'在.{2,8}历史上占有重要地位', '「占有重要地位」套话'),
    (r'(值得|需要)注意的是[，,]', '「值得注意的是」过渡套话'),
    (r'(总的来说|综上所述|总体而言)[，,]', '「总的来说」型收尾套话'),
    (r'这(一|个).{0,5}(现象|问题|趋势|特点)表明', '「这一现象表明」转述腔'),
]
issues = []
for i, line in enumerate(body.splitlines(), 1):
    for pat, label in PATTERNS:
        if re.search(pat, line):
            issues.append(f'  - line {i}: {label}: {line.strip()[:80]!r}')
print('\n'.join(issues) if issues else 'OK')
```

### C4 无 PN 断言（CONSTITUTION §4.5）

```python
import re, sys
txt = open(sys.argv[1]).read()
body = txt.split('---', 2)[-1] if txt.startswith('---') else txt
issues = []
for i, line in enumerate(body.splitlines(), 1):
    s = line.strip()
    if not s or s.startswith(('#', '>', '|', '```', ':::')):
        continue
    if re.search(r'\b[12][0-9]{3}\b|公元前?[0-9]+年', s) \
       and not re.search(r'[（(][0-9]{3,4}-[0-9]{3}[）)]', s) \
       and len(s) > 30:
        issues.append(f'  - line {i}: 含年份事实但无 PN 引注（建议核查）: {s[:70]!r}')
print('\n'.join(issues) if issues else 'OK')
```

### C5 语义块空行缺失（CONSTITUTION §13.1）

```python
import re, sys
lines = open(sys.argv[1]).read().splitlines()
issues = []
for i, line in enumerate(lines):
    if re.match(r'^:::', line.strip()) and i > 0 and lines[i-1].strip() != '':
        issues.append(f'  - line {i+1}: ::: 块前缺少空行，前行: {lines[i-1].strip()!r}')
print('\n'.join(issues) if issues else 'OK')
```

### C5 Fix（仅 --fix 模式）

当指定 `--fix` 时，在缺少空行的 `:::` 块前插入空行：

```python
import re, sys, pathlib
path = sys.argv[1]
lines = pathlib.Path(path).read_text().splitlines()
new, fixed = [], 0
for i, line in enumerate(lines):
    if i > 0 and re.match(r'^:::', line.strip()) and lines[i-1].strip() != '':
        new.append('')
        fixed += 1
    new.append(line)
if fixed:
    pathlib.Path(path).write_text('\n'.join(new) + '\n')
    print(f'Fixed: {fixed} ::: 块前补空行')
else:
    print('OK')
```

### C6 引文格式（CONSTITUTION §十二）

```python
import re, sys
txt = open(sys.argv[1]).read()
body = txt.split('---', 2)[-1] if txt.startswith('---') else txt
lines = body.splitlines()
issues = []
in_q, q_start, q_lines = False, 0, []
for i, line in enumerate(lines, 1):
    if line.startswith('>'):
        if not in_q:
            in_q, q_start, q_lines = True, i, []
        q_lines.append(line)
    else:
        if in_q:
            qt = '\n'.join(q_lines)
            if not re.search(r'[（(][0-9]{3,4}-[0-9]{3}[）)]', qt):
                issues.append(f'  - line {q_start}–{i-1}: blockquote 无 PN 标注')
            for qi, ql in enumerate(q_lines):
                body_part = ql.lstrip('> ').strip()
                if re.search(r'[（(][0-9]{3,4}-[0-9]{3}[）)]', body_part) and len(body_part) > 10:
                    issues.append(f'  - line {q_start+qi}: PN 与引文正文同行，建议移到独立 > 行')
            in_q, q_lines = False, []
print('\n'.join(issues) if issues else 'OK')
```

### C7 标题含 Wikilink（CONSTITUTION §8.2）

```bash
grep -n "^#{1,3} .*\[\[" <文件路径> | sed 's/^/  - /' || echo "OK"
```

### C8 截断 Wikilink（CONSTITUTION §8.6）

```bash
grep -n "\[\[.*\.\.\.\]\]\|\[\[.*…\]\]" <文件路径> | sed 's/^/  - /' || echo "OK"
```

### C9 语义块空格缺失（CONSTITUTION §13.2）

规则：`:::` 与块类型名之间必须有空格。`:::query`（无空格）导致解析静默失效。

```bash
grep -n "^:::[a-zA-Z]" <文件路径> | sed 's/^/  - /' || echo "OK"
```

### C9 Fix（仅 --fix 模式）

当指定 `--fix` 时，在 `:::` 与类型名之间插入空格：

```python
import re, sys, pathlib
path = sys.argv[1]
txt = pathlib.Path(path).read_text()
new_txt, n = re.subn(r'(^:::[a-zA-Z])', lambda m: m.group(0)[:3] + ' ' + m.group(0)[3:], txt, flags=re.M)
if n:
    pathlib.Path(path).write_text(new_txt)
    print(f'Fixed: {n} ::: 块补空格')
else:
    print('OK')
```

### C10 PN 引注格式

PN 格式检查（合并 PN、半角括号等）由 **QUO7**（`skills/gene/QUO7-pn-format-lint.md`）统一负责。
在 wiki 页面 comply 中不需要再定义重复检查。

## 全量自动修复（仅 --fix 模式）

指定 `--fix` 时，除 C5（空行补全）和 C9（空格补全）外，还自动修复以下机械性问题：

### D3 Fix：命名规约（CONSTITUTION §17.1）

将中文文本中禁止使用的"但丁"、"但尔"替换为"管家"：

```python
import re, sys, pathlib
path = sys.argv[1]
txt = pathlib.Path(path).read_text()
new_txt, n1 = re.subn('但丁', '管家', txt)
new_txt, n2 = re.subn('但尔', '管家', new_txt)
n = n1 + n2
if n:
    pathlib.Path(path).write_text(new_txt)
    print(f'Fixed: {n} 处禁用用名替换为"管家"')
else:
    print('OK')
```

### S1 Fix：过时路径（CHK5 S1）

将已弃用的 `wiki/public` 替换为 `docs/wiki/`：

```python
import re, sys, pathlib
path = sys.argv[1]
txt = pathlib.Path(path).read_text()
if re.search(r'wiki/public', txt):
    txt = txt.replace('wiki/public', 'docs/wiki/')
    pathlib.Path(path).write_text(txt)
    print('Fixed: wiki/public → docs/wiki/')
else:
    print('OK')
```

### S3 Fix：过时引用替换（CHK5 S3）

按已知映射表替换已废弃的引用：

```python
import re, sys, pathlib
path = sys.argv[1]
txt = pathlib.Path(path).read_text()
mapping = [
    (r'\bln2pn\.py\b', 'corpus_search.py'),
    (r'\bD1\s+discover\b', 'SCN1-discover'),
    (r'\bhousekeeping_queue\.md\b', 'queue.md'),
]
new_txt, n = txt, 0
for pat, repl in mapping:
    new_txt, cnt = re.subn(pat, repl, new_txt)
    n += cnt
if n:
    pathlib.Path(path).write_text(new_txt)
    print(f'Fixed: {n} 处过时引用替换')
else:
    print('OK')
```

### S5 Fix（同 C9 Fix）

与 C9 一致——`:::` 与类型名之间补空格。参见上方 C9 Fix 节。

---

## 汇总输出格式

**非 wiki 页面**（如 `BIRTH.md`、`*.spec.md` 等非 gene 的 `.md`）：

```
comply: <文件路径>

=== CHK5 语义检查 ===
✓/✗ T 过时错误    （列出每处，或"无"）
✓/✗ L 逻辑错误    （列出每处，或"无"）
✓/✗ V 违宪违法    （列出每处，附条款引用，或"无"）
```

**BIRTH.md / GROW.md spec-instance 文件**（含 phase N 参数时，在 CHK5 后附加）：

```
=== PCF Phase Content Fidelity ===
✓/✗ PCF1 代码块完整性  （spec N 个，实例 M 个 — M/N%）
✓/✗ PCF2 复选框完整性  （spec N 个，实例 M 个 — 缺失 P 个在节 X）
✓/✗ PCF3 内容体量偏差  （spec N 行 vs 实例 M 行 — M/N%）
✓/✗ PCF4 占位符残留   （无 / 发现 N 个）
✓/✗ PCF5 结构性节缺失  （全部存在 / N 处缺失）
✓/✗ PCF6 逐节实例化验证（spec N 小节 vs 实例 M 小节 — 缺失/偏薄/未实例化/扩展）
```

**Gene 文件**（`skills/gene/*.md`）：

```
comply: skills/gene/<基因名>.md

=== CHK5 语义检查 ===
✓/✗ T 过时错误    （列出每处，或"无"）
✓/✗ L 逻辑错误    （列出每处，或"无"）
✓/✗ V 违宪违法    （列出每处，附条款引用，或"无"）

=== G 组 frontmatter 检查 ===
✓/✗ G1–G6 ...

=== S 组 内容时效检查 ===
✓/✗ S1–S5 ...

=== GS 配套脚本检查 ===
引用脚本：<脚本名>（若无引用则注明"无脚本引用，GS 组跳过"）
✓/✗ GS1 脚本存在性  （列出每个不存在的脚本，或"全部存在"）
✓/✗ GS2 签名一致性  （列出每处，或"无"）
✓/✗ GS3 输入输出一致（列出每处，或"无"）
```

> 若 gene 中无任何 `.py` 引用，省略 GS 节。

**Python 脚本**（`wiki/scripts/*.py` 等）：

```
comply: wiki/scripts/<脚本名>.py

=== CHK5 语义检查 ===
✓/✗ T 过时错误    （列出每处，或"无"）
✓/✗ L 逻辑错误    （列出每处，或"无"）
✓/✗ V 违宪违法    （列出每处，附条款引用，或"无"）

=== SC 调用基因上位法检查（法源体系 L5→L6，详见 ref/spec/sys-norm-hierarchy.md）===
调用基因：<基因文件名>（若多个则逐一列出）
✓/✗ SC1 函数签名    （列出每处，或"无"）
✓/✗ SC2 输入输出格式（列出每处，或"无"）
✓/✗ SC3 调用约定    （列出每处，或"无"）
```

> 若脚本无调用基因（grep 无结果），省略 SC 节，在语义检查后注明"无调用基因，SC 组跳过"。

**wiki 页面**（路径以 `docs/wiki/pages/` 开头）：

```
comply: <文件路径>

=== CHK5 语义检查 ===
✓/✗ T 过时错误    （列出每处，或"无"）
✓/✗ L 逻辑错误    （列出每处，或"无"）
✓/✗ V 违宪违法    （列出每处，附条款引用，或"无"）

=== CHK6 格式检查 ===
✓/✗ C1 破折号滥用
...

=== IMG11 图片检查（仅含 ::: image 块时输出）===
✓/✗ C1 冒号数（::: image 必须为 3 冒号）
✓/✗ C2 caption 存在性（::: image 块内必须有非空文本）
✓/✗ C4 图片文件存在（引用的 images/ 文件实际存在）
```

> **重要**：
> - 对非 wiki 文件，**完全省略 CHK6 节和 IMG11 节**。
> - 对 wiki 页面，若文件中**不含任何 `::: image` 块**，则完全省略 IMG11 节（不标注"跳过"）。
> - IMG11 的 C5（孤立图）/C6（epub 覆盖缺口）为全 wiki 级检查，不在单文件 comply 中执行。

### --fix 模式输出

指定 `--fix` 时，在常规检查结果后追加修复报告：

```
=== 自动修复 ===
✓ C5 语义块空行   Fixed: 2 处补空行
✓ C9 语义块空格   Fixed: 1 处补空格
✓ C10 PN 引注格式   由 QUO7 统一负责（本 skill 不重复定义）
✓ D3 命名规约     Fixed: 1 处「但丁」→「管家」
✓ S1 过时路径     OK
✓ S3 过时引用     OK
总计：修复 4 项，无需修复 2 项
```

可修复项完整列表：

| 检查 | 来源 | 修复内容 | 状态 |
|------|------|---------|------|
| C5 | CHK6 | `:::` 块前插入空行 | 修复 / OK |
| C9 | CHK6 | `:::` 与类型名间补空格 | 修复 / OK |
| C10 | CHK6 | PN 引注格式（由 QUO7 统一负责） | 本 skill 不重复定义 |
| D3 | CHK5 | 禁用名「但丁/但尔」→「管家」 | 修复 / OK |
| S1 | CHK5 | `wiki/public` → `docs/wiki/` | 修复 / OK |
| S3 | CHK5 | 过时引用按映射表替换 | 修复 / OK |

---

## 禁止事项

- **默认模式**下禁止修改被检查的文件
- **--fix 模式**下仅允许对以下机械性问题执行自动修复，禁止语义性修改：
  - C5：`:::` 块前补空行
  - C9：`:::` 与类型名间补空格
  - C10：PN 引注格式（由 QUO7 统一负责，本 skill 不定义 auto-fix）
  - D3：禁用名「但丁/但尔」→「管家」
  - S1：`wiki/public` → `docs/wiki/`
  - S3：过时引用按已知映射表替换
- 禁止 git commit
- 检查结果是建议，修复由调用方决定

