ADR 0002 深度解读:diagram-design 技能库如何用七种语义模式守住 39 种视觉类型的分类边界
【免费下载链接】diagram-design38 editorial diagram types for Claude Code, Codex, and Pi. Self-contained HTML + SVG. No shadows. No Mermaid slop.项目地址: https://gitcode.com/GitHub_Trending/di/diagram-design
导读
本文围绕 diagram-design 开源仓库中的架构决策记录 ADR 0002 — Semantic patterns never expand the visual-type taxonomy 展开,剖析该项目在“表现系统行为(队列、策略追踪、信任边界)”与“视觉布局分类法”之间划出的一条关键边界:行为走语义模式(semantic patterns)通道,布局走视觉类型(visual types)通道,二者永不混用。读完本文,你将掌握这套“先选语义模式、再选最近视觉类型”的双轴路由方法论,理解 27 → 28 → 38 → 39 的分类数量变化为何是可验证、可审查的工程事实,并能在自己的图型设计技能库中复刻这套护栏。
1. 背景:为什么“多加一种图型”不是正解
在 ADR 0002 被采纳(v2.3)之前,项目团队审计了一批“行为密集”的图形:排队队列、策略追踪(policy trace)、信任边界(trust boundary)。审计结论直指一个能力缺口——技能能摆放盒子(layout),却无法建模系统行为(behavior)。一个节点连一个节点的“静态示意”回答不了这类问题:请求为什么排队、两条策略为什么走向不同结局、哪个控制点真正兜住了风险。
最“显而易见”的修法是扩充图型分类法:加一个 Queue 类型、加一个 Trace 类型、加一个 Trust Boundary 类型。但这条路的代价在 ADR 0002 的 Context 一节 里被明确否定:
- 分类法会迅速膨胀,39 种类型的选型指南会被稀释,读者面对一张越来越长的路由表无从下手;
- 每种新行为都要配套一套新的布局语法(layout grammar),即新的类型参考文档、模板组、示例三件套,维护成本线性叠加。
于是决策转向:行为是独立于布局的另一个轴(axis)。
2. 决策:行为走“语义模式”通道,布局走“视觉类型”通道
ADR 0002 的核心决策只有一句话:七种语义模式各自路由到“最近的既有视觉类型”完成布局;语义模式拥有语义原语(semantic primitives)和更紧的复杂度预算,但绝不拥有第二套布局语法。视觉类型数量只在出现真正全新的布局语法时才增长。
这条决策的直接落地物是 语义模式参考文档,它开篇就给出了整套方法论的判断顺序:
Semantic patterns describewhat a system does; the 39 visual types describehow information is arranged. Choose a pattern first when behavior, state, enforcement, or risk is load-bearing, then use its nearest visual type as the layout grammar. If no pattern matches, choose a visual type directly.
翻译成操作规则就是:当行为、状态、强制(enforcement)或风险承载含义时,先选一个语义模式;再从视觉类型表里挑“最近的”类型来承担布局。没有模式匹配时,才直接选视觉类型。选型流程在 SKILL.md 第 3 节 中进一步固化为“semantic pattern, then visual type”的固定顺序,并在 SKILL.md 里提供了一张行为触发器 → 模式 → 最近类型的速查表。
3. 七种语义模式的完整规格
这七种模式不是空泛标签,每一种都定义了六项强制字段:Selection triggers(选择触发器)、Required primitives(必需原语)、Complexity budget(复杂度预算)、Anti-patterns(反模式)、Static fallback(静态回退)、Nearest visual type(最近视觉类型)。六项字段的完整性由 verify-semantic-motion.py 逐模式校验,缺一即 CI 失败。下面逐一展开。
3.1 Fan-in queue / bottleneck(扇入队列 / 瓶颈)→ Data flow / Process
- 触发器:多个生产者汇聚到一个审核者、服务、关卡或受限资源;故事取决于到达率、队列深度、等待、容量或背压。
- 必需原语:不同来源、扇入入口、带可见槽位与计数的有序队列、容量/服务速率标签、一个受限服务点、准入与延迟/拒绝两种结局。必须标注单位(如
8/hour、3 slots),不能只写“high”。 - 复杂度预算:≤5 个来源、≤5 个队列槽位、1 个瓶颈、2 种结局、≤9 个主节点;多余的来源合并为具名群组。
- 反模式:等宽流水线掩盖争用;箭头过早合并无法追踪;只用盒子大小暗示容量;装饰性堆叠;改变条目顺序的动画;仅用红色表示过载。
- 静态回退:展示代表性最终队列、数字计数/容量、瓶颈标签与两条结局路径——静止画面也必须能看出工作为何等待。
- 最近视觉类型:默认Data flow;当服务阶段(而非来源)占主导时用Process。
3.2 Stage framework with semantic slots(带语义槽位的阶段框架)→ Process / Swimlane
- 触发器:生命周期或运营模型在多个阶段重复同一组语义问题(典型是 Question、Input、Governance、Output),跨阶段可比性比消息时序更重要。
- 必需原语:有序阶段头、一致的槽位网格、显式的空/不适用槽位、阶段间交接、稳定的槽位标签、每阶段一个主输出;所有阶段必须保持槽位顺序。
- 复杂度预算:3–6 个阶段、3–4 种槽位、≤20 个填充单元格、每格 ≤2 行;单元格需要长文时拆分细节。
- 反模式:每个阶段自创内部布局;仅靠位置编码槽位含义而无标签;用几十个单元格制造虚假精确;把阶段顺序与所有权泳道混淆;为塞进单张画布而缩小字号。
- 静态回退:渲染完整的阶段 × 槽位矩阵,含交接与显式
—/Not applicable条目。 - 最近视觉类型:Process;仅当重复行表示的是所有者(而非语义槽位)时才改用Swimlane。
3.3 Unstructured input → structured artifact(非结构化输入 → 结构化产物)→ Data flow / Process
- 触发器:对话、笔记、提示词或冗长请求被引出、规范化并写入持久的 brief、ticket、记录、schema 等结构化产物。
- 必需原语:来源话语、澄清问题、抽取的字段/值对、具名转换、持久产物边界、从代表性语句到字段的溯源链接、缺失/未知状态。
- 复杂度预算:≤4 次交换、≤6 个产物字段、1 次转换、≤3 条溯源链接;展示代表性内容而非逐字转录。
- 反模式:“AI 魔法”式闪烁箭头;产物画成另一个聊天气泡;字段凭空出现无来源;给缺失事实编造确定性;打字动画作为唯一可读文本。
- 静态回退:短来源摘录与带标签的成品并排,至少一条溯源映射,未知字段可见。
- 最近视觉类型:Data flow;启发式询问有多道有序关卡时用Process。
3.4 Paired policy-evaluation traces(成对策略评估轨迹)→ Flowchart / Sequence
- 触发器:两个看似相似的请求走向不同结局;读者需要逐规则的
PASS、FAIL、SKIPPED、NOT REACHED状态与首个分歧点。 - 必需原语:两条轨迹上的同一组有序规则;状态文本 + 符号/形状双重编码;不同的输入;最终结局;带标签的首分歧标记;严格区分
SKIPPED(适用流程被有意绕过)与NOT REACHED(评估更早终止)。 - 复杂度预算:恰好 2 条轨迹、3–6 条规则、1 个首分歧、≤12 个状态单元格、每条轨迹 1 个结局;标签超一行则把规则说明移到注释。
- 反模式:比较两条各自独立排序的流程;只有绿/红圆点没有文字;把 skipped 与 not-reached 当同义词;高亮每一个差异;被拒绝的轨迹仍继续画后续规则。
- 静态回退:一次性展示所有规则状态与两个结局,用持续的括号/线条与标签标记首分歧。
- 最近视觉类型:有序决策逻辑用Flowchart;仅当消息时序与参与者之间的交互同样承载含义时用Sequence。
仓库级实现证据:example-policy-trace-animated.html 是这一模式的完整参考实现——两条轨迹以
data-trace-connector="trace-b"的持续连接线贯穿,Trace B 在第 3 条规则处以data-trace-b-terminal="fail"终止,其后的两行标注data-trace-b-state="not-reached"、结局标注data-trace-b-outcome="denied"。图上同时出现FIRST DIVERGENCE首分歧标记、— SKIPPED(有意绕过)与○ NOT REACHED(评估提前终止)两套不同语义,正是模式文档“区分 SKIPPED 与 NOT REACHED”要求的落地。verify-semantic-motion.py 甚至会对该文件的几何坐标做数值断言:持续连接线必须终止于首个 FAIL 的底部,且其后不得再有贯穿线,否则判为失败。
3.5 Secure paved road(安全铺装道路)→ Architecture
- 触发器:受支持的架构从 intake/build 到部署形成有界路径;信任边界、特权时刻、允许/禁止的进入、批准与被阻断的部署路径是重点。
- 必需原语:带标签的信任边界、参与者与身份、带肯定文本标签的允许进入、终止于边界的禁止进入、批准的部署路径、被阻断的绕行路径、特权关卡、隔离运行时、审计目的地;必须用不同线型与终止符号,不能只靠颜色。
- 复杂度预算:≤3 个信任区、≤8 个组件、≤10 条路径、≤2 条禁止路径、1 个特权关卡;控制细节拆到目录图。
- 反模式:虚线框写上“security”却没有路线语义;禁止箭头穿入保护区;暗示了密钥/身份却不标注;所有组件都画成受信;绕行路径视觉上重新汇入批准路线。
- 静态回退:渲染每条边界与允许/禁止两类路线,被阻断路径必须可见地停在进入或部署之前。
- 最近视觉类型:Architecture(唯一,无备选)。
3.6 Governance / control catalog(治理 / 控制目录)→ Layer stack / DP security matrix
- 触发器:控制清单必须按“在哪里被强制”来理解:authoring、workspace、merge/CI、deploy/runtime 或其它具名表面;单一清单会掩盖这些强制点。
- 必需原语:强制表面分组、具名控制、强制主体(
code/platform/human)、时机(write/merge/deploy/run)、可绕过性或例外路径、覆盖/缺口标注。 - 复杂度预算:3–5 个表面、每表面 3–7 条控制、总计 ≤24 条、每条控制 ≤3 个属性;仅在条目清单已存在于别处时才做计数汇总。
- 反模式:35 个细小胶囊;按模糊主题而非强制点分组;把愿望与已强制控制混为一谈;只有图标没有控制名;声称纵深防御却不展示表面覆盖。
- 静态回退:展示完整分组目录,含表面头与强制主体/时机文本标签,保留缺口与例外。
- 最近视觉类型:Layer stack;当比较主轴是角色权限(而非强制表面)时改用DP security matrix。
3.7 Compensating security layers(补偿性安全层级)→ Layer stack / Nested
- 触发器:没有一层防御是完美的;每层防御覆盖上一层留下的失效点,残余风险必须沿栈可见地收窄、转移或留存。
- 必需原语:有序威胁/风险输入、具名防御层、每层缓解措施、显式局限或逃逸、层间残余风险载体、最终残余风险与后果/响应;用标签或递减度量表达,不能只用面积。
- 复杂度预算:3–5 层、1 条主风险链、每层 ≤2 项缓解、1 条最终残余风险声明;多个无关威胁拆分为独立图形。
- 反模式:暗示最后一层把风险清零;等宽不透明板块没有传播语义;把审计当预防;形状缩小却无数字或文字含义;无解释地颠倒预防/检测/恢复顺序。
- 静态回退:展示完整传播链:初始风险 → 缓解 → 每层逃逸风险 → 最终残余风险与响应。
- 最近视觉类型:Layer stack;当承载含义的是包含边界(而非有序补偿)时用Nested。
3.8 组合规则:两层预算取严
语义模式文档末尾的Composition rules明确了模式与类型之间的权责划分:
- 模式可以特化状态、边界、队列或传播原语,但页面轴、连接器语法、间距与类型专属限制仍然归视觉类型所有;
- 取“模式预算”与“类型预算”两者中更严的那个;语义单元格/状态不是突破 9 节点概览目标的许可证;
- 状态与结局必须使用稳定文本;颜色、动效、位置只强化含义,绝不单独承载含义;
- 可选动画只是呈现层,不是另一种模式——只有显式要求动效或动效确实能阐明有序变化时才加载 animation.md。
这条“模式拥有语义原语和更紧预算、类型拥有布局语法”的分工,在 SKILL.md 第 3 节 被压缩成一句可执行规则,并由验证脚本强制检查该句必须出现。
4. 分类数量的可验证性:两个计数器就是本 ADR 的执法机关
ADR 0002 最具工程特色的设计,是把“视觉类型数量”变成稳定、可验证的断言,由两个脚本双重复核:
- verify-semantic-motion.py 硬编码
VISUAL_TYPE_COUNT = 39,并要求 SKILL.md 中存在### Visual-type guide (39)标题、选型表恰好 39 行、语义模式路由必须先于类型指南出现; - verify-docs-sync.py 同样硬编码
VISUAL_TYPE_COUNT = 39,并额外检查 SKILL.md frontmatter 的 description 必须包含全部 39 个类型的词法钩子(lexical hook)——这是 ADR 0004 确立的规则:description 是 Agent 决定是否加载该技能前唯一看到的文本,丢了 “flowchart”“Gantt” 这些词,技能就无法被“给我画个流程图”这类请求触发。
在仓库当前状态(v2.6)下实际运行两个验证器,输出为:
OK: 7 semantic patterns route independently to the preserved 39 visual types OK docs sync: description hooks, gallery reachability, README tree, reference links, packaged support files, routing surfaces, manifest descriptions, Factory install contract, type-count routing, High-Level invariants这从命令层面证实了 ADR 0002 的终极论断:七个模式各自独立路由,而 39 种视觉类型被原样保留。
计数器的“执法”逻辑在 ADR 0002 的 Amendments 末尾写得很直白:这两个计数器就是本 ADR 的执法机关——一个 PR 只改数字却不修本文件,等于悄悄让自己成了权威。要么在同一 PR 内修订本 ADR,要么测试里的数字就只是“上一个贡献者随手敲的”。
5. 逃逸条款:什么情况下才允许新增类型
ADR 0002 留了一个明确的“逃逸条款”(escape clause):如果某个模式需要的布局语法没有任何现有类型提供,那就是新增类型的信号,且必须附带完整的“§10 发布套件”(类型参考 + 浅色/深色/完整三套示例 + 画廊标签页 + 路由表行 + 预算表行,见 SKILL.md 第 10 节)。
该条款在 Amendments 中被三次触发,每次都是布局语法级的新颖性,而不是行为新颖性:
| 日期 | 数量变化 | 被接纳的类型 | 新布局语法是什么 |
|---|---|---|---|
| 2026-08-18 | 27 → 28 | Treemap | 递归面积细分:bar 用长度编码、nested 用包含关系且无量纲、pyramid 用排名,都无法表达“面积承载数量” |
| 2026-08-19 | 28 → 38 | Sankey、fishbone、Wardley map、kanban、user journey、deployment、dependency graph、UML class、story map、database schema | 每种类型的逐条论证见 ADR 0007 |
| 2026-08-20 | 38 → 39 | Polar | 角度编码有序循环类别、线性半径编码单一数量序列,是既有语法无法覆盖的组合 |
以 ADR 0007 的论证为例,可以更清楚地看到“语法级新颖”的判定标准有多严格:Sankey 的条带宽度编码可分可合的数量(pyramid 只能表现流失、process 只能表现步骤)、Dependency graph 的多父节点与可表示环(tree 结构上禁止两者)、Database schema 的外键锚定“列到列”(ER 只能连盒子、止步于基数)、Kanban 的有 WIP 限制且刻意无连接线的状态列(swimlane 是“泳道 + 穿行其间的流”,看板刻意没有流)。而 System context、UML activity、Data flow diagram、C4、Mindmap 等请求则被驳回——它们要么已被既有类型覆盖(是使用场景而非新语法),要么被 ADR 0007 的“按 ADR 0002 标准驳回”清单 以编辑适配性理由拒绝。
Polar 作为最新一次逃逸(38 → 39),其实现全过程记录在 实施计划 与 设计规格 中,是观察“完整 §10 套件”如何落地的绝佳案例:类型参考 type-polar.md、三套几何字节一致的示例、独立的量化验证器 verify-polar.py 与对抗性测试 test-verify-polar.py、README 画廊条目与截图、两个计数器同步上调、插件版本随 minor 发布同步。
6. 为什么“新增一个模式”的成本远低于“新增一个类型”
ADR 0002 的 Consequences 给出了一条直接的成本对比:
一个新行为只需要一个模式小节 + 一行路由表,而不是一套新的类型参考、模板组和示例三件套。
把两条路线的成本摊开看:
| 成本项 | 走语义模式(行为) | 走视觉类型(布局) |
|---|---|---|
| 文档 | 1 个模式小节(六字段规格) | 1 份类型参考(数百行) |
| 示例 | 无强制示例(可复用类型的三变体) | 浅色/深色/完整 3 个示例文件 |
| 画廊 | 无需新增标签页 | 需新增画廊标签页 + 截图 |
| 路由 | 路由表 +1 行 | 路由表行、frontmatter 描述词法钩子、SKILL.md 选型表 |
| 预算 | 模式自定更紧预算 | §7 复杂度预算表 +1 组条目 |
| 计数器 | 不动 | verify-docs-sync.py / verify-semantic-motion.py 两个硬编码必须同步更新 |
| 发布 | 常规演进 | 触发 ADR 0004 的 40 KB 字节上限压力(SKILL.md 当前约 39.2 KB),新增类型必须“支付”字节成本 |
这个对比在 ADR 0007 的 Consequences 里得到了一次实证:10 个新类型落地时,SKILL.md 正文必须被压缩(§11 导入后果压缩、终端变体与排版段落收紧、§4 连接器反模式表从六行合并为一行)才能保住 40 KB 上限——“新增类型必须付费,且永远不能靠裁剪 frontmatter description 来付费”。
7. 静态优先:模式与 ADR 0001 的无缝衔接
语义模式文档通篇强调Static fallback(每种模式都定义了“静止画面必须传达什么”),这与 ADR 0001 — Static by default; one pinned controller for motion 的决策完全同构:
- ADR 0001 规定输出默认静态且无脚本(
data-motion-mode="none");请求动效时,文件最多携带一个<script contenteditable="false">【免费下载链接】diagram-design38 editorial diagram types for Claude Code, Codex, and Pi. Self-contained HTML + SVG. No shadows. No Mermaid slop.项目地址: https://gitcode.com/GitHub_Trending/di/diagram-design
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考