@nurix/etna 0.19.10 → 0.19.12

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 (491) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/harness.json +1 -1
  3. package/data/harnesses/code/rules/frontend.md +5 -5
  4. package/data/harnesses/code/skills/design/SKILL.md +70 -50
  5. package/data/harnesses/code/skills/design/components/charts.md +76 -0
  6. package/data/harnesses/code/skills/design/components/collections.md +132 -0
  7. package/data/harnesses/code/skills/design/components/feedback.md +47 -0
  8. package/data/harnesses/code/skills/design/components/hooks.md +35 -0
  9. package/data/harnesses/code/skills/design/components/index.md +143 -0
  10. package/data/harnesses/code/skills/design/components/inputs.md +327 -0
  11. package/data/harnesses/code/skills/design/components/layout.md +52 -0
  12. package/data/harnesses/code/skills/design/components/media.md +66 -0
  13. package/data/harnesses/code/skills/design/components/motion.md +82 -0
  14. package/data/harnesses/code/skills/design/components/navigation.md +29 -0
  15. package/data/harnesses/code/skills/design/components/overlays.md +72 -0
  16. package/data/harnesses/code/skills/design/components/setup.md +40 -0
  17. package/data/harnesses/code/skills/design/components/typography.md +46 -0
  18. package/data/harnesses/code/skills/design/components/utils.md +37 -0
  19. package/data/harnesses/code/skills/design/data/blueprints/browse.md +38 -0
  20. package/data/harnesses/code/skills/design/data/blueprints/creation-flow.md +38 -0
  21. package/data/harnesses/code/skills/design/data/blueprints/dashboard.md +38 -0
  22. package/data/harnesses/code/skills/design/data/blueprints/grid.md +38 -0
  23. package/data/harnesses/code/skills/design/data/blueprints/queue.md +38 -0
  24. package/data/harnesses/code/skills/design/data/blueprints/record-detail.md +38 -0
  25. package/data/harnesses/code/skills/design/data/blueprints/settings.md +38 -0
  26. package/data/harnesses/code/skills/design/data/chart-styling/Readme.md +33 -0
  27. package/data/harnesses/code/skills/design/data/chart-styling/carbon-accessible-alert-semantic.md +19 -0
  28. package/data/harnesses/code/skills/design/data/chart-styling/carbon-monochrome-sequential-trend.md +19 -0
  29. package/data/harnesses/code/skills/design/data/chart-styling/datadog-classic-six-aligned.md +19 -0
  30. package/data/harnesses/code/skills/design/data/chart-styling/datawrapper-tiered-gray-hierarchy.md +19 -0
  31. package/data/harnesses/code/skills/design/data/chart-styling/econ-red-rule-horizontal.md +19 -0
  32. package/data/harnesses/code/skills/design/data/chart-styling/financial-diverging-threshold-overlay.md +19 -0
  33. package/data/harnesses/code/skills/design/data/chart-styling/ft-vocabulary-ranked-muted.md +19 -0
  34. package/data/harnesses/code/skills/design/data/chart-styling/grafana-dark-threshold-bands.md +19 -0
  35. package/data/harnesses/code/skills/design/data/chart-styling/material-rounded-explicit-label.md +19 -0
  36. package/data/harnesses/code/skills/design/data/chart-styling/nyt-ghost-grid-direct-label.md +19 -0
  37. package/data/harnesses/code/skills/design/data/chart-styling/plot-currentcolor-inherit.md +19 -0
  38. package/data/harnesses/code/skills/design/data/chart-styling/saas-gradient-glow-area.md +19 -0
  39. package/data/harnesses/code/skills/design/data/chart-styling/shadcn-composable-css-vars.md +19 -0
  40. package/data/harnesses/code/skills/design/data/charts/census.csv +58 -0
  41. package/data/harnesses/code/skills/design/data/checklists/browse.md +21 -0
  42. package/data/harnesses/code/skills/design/data/checklists/creation-flow.md +20 -0
  43. package/data/harnesses/code/skills/design/data/checklists/dashboard.md +21 -0
  44. package/data/harnesses/code/skills/design/data/checklists/grid.md +21 -0
  45. package/data/harnesses/code/skills/design/data/checklists/queue.md +21 -0
  46. package/data/harnesses/code/skills/design/data/checklists/record-detail.md +21 -0
  47. package/data/harnesses/code/skills/design/data/checklists/settings.md +21 -0
  48. package/data/harnesses/code/skills/design/data/chrome/board-column.md +68 -0
  49. package/data/harnesses/code/skills/design/data/chrome/data-table.md +63 -0
  50. package/data/harnesses/code/skills/design/data/chrome/side-panel.md +60 -0
  51. package/data/harnesses/code/skills/design/data/chrome/sidebar.md +78 -0
  52. package/data/harnesses/code/skills/design/data/chrome/stat-cards.md +62 -0
  53. package/data/harnesses/code/skills/design/data/chrome/topbar.md +65 -0
  54. package/data/harnesses/code/skills/design/data/color/accent-presets.md +90 -0
  55. package/data/harnesses/code/skills/design/data/color/aesop-earth-mute.md +91 -0
  56. package/data/harnesses/code/skills/design/data/color/arc-peach-play.md +90 -0
  57. package/data/harnesses/code/skills/design/data/color/attio-hunter-teal.md +90 -0
  58. package/data/harnesses/code/skills/design/data/color/carbon-cyan-signal.md +90 -0
  59. package/data/harnesses/code/skills/design/data/color/clay-parchment.md +90 -0
  60. package/data/harnesses/code/skills/design/data/color/duolingo-feather.md +90 -0
  61. package/data/harnesses/code/skills/design/data/color/geist-mono-signal.md +90 -0
  62. package/data/harnesses/code/skills/design/data/color/linear-graphite-violet.md +90 -0
  63. package/data/harnesses/code/skills/design/data/color/mercury-onyx-cobalt.md +90 -0
  64. package/data/harnesses/code/skills/design/data/color/notion-paper-ink.md +90 -0
  65. package/data/harnesses/code/skills/design/data/color/radix-slate-iris.md +90 -0
  66. package/data/harnesses/code/skills/design/data/color/raycast-void-spectrum.md +90 -0
  67. package/data/harnesses/code/skills/design/data/color/spectrum-celery-fuchsia.md +90 -0
  68. package/data/harnesses/code/skills/design/data/color/stripe-blurple-ruby.md +90 -0
  69. package/data/harnesses/code/skills/design/data/color/superhuman-cod-picton.md +89 -0
  70. package/data/harnesses/code/skills/design/data/corpora/operations-review/companies.csv +15 -0
  71. package/data/harnesses/code/skills/design/data/corpora/operations-review/corpus.md +87 -0
  72. package/data/harnesses/code/skills/design/data/corpora/operations-review/people.csv +25 -0
  73. package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/companies.csv +15 -0
  74. package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/corpus.md +83 -0
  75. package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/people.csv +25 -0
  76. package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/companies.csv +15 -0
  77. package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/corpus.md +89 -0
  78. package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/people.csv +25 -0
  79. package/data/harnesses/code/skills/design/data/elevation/ant-design-directional-shadow.md +19 -0
  80. package/data/harnesses/code/skills/design/data/elevation/apple-liquid-glass-material.md +18 -0
  81. package/data/harnesses/code/skills/design/data/elevation/atlassian-surface-shadow-pairing.md +20 -0
  82. package/data/harnesses/code/skills/design/data/elevation/fluent-2-key-ambient-ramp.md +20 -0
  83. package/data/harnesses/code/skills/design/data/elevation/github-primer-sparing-shadow.md +19 -0
  84. package/data/harnesses/code/skills/design/data/elevation/ibm-carbon-layer-and-border.md +19 -0
  85. package/data/harnesses/code/skills/design/data/elevation/linear-dark-surface-ladder.md +17 -0
  86. package/data/harnesses/code/skills/design/data/elevation/material-2-key-ambient-dp-ramp.md +19 -0
  87. package/data/harnesses/code/skills/design/data/elevation/material-3-tonal-elevation.md +21 -0
  88. package/data/harnesses/code/skills/design/data/elevation/neobrutalist-hard-offset.md +19 -0
  89. package/data/harnesses/code/skills/design/data/elevation/neumorphic-soft-dual-shadow.md +18 -0
  90. package/data/harnesses/code/skills/design/data/elevation/notion-warm-minimal-hairline.md +17 -0
  91. package/data/harnesses/code/skills/design/data/elevation/polaris-elevation-inset-bevel.md +21 -0
  92. package/data/harnesses/code/skills/design/data/elevation/radix-themes-alpha-ring-scale.md +19 -0
  93. package/data/harnesses/code/skills/design/data/elevation/shadcn-neutral-derived-radius.md +19 -0
  94. package/data/harnesses/code/skills/design/data/elevation/stripe-brand-tinted-dual-shadow.md +18 -0
  95. package/data/harnesses/code/skills/design/data/elevation/tailwind-default-utility-scale.md +19 -0
  96. package/data/harnesses/code/skills/design/data/elevation/vercel-geist-shadow-as-border.md +20 -0
  97. package/data/harnesses/code/skills/design/data/gradients/amber-attention-fill.md +16 -0
  98. package/data/harnesses/code/skills/design/data/gradients/cloud-shadow-wash.md +16 -0
  99. package/data/harnesses/code/skills/design/data/gradients/confident-lavender-wash.md +16 -0
  100. package/data/harnesses/code/skills/design/data/gradients/ember-ship-flare.md +18 -0
  101. package/data/harnesses/code/skills/design/data/gradients/full-metal-wash.md +16 -0
  102. package/data/harnesses/code/skills/design/data/gradients/indigo-ruby-cta-band.md +18 -0
  103. package/data/harnesses/code/skills/design/data/gradients/linear-graphite-wash.md +18 -0
  104. package/data/harnesses/code/skills/design/data/gradients/marble-quartz-wash.md +16 -0
  105. package/data/harnesses/code/skills/design/data/gradients/midnight-aurora-panel.md +16 -0
  106. package/data/harnesses/code/skills/design/data/gradients/neutral-volume-fill.md +16 -0
  107. package/data/harnesses/code/skills/design/data/gradients/revenue-uptrend-fill.md +16 -0
  108. package/data/harnesses/code/skills/design/data/gradients/risk-decline-fill.md +16 -0
  109. package/data/harnesses/code/skills/design/data/gradients/signal-blue-develop.md +18 -0
  110. package/data/harnesses/code/skills/design/data/gradients/slate-mist-wash.md +16 -0
  111. package/data/harnesses/code/skills/design/data/gradients/stripe-atmosphere-mesh.md +18 -0
  112. package/data/harnesses/code/skills/design/data/gradients/teal-signal-accent.md +16 -0
  113. package/data/harnesses/code/skills/design/data/gradients/violet-magenta-promo.md +16 -0
  114. package/data/harnesses/code/skills/design/data/iconography.md +199 -0
  115. package/data/harnesses/code/skills/design/data/motion/accordion-expand.md +18 -0
  116. package/data/harnesses/code/skills/design/data/motion/destructive-hold-confirm.md +18 -0
  117. package/data/harnesses/code/skills/design/data/motion/drag-dismiss-momentum.md +18 -0
  118. package/data/harnesses/code/skills/design/data/motion/empty-state-arrive.md +18 -0
  119. package/data/harnesses/code/skills/design/data/motion/hover-lift.md +18 -0
  120. package/data/harnesses/code/skills/design/data/motion/modal-center-arrive.md +18 -0
  121. package/data/harnesses/code/skills/design/data/motion/number-ticker-roll.md +18 -0
  122. package/data/harnesses/code/skills/design/data/motion/onboarding-bounce.md +18 -0
  123. package/data/harnesses/code/skills/design/data/motion/panel-slide.md +18 -0
  124. package/data/harnesses/code/skills/design/data/motion/press-feedback.md +18 -0
  125. package/data/harnesses/code/skills/design/data/motion/progress-linear-loop.md +18 -0
  126. package/data/harnesses/code/skills/design/data/motion/route-crossfade.md +18 -0
  127. package/data/harnesses/code/skills/design/data/motion/rubber-band-overscroll.md +18 -0
  128. package/data/harnesses/code/skills/design/data/motion/skeleton-shimmer.md +18 -0
  129. package/data/harnesses/code/skills/design/data/motion/stagger-arrive.md +18 -0
  130. package/data/harnesses/code/skills/design/data/motion/toast-enter-stack.md +18 -0
  131. package/data/harnesses/code/skills/design/data/motion/tooltip-chain-instant.md +18 -0
  132. package/data/harnesses/code/skills/design/data/motion/trigger-anchored-reveal.md +18 -0
  133. package/data/harnesses/code/skills/design/data/tells.csv +34 -0
  134. package/data/harnesses/code/skills/design/data/typography/anton-work-sans.md +17 -0
  135. package/data/harnesses/code/skills/design/data/typography/archivo-black-archivo.md +17 -0
  136. package/data/harnesses/code/skills/design/data/typography/bitter-karla.md +17 -0
  137. package/data/harnesses/code/skills/design/data/typography/dm-serif-dm-sans.md +17 -0
  138. package/data/harnesses/code/skills/design/data/typography/fraunces-inter.md +17 -0
  139. package/data/harnesses/code/skills/design/data/typography/geist-geist-mono.md +17 -0
  140. package/data/harnesses/code/skills/design/data/typography/hubot-sans-mona-sans.md +17 -0
  141. package/data/harnesses/code/skills/design/data/typography/ibm-plex-sans-operator-single-family.md +17 -0
  142. package/data/harnesses/code/skills/design/data/typography/instrument-serif-instrument-sans.md +17 -0
  143. package/data/harnesses/code/skills/design/data/typography/inter-operator-single-family.md +17 -0
  144. package/data/harnesses/code/skills/design/data/typography/libre-baskerville-libre-franklin.md +17 -0
  145. package/data/harnesses/code/skills/design/data/typography/newsreader-inter.md +17 -0
  146. package/data/harnesses/code/skills/design/data/typography/playfair-display-source-sans.md +17 -0
  147. package/data/harnesses/code/skills/design/data/typography/public-sans-operator-single-family.md +17 -0
  148. package/data/harnesses/code/skills/design/data/typography/sohne-inter-fintech.md +17 -0
  149. package/data/harnesses/code/skills/design/data/typography/source-serif-source-sans.md +17 -0
  150. package/data/harnesses/code/skills/design/data/typography/space-grotesk-work-sans-space-mono.md +17 -0
  151. package/data/harnesses/code/skills/design/data/typography/spectral-manrope.md +17 -0
  152. package/data/harnesses/code/skills/design/data/voices/bright-collaborator.md +29 -0
  153. package/data/harnesses/code/skills/design/data/voices/direct-operator.md +29 -0
  154. package/data/harnesses/code/skills/design/data/voices/earnest-helper.md +29 -0
  155. package/data/harnesses/code/skills/design/data/voices/editorial-composed.md +29 -0
  156. package/data/harnesses/code/skills/design/data/voices/quiet-concierge.md +29 -0
  157. package/data/harnesses/code/skills/design/data/voices/warm-guide.md +29 -0
  158. package/data/harnesses/code/skills/design/design-md/SCHEMA.md +179 -0
  159. package/data/harnesses/code/skills/design/design-md/index.csv +67 -0
  160. package/data/harnesses/code/skills/design/design-md/library/airbnb.md +207 -0
  161. package/data/harnesses/code/skills/design/design-md/library/airtable.md +205 -0
  162. package/data/harnesses/code/skills/design/design-md/library/anthropic-claude.md +203 -0
  163. package/data/harnesses/code/skills/design/design-md/library/apple.md +206 -0
  164. package/data/harnesses/code/skills/design/design-md/library/binance.md +210 -0
  165. package/data/harnesses/code/skills/design/design-md/library/bmw.md +210 -0
  166. package/data/harnesses/code/skills/design/design-md/library/cal.md +209 -0
  167. package/data/harnesses/code/skills/design/design-md/library/clay.md +204 -0
  168. package/data/harnesses/code/skills/design/design-md/library/clickhouse.md +205 -0
  169. package/data/harnesses/code/skills/design/design-md/library/cohere.md +205 -0
  170. package/data/harnesses/code/skills/design/design-md/library/coinbase.md +198 -0
  171. package/data/harnesses/code/skills/design/design-md/library/composio.md +198 -0
  172. package/data/harnesses/code/skills/design/design-md/library/cursor.md +197 -0
  173. package/data/harnesses/code/skills/design/design-md/library/elevenlabs.md +199 -0
  174. package/data/harnesses/code/skills/design/design-md/library/expo.md +200 -0
  175. package/data/harnesses/code/skills/design/design-md/library/figma.md +199 -0
  176. package/data/harnesses/code/skills/design/design-md/library/framer.md +202 -0
  177. package/data/harnesses/code/skills/design/design-md/library/hashicorp.md +205 -0
  178. package/data/harnesses/code/skills/design/design-md/library/ibm.md +205 -0
  179. package/data/harnesses/code/skills/design/design-md/library/intercom.md +204 -0
  180. package/data/harnesses/code/skills/design/design-md/library/kraken.md +200 -0
  181. package/data/harnesses/code/skills/design/design-md/library/linear-app.md +198 -0
  182. package/data/harnesses/code/skills/design/design-md/library/lovable.md +199 -0
  183. package/data/harnesses/code/skills/design/design-md/library/meta.md +204 -0
  184. package/data/harnesses/code/skills/design/design-md/library/minimax.md +204 -0
  185. package/data/harnesses/code/skills/design/design-md/library/mintlify.md +210 -0
  186. package/data/harnesses/code/skills/design/design-md/library/miro.md +209 -0
  187. package/data/harnesses/code/skills/design/design-md/library/mistral-ai.md +201 -0
  188. package/data/harnesses/code/skills/design/design-md/library/mongodb.md +201 -0
  189. package/data/harnesses/code/skills/design/design-md/library/notion.md +204 -0
  190. package/data/harnesses/code/skills/design/design-md/library/nvidia.md +215 -0
  191. package/data/harnesses/code/skills/design/design-md/library/ollama.md +213 -0
  192. package/data/harnesses/code/skills/design/design-md/library/opencode-ai.md +216 -0
  193. package/data/harnesses/code/skills/design/design-md/library/posthog.md +218 -0
  194. package/data/harnesses/code/skills/design/design-md/library/raycast.md +214 -0
  195. package/data/harnesses/code/skills/design/design-md/library/replicate.md +202 -0
  196. package/data/harnesses/code/skills/design/design-md/library/resend.md +203 -0
  197. package/data/harnesses/code/skills/design/design-md/library/revolut.md +203 -0
  198. package/data/harnesses/code/skills/design/design-md/library/runwayml.md +203 -0
  199. package/data/harnesses/code/skills/design/design-md/library/sanity.md +200 -0
  200. package/data/harnesses/code/skills/design/design-md/library/sentry.md +201 -0
  201. package/data/harnesses/code/skills/design/design-md/library/shopify.md +202 -0
  202. package/data/harnesses/code/skills/design/design-md/library/slack.md +202 -0
  203. package/data/harnesses/code/skills/design/design-md/library/spacex.md +206 -0
  204. package/data/harnesses/code/skills/design/design-md/library/spotify.md +206 -0
  205. package/data/harnesses/code/skills/design/design-md/library/stripe.md +196 -0
  206. package/data/harnesses/code/skills/design/design-md/library/supabase.md +196 -0
  207. package/data/harnesses/code/skills/design/design-md/library/superhuman.md +194 -0
  208. package/data/harnesses/code/skills/design/design-md/library/tesla.md +198 -0
  209. package/data/harnesses/code/skills/design/design-md/library/theverge.md +199 -0
  210. package/data/harnesses/code/skills/design/design-md/library/together-ai.md +193 -0
  211. package/data/harnesses/code/skills/design/design-md/library/uber.md +195 -0
  212. package/data/harnesses/code/skills/design/design-md/library/vercel.md +195 -0
  213. package/data/harnesses/code/skills/design/design-md/library/voltagent.md +197 -0
  214. package/data/harnesses/code/skills/design/design-md/library/warp.md +196 -0
  215. package/data/harnesses/code/skills/design/design-md/library/webflow.md +197 -0
  216. package/data/harnesses/code/skills/design/design-md/library/wired.md +197 -0
  217. package/data/harnesses/code/skills/design/design-md/library/wise.md +198 -0
  218. package/data/harnesses/code/skills/design/design-md/library/x-ai.md +199 -0
  219. package/data/harnesses/code/skills/design/design-md/library/zapier.md +198 -0
  220. package/data/harnesses/code/skills/design/design-md/nurix.md +214 -0
  221. package/data/harnesses/code/skills/design/design-md/variants/editorial-luxury.md +184 -0
  222. package/data/harnesses/code/skills/design/design-md/variants/expressive-saas.md +216 -0
  223. package/data/harnesses/code/skills/design/design-md/variants/quiet-premium.md +211 -0
  224. package/data/harnesses/code/skills/design/design-md/variants/terse-dense-operator.md +212 -0
  225. package/data/harnesses/code/skills/design/design-md/variants/warm-approachable.md +216 -0
  226. package/data/harnesses/code/skills/design/references/compose.md +23 -0
  227. package/data/harnesses/code/skills/design/references/content.md +28 -0
  228. package/data/harnesses/code/skills/design/references/emission.md +21 -0
  229. package/data/harnesses/code/skills/design/references/existing-apps.md +27 -0
  230. package/data/harnesses/code/skills/design/references/intake.md +36 -0
  231. package/data/harnesses/code/skills/design/references/object-pass.md +24 -0
  232. package/data/harnesses/code/skills/design/references/ship-gate.md +29 -0
  233. package/data/harnesses/code/skills/design/references/ux-patterns/Readme.md +195 -0
  234. package/data/harnesses/code/skills/design/references/ux-patterns/ai-layer.md +49 -0
  235. package/data/harnesses/code/skills/design/references/ux-patterns/attributes-lifecycle.md +43 -0
  236. package/data/harnesses/code/skills/design/references/ux-patterns/container-choice.md +44 -0
  237. package/data/harnesses/code/skills/design/references/ux-patterns/creation-paths.md +46 -0
  238. package/data/harnesses/code/skills/design/references/ux-patterns/dashboards.md +42 -0
  239. package/data/harnesses/code/skills/design/references/ux-patterns/modes.md +42 -0
  240. package/data/harnesses/code/skills/design/references/ux-patterns/object-model.md +46 -0
  241. package/data/harnesses/code/skills/design/references/ux-patterns/page-archetype.md +48 -0
  242. package/data/harnesses/code/skills/design/references/ux-patterns/promotion-demotion.md +37 -0
  243. package/data/harnesses/code/skills/design/references/ux-patterns/settings.md +42 -0
  244. package/data/harnesses/code/skills/design/references/ux-patterns/standard-pages.md +46 -0
  245. package/data/harnesses/code/skills/design/references/ux-patterns/state-matrix.md +41 -0
  246. package/data/harnesses/code/skills/design/references/ux-patterns/table-mechanics.md +48 -0
  247. package/data/harnesses/code/skills/design/references/ux-patterns/verbs.md +45 -0
  248. package/data/harnesses/code/skills/design/references/ux-patterns/viewer-context.md +40 -0
  249. package/data/harnesses/code/skills/design/scripts/README-validator.md +27 -0
  250. package/data/harnesses/code/skills/design/scripts/select-chart.mjs +596 -0
  251. package/data/harnesses/code/skills/design/scripts/validate-design-md.mjs +1198 -0
  252. package/data/harnesses/discussion/CLAUDE.md +1 -1
  253. package/data/harnesses/discussion/agents/discussion-baseline.md +27 -2
  254. package/data/harnesses/discussion/harness.json +2 -2
  255. package/data/harnesses/discussion/rules/artifacts.md +2 -0
  256. package/data/harnesses/discussion/rules/method.md +5 -1
  257. package/package.json +1 -1
  258. package/data/harnesses/code/skills/design/data/catalog/rules.csv +0 -137
  259. package/data/harnesses/code/skills/design/data/combinations/Readme.md +0 -33
  260. package/data/harnesses/code/skills/design/data/combinations/accent-presets.md +0 -113
  261. package/data/harnesses/code/skills/design/data/combinations/charts.csv +0 -33
  262. package/data/harnesses/code/skills/design/data/combinations/fonts-known.json +0 -448
  263. package/data/harnesses/code/skills/design/data/combinations/icons.csv +0 -157
  264. package/data/harnesses/code/skills/design/data/combinations/landing.csv +0 -38
  265. package/data/harnesses/code/skills/design/data/combinations/lucide-names.json +0 -2001
  266. package/data/harnesses/code/skills/design/data/combinations/manifest.json +0 -330
  267. package/data/harnesses/code/skills/design/data/combinations/motion.csv +0 -10
  268. package/data/harnesses/code/skills/design/data/combinations/palettes.csv +0 -92
  269. package/data/harnesses/code/skills/design/data/combinations/product-router.csv +0 -80
  270. package/data/harnesses/code/skills/design/data/combinations/styles.csv +0 -67
  271. package/data/harnesses/code/skills/design/data/combinations/typography.csv +0 -64
  272. package/data/harnesses/code/skills/design/data/design-md/SCHEMA.md +0 -106
  273. package/data/harnesses/code/skills/design/data/design-md/library/airbnb.md +0 -154
  274. package/data/harnesses/code/skills/design/data/design-md/library/airtable.md +0 -151
  275. package/data/harnesses/code/skills/design/data/design-md/library/anthropic-claude.md +0 -139
  276. package/data/harnesses/code/skills/design/data/design-md/library/apple.md +0 -139
  277. package/data/harnesses/code/skills/design/data/design-md/library/binance.md +0 -140
  278. package/data/harnesses/code/skills/design/data/design-md/library/bmw.md +0 -140
  279. package/data/harnesses/code/skills/design/data/design-md/library/cal.md +0 -140
  280. package/data/harnesses/code/skills/design/data/design-md/library/clay.md +0 -139
  281. package/data/harnesses/code/skills/design/data/design-md/library/clickhouse.md +0 -139
  282. package/data/harnesses/code/skills/design/data/design-md/library/cohere.md +0 -147
  283. package/data/harnesses/code/skills/design/data/design-md/library/coinbase.md +0 -156
  284. package/data/harnesses/code/skills/design/data/design-md/library/composio.md +0 -138
  285. package/data/harnesses/code/skills/design/data/design-md/library/cursor.md +0 -138
  286. package/data/harnesses/code/skills/design/data/design-md/library/elevenlabs.md +0 -137
  287. package/data/harnesses/code/skills/design/data/design-md/library/expo.md +0 -148
  288. package/data/harnesses/code/skills/design/data/design-md/library/figma.md +0 -141
  289. package/data/harnesses/code/skills/design/data/design-md/library/framer.md +0 -156
  290. package/data/harnesses/code/skills/design/data/design-md/library/hashicorp.md +0 -140
  291. package/data/harnesses/code/skills/design/data/design-md/library/ibm.md +0 -153
  292. package/data/harnesses/code/skills/design/data/design-md/library/intercom.md +0 -158
  293. package/data/harnesses/code/skills/design/data/design-md/library/kraken.md +0 -156
  294. package/data/harnesses/code/skills/design/data/design-md/library/linear-app.md +0 -122
  295. package/data/harnesses/code/skills/design/data/design-md/library/lovable.md +0 -140
  296. package/data/harnesses/code/skills/design/data/design-md/library/meta.md +0 -139
  297. package/data/harnesses/code/skills/design/data/design-md/library/minimax.md +0 -139
  298. package/data/harnesses/code/skills/design/data/design-md/library/mintlify.md +0 -139
  299. package/data/harnesses/code/skills/design/data/design-md/library/miro.md +0 -153
  300. package/data/harnesses/code/skills/design/data/design-md/library/mistral-ai.md +0 -140
  301. package/data/harnesses/code/skills/design/data/design-md/library/mongodb.md +0 -155
  302. package/data/harnesses/code/skills/design/data/design-md/library/notion.md +0 -140
  303. package/data/harnesses/code/skills/design/data/design-md/library/nvidia.md +0 -141
  304. package/data/harnesses/code/skills/design/data/design-md/library/ollama.md +0 -145
  305. package/data/harnesses/code/skills/design/data/design-md/library/opencode-ai.md +0 -142
  306. package/data/harnesses/code/skills/design/data/design-md/library/posthog.md +0 -152
  307. package/data/harnesses/code/skills/design/data/design-md/library/raycast.md +0 -137
  308. package/data/harnesses/code/skills/design/data/design-md/library/replicate.md +0 -140
  309. package/data/harnesses/code/skills/design/data/design-md/library/resend.md +0 -170
  310. package/data/harnesses/code/skills/design/data/design-md/library/revolut.md +0 -145
  311. package/data/harnesses/code/skills/design/data/design-md/library/runwayml.md +0 -137
  312. package/data/harnesses/code/skills/design/data/design-md/library/sanity.md +0 -168
  313. package/data/harnesses/code/skills/design/data/design-md/library/sentry.md +0 -163
  314. package/data/harnesses/code/skills/design/data/design-md/library/shopify.md +0 -147
  315. package/data/harnesses/code/skills/design/data/design-md/library/slack.md +0 -158
  316. package/data/harnesses/code/skills/design/data/design-md/library/spacex.md +0 -171
  317. package/data/harnesses/code/skills/design/data/design-md/library/spotify.md +0 -166
  318. package/data/harnesses/code/skills/design/data/design-md/library/stripe.md +0 -160
  319. package/data/harnesses/code/skills/design/data/design-md/library/supabase.md +0 -173
  320. package/data/harnesses/code/skills/design/data/design-md/library/superhuman.md +0 -145
  321. package/data/harnesses/code/skills/design/data/design-md/library/tesla.md +0 -153
  322. package/data/harnesses/code/skills/design/data/design-md/library/theverge.md +0 -167
  323. package/data/harnesses/code/skills/design/data/design-md/library/together-ai.md +0 -140
  324. package/data/harnesses/code/skills/design/data/design-md/library/uber.md +0 -140
  325. package/data/harnesses/code/skills/design/data/design-md/library/vercel.md +0 -140
  326. package/data/harnesses/code/skills/design/data/design-md/library/voltagent.md +0 -130
  327. package/data/harnesses/code/skills/design/data/design-md/library/warp.md +0 -140
  328. package/data/harnesses/code/skills/design/data/design-md/library/webflow.md +0 -140
  329. package/data/harnesses/code/skills/design/data/design-md/library/wired.md +0 -139
  330. package/data/harnesses/code/skills/design/data/design-md/library/wise.md +0 -137
  331. package/data/harnesses/code/skills/design/data/design-md/library/x-ai.md +0 -138
  332. package/data/harnesses/code/skills/design/data/design-md/library/zapier.md +0 -158
  333. package/data/harnesses/code/skills/design/data/design-md/nurix.md +0 -138
  334. package/data/harnesses/code/skills/design/data/design-tokens/SCHEMA.md +0 -695
  335. package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.resolver.json +0 -20
  336. package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.tokens.json +0 -1272
  337. package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.resolver.json +0 -20
  338. package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.tokens.json +0 -1268
  339. package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.resolver.json +0 -20
  340. package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.tokens.json +0 -1273
  341. package/data/harnesses/code/skills/design/data/design-tokens/apple/design.resolver.json +0 -20
  342. package/data/harnesses/code/skills/design/data/design-tokens/apple/design.tokens.json +0 -1262
  343. package/data/harnesses/code/skills/design/data/design-tokens/binance/design.resolver.json +0 -20
  344. package/data/harnesses/code/skills/design/data/design-tokens/binance/design.tokens.json +0 -1257
  345. package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.resolver.json +0 -20
  346. package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.tokens.json +0 -1270
  347. package/data/harnesses/code/skills/design/data/design-tokens/cal/design.resolver.json +0 -20
  348. package/data/harnesses/code/skills/design/data/design-tokens/cal/design.tokens.json +0 -1270
  349. package/data/harnesses/code/skills/design/data/design-tokens/clay/design.resolver.json +0 -20
  350. package/data/harnesses/code/skills/design/data/design-tokens/clay/design.tokens.json +0 -1261
  351. package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.resolver.json +0 -20
  352. package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.tokens.json +0 -1268
  353. package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.resolver.json +0 -20
  354. package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.tokens.json +0 -1281
  355. package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.resolver.json +0 -20
  356. package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.tokens.json +0 -1262
  357. package/data/harnesses/code/skills/design/data/design-tokens/composio/design.resolver.json +0 -20
  358. package/data/harnesses/code/skills/design/data/design-tokens/composio/design.tokens.json +0 -1271
  359. package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.resolver.json +0 -20
  360. package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.tokens.json +0 -1276
  361. package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.resolver.json +0 -20
  362. package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.tokens.json +0 -1293
  363. package/data/harnesses/code/skills/design/data/design-tokens/expo/design.resolver.json +0 -20
  364. package/data/harnesses/code/skills/design/data/design-tokens/expo/design.tokens.json +0 -1270
  365. package/data/harnesses/code/skills/design/data/design-tokens/figma/design.resolver.json +0 -20
  366. package/data/harnesses/code/skills/design/data/design-tokens/figma/design.tokens.json +0 -1276
  367. package/data/harnesses/code/skills/design/data/design-tokens/framer/design.resolver.json +0 -20
  368. package/data/harnesses/code/skills/design/data/design-tokens/framer/design.tokens.json +0 -1267
  369. package/data/harnesses/code/skills/design/data/design-tokens/goldens.json +0 -251
  370. package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.resolver.json +0 -20
  371. package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.tokens.json +0 -1273
  372. package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.resolver.json +0 -20
  373. package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.tokens.json +0 -1286
  374. package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.resolver.json +0 -20
  375. package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.tokens.json +0 -1290
  376. package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.resolver.json +0 -20
  377. package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.tokens.json +0 -1270
  378. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.resolver.json +0 -23
  379. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.dark.json +0 -599
  380. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.json +0 -1272
  381. package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.resolver.json +0 -20
  382. package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.tokens.json +0 -1267
  383. package/data/harnesses/code/skills/design/data/design-tokens/meta/design.resolver.json +0 -20
  384. package/data/harnesses/code/skills/design/data/design-tokens/meta/design.tokens.json +0 -1289
  385. package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.resolver.json +0 -20
  386. package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.tokens.json +0 -1258
  387. package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.resolver.json +0 -20
  388. package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.tokens.json +0 -1284
  389. package/data/harnesses/code/skills/design/data/design-tokens/miro/design.resolver.json +0 -20
  390. package/data/harnesses/code/skills/design/data/design-tokens/miro/design.tokens.json +0 -1291
  391. package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.resolver.json +0 -20
  392. package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.tokens.json +0 -1263
  393. package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.resolver.json +0 -20
  394. package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.tokens.json +0 -1270
  395. package/data/harnesses/code/skills/design/data/design-tokens/notion/design.resolver.json +0 -20
  396. package/data/harnesses/code/skills/design/data/design-tokens/notion/design.tokens.json +0 -1261
  397. package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.resolver.json +0 -20
  398. package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.tokens.json +0 -1209
  399. package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.resolver.json +0 -20
  400. package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.tokens.json +0 -1265
  401. package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.resolver.json +0 -20
  402. package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.tokens.json +0 -1253
  403. package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.resolver.json +0 -20
  404. package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.tokens.json +0 -1268
  405. package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.resolver.json +0 -20
  406. package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.tokens.json +0 -1261
  407. package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.resolver.json +0 -20
  408. package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.tokens.json +0 -1263
  409. package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.resolver.json +0 -20
  410. package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.tokens.json +0 -1266
  411. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.resolver.json +0 -23
  412. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.dark.json +0 -623
  413. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.json +0 -1276
  414. package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.resolver.json +0 -20
  415. package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.tokens.json +0 -1264
  416. package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.resolver.json +0 -20
  417. package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.tokens.json +0 -1268
  418. package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.resolver.json +0 -20
  419. package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.tokens.json +0 -1270
  420. package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.resolver.json +0 -20
  421. package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.tokens.json +0 -1288
  422. package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.resolver.json +0 -20
  423. package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.tokens.json +0 -1272
  424. package/data/harnesses/code/skills/design/data/design-tokens/slack/design.resolver.json +0 -20
  425. package/data/harnesses/code/skills/design/data/design-tokens/slack/design.tokens.json +0 -1265
  426. package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.resolver.json +0 -20
  427. package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.tokens.json +0 -1287
  428. package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.resolver.json +0 -20
  429. package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.tokens.json +0 -1286
  430. package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.resolver.json +0 -20
  431. package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.tokens.json +0 -1285
  432. package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.resolver.json +0 -20
  433. package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.tokens.json +0 -1287
  434. package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.resolver.json +0 -20
  435. package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.tokens.json +0 -1278
  436. package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.resolver.json +0 -20
  437. package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.tokens.json +0 -1269
  438. package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.resolver.json +0 -20
  439. package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.tokens.json +0 -1285
  440. package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.resolver.json +0 -20
  441. package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.tokens.json +0 -1303
  442. package/data/harnesses/code/skills/design/data/design-tokens/uber/design.resolver.json +0 -20
  443. package/data/harnesses/code/skills/design/data/design-tokens/uber/design.tokens.json +0 -1274
  444. package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.resolver.json +0 -20
  445. package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.tokens.json +0 -1296
  446. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.resolver.json +0 -23
  447. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.dark.json +0 -612
  448. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.json +0 -1282
  449. package/data/harnesses/code/skills/design/data/design-tokens/warp/design.resolver.json +0 -20
  450. package/data/harnesses/code/skills/design/data/design-tokens/warp/design.tokens.json +0 -1287
  451. package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.resolver.json +0 -20
  452. package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.tokens.json +0 -1268
  453. package/data/harnesses/code/skills/design/data/design-tokens/wired/design.resolver.json +0 -20
  454. package/data/harnesses/code/skills/design/data/design-tokens/wired/design.tokens.json +0 -1276
  455. package/data/harnesses/code/skills/design/data/design-tokens/wise/design.resolver.json +0 -20
  456. package/data/harnesses/code/skills/design/data/design-tokens/wise/design.tokens.json +0 -1273
  457. package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.resolver.json +0 -20
  458. package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.tokens.json +0 -1296
  459. package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.resolver.json +0 -20
  460. package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.tokens.json +0 -1286
  461. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/command-center.tsx +0 -249
  462. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/create-edit.tsx +0 -249
  463. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/dashboard.tsx +0 -225
  464. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/entity-detail.tsx +0 -249
  465. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/list-detail.tsx +0 -224
  466. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/log-stream.tsx +0 -249
  467. package/data/harnesses/code/skills/design/data/operator-pack/fixtures.md +0 -88
  468. package/data/harnesses/code/skills/design/data/operator-pack/surface-catalog.md +0 -132
  469. package/data/harnesses/code/skills/design/data/operator-pack/trust-rubric.md +0 -76
  470. package/data/harnesses/code/skills/design/references/create.md +0 -173
  471. package/data/harnesses/code/skills/design/references/diagnosis.md +0 -108
  472. package/data/harnesses/code/skills/design/references/hard-rules.md +0 -177
  473. package/data/harnesses/code/skills/design/references/improve.md +0 -116
  474. package/data/harnesses/code/skills/design/references/interaction.md +0 -77
  475. package/data/harnesses/code/skills/design/references/introspect.md +0 -100
  476. package/data/harnesses/code/skills/design/references/lifecycle.md +0 -73
  477. package/data/harnesses/code/skills/design/references/personality.md +0 -575
  478. package/data/harnesses/code/skills/design/references/structure.md +0 -159
  479. package/data/harnesses/code/skills/design/scripts/convert-design-md.mjs +0 -1312
  480. package/data/harnesses/code/skills/design/scripts/derive-personality.mjs +0 -1498
  481. package/data/harnesses/code/skills/design/scripts/generate-fixtures.mjs +0 -551
  482. package/data/harnesses/code/skills/design/scripts/lib/checks.mjs +0 -1092
  483. package/data/harnesses/code/skills/design/scripts/lib/golden.mjs +0 -26
  484. package/data/harnesses/code/skills/design/scripts/lib/vocabulary.mjs +0 -65
  485. package/data/harnesses/code/skills/design/scripts/phase-gate.mjs +0 -538
  486. package/data/harnesses/code/skills/design/scripts/preship-sweep.mjs +0 -312
  487. package/data/harnesses/code/skills/design/scripts/render-rung.mjs +0 -890
  488. package/data/harnesses/code/skills/design/scripts/scaffold.mjs +0 -769
  489. package/data/harnesses/code/skills/design/scripts/self-integrity.mjs +0 -675
  490. package/data/harnesses/code/skills/design/scripts/snapshot-goldens.mjs +0 -164
  491. package/data/harnesses/code/skills/design/scripts/validate-combinations.mjs +0 -439
