@intentius/chant 0.124.17 → 0.124.18

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 (115) hide show
  1. package/dist/__golden__/wave-loop/fan-out-applied.json +511 -0
  2. package/dist/__golden__/wave-loop/fan-out-apply-fails.json +406 -0
  3. package/dist/__golden__/wave-loop/fan-out-gated.json +707 -0
  4. package/dist/__golden__/wave-loop/fan-out-no-members.json +898 -0
  5. package/dist/__golden__/wave-loop/fan-out-only.json +514 -0
  6. package/dist/__golden__/wave-loop/fan-out-plan-fails.json +359 -0
  7. package/dist/__golden__/wave-loop/fan-out-same-root.json +311 -0
  8. package/dist/__golden__/wave-loop/op-by-apply-after-fails.json +401 -0
  9. package/dist/__golden__/wave-loop/op-by-apply-hold.json +756 -0
  10. package/dist/__golden__/wave-loop/op-by-apply-ignored.json +340 -0
  11. package/dist/__golden__/wave-loop/op-by-apply-pass.json +400 -0
  12. package/dist/__golden__/wave-loop/op-by-apply-skip.json +404 -0
  13. package/dist/__golden__/wave-loop/op-cost-member-clash.json +62 -0
  14. package/dist/__golden__/wave-loop/op-cost-member.json +191 -0
  15. package/dist/__golden__/wave-loop/op-denied-source.json +407 -0
  16. package/dist/__golden__/wave-loop/op-denied.json +399 -0
  17. package/dist/__golden__/wave-loop/op-discover-rest-short.json +92 -0
  18. package/dist/__golden__/wave-loop/op-discover-rest-stops.json +340 -0
  19. package/dist/__golden__/wave-loop/op-discover-rest.json +659 -0
  20. package/dist/__golden__/wave-loop/op-discover-wide.json +290 -0
  21. package/dist/__golden__/wave-loop/op-held-on-again.json +176 -0
  22. package/dist/__golden__/wave-loop/op-held-on-before-apply.json +689 -0
  23. package/dist/__golden__/wave-loop/op-held-on.json +1455 -0
  24. package/dist/__golden__/wave-loop/op-hooks-apply-fails.json +673 -0
  25. package/dist/__golden__/wave-loop/op-hooks-fail-after-apply.json +737 -0
  26. package/dist/__golden__/wave-loop/op-hooks-fail-before-apply.json +450 -0
  27. package/dist/__golden__/wave-loop/op-hooks-fail-before-plan.json +97 -0
  28. package/dist/__golden__/wave-loop/op-hooks-held.json +1059 -0
  29. package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +693 -0
  30. package/dist/__golden__/wave-loop/op-hooks-pass.json +735 -0
  31. package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +148 -0
  32. package/dist/__golden__/wave-loop/op-hooks-share.json +1225 -0
  33. package/dist/__golden__/wave-loop/op-outcome-held.json +202 -0
  34. package/dist/__golden__/wave-loop/op-outcome-replan-approved.json +286 -0
  35. package/dist/__golden__/wave-loop/op-outcome-replan-forever.json +823 -0
  36. package/dist/__golden__/wave-loop/op-outcome-replan.json +259 -0
  37. package/dist/__golden__/wave-loop/op-outcome-stood-down.json +196 -0
  38. package/dist/__golden__/wave-loop/op-outcome-unreadable.json +193 -0
  39. package/dist/__golden__/wave-loop/op-overridden.json +508 -0
  40. package/dist/__golden__/wave-loop/op-per-run.json +518 -0
  41. package/dist/__golden__/wave-loop/op-point.json +495 -0
  42. package/dist/__golden__/wave-loop/op-pr-review.json +397 -0
  43. package/dist/__golden__/wave-loop/op-sealed.json +125 -0
  44. package/dist/__golden__/wave-loop/op-spend-change-only.json +168 -0
  45. package/dist/__golden__/wave-loop/op-spend.json +328 -0
  46. package/dist/__golden__/wave-loop/op-wave-commands.json +1808 -0
  47. package/dist/__golden__/wave-loop/op-wide-refused.json +291 -0
  48. package/dist/__golden__/wave-loop/op-wide-waiting.json +231 -0
  49. package/dist/__golden__/wave-loop/op-wide.json +440 -0
  50. package/dist/components/fan-out-run.d.ts +4 -3
  51. package/dist/components/fan-out-run.d.ts.map +1 -1
  52. package/dist/components/fan-out-run.js +138 -123
  53. package/dist/op/op-waves-run.d.ts +7 -1
  54. package/dist/op/op-waves-run.d.ts.map +1 -1
  55. package/dist/op/op-waves-run.js +129 -72
  56. package/dist/wave-engine.d.ts +74 -5
  57. package/dist/wave-engine.d.ts.map +1 -1
  58. package/dist/wave-engine.js +47 -5
  59. package/dist/wave-runtime.mjs +202 -202
  60. package/package.json +1 -1
  61. package/src/__golden__/wave-loop/fan-out-applied.json +511 -0
  62. package/src/__golden__/wave-loop/fan-out-apply-fails.json +406 -0
  63. package/src/__golden__/wave-loop/fan-out-gated.json +707 -0
  64. package/src/__golden__/wave-loop/fan-out-no-members.json +898 -0
  65. package/src/__golden__/wave-loop/fan-out-only.json +514 -0
  66. package/src/__golden__/wave-loop/fan-out-plan-fails.json +359 -0
  67. package/src/__golden__/wave-loop/fan-out-same-root.json +311 -0
  68. package/src/__golden__/wave-loop/op-by-apply-after-fails.json +401 -0
  69. package/src/__golden__/wave-loop/op-by-apply-hold.json +756 -0
  70. package/src/__golden__/wave-loop/op-by-apply-ignored.json +340 -0
  71. package/src/__golden__/wave-loop/op-by-apply-pass.json +400 -0
  72. package/src/__golden__/wave-loop/op-by-apply-skip.json +404 -0
  73. package/src/__golden__/wave-loop/op-cost-member-clash.json +62 -0
  74. package/src/__golden__/wave-loop/op-cost-member.json +191 -0
  75. package/src/__golden__/wave-loop/op-denied-source.json +407 -0
  76. package/src/__golden__/wave-loop/op-denied.json +399 -0
  77. package/src/__golden__/wave-loop/op-discover-rest-short.json +92 -0
  78. package/src/__golden__/wave-loop/op-discover-rest-stops.json +340 -0
  79. package/src/__golden__/wave-loop/op-discover-rest.json +659 -0
  80. package/src/__golden__/wave-loop/op-discover-wide.json +290 -0
  81. package/src/__golden__/wave-loop/op-held-on-again.json +176 -0
  82. package/src/__golden__/wave-loop/op-held-on-before-apply.json +689 -0
  83. package/src/__golden__/wave-loop/op-held-on.json +1455 -0
  84. package/src/__golden__/wave-loop/op-hooks-apply-fails.json +673 -0
  85. package/src/__golden__/wave-loop/op-hooks-fail-after-apply.json +737 -0
  86. package/src/__golden__/wave-loop/op-hooks-fail-before-apply.json +450 -0
  87. package/src/__golden__/wave-loop/op-hooks-fail-before-plan.json +97 -0
  88. package/src/__golden__/wave-loop/op-hooks-held.json +1059 -0
  89. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +693 -0
  90. package/src/__golden__/wave-loop/op-hooks-pass.json +735 -0
  91. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +148 -0
  92. package/src/__golden__/wave-loop/op-hooks-share.json +1225 -0
  93. package/src/__golden__/wave-loop/op-outcome-held.json +202 -0
  94. package/src/__golden__/wave-loop/op-outcome-replan-approved.json +286 -0
  95. package/src/__golden__/wave-loop/op-outcome-replan-forever.json +823 -0
  96. package/src/__golden__/wave-loop/op-outcome-replan.json +259 -0
  97. package/src/__golden__/wave-loop/op-outcome-stood-down.json +196 -0
  98. package/src/__golden__/wave-loop/op-outcome-unreadable.json +193 -0
  99. package/src/__golden__/wave-loop/op-overridden.json +508 -0
  100. package/src/__golden__/wave-loop/op-per-run.json +518 -0
  101. package/src/__golden__/wave-loop/op-point.json +495 -0
  102. package/src/__golden__/wave-loop/op-pr-review.json +397 -0
  103. package/src/__golden__/wave-loop/op-sealed.json +125 -0
  104. package/src/__golden__/wave-loop/op-spend-change-only.json +168 -0
  105. package/src/__golden__/wave-loop/op-spend.json +328 -0
  106. package/src/__golden__/wave-loop/op-wave-commands.json +1808 -0
  107. package/src/__golden__/wave-loop/op-wide-refused.json +291 -0
  108. package/src/__golden__/wave-loop/op-wide-waiting.json +231 -0
  109. package/src/__golden__/wave-loop/op-wide.json +440 -0
  110. package/src/components/fan-out-run.ts +156 -128
  111. package/src/meta/peer-deps.test.ts +39 -0
  112. package/src/op/op-waves-run.ts +184 -68
  113. package/src/wave-engine.test.ts +38 -1
  114. package/src/wave-engine.ts +101 -5
  115. package/src/wave-loop-golden.test.ts +627 -0
