| name | comply |
| description | 对任意项目文件(gene、spec、skill、script、wiki页面等)执行三类语义检查:过时错误(不再符合项目现状)、逻辑错误(文件内部自相矛盾)、违宪违法(违反CONSTITUTION.md或LAW.md)。wiki页面额外执行N1–N7结构检查+C1–C9内容检查(共16项)。默认只报告,不修改文件;指定 --fix 时自动修复可修复的机械性问题。当用户说 /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 节的代码块(```)数量:
import re, sys
spec_path = sys.argv[1]
inst_path = sys.argv[2]
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 节的复选框([ ])数量,含代码块内的:
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)
inst_all = inst_cnt
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%:
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 节中搜索 {{...}} 模式:
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 的完整结构树(标题下的第一级结构元素类型),与实例对比:
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 = {}
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(全局体量)的补充——防止个别小节骨架化被其他小节掩盖。
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)
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)
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)
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)
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)
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 时,在缺少空行的 ::: 块前插入空行:
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 §十二)
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)
grep -n "^#{1,3} .*\[\[" <文件路径> | sed 's/^/ - /' || echo "OK"
C8 截断 Wikilink(CONSTITUTION §8.6)
grep -n "\[\[.*\.\.\.\]\]\|\[\[.*…\]\]" <文件路径> | sed 's/^/ - /' || echo "OK"
C9 语义块空格缺失(CONSTITUTION §13.2)
规则:::: 与块类型名之间必须有空格。:::query(无空格)导致解析静默失效。
grep -n "^:::[a-zA-Z]" <文件路径> | sed 's/^/ - /' || echo "OK"
C9 Fix(仅 --fix 模式)
当指定 --fix 时,在 ::: 与类型名之间插入空格:
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)
将中文文本中禁止使用的"但丁"、"但尔"替换为"管家":
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/:
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)
按已知映射表替换已废弃的引用:
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
- 检查结果是建议,修复由调用方决定