dsh-ppt-studio 1.1.5 → 1.2.1

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 (94) hide show
  1. package/README.md +4 -1
  2. package/docs/00-/350/256/276/350/256/241/346/272/220.md +4 -0
  3. package/docs/02-/346/212/200/346/234/257/346/212/245/345/221/212.md +114 -1
  4. package/docs/03-/346/233/264/346/226/260/346/227/245/345/277/227.md +159 -0
  5. package/docs/05-/350/277/255/344/273/243/346/265/201/347/250/213.md +23 -0
  6. package/docs/06-/350/257/204/345/256/241/344/270/216/346/265/213/350/257/225.md +2 -1
  7. package/docs/07-/345/244/215/346/235/202/345/233/276/350/203/275/345/212/233/347/253/213/351/241/271/344/270/216/351/243/216/351/231/251/347/231/273/350/256/260.md +319 -0
  8. package/docs/08-/351/230/266/346/256/265A/350/256/276/350/256/241/350/257/264/346/230/216-/347/273/223/346/236/204/345/205/263/347/263/273/344/270/216/345/233/276/344/270/223/345/261/236/346/240/241/351/252/214.md +306 -0
  9. package/docs/09-/344/273/243/347/240/201/345/234/260/345/233/276/344/270/216/346/250/241/345/235/227/350/201/214/350/264/243.md +148 -0
  10. package/docs/10-/345/256/277/344/270/273/350/200/246/345/220/210/347/202/271/346/270/205/345/215/225.md +49 -0
  11. package/docs/11-/346/234/257/350/257/255/350/241/250.md +42 -0
  12. package/docs/12-/345/244/215/346/235/202/345/233/276/351/200/232/350/267/257/347/232/204/351/200/211/346/213/251/344/270/216/351/252/214/346/224/266.md +65 -0
  13. package/docs/13-/345/217/221/347/211/210/345/207/206/345/244/207/350/256/241/345/210/222.md +79 -0
  14. package/docs/14-/345/217/221/345/270/203/346/270/205/345/215/225/357/274/210/350/215/211/347/250/277/357/274/211.md +57 -0
  15. package/docs/15-1.2.0 /345/217/221/345/270/203/346/212/245/345/221/212.md" +46 -0
  16. package/docs/17-/346/211/213/347/224/27313/351/241/265/350/255/246/345/221/212/351/200/220/346/235/241/345/244/204/347/275/256.md +102 -0
  17. package/examples/fx/fx-pro/preview/layout.json +12 -0
  18. package/examples/fx/fx-pro/preview/measured.json +1 -1
  19. package/examples/fx/fx-pro.pptx +0 -0
  20. package/examples/fx/seed.pptx +0 -0
  21. package/examples/fx/single.pptx +0 -0
  22. package/examples/fx/spliced.pptx +0 -0
  23. package/examples/smoke/imported/preview-rt/layout.json +3 -0
  24. package/examples/smoke/imported/source.pptx +0 -0
  25. package/examples/smoke/out-smoke.pptx +0 -0
  26. package/examples/smoke/preview/layout.json +3 -0
  27. package/lib/group-render.js +177 -0
  28. package/lib/msrender.js +27 -12
  29. package/lib/pptd/blocks.js +52 -0
  30. package/lib/pptd/export-pptx.js +266 -11
  31. package/lib/pptd/layout.js +54 -3
  32. package/lib/pptd/line-rules.js +259 -0
  33. package/lib/pptd/line-text-rule.js +90 -0
  34. package/lib/pptd/relations.js +615 -0
  35. package/lib/pptd/render-html.js +19 -1
  36. package/lib/pptd/route-geometry.js +120 -0
  37. package/lib/pptd/schema.js +146 -11
  38. package/lib/pptd/style-profile.js +133 -0
  39. package/lib/scaffold.js +54 -1
  40. package/lib/tools.js +20 -2
  41. package/lib/verify.js +69 -1
  42. package/package.json +20 -3
  43. package/scripts/audit-manual-facts.mjs +15 -3
  44. package/scripts/bench-diagram-scale.mjs +165 -0
  45. package/scripts/check-generators.mjs +22 -0
  46. package/scripts/check-lib-sync.mjs +33 -0
  47. package/scripts/check-line-text.mjs +30 -0
  48. package/scripts/check-package.mjs +60 -0
  49. package/scripts/check-removed-traces.mjs +37 -0
  50. package/scripts/check-syntax.mjs +44 -0
  51. package/scripts/check-unknown-keys.mjs +114 -0
  52. package/scripts/fixtures/handdrawn-baseline.json +177 -0
  53. package/scripts/fixtures/prompt-cost-baseline.json +178 -0
  54. package/scripts/handdrawn-option-probe.mjs +78 -0
  55. package/scripts/probe-prompt-cost.mjs +127 -0
  56. package/scripts/red-probe.mjs +75 -0
  57. package/scripts/render-group.mjs +72 -0
  58. package/scripts/smoke.mjs +191 -20
  59. package/scripts/test-fast.mjs +108 -0
  60. package/scripts/test-map.mjs +162 -0
  61. package/scripts/test-release.mjs +64 -0
  62. package/scripts/verify-diagram-relations.mjs +405 -0
  63. package/scripts/verify-handdrawn.mjs +115 -0
  64. package/scripts/verify-handwritten.mjs +203 -0
  65. package/scripts/verify-preset-scope.mjs +1 -1
  66. package/scripts/verify-primitives.mjs +714 -0
  67. package/scripts/verify-products.mjs +37 -0
  68. package/scripts/verify-shape.mjs +84 -0
  69. package/scripts/visual-pair-batch.mjs +77 -0
  70. package/skills/ppt-studio-diagram/SKILL.md +30 -0
  71. package/skills/ppt-studio-diagram/capability-matrix.md +22 -0
  72. package/skills/ppt-studio-diagram/composition.md +22 -0
  73. package/skills/ppt-studio-diagram/mechanisms.md +141 -0
  74. package/skills/ppt-studio-diagram/pitfalls.md +97 -0
  75. package/skills/ppt-studio-diagram/routing.md +17 -0
  76. package/skills/ppt-studio-diagram/text-and-spacing.md +16 -0
  77. package/skills/ppt-studio-diagram/verify.md +50 -0
  78. package/skills/ppt-studio-diagram-compare/SKILL.md +38 -0
  79. package/skills/ppt-studio-diagram-flow/SKILL.md +38 -0
  80. package/skills/ppt-studio-diagram-funnel/SKILL.md +39 -0
  81. package/skills/ppt-studio-diagram-layers/SKILL.md +32 -0
  82. package/skills/ppt-studio-diagram-loop/SKILL.md +39 -0
  83. package/skills/ppt-studio-diagram-matrix/SKILL.md +37 -0
  84. package/skills/ppt-studio-diagram-sequence/SKILL.md +31 -0
  85. package/skills/ppt-studio-diagram-state/SKILL.md +48 -0
  86. package/skills/ppt-studio-diagram-steps-ring/SKILL.md +38 -0
  87. package/skills/ppt-studio-diagram-swimlane/SKILL.md +37 -0
  88. package/skills/ppt-studio-diagram-timeline/SKILL.md +38 -0
  89. package/skills/ppt-studio-diagram-tree/SKILL.md +38 -0
  90. package/skills/ppt-studio-manual/SKILL.md +2 -2
  91. package/templates/academic-white/preview.png +0 -0
  92. package/templates/business-blue/preview.png +0 -0
  93. package/templates/pitch-bold/preview.png +0 -0
  94. package/templates/tech-dark/preview.png +0 -0