@@ -0,0 +1,1225 @@
1
+ {
2
+ "jobs": [
3
+ {
4
+ "label": "decide, held",
5
+ "job": {
6
+ "wave": 1,
7
+ "decide": true
8
+ },
9
+ "result": {
10
+ "exitCode": 3,
11
+ "applied": [],
12
+ "failed": [],
13
+ "moved": [],
14
+ "hooks": [
15
+ {
16
+ "moment": "before-plan",
17
+ "name": "lint",
18
+ "exit": 0,
19
+ "outcome": "passed"
20
+ },
21
+ {
22
+ "moment": "after-plan",
23
+ "name": "check",
24
+ "target": "t1",
25
+ "exit": 0,
26
+ "outcome": "passed"
27
+ },
28
+ {
29
+ "moment": "after-plan",
30
+ "name": "check",
31
+ "target": "t2",
32
+ "exit": 1,
33
+ "outcome": "held"
34
+ }
35
+ ],
36
+ "decision": {
37
+ "wave": 1,
38
+ "name": "prod",
39
+ "op": "migrations",
40
+ "gate": "migrations-wave-1",
41
+ "policy": "never",
42
+ "approval": "ledger",
43
+ "policySource": "base",
44
+ "base": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
45
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
46
+ "members": [
47
+ {
48
+ "member": "t1",
49
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
50
+ "op": "migrate"
51
+ },
52
+ {
53
+ "member": "t2",
54
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
55
+ "op": "migrate"
56
+ }
57
+ ],
58
+ "status": "waiting",
59
+ "hooks": {
60
+ "before-plan": [
61
+ {
62
+ "name": "lint",
63
+ "command": [
64
+ "hook",
65
+ "lint",
66
+ "{runs}"
67
+ ]
68
+ }
69
+ ],
70
+ "after-plan": [
71
+ {
72
+ "name": "check",
73
+ "command": [
74
+ "hook",
75
+ "check",
76
+ "{target}",
77
+ "{plan}"
78
+ ],
79
+ "perRun": true,
80
+ "onFailure": "approve"
81
+ }
82
+ ],
83
+ "before-apply": [
84
+ {
85
+ "name": "backup",
86
+ "command": [
87
+ "hook",
88
+ "backup",
89
+ "{runs}"
90
+ ]
91
+ }
92
+ ],
93
+ "after-apply": [
94
+ {
95
+ "name": "smoke",
96
+ "command": [
97
+ "hook",
98
+ "smoke",
99
+ "{wave}"
100
+ ]
101
+ }
102
+ ]
103
+ },
104
+ "heldBy": [
105
+ "after-plan hook check (t2)"
106
+ ],
107
+ "pendingFact": {
108
+ "version": 1,
109
+ "kind": "pending",
110
+ "approvalMode": "ledger",
111
+ "op": "migrations",
112
+ "gate": "migrations-wave-1",
113
+ "timestamp": "2026-10-11T00:00:00.000Z",
114
+ "expiresAt": "2026-10-13T00:00:00.000Z",
115
+ "description": "wave 1 (prod): 2 runs, gate never, approval ledger, held by after-plan hook check (t2)",
116
+ "planDigest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f"
117
+ },
118
+ "recorded": true,
119
+ "waitingSince": "2026-10-11T00:00:00.000Z",
120
+ "approve": "chant approve migrations migrations-wave-1 --plan jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
121
+ "outcomes": [
122
+ {
123
+ "moment": "before-plan",
124
+ "name": "lint",
125
+ "exit": 0,
126
+ "outcome": "passed"
127
+ },
128
+ {
129
+ "moment": "after-plan",
130
+ "name": "check",
131
+ "target": "t1",
132
+ "exit": 0,
133
+ "outcome": "passed"
134
+ },
135
+ {
136
+ "moment": "after-plan",
137
+ "name": "check",
138
+ "target": "t2",
139
+ "exit": 1,
140
+ "outcome": "held"
141
+ }
142
+ ]
143
+ }
144
+ },
145
+ "ledger": {
146
+ "appended": [
147
+ {
148
+ "version": 1,
149
+ "kind": "pending",
150
+ "approvalMode": "ledger",
151
+ "op": "migrations",
152
+ "gate": "migrations-wave-1",
153
+ "timestamp": "2026-10-11T00:00:00.000Z",
154
+ "expiresAt": "2026-10-13T00:00:00.000Z",
155
+ "description": "wave 1 (prod): 2 runs, gate never, approval ledger, held by after-plan hook check (t2)",
156
+ "planDigest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f"
157
+ }
158
+ ],
159
+ "resolved": [],
160
+ "applied": []
161
+ },
162
+ "calls": 5,
163
+ "logs": 2
164
+ },
165
+ {
166
+ "label": "share 1, waiting decision",
167
+ "job": {
168
+ "wave": 1,
169
+ "share": 1
170
+ },
171
+ "result": {
172
+ "exitCode": 3,
173
+ "applied": [],
174
+ "failed": [],
175
+ "moved": [],
176
+ "hooks": [],
177
+ "decision": {
178
+ "wave": 1,
179
+ "name": "prod",
180
+ "op": "migrations",
181
+ "gate": "migrations-wave-1",
182
+ "policy": "never",
183
+ "approval": "ledger",
184
+ "policySource": "base",
185
+ "base": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
186
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
187
+ "members": [
188
+ {
189
+ "member": "t1",
190
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
191
+ "op": "migrate"
192
+ },
193
+ {
194
+ "member": "t2",
195
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
196
+ "op": "migrate"
197
+ }
198
+ ],
199
+ "status": "waiting",
200
+ "hooks": {
201
+ "before-plan": [
202
+ {
203
+ "name": "lint",
204
+ "command": [
205
+ "hook",
206
+ "lint",
207
+ "{runs}"
208
+ ]
209
+ }
210
+ ],
211
+ "after-plan": [
212
+ {
213
+ "name": "check",
214
+ "command": [
215
+ "hook",
216
+ "check",
217
+ "{target}",
218
+ "{plan}"
219
+ ],
220
+ "perRun": true,
221
+ "onFailure": "approve"
222
+ }
223
+ ],
224
+ "before-apply": [
225
+ {
226
+ "name": "backup",
227
+ "command": [
228
+ "hook",
229
+ "backup",
230
+ "{runs}"
231
+ ]
232
+ }
233
+ ],
234
+ "after-apply": [
235
+ {
236
+ "name": "smoke",
237
+ "command": [
238
+ "hook",
239
+ "smoke",
240
+ "{wave}"
241
+ ]
242
+ }
243
+ ]
244
+ },
245
+ "heldBy": [
246
+ "after-plan hook check (t2)"
247
+ ],
248
+ "pendingFact": {
249
+ "version": 1,
250
+ "kind": "pending",
251
+ "approvalMode": "ledger",
252
+ "op": "migrations",
253
+ "gate": "migrations-wave-1",
254
+ "timestamp": "2026-10-11T00:00:00.000Z",
255
+ "expiresAt": "2026-10-13T00:00:00.000Z",
256
+ "description": "wave 1 (prod): 2 runs, gate never, approval ledger, held by after-plan hook check (t2)",
257
+ "planDigest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f"
258
+ },
259
+ "recorded": true,
260
+ "waitingSince": "2026-10-11T00:00:00.000Z",
261
+ "approve": "chant approve migrations migrations-wave-1 --plan jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
262
+ "outcomes": [
263
+ {
264
+ "moment": "before-plan",
265
+ "name": "lint",
266
+ "exit": 0,
267
+ "outcome": "passed"
268
+ },
269
+ {
270
+ "moment": "after-plan",
271
+ "name": "check",
272
+ "target": "t1",
273
+ "exit": 0,
274
+ "outcome": "passed"
275
+ },
276
+ {
277
+ "moment": "after-plan",
278
+ "name": "check",
279
+ "target": "t2",
280
+ "exit": 1,
281
+ "outcome": "held"
282
+ }
283
+ ]
284
+ }
285
+ },
286
+ "ledger": {
287
+ "appended": [],
288
+ "resolved": [],
289
+ "applied": []
290
+ },
291
+ "calls": 0,
292
+ "logs": 1
293
+ },
294
+ {
295
+ "label": "decide, approved",
296
+ "job": {
297
+ "wave": 1,
298
+ "decide": true
299
+ },
300
+ "result": {
301
+ "exitCode": 0,
302
+ "applied": [],
303
+ "failed": [],
304
+ "moved": [],
305
+ "hooks": [
306
+ {
307
+ "moment": "before-plan",
308
+ "name": "lint",
309
+ "exit": 0,
310
+ "outcome": "passed"
311
+ },
312
+ {
313
+ "moment": "after-plan",
314
+ "name": "check",
315
+ "target": "t1",
316
+ "exit": 0,
317
+ "outcome": "passed"
318
+ },
319
+ {
320
+ "moment": "after-plan",
321
+ "name": "check",
322
+ "target": "t2",
323
+ "exit": 1,
324
+ "outcome": "held"
325
+ }
326
+ ],
327
+ "decision": {
328
+ "wave": 1,
329
+ "name": "prod",
330
+ "op": "migrations",
331
+ "gate": "migrations-wave-1",
332
+ "policy": "never",
333
+ "approval": "ledger",
334
+ "policySource": "base",
335
+ "base": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
336
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
337
+ "members": [
338
+ {
339
+ "member": "t1",
340
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
341
+ "op": "migrate"
342
+ },
343
+ {
344
+ "member": "t2",
345
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
346
+ "op": "migrate"
347
+ }
348
+ ],
349
+ "status": "approved",
350
+ "hooks": {
351
+ "before-plan": [
352
+ {
353
+ "name": "lint",
354
+ "command": [
355
+ "hook",
356
+ "lint",
357
+ "{runs}"
358
+ ]
359
+ }
360
+ ],
361
+ "after-plan": [
362
+ {
363
+ "name": "check",
364
+ "command": [
365
+ "hook",
366
+ "check",
367
+ "{target}",
368
+ "{plan}"
369
+ ],
370
+ "perRun": true,
371
+ "onFailure": "approve"
372
+ }
373
+ ],
374
+ "before-apply": [
375
+ {
376
+ "name": "backup",
377
+ "command": [
378
+ "hook",
379
+ "backup",
380
+ "{runs}"
381
+ ]
382
+ }
383
+ ],
384
+ "after-apply": [
385
+ {
386
+ "name": "smoke",
387
+ "command": [
388
+ "hook",
389
+ "smoke",
390
+ "{wave}"
391
+ ]
392
+ }
393
+ ]
394
+ },
395
+ "heldBy": [
396
+ "after-plan hook check (t2)"
397
+ ],
398
+ "via": "ledger",
399
+ "approvedBy": "alice",
400
+ "approvedAt": "2026-10-10T00:00:00Z",
401
+ "outcomes": [
402
+ {
403
+ "moment": "before-plan",
404
+ "name": "lint",
405
+ "exit": 0,
406
+ "outcome": "passed"
407
+ },
408
+ {
409
+ "moment": "after-plan",
410
+ "name": "check",
411
+ "target": "t1",
412
+ "exit": 0,
413
+ "outcome": "passed"
414
+ },
415
+ {
416
+ "moment": "after-plan",
417
+ "name": "check",
418
+ "target": "t2",
419
+ "exit": 1,
420
+ "outcome": "held"
421
+ }
422
+ ]
423
+ }
424
+ },
425
+ "ledger": {
426
+ "appended": [],
427
+ "resolved": [],
428
+ "applied": []
429
+ },
430
+ "calls": 5,
431
+ "logs": 2
432
+ },
433
+ {
434
+ "label": "share 2, approved",
435
+ "job": {
436
+ "wave": 1,
437
+ "share": 2
438
+ },
439
+ "result": {
440
+ "exitCode": 0,
441
+ "applied": [
442
+ "t2"
443
+ ],
444
+ "failed": [],
445
+ "moved": [],
446
+ "hooks": [
447
+ {
448
+ "moment": "before-plan",
449
+ "name": "lint",
450
+ "exit": 0,
451
+ "outcome": "passed"
452
+ },
453
+ {
454
+ "moment": "after-plan",
455
+ "name": "check",
456
+ "target": "t2",
457
+ "exit": 1,
458
+ "outcome": "held"
459
+ },
460
+ {
461
+ "moment": "before-apply",
462
+ "name": "backup",
463
+ "exit": 0,
464
+ "outcome": "passed"
465
+ },
466
+ {
467
+ "moment": "after-apply",
468
+ "name": "smoke",
469
+ "exit": 0,
470
+ "outcome": "passed"
471
+ }
472
+ ],
473
+ "decision": {
474
+ "wave": 1,
475
+ "name": "prod",
476
+ "op": "migrations",
477
+ "gate": "migrations-wave-1",
478
+ "policy": "never",
479
+ "approval": "ledger",
480
+ "policySource": "base",
481
+ "base": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
482
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
483
+ "members": [
484
+ {
485
+ "member": "t1",
486
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
487
+ "op": "migrate"
488
+ },
489
+ {
490
+ "member": "t2",
491
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
492
+ "op": "migrate"
493
+ }
494
+ ],
495
+ "status": "approved",
496
+ "hooks": {
497
+ "before-plan": [
498
+ {
499
+ "name": "lint",
500
+ "command": [
501
+ "hook",
502
+ "lint",
503
+ "{runs}"
504
+ ]
505
+ }
506
+ ],
507
+ "after-plan": [
508
+ {
509
+ "name": "check",
510
+ "command": [
511
+ "hook",
512
+ "check",
513
+ "{target}",
514
+ "{plan}"
515
+ ],
516
+ "perRun": true,
517
+ "onFailure": "approve"
518
+ }
519
+ ],
520
+ "before-apply": [
521
+ {
522
+ "name": "backup",
523
+ "command": [
524
+ "hook",
525
+ "backup",
526
+ "{runs}"
527
+ ]
528
+ }
529
+ ],
530
+ "after-apply": [
531
+ {
532
+ "name": "smoke",
533
+ "command": [
534
+ "hook",
535
+ "smoke",
536
+ "{wave}"
537
+ ]
538
+ }
539
+ ]
540
+ },
541
+ "heldBy": [
542
+ "after-plan hook check (t2)"
543
+ ],
544
+ "via": "ledger",
545
+ "approvedBy": "alice",
546
+ "approvedAt": "2026-10-10T00:00:00Z",
547
+ "outcomes": [
548
+ {
549
+ "moment": "before-plan",
550
+ "name": "lint",
551
+ "exit": 0,
552
+ "outcome": "passed"
553
+ },
554
+ {
555
+ "moment": "after-plan",
556
+ "name": "check",
557
+ "target": "t1",
558
+ "exit": 0,
559
+ "outcome": "passed"
560
+ },
561
+ {
562
+ "moment": "after-plan",
563
+ "name": "check",
564
+ "target": "t2",
565
+ "exit": 1,
566
+ "outcome": "held"
567
+ }
568
+ ]
569
+ }
570
+ },
571
+ "ledger": {
572
+ "appended": [],
573
+ "resolved": [],
574
+ "applied": []
575
+ },
576
+ "calls": 6,
577
+ "logs": 1
578
+ }
579
+ ],
580
+ "calls": [
581
+ {
582
+ "argv": [
583
+ "hook",
584
+ "lint",
585
+ ".chant/op-waves/migrations/wave-1/runs.json"
586
+ ],
587
+ "env": {
588
+ "CHANT_OP_WAVES": "migrations",
589
+ "CHANT_WAVE": "prod",
590
+ "CHANT_WAVE_NUMBER": "1",
591
+ "CHANT_HOOK": "before-plan",
592
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
593
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json"
594
+ },
595
+ "read": {
596
+ "CHANT_RUNS": {
597
+ "wave": "prod",
598
+ "number": 1,
599
+ "runs": [
600
+ {
601
+ "target": "t1",
602
+ "op": "migrate"
603
+ },
604
+ {
605
+ "target": "t2",
606
+ "op": "migrate"
607
+ }
608
+ ]
609
+ },
610
+ ".chant/op-waves/migrations/wave-1/runs.json": {
611
+ "wave": "prod",
612
+ "number": 1,
613
+ "runs": [
614
+ {
615
+ "target": "t1",
616
+ "op": "migrate"
617
+ },
618
+ {
619
+ "target": "t2",
620
+ "op": "migrate"
621
+ }
622
+ ]
623
+ }
624
+ }
625
+ },
626
+ {
627
+ "argv": [
628
+ "tool",
629
+ "plan",
630
+ "t1",
631
+ ".chant/op-waves/migrations/wave-1/t1.plan.json"
632
+ ]
633
+ },
634
+ {
635
+ "argv": [
636
+ "tool",
637
+ "plan",
638
+ "t2",
639
+ ".chant/op-waves/migrations/wave-1/t2.plan.json"
640
+ ]
641
+ },
642
+ {
643
+ "argv": [
644
+ "hook",
645
+ "check",
646
+ "t1",
647
+ ".chant/op-waves/migrations/wave-1/t1.plan.json"
648
+ ],
649
+ "env": {
650
+ "CHANT_OP_WAVES": "migrations",
651
+ "CHANT_WAVE": "prod",
652
+ "CHANT_WAVE_NUMBER": "1",
653
+ "CHANT_HOOK": "after-plan",
654
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
655
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json",
656
+ "CHANT_TARGET": "t1",
657
+ "CHANT_PLAN": ".chant/op-waves/migrations/wave-1/t1.plan.json"
658
+ },
659
+ "read": {
660
+ "CHANT_RUNS": {
661
+ "wave": "prod",
662
+ "number": 1,
663
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
664
+ "runs": [
665
+ {
666
+ "target": "t1",
667
+ "op": "migrate",
668
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
669
+ },
670
+ {
671
+ "target": "t2",
672
+ "op": "migrate",
673
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
674
+ }
675
+ ]
676
+ }
677
+ }
678
+ },
679
+ {
680
+ "argv": [
681
+ "hook",
682
+ "check",
683
+ "t2",
684
+ ".chant/op-waves/migrations/wave-1/t2.plan.json"
685
+ ],
686
+ "env": {
687
+ "CHANT_OP_WAVES": "migrations",
688
+ "CHANT_WAVE": "prod",
689
+ "CHANT_WAVE_NUMBER": "1",
690
+ "CHANT_HOOK": "after-plan",
691
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
692
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json",
693
+ "CHANT_TARGET": "t2",
694
+ "CHANT_PLAN": ".chant/op-waves/migrations/wave-1/t2.plan.json"
695
+ },
696
+ "read": {
697
+ "CHANT_RUNS": {
698
+ "wave": "prod",
699
+ "number": 1,
700
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
701
+ "runs": [
702
+ {
703
+ "target": "t1",
704
+ "op": "migrate",
705
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
706
+ },
707
+ {
708
+ "target": "t2",
709
+ "op": "migrate",
710
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
711
+ }
712
+ ]
713
+ }
714
+ }
715
+ },
716
+ {
717
+ "argv": [
718
+ "hook",
719
+ "lint",
720
+ ".chant/op-waves/migrations/wave-1/runs.json"
721
+ ],
722
+ "env": {
723
+ "CHANT_OP_WAVES": "migrations",
724
+ "CHANT_WAVE": "prod",
725
+ "CHANT_WAVE_NUMBER": "1",
726
+ "CHANT_HOOK": "before-plan",
727
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
728
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json"
729
+ },
730
+ "read": {
731
+ "CHANT_RUNS": {
732
+ "wave": "prod",
733
+ "number": 1,
734
+ "runs": [
735
+ {
736
+ "target": "t1",
737
+ "op": "migrate"
738
+ },
739
+ {
740
+ "target": "t2",
741
+ "op": "migrate"
742
+ }
743
+ ]
744
+ },
745
+ ".chant/op-waves/migrations/wave-1/runs.json": {
746
+ "wave": "prod",
747
+ "number": 1,
748
+ "runs": [
749
+ {
750
+ "target": "t1",
751
+ "op": "migrate"
752
+ },
753
+ {
754
+ "target": "t2",
755
+ "op": "migrate"
756
+ }
757
+ ]
758
+ }
759
+ }
760
+ },
761
+ {
762
+ "argv": [
763
+ "tool",
764
+ "plan",
765
+ "t1",
766
+ ".chant/op-waves/migrations/wave-1/t1.plan.json"
767
+ ]
768
+ },
769
+ {
770
+ "argv": [
771
+ "tool",
772
+ "plan",
773
+ "t2",
774
+ ".chant/op-waves/migrations/wave-1/t2.plan.json"
775
+ ]
776
+ },
777
+ {
778
+ "argv": [
779
+ "hook",
780
+ "check",
781
+ "t1",
782
+ ".chant/op-waves/migrations/wave-1/t1.plan.json"
783
+ ],
784
+ "env": {
785
+ "CHANT_OP_WAVES": "migrations",
786
+ "CHANT_WAVE": "prod",
787
+ "CHANT_WAVE_NUMBER": "1",
788
+ "CHANT_HOOK": "after-plan",
789
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
790
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json",
791
+ "CHANT_TARGET": "t1",
792
+ "CHANT_PLAN": ".chant/op-waves/migrations/wave-1/t1.plan.json"
793
+ },
794
+ "read": {
795
+ "CHANT_RUNS": {
796
+ "wave": "prod",
797
+ "number": 1,
798
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
799
+ "runs": [
800
+ {
801
+ "target": "t1",
802
+ "op": "migrate",
803
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
804
+ },
805
+ {
806
+ "target": "t2",
807
+ "op": "migrate",
808
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
809
+ }
810
+ ]
811
+ }
812
+ }
813
+ },
814
+ {
815
+ "argv": [
816
+ "hook",
817
+ "check",
818
+ "t2",
819
+ ".chant/op-waves/migrations/wave-1/t2.plan.json"
820
+ ],
821
+ "env": {
822
+ "CHANT_OP_WAVES": "migrations",
823
+ "CHANT_WAVE": "prod",
824
+ "CHANT_WAVE_NUMBER": "1",
825
+ "CHANT_HOOK": "after-plan",
826
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
827
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json",
828
+ "CHANT_TARGET": "t2",
829
+ "CHANT_PLAN": ".chant/op-waves/migrations/wave-1/t2.plan.json"
830
+ },
831
+ "read": {
832
+ "CHANT_RUNS": {
833
+ "wave": "prod",
834
+ "number": 1,
835
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
836
+ "runs": [
837
+ {
838
+ "target": "t1",
839
+ "op": "migrate",
840
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
841
+ },
842
+ {
843
+ "target": "t2",
844
+ "op": "migrate",
845
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
846
+ }
847
+ ]
848
+ }
849
+ }
850
+ },
851
+ {
852
+ "argv": [
853
+ "hook",
854
+ "lint",
855
+ ".chant/op-waves/migrations/wave-1/runs.json"
856
+ ],
857
+ "env": {
858
+ "CHANT_OP_WAVES": "migrations",
859
+ "CHANT_WAVE": "prod",
860
+ "CHANT_WAVE_NUMBER": "1",
861
+ "CHANT_HOOK": "before-plan",
862
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
863
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json"
864
+ },
865
+ "read": {
866
+ "CHANT_RUNS": {
867
+ "wave": "prod",
868
+ "number": 1,
869
+ "runs": [
870
+ {
871
+ "target": "t2",
872
+ "op": "migrate"
873
+ }
874
+ ]
875
+ },
876
+ ".chant/op-waves/migrations/wave-1/runs.json": {
877
+ "wave": "prod",
878
+ "number": 1,
879
+ "runs": [
880
+ {
881
+ "target": "t2",
882
+ "op": "migrate"
883
+ }
884
+ ]
885
+ }
886
+ }
887
+ },
888
+ {
889
+ "argv": [
890
+ "tool",
891
+ "plan",
892
+ "t2",
893
+ ".chant/op-waves/migrations/wave-1/t2.plan.json"
894
+ ]
895
+ },
896
+ {
897
+ "argv": [
898
+ "hook",
899
+ "check",
900
+ "t2",
901
+ ".chant/op-waves/migrations/wave-1/t2.plan.json"
902
+ ],
903
+ "env": {
904
+ "CHANT_OP_WAVES": "migrations",
905
+ "CHANT_WAVE": "prod",
906
+ "CHANT_WAVE_NUMBER": "1",
907
+ "CHANT_HOOK": "after-plan",
908
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
909
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json",
910
+ "CHANT_TARGET": "t2",
911
+ "CHANT_PLAN": ".chant/op-waves/migrations/wave-1/t2.plan.json"
912
+ },
913
+ "read": {
914
+ "CHANT_RUNS": {
915
+ "wave": "prod",
916
+ "number": 1,
917
+ "runs": [
918
+ {
919
+ "target": "t2",
920
+ "op": "migrate",
921
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
922
+ }
923
+ ]
924
+ }
925
+ }
926
+ },
927
+ {
928
+ "argv": [
929
+ "hook",
930
+ "backup",
931
+ ".chant/op-waves/migrations/wave-1/runs.json"
932
+ ],
933
+ "env": {
934
+ "CHANT_OP_WAVES": "migrations",
935
+ "CHANT_WAVE": "prod",
936
+ "CHANT_WAVE_NUMBER": "1",
937
+ "CHANT_HOOK": "before-apply",
938
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
939
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json"
940
+ },
941
+ "read": {
942
+ "CHANT_RUNS": {
943
+ "wave": "prod",
944
+ "number": 1,
945
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
946
+ "runs": [
947
+ {
948
+ "target": "t2",
949
+ "op": "migrate",
950
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
951
+ }
952
+ ]
953
+ },
954
+ ".chant/op-waves/migrations/wave-1/runs.json": {
955
+ "wave": "prod",
956
+ "number": 1,
957
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
958
+ "runs": [
959
+ {
960
+ "target": "t2",
961
+ "op": "migrate",
962
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
963
+ }
964
+ ]
965
+ }
966
+ }
967
+ },
968
+ {
969
+ "argv": [
970
+ "tool",
971
+ "apply",
972
+ "t2",
973
+ ".chant/op-waves/migrations/wave-1/t2.plan.json"
974
+ ],
975
+ "env": {
976
+ "CHANT_HOOKS": ".chant/op-waves/migrations/wave-1/t2.hooks.json",
977
+ "CHANT_APPLY_OUTCOME": ".chant/op-waves/migrations/wave-1/t2.hooks-outcome.json"
978
+ },
979
+ "read": {
980
+ "CHANT_HOOKS": {
981
+ "version": 1,
982
+ "opWaves": "migrations",
983
+ "op": "migrate",
984
+ "wave": "prod",
985
+ "number": 1,
986
+ "base": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
987
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
988
+ "approved": true,
989
+ "heldBy": [
990
+ "after-plan hook check (t2)"
991
+ ],
992
+ "runBy": "chant",
993
+ "runs": [
994
+ {
995
+ "target": "t2",
996
+ "op": "migrate",
997
+ "plan": ".chant/op-waves/migrations/wave-1/t2.plan.json"
998
+ }
999
+ ],
1000
+ "runsFile": ".chant/op-waves/migrations/wave-1/runs.json",
1001
+ "hooks": {},
1002
+ "outcomes": [
1003
+ {
1004
+ "moment": "before-plan",
1005
+ "name": "lint",
1006
+ "exit": 0,
1007
+ "outcome": "passed"
1008
+ },
1009
+ {
1010
+ "moment": "after-plan",
1011
+ "name": "check",
1012
+ "target": "t2",
1013
+ "exit": 1,
1014
+ "outcome": "held"
1015
+ },
1016
+ {
1017
+ "moment": "before-apply",
1018
+ "name": "backup",
1019
+ "exit": 0,
1020
+ "outcome": "passed"
1021
+ }
1022
+ ]
1023
+ }
1024
+ }
1025
+ },
1026
+ {
1027
+ "argv": [
1028
+ "hook",
1029
+ "smoke",
1030
+ "prod"
1031
+ ],
1032
+ "env": {
1033
+ "CHANT_OP_WAVES": "migrations",
1034
+ "CHANT_WAVE": "prod",
1035
+ "CHANT_WAVE_NUMBER": "1",
1036
+ "CHANT_HOOK": "after-apply",
1037
+ "CHANT_RUNS": ".chant/op-waves/migrations/wave-1/runs.json",
1038
+ "CHANT_HOLD": ".chant/op-waves/migrations/wave-1/hold.json"
1039
+ },
1040
+ "read": {
1041
+ "CHANT_RUNS": {
1042
+ "wave": "prod",
1043
+ "number": 1,
1044
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
1045
+ "runs": [
1046
+ {
1047
+ "target": "t2",
1048
+ "op": "migrate",
1049
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
1050
+ }
1051
+ ]
1052
+ }
1053
+ }
1054
+ }
1055
+ ],
1056
+ "logs": [
1057
+ "after-plan hook check (t2) exited 1, so wave 1 (prod) waits for an approval of its set digest",
1058
+ "Nothing in wave 1 or after it ran. Read the plans, then approve: chant approve migrations migrations-wave-1 --plan jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f (with --resume, the approval also starts this job again)",
1059
+ "wave 1 (prod) is waiting on migrations-wave-1; nothing applied. chant approve migrations migrations-wave-1 --plan jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
1060
+ "after-plan hook check (t2) exited 1, so wave 1 (prod) waits for an approval of its set digest",
1061
+ "wave 1 (prod): gate never (read at bbbbbbbbbbbb), digest jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f: approved by alice; held by after-plan hook check (t2)",
1062
+ "after-plan hook check (t2) exited 1, so wave 1 (prod) waits for an approval of its set digest"
1063
+ ],
1064
+ "files": {
1065
+ ".chant/op-waves/migrations/wave-1/runs.json": {
1066
+ "wave": "prod",
1067
+ "number": 1,
1068
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
1069
+ "runs": [
1070
+ {
1071
+ "target": "t2",
1072
+ "op": "migrate",
1073
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
1074
+ }
1075
+ ]
1076
+ },
1077
+ ".chant/op-waves/migrations/wave-1/t1.plan.json": {
1078
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
1079
+ },
1080
+ ".chant/op-waves/migrations/wave-1/t2.hooks.json": {
1081
+ "version": 1,
1082
+ "opWaves": "migrations",
1083
+ "op": "migrate",
1084
+ "wave": "prod",
1085
+ "number": 1,
1086
+ "base": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
1087
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
1088
+ "approved": true,
1089
+ "heldBy": [
1090
+ "after-plan hook check (t2)"
1091
+ ],
1092
+ "runBy": "chant",
1093
+ "runs": [
1094
+ {
1095
+ "target": "t2",
1096
+ "op": "migrate",
1097
+ "plan": ".chant/op-waves/migrations/wave-1/t2.plan.json"
1098
+ }
1099
+ ],
1100
+ "runsFile": ".chant/op-waves/migrations/wave-1/runs.json",
1101
+ "hooks": {},
1102
+ "outcomes": [
1103
+ {
1104
+ "moment": "before-plan",
1105
+ "name": "lint",
1106
+ "exit": 0,
1107
+ "outcome": "passed"
1108
+ },
1109
+ {
1110
+ "moment": "after-plan",
1111
+ "name": "check",
1112
+ "target": "t2",
1113
+ "exit": 1,
1114
+ "outcome": "held"
1115
+ },
1116
+ {
1117
+ "moment": "before-apply",
1118
+ "name": "backup",
1119
+ "exit": 0,
1120
+ "outcome": "passed"
1121
+ }
1122
+ ]
1123
+ },
1124
+ ".chant/op-waves/migrations/wave-1/t2.plan.json": {
1125
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"
1126
+ },
1127
+ ".chant/op-waves/migrations/wave-1.json": {
1128
+ "wave": 1,
1129
+ "name": "prod",
1130
+ "op": "migrations",
1131
+ "gate": "migrations-wave-1",
1132
+ "policy": "never",
1133
+ "approval": "ledger",
1134
+ "policySource": "base",
1135
+ "base": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
1136
+ "digest": "jcs1-sha256:52d1b04601e89971eab0e24094024707e878042be4b79ad476d6230ac5ef383f",
1137
+ "members": [
1138
+ {
1139
+ "member": "t1",
1140
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
1141
+ "op": "migrate"
1142
+ },
1143
+ {
1144
+ "member": "t2",
1145
+ "planDigest": "sha256:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
1146
+ "op": "migrate"
1147
+ }
1148
+ ],
1149
+ "status": "approved",
1150
+ "hooks": {
1151
+ "before-plan": [
1152
+ {
1153
+ "name": "lint",
1154
+ "command": [
1155
+ "hook",
1156
+ "lint",
1157
+ "{runs}"
1158
+ ]
1159
+ }
1160
+ ],
1161
+ "after-plan": [
1162
+ {
1163
+ "name": "check",
1164
+ "command": [
1165
+ "hook",
1166
+ "check",
1167
+ "{target}",
1168
+ "{plan}"
1169
+ ],
1170
+ "perRun": true,
1171
+ "onFailure": "approve"
1172
+ }
1173
+ ],
1174
+ "before-apply": [
1175
+ {
1176
+ "name": "backup",
1177
+ "command": [
1178
+ "hook",
1179
+ "backup",
1180
+ "{runs}"
1181
+ ]
1182
+ }
1183
+ ],
1184
+ "after-apply": [
1185
+ {
1186
+ "name": "smoke",
1187
+ "command": [
1188
+ "hook",
1189
+ "smoke",
1190
+ "{wave}"
1191
+ ]
1192
+ }
1193
+ ]
1194
+ },
1195
+ "heldBy": [
1196
+ "after-plan hook check (t2)"
1197
+ ],
1198
+ "via": "ledger",
1199
+ "approvedBy": "alice",
1200
+ "approvedAt": "2026-10-10T00:00:00Z",
1201
+ "outcomes": [
1202
+ {
1203
+ "moment": "before-plan",
1204
+ "name": "lint",
1205
+ "exit": 0,
1206
+ "outcome": "passed"
1207
+ },
1208
+ {
1209
+ "moment": "after-plan",
1210
+ "name": "check",
1211
+ "target": "t1",
1212
+ "exit": 0,
1213
+ "outcome": "passed"
1214
+ },
1215
+ {
1216
+ "moment": "after-plan",
1217
+ "name": "check",
1218
+ "target": "t2",
1219
+ "exit": 1,
1220
+ "outcome": "held"
1221
+ }
1222
+ ]
1223
+ }
1224
+ }
1225
+ }