@intentius/chant 0.124.52 → 0.124.54

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 (584) hide show
  1. package/dist/audit/discover.d.ts.map +1 -1
  2. package/dist/audit/discover.js +3 -1
  3. package/dist/behaviour.d.ts +1 -1
  4. package/dist/behaviour.d.ts.map +1 -1
  5. package/dist/capabilities/templates.d.ts +65 -0
  6. package/dist/capabilities/templates.d.ts.map +1 -0
  7. package/dist/capabilities/templates.js +193 -0
  8. package/dist/capabilities/templates.json +145 -0
  9. package/dist/change-set-graph.d.ts +35 -3
  10. package/dist/change-set-graph.d.ts.map +1 -1
  11. package/dist/change-set-graph.js +60 -9
  12. package/dist/change-set.d.ts +65 -7
  13. package/dist/change-set.d.ts.map +1 -1
  14. package/dist/change-set.js +23 -12
  15. package/dist/ci-identity.d.ts +7 -2
  16. package/dist/ci-identity.d.ts.map +1 -1
  17. package/dist/ci-identity.js +4 -1
  18. package/dist/cli/commands/import-index.d.ts +52 -0
  19. package/dist/cli/commands/import-index.d.ts.map +1 -0
  20. package/dist/cli/commands/import-index.js +226 -0
  21. package/dist/cli/commands/lint.d.ts.map +1 -1
  22. package/dist/cli/commands/lint.js +4 -2
  23. package/dist/cli/handlers/components.d.ts.map +1 -1
  24. package/dist/cli/handlers/components.js +11 -2
  25. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  26. package/dist/cli/handlers/fan-out.js +16 -3
  27. package/dist/cli/handlers/graph.d.ts.map +1 -1
  28. package/dist/cli/handlers/graph.js +22 -4
  29. package/dist/cli/handlers/index-cloud.d.ts +14 -0
  30. package/dist/cli/handlers/index-cloud.d.ts.map +1 -0
  31. package/dist/cli/handlers/index-cloud.js +22 -0
  32. package/dist/cli/handlers/index-diff.d.ts +18 -0
  33. package/dist/cli/handlers/index-diff.d.ts.map +1 -0
  34. package/dist/cli/handlers/index-diff.js +142 -0
  35. package/dist/cli/handlers/lifecycle-drift.d.ts +25 -0
  36. package/dist/cli/handlers/lifecycle-drift.d.ts.map +1 -0
  37. package/dist/cli/handlers/lifecycle-drift.js +64 -0
  38. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  39. package/dist/cli/handlers/lifecycle.js +188 -28
  40. package/dist/cli/handlers/misc.d.ts +9 -0
  41. package/dist/cli/handlers/misc.d.ts.map +1 -1
  42. package/dist/cli/handlers/misc.js +77 -0
  43. package/dist/cli/handlers/pr.d.ts.map +1 -1
  44. package/dist/cli/handlers/pr.js +15 -2
  45. package/dist/cli/handlers/promote.d.ts.map +1 -1
  46. package/dist/cli/handlers/promote.js +89 -15
  47. package/dist/cli/handlers/query.d.ts.map +1 -1
  48. package/dist/cli/handlers/query.js +28 -4
  49. package/dist/cli/handlers/scenario.d.ts.map +1 -1
  50. package/dist/cli/handlers/scenario.js +8 -7
  51. package/dist/cli/handlers/search.d.ts +34 -4
  52. package/dist/cli/handlers/search.d.ts.map +1 -1
  53. package/dist/cli/handlers/search.js +216 -36
  54. package/dist/cli/main.d.ts.map +1 -1
  55. package/dist/cli/main.js +55 -1
  56. package/dist/cli/mcp/lifecycle-tools.d.ts.map +1 -1
  57. package/dist/cli/mcp/lifecycle-tools.js +3 -2
  58. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  59. package/dist/cli/mcp/resource-handlers.js +4 -3
  60. package/dist/cli/mcp/workspace-tools.js +1 -1
  61. package/dist/cli/parse-args.d.ts.map +1 -1
  62. package/dist/cli/parse-args.js +55 -2
  63. package/dist/cli/registry.d.ts +19 -1
  64. package/dist/cli/registry.d.ts.map +1 -1
  65. package/dist/cloud-lister/aws.d.ts +35 -0
  66. package/dist/cloud-lister/aws.d.ts.map +1 -0
  67. package/dist/cloud-lister/aws.js +203 -0
  68. package/dist/cloud-lister/azure.d.ts +34 -0
  69. package/dist/cloud-lister/azure.d.ts.map +1 -0
  70. package/dist/cloud-lister/azure.js +129 -0
  71. package/dist/cloud-lister/common.d.ts +40 -0
  72. package/dist/cloud-lister/common.d.ts.map +1 -0
  73. package/dist/cloud-lister/common.js +83 -0
  74. package/dist/cloud-lister/credentials.d.ts +50 -0
  75. package/dist/cloud-lister/credentials.d.ts.map +1 -0
  76. package/dist/cloud-lister/credentials.js +86 -0
  77. package/dist/cloud-lister/fakes.d.ts +27 -0
  78. package/dist/cloud-lister/fakes.d.ts.map +1 -0
  79. package/dist/cloud-lister/fakes.js +50 -0
  80. package/dist/cloud-lister/gcp.d.ts +42 -0
  81. package/dist/cloud-lister/gcp.d.ts.map +1 -0
  82. package/dist/cloud-lister/gcp.js +143 -0
  83. package/dist/cloud-lister/guard.d.ts +49 -0
  84. package/dist/cloud-lister/guard.d.ts.map +1 -0
  85. package/dist/cloud-lister/guard.js +103 -0
  86. package/dist/cloud-lister/ids.d.ts +23 -0
  87. package/dist/cloud-lister/ids.d.ts.map +1 -0
  88. package/dist/cloud-lister/ids.js +42 -0
  89. package/dist/cloud-lister/index.d.ts +67 -0
  90. package/dist/cloud-lister/index.d.ts.map +1 -0
  91. package/dist/cloud-lister/index.js +102 -0
  92. package/dist/cloud-lister/kubernetes.d.ts +64 -0
  93. package/dist/cloud-lister/kubernetes.d.ts.map +1 -0
  94. package/dist/cloud-lister/kubernetes.js +276 -0
  95. package/dist/cloud-lister/markers.d.ts +31 -0
  96. package/dist/cloud-lister/markers.d.ts.map +1 -0
  97. package/dist/cloud-lister/markers.js +73 -0
  98. package/dist/cloud-lister/mask.d.ts +31 -0
  99. package/dist/cloud-lister/mask.d.ts.map +1 -0
  100. package/dist/cloud-lister/mask.js +74 -0
  101. package/dist/cloud-lister/sigv4.d.ts +29 -0
  102. package/dist/cloud-lister/sigv4.d.ts.map +1 -0
  103. package/dist/cloud-lister/sigv4.js +54 -0
  104. package/dist/cloud-lister/transport.d.ts +55 -0
  105. package/dist/cloud-lister/transport.d.ts.map +1 -0
  106. package/dist/cloud-lister/transport.js +86 -0
  107. package/dist/cloud-lister/types.d.ts +121 -0
  108. package/dist/cloud-lister/types.d.ts.map +1 -0
  109. package/dist/cloud-lister/types.js +24 -0
  110. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  111. package/dist/components/capability-plugin-loader.js +6 -0
  112. package/dist/components/capability-plugin.d.ts +9 -0
  113. package/dist/components/capability-plugin.d.ts.map +1 -1
  114. package/dist/components/capability.d.ts +215 -0
  115. package/dist/components/capability.d.ts.map +1 -1
  116. package/dist/components/cli-support.d.ts +21 -0
  117. package/dist/components/cli-support.d.ts.map +1 -1
  118. package/dist/components/cli-support.js +58 -14
  119. package/dist/components/declared-reads.d.ts +38 -0
  120. package/dist/components/declared-reads.d.ts.map +1 -0
  121. package/dist/components/declared-reads.js +131 -0
  122. package/dist/components/deploy-units.d.ts.map +1 -1
  123. package/dist/components/deploy-units.js +4 -0
  124. package/dist/components/driver.d.ts +34 -1
  125. package/dist/components/driver.d.ts.map +1 -1
  126. package/dist/components/driver.js +66 -3
  127. package/dist/components/fan-out-run.d.ts +23 -1
  128. package/dist/components/fan-out-run.d.ts.map +1 -1
  129. package/dist/components/fan-out-run.js +82 -14
  130. package/dist/components/fan-out-support.d.ts +6 -0
  131. package/dist/components/fan-out-support.d.ts.map +1 -1
  132. package/dist/components/fan-out-support.js +4 -1
  133. package/dist/components/fan-out.d.ts +28 -0
  134. package/dist/components/fan-out.d.ts.map +1 -1
  135. package/dist/components/groups.d.ts +229 -0
  136. package/dist/components/groups.d.ts.map +1 -0
  137. package/dist/components/groups.js +760 -0
  138. package/dist/components/index.d.ts +6 -2
  139. package/dist/components/index.d.ts.map +1 -1
  140. package/dist/components/index.js +4 -0
  141. package/dist/components/plan-shape-conformance.d.ts +48 -0
  142. package/dist/components/plan-shape-conformance.d.ts.map +1 -0
  143. package/dist/components/plan-shape-conformance.js +122 -0
  144. package/dist/components/pr-run.d.ts +41 -4
  145. package/dist/components/pr-run.d.ts.map +1 -1
  146. package/dist/components/pr-run.js +209 -39
  147. package/dist/components/promote-rounds.d.ts +9 -0
  148. package/dist/components/promote-rounds.d.ts.map +1 -1
  149. package/dist/components/promote-rounds.js +23 -2
  150. package/dist/components/promote.d.ts +17 -0
  151. package/dist/components/promote.d.ts.map +1 -1
  152. package/dist/components/promote.js +36 -6
  153. package/dist/components/release-gate.d.ts +23 -1
  154. package/dist/components/release-gate.d.ts.map +1 -1
  155. package/dist/components/release-gate.js +97 -33
  156. package/dist/components/run-groups.d.ts +58 -0
  157. package/dist/components/run-groups.d.ts.map +1 -0
  158. package/dist/components/run-groups.js +78 -0
  159. package/dist/components/starter-plugin.d.ts +1 -0
  160. package/dist/components/starter-plugin.d.ts.map +1 -1
  161. package/dist/components/starter-plugin.js +6 -1
  162. package/dist/components/verbs/index.d.ts +1 -0
  163. package/dist/components/verbs/index.d.ts.map +1 -1
  164. package/dist/components/verbs/index.js +1 -0
  165. package/dist/components/verbs/member-outputs.d.ts +187 -0
  166. package/dist/components/verbs/member-outputs.d.ts.map +1 -0
  167. package/dist/components/verbs/member-outputs.js +218 -0
  168. package/dist/config.d.ts +60 -0
  169. package/dist/config.d.ts.map +1 -1
  170. package/dist/config.js +27 -0
  171. package/dist/deep-observation.d.ts +1 -13
  172. package/dist/deep-observation.d.ts.map +1 -1
  173. package/dist/deep-observation.js +5 -22
  174. package/dist/drift-record.d.ts +542 -0
  175. package/dist/drift-record.d.ts.map +1 -0
  176. package/dist/drift-record.js +886 -0
  177. package/dist/engine-facts.d.ts +144 -0
  178. package/dist/engine-facts.d.ts.map +1 -0
  179. package/dist/engine-facts.js +14 -0
  180. package/dist/graph-ir.d.ts +153 -2
  181. package/dist/graph-ir.d.ts.map +1 -1
  182. package/dist/graph-ir.js +224 -6
  183. package/dist/graph-refs.d.ts +145 -0
  184. package/dist/graph-refs.d.ts.map +1 -1
  185. package/dist/graph-refs.js +305 -0
  186. package/dist/graph-schema/fixtures/adopt.json +15 -0
  187. package/dist/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
  188. package/dist/graph-schema/fixtures/index.json +68 -0
  189. package/dist/graph-schema/fixtures/plunge.engine-graph.json +158 -0
  190. package/dist/graph-schema/fixtures.d.ts +23 -0
  191. package/dist/graph-schema/fixtures.d.ts.map +1 -0
  192. package/dist/graph-schema/fixtures.js +246 -0
  193. package/dist/graph-schema/generate.d.ts +15 -0
  194. package/dist/graph-schema/generate.d.ts.map +1 -0
  195. package/dist/graph-schema/generate.js +267 -0
  196. package/dist/graph-schema/graph.schema.json +1387 -0
  197. package/dist/health.schema.json +2 -1
  198. package/dist/identity.d.ts.map +1 -1
  199. package/dist/identity.js +2 -0
  200. package/dist/index.d.ts +1 -0
  201. package/dist/index.d.ts.map +1 -1
  202. package/dist/index.js +2 -0
  203. package/dist/instance-nodes.d.ts +159 -0
  204. package/dist/instance-nodes.d.ts.map +1 -0
  205. package/dist/instance-nodes.js +231 -0
  206. package/dist/lexicon.d.ts +72 -0
  207. package/dist/lexicon.d.ts.map +1 -1
  208. package/dist/lifecycle/adoption-file.d.ts +56 -0
  209. package/dist/lifecycle/adoption-file.d.ts.map +1 -0
  210. package/dist/lifecycle/adoption-file.js +123 -0
  211. package/dist/lifecycle/cloud-index.d.ts +186 -0
  212. package/dist/lifecycle/cloud-index.d.ts.map +1 -0
  213. package/dist/lifecycle/cloud-index.js +618 -0
  214. package/dist/lifecycle/derive-edges.d.ts +59 -0
  215. package/dist/lifecycle/derive-edges.d.ts.map +1 -0
  216. package/dist/lifecycle/derive-edges.js +126 -0
  217. package/dist/lifecycle/git.d.ts +10 -9
  218. package/dist/lifecycle/git.d.ts.map +1 -1
  219. package/dist/lifecycle/git.js +7 -1
  220. package/dist/lifecycle/identity-match.d.ts +133 -0
  221. package/dist/lifecycle/identity-match.d.ts.map +1 -0
  222. package/dist/lifecycle/identity-match.js +147 -0
  223. package/dist/lifecycle/index-diff.d.ts +224 -0
  224. package/dist/lifecycle/index-diff.d.ts.map +1 -0
  225. package/dist/lifecycle/index-diff.js +327 -0
  226. package/dist/lifecycle/index-document.d.ts +130 -0
  227. package/dist/lifecycle/index-document.d.ts.map +1 -0
  228. package/dist/lifecycle/index-document.js +189 -0
  229. package/dist/lifecycle/index-drift.d.ts +121 -0
  230. package/dist/lifecycle/index-drift.d.ts.map +1 -0
  231. package/dist/lifecycle/index-drift.js +178 -0
  232. package/dist/lifecycle/index-import.d.ts +168 -0
  233. package/dist/lifecycle/index-import.d.ts.map +1 -0
  234. package/dist/lifecycle/index-import.js +515 -0
  235. package/dist/lifecycle/index-join.d.ts +129 -0
  236. package/dist/lifecycle/index-join.d.ts.map +1 -0
  237. package/dist/lifecycle/index-join.js +248 -0
  238. package/dist/lifecycle/index.d.ts +4 -0
  239. package/dist/lifecycle/index.d.ts.map +1 -1
  240. package/dist/lifecycle/index.js +4 -0
  241. package/dist/lifecycle/observation-baseline.d.ts +61 -21
  242. package/dist/lifecycle/observation-baseline.d.ts.map +1 -1
  243. package/dist/lifecycle/observation-baseline.js +144 -19
  244. package/dist/lifecycle/observe.d.ts.map +1 -1
  245. package/dist/lifecycle/observe.js +6 -1
  246. package/dist/lifecycle/query.d.ts +45 -4
  247. package/dist/lifecycle/query.d.ts.map +1 -1
  248. package/dist/lifecycle/query.js +89 -7
  249. package/dist/lifecycle/replay.d.ts +10 -3
  250. package/dist/lifecycle/replay.d.ts.map +1 -1
  251. package/dist/lifecycle/replay.js +10 -6
  252. package/dist/lifecycle/scenario.d.ts +4 -3
  253. package/dist/lifecycle/scenario.d.ts.map +1 -1
  254. package/dist/lifecycle/snapshot-store-fake.d.ts +9 -0
  255. package/dist/lifecycle/snapshot-store-fake.d.ts.map +1 -0
  256. package/dist/lifecycle/snapshot-store-fake.js +21 -0
  257. package/dist/lifecycle/snapshot-store-s3.d.ts +102 -0
  258. package/dist/lifecycle/snapshot-store-s3.d.ts.map +1 -0
  259. package/dist/lifecycle/snapshot-store-s3.js +254 -0
  260. package/dist/lifecycle/snapshot-store.d.ts +170 -0
  261. package/dist/lifecycle/snapshot-store.d.ts.map +1 -0
  262. package/dist/lifecycle/snapshot-store.js +832 -0
  263. package/dist/lifecycle/snapshot.d.ts +11 -0
  264. package/dist/lifecycle/snapshot.d.ts.map +1 -1
  265. package/dist/lifecycle/snapshot.js +18 -5
  266. package/dist/lifecycle/type-listing.d.ts +148 -0
  267. package/dist/lifecycle/type-listing.d.ts.map +1 -0
  268. package/dist/lifecycle/type-listing.js +166 -0
  269. package/dist/lint/component-checks.d.ts +15 -1
  270. package/dist/lint/component-checks.d.ts.map +1 -1
  271. package/dist/lint/component-checks.js +1 -0
  272. package/dist/lint/presets/relaxed.json +2 -1
  273. package/dist/lint/presets/strict.json +2 -1
  274. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts +4 -0
  275. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts.map +1 -0
  276. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.js +13 -0
  277. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts +4 -0
  278. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts.map +1 -0
  279. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.js +8 -0
  280. package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts +33 -0
  281. package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts.map +1 -0
  282. package/dist/lint/rules/comp/comp008-applies-signal-only-root.js +123 -0
  283. package/dist/lint/rules/comp/index.d.ts +2 -1
  284. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  285. package/dist/lint/rules/comp/index.js +4 -1
  286. package/dist/observation.d.ts +19 -2
  287. package/dist/observation.d.ts.map +1 -1
  288. package/dist/observation.js +18 -1
  289. package/dist/op/activities/activity-contracts.d.ts +1 -1
  290. package/dist/op/activities/activity-contracts.js +1 -1
  291. package/dist/op/activities/change-set.d.ts +6 -4
  292. package/dist/op/activities/change-set.d.ts.map +1 -1
  293. package/dist/op/activities/change-set.js +4 -2
  294. package/dist/op/activity-failure.d.ts +27 -0
  295. package/dist/op/activity-failure.d.ts.map +1 -1
  296. package/dist/op/activity-failure.js +31 -0
  297. package/dist/op/index.d.ts +2 -1
  298. package/dist/op/index.d.ts.map +1 -1
  299. package/dist/op/index.js +1 -1
  300. package/dist/op/local-executor.d.ts +5 -1
  301. package/dist/op/local-executor.d.ts.map +1 -1
  302. package/dist/op/local-executor.js +22 -8
  303. package/dist/pr-loop.d.ts +56 -1
  304. package/dist/pr-loop.d.ts.map +1 -1
  305. package/dist/pr-loop.js +51 -1
  306. package/dist/pulumi-urn.d.ts +101 -0
  307. package/dist/pulumi-urn.d.ts.map +1 -0
  308. package/dist/pulumi-urn.js +131 -0
  309. package/dist/release-floors.d.ts +23 -0
  310. package/dist/release-floors.d.ts.map +1 -0
  311. package/dist/release-floors.js +22 -0
  312. package/dist/sensitive-key.d.ts +23 -0
  313. package/dist/sensitive-key.d.ts.map +1 -0
  314. package/dist/sensitive-key.js +31 -0
  315. package/dist/wave-runtime.mjs +234 -234
  316. package/dist/workspace/adoption-report.d.ts +53 -0
  317. package/dist/workspace/adoption-report.d.ts.map +1 -0
  318. package/dist/workspace/adoption-report.js +76 -0
  319. package/dist/workspace/capabilities-contract.d.ts +7 -0
  320. package/dist/workspace/capabilities-contract.d.ts.map +1 -1
  321. package/dist/workspace/capabilities-contract.js +2 -1
  322. package/dist/workspace/capabilities.schema.json +98 -0
  323. package/dist/workspace/change-set.schema.json +42 -3
  324. package/dist/workspace/ci-cloud-identity.d.ts +13 -1
  325. package/dist/workspace/ci-cloud-identity.d.ts.map +1 -1
  326. package/dist/workspace/ci-cloud-identity.js +30 -1
  327. package/dist/workspace/compose-graph.d.ts +10 -1
  328. package/dist/workspace/compose-graph.d.ts.map +1 -1
  329. package/dist/workspace/compose-graph.js +6 -1
  330. package/dist/workspace/conformance/index.d.ts +1 -1
  331. package/dist/workspace/conformance/index.d.ts.map +1 -1
  332. package/dist/workspace/conformance/index.js +6 -1
  333. package/dist/workspace/drift-cli.d.ts +81 -0
  334. package/dist/workspace/drift-cli.d.ts.map +1 -0
  335. package/dist/workspace/drift-cli.js +317 -0
  336. package/dist/workspace/drift.schema.json +672 -0
  337. package/dist/workspace/graph-cli.d.ts +2 -0
  338. package/dist/workspace/graph-cli.d.ts.map +1 -1
  339. package/dist/workspace/graph-cli.js +3 -0
  340. package/dist/workspace/graph.schema.json +72 -0
  341. package/dist/workspace/init.d.ts +5 -1
  342. package/dist/workspace/init.d.ts.map +1 -1
  343. package/dist/workspace/init.js +55 -9
  344. package/dist/workspace/ledger.schema.json +1 -1
  345. package/dist/workspace/nested-graph.d.ts.map +1 -1
  346. package/dist/workspace/nested-graph.js +2 -0
  347. package/dist/workspace/pr-report.schema.json +51 -2
  348. package/dist/workspace/promote-waves.d.ts +112 -0
  349. package/dist/workspace/promote-waves.d.ts.map +1 -0
  350. package/dist/workspace/promote-waves.js +290 -0
  351. package/dist/workspace/promote.d.ts +84 -2
  352. package/dist/workspace/promote.d.ts.map +1 -1
  353. package/dist/workspace/promote.js +347 -61
  354. package/dist/workspace/reason-codes.d.ts +12 -0
  355. package/dist/workspace/reason-codes.d.ts.map +1 -1
  356. package/dist/workspace/reason-codes.js +14 -0
  357. package/dist/workspace/search-contract.d.ts +3 -3
  358. package/dist/workspace/search-contract.d.ts.map +1 -1
  359. package/dist/workspace/search-contract.js +2 -0
  360. package/dist/workspace/search.schema.json +103 -5
  361. package/package.json +14 -1
  362. package/src/__fixtures__/drift-record/README.md +58 -0
  363. package/src/__fixtures__/drift-record/choudoufu-cone.ndjson +4 -0
  364. package/src/__fixtures__/drift-record/choudoufu-resource.ndjson +3 -0
  365. package/src/__fixtures__/drift-record/component-status-ledger.json +65 -0
  366. package/src/__fixtures__/drift-record/component-status.json +91 -0
  367. package/src/__fixtures__/drift-record/deep-diff.json +259 -0
  368. package/src/__fixtures__/drift-record/lifecycle-diff-live.json +825 -0
  369. package/src/__fixtures__/drift-record/live-diff.json +125 -0
  370. package/src/audit/discover.e2e.test.ts +14 -0
  371. package/src/audit/discover.ts +3 -1
  372. package/src/behaviour.ts +1 -1
  373. package/src/capabilities/templates.json +145 -0
  374. package/src/capabilities/templates.test.ts +212 -0
  375. package/src/capabilities/templates.ts +204 -0
  376. package/src/change-set-bundle.test.ts +83 -0
  377. package/src/change-set-graph.ts +80 -9
  378. package/src/change-set.test.ts +24 -0
  379. package/src/change-set.ts +77 -14
  380. package/src/ci-identity-targets.test.ts +23 -0
  381. package/src/ci-identity.ts +10 -4
  382. package/src/cli/commands/import-index.test.ts +117 -0
  383. package/src/cli/commands/import-index.ts +265 -0
  384. package/src/cli/commands/lint.ts +4 -2
  385. package/src/cli/handlers/components.test.ts +9 -0
  386. package/src/cli/handlers/components.ts +12 -2
  387. package/src/cli/handlers/fan-out.ts +17 -3
  388. package/src/cli/handlers/graph.test.ts +42 -0
  389. package/src/cli/handlers/graph.ts +26 -4
  390. package/src/cli/handlers/index-cloud.ts +32 -0
  391. package/src/cli/handlers/index-diff.test.ts +68 -0
  392. package/src/cli/handlers/index-diff.ts +146 -0
  393. package/src/cli/handlers/ledger-root-member.test.ts +161 -0
  394. package/src/cli/handlers/lifecycle-drift.ts +68 -0
  395. package/src/cli/handlers/lifecycle.test.ts +33 -11
  396. package/src/cli/handlers/lifecycle.ts +205 -30
  397. package/src/cli/handlers/misc.ts +73 -0
  398. package/src/cli/handlers/pr-waves-blocked.test.ts +37 -2
  399. package/src/cli/handlers/pr.ts +14 -2
  400. package/src/cli/handlers/promote.test.ts +64 -0
  401. package/src/cli/handlers/promote.ts +81 -6
  402. package/src/cli/handlers/query.ts +27 -4
  403. package/src/cli/handlers/run-declared-reads-cli.test.ts +187 -0
  404. package/src/cli/handlers/run-groups-cli.test.ts +229 -0
  405. package/src/cli/handlers/scenario.test.ts +13 -0
  406. package/src/cli/handlers/scenario.ts +8 -7
  407. package/src/cli/handlers/search-index.test.ts +255 -0
  408. package/src/cli/handlers/search-json.test.ts +1 -1
  409. package/src/cli/handlers/search-ownership.test.ts +194 -0
  410. package/src/cli/handlers/search.ts +271 -38
  411. package/src/cli/main.test.ts +7 -0
  412. package/src/cli/main.ts +56 -1
  413. package/src/cli/mcp/lifecycle-tools.ts +3 -2
  414. package/src/cli/mcp/resource-handlers.ts +4 -3
  415. package/src/cli/mcp/workspace-tools.ts +1 -1
  416. package/src/cli/parse-args.ts +40 -2
  417. package/src/cli/registry.ts +19 -1
  418. package/src/cloud-lister/aws.test.ts +202 -0
  419. package/src/cloud-lister/aws.ts +226 -0
  420. package/src/cloud-lister/azure.test.ts +132 -0
  421. package/src/cloud-lister/azure.ts +142 -0
  422. package/src/cloud-lister/common.ts +115 -0
  423. package/src/cloud-lister/credentials.ts +110 -0
  424. package/src/cloud-lister/fakes.ts +66 -0
  425. package/src/cloud-lister/gcp.test.ts +121 -0
  426. package/src/cloud-lister/gcp.ts +159 -0
  427. package/src/cloud-lister/guard.test.ts +198 -0
  428. package/src/cloud-lister/guard.ts +111 -0
  429. package/src/cloud-lister/ids.ts +54 -0
  430. package/src/cloud-lister/index.ts +134 -0
  431. package/src/cloud-lister/kubernetes.test.ts +160 -0
  432. package/src/cloud-lister/kubernetes.ts +284 -0
  433. package/src/cloud-lister/markers.ts +74 -0
  434. package/src/cloud-lister/mask.ts +77 -0
  435. package/src/cloud-lister/shape.test.ts +81 -0
  436. package/src/cloud-lister/sigv4.ts +70 -0
  437. package/src/cloud-lister/transport.ts +118 -0
  438. package/src/cloud-lister/types.ts +135 -0
  439. package/src/components/capability-plugin-loader.ts +4 -0
  440. package/src/components/capability-plugin.ts +10 -0
  441. package/src/components/capability.ts +229 -0
  442. package/src/components/cli-support.ts +70 -14
  443. package/src/components/declared-reads.test.ts +103 -0
  444. package/src/components/declared-reads.ts +134 -0
  445. package/src/components/deploy-units.ts +4 -0
  446. package/src/components/driver.ts +89 -4
  447. package/src/components/fan-out-run.ts +95 -15
  448. package/src/components/fan-out-support.ts +10 -1
  449. package/src/components/fan-out.ts +30 -0
  450. package/src/components/groups.test.ts +320 -0
  451. package/src/components/groups.ts +880 -0
  452. package/src/components/index.ts +42 -0
  453. package/src/components/plan-shape-conformance.ts +130 -0
  454. package/src/components/pr-env-run-bundle.test.ts +2 -0
  455. package/src/components/pr-run.test.ts +516 -3
  456. package/src/components/pr-run.ts +231 -41
  457. package/src/components/promote-rounds.ts +25 -2
  458. package/src/components/promote.ts +55 -5
  459. package/src/components/registry.test.ts +1 -1
  460. package/src/components/release-gate.ts +115 -30
  461. package/src/components/release-groups.test.ts +362 -0
  462. package/src/components/run-groups.ts +113 -0
  463. package/src/components/starter-plugin.ts +6 -0
  464. package/src/components/verbs/index.ts +1 -0
  465. package/src/components/verbs/member-outputs.test.ts +205 -0
  466. package/src/components/verbs/member-outputs.ts +308 -0
  467. package/src/config.ts +44 -0
  468. package/src/deep-observation.ts +5 -23
  469. package/src/drift-record.test.ts +596 -0
  470. package/src/drift-record.ts +1206 -0
  471. package/src/engine-facts.guard.test.ts +111 -0
  472. package/src/engine-facts.test.ts +178 -0
  473. package/src/engine-facts.ts +154 -0
  474. package/src/gated-waves-bundle.test.ts +2 -0
  475. package/src/graph-ir-live.test.ts +92 -0
  476. package/src/graph-ir.ts +317 -7
  477. package/src/graph-refs.ts +416 -0
  478. package/src/graph-schema/fixtures/adopt.json +15 -0
  479. package/src/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
  480. package/src/graph-schema/fixtures/index.json +68 -0
  481. package/src/graph-schema/fixtures/plunge.engine-graph.json +158 -0
  482. package/src/graph-schema/fixtures.ts +267 -0
  483. package/src/graph-schema/generate.ts +263 -0
  484. package/src/graph-schema/graph-schema.test.ts +153 -0
  485. package/src/graph-schema/graph.schema.json +1387 -0
  486. package/src/health.schema.json +2 -1
  487. package/src/identity.ts +2 -0
  488. package/src/index.ts +2 -0
  489. package/src/instance-nodes.ts +288 -0
  490. package/src/lexicon.ts +76 -0
  491. package/src/lifecycle/__fixtures__/index-diff/20261026T120000Z-aaaaaaaaaaaa.json +149 -0
  492. package/src/lifecycle/__fixtures__/index-diff/20261026T130000Z-bbbbbbbbbbbb.json +127 -0
  493. package/src/lifecycle/adoption-file.test.ts +100 -0
  494. package/src/lifecycle/adoption-file.ts +154 -0
  495. package/src/lifecycle/cloud-index.test.ts +517 -0
  496. package/src/lifecycle/cloud-index.ts +736 -0
  497. package/src/lifecycle/derive-edges.test.ts +193 -0
  498. package/src/lifecycle/derive-edges.ts +182 -0
  499. package/src/lifecycle/git.ts +10 -4
  500. package/src/lifecycle/identity-match.test.ts +308 -0
  501. package/src/lifecycle/identity-match.ts +257 -0
  502. package/src/lifecycle/index-diff.test.ts +198 -0
  503. package/src/lifecycle/index-diff.ts +476 -0
  504. package/src/lifecycle/index-document.test.ts +64 -0
  505. package/src/lifecycle/index-document.ts +299 -0
  506. package/src/lifecycle/index-drift.test.ts +191 -0
  507. package/src/lifecycle/index-drift.ts +304 -0
  508. package/src/lifecycle/index-import.test.ts +255 -0
  509. package/src/lifecycle/index-import.ts +634 -0
  510. package/src/lifecycle/index-join.test.ts +250 -0
  511. package/src/lifecycle/index-join.ts +304 -0
  512. package/src/lifecycle/index-store-load-bearing.test.ts +187 -0
  513. package/src/lifecycle/index.ts +4 -0
  514. package/src/lifecycle/member-ledger.test.ts +25 -7
  515. package/src/lifecycle/observation-baseline.test.ts +72 -1
  516. package/src/lifecycle/observation-baseline.ts +190 -27
  517. package/src/lifecycle/observe.ts +6 -1
  518. package/src/lifecycle/query.test.ts +69 -1
  519. package/src/lifecycle/query.ts +103 -10
  520. package/src/lifecycle/replay.test.ts +9 -5
  521. package/src/lifecycle/replay.ts +9 -5
  522. package/src/lifecycle/scenario.ts +4 -3
  523. package/src/lifecycle/snapshot-store-fake.ts +29 -0
  524. package/src/lifecycle/snapshot-store-s3.ts +316 -0
  525. package/src/lifecycle/snapshot-store.test.ts +385 -0
  526. package/src/lifecycle/snapshot-store.ts +981 -0
  527. package/src/lifecycle/snapshot.test.ts +13 -0
  528. package/src/lifecycle/snapshot.ts +23 -6
  529. package/src/lifecycle/type-listing.test.ts +166 -0
  530. package/src/lifecycle/type-listing.ts +309 -0
  531. package/src/lint/component-checks.ts +17 -1
  532. package/src/lint/config.test.ts +3 -0
  533. package/src/lint/presets/relaxed.json +2 -1
  534. package/src/lint/presets/strict.json +2 -1
  535. package/src/lint/rules/__fixtures__/comp/comp008/fail/dns.component.ts +15 -0
  536. package/src/lint/rules/__fixtures__/comp/comp008/pass/dns.component.ts +10 -0
  537. package/src/lint/rules/comp/comp.test.ts +2 -1
  538. package/src/lint/rules/comp/comp008-applies-signal-only-root.ts +121 -0
  539. package/src/lint/rules/comp/comp008.test.ts +77 -0
  540. package/src/lint/rules/comp/index.ts +4 -1
  541. package/src/observation-edges.test.ts +33 -0
  542. package/src/observation.ts +36 -1
  543. package/src/op/activities/activity-contracts.ts +1 -1
  544. package/src/op/activities/change-set.ts +8 -5
  545. package/src/op/activity-failure.ts +36 -0
  546. package/src/op/index.ts +2 -1
  547. package/src/op/local-executor.test.ts +80 -0
  548. package/src/op/local-executor.ts +27 -9
  549. package/src/pr-loop-bundle.test.ts +5 -2
  550. package/src/pr-loop.test.ts +43 -0
  551. package/src/pr-loop.ts +111 -2
  552. package/src/pulumi-urn.ts +151 -0
  553. package/src/release-floors.ts +22 -0
  554. package/src/sensitive-key.ts +34 -0
  555. package/src/workspace/adoption-report.test.ts +61 -0
  556. package/src/workspace/adoption-report.ts +103 -0
  557. package/src/workspace/capabilities-contract.test.ts +4 -0
  558. package/src/workspace/capabilities-contract.ts +9 -1
  559. package/src/workspace/capabilities.schema.json +98 -0
  560. package/src/workspace/change-set.schema.json +42 -3
  561. package/src/workspace/ci-cloud-identity.ts +31 -1
  562. package/src/workspace/compose-graph.test.ts +12 -0
  563. package/src/workspace/compose-graph.ts +12 -1
  564. package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
  565. package/src/workspace/conformance/index.ts +6 -1
  566. package/src/workspace/drift-cli.test.ts +65 -0
  567. package/src/workspace/drift-cli.ts +365 -0
  568. package/src/workspace/drift.schema.json +672 -0
  569. package/src/workspace/graph-cli.ts +5 -0
  570. package/src/workspace/graph.schema.json +72 -0
  571. package/src/workspace/init.test.ts +38 -1
  572. package/src/workspace/init.ts +50 -8
  573. package/src/workspace/intent-gaps.test.ts +18 -2
  574. package/src/workspace/ledger.schema.json +1 -1
  575. package/src/workspace/nested-graph.ts +1 -0
  576. package/src/workspace/pr-report.schema.json +51 -2
  577. package/src/workspace/promote-waves.test.ts +296 -0
  578. package/src/workspace/promote-waves.ts +340 -0
  579. package/src/workspace/promote.test.ts +158 -4
  580. package/src/workspace/promote.ts +398 -57
  581. package/src/workspace/reason-codes.test.ts +4 -1
  582. package/src/workspace/reason-codes.ts +14 -0
  583. package/src/workspace/search-contract.ts +2 -0
  584. package/src/workspace/search.schema.json +103 -5
