@kitn.ai/ui 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-tooling/construct/public.d.ts +15 -0
  3. package/dist/agent-tooling/construct/schema.d.ts +111 -0
  4. package/dist/construct-cli.es.js +3 -3
  5. package/dist/construct.d.ts +5 -0
  6. package/dist/construct.js +327 -0
  7. package/dist/core-C8fzo39E.js +1 -12
  8. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  9. package/dist/mcp.es.js +1 -1
  10. package/package.json +16 -16
  11. package/bin/route.test.js +0 -58
  12. package/src/agent-tooling/README.md +0 -192
  13. package/src/agent-tooling/archetypes.ts +0 -205
  14. package/src/agent-tooling/catalog/README.md +0 -676
  15. package/src/agent-tooling/catalog/catalog-types.ts +0 -231
  16. package/src/agent-tooling/catalog/fabrications.ts +0 -96
  17. package/src/agent-tooling/catalog/invariants.ts +0 -284
  18. package/src/agent-tooling/catalog/labs-titles.ts +0 -114
  19. package/src/agent-tooling/catalog/scenarios.ts +0 -87
  20. package/src/agent-tooling/catalog/surfaces.ts +0 -347
  21. package/src/agent-tooling/construct/cli-entry.ts +0 -8
  22. package/src/agent-tooling/construct/cli.ts +0 -147
  23. package/src/agent-tooling/construct/codegen.ts +0 -1635
  24. package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
  25. package/src/agent-tooling/construct/dev.ts +0 -148
  26. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
  27. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
  28. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
  29. package/src/agent-tooling/construct/schema.ts +0 -452
  30. package/src/agent-tooling/integrations/anthropic.ts +0 -442
  31. package/src/agent-tooling/integrations/cloudflare.ts +0 -218
  32. package/src/agent-tooling/integrations/langgraph.ts +0 -133
  33. package/src/agent-tooling/integrations/mastra.ts +0 -182
  34. package/src/agent-tooling/integrations/mock.ts +0 -148
  35. package/src/agent-tooling/integrations/ollama.ts +0 -97
  36. package/src/agent-tooling/integrations/openai.ts +0 -95
  37. package/src/agent-tooling/integrations/openrouter.ts +0 -82
  38. package/src/agent-tooling/integrations/pi.ts +0 -176
  39. package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
  40. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
  41. package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
  42. package/src/agent-tooling/mcp/manifest.ts +0 -422
  43. package/src/agent-tooling/mcp/server.ts +0 -116
  44. package/src/agent-tooling/mcp/stdio.ts +0 -18
  45. package/src/agent-tooling/mcp/tools/construct.ts +0 -130
  46. package/src/agent-tooling/mcp/tools/debug.ts +0 -621
  47. package/src/agent-tooling/mcp/tools/reference.ts +0 -980
  48. package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
  49. package/src/agent-tooling/mcp/tools/theme.ts +0 -456
  50. package/src/agent-tooling/mcp/tools/types.ts +0 -14
  51. package/src/agent-tooling/mcp/validate-args.ts +0 -141
  52. package/src/agent-tooling/recipes/composed-thread.ts +0 -714
  53. package/src/agent-tooling/recipes/index.ts +0 -22
  54. package/src/agent-tooling/recipes/types.ts +0 -32
  55. package/src/agent-tooling/registry.ts +0 -132
  56. package/src/agent-tooling/route-emit.ts +0 -305
  57. package/src/agent-tooling/types.ts +0 -390
  58. package/src/components/artifact-card.tsx +0 -120
  59. package/src/components/artifact.tsx +0 -914
  60. package/src/components/attachment-types.ts +0 -66
  61. package/src/components/attachments.tsx +0 -536
  62. package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
  63. package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
  64. package/src/components/audio-visualizer/fit-scale.ts +0 -112
  65. package/src/components/audio-visualizer/index.tsx +0 -528
  66. package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
  67. package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
  68. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
  69. package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
  70. package/src/components/audio-visualizer/sizes.ts +0 -54
  71. package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
  72. package/src/components/audio-visualizer/variant-bar.tsx +0 -175
  73. package/src/components/audio-visualizer/variant-custom.tsx +0 -344
  74. package/src/components/audio-visualizer/variant-grid.tsx +0 -175
  75. package/src/components/audio-visualizer/variant-radial.tsx +0 -163
  76. package/src/components/audio-visualizer/variant-wave.tsx +0 -130
  77. package/src/components/audio-visualizer/wave.glsl.ts +0 -130
  78. package/src/components/card-fallback.tsx +0 -60
  79. package/src/components/card-renderer.tsx +0 -220
  80. package/src/components/card.tsx +0 -212
  81. package/src/components/chain-of-thought.tsx +0 -348
  82. package/src/components/chat-container.tsx +0 -89
  83. package/src/components/chat-scope-picker.tsx +0 -57
  84. package/src/components/chat-thread.tsx +0 -1014
  85. package/src/components/checkpoint.tsx +0 -88
  86. package/src/components/choice-card.tsx +0 -743
  87. package/src/components/coachmark.tsx +0 -249
  88. package/src/components/code-block.tsx +0 -181
  89. package/src/components/composer-dom.ts +0 -159
  90. package/src/components/composer-highlight.ts +0 -242
  91. package/src/components/composer-history.ts +0 -82
  92. package/src/components/composer.tsx +0 -1075
  93. package/src/components/confirm-card.tsx +0 -402
  94. package/src/components/context.tsx +0 -377
  95. package/src/components/conversation-item.tsx +0 -241
  96. package/src/components/conversation-list.tsx +0 -429
  97. package/src/components/conversation-panel.tsx +0 -118
  98. package/src/components/dismissed-stub.tsx +0 -80
  99. package/src/components/embed.tsx +0 -200
  100. package/src/components/empty.tsx +0 -177
  101. package/src/components/feedback-bar.tsx +0 -166
  102. package/src/components/file-tree.tsx +0 -530
  103. package/src/components/file-upload.tsx +0 -167
  104. package/src/components/form-widgets.tsx +0 -525
  105. package/src/components/form.tsx +0 -1296
  106. package/src/components/home-panel.tsx +0 -159
  107. package/src/components/image.tsx +0 -65
  108. package/src/components/link-preview.tsx +0 -195
  109. package/src/components/loader.tsx +0 -367
  110. package/src/components/markdown.tsx +0 -162
  111. package/src/components/message-skills.tsx +0 -40
  112. package/src/components/message.tsx +0 -765
  113. package/src/components/model-switcher.tsx +0 -132
  114. package/src/components/prompt-input.tsx +0 -188
  115. package/src/components/prompt-suggestion.tsx +0 -150
  116. package/src/components/reasoning.tsx +0 -293
  117. package/src/components/response-compare-types.ts +0 -152
  118. package/src/components/response-compare.tsx +0 -455
  119. package/src/components/response-stream.tsx +0 -109
  120. package/src/components/screen.tsx +0 -181
  121. package/src/components/scroll-button.tsx +0 -93
  122. package/src/components/source.tsx +0 -192
  123. package/src/components/tasks-card.tsx +0 -801
  124. package/src/components/text-shimmer.tsx +0 -37
  125. package/src/components/thinking-bar.tsx +0 -50
  126. package/src/components/thread.tsx +0 -228
  127. package/src/components/toast.tsx +0 -503
  128. package/src/components/tool-classify.ts +0 -26
  129. package/src/components/tool-types.ts +0 -49
  130. package/src/components/tool.tsx +0 -190
  131. package/src/components/use-card-resolution.ts +0 -44
  132. package/src/components/voice-input.tsx +0 -222
  133. package/src/components/voice-output.tsx +0 -242
  134. package/src/components/widget-tab-bar.tsx +0 -73
  135. package/src/components/workspace-shell.tsx +0 -285
  136. package/src/diagnostics/hook.ts +0 -352
  137. package/src/diagnostics/index.ts +0 -82
  138. package/src/diagnostics/report-request.ts +0 -296
  139. package/src/elements/agent-card.tsx +0 -67
  140. package/src/elements/artifact.tsx +0 -194
  141. package/src/elements/attachments.tsx +0 -140
  142. package/src/elements/audio-visualizer.tsx +0 -227
  143. package/src/elements/autoloader.ts +0 -89
  144. package/src/elements/avatar.tsx +0 -33
  145. package/src/elements/badge.tsx +0 -32
  146. package/src/elements/button.tsx +0 -149
  147. package/src/elements/card.tsx +0 -133
  148. package/src/elements/cards.tsx +0 -266
  149. package/src/elements/chain-of-thought.tsx +0 -141
  150. package/src/elements/chat-scope-picker.tsx +0 -65
  151. package/src/elements/chat-types.ts +0 -102
  152. package/src/elements/chat-workspace.tsx +0 -188
  153. package/src/elements/chat.tsx +0 -304
  154. package/src/elements/checkbox-group.tsx +0 -164
  155. package/src/elements/checkbox.tsx +0 -134
  156. package/src/elements/checkpoint.tsx +0 -47
  157. package/src/elements/choice.tsx +0 -100
  158. package/src/elements/coachmark.tsx +0 -90
  159. package/src/elements/code-block.tsx +0 -60
  160. package/src/elements/command.tsx +0 -197
  161. package/src/elements/compare.tsx +0 -111
  162. package/src/elements/compiled.css +0 -2
  163. package/src/elements/composer.tsx +0 -162
  164. package/src/elements/confirm-card.tsx +0 -76
  165. package/src/elements/context-meter.tsx +0 -107
  166. package/src/elements/conversation-item.tsx +0 -120
  167. package/src/elements/conversation-list.tsx +0 -203
  168. package/src/elements/css.ts +0 -5
  169. package/src/elements/default-input.tsx +0 -392
  170. package/src/elements/define-entry.ts +0 -12
  171. package/src/elements/define.tsx +0 -563
  172. package/src/elements/diagnostic-events.ts +0 -114
  173. package/src/elements/dialog.tsx +0 -145
  174. package/src/elements/disclosure.ts +0 -95
  175. package/src/elements/dock.tsx +0 -215
  176. package/src/elements/dropdown.tsx +0 -123
  177. package/src/elements/editable-label.tsx +0 -140
  178. package/src/elements/element-data-types.ts +0 -152
  179. package/src/elements/element-diagnostics.ts +0 -392
  180. package/src/elements/element-manifest.json +0 -354
  181. package/src/elements/element-nonscalar.json +0 -187
  182. package/src/elements/element-types.d.ts +0 -4353
  183. package/src/elements/embed.tsx +0 -35
  184. package/src/elements/empty.tsx +0 -29
  185. package/src/elements/feedback-bar.tsx +0 -66
  186. package/src/elements/file-tree.tsx +0 -62
  187. package/src/elements/file-upload.tsx +0 -44
  188. package/src/elements/form.tsx +0 -94
  189. package/src/elements/hover-card.tsx +0 -80
  190. package/src/elements/icon.tsx +0 -41
  191. package/src/elements/image.tsx +0 -32
  192. package/src/elements/input.tsx +0 -492
  193. package/src/elements/kbd.tsx +0 -45
  194. package/src/elements/link-preview.tsx +0 -34
  195. package/src/elements/loader.tsx +0 -25
  196. package/src/elements/markdown.tsx +0 -38
  197. package/src/elements/menu.tsx +0 -241
  198. package/src/elements/message-skills.tsx +0 -83
  199. package/src/elements/message.tsx +0 -361
  200. package/src/elements/model-switcher.tsx +0 -121
  201. package/src/elements/nav.tsx +0 -87
  202. package/src/elements/notice.tsx +0 -53
  203. package/src/elements/pane-grid.tsx +0 -111
  204. package/src/elements/pane-group.tsx +0 -119
  205. package/src/elements/pane.tsx +0 -129
  206. package/src/elements/popover.tsx +0 -81
  207. package/src/elements/progress-bar.tsx +0 -39
  208. package/src/elements/prompt-dock.tsx +0 -82
  209. package/src/elements/prompt-input.tsx +0 -240
  210. package/src/elements/prompt-suggestions.tsx +0 -113
  211. package/src/elements/radio-group.tsx +0 -129
  212. package/src/elements/reasoning.tsx +0 -71
  213. package/src/elements/register-impl.ts +0 -148
  214. package/src/elements/register.ts +0 -76
  215. package/src/elements/remote.tsx +0 -225
  216. package/src/elements/resizable.globals.d.ts +0 -36
  217. package/src/elements/resizable.tsx +0 -704
  218. package/src/elements/response-stream.tsx +0 -40
  219. package/src/elements/screen.tsx +0 -90
  220. package/src/elements/scroll-area.tsx +0 -33
  221. package/src/elements/scroll-button.tsx +0 -179
  222. package/src/elements/search.tsx +0 -185
  223. package/src/elements/segmented.tsx +0 -129
  224. package/src/elements/select.tsx +0 -165
  225. package/src/elements/separator.tsx +0 -36
  226. package/src/elements/setting-item.tsx +0 -50
  227. package/src/elements/settings-group.tsx +0 -37
  228. package/src/elements/skeleton.tsx +0 -45
  229. package/src/elements/slider.tsx +0 -171
  230. package/src/elements/slot-text.ts +0 -73
  231. package/src/elements/slots.ts +0 -787
  232. package/src/elements/source.tsx +0 -126
  233. package/src/elements/status.tsx +0 -42
  234. package/src/elements/styles.css +0 -328
  235. package/src/elements/switch.tsx +0 -118
  236. package/src/elements/tabs.tsx +0 -95
  237. package/src/elements/tasks.tsx +0 -103
  238. package/src/elements/text-shimmer.tsx +0 -28
  239. package/src/elements/thinking-bar.tsx +0 -43
  240. package/src/elements/thread.tsx +0 -139
  241. package/src/elements/toast.tsx +0 -106
  242. package/src/elements/tool.tsx +0 -78
  243. package/src/elements/tooltip.tsx +0 -85
  244. package/src/elements/validate-messages.ts +0 -76
  245. package/src/elements/voice-input.tsx +0 -100
  246. package/src/elements/voice-output.tsx +0 -82
  247. package/src/index.ts +0 -430
  248. package/src/primitives/audio-bands.ts +0 -174
  249. package/src/primitives/card-component-types.ts +0 -63
  250. package/src/primitives/card-contract.ts +0 -80
  251. package/src/primitives/card-data-types.ts +0 -361
  252. package/src/primitives/card-host.tsx +0 -37
  253. package/src/primitives/card-recovery.ts +0 -160
  254. package/src/primitives/card-registry.tsx +0 -78
  255. package/src/primitives/card-resolution.ts +0 -36
  256. package/src/primitives/card-routing.ts +0 -85
  257. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  258. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  259. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  260. package/src/primitives/card-schemas/choice.schema.json +0 -75
  261. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  262. package/src/primitives/card-schemas/embed.schema.json +0 -63
  263. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  264. package/src/primitives/card-schemas/form.schema.json +0 -53
  265. package/src/primitives/card-schemas/link.schema.json +0 -54
  266. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  267. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  268. package/src/primitives/card-tags.ts +0 -61
  269. package/src/primitives/card-validate-cards.ts +0 -255
  270. package/src/primitives/card-validate-schemas.ts +0 -58
  271. package/src/primitives/card-validate.ts +0 -131
  272. package/src/primitives/chat-config.tsx +0 -103
  273. package/src/primitives/composer-model.ts +0 -49
  274. package/src/primitives/composer-triggers.ts +0 -35
  275. package/src/primitives/controllable.ts +0 -21
  276. package/src/primitives/conversation-store.ts +0 -248
  277. package/src/primitives/create-kai-chat.ts +0 -66
  278. package/src/primitives/create-tween.ts +0 -266
  279. package/src/primitives/embed-providers.ts +0 -254
  280. package/src/primitives/field-mask.ts +0 -256
  281. package/src/primitives/field-semantics.ts +0 -115
  282. package/src/primitives/highlighter.ts +0 -157
  283. package/src/primitives/input-mask.ts +0 -853
  284. package/src/primitives/link-preview.ts +0 -87
  285. package/src/primitives/message-feedback.ts +0 -124
  286. package/src/primitives/pdf-preview.ts +0 -121
  287. package/src/primitives/toast-store.ts +0 -338
  288. package/src/primitives/url-scheme-policy.ts +0 -70
  289. package/src/primitives/use-audio-analysis.ts +0 -340
  290. package/src/primitives/use-auto-resize.ts +0 -31
  291. package/src/primitives/use-resize-observer.ts +0 -45
  292. package/src/primitives/use-sequencer.ts +0 -72
  293. package/src/primitives/use-speech-recognition.ts +0 -146
  294. package/src/primitives/use-stick-to-bottom.ts +0 -75
  295. package/src/primitives/use-text-stream.ts +0 -143
  296. package/src/primitives/use-voice-recorder.ts +0 -62
  297. package/src/primitives/visualizer-sequences.ts +0 -350
  298. package/src/remote/host-embed.ts +0 -345
  299. package/src/remote/index.ts +0 -2
  300. package/src/remote/origin.ts +0 -30
  301. package/src/remote/provider-runtime.ts +0 -262
  302. package/src/remote/provider.ts +0 -2
  303. package/src/remote/validate.ts +0 -22
  304. package/src/remote/version.ts +0 -12
  305. package/src/remote/wire.ts +0 -48
  306. package/src/schemas/from-tool-call.ts +0 -151
  307. package/src/schemas/index.ts +0 -341
  308. package/src/schemas/provider-subsets.ts +0 -538
  309. package/src/schemas/registry.ts +0 -355
  310. package/src/schemas/tool-defs.ts +0 -793
  311. package/src/solid.ts +0 -173
  312. package/src/state/index.ts +0 -44
  313. package/src/state/messages.ts +0 -53
  314. package/src/state/mock.ts +0 -297
  315. package/src/state/parts.ts +0 -295
  316. package/src/state/persistence.ts +0 -180
  317. package/src/state/stream.ts +0 -246
  318. package/src/state/suggestions.ts +0 -9
  319. package/src/state/threads.ts +0 -142
  320. package/src/test-utils/fake-clock.ts +0 -88
  321. package/src/types.ts +0 -95
  322. package/src/ui/action-icons.ts +0 -53
  323. package/src/ui/agent-card.tsx +0 -218
  324. package/src/ui/avatar.tsx +0 -23
  325. package/src/ui/badge.tsx +0 -21
  326. package/src/ui/button.tsx +0 -49
  327. package/src/ui/card.tsx +0 -245
  328. package/src/ui/checkbox-group.tsx +0 -153
  329. package/src/ui/checkbox.tsx +0 -63
  330. package/src/ui/collapsible.tsx +0 -163
  331. package/src/ui/command.tsx +0 -103
  332. package/src/ui/dialog.tsx +0 -223
  333. package/src/ui/dock.tsx +0 -630
  334. package/src/ui/dropdown.tsx +0 -636
  335. package/src/ui/editable-label.tsx +0 -112
  336. package/src/ui/hover-card.tsx +0 -345
  337. package/src/ui/icon.tsx +0 -167
  338. package/src/ui/input.tsx +0 -391
  339. package/src/ui/kbd.tsx +0 -118
  340. package/src/ui/nav.tsx +0 -282
  341. package/src/ui/notice.tsx +0 -84
  342. package/src/ui/overlay.tsx +0 -277
  343. package/src/ui/pane-grid.tsx +0 -117
  344. package/src/ui/pane-group.tsx +0 -291
  345. package/src/ui/pane.tsx +0 -193
  346. package/src/ui/popover.tsx +0 -106
  347. package/src/ui/progress-bar.tsx +0 -83
  348. package/src/ui/prompt-dock.tsx +0 -145
  349. package/src/ui/radio.tsx +0 -150
  350. package/src/ui/resizable.tsx +0 -693
  351. package/src/ui/scroll-area.tsx +0 -26
  352. package/src/ui/segmented.tsx +0 -109
  353. package/src/ui/select.tsx +0 -168
  354. package/src/ui/separator.tsx +0 -10
  355. package/src/ui/settings-group.tsx +0 -67
  356. package/src/ui/skeleton.tsx +0 -73
  357. package/src/ui/slider.tsx +0 -178
  358. package/src/ui/status.tsx +0 -48
  359. package/src/ui/switch.tsx +0 -119
  360. package/src/ui/tabs.tsx +0 -168
  361. package/src/ui/textarea.tsx +0 -21
  362. package/src/ui/tooltip.tsx +0 -118
  363. package/src/utils/cn.ts +0 -30
  364. package/src/wire/chunk.ts +0 -248
  365. package/src/wire/consume.ts +0 -599
  366. package/src/wire/diagnostics.ts +0 -727
  367. package/src/wire/encode-probe.ts +0 -214
  368. package/src/wire/encode.ts +0 -947
  369. package/src/wire/files.ts +0 -342
  370. package/src/wire/formats/anthropic.ts +0 -274
  371. package/src/wire/formats/openai.ts +0 -228
  372. package/src/wire/index.ts +0 -95
  373. package/src/wire/media-types.ts +0 -344
  374. package/src/wire/read.ts +0 -396
  375. package/src/wire/sink-helpers.ts +0 -50
  376. package/src/wire/sse.ts +0 -153
