@qijenchen/design-system 0.1.0-beta.83 → 0.1.0-beta.85

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 (622) hide show
  1. package/CLAUDE.md +8 -8
  2. package/README.md +3 -2
  3. package/dist/components/Alert/alert.js.map +1 -1
  4. package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
  5. package/dist/components/AppShell/app-shell.d.ts +1 -1
  6. package/dist/components/AppShell/app-shell.d.ts.map +1 -1
  7. package/dist/components/AppShell/app-shell.js +22 -2
  8. package/dist/components/AppShell/app-shell.js.map +1 -1
  9. package/dist/components/Avatar/avatar.d.ts.map +1 -1
  10. package/dist/components/Avatar/avatar.js +4 -4
  11. package/dist/components/Avatar/avatar.js.map +1 -1
  12. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
  13. package/dist/components/Breadcrumb/breadcrumb.js +1 -1
  14. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  15. package/dist/components/Button/button.d.ts +2 -2
  16. package/dist/components/Button/button.d.ts.map +1 -1
  17. package/dist/components/Button/button.js +12 -3
  18. package/dist/components/Button/button.js.map +1 -1
  19. package/dist/components/Calendar/calendar.d.ts +13 -5
  20. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  21. package/dist/components/Calendar/calendar.js +7 -1
  22. package/dist/components/Calendar/calendar.js.map +1 -1
  23. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  24. package/dist/components/Carousel/carousel.js +8 -3
  25. package/dist/components/Carousel/carousel.js.map +1 -1
  26. package/dist/components/Chart/chart.d.ts.map +1 -1
  27. package/dist/components/Chart/chart.js +1 -0
  28. package/dist/components/Chart/chart.js.map +1 -1
  29. package/dist/components/Checkbox/checkbox.d.ts +1 -1
  30. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  31. package/dist/components/Checkbox/checkbox.js +8 -4
  32. package/dist/components/Checkbox/checkbox.js.map +1 -1
  33. package/dist/components/Chip/chip.d.ts +1 -1
  34. package/dist/components/Chip/chip.d.ts.map +1 -1
  35. package/dist/components/Chip/chip.js.map +1 -1
  36. package/dist/components/Coachmark/coachmark.d.ts +10 -3
  37. package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
  38. package/dist/components/Coachmark/coachmark.js.map +1 -1
  39. package/dist/components/Combobox/combobox.d.ts +5 -1
  40. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  41. package/dist/components/Combobox/combobox.js +30 -13
  42. package/dist/components/Combobox/combobox.js.map +1 -1
  43. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  44. package/dist/components/DataTable/cell-registry.js +53 -62
  45. package/dist/components/DataTable/cell-registry.js.map +1 -1
  46. package/dist/components/DataTable/column-types.d.ts +10 -4
  47. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  48. package/dist/components/DataTable/column-types.js.map +1 -1
  49. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +1 -1
  50. package/dist/components/DataTable/data-table-column-visibility-panel.js +183 -0
  51. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
  52. package/dist/components/DataTable/data-table-filter-group.d.ts +47 -0
  53. package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
  54. package/dist/components/DataTable/data-table-filter-group.js +154 -0
  55. package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
  56. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  57. package/dist/components/DataTable/data-table-filter-panel.js +285 -0
  58. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
  59. package/dist/components/DataTable/data-table-filter-value-picker.d.ts +29 -0
  60. package/dist/components/DataTable/data-table-filter-value-picker.d.ts.map +1 -0
  61. package/dist/components/DataTable/data-table-filter-value-picker.js +187 -0
  62. package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
  63. package/dist/components/DataTable/data-table-interaction-layer.d.ts +11 -15
  64. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
  65. package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
  66. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  67. package/dist/components/DataTable/data-table-sort-manager.js +140 -0
  68. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
  69. package/dist/components/DataTable/data-table.d.ts +5 -6
  70. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  71. package/dist/components/DataTable/data-table.js +36 -15
  72. package/dist/components/DataTable/data-table.js.map +1 -1
  73. package/dist/components/DataTable/filter-operators.js +140 -0
  74. package/dist/components/DataTable/filter-operators.js.map +1 -0
  75. package/dist/components/DataTable/filter-tree.js +312 -0
  76. package/dist/components/DataTable/filter-tree.js.map +1 -0
  77. package/dist/components/DataTable/index.d.ts +3 -0
  78. package/dist/components/DataTable/index.d.ts.map +1 -1
  79. package/dist/components/DataTable/index.js +12 -1
  80. package/dist/components/DataTable/index.js.map +1 -1
  81. package/dist/components/DataTable/lib/column-meta.js +25 -0
  82. package/dist/components/DataTable/lib/column-meta.js.map +1 -0
  83. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  84. package/dist/components/DateGrid/date-grid.js +3 -1
  85. package/dist/components/DateGrid/date-grid.js.map +1 -1
  86. package/dist/components/DatePicker/date-picker.d.ts +7 -1
  87. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  88. package/dist/components/DatePicker/date-picker.js +105 -74
  89. package/dist/components/DatePicker/date-picker.js.map +1 -1
  90. package/dist/components/Dialog/dialog.d.ts +20 -3
  91. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  92. package/dist/components/Dialog/dialog.js +38 -20
  93. package/dist/components/Dialog/dialog.js.map +1 -1
  94. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  95. package/dist/components/DropdownMenu/dropdown-menu.js +3 -1
  96. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  97. package/dist/components/Field/field-context.d.ts +45 -5
  98. package/dist/components/Field/field-context.d.ts.map +1 -1
  99. package/dist/components/Field/field-context.js +19 -0
  100. package/dist/components/Field/field-context.js.map +1 -1
  101. package/dist/components/Field/field-edit-keys.d.ts +21 -0
  102. package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
  103. package/dist/components/Field/field-edit-keys.js +19 -0
  104. package/dist/components/Field/field-edit-keys.js.map +1 -0
  105. package/dist/components/Field/field-types.d.ts +20 -1
  106. package/dist/components/Field/field-types.d.ts.map +1 -1
  107. package/dist/components/Field/field-types.js.map +1 -1
  108. package/dist/components/Field/field-wrapper.d.ts +3 -2
  109. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  110. package/dist/components/Field/field-wrapper.js +38 -39
  111. package/dist/components/Field/field-wrapper.js.map +1 -1
  112. package/dist/components/Field/field.d.ts +2 -1
  113. package/dist/components/Field/field.d.ts.map +1 -1
  114. package/dist/components/Field/field.js.map +1 -1
  115. package/dist/components/Field/index.d.ts +1 -0
  116. package/dist/components/Field/index.d.ts.map +1 -1
  117. package/dist/components/Field/index.js +2 -0
  118. package/dist/components/Field/index.js.map +1 -1
  119. package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
  120. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
  121. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  122. package/dist/components/FileItem/file-item.js +1 -1
  123. package/dist/components/FileItem/file-item.js.map +1 -1
  124. package/dist/components/FileUpload/file-upload.d.ts +1 -1
  125. package/dist/components/FileUpload/file-upload.js.map +1 -1
  126. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  127. package/dist/components/FileViewer/file-viewer.js +7 -2
  128. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  129. package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
  130. package/dist/components/FileViewer/image-renderer.js +22 -1
  131. package/dist/components/FileViewer/image-renderer.js.map +1 -1
  132. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  133. package/dist/components/HoverCard/hover-card.js +5 -3
  134. package/dist/components/HoverCard/hover-card.js.map +1 -1
  135. package/dist/components/InlineEdit/index.d.ts +2 -0
  136. package/dist/components/InlineEdit/index.d.ts.map +1 -0
  137. package/dist/components/InlineEdit/index.js +5 -0
  138. package/dist/components/InlineEdit/index.js.map +1 -0
  139. package/dist/components/InlineEdit/inline-edit.d.ts +59 -0
  140. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
  141. package/dist/components/InlineEdit/inline-edit.js +164 -0
  142. package/dist/components/InlineEdit/inline-edit.js.map +1 -0
  143. package/dist/components/Input/input.d.ts +6 -11
  144. package/dist/components/Input/input.d.ts.map +1 -1
  145. package/dist/components/Input/input.js +43 -13
  146. package/dist/components/Input/input.js.map +1 -1
  147. package/dist/components/LinkInput/link-input.d.ts +2 -2
  148. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  149. package/dist/components/LinkInput/link-input.js +6 -5
  150. package/dist/components/LinkInput/link-input.js.map +1 -1
  151. package/dist/components/Menu/menu-item.d.ts +14 -2
  152. package/dist/components/Menu/menu-item.d.ts.map +1 -1
  153. package/dist/components/Menu/menu-item.js +25 -3
  154. package/dist/components/Menu/menu-item.js.map +1 -1
  155. package/dist/components/NumberInput/number-input.d.ts +3 -3
  156. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  157. package/dist/components/NumberInput/number-input.js +6 -5
  158. package/dist/components/NumberInput/number-input.js.map +1 -1
  159. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  160. package/dist/components/OverflowIndicator/overflow-indicator.js +2 -6
  161. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  162. package/dist/components/Pagination/pagination.js +1 -1
  163. package/dist/components/Pagination/pagination.js.map +1 -1
  164. package/dist/components/PeoplePicker/index.js +7 -1
  165. package/dist/components/PeoplePicker/index.js.map +1 -1
  166. package/dist/components/PeoplePicker/people-picker.d.ts +9 -2
  167. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  168. package/dist/components/PeoplePicker/people-picker.js +23 -10
  169. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  170. package/dist/components/PeoplePicker/person-display.d.ts +6 -3
  171. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
  172. package/dist/components/PeoplePicker/person-display.js +19 -14
  173. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  174. package/dist/components/Popover/popover.d.ts.map +1 -1
  175. package/dist/components/Popover/popover.js +3 -1
  176. package/dist/components/Popover/popover.js.map +1 -1
  177. package/dist/components/ProfileCard/profile-card.d.ts +2 -2
  178. package/dist/components/ProfileCard/profile-card.js +3 -3
  179. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  180. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  181. package/dist/components/RadioGroup/radio-group.js +15 -9
  182. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  183. package/dist/components/ScrollArea/scroll-area.d.ts +11 -1
  184. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  185. package/dist/components/ScrollArea/scroll-area.js +6 -3
  186. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  187. package/dist/components/Select/select.d.ts +46 -5
  188. package/dist/components/Select/select.d.ts.map +1 -1
  189. package/dist/components/Select/select.js +109 -28
  190. package/dist/components/Select/select.js.map +1 -1
  191. package/dist/components/SelectMenu/select-menu.d.ts +3 -1
  192. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  193. package/dist/components/SelectMenu/select-menu.js +8 -1
  194. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  195. package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
  196. package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
  197. package/dist/components/SelectionControl/boolean-value.js +23 -0
  198. package/dist/components/SelectionControl/boolean-value.js.map +1 -0
  199. package/dist/components/SelectionControl/index.d.ts +1 -0
  200. package/dist/components/SelectionControl/index.d.ts.map +1 -1
  201. package/dist/components/SelectionControl/index.js +2 -0
  202. package/dist/components/SelectionControl/index.js.map +1 -1
  203. package/dist/components/Sheet/index.js +2 -1
  204. package/dist/components/Sheet/sheet.d.ts +7 -1
  205. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  206. package/dist/components/Sheet/sheet.js +5 -2
  207. package/dist/components/Sheet/sheet.js.map +1 -1
  208. package/dist/components/Sidebar/sidebar.d.ts +9 -4
  209. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  210. package/dist/components/Sidebar/sidebar.js +8 -10
  211. package/dist/components/Sidebar/sidebar.js.map +1 -1
  212. package/dist/components/Slider/slider.d.ts.map +1 -1
  213. package/dist/components/Slider/slider.js.map +1 -1
  214. package/dist/components/Switch/switch.d.ts +6 -6
  215. package/dist/components/Switch/switch.d.ts.map +1 -1
  216. package/dist/components/Switch/switch.js +3 -2
  217. package/dist/components/Switch/switch.js.map +1 -1
  218. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  219. package/dist/components/Tabs/tabs.js +15 -1
  220. package/dist/components/Tabs/tabs.js.map +1 -1
  221. package/dist/components/Textarea/textarea.d.ts +2 -2
  222. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  223. package/dist/components/Textarea/textarea.js +50 -42
  224. package/dist/components/Textarea/textarea.js.map +1 -1
  225. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  226. package/dist/components/TimePicker/time-columns.js +42 -38
  227. package/dist/components/TimePicker/time-columns.js.map +1 -1
  228. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  229. package/dist/components/TimePicker/time-picker.js +8 -6
  230. package/dist/components/TimePicker/time-picker.js.map +1 -1
  231. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  232. package/dist/components/Tooltip/tooltip.js +7 -5
  233. package/dist/components/Tooltip/tooltip.js.map +1 -1
  234. package/dist/components/TreeView/tree-view.d.ts +56 -1
  235. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  236. package/dist/components/TreeView/tree-view.js +211 -12
  237. package/dist/components/TreeView/tree-view.js.map +1 -1
  238. package/dist/index.d.ts +115 -58
  239. package/dist/index.d.ts.map +1 -1
  240. package/dist/index.js +95 -108
  241. package/dist/index.js.map +1 -1
  242. package/dist/patterns/element-anatomy/item-anatomy.d.ts +7 -6
  243. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  244. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  245. package/dist/tokens/categorical-color.js +15 -0
  246. package/dist/tokens/categorical-color.js.map +1 -1
  247. package/dist/tokens/motion/motion.d.ts +7 -6
  248. package/dist/tokens/motion/motion.d.ts.map +1 -1
  249. package/dist/tokens/motion/motion.js +6 -6
  250. package/dist/tokens/motion/motion.js.map +1 -1
  251. package/dist/tokens/motion/overlay-motion.d.ts +19 -0
  252. package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
  253. package/dist/tokens/motion/overlay-motion.js +9 -0
  254. package/dist/tokens/motion/overlay-motion.js.map +1 -0
  255. package/dist/tokens/uiSize/icon-size.js +5 -0
  256. package/dist/tokens/uiSize/icon-size.js.map +1 -0
  257. package/ds-canonical/fork/governance.lock +31 -19
  258. package/ds-canonical/fork/hooks/_log-fire.sh +46 -0
  259. package/ds-canonical/fork/hooks/block_prototype_imports.py +15 -4
  260. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +145 -13
  261. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -1
  262. package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +47 -0
  263. package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +27 -0
  264. package/ds-canonical/fork/hooks/check_field_family_invariants.sh +61 -1
  265. package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +28 -4
  266. package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +28 -0
  267. package/ds-canonical/fork/hooks/check_story_determinism.sh +2 -0
  268. package/ds-canonical/fork/hooks/check_story_invariants.sh +119 -0
  269. package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  270. package/ds-canonical/fork/manifest.json +15 -0
  271. package/ds-canonical/fork/preamble.md +20 -18
  272. package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +3 -3
  273. package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
  274. package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +1 -1
  275. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +3 -3
  276. package/ds-canonical/fork/skills/propose-options/SKILL.md +3 -3
  277. package/ds-canonical/fork/skills/prototype/SKILL.md +1 -1
  278. package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -2
  279. package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -2
  280. package/ds-canonical/hooks/README.md +1 -1
  281. package/ds-canonical/hooks/block_prototype_imports.py +15 -4
  282. package/ds-canonical/hooks/check_audit_post_report_validator.sh +65 -7
  283. package/ds-canonical/hooks/check_codex_brief_invariants.sh +28 -1
  284. package/ds-canonical/hooks/check_consumer_app_invariants.sh +145 -13
  285. package/ds-canonical/hooks/check_datatable_invariants.sh +6 -3
  286. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -1
  287. package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +47 -0
  288. package/ds-canonical/hooks/check_escape_marker_abuse.sh +27 -0
  289. package/ds-canonical/hooks/check_field_family_invariants.sh +61 -1
  290. package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +28 -4
  291. package/ds-canonical/hooks/check_naming_and_abstraction.sh +1 -1
  292. package/ds-canonical/hooks/check_opacity_token_usage.sh +28 -0
  293. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +3 -2
  294. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +6 -1
  295. package/ds-canonical/hooks/check_ssot_header_declaration.sh +3 -1
  296. package/ds-canonical/hooks/check_story_determinism.sh +2 -0
  297. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +8 -7
  298. package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  299. package/ds-canonical/hooks/lib/_story_compile_drift.sh +1 -1
  300. package/ds-canonical/hooks/lib/_token_hygiene.sh +10 -1
  301. package/ds-canonical/hooks/stop_self_audit.sh +31 -0
  302. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +24 -0
  303. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +44 -0
  304. package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +43 -2
  305. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +112 -0
  306. package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +9 -2
  307. package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
  308. package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +24 -0
  309. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +27 -2
  310. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +39 -0
  311. package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
  312. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +1 -1
  313. package/ds-canonical/references/build-ui-canonicals.md +2 -1
  314. package/ds-canonical/references/failure-class-registry.json +145 -0
  315. package/ds-canonical/references/governance-audit-coverage.md +33 -0
  316. package/ds-canonical/references/item-anatomy-recipe.md +2 -2
  317. package/ds-canonical/references/scenario-definition.md +6 -9
  318. package/ds-canonical/references/ssot-consultation.md +2 -2
  319. package/ds-canonical/references/ssot-index.md +5 -4
  320. package/ds-canonical/references/story-baseline-registry.json +8 -2
  321. package/ds-canonical/references/structural-token-retention.md +6 -9
  322. package/ds-canonical/rules/meta-patterns.md +8 -8
  323. package/ds-canonical/rules/self-verify.md +4 -3
  324. package/ds-canonical/rules/story-rules.md +2 -2
  325. package/ds-canonical/rules/ui-development.md +2 -2
  326. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +3 -3
  327. package/ds-canonical/skills/code-quality-audit/SKILL.md +3 -3
  328. package/ds-canonical/skills/codex-collab/SKILL.md +9 -7
  329. package/ds-canonical/skills/codex-collab/references/brief-template.md +1 -1
  330. package/ds-canonical/skills/codify-principle/SKILL.md +2 -2
  331. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  332. package/ds-canonical/skills/component-quality-gate/references/checklist.md +2 -2
  333. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +51 -58
  334. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +29 -0
  335. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +29 -10
  336. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +21 -0
  337. package/ds-canonical/skills/delivery-handoff/SKILL.md +1 -1
  338. package/ds-canonical/skills/design-system-audit/SKILL.md +26 -25
  339. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +13 -1
  340. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +1 -1
  341. package/ds-canonical/skills/governance-health/SKILL.md +1 -1
  342. package/ds-canonical/skills/knowledge-prune/SKILL.md +3 -0
  343. package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +1 -0
  344. package/ds-canonical/skills/new-component/SKILL.md +5 -5
  345. package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
  346. package/ds-canonical/skills/product-ui-audit/SKILL.md +3 -3
  347. package/ds-canonical/skills/propose-options/SKILL.md +3 -3
  348. package/ds-canonical/skills/prototype/SKILL.md +1 -1
  349. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +2 -2
  350. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +3 -3
  351. package/ds-canonical/skills/story-writing/SKILL.md +3 -3
  352. package/ds-canonical/skills/visual-audit/SKILL.md +2 -2
  353. package/ds-story-manifest.json +29 -20
  354. package/llms-full.txt +22 -1
  355. package/llms.txt +5 -4
  356. package/package.json +7 -3
  357. package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
  358. package/src/components/Accordion/accordion.stories.tsx +16 -1
  359. package/src/components/Alert/alert.principles.stories.tsx +1 -1
  360. package/src/components/Alert/alert.spec.md +8 -10
  361. package/src/components/Alert/alert.stories.tsx +28 -28
  362. package/src/components/Alert/alert.tsx +1 -1
  363. package/src/components/AppShell/_demo-helpers.tsx +6 -3
  364. package/src/components/AppShell/app-shell.spec.md +4 -4
  365. package/src/components/AppShell/app-shell.tsx +28 -2
  366. package/src/components/AspectRatio/aspect-ratio.spec.md +1 -1
  367. package/src/components/AspectRatio/aspect-ratio.stories.tsx +7 -89
  368. package/src/components/Avatar/avatar.anatomy.stories.tsx +7 -3
  369. package/src/components/Avatar/avatar.principles.stories.tsx +19 -15
  370. package/src/components/Avatar/avatar.spec.md +2 -2
  371. package/src/components/Avatar/avatar.stories.tsx +8 -6
  372. package/src/components/Avatar/avatar.tsx +13 -5
  373. package/src/components/Badge/badge.principles.stories.tsx +1 -1
  374. package/src/components/Badge/badge.spec.md +2 -0
  375. package/src/components/Badge/badge.stories.tsx +4 -2
  376. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +6 -4
  377. package/src/components/Breadcrumb/breadcrumb.stories.tsx +6 -5
  378. package/src/components/Breadcrumb/breadcrumb.tsx +3 -2
  379. package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
  380. package/src/components/Button/button.principles.stories.tsx +1 -1
  381. package/src/components/Button/button.spec.md +2 -2
  382. package/src/components/Button/button.tsx +18 -3
  383. package/src/components/Calendar/calendar.anatomy.stories.tsx +12 -10
  384. package/src/components/Calendar/calendar.principles.stories.tsx +14 -6
  385. package/src/components/Calendar/calendar.spec.md +5 -4
  386. package/src/components/Calendar/calendar.stories.tsx +7 -4
  387. package/src/components/Calendar/calendar.tsx +26 -7
  388. package/src/components/Carousel/carousel.anatomy.stories.tsx +5 -4
  389. package/src/components/Carousel/carousel.spec.md +2 -2
  390. package/src/components/Carousel/carousel.tsx +11 -3
  391. package/src/components/Chart/chart.anatomy.stories.tsx +7 -4
  392. package/src/components/Chart/chart.principles.stories.tsx +1 -1
  393. package/src/components/Chart/chart.stories.tsx +2 -8
  394. package/src/components/Chart/chart.tsx +3 -0
  395. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +28 -49
  396. package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
  397. package/src/components/Checkbox/checkbox.spec.md +13 -26
  398. package/src/components/Checkbox/checkbox.stories.tsx +11 -8
  399. package/src/components/Checkbox/checkbox.tsx +18 -13
  400. package/src/components/Chip/chip.anatomy.stories.tsx +44 -24
  401. package/src/components/Chip/chip.principles.stories.tsx +1 -1
  402. package/src/components/Chip/chip.spec.md +5 -4
  403. package/src/components/Chip/chip.tsx +5 -1
  404. package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -4
  405. package/src/components/CircularProgress/circular-progress.spec.md +3 -3
  406. package/src/components/CircularProgress/circular-progress.stories.tsx +2 -2
  407. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
  408. package/src/components/Coachmark/coachmark.principles.stories.tsx +2 -1
  409. package/src/components/Coachmark/coachmark.spec.md +5 -5
  410. package/src/components/Coachmark/coachmark.stories.tsx +3 -1
  411. package/src/components/Coachmark/coachmark.tsx +10 -3
  412. package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
  413. package/src/components/Combobox/combobox.tsx +53 -19
  414. package/src/components/Command/command.anatomy.stories.tsx +2 -2
  415. package/src/components/Command/command.principles.stories.tsx +1 -1
  416. package/src/components/Command/command.stories.tsx +42 -10
  417. package/src/components/DataTable/cell-registry.tsx +86 -63
  418. package/src/components/DataTable/column-types.ts +10 -1
  419. package/src/components/DataTable/data-table-column-visibility-panel.tsx +1 -1
  420. package/src/components/DataTable/data-table-filter-group.tsx +231 -0
  421. package/src/components/DataTable/data-table-filter-panel.tsx +16 -430
  422. package/src/components/DataTable/data-table-filter-value-picker.tsx +237 -0
  423. package/src/components/DataTable/data-table-interaction-layer.tsx +15 -19
  424. package/src/components/DataTable/data-table.anatomy.stories.tsx +15 -13
  425. package/src/components/DataTable/data-table.principles.stories.tsx +9 -9
  426. package/src/components/DataTable/data-table.spec.md +33 -13
  427. package/src/components/DataTable/data-table.stories.tsx +16 -17
  428. package/src/components/DataTable/data-table.tsx +107 -61
  429. package/src/components/DataTable/filter-operators.spec.md +3 -3
  430. package/src/components/DataTable/index.ts +3 -0
  431. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +4 -4
  432. package/src/components/DateGrid/date-grid.principles.stories.tsx +1 -1
  433. package/src/components/DateGrid/date-grid.spec.md +1 -1
  434. package/src/components/DateGrid/date-grid.tsx +3 -1
  435. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +8 -8
  436. package/src/components/DatePicker/date-picker.principles.stories.tsx +3 -3
  437. package/src/components/DatePicker/date-picker.spec.md +3 -3
  438. package/src/components/DatePicker/date-picker.stories.tsx +4 -5
  439. package/src/components/DatePicker/date-picker.tsx +99 -45
  440. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +12 -10
  441. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  442. package/src/components/DescriptionList/description-list.spec.md +3 -3
  443. package/src/components/DescriptionList/description-list.stories.tsx +7 -6
  444. package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -0
  445. package/src/components/Dialog/dialog.spec.md +9 -0
  446. package/src/components/Dialog/dialog.stories.tsx +66 -5
  447. package/src/components/Dialog/dialog.tsx +60 -25
  448. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
  449. package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +8 -6
  450. package/src/components/DropdownMenu/dropdown-menu.spec.md +5 -5
  451. package/src/components/DropdownMenu/dropdown-menu.tsx +18 -9
  452. package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
  453. package/src/components/Empty/empty.spec.md +2 -2
  454. package/src/components/Field/field-context.ts +69 -5
  455. package/src/components/Field/field-controls.spec.md +62 -8
  456. package/src/components/Field/field-edit-keys.ts +66 -0
  457. package/src/components/Field/field-types.ts +58 -9
  458. package/src/components/Field/field-wrapper.tsx +50 -42
  459. package/src/components/Field/field.anatomy.stories.tsx +9 -6
  460. package/src/components/Field/field.spec.md +1 -1
  461. package/src/components/Field/field.stories.tsx +1 -1
  462. package/src/components/Field/field.tsx +2 -1
  463. package/src/components/Field/form-validation.spec.md +3 -3
  464. package/src/components/Field/index.ts +1 -0
  465. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +6 -6
  466. package/src/components/FieldControlGroup/field-control-group.spec.md +9 -4
  467. package/src/components/FieldControlGroup/field-control-group.tsx +1 -1
  468. package/src/components/FileItem/file-item.anatomy.stories.tsx +1 -1
  469. package/src/components/FileItem/file-item.spec.md +5 -8
  470. package/src/components/FileItem/file-item.stories.tsx +36 -25
  471. package/src/components/FileItem/file-item.tsx +8 -6
  472. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +6 -6
  473. package/src/components/FileUpload/file-upload.principles.stories.tsx +5 -5
  474. package/src/components/FileUpload/file-upload.spec.md +1 -1
  475. package/src/components/FileUpload/file-upload.tsx +1 -1
  476. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +4 -3
  477. package/src/components/FileViewer/file-viewer.principles.stories.tsx +3 -3
  478. package/src/components/FileViewer/file-viewer.spec.md +30 -12
  479. package/src/components/FileViewer/file-viewer.stories.tsx +1 -2
  480. package/src/components/FileViewer/file-viewer.tsx +12 -4
  481. package/src/components/FileViewer/image-renderer.tsx +35 -7
  482. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -2
  483. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -3
  484. package/src/components/HoverCard/hover-card.spec.md +5 -5
  485. package/src/components/HoverCard/hover-card.stories.tsx +16 -16
  486. package/src/components/HoverCard/hover-card.tsx +5 -3
  487. package/src/components/InlineEdit/index.ts +5 -0
  488. package/src/components/InlineEdit/inline-edit.spec.md +149 -0
  489. package/src/components/InlineEdit/inline-edit.stories.tsx +246 -0
  490. package/src/components/InlineEdit/inline-edit.tsx +287 -0
  491. package/src/components/Input/input.anatomy.stories.tsx +8 -7
  492. package/src/components/Input/input.principles.stories.tsx +2 -12
  493. package/src/components/Input/input.spec.md +13 -18
  494. package/src/components/Input/input.tsx +69 -22
  495. package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
  496. package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
  497. package/src/components/LinkInput/link-input.tsx +11 -10
  498. package/src/components/Menu/menu-item.anatomy.stories.tsx +3 -3
  499. package/src/components/Menu/menu-item.principles.stories.tsx +1 -1
  500. package/src/components/Menu/menu-item.spec.md +22 -15
  501. package/src/components/Menu/menu-item.stories.tsx +39 -11
  502. package/src/components/Menu/menu-item.tsx +38 -4
  503. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  504. package/src/components/Notice/notice.spec.md +16 -3
  505. package/src/components/NumberInput/number-input.anatomy.stories.tsx +3 -3
  506. package/src/components/NumberInput/number-input.principles.stories.tsx +1 -1
  507. package/src/components/NumberInput/number-input.spec.md +4 -4
  508. package/src/components/NumberInput/number-input.tsx +19 -12
  509. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +10 -8
  510. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +3 -3
  511. package/src/components/OverflowIndicator/overflow-indicator.spec.md +4 -2
  512. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +71 -63
  513. package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -8
  514. package/src/components/Pagination/pagination.spec.md +1 -1
  515. package/src/components/Pagination/pagination.stories.tsx +2 -6
  516. package/src/components/Pagination/pagination.tsx +1 -1
  517. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +4 -4
  518. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +2 -2
  519. package/src/components/PeoplePicker/people-picker.spec.md +6 -6
  520. package/src/components/PeoplePicker/people-picker.tsx +56 -16
  521. package/src/components/PeoplePicker/person-display.tsx +32 -16
  522. package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
  523. package/src/components/Popover/popover.tsx +3 -1
  524. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +12 -23
  525. package/src/components/ProfileCard/profile-card.spec.md +3 -3
  526. package/src/components/ProfileCard/profile-card.tsx +6 -6
  527. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +3 -1
  528. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +1 -1
  529. package/src/components/ProgressBar/progress-bar.stories.tsx +50 -42
  530. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +10 -28
  531. package/src/components/RadioGroup/radio-group.stories.tsx +29 -32
  532. package/src/components/RadioGroup/radio-group.tsx +41 -15
  533. package/src/components/Rating/rating.spec.md +11 -3
  534. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
  535. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  536. package/src/components/ScrollArea/scroll-area.spec.md +7 -3
  537. package/src/components/ScrollArea/scroll-area.stories.tsx +1 -1
  538. package/src/components/ScrollArea/scroll-area.tsx +17 -4
  539. package/src/components/Select/select.anatomy.stories.tsx +3 -3
  540. package/src/components/Select/select.spec.md +29 -17
  541. package/src/components/Select/select.stories.tsx +33 -0
  542. package/src/components/Select/select.tsx +190 -36
  543. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +4 -4
  544. package/src/components/SelectMenu/select-menu.spec.md +15 -7
  545. package/src/components/SelectMenu/select-menu.tsx +16 -3
  546. package/src/components/SelectionControl/boolean-value.tsx +39 -0
  547. package/src/components/SelectionControl/index.ts +1 -0
  548. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +2 -2
  549. package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
  550. package/src/components/SelectionControl/selection-item.spec.md +3 -3
  551. package/src/components/SelectionControl/selection-item.stories.tsx +3 -3
  552. package/src/components/Separator/separator.spec.md +2 -2
  553. package/src/components/Separator/separator.stories.tsx +6 -27
  554. package/src/components/Sheet/sheet.anatomy.stories.tsx +1 -1
  555. package/src/components/Sheet/sheet.principles.stories.tsx +1 -1
  556. package/src/components/Sheet/sheet.spec.md +2 -2
  557. package/src/components/Sheet/sheet.tsx +9 -5
  558. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +16 -12
  559. package/src/components/Sidebar/sidebar.principles.stories.tsx +10 -8
  560. package/src/components/Sidebar/sidebar.spec.md +13 -15
  561. package/src/components/Sidebar/sidebar.stories.tsx +8 -7
  562. package/src/components/Sidebar/sidebar.tsx +37 -25
  563. package/src/components/Skeleton/skeleton.stories.tsx +4 -11
  564. package/src/components/Slider/slider.anatomy.stories.tsx +3 -3
  565. package/src/components/Slider/slider.principles.stories.tsx +2 -2
  566. package/src/components/Slider/slider.spec.md +5 -5
  567. package/src/components/Slider/slider.tsx +3 -1
  568. package/src/components/Steps/steps.anatomy.stories.tsx +4 -4
  569. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  570. package/src/components/Steps/steps.spec.md +1 -1
  571. package/src/components/Switch/switch.anatomy.stories.tsx +7 -7
  572. package/src/components/Switch/switch.principles.stories.tsx +4 -4
  573. package/src/components/Switch/switch.spec.md +8 -8
  574. package/src/components/Switch/switch.stories.tsx +9 -24
  575. package/src/components/Switch/switch.tsx +17 -13
  576. package/src/components/Tabs/tabs.anatomy.stories.tsx +10 -7
  577. package/src/components/Tabs/tabs.spec.md +1 -1
  578. package/src/components/Tabs/tabs.tsx +21 -1
  579. package/src/components/Textarea/textarea.anatomy.stories.tsx +1 -1
  580. package/src/components/Textarea/textarea.principles.stories.tsx +1 -1
  581. package/src/components/Textarea/textarea.spec.md +4 -4
  582. package/src/components/Textarea/textarea.tsx +72 -46
  583. package/src/components/TimePicker/time-columns.tsx +6 -2
  584. package/src/components/TimePicker/time-picker.principles.stories.tsx +1 -1
  585. package/src/components/TimePicker/time-picker.spec.md +3 -3
  586. package/src/components/TimePicker/time-picker.tsx +16 -10
  587. package/src/components/Toast/toast.stories.tsx +7 -4
  588. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +4 -4
  589. package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
  590. package/src/components/Tooltip/tooltip.spec.md +1 -1
  591. package/src/components/Tooltip/tooltip.stories.tsx +4 -39
  592. package/src/components/Tooltip/tooltip.tsx +8 -6
  593. package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -3
  594. package/src/components/TreeView/tree-view.spec.md +42 -11
  595. package/src/components/TreeView/tree-view.stories.tsx +1 -0
  596. package/src/components/TreeView/tree-view.tsx +322 -17
  597. package/src/index.ts +588 -60
  598. package/src/patterns/action-bar/action-bar.spec.md +9 -0
  599. package/src/patterns/action-bar/action-bar.stories.tsx +6 -3
  600. package/src/patterns/element-anatomy/inline-action.spec.md +2 -0
  601. package/src/patterns/element-anatomy/item-anatomy.spec.md +14 -5
  602. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -4
  603. package/src/patterns/element-anatomy/item-anatomy.tsx +7 -6
  604. package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
  605. package/src/patterns/overlay-surface/overlay-surface.spec.md +22 -1
  606. package/src/styles/tokens.css +3 -0
  607. package/src/tokens/README.md +1 -1
  608. package/src/tokens/color/color.spec.md +4 -4
  609. package/src/tokens/color/color.stories.tsx +3 -3
  610. package/src/tokens/density/density.stories.tsx +16 -3
  611. package/src/tokens/layoutSpace/layoutSpace.spec.md +3 -1
  612. package/src/tokens/motion/motion.css +33 -21
  613. package/src/tokens/motion/motion.spec.md +32 -15
  614. package/src/tokens/motion/motion.stories.tsx +58 -5
  615. package/src/tokens/motion/motion.ts +7 -6
  616. package/src/tokens/motion/overlay-motion.ts +26 -0
  617. package/src/tokens/orphan-tokens.spec.md +4 -4
  618. package/src/tokens/token-system.spec.md +1 -0
  619. package/src/tokens/uiSize/uiSize.css +1 -1
  620. package/src/tokens/uiSize/uiSize.spec.md +1 -1
  621. package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
  622. package/src/tokens/utility-registry.json +160 -23
