@intentius/sql-yodeler 0.1.0 → 0.3.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 (297) hide show
  1. package/README.md +28 -26
  2. package/dist/bin.js +15 -0
  3. package/dist/bin.js.map +1 -1
  4. package/dist/chant/apply.d.ts +9 -1
  5. package/dist/chant/apply.js +13 -1
  6. package/dist/chant/apply.js.map +1 -1
  7. package/dist/chant/build.js +7 -0
  8. package/dist/chant/build.js.map +1 -1
  9. package/dist/chant/drift.d.ts +69 -1
  10. package/dist/chant/drift.js +152 -5
  11. package/dist/chant/drift.js.map +1 -1
  12. package/dist/chant/runnable.d.ts +19 -0
  13. package/dist/chant/runnable.js +47 -0
  14. package/dist/chant/runnable.js.map +1 -0
  15. package/dist/ci/render.d.ts +289 -0
  16. package/dist/ci/render.js +688 -0
  17. package/dist/ci/render.js.map +1 -0
  18. package/dist/ci/replay.d.ts +17 -0
  19. package/dist/ci/replay.js +69 -0
  20. package/dist/ci/replay.js.map +1 -0
  21. package/dist/cli.d.ts +4 -0
  22. package/dist/cli.js +40 -0
  23. package/dist/cli.js.map +1 -1
  24. package/dist/command.d.ts +6 -0
  25. package/dist/command.js.map +1 -1
  26. package/dist/commands/apply.d.ts +113 -0
  27. package/dist/commands/apply.js +376 -49
  28. package/dist/commands/apply.js.map +1 -1
  29. package/dist/commands/approve.d.ts +5 -0
  30. package/dist/commands/approve.js +155 -0
  31. package/dist/commands/approve.js.map +1 -0
  32. package/dist/commands/checkpoint.d.ts +3 -0
  33. package/dist/commands/checkpoint.js +78 -0
  34. package/dist/commands/checkpoint.js.map +1 -0
  35. package/dist/commands/ci.d.ts +3 -0
  36. package/dist/commands/ci.js +118 -0
  37. package/dist/commands/ci.js.map +1 -0
  38. package/dist/commands/docs.d.ts +11 -0
  39. package/dist/commands/docs.js +108 -0
  40. package/dist/commands/docs.js.map +1 -0
  41. package/dist/commands/drift.d.ts +23 -0
  42. package/dist/commands/drift.js +263 -18
  43. package/dist/commands/drift.js.map +1 -1
  44. package/dist/commands/index.js +16 -0
  45. package/dist/commands/index.js.map +1 -1
  46. package/dist/commands/init.d.ts +3 -0
  47. package/dist/commands/init.js +15 -11
  48. package/dist/commands/init.js.map +1 -1
  49. package/dist/commands/lint.js +25 -8
  50. package/dist/commands/lint.js.map +1 -1
  51. package/dist/commands/mcp.d.ts +3 -0
  52. package/dist/commands/mcp.js +50 -0
  53. package/dist/commands/mcp.js.map +1 -0
  54. package/dist/commands/new.d.ts +2 -0
  55. package/dist/commands/new.js +134 -10
  56. package/dist/commands/new.js.map +1 -1
  57. package/dist/commands/override.d.ts +3 -0
  58. package/dist/commands/override.js +150 -0
  59. package/dist/commands/override.js.map +1 -0
  60. package/dist/commands/plan.js +43 -27
  61. package/dist/commands/plan.js.map +1 -1
  62. package/dist/commands/repair.d.ts +11 -0
  63. package/dist/commands/repair.js +15 -7
  64. package/dist/commands/repair.js.map +1 -1
  65. package/dist/commands/report.d.ts +13 -0
  66. package/dist/commands/report.js +121 -0
  67. package/dist/commands/report.js.map +1 -0
  68. package/dist/commands/revert.d.ts +20 -0
  69. package/dist/commands/revert.js +246 -0
  70. package/dist/commands/revert.js.map +1 -0
  71. package/dist/commands/status.js +44 -17
  72. package/dist/commands/status.js.map +1 -1
  73. package/dist/config/base.d.ts +69 -0
  74. package/dist/config/base.js +121 -0
  75. package/dist/config/base.js.map +1 -0
  76. package/dist/config/define.d.ts +223 -3
  77. package/dist/config/define.js +3 -1
  78. package/dist/config/define.js.map +1 -1
  79. package/dist/config/index.d.ts +2 -0
  80. package/dist/config/index.js +2 -0
  81. package/dist/config/index.js.map +1 -1
  82. package/dist/config/load.d.ts +1 -1
  83. package/dist/config/load.js +150 -5
  84. package/dist/config/load.js.map +1 -1
  85. package/dist/config/settings.d.ts +18 -2
  86. package/dist/config/settings.js +40 -6
  87. package/dist/config/settings.js.map +1 -1
  88. package/dist/env-args.d.ts +6 -0
  89. package/dist/env-args.js +31 -1
  90. package/dist/env-args.js.map +1 -1
  91. package/dist/exit.d.ts +20 -0
  92. package/dist/exit.js +28 -0
  93. package/dist/exit.js.map +1 -0
  94. package/dist/history/client.d.ts +8 -0
  95. package/dist/history/client.js +24 -1
  96. package/dist/history/client.js.map +1 -1
  97. package/dist/history/lock.d.ts +5 -1
  98. package/dist/history/lock.js +8 -2
  99. package/dist/history/lock.js.map +1 -1
  100. package/dist/history/postgres/ddl.d.ts +18 -0
  101. package/dist/history/postgres/ddl.js +27 -2
  102. package/dist/history/postgres/ddl.js.map +1 -1
  103. package/dist/history/postgres/store.d.ts +2 -0
  104. package/dist/history/postgres/store.js +7 -1
  105. package/dist/history/postgres/store.js.map +1 -1
  106. package/dist/history/rows.d.ts +16 -3
  107. package/dist/history/rows.js +30 -1
  108. package/dist/history/rows.js.map +1 -1
  109. package/dist/history/store.d.ts +2 -0
  110. package/dist/history/store.js +2 -2
  111. package/dist/history/store.js.map +1 -1
  112. package/dist/index.d.ts +4 -1
  113. package/dist/index.js +1 -0
  114. package/dist/index.js.map +1 -1
  115. package/dist/init/adopt.js +8 -3
  116. package/dist/init/adopt.js.map +1 -1
  117. package/dist/init/live.d.ts +11 -0
  118. package/dist/init/live.js +25 -2
  119. package/dist/init/live.js.map +1 -1
  120. package/dist/lint/check.d.ts +8 -1
  121. package/dist/lint/check.js +38 -4
  122. package/dist/lint/check.js.map +1 -1
  123. package/dist/lint/report.js +1 -1
  124. package/dist/lint/report.js.map +1 -1
  125. package/dist/lint/routines.d.ts +26 -0
  126. package/dist/lint/routines.js +65 -0
  127. package/dist/lint/routines.js.map +1 -0
  128. package/dist/lint/rules.d.ts +16 -4
  129. package/dist/lint/rules.js +9 -4
  130. package/dist/lint/rules.js.map +1 -1
  131. package/dist/mcp/server.d.ts +40 -0
  132. package/dist/mcp/server.js +106 -0
  133. package/dist/mcp/server.js.map +1 -0
  134. package/dist/mcp/tools.d.ts +72 -0
  135. package/dist/mcp/tools.js +178 -0
  136. package/dist/mcp/tools.js.map +1 -0
  137. package/dist/migrations/checkpoint.d.ts +45 -0
  138. package/dist/migrations/checkpoint.js +110 -0
  139. package/dist/migrations/checkpoint.js.map +1 -0
  140. package/dist/migrations/checks.d.ts +28 -0
  141. package/dist/migrations/checks.js +97 -0
  142. package/dist/migrations/checks.js.map +1 -0
  143. package/dist/migrations/create.d.ts +3 -1
  144. package/dist/migrations/create.js +3 -0
  145. package/dist/migrations/create.js.map +1 -1
  146. package/dist/migrations/directory.js +4 -0
  147. package/dist/migrations/directory.js.map +1 -1
  148. package/dist/migrations/document.d.ts +33 -0
  149. package/dist/migrations/document.js +2 -0
  150. package/dist/migrations/document.js.map +1 -1
  151. package/dist/migrations/index.d.ts +3 -0
  152. package/dist/migrations/index.js +3 -0
  153. package/dist/migrations/index.js.map +1 -1
  154. package/dist/migrations/routines.d.ts +31 -0
  155. package/dist/migrations/routines.js +55 -0
  156. package/dist/migrations/routines.js.map +1 -0
  157. package/dist/notify/index.d.ts +124 -0
  158. package/dist/notify/index.js +210 -0
  159. package/dist/notify/index.js.map +1 -0
  160. package/dist/notify/verify.d.ts +53 -0
  161. package/dist/notify/verify.js +71 -0
  162. package/dist/notify/verify.js.map +1 -0
  163. package/dist/pr/forge.d.ts +4 -0
  164. package/dist/pr/forge.js +21 -7
  165. package/dist/pr/forge.js.map +1 -1
  166. package/dist/pr/issue.d.ts +68 -0
  167. package/dist/pr/issue.js +107 -0
  168. package/dist/pr/issue.js.map +1 -0
  169. package/dist/pr/model.d.ts +12 -1
  170. package/dist/pr/model.js +44 -6
  171. package/dist/pr/model.js.map +1 -1
  172. package/dist/pr/render.d.ts +3 -1
  173. package/dist/pr/render.js +63 -4
  174. package/dist/pr/render.js.map +1 -1
  175. package/dist/project.d.ts +19 -2
  176. package/dist/project.js +33 -1
  177. package/dist/project.js.map +1 -1
  178. package/dist/replay/index.d.ts +3 -0
  179. package/dist/replay/index.js +3 -0
  180. package/dist/replay/index.js.map +1 -1
  181. package/dist/replay/replay.d.ts +9 -1
  182. package/dist/replay/replay.js +63 -32
  183. package/dist/replay/replay.js.map +1 -1
  184. package/dist/replay/report.js +1 -1
  185. package/dist/replay/report.js.map +1 -1
  186. package/dist/replay/shared.d.ts +28 -0
  187. package/dist/replay/shared.js +77 -0
  188. package/dist/replay/shared.js.map +1 -0
  189. package/dist/report/audit.d.ts +138 -0
  190. package/dist/report/audit.js +202 -0
  191. package/dist/report/audit.js.map +1 -0
  192. package/dist/report/jsonl.d.ts +21 -0
  193. package/dist/report/jsonl.js +52 -0
  194. package/dist/report/jsonl.js.map +1 -0
  195. package/dist/report/model.d.ts +68 -0
  196. package/dist/report/model.js +127 -0
  197. package/dist/report/model.js.map +1 -0
  198. package/dist/report/render.d.ts +18 -0
  199. package/dist/report/render.js +127 -0
  200. package/dist/report/render.js.map +1 -0
  201. package/dist/schema-docs/render.d.ts +49 -0
  202. package/dist/schema-docs/render.js +359 -0
  203. package/dist/schema-docs/render.js.map +1 -0
  204. package/dist/schemas.d.ts +37 -0
  205. package/dist/schemas.js +41 -0
  206. package/dist/schemas.js.map +1 -0
  207. package/dist/server.d.ts +40 -0
  208. package/dist/server.js +87 -0
  209. package/dist/server.js.map +1 -0
  210. package/dist/sources/ddl.d.ts +53 -0
  211. package/dist/sources/ddl.js +347 -0
  212. package/dist/sources/ddl.js.map +1 -0
  213. package/dist/sources/index.d.ts +69 -0
  214. package/dist/sources/index.js +170 -0
  215. package/dist/sources/index.js.map +1 -0
  216. package/dist/steps/backfill.d.ts +21 -17
  217. package/dist/steps/backfill.js +20 -20
  218. package/dist/steps/backfill.js.map +1 -1
  219. package/dist/steps/index.d.ts +2 -2
  220. package/dist/steps/index.js +3 -3
  221. package/dist/steps/index.js.map +1 -1
  222. package/dist/steps/postgres-migration.d.ts +35 -25
  223. package/dist/steps/postgres-migration.js +42 -29
  224. package/dist/steps/postgres-migration.js.map +1 -1
  225. package/dist/steps/rebuild.d.ts +15 -15
  226. package/dist/steps/rebuild.js +17 -24
  227. package/dist/steps/rebuild.js.map +1 -1
  228. package/dist/tenants/index.d.ts +40 -0
  229. package/dist/tenants/index.js +122 -0
  230. package/dist/tenants/index.js.map +1 -0
  231. package/dist/tenants/target.d.ts +23 -0
  232. package/dist/tenants/target.js +29 -0
  233. package/dist/tenants/target.js.map +1 -0
  234. package/dist/versioned/checks.d.ts +29 -0
  235. package/dist/versioned/checks.js +54 -0
  236. package/dist/versioned/checks.js.map +1 -0
  237. package/dist/versioned/clickhouse.js +8 -0
  238. package/dist/versioned/clickhouse.js.map +1 -1
  239. package/dist/versioned/driver.d.ts +10 -0
  240. package/dist/versioned/engine.d.ts +61 -1
  241. package/dist/versioned/engine.js +109 -6
  242. package/dist/versioned/engine.js.map +1 -1
  243. package/dist/versioned/explain.js +7 -2
  244. package/dist/versioned/explain.js.map +1 -1
  245. package/dist/versioned/index.d.ts +10 -0
  246. package/dist/versioned/index.js +25 -1
  247. package/dist/versioned/index.js.map +1 -1
  248. package/dist/versioned/op.d.ts +16 -1
  249. package/dist/versioned/op.js +43 -6
  250. package/dist/versioned/op.js.map +1 -1
  251. package/dist/versioned/policy.d.ts +98 -0
  252. package/dist/versioned/policy.js +212 -0
  253. package/dist/versioned/policy.js.map +1 -0
  254. package/dist/versioned/postgres/driver.d.ts +3 -1
  255. package/dist/versioned/postgres/driver.js +30 -3
  256. package/dist/versioned/postgres/driver.js.map +1 -1
  257. package/dist/versioned/postgres/waits.d.ts +46 -0
  258. package/dist/versioned/postgres/waits.js +78 -0
  259. package/dist/versioned/postgres/waits.js.map +1 -0
  260. package/dist/versioned/report.d.ts +3 -0
  261. package/dist/versioned/report.js +13 -1
  262. package/dist/versioned/report.js.map +1 -1
  263. package/dist/versioned/revert.d.ts +128 -0
  264. package/dist/versioned/revert.js +251 -0
  265. package/dist/versioned/revert.js.map +1 -0
  266. package/dist/versioned/stand-down.d.ts +30 -0
  267. package/dist/versioned/stand-down.js +56 -0
  268. package/dist/versioned/stand-down.js.map +1 -0
  269. package/dist/versioned/state.d.ts +25 -0
  270. package/dist/versioned/state.js +36 -3
  271. package/dist/versioned/state.js.map +1 -1
  272. package/dist/waves/index.d.ts +179 -0
  273. package/dist/waves/index.js +268 -0
  274. package/dist/waves/index.js.map +1 -0
  275. package/dist/waves/promotion.d.ts +56 -0
  276. package/dist/waves/promotion.js +108 -0
  277. package/dist/waves/promotion.js.map +1 -0
  278. package/dist/waves/record.d.ts +24 -0
  279. package/dist/waves/record.js +20 -0
  280. package/dist/waves/record.js.map +1 -0
  281. package/package.json +22 -8
  282. package/schemas/apply.schema.json +428 -0
  283. package/schemas/checkpoint.schema.json +19 -0
  284. package/schemas/common.schema.json +213 -0
  285. package/schemas/drift.schema.json +61 -0
  286. package/schemas/event.schema.json +36 -0
  287. package/schemas/init.schema.json +31 -0
  288. package/schemas/lint-rules.schema.json +54 -0
  289. package/schemas/lint.schema.json +294 -0
  290. package/schemas/mcp.schema.json +70 -0
  291. package/schemas/new.schema.json +71 -0
  292. package/schemas/plan.schema.json +489 -0
  293. package/schemas/rebase.schema.json +54 -0
  294. package/schemas/repair.schema.json +20 -0
  295. package/schemas/report.schema.json +114 -0
  296. package/schemas/revert.schema.json +69 -0
  297. package/schemas/status.schema.json +371 -0