@@ -1,676 +0,0 @@
1
- # The composition catalog
2
-
3
- A machine-readable description of what can be composed from this kit: the parts,
4
- what each one requires, and the invariants that must hold. It exists so a coding
5
- agent building `kai-*` into someone else's app has the **contracts** — which
6
- event carries which detail, which prop must be a JS property, what breaks if you
7
- set the same array back — and not just a prop list it can already read off
8
- `element-meta.json`.
9
-
10
- The measurement is the point. An acceptance deck of seven scenarios hands an
11
- agent the catalog and **no kit source**; whatever it cannot build names what the
12
- catalog is missing. The evaluator attributes every failure to the catalog record
13
- that should have prevented it and ranks the fixes. That ranked list, not the
14
- score, is the output.
15
-
16
- Every command below was run from the repo root and its output pasted verbatim.
17
-
18
- ---
19
-
20
- ## Generated vs authored
21
-
22
- Half the confusion here is which files you may edit. `derived.json` is read out
23
- of the tree by a generator; everything else is written by hand.
24
-
25
- ### `src/agent-tooling/catalog/`
26
-
27
- | file | what it is | who writes it | edit by hand? |
28
- | --- | --- | --- | --- |
29
- | `derived.json` | Every element's props/events/methods/parts, the `MessagePart` variants, integrations, capability groups, theme tokens, event exceptions | `scripts/gen-catalog.mjs`, via `build:api` | **Never.** Change the source it reads (`src/elements/element-meta.json`, `src/elements/chat-types.ts`, `src/agent-tooling/registry.ts`, `archetypes.ts`, `theme.css`) and regenerate |
30
- | `catalog-types.ts` | The Zod schemas every authored record is parsed against | you | yes |
31
- | `invariants.ts` | The rules that break real consumers, each with a statement, `diagnosis` symptom/cause pairs, wrong/right code examples, and an honest `enforcedBy` | you | yes |
32
- | `surfaces.ts` | `inventory` (what is a surface vs an ingredient vs corpus), `surfaceRecipes` (proven compositions with their host wiring written out), `partConsumption` | you | yes |
33
- | `scenarios.ts` | The seven acceptance scenarios: prompt, what it needs, scoring lines | you | yes |
34
- | `fabrications.ts` | Tags agents invented that do not exist. Empty until a run fills it | you, from a run's report | yes |
35
- | `labs-titles.ts` | TypeScript parser that reads the `title` off a story's default-exported meta. Used by the drift lint to resolve inventory rows | you | rarely |
36
- | `*.test.ts` | The tests that pin all of the above | you | yes |
37
-
38
- ### Scripts
39
-
40
- | script | what it does |
41
- | --- | --- |
42
- | `scripts/gen-catalog.mjs` | Writes `derived.json`. Runs inside `build:api` |
43
- | `scripts/lint-catalog-drift.mjs` | Required CI. Every authored claim — element tags, events, properties, invariant ids, corpus paths, inventory titles, scenario invariant refs — must resolve against `derived.json` and the tree |
44
- | `scripts/acceptance-pack.mjs` | Builds one scenario's pack: `agent/` and `judge/` |
45
- | `scripts/acceptance-run.mjs` | Records what is about to be measured, and isolates the handover. Invokes no model |
46
- | `scripts/acceptance-eval.mjs` | Scores a run and produces the catalog-improvement analysis |
47
- | `scripts/acceptance-gate-compiles.mjs` | The `compiles` gate. Runs `tsc --strict` over the output under the real consumer projects and writes `gates.json` |
48
-
49
- `scripts/lib/` holds the pieces those four share: `rubric.mjs` (weighted
50
- dimensions, 0–10 anchors, the severity ladder), `catalog-attribution.mjs` (the
51
- improvement analysis), `invariant-floor.mjs` (executes every `examples[].right`),
52
- `audit-needles.mjs` (the self-audit search strings and their recall tier),
53
- `output-scan.mjs` (the two gates the evaluator runs itself), `run-routing.mjs`
54
- (which model may take which execution path), `handover.mjs` (the judge-leak
55
- scan), `import-catalog.mjs` (esbuild-bundles the authored TS for plain Node),
56
- `consumer-tsc-projects.mjs` (the throwaway consumer tree and the six tsc
57
- projects — shared with `verify:scaffold`, never copied), `compile-plan.mjs`
58
- (which scanned units tsc can actually check, and what the rest are reported as).
59
-
60
- ---
61
-
62
- ## It already runs without you
63
-
64
- Three things fire on their own. You do not have to do anything for these.
65
-
66
- **`build:api` regenerates `derived.json`.** `gen-catalog.mjs` is chained onto the
67
- end of it, so a normal build keeps the derived layer current:
68
-
69
- ```
70
- "build:api": "node scripts/gen-elements-manifest.mjs && node scripts/gen-element-api.mjs && node scripts/gen-catalog.mjs"
71
- ```
72
-
73
- **`verify:generated` fails CI if a checked-in generated artifact is stale.**
74
- `derived.json` is one of the nine it re-derives and diffs, and it seeds each with
75
- a single-use sentinel first so a dead generator cannot pass as "in sync":
76
-
77
- ```
78
- $ pnpm --filter @kitn.ai/ui run verify:generated
79
- verify-generated-sync: regenerating 9 artifacts via `npm run build:api`
80
-
81
- · model parsed: 80 kai-* elements
82
-
83
- ✓ packages/ui/src/elements/element-meta.json
84
- ...
85
- ✓ packages/ui/src/agent-tooling/catalog/derived.json
86
- ✓ docs/web-components.md
87
-
88
- ✓ verify-generated-sync: all 9 generated artifacts match their source (each one proven rewritten this run).
89
- ```
90
-
91
- **`lint:catalog-drift` fails CI if an authored claim stopped resolving.** Needs
92
- no build, about a second:
93
-
94
- ```
95
- $ pnpm --filter @kitn.ai/ui run lint:catalog-drift
96
- ...
97
- lint-catalog-drift --self-test: all 71 cases behaved.
98
- ⚠ coverage gap: invariant props-not-attributes: enforced by nothing.
99
- ⚠ coverage gap: invariant host-coordinates: enforced by nothing.
100
- ⚠ coverage gap: invariant untrusted-model-output: PARTIAL — ... covers part of it; the statement says which half is uncovered.
101
- ⚠ coverage gap: invariant kit-parses-consumer-fetches: PARTIAL — lint:silent-drops covers part of it; the statement says which half is uncovered.
102
- ⚠ coverage gap: invariant upgrade-race: enforced by nothing (until issue #99 option B lands in defineWebComponent).
103
- lint-catalog-drift: 2 recipes, 7 invariants, 26 inventory rows resolved clean (5 reported gaps).
104
- ```
105
-
106
- The `⚠ coverage gap` lines are reports, not failures — an invariant that nothing
107
- in the repo enforces is a fact the catalog states out loud rather than hides.
108
-
109
- The MCP consumes the catalog too. `component_reference` for a tag now serves the
110
- invariants that apply to it and the recipes it appears in, with the enforcement
111
- line attached:
112
-
113
- ```
114
- ### Invariants
115
- Rules that have already broken real consumers of this kit. Each block says what
116
- enforces it — read that line rather than assuming CI catches a violation, because
117
- nothing here reads YOUR code. 3 of the 7 below are enforced by NOTHING at all,
118
- and 2 more by only half of what they say.
119
-
120
- #### reactivity-two-halves (only kai-chat, kai-conversations) — enforced by the kit's own tests (packages/ui/src/components/reactivity-contract.test.tsx)
121
- ```
122
-
123
- ---
124
-
125
- ## Running it against a model
126
-
127
- **Nothing here calls a model.** There is no API key, no socket and no network in
128
- any of these scripts. The model invocation is a seam you cross by hand (or with a
129
- transport module you supply). Everything on either side of the seam is offline
130
- and tested; only the part that costs money needs you.
131
-
132
- ### 1. See the deck
133
-
134
- ```
135
- $ pnpm --filter @kitn.ai/ui exec node scripts/acceptance-pack.mjs --list
136
- S1 surface recipe applied to an existing tree
137
- S2 greenfield, contract
138
- S3 capability
139
- S4 whole surface; expected to fail hardest first
140
- S5 platform embed
141
- S6 refusal
142
- S7 debugging
143
- ```
144
-
145
- The prompts and scoring lines are in `scenarios.ts`. S6 is the strongest signal
146
- in the deck: a model with no catalog cannot refuse honestly, because it does not
147
- know what does not exist.
148
-
149
- ### 2. Pack a scenario
150
-
151
- ```
152
- $ pnpm --filter @kitn.ai/ui exec node scripts/acceptance-pack.mjs \
153
- --scenario S6 --out /tmp/pack-S6
154
- acceptance-pack: packed S6 into /tmp/pack-S6 (agent/: 80 element pages + 13 guides; judge/: 2 reports + catalog.json)
155
- ```
156
-
157
- `--out` must be new or empty; the packer refuses to merge into a directory it
158
- does not own. Use absolute paths — `pnpm exec` runs from `packages/ui`, so a
159
- relative path lands there.
160
-
161
- Before it writes anything the packer runs the **floor stage**: every
162
- `examples[].right` in `invariants.ts` is executed. You can run it alone:
163
-
164
- ```
165
- $ pnpm --filter @kitn.ai/ui exec node scripts/acceptance-pack.mjs --floor
166
- PASS reactivity-two-halves#0 [stand-ins: `chat` is a plain object, not a registered element]
167
- · appending a turn produces a NEW array reference
168
- ...
169
- ✓ acceptance-pack: floor clean — 15 examples executed.
170
- ```
171
-
172
- A pack built on advice that does not run measures the wrong thing, so a red floor
173
- means no pack.
174
-
175
- ### 3. Prepare the run
176
-
177
- `acceptance-pack` gives you a pack. `acceptance-run` gives you a **ledger** — a
178
- timestamped record of what is about to be measured — plus a handover directory
179
- holding `agent/` and nothing else.
180
-
181
- ```
182
- $ pnpm --filter @kitn.ai/ui exec node scripts/acceptance-run.mjs \
183
- --scenario S6 --model claude-opus-5 --tier frontier --runs-dir /tmp/runs
184
- acceptance-run: no --path was given; "claude-opus-5" admits exactly one (claude-code, rule anthropic-via-subscription). Recorded as inferred.
185
- acceptance-pack: packed S6 into /tmp/runs/20260818-110728-S6-claude-opus-5/pack (agent/: 80 element pages + 13 guides; judge/: 2 reports + catalog.json)
186
- acceptance-run: prepared 20260818-110728-S6-claude-opus-5
187
- scenario S6
188
- model claude-opus-5 (tier frontier)
189
- path claude-code [inferred, anthropic-via-subscription]
190
- kit version 0.25.2
191
- HAND THIS TO THE AGENT, and nothing else:
192
- /var/folders/.../T/kai-handover-20260818-110728-S6-claude-opus-5-AVqU8s (93 files, sha256:894f68b5638d…)
193
- collect its output into:
194
- /tmp/runs/20260818-110728-S6-claude-opus-5/output
195
- then: node scripts/acceptance-eval.mjs --run /tmp/runs/20260818-110728-S6-claude-opus-5
196
- ```
197
-
198
- Flags: `--scenario` `--model` `--tier` `--runs-dir` are required; `--path`
199
- `--effort` `--handover` `--note` `--exec` are optional. Every one of them is
200
- recorded in the ledger and compared across runs, so a flag given no value is
201
- refused rather than guessed.
202
-
203
- The handover defaults to the OS temp directory. Pass `--handover <dir>` to put it
204
- somewhere durable — on this machine the temp copies vanished between commands.
205
- `--prune-handovers <runs-dir>` deletes every handover no ledger still references.
206
-
207
- The ledger (`run-info.json`) records the third thing everyone forgets — **which
208
- execution path ran** — alongside the scenario and the model:
209
-
210
- ```json
211
- {
212
- "runId": "20260818-110728-S6-claude-opus-5",
213
- "scenarioId": "S6",
214
- "model": "claude-opus-5",
215
- "modelCanonical": "claude-opus-5",
216
- "tier": "frontier",
217
- "executionPath": "claude-code",
218
- "pathSource": "inferred",
219
- "routingRule": "anthropic-via-subscription",
220
- "kitVersion": "0.25.2",
221
- "handoverFiles": 93,
222
- "handoverDigest": "sha256:894f68b5638d811b809c1a1606f2a917088c120f74af1d11a78dcd2eadf509a1",
223
- "status": "prepared",
224
- "transport": null
225
- }
226
- ```
227
-
228
- Without the path, a later cost or quality comparison is guesswork: the same model
229
- identifier can mean a subscription seat or a metered invoice.
230
-
231
- ### 4. Cross the seam
232
-
233
- The handover directory is a flat set of markdown files:
234
-
235
- ```
236
- $ ls /var/folders/.../T/kai-handover-20260818-111237-S7-claude-opus-5-V3vZSo
237
- DELIVERY.md FABRICATED.md INVARIANTS.md PARTS.md README.md SELF-AUDIT.md THEME.md
238
- ELEMENTS.md INTEGRATIONS.md INVENTORY.md PROMPT.md RECIPES.md SHARED-PROPS.md elements
239
- $ ls .../judge
240
- ls: .../judge: No such file or directory
241
- ```
242
-
243
- **Anthropic models — your Claude Code subscription.** Start a session with the
244
- handover directory as its working directory, give it the contents of `PROMPT.md`,
245
- and tell it that directory is all the documentation there is. Save whatever it
246
- produces into the run's `output/`. Do not let it read your repo: the whole
247
- measurement is "what can it build from the catalog alone".
248
-
249
- **OpenRouter — the models you name.** Same shape, different transport: POST the
250
- handover's markdown plus `PROMPT.md` to OpenRouter with your own key, write the
251
- reply into `output/`. Only `~deepseek/deepseek-v4-flash-latest` is allowed today;
252
- the list lives in `OPENROUTER_ALLOWED` in `scripts/lib/run-routing.mjs`.
253
-
254
- **The router refuses, it never reroutes.** The two paths bill to different
255
- places, and quietly moving a run would also make the `executionPath` in the
256
- ledger untrue:
257
-
258
- ```
259
- $ ... --model claude-opus-5 --path openrouter
260
- ✗ acceptance-run: routing refused [anthropic-never-openrouter]: "claude-opus-5" is an Anthropic model and the openrouter path was selected. ... This is REFUSED rather than rerouted: the two paths bill to different places, and quietly moving the run would also make the executionPath recorded in the ledger untrue.
261
-
262
- $ ... --model '~deepseek/deepseek-v4-flash-latest' --path claude-code
263
- ✗ acceptance-run: routing refused [non-anthropic-never-claude-code]: "~deepseek/deepseek-v4-flash-latest" is not an Anthropic model, so it cannot run through the Claude Code subscription. Re-run with --path openrouter.
264
-
265
- $ ... --model meta/llama-4
266
- ✗ acceptance-run: routing refused [no-path-for-model]: "meta/llama-4" is neither an Anthropic model nor one of the owner-named OpenRouter models (~deepseek/deepseek-v4-flash-latest), so there is no path it may take. Neither "charge the card" nor "use the subscription" is this script's decision to make.
267
- ```
268
-
269
- **Automating the seam.** `--exec <module>` imports a module you write and calls
270
- its `runAgent(request)`:
271
-
272
- ```js
273
- export async function runAgent(request) {
274
- // request = { runId, scenarioId, model, executionPath, effort, handoverDir, outputDir }
275
- return {
276
- files: [{ name: 'ANSWER.md', text }], // written into outputDir
277
- transcript, // written as output/TRANSCRIPT.md
278
- meta, // recorded in run-info.transport
279
- };
280
- }
281
- ```
282
-
283
- `request` carries no pack directory and no run directory, so a transport cannot
284
- hand an agent the answer key by accident — it is never told where the answer key
285
- is. CI never passes `--exec`.
286
-
287
- ### 5. Run the external gates
288
-
289
- `compiles` is implemented; `registers` and `streams` are not (see *What is not
290
- built*). It compiles the run's output under the same tsc projects
291
- `verify:scaffold` uses — the real `@kitn.ai/ui` exports map, `--strict`,
292
- `noUnusedLocals` — and writes its verdict into the run's `gates.json`. It needs
293
- a built tree, and it will not guess which framework was asked for:
294
-
295
- ```
296
- $ pnpm --filter @kitn.ai/ui exec node scripts/acceptance-gate-compiles.mjs \
297
- --run /tmp/runs/20260818-181634-S1-claude-opus-5 --framework react
298
- acceptance-gate-compiles: 20260818-181634-S1-claude-opus-5 — S1, framework react → default project
299
- ✓ self-test [default]: types resolve for real (TS2322) and noUnusedLocals is live (TS6133)
300
- ✓ 1 unit(s) compile clean under the default project (framework react)
301
- acceptance-gate-compiles: wrote compiles = PASSED into .../gates.json
302
- ```
303
-
304
- A failure names the file and the diagnostic, with the harness's own path prefix
305
- stripped off:
306
-
307
- ```
308
- ✗ 1 error(s) under the default project (framework react):
309
- src/main.ts(30,26): error TS2345: Argument of type 'ReadableStream<Uint8Array<ArrayBuffer>> | null' is not assignable to parameter of type 'StreamSource'.
310
- acceptance-gate-compiles: wrote compiles = FAILED into .../gates.json
311
- ```
312
-
313
- **And an answer with no code in it FAILS**, with the reason recorded — this gate
314
- only applies to scenarios that asked for code, so an answer without any did not
315
- do the thing:
316
-
317
- ```
318
- acceptance-gate-compiles: wrote compiles = FAILED into .../gates.json
319
- ```
320
-
321
- It refuses a scenario the dimension does not apply to, rather than compiling
322
- something whose result the evaluator would then throw away:
323
-
324
- ```
325
- ✗ acceptance-gate-compiles: "compiles" does not apply to S6 — no scoring line in that scenario claims it, so acceptance-eval would refuse a gates file that answered it. Scenarios that need it: S1, S2, S4.
326
- ```
327
-
328
- `--self-test` plants a fault per outcome and watches each one fire, including
329
- the ones only `--strict` produces and a sandbox whose tsconfig has been gutted:
330
-
331
- ```
332
- $ pnpm --filter @kitn.ai/ui run gate:compiles:self-test
333
- ...
334
- ✓ OUTCOME 2 — an implicit `any` (TS7006) — the error ONLY --strict produces
335
- ✓ OUTCOME 2 — a possibly-null value used without a check (TS18047/TS2531) — strictNullChecks is live
336
- ✓ OUTCOME 2 — an unused import (TS6133) — noUnusedLocals is live, which is what fails a stock `npm run build`
337
- ✓ OUTCOME 2 — a WRONG-TYPE use of the kit (TS2322) — @kitn.ai/ui did not resolve to `any`
338
- ✓ OUTCOME 2 — a broken fence inside a markdown answer — a prose-shaped answer is measured too
339
- ✓ the sandbox control PASSES on the real tsconfig (positive control)
340
- ✓ a sandbox whose tsconfig lost its strict flags is DETECTED, so a green cannot come from a dead harness
341
- ✓ acceptance-gate-compiles: 16 controls, every planted fault detected.
342
- ```
343
-
344
- ### 6. Score it
345
-
346
- Generate the findings template, fill it, then evaluate:
347
-
348
- ```
349
- $ pnpm --filter @kitn.ai/ui exec node scripts/acceptance-eval.mjs --template /tmp/runs/20260818-111308-S1-claude-opus-5
350
- acceptance-eval: wrote .../findings.template.json — fill judgedScores and findings, then --run ...
351
- external gates still needed: compiles, registers (supply via --gates; absent is an ERROR, never "skipped" and never a pass)
352
- · compiles: node scripts/acceptance-gate-compiles.mjs --run /tmp/runs/20260818-111308-S1-claude-opus-5 --framework <react|vue|…>
353
- ```
354
-
355
- The template carries the full rubric, the severity ladder and the attribution
356
- kinds inline, so you are not guessing at the vocabulary. Rename it to
357
- `findings.json` (the default `--findings` path) and fill `judgedScores` plus a
358
- `findings` array. Then:
359
-
360
- ```
361
- $ pnpm --filter @kitn.ai/ui exec node scripts/acceptance-eval.mjs --run /tmp/runs/20260818-110728-S6-claude-opus-5
362
- acceptance-eval: S6 gated-fail — 2.84/10 via claude-code. 2 catalog change(s) proposed. Wrote .../REPORT.md.
363
- ```
364
-
365
- Flags: `--run <dir>` `[--findings f] [--gates g]`, `--template <dir> [--out f]`,
366
- `--compare --strong <dir> --weak <dir>`, `--self-test`.
367
-
368
- The evaluator refuses more than it accepts, and every refusal is a real one you
369
- will hit:
370
-
371
- ```
372
- ✗ acceptance-eval: no findings file at .../findings.json. Generate one with --template ...; a run with no judgement is not an evaluation.
373
-
374
- ✗ acceptance-eval: findings could not be attributed to the catalog, so no improvement analysis was produced:
375
- - finding "F1": fabricated-element with no `useInstead` must carry `noReplacementReason` — "there is no replacement" is a real and useful answer, but it has to be said rather than left blank.
376
-
377
- ✗ acceptance-eval: ... is a gated-fail (registers) with ZERO findings recorded. That is not an evaluation: the premise of the deck is that whatever the agent could not build names what the catalog is missing, so a failing run must say what went wrong and what would have prevented it.
378
-
379
- - mechanical dimension "compiles" has no gate result. That is an ERROR, not a skip and not a pass: an unrun gate and a clean gate produce the same silence, and only one of them means anything.
380
- ```
381
-
382
- ---
383
-
384
- ## What the pack contains
385
-
386
- ```
387
- $ find /tmp/pack-S6 -maxdepth 2 -not -path '*/agent/elements/*' | sort
388
- ./PACK.md
389
- ./agent
390
- ./agent/DELIVERY.md
391
- ./agent/ELEMENTS.md
392
- ./agent/FABRICATED.md
393
- ./agent/INTEGRATIONS.md
394
- ./agent/INVARIANTS.md
395
- ./agent/INVENTORY.md
396
- ./agent/PARTS.md
397
- ./agent/PROMPT.md
398
- ./agent/README.md
399
- ./agent/RECIPES.md
400
- ./agent/SELF-AUDIT.md
401
- ./agent/SHARED-PROPS.md
402
- ./agent/THEME.md
403
- ./agent/elements
404
- ./judge
405
- ./judge/FLOOR.md
406
- ./judge/JUDGE.md
407
- ./judge/catalog.json
408
- ```
409
-
410
- `agent/` is the whole catalog and no kit source: the task, how to install and
411
- register, an exhaustive element index with one page per tag, the shared props,
412
- the invariants with wrong/right pairs, the recipes with host wiring, and a
413
- self-audit the agent runs over its own output before delivering.
414
-
415
- `judge/` is the answer key. `JUDGE.md` carries the scoring checklist, the
416
- `enforcedBy` table for triage, and the recipe corpus paths — repo paths pointing
417
- at files the agent is deliberately not given. Handing any of it to the agent
418
- invalidates the run, which is why `acceptance-run` copies `agent/` alone into an
419
- isolated handover and verifies afterwards that no judge material leaked in.
420
-
421
- ---
422
-
423
- ## Reading a result
424
-
425
- `REPORT.md`, from a real S6 run where the agent invented `<kai-datagrid>`:
426
-
427
- ```md
428
- ## Verdict: gated-fail — 2.84 / 10
429
-
430
- **Gated failure.** elements-exist did not pass. A gated failure outranks the
431
- score: "it scored 2.84" and "it does not compile" are different facts.
432
-
433
- | dimension | gate | weight | score | source | detail |
434
- | --- | --- | --- | --- | --- | --- |
435
- | elements-exist | mechanical | 3 | 0.0 | gate | 1 fabricated tag(s) in 2 place(s): kai-datagrid |
436
- | audit-clean | mechanical | 3 | 10.0 | gate | no wrong-form needle fired across 15 needles — a floor, not a proof |
437
- | contract-correctness | judged | 3 | 2.0 | judged | |
438
- | invariant-compliance | judged | 3 | 3.0 | judged | |
439
- | honesty-bound | judged | 4 | 0.0 | judged | |
440
- | completeness | judged | 3 | 3.0 | judged | |
441
- ```
442
-
443
- **The weighted score** is a renormalised 0–10 over the dimensions that applied.
444
- It is for comparing two runs, not for reporting a verdict.
445
-
446
- **Gates fail closed.** A gate that did not run scores 0 — never "skipped" —
447
- because an unrun gate and a clean gate produce the same silence and only one of
448
- them means anything. `elements-exist` and `audit-clean` the evaluator computes
449
- itself from the output text and the catalog; supplying either through `--gates`
450
- is refused. `compiles`, `registers` and `streams` need real tooling and come in
451
- through `--gates`. There is no exception: an output with no code in it is a
452
- FAILED `compiles`, not an absent one — see below.
453
-
454
- **Severity caps the dimension.** From an S1 run: a `does-not-render` finding
455
- filed against `completeness` produced `0.0 (capped from 7.0)`. The ladder is
456
- `does-not-render` (cap 0) · `does-not-function` (3) · `does-not-wire` (5) ·
457
- `cosmetic-or-practice` (8, never blocking).
458
-
459
- **Not-applicable belongs to the evaluator's OWN gates, and to no other.** A
460
- prose answer — a refusal, a diagnosis — gives `elements-exist` and `audit-clean`
461
- nothing to read, and those two leave the score entirely rather than scoring 0.
462
- They are the gates the evaluator runs itself, over the output it holds.
463
-
464
- **An external gate never leaves the score.** That was tried and removed. The
465
- evaluator ran the same `codeUnits()` scan for the external dimensions too and,
466
- finding nothing, marked them not-applicable with an `adjudicated: 'evaluator'`
467
- stamp. The scan cannot support that verdict: it reads recognised code files and
468
- LABELLED fences, so an unlabelled fence — how models most often emit code — is
469
- indistinguishable from prose, and "no code my scanner recognises" was being read
470
- as "no code". Measured: an S1 run producing **zero output files** scored 8.93/10
471
- and exit 0 where it had previously hard-failed, and a mixed answer that
472
- fabricated `<kai-datagrid>` and failed typecheck scored every mechanical gate
473
- 10/10.
474
-
475
- Deleting it cost nothing, because the benefit was unreachable. The
476
- prose-by-design case it was argued for is S6's refusal and S7's diagnosis, and
477
- neither scenario carries an external mechanical dimension at all —
478
- `compiles`/`registers`/`streams` exist only on S1/S2/S4/S5, where an answer with
479
- no code is a failure and not an absence. So:
480
-
481
- - a self-declared `vacuous: true` from a runner is refused, as it always was;
482
- - so is one that claims the evaluator adjudicated it;
483
- - an external gate with no result at all is an ERROR, never a skip and never a
484
- pass;
485
- - `compiles` reports `passed: false` when it finds nothing to compile.
486
-
487
- `tests/scripts/acceptance-gate-compiles.test.ts` pins each of those.
488
-
489
- **The tier delta** is the point of running two models. `--compare` puts them side
490
- by side, and warns when the denominators differ:
491
-
492
- ```
493
- $ ... --compare --strong <dir> --weak <dir>
494
- > **⚠ Different denominators.** The strong run was scored over 19 weight and the
495
- > weak run over 13 ... They are not directly comparable; read the per-dimension
496
- > rows instead of the headline.
497
-
498
- **The headline is not "did it pass".** It is how far down the model tier the
499
- catalog keeps working. Anything the strong model gets right and the weak one gets
500
- wrong names a contract the catalog leaves IMPLICIT and is currently relying on
501
- the model to supply from its own priors.
502
- ```
503
-
504
- **The catalog-improvement analysis is the actual output.** Every finding is
505
- attributed to the record that should have prevented it, and the changes are
506
- ranked by how many findings each would close:
507
-
508
- ```md
509
- | # | change | kind | closes | severity weight | tier-revealed |
510
- | --- | --- | --- | --- | --- | --- |
511
- | 1 | `fabricated:kai-datagrid` | fabricated-element | 1 | 16 | |
512
- | 2 | `invariant:strengthen:props-not-attributes` | invariant-ineffective | 1 | 9 | |
513
-
514
- Addressable share: 1 — all 2 finding(s) name a catalog change.
515
- ```
516
-
517
- Attribution kinds: `missing-invariant` · `invariant-ineffective` ·
518
- `missing-recipe` · `recipe-ineffective` · `underived-contract` ·
519
- `missing-element-description` · `fabricated-element` · `pack-defect` ·
520
- `not-a-catalog-gap`. The last is the escape hatch and it costs something: it must
521
- quote the page and the line that said it plainly, because an uncosted escape
522
- hatch swallows the analysis.
523
-
524
- Fabrications are proposed, never written:
525
-
526
- ```md
527
- ## Proposed FABRICATED.md rows
528
-
529
- Paste into `src/agent-tooling/catalog/fabrications.ts` after checking each tag.
530
- **Not written automatically:** a mis-scored run editing the catalog would teach
531
- every later agent that a real element is imaginary.
532
- ```
533
-
534
- ---
535
-
536
- ## Making improvements
537
-
538
- The loop: **run → read the improvement list → edit the authored records → the
539
- lints keep you honest → re-run.** Only `derived.json` is off limits.
540
-
541
- ### Worked example: adding an invariant
542
-
543
- Add a record to `invariants.ts` and nothing complains yet — the drift lint only
544
- resolves references, and a new id refers to nothing:
545
-
546
- ```
547
- $ pnpm --filter @kitn.ai/ui exec node scripts/lint-catalog-drift.mjs
548
- lint-catalog-drift: 2 recipes, 8 invariants, 26 inventory rows resolved clean (6 reported gaps).
549
- ```
550
-
551
- The packer is where it bites. The floor stage refuses to pack advice it cannot
552
- execute:
553
-
554
- ```
555
- $ ... acceptance-pack.mjs --scenario S6 --out /tmp/pack-bad
556
- ERROR no harness for theme-attribute-scalar#0 (wrong: chat.theme = { mode: 'dark' };). Every examples[].right must be executed; add a harness in scripts/lib/invariant-floor.mjs binding its free variables, or the example stops being measured.
557
- ✗ acceptance-pack: the floor stage failed, so nothing was packed. 1 problem(s) in the catalog's own examples[].right forms — fix those first; a pack built on broken advice measures the wrong thing.
558
- ```
559
-
560
- Add the harness, and the next gate fires:
561
-
562
- ```
563
- ✗ acceptance-pack: the self-audit needles are unsound, so nothing was packed:
564
- - no search needle for theme-attribute-scalar#0. Every wrong/right pair needs one, or that mistake is unsearchable.
565
- ```
566
-
567
- So a new invariant is three edits, in this order:
568
-
569
- 1. the record in `invariants.ts` — statement, `appliesTo`, an honest
570
- `enforcedBy` (`kind: 'none'` is fine and preferred over a fake pointer),
571
- `diagnosis` pairs, and wrong/right examples;
572
- 2. a harness in `scripts/lib/invariant-floor.mjs` binding the example's free
573
- variables, so the `right` form is executed and its behavioural claim asserted;
574
- 3. a needle in `NEEDLE_TABLE` in `scripts/lib/audit-needles.mjs`, with its tier.
575
- The needle is checked to appear in its own `wrong` form, in **zero** `right`
576
- forms across all invariants in either quote style, and to hold its claimed
577
- tier against rename and quote transforms.
578
-
579
- ### Worked example: a recipe or an inventory row
580
-
581
- Every authored claim is resolved against the tree. Misspell an ingredient:
582
-
583
- ```
584
- $ pnpm --filter @kitn.ai/ui exec node scripts/lint-catalog-drift.mjs
585
- ✗ lint-catalog-drift: recipe workspace-chat: ingredient kai-datagrid is not a derived element.
586
- $ echo $?
587
- 1
588
- ```
589
-
590
- Inventory titles resolve the same way, against real `Labs/` story titles parsed
591
- out of each story's default-exported meta. What resolution does **not** cover is
592
- deletion, for most rows: the check runs row → tree, and a deleted row asks
593
- nothing of the tree. The exceptions are documented at the top of `surfaces.ts`.
594
-
595
- ### Before you push
596
-
597
- ```
598
- pnpm --filter @kitn.ai/ui run lint:catalog-drift
599
- pnpm --filter @kitn.ai/ui run verify:generated
600
- pnpm --filter @kitn.ai/ui exec node scripts/acceptance-pack.mjs --floor
601
- pnpm --filter @kitn.ai/ui exec vitest run --project=unit src/agent-tooling/catalog tests/scripts
602
- ```
603
-
604
- And, if you touched the `compiles` gate or the tsc projects it shares with
605
- `verify:scaffold` (both need a build):
606
-
607
- ```
608
- pnpm --filter @kitn.ai/ui run gate:compiles:self-test
609
- pnpm --filter @kitn.ai/ui run verify:scaffold
610
- ```
611
-
612
- The vitest line above, on this tree:
613
-
614
- ```
615
- Test Files 32 passed (32)
616
- Tests 448 passed (448)
617
- ```
618
-
619
- Each script also takes `--self-test`, which watches every refusal fire rather
620
- than asserting it works.
621
-
622
- ---
623
-
624
- ## What is not built
625
-
626
- Say this plainly, because the machinery looks more finished than it is.
627
-
628
- **No acceptance run has ever happened.** Everything above was exercised with
629
- hand-written stand-in output. No model has been given a pack.
630
-
631
- **Two of the three external gates are still unimplemented.** `compiles` now runs
632
- (step 5 above). `registers` and `streams` have weights, anchors and a refusal if
633
- they are missing — and nothing runs them. Supplying one by hand means writing
634
- `gates.json` in the run directory:
635
-
636
- ```json
637
- {
638
- "registers": { "passed": false, "detail": "kai-artifact never upgraded" },
639
- "streams": { "passed": true, "detail": "tokens appended; final turn matched the fixture" }
640
- }
641
- ```
642
-
643
- You get those verdicts by doing the work yourself: mount the output in a browser
644
- and check `customElements.get`, drive it with a mock provider-SSE fixture. What
645
- you may NOT write is `vacuous: true` — a runner that never read the output cannot
646
- discover that there was nothing in it. And do not leave the gate out: an absent
647
- external verdict is a hard error, not a skip. If the answer really contains no
648
- code, that is `passed: false` on a scenario that asked for some.
649
-
650
- The shape to copy when implementing them is `acceptance-gate-compiles.mjs`, and
651
- the part worth copying is not the tsc plumbing — it is that the script always
652
- returns a verdict, and says in `detail` exactly what it did and did not read.
653
-
654
- **`FABRICATED.md` is empty by construction.** `fabrications.ts` holds no rows,
655
- and the page in every pack says so in those words. Read the emptiness as "nobody
656
- has looked yet", not "agents get this right".
657
-
658
- **There are almost no element descriptions in the tree.** The index's "what it
659
- is" column is blank for nearly every row:
660
-
661
- ```
662
- $ grep -c '^- `<kai-' packages/ui/llms.txt
663
- 3
664
- ```
665
-
666
- Three curated one-liners, and `llms.txt` is the only place they live. This is why
667
- `missing-element-description` is an attribution kind: an agent choosing between
668
- two elements has counts and a capability group and nothing else.
669
-
670
- ---
671
-
672
- ## Reference
673
-
674
- - Design: `docs/superpowers/specs/2026-08-17-composition-catalog-design.md`
675
- - Brief: `docs/superpowers/specs/2026-08-16-composition-catalog-brief.md`
676
- - Plan: `docs/superpowers/plans/2026-08-17-composition-catalog.md`