@@ -20,6 +20,15 @@ except Exception:
20
20
  EXPLORATION_PREFIX = "src/explorations/"
21
21
  SRC_PREFIX = "src/"
22
22
 
23
+ # Project root for absolute→relative path normalization(real Edit/Write events
24
+ # carry absolute file_path;prefix 比對必先轉 project-root 相對,否則 hook 永不 fire)。
25
+ PROJECT_ROOT = os.environ.get('CLAUDE_PROJECT_DIR') or os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
26
+
27
+ def to_project_relative(path):
28
+ if os.path.isabs(path):
29
+ return os.path.relpath(path, PROJECT_ROOT)
30
+ return path
31
+
23
32
  def load_event():
24
33
  try:
25
34
  return json.load(sys.stdin)
@@ -83,19 +92,21 @@ def main():
83
92
  offenders = []
84
93
 
85
94
  for path in touched_paths:
86
- if not should_check(path):
95
+ rel_path = to_project_relative(path)
96
+ if not should_check(rel_path):
87
97
  continue
88
- if not os.path.exists(path):
98
+ abs_path = path if os.path.isabs(path) else os.path.join(PROJECT_ROOT, path)
99
+ if not os.path.exists(abs_path):
89
100
  continue
90
101
 
91
102
  try:
92
- with open(path, "r", encoding="utf-8") as f:
103
+ with open(abs_path, "r", encoding="utf-8") as f:
93
104
  content = f.read()
