@intentius/chant 0.13.0 → 0.15.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 (453) hide show
  1. package/dist/audit/catalog.d.ts +45 -5
  2. package/dist/audit/catalog.d.ts.map +1 -1
  3. package/dist/audit/fetch.d.ts.map +1 -1
  4. package/dist/audit/proof.d.ts +3 -0
  5. package/dist/audit/proof.d.ts.map +1 -1
  6. package/dist/audit/report-model.d.ts +4 -1
  7. package/dist/audit/report-model.d.ts.map +1 -1
  8. package/dist/audit/report.d.ts +3 -0
  9. package/dist/audit/report.d.ts.map +1 -1
  10. package/dist/audit/rules-doc.d.ts +8 -2
  11. package/dist/audit/rules-doc.d.ts.map +1 -1
  12. package/dist/cli/commands/audit.d.ts.map +1 -1
  13. package/dist/cli/commands/doctor.d.ts.map +1 -1
  14. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
  15. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
  16. package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
  17. package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
  18. package/dist/cli/commands/lint.d.ts.map +1 -1
  19. package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
  20. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
  21. package/dist/cli/handlers/build.d.ts.map +1 -1
  22. package/dist/cli/handlers/components.d.ts +39 -0
  23. package/dist/cli/handlers/components.d.ts.map +1 -0
  24. package/dist/cli/handlers/dev.d.ts +3 -0
  25. package/dist/cli/handlers/dev.d.ts.map +1 -1
  26. package/dist/cli/handlers/graph.d.ts +4 -2
  27. package/dist/cli/handlers/graph.d.ts.map +1 -1
  28. package/dist/cli/handlers/misc.d.ts.map +1 -1
  29. package/dist/cli/handlers/run.d.ts +49 -0
  30. package/dist/cli/handlers/run.d.ts.map +1 -1
  31. package/dist/cli/main.d.ts.map +1 -1
  32. package/dist/cli/registry.d.ts +35 -0
  33. package/dist/cli/registry.d.ts.map +1 -1
  34. package/dist/codegen/fetch.d.ts +22 -0
  35. package/dist/codegen/fetch.d.ts.map +1 -1
  36. package/dist/codegen/lexicon-regen.d.ts +110 -0
  37. package/dist/codegen/lexicon-regen.d.ts.map +1 -0
  38. package/dist/codegen/pinned-upgrade.d.ts +153 -0
  39. package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
  40. package/dist/codegen/rolling-upgrade.d.ts +138 -0
  41. package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
  42. package/dist/codegen/surface-snapshot.d.ts +173 -0
  43. package/dist/codegen/surface-snapshot.d.ts.map +1 -0
  44. package/dist/codegen/version-bump.d.ts +21 -0
  45. package/dist/codegen/version-bump.d.ts.map +1 -0
  46. package/dist/components/auto-release.d.ts +93 -0
  47. package/dist/components/auto-release.d.ts.map +1 -0
  48. package/dist/components/builders.d.ts +37 -0
  49. package/dist/components/builders.d.ts.map +1 -0
  50. package/dist/components/capability-plugin-loader.d.ts +111 -0
  51. package/dist/components/capability-plugin-loader.d.ts.map +1 -0
  52. package/dist/components/capability-plugin-schema.d.ts +24 -0
  53. package/dist/components/capability-plugin-schema.d.ts.map +1 -0
  54. package/dist/components/capability-plugin.d.ts +85 -0
  55. package/dist/components/capability-plugin.d.ts.map +1 -0
  56. package/dist/components/capability.d.ts +89 -0
  57. package/dist/components/capability.d.ts.map +1 -0
  58. package/dist/components/cli-support.d.ts +204 -0
  59. package/dist/components/cli-support.d.ts.map +1 -0
  60. package/dist/components/component.d.ts +179 -0
  61. package/dist/components/component.d.ts.map +1 -0
  62. package/dist/components/config-defaults.d.ts +41 -0
  63. package/dist/components/config-defaults.d.ts.map +1 -0
  64. package/dist/components/discover.d.ts +60 -0
  65. package/dist/components/discover.d.ts.map +1 -0
  66. package/dist/components/driver-output.d.ts +20 -0
  67. package/dist/components/driver-output.d.ts.map +1 -0
  68. package/dist/components/driver.d.ts +209 -0
  69. package/dist/components/driver.d.ts.map +1 -0
  70. package/dist/components/index.d.ts +22 -0
  71. package/dist/components/index.d.ts.map +1 -0
  72. package/dist/components/manifest-persistence.d.ts +79 -0
  73. package/dist/components/manifest-persistence.d.ts.map +1 -0
  74. package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
  75. package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
  76. package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
  77. package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
  78. package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
  79. package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
  80. package/dist/components/pilots/lambda.pilot.d.ts +35 -0
  81. package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
  82. package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
  83. package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
  84. package/dist/components/pilots/project.d.ts +13 -0
  85. package/dist/components/pilots/project.d.ts.map +1 -0
  86. package/dist/components/presets/ecs-fargate.d.ts +59 -0
  87. package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
  88. package/dist/components/presets/index.d.ts +29 -0
  89. package/dist/components/presets/index.d.ts.map +1 -0
  90. package/dist/components/presets/lambda.d.ts +35 -0
  91. package/dist/components/presets/lambda.d.ts.map +1 -0
  92. package/dist/components/presets/single-host-compose.d.ts +43 -0
  93. package/dist/components/presets/single-host-compose.d.ts.map +1 -0
  94. package/dist/components/registry.d.ts +29 -0
  95. package/dist/components/registry.d.ts.map +1 -0
  96. package/dist/components/starter-plugin.d.ts +51 -0
  97. package/dist/components/starter-plugin.d.ts.map +1 -0
  98. package/dist/components/temporal-codegen-loader.d.ts +27 -0
  99. package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
  100. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
  101. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
  102. package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
  103. package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
  104. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
  105. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
  106. package/dist/components/verbs/bom-writer.d.ts +155 -0
  107. package/dist/components/verbs/bom-writer.d.ts.map +1 -0
  108. package/dist/components/verbs/build-archive.d.ts +205 -0
  109. package/dist/components/verbs/build-archive.d.ts.map +1 -0
  110. package/dist/components/verbs/build.d.ts +150 -0
  111. package/dist/components/verbs/build.d.ts.map +1 -0
  112. package/dist/components/verbs/cloud-executor.d.ts +88 -0
  113. package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
  114. package/dist/components/verbs/component-bom.d.ts +103 -0
  115. package/dist/components/verbs/component-bom.d.ts.map +1 -0
  116. package/dist/components/verbs/index.d.ts +49 -0
  117. package/dist/components/verbs/index.d.ts.map +1 -0
  118. package/dist/components/verbs/license-policy.d.ts +56 -0
  119. package/dist/components/verbs/license-policy.d.ts.map +1 -0
  120. package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
  121. package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
  122. package/dist/components/verbs/process-runner.d.ts +64 -0
  123. package/dist/components/verbs/process-runner.d.ts.map +1 -0
  124. package/dist/components/verbs/reproducibility.d.ts +80 -0
  125. package/dist/components/verbs/reproducibility.d.ts.map +1 -0
  126. package/dist/components/verbs/sbom-generator.d.ts +157 -0
  127. package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
  128. package/dist/components/verbs/sbom.d.ts +79 -0
  129. package/dist/components/verbs/sbom.d.ts.map +1 -0
  130. package/dist/components/verbs/shell.d.ts +35 -0
  131. package/dist/components/verbs/shell.d.ts.map +1 -0
  132. package/dist/components/verbs/sign.d.ts +222 -0
  133. package/dist/components/verbs/sign.d.ts.map +1 -0
  134. package/dist/components/verbs/stub.d.ts +18 -0
  135. package/dist/components/verbs/stub.d.ts.map +1 -0
  136. package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
  137. package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
  138. package/dist/components/verbs/verify.d.ts +106 -0
  139. package/dist/components/verbs/verify.d.ts.map +1 -0
  140. package/dist/components/verbs/vex.d.ts +65 -0
  141. package/dist/components/verbs/vex.d.ts.map +1 -0
  142. package/dist/components/verbs/vuln-gate.d.ts +91 -0
  143. package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
  144. package/dist/components/verbs/vuln-scan.d.ts +116 -0
  145. package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
  146. package/dist/components/verbs/wait-verify.d.ts +85 -0
  147. package/dist/components/verbs/wait-verify.d.ts.map +1 -0
  148. package/dist/config.d.ts +205 -0
  149. package/dist/config.d.ts.map +1 -1
  150. package/dist/index.d.ts +4 -0
  151. package/dist/index.d.ts.map +1 -1
  152. package/dist/lexicon.d.ts +78 -0
  153. package/dist/lexicon.d.ts.map +1 -1
  154. package/dist/lifecycle/build-ledger-store.d.ts +121 -0
  155. package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
  156. package/dist/lifecycle/build-ledger.d.ts +225 -0
  157. package/dist/lifecycle/build-ledger.d.ts.map +1 -0
  158. package/dist/lifecycle/git.d.ts +84 -0
  159. package/dist/lifecycle/git.d.ts.map +1 -1
  160. package/dist/lifecycle/index.d.ts +5 -0
  161. package/dist/lifecycle/index.d.ts.map +1 -1
  162. package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
  163. package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
  164. package/dist/lifecycle/release-ledger.d.ts +122 -0
  165. package/dist/lifecycle/release-ledger.d.ts.map +1 -0
  166. package/dist/lifecycle/status.d.ts +150 -0
  167. package/dist/lifecycle/status.d.ts.map +1 -0
  168. package/dist/lint/component-checks.d.ts +95 -0
  169. package/dist/lint/component-checks.d.ts.map +1 -0
  170. package/dist/lint/engine.d.ts +23 -0
  171. package/dist/lint/engine.d.ts.map +1 -1
  172. package/dist/lint/presets/strict.json +8 -1
  173. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
  174. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
  175. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
  176. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
  177. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
  178. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
  179. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
  180. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
  181. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
  182. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
  183. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
  184. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
  185. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
  186. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
  187. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
  188. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
  189. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
  190. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
  191. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
  192. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
  193. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
  194. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
  195. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
  196. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
  197. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
  198. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
  199. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
  200. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
  201. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
  202. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
  203. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
  204. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
  205. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
  206. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
  207. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
  208. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
  209. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
  210. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
  211. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
  212. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
  213. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
  214. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
  215. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
  216. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
  217. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
  218. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
  219. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
  220. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
  221. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
  222. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
  223. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
  224. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
  225. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
  226. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
  227. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
  228. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
  229. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
  230. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
  231. package/dist/lint/rules/comp/index.d.ts +18 -0
  232. package/dist/lint/rules/comp/index.d.ts.map +1 -0
  233. package/dist/lint/rules/comp/support.d.ts +71 -0
  234. package/dist/lint/rules/comp/support.d.ts.map +1 -0
  235. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  236. package/dist/op/activity-registry.d.ts +11 -6
  237. package/dist/op/activity-registry.d.ts.map +1 -1
  238. package/dist/op/activity-runtime.d.ts +24 -0
  239. package/dist/op/activity-runtime.d.ts.map +1 -0
  240. package/dist/op/builders.d.ts +56 -0
  241. package/dist/op/builders.d.ts.map +1 -1
  242. package/dist/op/index.d.ts +2 -1
  243. package/dist/op/index.d.ts.map +1 -1
  244. package/dist/ownership.d.ts +20 -14
  245. package/dist/ownership.d.ts.map +1 -1
  246. package/package.json +14 -1
  247. package/src/audit/catalog.test.ts +74 -22
  248. package/src/audit/catalog.ts +74 -471
  249. package/src/audit/fetch.test.ts +112 -8
  250. package/src/audit/fetch.ts +53 -8
  251. package/src/audit/proof.ts +4 -2
  252. package/src/audit/report-html.test.ts +14 -7
  253. package/src/audit/report-model.ts +20 -9
  254. package/src/audit/report.test.ts +36 -13
  255. package/src/audit/report.ts +2 -0
  256. package/src/audit/rules-doc.test.ts +8 -6
  257. package/src/audit/rules-doc.ts +13 -5
  258. package/src/cli/commands/audit.ts +23 -18
  259. package/src/cli/commands/component-lint.test.ts +158 -0
  260. package/src/cli/commands/doctor.test.ts +116 -2
  261. package/src/cli/commands/doctor.ts +46 -0
  262. package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
  263. package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
  264. package/src/cli/commands/lexicon-surface-diff.ts +185 -0
  265. package/src/cli/commands/lint.ts +142 -1
  266. package/src/cli/commands/pinned-upgrade.ts +204 -0
  267. package/src/cli/handlers/build.ts +58 -1
  268. package/src/cli/handlers/components.test.ts +504 -0
  269. package/src/cli/handlers/components.ts +404 -0
  270. package/src/cli/handlers/dev.ts +60 -1
  271. package/src/cli/handlers/graph.ts +47 -2
  272. package/src/cli/handlers/misc.ts +45 -1
  273. package/src/cli/handlers/run.test.ts +967 -3
  274. package/src/cli/handlers/run.ts +618 -11
  275. package/src/cli/main.test.ts +66 -0
  276. package/src/cli/main.ts +105 -2
  277. package/src/cli/registry.ts +35 -0
  278. package/src/codegen/fetch.test.ts +84 -3
  279. package/src/codegen/fetch.ts +76 -2
  280. package/src/codegen/lexicon-regen.test.ts +298 -0
  281. package/src/codegen/lexicon-regen.ts +545 -0
  282. package/src/codegen/pinned-upgrade.test.ts +399 -0
  283. package/src/codegen/pinned-upgrade.ts +423 -0
  284. package/src/codegen/rolling-upgrade.test.ts +333 -0
  285. package/src/codegen/rolling-upgrade.ts +320 -0
  286. package/src/codegen/surface-snapshot.test.ts +461 -0
  287. package/src/codegen/surface-snapshot.ts +546 -0
  288. package/src/codegen/version-bump.test.ts +47 -0
  289. package/src/codegen/version-bump.ts +39 -0
  290. package/src/components/README.md +130 -0
  291. package/src/components/SPRAWL-VALIDATION.md +181 -0
  292. package/src/components/__fixtures__/alb-ecs-service.json +51 -0
  293. package/src/components/__fixtures__/dynamodb-infra.json +32 -0
  294. package/src/components/__fixtures__/emr-job-consumer.json +26 -0
  295. package/src/components/__fixtures__/jar-lib-producer.json +16 -0
  296. package/src/components/__fixtures__/lambda-image-processor.json +28 -0
  297. package/src/components/__fixtures__/neo4j-fanout.json +34 -0
  298. package/src/components/__fixtures__/single-host-compose.json +29 -0
  299. package/src/components/auto-release.test.ts +217 -0
  300. package/src/components/auto-release.ts +216 -0
  301. package/src/components/builders.test.ts +45 -0
  302. package/src/components/builders.ts +71 -0
  303. package/src/components/capability-plugin-loader.ts +218 -0
  304. package/src/components/capability-plugin-schema.ts +56 -0
  305. package/src/components/capability-plugin.test.ts +235 -0
  306. package/src/components/capability-plugin.ts +108 -0
  307. package/src/components/capability.ts +117 -0
  308. package/src/components/cli-support.test.ts +579 -0
  309. package/src/components/cli-support.ts +481 -0
  310. package/src/components/component-schema.test.ts +265 -0
  311. package/src/components/component.schema.json +235 -0
  312. package/src/components/component.test.ts +251 -0
  313. package/src/components/component.ts +255 -0
  314. package/src/components/config-defaults.test.ts +263 -0
  315. package/src/components/config-defaults.ts +145 -0
  316. package/src/components/discover.test.ts +352 -0
  317. package/src/components/discover.ts +167 -0
  318. package/src/components/driver-output.ts +71 -0
  319. package/src/components/driver.test.ts +638 -0
  320. package/src/components/driver.ts +690 -0
  321. package/src/components/index.ts +113 -0
  322. package/src/components/manifest-persistence.test.ts +152 -0
  323. package/src/components/manifest-persistence.ts +164 -0
  324. package/src/components/pilots/README.md +33 -0
  325. package/src/components/pilots/alb-ecs.pilot.ts +63 -0
  326. package/src/components/pilots/dynamodb.pilot.ts +59 -0
  327. package/src/components/pilots/jar-emr.pilot.ts +69 -0
  328. package/src/components/pilots/lambda.pilot.ts +55 -0
  329. package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
  330. package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
  331. package/src/components/pilots/pilots.test.ts +126 -0
  332. package/src/components/pilots/project.ts +13 -0
  333. package/src/components/presets/comp007-reduction.test.ts +122 -0
  334. package/src/components/presets/ecs-fargate.test.ts +84 -0
  335. package/src/components/presets/ecs-fargate.ts +103 -0
  336. package/src/components/presets/index.ts +32 -0
  337. package/src/components/presets/lambda.test.ts +35 -0
  338. package/src/components/presets/lambda.ts +53 -0
  339. package/src/components/presets/single-host-compose.test.ts +65 -0
  340. package/src/components/presets/single-host-compose.ts +64 -0
  341. package/src/components/registry.test.ts +112 -0
  342. package/src/components/registry.ts +37 -0
  343. package/src/components/starter-plugin.ts +105 -0
  344. package/src/components/temporal-codegen-loader.ts +41 -0
  345. package/src/components/verbs/__fixtures__/package-lock.json +45 -0
  346. package/src/components/verbs/__fixtures__/pom.xml +37 -0
  347. package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
  348. package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
  349. package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
  350. package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
  351. package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
  352. package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
  353. package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
  354. package/src/components/verbs/bom-writer.test.ts +331 -0
  355. package/src/components/verbs/bom-writer.ts +386 -0
  356. package/src/components/verbs/build-archive.test.ts +251 -0
  357. package/src/components/verbs/build-archive.ts +296 -0
  358. package/src/components/verbs/build.test.ts +222 -0
  359. package/src/components/verbs/build.ts +252 -0
  360. package/src/components/verbs/cloud-executor.ts +181 -0
  361. package/src/components/verbs/component-bom.test.ts +219 -0
  362. package/src/components/verbs/component-bom.ts +189 -0
  363. package/src/components/verbs/index.ts +49 -0
  364. package/src/components/verbs/license-policy.ts +115 -0
  365. package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
  366. package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
  367. package/src/components/verbs/process-runner.test.ts +79 -0
  368. package/src/components/verbs/process-runner.ts +113 -0
  369. package/src/components/verbs/reproducibility.test.ts +24 -0
  370. package/src/components/verbs/reproducibility.ts +100 -0
  371. package/src/components/verbs/sbom-generator.test.ts +96 -0
  372. package/src/components/verbs/sbom-generator.ts +209 -0
  373. package/src/components/verbs/sbom.test.ts +184 -0
  374. package/src/components/verbs/sbom.ts +152 -0
  375. package/src/components/verbs/shell.test.ts +36 -0
  376. package/src/components/verbs/shell.ts +51 -0
  377. package/src/components/verbs/sign.test.ts +210 -0
  378. package/src/components/verbs/sign.ts +350 -0
  379. package/src/components/verbs/stub.ts +34 -0
  380. package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
  381. package/src/components/verbs/tool-sbom-generator.ts +192 -0
  382. package/src/components/verbs/verify.test.ts +159 -0
  383. package/src/components/verbs/verify.ts +179 -0
  384. package/src/components/verbs/vex.ts +182 -0
  385. package/src/components/verbs/vuln-gate.test.ts +201 -0
  386. package/src/components/verbs/vuln-gate.ts +170 -0
  387. package/src/components/verbs/vuln-scan.test.ts +145 -0
  388. package/src/components/verbs/vuln-scan.ts +266 -0
  389. package/src/components/verbs/wait-verify.test.ts +111 -0
  390. package/src/components/verbs/wait-verify.ts +171 -0
  391. package/src/config.test.ts +74 -1
  392. package/src/config.ts +219 -0
  393. package/src/index.ts +32 -0
  394. package/src/lexicon.ts +88 -0
  395. package/src/lifecycle/build-ledger-store.test.ts +217 -0
  396. package/src/lifecycle/build-ledger-store.ts +165 -0
  397. package/src/lifecycle/build-ledger.test.ts +349 -0
  398. package/src/lifecycle/build-ledger.ts +305 -0
  399. package/src/lifecycle/git.test.ts +118 -0
  400. package/src/lifecycle/git.ts +149 -14
  401. package/src/lifecycle/index.ts +5 -0
  402. package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
  403. package/src/lifecycle/oras-referrer-lookup.ts +110 -0
  404. package/src/lifecycle/release-ledger.test.ts +209 -0
  405. package/src/lifecycle/release-ledger.ts +185 -0
  406. package/src/lifecycle/status.test.ts +330 -0
  407. package/src/lifecycle/status.ts +278 -0
  408. package/src/lint/component-checks.ts +148 -0
  409. package/src/lint/config.test.ts +21 -0
  410. package/src/lint/engine.ts +11 -2
  411. package/src/lint/presets/relaxed.json +8 -1
  412. package/src/lint/presets/strict.json +8 -1
  413. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
  414. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
  415. package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
  416. package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
  417. package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
  418. package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
  419. package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
  420. package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
  421. package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
  422. package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
  423. package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
  424. package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
  425. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
  426. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
  427. package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
  428. package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
  429. package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
  430. package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
  431. package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
  432. package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
  433. package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
  434. package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
  435. package/src/lint/rules/comp/comp.test.ts +378 -0
  436. package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
  437. package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
  438. package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
  439. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
  440. package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
  441. package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
  442. package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
  443. package/src/lint/rules/comp/index.ts +37 -0
  444. package/src/lint/rules/comp/support.ts +173 -0
  445. package/src/lsp/lexicon-providers.test.ts +55 -0
  446. package/src/lsp/lexicon-providers.ts +13 -3
  447. package/src/op/activity-registry.test.ts +38 -0
  448. package/src/op/activity-registry.ts +31 -12
  449. package/src/op/activity-runtime.ts +73 -0
  450. package/src/op/builders.ts +92 -0
  451. package/src/op/index.ts +3 -1
  452. package/src/ownership.test.ts +24 -26
  453. package/src/ownership.ts +26 -38
