cardbuddy 0.14.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/cli.js +0 -0
  2. package/dist/preview-editor/assets/{index-BN79pTkQ.js → index-CIIfMlwI.js} +43 -40
  3. package/dist/preview-editor/assets/index-DQn0zQBP.css +1 -0
  4. package/dist/preview-editor/index.html +2 -2
  5. package/dist/standalone.js +3 -0
  6. package/dist/vendored/mcp/client.mjs +8 -1
  7. package/dist/vendored/server/core/ai-chat.js +1521 -124
  8. package/dist/vendored/server/core/browser.js +12 -3
  9. package/dist/vendored/server/core/cardFiles.js +3 -0
  10. package/dist/vendored/server/core/cardHistory.js +1 -0
  11. package/dist/vendored/server/core/cardImportMeta.js +7 -6
  12. package/dist/vendored/server/core/cardOpenFolder.js +1 -0
  13. package/dist/vendored/server/core/cardSave.js +1 -0
  14. package/dist/vendored/server/core/cardSync.js +3 -0
  15. package/dist/vendored/server/core/codeBridge.js +5 -1
  16. package/dist/vendored/server/core/logStream.js +1 -0
  17. package/dist/vendored/server/core/sliceStatic.js +24 -4
  18. package/dist/vendored/server/core/sliceUpload.js +1 -0
  19. package/dist/vendored/server/core/turnJournal.js +6 -0
  20. package/dist/vendored/skills/card-skill-trainer/SKILL.md +196 -195
  21. package/dist/vendored/skills/dsl-card-ai/SKILL.md +1 -1
  22. package/dist/vendored/skills/dsl-card-generator/SKILL.md +142 -380
  23. package/dist/vendored/skills/dsl-card-generator/references/generation_pitfalls.md +65 -18
  24. package/dist/vendored/skills/dsl-card-generator/references/ir-format.md +116 -2
  25. package/dist/vendored/skills/dsl-card-generator/references/iteration_protocol.md +58 -0
  26. package/dist/vendored/skills/dsl-card-generator/references/previewer_contract.md +1 -1
  27. package/dist/vendored/skills/dsl-card-generator/references/quickref.md +15 -7
  28. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/title-underline-overlay.json +59 -11
  29. package/dist/vendored/skills/dsl-card-generator/references/recipes.md +14 -0
  30. package/dist/vendored/skills/dsl-card-generator/references/rules.md +23 -4
  31. package/dist/vendored/skills/dsl-card-generator/references/scripts_reference.md +51 -0
  32. package/dist/vendored/skills/dsl-card-generator/references/semantic_adjudication.md +23 -0
  33. package/dist/vendored/skills/dsl-card-generator/references/slices_convention.md +4 -3
  34. package/dist/vendored/skills/dsl-card-generator/references/spec_to_schema_patterns.md +32 -0
  35. package/dist/vendored/skills/dsl-card-generator/references/ui_fidelity_rules.md +13 -1
  36. package/dist/vendored/skills/dsl-card-generator/scripts/autofix_schema.py +45 -2
  37. package/dist/vendored/skills/dsl-card-generator/scripts/check_fidelity.mjs +116 -10
  38. package/dist/vendored/skills/dsl-card-generator/scripts/check_magic_values.mjs +6 -1
  39. package/dist/vendored/skills/dsl-card-generator/scripts/crop_slices.mjs +92 -6
  40. package/dist/vendored/skills/dsl-card-generator/scripts/expand_ir.mjs +227 -23
  41. package/dist/vendored/skills/dsl-card-generator/scripts/gate.mjs +144 -0
  42. package/dist/vendored/skills/dsl-card-generator/scripts/generate_cards.mjs +12 -8
  43. package/dist/vendored/skills/dsl-card-generator/scripts/ir_merge.mjs +288 -0
  44. package/dist/vendored/skills/dsl-card-generator/scripts/ir_restore.mjs +175 -0
  45. package/dist/vendored/skills/dsl-card-generator/scripts/iterate.mjs +644 -42
  46. package/dist/vendored/skills/dsl-card-generator/scripts/lib/geometry_audit.mjs +131 -0
  47. package/dist/vendored/skills/dsl-card-generator/scripts/lib/layout_rules.mjs +160 -0
  48. package/dist/vendored/skills/dsl-card-generator/scripts/lib/slicePath.mjs +17 -5
  49. package/dist/vendored/skills/dsl-card-generator/scripts/lib/slice_dedupe.mjs +102 -0
  50. package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_assemble.mjs +5443 -0
  51. package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_extract.mjs +4108 -0
  52. package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_shared.mjs +1116 -0
  53. package/dist/vendored/skills/dsl-card-generator/scripts/lint_card.mjs +214 -4
  54. package/dist/vendored/skills/dsl-card-generator/scripts/preflight.mjs +48 -2
  55. package/dist/vendored/skills/dsl-card-generator/scripts/render_card.mjs +91 -43
  56. package/dist/vendored/skills/dsl-card-generator/scripts/route_input.mjs +4 -3
  57. package/dist/vendored/skills/dsl-card-generator/scripts/spec_audit.mjs +150 -38
  58. package/dist/vendored/skills/dsl-card-generator/scripts/spec_to_schema_v3.mjs +43 -10499
  59. package/dist/vendored/skills/dsl-card-generator/scripts/v3_regression.mjs +186 -0
  60. package/dist/vendored/skills/sketch-spec-to-card/SKILL.md +18 -12
  61. package/dist/vendored/skills/sketch-spec-to-card/references/spec-schema.md +1 -1
  62. package/dist/vendored/skills/sketch-spec-to-card/scripts/build_prompt.py +47 -1
  63. package/dist/vendored/skills/sketch-spec-to-card/scripts/parse_meaxure.py +460 -49
  64. package/dist/vendored/skills/sketch-spec-to-card/scripts/png_utils.py +51 -0
  65. package/dist/vendored/skills/sketch-spec-to-card/scripts/test_text_only_artboard.py +157 -0
  66. package/dist/vendored/skills/sketch-spec-to-card/scripts/vision.py +24 -0
  67. package/package.json +1 -1
  68. package/dist/preview-editor/assets/index-cbTCHp8J.css +0 -1