package/README.md CHANGED
@@ -462,7 +462,10 @@ ppt_visual # Office 真渲染复核(有 Office 时;audit
462
462
 
463
463
  ```bash
464
464
  node scripts/build.mjs # 免 tsc:src → lib 复制(纯 ESM JS,源码即产物)
465
- npm test # build + LF 守卫 + smoke(303 断言)+ 预设漂移自检
465
+ npm run test:fast # 【每条改动默认跑】廉价跨切面守卫 + 按改动文件选影响面(实测:只改文档 ≈8s)
466
+ npm test # 【批次边界/发版】全量门禁:build + LF 守卫 + smoke(322 断言)+ 预设自检(≈5.5min)
467
+ npm run test:release # 【发版】全量 + e2e + 隔离矩阵 + 原生图表 + 损失审计 + 安装自证(并行,≈5min)
468
+ npm run test:map:audit # 防"孤儿分节":每个 smoke 分节都必须能被影响面选中
466
469
  npm run check:eol # 发行字节守卫:跟踪的文本文件必须全 LF(--fix 就地修)
467
470
  npm run fresh # 用户视角终验:干净克隆 npm test + 真装一遍
468
471
  npm run test:bundle # 安装路径自证:隔离 DSH_HOME + 真 dsh plugin add + dump-config
@@ -1,5 +1,9 @@
1
1
  # PPT 插件设计文档(头脑风暴成果 · 持续更新)
2
2
 
3
+ > **状态:历史存档(2026-09-03 起未再更新;此后从 v0.3 走到 1.1.5)。**
4
+ > 现行描述以 **docs/02 技术报告** 与 **docs/04 路线图** 为准;本文件保留当时的愿景与取舍脉络,**不要用它核对当前行为**。
5
+ > 如需重启本文件(作为新的设计源),请先与维护者确认,避免出现两份互相矛盾的"设计源"。
6
+
3
7
  > 状态:讨论推进中,主干已定;待细化项见文末清单。
4
8
  > 愿景:**该插件能应用到复杂场景中,实现其他工具做不好的 PPT 制作。**
5
9
  > 差异化 = 四类任务全兼容 + 布局工程(元素冲突防治)+ 跨页整体性 +
@@ -417,7 +417,7 @@
417
417
 
418
418
  | 层 | 手段 | 触发点 | 覆盖 |
419
419
  |---|---|---|---|
420
- | L0 单测 | `scripts/smoke.mjs`(303 断言) | 每次改动后 | schema/渲染/校验/导出/导入/媒体/背景/声明制(含闭包)/美学/Quick/引擎/样式回环/噪声过滤/**连线方向** |
420
+ | L0 单测 | `scripts/smoke.mjs`(322 断言) | 每次改动后 | schema/渲染/校验/导出/导入/媒体/背景/声明制(含闭包)/美学/Quick/引擎/样式回环/噪声过滤/**连线方向** |
421
421
  | L1 真实回归 | `scripts/regression-real.mjs` | 每次改动后(有资产则跑) | 19 页产能 deck(0 错误 + 0 缩字)、WPS UTF-16 文件导入 |
422
422
  | L2 数字门禁 | render→verify 逐页 | 每页制作后(工作流内) | overlap/出界/溢出/对齐 |
423
423
  | L3 视觉审阅 | shot + read_image / **Office 真渲染 + read_image**(v0.8,有条件) | 每页/整体(工作流内) | 构图/断行/对比度/孤字(估算漏报兜底)/真实观感 |
@@ -444,6 +444,22 @@
444
444
  - zip 用纯 JS deflate(zips.js),导出大媒体(>10MB 图片)时内存与耗时需关注(路线图:流式写/原样复制)。
445
445
  - 未设 scale 上限校验:超大尺寸 deck(>4096px)Edge 截图可能超限(路线图:scale 探测);overview 整览 >30 页自动截前 30。
446
446
 
447
+ ### 6.1 阶段 A 硬门槛基线(150 元素规模,2026-09-28 实测)
448
+
449
+ 命令:`node scripts/bench-diagram-scale.mjs`(可复跑;门槛不达标退出码 1。**计时断言不放进 smoke**——CI 共享 runner 上必然抖动,把抖动带进门禁会让"红"失去意义)。
450
+
451
+ 夹具刻意用满阶段 A 的新能力:1 容器 + 40 盒(各 `contains` 自己的标签)+ 48 注记 + 20 线(8 `attach`、6 条 3 点折线、6 条双箭头)+ 1 徽章 + 5 组(一层嵌套)+ 2 条有意重叠声明 ⇒ **150 元素**。
452
+
453
+ | 指标 | 实测 | 门槛(docs/08 §8 初值) |
454
+ |---|---|---|
455
+ | 结构关系推导 | 148 包含|16 附着|1 徽章|5 组;**豁免 189 对**(其中传递闭包 40) | — |
456
+ | `verifyDeck` | **42.5ms** | ≤ 3000ms |
457
+ | 预览 HTML 体积 | **73KB** | ≤ 1.5MB |
458
+ | 单页总处理(resolve+render+verify+export) | **284ms** | ≤ 10000ms |
459
+ | 报告规模 | 24 行 / 0 错误 / 17 警告(全部为审美建议:hotspot×16、density×1) | — |
460
+
461
+
462
+
447
463
  ## 7. 代码改动的波及面速查(改 X 要同步 Y)
448
464
 
449
465
  | 改了 | 必须同步 |
@@ -485,3 +501,100 @@ docs/ 本档案库(00 设计源 / 01 需求目标 / 02 技术报告
485
501
  - **媒体部件命名(2026-09-26)**:整册共享、按 `srcPath` 唯一 —— ASCII 且未被占用 ⇒ **原名不动**(既有工程产物逐字节不变);非 ASCII/空格或**重名** ⇒ `stem-<hash8>.<ext>`(hash 取相对路径,跨机器确定;`ppt/media/` 是包内部件名,用户看不到)。同一个名同时用于 rels Target 与包内条目;改名进 `report.mediaRenamed` 并在导出输出里**明说**(不静默)。
486
502
  README.md 使用者入口(轻量,指向 docs/)
487
503
  ```