@@ -1,675 +0,0 @@
1
- // skills/design/scripts/self-integrity.mjs — the design skill's own CI check: anchor parity (rule ids and the doctrine-floor f-ids), catalog invariants, stated-count and fixture-pair validation (pairs exercised through lib/checks.mjs), the token-era net — token file-tree + goldens parity, per-artifact --check validity, and (behind --goldens) golden emission hash match — plus combination-data validation (validate-combinations.mjs); --fixture <rule-id> runs a single pair
2
- import { readFileSync, existsSync, readdirSync, mkdtempSync, rmSync } from "node:fs";
3
- import { join, dirname, resolve } from "node:path";
4
- import { tmpdir } from "node:os";
5
- import { spawn } from "node:child_process";
6
- import { fileURLToPath } from "node:url";
7
- import { runChecks } from "./lib/checks.mjs";
8
- import { goldenHash } from "./lib/golden.mjs";
9
- import { validateCombinations } from "./validate-combinations.mjs";
10
-
11
- const SCRIPTS_DIR = dirname(fileURLToPath(import.meta.url));
12
- const SKILL_ROOT = join(SCRIPTS_DIR, "..");
13
-
14
- const CATALOG_CSV = join(SKILL_ROOT, "data/catalog/rules.csv");
15
- const FIXTURES_DIR = join(SKILL_ROOT, "data/catalog/fixtures");
16
- const HARD_RULES_MD = join(SKILL_ROOT, "references/hard-rules.md");
17
- const TOKENS_DIR = join(SKILL_ROOT, "data/design-tokens");
18
- const COMBINATIONS_DIR = join(SKILL_ROOT, "data/combinations");
19
- const GOLDENS_JSON = join(TOKENS_DIR, "goldens.json");
20
- const DERIVE_PERSONALITY = join(SCRIPTS_DIR, "derive-personality.mjs");
21
- const SPAWN_LIMIT = 8;
22
-
23
- const CSV_HEADER = ["id", "dimension", "statement", "numbers", "grade", "fire_points", "detector", "scope_note", "provenance", "fixture_pair"];
24
- const VALID_DIMENSIONS = new Set(["P1", "P2", "P3", "P4", "P5", "P6", "P7", "S1", "S2", "S3", "S4", "B1", "B2", "B3", "B4", "B5"]);
25
- const ANCHOR_PREFIXES = "typ|col|spc|dep|int|mot|sta|cod|proc|inst|trust";
26
- const ANCHOR_TOKEN = new RegExp("`(" + ANCHOR_PREFIXES + ")-(\\d{2})`", "g");
27
- const ANCHOR_ID = "(?:" + ANCHOR_PREFIXES + ")-\\d{2}";
28
-
29
- const PINNED = { rows: 136, source: 70, render: 12, archetypes: 6, primitives: 27, colorTokens: 36, semanticTokens: 19, substrateTokens: 17, rampSteps: 7, elevation: 4 };
30
-
31
- // The doctrine floor's canonical ids (f01-f12) — enumerated once in hard-rules.md's Doctrine floor
32
- // section; every in-skill floor citation must name one of these (05-rule-amendments.md, the mapping).
33
- const FLOOR_IDS = Array.from({ length: 12 }, (_, i) => "f" + String(i + 1).padStart(2, "0"));
34
-
35
- // Read a UTF-8 file, returning null when it does not exist.
36
- function readSafe(path) {
37
- return existsSync(path) ? readFileSync(path, "utf8") : null;
38
- }
39
-
40
- // Parse RFC4180-style CSV text into an array of field arrays (quotes + doubled-quote escapes honored).
41
- function parseCsv(text) {
42
- const rows = [];
43
- let field = "";
44
- let record = [];
45
- let inQuotes = false;
46
- for (let i = 0; i < text.length; i++) {
47
- const ch = text[i];
48
- if (inQuotes) {
49
- if (ch === '"') {
50
- if (text[i + 1] === '"') { field += '"'; i++; }
51
- else inQuotes = false;
52
- } else field += ch;
53
- } else if (ch === '"') inQuotes = true;
54
- else if (ch === ",") { record.push(field); field = ""; }
55
- else if (ch === "\n") { record.push(field); rows.push(record); record = []; field = ""; }
56
- else if (ch === "\r") { /* skip */ }
57
- else field += ch;
58
- }
59
- if (field.length > 0 || record.length > 0) { record.push(field); rows.push(record); }
60
- return rows;
61
- }
62
-
63
- // Split a rule id into its {prefix, num} parts, or null when it is not a well-formed anchor id.
64
- function splitId(id) {
65
- const m = /^([a-z]+)-(\d{2})$/.exec(id);
66
- return m ? { prefix: m[1], num: parseInt(m[2], 10) } : null;
67
- }
68
-
69
- // Strip leading whitespace and a single markdown list marker from a line.
70
- function stripListMarker(line) {
71
- return line.replace(/^\s*/, "").replace(/^[-*+]\s+/, "");
72
- }
73
-
74
- // Load and index the rule catalog into typed row objects plus derived counts.
75
- function loadCatalog() {
76
- const text = readSafe(CATALOG_CSV);
77
- if (text === null) throw new Error("rules.csv not found at " + CATALOG_CSV);
78
- const raw = parseCsv(text).filter((r) => r.length > 1 || (r.length === 1 && r[0].trim() !== ""));
79
- const header = raw[0];
80
- const dataRows = raw.slice(1).map((cells) => {
81
- const obj = {};
82
- CSV_HEADER.forEach((k, idx) => { obj[k] = cells[idx] !== undefined ? cells[idx] : ""; });
83
- obj._cells = cells;
84
- return obj;
85
- });
86
- return { header, rows: dataRows };
87
- }
88
-
89
- // ── Check 1: rules.csv is well-formed ──────────────────────────────────────────
90
- function checkCsvWellFormed(catalog) {
91
- const errors = [];
92
- const { header, rows } = catalog;
93
-
94
- if (header.length !== CSV_HEADER.length || CSV_HEADER.some((h, i) => header[i] !== h))
95
- errors.push(`header mismatch: expected [${CSV_HEADER.join(",")}] got [${header.join(",")}]`);
96
-
97
- const seen = new Map();
98
- const byPrefix = new Map();
99
- for (const row of rows) {
100
- if (row._cells.length !== CSV_HEADER.length)
101
- errors.push(`${row.id || "?"}: has ${row._cells.length} columns, expected ${CSV_HEADER.length}`);
102
-
103
- const parts = splitId(row.id);
104
- if (!parts) { errors.push(`malformed id "${row.id}" (want <prefix>-NN)`); }
105
- else {
106
- if (seen.has(row.id)) errors.push(`duplicate id ${row.id}`);
107
- seen.set(row.id, true);
108
- if (!byPrefix.has(parts.prefix)) byPrefix.set(parts.prefix, []);
109
- byPrefix.get(parts.prefix).push(parts.num);
110
- }
111
-
112
- if (!VALID_DIMENSIONS.has(row.dimension))
113
- errors.push(`${row.id}: invalid dimension "${row.dimension}"`);
114
-
115
- // grade/detector/fixture_pair invariants
116
- if (row.detector === "source" && row.fixture_pair !== "yes")
117
- errors.push(`${row.id}: detector=source must have fixture_pair=yes (got "${row.fixture_pair}")`);
118
- if (row.grade === "judged" && !(row.detector === "none" || row.detector === "render"))
119
- errors.push(`${row.id}: grade=judged must have detector none|render (got "${row.detector}")`);
120
- if (row.grade === "procedure" && row.detector !== "procedure")
121
- errors.push(`${row.id}: grade=procedure must have detector=procedure (got "${row.detector}")`);
122
- if (!["machine", "judged", "procedure"].includes(row.grade))
123
- errors.push(`${row.id}: invalid grade "${row.grade}"`);
124
- if (!["source", "render", "procedure", "none"].includes(row.detector))
125
- errors.push(`${row.id}: invalid detector "${row.detector}"`);
126
- if (!["yes", "na"].includes(row.fixture_pair))
127
- errors.push(`${row.id}: invalid fixture_pair "${row.fixture_pair}"`);
128
- }
129
-
130
- // Contiguous numbering per prefix: 1..N with no gaps, no duplicates.
131
- for (const [prefix, nums] of byPrefix) {
132
- const sorted = [...nums].sort((a, b) => a - b);
133
- for (let i = 0; i < sorted.length; i++) {
134
- if (sorted[i] !== i + 1) {
135
- errors.push(`${prefix}-* numbering not contiguous: expected ${i + 1} at position ${i}, got ${sorted[i]} (full: ${sorted.join(",")})`);
136
- break;
137
- }
138
- }
139
- }
140
-
141
- return { name: "rules.csv well-formed", pass: errors.length === 0, detail: errors.length ? `${errors.length} issue(s)` : `${rows.length} rows, ${byPrefix.size} prefixes`, errors };
142
- }
143
-
144
- // ── Check 2: anchor parity between rules.csv and hard-rules.md ──────────────────
145
- function checkAnchorParity(catalog) {
146
- const errors = [];
147
- const md = readSafe(HARD_RULES_MD);
148
- if (md === null) return { name: "anchor parity (prose<->catalog)", pass: false, detail: "hard-rules.md missing", errors: ["hard-rules.md not found at " + HARD_RULES_MD] };
149
-
150
- const lines = md.split("\n");
151
- const defCounts = new Map(); // id -> { main, judged }
152
- const rangeCovered = new Set();
153
- const allBacktickIds = new Set();
154
- const judgedHeader = /^##\s+judged dimensions/i;
155
- let inJudged = false;
156
-
157
- const bump = (id, section) => {
158
- if (!defCounts.has(id)) defCounts.set(id, { main: 0, judged: 0 });
159
- defCounts.get(id)[section]++;
160
- };
161
-
162
- for (const line of lines) {
163
- if (judgedHeader.test(line.trim())) inJudged = true;
164
-
165
- let m;
166
- ANCHOR_TOKEN.lastIndex = 0;
167
- while ((m = ANCHOR_TOKEN.exec(line)) !== null) allBacktickIds.add(`${m[1]}-${m[2]}`);
168
-
169
- const body = stripListMarker(line);
170
- const rangeMatch = new RegExp("^`(" + ANCHOR_ID + ")`\\s*[\\u2013\\u2014-]\\s*`(" + ANCHOR_ID + ")`").exec(body);
171
- const defMatch = new RegExp("^`(" + ANCHOR_ID + ")`").exec(body);
172
-
173
- if (rangeMatch) {
174
- const a = splitId(rangeMatch[1]);
175
- const b = splitId(rangeMatch[2]);
176
- if (a && b && a.prefix === b.prefix) for (let n = a.num; n <= b.num; n++) rangeCovered.add(`${a.prefix}-${String(n).padStart(2, "0")}`);
177
- }
178
- if (defMatch) bump(defMatch[1], inJudged ? "judged" : "main");
179
- }
180
-
181
- const csvIds = new Set(catalog.rows.map((r) => r.id));
182
- const proseCovered = new Set([...rangeCovered, ...defCounts.keys()]);
183
-
184
- // No prose anchor without a csv row.
185
- for (const id of allBacktickIds)
186
- if (!csvIds.has(id)) errors.push(`prose anchor ${id} has no rules.csv row`);
187
-
188
- for (const row of catalog.rows) {
189
- const c = defCounts.get(row.id) || { main: 0, judged: 0 };
190
- const total = c.main + c.judged;
191
- const isInstTrust = row.id.startsWith("inst-") || row.id.startsWith("trust-");
192
-
193
- if (row.grade === "machine" || row.grade === "procedure") {
194
- if (c.main === 1 && c.judged === 0) { /* ok */ }
195
- else if (total === 0) errors.push(`${row.grade} rule ${row.id} has no backticked definition line in hard-rules.md`);
196
- else if (total > 1) errors.push(`${row.id} defined ${total} times (want exactly 1)`);
197
- else if (c.judged > 0) errors.push(`${row.grade} rule ${row.id} is defined inside the Judged dimensions section`);
198
- } else if (row.grade === "judged" && isInstTrust) {
199
- if (!rangeCovered.has(row.id) && total === 0)
200
- errors.push(`judged range rule ${row.id} not covered by a range pointer line`);
201
- } else if (row.grade === "judged") {
202
- if (c.judged === 1 && c.main === 0) { /* ok */ }
203
- else if (total === 0) errors.push(`judged rule ${row.id} missing from the Judged dimensions index`);
204
- else if (c.main > 0) errors.push(`judged rule ${row.id} defined outside the Judged dimensions section`);
205
- else if (c.judged > 1) errors.push(`judged rule ${row.id} indexed ${c.judged} times (want exactly 1)`);
206
- }
207
-
208
- if (!proseCovered.has(row.id)) errors.push(`rules.csv row ${row.id} has no prose coverage`);
209
- }
210
-
211
- // The two collapsed range pointers must be present and complete.
212
- for (let n = 1; n <= 11; n++) if (!rangeCovered.has(`inst-${String(n).padStart(2, "0")}`)) errors.push(`inst-${String(n).padStart(2, "0")} not covered by the inst range pointer`);
213
- for (let n = 1; n <= 4; n++) if (!rangeCovered.has(`trust-0${n}`)) errors.push(`trust-0${n} not covered by the trust range pointer`);
214
-
215
- const defTotal = [...defCounts.keys()].length;
216
- return { name: "anchor parity (prose<->catalog)", pass: errors.length === 0, detail: errors.length ? `${errors.length} parity break(s)` : `${defTotal} definitions, ${rangeCovered.size} range-covered, all ${catalog.rows.length} rows covered`, errors };
217
- }
218
-
219
- // ── Check 3: every fixture_pair=yes rule ships a flag + pass fixture ────────────
220
- function checkFixturePresence(catalog) {
221
- const errors = [];
222
- const files = existsSync(FIXTURES_DIR) ? readdirSync(FIXTURES_DIR) : null;
223
- if (files === null) {
224
- const needed = catalog.rows.filter((r) => r.fixture_pair === "yes");
225
- return { name: "fixture-pair presence", pass: false, detail: `fixtures dir missing; ${needed.length} pairs needed`, errors: ["data/catalog/fixtures/ does not exist"] };
226
- }
227
- const present = new Set(files);
228
- const hasKind = (id, kind) => [...present].some((f) => f.startsWith(`${id}.${kind}.`));
229
- let ok = 0;
230
- for (const row of catalog.rows) {
231
- if (row.fixture_pair !== "yes") continue;
232
- const hasFlag = hasKind(row.id, "flag");
233
- const hasPass = hasKind(row.id, "pass");
234
- if (!hasFlag) errors.push(`${row.id}: missing ${row.id}.flag.*`);
235
- if (!hasPass) errors.push(`${row.id}: missing ${row.id}.pass.*`);
236
- if (hasFlag && hasPass) ok++;
237
- }
238
- const total = catalog.rows.filter((r) => r.fixture_pair === "yes").length;
239
- return { name: "fixture-pair presence", pass: errors.length === 0, detail: `${ok}/${total} pairs present`, errors };
240
- }
241
-
242
- // Run the check engine (lib/checks.mjs) on one fixture file and return the set of anchor ids it reports.
243
- function runEngine(file) {
244
- // Scan the leading comment block for a `// detector-args:` directive (the mandatory file-path
245
- // comment occupies line 1, so the directive cannot be line 0). Relative paths in it (e.g. a
246
- // --manifest sibling) resolve against FIXTURES_DIR, matching each fixture's documented verify command.
247
- let extra = [];
248
- for (const line of (readSafe(file) || "").split("\n")) {
249
- const t = line.trim();
250
- if (t !== "" && !t.startsWith("//")) break;
251
- const argMatch = /^\/\/\s*detector-args:\s*(.+)$/.exec(t);
252
- if (argMatch) { extra = argMatch[1].trim().split(/\s+/); break; }
253
- }
254
- let manifestPath = null;
255
- const extraFiles = [];
256
- for (let i = 0; i < extra.length; i++) {
257
- const a = extra[i];
258
- if (a === "--manifest") manifestPath = resolve(FIXTURES_DIR, extra[++i] || "");
259
- else if (a.startsWith("--manifest=")) manifestPath = resolve(FIXTURES_DIR, a.slice("--manifest=".length));
260
- else if (!a.startsWith("--")) extraFiles.push(resolve(FIXTURES_DIR, a));
261
- }
262
- try {
263
- const findings = runChecks([file, ...extraFiles], { manifestPath });
264
- return { ids: new Set(findings.map((f) => f.rule)) };
265
- } catch (e) {
266
- return { ids: new Set(), error: String(e) };
267
- }
268
- }
269
-
270
- // ── Check 4: contrastive validity — flag fires the rule, pass does not ──────────
271
- function checkContrastiveValidity(catalog, onlyId = null) {
272
- const errors = [];
273
- if (!existsSync(FIXTURES_DIR)) return { name: "contrastive fixture validity", pass: false, detail: "fixtures dir missing", errors: ["data/catalog/fixtures/ does not exist"] };
274
- const files = readdirSync(FIXTURES_DIR);
275
- const findFile = (id, kind) => files.find((f) => f.startsWith(`${id}.${kind}.`));
276
- let checked = 0;
277
- for (const row of catalog.rows) {
278
- if (row.fixture_pair !== "yes") continue;
279
- if (onlyId && row.id !== onlyId) continue;
280
- const flag = findFile(row.id, "flag");
281
- const pass = findFile(row.id, "pass");
282
- if (!flag || !pass) continue; // absence is check 3's job
283
- checked++;
284
- const flagRes = runEngine(join(FIXTURES_DIR, flag));
285
- if (flagRes.error) { errors.push(`${row.id}: check engine threw on flag (${flagRes.error})`); continue; }
286
- if (!flagRes.ids.has(row.id)) errors.push(`${row.id}: flag fixture did not report ${row.id} (reported: ${[...flagRes.ids].join(",") || "none"})`);
287
- const passRes = runEngine(join(FIXTURES_DIR, pass));
288
- if (passRes.error) { errors.push(`${row.id}: check engine threw on pass (${passRes.error})`); continue; }
289
- if (passRes.ids.has(row.id)) errors.push(`${row.id}: pass fixture wrongly reported ${row.id}`);
290
- }
291
- return { name: "contrastive fixture validity", pass: errors.length === 0, detail: `${checked} pair(s) exercised`, errors };
292
- }
293
-
294
- // Recursively collect prose/data files (.md/.csv/.tsx/.json) under a dir for the floor-citation scan.
295
- function walkTextFiles(dir, acc = []) {
296
- if (!existsSync(dir)) return acc;
297
- for (const ent of readdirSync(dir, { withFileTypes: true })) {
298
- if (ent.name.startsWith(".") || ent.name === "node_modules") continue;
299
- const full = join(dir, ent.name);
300
- if (ent.isDirectory()) walkTextFiles(full, acc);
301
- else if (/\.(md|csv|tsx|json)$/.test(ent.name)) acc.push(full);
302
- }
303
- return acc;
304
- }
305
-
306
- // ── Check 2b: doctrine-floor anchor parity (f-ids) ─────────────────────────────
307
- // Same mechanism as rule-id parity: hard-rules.md's Doctrine floor section is the canonical
308
- // enumeration (exactly f01-f12, once each); every f-id cited anywhere in the skill's prose/data
309
- // names an enumerated id, and the retired "floor P<n>" numbering is gone.
310
- function checkFloorParity() {
311
- const errors = [];
312
- const md = readSafe(HARD_RULES_MD);
313
- if (md === null) return { name: "floor parity (f-ids)", pass: false, detail: "hard-rules.md missing", errors: ["hard-rules.md not found at " + HARD_RULES_MD] };
314
-
315
- const section = /^##\s+Doctrine floor\s*$([\s\S]*?)(?=^##\s)/m.exec(md);
316
- const enumerated = new Map();
317
- if (!section) errors.push('hard-rules.md has no "## Doctrine floor" section (the canonical f01-f12 enumeration)');
318
- else {
319
- for (const m of section[1].matchAll(/`(f\d{2})`/g)) enumerated.set(m[1], (enumerated.get(m[1]) || 0) + 1);
320
- for (const id of FLOOR_IDS) {
321
- const n = enumerated.get(id) || 0;
322
- if (n === 0) errors.push(`doctrine floor enumeration is missing ${id}`);
323
- else if (n > 1) errors.push(`${id} enumerated ${n} times (want exactly 1)`);
324
- }
325
- for (const id of enumerated.keys()) if (!FLOOR_IDS.includes(id)) errors.push(`enumeration carries unknown floor id ${id} (legal: f01-f12)`);
326
- }
327
-
328
- const targets = [join(SKILL_ROOT, "SKILL.md"), ...walkTextFiles(join(SKILL_ROOT, "references")), ...walkTextFiles(join(SKILL_ROOT, "data"))];
329
- let cited = 0;
330
- for (const file of targets) {
331
- const text = readSafe(file);
332
- if (text === null) continue;
333
- const rel = file.replace(SKILL_ROOT + "/", "");
334
- text.split("\n").forEach((line, i) => {
335
- for (const m of line.matchAll(/(?:\bfloor\s+|[(`/]\s?)(f\d{2})\b/g)) {
336
- cited++;
337
- if (!FLOOR_IDS.includes(m[1])) errors.push(`${rel}:${i + 1}: cites unknown floor id ${m[1]} (legal: f01-f12)`);
338
- }
339
- const stale = /\bfloor\s+P\d+\b/.exec(line);
340
- if (stale) errors.push(`${rel}:${i + 1}: retired P-numbered floor citation "${stale[0]}" — rename to its f-id (05-rule-amendments.md mapping)`);
341
- });
342
- }
343
- return { name: "floor parity (f-ids)", pass: errors.length === 0, detail: errors.length ? `${errors.length} parity break(s)` : `${enumerated.size} enumerated, ${cited} citation(s) checked`, errors };
344
- }
345
-
346
- const NUMBER_WORDS = { one: 1, two: 2, three: 3, four: 4, five: 5, six: 6, seven: 7, eight: 8, nine: 9, ten: 10, eleven: 11, twelve: 12, thirteen: 13, fourteen: 14, fifteen: 15, sixteen: 16, seventeen: 17, eighteen: 18, nineteen: 19, twenty: 20, "twenty-six": 26 };
347
-
348
- // Resolve a numeric token (digits or an English number word) to a number, or NaN.
349
- function toNumber(tok) {
350
- if (/^\d+$/.test(tok)) return parseInt(tok, 10);
351
- return NUMBER_WORDS[tok.toLowerCase()] ?? NaN;
352
- }
353
-
354
- // ── Check 5: stated counts in prose match the ground truth ─────────────────────
355
- function checkStatedCounts(catalog, ground) {
356
- const errors = [];
357
- // Ground truth drift guard: derived counts (CSV rows; the token surface counted off the Nurix
358
- // default artifact) must match the pinned numbers.
359
- if (ground.rows !== PINNED.rows) errors.push(`derived row count ${ground.rows} != pinned ${PINNED.rows}`);
360
- if (ground.source !== PINNED.source) errors.push(`derived source count ${ground.source} != pinned ${PINNED.source}`);
361
- if (ground.render !== PINNED.render) errors.push(`derived machine-render count ${ground.render} != pinned ${PINNED.render}`);
362
- if (ground.primitives !== null && ground.primitives !== PINNED.primitives) errors.push(`derived primitive count ${ground.primitives} != pinned ${PINNED.primitives}`);
363
- if (ground.colorTokens !== null && ground.colorTokens !== PINNED.colorTokens) errors.push(`derived color-token count ${ground.colorTokens} != pinned ${PINNED.colorTokens}`);
364
- if (ground.rampSteps !== null && ground.rampSteps !== PINNED.rampSteps) errors.push(`derived ramp-step count ${ground.rampSteps} != pinned ${PINNED.rampSteps}`);
365
- if (ground.elevation !== null && ground.elevation !== PINNED.elevation) errors.push(`derived elevation count ${ground.elevation} != pinned ${PINNED.elevation}`);
366
-
367
- const gtMap = {
368
- rules: ground.rows, rule: ground.rows, rows: ground.rows, row: ground.rows,
369
- source: ground.source, render: ground.render,
370
- archetypes: PINNED.archetypes, archetype: PINNED.archetypes,
371
- primitives: PINNED.primitives, primitive: PINNED.primitives,
372
- "color-tokens": PINNED.colorTokens, "color tokens": PINNED.colorTokens, colortokens: PINNED.colorTokens,
373
- "semantic-tokens": PINNED.semanticTokens, "substrate-tokens": PINNED.substrateTokens,
374
- "ramp-steps": PINNED.rampSteps, rampsteps: PINNED.rampSteps, elevation: PINNED.elevation,
375
- };
376
-
377
- const targets = [join(SKILL_ROOT, "SKILL.md"), ...(existsSync(join(SKILL_ROOT, "references")) ? readdirSync(join(SKILL_ROOT, "references")).filter((f) => f.endsWith(".md")).map((f) => join(SKILL_ROOT, "references", f)) : [])];
378
- let commentClaims = 0;
379
- let bareClaims = 0;
380
- for (const file of targets) {
381
- const text = readSafe(file);
382
- if (text === null) continue;
383
- const rel = file.replace(SKILL_ROOT + "/", "");
384
- const linesArr = text.split("\n");
385
- linesArr.forEach((line, i) => {
386
- // (a) machine-readable HTML comment claims: <!-- count:<name>=<n> -->
387
- const cmt = /<!--\s*count:([a-z0-9 _-]+)=(\d+)\s*-->/gi;
388
- let cm;
389
- while ((cm = cmt.exec(line)) !== null) {
390
- commentClaims++;
391
- const name = cm[1].trim().toLowerCase().replace(/\s+/g, "-");
392
- const val = parseInt(cm[2], 10);
393
- const expected = gtMap[name] ?? gtMap[name.replace(/-/g, " ")];
394
- if (expected === undefined) errors.push(`${rel}:${i + 1}: count comment names unknown quantity "${cm[1].trim()}"`);
395
- else if (expected !== val) errors.push(`${rel}:${i + 1}: count:${cm[1].trim()}=${val} but ground truth is ${expected}`);
396
- }
397
- // (b) bare claims of the exact named forms. Require adjacency (number immediately
398
- // before the noun) so qualified subset phrases ("24 static primitives", "one layout
399
- // primitive") are not misread as grand-total claims.
400
- const bare = /\b(\d+|[a-z]+)\s+(rules?|archetypes?|primitives?)\b/gi;
401
- let bm;
402
- while ((bm = bare.exec(line)) !== null) {
403
- const n = toNumber(bm[1]);
404
- if (Number.isNaN(n)) continue;
405
- const key = bm[2].toLowerCase();
406
- const expected = gtMap[key];
407
- if (expected === undefined) continue;
408
- bareClaims++;
409
- if (n !== expected) errors.push(`${rel}:${i + 1}: bare claim "${bm[0].trim()}" (=${n}) contradicts ground truth ${expected}`);
410
- }
411
- });
412
- }
413
- return { name: "stated-count integrity", pass: errors.length === 0, detail: `${commentClaims} comment + ${bareClaims} bare claim(s) checked`, errors };
414
- }
415
-
416
- // ── Check 6: every brief-pinned path exists ────────────────────────────────────
417
- function checkFileTree() {
418
- const errors = [];
419
- const files = [
420
- "SKILL.md",
421
- "references/hard-rules.md", "references/create.md", "references/improve.md", "references/introspect.md",
422
- "references/diagnosis.md", "references/structure.md", "references/personality.md", "references/interaction.md", "references/lifecycle.md",
423
- "data/catalog/rules.csv",
424
- "data/catalog/fixtures/cod-02.manifest.tokens.json",
425
- "data/design-md/SCHEMA.md", "data/design-md/nurix.md",
426
- "data/operator-pack/surface-catalog.md", "data/operator-pack/fixtures.md", "data/operator-pack/trust-rubric.md",
427
- "data/operator-pack/exemplars/list-detail.tsx", "data/operator-pack/exemplars/dashboard.tsx",
428
- "data/operator-pack/exemplars/entity-detail.tsx", "data/operator-pack/exemplars/create-edit.tsx",
429
- "data/operator-pack/exemplars/log-stream.tsx", "data/operator-pack/exemplars/command-center.tsx",
430
- "scripts/lib/checks.mjs", "scripts/phase-gate.mjs", "scripts/preship-sweep.mjs", "scripts/render-rung.mjs",
431
- "scripts/scaffold.mjs", "scripts/derive-personality.mjs", "scripts/generate-fixtures.mjs",
432
- "scripts/self-integrity.mjs",
433
- ];
434
- for (const rel of files) if (!existsSync(join(SKILL_ROOT, rel))) errors.push(`missing ${rel}`);
435
-
436
- const dirs = ["data/catalog/fixtures", "data/design-md/library"];
437
- for (const rel of dirs) {
438
- const abs = join(SKILL_ROOT, rel);
439
- if (!existsSync(abs)) errors.push(`missing dir ${rel}/`);
440
- else if (readdirSync(abs).length === 0) errors.push(`empty dir ${rel}/`);
441
- }
442
- const found = files.length - errors.filter((e) => e.startsWith("missing ")).length;
443
- return { name: "file-tree presence", pass: errors.length === 0, detail: `${found}/${files.length} files present`, errors };
444
- }
445
-
446
- // Every artifact directory under data/design-tokens/ (a directory holding design.tokens.json), sorted by slug.
447
- function listArtifactSlugs() {
448
- if (!existsSync(TOKENS_DIR)) return [];
449
- return readdirSync(TOKENS_DIR, { withFileTypes: true })
450
- .filter((d) => d.isDirectory() && existsSync(join(TOKENS_DIR, d.name, "design.tokens.json")))
451
- .map((d) => d.name)
452
- .sort();
453
- }
454
-
455
- // Parse goldens.json into its entry slugs (every key except "_meta"), or null when absent/unparseable.
456
- function readGoldenSlugs() {
457
- const text = readSafe(GOLDENS_JSON);
458
- if (text === null) return null;
459
- try { return Object.keys(JSON.parse(text)).filter((k) => k !== "_meta").sort(); }
460
- catch { return null; }
461
- }
462
-
463
- // Run an async worker over items with at most `limit` in flight; results keep item order.
464
- async function runPool(items, limit, worker) {
465
- const results = new Array(items.length);
466
- let next = 0;
467
- const lane = async () => {
468
- while (next < items.length) {
469
- const i = next++;
470
- results[i] = await worker(items[i], i);
471
- }
472
- };
473
- await Promise.all(Array.from({ length: Math.min(limit, items.length) || 1 }, lane));
474
- return results;
475
- }
476
-
477
- // Spawn `node <args>` and resolve with { status, stdout, stderr } (never rejects; a spawn error surfaces as status -1).
478
- function execNode(args) {
479
- return new Promise((resolveExec) => {
480
- const child = spawn(process.execPath, args, { stdio: ["ignore", "pipe", "pipe"] });
481
- let stdout = "";
482
- let stderr = "";
483
- child.stdout.on("data", (d) => { stdout += d; });
484
- child.stderr.on("data", (d) => { stderr += d; });
485
- child.on("error", (e) => resolveExec({ status: -1, stdout, stderr: stderr + String(e) }));
486
- child.on("close", (status) => resolveExec({ status, stdout, stderr }));
487
- });
488
- }
489
-
490
- // First non-empty line of a child process's output, for one-line error reporting.
491
- function firstLine(text) {
492
- return (text || "").split("\n").find((l) => l.trim() !== "") || "(no output)";
493
- }
494
-
495
- // ── Check 7: token-era file tree + goldens<->artifact parity ───────────────────
496
- function checkTokenFileTree() {
497
- const errors = [];
498
- const pins = [
499
- "data/design-tokens/SCHEMA.md",
500
- "data/design-tokens/goldens.json",
501
- "scripts/convert-design-md.mjs",
502
- "scripts/snapshot-goldens.mjs",
503
- "scripts/lib/golden.mjs",
504
- ];
505
- for (const rel of pins) if (!existsSync(join(SKILL_ROOT, rel))) errors.push(`missing ${rel}`);
506
- const pinsFound = pins.length - errors.length;
507
-
508
- const diskSlugs = listArtifactSlugs();
509
- const goldenSlugs = readGoldenSlugs();
510
- if (goldenSlugs === null) {
511
- errors.push("goldens.json missing or does not parse as JSON");
512
- } else {
513
- const goldenSet = new Set(goldenSlugs);
514
- for (const slug of goldenSlugs) {
515
- if (!existsSync(join(TOKENS_DIR, slug, "design.tokens.json")))
516
- errors.push(`goldens.json entry "${slug}" has no data/design-tokens/${slug}/design.tokens.json on disk`);
517
- else if (!existsSync(join(TOKENS_DIR, slug, "design.resolver.json")))
518
- errors.push(`goldens.json entry "${slug}": data/design-tokens/${slug}/ is missing design.resolver.json`);
519
- }
520
- for (const slug of diskSlugs) {
521
- if (!goldenSet.has(slug)) errors.push(`artifact dir data/design-tokens/${slug}/ has no goldens.json entry`);
522
- else if (!existsSync(join(TOKENS_DIR, slug, "design.resolver.json")) && !errors.some((e) => e.includes(`"${slug}"`)))
523
- errors.push(`artifact dir data/design-tokens/${slug}/ is missing design.resolver.json`);
524
- }
525
- }
526
- const goldenCount = goldenSlugs === null ? 0 : goldenSlugs.length;
527
- return { name: "token file-tree + goldens parity", pass: errors.length === 0, detail: errors.length ? `${errors.length} issue(s)` : `${pinsFound}/${pins.length} pins, goldens<->artifacts ${goldenCount}<->${diskSlugs.length}`, errors };
528
- }
529
-
530
- // ── Check 8: every design-tokens artifact passes derive-personality --check ────
531
- async function checkArtifactValidity() {
532
- const slugs = listArtifactSlugs();
533
- if (slugs.length === 0) return { name: "artifact validity (--check)", pass: false, detail: "no artifact dirs found", errors: [`no design.tokens.json dirs under ${TOKENS_DIR}`] };
534
- const runs = await runPool(slugs, SPAWN_LIMIT, (slug) => execNode([DERIVE_PERSONALITY, join(TOKENS_DIR, slug), "--check"]));
535
- const errors = [];
536
- runs.forEach((res, i) => {
537
- if (res.status !== 0) errors.push(`${slugs[i]}: --check exited ${res.status}: ${firstLine(res.stderr || res.stdout)}`);
538
- });
539
- return { name: "artifact validity (--check)", pass: errors.length === 0, detail: `${slugs.length - errors.length}/${slugs.length} artifacts pass --check`, errors };
540
- }
541
-
542
- // ── Check 9: emitted CSS hashes match goldens.json (slow; gated behind --goldens) ──
543
- async function checkGoldenMatch(enabled) {
544
- if (!enabled) return { name: "golden emission match", pass: true, skip: true, detail: "skipped (slow) — run with --goldens to verify emitted hashes against goldens.json", errors: [] };
545
- const goldenSlugs = readGoldenSlugs();
546
- if (goldenSlugs === null) return { name: "golden emission match", pass: false, detail: "goldens.json missing/unparseable", errors: ["goldens.json missing or does not parse as JSON"] };
547
- const goldens = JSON.parse(readSafe(GOLDENS_JSON));
548
- const emitRoot = mkdtempSync(join(tmpdir(), "design-self-integrity-"));
549
- let matched = 0;
550
- const errors = [];
551
- try {
552
- // Each worker returns its slug's error list; flattening after the pool keeps report order deterministic.
553
- const perSlug = await runPool(goldenSlugs, SPAWN_LIMIT, async (slug) => {
554
- const slugErrors = [];
555
- const outdir = join(emitRoot, slug);
556
- const res = await execNode([DERIVE_PERSONALITY, join(TOKENS_DIR, slug), "--emit", outdir, "--provisional"]);
557
- if (res.status !== 0) {
558
- slugErrors.push(`${slug}: --emit exited ${res.status}: ${firstLine(res.stderr || res.stdout)}`);
559
- return slugErrors;
560
- }
561
- for (const [key, fileName] of [["personality", "personality.css"], ["globals", "globals.css"]]) {
562
- const css = readSafe(join(outdir, "src/styles", fileName));
563
- if (css === null) { slugErrors.push(`${slug}: emit produced no src/styles/${fileName}`); continue; }
564
- const actual = goldenHash(css);
565
- const expected = goldens[slug] && goldens[slug][key];
566
- if (actual === expected) matched++;
567
- else slugErrors.push(`${slug}: ${fileName} hash ${actual} != golden ${expected ?? "(missing key)"}`);
568
- }
569
- return slugErrors;
570
- });
571
- for (const slugErrors of perSlug) errors.push(...slugErrors);
572
- } finally {
573
- rmSync(emitRoot, { recursive: true, force: true });
574
- }
575
- return { name: "golden emission match", pass: errors.length === 0, detail: `${matched}/${goldenSlugs.length * 2} hashes match goldens.json`, errors };
576
- }
577
-
578
- // Derive the ground-truth counts: rule counts from the catalog itself; the token-surface counts
579
- // (primitives, color roles, ramp steps, elevation levels) from the Nurix default artifact, the
580
- // schema's worked example. null when the artifact is unreadable (check 8 reports that separately).
581
- function deriveGround(catalog) {
582
- const ground = {
583
- rows: catalog.rows.length,
584
- source: catalog.rows.filter((r) => r.detector === "source").length,
585
- render: catalog.rows.filter((r) => r.detector === "render" && r.grade === "machine").length,
586
- primitives: null, colorTokens: null, rampSteps: null, elevation: null,
587
- };
588
- try {
589
- const nurix = JSON.parse(readFileSync(join(TOKENS_DIR, "nurix", "design.tokens.json"), "utf8"));
590
- const count = (group) => Object.keys(group || {}).filter((k) => !k.startsWith("$")).length;
591
- ground.primitives = count(nurix.primitive);
592
- ground.colorTokens = count(nurix.color);
593
- ground.rampSteps = count(nurix.typography && nurix.typography.ramp);
594
- ground.elevation = count(nurix.elevation);
595
- } catch { /* artifact validity is check 8's job */ }
596
- return ground;
597
- }
598
-
599
- // Run one rule's contrastive fixture pair through the check engine and exit 0/1 on its result.
600
- function runSingleFixture(catalog, ruleId) {
601
- const row = catalog.rows.find((r) => r.id === ruleId);
602
- if (!row) { console.error(`--fixture: no rules.csv row with id "${ruleId}"`); process.exit(2); }
603
- if (row.fixture_pair !== "yes") { console.error(`--fixture: ${ruleId} has fixture_pair=${row.fixture_pair}; no contrastive pair to run`); process.exit(2); }
604
- const r = checkContrastiveValidity(catalog, ruleId);
605
- if (r.errors.length === 0 && r.detail.startsWith("0 ")) {
606
- console.error(`--fixture: ${ruleId}.flag.* / ${ruleId}.pass.* not found in data/catalog/fixtures/`);
607
- process.exit(2);
608
- }
609
- if (r.pass) { console.log(`PASS fixture pair ${ruleId} — flag reports ${ruleId}, pass reports zero.`); process.exit(0); }
610
- console.error(`FAIL fixture pair ${ruleId}`);
611
- for (const e of r.errors) console.error(` - ${e}`);
612
- process.exit(1);
613
- }
614
-
615
- // Run every check, print the summary table, and exit non-zero on any failure.
616
- async function main() {
617
- const args = process.argv.slice(2);
618
- let fixtureId = null;
619
- let runGoldens = false;
620
- for (let i = 0; i < args.length; i++) {
621
- if (args[i] === "--fixture") fixtureId = args[++i] || null;
622
- else if (args[i].startsWith("--fixture=")) fixtureId = args[i].slice("--fixture=".length);
623
- else if (args[i] === "--goldens") runGoldens = true;
624
- }
625
-
626
- const results = [];
627
- let catalog = null;
628
- try { catalog = loadCatalog(); } catch (e) {
629
- console.error("FATAL: " + e.message);
630
- process.exit(2);
631
- }
632
-
633
- if (fixtureId) runSingleFixture(catalog, fixtureId);
634
-
635
- const ground = deriveGround(catalog);
636
-
637
- const runners = [
638
- () => checkCsvWellFormed(catalog),
639
- () => checkAnchorParity(catalog),
640
- () => checkFloorParity(),
641
- () => checkFixturePresence(catalog),
642
- () => checkContrastiveValidity(catalog),
643
- () => checkStatedCounts(catalog, ground),
644
- () => checkFileTree(),
645
- () => checkTokenFileTree(),
646
- () => checkArtifactValidity(),
647
- () => checkGoldenMatch(runGoldens),
648
- () => validateCombinations(COMBINATIONS_DIR),
649
- ];
650
- for (const run of runners) {
651
- try { results.push(await run()); }
652
- catch (e) { results.push({ name: run.name || "check", pass: false, detail: "threw", errors: [e.stack || String(e)] }); }
653
- }
654
-
655
- for (const r of results) {
656
- if (r.errors && r.errors.length) {
657
- console.log(`\n[${r.pass ? "PASS" : "FAIL"}] ${r.name}`);
658
- for (const e of r.errors) console.log(` - ${e}`);
659
- }
660
- }
661
-
662
- console.log("\n" + "=".repeat(60));
663
- console.log("self-integrity — design skill");
664
- console.log("=".repeat(60));
665
- const pad = (s, n) => (s + " ".repeat(n)).slice(0, n);
666
- for (const r of results) console.log(`${r.skip ? "SKIP" : r.pass ? "PASS" : "FAIL"} ${pad(r.name, 34)} ${r.detail}`);
667
- console.log("=".repeat(60));
668
-
669
- const failed = results.filter((r) => !r.pass);
670
- if (failed.length) { console.log(`${failed.length} check(s) failed.`); process.exit(1); }
671
- console.log("all checks passed.");
672
- process.exit(0);
673
- }
674
-
675
- main().catch((e) => { console.error("FATAL: " + (e.stack || String(e))); process.exit(2); });