@@ -1,14 +1,14 @@
1
- ---
2
- name: card-skill-trainer
3
- description: 无人值守联合训练 sketch-spec-to-card 与 dsl-card-generator。扫描桌面已确认 Sketch 导出,评估卡片聚焦与标注契约,批量生成 schema/data,渲染截图,执行结构、事实与像素评分,输出失败归因和下一轮规则候选。触发词:卡片训练、自动训练、训练闭环、skill 回归、还原度优化。
4
- ---
5
-
6
- # Card Skill Trainer
7
-
8
- ## 定位
9
-
10
- 本 Skill 联合训练 `sketch-spec-to-card` 和 `dsl-card-generator`:前者负责卡片聚焦与标注契约,后者负责 DSL 还原,两者都被当作被评测对象。
11
-
1
+ ---
2
+ name: card-skill-trainer
3
+ description: 无人值守联合训练 sketch-spec-to-card 与 dsl-card-generator。扫描桌面已确认 Sketch 导出,评估卡片聚焦与标注契约,批量生成 schema/data,渲染截图,执行结构、事实与像素评分,输出失败归因和下一轮规则候选。触发词:卡片训练、自动训练、训练闭环、skill 回归、还原度优化。
4
+ ---
5
+
6
+ # Card Skill Trainer
7
+
8
+ ## 定位
9
+
10
+ 本 Skill 联合训练 `sketch-spec-to-card` 和 `dsl-card-generator`:前者负责卡片聚焦与标注契约,后者负责 DSL 还原,两者都被当作被评测对象。
11
+
12
12
  ```text
13
13
  build_dataset.py → build_sample.mjs(结构去重抽样)
14
14
  → run_round.mjs(收尾自动调 score_round:summary.json/md + roundGate)
@@ -20,37 +20,37 @@ build_dataset.py → build_sample.mjs(结构去重抽样)
20
20
  人工不阻塞主流程。连续回归、渲染器崩溃或置信度低于阈值的样本会进入 `review-queue.jsonl`(带 `failureClass` 与未达标维度,可直接聚类);像素/结构失败同时生成 `semantic-review.jsonl`,由执行 Skill 的 Agent 在下一轮自动做多模态归因,再回灌到 `dsl-card-generator` 或 `sketch-spec-to-card` 的文档规则。脚本负责提出证据和复跑回归,不负责把业务语义硬编码。
21
21
 
22
22
  **口径唯一来源**:单案例门(`PASS_GATE`)、轮级门(`ROUND_GATE_TARGETS`)、盲测门(`GENERALIZATION_GATE`)、失败签名与失败类归因全部定义在 `scripts/lib/scoring.mjs`;轮次/锚点读取与轮间对比定义在 `scripts/lib/runs.mjs`。run_round / score_round / round_diff / plan_next_round / diagnose_case 一律 import 复用,**禁止在脚本里另写一套阈值**——`tools/tests/scoring.test.mjs` 会反向断言本文档验收表里的数字与 `PASS_GATE` 逐条一致,改门必须同步改文档。
23
-
24
- ## 源码隔离铁律
25
-
26
- 训练、评测和冒烟测试**绝不写入宿主源码目录**:
27
-
28
- - 禁止写 `src/cards/`
29
- - 禁止写 `src/slices/`
30
- - 禁止写 `.card-baselines/`
31
- - 原始桌面设计稿只读
32
- - 所有生成物落在 `training/datasets/<version>/raw/` 或 `training/runs/<round>/`
33
-
34
- 执行器必须在动态 import 生成器和渲染器之前设置:
35
-
36
- ```bash
37
- DSL_CARD_CARDS_DIR=<training-run>/cards
38
- DSL_CARD_SLICES_DIR=<training-run>/slices
39
- ```
40
-
41
- 每轮结束后可用 `git status --short -- src` 验证必须为空。
42
-
43
- ## 自动化流程
44
-
45
- 1. 扫描所有包含 `index.html` 的 MeaXure 导出。
23
+
24
+ ## 源码隔离铁律
25
+
26
+ 训练、评测和冒烟测试**绝不写入宿主源码目录**:
27
+
28
+ - 禁止写 `src/cards/`
29
+ - 禁止写 `src/slices/`
30
+ - 禁止写 `.card-baselines/`
31
+ - 原始桌面设计稿只读
32
+ - 所有生成物落在 `training/datasets/<version>/raw/` 或 `training/runs/<round>/`
33
+
34
+ 执行器必须在动态 import 生成器和渲染器之前设置:
35
+
36
+ ```bash
37
+ DSL_CARD_CARDS_DIR=<training-run>/cards
38
+ DSL_CARD_SLICES_DIR=<training-run>/slices
39
+ ```
40
+
41
+ 每轮结束后可用 `git status --short -- src` 验证必须为空。
42
+
43
+ ## 自动化流程
44
+
45
+ 1. 扫描所有包含 `index.html` 的 MeaXure 导出。
46
46
  2. 每套导出独立解析到 `training/datasets/<version>/raw/<source>/`,不修改桌面源文件。
47
- 3. 将每个有效画板登记为一个案例,按内容哈希稳定划分 train/dev/eval/holdout。
48
- 4. 使用 `v3` 策略批量生成到隔离的 run 目录(本技能是「多画板必须先选卡」铁律的**显式批量例外**:用户点名跑无人值守训练即等于授权全量画板;产物落隔离 run 目录、不写 `src/cards/`。见 `dsl-card-generator/references/rules.md §十三`)。
49
- 5. 复制 schema 实际引用的 slices 到当前 run 的隔离资源目录。
50
- 6. 执行 Python 结构校验、Node lint、独立 Chrome 渲染、重复内容检测和像素差异计算。
47
+ 3. 将每个有效画板登记为一个案例,按内容哈希稳定划分 train/dev/eval/holdout。
48
+ 4. 使用 `v3` 策略批量生成到隔离的 run 目录(本技能是「多画板必须先选卡」铁律的**显式批量例外**:用户点名跑无人值守训练即等于授权全量画板;产物落隔离 run 目录、不写 `src/cards/`。见 `dsl-card-generator/references/rules.md §十三`)。
49
+ 5. 复制 schema 实际引用的 slices 到当前 run 的隔离资源目录。
50
+ 6. 执行 Python 结构校验、Node lint、独立 Chrome 渲染、重复内容检测和像素差异计算。
51
51
  7. 聚合 Round 报告(`run_round.mjs` 收尾自动调用 `score_round.mjs`),按主失败签名与失败类出直方图。
52
52
  8. `plan_next_round.mjs` 把「归因 → 聚类 → 焦点集 → 门禁判定 → 收敛信号 → lesson 草稿」一次算完,产出 `next-round-plan.json` 与 `lesson-drafts.jsonl`(`status=candidate`,人工审批后才落盘 lessons)。Agent 按聚类逐例复核 `designImage + render.png + spec.json`,把失败归入 PARSER / DSL / STYLE / DATA / INTERACTION / ASSET / EVALUATOR,并只推广通用规则。
53
-
53
+
54
54
  ## 高效迭代闭环(r172 起;r263 补自动归因与增量轮补齐)
55
55
 
56
56
  单案例修复循环按此顺序推进,避免整轮盲跑浪费时间:
@@ -75,54 +75,55 @@ DSL_CARD_SLICES_DIR=<training-run>/slices
75
75
 
76
76
  > **继承轮不是锚点**:`--inherit` 轮的 `cards/`、`slices/` 只含本轮重跑案例,因此可用于门禁与
77
77
  > 回归对账,但**不能作为冻结锚点载体**——锚点必须整轮全量跑(含全部 cards/slices 证据)。
78
-
79
- ### 校正器纪律
80
-
81
- 后置布局校正器是安全网而不是拐杖:
82
-
83
- - 校正采纳需**双指标守卫**:position 提升 **且** pixel 不退化(容忍 +0.005),否则回退并记
84
- `correctorRejected`;采纳时记 `layoutCorrections` 明细。
85
- - `summary.json` 的 `correctorCoverage`(触发率)持续 >25% 说明生成器缺陷被校正器掩盖,
86
- 应把高频校正模式沉淀回生成器规则,而不是放任校正器兜底。
87
- - 每 3~5 轮安排一次里程碑裸测:`run_round.mjs --no-correct --round <轮次>nc`,与同期
88
- 正常轮对比 passRate/avgPosition,差值就是校正器的真实贡献与生成器的真实缺口。
89
- - 模拟否决快路径:纯纵向 rigidSafe 校正的 position 分可精确模拟(22/22 对账逐位一致),
90
- 模拟不提升即跳过二次渲染,报告记 `correctorRejected.reason=position-not-better-simulated`;
91
- 可用 `CORR_SIM_VALIDATE=1` 双跑对账复核保真度。
92
-
93
- ### 分区纪律
94
-
95
- - 迭代修复**只用 train/dev**;eval 每 3 轮盲测一次;holdout 只在晋级落地时启用。
96
- - 同一案例连续出现在诊断视野里超过 2 轮,视为过拟合风险,下一轮诊断必须换一批样本。
97
-
98
- ## 上游质量门
99
-
100
- 每个案例先检查 `sketch-spec-to-card` 产物,再进入 DSL 评分:
101
-
102
- - `annotationCompleteness`:画板内叶子标注是否被完整归属到聚焦卡。
103
- - `textRetention`:卡片内文案是否被完整保留。
104
- - `structuralFocus`:候选是否具备卡片级结构,而不是气泡、按钮条或空壳。
105
- - `trainingEligible`:弹窗、toast、底部抽屉必须为 false。
106
-
107
- 任一门失败优先归因 `PARSER`,修复目标是 `vision.py` / `parse_meaxure.py` / `boundary.json` 的通用几何规则,不允许用业务名救某个样本。
108
-
109
- ## 验收标准(r060 起)
110
-
111
- ### 单案例通过门(per-case pass gate)
112
-
113
- 每张卡片必须同时满足以下全部条件才算 PASS:
114
-
78
+
79
+ ### 校正器纪律
80
+
81
+ 后置布局校正器是安全网而不是拐杖:
82
+
83
+ - 校正采纳需**双指标守卫**:position 提升 **且** pixel 不退化(容忍 +0.005),否则回退并记
84
+ `correctorRejected`;采纳时记 `layoutCorrections` 明细。
85
+ - `summary.json` 的 `correctorCoverage`(触发率)持续 >25% 说明生成器缺陷被校正器掩盖,
86
+ 应把高频校正模式沉淀回生成器规则,而不是放任校正器兜底。
87
+ - 每 3~5 轮安排一次里程碑裸测:`run_round.mjs --no-correct --round <轮次>nc`,与同期
88
+ 正常轮对比 passRate/avgPosition,差值就是校正器的真实贡献与生成器的真实缺口。
89
+ - 模拟否决快路径:纯纵向 rigidSafe 校正的 position 分可精确模拟(22/22 对账逐位一致),
90
+ 模拟不提升即跳过二次渲染,报告记 `correctorRejected.reason=position-not-better-simulated`;
91
+ 可用 `CORR_SIM_VALIDATE=1` 双跑对账复核保真度。
92
+
93
+ ### 分区纪律
94
+
95
+ - 迭代修复**只用 train/dev**;eval 每 3 轮盲测一次;holdout 只在晋级落地时启用。
96
+ - **holdout 污染标记(seq5-l12,2026-09-21)**:用户显式指定训练某个 holdout 分区案例时按指令执行,但该轮结论**必须标记**:此案例此后移出晋级盲测的未见样本池(holdout 只剩晋级落地一次性启用;被点名训练过 = 已见过,继续计入盲测会虚高泛化分)。
97
+ - 同一案例连续出现在诊断视野里超过 2 轮,视为过拟合风险,下一轮诊断必须换一批样本。
98
+
99
+ ## 上游质量门
100
+
101
+ 每个案例先检查 `sketch-spec-to-card` 产物,再进入 DSL 评分:
102
+
103
+ - `annotationCompleteness`:画板内叶子标注是否被完整归属到聚焦卡。
104
+ - `textRetention`:卡片内文案是否被完整保留。
105
+ - `structuralFocus`:候选是否具备卡片级结构,而不是气泡、按钮条或空壳。
106
+ - `trainingEligible`:弹窗、toast、底部抽屉、纯文本板(`artboardType=text_only`,整板只有对话/问答/提示文字)必须为 false。
107
+
108
+ 任一门失败优先归因 `PARSER`,修复目标是 `vision.py` / `parse_meaxure.py` / `boundary.json` 的通用几何规则,不允许用业务名救某个样本。
109
+
110
+ ## 验收标准(r060 起)
111
+
112
+ ### 单案例通过门(per-case pass gate)
113
+
114
+ 每张卡片必须同时满足以下全部条件才算 PASS:
115
+
115
116
  | 维度 | 门(`lib/scoring.mjs::PASS_GATE`) | 说明 |
116
117
  |---|---:|---|
117
- | 像素差异 (pixelDiff) | **≤ 0.08** | 逐像素差异比;标注缺陷矩形、非标字体字形带、以及「导出素材缺失→画板裁切兜底切图」(reason=crop-fallback-slice,仅掩 schema 真实引用的裁切盒)局部掩膜(报告 pixelExclusions 透明可见) |
118
- | UI 还原度 (overall) | **≥ 0.85** | 综合像素+结构+组件+文本 |
119
- | 组件相似度 (components) | **≥ 0.75** | 文本/媒体/富文本计数匹配(ListLayout 按数据项展开计数) |
120
- | 位置还原度 (position) | **≥ 0.80** | 文本盒对齐(含形状锚点) |
121
- | 文本溢出 (textOverflow) | **≥ 0.90** | 渲染盒溢出/裁切 |
122
- | 结构还原度 (structure) | **≥ 0.85** | 轮廓直方图(含 1.25% 容差窗) |
123
- | 色彩还原度 (color) | **≥ 0.90** | 颜色分布相似度 |
124
- | 尺寸还原度 (dimension) | **≥ 0.95** | 宽高比匹配 |
125
- | 重复内容 (duplication) | **≥ 0.95** | 同一文案渲染次数不得超出标注次数 5%;合并渲染(¥+金额 合一)豁免 |
118
+ | 像素差异 (pixelDiff) | **≤ 0.08** | 逐像素差异比;标注缺陷矩形、非标字体字形带、以及「导出素材缺失→画板裁切兜底切图」(reason=crop-fallback-slice,仅掩 schema 真实引用的裁切盒)局部掩膜(报告 pixelExclusions 透明可见) |
119
+ | UI 还原度 (overall) | **≥ 0.85** | 综合像素+结构+组件+文本 |
120
+ | 组件相似度 (components) | **≥ 0.75** | 文本/媒体/富文本计数匹配(ListLayout 按数据项展开计数) |
121
+ | 位置还原度 (position) | **≥ 0.80** | 文本盒对齐(含形状锚点) |
122
+ | 文本溢出 (textOverflow) | **≥ 0.90** | 渲染盒溢出/裁切 |
123
+ | 结构还原度 (structure) | **≥ 0.85** | 轮廓直方图(含 1.25% 容差窗) |
124
+ | 色彩还原度 (color) | **≥ 0.90** | 颜色分布相似度 |
125
+ | 尺寸还原度 (dimension) | **≥ 0.95** | 宽高比匹配 |
126
+ | 重复内容 (duplication) | **≥ 0.95** | 同一文案渲染次数不得超出标注次数 5%;合并渲染(¥+金额 合一)豁免 |
126
127
  | validate / lint / render | 0 | 零容忍 |
127
128
 
128
129
  > **未达标维度按缺口排序落盘**:报告里的 `gateFailures`(全部未过门维度 + 归一化缺口)、
@@ -137,10 +138,10 @@ DSL_CARD_SLICES_DIR=<training-run>/slices
137
138
  > 取值顺序:逐样本比例 → 同 fontSize 档中位数 → overall 中位数 → 文件缺失回退 `1.35`。
138
139
  > 换字体栈、改 `card-editor/styles/app.css` 或改掩膜逻辑后**必须重跑探针**(`node training/tools/probe_font_metrics.mjs`),
139
140
  > 否则 pixelDiff 口径漂移、轮间与锚点不可比。
140
- > **掩膜门环境感知(seq4 起)**:掩膜门不再只看字体家族名——探针实测「回退栈宽/标注宽」
141
- > `fontMaskWiden > 1.06` 即该字体在本机渲染环境不可得(PingFang SC 在 Windows 同样回退合成),
142
- > 一律掩膜;探针缺失回退家族名判据。否则设计稿字体与训练环境字体差会把像素门顶在
143
- > 8% 门外(实测卡 4 文本字形带单带 16-36%),误逼生成器改字重/字号扭曲 spec。
141
+ > **掩膜门环境感知(seq4 起)**:掩膜门不再只看字体家族名——探针实测「回退栈宽/标注宽」
142
+ > `fontMaskWiden > 1.06` 即该字体在本机渲染环境不可得(PingFang SC 在 Windows 同样回退合成),
143
+ > 一律掩膜;探针缺失回退家族名判据。否则设计稿字体与训练环境字体差会把像素门顶在
144
+ > 8% 门外(实测卡 4 文本字形带单带 16-36%),误逼生成器改字重/字号扭曲 spec。
144
145
 
145
146
 
146
147
 
@@ -172,14 +173,14 @@ DSL_CARD_SLICES_DIR=<training-run>/slices
172
173
  | duplicationFailures | 0 | 重复内容超限(重影)样本数 |
173
174
  | lint / validate / render / upstream | 0 | 全零 |
174
175
  | 高掩膜 PASS | 需复核 | 掩膜 ≥25% 的通过案例不计入晋级证据(见「掩膜覆盖率护栏」) |
175
-
176
+
176
177
  > 基线载体是**冻结锚点轮目录**(含 `reports/` 全量证据)+ **入库压缩锚点** `training/anchors/<round>.json`
177
178
  > (P0-2 起:干净克隆与 CI 上唯一的锚点载体,`round_diff.mjs` / `plan_next_round.mjs` 都直接吃它)。
178
179
  > 本 Skill 目录下的历史 `baselines/v3-r0*.json` 范式已废弃并删除(指标快照改由 summary.json + 压缩锚点承载)。
179
180
  > 晋级 = 新轮成为下一冻结锚点候选,在 `training/plans/` 记录轮号与指标,并重新生成压缩锚点入库。
180
-
181
- ### 泛化盲测门(generalization gate)
182
-
181
+
182
+ ### 泛化盲测门(generalization gate)
183
+
183
184
  每 **3 轮**锚点回归后(或每次晋级基线前),必须用**未参与修复的新批次数据集**(或 holdout / eval 分区)抽取 **不少于 24 例未见样本** 做盲测(如 v6 sampled 30 例):
184
185
 
185
186
  | 门禁 | 目标 | 说明 |
@@ -196,15 +197,15 @@ DSL_CARD_SLICES_DIR=<training-run>/slices
196
197
  用 `build_sample.mjs` 从 v6 + v7 全量池各抽代表,合并成 `training/datasets/blindset/train-set.jsonl`
197
198
  (≥24 例,结构聚类去重后覆盖列表/表单/结果/媒体/空状态),晋级轮一律用它盲测,
198
199
  并在 `training/plans/` 记录该盲测集的 provenance 与轮号。盲测集**不参与任何修复迭代**。
199
- ### 收敛检测与早停
200
-
201
- 当出现以下任一信号时,**停止脚本微调,转而修订 Skill 文档规则或范式**:
202
-
203
- 1. **边际收益递减**:连续 3 轮焦点集 avgFidelity 提升 < 1pt(0.01)。
204
- 2. **锚点升但盲测降**:锚点 avgFidelity 提升但盲测 avgFidelity 下降 → 判定过拟合,拒绝晋级。
205
- 3. **同一签名反复出现**:同一失败签名在 ≥ 3 轮中重复出现且未消除 → 说明脚本补丁无效,需升级 Skill 级别范式。
206
- 4. **盲测差扩大**:锚点−盲测差从 ≤5pts 扩大到 ≥10pts → 过拟合风险,强制回退。
207
-
200
+ ### 收敛检测与早停
201
+
202
+ 当出现以下任一信号时,**停止脚本微调,转而修订 Skill 文档规则或范式**:
203
+
204
+ 1. **边际收益递减**:连续 3 轮焦点集 avgFidelity 提升 < 1pt(0.01)。
205
+ 2. **锚点升但盲测降**:锚点 avgFidelity 提升但盲测 avgFidelity 下降 → 判定过拟合,拒绝晋级。
206
+ 3. **同一签名反复出现**:同一失败签名在 ≥ 3 轮中重复出现且未消除 → 说明脚本补丁无效,需升级 Skill 级别范式。
207
+ 4. **盲测差扩大**:锚点−盲测差从 ≤5pts 扩大到 ≥10pts → 过拟合风险,强制回退。
208
+
208
209
  以上 4 类信号由 `plan_next_round.mjs` 自动计算(信号名:`marginal-gain-below-1pt` /
209
210
  `anchor-up-blind-down` / `same-signature-3-rounds` / `anchor-blind-gap-over-10pts`,另有 `pass-by-mask`),
210
211
  任一触发即写出 `reports/convergence-report.json`。收敛触发后,Agent 必须在该报告基础上给出瓶颈分类和
@@ -213,21 +214,21 @@ Skill 级改进建议,而非继续打脚本补丁。
213
214
  > 趋势口径:边际收益按**最近 ≤4 轮的共同案例集**算 avgFidelity 逐轮 delta(跨批次轮次案例集不同,
214
215
  > 直接比均值是假信号);重复签名按 `--history`(默认自动扫 `training/runs/` 最近 8 轮)统计,
215
216
  > 老报告没有签名字段时按当前尺子现算,保证跨轮可比。
216
-
217
- ### 视觉修正回路(模型在环)
218
-
219
- 当脚本化校正(`correctCardLayout` 的 X/Y 轴 padding 对齐)收敛后仍无法通过门禁时,启用模型多模态回路,遵循「模型视觉判断 > 脚本启发式」的优先级:
220
-
221
- 1. 对焦点集每例收集 `design.png`、`render.png`、`spec.json`、`schema.json` 与渲染元素盒 `elementBoxes`。
222
- 2. 模型逐区域比对设计稿与渲染图,输出**可执行的布局修正指令**(目标节点 + 属性 + 期望值 + 证据区域),写入 `visual-fix.jsonl`;指令只允许引用结构证据(坐标、尺寸、颜色、文本),禁止出现业务词硬编码。
223
- 3. 脚本按指令修改 schema 并重渲染,仅当 position / pixel / duplication 三项均不退化时才保留,否则回滚。
224
- 4. 同一修正模式在 ≥3 个案例中复现 → 抽象为通用规则回灌 `dsl-card-generator` 或 `sketch-spec-to-card`,并登记 `training/lessons/lessons.jsonl`。
225
- 5. 每轮视觉修正后必须复跑冻结锚点,防止局部修正引发全局回归。
226
-
227
- > **lessons 反哺提案**:定期(建议每个训练批次收尾时)跑 `node training/tools/aggregate_lessons.mjs` 聚合 lessons.jsonl——重复签名(同一坑重复踩)、未落盘规则(按 targetFiles 给建议落点)、密集落盘点(规则密集文件需结构性审视)三类提案,人工逐条 yes/no 审批后落盘,工具本身不自动改任何 skill 文件。
228
-
229
- ## 当前基线与落地门
230
-
217
+
218
+ ### 视觉修正回路(模型在环)
219
+
220
+ 当脚本化校正(`correctCardLayout` 的 X/Y 轴 padding 对齐)收敛后仍无法通过门禁时,启用模型多模态回路,遵循「模型视觉判断 > 脚本启发式」的优先级:
221
+
222
+ 1. 对焦点集每例收集 `design.png`、`render.png`、`spec.json`、`schema.json` 与渲染元素盒 `elementBoxes`。
223
+ 2. 模型逐区域比对设计稿与渲染图,输出**可执行的布局修正指令**(目标节点 + 属性 + 期望值 + 证据区域),写入 `visual-fix.jsonl`;指令只允许引用结构证据(坐标、尺寸、颜色、文本),禁止出现业务词硬编码。
224
+ 3. 脚本按指令修改 schema 并重渲染,仅当 position / pixel / duplication 三项均不退化时才保留,否则回滚。
225
+ 4. 同一修正模式在 ≥3 个案例中复现 → 抽象为通用规则回灌 `dsl-card-generator` 或 `sketch-spec-to-card`,并登记 `training/lessons/lessons.jsonl`。
226
+ 5. 每轮视觉修正后必须复跑冻结锚点,防止局部修正引发全局回归。
227
+
228
+ > **lessons 反哺提案**:定期(建议每个训练批次收尾时)跑 `node training/tools/aggregate_lessons.mjs` 聚合 lessons.jsonl——重复签名(同一坑重复踩)、未落盘规则(按 targetFiles 给建议落点)、密集落盘点(规则密集文件需结构性审视)三类提案,人工逐条 yes/no 审批后落盘,工具本身不自动改任何 skill 文件。
229
+
230
+ ## 当前基线与落地门
231
+
231
232
  当前冻结锚点 = `training/runs/r176`(v4 sampled 44 例)/入库压缩锚点 `training/anchors/r176.json`(40 例共享)。
232
233
  最近一次锚点回归 **r262 = 44/44 PASS,对 r176 0 例 pass→fail**(v7 焦点集双案例过门后收口);
233
234
  r198 记录的共享 40 例均值为 fidelity 96.4% / pixel 3.8% / position 95.7% / structure 95.6%。
@@ -247,18 +248,18 @@ r198 记录的共享 40 例均值为 fidelity 96.4% / pixel 3.8% / position 95.7
247
248
  > `training/anchors/r176.json`;保真度软门禁走入库 fixture `training/fixtures/ui-drafts/`
248
249
  > (`tools/regress-fidelity.mjs` 在 `UI/` 缺失时自动回退);数据集需用 `build_dataset.py`
249
250
  > 从桌面导出重建,provenance 记在 `dataset-summary.json`。
250
-
251
- 历史演进(baseline JSON 范式时期,仅供追溯):
252
-
253
- | 基线 | 平均还原度 | 最低 | 低于80% | 结构还原度 |
254
- |---|---:|---:|---:|---:|
255
- | v3-r050n (08/26) | 79.5% | 73.2% | 26 | 70.4% |
256
- | v3-r052n (08/27) | 80.5% | 74.1% | 15 | 71.1% |
251
+
252
+ 历史演进(baseline JSON 范式时期,仅供追溯):
253
+
254
+ | 基线 | 平均还原度 | 最低 | 低于80% | 结构还原度 |
255
+ |---|---:|---:|---:|---:|
256
+ | v3-r050n (08/26) | 79.5% | 73.2% | 26 | 70.4% |
257
+ | v3-r052n (08/27) | 80.5% | 74.1% | 15 | 71.1% |
257
258
  | v3-r058 (08/28) | 85.9% | 82.0% | 0 | 93.2% |
258
259
  | 冻结锚点范式 (r176→r198→r262) | 96.2%→96.4% | — | 0 | 95.4%→95.6%(r262 全量 44/44 PASS) |
259
-
260
- ### 定向还原度迭代协议(r060 起)
261
-
260
+
261
+ ### 定向还原度迭代协议(r060 起)
262
+
262
263
  基线通过后不直接全量重训。每轮使用「冻结锚点(案例数以锚点载体为准:压缩锚点 40 例 / 冻结轮 44 例)
263
264
  + 低分焦点集 + 未见样本盲测」:
264
265
 
@@ -267,16 +268,16 @@ r198 记录的共享 40 例均值为 fidelity 96.4% / pixel 3.8% / position 95.7
267
268
  `<82%` 必须逐张多模态归因。
268
269
  2. Agent 同时读取设计稿、渲染截图、`spec.json` 和 `schema.json`(`diagnose_case.mjs --out` 已把这些
269
270
  证据与偏差表打包成 JSON),输出区域级 `agent-audit.jsonl`;结论必须包含失败类、通用规则候选、置信度和目标 Skill。
270
- 3. 修复优先级:可见媒体与重影 → 语义顺序与纵向节奏 → 背景/圆角/留白 → 未见样本泛化。
271
- 4. 缺失/状态错切图优先画板裁切(`cropSlice`,含宽条切图与纯矢量 logo 组;矩形内有文本叠加或背景级大矩形禁裁),裁切不可用才纯色近似并标记缺陷;弥散/光晕类纹理特事特办,计入局部还原度豁免。
271
+ 3. 修复优先级:可见媒体与重影 → 语义顺序与纵向节奏 → 背景/圆角/留白 → 未见样本泛化。
272
+ 4. 缺失/状态错切图优先画板裁切(`cropSlice`,含宽条切图与纯矢量 logo 组;矩形内有文本叠加或背景级大矩形禁裁),裁切不可用才纯色近似并标记缺陷;弥散/光晕类纹理特事特办,计入局部还原度豁免。
272
273
  5. 焦点样本通过后必须复跑冻结锚点全量;每 3 轮做不少于 24 例未见样本盲测(固定跨批次盲测集见上文)。
273
274
  6. 晋级门、焦点 ID 和产物路径以 `training/plans/` 下最新 plan 与本轮 `reports/next-round-plan.json` 为准。
274
- 7. 新布局通道(如散点带 §21、段落壳归属 §22、行锚点/尾随切片 §23)落盘生成器后,同步 lessons.jsonl + generation_pitfalls/quickref/previewer_contract,并复跑冻结锚点确认 0 回归;通道判据只认几何/样式结构,不认业务词。
275
-
276
- 训练清单可记录样本 ID 和画板名作为证据;运行时代码、Skill 判定和校验器不得引用业务词、画板名或样本专属文案。
277
-
278
- ### 晋级落地检查清单
279
-
275
+ 7. 新布局通道(如散点带 §21、段落壳归属 §22、行锚点/尾随切片 §23)落盘生成器后,同步 lessons.jsonl + generation_pitfalls/quickref/previewer_contract,并复跑冻结锚点确认 0 回归;通道判据只认几何/样式结构,不认业务词。
276
+
277
+ 训练清单可记录样本 ID 和画板名作为证据;运行时代码、Skill 判定和校验器不得引用业务词、画板名或样本专属文案。
278
+
279
+ ### 晋级落地检查清单
280
+
280
281
  新一轮改动落地前必须满足:
281
282
 
282
283
  1. 失败样本探针全部通过。
@@ -284,8 +285,8 @@ r198 记录的共享 40 例均值为 fidelity 96.4% / pixel 3.8% / position 95.7
284
285
  (`plan_next_round.mjs --anchor` 的 `promotionGate.passed = true`)。
285
286
  3. validate/lint/render/upstream 失败数均为 0。
286
287
  4. `git status --short -- src` 为空。
287
- 5. 批次轮 score_round:duplicationFailures = 0;成熟批次(v4/v5)另要求 passRate 趋势向上且残留失败逐例归因。
288
- 6. 若为晋级轮,盲测 24 例 passRate ≥ 85%,盲测 avgFidelity ≥ 78%,锚点−盲测差 ≤ 10pts。
288
+ 5. 批次轮 score_round:duplicationFailures = 0;成熟批次(v4/v5)另要求 passRate 趋势向上且残留失败逐例归因。
289
+ 6. 若为晋级轮,盲测 24 例 passRate ≥ 85%,盲测 avgFidelity ≥ 78%,锚点−盲测差 ≤ 10pts。
289
290
  7. 通用规则写入 `training/lessons/lessons.jsonl`(新格式 `{lessonId, signature, failureClass, evidenceCases,
290
291
  rule, targetFiles, status, round}`;`plan_next_round.mjs` 产的 `lesson-drafts.jsonl` 是待补 rule 的草稿),
291
292
  并同步到对应 Skill 的 `SKILL.md` 或 `references/`;业务词、画板名和样本专属文案不得进入规则。
@@ -296,15 +297,15 @@ r198 记录的共享 40 例均值为 fidelity 96.4% / pixel 3.8% / position 95.7
296
297
  `tools/tests/scoring.test.mjs` 直接拦截;lint 走棘轮(`tools/lint-baseline.json`,error 只减不增,
297
298
  治理后 `node tools/lint-ratchet.mjs --update` 收紧)。
298
299
  10. 掩膜 ≥25% 的通过案例已人工看图复核(`summary.json::highMaskCases` / plan 的 `pass-by-mask` 信号)。
299
-
300
- 评分器本身也要参与回归:组件语义升级(如 `Input` 正确承载金额)时,评分器必须把可编辑文本组件计入 text 维度;ListLayout 必须按数据项数展开模板内 Text/Image/Input/Button 计数,避免正确模板复用被当成组件丢失。
301
-
302
- 结构评分对轮廓直方图使用约 1.25% 尺寸的对称最近邻对齐窗口:1–2 像素渲染偏移不视为结构丢失,明显缺块、错位和错误背景仍会扣分。调整该容差必须同步复跑冻结锚点,不允许用放宽阈值掩盖还原缺陷。
303
-
304
- 像素对比额外记录 `bestAlignDy`(最佳纵向对齐偏移,仅诊断字段,不参与评分):用于区分「截图裁切/节奏误差」与「真实布局错误」。**禁止**用对齐搜索后的差异替代零偏移差异参与评分——实测(r125)偏移因案例而异(0 / -4 / -16px 并存),不存在可统一归一化的系统性裁切偏移,统一平移只会掩盖真实的纵向节奏缺陷。
305
-
306
- 布局自动校正覆盖 X/Y 两轴:`correctCardLayout` 按渲染元素与标注的偏差调整子节点的 `paddingTop`/`paddingLeft`(X 轴钳制 ±48px),仅当校正后 position 总分变好才保留,否则回滚 schema。
307
-
300
+
301
+ 评分器本身也要参与回归:组件语义升级(如 `Input` 正确承载金额)时,评分器必须把可编辑文本组件计入 text 维度;ListLayout 必须按数据项数展开模板内 Text/Image/Input/Button 计数,避免正确模板复用被当成组件丢失。
302
+
303
+ 结构评分对轮廓直方图使用约 1.25% 尺寸的对称最近邻对齐窗口:1–2 像素渲染偏移不视为结构丢失,明显缺块、错位和错误背景仍会扣分。调整该容差必须同步复跑冻结锚点,不允许用放宽阈值掩盖还原缺陷。
304
+
305
+ 像素对比额外记录 `bestAlignDy`(最佳纵向对齐偏移,仅诊断字段,不参与评分):用于区分「截图裁切/节奏误差」与「真实布局错误」。**禁止**用对齐搜索后的差异替代零偏移差异参与评分——实测(r125)偏移因案例而异(0 / -4 / -16px 并存),不存在可统一归一化的系统性裁切偏移,统一平移只会掩盖真实的纵向节奏缺陷。
306
+
307
+ 布局自动校正覆盖 X/Y 两轴:`correctCardLayout` 按渲染元素与标注的偏差调整子节点的 `paddingTop`/`paddingLeft`(X 轴钳制 ±48px),仅当校正后 position 总分变好才保留,否则回滚 schema。
308
+
308
309
  ## 命令
309
310
 
310
311
  ### 运行前置(跨平台)
@@ -324,20 +325,20 @@ r198 记录的共享 40 例均值为 fidelity 96.4% / pixel 3.8% / position 95.7
324
325
  > 否则 pixelDiff 口径漂移。
325
326
 
326
327
  ### 构建数据集
327
-
328
- ```bash
329
- python skills/card-skill-trainer/scripts/build_dataset.py \
330
- --src "<设计稿导出根目录>" \
331
- --out training/datasets/v1 \
332
- --max-cases 160
333
-
334
- # 聚焦训练(提速首选):--src 可直接指单份 MeaXure 导出;--artboards 只构建指定画板
335
- python skills/card-skill-trainer/scripts/build_dataset.py \
336
- --src ~/Desktop/某设计稿导出 \
337
- --out training/datasets/v7 \
338
- --artboards 4,14 --no-artboard-dedup
339
- ```
340
-
328
+
329
+ ```bash
330
+ python skills/card-skill-trainer/scripts/build_dataset.py \
331
+ --src "<设计稿导出根目录>" \
332
+ --out training/datasets/v1 \
333
+ --max-cases 160
334
+
335
+ # 聚焦训练(提速首选):--src 可直接指单份 MeaXure 导出;--artboards 只构建指定画板
336
+ python skills/card-skill-trainer/scripts/build_dataset.py \
337
+ --src ~/Desktop/某设计稿导出 \
338
+ --out training/datasets/v7 \
339
+ --artboards 4,14 --no-artboard-dedup
340
+ ```
341
+
341
342
  - `--artboards`:1 起序号或画板名关键词(逗号分隔,可混用)。序号转 parse_meaxure 的 0 起
342
343
  `--indices`、关键词走 `--only`;未选画板不进数据集。实测 47 画板整稿 → 2 画板:构建耗时降到 ~43s。
343
344
  - `--src` 指向自带 index.html 的单份导出时,它自身即唯一 source(不必再指到父目录把同级稿子全卷进来)。
@@ -357,15 +358,15 @@ node skills/card-skill-trainer/scripts/build_sample.mjs \
357
358
  实例:v5 39 画板 → 28 case → **17 代表**;v6 → **30 代表**。
358
359
 
359
360
  ### 运行一轮
360
-
361
- ```bash
362
- node skills/card-skill-trainer/scripts/run_round.mjs \
363
- --dataset training/datasets/v3/train-set.jsonl \
364
- --round r060 \
365
- --strategy v3 \
366
- --limit 48
367
- ```
368
-
361
+
362
+ ```bash
363
+ node skills/card-skill-trainer/scripts/run_round.mjs \
364
+ --dataset training/datasets/v3/train-set.jsonl \
365
+ --round r060 \
366
+ --strategy v3 \
367
+ --limit 48
368
+ ```
369
+
369
370
  常用开关:
370
371
 
371
372
  - `--only <caseId[,caseId]>`:只跑指定案例(冒烟用)。
@@ -379,13 +380,13 @@ node skills/card-skill-trainer/scripts/run_round.mjs \
379
380
  - `--no-summary`:跳过收尾自动汇总(默认自动调 `score_round.mjs --quiet`,直接打出 pass/avgFid/roundGate)。
380
381
  - `--splits train,dev`:限定分区(迭代纪律见上文)。
381
382
  - `--only` / `--only-failed` / `--focus` 三者互斥,同时传会直接报错而不是静默取其一。
382
-
383
- 渲染会话(Chrome + 预览 HTTP server)由 `skills/dsl-card-generator/scripts/render_card.mjs::createRenderSession`
384
- 持有,收尾 `close()` **必须能返回**:CDP `send()` 带 60s 兜底超时、WebSocket `close/error` 立即拒绝全部在途请求、
385
- `server.close()` 2s 后强制 `closeAllConnections()`(Chrome 的 keep-alive 连接不会自己断)。
386
- 少了任一条,浏览器异常退出时会出现「全案例跑完、`reports/` 齐全,却卡在 finally 写不出
387
- `review-queue.jsonl` / `summary.json`,node 进程 0% CPU 常驻」的假死(r202 实测),只能 `kill -9` 重跑整轮。
388
-
383
+
384
+ 渲染会话(Chrome + 预览 HTTP server)由 `skills/dsl-card-generator/scripts/render_card.mjs::createRenderSession`
385
+ 持有,收尾 `close()` **必须能返回**:CDP `send()` 带 60s 兜底超时、WebSocket `close/error` 立即拒绝全部在途请求、
386
+ `server.close()` 2s 后强制 `closeAllConnections()`(Chrome 的 keep-alive 连接不会自己断)。
387
+ 少了任一条,浏览器异常退出时会出现「全案例跑完、`reports/` 齐全,却卡在 finally 写不出
388
+ `review-queue.jsonl` / `summary.json`,node 进程 0% CPU 常驻」的假死(r202 实测),只能 `kill -9` 重跑整轮。
389
+
389
390
  ### 单案例诊断(支持批量)
390
391
 
391
392
  ```bash