504
+
505
+ ---
506
+
507
+ ## 10. 阶段 A 增补:复杂图地基(2026-09-28)
508
+
509
+ **要解决的问题**:复杂图(流程图/架构图)此前只能"每个盒子、每条线手写像素 + 逐对手写 `expectedOverlaps`"——
510
+ 一页 5 容器 × 10 子元素就是 50 对声明,既写不动也维护不了;元素一动,坐标全错。
511
+
512
+ **做法**:把"结构"写成声明,引擎**推导关系并做几何反验证**;导出侧补齐画复杂图必需的基元。
513
+
514
+ ### 10.1 结构声明词表(`src/pptd/schema.js` + `src/pptd/relations.js`)
515
+
516
+ | 声明 | 位置 | 语义 | 几何反验证(不成立 ⇒ **按普通冲突报错**,声明作废) |
517
+ |---|---|---|---|
518
+ | `groups[]`(`id/label/members`) | 页面级 | 逻辑组合(可嵌套 ≤3 层):审计/剪枝/豁免的单位 | 成员存在、无重复、只允许一个直接父组、嵌套无环 |
519
+ | `element.contains[]` | 元素 | 视觉容器"我真包住这些" | **严格包含**(pad=0);沿有效边做**传递闭包**(A ⊇ B ⊇ C ⇒ A×C 也豁免) |
520
+ | `element.attach{from,to:{ref,side}}` | line | 把端点锚到元素边(**优先于**手写 points) | 端点必须落在目标元素的对应边上(tol 1.5px);被改写的手写坐标进 `attachNotes` 并在门禁报 `attach-override` |
521
+ | `element.badgeOf` | 元素 | 徽章/标签的归属 | 必须相交、面积 ≤ 0.5×被归属者、不得盖满(否则更像"遮罩") |
522
+ | `element.roleReason` | 元素 | `role` 覆盖推断值时的理由 | 进"设计声明复核"段(缺失只警告,不破坏既有 deck) |
523
+ | `expectedOverlaps[].reason` | 页面级 | 有意重叠的理由(`expectedIntersections` 已收敛进来) | 两端必须存在、**不得同为内容元素**、必须确实相交(已失效 ⇒ 警告) |
524
+
525
+ 三条硬纪律:**推导的豁免不落盘**(每次现算,数据里看不到也不用维护);**确定性**(输出按 id 字典序,同输入两次深度相等);**纯函数不改输入**。
526
+
527
+ ### 10.2 门禁报告形态与"门控"
528
+
529
+ - 用了结构声明的页,报告多两行:`· 结构关系:组 N|包含 N|附着 N|徽章 N|有意重叠 N(自动豁免重叠 N 处,未落盘)` 与 `· 设计声明复核:…`(**固定存在**,让豁免可见)。
530
+ - **门控**:只有"本页用了阶段 A 字段(含 >2 点折线)"时才启用结构豁免与图专属检查 ⇒ **没有用新字段的页面,findings 与报告文本与从前完全一致**(这是"既有能力不退化"的机械保证)。
531
+ - 图专属机械检查:`duplicate-element`(几乎重合)、`text-over-text`(内容互压,永不可声明)、`line-through-box`(线穿盒;容器自身不算)、`arrow-not-on-edge`(脱靶;有 attach 则升级为错误)。
532
+
533
+ ### 10.3 导出基元与 parity
534
+
535
+ `points` >2 点 = **一帧 custGeom 开放路径**(不 close、无填充);`arrow: true|'end'|'both'`(两端箭头落在同一段 `a:ln` 内,顺序 `solidFill → prstDash → headEnd → tailEnd`);`line.dash: solid|dash|dot|dashDot`;`kind: notchedRightArrow`。
536
+ parity 新增 `polyLinesExp/Out`、`arrowEndsExp/Out`、**`attachedLinesExp/Out`(导出侧独立复核端点落在被引用元素的对应边上)**;无此类元素的工程全部为 0,既有断言不受影响。
537
+
538
+ ### 10.4 性能与成本(详见 §6.1)
539
+
540
+ 150 元素页:verify **14.6ms**、预览 HTML **73KB**、单页总处理 **122.6ms**(门槛 3000ms / 1.5MB / 10000ms);
541
+ 常驻 prompt 面 **4925 tokens**(22 工具 4492 + 技能目录 433),`npm run probe:prompt:check` 增幅上限 +5%。
542
+
543
+ (模块与文件职责见 docs/09;新增 DSL 字段必须同步"三处白名单"的纪律见 docs/09 §9。)
544
+
545
+ ---
546
+
547
+
548
+ **要解决的问题**:阶段 A 让"结构可声明",但仍要**手算每个盒子的像素**;元素一动,坐标全错,且结构关系要手写。
549
+
550
+ **做法**:写结构 → 引擎算几何 → **同时产出结构关系**(docs/12 是实施契约)。
551
+
552
+
553
+ 未实现类型/无效画布 ⇒ **不产任何元素 + notes 说明**(优雅降级,绝不产半成品图)。族带 `maturity`(现均为 `beta`)。
554
+
555
+ ### 11.2 引擎契约(六条,均有断言)
556
+
557
+ 纯函数|确定性(同输入两次深度相等)|只产既有元素类型(shape/text/line)|不产结构冲突|**自动产出结构关系**|优雅降级。
558
+
559
+ ### 11.3 物化与同源
560
+
561
+
562
+ ### 11.4 结构关系自动产出(阶段 A 的地基在这里被用起来)
563
+
564
+ | 关系 | 由谁产出 | 效果 |
565
+ |---|---|---|
566
+ | 分组 → 容器 + `contains` + `groups` | 引擎 | 组内重叠自动豁免;容器与逻辑组一并可见 |
567
+ | 连线 → `attach`(端点锚在节点边) | 引擎 | **箭头必然落边**,"箭头脱靶"永不触发;且无需任何声明 |
568
+
569
+ 实测:一页 4 节点 + 3 边 + 2 组的 IR,真实门禁 **0 错误 0 警告、页面零声明**。
570
+
571
+ ### 11.5 组级裁剪渲染(`scripts/render-group.mjs`,`npm run render:group`)
572
+
573
+ 整页缩略图会掩盖小尺寸缺陷(docs/07 R21)。做法:取该组元素并集包围盒,**造一个"幻灯片尺寸 = 该组包围盒"的临时工程**(元素整体平移)⇒ 渲染结果天然就是该组,**不需要图像裁剪库、无像素误差**;同时支持 `--page-render` 出整页版对照。取景用"成员框 + 有界迭代"规则纳入本组容器/组内连线/组标题,外层容器与隔壁组不会被误吞。输出明确标注"这是第 N 页的某个组合的局部图,不是整页"。
574
+
575
+ ### 11.6 顺带加固:COM 渲染的偶发失败
576
+
577
+ `Presentations.Open : Failed` 的根因是**上一次异常退出留下的无窗口 POWERPNT 实例**(队友在阶段 A 定位)。已在 `src/msrender.js` 做两件事:
578
+ ① 打开前**只清理没有主窗口**的残留实例(用户正在用的 PowerPoint 一定有主窗口,**绝不动**,不能为了渲染丢用户的活);
579
+ ② 失败后**重试一次**(渲染失败通常是瞬时的,重试成本远低于让用户看到假失败)。
580
+
581
+ (模块与文件职责见 docs/09;阶段 B DoD 与硬门槛复测见 docs/12 §12。)
582
+
583
+ ## 13. 阶段 D(参考稿样式 / 可复用块 / 北极星)与泛用性收口(2026-09-28/29)
584
+
585
+ **阶段 D 三件**:
586
+
587
+ | 项 | 内容 | 自证 |
588
+ |---|---|---|
589
+ | D-② 组合作为可复用块 | `src/pptd/blocks.js`:`deck.blocks.<名>` + 页面 `blocks: [{name, at}]`,**copy 语义**(深拷贝、id 加 `bk<n>_` 前缀、按 `at` 平移、`contains`/`attach`/`badgeOf`/`groups` 引用同步重映射) | `verify:ir` 第 7 节 5 条(6 份同款卡片过门禁 0 错误) |
590
+ | D-③ 北极星端到端 | `scripts/verify-northstar.mjs`:参考稿 → 档案 → 同构换内容 → 导出,断言**其它页逐字节不变**、目标页确实变了、两版 parity、确定性;并证明 **IR 是手写能力的无损超级集**(摊平后 14 个部件逐字节一致) | 8/0 |
591
+
592
+ **泛用性收口("不损害助手泛用性"作为排序原则)**:
593
+
594
+ - **手写路径也有机械反馈**:`src/pptd/line-rules.js` 在 `verify.js` 的**非门控**位置运行,对所有页面的折线报 `arrow-end-short-run` / `line-diagonal-segment`(只警告不改判定;`role: decoration` 声明刻意斜线即豁免)。规则同时写进 `SCHEMA_REF`(模型可见),并明确"**家族库没有的图就手写 elements——这是被支持的路径,不是退路**"。
595
+ - **消灭漏保护的路径**:遗留 `flow`/`layers` 改走 `makeEdge`,接入 R1(轴对齐)/R2(箭头端直段)。
596
+ - **证据**:`npm run verify:handwritten` 7/0(合法手写复杂图 0 错误 + 规则不误报 + 导出 parity);`examples/warm-arch/`(暖色系手写架构图)在编写时被规则当场抓出两个真错。
597
+ - **回归守门**:无图页产物逐字节不变;常驻 prompt 增幅 0.00%;全量 `npm test` 322/0;`render-families` 12/12 族 0 错误;**逐族 PNG 逐字节对比**证明改动的影响面被限制在目标族内(例:状态机路由改造后 12 族里只有 state 变化,其余 11 族逐字节不动)。
598
+
599
+
600
+
@@ -1,6 +1,103 @@
1
1
  # 03 · 更新日志(每次改动必须追加)
