@intentius/chant 0.101.0 → 0.104.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 (739) hide show
  1. package/dist/agents/checks.d.ts.map +1 -1
  2. package/dist/attrref.d.ts.map +1 -1
  3. package/dist/audit/core.d.ts +2 -0
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts.map +1 -1
  6. package/dist/audit/nginx.d.ts.map +1 -1
  7. package/dist/audit/prior-art.d.ts +48 -0
  8. package/dist/audit/prior-art.d.ts.map +1 -1
  9. package/dist/behaviour-kinds.d.ts.map +1 -1
  10. package/dist/builder.d.ts.map +1 -1
  11. package/dist/change-set.d.ts +232 -0
  12. package/dist/change-set.d.ts.map +1 -0
  13. package/dist/cli/commands/audit.d.ts +7 -0
  14. package/dist/cli/commands/audit.d.ts.map +1 -1
  15. package/dist/cli/commands/build.d.ts.map +1 -1
  16. package/dist/cli/commands/carve-emit.d.ts.map +1 -1
  17. package/dist/cli/commands/check-lexicon.d.ts +16 -0
  18. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  19. package/dist/cli/commands/import.d.ts +8 -0
  20. package/dist/cli/commands/import.d.ts.map +1 -1
  21. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  22. package/dist/cli/commands/init.d.ts +19 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -1
  24. package/dist/cli/commands/onboard.d.ts +9 -0
  25. package/dist/cli/commands/onboard.d.ts.map +1 -1
  26. package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
  27. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
  28. package/dist/cli/handlers/build.d.ts.map +1 -1
  29. package/dist/cli/handlers/change-set.d.ts +11 -0
  30. package/dist/cli/handlers/change-set.d.ts.map +1 -0
  31. package/dist/cli/handlers/dev.d.ts.map +1 -1
  32. package/dist/cli/handlers/fan-out.d.ts +33 -0
  33. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  34. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  35. package/dist/cli/handlers/misc.d.ts.map +1 -1
  36. package/dist/cli/handlers/operator.d.ts +16 -0
  37. package/dist/cli/handlers/operator.d.ts.map +1 -1
  38. package/dist/cli/handlers/pr.d.ts +31 -0
  39. package/dist/cli/handlers/pr.d.ts.map +1 -0
  40. package/dist/cli/handlers/run.d.ts.map +1 -1
  41. package/dist/cli/lsp/server.d.ts.map +1 -1
  42. package/dist/cli/main.d.ts.map +1 -1
  43. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  44. package/dist/cli/mcp/server.d.ts.map +1 -1
  45. package/dist/cli/mcp/tools/build.d.ts.map +1 -1
  46. package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
  47. package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
  48. package/dist/cli/mcp/tools/import.d.ts.map +1 -1
  49. package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
  50. package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
  51. package/dist/cli/mcp/tools/search.d.ts.map +1 -1
  52. package/dist/cli/mcp/workspace-tools.d.ts +4 -3
  53. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  54. package/dist/cli/registry.d.ts +74 -3
  55. package/dist/cli/registry.d.ts.map +1 -1
  56. package/dist/codegen/fetch.d.ts.map +1 -1
  57. package/dist/codegen/naming.d.ts.map +1 -1
  58. package/dist/codegen/pinned-upgrade.d.ts +67 -3
  59. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  60. package/dist/codegen/registry.d.ts.map +1 -1
  61. package/dist/components/auto-release.d.ts +16 -0
  62. package/dist/components/auto-release.d.ts.map +1 -1
  63. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  64. package/dist/components/capability.d.ts +53 -0
  65. package/dist/components/capability.d.ts.map +1 -1
  66. package/dist/components/changed-files.d.ts +31 -0
  67. package/dist/components/changed-files.d.ts.map +1 -0
  68. package/dist/components/cli-support.d.ts +9 -1
  69. package/dist/components/cli-support.d.ts.map +1 -1
  70. package/dist/components/component.d.ts +24 -0
  71. package/dist/components/component.d.ts.map +1 -1
  72. package/dist/components/deploy-units.d.ts.map +1 -1
  73. package/dist/components/driver.d.ts +13 -0
  74. package/dist/components/driver.d.ts.map +1 -1
  75. package/dist/components/fan-out-output.d.ts +6 -0
  76. package/dist/components/fan-out-output.d.ts.map +1 -1
  77. package/dist/components/fan-out-record.d.ts +41 -0
  78. package/dist/components/fan-out-record.d.ts.map +1 -0
  79. package/dist/components/fan-out-run.d.ts +65 -0
  80. package/dist/components/fan-out-run.d.ts.map +1 -1
  81. package/dist/components/fan-out-support.d.ts +2 -0
  82. package/dist/components/fan-out-support.d.ts.map +1 -1
  83. package/dist/components/fan-out.d.ts +6 -0
  84. package/dist/components/fan-out.d.ts.map +1 -1
  85. package/dist/components/gated-wave-pipeline.d.ts +50 -0
  86. package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
  87. package/dist/components/index.d.ts +1 -1
  88. package/dist/components/index.d.ts.map +1 -1
  89. package/dist/components/layers.d.ts +25 -0
  90. package/dist/components/layers.d.ts.map +1 -0
  91. package/dist/components/pr-pipeline.d.ts +61 -0
  92. package/dist/components/pr-pipeline.d.ts.map +1 -0
  93. package/dist/components/pr-run.d.ts +119 -0
  94. package/dist/components/pr-run.d.ts.map +1 -0
  95. package/dist/components/promote.d.ts.map +1 -1
  96. package/dist/components/starter-plugin.d.ts.map +1 -1
  97. package/dist/components/verbs/process-runner.d.ts.map +1 -1
  98. package/dist/components/verbs/r2-sync.d.ts.map +1 -1
  99. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  100. package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
  101. package/dist/components/verbs/shell.d.ts.map +1 -1
  102. package/dist/components/verbs/sign.d.ts.map +1 -1
  103. package/dist/components/verbs/verify.d.ts.map +1 -1
  104. package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
  105. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  106. package/dist/components/verbs/wrangler.d.ts.map +1 -1
  107. package/dist/components/wave-plan.d.ts +49 -0
  108. package/dist/components/wave-plan.d.ts.map +1 -0
  109. package/dist/composite.d.ts.map +1 -1
  110. package/dist/config.d.ts +19 -7
  111. package/dist/config.d.ts.map +1 -1
  112. package/dist/declarable.d.ts +16 -0
  113. package/dist/declarable.d.ts.map +1 -1
  114. package/dist/discovery/cache.d.ts.map +1 -1
  115. package/dist/discovery/fold-import.d.ts +15 -5
  116. package/dist/discovery/fold-import.d.ts.map +1 -1
  117. package/dist/discovery/param-deps.d.ts +16 -0
  118. package/dist/discovery/param-deps.d.ts.map +1 -1
  119. package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
  120. package/dist/discovery/specifier-resolve.d.ts +37 -0
  121. package/dist/discovery/specifier-resolve.d.ts.map +1 -0
  122. package/dist/errors.d.ts.map +1 -1
  123. package/dist/fold/fold.d.ts +3 -1
  124. package/dist/fold/fold.d.ts.map +1 -1
  125. package/dist/gated-waves.d.ts +147 -0
  126. package/dist/gated-waves.d.ts.map +1 -0
  127. package/dist/graph-detail.d.ts.map +1 -1
  128. package/dist/graph-ir.d.ts.map +1 -1
  129. package/dist/graph-layout.d.ts.map +1 -1
  130. package/dist/import/base-parser.d.ts.map +1 -1
  131. package/dist/import/embedded.d.ts +7 -0
  132. package/dist/import/embedded.d.ts.map +1 -1
  133. package/dist/import/parser-options.d.ts +14 -0
  134. package/dist/import/parser-options.d.ts.map +1 -0
  135. package/dist/import/parser.d.ts +17 -0
  136. package/dist/import/parser.d.ts.map +1 -1
  137. package/dist/index.d.ts +1 -0
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/kubectl-context.d.ts.map +1 -1
  140. package/dist/lexicon-output.d.ts.map +1 -1
  141. package/dist/lexicon-schema.d.ts +3 -3
  142. package/dist/lexicon.d.ts +103 -3
  143. package/dist/lexicon.d.ts.map +1 -1
  144. package/dist/lifecycle/assert-live.d.ts.map +1 -1
  145. package/dist/lifecycle/gate-ledger.d.ts +22 -0
  146. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  147. package/dist/lifecycle/git.d.ts +46 -1
  148. package/dist/lifecycle/git.d.ts.map +1 -1
  149. package/dist/lifecycle/member-ledger.d.ts.map +1 -1
  150. package/dist/lifecycle/observe.d.ts.map +1 -1
  151. package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
  152. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  153. package/dist/lifecycle/scenario.d.ts.map +1 -1
  154. package/dist/lifecycle/status.d.ts.map +1 -1
  155. package/dist/lifecycle/work-lease.d.ts +61 -2
  156. package/dist/lifecycle/work-lease.d.ts.map +1 -1
  157. package/dist/lint/config.d.ts +8 -8
  158. package/dist/lint/engine.d.ts +6 -0
  159. package/dist/lint/engine.d.ts.map +1 -1
  160. package/dist/lint/post-synth.d.ts +18 -0
  161. package/dist/lint/post-synth.d.ts.map +1 -1
  162. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  163. package/dist/op/activities/activity-contracts.d.ts +137 -11
  164. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  165. package/dist/op/activities/apply.d.ts +79 -9
  166. package/dist/op/activities/apply.d.ts.map +1 -1
  167. package/dist/op/activities/change-set.d.ts +62 -0
  168. package/dist/op/activities/change-set.d.ts.map +1 -0
  169. package/dist/op/activities/decide.d.ts +2 -0
  170. package/dist/op/activities/decide.d.ts.map +1 -1
  171. package/dist/op/activities/factory.d.ts +137 -0
  172. package/dist/op/activities/factory.d.ts.map +1 -0
  173. package/dist/op/activities/index.d.ts +5 -1
  174. package/dist/op/activities/index.d.ts.map +1 -1
  175. package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
  176. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
  177. package/dist/op/activity-contract.d.ts +1 -1
  178. package/dist/op/activity-contract.d.ts.map +1 -1
  179. package/dist/op/activity-failure.d.ts.map +1 -1
  180. package/dist/op/activity-profiles.d.ts.map +1 -1
  181. package/dist/op/builders.d.ts +11 -0
  182. package/dist/op/builders.d.ts.map +1 -1
  183. package/dist/op/composites/apply-op.d.ts +12 -5
  184. package/dist/op/composites/apply-op.d.ts.map +1 -1
  185. package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
  186. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
  187. package/dist/op/decide-backend.d.ts +5 -1
  188. package/dist/op/decide-backend.d.ts.map +1 -1
  189. package/dist/op/decide-read-inputs.d.ts +4 -2
  190. package/dist/op/decide-read-inputs.d.ts.map +1 -1
  191. package/dist/op/emulator-lifecycle.d.ts +21 -2
  192. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  193. package/dist/op/factory.d.ts +83 -0
  194. package/dist/op/factory.d.ts.map +1 -0
  195. package/dist/op/gate-approval.d.ts +5 -1
  196. package/dist/op/gate-approval.d.ts.map +1 -1
  197. package/dist/op/gate-wait.d.ts.map +1 -1
  198. package/dist/op/gate.d.ts +19 -3
  199. package/dist/op/gate.d.ts.map +1 -1
  200. package/dist/op/index.d.ts +6 -1
  201. package/dist/op/index.d.ts.map +1 -1
  202. package/dist/op/local-executor.d.ts +6 -0
  203. package/dist/op/local-executor.d.ts.map +1 -1
  204. package/dist/op/op-ir.d.ts +2 -0
  205. package/dist/op/op-ir.d.ts.map +1 -1
  206. package/dist/op/op-verb-class.d.ts.map +1 -1
  207. package/dist/op/operator.d.ts.map +1 -1
  208. package/dist/op/run-context.d.ts +39 -0
  209. package/dist/op/run-context.d.ts.map +1 -0
  210. package/dist/op/run-live.d.ts.map +1 -1
  211. package/dist/op/runtimes/local.d.ts.map +1 -1
  212. package/dist/op/source-archive.d.ts.map +1 -1
  213. package/dist/op/steward-beside.d.ts.map +1 -1
  214. package/dist/op/steward-points.d.ts.map +1 -1
  215. package/dist/op/steward.d.ts.map +1 -1
  216. package/dist/op/types.d.ts +16 -3
  217. package/dist/op/types.d.ts.map +1 -1
  218. package/dist/op/work-lease-run.d.ts +24 -4
  219. package/dist/op/work-lease-run.d.ts.map +1 -1
  220. package/dist/plan-summary.d.ts +207 -0
  221. package/dist/plan-summary.d.ts.map +1 -0
  222. package/dist/pr-forge.d.ts +105 -0
  223. package/dist/pr-forge.d.ts.map +1 -0
  224. package/dist/pr-loop.d.ts +178 -0
  225. package/dist/pr-loop.d.ts.map +1 -0
  226. package/dist/project-root.d.ts.map +1 -1
  227. package/dist/provenance.d.ts +21 -0
  228. package/dist/provenance.d.ts.map +1 -1
  229. package/dist/pseudo-parameter.d.ts.map +1 -1
  230. package/dist/reconcile.d.ts.map +1 -1
  231. package/dist/secret-materialization.d.ts.map +1 -1
  232. package/dist/telemetry-attribution.d.ts +31 -0
  233. package/dist/telemetry-attribution.d.ts.map +1 -1
  234. package/dist/terraform/emit-source.d.ts.map +1 -1
  235. package/dist/terraform/hcl2json.d.ts +45 -0
  236. package/dist/terraform/hcl2json.d.ts.map +1 -0
  237. package/dist/terraform/parse.d.ts +4 -40
  238. package/dist/terraform/parse.d.ts.map +1 -1
  239. package/dist/testing.d.ts.map +1 -1
  240. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
  241. package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
  242. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
  243. package/dist/workspace/agent-cli.d.ts +5 -0
  244. package/dist/workspace/agent-cli.d.ts.map +1 -1
  245. package/dist/workspace/box-cli.d.ts +12 -0
  246. package/dist/workspace/box-cli.d.ts.map +1 -0
  247. package/dist/workspace/box-factory.d.ts +97 -0
  248. package/dist/workspace/box-factory.d.ts.map +1 -0
  249. package/dist/workspace/box-listing.d.ts +85 -0
  250. package/dist/workspace/box-listing.d.ts.map +1 -0
  251. package/dist/workspace/box-publish.d.ts +147 -0
  252. package/dist/workspace/box-publish.d.ts.map +1 -0
  253. package/dist/workspace/broker-protocol.d.ts +190 -0
  254. package/dist/workspace/broker-protocol.d.ts.map +1 -0
  255. package/dist/workspace/changes.d.ts.map +1 -1
  256. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
  257. package/dist/workspace/checks/boxes.d.ts.map +1 -1
  258. package/dist/workspace/checks.d.ts +5 -0
  259. package/dist/workspace/checks.d.ts.map +1 -1
  260. package/dist/workspace/compose-graph.d.ts +10 -0
  261. package/dist/workspace/compose-graph.d.ts.map +1 -1
  262. package/dist/workspace/composites.d.ts +2 -2
  263. package/dist/workspace/composites.d.ts.map +1 -1
  264. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
  265. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
  266. package/dist/workspace/conformance/broker.d.ts +202 -0
  267. package/dist/workspace/conformance/broker.d.ts.map +1 -0
  268. package/dist/workspace/conformance/index.d.ts +68 -6
  269. package/dist/workspace/conformance/index.d.ts.map +1 -1
  270. package/dist/workspace/conformance/vitest.d.ts +19 -3
  271. package/dist/workspace/conformance/vitest.d.ts.map +1 -1
  272. package/dist/workspace/conformance/writer.d.ts +462 -0
  273. package/dist/workspace/conformance/writer.d.ts.map +1 -0
  274. package/dist/workspace/decide.d.ts +126 -12
  275. package/dist/workspace/decide.d.ts.map +1 -1
  276. package/dist/workspace/decision-points.schema.json +11 -4
  277. package/dist/workspace/declaration.d.ts +156 -4
  278. package/dist/workspace/declaration.d.ts.map +1 -1
  279. package/dist/workspace/declaration.schema.json +383 -5
  280. package/dist/workspace/environments.d.ts +36 -10
  281. package/dist/workspace/environments.d.ts.map +1 -1
  282. package/dist/workspace/factory-rules.d.ts +180 -0
  283. package/dist/workspace/factory-rules.d.ts.map +1 -0
  284. package/dist/workspace/generated-files.d.ts.map +1 -1
  285. package/dist/workspace/graph-cache.d.ts.map +1 -1
  286. package/dist/workspace/graph-cli.d.ts +2 -0
  287. package/dist/workspace/graph-cli.d.ts.map +1 -1
  288. package/dist/workspace/identity.d.ts +111 -0
  289. package/dist/workspace/identity.d.ts.map +1 -0
  290. package/dist/workspace/init.d.ts +21 -0
  291. package/dist/workspace/init.d.ts.map +1 -1
  292. package/dist/workspace/intent-cli.d.ts +7 -4
  293. package/dist/workspace/intent-cli.d.ts.map +1 -1
  294. package/dist/workspace/intent-record.d.ts +36 -2
  295. package/dist/workspace/intent-record.d.ts.map +1 -1
  296. package/dist/workspace/intent.d.ts +249 -8
  297. package/dist/workspace/intent.d.ts.map +1 -1
  298. package/dist/workspace/json-edit.d.ts +24 -0
  299. package/dist/workspace/json-edit.d.ts.map +1 -0
  300. package/dist/workspace/jsonc.d.ts +11 -0
  301. package/dist/workspace/jsonc.d.ts.map +1 -1
  302. package/dist/workspace/kinds.d.ts +66 -4
  303. package/dist/workspace/kinds.d.ts.map +1 -1
  304. package/dist/workspace/lexicon-symbols.d.ts +29 -0
  305. package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
  306. package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
  307. package/dist/workspace/lineage-lock.d.ts +2 -2
  308. package/dist/workspace/lineage-lock.d.ts.map +1 -1
  309. package/dist/workspace/lineage-upgrade.d.ts +31 -2
  310. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  311. package/dist/workspace/links.d.ts.map +1 -1
  312. package/dist/workspace/point-answer.schema.json +42 -2
  313. package/dist/workspace/points-cli.d.ts +10 -3
  314. package/dist/workspace/points-cli.d.ts.map +1 -1
  315. package/dist/workspace/points.d.ts +66 -5
  316. package/dist/workspace/points.d.ts.map +1 -1
  317. package/dist/workspace/principal-classes.d.ts +114 -0
  318. package/dist/workspace/principal-classes.d.ts.map +1 -0
  319. package/dist/workspace/reason-codes.d.ts +53 -4
  320. package/dist/workspace/reason-codes.d.ts.map +1 -1
  321. package/dist/workspace/record-assets.d.ts.map +1 -1
  322. package/dist/workspace/record-sessions.d.ts +5 -7
  323. package/dist/workspace/record-sessions.d.ts.map +1 -1
  324. package/dist/workspace/records-checkout.d.ts +54 -0
  325. package/dist/workspace/records-checkout.d.ts.map +1 -0
  326. package/dist/workspace/records-cli.d.ts +34 -1
  327. package/dist/workspace/records-cli.d.ts.map +1 -1
  328. package/dist/workspace/records-close.d.ts +7 -3
  329. package/dist/workspace/records-close.d.ts.map +1 -1
  330. package/dist/workspace/records-since.d.ts.map +1 -1
  331. package/dist/workspace/records-write.d.ts +68 -7
  332. package/dist/workspace/records-write.d.ts.map +1 -1
  333. package/dist/workspace/records.d.ts +43 -9
  334. package/dist/workspace/records.d.ts.map +1 -1
  335. package/dist/workspace/runs-cli.d.ts +296 -0
  336. package/dist/workspace/runs-cli.d.ts.map +1 -0
  337. package/dist/workspace/runs.d.ts +544 -0
  338. package/dist/workspace/runs.d.ts.map +1 -0
  339. package/dist/workspace/session-kinds.d.ts +1 -1
  340. package/dist/workspace/session-kinds.d.ts.map +1 -1
  341. package/dist/workspace/source-block.d.ts +1 -1
  342. package/dist/workspace/source-block.d.ts.map +1 -1
  343. package/dist/workspace/squash.d.ts +80 -0
  344. package/dist/workspace/squash.d.ts.map +1 -0
  345. package/dist/workspace/status-gates.d.ts +17 -3
  346. package/dist/workspace/status-gates.d.ts.map +1 -1
  347. package/dist/workspace/status.d.ts +64 -0
  348. package/dist/workspace/status.d.ts.map +1 -1
  349. package/dist/workspace/symbols.d.ts +63 -0
  350. package/dist/workspace/symbols.d.ts.map +1 -0
  351. package/dist/workspace/trailer-joins.d.ts +46 -0
  352. package/dist/workspace/trailer-joins.d.ts.map +1 -0
  353. package/dist/workspace/trailers.d.ts +89 -0
  354. package/dist/workspace/trailers.d.ts.map +1 -0
  355. package/dist/workspace/trust/attestor.d.ts.map +1 -1
  356. package/dist/workspace/trust/rotation.d.ts.map +1 -1
  357. package/dist/workspace/trust/run-commits.d.ts +46 -0
  358. package/dist/workspace/trust/run-commits.d.ts.map +1 -0
  359. package/dist/workspace/trust/run-statement.d.ts +128 -0
  360. package/dist/workspace/trust/run-statement.d.ts.map +1 -0
  361. package/dist/workspace/trust/seal.d.ts +38 -0
  362. package/dist/workspace/trust/seal.d.ts.map +1 -1
  363. package/dist/workspace/trust/test-repo.d.ts.map +1 -1
  364. package/dist/workspace/trust/verify-cli.d.ts +1 -1
  365. package/dist/workspace/trust/verify.d.ts +16 -2
  366. package/dist/workspace/trust/verify.d.ts.map +1 -1
  367. package/dist/workspace/wip-cli.d.ts +21 -0
  368. package/dist/workspace/wip-cli.d.ts.map +1 -0
  369. package/dist/workspace/wip.d.ts +268 -0
  370. package/dist/workspace/wip.d.ts.map +1 -0
  371. package/dist/workspace/work-cli.d.ts +39 -3
  372. package/dist/workspace/work-cli.d.ts.map +1 -1
  373. package/dist/workspace/work-evidence.d.ts +1 -1
  374. package/dist/workspace/work-evidence.d.ts.map +1 -1
  375. package/dist/workspace/work-size.d.ts +55 -0
  376. package/dist/workspace/work-size.d.ts.map +1 -0
  377. package/dist/workspace/work.d.ts +26 -1
  378. package/dist/workspace/work.d.ts.map +1 -1
  379. package/dist/workspace/workspace-kinds.schema.json +122 -0
  380. package/dist/workspace/workspace-principals.schema.json +60 -0
  381. package/dist/workspace/write-lock-cli.d.ts +60 -0
  382. package/dist/workspace/write-lock-cli.d.ts.map +1 -0
  383. package/dist/workspace/write-lock.d.ts +152 -0
  384. package/dist/workspace/write-lock.d.ts.map +1 -0
  385. package/dist/workspace/write-scope.d.ts +83 -19
  386. package/dist/workspace/write-scope.d.ts.map +1 -1
  387. package/dist/yaml.d.ts +21 -39
  388. package/dist/yaml.d.ts.map +1 -1
  389. package/package.json +7 -2
  390. package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
  391. package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
  392. package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
  393. package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
  394. package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
  395. package/src/__fixtures__/change-set/warden.plan.json +44 -0
  396. package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
  397. package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
  398. package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
  399. package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
  400. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
  401. package/src/audit/core.test.ts +15 -0
  402. package/src/audit/core.ts +8 -2
  403. package/src/audit/discover.test.ts +11 -0
  404. package/src/audit/discover.ts +7 -2
  405. package/src/audit/prior-art.ts +15 -0
  406. package/src/change-set-bundle.test.ts +57 -0
  407. package/src/change-set.test.ts +215 -0
  408. package/src/change-set.ts +445 -0
  409. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
  410. package/src/cli/commands/audit-opt-in.test.ts +54 -0
  411. package/src/cli/commands/audit.ts +29 -2
  412. package/src/cli/commands/build.test.ts +19 -0
  413. package/src/cli/commands/build.ts +3 -2
  414. package/src/cli/commands/carve-emit-state.test.ts +4 -0
  415. package/src/cli/commands/carve-emit.ts +5 -19
  416. package/src/cli/commands/check-lexicon.test.ts +62 -1
  417. package/src/cli/commands/check-lexicon.ts +36 -6
  418. package/src/cli/commands/import-live.test.ts +18 -0
  419. package/src/cli/commands/import-parser-options.test.ts +133 -0
  420. package/src/cli/commands/import.ts +21 -3
  421. package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
  422. package/src/cli/commands/init.test.ts +8 -1
  423. package/src/cli/commands/init.ts +23 -8
  424. package/src/cli/commands/lint.test.ts +37 -0
  425. package/src/cli/commands/onboard.test.ts +53 -3
  426. package/src/cli/commands/onboard.ts +52 -4
  427. package/src/cli/commands/pinned-upgrade.ts +73 -33
  428. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
  429. package/src/cli/handlers/build.ts +13 -1
  430. package/src/cli/handlers/change-set.test.ts +56 -0
  431. package/src/cli/handlers/change-set.ts +44 -0
  432. package/src/cli/handlers/components.ts +2 -2
  433. package/src/cli/handlers/dev.ts +8 -6
  434. package/src/cli/handlers/fan-out.test.ts +221 -2
  435. package/src/cli/handlers/fan-out.ts +165 -75
  436. package/src/cli/handlers/graph.ts +3 -0
  437. package/src/cli/handlers/lifecycle.test.ts +67 -0
  438. package/src/cli/handlers/lifecycle.ts +6 -5
  439. package/src/cli/handlers/misc.ts +2 -0
  440. package/src/cli/handlers/operator.test.ts +21 -0
  441. package/src/cli/handlers/operator.ts +121 -6
  442. package/src/cli/handlers/pr.ts +373 -0
  443. package/src/cli/handlers/run.test.ts +111 -0
  444. package/src/cli/handlers/run.ts +86 -24
  445. package/src/cli/handlers/scenario.ts +2 -2
  446. package/src/cli/main.test.ts +21 -0
  447. package/src/cli/main.ts +246 -30
  448. package/src/cli/mcp/never-over-mcp.test.ts +101 -0
  449. package/src/cli/mcp/op-tools.ts +24 -2
  450. package/src/cli/mcp/workspace-tools.test.ts +5 -2
  451. package/src/cli/mcp/workspace-tools.ts +62 -7
  452. package/src/cli/registry.ts +74 -3
  453. package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
  454. package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
  455. package/src/codegen/pinned-upgrade.test.ts +104 -0
  456. package/src/codegen/pinned-upgrade.ts +250 -56
  457. package/src/codegen/testdata/postgres-tags.json +242 -0
  458. package/src/components/auto-release.ts +1 -1
  459. package/src/components/capability.ts +55 -0
  460. package/src/components/changed-files.ts +66 -0
  461. package/src/components/cli-support.ts +28 -5
  462. package/src/components/component.schema.json +17 -0
  463. package/src/components/component.ts +25 -0
  464. package/src/components/deploy-units.ts +3 -0
  465. package/src/components/driver.test.ts +52 -0
  466. package/src/components/driver.ts +31 -13
  467. package/src/components/fan-out-output.ts +42 -1
  468. package/src/components/fan-out-record.ts +69 -0
  469. package/src/components/fan-out-run.test.ts +17 -0
  470. package/src/components/fan-out-run.ts +304 -1
  471. package/src/components/fan-out-support.ts +3 -0
  472. package/src/components/fan-out-waves.test.ts +375 -0
  473. package/src/components/fan-out.ts +18 -17
  474. package/src/components/gated-wave-pipeline.ts +82 -0
  475. package/src/components/index.ts +1 -0
  476. package/src/components/layers.ts +30 -0
  477. package/src/components/pr-pipeline.ts +91 -0
  478. package/src/components/pr-run.test.ts +205 -0
  479. package/src/components/pr-run.ts +280 -0
  480. package/src/components/promote.ts +5 -0
  481. package/src/components/verbs/shell.test.ts +11 -0
  482. package/src/components/verbs/shell.ts +7 -3
  483. package/src/components/wave-plan.ts +124 -0
  484. package/src/config.test.ts +21 -0
  485. package/src/config.ts +15 -0
  486. package/src/declarable.test.ts +21 -0
  487. package/src/declarable.ts +19 -0
  488. package/src/discovery/fold-composite.test.ts +41 -5
  489. package/src/discovery/fold-import.test.ts +129 -0
  490. package/src/discovery/fold-import.ts +643 -131
  491. package/src/discovery/fold-package-composite.test.ts +264 -0
  492. package/src/discovery/fold-specifiers.test.ts +191 -0
  493. package/src/discovery/param-deps.test.ts +66 -1
  494. package/src/discovery/param-deps.ts +45 -0
  495. package/src/discovery/sandbox/bundle.ts +1 -1
  496. package/src/discovery/specifier-resolve.ts +344 -0
  497. package/src/fold/fold.test.ts +39 -1
  498. package/src/fold/fold.ts +83 -9
  499. package/src/fold-provenance.test.ts +140 -0
  500. package/src/gated-waves-bundle.test.ts +62 -0
  501. package/src/gated-waves.test.ts +118 -0
  502. package/src/gated-waves.ts +240 -0
  503. package/src/graph-ir.test.ts +83 -0
  504. package/src/graph-ir.ts +29 -0
  505. package/src/import/embedded.test.ts +20 -0
  506. package/src/import/embedded.ts +13 -0
  507. package/src/import/parser-options.ts +46 -0
  508. package/src/import/parser.ts +20 -0
  509. package/src/index.ts +1 -0
  510. package/src/lexicon.ts +106 -3
  511. package/src/lifecycle/gate-ledger.ts +23 -0
  512. package/src/lifecycle/git.ts +102 -16
  513. package/src/lifecycle/observe.test.ts +18 -0
  514. package/src/lifecycle/observe.ts +6 -4
  515. package/src/lifecycle/snapshot.ts +2 -2
  516. package/src/lifecycle/work-lease.test.ts +1 -1
  517. package/src/lifecycle/work-lease.ts +93 -2
  518. package/src/lint/engine.test.ts +55 -0
  519. package/src/lint/engine.ts +30 -4
  520. package/src/lint/output-docs.test.ts +59 -56
  521. package/src/lint/post-synth.test.ts +19 -0
  522. package/src/lint/post-synth.ts +19 -1
  523. package/src/meta/declared-imports.test.ts +1 -1
  524. package/src/op/activities/activity-contracts.ts +84 -0
  525. package/src/op/activities/apply.test.ts +189 -5
  526. package/src/op/activities/apply.ts +230 -8
  527. package/src/op/activities/change-set.ts +114 -0
  528. package/src/op/activities/decide.ts +3 -0
  529. package/src/op/activities/factory.ts +675 -0
  530. package/src/op/activities/index.ts +9 -0
  531. package/src/op/activities/lexicon-upgrade.test.ts +160 -6
  532. package/src/op/activities/lexicon-upgrade.ts +154 -51
  533. package/src/op/activity-contract.test.ts +21 -1
  534. package/src/op/activity-contract.ts +19 -9
  535. package/src/op/builders.ts +23 -0
  536. package/src/op/composites/apply-op.ts +12 -5
  537. package/src/op/composites/composites.test.ts +30 -3
  538. package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
  539. package/src/op/composites/lexicon-upgrade-op.ts +29 -8
  540. package/src/op/decide-backend.ts +5 -1
  541. package/src/op/decide-read-inputs.ts +33 -5
  542. package/src/op/emulator-lifecycle.test.ts +23 -0
  543. package/src/op/emulator-lifecycle.ts +52 -14
  544. package/src/op/factory.e2e.test.ts +232 -0
  545. package/src/op/factory.ts +118 -0
  546. package/src/op/gate-approval.test.ts +74 -0
  547. package/src/op/gate-approval.ts +5 -1
  548. package/src/op/gate.ts +31 -5
  549. package/src/op/index.ts +11 -1
  550. package/src/op/local-executor.test.ts +15 -0
  551. package/src/op/local-executor.ts +40 -12
  552. package/src/op/local-output.ts +1 -1
  553. package/src/op/op-ir.test.ts +9 -0
  554. package/src/op/op-ir.ts +4 -0
  555. package/src/op/op-verb-class.ts +3 -0
  556. package/src/op/operator.ts +4 -0
  557. package/src/op/run-context.test.ts +141 -0
  558. package/src/op/run-context.ts +51 -0
  559. package/src/op/runtimes/local.test.ts +14 -0
  560. package/src/op/runtimes/local.ts +2 -0
  561. package/src/op/steward-beside.ts +2 -0
  562. package/src/op/types.ts +16 -3
  563. package/src/op/work-lease-run.test.ts +47 -0
  564. package/src/op/work-lease-run.ts +76 -11
  565. package/src/plan-summary.test.ts +263 -0
  566. package/src/plan-summary.ts +845 -0
  567. package/src/pr-forge.test.ts +237 -0
  568. package/src/pr-forge.ts +332 -0
  569. package/src/pr-loop-bundle.test.ts +46 -0
  570. package/src/pr-loop.test.ts +171 -0
  571. package/src/pr-loop.ts +324 -0
  572. package/src/provenance.ts +35 -0
  573. package/src/telemetry-attribution.test.ts +23 -1
  574. package/src/telemetry-attribution.ts +51 -0
  575. package/src/terraform/hcl2json.test.ts +21 -0
  576. package/src/terraform/hcl2json.ts +81 -0
  577. package/src/terraform/parse.ts +11 -74
  578. package/src/workspace/agent-cli.ts +7 -3
  579. package/src/workspace/agent.schema.json +22 -0
  580. package/src/workspace/app-kind.test.ts +196 -0
  581. package/src/workspace/box-cli.ts +113 -0
  582. package/src/workspace/box-factory.test.ts +323 -0
  583. package/src/workspace/box-factory.ts +136 -0
  584. package/src/workspace/box-listing-write.schema.json +204 -0
  585. package/src/workspace/box-listing.test.ts +234 -0
  586. package/src/workspace/box-listing.ts +324 -0
  587. package/src/workspace/box-publish.schema.json +498 -0
  588. package/src/workspace/box-publish.test.ts +204 -0
  589. package/src/workspace/box-publish.ts +420 -0
  590. package/src/workspace/box-ship.test.ts +96 -0
  591. package/src/workspace/broker-protocol.schema.json +186 -0
  592. package/src/workspace/broker-protocol.test.ts +122 -0
  593. package/src/workspace/broker-protocol.ts +317 -0
  594. package/src/workspace/builder-tiers.test.ts +146 -0
  595. package/src/workspace/change-set.schema.json +460 -0
  596. package/src/workspace/changes.schema.json +12 -20
  597. package/src/workspace/changes.ts +4 -1
  598. package/src/workspace/chant-migrations.e2e.test.ts +17 -5
  599. package/src/workspace/checks/boxes.test.ts +5 -0
  600. package/src/workspace/checks.ts +39 -8
  601. package/src/workspace/component-environments.test.ts +105 -0
  602. package/src/workspace/compose-graph.ts +7 -0
  603. package/src/workspace/composites.schema.json +23 -4
  604. package/src/workspace/composites.test.ts +8 -8
  605. package/src/workspace/composites.ts +13 -2
  606. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
  607. package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
  608. package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
  609. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
  610. package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
  611. package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
  612. package/src/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
  613. package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
  614. package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
  615. package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
  616. package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
  617. package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
  618. package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
  619. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
  620. package/src/workspace/conformance/broker.test.ts +122 -0
  621. package/src/workspace/conformance/broker.ts +792 -0
  622. package/src/workspace/conformance/conformance.e2e.test.ts +36 -3
  623. package/src/workspace/conformance/index.mjs +51 -3
  624. package/src/workspace/conformance/index.ts +107 -15
  625. package/src/workspace/conformance/vitest.ts +76 -2
  626. package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
  627. package/src/workspace/conformance/writer.test.ts +186 -0
  628. package/src/workspace/conformance/writer.ts +1191 -0
  629. package/src/workspace/decide.test.ts +208 -4
  630. package/src/workspace/decide.ts +433 -73
  631. package/src/workspace/decision-points.schema.json +11 -4
  632. package/src/workspace/declaration.schema.json +383 -5
  633. package/src/workspace/declaration.ts +315 -10
  634. package/src/workspace/environments.ts +66 -14
  635. package/src/workspace/factory-rules.test.ts +62 -0
  636. package/src/workspace/factory-rules.ts +218 -0
  637. package/src/workspace/graph-cli.ts +6 -3
  638. package/src/workspace/graph.schema.json +314 -0
  639. package/src/workspace/identity.test.ts +219 -0
  640. package/src/workspace/identity.ts +186 -0
  641. package/src/workspace/init.ts +82 -2
  642. package/src/workspace/intent-cli.ts +84 -13
  643. package/src/workspace/intent-patch-id.test.ts +162 -0
  644. package/src/workspace/intent-record.schema.json +336 -1
  645. package/src/workspace/intent-record.ts +96 -16
  646. package/src/workspace/intent-reviews.test.ts +76 -0
  647. package/src/workspace/intent-squash.test.ts +213 -0
  648. package/src/workspace/intent-why.test.ts +274 -0
  649. package/src/workspace/intent.schema.json +950 -9
  650. package/src/workspace/intent.test.ts +11 -2
  651. package/src/workspace/intent.ts +722 -65
  652. package/src/workspace/json-edit.test.ts +121 -0
  653. package/src/workspace/json-edit.ts +142 -0
  654. package/src/workspace/jsonc.ts +20 -0
  655. package/src/workspace/kinds.ts +201 -39
  656. package/src/workspace/lexicon-symbols.test.ts +148 -0
  657. package/src/workspace/lexicon-symbols.ts +125 -0
  658. package/src/workspace/lineage-upgrade.test.ts +63 -0
  659. package/src/workspace/lineage-upgrade.ts +146 -5
  660. package/src/workspace/plan-summary.schema.json +155 -0
  661. package/src/workspace/point-answer.schema.json +42 -2
  662. package/src/workspace/points-cli.ts +42 -16
  663. package/src/workspace/points-write.schema.json +163 -4
  664. package/src/workspace/points.schema.json +157 -2
  665. package/src/workspace/points.test.ts +13 -1
  666. package/src/workspace/points.ts +118 -12
  667. package/src/workspace/pr-report.schema.json +95 -0
  668. package/src/workspace/principal-classes.test.ts +175 -0
  669. package/src/workspace/principal-classes.ts +307 -0
  670. package/src/workspace/profiles.test.ts +159 -0
  671. package/src/workspace/read-contract.test.ts +2 -2
  672. package/src/workspace/reason-codes.test.ts +23 -3
  673. package/src/workspace/reason-codes.ts +61 -4
  674. package/src/workspace/record-sessions.ts +9 -8
  675. package/src/workspace/records-amend.schema.json +80 -0
  676. package/src/workspace/records-checkout.ts +106 -0
  677. package/src/workspace/records-cli.ts +123 -17
  678. package/src/workspace/records-close.schema.json +79 -0
  679. package/src/workspace/records-close.ts +31 -7
  680. package/src/workspace/records-concurrent.e2e.test.ts +135 -0
  681. package/src/workspace/records-concurrent.test.ts +145 -0
  682. package/src/workspace/records-formats.test.ts +46 -10
  683. package/src/workspace/records-new.schema.json +9 -0
  684. package/src/workspace/records-review.schema.json +80 -0
  685. package/src/workspace/records-sessions-write.test.ts +69 -0
  686. package/src/workspace/records-sessions.test.ts +22 -0
  687. package/src/workspace/records-uncommitted.test.ts +171 -0
  688. package/src/workspace/records-write.ts +219 -30
  689. package/src/workspace/records.schema.json +88 -1
  690. package/src/workspace/records.ts +76 -8
  691. package/src/workspace/reference-kinds/app/package.json +10 -0
  692. package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
  693. package/src/workspace/run-statement.schema.json +622 -0
  694. package/src/workspace/runs-cli.ts +710 -0
  695. package/src/workspace/runs-statement.test.ts +239 -0
  696. package/src/workspace/runs-write.schema.json +994 -0
  697. package/src/workspace/runs.schema.json +1257 -0
  698. package/src/workspace/runs.test.ts +281 -0
  699. package/src/workspace/runs.ts +970 -0
  700. package/src/workspace/session-kinds.ts +3 -3
  701. package/src/workspace/squash.ts +198 -0
  702. package/src/workspace/status-contract.test.ts +10 -2
  703. package/src/workspace/status-gates.ts +25 -9
  704. package/src/workspace/status.schema.json +252 -4
  705. package/src/workspace/status.ts +110 -1
  706. package/src/workspace/symbols.ts +191 -0
  707. package/src/workspace/trailer-joins.test.ts +171 -0
  708. package/src/workspace/trailer-joins.ts +82 -0
  709. package/src/workspace/trailers.ts +148 -0
  710. package/src/workspace/trust/run-commits.ts +115 -0
  711. package/src/workspace/trust/run-statement.ts +226 -0
  712. package/src/workspace/trust/seal.ts +58 -1
  713. package/src/workspace/trust/verify-cli.ts +6 -5
  714. package/src/workspace/trust/verify.ts +39 -6
  715. package/src/workspace/wip-cli.ts +97 -0
  716. package/src/workspace/wip-write.schema.json +504 -0
  717. package/src/workspace/wip.schema.json +334 -0
  718. package/src/workspace/wip.test.ts +294 -0
  719. package/src/workspace/wip.ts +753 -0
  720. package/src/workspace/work-cli.e2e.test.ts +28 -1
  721. package/src/workspace/work-cli.ts +136 -8
  722. package/src/workspace/work-evidence.schema.json +5 -0
  723. package/src/workspace/work-history.schema.json +73 -1
  724. package/src/workspace/work-history.test.ts +48 -5
  725. package/src/workspace/work-kind-fields.test.ts +154 -0
  726. package/src/workspace/work-lease.schema.json +14 -1
  727. package/src/workspace/work-size.test.ts +77 -0
  728. package/src/workspace/work-size.ts +93 -0
  729. package/src/workspace/work.ts +82 -0
  730. package/src/workspace/workspace-kinds.schema.json +122 -0
  731. package/src/workspace/workspace-principals.schema.json +60 -0
  732. package/src/workspace/write-lock-cli.ts +131 -0
  733. package/src/workspace/write-lock.schema.json +172 -0
  734. package/src/workspace/write-lock.test.ts +189 -0
  735. package/src/workspace/write-lock.ts +474 -0
  736. package/src/workspace/write-scope.test.ts +144 -3
  737. package/src/workspace/write-scope.ts +192 -45
  738. package/src/yaml.test.ts +111 -1
  739. package/src/yaml.ts +141 -549