@@ -403,13 +404,13 @@ node skills/card-skill-trainer/scripts/diagnose_case.mjs \
403
404
  标注几何取「聚焦卡」的 elements(与评分同源,避免多卡画板下产出幻影偏差)。
404
405
 
405
406
  ### 轮间对比
406
-
407
- ```bash
408
- node skills/card-skill-trainer/scripts/round_diff.mjs \
409
- --from training/runs/r060 \
410
- --to training/runs/r061
411
- ```
412
-
407
+
408
+ ```bash
409
+ node skills/card-skill-trainer/scripts/round_diff.mjs \
410
+ --from training/runs/r060 \
411
+ --to training/runs/r061
412
+ ```
413
+
413
414
  列出指标 delta、fail→pass 修复清单、pass→fail 回归清单;存在回归时 exit 1,
414
415
  可作为提交前门禁(`--allow-regressions` 可豁免)。
415
416
  `--from` / `--to` 都可以是压缩锚点文件(干净克隆唯一可用的基线):
@@ -446,24 +447,24 @@ node skills/card-skill-trainer/scripts/plan_next_round.mjs \
446
447
  可直接粘贴的下一轮命令、以及 `lesson-drafts.jsonl`(`status=candidate` 草稿,人工补 rule 后落盘)。
447
448
  归因只认指标与标注缺陷证据,不认业务词。
