Files
dsh_ai1net_server/交付物/协作-同工作区多任务类别-20260930-图.html
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

480 lines
33 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>协作机制 · 同一工作区多任务类别 · 复盘图(2026-09-30)</title>
<style>
:root{
--bg:#0f1115; --panel:#161a21; --panel2:#1b2029; --line:#2a3140;
--tx:#e6e9ef; --tx2:#a8b0be; --tx3:#7d8695;
--red:#ff6b6b; --redbg:#3a1b1f; --amber:#ffb454; --amberbg:#3a2c14;
--green:#4ec9a0; --greenbg:#123028; --blue:#5aa9ff; --bluebg:#132539;
--purple:#b48cff; --purplebg:#241a3a;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--tx);
font-family:"Segoe UI","PingFang SC","Microsoft YaHei",system-ui,sans-serif;
font-size:13px;line-height:1.55;padding:26px 20px 60px}
.wrap{max-width:1180px;margin:0 auto}
h1{font-size:19px;margin:0 0 4px;font-weight:650}
.sub{color:var(--tx3);font-size:12px;margin-bottom:22px}
.card{background:var(--panel);border:1px solid var(--line);border-radius:10px;
padding:16px 18px 20px;margin-bottom:22px}
h2{font-size:15px;margin:0 0 3px;font-weight:620}
.cap{color:var(--tx3);font-size:11.5px;margin-bottom:14px}
svg{display:block;width:100%;height:auto}
.notes{margin-top:14px;display:grid;grid-template-columns:1fr 1fr;gap:10px}
.note{background:var(--panel2);border:1px solid var(--line);border-radius:8px;padding:9px 11px;font-size:12px}
.note b{color:var(--tx)}
.k{display:inline-block;padding:0 5px;border-radius:4px;font-size:11px;font-weight:600}
.k-red{background:var(--redbg);color:var(--red)}
.k-green{background:var(--greenbg);color:var(--green)}
.k-amber{background:var(--amberbg);color:var(--amber)}
@media(max-width:760px){.notes{grid-template-columns:1fr}}
</style>
</head>
<body>
<div class="wrap">
<h1>协作机制 · 同一工作区 · 多任务类别</h1>
<div class="sub">2026-09-30 | 归属锚点:跨工作区(cwd) → 同一工作区 + 名称前缀(任务类别) | 自测 <b>PASS 31 / FAIL 0</b> | 图 ③④ = 收尾整体验证抓到的两个「同族红线」复盘</div>
<!-- ─────────────── 图 1:泳道图 ─────────────── -->
<div class="card">
<h2>① 泳道图 · 「任务类别前缀」在哪些环节真正起作用</h2>
<div class="cap">横轴=机制流水线的五个环节;纵轴=四类参与物。<span class="k k-red">红格</span>=旧版在此失效(静默漏管);<span class="k k-green">绿格</span>=本棒修复后生效;<span class="k k-amber">黄格</span>=已知边界(诚实标注)。</div>
<svg viewBox="0 0 1140 560" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="ar" markerWidth="9" markerHeight="9" refX="7" refY="3.2" orient="auto">
<path d="M0,0 L7,3.2 L0,6.4 z" fill="#7d8695"/>
</marker>
<marker id="ar2" markerWidth="9" markerHeight="9" refX="7" refY="3.2" orient="auto">
<path d="M0,0 L7,3.2 L0,6.4 z" fill="#4ec9a0"/>
</marker>
</defs>
<!-- 表头 -->
<g font-size="12.5" fill="#a8b0be" text-anchor="middle">
<text x="150" y="30" font-weight="600">环节 →</text>
<text x="322" y="30">① 派活命名</text>
<text x="494" y="30">② 归属判定</text>
<text x="666" y="30">③ 主会话解析</text>
<text x="838" y="30">④ 投递</text>
<text x="1010" y="30">⑤ 展示/收尾</text>
</g>
<line x1="20" y1="40" x2="1120" y2="40" stroke="#2a3140"/>
<!-- 泳道底纹 -->
<g fill="#12161c">
<rect x="20" y="50" width="1100" height="120" rx="8"/>
<rect x="20" y="178" width="1100" height="120" rx="8"/>
<rect x="20" y="306" width="1100" height="120" rx="8"/>
<rect x="20" y="434" width="1100" height="106" rx="8"/>
</g>
<!-- 泳道名 -->
<g font-size="12.5" fill="#e6e9ef" font-weight="600">
<text x="34" y="115">主会话</text>
<text x="34" y="243">协作会话 / 协作棒</text>
<text x="34" y="371">自动唤醒任务</text>
<text x="34" y="492">协作程序 / 看板</text>
</g>
<g font-size="11" fill="#7d8695">
<text x="34" y="132">管类别清单、派活、收口</text>
<text x="34" y="260">干活的棒</text>
<text x="34" y="388">只当闹钟</text>
<text x="34" y="509">机械判定、投递、渲染</text>
</g>
<!-- 泳道 1 主会话 -->
<g>
<rect x="232" y="70" width="176" height="72" rx="7" fill="#132539" stroke="#5aa9ff"/>
<text x="244" y="92" font-size="12" fill="#e6e9ef">标题写类别</text>
<text x="244" y="110" font-size="11" fill="#5aa9ff">主控 · &lt;类别&gt; · &lt;具体&gt;</text>
<text x="244" y="128" font-size="11" fill="#a8b0be">例:主控 · 唤醒机制线 · …</text>
<rect x="420" y="70" width="176" height="72" rx="7" fill="#123028" stroke="#4ec9a0"/>
<text x="432" y="92" font-size="12" fill="#e6e9ef">类别进 sid 集</text>
<text x="432" y="110" font-size="11" fill="#4ec9a0">sid ∈ main_sids 即算本项目</text>
<text x="432" y="128" font-size="11" fill="#a8b0be">⛔ 标题无方括号也能认</text>
<rect x="608" y="70" width="176" height="72" rx="7" fill="#123028" stroke="#4ec9a0"/>
<text x="620" y="92" font-size="12" fill="#e6e9ef">每类各解析一条</text>
<text x="620" y="110" font-size="11" fill="#4ec9a0">resolve_mains()</text>
<text x="620" y="128" font-size="11" fill="#a8b0be">最长优先 · 主控优先</text>
<rect x="796" y="70" width="176" height="72" rx="7" fill="#132539" stroke="#5aa9ff"/>
<text x="808" y="92" font-size="12" fill="#e6e9ef">收该类的件</text>
<text x="808" y="110" font-size="11" fill="#5aa9ff">按件 line 选主会话</text>
<text x="808" y="128" font-size="11" fill="#a8b0be">⛔ 不投给别类别</text>
<rect x="984" y="70" width="124" height="72" rx="7" fill="#132539" stroke="#5aa9ff"/>
<text x="996" y="98" font-size="12" fill="#e6e9ef">被标「主会话」</text>
<text x="996" y="118" font-size="11" fill="#a8b0be">多条都对</text>
</g>
<!-- 泳道 2 协作棒 -->
<g>
<rect x="232" y="198" width="176" height="72" rx="7" fill="#132539" stroke="#5aa9ff"/>
<text x="244" y="220" font-size="12" fill="#e6e9ef">命名带类别前缀</text>
<text x="244" y="238" font-size="11" fill="#5aa9ff">[协作]-&lt;类别&gt;-&lt;具体&gt;</text>
<text x="244" y="256" font-size="11" fill="#a8b0be">标题=自动化名(自动带)</text>
<rect x="420" y="198" width="176" height="72" rx="7" fill="#3a1b1f" stroke="#ff6b6b"/>
<text x="432" y="220" font-size="12" fill="#e6e9ef">✗ 旧:只认一个 short</text>
<text x="432" y="238" font-size="11" fill="#ff6b6b">[短名] 之外的类别全判「否」</text>
<text x="432" y="256" font-size="11" fill="#a8b0be">⇒ 看板不列、收尾不算=漏管</text>
<rect x="608" y="198" width="176" height="72" rx="7" fill="#123028" stroke="#4ec9a0"/>
<text x="620" y="220" font-size="12" fill="#e6e9ef">✓ 新:认任一已登记类别</text>
<text x="620" y="238" font-size="11" fill="#4ec9a0">标题含 [&lt;类别&gt;] 即算</text>
<text x="620" y="256" font-size="11" fill="#a8b0be">⛔ 未登记的类别仍判否</text>
<rect x="796" y="198" width="176" height="72" rx="7" fill="#123028" stroke="#4ec9a0"/>
<text x="808" y="220" font-size="12" fill="#e6e9ef">上报带类别</text>
<text x="808" y="238" font-size="11" fill="#4ec9a0">--report … --line &lt;类别&gt;</text>
<text x="808" y="256" font-size="11" fill="#a8b0be">件 → 类别,投递据此选路</text>
<rect x="984" y="198" width="124" height="72" rx="7" fill="#3a2c14" stroke="#ffb454"/>
<text x="996" y="226" font-size="12" fill="#e6e9ef">历史 line</text>
<text x="996" y="246" font-size="11" fill="#ffb454">仍是工作区名</text>
<text x="996" y="264" font-size="11" fill="#a8b0be">照实多显示几行</text>
</g>
<!-- 泳道 3 唤醒任务 -->
<g>
<rect x="232" y="326" width="176" height="72" rx="7" fill="#123028" stroke="#4ec9a0"/>
<text x="244" y="348" font-size="12" fill="#e6e9ef">排期名也要带类别</text>
<text x="244" y="366" font-size="11" fill="#4ec9a0">[协作]-&lt;类别&gt;-唤醒轮A</text>
<text x="244" y="384" font-size="11" fill="#a8b0be">本棒已改(原缺第 2 级)</text>
<rect x="420" y="326" width="176" height="72" rx="7" fill="#123028" stroke="#4ec9a0"/>
<text x="432" y="348" font-size="12" fill="#e6e9ef">不被当主会话</text>
<text x="432" y="366" font-size="11" fill="#4ec9a0">标题含 [协作] ⇒ 排除</text>
<text x="432" y="384" font-size="11" fill="#a8b0be">这一条旧版已对</text>
<rect x="608" y="326" width="176" height="72" rx="7" fill="#132539" stroke="#5aa9ff"/>
<text x="620" y="348" font-size="12" fill="#e6e9ef">只拨钟</text>
<text x="620" y="366" font-size="11" fill="#5aa9ff">goalctl wake</text>
<text x="620" y="384" font-size="11" fill="#a8b0be">条件判断只在协作程序一处</text>
<rect x="796" y="326" width="176" height="72" rx="7" fill="#132539" stroke="#5aa9ff"/>
<text x="808" y="348" font-size="12" fill="#e6e9ef">投到「那一类」的主会话</text>
<text x="808" y="366" font-size="11" fill="#5aa9ff">按件 line 选路</text>
<text x="808" y="384" font-size="11" fill="#a8b0be">⛔ 无该类别主会话 ⇒ 降级报告</text>
<rect x="984" y="326" width="124" height="72" rx="7" fill="#132539" stroke="#5aa9ff"/>
<text x="996" y="354" font-size="12" fill="#e6e9ef">不抢锁</text>
<text x="996" y="374" font-size="11" fill="#a8b0be">闹钟不干活</text>
</g>
<!-- 泳道 4 协作程序/看板 -->
<g>
<rect x="232" y="452" width="364" height="72" rx="7" fill="#123028" stroke="#4ec9a0"/>
<text x="244" y="474" font-size="12" fill="#e6e9ef">类别是唯一键(一个词,四处同义)</text>
<text x="244" y="493" font-size="11" fill="#4ec9a0">goal.topics 的一项 ≡ 标题里的 &lt;类别&gt; ≡ 台账的 line ≡ 分工板的一行</text>
<text x="244" y="512" font-size="11" fill="#a8b0be">_goal_topics() | _topic_in_title() | _scan_mains() / _scan_ws_mains()(两处同款)</text>
<rect x="608" y="452" width="364" height="72" rx="7" fill="#123028" stroke="#4ec9a0"/>
<text x="620" y="474" font-size="12" fill="#e6e9ef">分工板的「行」=任务类别(原=工作区)</text>
<text x="620" y="493" font-size="11" fill="#4ec9a0">承接判据:topic == 线 ∨ cwd_tail == 线 ∨ 标题命中该线台账件</text>
<text x="620" y="512" font-size="11" fill="#a8b0be">双判据并列 ⇒ 新旧数据都能显示</text>
</g>
<!-- 箭头 -->
<g stroke="#7d8695" stroke-width="1.4" fill="none" marker-end="url(#ar)">
<path d="M408 106 L420 106"/>
<path d="M596 106 L608 106"/>
<path d="M784 106 L796 106"/>
<path d="M972 106 L984 106"/>
<path d="M408 234 L420 234"/>
<path d="M784 234 L796 234"/>
<path d="M408 362 L420 362"/>
<path d="M784 362 L796 362"/>
</g>
</svg>
<div class="notes">
<div class="note"><b>哪一格红了</b>:<span class="k k-red">「归属判定 · 只认一个 short」</span> ——
这是本棒修的**根因**。它不是崩溃,是**什么也不说**:那两个类别的会话从此不出现在看板上、
也不算"在跑" ⇒ 收尾确认会**误判可以派下一棒**。</div>
<div class="note"><b>哪几道防线缺席</b>:<br>
① 缺「**类别是一组**」的概念(旧代码把归属键写死成单值);<br>
② 缺「**按类别选主会话**」的选路(旧代码只有"唯一主会话");<br>
③ 缺「**命名规范覆盖自动唤醒任务**」的检查(唤醒轮名缺第 2 级没人拦)。</div>
<div class="note"><b>修好之后补上的三道闸</b>:<br>
① 归属判据吃**类别集合**(传 str 时与旧版逐字一致);<br>
② 投递经 <code>main_for_topic()</code>:**已登记类别严格取该类**、未登记才回落默认;<br>
③ 自测加了 **9 条结构断言 + 8 例多类别比对**(含"两处 by_topic 结构必须同款")。</div>
<div class="note"><b>为什么现在才对</b>:本工作区**本来就有 ≥2 条"主控"会话**,
类别名**早就写在标题里**(<code>主控 · 唤醒机制线 · …</code> / <code>[主控]-[机制线]-接续…</code>)。
也就是说"用前缀分任务类别"是**已经在用的习惯**,只是**程序侧没认**。本棒把它接上,
并把"类别清单"做成 <code>goal.json.topics</code> 一个可由主会话随时改的字段。</div>
</div>
</div>
<!-- ─────────────── 图 2:缺口 → 修复 链图 ─────────────── -->
<div class="card">
<h2>② 缺口 → 修复 链图 · 旧版是怎么静默漏管的、新版在哪一步拦住</h2>
<div class="cap">上排=**失效链**(旧版一步步走到"漏管");下排=**修复链**(新版在同样的步子上换成什么判据)。每步都标出**判据**。</div>
<svg viewBox="0 0 1140 430" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="ar3" markerWidth="10" markerHeight="10" refX="8" refY="3.5" orient="auto">
<path d="M0,0 L8,3.5 L0,7 z" fill="#ff6b6b"/>
</marker>
<marker id="ar4" markerWidth="10" markerHeight="10" refX="8" refY="3.5" orient="auto">
<path d="M0,0 L8,3.5 L0,7 z" fill="#4ec9a0"/>
</marker>
</defs>
<text x="20" y="26" font-size="13" font-weight="650" fill="#ff6b6b">失效链(旧版)</text>
<line x1="20" y1="36" x2="1120" y2="36" stroke="#3a1b1f"/>
<g>
<rect x="20" y="52" width="200" height="96" rx="8" fill="#3a1b1f" stroke="#ff6b6b"/>
<text x="34" y="76" font-size="12" font-weight="600" fill="#e6e9ef">① 主会话按类别命名</text>
<text x="34" y="96" font-size="11" fill="#a8b0be">主控 · 唤醒机制线 · …</text>
<text x="34" y="114" font-size="11" fill="#a8b0be">[协作]-[机制线]-…</text>
<text x="34" y="133" font-size="10.5" fill="#7d8695">判据:用户/主会话习惯</text>
<rect x="248" y="52" width="200" height="96" rx="8" fill="#3a1b1f" stroke="#ff6b6b"/>
<text x="262" y="76" font-size="12" font-weight="600" fill="#e6e9ef">② 归属判据只认一个</text>
<text x="262" y="96" font-size="11" fill="#ff6b6b">("[short]") in 标题</text>
<text x="262" y="114" font-size="11" fill="#a8b0be">short = 单个值</text>
<text x="262" y="133" font-size="10.5" fill="#7d8695">判据:_in_project()</text>
<rect x="476" y="52" width="200" height="96" rx="8" fill="#3a1b1f" stroke="#ff6b6b"/>
<text x="490" y="76" font-size="12" font-weight="600" fill="#e6e9ef">③ 另一类别判「否」</text>
<text x="490" y="96" font-size="11" fill="#ff6b6b">不属于本项目</text>
<text x="490" y="114" font-size="11" fill="#a8b0be">⛔ 不报错、不告警</text>
<text x="490" y="133" font-size="10.5" fill="#7d8695">静默</text>
<rect x="704" y="52" width="200" height="96" rx="8" fill="#3a1b1f" stroke="#ff6b6b"/>
<text x="718" y="76" font-size="12" font-weight="600" fill="#e6e9ef">④ 看板不列它</text>
<text x="718" y="96" font-size="11" fill="#a8b0be">分工板按 cwd 归线</text>
<text x="718" y="114" font-size="11" fill="#a8b0be">同工作区 ⇒ 塌成一行</text>
<text x="718" y="133" font-size="10.5" fill="#7d8695">判据:cwd_tail == 线</text>
<rect x="932" y="52" width="188" height="96" rx="8" fill="#3a1b1f" stroke="#ff6b6b"/>
<text x="946" y="76" font-size="12" font-weight="600" fill="#ff6b6b">⑤ 收尾误判「可以派棒」</text>
<text x="946" y="96" font-size="11" fill="#a8b0be">--ready-next 说没人跑</text>
<text x="946" y="114" font-size="11" fill="#a8b0be">其实那类正在跑</text>
<text x="946" y="133" font-size="10.5" fill="#7d8695">⇒ 同一件事干两遍</text>
</g>
<g stroke="#ff6b6b" stroke-width="1.5" fill="none" marker-end="url(#ar3)">
<path d="M220 100 L248 100"/>
<path d="M448 100 L476 100"/>
<path d="M676 100 L704 100"/>
<path d="M904 100 L932 100"/>
</g>
<line x1="20" y1="176" x2="1120" y2="176" stroke="#2a3140" stroke-dasharray="5 5"/>
<text x="20" y="204" font-size="13" font-weight="650" fill="#4ec9a0">修复链(本棒落地)</text>
<line x1="20" y1="214" x2="1120" y2="214" stroke="#123028"/>
<g>
<rect x="20" y="230" width="200" height="118" rx="8" fill="#123028" stroke="#4ec9a0"/>
<text x="34" y="254" font-size="12" font-weight="600" fill="#e6e9ef">① 命名规范补全</text>
<text x="34" y="274" font-size="11" fill="#4ec9a0">协作棒/唤醒任务:</text>
<text x="34" y="291" font-size="11" fill="#a8b0be">[协作]-&lt;类别&gt;-&lt;具体&gt;</text>
<text x="34" y="308" font-size="11" fill="#4ec9a0">主会话:主控 · &lt;类别&gt; · &lt;具体&gt;</text>
<text x="34" y="328" font-size="10.5" fill="#7d8695">唤醒轮 A/B 已改名(PAUSED,未启停)</text>
<rect x="248" y="230" width="200" height="118" rx="8" fill="#123028" stroke="#4ec9a0"/>
<text x="262" y="254" font-size="12" font-weight="600" fill="#e6e9ef">② 归属吃「类别集合」</text>
<text x="262" y="274" font-size="11" fill="#4ec9a0">goal.topics 清单</text>
<text x="262" y="291" font-size="11" fill="#a8b0be">任一命中即算本项目</text>
<text x="262" y="308" font-size="11" fill="#a8b0be">⛔ 缺省回落 [short]</text>
<text x="262" y="328" font-size="10.5" fill="#7d8695">传 str 时与旧版逐字一致</text>
<rect x="476" y="230" width="200" height="118" rx="8" fill="#123028" stroke="#4ec9a0"/>
<text x="490" y="254" font-size="12" font-weight="600" fill="#e6e9ef">③ 每类各解析一条主会话</text>
<text x="490" y="274" font-size="11" fill="#4ec9a0">resolve_mains()</text>
<text x="490" y="291" font-size="11" fill="#a8b0be">最长优先 · 显式主控优先</text>
<text x="490" y="308" font-size="11" fill="#a8b0be">默认类别才回落 default</text>
<text x="490" y="328" font-size="10.5" fill="#7d8695">_scan_mains() 一遍扫描,两处共用</text>
<rect x="704" y="230" width="200" height="118" rx="8" fill="#123028" stroke="#4ec9a0"/>
<text x="718" y="254" font-size="12" font-weight="600" fill="#e6e9ef">④ 投递按件的类别选路</text>
<text x="718" y="274" font-size="11" fill="#4ec9a0">main_for_topic()</text>
<text x="718" y="291" font-size="11" fill="#a8b0be">已登记类别 ⇒ 严格取该类</text>
<text x="718" y="308" font-size="11" fill="#ff6b6b">无该类主会话 ⇒ 降级报告</text>
<text x="718" y="328" font-size="10.5" fill="#7d8695">⛔ 绝不投给别类别</text>
<rect x="932" y="230" width="188" height="118" rx="8" fill="#123028" stroke="#4ec9a0"/>
<text x="946" y="254" font-size="12" font-weight="600" fill="#e6e9ef">⑤ 展示与收尾跟上</text>
<text x="946" y="274" font-size="11" fill="#4ec9a0">分工板行 = 任务类别</text>
<text x="946" y="291" font-size="11" fill="#a8b0be">收尾排除全部主会话</text>
<text x="946" y="308" font-size="11" fill="#4ec9a0">自测 28/28</text>
<text x="946" y="328" font-size="10.5" fill="#7d8695">+8 例多类别比对 +结构断言</text>
</g>
<g stroke="#4ec9a0" stroke-width="1.5" fill="none" marker-end="url(#ar4)">
<path d="M220 285 L248 285"/>
<path d="M448 285 L476 285"/>
<path d="M676 285 L704 285"/>
<path d="M904 285 L932 285"/>
</g>
<text x="20" y="382" font-size="11.5" fill="#a8b0be">🔴 两排逐格对照:旧版每一步都"看着没错",错的是**②里那个把归属键写死成单值的假设** ——
这也是"静默漏管"这类问题的共同形状:**不崩溃,只是少说一句话**。</text>
<text x="20" y="404" font-size="11.5" fill="#7d8695">已知边界(诚实标注):类别名走**子串匹配**(主会话命名是口语式,无方括号)⇒ 类别名别取太通用的词(如"机制");源码已做"最长优先",根本解法是取具体名。</text>
</svg>
</div>
<!-- ─────────────── 图 3:泳道图(收尾棒 · 整体验证抓到的两个同族红线) ─────────────── -->
<div class="card">
<h2>③ 泳道图 · 一条信息从「产生」到「被人看到」要过五关 —— 两次事故都栽在<u>后两关</u></h2>
<div class="cap">横轴=五道关口;纵轴=四个角色。<span class="k k-red">红格</span>=这一关静默吞掉了信息;<span class="k k-green">绿格</span>=本棒修复后重新说话。</div>
<svg viewBox="0 0 1140 486" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="ar5" markerWidth="9" markerHeight="9" refX="7" refY="3.2" orient="auto">
<path d="M0 0 L7 3.2 L0 6.4 Z" fill="#7d8695"/>
</marker>
</defs>
<!-- 阶段表头 -->
<g font-size="11.5" fill="#a8b0be" text-anchor="middle">
<text x="274" y="30">① 数据产生</text>
<text x="462" y="30">② 读出来</text>
<text x="650" y="30">③ 判 / 筛</text>
<text x="838" y="30">④ 渲染成图</text>
<text x="1026" y="30">⑤ 人眼看到</text>
</g>
<line x1="16" y1="40" x2="1124" y2="40" stroke="#2a3140" stroke-width="1"/>
<!-- 行 1:程序 · 数据源 -->
<rect x="16" y="52" width="154" height="76" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="28" y="84" font-size="12" fill="#e6e9ef" font-weight="600">程序 · 数据源</text>
<text x="28" y="104" font-size="10.5" fill="#7d8695">谁把数据落到盘上</text>
<rect x="180" y="52" width="188" height="76" rx="8" fill="#132539" stroke="#5aa9ff"/>
<text x="194" y="76" font-size="10.5" fill="#5aa9ff">验收:只写了两条</text>
<text x="194" y="93" font-size="10.5" fill="#5aa9ff">`_说明` 说明行</text>
<text x="194" y="112" font-size="10.5" fill="#a8b0be">台账:4 条旧线条目</text>
<!-- 行 2:技能代码 · 读取 + 判定 -->
<rect x="16" y="138" width="154" height="76" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="28" y="170" font-size="12" fill="#e6e9ef" font-weight="600">技能代码</text>
<text x="28" y="190" font-size="10.5" fill="#7d8695">读 + 判定「有没有」</text>
<rect x="368" y="138" width="188" height="76" rx="8" fill="#161a21" stroke="#2a3140"/>
<text x="382" y="170" font-size="10.5" fill="#a8b0be">读到字典 ⇒ <tspan fill="#e6e9ef">非空</tspan></text>
<text x="382" y="190" font-size="10.5" fill="#7d8695">(里面有两条说明行)</text>
<rect x="556" y="138" width="188" height="76" rx="8" fill="#3a1b1f" stroke="#ff6b6b" stroke-width="1.6"/>
<text x="570" y="164" font-size="10.5" fill="#ff6b6b" font-weight="600">🔴 判据写成 `if not acc`</text>
<text x="570" y="182" font-size="10.5" fill="#ff6b6b">= 判「字典空不空」</text>
<text x="570" y="200" font-size="10.5" fill="#ffb454">⇒ 永不成立,不报「未声明」</text>
<!-- 行 3:看板 · 渲染 -->
<rect x="16" y="224" width="154" height="76" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="28" y="256" font-size="12" fill="#e6e9ef" font-weight="600">看板</text>
<text x="28" y="276" font-size="10.5" fill="#7d8695">把状态画成图</text>
<rect x="368" y="224" width="188" height="76" rx="8" fill="#161a21" stroke="#2a3140"/>
<text x="382" y="256" font-size="10.5" fill="#a8b0be">读到 <tspan fill="#e6e9ef">6 行</tspan> 分工数据</text>
<text x="382" y="276" font-size="10.5" fill="#7d8695">(4 类 + 2 条旧线)</text>
<rect x="744" y="224" width="188" height="76" rx="8" fill="#3a1b1f" stroke="#ff6b6b" stroke-width="1.6"/>
<text x="758" y="250" font-size="10.5" fill="#ff6b6b" font-weight="600">🔴 只画前 4 格</text>
<text x="758" y="268" font-size="10.5" fill="#ff6b6b">= 恰好全是「0 件」的格</text>
<text x="758" y="286" font-size="10.5" fill="#ffb454">⇒ 那 2 格+4 件整块不见</text>
<!-- 行 4:用户 · 看 -->
<rect x="16" y="310" width="154" height="76" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="28" y="342" font-size="12" fill="#e6e9ef" font-weight="600">用户</text>
<text x="28" y="362" font-size="10.5" fill="#7d8695">据此判断要不要再推进</text>
<rect x="932" y="310" width="188" height="76" rx="8" fill="#161a21" stroke="#2a3140"/>
<text x="946" y="338" font-size="10.5" fill="#ff6b6b">「三路全过」</text>
<text x="946" y="356" font-size="10.5" fill="#ff6b6b">「件 0 · 完成 0」</text>
<text x="946" y="376" font-size="10.5" fill="#7d8695">两个都读成「没事」</text>
<!-- 修复后(绿) -->
<rect x="556" y="404" width="188" height="62" rx="8" fill="#123028" stroke="#4ec9a0" stroke-width="1.6"/>
<text x="570" y="428" font-size="10.5" fill="#4ec9a0" font-weight="600">③ 已改成判「有效项」</text>
<text x="570" y="446" font-size="10.5" fill="#4ec9a0">空 ⇒ `undeclared`</text>
<text x="570" y="462" font-size="10.5" fill="#a8b0be">⛔ 不判完成</text>
<rect x="744" y="404" width="188" height="62" rx="8" fill="#123028" stroke="#4ec9a0" stroke-width="1.6"/>
<text x="758" y="428" font-size="10.5" fill="#4ec9a0" font-weight="600">④ 已折叠成「未归类」格</text>
<text x="758" y="446" font-size="10.5" fill="#4ec9a0">+ 图外点名线名与件数</text>
<text x="758" y="462" font-size="10.5" fill="#a8b0be">⛔ 不隐藏、⛔ 不冒充类别</text>
<path d="M650 214 L650 404" stroke="#4ec9a0" stroke-width="1.4" stroke-dasharray="4 3" marker-end="url(#ar5)"/>
<path d="M838 300 L838 404" stroke="#4ec9a0" stroke-width="1.4" stroke-dasharray="4 3" marker-end="url(#ar5)"/>
<text x="16" y="428" font-size="11.5" fill="#a8b0be">前两关都没问题:数据**确实**落盘了、代码**确实**读到了。</text>
<text x="16" y="448" font-size="11.5" fill="#a8b0be">坏在后两关 —— 该说的那句话被一句看着很正常的判断/截断吞掉了。</text>
<text x="16" y="468" font-size="10.5" fill="#7d8695">⇒ 只查「有没有报错」永远查不出来;必须拿**两处读数对账**。</text>
</svg>
</div>
<!-- ─────────────── 图 4:事故链图 ─────────────── -->
<div class="card">
<h2>④ 事故链图 · 两次「读到了却没说」各自怎么坏的 + 本该拦住的防线为何失效</h2>
<div class="cap"><span class="k k-red">红框</span>=真正的 bug 位;<span class="k k-amber">黄框</span>=本该拦住它的那道防线,以及它为什么没拦住。</div>
<svg viewBox="0 0 1140 470" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="ar6" markerWidth="9" markerHeight="9" refX="7" refY="3.2" orient="auto">
<path d="M0 0 L7 3.2 L0 6.4 Z" fill="#7d8695"/>
</marker>
</defs>
<!-- 事故 A -->
<text x="20" y="26" font-size="13" fill="#ff6b6b" font-weight="650">事故 A · 「验收」被读成「全过」</text>
<rect x="20" y="38" width="530" height="52" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="34" y="60" font-size="11" fill="#e6e9ef">① 目标文件里只写了两条 `_说明`/`_更新`(说明行,不是判据)</text>
<text x="34" y="78" font-size="10.5" fill="#7d8695">写的人以为"留个说明",读的人以为"这就是判据表"</text>
<rect x="20" y="102" width="530" height="52" rx="8" fill="#3a1b1f" stroke="#ff6b6b" stroke-width="1.6"/>
<text x="34" y="124" font-size="11" fill="#ff6b6b">② 🔴 状态判据写成 `if not acc` —— 判的是「字典空不空」</text>
<text x="34" y="142" font-size="10.5" fill="#ffb454">字典**非空**(有两条说明行)⇒ 这个条件永不成立</text>
<rect x="20" y="166" width="530" height="52" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="34" y="188" font-size="11" fill="#e6e9ef">③ 于是"没有判据"这件事从头到尾没说出口</text>
<text x="34" y="206" font-size="10.5" fill="#7d8695">兜底分支也没触发(它也只认"字典为空")</text>
<rect x="20" y="230" width="530" height="52" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="34" y="252" font-size="11" fill="#e6e9ef">④ 控制台打出「<tspan fill="#ff6b6b">三路全过</tspan>」</text>
<text x="34" y="270" font-size="10.5" fill="#7d8695">用户据此认为目标已达成 —— 而实际上一条判据都没有</text>
<rect x="20" y="294" width="530" height="70" rx="8" fill="#3a2c14" stroke="#ffb454" stroke-width="1.4"/>
<text x="34" y="316" font-size="11" fill="#ffb454">⑤ 本该拦住它的防线:单测只造了「字典为空」</text>
<text x="34" y="334" font-size="10.5" fill="#ffb454">⇒ 用例覆盖不到「字典里只有说明行」这一格</text>
<text x="34" y="352" font-size="10.5" fill="#a8b0be">已补 7 项回归用例(三态)+ 看板命令行摘要同症一并收</text>
<!-- 事故 B -->
<text x="590" y="26" font-size="13" fill="#ff6b6b" font-weight="650">事故 B · 4 件已完成的活在图上「不存在」</text>
<rect x="590" y="38" width="530" height="52" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="604" y="60" font-size="11" fill="#e6e9ef">① 类别清单已迁成"任务类别";台账里仍是 2 条<tspan fill="#ff6b6b">旧工作区线</tspan></text>
<text x="604" y="78" font-size="10.5" fill="#7d8695">这 2 条各 2 件 —— <tspan fill="#e6e9ef">4 件全都已完成</tspan></text>
<rect x="590" y="102" width="530" height="52" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="604" y="124" font-size="11" fill="#e6e9ef">② 分工数据把旧线**也当"分工位"**排进去 ⇒ 一共 6 行</text>
<text x="604" y="142" font-size="10.5" fill="#7d8695">排序是"类别在前",旧线正好排在第 5、6 位</text>
<rect x="590" y="166" width="530" height="52" rx="8" fill="#3a1b1f" stroke="#ff6b6b" stroke-width="1.6"/>
<text x="604" y="188" font-size="11" fill="#ff6b6b">③ 🔴 图上只取前 4 格 ⇒ 恰好全是「件 0 · 完成 0」那 4 类</text>
<text x="604" y="206" font-size="10.5" fill="#ffb454">装着 4 件已完成活的那 2 格,被**整块切掉**</text>
<rect x="590" y="230" width="530" height="52" rx="8" fill="#1b2029" stroke="#2a3140"/>
<text x="604" y="252" font-size="11" fill="#e6e9ef">④ 图外只说一句「另有 <tspan fill="#ff6b6b">2</tspan> 个未画」——<tspan fill="#ff6b6b">不说是哪两个</tspan></text>
<text x="604" y="270" font-size="10.5" fill="#7d8695">读者猜不到"被藏起来的正是唯一有成果的地方"</text>
<rect x="590" y="294" width="530" height="70" rx="8" fill="#3a2c14" stroke="#ffb454" stroke-width="1.4"/>
<text x="604" y="316" font-size="11" fill="#ffb454">⑤ 本该拦住它的防线:截断提示不点名被截掉的东西</text>
<text x="604" y="334" font-size="10.5" fill="#ffb454">⇒ 提示写了,但信息量为零 ⇒ 等于没说</text>
<text x="604" y="352" font-size="10.5" fill="#a8b0be">已改:折叠成「未归类」格照画 + 图外点名线名与件数</text>
<path d="M285 90 L285 102" stroke="#7d8695" stroke-width="1.2" marker-end="url(#ar6)"/>
<path d="M285 154 L285 166" stroke="#7d8695" stroke-width="1.2" marker-end="url(#ar6)"/>
<path d="M285 218 L285 230" stroke="#7d8695" stroke-width="1.2" marker-end="url(#ar6)"/>
<path d="M285 282 L285 294" stroke="#7d8695" stroke-width="1.2" marker-end="url(#ar6)"/>
<path d="M855 90 L855 102" stroke="#7d8695" stroke-width="1.2" marker-end="url(#ar6)"/>
<path d="M855 154 L855 166" stroke="#7d8695" stroke-width="1.2" marker-end="url(#ar6)"/>
<path d="M855 218 L855 230" stroke="#7d8695" stroke-width="1.2" marker-end="url(#ar6)"/>
<path d="M855 282 L855 294" stroke="#7d8695" stroke-width="1.2" marker-end="url(#ar6)"/>
<line x1="20" y1="384" x2="1120" y2="384" stroke="#2a3140"/>
<rect x="20" y="396" width="1100" height="58" rx="8" fill="#161a21" stroke="#ff6b6b"/>
<text x="34" y="418" font-size="11.5" fill="#e6e9ef">共同形状:<tspan fill="#ff6b6b">不崩溃,只是少说一句话</tspan> —— 所以"跑一遍没报错 / build 通过 / 测试全绿"都验不出来;</text>
<text x="34" y="438" font-size="11.5" fill="#a8b0be">能验出它的只有一条:拿**两处独立读数对账**(台账 4 件 ↔ 图上 0 件;文件里 0 条判据 ↔ 控制台"全过")。</text>
</svg>
</div>
</div>
</body>
</html>