package/src/graph-ir.ts CHANGED
@@ -7,7 +7,9 @@ import { getProvenance } from "./provenance";
7
7
  import { INTRINSIC_MARKER } from "./intrinsic";
8
8
  import { subTemplateRefs } from "./graph-sub-template";
9
9
  import type { ResourceMetadata } from "./lexicon";
10
- import type { UnobservedEntity } from "./observation";
10
+ import { entityInstanceRollup, observedInstanceNodeId, type InstanceRollup } from "./instance-nodes";
11
+ import type { RootRead, UnobservedEntity } from "./observation";
12
+ import type { EdgeGrain, EngineFacts } from "./engine-facts";
11
13
 
12
14
  export { subTemplateRefs };
13
15
 
@@ -95,6 +97,68 @@ export interface IRNode {
95
97
  * unaffected.
96
98
  */
97
99
  runtimeOwner?: string;
100
+ /**
101
+ * On an instance node of a `count` or `for_each` block (#4454): the block
102
+ * node's id. The node's own id is that id followed by {@link instanceKey},
103
+ * `aws_eip.pool[0]` under `aws_eip.pool`, and the block node stays in the
104
+ * graph as the rollup. Absent on every other node. See `./instance-nodes.ts`.
105
+ */
106
+ instanceOf?: string;
107
+ /**
108
+ * With {@link instanceOf}: the block's own instance key as the engine
109
+ * prints it, `[0]` or `["a"]`. Absent on an instance that only an
110
+ * expanded enclosing scope makes (#4486), a block without `count` under
111
+ * `module "app" { count = 2 }`.
112
+ */
113
+ instanceKey?: string;
114
+ /**
115
+ * With {@link instanceOf}, under an expanded enclosing scope (#4486): that
116
+ * scope's path as the engine prints it, `module.app[0]`. The node id then
117
+ * carries the key on the scope's segment, `estate/module.app[0]/aws_eip.pool[1]`.
118
+ */
119
+ instanceScope?: string;
120
+ /**
121
+ * On a block node whose `count` or `for_each` the declared graph cannot
122
+ * count (#4489): why it stays one node, and the expression. Absent on a
123
+ * block that is not expanded and on one whose instances are listed. See
124
+ * `./instance-nodes.ts`.
125
+ */
126
+ instanceRollup?: InstanceRollup;
127
+ /**
128
+ * What an ownership engine (choudoufu, plunge) observed about this node
129
+ * (#4520, #4527). On a live node it is copied from `ResourceMetadata.facts`.
130
+ * On a declared node it comes from the entity's {@link entityFacts}: the
131
+ * pulumi lexicon reads a plunge member's checked-in `engine-graph.json`
132
+ * beside its stack export (#4529). For people and for readers that show
133
+ * the graph. Nothing in chant decides from it, and {@link ownership} keeps
134
+ * its own meaning. Absent unless an engine supplied it. See `./engine-facts.ts`.
135
+ */
136
+ facts?: EngineFacts;
137
+ /**
138
+ * Indexed nodes only (#4521, behold#1025): the inventory API's own type
139
+ * name, as the cloud lister read it: `AWS::S3::Bucket`,
140
+ * `microsoft.storage/storageaccounts`, `storage.googleapis.com/Bucket`,
141
+ * `apps/v1/Deployment`. Absent on every node a cloud listing did not make.
142
+ */
143
+ listedType?: string;
144
+ /**
145
+ * Indexed nodes only: the region or location the object was listed in,
146
+ * `global` for a global type, a namespace or `cluster` for Kubernetes.
147
+ */
148
+ location?: string;
149
+ /**
150
+ * Indexed nodes only: the identifier the listing returned, Cloud Control's
151
+ * `Identifier`, the ARM id, the asset `name`, or `namespace/name`.
152
+ */
153
+ nativeId?: string;
154
+ /** Indexed nodes only: tags or labels as read, masked by key. Where markers come from. */
155
+ tags?: Record<string, string>;
156
+ /**
157
+ * Indexed nodes only: true when no lexicon kind maps the listed type. The
158
+ * node keeps `kind` = {@link listedType} and `lexicon` = the substrate, and
159
+ * is never dropped (#4521).
160
+ */
161
+ unmappedKind?: boolean;
98
162
  }