94
105
  except Exception:
95
106
  continue
96
107
 
97
108
  if contains_exploration_import(content):
98
- offenders.append(path)
109
+ offenders.append(rel_path)
99
110
 
100
111
  if offenders:
101
112
  lines = [
@@ -3,6 +3,7 @@
3
3
  # 2026-05-17 ship — codex Q4 verdict「post-audit stop hook / final report validator」最合理 trigger 位置。
4
4
  #
5
5
  # Triggers: 任何 Write/Edit 到 `.claude/logs/audit-report-*.json` OR `.claude/memory/project_audit_progress.md`
6
+ # OR `*/C1-final-report*.md`(2026-07-14 加:C.1 決策清單真實載體,原 scope 漏 = Validator H/K 永不 fire)
6
7
  #
7
8
  # 驗證:
8
9
  # (a) NO-SAMPLE invariant — report 不含「sample top N / subset / pick top X」keyword
@@ -25,6 +26,7 @@ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null)
25
26
  case "$FILE_PATH" in
26
27
  */audit-report-*.json) ;;
27
28
  */project_audit_progress.md) ;;
29
+ */C1-final-report*.md) ;;
28
30
  *) exit 0 ;;
29
31
  esac
30
32
 
@@ -80,7 +82,7 @@ fi
80
82
  BENCH_DEBT=$(grep -rc '@benchmark-unverified-blanket' "$PROJECT_DIR/packages/design-system/src/" 2>/dev/null | awk -F: '{s+=$2} END{print s+0}')
