@intentius/chant 0.68.0 → 0.68.1

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.
@@ -66,6 +66,16 @@ export declare const sanitizeOneLine: typeof sanitizeLedgerText;
66
66
  * The gate a gated `chant run` stopped at, read off its JSON result (#2119) —
67
67
  * pure, unit-tested directly rather than only through `dispatchOp`'s
68
68
  * subprocess plumbing. `undefined` when the output says nothing about a gate.
69
+ *
70
+ * Reads `gate.name`, matching a real `OpRunStatus`/`OpRunRecord`
71
+ * (`../runtime.ts`'s own `gate?: { name: string; since: string }`) — a gated
72
+ * run's record never carries a nested field literally named `gate`. Checking
73
+ * `gate.gate` instead (chant#2396) is `typeof undefined === "string"`, always
74
+ * false, so every gated dispatch fell through to the regex below, which also
75
+ * never matches a `--json` result: the phrase it looks for belongs to the
76
+ * human-readable render `--json` mode suppresses. The regex stays as the
77
+ * fallback for exactly that human-mode case, where the caller's output is
78
+ * prose rather than JSON.
69
79
  */
70
80
  export declare function classifyDispatchFailure(raw: string): {
71
81
  gateName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"converge.d.ts","sourceRoot":"","sources":["../../../src/op/activities/converge.ts"],"names":[],"mappings":"AAkCA,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAKL,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,iCAAiC,CAAC;AAQzC,+JAA+J;AAC/J,MAAM,MAAM,sBAAsB,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAEnE,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;;;;OAWG;IACH,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IACxC,mHAAmH;IACnH,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,KAAK,EAAE,sBAAsB,EAAE,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,gIAAgI;IAChI,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;CACb;AAMD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,2BAAqB,CAAC;AA0BlD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAerF;AA0CD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAKtH;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAC9B,SAAS,EAAE,WAAW,GAAG,SAAS,GACjC,mBAAmB,CAWrB;AAaD;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,sBAAsB,EAAE,EAC/B,YAAY,EAAE,kBAAkB,EAAE,EAClC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAC9B,MAAM,EAAE,MAAM,GACb,gBAAgB,CAmDlB;AAoBD,wBAAsB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAyF5G"}
1
+ {"version":3,"file":"converge.d.ts","sourceRoot":"","sources":["../../../src/op/activities/converge.ts"],"names":[],"mappings":"AAkCA,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAKL,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,iCAAiC,CAAC;AAQzC,+JAA+J;AAC/J,MAAM,MAAM,sBAAsB,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAEnE,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;;;;OAWG;IACH,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IACxC,mHAAmH;IACnH,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,KAAK,EAAE,sBAAsB,EAAE,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,gIAAgI;IAChI,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;CACb;AAMD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,2BAAqB,CAAC;AA0BlD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAerF;AA0CD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAKtH;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAC9B,SAAS,EAAE,WAAW,GAAG,SAAS,GACjC,mBAAmB,CAWrB;AAaD;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,sBAAsB,EAAE,EAC/B,YAAY,EAAE,kBAAkB,EAAE,EAClC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAC9B,MAAM,EAAE,MAAM,GACb,gBAAgB,CAmDlB;AAoBD,wBAAsB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAyF5G"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.68.0",
3
+ "version": "0.68.1",
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",
@@ -307,12 +307,38 @@ describe("classifyDispatchFailure", () => {
307
307
  const raw = JSON.stringify({
308
308
  op: "fountain-apply",
309
309
  status: "gated",
310
- gate: { version: 1, kind: "pending", op: "fountain-apply", gate: "rollout-gate", timestamp: "t", expiresAt: "t2" },
310
+ gate: { name: "rollout-gate", since: "t2" },
311
311
  records: [],
312
312
  });
313
313
  expect(classifyDispatchFailure(raw)).toEqual({ gateName: "rollout-gate" });
314
314
  });
315
315
 
316
+ // chant#2396: a real gated `OpRunRecord` (`../runtime.ts`'s own
317
+ // `gate?: { name: string; since: string }`) never carries a nested field
318
+ // literally named `gate` — `parsed.gate?.gate` is always `undefined`, so
319
+ // this used to fall through to a regex that never matches `--json` output
320
+ // either, and a `ConvergeOp` tick recorded every gated dispatch as an
321
+ // ordinary "reported" failure. This is the exact record shape
322
+ // `TerraformApplyOp`'s own `chant run dev-apply --json` printed while
323
+ // building `examples/converge-operator` against a live floci.
324
+ test("reads the gate off a real gated Op run record — gate.name, not gate.gate (#2396)", () => {
325
+ const raw = JSON.stringify({
326
+ version: 1,
327
+ id: "local-abc123",
328
+ op: "dev-apply",
329
+ env: "dev",
330
+ started: "2026-09-11T05:39:16.000Z",
331
+ ended: "2026-09-11T05:39:16.058Z",
332
+ status: "gated",
333
+ labels: {},
334
+ outcomes: {},
335
+ phases: [],
336
+ gate: { name: "approve-dev-apply", since: "2026-09-11T05:39:16.058Z" },
337
+ approve: "chant approve dev-apply approve-dev-apply",
338
+ });
339
+ expect(classifyDispatchFailure(raw)).toEqual({ gateName: "approve-dev-apply" });
340
+ });
341
+
316
342
  test("falls back to the human summary line, wherever it appears in the output", () => {
317
343
  const raw = 'some earlier noise\nOp "prod-apply" is gated on "prod-approval" after 0.3s\n approve : chant approve prod-apply prod-approval';
318
344
  expect(classifyDispatchFailure(raw)).toEqual({ gateName: "prod-approval" });
@@ -153,15 +153,25 @@ const GATED_EXIT_CODE = 3;
153
153
  * The gate a gated `chant run` stopped at, read off its JSON result (#2119) —
154
154
  * pure, unit-tested directly rather than only through `dispatchOp`'s
155
155
  * subprocess plumbing. `undefined` when the output says nothing about a gate.
156
+ *
157
+ * Reads `gate.name`, matching a real `OpRunStatus`/`OpRunRecord`
158
+ * (`../runtime.ts`'s own `gate?: { name: string; since: string }`) — a gated
159
+ * run's record never carries a nested field literally named `gate`. Checking
160
+ * `gate.gate` instead (chant#2396) is `typeof undefined === "string"`, always
161
+ * false, so every gated dispatch fell through to the regex below, which also
162
+ * never matches a `--json` result: the phrase it looks for belongs to the
163
+ * human-readable render `--json` mode suppresses. The regex stays as the
164
+ * fallback for exactly that human-mode case, where the caller's output is
165
+ * prose rather than JSON.
156
166
  */
157
167
  export function classifyDispatchFailure(raw: string): { gateName: string } | undefined {
158
168
  for (const line of raw.split("\n")) {
159
169
  const trimmed = line.trim();
160
170
  if (!trimmed.startsWith("{")) continue;
161
171
  try {
162
- const parsed = JSON.parse(trimmed) as { status?: string; gate?: { gate?: string } };
163
- if (parsed.status === "gated" && typeof parsed.gate?.gate === "string") {
164
- return { gateName: parsed.gate.gate };
172
+ const parsed = JSON.parse(trimmed) as { status?: string; gate?: { name?: string } };
173
+ if (parsed.status === "gated" && typeof parsed.gate?.name === "string") {
174
+ return { gateName: parsed.gate.name };
165
175
  }
166
176
  } catch {
167
177
  // Not this line's JSON — keep looking.