@intentius/chant 0.50.0 → 0.52.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 (75) hide show
  1. package/dist/cli/build-options.d.ts +68 -0
  2. package/dist/cli/build-options.d.ts.map +1 -0
  3. package/dist/cli/commands/build.d.ts.map +1 -1
  4. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  5. package/dist/cli/handlers/op-progress.d.ts +57 -0
  6. package/dist/cli/handlers/op-progress.d.ts.map +1 -0
  7. package/dist/cli/handlers/run-client.d.ts +21 -1
  8. package/dist/cli/handlers/run-client.d.ts.map +1 -1
  9. package/dist/cli/handlers/run-report.d.ts.map +1 -1
  10. package/dist/cli/handlers/run.d.ts +0 -21
  11. package/dist/cli/handlers/run.d.ts.map +1 -1
  12. package/dist/cli/handlers/search.d.ts +22 -0
  13. package/dist/cli/handlers/search.d.ts.map +1 -1
  14. package/dist/cli/main.d.ts.map +1 -1
  15. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  16. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  17. package/dist/cli/registry.d.ts +33 -1
  18. package/dist/cli/registry.d.ts.map +1 -1
  19. package/dist/components/run-progress.d.ts +7 -5
  20. package/dist/components/run-progress.d.ts.map +1 -1
  21. package/dist/lexicon.d.ts +41 -0
  22. package/dist/lexicon.d.ts.map +1 -1
  23. package/dist/lifecycle/assert-live.d.ts +77 -0
  24. package/dist/lifecycle/assert-live.d.ts.map +1 -0
  25. package/dist/lifecycle/change-set.d.ts +40 -0
  26. package/dist/lifecycle/change-set.d.ts.map +1 -1
  27. package/dist/lifecycle/disruption.d.ts +96 -0
  28. package/dist/lifecycle/disruption.d.ts.map +1 -0
  29. package/dist/lifecycle/index.d.ts +2 -0
  30. package/dist/lifecycle/index.d.ts.map +1 -1
  31. package/dist/lifecycle/replay.d.ts +2 -0
  32. package/dist/lifecycle/replay.d.ts.map +1 -1
  33. package/dist/lint/policy.d.ts +16 -0
  34. package/dist/lint/policy.d.ts.map +1 -1
  35. package/dist/op/local-executor.d.ts +22 -2
  36. package/dist/op/local-executor.d.ts.map +1 -1
  37. package/dist/testing.d.ts +23 -2
  38. package/dist/testing.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/cli/build-options.test.ts +101 -0
  41. package/src/cli/build-options.ts +109 -0
  42. package/src/cli/commands/build.ts +24 -53
  43. package/src/cli/handlers/lifecycle.test.ts +109 -0
  44. package/src/cli/handlers/lifecycle.ts +32 -8
  45. package/src/cli/handlers/op-progress.test.ts +202 -0
  46. package/src/cli/handlers/op-progress.ts +192 -0
  47. package/src/cli/handlers/run-client.test.ts +82 -0
  48. package/src/cli/handlers/run-client.ts +85 -2
  49. package/src/cli/handlers/run-report.test.ts +62 -0
  50. package/src/cli/handlers/run-report.ts +20 -58
  51. package/src/cli/handlers/run.test.ts +240 -0
  52. package/src/cli/handlers/run.ts +76 -18
  53. package/src/cli/handlers/search-drift.test.ts +263 -0
  54. package/src/cli/handlers/search.ts +150 -1
  55. package/src/cli/main.ts +11 -0
  56. package/src/cli/mcp/op-tools.ts +17 -6
  57. package/src/cli/mcp/resource-handlers.ts +13 -5
  58. package/src/cli/registry.ts +33 -1
  59. package/src/components/run-progress.ts +9 -5
  60. package/src/lexicon.ts +51 -0
  61. package/src/lifecycle/assert-live.test.ts +125 -0
  62. package/src/lifecycle/assert-live.ts +154 -0
  63. package/src/lifecycle/change-set.test.ts +144 -1
  64. package/src/lifecycle/change-set.ts +165 -11
  65. package/src/lifecycle/disruption.test.ts +186 -0
  66. package/src/lifecycle/disruption.ts +224 -0
  67. package/src/lifecycle/index.ts +2 -0
  68. package/src/lifecycle/replay.test.ts +25 -0
  69. package/src/lifecycle/replay.ts +11 -3
  70. package/src/lint/policy-build-parity.test.ts +232 -0
  71. package/src/lint/policy.ts +51 -6
  72. package/src/op/local-executor.ts +35 -1
  73. package/src/op/local-output.ts +1 -1
  74. package/src/testing.test.ts +89 -2
  75. package/src/testing.ts +63 -3
