工程(复核纪律批·机检面): pipeline_gate 新增卡片复核判据——生效日 REVIEW_RULE_DATE=(2026,11,6) 按文件名日期挡旧卡;三条子判据=有「复核记录」节/节内每条发现记录带四类去向之一(自判·补写·待裁·退回上游)且表格行处置格非空/节末申报 reports/复核-*.md 且文件在盘可核;分流语义不判。头注与 check_cards 文档串随动(卡片口径列 C1–C6)·cross_check 注释编排五查随动。四态自证(临时卡 reports/需求卡片-闸件自检临时-2026-11-07.md 验毕已删):缺节→判据「复核记录缺失」exit 1;记录行无去向→「复核去向未标」+「复核记录空节」+「复核报告未申报」exit 1;合规节→复核类红项 0(该临时卡剩 3 红均为造件自身的 能力行/行锚/审计声明 缺项,属预期);处置空格+假报告路径→「复核处置未填」+「复核报告不可核」exit 1。存量三张卡(最新 2026-11-05)不受影响 exit=0

This commit is contained in:
DKChan committed 2026-11-05 07:01:37 +08:00
1 parent b86e0b803a
commit 121aca4073
1 file changed
+70 -2
+70 -2
View File
@@ -5,7 +5,8 @@ r"""pipeline_gate.py — 工作流程流水线闸(待办清单条目状态机
职责:机检待办清单条目(标题元数据与可选优先级档名/四属性齐备与旧属性名防回潮/状态词白名单/
改动面四档白名单/条件凭据/无设计线段条目的证据指认/状态段累积制/特批/正文限长双判据/零命中)
与 roadmap 迭代总表(六列/状态五形态/卡片与报告存在性/编入时间与预计周期的
分档放行)/需求卡片口径(C1 文档义务/C2 设计事实源/C3 改动—验收对照表/C4 验收档申报)+一次交叉核。
分档放行)/需求卡片口径(C1 文档义务/C2 设计事实源/C3 改动—验收对照表/C4 验收档申报/
C5 判据出处行锚/C6 复核记录)+一次交叉核。
约束:每红项一行「文件:行号 判据名 一句白话说明」,exit 0=全绿 / 1=有红 / 2=输入件缺失;
卡片与报告存在性相对 --repo-root 解析(缺省=本文件上两级);待办清单与 roadmap 均已为新格式
(2026-10-18 数据整改批),本闸已注册进 tools/run_all_gates.sh 文档域(流水线闸)。
@@ -66,6 +67,12 @@ 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+)")
# C6 复核记录(2026-11-05 立,生效 2026-11-06;req-card 必备结构第 17 节+纪律「复核发现四类分流」)
REVIEW_RULE_DATE = (2026, 11, 6)
REVIEW_HEADING_RE = re.compile(r"^#{2,4}\s*\d*\.?\s*复核记录")
REVIEW_TARGET_WORDS = ("自判", "补写", "待裁", "退回上游")
REVIEW_HEADER_WORDS = ("轮次", "去向")
REVIEW_REPORT_RE = re.compile(r"reports/复核-[^\s()(),,、|]+\.md")
# 待办条目正文限长双判据(2026-11-04 立,doc-conventions §12.1:行数抓清单蔓延、字数抓单行堆砌)
ENTRY_MAX_LINES = 12
ENTRY_MAX_CHARS = 700
@@ -455,7 +462,7 @@ def cross_check(links, index, issues, where):
一条目可有多张已写卡分编多个迭代(状态段累积「已编迭代 40+已编迭代 41」):
对每个已编迭代号核两件——总表该行存在;该行卡片列含本条目至少一张已写卡路径。
哪张卡编哪个迭代的卡级映射由编排四查与人工核验,闸不猜卡级映射。
哪张卡编哪个迭代的卡级映射由编排五查与人工核验,闸不猜卡级映射。
"""
for line, no, cards in links:
row = index.get(no)
@@ -641,6 +648,55 @@ def check_ledger(text, path, when, issues, root):
"表内没有数据行"))
def check_review(lines, start, path, issues, root):
"""C6 复核记录的单节校验(req-card 必备结构第 17 节,生效 2026-11-06)。
只查结构与可核性:节内每条记录行都要带四类去向之一(自判/补写/待裁/退回上游),
表格行的处置结果格(末格)非空;节内须申报 reports/复核-*.md 路径且该文件在盘上存在。
分流分得对不对属语义判断,本闸不判。返回节末行下标(不含)。
"""
end = len(lines)
for i in range(start + 1, len(lines)):
if lines[i].strip().startswith("#"):
end = i
break
records = 0
for i in range(start + 1, end):
s = lines[i].strip()
if not s or s.startswith("|") and SEP_ROW_RE.match(s):
continue
is_row = s.startswith("|")
is_bullet = bool(re.match(r"^[-*]\s+", s))
if not (is_row or is_bullet):
continue
if any(mark in s for mark in REVIEW_HEADER_WORDS):
continue
if not any(word in s for word in REVIEW_TARGET_WORDS):
issues.append((str(path), i + 1, "复核去向未标",
"该条复核记录缺四类去向之一(自判/补写/待裁/退回上游)——"
"先按 req-card「复核发现四类分流」判归属,前两类禁转成问句呈报用户"))
continue
if is_row:
cells = row_cells(s)
if not cells or not cells[-1].strip():
issues.append((str(path), i + 1, "复核处置未填",
"处置结果格为空——须写改了卡内哪一节、退给了哪一段、或用户裁决的结论"))
records += 1
if records == 0:
issues.append((str(path), start + 1, "复核记录空节",
"「复核记录」节内没有一条发现记录——卡片必经对抗复核并逐轮登记"))
sec = "\n".join(lines[start:end])
reports = REVIEW_REPORT_RE.findall(sec)
if not reports:
issues.append((str(path), start + 1, "复核报告未申报",
"「复核记录」节末须申报复核报告落盘路径 reports/复核-<批名>-<日期>.md"))
for rel in reports:
if not (root / rel).is_file():
issues.append((str(path), start + 1, "复核报告不可核",
"申报的复核报告不在盘上:%s" % rel))
return end
def check_cards(root, issues):
"""C1 文档义务口径(生效 2026-10-17)+C2 设计事实源声明(生效 2026-10-18)
+C3 改动—验收对照表结构(生效 2026-10-21)。
@@ -654,6 +710,8 @@ def check_cards(root, issues):
能力行列(2026-10-29 起)既有与新增的名称都须在 game/tests/README.md 能力表在场
(新增=写卡同批入表,test-conventions §8.3);至少一行;必填格非空;全文含「验收审计」声明。
语义覆盖不在此判。
C6 判据(生效 2026-11-06):有「复核记录」节;节内每条发现记录带四类去向之一
(自判/补写/待裁/退回上游)且表格行处置格非空;节内申报 reports/复核-*.md 且文件在盘。
"""
dirn = root / CARD_DIR
if not dirn.is_dir():
@@ -680,6 +738,16 @@ def check_cards(root, issues):
issues.append((str(path), 1, "验收档未申报",
"须在卡片头部信息区申报「验收档:高/中/低」(2026-11-05 起,"
"test-conventions §8.3)"))
if when >= REVIEW_RULE_DATE:
lines = text.splitlines()
head = next((i for i, raw in enumerate(lines)
if REVIEW_HEADING_RE.match(raw.strip())), None)
if head is None:
issues.append((str(path), 1, "复核记录缺失",
"缺「复核记录」节——卡片必经对抗复核,逐轮发现与处置须登记在案"
"(req-card 必备结构第 17 节,2026-11-06 起生效)"))
else:
check_review(lines, head, path, issues, root)
if when < SYNC_RULE_DATE:
continue
in_sec = False