99
163
 
100
164
  /**
@@ -134,6 +198,34 @@ export interface IREdge {
134
198
  * this to route the edge between groups. Absent on every in-pipeline edge.
135
199
  */
136
200
  crossPipeline?: boolean;
201
+ /**
202
+ * What the edge joins (#4520): two blocks, two instances, or a property of
203
+ * one instance to another. Set by an engine's graph (choudoufu: `block`;
204
+ * plunge: `instance` for dependencies, parents and providers, `property`
205
+ * for property dependencies). Absent when the source does not say. Two
206
+ * edges between the same pair that differ only in grain are two edges.
207
+ */
208
+ grain?: EdgeGrain;
209
+ /**
210
+ * Where the edge came from (behold#1025): `declared` (an AttrRef or an
211
+ * EntityReference), `observed` (the engine or the cloud reported it), or
212
+ * `derived` (a reference catalog rule matched an attribute value to another
213
+ * node, #4522). Absent reads as `declared` on a source IR and `observed` on
214
+ * a live one, which is what both meant before the field.
215
+ */
216
+ origin?: "declared" | "observed" | "derived";
217
+ /**
218
+ * With `origin: "derived"`: the rule that produced the edge,
219
+ * `<lexicon>:<from kind>:<path>` for a catalog rule and
220
+ * `<lexicon>:<from kind>:tag:<key>` for a typed tag rule.
221
+ */
222
+ rule?: string;
223
+ /**
224
+ * `reference` (the default when absent) or `containment`: the holder sits
225
+ * inside the target (a subnet in its VPC). A containment edge is also in
226
+ * `groups.byContainer`, so a renderer that draws boxes can skip the line.
227
+ */
228
+ relation?: "reference" | "containment";
137
229
  }