2
2
 
3
3
  > 格式:`## [版本号] 日期` → 目的(为什么改,引测试反馈编号)→ 改动 → 验证 → 影响/后续。
4
+
5
+ ## [1.2.1] 2026-09-30 —— 修复:复杂图 skills 未被注册(用户实测)
6
+
7
+ **问题**:新预设会话里,斜杠命令与助手的 skill 清单都找不到复杂图相关 skill(四份 `ppt-studio-*` 正常可见)。
8
+
9
+ **根因(实测)**:DSH 按「`SKILL.md` + frontmatter(`name`/`description`/`whenToUse`)」注册 skill;而 `skills/ppt-studio-diagram/SKILL.md` **没有 frontmatter**,12 份配方只是 `skills/diagrams/` 下**散装的 `.md`**、该目录**没有 `SKILL.md`** ⇒ 两组都不满足注册条件(打包正常,文件都在)。
10
+
11
+ **修法**:① 给 `ppt-studio-diagram/SKILL.md` 补 frontmatter;② 把 12 份配方各自拆成独立 skill 目录(各带 frontmatter),并**统一命名为 `ppt-studio-` 前缀**:`ppt-studio-diagram`(总纲)+ 12 份 `ppt-studio-diagram-<类型>`(tree/matrix/timeline/swimlane/compare/loop/funnel/steps-ring/sequence/state/flow/layers)⇒ 共 **17 个**内置技能(含原有 4 份)随**预设作用域**注册,不进全局技能目录。同期修:描述补足 >20 字符并剔除会破坏 YAML 的 `: ` 写法、正文 >800 字符、每份补「收工自检」与「优先级边界」块、smoke 的 §40/§52 期望技能数 4→17。
12
+
13
+ **验证**:仓库内 17 个 skill 目录均含 `SKILL.md`;安装后应能在预设会话的 skill 清单/斜杠命令中看到 `ppt-studio-diagram` 与 12 份 `diagram-*`。
14
+
15
+ ## [1.2.0] 2026-09-30 —— 复杂图通路定稿 + 适配 DSH 0.2.0-rc.2
16
+
17
+ **场景**(docs/07 §2 的可验证内核):拿到一份已有风格的参考稿,要在**同一风格**下换/加一页复杂图。
18
+
19
+
20
+ **验证(7/0)**:档案归纳正确(palette 按频次、bg、lineWidth);新页取色确实来自档案;**新页门禁 0 错误**;**第 1 页 slide XML / rels / 布局部件逐字节不变**(只换了目标页);目标页确实变了(防"假绿");两版 parity 均自洽;同一 deck 两次导出除 `core.xml` 外逐部件一致。
21
+
22
+ **顺带修掉的真问题**:`observeFromDeck` 第一版直接读 `el.fill`,于是 **`$themeRef` 未解析字符串**被当成中性色并挤掉真正的调色板(实测 `palette[0]` 排错、进而让新页取色走偏)。改为用 `ctx.resolveColor` **先解析成实际色值**再统计,非十六进制一律丢弃。
23
+
24
+ ### 2026-09-28 —— 阶段 D-②:组合作为可复用块(copy 语义)
25
+
26
+ **目的**(docs/07 §4:用户的真实工作方式是"把一组元素当成一个整体,反复用")。**改动**:新增 `src/pptd/blocks.js` + `resolveDeck` 物化——`deck.blocks.<名> = {elements, groups?}` 定义块,页面 `blocks: [{name, at:[x,y]}]` 复用;物化时**深拷贝**、id 加 `bk<n>_` 前缀、按 `at` 平移(`bounds` 数组/对象与 `points` 都位移)、**内部引用同步重映射**(`contains` / `attach.ref` / `badgeOf` / `groups.members`),块自带分组一并展开。物化后就是普通元素 ⇒ 预览/导出/校验**零改动**。
27
+
28
+ **验证**:`npm run verify:ir` 从 76 → **81 条**(新增第 7 节:前缀+引用重映射 / 平移 / **copy 语义**(改一份不影响另一份)/ 分组前缀不撞名 / **6 份同款卡片过真实门禁 0 错误**);`SCHEMA_REF` 补 `blocks` 与 `styles` 语法(能力可发现)。全量 `npm test` 全绿。
29
+
30
+ **要点**:块内**结构声明随拷贝一起生效**(卡片 `contains` 其文字 ⇒ 6 份拷贝都不报"背景×内容"重叠),所以 D-② 与阶段 A 的地基是叠加收益而不是两套机制。
31
+
32
+ ### 2026-09-28 —— 阶段 D-①(前半):参考稿样式档案的**观测与归纳**
33
+
34
+ **改动**:新增 `src/pptd/style-profile.js`——`observeFromDeck(ctx)` / `observeFromLayout(layout)` 从参考稿观测"实际出现了什么"(取色 / 线宽 / 字号 / 圆角 / 底色);`extractStyleProfile()` 归纳成令牌(**调色板按出现频次排序**、同频按色值字典序;墨色取中性色里最深的;中性色判定与 verify 同口径);`profileToTheme()` 折成普通 theme 对象(目的是让引擎侧零改动地吃它)。
35
+
36
+ **已验证**:观测→档案→theme 三步确定性(两次提取深度相等);参考稿样例(4 个色块 / 2 种主色 / 线宽 2 / 字号 22 / 底色)归纳出 `palette = ["#0F766E", "#14B8A6", "#F97316"]`、`bg = #F0FDFA`、`lineWidth = 2`。全量门禁 322/0。
37
+
38
+
39
+ **(同日补记·已打通)**绑定完成,根因值得留档:`render-html` 里 `layout.theme.colors = ctx.colors` 引用的是 **resolveDeck 开头捕获的那个对象**,而前两次我写的是 `theme.colors = { ...theme.colors, ... }`(**重新赋值造了新对象**)⇒ 合并生效了但门禁看不到。改为**原地写入** `live = theme.colors`(只在色板不存在时才建对象)后:档案驱动页**门禁 0 错误 0 警告**、取色与线宽来自档案、`layout.theme.colors` 里能查到档案色。自证 `verify:ir` 从 70 → **76 条**(新增第 6 节:频次排序 / 确定性 / 档案→theme / 档案驱动生成 / 门禁 0 错误 / 色板可达)。**教训**:在这套代码里改"共享的可变对象"要**原地写**,替换引用会被下游捕获的旧引用吃掉。
40
+
41
+
42
+ **改动**:`funnel`(`custGeom` 梯形逐段收窄,段内标签声明在段内)、`steps`(环上编号圆点 + 环外标签的**两轮放置**:放不下就省略,因为压字是永不可声明的 content-collision)、`sequence`(参与者盒 + **2px 窄矩形生命线**,这样消息端点能落在"盒子的边"上并写 attach)、`state`(**BFS 最短分层** + 列间走廊 + 转移总线,**回边不做特例**)。
43
+
44
+ **验证**:`npm run verify:ir` **70/0**(十二族 × 确定性/schema/画布内/attach 落边 + 十二页合并过真实门禁 **0 错误零声明**);全量 `npm test` 全绿。
45
+
46
+ **踩坑(全部由门禁抓出)**:① 漏斗标题压首段 + 段内标签未声明 `contains`;② 步骤环"编号/标签"互相压字 ⇒ 改**布局策略**(外推找空位)而不是加声明;③ 时序图标题掉出安全区;④ **状态机用"最长路径分层"会被环无限推高**(迭代上限后仍 7 层 ⇒ 列宽压到最小、节点重叠、标签越界)⇒ 改 BFS;⑤ 状态机的"从底边直接下行"被同列下方节点挡住、同层边切回列内撞上方节点 ⇒ 改"列间走廊 + 同侧进出"。
47
+
48
+
49
+
50
+ **验证**:`npm run verify:ir` **54/0**(六族 × 确定性/schema/画布内/attach 落边 + 六页合并过真实门禁 **0 错误零声明**);三族真渲染读图;全量 `npm test` 全绿。
51
+
52
+ **踩坑(全部由门禁抓出,已固化)**:① 泳道跨道连线第一版走"源右侧竖直走廊",横向段直接穿整行节点盒;② `compare` 自己造容器又没 `skipContainers` ⇒ 派发器再造一遍(同 id 重复 + 外扩越界);③ `cycle` 用角平分方向近似求端点 ⇒ 落到错误的那条边、线段斜穿节点盒。
53
+
54
+
55
+ **目的**:把"能画结构图"扩到**能画一族一族的经典图**(docs/07 §5 阶段 C),每族都要有布局策略 + 契约夹具 + 真渲染验收 + `maturity`。
56
+
57
+ **改动**
58
+ - **族清单冻结**在 docs/13(12 族 + 批次 + maturity + 每族 DoD);`SCHEMA_REF` 的 `type:` 行列出全部已实现族(能力可发现)。
59
+
60
+ **验证**:`npm run verify:ir` **42/0**(新增第 5 节:三族的确定性 / schema 合法 / 落在画布内 / attach 端点落边 + 三页合并过真实门禁 **0 错误零声明** + 族清单登记);真渲染三页读图(层级树的分组容器、肘形连线、箭头落边全部正确);全量 `npm test` 全绿。
61
+
62
+ **踩坑(已固化)**:① 树的分组容器与**组内折线**(AABB 有高度)被判意外重叠 ⇒ 容器把"两端都在组内"的连线纳入 `contains`;② 矩阵标题放在画布外 ⇒ 改为占画布内一条;③ 断言侧:IR 产出的 `line` 没有 `bounds`(由 points 推导),断言必须自己求 AABB(真实门禁不受影响)。
63
+
64
+
65
+ ### 2026-09-28 —— 阶段 A:复杂图地基(结构声明 + 几何反验证 + 导出基元)
66
+
67
+ **目的(用户立项原话)**:"不计成本,以'**最大幅度提高能力上限**'为目的……**必须得以'不影响已有功能与能力'为前提**";能力标尺是真实复杂图稿(精益大赛 deck,非风格模板)。
68
+
69
+ **问题**:复杂图只能"每个盒子每条线手写像素 + 逐对手写 expectedOverlaps"——一页 50 对声明写不动也维护不了,元素一动坐标全错。
70
+
71
+ **改动**
72
+ - **结构声明词表**:页面级 `groups[]`(可嵌套)+ `expectedOverlaps[].reason`;元素级 `contains` / `badgeOf` / `roleReason`;线级 `attach{from,to:{ref,side}}`(schema 校验含**顺序无关的引用检查**)。
73
+ - **`src/pptd/relations.js`(新模块)**:五类关系的推导 + **几何反验证**(声明不成立 ⇒ 按普通冲突点名报错;推导的豁免**不落盘**)+ 包含关系的**传递闭包**(嵌套组合不必枚举深后代)+ 四类图专属机械检查。三条硬纪律:确定性 / 不改输入 / 豁免不落盘。
74
+ - **verify 集成**:结构豁免注入声明集;报告新增"结构关系"计数行与"**设计声明复核**"段;**门控**保证没用新字段的页面行为与报告**完全不变**。
75
+ - **导出基元**:`attach` 在归一化阶段解析成坐标(**优先于手写 points 且改写可见**);>2 点折线 = 一帧 custGeom 开放路径;`arrow: 'both'` 两端箭头;`line.dash` 虚线;`notchedRightArrow`。
76
+ - **图进 parity**:`polyLinesExp/Out`、`arrowEndsExp/Out`、`attachedLinesExp/Out`(导出侧独立复核)。
77
+ - **量具**:`scripts/bench-diagram-scale.mjs`(150 元素规模,四条硬门槛之一)、`scripts/probe-prompt-cost.mjs`(常驻 prompt 成本基线 + `--check`)、`scripts/verify-diagram-relations.mjs`(70 条自证)、smoke §58(14 条)。
78
+
79
+ **验证**:全量 `npm test` **317/0**;自证脚本 **70/0**;150 元素基线全部达标(verify 14.6ms/HTML 73KB/单页 122.6ms);常驻 prompt 成本增幅 **0.00%**(≤5%);队友导出基元脚本 35/0(含与基线 tag **逐部件逐字节一致**);PowerPoint COM 真渲染读图确认附着线落边、虚线折线两端箭头、容器/徽章/notched 形状正确。
80
+
81
+ **踩坑(已固化为纪律)**:归一化与快照是**白名单式构造**,新字段不加进去就"静默消失"——`normalizePage`、`render-html.snap()`、导入侧三处都踩过(表现为"功能做了、跑起来全 0")。纪律见 docs/09 §9,守卫是 smoke §58 的"三处白名单透传"断言与基线脚本的"结构关系被真的用到"断言。
82
+
83
+
84
+
85
+ ### 2026-09-27 —— 开发流程:**测试分档**(改动即跑快测 / 发版跑全量并行档)
86
+
87
+ **触发(用户原话)**:"我发现你经常动不动就去跑全量测试,而现在测试条目多,每次都要花很长时间,导致效率低下……每次改动时,只测试那些会因改动受到影响的部分,以缩短测试用时;等发版前后再去跑全量测试。"
88
+
89
+ **实测成本(改造前,2026-09-27)**:smoke 全量 311.8s(303 条 / 47 节)· e2e 146.3s · 隔离矩阵 61.7s · 原生图表 48.3s · 损失审计 48.2s · LF 4.6s · 手册事实 0.6s · lib 0.1s ⇒ 全量约 **621.7s(10.4 分钟)**。当日因"只改文档"也跑全量的情况至少 3 次。
90
+
91
+ **改动**
92
+ - 新增 `scripts/test-map.mjs`:影响面映射(文件 → 标签 → 分节),自动从 smoke 源码扫分节并按标题打标签;`HEAVY_SECTIONS` 标注重节;`--explain` 可解释、`--audit` 做覆盖率审计。
93
+ - 新增 `scripts/test-fast.mjs`(`npm run test:fast`):**廉价跨切面守卫永远全跑**(build / LF / lib 新鲜度 / 预设门禁 / 手册事实审计)+按 `git diff`(或 CI 传入的改动清单 `TEST_FAST_FILES`)选影响面;**fail-safe**:无改动文件或出现未映射文件 ⇒ 自动升级为全量 smoke。
94
+ - 新增 `scripts/test-release.mjs`(`npm run test:release`):全量 + e2e + 隔离矩阵 + 原生图表 + 损失审计 + 安装自证 + 手册事实,**独立项并行**,各自写独立日志后汇总(失败时打印该日志末尾)。
95
+ - `package.json` 新增 4 条脚本;`.github/workflows/ci.yml` 分档:**PR → `test:fast`**(先取 PR 改动清单,取不到则 fail-safe 全量)、**main/手动 → `npm test` 全量**(合并门槛不降);checkout 加 `fetch-depth: 0`。
96
+ - 文档:README §10 开发命令、docs/05 新增「测试分档」章(含三条安全设计与"下一步增量")、docs/06 测试矩阵加一行。
97
+
98
+ **验证**:`npm run test:map:audit` → 47/47 分节可被选中(**这条审计当场抓出 6 个"永远选不中"的分节**:§12 §24 §45 §47 §48 §57,已补规则);`npm run test:fast --files=docs/03-更新日志.md` → **8.4s,5/5 通过,smoke 按预期跳过**;`npm run test:fast --files=src/tools.js` → **4.6s,5/5 通过**,并列出受影响的 24 个分节;未映射文件(`--files=some-unknown-file.xyz`)→ 正确判定 fail-safe。
99
+
100
+ **诚实边界**:快测目前对"改 src 模块"是**不跑 smoke**(靠影响面清单人工判断是否需要 `--full`),**不是**"只跑相关分节"——smoke 内部分节闸门留作下一步增量(原因:3000 行文件里节间存在 `const` 依赖,需按依赖闭包实现并单独验证)。
4
101
  > 版本规则:semver;功能新特性 minor,修复/文档 patch,破坏性 major(目前无)。