@@ -508,3 +508,143 @@ describe("fold provenance over a real composite build (#2161)", () => {
508
508
  expect(verdicts[3].resolution.kind).toBe("edit-declaration");
509
509
  });
510
510
  });
511
+
512
+ // ─────────────────────────────────────────────────────────────────────────
513
+ // chant #3212 — a registered tag inside a composite factory.
514
+ // ─────────────────────────────────────────────────────────────────────────
515
+
516
+ const runtimePath = resolve(thisDir, "./runtime");
517
+ const provenancePath = resolve(thisDir, "./provenance");
518
+
519
+ /**
520
+ * A SQL-shaped tag, the shape the sql lexicon's `table` takes: it builds one
521
+ * entity out of its text and reports, per interpolation, which of the entity's
522
+ * fields that interpolation fed. An interpolated entity is a reference and
523
+ * feeds nothing the author typed, so it reports no field.
524
+ */
525
+ const TAGS = `
526
+ import { createResource } from ${JSON.stringify(runtimePath)};
527
+ import { setInterpolationFields } from ${JSON.stringify(provenancePath)};
528
+ const Table = createResource("Test::Table", ${JSON.stringify(LEXICON_NAME)}, {});
529
+ const CLAUSE = { TABLE: "name", "ENGINE =": "engine", "ORDER BY": "orderBy", TTL: "ttl", COMMENT: "comment" };
530
+
531
+ export function table(strings, ...values) {
532
+ const isEntity = (v) => typeof v === "object" && v !== null && "props" in v;
533
+ let ddl = strings[0];
534
+ const fields = values.map((v, i) => {
535
+ ddl += (isEntity(v) ? v.props.name : String(v)) + strings[i + 1];
536
+ if (isEntity(v)) return [];
537
+ const at = (k) => strings[i].lastIndexOf(k);
538
+ const clause = Object.keys(CLAUSE).sort((a, b) => at(b) - at(a))[0];
539
+ return at(clause) >= 0 ? [CLAUSE[clause], "ddl"] : ["ddl"];
540
+ });
541
+ const m = /CREATE TABLE (\\w+) ENGINE = (\\w+) ORDER BY (\\w+)(?: TTL (.+?))?(?: COMMENT (\\w+))?$/.exec(ddl);
542
+ if (!m) throw new Error("cannot parse: " + ddl);
543
+ const props = { name: m[1], engine: m[2], orderBy: m[3], ddl };
544
+ if (m[4]) props.ttl = m[4];
545
+ if (m[5]) props.comment = m[5];
546
+ const entity = new Table(props);
547
+ setInterpolationFields(entity, fields);
548
+ return entity;
549
+ }
550
+ `;
551
+
552
+ const TAG_COMPOSITES = `
553
+ import { table } from "./tags";
554
+ import { Composite } from ${JSON.stringify(compositePath)};
555
+
556
+ export const EventsTable = Composite((props) => {
557
+ const rollupName = \`\${props.name}_daily\`;
558
+ const events = table\`CREATE TABLE \${props.name} ENGINE = MergeTree ORDER BY ts TTL ts + INTERVAL \${props.ttlDays} DAY\`;
559
+ const rollup = table\`CREATE TABLE \${rollupName} ENGINE = \${"SummingMergeTree"} ORDER BY ts COMMENT \${events}\`;
560
+ return { events, rollup };
561
+ }, "EventsTable");
562
+ `;
563
+
564
+ const TAG_MAIN = `
565
+ import { table } from "../tags";
566
+ import { EventsTable } from "../composites";
567
+
568
+ export const audit = table\`CREATE TABLE audit ENGINE = MergeTree ORDER BY ts\`;
569
+ export const clicks = EventsTable({ name: "clicks", ttlDays: 30 });
570
+ `;
571
+
572
+ describe("fold provenance through a tagged template in a composite factory (#3212)", () => {
573
+ let testDir: string;
574
+ let srcDir: string;
575
+
576
+ beforeEach(async () => {
577
+ const dir = join(repoRoot, ".cache", `chant-3212-${process.pid}-${seq++}`);
578
+ await rm(dir, { recursive: true, force: true });
579
+ await mkdir(dir, { recursive: true });
580
+ testDir = await realpath(dir);
581
+ srcDir = join(testDir, "src");
582
+ await mkdir(srcDir, { recursive: true });
583
+ await writeFile(join(testDir, "tags.ts"), TAGS);
584
+ await writeFile(join(testDir, "composites.ts"), TAG_COMPOSITES);
585
+ await writeFile(join(srcDir, "main.ts"), TAG_MAIN);
586
+ });
587
+
588
+ afterEach(async () => {
589
+ await rm(testDir, { recursive: true, force: true });
590
+ });
591
+
592
+ const buildIt = () =>
593
+ build(srcDir, [namesSerializer], undefined, {
594
+ fold: true,
595
+ lexicons: [LEXICON_NAME],
596
+ intrinsics: [{ name: "table", isTag: true }],
597
+ });
598
+
599
+ test("a field fed by ${props.x} is that parameter, a field the text fixes is a literal", async () => {
600
+ const result = await buildIt();
601
+ expect(result.errors).toEqual([]);
602
+ const events = result.foldProvenance.clicksEvents;
603
+ const rollup = result.foldProvenance.clicksRollup;
604
+ const at = (parameters: string[]) => ({ kind: "composite-parameter", composite: "EventsTable", instance: "clicks", parameters });
605
+ const fixed = { kind: "composite-literal", composite: "EventsTable", instance: "clicks" };
606
+
607
+ expect(events.fields.name).toEqual(at(["name"]));
608
+ expect(events.fields.ttl).toEqual(at(["ttlDays"]));
609
+ expect(events.fields.ddl).toEqual(at(["name", "ttlDays"]));
610
+ expect(events.fields.engine).toEqual(fixed);
611
+ expect(events.fields.orderBy).toEqual(fixed);
612
+
613
+ // Through a body `const`; an interpolated literal string is fixed; an
614
+ // interpolated sibling entity is wiring, so it governs nothing.
615
+ expect(rollup.fields.name).toEqual(at(["name"]));
616
+ expect(rollup.fields.engine).toEqual(fixed);
617
+ expect(rollup.fields.comment).toEqual(fixed);
618
+ expect(rollup.fields.ddl).toEqual(at(["name"]));
619
+
620
+ expect(result.foldProvenance.audit.fields.ttl).toBeUndefined();
621
+ expect(result.foldProvenance.audit.fields.name).toEqual({ kind: "direct" });
622
+ });
623
+
624
+ test("drift on a parameter-fed field proposes the parameter at the call site", async () => {
625
+ const result = await buildIt();
626
+ const provenanceOf = (name: string): EntityProvenance | undefined => {
627
+ const entity = result.entities.get(name);
628
+ return entity ? getProvenance(entity) : undefined;
629
+ };
630
+ const drift = (name: string, path: string, declared: unknown, live: unknown): DeepEntityDrift => {
631
+ const origin = originOfPath(provenanceOf(name)?.paths, path);
632
+ return { name, type: "Test::Table", changes: [{ path, kind: "changed", declared, live, ...(origin ? { origin } : {}) }] };
633
+ };
634
+
635
+ const [ttl, engine] = resolveDeepDrift(
636
+ [
637
+ drift("clicksEvents", "ttl", "ts + INTERVAL 30 DAY", "ts + INTERVAL 90 DAY"),
638
+ drift("clicksEvents", "engine", "MergeTree", "ReplacingMergeTree"),
639
+ ],
640
+ provenanceOf,
641
+ );
642
+
643
+ expect(ttl.resolution.kind).toBe("propose-parameter");
644
+ if (ttl.resolution.kind !== "propose-parameter") throw new Error("unreachable");
645
+ expect(ttl.resolution.parameters).toEqual(["ttlDays"]);
646
+ expect(ttl.resolution.instance).toBe("clicks");
647
+ expect(ttl.resolution.sourceFile).toContain("main.ts");
648
+ expect(engine.resolution.kind).toBe("refuse-fixed");
649
+ });
650
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * The gated-wave primitives bundle small (#3049, ruling #3421).
3
+ *
4
+ * terragucci runs a wave per CI job from one bundled file with no TypeScript
5
+ * toolchain. It calls wave planning, the set digest and the gate names from
6
+ * `@intentius/chant/gated-waves`, and decides a wave's gate with
7
+ * `evaluateGate` from `@intentius/chant/op/gate` against the
8
+ * `chant/lifecycle` ledger. This bundles both the way terragucci would and
9
+ * reads esbuild's own list of what went in.
10
+ */
11
+
12
+ import { join } from "node:path";
13
+ import { build } from "esbuild";
14
+ import { describe, expect, test } from "vitest";
15
+ import { REPO } from "./workspace/__fixtures__/contract-repo";
16
+
17
+ const HEAVY = [/node_modules\/typescript\//, /node_modules\/esbuild\//, /\/src\/fold\//, /\/src\/lint\//, /\/src\/codegen\//];
18
+
19
+ async function inputsOf(entry: string): Promise<{ inputs: string[]; bytes: number }> {
20
+ const result = await build({
21
+ entryPoints: [join(REPO, "packages", "core", "src", entry)],
22
+ bundle: true,
23
+ platform: "node",
24
+ format: "esm",
25
+ write: false,
26
+ metafile: true,
27
+ outdir: "out",
28
+ logLevel: "silent",
29
+ });
30
+ return {
31
+ inputs: Object.keys(result.metafile.inputs),
32
+ bytes: result.outputFiles.reduce((n, f) => n + f.contents.byteLength, 0),
33
+ };
34
+ }
35
+
36
+ describe("the gated-wave bundle", () => {
37
+ test("wave planning, the set digest and the records hold the change-set digest code and nothing heavier", async () => {
38
+ const { inputs, bytes } = await inputsOf("gated-waves.ts");
39
+ for (const pattern of [...HEAVY, /node_modules\/zod\//]) {
40
+ expect(inputs.filter((i) => pattern.test(i)), String(pattern)).toEqual([]);
41
+ }
42
+ expect(inputs.map((i) => i.replace(/^.*?packages\//, "packages/")).sort()).toEqual([
43
+ "packages/core/src/change-set.ts",
44
+ "packages/core/src/content-digest.ts",
45
+ "packages/core/src/declarable.ts",
46
+ "packages/core/src/effect-receipt.ts",
47
+ "packages/core/src/gated-waves.ts",
48
+ "packages/core/src/intrinsic.ts",
49
+ "packages/core/src/lifecycle/plan-digest.ts",
50
+ ]);
51
+ expect(bytes).toBeLessThan(24 * 1024);
52
+ });
53
+
54
+ test("the gate decision reaches no TypeScript, esbuild, fold, lint or codegen module", async () => {
55
+ // It does reach zod, through the workspace identity rules a gate reads
56
+ // (#3163). That is weight, not a toolchain, and #3421 forbids the toolchain.
57
+ const { inputs } = await inputsOf("op/gate.ts");
58
+ for (const pattern of HEAVY) {
59
+ expect(inputs.filter((i) => pattern.test(i)), String(pattern)).toEqual([]);
60
+ }
61
+ });
62
+ });
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Gated waves (#3049): the parts with no runner. Wave layering with a canary
3
+ * list, the set digest, gate names and the attempt record's wave entries.
4
+ */
5
+
6
+ import { describe, expect, test } from "vitest";
7
+ import {
8
+ ProvisionalWaveMemberError,
9
+ UnknownCanaryError,
10
+ WaveCycleError,
11
+ describeChangedWave,
12
+ layerWaves,
13
+ readWaveRecords,
14
+ waveGateName,
15
+ waveSetDigest,
16
+ withWaveRecord,
17
+ type WaveRecord,
18
+ } from "./gated-waves";
19
+ import { changeSetDigest } from "./change-set";
20
+
21
+ /** net → a, b → app-a (on a), app-b (on b). */
22
+ const ROOTS = [
23
+ { name: "net" },
24
+ { name: "a", dependsOn: ["net"] },
25
+ { name: "b", dependsOn: ["net"] },
26
+ { name: "app-a", dependsOn: ["a"] },
27
+ { name: "app-b", dependsOn: ["b"] },
28
+ ];
29
+
30
+ describe("layerWaves", () => {
31
+ test("dependency order, each wave sorted", () => {
32
+ expect(layerWaves(ROOTS)).toEqual([["net"], ["a", "b"], ["app-a", "app-b"]]);
33
+ });
34
+
35
+ test("a canary list is wave 1 whatever the graph order, and the rest follow the graph", () => {
36
+ expect(layerWaves(ROOTS, { canary: ["app-b"] })).toEqual([["app-b"], ["net"], ["a", "b"], ["app-a"]]);
37
+ expect(layerWaves(ROOTS, { canary: ["b", "net"] })).toEqual([["b", "net"], ["a", "app-b"], ["app-a"]]);
38
+ });
39
+
40
+ test("a dependency outside the set does not hold a node back", () => {
41
+ expect(layerWaves([{ name: "a", dependsOn: ["net"] }, { name: "app-a", dependsOn: ["a"] }])).toEqual([["a"], ["app-a"]]);
42
+ });
43
+
44
+ test("a canary that is not in the set is refused, unless it is known and just not changing", () => {
45
+ expect(() => layerWaves(ROOTS, { canary: ["nope"] })).toThrow(UnknownCanaryError);
46
+ expect(layerWaves(ROOTS.slice(0, 2), { canary: ["app-b"], known: ["app-b"] })).toEqual([["net"], ["a"]]);
47
+ });
48
+
49
+ test("a cycle is refused by name", () => {
50
+ expect(() => layerWaves([{ name: "x", dependsOn: ["y"] }, { name: "y", dependsOn: ["x"] }])).toThrow(WaveCycleError);
51
+ });
52
+ });
53
+
54
+ describe("the set digest", () => {
55
+ const members = [
56
+ { member: "net", planDigest: "jcs1-sha256:" + "1".repeat(64) },
57
+ { member: "a", planDigest: "jcs1-sha256:" + "2".repeat(64) },
58
+ ];
59
+
60
+ test("is the change-set digest of the wave's members", () => {
61
+ expect(waveSetDigest(members)).toBe(changeSetDigest(members));
62
+ expect(waveSetDigest(members)).toMatch(/^jcs1-sha256:[0-9a-f]{64}$/);
63
+ });
64
+
65
+ test("does not depend on order and moves when one root's plan does", () => {
66
+ expect(waveSetDigest([...members].reverse())).toBe(waveSetDigest(members));
67
+ expect(waveSetDigest([members[0], { member: "a", planDigest: "jcs1-sha256:" + "3".repeat(64) }])).not.toBe(
68
+ waveSetDigest(members),
69
+ );
70
+ });
71
+
72
+ test("refuses a wave that names one root twice", () => {
73
+ expect(() => waveSetDigest([members[0], members[0]])).toThrow(/twice/);
74
+ });
75
+
76
+ test("refuses a wave holding a provisional plan, by name", () => {
77
+ expect(() => waveSetDigest([members[0], { ...members[1], provisional: true }])).toThrow(ProvisionalWaveMemberError);
78
+ expect(() => waveSetDigest([members[0], { ...members[1], provisional: true }])).toThrow(/provisional plan: a planned/);
79
+ });
80
+ });
81
+
82
+ describe("wave records", () => {
83
+ const record: WaveRecord = {
84
+ wave: 2,
85
+ op: "fan-out",
86
+ gate: waveGateName("release", 2),
87
+ components: ["a", "b"],
88
+ digest: "jcs1-sha256:" + "4".repeat(64),
89
+ members: [{ member: "a", planDigest: "jcs1-sha256:" + "5".repeat(64) }],
90
+ status: "gated",
91
+ approved: "jcs1-sha256:" + "6".repeat(64),
92
+ };
93
+
94
+ test("each wave has its own gate", () => {
95
+ expect(waveGateName("release", 1)).toBe("release-wave-1");
96
+ expect(waveGateName("release", 1)).not.toBe(waveGateName("release", 2));
97
+ });
98
+
99
+ test("round-trip through JSON, dropping malformed entries", () => {
100
+ const read = readWaveRecords(JSON.parse(JSON.stringify([record, { wave: "x" }, null])));
101
+ expect(read).toEqual([record]);
102
+ expect(readWaveRecords(undefined)).toEqual([]);
103
+ });
104
+
105
+ test("a later record for the same wave replaces the earlier one", () => {
106
+ const applied: WaveRecord = { ...record, status: "applied", approvedBy: "ana" };
107
+ delete applied.approved;
108
+ expect(withWaveRecord([record], applied)).toEqual([applied]);
109
+ });
110
+
111
+ test("the changed-set refusal names both digests and says nothing applied", () => {
112
+ const line = describeChangedWave(record);
113
+ expect(line).toContain(record.approved);
114
+ expect(line).toContain(record.digest);
115
+ expect(line).toContain("nothing in it was applied");
116
+ expect(line).toContain("chant approve fan-out release-wave-2 --plan");
117
+ });
118
+ });
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Gated waves (#3049): one change rolled out across many roots, a wave at a
3
+ * time, each wave behind its own gate bound to that wave's set digest.
4
+ *
5
+ * `chant components fan-out --wave-gate` is the runner. This module holds the
6
+ * parts that need no runner: how a set of roots is cut into waves, what a
7
+ * wave's digest is, what its gate is called, and what the attempt record says
8
+ * about each wave. They are kept apart from the runner because terragucci
9
+ * calls them from its CI stages as one bundled file with no TypeScript
10
+ * toolchain (#3421). Everything here imports `./change-set` and nothing else,
11
+ * and `gated-waves-bundle.test.ts` holds that.
12
+ *
13
+ * ## The set digest
14
+ *
15
+ * A wave's digest is {@link changeSetDigest} over its members' `{ member,
16
+ * planDigest }` pairs, the function #3181's change-set document uses. A
17
+ * terraform-family member is named after its root, so this is the issue's
18
+ * `jcs1-sha256` over sorted `{ root, planDigest }`, and a wave's digest equals
19
+ * the change-set digest of the wave's members. Each member's plan digest is
20
+ * the one a gate on that root alone binds (`terraformPlanDigest`, #2300), so a
21
+ * one-root wave and a one-root `TerraformApplyOp` approve the same value.
22
+ *
23
+ * ## Why a wave is planned when it is reached
24
+ *
25
+ * A later wave planned up front reads outputs that do not exist yet. Planned
26
+ * after the wave before it applied, its digest describes the real upstream
27
+ * values, which is what an approver of that wave is shown.
28
+ */
29
+
30
+ import { changeSetDigest } from "./change-set";
31
+
32
+ /** A root, or a component, as wave planning sees it: a name and what it reads. */
33
+ export interface WaveNode {
34
+ name: string;
35
+ /** Names this node reads from. A name outside the node set is already satisfied. */
36
+ dependsOn?: readonly string[];
37
+ }
38
+
39
+ /** Thrown when a canary names something that is not in the set being planned. */
40
+ export class UnknownCanaryError extends Error {
41
+ constructor(
42
+ readonly canary: string,
43
+ known: readonly string[],
44
+ ) {
45
+ super(`canary names "${canary}", which is not in this set (known: ${known.join(", ") || "none"})`);
46
+ this.name = "UnknownCanaryError";
47
+ }
48
+ }
49
+
50
+ /** Thrown when the nodes being layered depend on each other in a cycle. */
51
+ export class WaveCycleError extends Error {
52
+ constructor(readonly members: string[]) {
53
+ super(`dependency cycle among: ${members.join(", ")}`);
54
+ this.name = "WaveCycleError";
55
+ }
56
+ }
57
+
58
+ export interface LayerWavesOptions {
59
+ /**
60
+ * Nodes that form wave 1 whatever the graph says (#3049). Only those in the
61
+ * set are placed; one outside it has nothing to apply. The rest follow in
62
+ * dependency order, and a dependency on a canary counts as satisfied by
63
+ * wave 1.
64
+ */
65
+ canary?: readonly string[];
66
+ /**
67
+ * Names known to exist outside `nodes`. A canary naming one of them is
68
+ * left out quietly, since it is real but not part of this change; any
69
+ * other unknown canary is refused. Defaults to `nodes` alone.
70
+ */
71
+ known?: readonly string[];
72
+ }
73
+
74
+ /**
75
+ * Cut `nodes` into ordered waves: each node lands after every node it reads
76
+ * from, and each wave is sorted by name so the same graph always produces the
77
+ * same waves. With a canary list, those nodes are wave 1.
78
+ *
79
+ * A dependency on a name outside `nodes` does not hold a node back. That is
80
+ * the subset case: the dependency already applied, or is not changing.
81
+ */
82
+ export function layerWaves(nodes: readonly WaveNode[], options: LayerWavesOptions = {}): string[][] {
83
+ const names = new Set(nodes.map((n) => n.name));
84
+ const known = new Set([...names, ...(options.known ?? [])]);
85
+ for (const canary of options.canary ?? []) {
86
+ if (!known.has(canary)) throw new UnknownCanaryError(canary, [...known].sort());
87
+ }
88
+ const canaries = [...new Set((options.canary ?? []).filter((c) => names.has(c)))].sort();
89
+
90
+ const waves: string[][] = canaries.length > 0 ? [canaries] : [];
91
+ const remaining = new Set([...names].filter((n) => !canaries.includes(n)));
92
+ const deps = new Map(nodes.map((n) => [n.name, (n.dependsOn ?? []).filter((d) => remaining.has(d))]));
93
+ while (remaining.size > 0) {
94
+ const wave = [...remaining].filter((n) => deps.get(n)!.every((d) => !remaining.has(d))).sort();
95
+ if (wave.length === 0) throw new WaveCycleError([...remaining].sort());
96
+ for (const n of wave) remaining.delete(n);
97
+ waves.push(wave);
98
+ }
99
+ return waves;
100
+ }
101
+
102
+ /** One member of a wave: a root (or a component with no plannable step) and its plan digest. */
103
+ export interface WaveMember {
104
+ member: string;
105
+ planDigest: string;
106
+ /** A provisional plan (`ChangeSetMember.provisional`, #3416). A wave refuses it. */
107
+ provisional?: true;
108
+ }
109
+
110
+ /** Thrown when a wave's members include a provisional plan, which no gate may bind. */
111
+ export class ProvisionalWaveMemberError extends Error {
112
+ constructor(readonly members: string[]) {
113
+ super(
114
+ `a wave cannot be gated on a provisional plan: ${members.join(", ")} planned before what it reads applied. ` +
115
+ `Plan it again in its own wave, after its upstream applied`,
116
+ );
117
+ this.name = "ProvisionalWaveMemberError";
118
+ }
119
+ }
120
+
121
+ /**
122
+ * A wave's set digest: {@link changeSetDigest} over its members. Order does
123
+ * not matter, and it moves whenever one member's plan digest does. A wave
124
+ * naming one member twice has no digest and is refused, and so is a wave
125
+ * holding a provisional plan (#3416): a gate bound to it would approve
126
+ * values nobody has yet.
127
+ */
128
+ export function waveSetDigest(members: readonly WaveMember[]): string {
129
+ const provisional = members.filter((m) => m.provisional === true).map((m) => m.member);
130
+ if (provisional.length > 0) throw new ProvisionalWaveMemberError([...new Set(provisional)].sort());
131
+ return changeSetDigest(members);
132
+ }
133
+
134
+ /**
135
+ * The gate a wave waits on: `<gate>-wave-<n>`, under the fan-out's op.
136
+ *
137
+ * One gate name per wave keeps each wave's approvals apart. With one name
138
+ * shared by every wave, wave 2 would find wave 1's approval and report it as
139
+ * an approval of another plan, which is true and useless. Wave numbers come
140
+ * from the derivation, not from what is left to run, so wave 3 stays wave 3
141
+ * on a resumed attempt and its approval still applies.
142
+ */
143
+ export function waveGateName(gate: string, wave: number): string {
144
+ return `${gate}-wave-${wave}`;
145
+ }
146
+
147
+ /** Where a wave got to. */
148
+ export type WaveStatus =
149
+ /** Planned, and its gate is not approved for this digest. Nothing in it ran. */
150
+ | "gated"
151
+ /** Every member applied. */
152
+ | "applied"
153
+ /** At least one member failed to plan or to apply. Its dependents are blocked. */
154
+ | "failed";
155
+
156
+ /**
157
+ * One wave, as an attempt record and a run result carry it. The plan report
158
+ * (#3349) reads these and points at the gate record rather than copying it:
159
+ * `op` and `gate` name the ledger entry (`_gates/<op>.jsonl` on
160
+ * `chant/lifecycle`).
161
+ */
162
+ export interface WaveRecord {
163
+ /** 1-based, from the derivation. */
164
+ wave: number;
165
+ op: string;
166
+ /** The full gate name, {@link waveGateName}. */
167
+ gate: string;
168
+ /** What was planned in this wave on this attempt. */
169
+ components: string[];
170
+ /** The set digest the gate was decided against. */
171
+ digest: string;
172
+ members: WaveMember[];
173
+ status: WaveStatus;
174
+ /** Who approved this digest, once the gate passed. */
175
+ approvedBy?: string;
176
+ /** When the gate refused because an approval stands for another digest: that digest. */
177
+ approved?: string;
178
+ /** Components that failed to plan or to apply, with why. */
179
+ failed?: Array<{ component: string; error?: string }>;
180
+ }
181
+
182
+ const isObject = (value: unknown): value is Record<string, unknown> =>
183
+ typeof value === "object" && value !== null && !Array.isArray(value);
184
+ const strings = (value: unknown): string[] =>
185
+ Array.isArray(value) ? value.filter((v): v is string => typeof v === "string") : [];
186
+
187
+ /**
188
+ * Read the `waves` array of an attempt record, dropping anything malformed.
189
+ * A record written before #3049 has none, which reads as no waves.
190
+ */
191
+ export function readWaveRecords(value: unknown): WaveRecord[] {
192
+ if (!Array.isArray(value)) return [];
193
+ const out: WaveRecord[] = [];
194
+ for (const raw of value) {
195
+ if (!isObject(raw)) continue;
196
+ const { wave, op, gate, digest, status } = raw;
197
+ if (typeof wave !== "number" || typeof op !== "string" || typeof gate !== "string" || typeof digest !== "string") continue;
198
+ if (status !== "gated" && status !== "applied" && status !== "failed") continue;
199
+ const members = Array.isArray(raw.members)
200
+ ? raw.members.filter(
201
+ (m): m is WaveMember => isObject(m) && typeof m.member === "string" && typeof m.planDigest === "string",
202
+ )
203
+ : [];
204
+ const failed = Array.isArray(raw.failed)
205
+ ? raw.failed
206
+ .filter((f): f is { component: string; error?: unknown } => isObject(f) && typeof f.component === "string")
207
+ .map((f) => ({ component: f.component, ...(typeof f.error === "string" ? { error: f.error } : {}) }))
208
+ : [];
209
+ out.push({
210
+ wave,
211
+ op,
212
+ gate,
213
+ components: strings(raw.components),
214
+ digest,
215
+ members: members.map((m) => ({ member: m.member, planDigest: m.planDigest })),
216
+ status,
217
+ ...(typeof raw.approvedBy === "string" ? { approvedBy: raw.approvedBy } : {}),
218
+ ...(typeof raw.approved === "string" ? { approved: raw.approved } : {}),
219
+ ...(failed.length > 0 ? { failed } : {}),
220
+ });
221
+ }
222
+ return out;
223
+ }
224
+
225
+ /** Put `record` in `records` in place of any earlier record for the same wave, sorted by wave. */
226
+ export function withWaveRecord(records: readonly WaveRecord[], record: WaveRecord): WaveRecord[] {
227
+ return [...records.filter((r) => r.wave !== record.wave), record].sort((a, b) => a.wave - b.wave);
228
+ }
229
+
230
+ /**
231
+ * The refusal for a wave whose set changed after it was approved: the digest
232
+ * that was approved, the one planned now, and that nothing in the wave ran.
233
+ */
234
+ export function describeChangedWave(record: Pick<WaveRecord, "wave" | "op" | "gate" | "digest" | "approved">): string {
235
+ return (
236
+ `wave ${record.wave} changed after it was approved, so nothing in it was applied. ` +
237
+ `approved: ${record.approved ?? "(none)"}; planned now: ${record.digest}. ` +
238
+ `Read the new plan, then approve it: chant approve ${record.op} ${record.gate} --plan ${record.digest}`
239
+ );
240
+ }
@@ -287,3 +287,86 @@ describe("entity-declared references and stacks", () => {
287
287
  expect(ir.nodes.find((n) => n.id === "app/vpc")!.attrs).not.toHaveProperty("stack");
288
288
  });
289
289
  });
290
+
291
+ describe("whole declarables held in an entity's fields (#3257)", () => {
292
+ /** An entity shaped like the sql lexicon's: props non-enumerable, `dependsOn` enumerable. */
293
+ function holder(dependsOn: unknown[], extra: object = {}) {
294
+ const e = decl({ lexicon: "sql", entityType: "ClickHouse::Table", ...extra });
295
+ Object.defineProperty(e, "dependsOn", { value: dependsOn, enumerable: true });
296
+ return e;
297
+ }
298
+
299
+ test("draws an edge to each node named directly in an enumerable array", () => {
300
+ const db = decl({ lexicon: "sql", entityType: "ClickHouse::Database" });
301
+ const target = holder([db]);
302
+ const events = holder([db]);
303
+ const mv = holder([db, target, events]);
304
+ const entities = new Map<string, Declarable>([
305
+ ["analytics", db],
306
+ ["dailyActive", target],
307
+ ["events", events],
308
+ ["dailyActiveMv", mv],
309
+ ]);
310
+ resolveAttrRefs(entities);
311
+
312
+ const ir = buildGraphIr(entities);
313
+ const dep = (from: string, to: string) => ({ from, to, kind: "ref", viaAttr: "dependsOn" });
314
+ expect(ir.edges).toEqual([
315
+ dep("dailyActive", "analytics"),
316
+ dep("dailyActiveMv", "analytics"),
317
+ dep("dailyActiveMv", "dailyActive"),
318
+ dep("dailyActiveMv", "events"),
319
+ dep("events", "analytics"),
320
+ ]);
321
+ });
322
+
323
+ test("does not walk into the referenced node, and projects it as a $ref", () => {
324
+ const db = decl({ lexicon: "sql", entityType: "ClickHouse::Database", props: { name: "analytics" } });
325
+ const events = holder([db]);
326
+ const entities = new Map<string, Declarable>([
327
+ ["analytics", db],
328
+ ["events", events],
329
+ ]);
330
+ resolveAttrRefs(entities);
331
+
332
+ const ir = buildGraphIr(entities);
333
+ expect(ir.nodes.find((n) => n.id === "events")!.attrs.dependsOn).toEqual([{ $ref: "analytics" }]);
334
+ });
335
+
336
+ test("an AttrRef and the whole node to the same target collapse to one edge", () => {
337
+ const db = decl({ lexicon: "sql", entityType: "ClickHouse::Database" });
338
+ const events = decl({ lexicon: "sql", entityType: "ClickHouse::Table" });
339
+ const mv = holder([events, new AttrRef(events, "user_id")]);
340
+ const entities = new Map<string, Declarable>([
341
+ ["analytics", db],
342
+ ["events", events],
343
+ ["mv", mv],
344
+ ]);
345
+ resolveAttrRefs(entities);
346
+
347
+ const ir = buildGraphIr(entities);
348
+ expect(ir.edges).toEqual([{ from: "mv", to: "events", kind: "ref", viaAttr: "dependsOn" }]);
349
+ });
350
+
351
+ test("ignores a self reference, and still descends into an inlined property-kind resource", () => {
352
+ const self: Declarable = holder([]);
353
+ (self as unknown as { dependsOn: unknown[] }).dependsOn.push(self);
354
+ const vpc = decl({ lexicon: "aws", entityType: "Vpc" });
355
+ const inline = decl({
356
+ lexicon: "aws",
357
+ entityType: "Listener_Action",
358
+ kind: "property",
359
+ props: { vpc: new AttrRef(vpc, "Id") },
360
+ });
361
+ const lb = decl({ lexicon: "aws", entityType: "Lb", props: { actions: [inline] } });
362
+ const entities = new Map<string, Declarable>([
363
+ ["self", self],
364
+ ["vpc", vpc],
365
+ ["lb", lb],
366
+ ]);
367
+ resolveAttrRefs(entities);
368
+
369
+ const ir = buildGraphIr(entities);
370
+ expect(ir.edges).toEqual([{ from: "lb", to: "vpc", kind: "ref", viaAttr: "actions" }]);
371
+ });
372
+ });