138
230
 
139
231
  /**
@@ -286,6 +378,8 @@ export interface EntityReference {
286
378
  viaAttr?: string;
287
379
  /** The producer-side attribute referenced (`IREdge.toAttr`), when the reference named exactly one. */
288
380
  toAttr?: string;
381
+ /** What the reference joins (`IREdge.grain`, #4529), when its source says. */
382
+ grain?: EdgeGrain;
289
383
  }
290
384
 
291
385
  /** True when `value` has the {@link EntityReference} shape. */
@@ -329,6 +423,59 @@ export function entityStack(entity: Declarable): string | undefined {
329
423
  return typeof stack === "string" && stack.length > 0 ? stack : undefined;
330
424
  }
331
425
 
426
+ /**
427
+ * What an ownership engine observed about an entity (#4529), or undefined.
428
+ * Duck-typed like {@link entityStack}: the pulumi lexicon sets `facts` on a
429
+ * plunge member's entity from the member's checked-in engine graph. It is
430
+ * defined non-enumerable there, so a chant older than this reader does not
431
+ * project it into `attrs`. {@link buildGraphIr} copies it onto the node, and
432
+ * nothing in chant decides from it (see `IRNode.facts`).
433
+ */
434
+ export function entityFacts(entity: Declarable): EngineFacts | undefined {
435
+ const facts = (entity as unknown as { facts?: unknown }).facts;
436
+ return typeof facts === "object" && facts !== null && !Array.isArray(facts) ? (facts as EngineFacts) : undefined;
437
+ }
438
+
439
+ /**
440
+ * The instance keys an entity says its source expands to (#4454), as the
441
+ * engine prints them (`[0]`, `["a"]`), or an empty list. Duck-typed like
442
+ * {@link entityStack}: the terraform lexicon sets `instanceKeys` on a block
443
+ * whose `count` or `for_each` is a literal.
444
+ */
445
+ export function entityInstanceKeys(entity: Declarable): readonly string[] {
446
+ const keys = (entity as unknown as { instanceKeys?: unknown }).instanceKeys;
447
+ if (!Array.isArray(keys)) return [];
448
+ return keys.filter((k): k is string => typeof k === "string" && k.startsWith("[") && k.endsWith("]"));
449
+ }
450
+
451
+ /** One instance node an entity names (#4486): its full id, and the key and scope it carries. */
452
+ export interface EntityInstance {
453
+ id: string;
454
+ key?: string;
455
+ scope?: string;
456
+ }
457
+
458
+ /**
459
+ * The instance nodes an entity names, given its own key `name`: the
460
+ * duck-typed `instances` list when it carries one (full ids, which an
461
+ * instance under an expanded module call needs, #4486), else one per
462
+ * {@link entityInstanceKeys} key, id `<name><key>`.
463
+ */
464
+ export function entityInstances(name: string, entity: Declarable): EntityInstance[] {
465
+ const listed = (entity as unknown as { instances?: unknown }).instances;
466
+ if (Array.isArray(listed)) {
467
+ const out: EntityInstance[] = [];
468
+ for (const item of listed) {
469
+ if (typeof item !== "object" || item === null) continue;
470
+ const { id, key, scope } = item as { id?: unknown; key?: unknown; scope?: unknown };
471
+ if (typeof id !== "string" || id.length === 0 || id === name) continue;
472
+ out.push({ id, ...(typeof key === "string" ? { key } : {}), ...(typeof scope === "string" ? { scope } : {}) });
473
+ }
474
+ return out;
475
+ }
476
+ return entityInstanceKeys(entity).map((key) => ({ id: `${name}${key}`, key }));
477
+ }
478
+
332
479
  /** Grouping metadata for cluster/subgraph rendering. Maps group name -> node ids. */