@@ -22,6 +22,12 @@
22
22
  * replayed: the check stops there, naming it ({@link ReplayResult} outcome
23
23
  * `unreplayable`).
24
24
  *
25
+ * A checkpoint (#63) is left out of the chain: it creates its parent's
26
+ * recorded schema from nothing. After the chain, each checkpoint is
27
+ * replayed on its own into the database emptied again, and compared with
28
+ * its recorded schema, the one the chain was shown to give. So a fresh
29
+ * environment that starts from it ends where one that ran the chain does.
30
+ *
25
31
  * The database is the replay's: it must be fresh when the replay starts
26
32
  * (every database or schema the history names absent, the default one
27
33
  * empty), or emptied first when the caller says so (`reset`), and it is
@@ -29,6 +35,7 @@
29
35
  * table; no lock is taken.
30
36
  */
31
37
  import { YodelError } from "../project.js";
38
+ import { isCheckpoint } from "../migrations/index.js";
32
39
  import { asBackfill, describeStep, planStep } from "../steps/kinds.js";
33
40
  /** Exit code: the target is not fresh and `reset` was not given; nothing was run. */
34
41
  export const NOT_FRESH = 4;
@@ -46,48 +53,72 @@ export async function replayMigrations(ordered, driver, options = {}) {
46
53
  if (occupied.length > 0) {
47
54
  if (options.reset !== true) {
48
55
  throw new YodelError(`refused: the replay needs a fresh database, and ${driver.where} already holds ${occupied.join(", ")}. ` +
49
- `Point the replay at a throwaway emulator (chant emulator up --lexicon sql), or pass reset to drop ${occupied.length === 1 ? "it" : "them"} first. Nothing was run.`, NOT_FRESH);
56
+ `Point the replay at a throwaway emulator (chant emulator up --lexicon sql), or pass --reset to drop ${occupied.length === 1 ? "it" : "them"} first. Nothing was run.`, NOT_FRESH);
50
57
  }
51
58
  log(`emptying ${occupied.join(", ")} on ${driver.where}`);
52
59
  await driver.clear();
53
60
  }
54
61
  const matched = [];
55
- try {
56
- for (const m of ordered) {
57
- const done = { id: m.id, statements: 0, ran: [], skipped: [] };
58
- log(`${m.id}: replaying`);
59
- for (const [i, step] of m.document.steps.entries()) {
60
- const s = step;
61
- if (s.kind === "statement") {
62
- try {
63
- await driver.statement(m, i, s);
64
- }
65
- catch (e) {
66
- return { ...base, reset: occupied.length > 0, matched, outcome: "failed", migration: m.id, step: i, error: firstLine(message(e)) };
67
- }
68
- done.statements++;
69
- continue;
62
+ const reset = occupied.length > 0;
63
+ /** Replays one migration's steps on what the database holds now, then compares; a failure, or the migration replayed. */
64
+ const replayOne = async (m) => {
65
+ const done = { id: m.id, statements: 0, ran: [], skipped: [], ...(isCheckpoint(m) ? { checkpoint: true } : {}) };
66
+ log(`${m.id}: replaying${isCheckpoint(m) ? " (a checkpoint, into an empty database)" : ""}`);
67
+ for (const [i, step] of m.document.steps.entries()) {
68
+ const s = step;
69
+ if (s.kind === "statement") {
70
+ try {
71
+ await driver.statement(m, i, s);
70
72
  }
71
- if (asBackfill(s)) {
72
- done.skipped.push(`step ${String(i)}: ${describeStep(s)} (moves data; the replayed database has none)`);
73
- continue;
73
+ catch (e) {
74
+ return { ...base, reset, matched, outcome: "failed", migration: m.id, step: i, error: firstLine(message(e)) };
74
75
  }
75
- const plan = planStep(s);
76
- const outcome = plan.run === "refused" ? { refused: plan.reason } : await driver.opStep(m, i);
77
- if ("refused" in outcome) {
78
- return { ...base, reset: occupied.length > 0, matched, outcome: "unreplayable", migration: m.id, step: i, reason: outcome.refused };
79
- }
80
- done.ran.push(`step ${String(i)}: ${describeStep(s)}${outcome.note ? ` (${outcome.note})` : ""}`);
76
+ done.statements++;
77
+ continue;
78
+ }
79
+ if (asBackfill(s)) {
80
+ done.skipped.push(`step ${String(i)}: ${describeStep(s)} (moves data; the replayed database has none)`);
81
+ continue;
81
82
  }
82
- const changes = await driver.compare(m);
83
- if (changes.length > 0) {
84
- log(`${m.id}: differs from its recorded schema (${String(changes.length)} difference${changes.length === 1 ? "" : "s"})`);
85
- return { ...base, reset: occupied.length > 0, matched, outcome: "differs", migration: done, changes };
83
+ const plan = planStep(s);
84
+ const outcome = plan.run === "refused" ? { refused: plan.reason } : await driver.opStep(m, i);
85
+ if ("refused" in outcome) {
86
+ return { ...base, reset, matched, outcome: "unreplayable", migration: m.id, step: i, reason: outcome.refused };
86
87
  }
87
- log(`${m.id}: matches its recorded schema`);
88
- matched.push(done);
88
+ done.ran.push(`step ${String(i)}: ${describeStep(s)}${outcome.note ? ` (${outcome.note})` : ""}`);
89
+ }
90
+ const changes = await driver.compare(m);
91
+ if (changes.length > 0) {
92
+ log(`${m.id}: differs from its recorded schema (${String(changes.length)} difference${changes.length === 1 ? "" : "s"})`);
93
+ return { ...base, reset, matched, outcome: "differs", migration: done, changes };
94
+ }
95
+ log(`${m.id}: matches its recorded schema`);
96
+ return done;
97
+ };
98
+ const failed = (r) => "outcome" in r;
99
+ try {
100
+ // The chain, first to newest. A checkpoint (#63) creates its parent's schema from nothing, so on top of the chain it would only fail: it is replayed on its own below.
101
+ const checkpoints = [];
102
+ for (const m of ordered) {
103
+ if (isCheckpoint(m)) {
104
+ checkpoints.push(m);
105
+ log(`${m.id}: a checkpoint; replayed on its own, into an empty database, after the chain`);
106
+ continue;
107
+ }
108
+ const r = await replayOne(m);
109
+ if (failed(r))
110
+ return r;
111
+ matched.push(r);
112
+ }
113
+ // Each checkpoint into an empty database: its statements must give its recorded schema, its parent's, which the chain was just shown to give.
114
+ for (const m of checkpoints) {
115
+ await driver.clear();
116
+ const r = await replayOne(m);
117
+ if (failed(r))
118
+ return r;
119
+ matched.push(r);
89
120
  }
90
- return { ...base, reset: occupied.length > 0, matched, outcome: "matches" };
121
+ return { ...base, reset, matched, outcome: "matches" };
91
122
  }
92
123
  finally {
93
124
  // Emptying afterwards is housekeeping: its failure is reported, never put in place of the result.
@@ -1 +1 @@
1
- {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/replay/replay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/replay/replay.ts"],"names":[],"mappings":"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"}
@@ -54,7 +54,7 @@ export function renderReplay(result) {
54
54
  lines.push(` ${result.dialect === "postgres" ? "schemas" : "databases"}: ${result.scope.join(", ")}${result.reset ? " (emptied first)" : ""}${result.kept ? " (left in place)" : ""}`);
55
55
  for (const m of result.matched) {
56
56
  const extra = [...m.ran.map((r) => `ran ${r}`), ...m.skipped.map((s) => `skipped ${s}`)];
57
- lines.push(` ok ${m.id} (${String(m.statements)} statement${m.statements === 1 ? "" : "s"}${extra.length > 0 ? `; ${extra.join("; ")}` : ""})`);
57
+ lines.push(` ok ${m.id} (${String(m.statements)} statement${m.statements === 1 ? "" : "s"}${m.checkpoint ? ", a checkpoint, from an empty database" : ""}${extra.length > 0 ? `; ${extra.join("; ")}` : ""})`);
58
58
  }
59
59
  const failure = replayFailure(result);
60
60
  if (!failure) {
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/replay/report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/replay/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The replay empties every database (ClickHouse) or schema (Postgres) the
3
+ * history names on the server its profile binds. When another profile binds
4
+ * the same server and names one of those too (locally, `dev` and `replay`
5
+ * both on the emulator at 127.0.0.1), the replay would drop that profile's
6
+ * database: the one just applied to. So it refuses, naming the profile,
7
+ * even with `--reset`, unless that profile is named with
8
+ * `--reset-shared <profile>` (#12).
9
+ *
10
+ * Only profiles that resolve are compared: one whose credentials are not set
11
+ * in this shell (a CI job that holds only the replay server's) binds no
12
+ * server here, and the replay cannot reach its data through it.
13
+ */
14
+ import { type Environment, type Project } from "../project.js";
15
+ /** Another profile the replay would empty part of. */
16
+ export interface SharedProfile {
17
+ profile: string;
18
+ /** `host:port` (ClickHouse) or `host:port/database` (Postgres). */
19
+ server: string;
20
+ /** The databases or schemas both name. */
21
+ names: string[];
22
+ }
23
+ /** A server URL as a comparable key: loopback names folded together, the default port filled in, no credentials. */
24
+ export declare function serverKey(dialect: Project["dialect"], url: string): string;
25
+ /** The other profiles on `env`'s server that name one of `scope`, the databases or schemas the replay empties. */
26
+ export declare function sharedProfiles(project: Project, env: Environment, scope: readonly string[], processEnv?: NodeJS.ProcessEnv): Promise<SharedProfile[]>;
27
+ /** Refuses a replay that would empty another profile's databases, unless each such profile is named in `allowed`. */
28
+ export declare function refuseShared(env: Environment, shared: readonly SharedProfile[], allowed: readonly string[], dialect: Project["dialect"]): void;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The replay empties every database (ClickHouse) or schema (Postgres) the
3
+ * history names on the server its profile binds. When another profile binds
4
+ * the same server and names one of those too (locally, `dev` and `replay`
5
+ * both on the emulator at 127.0.0.1), the replay would drop that profile's
6
+ * database: the one just applied to. So it refuses, naming the profile,
7
+ * even with `--reset`, unless that profile is named with
8
+ * `--reset-shared <profile>` (#12).
9
+ *
10
+ * Only profiles that resolve are compared: one whose credentials are not set
11
+ * in this shell (a CI job that holds only the replay server's) binds no
12
+ * server here, and the replay cannot reach its data through it.
13
+ */
14
+ import { YodelError } from "../project.js";
15
+ import { environmentSettings } from "../config/settings.js";
16
+ import { NOT_FRESH } from "./replay.js";
17
+ const LOOPBACK = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
18
+ /** A server URL as a comparable key: loopback names folded together, the default port filled in, no credentials. */
19
+ export function serverKey(dialect, url) {
20
+ let u;
21
+ try {
22
+ u = new URL(url);
23
+ }
24
+ catch {
25
+ return url;
26
+ }
27
+ const host = LOOPBACK.has(u.hostname) ? "127.0.0.1" : u.hostname.toLowerCase();
28
+ if (dialect === "postgres")
29
+ return `${host}:${u.port || "5432"}/${decodeURIComponent(u.pathname.replace(/^\/+/, "")) || "postgres"}`;
30
+ return `${host}:${u.port || (u.protocol === "https:" ? "8443" : "8123")}`;
31
+ }
32
+ async function bind(project, name, processEnv) {
33
+ if (project.dialect === "postgres") {
34
+ const { resolvePostgresTarget, isUnresolvedTarget } = await import("@intentius/chant-lexicon-sql/postgres/live/bind");
35
+ const t = resolvePostgresTarget({ environment: name, config: project.config, env: processEnv });
36
+ if (isUnresolvedTarget(t) || !t.source.startsWith("sql.profiles."))
37
+ return undefined;
38
+ return { key: serverKey("postgres", t.endpoint.url), names: t.schemas };
39
+ }
40
+ const { resolveClickHouseTarget, isUnresolvedTarget } = await import("@intentius/chant-lexicon-sql/clickhouse/live/bind");
41
+ const t = resolveClickHouseTarget({ environment: name, config: project.config, env: processEnv });
42
+ if (isUnresolvedTarget(t) || !t.source.startsWith("sql.profiles."))
43
+ return undefined;
44
+ return { key: serverKey("clickhouse", t.endpoint.url), names: t.databases };
45
+ }
46
+ /** The other profiles on `env`'s server that name one of `scope`, the databases or schemas the replay empties. */
47
+ export async function sharedProfiles(project, env, scope, processEnv = process.env) {
48
+ const profiles = Object.keys(project.config.sql?.profiles ?? {});
49
+ const own = await bind(project, env.name, processEnv);
50
+ if (!own)
51
+ return [];
52
+ const shared = [];
53
+ for (const other of profiles) {
54
+ if (other === env.name)
55
+ continue;
56
+ const b = await bind(project, other, processEnv).catch(() => undefined);
57
+ if (!b || b.key !== own.key)
58
+ continue;
59
+ const history = environmentSettings(project, other, processEnv).historyDatabase;
60
+ const theirs = b.names === undefined ? undefined : new Set([...b.names, history]);
61
+ const names = scope.filter((s) => theirs === undefined || theirs.has(s));
62
+ if (names.length > 0)
63
+ shared.push({ profile: other, server: own.key, names });
64
+ }
65
+ return shared;
66
+ }
67
+ /** Refuses a replay that would empty another profile's databases, unless each such profile is named in `allowed`. */
68
+ export function refuseShared(env, shared, allowed, dialect) {
69
+ const blocking = shared.filter((s) => !allowed.includes(s.profile));
70
+ if (blocking.length === 0)
71
+ return;
72
+ const what = dialect === "postgres" ? "schema" : "database";
73
+ const lines = blocking.map((s) => `${env.name} and ${s.profile} are the same server (${s.server}) and both name ${s.names.join(", ")}; the replay would drop ${s.profile}'s ${what}${s.names.length === 1 ? "" : "s"}, with or without --reset`);
74
+ throw new YodelError(`refused: ${lines.join("; ")}. Point ${env.name} at a throwaway server of its own (a second emulator on another port), ` +
75
+ `or, to empty ${blocking.map((s) => s.profile).join(" and ")} too, add ${blocking.map((s) => `--reset-shared ${s.profile}`).join(" ")}. Nothing was run.`, NOT_FRESH);
76
+ }
77
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/replay/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * The audit log (#57), derived and never written by hand: every entry comes
3
+ * from a row of an environment's history table or a line of chant's gate
4
+ * ledger (`_gates/<op>.jsonl` on the `chant/lifecycle` branch), so the log
5
+ * cannot say something those two do not. Pure: rows and ledger lines in,
6
+ * entries and gaps out.
7
+ *
8
+ * Entries, by where they come from:
9
+ *
10
+ * | kind | source |
11
+ * |----------------------|---------------------------------------------------------------|
12
+ * | `approval-requested` | a pending fact on the ledger: a run stopped at the gate |
13
+ * | `approved` | a resolution of the migrations Op's gate |
14
+ * | `override` | a resolution of an `override-<rule>` gate (`yodel override`) |
15
+ * | `silenced` | a `-- yodel:allow` silence on a migration's first started row |
16
+ * | `applied` | the migration row that first recorded a migration succeeded |
17
+ * | `refused` | a failed migration row naming a pre-migration check |
18
+ * | `failed` | any other failed migration row |
19
+ * | `repaired` | a succeeded migration row after it was applied (`yodel repair`) |
20
+ *
21
+ * Each entry's `id` is a hash of what it says and where it came from, so
22
+ * deriving again from the same sources gives the same ids, and an audit.jsonl
23
+ * written earlier can be checked against the sources now (`./jsonl.ts`).
24
+ *
25
+ * Gaps are what the sources show is missing from themselves:
26
+ *
27
+ * - `history-row`: the history's seqs run from 1 with no hole (every run
28
+ * appends at the highest seq plus one, under the lock); a hole is a row
29
+ * that was deleted.
30
+ * - `approval`: a migration applied under a plan digest that the ledger
31
+ * holds no approval of the environment's gate for. A baseline (`yodel init
32
+ * --from`, no digest) needs none. A migration a wave of the apply pipeline
33
+ * applied (#87) was approved on the wave's gate (`<op>-wave-<k>`), for the
34
+ * wave's set digest its `started` row records (`note.wave`); a wave whose
35
+ * policy at the base needed no approval records that instead, and needs
36
+ * none.
37
+ */
38
+ import type { HistoryRow } from "../history/index.js";
39
+ export declare const AUDIT_KINDS: readonly ["approval-requested", "approved", "override", "silenced", "applied", "refused", "failed", "repaired", "reverted"];
40
+ export type AuditKind = (typeof AUDIT_KINDS)[number];
41
+ export type AuditSource = {
42
+ ledger: string;
43
+ op: string;
44
+ gate: string;
45
+ } | {
46
+ history: string;
47
+ seq: number;
48
+ run: string;
49
+ };
50
+ export interface AuditEntry {
51
+ /** A hash of everything below: the same sources always give the same id. */
52
+ id: string;
53
+ /** When it happened, ISO 8601 UTC: the ledger line's timestamp, or the history row's `recorded_at`. */
54
+ at: string;
55
+ environment: string;
56
+ kind: AuditKind;
57
+ /** Who: the approver, or who ran the apply. */
58
+ by?: string;
59
+ migration?: string;
60
+ /** The plan digest it is about. */
61
+ digest?: string;
62
+ /** The silence, the override's rule and reason, the error, the repair's reason. */
63
+ detail?: string;
64
+ /** `applied` by a wave of the apply pipeline: the wave's gate, its set digest, and whether it was approved or needed no approval. */
65
+ wave?: {
66
+ gate: string;
67
+ digest: string;
68
+ status: "approved" | "not-required";
69
+ };
70
+ source: AuditSource;
71
+ }
72
+ export interface AuditGap {
73
+ environment: string;
74
+ kind: "history-row" | "approval";
75
+ detail: string;
76
+ }
77
+ /** One environment's ledger, as chant's GateLedgerPort reads it. */
78
+ export interface LedgerInput {
79
+ op: string;
80
+ gate: string;
81
+ /** Where the lines are, for the entries' source: `_gates/<op>.jsonl`. */
82
+ path: string;
83
+ pending: ReadonlyArray<{
84
+ gate: string;
85
+ timestamp: string;
86
+ planDigest?: string | undefined;
87
+ runId?: string | undefined;
88
+ }>;
89
+ resolutions: ReadonlyArray<{
90
+ gate: string;
91
+ timestamp: string;
92
+ resolvedBy: string;
93
+ planDigest?: string | undefined;
94
+ note?: string | undefined;
95
+ }>;
96
+ }
97
+ /** The apply pipeline's wave gates on the ledger (`_gates/<op>.jsonl` of the waves' op): their pending lines and resolutions. */
98
+ export interface WaveLedgerInput {
99
+ op: string;
100
+ path: string;
101
+ /** The wave gate yodel.config.ts gives the environment now, if any; the gates its history's waves recorded are read too. */
102
+ gate?: string | undefined;
103
+ pending: LedgerInput["pending"];
104
+ resolutions: LedgerInput["resolutions"];
105
+ }
106
+ export interface AuditInput {
107
+ environment: string;
108
+ /** `<database>.history`, for the entries' source. */
109
+ history: string;
110
+ rows: readonly HistoryRow[];
111
+ /** Absent when the environment has no migrations Op to read the ledger of. */
112
+ ledger?: LedgerInput | undefined;
113
+ /** The waves' gate ledger, when the project's apply pipeline runs waves. */
114
+ waves?: WaveLedgerInput | undefined;
115
+ /** Whether two digests are the same plan (chant's samePlanDigest). Default: equal strings. */
116
+ sameDigest?: (a: string | undefined, b: string | undefined) => boolean;
117
+ }
118
+ /** `2026-10-10 09:12:44.123456` (the history's UTC) as ISO 8601. An ISO time is returned as it is. */
119
+ export declare function isoTime(t: string): string;
120
+ /** A key that orders ISO times written to the millisecond (the ledger) and the microsecond (the history) together. */
121
+ export declare function timeKey(t: string): string;
122
+ /** Oldest first. */
123
+ export declare const byTime: (a: {
124
+ at: string;
125
+ }, b: {
126
+ at: string;
127
+ }) => number;
128
+ /**
129
+ * The approval an `applied` entry was let through by, among `entries`: on
130
+ * the wave's gate for the wave's set digest when a wave applied it, else
131
+ * on the migrations gate for its plan digest. Undefined when none is there.
132
+ */
133
+ export declare function approvalOf(applied: AuditEntry, entries: readonly AuditEntry[], same?: (a: string | undefined, b: string | undefined) => boolean): AuditEntry | undefined;
134
+ /** The entries one environment's history and ledger add up to, oldest first, and the gaps they show. */
135
+ export declare function deriveAudit(input: AuditInput): {
136
+ entries: AuditEntry[];
137
+ gaps: AuditGap[];
138
+ };
@@ -0,0 +1,202 @@
1
+ /**
2
+ * The audit log (#57), derived and never written by hand: every entry comes
3
+ * from a row of an environment's history table or a line of chant's gate
4
+ * ledger (`_gates/<op>.jsonl` on the `chant/lifecycle` branch), so the log
5
+ * cannot say something those two do not. Pure: rows and ledger lines in,
6
+ * entries and gaps out.
7
+ *
8
+ * Entries, by where they come from:
9
+ *
10
+ * | kind | source |
11
+ * |----------------------|---------------------------------------------------------------|
12
+ * | `approval-requested` | a pending fact on the ledger: a run stopped at the gate |
13
+ * | `approved` | a resolution of the migrations Op's gate |
14
+ * | `override` | a resolution of an `override-<rule>` gate (`yodel override`) |
15
+ * | `silenced` | a `-- yodel:allow` silence on a migration's first started row |
16
+ * | `applied` | the migration row that first recorded a migration succeeded |
17
+ * | `refused` | a failed migration row naming a pre-migration check |
18
+ * | `failed` | any other failed migration row |
19
+ * | `repaired` | a succeeded migration row after it was applied (`yodel repair`) |
20
+ *
21
+ * Each entry's `id` is a hash of what it says and where it came from, so
22
+ * deriving again from the same sources gives the same ids, and an audit.jsonl
23
+ * written earlier can be checked against the sources now (`./jsonl.ts`).
24
+ *
25
+ * Gaps are what the sources show is missing from themselves:
26
+ *
27
+ * - `history-row`: the history's seqs run from 1 with no hole (every run
28
+ * appends at the highest seq plus one, under the lock); a hole is a row
29
+ * that was deleted.
30
+ * - `approval`: a migration applied under a plan digest that the ledger
31
+ * holds no approval of the environment's gate for. A baseline (`yodel init
32
+ * --from`, no digest) needs none. A migration a wave of the apply pipeline
33
+ * applied (#87) was approved on the wave's gate (`<op>-wave-<k>`), for the
34
+ * wave's set digest its `started` row records (`note.wave`); a wave whose
35
+ * policy at the base needed no approval records that instead, and needs
36
+ * none.
37
+ */
38
+ import { createHash } from "node:crypto";
39
+ import { waveRecordOf } from "../waves/record.js";
40
+ export const AUDIT_KINDS = ["approval-requested", "approved", "override", "silenced", "applied", "refused", "failed", "repaired", "reverted"];
41
+ /** `2026-10-10 09:12:44.123456` (the history's UTC) as ISO 8601. An ISO time is returned as it is. */
42
+ export function isoTime(t) {
43
+ if (!t)
44
+ return "";
45
+ if (/T.*(Z|[+-]\d\d:?\d\d)$/.test(t))
46
+ return t;
47
+ return `${t.replace(" ", "T")}Z`;
48
+ }
49
+ /** A key that orders ISO times written to the millisecond (the ledger) and the microsecond (the history) together. */
50
+ export function timeKey(t) {
51
+ const m = /^(.*?)(?:\.(\d+))?Z$/.exec(t);
52
+ return m ? `${m[1] ?? ""}.${(m[2] ?? "").padEnd(6, "0")}Z` : t;
53
+ }
54
+ /** Oldest first. */
55
+ export const byTime = (a, b) => {
56
+ const x = timeKey(a.at);
57
+ const y = timeKey(b.at);
58
+ return x < y ? -1 : x > y ? 1 : 0;
59
+ };
60
+ function entry(fields) {
61
+ // An entry with no wave hashes as it did before waves were recorded, so audit files written then still match.
62
+ const key = JSON.stringify([fields.environment, fields.kind, fields.at, fields.by ?? "", fields.migration ?? "", fields.digest ?? "", fields.detail ?? "", fields.source, ...(fields.wave ? [fields.wave] : [])]);
63
+ return { id: `sha256:${createHash("sha256").update(key).digest("hex").slice(0, 24)}`, ...fields };
64
+ }
65
+ const CHECK_FAILED = /\bcheck \S+ failed\b/;
66
+ function fromHistory(input) {
67
+ const { environment, history } = input;
68
+ const out = [];
69
+ const applied = new Set();
70
+ const silenced = new Set();
71
+ /** Each migration's wave, from its latest started row. */
72
+ const waveOf = new Map();
73
+ for (const r of [...input.rows].sort((a, b) => a.seq - b.seq)) {
74
+ if (r.kind !== "migration")
75
+ continue;
76
+ const source = { history, seq: r.seq, run: r.run_id };
77
+ const base = { at: isoTime(r.recorded_at ?? ""), environment, by: r.applied_by, migration: r.migration_id, ...(r.plan_digest ? { digest: r.plan_digest } : {}), source };
78
+ if (r.status === "started") {
79
+ const w = waveRecordOf(r.note);
80
+ if (w)
81
+ waveOf.set(r.migration_id, { gate: w.gate, digest: w.digest, status: w.status });
82
+ else
83
+ waveOf.delete(r.migration_id);
84
+ let list = [];
85
+ try {
86
+ list = JSON.parse(r.silences || "[]");
87
+ }
88
+ catch {
89
+ list = [];
90
+ }
91
+ for (const s of list) {
92
+ const key = `${r.migration_id}\u0000${String(s.step)}\u0000${s.rule ?? ""}\u0000${s.reason ?? ""}`;
93
+ if (silenced.has(key))
94
+ continue;
95
+ silenced.add(key);
96
+ out.push(entry({ ...base, kind: "silenced", detail: `step ${String(s.step)}: ${s.rule ?? ""} ${s.reason ?? ""}`.trim() }));
97
+ }
98
+ }
99
+ else if (r.status === "reverted") {
100
+ // yodel revert (#55): applied again later, it is applied, not repaired.
101
+ applied.delete(r.migration_id);
102
+ out.push(entry({ ...base, kind: "reverted", ...(r.note ? { detail: r.note } : {}) }));
103
+ }
104
+ else if (r.status === "succeeded") {
105
+ if (applied.has(r.migration_id))
106
+ out.push(entry({ ...base, kind: "repaired", detail: r.note || `checksum ${r.checksum}` }));
107
+ else {
108
+ applied.add(r.migration_id);
109
+ const wave = waveOf.get(r.migration_id);
110
+ out.push(entry({ ...base, kind: "applied", ...(r.note ? { detail: r.note } : {}), ...(wave ? { wave } : {}) }));
111
+ }
112
+ }
113
+ else {
114
+ out.push(entry({ ...base, kind: CHECK_FAILED.test(r.error) ? "refused" : "failed", detail: r.error }));
115
+ }
116
+ }
117
+ return out;
118
+ }
119
+ function fromLedger(environment, l) {
120
+ const out = [];
121
+ const source = { ledger: l.path, op: l.op, gate: l.gate };
122
+ for (const p of l.pending) {
123
+ if (p.gate !== l.gate)
124
+ continue;
125
+ out.push(entry({ at: p.timestamp, environment, kind: "approval-requested", ...(p.planDigest ? { digest: p.planDigest } : {}), ...(p.runId ? { detail: `run ${p.runId}` } : {}), source }));
126
+ }
127
+ for (const r of l.resolutions) {
128
+ const override = r.gate.startsWith("override-");
129
+ if (!override && r.gate !== l.gate)
130
+ continue;
131
+ out.push(entry({
132
+ at: r.timestamp,
133
+ environment,
134
+ kind: override ? "override" : "approved",
135
+ by: r.resolvedBy,
136
+ ...(r.planDigest ? { digest: r.planDigest } : {}),
137
+ ...(override ? { detail: `${r.gate.slice("override-".length)}: ${r.note ?? ""}`.trim() } : r.note ? { detail: r.note } : {}),
138
+ source: { ...source, gate: r.gate },
139
+ }));
140
+ }
141
+ return out;
142
+ }
143
+ /** The wave gates' lines that are this environment's: its configured wave gate, and every gate its history's waves recorded. */
144
+ function fromWaves(environment, w, history) {
145
+ const gates = new Set([...(w.gate ? [w.gate] : []), ...history.flatMap((e) => (e.wave ? [e.wave.gate] : []))]);
146
+ const out = [];
147
+ for (const gate of gates)
148
+ out.push(...fromLedger(environment, { op: w.op, gate, path: w.path, pending: w.pending, resolutions: w.resolutions.filter((r) => !r.gate.startsWith("override-")) }));
149
+ return out;
150
+ }
151
+ /**
152
+ * The approval an `applied` entry was let through by, among `entries`: on
153
+ * the wave's gate for the wave's set digest when a wave applied it, else
154
+ * on the migrations gate for its plan digest. Undefined when none is there.
155
+ */
156
+ export function approvalOf(applied, entries, same = (a, b) => a === b) {
157
+ const approvals = entries.filter((e) => e.kind === "approved" && e.environment === applied.environment);
158
+ const wave = applied.wave;
159
+ if (wave)
160
+ return approvals.filter((x) => "ledger" in x.source && x.source.gate === wave.gate && same(x.digest, wave.digest)).at(-1);
161
+ return approvals.filter((x) => same(x.digest, applied.digest)).at(-1);
162
+ }
163
+ /** The entries one environment's history and ledger add up to, oldest first, and the gaps they show. */
164
+ export function deriveAudit(input) {
165
+ const same = input.sameDigest ?? ((a, b) => a === b);
166
+ const history = fromHistory(input);
167
+ const entries = [...history, ...(input.ledger ? fromLedger(input.environment, input.ledger) : []), ...(input.waves ? fromWaves(input.environment, input.waves, history) : [])].sort(byTime);
168
+ const gaps = [];
169
+ const seqs = new Set(input.rows.map((r) => r.seq));
170
+ const max = Math.max(0, ...seqs);
171
+ const missing = [];
172
+ for (let s = 1; s <= max; s++)
173
+ if (!seqs.has(s))
174
+ missing.push(s);
175
+ if (missing.length > 0) {
176
+ gaps.push({ environment: input.environment, kind: "history-row", detail: `${input.history} has no row with seq ${missing.join(", ")} of 1..${String(max)}: rows are only ever appended, so ${missing.length === 1 ? "that row was" : "those rows were"} deleted` });
177
+ }
178
+ for (const a of entries.filter((e) => (e.kind === "applied" || e.kind === "reverted") && e.digest)) {
179
+ const seq = "history" in a.source ? a.source.seq : 0;
180
+ const wave = a.wave;
181
+ if (wave) {
182
+ // A wave's policy at the base let it through with no approval; the run checked that under the lock.
183
+ if (wave.status === "not-required" || !input.waves || approvalOf(a, entries, same))
184
+ continue;
185
+ gaps.push({
186
+ environment: input.environment,
187
+ kind: "approval",
188
+ detail: `${String(a.migration)} was applied by a wave under ${wave.digest} (${input.history} seq ${String(seq)}), but ${input.waves.path} holds no approval of ${input.waves.op} / ${wave.gate} for that digest`,
189
+ });
190
+ continue;
191
+ }
192
+ if (!input.ledger || approvalOf(a, entries, same))
193
+ continue;
194
+ gaps.push({
195
+ environment: input.environment,
196
+ kind: "approval",
197
+ detail: `${String(a.migration)} was ${a.kind} under ${String(a.digest)} (${input.history} seq ${String(seq)}), but ${input.ledger.path} holds no approval of ${input.ledger.op} / ${input.ledger.gate} for that digest`,
198
+ });
199
+ }
200
+ return { entries, gaps };
201
+ }
202
+ //# sourceMappingURL=audit.js.map