448
449
 
449
- ### 训练设施工具(`training/tools/`,已入库)
450
-
451
- ```bash
452
- node training/tools/aggregate_lessons.mjs # lessons 聚合 → 反哺提案(P-B 未落盘规则 / P-C 密集落盘点)
453
- node training/tools/probe_font_metrics.mjs # 非标字体回退字宽探针 → training/reports/font-metrics.json(掩膜扩宽比)
450
+ ### 训练设施工具(`training/tools/`,已入库)
451
+
452
+ ```bash
453
+ node training/tools/aggregate_lessons.mjs # lessons 聚合 → 反哺提案(P-B 未落盘规则 / P-C 密集落盘点)
454
+ node training/tools/probe_font_metrics.mjs # 非标字体回退字宽探针 → training/reports/font-metrics.json(掩膜扩宽比)
454
455
  node training/tools/analyze_position.mjs <round> [caseIdPrefix...] [--dataset <jsonl>] # 逐样本 spec 文本框 vs 渲染 elementBoxes 配对偏差(缺省扫 training/datasets/*/*.jsonl)
455
- node training/tools/probe_offsets.mjs <cardsRoot> <cardId> <width> [captureHeight] # 实测渲染页 DOM 几何(padding / content box / 偏移)
456
- python3 training/tools/split_report.py <runDir> [topN] # 按 split 聚合指标并列出最差 N 例
457
- ```
458
-
456
+ node training/tools/probe_offsets.mjs <cardsRoot> <cardId> <width> [captureHeight] # 实测渲染页 DOM 几何(padding / content box / 偏移)
457
+ python3 training/tools/split_report.py <runDir> [topN] # 按 split 聚合指标并列出最差 N 例
458
+ ```
459
+
459
460
  > `training/datasets/`、`training/runs/` 仍被 gitignore(体积 + 源稿版权)。数据集可复现性靠