@@ -0,0 +1,77 @@
1
+ /**
2
+ * assertLive (#1857) — the read half of the test harness (#1224):
3
+ * observation-backed assertions against a live deploy, for exactly one
4
+ * declared entity at a time. Same primitive teardown.ts's fallback path
5
+ * uses — `describeResources` — turned into a pass/throw instead of a
6
+ * would-delete set.
7
+ *
8
+ * The observation contract (#1089) draws a hard line between OBSERVED-ABSENT
9
+ * and NOT-OBSERVED: a declared entity the read could not cover is never the
10
+ * same as one confirmed missing. `assertLiveEntity` preserves that line by
11
+ * construction — NOT-OBSERVED throws {@link UnobservedAssertionError}, a type
12
+ * distinct from the {@link LiveAssertionError} an observed-absent, foreign,
13
+ * or status-mismatched verdict throws, so a caller can tell "could not tell"
14
+ * from "confirmed wrong" without parsing a message.
15
+ *
16
+ * Marker verification is best-effort by the same logic {@link
17
+ * ResourceMetadata.marker}'s own contract states: a lexicon with no marker
18
+ * channel on this read path (aws's thin `describeResources`, `ownership:
19
+ * "unknown"`) reports no marker at all, which is not the same claim as
20
+ * "foreign". Enforcing a match whenever the channel exists — a present
21
+ * mismatch, or `ownership: "foreign"` with no marker to show — catches the
22
+ * case the harness cares about (a same-named leftover from another env);
23
+ * an absent channel is passed through unverified rather than making every
24
+ * lexicon without one unusable.
25
+ */
26
+ import { type UnobservedReason } from "../observation.js";
27
+ import type { ObservationLexicon, ResourceMetadata } from "../lexicon.js";
28
+ import type { OwnershipMarker } from "../ownership.js";
29
+ /**
30
+ * Thrown by {@link assertLiveEntity} for a confirmed failure: observed
31
+ * absent, a marker that names another stack/env, a resource confirmed
32
+ * foreign, or a status mismatch. Never thrown for NOT-OBSERVED — see {@link
33
+ * UnobservedAssertionError}.
34
+ */
35
+ export declare class LiveAssertionError extends Error {
36
+ constructor(message: string);
37
+ }
38
+ /**
39
+ * Thrown when the entity is NOT-OBSERVED (#1089) rather than confirmed
40
+ * present or absent. Kept as its own type, not a flag on {@link
41
+ * LiveAssertionError}: a suite (or a CI policy) that wants to fail loudly on
42
+ * "could not tell" but treat it differently from a confirmed miss can catch
43
+ * this one specifically.
44
+ */
45
+ export declare class UnobservedAssertionError extends Error {
46
+ readonly entity: string;
47
+ readonly reason: UnobservedReason;
48
+ readonly detail?: string | undefined;
49
+ constructor(entity: string, reason: UnobservedReason, detail?: string | undefined);
50
+ }
51
+ export interface AssertLiveOptions {
52
+ /** Expected `ResourceMetadata.status`, where the lexicon reports one. Skipped when omitted. */
53
+ status?: string;
54
+ }
55
+ export interface AssertLiveEntityOptions extends AssertLiveOptions {
56
+ plugin: ObservationLexicon;
57
+ /** chant entity name — the key to assert on. */
58
+ name: string;
59
+ entityType: string;
60
+ props: Record<string, unknown>;
61
+ /** This lexicon's own built output for the deploy, or `""` when none was built. */
62
+ buildOutput: string;
63
+ environment: string;
64
+ /** This deploy's identity — the marker an observed resource is checked against. */
65
+ marker: OwnershipMarker;
66
+ }
67
+ /**
68
+ * Assert one declared entity is live: observed present in `environment`, not
69
+ * a confirmed-foreign resource, and — when `status` is given — reporting
70
+ * that status. Resolves to the entity's {@link ResourceMetadata} on success.
71
+ *
72
+ * Throws {@link UnobservedAssertionError} for NOT-OBSERVED. Throws {@link
73
+ * LiveAssertionError} for observed-absent, a confirmed-foreign identity, or a
74
+ * status mismatch.
75
+ */
76
+ export declare function assertLiveEntity(opts: AssertLiveEntityOptions): Promise<ResourceMetadata>;
77
+ //# sourceMappingURL=assert-live.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-live.d.ts","sourceRoot":"","sources":["../../src/lifecycle/assert-live.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAA6D,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClH,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;aAE/B,MAAM,EAAE,MAAM;aACd,MAAM,EAAE,gBAAgB;aACxB,MAAM,CAAC,EAAE,MAAM;gBAFf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,gBAAgB,EACxB,MAAM,CAAC,EAAE,MAAM,YAAA;CAQlC;AAED,MAAM,WAAW,iBAAiB;IAChC,+FAA+F;IAC/F,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,MAAM,EAAE,kBAAkB,CAAC;IAC3B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,MAAM,EAAE,eAAe,CAAC;CACzB;AAQD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwD/F"}
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import { type AttributeChange, type DiffLiveInput } from "./live-diff.js";
16
16
  import { type UnobservedReason } from "../observation.js";