5
102
 
6
103
  ---
@@ -18,6 +115,8 @@
18
115
 
19
116
  **影响**:纯文案 + 证据脚本修正,**无行为变化**;1.1.4 的功能不受影响(图表本来就是原生可编辑,只是描述与提示词没跟上)。
20
117
 
118
+ **发布结果(1.1.5)**:构件 sha256 `70ce20bc…`;`npm run sync` 三向一致 + 终验 9/0;CI run [`36253079568`](https://github.com/zbsph/dsh-ppt-studio/actions/runs/36253079568) **success**(release 事件 → 等资产 → OIDC `npm publish` → 发后自证 integrity == 本地 tgz sha512;该步失败会让 job 红)。本机到 npm 的 TLS 仍不通(fake-IP 路由),故本地复核对 1.1.5 同样跳过。
119
+
21
120
  ## [1.1.4] 2026-09-26 —— 三个批次:按预设隔离(默认)+ office 接入与兜底增强 + pptd 原生可编辑图表
22
121
 
23
122
  > 本批按「发布列车」攒着:`package.json` 版本号与 tag 在发版那一步才推进(见 docs/05「发版节奏」)。
@@ -3161,3 +3260,63 @@ smoke 14 → 21(媒体回环、声明制 6 断言、美学、背景回环)
3161
3260
  ## 历史探索(归档,未形成发布版)
3162
3261
  - 2026-08 前后:调研 pipitmk/ultimate-ppt-master-skill/claude-office-skills/open-kimi-ppt-skill(已下架)→ 结论:PPTD 自定义实现(不依赖逆向产物);pipitmk 借鉴"校验先行/文本溢出启发式/矢量拼绘"思路。
3163
3262
  - DESIGN.md(537 行)→ docs/00-设计源.md 归档;后续决策以 01 需求文件为活跃约束。
3263
+
3264
+ ### 复杂图通路定稿与发版准备
3265
+
3266
+ **目的**:把「手写显式 elements」确立为复杂图的唯一通路,并为发版补齐守卫与文档。
3267
+
3268
+ **改动**:
3269
+ - 复杂图统一走**手写 elements + 机制**(`attach` 锚真实边缘、折线自动正交化、箭头前直段 ≥18px、结构关系反验证);引擎不引入编译器。
3270
+ - 新增门禁 `line-cross-text`(线 × 文字碰撞)。
3271
+ - 并入 `npm test` 的守卫:`verify:handdrawn`(13 页回归基线:layout 摘要 + 错警计数 + PNG sha)、`verify:redprobe`(6 条)、`verify:linetext`(3 条)、`verify:optionprobe`(2 条)、`check-generators`(生成器语法)、`check-lib-sync`(lib ⟷ src 逐字节)、`check-unknown-keys`(未知键 warning)。
3272
+ - 本机专用命令:`verify:products`(重出 → 导出 → 渲染 → 与基线比对)、`verify:package`(打包与安装一致性)。
3273
+ - 回归基线引入 `history` + `--reason`(改基线必须留痕,且由断言强制)。
3274
+
3275
+ **验证**:`npm test` 322/0;13 页手画 0 错;红样本 6/6;`verify:package` 通过(装出来能 `require`、包内无已移除方案的痕迹)。
3276
+
3277
+ **已知限制**:
3278
+ 1. 无逐形状样式(阴影/高光/笔触);开发期的强样式控制选项未纳入本版;
3279
+ 2. 手写几何由作者给出 ⇒ 单页成本更高、批量大 deck 更慢;
3280
+ 3. 生成器检查为**语法级**(运行期类错误仍可能漏网);
3281
+ 4. 13 页手画回归语料**不随包发布** ⇒ 该回归只在仓库内可跑;包内只发 `lib`;
3282
+ 5. `files` 中过期的 `vendor` 项已清理(仓库无此目录)。
3283
+
3284
+ ### 适配 DSH 0.2.0-rc.2(桌面端为准)
3285
+
3286
+ **目的**:把插件适配到 DSH 0.2.0-rc.2,并固化后续适配规则。
3287
+
3288
+ **环境事实(实测)**
3289
+ - 运行中的 runtime 与全局 npm:`dsh = 0.2.0-rc.2`(嵌套约 300 个 DSH 包同版;`cordis 4.0.4`);本会话 profile = **desktop**;Web UI 即桌面端内置的 web 服务(跑 desktop profile)⇒ **当前只有一套 runtime、一个 profile**。
3290
+ - 插件在桌面 profile 的**实时装配树**中:条目 `include:ppt-studio`(`patchId: ppt-studio` ✓),`packageDir` 指向 `~/.dsh/profiles/desktop/node_modules/dsh-ppt-studio`,版本 **1.1.5**。
3291
+
3292
+ **兼容性复核(实测)**
3293
+ - 预设 patch 对 `dsh-web-app@0.2.0-rc.2` 的 `presets/standard.patch.yml`:**漂移 0 / 缺行 0 / 有意差异 1**(插件 persona)。
3294
+ - `dsh-tools`:`register(definition: ToolDefinition): () => void`;`defineTool(options)` 仍在。
3295
+ - `dsh-commands`:`register(definition: CommandDefinition): () => void`。
3296
+ - `dsh-system-prompt`:`SystemPrompt extends Service`、`section(section: PromptSection): () => void`。
3297
+ - 插件实际调用:`ctx.tools.register(defineTool({ name: 'ppt_state', … }))`、`ctx.commands.register({…})`、`ctx.inject(['agentPresets'], …)`;导出面 `apply / inject / name / statusToolFor`,`inject = ['tools','commands','systemPrompt']`。
3298
+ - 装配语义:`dsh-plugin-manager@0.2.0-rc.2` 仍以 `bundlePatchPaths` / `readProfileManifest` / `composeEntries` 等处理 `dsh.bundle.patch` 与 `dsh.profile.bundles`。
3299
+ - 全链复跑:`npm test` **322/0**、`verify:package` 通过(装出来能 `require`、包内无痕迹)、`verify:products` 通过(13 张 PNG 一致)、预设漂移 **0**。
3300
+
3301
+ **长期适配规则(用户指定)**
3302
+ 1. 适配**以桌面端为准**;桌面端更新不与 web 同步。
3303
+ 2. 若两端版本不一致(web 只落后):**先把落后端升到与桌面端相同版本,再统一适配**;绝不在版本不同的状态下适配。
3304
+ 3. 任何升级前先核对目标版本:`npm view @deepseek-ai/dsh@next version` 必须 **≤** 已装版本,否则**停手询问**(防某一端超前);升级用 `npm install -g @deepseek-ai/dsh@next`;版本看 `dsh --version`;运行 `dsh web`。
3305
+ 4. **版本号 / 发布标签 / 发包到 registry / 对外发布说明仍锁定**,只等用户指令;本次适配只形成本"待发"条目。
3306
+
3307
+ **两条新增事实(很重要)**
3308
+ - **桌面端 profile 由 Electron 应用独占管理**:`dsh plugin --profile desktop …` 会被拒绝(`managed exclusively by the Electron application`)⇒ 桌面端插件的增删**只能走应用的「插件管理」界面**。
3309
+ - **保持 `web` / `headless` profile 干净**:二者当前无消费者,插件已从二者移除(避免未来同时维护三份依赖);需要时用 `dsh plugin --profile web add dsh-ppt-studio` **一条命令**补装。
3310
+
3311
+ **教训(本轮实测)**
3312
+ - 新增守卫时必须**同步其它守卫的"自身豁免清单"**:`verify:package` 的扫描原先只豁免它自己,导致新增的可见文本痕迹守卫被它**自己的词表**判为命中(`exit=1`)⇒ 已把两个词表文件一并豁免并注明原因。
3313
+
3314
+ **遗留(如实)**
3315
+ - 运行时 **fiber 状态**尚未正面确认:装配树、`packageDir`、patch 行均已证;`Config` 查询显示该条目 `status: absent`(解读为"无 Config schema",非"未激活"),仍需一次 `Tool.listTools` 或插件管理界面核对。
3316
+
3317
+ **A 收口(运行时激活,正面证据)**
3318
+
3319
+ `plugin_manager` 实时条目:`{ entryId: "include:ppt-studio", moduleName: "dsh-ppt-studio", enabled: true, fiberPhase: "active", patchId: "ppt-studio" }`
3320
+ ⇒ 在 DSH 0.2.0-rc.2 的桌面 profile 下,插件 **已启用且 fiber 处于 active**。附带说明:`Config` 查询中该条目的 `status: absent` 表示**该条目没有 Config schema**(插件未声明 Config),与激活状态无关。
3321
+
3322
+ **适配结论(A–F)**:A 运行时激活 ✓(上条证据)|B 服务 API 形状 ✓|C 装配语义 ✓|D 全链复跑 ✓|E 文档 ✓|F 本条目 ✓ —— **本轮适配完成,仍停在发版之前**(版本号 / 发布标签 / 发包 / 对外说明均未执行,等指令)。
@@ -137,6 +137,29 @@
137
137
  - **能力边界**:仅支持云托管 runner(self-hosted 不支持);`npm whoami` 不反映 OIDC 状态;OIDC 只能跑 `npm publish` / `npm stage publish`,其它 stage 子命令与 `install`/`view`/`access` 仍需传统认证;npm CLI ≥ 11.5.1(OIDC)/ ≥ 11.15.0(stage 命令)、Node ≥ 22.14.0 ⇒ 工作流用 node 24 并带版本门禁。
138
138
  - **两条已实测的运行期坑**(2026-09-26 两次预检跑,run `36189160940` / `36190325252`):① 工作流**不 checkout** 时 `gh` 会报 `fatal: not a git repository` ⇒ 必须给 job 级 `GH_REPO: ${{ github.repository }}`;② `actions/setup-node` 一旦传 `registry-url`,运行期会注入 `NPM_CONFIG_USERCONFIG` 与一个占位 `NODE_AUTH_TOKEN`(env 里可见)——**正是会顶掉 OIDC 的东西** ⇒ 不要传 `registry-url`,并在发布前 `unset NODE_AUTH_TOKEN` 兜底。两条都由 smoke §51 钉住。
139
139
 
140
+ ## 测试分档(2026-09-27,用户提出"轻量化测试"后定)
141
+
142
+ **问题(实测成本)**:smoke 全量 311.8s(303 条 / 47 节)· e2e 146.3s · 隔离矩阵 61.7s · 原生图表 48.3s · 损失审计 48.2s · LF 4.6s · 手册事实 0.6s · lib 0.1s ⇒ 全部约 621.7s(10.4 分钟)。改动后无脑全量 ⇒ 迭代慢。
143
+
144
+ **分档契约**(脚本:`scripts/test-map.mjs` 影响面 + `scripts/test-fast.mjs` 快测 + `scripts/test-release.mjs` 并行全档)
145
+
146
+ | 档 | 何时跑 | 内容 | 实测 |
147
+ |---|---|---|---|
148
+ | `npm run test:fast` | **每条改动** | ① 廉价跨切面守卫**永远全跑**:build / LF / lib 新鲜度 / 预设门禁 / 手册事实审计;② 按 `git diff` 选影响面并**打印**选中的分节;③ 重节(真渲染/真装包/真跑 python)默认不进 | 只改文档 ≈8s;改单模块 ≈5s |
149
+ | `npm test` | **批次边界 / 发版前** | 全量:build + LF + smoke 全量 + 预设门禁(CI 与本地都跑) | ≈5.5min |
150
+ | `npm run test:release` | **发版** | 全量 + e2e + 隔离矩阵 + 原生图表自证 + 损失审计 + 安装路径自证 + 手册事实,**独立项并行**(各自写独立日志,末尾汇总) | ≈5–6min(原串行 10.4min) |
151
+
152
+ **为什么"廉价守卫必须永远全跑"**:它们抓的正是"改 A 文件、断言在 B 文件"这类漂移——真实案例两次:改技能正文撞 ≤8000 字上限;改 `schema.js` 的 chart 字段撞"手册 vs 源码事实审计"。这类断言分布在 docs/技能/README 里,**不跑就等于把风险推到发版日**。它们加起来的代价约 6s,是快测的固定底座。
153
+
154
+ **三条安全设计(改动选择器时不得破坏)**
155
+ 1. **fail-safe**:改动文件没映射到任何规则 ⇒ 视为影响面未知 ⇒ 自动升级为全量(**不是**跑零条);CI 上取不到 PR 改动清单时同样升级全量。
156
+ 2. **可解释**:每次打印"因哪些文件选中了哪些分节",并醒目标注"非全量"。
157
+ 3. **可审计**:`npm run test:map:audit` 保证每个 smoke 分节至少被一条规则覆盖(防"孤儿分节永远不跑");新增分节后必须让审计仍然绿。
158
+
159
+ **个人纪律(Lead 自述,供审计)**:每条改动只跑 `test:fast`;**批次边界、发版前、以及动到基线/断言计数/LF/lib 这类跨切面文件时**才跑 `npm test` 全量;发版跑 `test:release`。汇报里写清"本轮跑的是快测还是全量"。
160
+
161
+ **下一步增量**:smoke 内部的**分节闸门**(把 §17/§22/§29/§40/§41/§43 这类重节做成 `--with-heavy` 可跳过),让"改 src 模块"的快测从"不跑 smoke"变成"只跑相关分节"(预计 40–60s)。难点是 3000 行 smoke 里节与节之间存在 `const` 依赖(跳过 §16 会让 §16b 的 `bandImp` 未定义),需按依赖闭包实现并单独验证。
162
+
140
163
  ## 发版节奏("发布列车",2026-09-26 用户提出后定)
141
164
 
142
165
  > 用户原话:"像现在这样过于频繁地发版是不是也会有些不好?我想能不能平时的小更新就在本地一步步来,然后等攒够一波之后再统一发版(GitHub + npm 包)?"
@@ -72,7 +72,8 @@
72
72
 
73
73
  | 场景 | 类型 | 结果 |
74
74
  |---|---|---|
75
- | smoke.mjs(303 断言:全链路 + 路由幂等 + autodeclare 回归 + splice/slice zip 级 + 度量/声明/防呆 + **连线方向/箭头/包围盒** + **内置技能包与"老用户不受影响"超集断言** + **手册 vs 源码事实一致性 13 条** + **讲稿备注/实体解码/图表配色** + **答疑手册触发纪律 3 条** + **lib/ 入库一致性** + **M2 真产物页号契约与注入自证 4 条** + **python-pptx 兜底生成物过真消费者 2 条** + **表格字号三层同源与 audit 下限 2 条** + **质量档降级可见 3 条** + **引擎不静默切换 3 条** + **出界分级两码可分 1 条** + **surgicalMap 消费自证 2 条** + **工具描述页数守卫 1 条** + **表格门禁 2 条** + **换行鲁棒(CRLF+BOM)3 条** + **用户模板库两层目录与入库/物化/删除 5 条** + **DSH 0.1.7:预设声明 / 门禁新参照格式 / 安装器路径** + **桌面端安装器(桩工具链 dry-run,不碰真桌面端)**) | 自动化 | 303/303 |
75
+ | smoke.mjs(322 断言:全链路 + 路由幂等 + autodeclare 回归 + splice/slice zip 级 + 度量/声明/防呆 + **连线方向/箭头/包围盒** + **内置技能包与"老用户不受影响"超集断言** + **手册 vs 源码事实一致性 13 条** + **讲稿备注/实体解码/图表配色** + **答疑手册触发纪律 3 条** + **lib/ 入库一致性** + **M2 真产物页号契约与注入自证 4 条** + **python-pptx 兜底生成物过真消费者 2 条** + **表格字号三层同源与 audit 下限 2 条** + **质量档降级可见 3 条** + **引擎不静默切换 3 条** + **出界分级两码可分 1 条** + **surgicalMap 消费自证 2 条** + **工具描述页数守卫 1 条** + **表格门禁 2 条** + **换行鲁棒(CRLF+BOM)3 条** + **用户模板库两层目录与入库/物化/删除 5 条** + **DSH 0.1.7:预设声明 / 门禁新参照格式 / 安装器路径** + **桌面端安装器(桩工具链 dry-run,不碰真桌面端)** + **阶段 A:结构声明 schema / 三处白名单透传 / 结构豁免与门控 / attach 解析与改写可见 / 折线 custGeom / 双箭头 / 虚线 / 图进 parity / 能力可发现(SCHEMA_REF 词汇)14 条** + **阶段 B:IR 语法可发现 / 物化展开 + 逻辑组与 contains / 引擎产出零冲突零声明 / 无 diagram 页一个字不多 5 条**) | 自动化 | 322/322 |
76
+ | **测试分档**(2026-09-27,用户提出"轻量化测试"):`test:fast` 改动即跑(实测只改文档 ≈8s、改 src 模块 ≈5s)|`npm test` 全量(≈5.5min)|`test:release` 并行全档(≈5min)|映射覆盖率审计 47/47 分节可被选中 | 自动化 | 三档齐备(详见 docs/05「测试分档」) |
76
77
  | **讲稿(备注)真消费者验证**(2026-09-14):① **真 PowerPoint COM** 打开带备注的导出件并逐页读回讲稿文本(多行 18 字 / 无备注页 NONE / 单行含 `<特殊> &` 15 字);② **python-pptx 1.0.2** 独立读回同样三页文本 + 重新打包成功(smoke 里以可选断言固化,缺 python 时跳过) | 真机/第三方 | ✓ 两路一致 |
77
78
  | **python-pptx 兜底引擎真消费者验证**(2026-09-18 新增,smoke §43):生成一段覆盖「shape 无填充 / 对象填充 `{color,alpha}` / 带描边 + line 连接线 + table + text」的 deck → `genPythonScript` → ① `python -m py_compile` 必须过;② `runPythonExport` 必须真跑出 .pptx,且 **python-pptx 自己打开它并读回**(1 页 ≥ 6 形状)。**为什么必须补**:这条路径此前在 `scripts/` 里**零调用**,而它是"pptd 硬失败时"的最后保险;python 是可选依赖,"跳过"与"通过"印同一个颜色,于是它连编译都过不去也没人知道 | 真机/第三方 | 2 条全绿 |
78
79
  | 文档计数自证(smoke 内):README/docs02/docs06/手册里所有"smoke N 断言 / N/N"必须等于真实断言数 | 自动化 | 303 全中 |