@@ -0,0 +1,461 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import {
3
+ extractSurface,
4
+ extractPropsFromDts,
5
+ diffSurface,
6
+ serializeSnapshot,
7
+ parseSnapshot,
8
+ formatDelta,
9
+ type SurfaceSnapshot,
10
+ } from "./surface-snapshot";
11
+
12
+ // ── Fixtures ──────────────────────────────────────────────────────────
13
+
14
+ const SIMPLE_LEXICON_JSON = JSON.stringify({
15
+ Bucket: {
16
+ kind: "resource",
17
+ resourceType: "AWS::S3::Bucket",
18
+ attrs: { WebsiteURL: "WebsiteURL", Arn: "Arn" },
19
+ createOnly: ["BucketName"],
20
+ tagging: { taggable: true, tagOnCreate: true, tagUpdatable: true },
21
+ },
22
+ Bucket_Tag: {
23
+ kind: "property",
24
+ resourceType: "AWS::S3::Bucket.Tag",
25
+ },
26
+ Function: {
27
+ kind: "resource",
28
+ resourceType: "AWS::Lambda::Function",
29
+ attrs: { Arn: "Arn" },
30
+ createOnly: [],
31
+ },
32
+ });
33
+
34
+ const SIMPLE_DTS = `
35
+ // Code generated by chant aws generate. DO NOT EDIT generated sections.
36
+
37
+ export declare class Bucket {
38
+ constructor(props: {
39
+ BucketName?: string;
40
+ Tags?: Bucket_Tag[];
41
+ }, attributes?: CFResourceAttributes);
42
+ readonly Arn: string;
43
+ readonly WebsiteURL: string;
44
+ }
45
+
46
+ export declare class Function {
47
+ constructor(props: {
48
+ Code: string;
49
+ Role: string;
50
+ FunctionName?: string;
51
+ }, attributes?: CFResourceAttributes);
52
+ readonly Arn: string;
53
+ }
54
+ `;
55
+
56
+ // ── extractPropsFromDts ───────────────────────────────────────────────
57
+
58
+ describe("extractPropsFromDts", () => {
59
+ test("extracts required and optional props from class declarations", () => {
60
+ const map = extractPropsFromDts(SIMPLE_DTS);
61
+
62
+ expect(map.has("Bucket")).toBe(true);
63
+ const bucketProps = map.get("Bucket")!;
64
+ // BucketName?: string → optional → :false
65
+ expect(bucketProps).toContain("BucketName:false");
66
+ // Tags?: Bucket_Tag[] → optional → :false
67
+ expect(bucketProps).toContain("Tags:false");
68
+ expect(bucketProps).toHaveLength(2);
69
+ });
70
+
71
+ test("extracts required props correctly", () => {
72
+ const map = extractPropsFromDts(SIMPLE_DTS);
73
+
74
+ const fnProps = map.get("Function")!;
75
+ expect(fnProps).toContain("Code:true");
76
+ expect(fnProps).toContain("Role:true");
77
+ expect(fnProps).toContain("FunctionName:false");
78
+ expect(fnProps).toHaveLength(3);
79
+ });
80
+
81
+ test("returns sorted props", () => {
82
+ const map = extractPropsFromDts(SIMPLE_DTS);
83
+ const props = map.get("Bucket")!;
84
+ const sorted = [...props].sort();
85
+ expect(props).toEqual(sorted);
86
+ });
87
+
88
+ test("skips comment lines in constructor body", () => {
89
+ const dts = `
90
+ export declare class Widget {
91
+ constructor(props: {
92
+ /** The widget name. */
93
+ Name: string;
94
+ // legacy
95
+ OldProp?: string;
96
+ });
97
+ }
98
+ `;
99
+ const map = extractPropsFromDts(dts);
100
+ const props = map.get("Widget")!;
101
+ expect(props).toContain("Name:true");
102
+ expect(props).toContain("OldProp:false");
103
+ expect(props).toHaveLength(2);
104
+ });
105
+
106
+ test("handles empty constructor (Record<string, unknown> form)", () => {
107
+ const dts = `
108
+ export declare class Simple {
109
+ constructor(props: Record<string, unknown>);
110
+ }
111
+ `;
112
+ const map = extractPropsFromDts(dts);
113
+ // No props extracted for this form
114
+ expect(map.has("Simple")).toBe(false);
115
+ });
116
+
117
+ test("handles quoted property names", () => {
118
+ const dts = `
119
+ export declare class Quirky {
120
+ constructor(props: {
121
+ "some-key": string;
122
+ "other-key"?: number;
123
+ });
124
+ }
125
+ `;
126
+ const map = extractPropsFromDts(dts);
127
+ const props = map.get("Quirky")!;
128
+ expect(props).toContain("some-key:true");
129
+ expect(props).toContain("other-key:false");
130
+ });
131
+ });
132
+
133
+ // ── extractSurface ────────────────────────────────────────────────────
134
+
135
+ describe("extractSurface", () => {
136
+ test("extracts resource entries with attrs and props", () => {
137
+ const snap = extractSurface(SIMPLE_LEXICON_JSON, SIMPLE_DTS);
138
+
139
+ expect(snap.schemaVersion).toBe(1);
140
+ expect(typeof snap.generatedAt).toBe("string");
141
+
142
+ const bucket = snap.entries.Bucket;
143
+ expect(bucket).toBeDefined();
144
+ expect(bucket.kind).toBe("resource");
145
+ expect(bucket.resourceType).toBe("AWS::S3::Bucket");
146
+ expect(bucket.attrs).toContain("Arn");
147
+ expect(bucket.attrs).toContain("WebsiteURL");
148
+ expect(bucket.props).toContain("BucketName:false");
149
+ expect(bucket.createOnly).toEqual(["BucketName"]);
150
+ expect(bucket.taggable).toBe(true);
151
+ });
152
+
153
+ test("extracts property-type entries without props/attrs", () => {
154
+ const snap = extractSurface(SIMPLE_LEXICON_JSON, SIMPLE_DTS);
155
+
156
+ const bucketTag = snap.entries.Bucket_Tag;
157
+ expect(bucketTag).toBeDefined();
158
+ expect(bucketTag.kind).toBe("property");
159
+ expect(bucketTag.props).toBeUndefined();
160
+ expect(bucketTag.attrs).toBeUndefined();
161
+ });
162
+
163
+ test("entries are sorted alphabetically", () => {
164
+ const snap = extractSurface(SIMPLE_LEXICON_JSON, SIMPLE_DTS);
165
+ const keys = Object.keys(snap.entries);
166
+ expect(keys).toEqual([...keys].sort());
167
+ });
168
+
169
+ test("works without .d.ts (no props extracted)", () => {
170
+ const snap = extractSurface(SIMPLE_LEXICON_JSON, "");
171
+ const bucket = snap.entries.Bucket;
172
+ expect(bucket).toBeDefined();
173
+ expect(bucket.attrs).toContain("Arn");
174
+ // No props without .d.ts
175
+ expect(bucket.props).toBeUndefined();
176
+ });
177
+ });
178
+
179
+ // ── diffSurface ───────────────────────────────────────────────────────
180
+
181
+ function makeSnapshot(entries: SurfaceSnapshot["entries"]): SurfaceSnapshot {
182
+ return { schemaVersion: 1, generatedAt: new Date().toISOString(), entries };
183
+ }
184
+
185
+ describe("diffSurface — additive changes", () => {
186
+ test("added resource entry → additive severity", () => {
187
+ const baseline = makeSnapshot({});
188
+ const fresh = makeSnapshot({
189
+ NewBucket: { kind: "resource", resourceType: "AWS::S3::Bucket" },
190
+ });
191
+
192
+ const delta = diffSurface(baseline, fresh);
193
+ expect(delta.added).toHaveLength(1);
194
+ expect(delta.added[0].name).toBe("NewBucket");
195
+ expect(delta.removed).toHaveLength(0);
196
+ expect(delta.changed).toHaveLength(0);
197
+ expect(delta.severity).toBe("additive");
198
+ });
199
+
200
+ test("added optional prop → additive severity", () => {
201
+ const baseline = makeSnapshot({
202
+ Bucket: { kind: "resource", resourceType: "AWS::S3::Bucket", props: ["Name:false"] },
203
+ });
204
+ const fresh = makeSnapshot({
205
+ Bucket: { kind: "resource", resourceType: "AWS::S3::Bucket", props: ["Name:false", "Tags:false"] },
206
+ });
207
+
208
+ const delta = diffSurface(baseline, fresh);
209
+ expect(delta.changed).toHaveLength(1);
210
+ expect(delta.changed[0].addedProps).toContain("Tags");
211
+ expect(delta.severity).toBe("additive");
212
+ });
213
+
214
+ test("added attr → additive severity", () => {
215
+ const baseline = makeSnapshot({
216
+ Bucket: { kind: "resource", resourceType: "AWS::S3::Bucket", attrs: ["Arn"] },
217
+ });
218
+ const fresh = makeSnapshot({
219
+ Bucket: { kind: "resource", resourceType: "AWS::S3::Bucket", attrs: ["Arn", "WebsiteURL"] },
220
+ });
221
+
222
+ const delta = diffSurface(baseline, fresh);
223
+ expect(delta.changed[0].addedAttrs).toContain("WebsiteURL");
224
+ expect(delta.severity).toBe("additive");
225
+ });
226
+
227
+ test("required prop becoming optional → additive severity", () => {
228
+ const baseline = makeSnapshot({
229
+ Fn: { kind: "resource", resourceType: "AWS::Lambda::Function", props: ["Code:true", "Role:true"] },
230
+ });
231
+ const fresh = makeSnapshot({
232
+ Fn: { kind: "resource", resourceType: "AWS::Lambda::Function", props: ["Code:false", "Role:true"] },
233
+ });
234
+
235
+ const delta = diffSurface(baseline, fresh);
236
+ expect(delta.changed[0].nowOptional).toContain("Code");
237
+ expect(delta.severity).toBe("additive");
238
+ });
239
+
240
+ test("gaining taggable → additive severity", () => {
241
+ const baseline = makeSnapshot({
242
+ Res: { kind: "resource", resourceType: "X::Y::Z", taggable: false },
243
+ });
244
+ const fresh = makeSnapshot({
245
+ Res: { kind: "resource", resourceType: "X::Y::Z", taggable: true },
246
+ });
247
+
248
+ const delta = diffSurface(baseline, fresh);
249
+ expect(delta.changed[0].taggableChanged).toEqual({ before: false, after: true });
250
+ expect(delta.severity).toBe("additive");
251
+ });
252
+ });
253
+
254
+ describe("diffSurface — breaking changes", () => {
255
+ test("removed resource entry → breaking severity", () => {
256
+ const baseline = makeSnapshot({
257
+ OldBucket: { kind: "resource", resourceType: "AWS::S3::Bucket" },
258
+ });
259
+ const fresh = makeSnapshot({});
260
+
261
+ const delta = diffSurface(baseline, fresh);
262
+ expect(delta.removed).toHaveLength(1);
263
+ expect(delta.removed[0].name).toBe("OldBucket");
264
+ expect(delta.severity).toBe("breaking");
265
+ });
266
+
267
+ test("removed required prop → breaking severity", () => {
268
+ const baseline = makeSnapshot({
269
+ Fn: { kind: "resource", resourceType: "X", props: ["Code:true", "Role:true"] },
270
+ });
271
+ const fresh = makeSnapshot({
272
+ Fn: { kind: "resource", resourceType: "X", props: ["Role:true"] },
273
+ });
274
+
275
+ const delta = diffSurface(baseline, fresh);
276
+ expect(delta.changed[0].removedProps).toContain("Code");
277
+ expect(delta.severity).toBe("breaking");
278
+ });
279
+
280
+ test("removed optional prop → breaking severity", () => {
281
+ const baseline = makeSnapshot({
282
+ Fn: { kind: "resource", resourceType: "X", props: ["Code:true", "Tags:false"] },
283
+ });
284
+ const fresh = makeSnapshot({
285
+ Fn: { kind: "resource", resourceType: "X", props: ["Code:true"] },
286
+ });
287
+
288
+ const delta = diffSurface(baseline, fresh);
289
+ expect(delta.changed[0].removedProps).toContain("Tags");
290
+ expect(delta.severity).toBe("breaking");
291
+ });
292
+
293
+ test("optional prop becoming required → breaking severity", () => {
294
+ const baseline = makeSnapshot({
295
+ Fn: { kind: "resource", resourceType: "X", props: ["Code:false"] },
296
+ });
297
+ const fresh = makeSnapshot({
298
+ Fn: { kind: "resource", resourceType: "X", props: ["Code:true"] },
299
+ });
300
+
301
+ const delta = diffSurface(baseline, fresh);
302
+ expect(delta.changed[0].nowRequired).toContain("Code");
303
+ expect(delta.severity).toBe("breaking");
304
+ });
305
+
306
+ test("removed attr → breaking severity", () => {
307
+ const baseline = makeSnapshot({
308
+ Res: { kind: "resource", resourceType: "X", attrs: ["Arn", "Name"] },
309
+ });
310
+ const fresh = makeSnapshot({
311
+ Res: { kind: "resource", resourceType: "X", attrs: ["Arn"] },
312
+ });
313
+
314
+ const delta = diffSurface(baseline, fresh);
315
+ expect(delta.changed[0].removedAttrs).toContain("Name");
316
+ expect(delta.severity).toBe("breaking");
317
+ });
318
+
319
+ test("resourceType changed → breaking severity", () => {
320
+ const baseline = makeSnapshot({
321
+ Res: { kind: "resource", resourceType: "AWS::S3::Bucket" },
322
+ });
323
+ const fresh = makeSnapshot({
324
+ Res: { kind: "resource", resourceType: "AWS::S3::BucketV2" },
325
+ });
326
+
327
+ const delta = diffSurface(baseline, fresh);
328
+ expect(delta.changed[0].resourceTypeChanged?.before).toBe("AWS::S3::Bucket");
329
+ expect(delta.changed[0].resourceTypeChanged?.after).toBe("AWS::S3::BucketV2");
330
+ expect(delta.severity).toBe("breaking");
331
+ });
332
+
333
+ test("kind changed resource→property → breaking severity", () => {
334
+ const baseline = makeSnapshot({
335
+ Res: { kind: "resource", resourceType: "X" },
336
+ });
337
+ const fresh = makeSnapshot({
338
+ Res: { kind: "property", resourceType: "X" },
339
+ });
340
+
341
+ const delta = diffSurface(baseline, fresh);
342
+ expect(delta.changed[0].kindChanged).toBeDefined();
343
+ expect(delta.severity).toBe("breaking");
344
+ });
345
+
346
+ test("createOnly set changed → breaking severity", () => {
347
+ const baseline = makeSnapshot({
348
+ Res: { kind: "resource", resourceType: "X", createOnly: ["BucketName"] },
349
+ });
350
+ const fresh = makeSnapshot({
351
+ Res: { kind: "resource", resourceType: "X", createOnly: [] },
352
+ });
353
+
354
+ const delta = diffSurface(baseline, fresh);
355
+ expect(delta.changed[0].createOnlyChanged).toBeDefined();
356
+ expect(delta.severity).toBe("breaking");
357
+ });
358
+
359
+ test("losing taggable → breaking severity", () => {
360
+ const baseline = makeSnapshot({
361
+ Res: { kind: "resource", resourceType: "X", taggable: true },
362
+ });
363
+ const fresh = makeSnapshot({
364
+ Res: { kind: "resource", resourceType: "X", taggable: false },
365
+ });
366
+
367
+ const delta = diffSurface(baseline, fresh);
368
+ expect(delta.changed[0].taggableChanged).toEqual({ before: true, after: false });
369
+ expect(delta.severity).toBe("breaking");
370
+ });
371
+ });
372
+
373
+ describe("diffSurface — no changes", () => {
374
+ test("identical snapshots → severity none", () => {
375
+ const baseline = makeSnapshot({
376
+ Bucket: { kind: "resource", resourceType: "AWS::S3::Bucket", props: ["Name:false"] },
377
+ });
378
+
379
+ const delta = diffSurface(baseline, baseline);
380
+ expect(delta.added).toHaveLength(0);
381
+ expect(delta.changed).toHaveLength(0);
382
+ expect(delta.removed).toHaveLength(0);
383
+ expect(delta.severity).toBe("none");
384
+ });
385
+
386
+ test("empty baseline and empty fresh → severity none", () => {
387
+ const baseline = makeSnapshot({});
388
+ const fresh = makeSnapshot({});
389
+ const delta = diffSurface(baseline, fresh);
390
+ expect(delta.severity).toBe("none");
391
+ });
392
+ });
393
+
394
+ describe("diffSurface — mixed severities", () => {
395
+ test("breaking change dominates additive change", () => {
396
+ const baseline = makeSnapshot({
397
+ Res: { kind: "resource", resourceType: "X", props: ["Name:false"] },
398
+ });
399
+ const fresh = makeSnapshot({
400
+ Res: { kind: "resource", resourceType: "X", props: ["Name:true"] }, // now required = breaking
401
+ NewRes: { kind: "resource", resourceType: "Y" }, // added = additive
402
+ });
403
+
404
+ const delta = diffSurface(baseline, fresh);
405
+ expect(delta.severity).toBe("breaking");
406
+ });
407
+ });
408
+
409
+ // ── Serialization round-trip ──────────────────────────────────────────
410
+
411
+ describe("serializeSnapshot / parseSnapshot", () => {
412
+ test("round-trips a snapshot", () => {
413
+ const snap = extractSurface(SIMPLE_LEXICON_JSON, SIMPLE_DTS);
414
+ const json = serializeSnapshot(snap);
415
+ const back = parseSnapshot(json);
416
+ expect(back.schemaVersion).toBe(1);
417
+ expect(Object.keys(back.entries)).toEqual(Object.keys(snap.entries));
418
+ expect(back.entries.Bucket.kind).toBe("resource");
419
+ expect(back.entries.Bucket.attrs).toEqual(snap.entries.Bucket.attrs);
420
+ });
421
+
422
+ test("serialized JSON ends with newline", () => {
423
+ const snap = makeSnapshot({});
424
+ const json = serializeSnapshot(snap);
425
+ expect(json.endsWith("\n")).toBe(true);
426
+ });
427
+ });
428
+
429
+ // ── formatDelta ───────────────────────────────────────────────────────
430
+
431
+ describe("formatDelta", () => {
432
+ test("includes severity in output", () => {
433
+ const delta = diffSurface(
434
+ makeSnapshot({}),
435
+ makeSnapshot({ NewRes: { kind: "resource", resourceType: "X" } }),
436
+ );
437
+ const text = formatDelta(delta);
438
+ expect(text).toContain("Severity: additive");
439
+ });
440
+
441
+ test("shows 'No surface changes.' when nothing changed", () => {
442
+ const snap = makeSnapshot({});
443
+ const delta = diffSurface(snap, snap);
444
+ expect(formatDelta(delta)).toContain("No surface changes.");
445
+ });
446
+
447
+ test("shows added/removed/changed counts", () => {
448
+ const baseline = makeSnapshot({
449
+ Old: { kind: "resource", resourceType: "X" },
450
+ Both: { kind: "resource", resourceType: "Y", attrs: ["Arn"] },
451
+ });
452
+ const fresh = makeSnapshot({
453
+ New: { kind: "resource", resourceType: "Z" },
454
+ Both: { kind: "resource", resourceType: "Y", attrs: ["Arn", "Extra"] },
455
+ });
456
+ const text = formatDelta(diffSurface(baseline, fresh));
457
+ expect(text).toContain("Added (1):");
458
+ expect(text).toContain("Removed (1):");
459
+ expect(text).toContain("Changed (1):");
460
+ });
461
+ });