460
461
  > `dataset-summary.json` 的 `provenance`(sourceRoot / sourceNames / toolchainRev / 解析器参数)
461
462
  > 与 `training/plans/` 的轮次记录;锚点回归靠冻结轮目录(`training/runs/r176`)**或入库压缩锚点**
462
463
  > (`training/anchors/r176.json`,干净克隆唯一可用载体)。已入库的训练设施还有
463
464
  > `training/tools/*`、`training/reports/font-metrics.json`、`training/fixtures/ui-drafts/`(保真度软门禁兜底稿)。
464
-
465
- ## 输出
466
-
465
+
466
+ ## 输出
467
+
467
468
  ```text
468
469
  training/runs/<round>/
469
470
  cards/
@@ -218,7 +218,7 @@ node skills/dsl-card-generator/scripts/describe_card.mjs --id <cardId> --json
218
218
  | `card-dir` | 已存在卡片目录(含 `schema.json`) | 不是建卡是改卡 → 转本技能 Workflow A(修绑定)/ Workflow B(批量改) |
219
219
  | `unknown` | 判不出形态(`ok:false`) | **不要猜**:向用户确认输入形态,或让其显式给出 `UI/<画板>/spec.json` 与 `card-N.png` |
220
220
 
221
- > **多画板选择门禁(铁律 §十三)**:`meaxure-export` / `ui-bundle` 判定为多画板输入时,**UI 产物可全量生成**(上游前处理一次跑完整份导出),但**产卡必须以单个画板 / 单个 cardKey 为单位**。用户未指定目标画板时:先机械取全量画板(未前处理 → `parse_meaxure.py --src <导出目录> --list`,展示 1 起;已前处理 → `manifest.json` 的 `canvases[]` + `clusters.json` 的 `cards[]`),按 **`1..n` 编号列出 + 末尾追加 `全部`**;**没有弹选项工具**(不存在 `request_user_input`,**不要去调用或寻找**),一律在正文列出清单 + 一句纯文本提问后**停止输出、等用户回序号**再继续。**UI 产物可回 `全部` 全量生成**;**产卡默认单画板 / 单 cardKey**,用户回 `全部` 才视为显式批量授权——**禁止**自行挑画板、禁止未经同意批量 `card_write`。系统级选择弹窗不可实现,「正文列清单 / 停下等序号」即等价物;清单**逐行配图**(每画板行下紧跟它自己的预览图绝对路径,缺图显式标缺失,禁止把图堆在清单末尾),转给用户时逐条内联 Markdown 图片看图选。
221
+ > **多画板选择门禁(铁律 §十三)**:`meaxure-export` / `ui-bundle` 判定为多画板输入时,**UI 产物可全量生成**(上游前处理一次跑完整份导出),但**产卡必须以单个画板 / 单个 cardKey 为单位**。用户未指定目标画板时:先机械取全量画板(未前处理 → `parse_meaxure.py --src <导出目录> --list`,展示 1 起;已前处理 → `manifest.json` 的 `canvases[]` + `clusters.json` 的 `cards[]`),按 **`1..n` 编号列出 + 末尾追加 `全部`**;**没有弹选项工具**(不存在 `request_user_input`,**不要去调用或寻找**),一律在正文列出清单 + 一句纯文本提问后**停止输出、等用户回序号**再继续。**UI 产物可回 `全部` 全量生成**;**产卡默认单画板 / 单 cardKey**,用户回 `全部` 才视为显式批量授权——**禁止**自行挑画板、禁止未经同意批量 `card_write`。系统级选择弹窗不可实现,「正文列清单 / 停下等序号」即等价物;清单**逐行配图**(每画板行下紧跟它自己的预览图绝对路径,缺图显式标缺失,禁止把图堆在清单末尾)——**路径照抄完整绝对路径:禁止用 `…` / `...` 省略前缀、禁止包进反引号或代码块**(缩写的路径渲染端取不到图),转给用户时逐条内联 Markdown 图片看图选。
222
222
 
223
223
  ### 6.3 交接生成与收口
224
224