17
+ import { type Disruption } from "./disruption.js";
17
18
  /**
18
19
  * What the projection proposes for a single resource.
19
20
  *
@@ -125,6 +126,22 @@ export interface ChangeSetEntry {
125
126
  effectReason?: EffectFireReason;
126
127
  /** Human-readable backing for `effectReason` (the digests that differ, the unresolved path). */
127
128
  effectDetail?: string;
129
+ /**
130
+ * How much applying this change hurts (#1665) — in-place / rolling / replace
131
+ * / destroy / unknown. Set on `update` entries only: every other action
132
+ * carries its blast radius in the action itself.
133
+ *
134
+ * The verdict comes from the lexicon that owns the spec
135
+ * ({@link LexiconPlugin.classifyDisruption}), never from core, which has no
136
+ * per-provider replacement rules and must not grow any. `unknown` is the
137
+ * default and the only fallback — read it as "nobody could say", never as
138
+ * "probably in place".
139
+ */
140
+ disruption?: Disruption;
141
+ /** The attribute paths that forced `disruption` (#1665). */
142
+ disruptionBecause?: string[];
143
+ /** Human-readable backing for `disruption` — the spec knowledge behind the call, or why there is none. */
144
+ disruptionDetail?: string;
128
145
  }
129
146
  export interface ChangeSet {
130
147
  env: string;
@@ -170,6 +187,29 @@ export interface GitlabMrReport {
170
187
  }
171
188
  /** Project a change set onto the GitLab MR plan widget shape. Pure. */
172
189
  export declare function gitlabMrReport(cs: ChangeSet): GitlabMrReport;
190
+ /**
191
+ * Warning a plan should print when it carries a hole — a declared entity the
192
+ * lexicon could not observe (#1089). The `--json` and `--report gitlab-mr`
193
+ * shapes have no column for `unobserved`, so both the CLI (on stderr) and the
194
+ * `markdown` report (in the body, since a reviewer never sees a job's stderr)
195
+ * read this same wording rather than drifting apart. Empty when the plan has
196
+ * no hole. Same discipline as {@link disruptionNotices} in `./disruption`.
197
+ */
198
+ export declare function unobservedPlanNotice(cs: ChangeSet): string[];
173
199
  /** Human-readable render of a change set. Pure — returns a string. */
174
200
  export declare function renderChangeSet(cs: ChangeSet): string;
201
+ /**
202
+ * Markdown projection of a change set (#1983) — sized for a PR/MR comment
203
+ * rather than a terminal. A scannable counts header, entries grouped by
204
+ * action and attributed to their lexicon, deltas in a fenced block, and any
205
+ * group past {@link MARKDOWN_FOLD_THRESHOLD} folded into a `<details>` so a
206
+ * large plan doesn't bury the comment. Pure — no ANSI, no I/O — and
207
+ * deterministic: same entry ordering as {@link renderChangeSet}.
208
+ *
209
+ * Both a hole (#1089) and an expensive verdict (#1665) are surfaced IN the
210
+ * body, not left to stderr the way `--json` and `--report gitlab-mr` leave
211
+ * them: a reviewer reading a comment never sees the job's log, so a plan
212
+ * carrying either must not read as clean.
213
+ */
214
+ export declare function renderChangeSetMarkdown(cs: ChangeSet): string;
175
215
  //# sourceMappingURL=change-set.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"change-set.d.ts","sourceRoot":"","sources":["../../src/lifecycle/change-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAY,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAwB,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAEnH;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAEvF;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,kEAAkE;IAClE,QAAQ,EAAE;QACR,oCAAoC;QACpC,QAAQ,EAAE,OAAO,CAAC;QAClB,oCAAoC;QACpC,UAAU,EAAE,OAAO,CAAC;QACpB,qDAAqD;QACrD,IAAI,EAAE,OAAO,CAAC;QACd;;;;;WAKG;QACH,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC;IACF,6CAA6C;IAC7C,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,oDAAoD;IACpD,SAAS,EAAE,SAAS,CAAC;IACrB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oGAAoG;IACpG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CA6GvG;AAID,gCAAgC;AAChC,wBAAgB,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAarE;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,cAAc,CAG5D;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAsCrD"}
1
+ {"version":3,"file":"change-set.d.ts","sourceRoot":"","sources":["../../src/lifecycle/change-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAY,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAwB,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAyC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAEnH;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAEvF;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,kEAAkE;IAClE,QAAQ,EAAE;QACR,oCAAoC;QACpC,QAAQ,EAAE,OAAO,CAAC;QAClB,oCAAoC;QACpC,UAAU,EAAE,OAAO,CAAC;QACpB,qDAAqD;QACrD,IAAI,EAAE,OAAO,CAAC;QACd;;;;;WAKG;QACH,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC;IACF,6CAA6C;IAC7C,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,oDAAoD;IACpD,SAAS,EAAE,SAAS,CAAC;IACrB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oGAAoG;IACpG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,0GAA0G;IAC1G,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CA6GvG;AAID,gCAAgC;AAChC,wBAAgB,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAarE;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,cAAc,CAG5D;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,EAAE,CAO5D;AAwBD,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CA2CrD;AA0CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAsC7D"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Per-change disruption classification (#1665).
3
+ *
4
+ * The change set says WHAT a pending change is (`create`/`update`/`delete`/…).
5
+ * It says nothing about what applying it costs. An `update` that flips a tag
6
+ * and an `update` that rebuilds a database read identically, and the second one
7
+ * is the one that wakes somebody up.
8
+ *
9
+ * The knowledge that separates them is spec knowledge. CloudFormation's
10
+ * registry schema declares `createOnlyProperties` per type; Kubernetes' SSA
11
+ * schema knows which field changes roll a workload. Core owns neither, and
12
+ * hardcoding either here would put per-provider replacement rules in the tool
13
+ * — the same mistake `postSynthChecks` exists to avoid. So core defines the
14
+ * contract and the reporting, and the lexicon that compiled the spec supplies
15
+ * the answer, via {@link LexiconPlugin.classifyDisruption}.
16
+ *
17
+ * The invariant that makes the field trustworthy is that `unknown` is the
18
+ * default and the only fallback. No classifier, a classifier that says nothing
19
+ * about an entry, a classifier that throws, a classifier that returns a level
20
+ * outside the vocabulary — all of them land on `unknown`, never on `in-place`.
21
+ * A confident "this mutates in place" is only ever a lexicon's own claim.
22
+ */
23
+ import type { AttributeChange } from "./live-diff.js";
24
+ import type { ChangeSet, ChangeSetEntry } from "./change-set.js";
25
+ /**
26
+ * How much applying one pending change hurts.
27
+ *
28
+ * - `in-place` — the provider mutates the existing resource. No new identity,
29
+ * no window where it is absent.
30
+ * - `rolling` — the resource survives, but its workload is replaced
31
+ * incrementally (a Deployment's pod template changing). Disruptive to what
32
+ * is running, not to the resource.
33
+ * - `replace` — a new resource is created and the old one removed. The
34
+ * physical id changes; anything holding the old one has to be updated.
35
+ * - `destroy` — replacement that removes the old resource FIRST. There is a
36
+ * window with nothing there, and whatever the old one held is gone.
37
+ * - `unknown` — nobody could say. The honest value, and the default: it is
38
+ * what a change gets when no lexicon classifies it, and it must never be
39
+ * read as "probably fine".
40
+ */
41
+ export type Disruption = "in-place" | "rolling" | "replace" | "destroy" | "unknown";
42
+ /** Every level, most disruptive last — also the guard core validates a lexicon's answer against. */
43
+ export declare const DISRUPTION_LEVELS: readonly Disruption[];
44
+ /** One pending change put to a lexicon for classification. */
45
+ export interface DisruptionQuery {
46
+ /** The change set entry's `name` — the key a verdict comes back under. */
47
+ name: string;
48
+ /** Resource type, when the observation reported one. */
49
+ type?: string;
50
+ /** The attribute-level changes the entry carries. */
51
+ deltas: AttributeChange[];
52
+ }
53
+ /** A lexicon's answer for one query. */
54
+ export interface DisruptionVerdict {
55
+ disruption: Disruption;
56
+ /** The attribute paths that forced the verdict — empty or absent when none did. */
57
+ because?: string[];
58
+ /** One line of human-readable backing, naming the spec knowledge behind the call. */
59
+ detail?: string;
60
+ }
61
+ /**
62
+ * The shape of {@link LexiconPlugin.classifyDisruption}. Keyed by query `name`;
63
+ * a name the lexicon says nothing about degrades to `unknown`, so a partial
64
+ * answer is a valid answer.
65
+ */
66
+ export type DisruptionClassifier = (options: {
67
+ environment: string;
68
+ changes: DisruptionQuery[];
69
+ }) => Record<string, DisruptionVerdict> | Promise<Record<string, DisruptionVerdict>>;
70
+ /** The verdict every fallback path produces. */
71
+ export declare function unknownDisruption(detail: string): DisruptionVerdict;
72
+ /**
73
+ * Annotate one lexicon's change set with a disruption verdict per `update`.
74
+ *
75
+ * Only `update` entries are asked about: every other action already carries its
76
+ * blast radius in the action itself. Called once per lexicon, before the plan
77
+ * merges the change sets, so `classify` is always the lexicon that produced the
78
+ * entries — the only party that can map its own observation's attribute paths
79
+ * back onto spec properties.
80
+ *
81
+ * Returns a new change set; the input is not mutated.
82
+ */
83
+ export declare function annotateDisruption(cs: ChangeSet, environment: string, classify?: DisruptionClassifier): Promise<ChangeSet>;
84
+ /** Count `update` entries per level. Entries with no verdict at all are not counted. */
85
+ export declare function summarizeDisruption(cs: ChangeSet): Record<Disruption, number>;
86
+ /** The most disruptive verdict in the set, or undefined when nothing was classified. */
87
+ export declare function worstDisruption(cs: ChangeSet): Disruption | undefined;
88
+ /**
89
+ * Warnings a plan should print on stderr — so a `--json` or `--report gitlab-mr`
90
+ * consumer, whose shape has no column for disruption, still hears about the
91
+ * expensive rows. Same discipline as the unobserved warning (#1089).
92
+ */
93
+ export declare function disruptionNotices(cs: ChangeSet): string[];
94
+ /** Render one entry's verdict for the human plan, or "" when there is none. */
95
+ export declare function renderDisruption(entry: ChangeSetEntry): string;
96
+ //# sourceMappingURL=disruption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disruption.d.ts","sourceRoot":"","sources":["../../src/lifecycle/disruption.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpF,oGAAoG;AACpG,eAAO,MAAM,iBAAiB,EAAE,SAAS,UAAU,EAMlD,CAAC;AAWF,8DAA8D;AAC9D,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,wCAAwC;AACxC,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B,KAAK,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAErF,gDAAgD;AAChD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAEnE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,SAAS,EACb,WAAW,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,SAAS,CAAC,CA0CpB;AAiBD,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAY7E;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,CAOrE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,EAAE,CAkBzD;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAG9D"}
@@ -7,6 +7,7 @@ export * from "./deep-diff.js";
7
7
  export * from "./deep-observe.js";
8
8
  export * from "./observation-baseline.js";
9
9
  export * from "./change-set.js";
10
+ export * from "./disruption.js";
10
11
  export * from "./unobserved-gate.js";
11
12
  export * from "./receipt-plan.js";
12
13
  export * from "./affected.js";
@@ -16,6 +17,7 @@ export * from "./build-ledger-store.js";
16
17
  export * from "./oras-referrer-lookup.js";
17
18
  export * from "./status.js";
18
19
  export * from "./teardown.js";
20
+ export * from "./assert-live.js";
19
21
  export * from "./symptoms.js";
20
22
  export * from "./converge-ledger.js";
21
23
  export * from "./scenario.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lifecycle/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lifecycle/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
@@ -14,6 +14,7 @@
14
14
  * answer most questions but never all of them.
15
15
  */
16
16
  import type { LiveObservation } from "../graph-ir.js";
17
+ import type { ObservationDepth } from "./types.js";
17
18
  /**
18
19
  * Rebuild observations from a recorded snapshot (#1266).
19
20
  *
@@ -40,6 +41,7 @@ export declare function replaySnapshots(environment: string, ref: string, scoped
40
41
  observations: LiveObservation[];
41
42
  commit: string;
42
43
  timestamp: string;
44
+ depth: ObservationDepth;
43
45
  } | {
44
46
  error: string;
45
47
  hint?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/lifecycle/replay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD;;;;;;;;;;;;GAYG;AACH;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMvE;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GACxB,OAAO,CAAC;IAAE,YAAY,EAAE,eAAe,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyIpH"}
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/lifecycle/replay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAqB,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEnE;;;;;;;;;;;;GAYG;AACH;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMvE;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GACxB,OAAO,CACN;IAAE,YAAY,EAAE,eAAe,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,GAC/F;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CACnC,CA8IA"}
@@ -25,12 +25,28 @@ export interface PolicyEvaluation {
25
25
  * of the finding just vanishing.
26
26
  */
27
27
  suppressed: PostSynthDiagnostic[];
28
+ /**
29
+ * chant #2002 — divergences between this evaluation and what `chant build`
30
+ * would do, named rather than left silent. Today that is a project whose
31
+ * resolved `build.sandbox` is `true`: the gate builds unsandboxed, because
32
+ * running it inside the boundary needs the per-execution arming decision
33
+ * tracked on #1157. Also written to stderr — the gate's caller is an
34
+ * activity wrapper that surfaces output, not a structured result.
35
+ */
36
+ warnings: string[];
28
37
  }
29
38
  /**
30
39
  * Build a project and run its `lint.policies` over the resolved resources,
31
40
  * standalone — used by the `policyGate` Op step to gate an apply on the same
32
41
  * organizational policy `chant build` enforces. Loads the project's lexicons,
33
42
  * builds, then runs the policy pack with `env` (explicit, else `ownership.env`).
43
+ *
44
+ * chant #2002 — "the same organizational policy `chant build` enforces" only
45
+ * holds if it is the same build. The build options are assembled by
46
+ * `../cli/build-options.ts`'s `resolveProjectBuildOptions`, the single function
47
+ * `chant build` also calls, rather than by a second list here; a build option
48
+ * added for one caller and not the other is what let a gate pass a build
49
+ * `chant build` fails.
34
50
  */
35
51
  export declare function evaluateProjectPolicies(opts: {
36
52
  path: string;
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/lint/policy.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxE;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAuBpG;AAED,MAAM,WAAW,gBAAgB;IAC/B,yFAAyF;IACzF,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,2FAA2F;IAC3F,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,UAAU,EAAE,mBAAmB,EAAE,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6C5B"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/lint/policy.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxE;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAuBpG;AAED,MAAM,WAAW,gBAAgB;IAC/B,yFAAyF;IACzF,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,2FAA2F;IAC3F,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwE5B"}
@@ -10,12 +10,18 @@
10
10
  * implementations and profiles are passed in (loaded dynamically by the CLI),
11
11
  * so core never statically depends on `@intentius/chant-lexicon-temporal`.
12
12
  */
13
- import type { OpConfig, GateStep } from "./types.js";
13
+ import type { OpConfig, ActivityStep, GateStep } from "./types.js";
14
14
  import { type ActivityFn, type ActivityProfile } from "./activity-registry.js";
15
15
  export interface StepRecord {
16
16
  phase: string;
17
17
  fn: string;
18
- args: Record<string, unknown>;
18
+ /**
19
+ * Present for a local-executor record. Absent for one reconstructed from
20
+ * Temporal workflow history (op-progress.ts) — an activity's scheduled
21
+ * input isn't decoded there, so the field is simply omitted rather than
22
+ * populated with a guess.
23
+ */
24
+ args?: Record<string, unknown>;
19
25
  status: "ok" | "fail" | "skipped";
20
26
  durationMs: number;
21
27
  outcome?: {
@@ -45,6 +51,20 @@ export declare function parseDuration(s: string): number;
45
51
  /** Find the first gate step anywhere in the Op (phases + onFailure, including
46
52
  * gates nested inside effect steps), if any. */
47
53
  export declare function findGate(config: OpConfig): GateStep | undefined;
54
+ /**
55
+ * Find the first `policyGate` step anywhere in the Op (phases + `onFailure`,
56
+ * including steps nested inside effect steps), if any.
57
+ *
58
+ * chant #2003 — `--sandbox` is a GLOBAL flag (`../cli/registry.ts`), and
59
+ * `../cli/main.ts` arms the process-wide policy latch off it for every command,
60
+ * `chant run` included. A `policyGate` step then reaches `loadPolicyChecks`,
61
+ * which refuses while armed with a message written for a chant maintainer —
62
+ * shown to a user who passed a documented flag. The combination cannot be
63
+ * honoured until the gate can build and load policies inside the boundary
64
+ * (#1157), so both `chant run` paths pre-flight it with this and refuse before
65
+ * any phase executes, the same shape as {@link findGate}'s pre-flight.
66
+ */
67
+ export declare function findPolicyGateStep(config: OpConfig): ActivityStep | undefined;
48
68
  /**
49
69
  * Execute an Op locally. Resolves with the run result on success; rejects with
50
70
  * `OpRunFailure` (carrying the partial result) on terminal failure, after
@@ -1 +1 @@
1
- {"version":3,"file":"local-executor.d.ts","sourceRoot":"","sources":["../../src/op/local-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAiC,QAAQ,EAA8B,MAAM,SAAS,CAAC;AAC7G,OAAO,EAAmB,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAM7F,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;CACb;AAID,kFAAkF;AAClF,qBAAa,yBAA0B,SAAQ,KAAK;aACtB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAO/C;AAED,mFAAmF;AACnF,qBAAa,YAAa,SAAQ,KAAK;aACT,MAAM,EAAE,WAAW;gBAAnB,MAAM,EAAE,WAAW;CAIhD;AAmBD,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAU/C;AA8BD;gDACgD;AAChD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAY/D;AAiSD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,QAAQ,EAChB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,CAgDtB"}
1
+ {"version":3,"file":"local-executor.d.ts","sourceRoot":"","sources":["../../src/op/local-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAmB,YAAY,EAAE,QAAQ,EAA8B,MAAM,SAAS,CAAC;AAC7G,OAAO,EAAmB,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAM7F,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;CACb;AAID,kFAAkF;AAClF,qBAAa,yBAA0B,SAAQ,KAAK;aACtB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAO/C;AAED,mFAAmF;AACnF,qBAAa,YAAa,SAAQ,KAAK;aACT,MAAM,EAAE,WAAW;gBAAnB,MAAM,EAAE,WAAW;CAIhD;AAmBD,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAU/C;AA8BD;gDACgD;AAChD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAY/D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,YAAY,GAAG,SAAS,CAa7E;AAiSD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,QAAQ,EAChB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,CAgDtB"}
package/dist/testing.d.ts CHANGED
@@ -15,6 +15,12 @@
15
15
  * in-process for exactly this suite's environment. Stateless by design:
16
16
  * a crashed suite's environment is recovered by calling destroy again (or
17
17
  * `chant lifecycle teardown <env> --yes`).
18
+ * - **assertLive** (#1857) — `describeResources()` against exactly one
19
+ * declared entity, turned into a pass or a thrown failure. Preserves
20
+ * #1089's tri-state rather than collapsing it: NOT-OBSERVED throws {@link
21
+ * UnobservedAssertionError}, never a silent pass and never an ordinary
22
+ * failure, because chant could not read the entity is not the same claim
23
+ * as chant read it and it is gone.
18
24
  *
19
25
  * ## Isolation
20
26
  *
@@ -39,12 +45,14 @@
39
45
  * exported, and a CI job pointing the identical suite at a real account just
40
46
  * leaves both unset.
41
47
  */
42
- import type { Declarable } from "./declarable.js";
48
+ import { type Declarable } from "./declarable.js";
43
49
  import type { SerializerResult } from "./serializer.js";
44
50
  import { type BuildParamValue } from "./build-params.js";
45
- import type { LexiconPlugin } from "./lexicon.js";
51
+ import type { LexiconPlugin, ResourceMetadata } from "./lexicon.js";
46
52
  import { type ActivityFn, type ActivityProfile } from "./op/activity-registry.js";
47
53
  import { type TeardownReport } from "./lifecycle/teardown.js";
54
+ import { LiveAssertionError, UnobservedAssertionError, type AssertLiveOptions } from "./lifecycle/assert-live.js";
55
+ export { LiveAssertionError, UnobservedAssertionError, type AssertLiveOptions };
48
56
  export interface DeployStackOptions {
49
57
  /** The chant project directory (where the infra source lives). */
50
58
  dir: string;
@@ -86,6 +94,19 @@ export interface DeployedStack {
86
94
  entities: Map<string, Declarable>;
87
95
  /** The environment this deploy targeted — the teardown key. */
88
96
  env: string;
97
+ /**
98
+ * Assert that a declared entity is live: observed present in this
99
+ * deploy's environment, not confirmed as another stack/env's resource,
100
+ * and — when `status` is given — reporting that status.
101
+ *
102
+ * Rides the observation contract (#1089): an entity `describeResources`
103
+ * could not cover throws {@link UnobservedAssertionError}, never a pass
104
+ * and never a plain failure — NOT-OBSERVED is not the same claim as
105
+ * absent. Observed-absent, a confirmed-foreign identity, or a status
106
+ * mismatch throws {@link LiveAssertionError}. Resolves to the entity's
107
+ * `ResourceMetadata` on success.
108
+ */
109
+ assertLive(name: string, options?: AssertLiveOptions): Promise<ResourceMetadata>;
89
110
  /**
90
111
  * Tear down everything carrying this suite's marker `{ stack, env }`.
91
112
  * Throws {@link TeardownIncompleteError} when any candidate failed to
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAMrD,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAI1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/C,OAAO,EAAgC,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE7G,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAgB5E,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3C;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC;IAChD,8CAA8C;IAC9C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;CACpC;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;aACpB,MAAM,EAAE,cAAc;gBAAtB,MAAM,EAAE,cAAc;CAkBnD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUjD;AA8BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAkHrF"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAMH,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAMrD,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAI1E,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,EAAgC,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE7G,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAEL,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,KAAK,iBAAiB,EAAE,CAAC;AAgBhF,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3C;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC;IAChD,8CAA8C;IAC9C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjF;;;;;;;OAOG;IACH,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;CACpC;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;aACpB,MAAM,EAAE,cAAc;gBAAtB,MAAM,EAAE,cAAc;CAkBnD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUjD;AA8BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAmJrF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.50.0",
3
+ "version": "0.52.0",
4
4
  "description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -0,0 +1,101 @@
1
+ /**
2
+ * chant #2002 — the shared build-option assembler. `chant build` and the
3
+ * `policyGate` step both call this; `../lint/policy-build-parity.test.ts`
4
+ * proves they stay in step, this file pins what the function itself resolves.
5
+ */
6
+ import { describe, test, expect } from "vitest";
7
+ import { createMockPlugin } from "@intentius/chant-test-utils";
8
+ import type { LexiconPlugin } from "../lexicon";
9
+ import type { ChantConfig } from "../config";
10
+ import { resolveBuildModes, resolveProjectBuildOptions } from "./build-options";
11
+
12
+ const config = (over: Record<string, unknown> = {}): ChantConfig => over as ChantConfig;
13
+
14
+ describe("resolveBuildModes", () => {
15
+ test("fold defaults on, sandbox defaults off (#1134 / #1045)", () => {
16
+ expect(resolveBuildModes(config())).toEqual({ fold: true, sandbox: false });
17
+ });
18
+
19
+ test("the project config decides when no flag is given", () => {
20
+ expect(resolveBuildModes(config({ build: { fold: false, sandbox: true } })))
21
+ .toEqual({ fold: false, sandbox: true });
22
+ });
23
+
24
+ test("an explicit flag wins over the config, in both directions", () => {
25
+ expect(resolveBuildModes(config({ build: { fold: false } }), { fold: true }).fold).toBe(true);
26
+ expect(resolveBuildModes(config({ build: { fold: true } }), { fold: false }).fold).toBe(false);
27
+ expect(resolveBuildModes(config(), { sandbox: true }).sandbox).toBe(true);
28
+ });
29
+ });
30
+
31
+ describe("resolveProjectBuildOptions", () => {
32
+ const modes = { fold: true, sandbox: false };
33
+
34
+ test("threads the project config through to the serializers", () => {
35
+ const projectConfig = config({ forgejo: { runnerLabels: { "ubuntu-latest": "docker-arm" } } });
36
+ const options = resolveProjectBuildOptions({ config: projectConfig, configDir: "/p", modes });
37
+ expect(options.config).toEqual(projectConfig);
38
+ });
39
+
40
+ test("collects intrinsics and lexicon names from the loaded plugins", () => {
41
+ const intrinsic = { tag: "Sub", lexicon: "aws" } as never;
42
+ const plugins: LexiconPlugin[] = [
43
+ { ...createMockPlugin({ name: "aws" }), intrinsics: () => [intrinsic] },
44
+ createMockPlugin({ name: "k8s" }),
45
+ ];
46
+ const options = resolveProjectBuildOptions({ config: config(), configDir: "/p", plugins, modes });
47
+ expect(options.lexicons).toEqual(["aws", "k8s"]);
48
+ expect(options.intrinsics).toEqual([intrinsic]);
49
+ });
50
+
51
+ test("binds each plugin's buildRoots hook to the CONFIG dir, not the build path", async () => {
52
+ let seenRoot: string | undefined;
53
+ const plugins: LexiconPlugin[] = [
54
+ {
55
+ ...createMockPlugin({ name: "cedar" }),
56
+ buildRoots: async (ctx) => {
57
+ seenRoot = ctx.projectRoot;
58
+ return { entities: new Map() };
59
+ },
60
+ },
61
+ ];
62
+ const options = resolveProjectBuildOptions({ config: config(), configDir: "/project", plugins, modes });
63
+ expect(options.buildRoots).toHaveLength(1);
64
+ await options.buildRoots![0]({ entities: new Map() });
65
+ expect(seenRoot).toBe("/project");
66
+ });
67
+
68
+ test("a plugin without a buildRoots hook contributes nothing", () => {
69
+ const options = resolveProjectBuildOptions({
70
+ config: config(),
71
+ configDir: "/p",
72
+ plugins: [createMockPlugin({ name: "k8s" })],
73
+ modes,
74
+ });
75
+ expect(options.buildRoots).toEqual([]);
76
+ });
77
+
78
+ test("no plugins at all is empty, never undefined-by-accident", () => {
79
+ const options = resolveProjectBuildOptions({ config: config(), configDir: "/p", modes });
80
+ expect(options.lexicons).toEqual([]);
81
+ expect(options.intrinsics).toEqual([]);
82
+ expect(options.buildRoots).toEqual([]);
83
+ expect(options.lexiconVersions).toEqual({});
84
+ });
85
+
86
+ test("carries the resolved modes, ownership and build parameters verbatim", () => {
87
+ const ownership = { stack: "s", env: "prod" } as never;
88
+ const buildParams = [{ name: "env", value: "prod", source: "default" }] as never;
89
+ const options = resolveProjectBuildOptions({
90
+ config: config(),
91
+ configDir: "/p",
92
+ modes: { fold: false, sandbox: true },
93
+ ownership,
94
+ buildParams,
95
+ });
96
+ expect(options.fold).toBe(false);
97
+ expect(options.sandbox).toBe(true);
98
+ expect(options.ownership).toBe(ownership);
99
+ expect(options.buildParams).toBe(buildParams);
100
+ });
101
+ });