333
480
  export interface IRGroups {
334
481
  byLexicon?: Record<string, string[]>;
@@ -517,6 +664,18 @@ export interface GraphIR {
517
664
  * (`capabilities/view.ts`). Absent unless asked for.
518
665
  */
519
666
  capabilityView?: unknown;
667
+ /**
668
+ * With `chant graph --live` (INTENTIUS/chant#4452): which read answered each
669
+ * root, the observation's structured {@link RootRead} report passed through
670
+ * as the lexicon wrote it, keyed by the lexicon's root key (terraform uses
671
+ * `terraform.roots.<root>`). `depth` is the read asked for, and `fellBackTo`
672
+ * and `reason` are set only when that read failed, so the read that answered
673
+ * is `fellBackTo ?? depth`. A consumer reads this and never the stderr notes
674
+ * that say the same thing in prose. Additive: absent when no lexicon reported
675
+ * one (a lexicon with one read path, a source graph, an `--at` replay), and
676
+ * an older chant never writes it.
677
+ */
678
+ rootReads?: Record<string, RootRead>;
520
679
  }
521
680
 
522
681
  /** A node is anything that serializes to a resource — not a property or output. */
@@ -730,7 +889,8 @@ function subEnvelope(sub: SubForm, seen: Set<unknown>, reverse: Map<object, stri
730
889
  // entity's place in the graph, not declared configuration, and both are read
731
890
  // directly, so projecting them into `attrs` would only restate an edge and a
732
891
  // group key the IR already carries.
733
- const SKIP_KEYS = new Set(["lexicon", "entityType", "kind", "attributes", "Ref", "references", "stack"]);
892
+ // `facts` (#4529) is an engine's observation, carried onto `IRNode.facts`, not configuration.
893
+ const SKIP_KEYS = new Set(["lexicon", "entityType", "kind", "attributes", "Ref", "references", "stack", "facts"]);
734
894
 
735
895
  /** The config bag of a node, paired with each key. Lexicon entities keep their
736
896
  * declared props in a (usually non-enumerable) `props` object; simpler entities
@@ -790,6 +950,7 @@ function collectEdges(
790
950
  kind: "ref",
791
951
  ...(ref.viaAttr ? { viaAttr: ref.viaAttr } : {}),
792
952
  ...(ref.toAttr ? { toAttr: ref.toAttr } : {}),
953
+ ...(ref.grain === "block" || ref.grain === "instance" || ref.grain === "property" ? { grain: ref.grain } : {}),
793
954
  });
794
955
  }
795
956
  const seen = new Set<unknown>();
@@ -868,7 +1029,8 @@ function collectEdges(
868
1029
 
869
1030
  /** Stable key for deduping and sorting an edge. */
870
1031
  function edgeKey(e: IREdge): string {
871
- return `${e.from}\0${e.to}\0${e.viaAttr ?? ""}`;
1032
+ // `grain` joins the key only when set, so an edge without one keys as before.
1033
+ return `${e.from}\0${e.to}\0${e.viaAttr ?? ""}${e.grain ? `\0${e.grain}` : ""}`;
872
1034
  }
873
1035
 
874
1036
  /**
@@ -907,6 +1069,8 @@ export function buildGraphIr(
907
1069
  if (prov?.compositeInstance) node.compositeInstance = prov.compositeInstance;
908
1070
  const file = relFile(prov?.sourceFile, projectPath);
909
1071
  if (file) node.sourceLoc = { file };
1072
+ const facts = entityFacts(entity);
1073
+ if (facts) node.facts = facts;
910
1074
  nodes.push(node);
911
1075
 
912
1076
  (byLexicon[entity.lexicon] ??= []).push(name);
@@ -982,6 +1146,71 @@ export function buildGraphIr(
982
1146
  return ir;
983
1147
  }
984
1148
 
1149
+ /**
1150
+ * Add an instance node (#4454) under each node whose entity names its
1151
+ * instances ({@link entityInstances}): id `<block id><key>`, or the full id
1152
+ * the entity lists under an expanded module call (#4486), the
1153
+ * block's kind, lexicon and source location, `instanceOf` and `instanceKey`,
1154
+ * no attrs and no edges. Each instance joins every group its block is in, so
1155
+ * a renderer draws it in the block's box. A block node whose entity carries
1156
+ * an `instanceRollup` (#4489) gets it. Pure. Returns `ir` itself when no
1157
+ * entity has instance keys or a rollup, so a graph with none prints what it
1158
+ * did before.
1159
+ *
1160
+ * Called by `chant graph` and the declared half of `--live`, not by
1161
+ * {@link buildGraphIr}, so `chant search`, which reads the base IR, still
1162
+ * counts blocks.
1163
+ */
1164
+ export function withInstanceNodes(ir: GraphIR, entities: ReadonlyMap<string, Declarable>): GraphIR {
1165
+ const byId = new Map(ir.nodes.map((n) => [n.id, n]));
1166
+ const added: IRNode[] = [];
1167
+ const childrenOf = new Map<string, string[]>();
1168
+ const rolledUp = new Map<string, InstanceRollup>();
1169
+ for (const [name, entity] of entities) {
1170
+ const block = byId.get(name);
1171
+ if (!block || block.instanceOf) continue;
1172
+ const rollup = entityInstanceRollup(entity);
1173
+ if (rollup) rolledUp.set(name, rollup);
1174
+ for (const { id, key, scope } of entityInstances(name, entity)) {
1175
+ if (byId.has(id)) continue;
1176
+ const node: IRNode = {
1177
+ id,
1178
+ kind: block.kind,
1179
+ lexicon: block.lexicon,
1180
+ attrs: {},
1181
+ instanceOf: name,
1182
+ ...(key !== undefined ? { instanceKey: key } : {}),
1183
+ ...(scope !== undefined ? { instanceScope: scope } : {}),
1184
+ };
1185
+ if (block.sourceLoc) node.sourceLoc = { ...block.sourceLoc };
1186
+ if (block.compositeParent) node.compositeParent = block.compositeParent;
1187
+ if (block.compositeInstance) node.compositeInstance = block.compositeInstance;
1188
+ added.push(node);
1189
+ byId.set(id, node);
1190
+ (childrenOf.get(name) ?? childrenOf.set(name, []).get(name)!).push(id);
1191
+ }
1192
+ }
1193
+ if (added.length === 0 && rolledUp.size === 0) return ir;
1194
+ const own = ir.nodes.map((n) => {
1195
+ const rollup = rolledUp.get(n.id);
1196
+ return rollup ? { ...n, instanceRollup: rollup } : n;
1197
+ });
1198
+ if (added.length === 0) return { ...ir, nodes: own };
1199
+ const nodes = [...own, ...added].sort((a, b) => a.id.localeCompare(b.id));
1200
+ const withChildren = (rec: Record<string, string[]> | undefined): Record<string, string[]> | undefined => {
1201
+ if (!rec) return rec;
1202
+ const out: Record<string, string[]> = {};
1203
+ for (const [k, ids] of Object.entries(rec)) out[k] = [...ids, ...ids.flatMap((id) => childrenOf.get(id) ?? [])].sort();
1204
+ return out;
1205
+ };
1206
+ const groups: IRGroups = { ...ir.groups };
1207
+ for (const key of ["byLexicon", "byComposite", "byStack"] as const) {
1208
+ const grown = withChildren(ir.groups[key]);
1209
+ if (grown) groups[key] = grown;
1210
+ }
1211
+ return { ...ir, nodes, groups };
1212
+ }
1213
+
985
1214
  /**
986
1215
  * Add what the lexicons' `graphEdges` hooks reported (#3910) to a built IR.
987
1216
  *
@@ -1152,10 +1381,39 @@ export function buildLiveGraphIr(observations: LiveObservation[]): GraphIR {
1152
1381
  // ownership above, since `unowned`/`foreign`/`unknown` all mean "no
1153
1382
  // declared owner", which is simply the absence of this field.
1154
1383
  if (meta.ownerChain?.root === "declared") node.runtimeOwner = meta.ownerChain.entity;
1384
+ // An engine's facts (#4527) ride beside `physicalId`, as the engine gave them.
1385
+ if (meta.facts) node.facts = meta.facts;
1155
1386
  nodes.push(node);
1156
1387
  (byLexicon[lexicon] ??= []).push(name);
1157
1388
  // A live lexicon maps to one deployable stack, same as the source IR.
1158
1389
  (byStack[lexicon] ??= []).push(name);
1390
+ // Each present instance of a `count` or `for_each` block is a node of
1391
+ // its own under the block's (#4454), so the overlay paints it alone.
1392
+ // The block node above is the rollup. An absent or not-observed
1393
+ // instance is no live node: the overlay reads that off `instances`.
1394
+ // Under an expanded module call the id follows the declared graph's
1395
+ // rule (#4486, #4488), `estate/module.app[0]/aws_eip.pool[1]`, with
1396
+ // `instanceScope` and no `instanceKey` when only the call is expanded.
1397
+ for (const inst of meta.instances ?? []) {
1398
+ if (inst.verdict !== "present") continue;
1399
+ const id = observedInstanceNodeId(name, inst);
1400
+ if (id === undefined) continue;
1401
+ const child: IRNode = {
1402
+ id,
1403
+ kind: meta.type,
1404
+ lexicon,
1405
+ attrs: { address: inst.address, ...(inst.status ? { status: inst.status } : {}) },
1406
+ instanceOf: name,
1407
+ ...(inst.key !== undefined ? { instanceKey: inst.key } : {}),
1408
+ ...(inst.scope !== undefined ? { instanceScope: inst.scope } : {}),
1409
+ };
1410
+ if (inst.physicalId) child.physicalId = inst.physicalId;
1411
+ if (inst.ownership === "owned" || inst.ownership === "foreign") child.ownership = inst.ownership;
1412
+ if (inst.facts) child.facts = inst.facts;
1413
+ nodes.push(child);
1414
+ (byLexicon[lexicon] ??= []).push(id);
1415
+ (byStack[lexicon] ??= []).push(id);
1416
+ }
1159
1417
  }
1160
1418
  }
1161
1419
 
@@ -1178,7 +1436,9 @@ export function buildLiveGraphIr(observations: LiveObservation[]): GraphIR {
1178
1436
  for (const observation of observations) {
1179
1437
  for (const edge of observation.edges ?? []) {
1180
1438
  if (!observedIds.has(edge.from) || !observedIds.has(edge.to)) continue;
1181
- const key = `${edge.from}\u0000${edge.to}\u0000${edge.viaAttr ?? ""}\u0000${edge.toAttr ?? ""}`;
1439
+ // `grain` is in the key (#4527): a block edge and an instance edge
1440
+ // between the same pair stay two edges.
1441
+ const key = `${edge.from}\u0000${edge.to}\u0000${edge.viaAttr ?? ""}\u0000${edge.toAttr ?? ""}\u0000${edge.grain ?? ""}`;
1182
1442
  if (seen.has(key)) continue;
1183
1443
  seen.add(key);
1184
1444
  edges.push(edge);
@@ -1188,7 +1448,8 @@ export function buildLiveGraphIr(observations: LiveObservation[]): GraphIR {
1188
1448
  (a, b) =>
1189
1449
  a.from.localeCompare(b.from) ||
1190
1450
  a.to.localeCompare(b.to) ||
1191
- (a.viaAttr ?? "").localeCompare(b.viaAttr ?? ""),
1451
+ (a.viaAttr ?? "").localeCompare(b.viaAttr ?? "") ||
1452
+ (a.grain ?? "").localeCompare(b.grain ?? ""),
1192
1453
  );
1193
1454
 
1194
1455
  // Stack exports (#1279) land on the IR's `exports`, the same place the
@@ -1226,17 +1487,48 @@ export function collectUnobserved(observations: LiveObservation[]): Record<strin
1226
1487
  * `runtime` = live, undeclared, owner chain reaches a declared entity (#1077). */
1227
1488
  type OverlayNodeStatus = "good" | "warn" | "accent" | "neutral" | "runtime";
1228
1489
 
1490
+ /**
1491
+ * The overlay paint on one node. `_ownership` (#4534, behold#906 Q2) is
1492
+ * chant's own marker verdict, {@link IRNode.ownership}, beside `_status`, so
1493
+ * `chant search` answers ownership with no grammar of its own:
1494
+ * `attr:_ownership=foreign`, `--show _ownership`, `--count-by attr:_ownership`.
1495
+ * It is `owned` or `foreign`; absent means unknown (no marker channel on the
1496
+ * read, or a node nobody observed). It never reads `facts.ownership`, the
1497
+ * engine's verdict, which stays for display (#4520 Q1).
1498
+ */
1229
1499
  function tagStatus(n: IRNode, status: OverlayNodeStatus, unobserved?: UnobservedEntity): IRNode {
1230
1500
  return {
1231
1501
  ...n,
1232
1502
  attrs: {
1233
1503
  ...n.attrs,
1234
1504
  _status: status,
1505
+ ...(n.ownership ? { _ownership: n.ownership } : {}),
1235
1506
  ...(unobserved ? { _unobserved: unobserved.reason } : {}),
1236
1507
  },
1237
1508
  };
1238
1509
  }
1239
1510
 
1511
+ /**
1512
+ * The paint for a declared instance node (#4454) the live graph has no node
1513
+ * for. Its block not observed: `neutral` with the block's reason, since the
1514
+ * rollup put the whole block there. Its block live with instances read: the
1515
+ * instance is not among them, so `accent`, pending. Its block live with no
1516
+ * instance read at all: `neutral`, since nothing said either way. Its block
1517
+ * absent: `accent`, like the block.
1518
+ */
1519
+ function missingInstance(n: IRNode, live: ReadonlySet<string>, read: ReadonlySet<string>, unobserved: Record<string, UnobservedEntity>): IRNode {
1520
+ const block = n.instanceOf!;
1521
+ const u = unobserved[n.id] ?? unobserved[block];
1522
+ if (u) return tagStatus(n, "neutral", u);
1523
+ if (live.has(block) && !read.has(block)) return tagStatus(n, "neutral");
1524
+ return tagStatus(n, "accent");
1525
+ }
1526
+
1527
+ /** The block ids some live instance node names (#4454): the blocks whose read reported instances. */
1528
+ function blocksWithInstances(live: GraphIR): Set<string> {
1529
+ return new Set(live.nodes.map((n) => n.instanceOf).filter((b): b is string => b !== undefined));
1530
+ }
1531
+
1240
1532
  /**
1241
1533
  * Overlay the declared graph on the provisioned one (#780, `chant graph --live
1242
1534
  * --overlay`) and classify each resource, tagging a `_status` a renderer colours:
@@ -1256,8 +1548,13 @@ export function overlayGraphs(live: GraphIR, declared: GraphIR, opts?: OverlayOp
1256
1548
  const liveIds = new Set(live.nodes.map((n) => n.id));
1257
1549
  const unobserved = opts?.unobserved ?? {};
1258
1550
 
1551
+ const read = blocksWithInstances(live);
1552
+
1259
1553
  const nodes: IRNode[] = live.nodes.map((n) => {
1260
1554
  const d = declaredById.get(n.id);
1555
+ // A live instance of a declared block whose expansion the source could
1556
+ // not count (`count = var.n`) is managed, never foreign (#4454).
1557
+ if (!d && n.instanceOf && declaredById.has(n.instanceOf)) return tagStatus(n, "good");
1261
1558
  if (!d) return tagStatus(n, n.runtimeOwner ? "runtime" : "warn");
1262
1559
  // A managed node keeps the composite it was declared in, so `--detail 1`
1263
1560
  // collapses it with its siblings and rolls their status up (#4227).
@@ -1269,6 +1566,10 @@ export function overlayGraphs(live: GraphIR, declared: GraphIR, opts?: OverlayOp
1269
1566
  });
1270
1567
  for (const n of declared.nodes) {
1271
1568
  if (liveIds.has(n.id)) continue;
1569
+ if (n.instanceOf) {
1570
+ nodes.push(missingInstance(n, liveIds, read, unobserved));
1571
+ continue;
1572
+ }
1272
1573
  const u = unobserved[n.id];
1273
1574
  nodes.push(u ? tagStatus(n, "neutral", u) : tagStatus(n, "accent"));
1274
1575
  }
@@ -1287,7 +1588,7 @@ export function overlayGraphs(live: GraphIR, declared: GraphIR, opts?: OverlayOp
1287
1588
  *
1288
1589
  * Each declared node is classified against live observation and tagged `_status`:
1289
1590
  * - **managed** (declared + provisioned) → `good`, carrying the observed
1290
- * `physicalId` / `ownership` onto the declared node
1591
+ * `physicalId` / `ownership` / engine `facts` onto the declared node
1291
1592
  * - **pending** (declared, provider confirmed absent) → `accent`
1292
1593
  * - **unobserved** (declared, chant could not look — #1089) → `neutral`, with
1293
1594
  * the reason on `_unobserved`. A wrong-cluster or unsupported-kind read used
@@ -1302,12 +1603,19 @@ export function overlayGraphs(live: GraphIR, declared: GraphIR, opts?: OverlayOp
1302
1603
  */
1303
1604
  export function sourceOverlayGraphs(declared: GraphIR, live: GraphIR, opts?: OverlayOptions): GraphIR {
1304
1605
  const liveById = new Map(live.nodes.map((n) => [n.id, n]));
1606
+ const liveIds = new Set(liveById.keys());
1305
1607
  const declaredIds = new Set(declared.nodes.map((n) => n.id));
1306
- const foreignIds = new Set(live.nodes.filter((n) => !declaredIds.has(n.id)).map((n) => n.id));
1608
+ // A live instance of a declared block (#4454) the source could not count
1609
+ // is managed: appended `good`, and never foreign.
1610
+ const managedInstances = live.nodes.filter((n) => !declaredIds.has(n.id) && n.instanceOf !== undefined && declaredIds.has(n.instanceOf));
1611
+ const managedInstanceIds = new Set(managedInstances.map((n) => n.id));
1612
+ const foreignIds = new Set(live.nodes.filter((n) => !declaredIds.has(n.id) && !managedInstanceIds.has(n.id)).map((n) => n.id));
1307
1613
  const unobserved = opts?.unobserved ?? {};
1614
+ const read = blocksWithInstances(live);
1308
1615
 
1309
1616
  const nodes: IRNode[] = declared.nodes.map((n) => {
1310
1617
  const obs = liveById.get(n.id);
1618
+ if (!obs && n.instanceOf) return missingInstance(n, liveIds, read, unobserved);
1311
1619
  if (!obs) {
1312
1620
  const u = unobserved[n.id];
1313
1621
  // unobserved — declared, and nobody looked; not "pending"
@@ -1316,6 +1624,7 @@ export function sourceOverlayGraphs(declared: GraphIR, live: GraphIR, opts?: Ove
1316
1624
  const merged: IRNode = { ...n }; // managed — carry the observed identity
1317
1625
  if (obs.physicalId) merged.physicalId = obs.physicalId;
1318
1626
  if (obs.ownership) merged.ownership = obs.ownership;
1627
+ if (obs.facts) merged.facts = obs.facts;
1319
1628
  // ...and what was observed ABOUT it (#1279). The declared canvas holds what
1320
1629
  // the source says; the observation holds what the account says, and a fact
1321
1630
  // like `VpcId` exists only on the second. Dropping it here made every
@@ -1334,6 +1643,7 @@ export function sourceOverlayGraphs(declared: GraphIR, live: GraphIR, opts?: Ove
1334
1643
  if (!foreignIds.has(n.id)) continue;
1335
1644
  nodes.push(tagStatus(n, n.runtimeOwner ? "runtime" : "warn")); // runtime child or foreign
1336
1645
  }
1646
+ for (const n of managedInstances) nodes.push(tagStatus(n, "good"));
1337
1647
  nodes.sort((a, b) => a.id.localeCompare(b.id));
1338
1648
 
1339
1649
  // Declared edges are the canvas (the cross-substrate topology). Add only the