@legionworks/facet 1.9.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 (327) hide show
  1. package/LICENSE-APACHE +202 -0
  2. package/LICENSE-MIT +23 -0
  3. package/README.md +158 -0
  4. package/dist/gallery/chunk-4g8rem85.css +656 -0
  5. package/dist/gallery/chunk-c6s9k9ty.js +5970 -0
  6. package/dist/gallery/frame/artifact.css +8424 -0
  7. package/dist/gallery/frame/chunks/abnfDiagram-N423BO3Z-jj74szbm.js +155 -0
  8. package/dist/gallery/frame/chunks/architecture-TIHT7OUA-cvdjn7dt.js +10 -0
  9. package/dist/gallery/frame/chunks/architectureDiagram-T3A2C74G-n4z77eg6.js +8675 -0
  10. package/dist/gallery/frame/chunks/blockDiagram-VBNYF7ZC-7xsqzrd1.js +3529 -0
  11. package/dist/gallery/frame/chunks/c4Diagram-5PPSVZJV-z2zjs7wx.js +2413 -0
  12. package/dist/gallery/frame/chunks/classDiagram-JCYQIIEL-ve8rngqp.js +47 -0
  13. package/dist/gallery/frame/chunks/classDiagram-v2-OCEON4UE-8cfaxb8z.js +47 -0
  14. package/dist/gallery/frame/chunks/cose-bilkent-JH36ORCC-sn92qexx.js +4822 -0
  15. package/dist/gallery/frame/chunks/cynefin-VYW2F7L2-tqjv913d.js +10 -0
  16. package/dist/gallery/frame/chunks/cynefinDiagram-MW4NZA55-c1c0dj12.js +500 -0
  17. package/dist/gallery/frame/chunks/dagre-VZM6K2ZE-7tyg4yt2.js +476 -0
  18. package/dist/gallery/frame/chunks/diagram-7IWD3JNH-y4eng9sc.js +526 -0
  19. package/dist/gallery/frame/chunks/diagram-B4RE2ZJO-rn3p7j5h.js +673 -0
  20. package/dist/gallery/frame/chunks/diagram-LBJQPF4R-w4a2cm9q.js +255 -0
  21. package/dist/gallery/frame/chunks/diagram-Q27KOJAE-aqc2v7wy.js +575 -0
  22. package/dist/gallery/frame/chunks/diagram-UB23O5K3-xncy8nyd.js +355 -0
  23. package/dist/gallery/frame/chunks/ebnfDiagram-BXEA7PRR-acwgxz16.js +175 -0
  24. package/dist/gallery/frame/chunks/erDiagram-JOGREHBK-mzp5nswt.js +1332 -0
  25. package/dist/gallery/frame/chunks/eventmodeling-45OFAUF4-sg07qr0c.js +10 -0
  26. package/dist/gallery/frame/chunks/flowDiagram-UKHOOZJN-2e5ygs44.js +29 -0
  27. package/dist/gallery/frame/chunks/ganttDiagram-PKOTCBZU-p2hhh7hr.js +2620 -0
  28. package/dist/gallery/frame/chunks/gitGraph-TEB2WS4Q-j6kw0naa.js +10 -0
  29. package/dist/gallery/frame/chunks/gitGraphDiagram-DS77QQ5N-4z9z8wjm.js +1347 -0
  30. package/dist/gallery/frame/chunks/info-DKCQHKI2-mpt80jd3.js +10 -0
  31. package/dist/gallery/frame/chunks/infoDiagram-6WML65LV-5rqm3mgg.js +65 -0
  32. package/dist/gallery/frame/chunks/ishikawaDiagram-WSZJBQD7-b51z96jy.js +975 -0
  33. package/dist/gallery/frame/chunks/journeyDiagram-NVQOT4AX-9jbfp0pk.js +1272 -0
  34. package/dist/gallery/frame/chunks/kanban-definition-27J2QSJJ-4x0vx4se.js +1116 -0
  35. package/dist/gallery/frame/chunks/katex-xfgk95tv.js +14034 -0
  36. package/dist/gallery/frame/chunks/markdown-1s5vwkf2.js +9 -0
  37. package/dist/gallery/frame/chunks/markdown-2h6bwsms.js +3239 -0
  38. package/dist/gallery/frame/chunks/markdown-2x113yh8.js +107 -0
  39. package/dist/gallery/frame/chunks/markdown-30b7rwmp.js +1943 -0
  40. package/dist/gallery/frame/chunks/markdown-356bfj4g.js +2031 -0
  41. package/dist/gallery/frame/chunks/markdown-44n9ea69.js +2406 -0
  42. package/dist/gallery/frame/chunks/markdown-56enrf2r.js +39 -0
  43. package/dist/gallery/frame/chunks/markdown-5avymm8t.js +725 -0
  44. package/dist/gallery/frame/chunks/markdown-6r4svars.js +33 -0
  45. package/dist/gallery/frame/chunks/markdown-6zz8efx2.js +24 -0
  46. package/dist/gallery/frame/chunks/markdown-7jp6prnb.js +19 -0
  47. package/dist/gallery/frame/chunks/markdown-809k7q41.js +55 -0
  48. package/dist/gallery/frame/chunks/markdown-82xmzhzd.js +1076 -0
  49. package/dist/gallery/frame/chunks/markdown-92n37gd4.js +7627 -0
  50. package/dist/gallery/frame/chunks/markdown-ag2sssf8.js +36 -0
  51. package/dist/gallery/frame/chunks/markdown-b4s7ntq2.js +19 -0
  52. package/dist/gallery/frame/chunks/markdown-c9k0fvp1.js +100 -0
  53. package/dist/gallery/frame/chunks/markdown-ceefymn8.js +125 -0
  54. package/dist/gallery/frame/chunks/markdown-d1wfbs70.js +243 -0
  55. package/dist/gallery/frame/chunks/markdown-dy5sgjhc.js +11022 -0
  56. package/dist/gallery/frame/chunks/markdown-dz3z5w30.js +30868 -0
  57. package/dist/gallery/frame/chunks/markdown-eg6ngz7y.js +30340 -0
  58. package/dist/gallery/frame/chunks/markdown-ff5wvb43.js +1149 -0
  59. package/dist/gallery/frame/chunks/markdown-ffg06nfz.js +86 -0
  60. package/dist/gallery/frame/chunks/markdown-fvfncadf.js +472 -0
  61. package/dist/gallery/frame/chunks/markdown-gvyszqpv.js +19 -0
  62. package/dist/gallery/frame/chunks/markdown-gx1p0ew0.js +88 -0
  63. package/dist/gallery/frame/chunks/markdown-gxye5frz.js +65 -0
  64. package/dist/gallery/frame/chunks/markdown-h7pzv34e.js +105 -0
  65. package/dist/gallery/frame/chunks/markdown-hab789t9.js +47 -0
  66. package/dist/gallery/frame/chunks/markdown-hjp6sj8t.js +125 -0
  67. package/dist/gallery/frame/chunks/markdown-jka64qgp.js +1993 -0
  68. package/dist/gallery/frame/chunks/markdown-k8xkn8mw.js +56 -0
  69. package/dist/gallery/frame/chunks/markdown-m7frq8x8.js +112 -0
  70. package/dist/gallery/frame/chunks/markdown-p740v4qm.js +36 -0
  71. package/dist/gallery/frame/chunks/markdown-pxfeh231.js +57 -0
  72. package/dist/gallery/frame/chunks/markdown-pzgd8z3s.js +87 -0
  73. package/dist/gallery/frame/chunks/markdown-qx3cngz2.js +1673 -0
  74. package/dist/gallery/frame/chunks/markdown-rawhfvvc.js +85 -0
  75. package/dist/gallery/frame/chunks/markdown-rd8w0ng9.js +49 -0
  76. package/dist/gallery/frame/chunks/markdown-rm2yxfjj.js +2773 -0
  77. package/dist/gallery/frame/chunks/markdown-s1jatrnk.js +993 -0
  78. package/dist/gallery/frame/chunks/markdown-sgfg5vvq.js +59 -0
  79. package/dist/gallery/frame/chunks/markdown-t4ethv9d.js +409 -0
  80. package/dist/gallery/frame/chunks/markdown-tnmabqvz.js +36 -0
  81. package/dist/gallery/frame/chunks/markdown-tvdpppw8.js +5292 -0
  82. package/dist/gallery/frame/chunks/markdown-v0x27twr.js +22 -0
  83. package/dist/gallery/frame/chunks/markdown-v14td68x.js +36 -0
  84. package/dist/gallery/frame/chunks/markdown-w6sgd54z.js +36 -0
  85. package/dist/gallery/frame/chunks/markdown-xw8dsk8b.js +2125 -0
  86. package/dist/gallery/frame/chunks/markdown-y18mve73.js +85 -0
  87. package/dist/gallery/frame/chunks/markdown-yengsms5.js +427 -0
  88. package/dist/gallery/frame/chunks/markdown-z1wc0v0d.js +1826 -0
  89. package/dist/gallery/frame/chunks/markdown-zazx9h4n.js +329 -0
  90. package/dist/gallery/frame/chunks/mermaid-de7p4v0x.js +30 -0
  91. package/dist/gallery/frame/chunks/mindmap-definition-FAOFIHXS-ra44cbem.js +1216 -0
  92. package/dist/gallery/frame/chunks/packet-7NZHBO7P-xppm5913.js +10 -0
  93. package/dist/gallery/frame/chunks/pegDiagram-VL7TDLO6-a2a4wg03.js +163 -0
  94. package/dist/gallery/frame/chunks/pie-RZYD4A2V-hnbxk152.js +10 -0
  95. package/dist/gallery/frame/chunks/pieDiagram-7S7Q4E2Y-f1vxjtmx.js +311 -0
  96. package/dist/gallery/frame/chunks/quadrantDiagram-CIZ2JOQS-ywafa6kh.js +1390 -0
  97. package/dist/gallery/frame/chunks/radar-I7S5WNFK-ewqd27se.js +10 -0
  98. package/dist/gallery/frame/chunks/railroad-3IZDKUUU-5hy4bdx3.js +10 -0
  99. package/dist/gallery/frame/chunks/railroad-abnf-AHOZXSZD-bh5sxz0d.js +10 -0
  100. package/dist/gallery/frame/chunks/railroad-ebnf-EBAXGLYW-6b9c3zeh.js +10 -0
  101. package/dist/gallery/frame/chunks/railroad-peg-LSFZ7HO6-avc8v39s.js +10 -0
  102. package/dist/gallery/frame/chunks/railroadDiagram-AXF67PYL-qc61wax4.js +131 -0
  103. package/dist/gallery/frame/chunks/requirementDiagram-LRYGKXZP-9bs4786c.js +1295 -0
  104. package/dist/gallery/frame/chunks/sankeyDiagram-W5VNT64P-awt1em8b.js +1339 -0
  105. package/dist/gallery/frame/chunks/sequenceDiagram-SI44F4Z6-qaf9mz3t.js +4324 -0
  106. package/dist/gallery/frame/chunks/sizeCapture-X5ZJPWSS-9fq685xd.js +64 -0
  107. package/dist/gallery/frame/chunks/stateDiagram-OKZ733FA-vx7a7hh0.js +456 -0
  108. package/dist/gallery/frame/chunks/stateDiagram-v2-UEYNNEHI-x4m6ws5t.js +46 -0
  109. package/dist/gallery/frame/chunks/swimlanes-SLNWSIFB-e4mxm1gh.js +8287 -0
  110. package/dist/gallery/frame/chunks/swimlanesDiagram-ULZ7WXOC-0h93e2qq.js +42 -0
  111. package/dist/gallery/frame/chunks/timeline-definition-Z64GVDOM-wp0bhbzg.js +1549 -0
  112. package/dist/gallery/frame/chunks/treeView-QDETBFTQ-hcx7n0vt.js +10 -0
  113. package/dist/gallery/frame/chunks/treemap-6X3UGDF4-av02skdw.js +10 -0
  114. package/dist/gallery/frame/chunks/vennDiagram-T6HMQDX7-pmvk1p7n.js +2566 -0
  115. package/dist/gallery/frame/chunks/wardley-OPB4EBWU-njsp6e40.js +10 -0
  116. package/dist/gallery/frame/chunks/wardleyDiagram-T6FBY63Y-eggmnv4z.js +979 -0
  117. package/dist/gallery/frame/chunks/xychartDiagram-ELKLHX3M-q40tnpe5.js +1954 -0
  118. package/dist/gallery/frame/frame.css +183 -0
  119. package/dist/gallery/frame/runtime/chart.js +42744 -0
  120. package/dist/gallery/frame/runtime/html.js +14 -0
  121. package/dist/gallery/frame/runtime/markdown.js +1403 -0
  122. package/dist/gallery/frame/runtime/mermaid.js +32 -0
  123. package/dist/gallery/frame/runtime/svg.js +14 -0
  124. package/dist/gallery/frame/runtime/tsx.js +52 -0
  125. package/dist/gallery/index.html +104 -0
  126. package/docs/reference/cli.md +163 -0
  127. package/docs/reference/export.md +106 -0
  128. package/docs/reference/html.md +215 -0
  129. package/docs/reference/http.md +85 -0
  130. package/docs/reference/mcp.md +78 -0
  131. package/docs/reference/security.md +119 -0
  132. package/docs/reference/storage.md +93 -0
  133. package/docs/reference/tsx.md +101 -0
  134. package/docs/reference/validation.md +212 -0
  135. package/package.json +89 -0
  136. package/scripts/build-gallery.ts +127 -0
  137. package/scripts/launch-netns.sh +67 -0
  138. package/skills/facet/SKILL.md +100 -0
  139. package/src/cli/client.ts +311 -0
  140. package/src/cli/commands/create.ts +49 -0
  141. package/src/cli/commands/doctor.ts +249 -0
  142. package/src/cli/commands/export.ts +179 -0
  143. package/src/cli/commands/instantiate.ts +35 -0
  144. package/src/cli/commands/list.ts +49 -0
  145. package/src/cli/commands/open.ts +75 -0
  146. package/src/cli/commands/pin.ts +39 -0
  147. package/src/cli/commands/promote.ts +49 -0
  148. package/src/cli/commands/publish.ts +122 -0
  149. package/src/cli/commands/read-back.ts +56 -0
  150. package/src/cli/commands/status.ts +114 -0
  151. package/src/cli/commands/watch.ts +146 -0
  152. package/src/cli/main.ts +522 -0
  153. package/src/cli/output.ts +106 -0
  154. package/src/cli/parser.ts +376 -0
  155. package/src/cli/presenter.ts +212 -0
  156. package/src/cli/service-metadata.ts +134 -0
  157. package/src/cli/spawn-service.ts +326 -0
  158. package/src/css.d.ts +4 -0
  159. package/src/gallery-web/app.ts +1581 -0
  160. package/src/gallery-web/export-menu.ts +121 -0
  161. package/src/gallery-web/export.ts +112 -0
  162. package/src/gallery-web/favicon.ts +54 -0
  163. package/src/gallery-web/frame/entries/chart.ts +6 -0
  164. package/src/gallery-web/frame/entries/html.ts +6 -0
  165. package/src/gallery-web/frame/entries/markdown.ts +6 -0
  166. package/src/gallery-web/frame/entries/mermaid.ts +6 -0
  167. package/src/gallery-web/frame/entries/svg.ts +6 -0
  168. package/src/gallery-web/frame/entries/tsx.ts +6 -0
  169. package/src/gallery-web/frame/frame-payload.ts +91 -0
  170. package/src/gallery-web/frame/renderer-validation.ts +13 -0
  171. package/src/gallery-web/frame/renderers/chart.ts +182 -0
  172. package/src/gallery-web/frame/renderers/dompurify-shim.ts +112 -0
  173. package/src/gallery-web/frame/renderers/html.ts +48 -0
  174. package/src/gallery-web/frame/renderers/markdown.ts +81 -0
  175. package/src/gallery-web/frame/renderers/mermaid.ts +120 -0
  176. package/src/gallery-web/frame/renderers/registry.ts +260 -0
  177. package/src/gallery-web/frame/renderers/svg.ts +393 -0
  178. package/src/gallery-web/frame/renderers/tsx.ts +61 -0
  179. package/src/gallery-web/frame/runtime.ts +501 -0
  180. package/src/gallery-web/frame/styles/artifact.css +8424 -0
  181. package/src/gallery-web/frame/styles/frame.css +183 -0
  182. package/src/gallery-web/frame/styles/html-source.css +23 -0
  183. package/src/gallery-web/frame/view-box.ts +33 -0
  184. package/src/gallery-web/frame-html.ts +72 -0
  185. package/src/gallery-web/index.html +104 -0
  186. package/src/gallery-web/session.ts +107 -0
  187. package/src/gallery-web/sse-client.ts +212 -0
  188. package/src/gallery-web/styles/app.css +420 -0
  189. package/src/gallery-web/styles/tokens.css +112 -0
  190. package/src/gallery-web/styles/verdict.css +186 -0
  191. package/src/gallery-web/swap.ts +64 -0
  192. package/src/gallery-web/theme.ts +40 -0
  193. package/src/gallery-web/view-state.ts +93 -0
  194. package/src/harness-adapters/claude-code/README.md +10 -0
  195. package/src/harness-adapters/claude-code/facet.sh +4 -0
  196. package/src/harness-adapters/codex/README.md +10 -0
  197. package/src/harness-adapters/codex/facet.sh +4 -0
  198. package/src/harness-adapters/mcp/README.md +13 -0
  199. package/src/harness-adapters/mcp/cli-bridge.ts +216 -0
  200. package/src/harness-adapters/mcp/main.ts +15 -0
  201. package/src/harness-adapters/mcp/server.ts +164 -0
  202. package/src/harness-adapters/mcp/tool-schemas.ts +53 -0
  203. package/src/harness-adapters/opencode/README.md +10 -0
  204. package/src/harness-adapters/opencode/facet.sh +4 -0
  205. package/src/runtime/compiled-entrypoints.ts +69 -0
  206. package/src/service/dispatcher.ts +717 -0
  207. package/src/service/export.ts +218 -0
  208. package/src/service/http-utils.ts +55 -0
  209. package/src/service/lexical/expectations.ts +210 -0
  210. package/src/service/lifecycle/idle-controller.ts +125 -0
  211. package/src/service/lifecycle/orphan-cleanup.ts +128 -0
  212. package/src/service/lifecycle/process-lock.ts +235 -0
  213. package/src/service/main.ts +136 -0
  214. package/src/service/process.ts +240 -0
  215. package/src/service/router-guards.ts +239 -0
  216. package/src/service/router.ts +627 -0
  217. package/src/service/security/auth.ts +168 -0
  218. package/src/service/security/host-origin.ts +138 -0
  219. package/src/service/security/http-guards.ts +13 -0
  220. package/src/service/security/leases.ts +182 -0
  221. package/src/service/security/token-store.ts +138 -0
  222. package/src/service/server.ts +356 -0
  223. package/src/service/store/database.ts +61 -0
  224. package/src/service/store/evidence-retention.ts +234 -0
  225. package/src/service/store/migrations.ts +167 -0
  226. package/src/service/store/repository-lifecycle.ts +121 -0
  227. package/src/service/store/repository.ts +732 -0
  228. package/src/service/store/schema.ts +218 -0
  229. package/src/service/stored-verdict.ts +97 -0
  230. package/src/service/stream.ts +301 -0
  231. package/src/service/verdict-enrichment.ts +45 -0
  232. package/src/shared/build/frame-bundle-plugins.ts +61 -0
  233. package/src/shared/build-mode.ts +28 -0
  234. package/src/shared/config/evidence-read.ts +98 -0
  235. package/src/shared/config/limits.ts +56 -0
  236. package/src/shared/config/paths.ts +96 -0
  237. package/src/shared/contracts/artifact-types.ts +2 -0
  238. package/src/shared/contracts/artifact.ts +98 -0
  239. package/src/shared/contracts/commands/_shared.ts +59 -0
  240. package/src/shared/contracts/commands/guards.ts +86 -0
  241. package/src/shared/contracts/commands/index.ts +204 -0
  242. package/src/shared/contracts/commands/names.ts +35 -0
  243. package/src/shared/contracts/commands/requests.ts +149 -0
  244. package/src/shared/contracts/commands/results.ts +200 -0
  245. package/src/shared/contracts/envelope.ts +140 -0
  246. package/src/shared/contracts/events.ts +41 -0
  247. package/src/shared/contracts/observed-counts.ts +19 -0
  248. package/src/shared/contracts/renderers.ts +6 -0
  249. package/src/shared/contracts/validation.ts +296 -0
  250. package/src/shared/errors/facet-error.ts +127 -0
  251. package/src/shared/errors/store-error.ts +68 -0
  252. package/src/shared/evidence-image.ts +37 -0
  253. package/src/shared/export.ts +31 -0
  254. package/src/shared/html/policy.ts +108 -0
  255. package/src/shared/html/style-vocabulary.ts +352 -0
  256. package/src/shared/logging/logger.ts +108 -0
  257. package/src/shared/logging/redact.ts +49 -0
  258. package/src/shared/security/frozen-csp.ts +13 -0
  259. package/src/shared/storage-version.ts +2 -0
  260. package/src/shared/tsx/execution.ts +29 -0
  261. package/src/shared/tsx/import-policy.ts +94 -0
  262. package/src/shared/util/dir-permissions.ts +94 -0
  263. package/src/shared/util/mermaid-nodes.ts +230 -0
  264. package/src/shared/util/process.ts +67 -0
  265. package/src/shared/util/time.ts +21 -0
  266. package/src/shared/version.ts +3 -0
  267. package/src/validation/sandbox/limits.ts +41 -0
  268. package/src/validation/sandbox/netns.ts +177 -0
  269. package/src/validation/tier0/chart.ts +177 -0
  270. package/src/validation/tier0/dom-shim.ts +54 -0
  271. package/src/validation/tier0/html.ts +408 -0
  272. package/src/validation/tier0/markdown.ts +285 -0
  273. package/src/validation/tier0/mermaid.ts +98 -0
  274. package/src/validation/tier0/runner.ts +504 -0
  275. package/src/validation/tier0/svg.ts +321 -0
  276. package/src/validation/tier0/tsx/allowlist-resolver.ts +77 -0
  277. package/src/validation/tier0/tsx/ast-policy-capabilities.ts +238 -0
  278. package/src/validation/tier0/tsx/ast-policy-shared.ts +71 -0
  279. package/src/validation/tier0/tsx/ast-policy.ts +181 -0
  280. package/src/validation/tier0/tsx/compiler.ts +156 -0
  281. package/src/validation/tier0/worker-dispatch.ts +211 -0
  282. package/src/validation/tier0/worker-entry.ts +96 -0
  283. package/src/validation/tier0/worker-input.ts +75 -0
  284. package/src/validation/tier1/browser-process.ts +147 -0
  285. package/src/validation/tier1/cdp-pipe.ts +281 -0
  286. package/src/validation/tier1/entries/chart.ts +5 -0
  287. package/src/validation/tier1/entries/html.ts +6 -0
  288. package/src/validation/tier1/entries/markdown.ts +5 -0
  289. package/src/validation/tier1/entries/mermaid.ts +5 -0
  290. package/src/validation/tier1/entries/svg.ts +5 -0
  291. package/src/validation/tier1/entries/tsx.ts +5 -0
  292. package/src/validation/tier1/frame-target.ts +162 -0
  293. package/src/validation/tier1/harness-entry.ts +261 -0
  294. package/src/validation/tier1/harness.ts +215 -0
  295. package/src/validation/tier1/isolated-probe.ts +94 -0
  296. package/src/validation/tier1/launcher.ts +177 -0
  297. package/src/validation/tier1/limits.ts +80 -0
  298. package/src/validation/tier1/nonce.ts +17 -0
  299. package/src/validation/tier1/protocol-probe.ts +519 -0
  300. package/src/validation/tier1/runner.ts +1122 -0
  301. package/src/validation/tier1/verdict.ts +246 -0
  302. package/src/validation/tier1/webp.ts +69 -0
  303. package/templates/README.md +88 -0
  304. package/templates/bar-compare.vl.json +63 -0
  305. package/templates/capacity-report.tsx +102 -0
  306. package/templates/decision-record.md +24 -0
  307. package/templates/deployment-state.mmd +40 -0
  308. package/templates/exemplar.md +91 -0
  309. package/templates/facet-story.tsx +799 -0
  310. package/templates/fleet-dashboard.html +141 -0
  311. package/templates/html-release-ledger.html +91 -0
  312. package/templates/html-status-report.html +114 -0
  313. package/templates/incident-console.tsx +147 -0
  314. package/templates/legion-boundaries.mmd +23 -0
  315. package/templates/legion-flow.mmd +15 -0
  316. package/templates/legion-sequence.mmd +14 -0
  317. package/templates/legion-state.mmd +7 -0
  318. package/templates/metric-card.svg +29 -0
  319. package/templates/observability-map.svg +101 -0
  320. package/templates/pipeline-audit.md +108 -0
  321. package/templates/release-metrics.vl.json +98 -0
  322. package/templates/service-topology.mmd +47 -0
  323. package/templates/status-report.md +32 -0
  324. package/templates/system-map.svg +53 -0
  325. package/templates/timeseries.vl.json +71 -0
  326. package/templates/tsx-interactive-counter.tsx +19 -0
  327. package/templates/tsx-status-report.tsx +31 -0
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Isolated-world probe — evaluate counts inside the pre-created
3
+ * execution context (`Page.createIsolatedWorld`). The isolated world
4
+ * is OUTSIDE the page's JavaScript scope: a hostile artifact that
5
+ * monkey-patched `document.querySelectorAll` (Test A) cannot reach
6
+ * it. Counts taken here are the third authority channel after
7
+ * `DOMSnapshot` and `DOM.getDocument`.
8
+ *
9
+ * Failure to evaluate returns null — the verifier falls back to
10
+ * `shim_only` instead of `tampered` because a missing isolated
11
+ * world is a probe-level failure, not a page-world divergence.
12
+ *
13
+ * `graphCount` matches the protocol probe: one count per
14
+ * renderer-owned `<svg>`. `mermaidNodeCount` sums the `g.node`
15
+ * descendants. Those renderer counts are marker-scoped; opaque regions
16
+ * deliberately census every owning `<canvas>` in the frame document so
17
+ * smuggled canvases cannot hide outside a marked root. The probe never
18
+ * calls getContext(), which would create an observation.
19
+ */
20
+
21
+ import type { ProtocolObservation } from "../../shared/contracts/validation";
22
+ import { HTML_STRUCTURAL_GROUPS } from "../../shared/html/policy";
23
+
24
+ import type { VerifierCdpSession } from "./browser-process";
25
+
26
+ export async function probeIsolatedCounts(
27
+ session: VerifierCdpSession,
28
+ executionContextId: number,
29
+ ): Promise<ProtocolObservation | null> {
30
+ try {
31
+ const selectors = Object.fromEntries(
32
+ Object.entries(HTML_STRUCTURAL_GROUPS).map(([group, names]) => [group, names.join(",")]),
33
+ );
34
+ const result = (await session.send("Runtime.evaluate", {
35
+ contextId: executionContextId,
36
+ returnByValue: true,
37
+ expression: [
38
+ "(function(){",
39
+ " var candidates = Array.prototype.slice.call(document.querySelectorAll('[data-facet-renderer-root=\"true\"]'));",
40
+ " var candidateSet = new Set(candidates);",
41
+ " var roots = candidates.filter(function(root){",
42
+ " for (var parent = root.parentElement; parent; parent = parent.parentElement) {",
43
+ " if (candidateSet.has(parent)) return false;",
44
+ " }",
45
+ " return true;",
46
+ " });",
47
+ " var svgRoots = roots.filter(function(root){ return String(root.nodeName).toLowerCase() === 'svg'; });",
48
+ " var graphRoots = svgRoots.filter(function(root){ return root.getAttribute('data-facet-renderer-graph') === 'true'; });",
49
+ " var htmlRoots = roots.filter(function(root){ return String(root.nodeName).toLowerCase() !== 'svg'; });",
50
+ ` var selectors = ${JSON.stringify(selectors)};`,
51
+ " var html = htmlRoots.length === 0 ? null : {rendererRootCount:htmlRoots.length,headingCount:0,tableCount:0,listCount:0,imageCount:0,canvasCount:0,externalImageCount:0};",
52
+ " var externalImageCount = 0;",
53
+ " for (var h = 0; h < htmlRoots.length; h++) {",
54
+ " var htmlRoot = htmlRoots[h];",
55
+ " html.headingCount += htmlRoot.querySelectorAll(selectors.headings).length;",
56
+ " html.tableCount += htmlRoot.querySelectorAll(selectors.tables).length;",
57
+ " html.listCount += htmlRoot.querySelectorAll(selectors.lists).length;",
58
+ " var images = Array.prototype.slice.call(htmlRoot.querySelectorAll(selectors.images));",
59
+ " html.imageCount += images.length;",
60
+ " var rootExternal = images.filter(function(image){ try { return new URL(image.getAttribute('src') || '').protocol === 'https:'; } catch (_) { return false; } }).length;",
61
+ " html.externalImageCount += rootExternal;",
62
+ " externalImageCount += rootExternal;",
63
+ " html.canvasCount += htmlRoot.querySelectorAll(selectors.canvases).length;",
64
+ " }",
65
+ " var nodeCount = 0;",
66
+ " var visibleSvgCount = 0;",
67
+ " for (var i = 0; i < svgRoots.length; i++) {",
68
+ " var vb = svgRoots[i].getAttribute('viewBox') || '';",
69
+ " var parts = vb.trim().split(/[\\s,]+/).map(Number.parseFloat);",
70
+ " if (parts.length === 4 && Number.isFinite(parts[2]) && Number.isFinite(parts[3]) && parts[2] > 0 && parts[3] > 0) visibleSvgCount += 1;",
71
+ " }",
72
+ " for (var j = 0; j < graphRoots.length; j++) nodeCount += graphRoots[j].querySelectorAll('g.node').length;",
73
+ " var errorCount = document.querySelectorAll('[data-facet-error]').length;",
74
+ " var opaqueRegionCount = Array.prototype.slice.call(document.querySelectorAll('*')).filter(function(el){ return String(el.nodeName).toLowerCase() === 'canvas'; }).length;",
75
+ " return {",
76
+ " rendererRootSvgCount: svgRoots.length,",
77
+ " graphCount: graphRoots.length,",
78
+ " mermaidNodeCount: nodeCount,",
79
+ " visibleSvgCount: visibleSvgCount,",
80
+ " viewBoxes: [],",
81
+ " errorCount: errorCount,",
82
+ " opaqueRegionCount: opaqueRegionCount,",
83
+ " externalImageCount: externalImageCount,",
84
+ " discriminativeErrors: [],",
85
+ " ...(html === null ? {} : {html: html})",
86
+ " };",
87
+ "})()",
88
+ ].join("\n"),
89
+ })) as { result: { value?: ProtocolObservation } };
90
+ return result.result.value ?? null;
91
+ } catch {
92
+ return null;
93
+ }
94
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Resolves the PINNED chrome-headless-shell binary and the production
3
+ * netns wrapper. Both paths live behind narrow helpers so the runner
4
+ * never inlines a path string and so the egress penetration harness
5
+ * can share the same lookup logic.
6
+ *
7
+ * The wrapper script (`scripts/launch-netns.sh`) is the egress boundary
8
+ * — `unshare --map-current-user --net --` removes every reachable
9
+ * interface, route, and DNS context from the browser process. A future
10
+ * regression that swaps the wrapper for a plain chromium exec would
11
+ * silently re-enable off-loopback traffic; the harness's CI test would
12
+ * catch that, but the path resolution here is the only place that
13
+ * names the wrapper script.
14
+ *
15
+ * The shell binary is pinned per ADR 0001 D3. The cache layout matches
16
+ * what `puppeteer` writes under `~/.cache/puppeteer/chrome-headless-shell/`.
17
+ */
18
+
19
+ import { existsSync } from "node:fs";
20
+ import { homedir } from "node:os";
21
+ import { join } from "node:path";
22
+
23
+ import { InsecureLevelSchema, type InsecureLevel } from "../../shared/contracts/validation";
24
+ import { TIER1_PINNED_VERSION } from "./limits";
25
+
26
+ const ENV_PINNED_VERSION = "FACET_TIER1_PINNED_VERSION";
27
+ const ENV_CACHE_DIR = "FACET_TIER1_BROWSER_CACHE";
28
+ // Test-only seam: production callers resolve the repository wrapper path.
29
+ const ENV_NETNS_WRAPPER = "FACET_TIER1_NETNS_WRAPPER";
30
+
31
+ /**
32
+ * A pair of resolved paths the runner hands to puppeteer-core. The
33
+ * wrapper (`executablePath`) is what puppeteer-core actually `exec`s;
34
+ * `binaryPath` records the absolute path to the shell inside the
35
+ * wrapper's argv so a failure diagnostic can cite it.
36
+ */
37
+ export interface ResolvedLauncher {
38
+ readonly executablePath: string;
39
+ readonly binaryPath: string;
40
+ readonly pinnedVersion: string;
41
+ }
42
+
43
+ type LauncherOverrides = {
44
+ readonly version?: string;
45
+ readonly cacheRoot?: string;
46
+ readonly wrapperPath?: string;
47
+ };
48
+
49
+ /**
50
+ * Default lookup locations for the cached shell. The cache directory
51
+ * layout matches what `puppeteer browsers install chrome-headless-shell`
52
+ * writes — pinning that layout here means the project does not need
53
+ * its own installer.
54
+ */
55
+ function defaultCacheRoot(): string {
56
+ return join(homedir(), ".cache", "puppeteer", "chrome-headless-shell");
57
+ }
58
+
59
+ /** Read an env var or return undefined. */
60
+ function readEnv(name: string): string | undefined {
61
+ const value = process.env[name];
62
+ return value !== undefined && value.length > 0 ? value : undefined;
63
+ }
64
+
65
+ /**
66
+ * Probe the cache layout for the pinned shell. Returns null when no
67
+ * candidate file exists; the caller turns that into a typed
68
+ * `tier1_launcher_missing` error.
69
+ */
70
+ export function resolveShellBinary(
71
+ overrides: { readonly version?: string; readonly cacheRoot?: string } = {},
72
+ ): string | null {
73
+ const version = overrides.version ?? readEnv(ENV_PINNED_VERSION) ?? TIER1_PINNED_VERSION;
74
+ const cacheRoot = overrides.cacheRoot ?? readEnv(ENV_CACHE_DIR) ?? defaultCacheRoot();
75
+ const candidates = [
76
+ join(cacheRoot, version, "chrome-headless-shell-linux64", "chrome-headless-shell"),
77
+ join(cacheRoot, `linux-${version}`, "chrome-headless-shell-linux64", "chrome-headless-shell"),
78
+ join(cacheRoot, version, "chrome-headless-shell"),
79
+ ];
80
+ for (const candidate of candidates) {
81
+ if (existsSync(candidate)) return candidate;
82
+ }
83
+ return null;
84
+ }
85
+
86
+ /**
87
+ * Resolve the production netns wrapper script. The wrapper is the
88
+ * only egress boundary — when it is missing, callers surface a typed
89
+ * `tier1_unavailable` instead of falling back to a plain exec.
90
+ */
91
+ export function resolveNetnsWrapper(overrides: { readonly wrapperPath?: string } = {}): string {
92
+ const override = overrides.wrapperPath ?? readEnv(ENV_NETNS_WRAPPER);
93
+ if (override !== undefined) return override;
94
+ const fromRepo = join(process.cwd(), "scripts", "launch-netns.sh");
95
+ if (existsSync(fromRepo)) return fromRepo;
96
+ const fromSibling = join(import.meta.dir, "..", "..", "..", "scripts", "launch-netns.sh");
97
+ return fromSibling;
98
+ }
99
+
100
+ /**
101
+ * The Puppeteer-compatible browser args. Every flag here is required:
102
+ *
103
+ * - `--headless=new` selects the modern headless mode that owns the
104
+ * same renderer as full Chrome.
105
+ * - `--no-sandbox` is OMITTED — we keep Chromium's browser sandbox
106
+ * (the netns wrapper passes `--map-current-user` so the user is
107
+ * not mapped to root, and the renderer retains its sandbox).
108
+ * - `--no-first-run`, `--disable-background-networking`,
109
+ * `--disable-component-update`, `--disable-default-apps`,
110
+ * `--disable-sync` keep first-launch noise and network from
111
+ * contaminating an isolated run.
112
+ * - `--user-data-dir=$tmp/...` plus the verifier's profile-mode
113
+ * (0o700) keeps the on-disk footprint ephemeral.
114
+ *
115
+ * `--single-process --no-zygote` are NOT used. The Phase-0 fidelity
116
+ * spike relied on them to bound the process tree, but the pinned
117
+ * The pinned build aborts the CDP target during `newPage()` when
118
+ * those flags are present (verified empirically against the wrapper).
119
+ * The multi-process model is fine inside an isolated verifier run
120
+ * because every renderer lives under the same netns pid and exits
121
+ * when the wrapper does.
122
+ *
123
+ * CDP transport (`--remote-debugging-pipe`) is added by puppeteer-core
124
+ * itself when `pipe: true` is set on the launch options; the netns
125
+ * wrapper inherits the pipe through `exec`.
126
+ */
127
+ export function buildBrowserArgs(userDataDir: string): readonly string[] {
128
+ return [
129
+ "--headless=new",
130
+ "--no-first-run",
131
+ "--disable-background-networking",
132
+ "--disable-component-update",
133
+ "--disable-default-apps",
134
+ "--disable-sync",
135
+ "--disable-features=AutofillServerCommunication,OptimizationHints",
136
+ `--user-data-dir=${userDataDir}`,
137
+ ];
138
+ }
139
+
140
+ /**
141
+ * Resolve every launcher path needed for a single run. Throws a
142
+ * plain `Error` (not `FacetError`) because the verifier is the only
143
+ * caller and maps the error into a typed `tier1_launcher_missing` or
144
+ * `tier1_unavailable` upstream.
145
+ */
146
+ export function resolveLauncher(
147
+ level: InsecureLevel,
148
+ overrides?: LauncherOverrides,
149
+ ): ResolvedLauncher;
150
+ export function resolveLauncher(overrides?: LauncherOverrides): ResolvedLauncher;
151
+ export function resolveLauncher(
152
+ levelOrOverrides: InsecureLevel | LauncherOverrides = 0,
153
+ passedOverrides: LauncherOverrides = {},
154
+ ): ResolvedLauncher {
155
+ const level = typeof levelOrOverrides === "number" ? levelOrOverrides : 0;
156
+ const overrides = typeof levelOrOverrides === "number" ? passedOverrides : levelOrOverrides;
157
+ InsecureLevelSchema.parse(level);
158
+ const binaryPath = resolveShellBinary({
159
+ ...(overrides.version !== undefined ? { version: overrides.version } : {}),
160
+ ...(overrides.cacheRoot !== undefined ? { cacheRoot: overrides.cacheRoot } : {}),
161
+ });
162
+ if (binaryPath === null) {
163
+ throw new Error(
164
+ `pinned chrome-headless-shell ${overrides.version ?? TIER1_PINNED_VERSION} not found in cache`,
165
+ );
166
+ }
167
+ return {
168
+ executablePath:
169
+ level === 0
170
+ ? resolveNetnsWrapper(
171
+ overrides.wrapperPath !== undefined ? { wrapperPath: overrides.wrapperPath } : {},
172
+ )
173
+ : binaryPath,
174
+ binaryPath,
175
+ pinnedVersion: overrides.version ?? TIER1_PINNED_VERSION,
176
+ };
177
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Resource caps for the Tier 1 verifier.
3
+ *
4
+ * Each cap is named and exposed so the runner, the harness builder,
5
+ * and the penetration test agree on a single value. A failing cap
6
+ * produces a typed `FacetError` with the matching `tier1_*` code.
7
+ */
8
+
9
+ /**
10
+ * Wall-clock budget for one Tier 1 verifier invocation. The harness
11
+ * bundles the REAL renderers (mermaid + marked + vega, ~8 MB inline);
12
+ * parse + first render of a 40-node fixture needs real headroom.
13
+ */
14
+ export const TIER1_TIMEOUT_MS = 60_000;
15
+
16
+ /**
17
+ * Path to the pinned `chrome-headless-shell` distribution. The release
18
+ * manifest pins a specific revision; the default resolves the first
19
+ * match under `~/.cache/puppeteer/chrome-headless-shell/`. Tests inject
20
+ * a custom resolver so the path does not become load-bearing on a
21
+ * specific dev workstation.
22
+ */
23
+ export { TIER1_PINNED_VERSION } from "../../shared/config/limits";
24
+
25
+ /** Network namespace label recorded with each Tier 1 run. */
26
+ export const TIER1_NETWORK_NAMESPACE = "facet-tier1-egress-isolated";
27
+
28
+ /** Lifetime of the ephemeral browser user-data directory (mode 0700). */
29
+ export const TIER1_USER_DATA_DIR_MODE = 0o700;
30
+
31
+ /**
32
+ * Per-render timeout the verifier waits for the trusted
33
+ * `render-complete` barrier before classifying the run as `timeout`.
34
+ * Sized for the real mermaid runtime: first-render initialization of
35
+ * the bundled runtime plus a 40-node layout must fit inside.
36
+ */
37
+ export const TIER1_RENDER_BARRIER_MS = 30_000;
38
+
39
+ /**
40
+ * Time between the first interactive TSX observation and its bounded
41
+ * stability re-check. It stays below the headroom after the render barrier so
42
+ * a typed `partial:unstable` verdict remains observable before Tier 1 times out.
43
+ */
44
+ export const TSX_STABILITY_WINDOW_MS = 1_000;
45
+
46
+ /**
47
+ * Ceiling for any single CDP call. Every protocol round-trip in a
48
+ * healthy session completes in well under a second; a call that
49
+ * outlives this budget means the pipe transport silently wedged
50
+ * (observed: a browser spawned immediately after another browser's
51
+ * teardown can have its devtools pipe torn down while the process
52
+ * stays alive — every subsequent call pends forever). The runner
53
+ * treats the typed rejection as retryable and relaunches once.
54
+ */
55
+ export const TIER1_CDP_CALL_WATCHDOG_MS = 10_000;
56
+
57
+ /** Screenshot evidence has a tighter deadline than the verifier transport watchdog. */
58
+ export const TIER1_SCREENSHOT_CAPTURE_TIMEOUT_MS = 2_000;
59
+ export const TIER1_SCREENSHOT_CAPTURE_ATTEMPTS = 2;
60
+
61
+ /** Deterministic viewport used for Tier 1 layout and screenshot evidence. */
62
+ export const TIER1_VIEWPORT_WIDTH = 1280;
63
+ export const TIER1_VIEWPORT_HEIGHT = 800;
64
+
65
+ /** Maximum CSS axis length for a whole-artifact evidence image. */
66
+ export const TIER1_SCREENSHOT_MAX_AXIS_PX = 4096;
67
+
68
+ /** Maximum decoded pixel count for a whole-artifact evidence image. */
69
+ export const TIER1_SCREENSHOT_MAX_PIXELS = 8_388_608;
70
+
71
+ /** Static evidence uses WebP at this quality. */
72
+ export const TIER1_SCREENSHOT_WEBP_QUALITY = 82;
73
+
74
+ /** Animated evidence samples four frames at fixed browser-time intervals. */
75
+ export const TIER1_ANIMATION_FRAME_COUNT = 4;
76
+ export const TIER1_ANIMATION_FRAME_INTERVAL_MS = 150;
77
+ export const TIER1_ANIMATION_WEBP_QUALITIES = [TIER1_SCREENSHOT_WEBP_QUALITY, 70, 55] as const;
78
+
79
+ /** Whole-artifact evidence above this cap after scaling and quality fallback is screenshot_unavailable. */
80
+ export const TIER1_SCREENSHOT_CAP_BYTES = 8 * 1024 * 1024;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Per-frame nonce for the Tier 1 verification harness.
3
+ *
4
+ * Cryptographically random; the harness pins it into the CSP meta and
5
+ * the <script nonce> for the same srcdoc so only that inlined bundle
6
+ * executes. A regression that reuses a nonce across builds would let a
7
+ * stale bundle survive a CSP bypass attempt.
8
+ *
9
+ * Kept separate from gallery-web so the gallery frame bundle cannot
10
+ * accidentally pull in any Tier 1 import.
11
+ */
12
+
13
+ export function freshHarnessNonce(): string {
14
+ const bytes = new Uint8Array(16);
15
+ crypto.getRandomValues(bytes);
16
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
17
+ }