81
83
  BENCH_DEBT=${BENCH_DEBT:-0}
82
84
  if [ "$BENCH_DEBT" -gt 0 ]; then
83
- WARNINGS="${WARNINGS}\n ⚠️ [D] Benchmark cite debt:${BENCH_DEBT} 處 `@benchmark-unverified-blanket` marker — 對應 prune D9(M22 cite debt)"
85
+ WARNINGS="${WARNINGS}\n ⚠️ [D] Benchmark cite debt:${BENCH_DEBT} 處「@benchmark-unverified-blanketmarker — 對應 prune D9(M22 cite debt)"
84
86
  TRIGGER_PRUNE=1
85
87
  fi
86
88
 
@@ -119,13 +121,16 @@ if [ "$DIM_COUNT" -ge 10 ]; then # 只對 full/deep-audit 規模 report 要求
119
121
  WARNINGS="${WARNINGS}\n 🔴 [I] D3/D4/D5 domain-skill chain 證據缺席:report 未提及${_D345_MISSING}。稽核 canonical 6-維度表(CLAUDE.md)deep 規模必 chain 三 domain skill(或明寫豁免理由 + skill 名)。補跑/補記再出 report。"
120
122
  TRIGGER_PRUNE=1; CRITICAL_FAIL=1
121
123
  fi
122
- fi
123
124
 
124
- # ─ Validator BLOCK gate(2026-05-31 fix infra-audit self-finding:原 hook 只 exit 0 + additionalContext
125
- # soft-inject = 我過度宣稱「BLOCKER」。改:C/F/G critical failstderr + exit 2 block PostToolUse)─
126
- if [ "${CRITICAL_FAIL:-0}" -eq 1 ]; then
127
- printf '🚨 AUDIT-REPORT VALIDATOR BLOCK(C/F/G critical):%b\n\n此 deep-audit report 不合格,補齊上述後重出 report。' "$WARNINGS" >&2
128
- exit 2
125
+ # ─ Validator J: codex dim 覆蓋對帳(2026-07-10 user「codex 稽核一模一樣所有項目,有確保嗎?」)─
126
+ # report 顯示 Phase B / codex 比稿有跑必含「dim 覆蓋對帳」表(彙總 codex brief 蓋到的
127
+ # dim vs dispatch 清單逐號對;SKILL B.2 Step 0 契約的報告端機械閘 保證鏈第三段)。
128
+ if grep -qiE 'Phase B|codex 比稿|cite battle|dual-track' "$FILE_PATH" 2>/dev/null; then
129
+ if ! grep -qiE 'dim 覆蓋對帳|dim 對帳|coverage tally' "$FILE_PATH" 2>/dev/null; then
130
+ WARNINGS="${WARNINGS}\n 🔴 [J] Codex dim 覆蓋對帳缺席:report 提及 Phase B/比稿但無「dim 覆蓋對帳」表(codex 各 brief 蓋到的 dim 號 vs dispatch 清單逐號對,缺號 = 補 brief)。per SKILL B.2 Step 0(2026-07-10),不齊不得宣稱雙軌全覆蓋。"
131
+ TRIGGER_PRUNE=1; CRITICAL_FAIL=1
132
+ fi
133
+ fi
129
134
  fi
130
135
 
131
136
  # ─ Validator H: 拍板清單 SSOT-理由 強制(2026-06-11 user 第 3 次糾正「要我拍板的都是 SSOT 的 UI/UX 嗎」)─
@@ -141,6 +146,59 @@ if grep -qE '待你拍板|拍板清單' "$FILE_PATH" 2>/dev/null; then
141
146
  fi
142
147
  fi
143
148
 
