diff --git a/roadmap.md b/roadmap.md
index e43ce854..ecd6f58a 100644
--- a/roadmap.md
+++ b/roadmap.md
@@ -74,6 +74,7 @@
| 迭代 38 | 已完成(2026-10-26) | 已退役(git 历史可考) | 2026-10-26 | ≈5.225 个工作日 | 已退役(git 历史可考) |
| 迭代 39 | 待开工 | reports/需求卡片-冒险域拆件与账本实体化批-2026-10-26.md
reports/需求卡片-同调配装充能域封装批-2026-10-26.md
reports/需求卡片-技能池情境条件触发器批-2026-10-26.md | 2026-10-26 | ≈10.15 个工作日〔用户特批 2026-10-26 超 10 个工作日〕 | — |
| 迭代 40 | 待开工 | reports/需求卡片-B1战斗域拆件批-2026-10-27.md
reports/需求卡片-结构小件定点修批-2026-10-26.md | 2026-10-27 | ≈6.225 个工作日 | — |
+| 迭代 41 | 待开工 | reports/需求卡片-核心数据面结构收敛批-2026-10-27.md
reports/需求卡片-呈现层结构收敛批-2026-10-27.md | 2026-10-27 | ≈13.15 个工作日〔用户特批 2026-10-27 超 10 个工作日〕 | — |
- 迭代 38 收口为带红合并〔用户特批 2026-10-26〕:09 静态扫描 S13 gdstyle 恶化 2 条经批准记入基线存量红(git 提交 c4c69701),卡② 停卡退上游,处方已于 2026-10-26 修订定稿 v1.3(git 提交 b3ea7532),随「gdstyle 存量债全量清偿」条目波 7 待编排。
- 历史行的「—」= 该列事实不可考:迭代 1~8 早于需求卡片制;编排时点与预计周期不再回溯,细节查 git 提交史。
diff --git a/tools/pipeline_gate.py b/tools/pipeline_gate.py
index d6ee448b..fe707606 100644
--- a/tools/pipeline_gate.py
+++ b/tools/pipeline_gate.py
@@ -148,7 +148,7 @@ def check_segment(word, line, issues, where):
def check_status(raw, line, issues, where):
- """判据 3+状态段累积制(§12.1)+特批/备选。返回 (状态词列表, 已编迭代号|None)。
+ """判据 3+状态段累积制(§12.1)+特批/备选。返回 (状态词列表, 已编迭代号列表|[])。
累积制:按+切段后段数不限,逐段各自合法;再查一条结构约束——下游段
(待写卡/已写卡/已编迭代)在场时禁残留未闭合设计段(带日期特批可豁免)。
@@ -177,13 +177,13 @@ def check_status(raw, line, issues, where):
if not segs:
issues.append((where, line, "状态词非法", "状态行内容为空"))
return [], None
- words, iter_no = [], None
+ words, iter_nos = [], []
for seg in segs:
w, it = check_segment(seg, line, issues, where)
if w:
words.append(w)
if it is not None:
- iter_no = it
+ iter_nos.append(it)
# 同一设计线只留最新一段:并现两段说明推进时忘了收旧段,或把另一条线的段
# 误写进本线条目;跨条设计线的未闭合依赖(如文档线已闭合写卡、美术线仍待设计)合法。
for track, name in ((DOC_DESIGN_WORDS, "文档线"), (ART_DESIGN_WORDS, "美术线")):
@@ -191,7 +191,7 @@ def check_status(raw, line, issues, where):
if len(hit) > 1:
issues.append((where, line, "设计线段并现",
"%s同时出现 %s(同线只留最新一段,§12.1)" % (name, "、".join(hit))))
- return words, iter_no
+ return words, iter_nos
def check_todo(text, issues, where, root):
@@ -228,7 +228,7 @@ def check_todo(text, issues, where, root):
issues.append((where, line, "属性缺失", "条目缺「**%s**」属性" % req))
if "状态" not in attrs:
continue
- words, iter_no = check_status(attrs["状态"], attr_line["状态"], issues, where)
+ words, iter_nos = check_status(attrs["状态"], attr_line["状态"], issues, where)
# 改动面:四档取多,+连接,禁重复、禁自造词
if "改动面" in attrs:
parts = [p.strip() for p in SURFACE_SEP_RE.split(attrs["改动面"]) if p.strip()]
@@ -297,8 +297,9 @@ def check_todo(text, issues, where, root):
if not need_gap and words and "缺口" in attrs:
issues.append((where, line, "缺口属性",
"状态为 %s,设计已闭合/后段不得残留「**缺口**」属性" % "、".join(words)))
- if iter_no is not None:
- links.append((line, iter_no, cards[0] if cards else None))
+ if iter_nos:
+ for no in iter_nos:
+ links.append((line, no, cards))
return links
@@ -423,17 +424,23 @@ def check_roadmap(text, issues, where, root):
def cross_check(links, index, issues, where):
- """唯一一处交叉核:已编迭代 N ↔ 总表迭代 N 行的需求卡片列。"""
- for line, no, card in links:
+ """唯一一处交叉核:已编迭代 N ↔ 总表迭代 N 行的需求卡片列。
+
+ 一条目可有多张已写卡分编多个迭代(状态段累积「已编迭代 40+已编迭代 41」):
+ 对每个已编迭代号核两件——总表该行存在;该行卡片列含本条目至少一张已写卡路径。
+ 哪张卡编哪个迭代的卡级映射由编排四查与人工核验,闸不猜卡级映射。
+ """
+ for line, no, cards in links:
row = index.get(no)
if row is None:
issues.append((where, line, "交叉核", "迭代总表无迭代 %d 行" % no))
- elif card is None:
+ elif not cards:
issues.append((where, line, "交叉核",
"已编迭代 %d 但条目无可引的已写卡路径(须先已写卡)" % no))
- elif card not in row[1]:
+ elif not any(c in row[1] for c in cards):
issues.append((where, line, "交叉核",
- "迭代 %d 行卡片列不含本条目已写卡路径 %s" % (no, card)))
+ "迭代 %d 行卡片列不含本条目任何已写卡路径(%s)"
+ % (no, "/".join(cards[:3]))))
def card_date(path):
diff --git a/待办清单.md b/待办清单.md
index abf112d2..6942a0c7 100644
--- a/待办清单.md
+++ b/待办清单.md
@@ -18,7 +18,7 @@
**改动面**:游戏代码+工具代码
-**状态**:文档设计已闭合+已写卡+已编迭代 40
+**状态**:文档设计已闭合+已写卡+已编迭代 40+已编迭代 41
#### 波 0:gdstyle 基线刷新——清 18 陈旧键+登记迭代 40 还债水位(2026-10-27 登记,来源=会话提及)