149
+ # ─ Validator K: 決策品質四要件(2026-07-13 user verbatim「需我拍板的議題,不是應該確保你和 codex 來回
150
+ # 討論辯論出來的共識與解法有研究過世界級的設計且符合我們需求與一致設計語言和設計原則並確保 SSOT?
151
+ # 現在跟未來都應該要確保這件事永遠成立」;SSOT = deep-audit SKILL C.1「🔒 決策品質四要件」。
152
+ # 命名注:SKILL 2026-07-13 初稿寫「Validator I」,但 I 已被 D3/D4/D5 chain(2026-07-04)佔用 → 定 K)─
153
+ # 報告含「待你拍板」/「拍板清單」section 時:section 內每個決策 block(切分同 Validator H heading regex)
154
+ # 必含全部四要件 marker:(1) SSOT-check(SSOT/既有拍板)(2) ≥3 世界級 cite(世界級/URL)
155
+ # (3) codex 辯論 verdict(codex)(4) design-fit(設計語言/設計原則/design-fit)。缺任一 → 該題不成熟
156
+ # → BLOCK(exit 2)。Detection conservative:只掃本 hook file scope(audit report / C1-final-report)
157
+ # 的拍板 section;無決策 block(「無待拍板」)= 合法 pass。
158
+ if grep -qE '待你拍板|拍板清單' "$FILE_PATH" 2>/dev/null; then
159
+ _K_MISSING=$(node -e '
160
+ try {
161
+ const fs = require("fs");
162
+ const txt = fs.readFileSync(process.argv[1], "utf8");
163
+ const m = txt.search(/待你拍板|拍板清單/);
164
+ if (m < 0) { console.log(""); process.exit(0); }
165
+ const lines = txt.slice(m).split("\n");
166
+ const headRe = /^\s*(?:\d+[.、)]|#{2,}\s*決策)/;
167
+ const blocks = []; let cur = null;
168
+ for (const ln of lines) {
169
+ if (headRe.test(ln)) { if (cur !== null) blocks.push(cur); cur = ln; }
170
+ else if (cur !== null) cur += "\n" + ln;
171
+ }
172
+ if (cur !== null) blocks.push(cur);
173
+ const req = [
174
+ ["SSOT-check", /SSOT|既有拍板/],
175
+ ["世界級cite", /世界級|https?:\/\//],
176
+ ["codex-verdict", /codex/i],
177
+ ["design-fit", /設計語言|設計原則|design-fit/],
178
+ ];
179
+ const miss = [];
180
+ blocks.forEach((b, i) => {
181
+ const lack = req.filter(([, re]) => !re.test(b)).map(([n]) => n);
182
+ if (lack.length) miss.push("決策" + (i + 1) + " 缺[" + lack.join("/") + "]");
183
+ });
184
+ console.log(miss.join(";"));
185
+ } catch (e) { console.log(""); }
186
+ ' "$FILE_PATH" 2>/dev/null || echo "")
187
+ if [ -n "$_K_MISSING" ]; then
188
+ CRITICAL_FAIL=1
189
+ WARNINGS="${WARNINGS}\n 🔴 [K] 決策四要件不全:${_K_MISSING} — 每個送 user 拍板的決策必含 (1)SSOT-check(先 grep 既有 canonical/已拍板)(2)≥3 世界級 cite(WebFetch 真 source + URL)(3)codex 辯論 verdict(4)設計語言/原則 fit。缺 = 該題不成熟,退回研究/辯論(deep-audit SKILL C.1 四要件),禁送 user。"
190
+ fi
191
+ fi
192
+
193
+ # ─ Validator BLOCK gate(2026-05-31 fix infra-audit self-finding:原 hook 只 exit 0 + additionalContext
194
+ # soft-inject = 我過度宣稱「BLOCKER」。改:critical fail → stderr + exit 2 真 block PostToolUse。
195
+ # 2026-07-10 user「只有 SSOT UI/UX 才交拍板,要確保」:Validator H 原在本 gate 之後 = CRITICAL_FAIL 白設
196
+ # 死旗(hunt finding #62)→ 搬到 gate 前,H 現在真擋)─
197
+ if [ "${CRITICAL_FAIL:-0}" -eq 1 ]; then
198
+ printf '🚨 AUDIT-REPORT VALIDATOR BLOCK(C/F/G/H/I/J/K critical):%b\n\n此 deep-audit report 不合格,補齊上述後重出 report。' "$WARNINGS" >&2
199
+ exit 2
200
+ fi
201
+
144
202
  # ─ Validator E: prune-chain-trigger emit ──────────────────────────────────
145
203
  # 2026-06-11 擴充(user 糾正「為何每次都要問我是否要跑 knowledge prune」機械兜底,SSOT = deep-audit SKILL C.0a):
146
204
  # deep-audit 規模 report(DIM_COUNT≥10)→ 無條件 fire prune-chain trigger,非僅 coverage 不足時。
@@ -2,10 +2,15 @@
2
2
  # Codex brief invariants enforcement(2026-05-23 永久 per user verbatim「codex 跑的稽核流程理應要跟你跑的深度稽核流程是一模一樣 SSOT 的不能偏移」)
3
3
  #
4
4
  # PreToolUse(Bash)hook:catch codex exec / cat ... | codex exec / 任何 codex CLI invocation
5
- # Scan codex brief content for 3 mandatory invariants(per feedback_codex_brief_invariants_2026_05_23.md):
5
+ # Scan codex brief content for 7 mandatory invariants(per feedback_codex_brief_invariants_2026_05_23.md
6
+ # + 2026-07-10 user directive「codex 做的任務 / 資訊 / 閱讀 / 判斷標準都要跟 Claude 一模一樣 SSOT」):
6
7
  # 1. 全盤閱讀(全部 source 列舉 or 「DS-wide」「全盤閱讀」「全 N files」 keyword)
7
8
  # 2. Triple-verify(「triple-verify」/「三重驗證」/「grep + Read + canonical exception」 keyword)
8
9
  # 3. 禁抽樣(「禁抽樣」/「禁 sample」/「NO-SAMPLE」/「DS-wide ALL files」 keyword)
10
+ # 4. 禁列檔(「禁列檔」/「禁 rg --files」/「只讀 N file」/「直接出 verdict」 keyword)
11
+ # 5. 輸入對等(閱讀清單逐字鏡射 A.0:含 meta-patterns rules + memory MEMORY.md index 錨點)
12
+ # 6. 判準對等(brief 給 codex audit-prompts.md 每-dim rubric + 逐 dim 套用)
13
+ # 7. A.1b 對等(brief 要求 codex 做 per-component claim-vs-code 對抗驗證 = Claude A.1b 鏡像)
9
14
  #
10
15
  # 缺任一 → exit 2 BLOCKER(stop codex 啟動)。Escape:brief 含 `// @codex-brief-invariant-skip: <rationale>`(極罕見)。
11
16
 
@@ -98,6 +103,28 @@ if ! echo "$BRIEF_CONTENT" | grep -qiE '禁列檔|禁 rg --files|禁 find 全|
98
103
  MISSING="${MISSING} • 4️⃣ 禁列檔 invariant 缺(「禁列檔」/「禁 rg --files」/「只讀 N file」/「直接出 verdict」keyword)— per 2026-05-27 codex token-burn 2× anchor\n"
99
104
  fi
100
105
 
106
+ # 5️⃣ 輸入對等(2026-07-10 user directive「codex 做的任務、擁有的資訊、閱讀的資訊要跟你一模一樣」):
107
+ # 閱讀清單必逐字鏡射 A.0(泛 glob ≠ 對等;至少含 meta-patterns rules + memory index 兩錨點,
108
+ # 具名鏡射時自然存在)。
109
+ if ! echo "$BRIEF_CONTENT" | grep -qi 'meta-patterns' || ! echo "$BRIEF_CONTENT" | grep -qiE 'MEMORY\.md|memory'; then
110
+ MISSING="${MISSING} • 5️⃣ 輸入對等 invariant 缺(閱讀清單必逐字鏡射 A.0 六項:含 .claude/rules/meta-patterns.md 等具名 rules + memory MEMORY.md index;泛 glob 不算)\n"
111
+ fi
112
+
113
+ # 6️⃣ 判準對等(2026-07-10 user directive「兩邊都用同樣的完美標準去稽核」):brief 必給 codex
114
+ # 我用的每-dim 判準 rubric(audit-prompts.md,SKILL.md:257「Use prompts in audit-prompts.md」=
115
+ # 我的 dim sub-agent 判準 SSOT),並要求逐 dim 套用 —— 只給 dim 編號 = codex 憑自己理解判 =
116
+ # 判斷標準不對稱(user 錨:「我基於治理判、codex 可能沒有」)。
117
+ if ! echo "$BRIEF_CONTENT" | grep -qi 'audit-prompts'; then
118
+ MISSING="${MISSING} • 6️⃣ 判準對等 invariant 缺(brief 必給 codex `design-system-audit/references/audit-prompts.md` 每-dim rubric + 要求逐 dim 套用同一判準;只給 dim 編號 = codex 憑己意判 = 標準不對稱)\n"
119
+ fi
120
+
121
+ # 7️⃣ A.1b 對等(2026-07-10 user「所有稽核任務都應對等」全盤盤點抓):brief 必要求 codex 做
122
+ # A.1b(per-component claim-vs-code 對抗驗證,讀每元件 .tsx + wrap lib 逐句驗宣稱)—— Claude
123
+ # 最高產出 pass(2026-05-30 抓 403 findings),漏了 = codex 少做一整趟 = 任務不對等。
124
+ if ! echo "$BRIEF_CONTENT" | grep -qiE 'A\.1b|claim-vs-code|per-component.*(對抗|逐句|verif)'; then
125
+ MISSING="${MISSING} • 7️⃣ A.1b 對等 invariant 缺(brief 必要求 codex 做 per-component claim-vs-code 對抗驗證 = Claude SKILL A.1b 鏡像;漏 = 少做最高產出 pass = 任務不對等)\n"
126
+ fi
127
+
101
128
  if [ -n "$MISSING" ]; then
102
129
  printf '🚨 CODEX BRIEF MISSING INVARIANTS BLOCKER(2026-05-23 user verbatim:「codex 會跑的稽核流程理應要跟你跑的深度稽核流程是一模一樣 SSOT 的不能偏移」):\n' >&2
103
130
  printf '\n Brief 缺以下 invariant:\n' >&2
@@ -14,6 +14,31 @@ source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
14
14
  set -uo pipefail
15
15
  INPUT=$(cat 2>/dev/null || echo "{}")
16
16
 
17
+ # ── Shared: 中和 consumer 自有 local 元件的裸 tag(named-import 除鏽的反向保護,2026-07-10 N6 根治)──
18
+ # 多數 r2/r3 pattern 用 `<(DS\.)?X`(named-import 除鏽,抓 fork 用 named import `<Dialog>` 繞過
19
+ # `<DS.>` 前綴)→ 但會誤殺 consumer 自有的同名 local 元件。判準:裸 <X> 只在「明確 named-import
20
+ # 自非 DS 模組」(local './x' 或他 package)時才確定是 consumer 自有 → 中和成 <LOCAL_X;
21
+ # 無 import(fixture 慣例)或 DS-package import → 視為 DS,保留(維持除鏽 intent)。
22
+ # namespace <DS.X>(capture 到 "DS" token → skip)/ raw 小寫 HTML tag 不受影響。
23
+ neutralize_local_tags() {
24
+ local content="$1"
25
+ # LOCAL_NAMED extraction 用 flattened 副本(抓跨行 import block);但**回傳保留原換行**
26
+ # (r2 的空 @story-baseline: marker 偵測是逐行的,flatten 會讓下一行內容誤填空 marker → P4)。
27
+ local local_named
28
+ local_named=$(printf '%s' "$content" | tr '\n' ' ' \
29
+ | grep -oE "import[[:space:]]*\{[^}]*\}[[:space:]]*from[[:space:]]*['\"][^'\"]+['\"]" \
30
+ | grep -vE "from[[:space:]]*['\"]@qijenchen/design-system" \
31
+ | grep -oE '\{[^}]*\}' | tr -d '{}' | tr ',' '\n' \
32
+ | sed -E 's/.*[[:space:]]as[[:space:]]+([A-Za-z0-9_]+).*/\1/; s/[[:space:]]//g' \
33
+ | grep -E '^[A-Z]' | sort -u)
34
+ local T
35
+ for T in $local_named; do
36
+ [ "$T" = "DS" ] && continue
37
+ content=$(printf '%s' "$content" | sed -E "s#<(/?)$T([[:space:]/>])#<\\1LOCAL_$T\\2#g")
38
+ done
39
+ printf '%s' "$content"
40
+ }
41
+
17
42
  r1_no_ds_catalog() {
18
43
  set -uo pipefail
19
44
 
@@ -117,11 +142,15 @@ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content /
117
142
  # Escape clauses
118
143
  if echo "$CONTENT" | grep -qE '@story-baseline-allow:|@consumer-catalog-allow:'; then exit 0; fi
119
144
 
145
+ # 中和 consumer 自有 local 元件的裸 tag(N6 over-broad guard;shared helper SSOT)
146
+ CONTENT=$(neutralize_local_tags "$CONTENT")
147
+
120
148
  # High-risk DS primitives requiring baseline marker
121
149
  HIGH_RISK_PRIMITIVES='DataTable|Dialog|Sheet|Popover|DropdownMenu|Tooltip|HoverCard|LinkInput|RadioGroup|CircularProgress|AppShell|Sidebar'
122
150
 
123
- # Detect usage
124
- USED=$(echo "$CONTENT" | grep -oE "<DS\.($HIGH_RISK_PRIMITIVES)\\b" | sort -u | head -10)
151
+ # Detect usage(named-import 除鏽:namespace <DS.X> + DS-named-import 的裸 <X> 皆計入;
152
+ # consumer 自有 local 元件已由 neutralize_local_tags 中和成 <LOCAL_X 不會誤匹配)
153
+ USED=$(echo "$CONTENT" | grep -oE "<(DS\.)?($HIGH_RISK_PRIMITIVES)\\b" | sort -u | head -10)
125
154
 
126
155
  if [ -z "$USED" ]; then exit 0; fi
127
156
 
@@ -179,33 +208,36 @@ CONTENT=$(echo "$CONTENT" | tr '\n' ' ')
179
208
  # Global escape — file-wide allowlist
180
209
  if echo "$CONTENT" | grep -q '@ds-misuse-allow:'; then exit 0; fi
181
210
 
211
+ # 中和 consumer 自有 local 元件的裸 tag(N6 over-broad guard;shared helper SSOT,對齊 r2_story_baseline)
212
+ CONTENT=$(neutralize_local_tags "$CONTENT")
213
+
182
214
  VIOLATIONS=""
183
215
 
184
216
  # Pattern 1: <CircularProgress size={N}> with literal number (override default 24)
185
- if echo "$CONTENT" | grep -qE '<DS\.CircularProgress[^>]+size=\{[0-9]+\}'; then
217
+ if echo "$CONTENT" | grep -qE '<(DS\.)?CircularProgress[^>]+size=\{[0-9]+\}'; then
186
218
  VIOLATIONS="${VIOLATIONS} - <CircularProgress size={N}> hardcoded number override default 24 (per circular-progress.spec.md:101)\n"
187
219
  fi
188
220
 
189
221
  # Pattern 2: <RadioGroupItem> NOT wrapped in <SelectionItem control={...}>
190
222
  # Approximation: file uses RadioGroupItem but doesn't reference SelectionItem
191
- if echo "$CONTENT" | grep -qE '<DS\.RadioGroupItem\b' && ! echo "$CONTENT" | grep -qE 'SelectionItem|<DS\.RadioGroupItem[^>]+label='; then
223
+ if echo "$CONTENT" | grep -qE '<(DS\.)?RadioGroupItem\b' && ! echo "$CONTENT" | grep -qE 'SelectionItem|<(DS\.)?RadioGroupItem[^>]+label='; then
192
224
  VIOLATIONS="${VIOLATIONS} - <RadioGroupItem> 沒 wrap <SelectionItem control={<RadioGroupItem>}> (per selection-item.spec.md:23 SSOT spacing/padding)\n"
193
225
  fi
194
226
 
195
227
  # Pattern 3: <DataTable columns={[…]}> with literal single column
196
- if echo "$CONTENT" | grep -qE '<DS\.DataTable[^>]+columns=\{\[\s*\{[^}]+\}\s*\]\}' && ! echo "$CONTENT" | grep -qE 'columns=\{[^}]*\},\s*\{'; then
228
+ if echo "$CONTENT" | grep -qE '<(DS\.)?DataTable[^>]+columns=\{\[\s*\{[^}]+\}\s*\]\}' && ! echo "$CONTENT" | grep -qE 'columns=\{[^}]*\},\s*\{'; then
197
229
  VIOLATIONS="${VIOLATIONS} - <DataTable columns={[single-col]}> minimal one-column = 違反 data-table.spec.md canonical(min 2 cols for meaningful render)\n"
198
230
  fi
199
231
 
200
232
  # Pattern 4: <LinkInput placeholder=...> without value prop
201
- if echo "$CONTENT" | grep -qE '<DS\.LinkInput[^>]+placeholder=' && ! echo "$CONTENT" | grep -qE '<DS\.LinkInput[^>]+(value|defaultValue)='; then
233
+ if echo "$CONTENT" | grep -qE '<(DS\.)?LinkInput[^>]+placeholder=' && ! echo "$CONTENT" | grep -qE '<(DS\.)?LinkInput[^>]+(value|defaultValue)='; then
202
234
  VIOLATIONS="${VIOLATIONS} - <LinkInput placeholder=...> 沒 value prop = placeholder-only mode 抹平 link/edit canonical (per link-input.spec.md:18,48-58)\n"
203
235
  fi
204
236
 
205
237
  # Pattern 5: <Empty title=...> without icon and without description
206
- if echo "$CONTENT" | grep -qE '<DS\.Empty[^>]+title=' && \
207
- ! echo "$CONTENT" | grep -qE '<DS\.Empty[^>]+icon=' && \
208
- ! echo "$CONTENT" | grep -qE '<DS\.Empty[^>]+description='; then
238
+ if echo "$CONTENT" | grep -qE '<(DS\.)?Empty[^>]+title=' && \
239
+ ! echo "$CONTENT" | grep -qE '<(DS\.)?Empty[^>]+icon=' && \
240
+ ! echo "$CONTENT" | grep -qE '<(DS\.)?Empty[^>]+description='; then
209
241
  VIOLATIONS="${VIOLATIONS} - <Empty title=...> 無 icon 無 description = 違反 Empty.tsx:11「預設只需 description」minimal mock looks weird\n"
210
242
  fi
211
243
 
@@ -219,12 +251,12 @@ if echo "$CONTENT" | grep -qE '\b[a-z][a-z-]*-\[(#[0-9a-fA-F]{3,8}|rgb|rgba|hsl|
219
251
  fi
220
252
 
221
253
  # Pattern 9(2026-06-12,user 抓 fork「四不像」G4 補洞):AppShell slot 餵 raw HTML element。
222
- # app-shell.spec.md:296-299 明文禁 sidebar={<div>}/header={<header>},原註「靠 audit 把關」
254
+ # app-shell.spec.md「Consumer 紀律」段明文禁 sidebar={<div>}/header={<header>},原註「靠 audit 把關」
223
255
  # 無機械閘 → 兌現成 P0(per memory feedback_ssot_mechanical_p0_not_p1_warn)。
224
256
  # 零誤判:雙條件 = 同檔有 <DS.AppShell> + slot 屬性直接餵 raw tag(div/header/nav/aside/section)。
225
- if echo "$CONTENT" | grep -qE '<DS\.AppShell\b' && \
257
+ if echo "$CONTENT" | grep -qE '<(DS\.)?AppShell\b' && \
226
258
  echo "$CONTENT" | grep -qE '\b(header|sidebar|aside)=\{ *<(div|header|nav|aside|section)\b'; then
227
- VIOLATIONS="${VIOLATIONS} - <AppShell header/sidebar/aside={<raw element>}> — slot 必餵 DS 元件(ChromeHeader / Sidebar / AppShellAside),raw div/header 漏接 border/scroll/responsive canonical(per app-shell.spec.md:296-299)\n"
259
+ VIOLATIONS="${VIOLATIONS} - <AppShell header/sidebar/aside={<raw element>}> — slot 必餵 DS 元件(ChromeHeader / Sidebar / AppShellAside),raw div/header 漏接 border/scroll/responsive canonical(per app-shell.spec.md「Consumer 紀律」段)\n"
228
260
  fi
229
261
 
230
262
  # Pattern 10(2026-06-16,user 抓 fork prototype 手刻 table 不用 DataTable):RAW PRIMITIVE 手刻
@@ -236,21 +268,121 @@ fi
236
268
  if echo "$CONTENT" | grep -qE '<table\b' && echo "$CONTENT" | grep -qE '<thead\b|<tbody\b|<th\b'; then
237
269
  VIOLATIONS="${VIOLATIONS} - 手刻 raw <table><thead>/<tbody> 資料表 → 必用 <DataTable columns={...} data={...} />(build-ui-canonicals.md:18 ❌→✅ SSOT;這是「優先消費既有元件」大原則,無理由不得手刻)\n"
238
270
  fi
271
+ # 2026-07-08 WM 戰役 R4:偽表格視覺簽名(div-grid 表格繞過字面 <table> 偵測 — WM 5 檔
272
+ # MINI_TABLE grid-cols + header bg + row 常數重複宣告實證,spec broad / hook narrow M34 gap)。
273
+ # 簽名 = 同段 content 有 grid-cols-[ 且(bg-muted|bg-neutral-selected 當 header 底 或 自創
274
+ # ROW_PAD 類常數)。escape:@handcraft-table-ok:(真非表格的 grid 佈局)。
275
+ if echo "$CONTENT" | grep -qE 'grid-cols-\[' && echo "$CONTENT" | grep -qE '(bg-muted|bg-neutral-selected)[^a-z-]' && echo "$CONTENT" | grep -qiE 'ROW_PAD|MINI_TABLE|<div[^>]*grid[^>]*font-medium' && ! echo "$CONTENT" | grep -q '@handcraft-table-ok:'; then
276
+ VIOLATIONS="${VIOLATIONS} - 偽表格簽名(div grid-cols + header bg + row 常數):div-grid 手刻資料表 → 必用 <DataTable size=\"sm\" height=\"auto\">(data-table.spec「嵌入式表格」canonical;WM MembersTab 等 5 檔錨例)。真非表格 grid 佈局 → 行內 @handcraft-table-ok: <rationale>\n"
277
+ fi
239
278
  if echo "$CONTENT" | grep -qE '<img\b[^>]*rounded-full'; then
240
279
  VIOLATIONS="${VIOLATIONS} - 手刻 <img ... rounded-full> 頭像 → 必用 <Avatar>(build-ui-canonicals.md:25)\n"
241
280
  fi
242
281
  if echo "$CONTENT" | grep -qE '<select\b'; then
243
282
  VIOLATIONS="${VIOLATIONS} - native <select> 手刻下拉 → 必用 <Select> / <DropdownMenu>(build-ui-canonicals.md:15)\n"
244
283
  fi
284
+ # 2026-07-08 WM 戰役 R4:手刻表單 validation 簽名(WM CreateWorkItemDialog 註解引 canonical
285
+ # 卻手刻 showErrors state = M23(d)「cite 存在 ≠ consume」;useFormValidation hook 零消費偵測缺口)。
286
+ # 簽名 = 檔內有 showErrors/submitAttempt 類 state + FieldError 渲染,但無 useFormValidation import。
287
+ if echo "$CONTENT" | grep -q 'useState' && echo "$CONTENT" | grep -qE '\b(showErrors|showError|submitAttempt|attemptedSubmit)\b' && echo "$CONTENT" | grep -q 'FieldError' && ! echo "$CONTENT" | grep -q 'useFormValidation' && ! echo "$CONTENT" | grep -q '@form-validation-ok:'; then
288
+ VIOLATIONS="${VIOLATIONS} - 手刻表單 validation state(showErrors/submitAttempt + FieldError)→ 必消費 useFormValidation hook(form-validation.spec 規則 1 blur/7 全驗/8 DOM 序 anchor 隨 hook 自帶;root barrel 有 export)。特殊表單 → 行內 @form-validation-ok: <rationale>\n"
289
+ fi
245
290
  if echo "$CONTENT" | grep -qE '<hr\b'; then
246
291
  VIOLATIONS="${VIOLATIONS} - 手刻 <hr> 分隔線 → 用 <Separator>(或 separator.spec 允許的 CSS border)(build-ui-canonicals.md:23)\n"
247
292
  fi
293
+ # 2026-07-10 WM 戰役收官:手刻 menu-item 可點列簽名(WM TypeSettingsDialog 左 rail 錨例 —
294
+ # 手刻 <button hover:bg-neutral-hover + bg-neutral-selected> nav row,未消費 MenuItem)。
295
+ # 前置:DS API 根因已修(MenuItem startContent slot,beta.84)→ 有合法替代才上機械攔(避免
296
+ # fork 無路可走 brick)。簽名 = hover:bg-neutral-hover 與 bg-neutral-selected 成對出現
297
+ # (= menu-item family 狀態語義)+ 可點訊號(<button/<a/onClick),且沒在消費 <MenuItem。
298
+ # 注意:不 tag-anchor className(WM 錨例把 class 抽 const 再 className={cls} 引用,
299
+ # tag-anchored regex 會漏 — test 27 抓到的真實 shape)。
300
+ if echo "$CONTENT" | grep -q 'hover:bg-neutral-hover' && \
301
+ echo "$CONTENT" | grep -q 'bg-neutral-selected' && \
302
+ echo "$CONTENT" | grep -qE '<button\b|<a\b|onClick=' && \
303
+ ! echo "$CONTENT" | grep -q '<MenuItem' && \
304
+ ! echo "$CONTENT" | grep -q '@nav-row-handcraft-ok:'; then
305
+ VIOLATIONS="${VIOLATIONS} - 手刻 menu-item 可點列(hover:bg-neutral-hover + bg-neutral-selected 成對)→ 必包 <MenuItem>(subpath @qijenchen/design-system/components/Menu;selected prop + startIcon/avatar/startContent slot;menu-item.spec.md「結構」)。非 menu-item 語義 → 行內 @nav-row-handcraft-ok: <rationale>\n"
306
+ fi
307
+
308
+ # ── 2026-07-10 批次 A(治理覆蓋 matrix 收官;來源 .claude/planning/2026-07-10-consumer-coverage-remediation.md)──
309
+ # C5 對比配對:深字桶 hue(yellow/amber/orange/lime step-6)配 text-white — 各自合法、組合對比違規
310
+ # (tag.spec.md 深字桶 = text-on-emphasis-dark)。修 → 消費 CAT_SOLID token pair。
311
+ if echo "$CONTENT" | grep -q 'text-white' && \
312
+ echo "$CONTENT" | grep -qE 'bg-\[var\(--color-(yellow|amber|orange|lime)-[0-9]' && \
313
+ ! echo "$CONTENT" | grep -q '@cat-solid-ok:'; then
314
+ VIOLATIONS="${VIOLATIONS} - 亮色底(yellow/amber/orange/lime step-6)配 text-white = 對比違規 → 消費 CAT_SOLID / CAT_SOLID_TOKENS pair(深字桶自帶 text-on-emphasis-dark;tokens/categorical-color.ts)。特例 → @cat-solid-ok: <rationale>\n"
315
+ fi
316
+ # C18 計數串接:element children 出現 {label} ({count/length/total})。attr(aria-label)字串層合法
317
+ # — regex 錨 children 的 > 前綴,attribute 不中(item-anatomy.spec.md:176 禁括號串接)。
318
+ if echo "$CONTENT" | grep -qE '>[^<]*\{[a-zA-Z0-9_.]+\} *\(\{[a-zA-Z0-9_.]*(count|Count|length|total)[a-zA-Z0-9_.]*\}\)' && \
319
+ ! echo "$CONTENT" | grep -q '@count-in-label-ok:'; then
320
+ VIOLATIONS="${VIOLATIONS} - 計數括號串接 {label} ({count}) → row header 用「標題左、純數字右 space-between + tabular-nums」(item-anatomy.spec.md:176);互動元素(tab/chip/button)用 badge slot。aria/純文字匯出層 → @count-in-label-ok: <rationale>\n"
321
+ fi
322
+ # C17 分隔線幾何:vertical Separator 無 mx- = 黏按鈕(action-bar.spec.md「分隔線幾何」h-6 mx-1;
323
+ # ButtonGroup 內用 <ButtonDivider/>(mx built-in))。
324
+ SEP_TAGS=$(echo "$CONTENT" | grep -oE '<(DS\.)?Separator[^>]*orientation=["'"'"']vertical["'"'"'][^>]*' || true)
325
+ if [ -n "$SEP_TAGS" ] && echo "$SEP_TAGS" | grep -qv 'mx-' && \
326
+ ! echo "$CONTENT" | grep -q '@separator-geometry-ok:'; then
327
+ VIOLATIONS="${VIOLATIONS} - vertical <Separator> 無 mx- = 分隔線黏按鈕 → toolbar 用 className=\"h-6 mx-1\"(dense h-5 mx-1);ButtonGroup 內用 <ButtonDivider/>(action-bar.spec.md「分隔線幾何」)。版面切分 divider → @separator-geometry-ok: <rationale>\n"
328
+ fi
329
+ # C20 連結字手刻 underline:color.spec.md「Action — Primary」= hover 換色不用底線;
330
+ # dropzone 連結走 FileUpload children slot。no-underline / hover:underline 皆不中此 regex 形。
331
+ if echo "$CONTENT" | grep -qE '<(span|a|button|div)[^>]*className="([^"]* )?underline( [^"]*)?"'; then
332
+ VIOLATIONS="${VIOLATIONS} - 手刻 underline 連結字 → Action—Primary canonical = text-primary + hover 換色(text-primary-hover),不用底線(color.spec.md「Action — Primary」);dropzone 連結走 <FileUpload> children slot\n"
333
+ fi
334
+ # C10 業務 search 被推最右:spacer(flex-1 自閉合 / ml-auto)緊接 Search Input。
335
+ # 過濾當前檢視的 search = 業務層,與其他操作同區(action-bar.spec.md:69/76);無標題 toolbar 靠左(:109)。
336
+ if echo "$CONTENT" | grep -qE '(flex-1[^>]*/>|ml-auto)[^<]{0,80}<(DS\.)?Input[^>]{0,200}placeholder="(Search|搜尋)' && \
337
+ ! echo "$CONTENT" | grep -q '@search-right-ok:'; then
338
+ VIOLATIONS="${VIOLATIONS} - 業務 search(過濾當前檢視)被 spacer 推到最右 → 歸業務層與其他操作同區(action-bar.spec.md:69/76;無標題 toolbar 業務層靠左 :109)。工具型跨頁 search 置最右合法 → @search-right-ok: <rationale>\n"
339
+ fi
340
+ # C11 dialog chrome 雙 X:DialogHeader 之後 250 字窗內手放 startIcon={X} 且窗內無 actions=
341
+ # (DialogHeader 自帶 Close;header 操作走 actions slot — action-bar.spec.md:281)。
342
+ DH_WIN=$(echo "$CONTENT" | grep -oE '<(DS\.)?DialogHeader.{0,250}' || true) # BSD grep bound 上限 255
343
+ if [ -n "$DH_WIN" ] && echo "$DH_WIN" | grep -qE 'startIcon=\{X\}' && ! echo "$DH_WIN" | grep -q 'actions=' && \
344
+ ! echo "$CONTENT" | grep -q '@dialog-chrome-ok:'; then
345
+ VIOLATIONS="${VIOLATIONS} - DialogHeader 內手放 X 關閉鈕(DialogHeader 已自帶 Close = 雙 X)→ header 操作走 actions slot(自動 ButtonDivider 分隔,action-bar.spec.md:281)。特例 → @dialog-chrome-ok: <rationale>\n"
346
+ fi
347
+ # C7 SelectMenu internal 直用(select-menu.spec.md:53 明文禁 consumer 直用 — 它是 Select/
348
+ # Combobox 的內部選單面,consumer 用 <Select>/<Combobox>;此為「internal 且 spec 明文禁直用」
349
+ # 特例,非一般 internal 包裝即可)。
350
+ if echo "$CONTENT" | grep -qE '<SelectMenu\b' && \
351
+ ! echo "$CONTENT" | grep -q '@selectmenu-direct-ok:'; then
352
+ VIOLATIONS="${VIOLATIONS} - <SelectMenu> 直用(internal 選單面,select-menu.spec.md:53 明文禁)→ 用 <Select> / <Combobox>(自帶 trigger + 選單接線)。極特例 → @selectmenu-direct-ok: <rationale>\n"
353
+ fi
354
+ # C13 手刻可收合 section header(2026-07-10 收官:R3-7 拍板 SectionHeader 留產品客製、但 layout
355
+ # 全消費 canonical — 組合鐵律 codify 於 item-anatomy.spec.md「可收合 section header」;簽名 =
356
+ # Chevron toggle + justify-between + 可點,且檔內無 SectionHeader 共用元件)。
357
+ if echo "$CONTENT" | grep -qE 'Chevron(Down|Right|Up)' && \
358
+ echo "$CONTENT" | grep -q 'justify-between' && \
359
+ echo "$CONTENT" | grep -qE '<button\b|onClick=' && \
360
+ ! echo "$CONTENT" | grep -q 'SectionHeader' && \
361
+ ! echo "$CONTENT" | grep -q '@section-header-ok:'; then
362
+ VIOLATIONS="${VIOLATIONS} - 手刻可收合 section 標題列(Chevron + justify-between + 可點)→ 抽共用 SectionHeader 元件並照 item-anatomy.spec.md「可收合 section header 組合 canonical」(chevron = title 後 suffix inline action / desc 用 item-gap token / endSlot 垂直置中;WM SectionHeader 錨例)。非 section 標題語義 → @section-header-ok: <rationale>\n"
363
+ fi
364
+ # C19 兩欄 dialog 共用捲軸(2026-07-10 user 拍板:兩欄是組合非元件;組合鐵律 = 各欄自帶
365
+ # ScrollArea,overlay-surface.spec.md「兩欄 dialog 組合 canonical」)。簽名 = Dialog body +
366
+ # 欄分隔 border-l + ScrollArea 少於 2 = 兩欄共用單一捲軸。
367
+ if echo "$CONTENT" | grep -qE '<(DS\.)?Dialog(Body|Content)\b' && \
368
+ echo "$CONTENT" | grep -q 'border-l' && \
369
+ echo "$CONTENT" | grep -qE 'className="[^"]*flex[^"]*"' && \
370
+ [ "$(echo "$CONTENT" | grep -o '<ScrollArea' | wc -l | tr -d ' ')" -lt 2 ] && \
371
+ ! echo "$CONTENT" | grep -q '@two-pane-dialog-ok:'; then
372
+ VIOLATIONS="${VIOLATIONS} - 兩欄 dialog(border-l 欄分隔)但 ScrollArea < 2 = 共用單一捲軸 → 各欄自帶 <ScrollArea> 獨立捲(overlay-surface.spec.md「兩欄 dialog 組合 canonical」;archetype = WM WorkItemDetailDialog / FileViewer InfoPanel)。非兩欄語義 → @two-pane-dialog-ok: <rationale>\n"
373
+ fi
374
+ # C12 Field family 硬寬:Select/Combobox/DatePicker/PeoplePicker 帶 w-N / w-[Npx] 硬寬
375
+ # → width="hug"/"fill" 語義軸(field-controls.spec.md「寬度」)。
376
+ if echo "$CONTENT" | grep -qE '<(DS\.)?(Select|Combobox|DatePicker|PeoplePicker)\b[^>]*className="[^"]*\bw-([0-9]+|\[[0-9]+(px|rem)\])' && \
377
+ ! echo "$CONTENT" | grep -q '@field-width-ok:'; then
378
+ VIOLATIONS="${VIOLATIONS} - Field 家族控件 className 硬寬(w-N / w-[Npx])→ 用 width=\"hug\"(內容自適)或預設 fill(field-controls.spec.md「寬度」;WM 詳情 metadata 全 hug 拍板錨例)。特例 → @field-width-ok: <rationale>\n"
379
+ fi
248
380
 
249
381
  # Pattern 6: Overlay trigger without defaultOpen state for visual demo
250
382
  # (Skip in production .tsx; only enforce in .stories.tsx where visual snapshot matters)
251
383
  if echo "$FILE" | grep -qE '\.stories\.tsx$'; then
252
384
  for overlay in Tooltip Popover Dialog Sheet DropdownMenu; do
253
- if echo "$CONTENT" | grep -qE "<DS\.${overlay}\b" && \
385
+ if echo "$CONTENT" | grep -qE "<(DS\.)?${overlay}\b" && \
254
386
  ! echo "$CONTENT" | grep -qE "(defaultOpen|open=\{(true|isOpen)\})"; then
255
387
  VIOLATIONS="${VIOLATIONS} - Story uses <${overlay}> without defaultOpen — visual audit can't see overlay content\n"
256
388
  fi
@@ -85,13 +85,15 @@ EOF
85
85
  esac
86
86
 
87
87
  # ── B.3 filter↔sort sibling sync reminder(P2 reminder)────────────────────────
88
+ # 2026-07-14 拆檔對齊:filter row/group renderer 移居 data-table-filter-group.tsx(@internal),
89
+ # row-layout 類 sync 關注點跟著搬 → 兩檔皆觸發 filter 側 reminder(M7 hook regex 對齊 file layout)。
88
90
  case "$FILE_PATH" in
89
- *data-table-filter-panel.tsx)
91
+ *data-table-filter-panel.tsx|*data-table-filter-group.tsx)
90
92
  cat >&2 <<EOF
91
93
 
92
94
  ┄┄┄ B.3 check_datatable_invariants — sibling sync reminder ┄┄┄
93
95
 
94
- [P2] 動到 filter panel → 是否需要對應修 data-table-sort-manager.tsx?
96
+ [P2] 動到 filter panel(或其 row/group renderer)→ 是否需要對應修 data-table-sort-manager.tsx?
95
97
  Self-check:row gap / row layout / row meta button / chrome corner action /
96
98
  empty state 行為 / CTA button variant — sort row 是否同步?
97
99
 
@@ -102,7 +104,8 @@ EOF
102
104
 
103
105
  ┄┄┄ B.3 check_datatable_invariants — sibling sync reminder ┄┄┄
104
106
 
105
- [P2] 動到 sort manager → 是否需要對應修 data-table-filter-panel.tsx?
107
+ [P2] 動到 sort manager → 是否需要對應修 data-table-filter-panel.tsx(row renderer 在
108
+ data-table-filter-group.tsx)?
106
109
  Self-check:row gap / row layout / row meta button / chrome corner action /
107
110
  empty state 行為 / CTA button variant — filter row 是否同步?
108
111
 
@@ -4,7 +4,8 @@
4
4
  #
5
5
  # Purpose: PreToolUse Edit/Write/MultiEdit 偵測 production tsx wrap DS primitive
6
6
  # (`<Sidebar>` / `<AppShell>` / `<DataTable>` / `<Dialog>` / `<Field>` 等)
7
- # 沒同 turn 跑過 Grep / Read DS canonical baseline → BLOCKER 提醒 propose 前必出 3-column owner table。
7
+ # 沒同 turn 跑過 Grep / Read DS canonical baseline → P0 BLOCKER(exit 2,2026-07-07 治理進化方向 2 升級;
8
+ # escape CLAUDE_BYPASS_DS_ANCHOR=1 audit-logged),propose 前必出 3-column owner table。
8
9
  #
9
10
  # Scope:同 check_substantive_edit_approval_preflight.sh extended scope
10
11
  # - packages/design-system/src/**.tsx (DS internal)
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+ # check_dynamic_tailwind_class — 攔「動態 Tailwind utility class」脆弱寫法(2026-07-09 root-cause 防線)
3
+ #
4
+ # 病根(user 以 GitHub Pages 對比抓出的 DataTable row-height regression):
5
+ # `h-table-row-${size}` 這種「class 名本身含 ${...} 插值」的模板字串,Tailwind **靜態掃描看不到**
6
+ # 完整 class → 只能靠專案別處剛好有 literal(如 spec.md)被 content-detection 掃到才生成。
7
+ # 一旦那個脆弱 literal 消失 / 掃描樹變動(本 case 是 .gitignore 加 reference/)→ 整組 `.h-table-row-*`
8
+ # 規則不生成 → 元件靜默塌成內容高度(non-editable 33px / editable 44px 而非 token 40px)+ 選取控件走位。
9
+ # tsc / build 全綠、CI 不紅 = 沉默陷阱。
10
+ #
11
+ # 正解(對齊 fieldWrapperStyles 的 `h-field-md` cva-literal 慣例):class 名必須是**完整 literal**;
12
+ # 要隨變數選 class 用 literal map:`{ sm:'h-table-row-sm', md:'h-table-row-md', lg:'h-table-row-lg' }[size]`。
13
+ #
14
+ # Scope:production tsx/ts(packages/design-system/src + apps)。CSS var 插值(`var(--x-${y})` / arbitrary
15
+ # value `[...${...}]`)不在此列(那是值,不是 class 名;且 CSS var 真存在,fail-loud 不同機制)。
16
+ # Escape:`// @dynamic-tailwind-allow: <理由>` per-line。
17
+ source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
18
+ set -euo pipefail
19
+ INPUT=$(cat)
20
+ fp=$(printf '%s' "$INPUT" | python3 -c "import sys,json;print(json.load(sys.stdin).get('tool_input',{}).get('file_path',''))" 2>/dev/null || true)
21
+ content=$(printf '%s' "$INPUT" | python3 -c "import sys,json;d=json.load(sys.stdin).get('tool_input',{});print(d.get('content') or d.get('new_string') or '')" 2>/dev/null || true)
22
+ [ -z "$fp" ] && exit 0
23
+ case "$fp" in
24
+ *packages/design-system/src/*.tsx|*packages/design-system/src/*.ts|*apps/*/src/*.tsx|*apps/*/src/*.ts) ;;
25
+ *) exit 0 ;;
26
+ esac
27
+ [ -z "$content" ] && exit 0
28
+
29
+ # 抓:backtick 字串內、Tailwind 尺寸/間距 utility 前綴 + 之後含 `${` 讓 class 名不完整。
30
+ # e.g. `h-table-row-${size}` / `h-${x}` / `min-h-${y}` / `w-col-${i}` / `gap-${g}` / `py-${p}`
31
+ # 排除:`[` 之後(arbitrary value,如 `h-[var(--x-${y})]`)、`var(` 內。
32
+ hits=$(printf '%s' "$content" | grep -nE '`[^`]*\b(h|w|min-h|max-h|min-w|max-w|size|gap|space-[xy]|p[xytblr]?|m[xytblr]?)-[a-z0-9-]*\$\{' 2>/dev/null \
33
+ | grep -vE '@dynamic-tailwind-allow' \
34
+ | grep -vE '\[[^]]*\$\{|var\(' || true)
35
+
36
+ if [ -n "$hits" ]; then
37
+ echo "🚨 BLOCKER: 動態 Tailwind class(class 名含 \${...} 插值)— Tailwind 靜態掃描看不到 → 靜默不生成規則" >&2
38
+ echo " file: $fp" >&2
39
+ echo "$hits" | sed 's/^/ /' >&2
40
+ echo "" >&2
41
+ echo " 病根:2026-07-09 DataTable row-height regression(h-table-row-\${size} → utility 消失 → row 塌 + 選取走位)" >&2
42
+ echo " 正解:改 literal map,class 名寫完整字面 —" >&2
43
+ echo " const cls = { sm: 'h-table-row-sm', md: 'h-table-row-md', lg: 'h-table-row-lg' }[size]" >&2
44
+ echo " 逃生:確實非 class(CSS var 值等)→ 行尾加 // @dynamic-tailwind-allow: <理由>" >&2
45
+ exit 2
46
+ fi
47
+ exit 0
@@ -135,6 +135,33 @@ $(echo "$MARKERS_FOUND" | sed 's/^/ /')
135
135
  EOF
136
136
  exit 2
137
137
  fi
138
+
139
+ # ── Repo 級累計 ratchet(2026-07-08 WM 戰役 R4)──────────────────────────────
140
+ # per-file gate(≥3 distinct/≥5 total)可被「每檔 1-2 個、散多檔」繞過 → repo 級 ceiling。
141
+ # Ratchet 精神(Polaris stylelint migrator):存量 ≥ cap 後只擋「本次 edit 再新增 marker」,
142
+ # 不因存量 brick 無關 edit(本次內容無 marker → 直接放行)。
143
+ EDIT_ADDS_MARKER=$(echo "$CONTENT" | grep -cE "$MARKER_RE" || true)
144
+ if [ "${EDIT_ADDS_MARKER:-0}" -gt 0 ]; then
145
+ APPS_ROOT="${CLAUDE_PROJECT_DIR:-.}/apps"
146
+ REPO_CAP=10
147
+ if [ -d "$APPS_ROOT" ]; then
148
+ REPO_TOTAL=$(grep -rhoE "$MARKER_RE" "$APPS_ROOT" --include='*.tsx' --include='*.ts' 2>/dev/null | wc -l | tr -d ' ')
149
+ if [ "${REPO_TOTAL:-0}" -ge "$REPO_CAP" ]; then
150
+ cat >&2 << EOF
151
+ 🚨 ESCAPE-MARKER-REPO-RATCHET BLOCKER(P0,2026-07-08 WM 戰役 R4)
152
+
153
+ apps/** 全 repo escape marker 存量已 $REPO_TOTAL 個(ceiling $REPO_CAP),本次 edit 又要新增 $EDIT_ADDS_MARKER 個。
154
+ 每檔 1-2 個散多檔 = 繞 per-file gate 的同型濫用 — repo 級 ratchet 攔。
155
+
156
+ 修法 2 選 1:
157
+ (a) 先清既有 escape 的根因(重構走 DS canonical),存量 < $REPO_CAP 後再加真必要的
158
+ (b) Override env(極罕見,commit msg 必記 rationale):
159
+ CLAUDE_BYPASS_ESCAPE_MARKER_AUDIT=1
160
+ EOF
161
+ exit 2
162
+ fi
163
+ fi
164
+ fi
138
165
  fi
139
166
 
140
167
  exit 0