@descryy/core 0.1.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 (366) hide show
  1. package/LICENSE +21 -0
  2. package/dist/capabilities/index.d.ts +3 -0
  3. package/dist/capabilities/index.d.ts.map +1 -0
  4. package/dist/capabilities/index.js +2 -0
  5. package/dist/capabilities/index.js.map +1 -0
  6. package/dist/capabilities/preconditions.d.ts +99 -0
  7. package/dist/capabilities/preconditions.d.ts.map +1 -0
  8. package/dist/capabilities/preconditions.js +94 -0
  9. package/dist/capabilities/preconditions.js.map +1 -0
  10. package/dist/contracts/engine.d.ts +90 -0
  11. package/dist/contracts/engine.d.ts.map +1 -0
  12. package/dist/contracts/engine.js +291 -0
  13. package/dist/contracts/engine.js.map +1 -0
  14. package/dist/contracts/index.d.ts +9 -0
  15. package/dist/contracts/index.d.ts.map +1 -0
  16. package/dist/contracts/index.js +5 -0
  17. package/dist/contracts/index.js.map +1 -0
  18. package/dist/contracts/orphans.d.ts +96 -0
  19. package/dist/contracts/orphans.d.ts.map +1 -0
  20. package/dist/contracts/orphans.js +241 -0
  21. package/dist/contracts/orphans.js.map +1 -0
  22. package/dist/contracts/paths.d.ts +132 -0
  23. package/dist/contracts/paths.d.ts.map +1 -0
  24. package/dist/contracts/paths.js +245 -0
  25. package/dist/contracts/paths.js.map +1 -0
  26. package/dist/contracts/shapes.d.ts +99 -0
  27. package/dist/contracts/shapes.d.ts.map +1 -0
  28. package/dist/contracts/shapes.js +196 -0
  29. package/dist/contracts/shapes.js.map +1 -0
  30. package/dist/governance/budget.d.ts +89 -0
  31. package/dist/governance/budget.d.ts.map +1 -0
  32. package/dist/governance/budget.js +101 -0
  33. package/dist/governance/budget.js.map +1 -0
  34. package/dist/governance/candidate-boundary.d.ts +49 -0
  35. package/dist/governance/candidate-boundary.d.ts.map +1 -0
  36. package/dist/governance/candidate-boundary.js +51 -0
  37. package/dist/governance/candidate-boundary.js.map +1 -0
  38. package/dist/governance/escalation.d.ts +63 -0
  39. package/dist/governance/escalation.d.ts.map +1 -0
  40. package/dist/governance/escalation.js +72 -0
  41. package/dist/governance/escalation.js.map +1 -0
  42. package/dist/governance/fact-boundary.d.ts +77 -0
  43. package/dist/governance/fact-boundary.d.ts.map +1 -0
  44. package/dist/governance/fact-boundary.js +91 -0
  45. package/dist/governance/fact-boundary.js.map +1 -0
  46. package/dist/governance/finding-funnel.d.ts +109 -0
  47. package/dist/governance/finding-funnel.d.ts.map +1 -0
  48. package/dist/governance/finding-funnel.js +137 -0
  49. package/dist/governance/finding-funnel.js.map +1 -0
  50. package/dist/governance/index.d.ts +11 -0
  51. package/dist/governance/index.d.ts.map +1 -0
  52. package/dist/governance/index.js +6 -0
  53. package/dist/governance/index.js.map +1 -0
  54. package/dist/graph/build.d.ts +127 -0
  55. package/dist/graph/build.d.ts.map +1 -0
  56. package/dist/graph/build.js +0 -0
  57. package/dist/graph/build.js.map +1 -0
  58. package/dist/graph/cross-language.d.ts +70 -0
  59. package/dist/graph/cross-language.d.ts.map +1 -0
  60. package/dist/graph/cross-language.js +104 -0
  61. package/dist/graph/cross-language.js.map +1 -0
  62. package/dist/graph/index.d.ts +11 -0
  63. package/dist/graph/index.d.ts.map +1 -0
  64. package/dist/graph/index.js +6 -0
  65. package/dist/graph/index.js.map +1 -0
  66. package/dist/graph/merge.d.ts +95 -0
  67. package/dist/graph/merge.d.ts.map +1 -0
  68. package/dist/graph/merge.js +131 -0
  69. package/dist/graph/merge.js.map +1 -0
  70. package/dist/graph/persist.d.ts +42 -0
  71. package/dist/graph/persist.d.ts.map +1 -0
  72. package/dist/graph/persist.js +52 -0
  73. package/dist/graph/persist.js.map +1 -0
  74. package/dist/graph/runtime-confirmation.d.ts +169 -0
  75. package/dist/graph/runtime-confirmation.d.ts.map +1 -0
  76. package/dist/graph/runtime-confirmation.js +318 -0
  77. package/dist/graph/runtime-confirmation.js.map +1 -0
  78. package/dist/index.d.ts +18 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +19 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/ledger/index.d.ts +5 -0
  83. package/dist/ledger/index.d.ts.map +1 -0
  84. package/dist/ledger/index.js +3 -0
  85. package/dist/ledger/index.js.map +1 -0
  86. package/dist/ledger/mint.d.ts +81 -0
  87. package/dist/ledger/mint.d.ts.map +1 -0
  88. package/dist/ledger/mint.js +138 -0
  89. package/dist/ledger/mint.js.map +1 -0
  90. package/dist/ledger/resolve.d.ts +124 -0
  91. package/dist/ledger/resolve.d.ts.map +1 -0
  92. package/dist/ledger/resolve.js +290 -0
  93. package/dist/ledger/resolve.js.map +1 -0
  94. package/dist/multipr/fingerprint.d.ts +56 -0
  95. package/dist/multipr/fingerprint.d.ts.map +1 -0
  96. package/dist/multipr/fingerprint.js +169 -0
  97. package/dist/multipr/fingerprint.js.map +1 -0
  98. package/dist/multipr/hidden-dependency.d.ts +120 -0
  99. package/dist/multipr/hidden-dependency.d.ts.map +1 -0
  100. package/dist/multipr/hidden-dependency.js +185 -0
  101. package/dist/multipr/hidden-dependency.js.map +1 -0
  102. package/dist/multipr/index.d.ts +14 -0
  103. package/dist/multipr/index.d.ts.map +1 -0
  104. package/dist/multipr/index.js +8 -0
  105. package/dist/multipr/index.js.map +1 -0
  106. package/dist/multipr/mechanical.d.ts +239 -0
  107. package/dist/multipr/mechanical.d.ts.map +1 -0
  108. package/dist/multipr/mechanical.js +333 -0
  109. package/dist/multipr/mechanical.js.map +1 -0
  110. package/dist/multipr/migration-heads.d.ts +160 -0
  111. package/dist/multipr/migration-heads.d.ts.map +1 -0
  112. package/dist/multipr/migration-heads.js +212 -0
  113. package/dist/multipr/migration-heads.js.map +1 -0
  114. package/dist/multipr/overlap.d.ts +186 -0
  115. package/dist/multipr/overlap.d.ts.map +1 -0
  116. package/dist/multipr/overlap.js +254 -0
  117. package/dist/multipr/overlap.js.map +1 -0
  118. package/dist/multipr/scope-store.d.ts +105 -0
  119. package/dist/multipr/scope-store.d.ts.map +1 -0
  120. package/dist/multipr/scope-store.js +182 -0
  121. package/dist/multipr/scope-store.js.map +1 -0
  122. package/dist/multipr/superseded.d.ts +133 -0
  123. package/dist/multipr/superseded.d.ts.map +1 -0
  124. package/dist/multipr/superseded.js +128 -0
  125. package/dist/multipr/superseded.js.map +1 -0
  126. package/dist/query/confirmed-facts.d.ts +56 -0
  127. package/dist/query/confirmed-facts.d.ts.map +1 -0
  128. package/dist/query/confirmed-facts.js +64 -0
  129. package/dist/query/confirmed-facts.js.map +1 -0
  130. package/dist/query/declared-value-closure.d.ts +126 -0
  131. package/dist/query/declared-value-closure.d.ts.map +1 -0
  132. package/dist/query/declared-value-closure.js +156 -0
  133. package/dist/query/declared-value-closure.js.map +1 -0
  134. package/dist/query/index.d.ts +28 -0
  135. package/dist/query/index.d.ts.map +1 -0
  136. package/dist/query/index.js +15 -0
  137. package/dist/query/index.js.map +1 -0
  138. package/dist/query/memory.d.ts +20 -0
  139. package/dist/query/memory.d.ts.map +1 -0
  140. package/dist/query/memory.js +55 -0
  141. package/dist/query/memory.js.map +1 -0
  142. package/dist/query/provider.d.ts +127 -0
  143. package/dist/query/provider.d.ts.map +1 -0
  144. package/dist/query/provider.js +54 -0
  145. package/dist/query/provider.js.map +1 -0
  146. package/dist/query/queries.d.ts +119 -0
  147. package/dist/query/queries.d.ts.map +1 -0
  148. package/dist/query/queries.js +267 -0
  149. package/dist/query/queries.js.map +1 -0
  150. package/dist/query/refusal-fetch.d.ts +114 -0
  151. package/dist/query/refusal-fetch.d.ts.map +1 -0
  152. package/dist/query/refusal-fetch.js +200 -0
  153. package/dist/query/refusal-fetch.js.map +1 -0
  154. package/dist/query/refusal-questions.d.ts +123 -0
  155. package/dist/query/refusal-questions.d.ts.map +1 -0
  156. package/dist/query/refusal-questions.js +122 -0
  157. package/dist/query/refusal-questions.js.map +1 -0
  158. package/dist/query/root-cause-score.d.ts +218 -0
  159. package/dist/query/root-cause-score.d.ts.map +1 -0
  160. package/dist/query/root-cause-score.js +251 -0
  161. package/dist/query/root-cause-score.js.map +1 -0
  162. package/dist/query/row-closure-picture.d.ts +108 -0
  163. package/dist/query/row-closure-picture.d.ts.map +1 -0
  164. package/dist/query/row-closure-picture.js +131 -0
  165. package/dist/query/row-closure-picture.js.map +1 -0
  166. package/dist/query/similar-incidents.d.ts +76 -0
  167. package/dist/query/similar-incidents.d.ts.map +1 -0
  168. package/dist/query/similar-incidents.js +169 -0
  169. package/dist/query/similar-incidents.js.map +1 -0
  170. package/dist/query/sqlite.d.ts +13 -0
  171. package/dist/query/sqlite.d.ts.map +1 -0
  172. package/dist/query/sqlite.js +54 -0
  173. package/dist/query/sqlite.js.map +1 -0
  174. package/dist/query/traverse.d.ts +110 -0
  175. package/dist/query/traverse.d.ts.map +1 -0
  176. package/dist/query/traverse.js +0 -0
  177. package/dist/query/traverse.js.map +1 -0
  178. package/dist/query/unresolved.d.ts +195 -0
  179. package/dist/query/unresolved.d.ts.map +1 -0
  180. package/dist/query/unresolved.js +225 -0
  181. package/dist/query/unresolved.js.map +1 -0
  182. package/dist/query/verification-status.d.ts +134 -0
  183. package/dist/query/verification-status.d.ts.map +1 -0
  184. package/dist/query/verification-status.js +163 -0
  185. package/dist/query/verification-status.js.map +1 -0
  186. package/dist/recording/index.d.ts +26 -0
  187. package/dist/recording/index.d.ts.map +1 -0
  188. package/dist/recording/index.js +30 -0
  189. package/dist/recording/index.js.map +1 -0
  190. package/dist/recording/migrate.d.ts +22 -0
  191. package/dist/recording/migrate.d.ts.map +1 -0
  192. package/dist/recording/migrate.js +51 -0
  193. package/dist/recording/migrate.js.map +1 -0
  194. package/dist/recording/reader.d.ts +27 -0
  195. package/dist/recording/reader.d.ts.map +1 -0
  196. package/dist/recording/reader.js +55 -0
  197. package/dist/recording/reader.js.map +1 -0
  198. package/dist/recording/redact.d.ts +63 -0
  199. package/dist/recording/redact.d.ts.map +1 -0
  200. package/dist/recording/redact.js +98 -0
  201. package/dist/recording/redact.js.map +1 -0
  202. package/dist/recording/schema.d.ts +41 -0
  203. package/dist/recording/schema.d.ts.map +1 -0
  204. package/dist/recording/schema.js +104 -0
  205. package/dist/recording/schema.js.map +1 -0
  206. package/dist/recording/writer.d.ts +120 -0
  207. package/dist/recording/writer.d.ts.map +1 -0
  208. package/dist/recording/writer.js +81 -0
  209. package/dist/recording/writer.js.map +1 -0
  210. package/dist/scoping/fanout.d.ts +86 -0
  211. package/dist/scoping/fanout.d.ts.map +1 -0
  212. package/dist/scoping/fanout.js +95 -0
  213. package/dist/scoping/fanout.js.map +1 -0
  214. package/dist/scoping/index.d.ts +10 -0
  215. package/dist/scoping/index.d.ts.map +1 -0
  216. package/dist/scoping/index.js +6 -0
  217. package/dist/scoping/index.js.map +1 -0
  218. package/dist/scoping/score.d.ts +83 -0
  219. package/dist/scoping/score.d.ts.map +1 -0
  220. package/dist/scoping/score.js +125 -0
  221. package/dist/scoping/score.js.map +1 -0
  222. package/dist/scoping/tiers.d.ts +32 -0
  223. package/dist/scoping/tiers.d.ts.map +1 -0
  224. package/dist/scoping/tiers.js +35 -0
  225. package/dist/scoping/tiers.js.map +1 -0
  226. package/dist/scoping/traverse.d.ts +60 -0
  227. package/dist/scoping/traverse.d.ts.map +1 -0
  228. package/dist/scoping/traverse.js +172 -0
  229. package/dist/scoping/traverse.js.map +1 -0
  230. package/dist/scoping/weights.d.ts +97 -0
  231. package/dist/scoping/weights.d.ts.map +1 -0
  232. package/dist/scoping/weights.js +167 -0
  233. package/dist/scoping/weights.js.map +1 -0
  234. package/dist/sources/git/diff.d.ts +53 -0
  235. package/dist/sources/git/diff.d.ts.map +1 -0
  236. package/dist/sources/git/diff.js +140 -0
  237. package/dist/sources/git/diff.js.map +1 -0
  238. package/dist/sources/git/env.d.ts +2 -0
  239. package/dist/sources/git/env.d.ts.map +1 -0
  240. package/dist/sources/git/env.js +21 -0
  241. package/dist/sources/git/env.js.map +1 -0
  242. package/dist/sources/git/history.d.ts +140 -0
  243. package/dist/sources/git/history.d.ts.map +1 -0
  244. package/dist/sources/git/history.js +314 -0
  245. package/dist/sources/git/history.js.map +1 -0
  246. package/dist/sources/git/index.d.ts +7 -0
  247. package/dist/sources/git/index.d.ts.map +1 -0
  248. package/dist/sources/git/index.js +4 -0
  249. package/dist/sources/git/index.js.map +1 -0
  250. package/dist/sources/git/source.d.ts +95 -0
  251. package/dist/sources/git/source.d.ts.map +1 -0
  252. package/dist/sources/git/source.js +0 -0
  253. package/dist/sources/git/source.js.map +1 -0
  254. package/dist/sources/migrations/dialects.d.ts +59 -0
  255. package/dist/sources/migrations/dialects.d.ts.map +1 -0
  256. package/dist/sources/migrations/dialects.js +84 -0
  257. package/dist/sources/migrations/dialects.js.map +1 -0
  258. package/dist/sources/migrations/index.d.ts +3 -0
  259. package/dist/sources/migrations/index.d.ts.map +1 -0
  260. package/dist/sources/migrations/index.js +2 -0
  261. package/dist/sources/migrations/index.js.map +1 -0
  262. package/dist/sources/migrations/read.d.ts +113 -0
  263. package/dist/sources/migrations/read.d.ts.map +1 -0
  264. package/dist/sources/migrations/read.js +270 -0
  265. package/dist/sources/migrations/read.js.map +1 -0
  266. package/dist/sources/workspace/index.d.ts +3 -0
  267. package/dist/sources/workspace/index.d.ts.map +1 -0
  268. package/dist/sources/workspace/index.js +2 -0
  269. package/dist/sources/workspace/index.js.map +1 -0
  270. package/dist/sources/workspace/workspace.d.ts +64 -0
  271. package/dist/sources/workspace/workspace.d.ts.map +1 -0
  272. package/dist/sources/workspace/workspace.js +294 -0
  273. package/dist/sources/workspace/workspace.js.map +1 -0
  274. package/dist/store/driver/driver.d.ts +82 -0
  275. package/dist/store/driver/driver.d.ts.map +1 -0
  276. package/dist/store/driver/driver.js +31 -0
  277. package/dist/store/driver/driver.js.map +1 -0
  278. package/dist/store/driver/node-sqlite.d.ts +28 -0
  279. package/dist/store/driver/node-sqlite.d.ts.map +1 -0
  280. package/dist/store/driver/node-sqlite.js +188 -0
  281. package/dist/store/driver/node-sqlite.js.map +1 -0
  282. package/dist/store/index.d.ts +33 -0
  283. package/dist/store/index.d.ts.map +1 -0
  284. package/dist/store/index.js +46 -0
  285. package/dist/store/index.js.map +1 -0
  286. package/dist/store/migrate.d.ts +68 -0
  287. package/dist/store/migrate.d.ts.map +1 -0
  288. package/dist/store/migrate.js +140 -0
  289. package/dist/store/migrate.js.map +1 -0
  290. package/dist/store/reader.d.ts +127 -0
  291. package/dist/store/reader.d.ts.map +1 -0
  292. package/dist/store/reader.js +269 -0
  293. package/dist/store/reader.js.map +1 -0
  294. package/dist/store/schema.d.ts +87 -0
  295. package/dist/store/schema.d.ts.map +1 -0
  296. package/dist/store/schema.js +322 -0
  297. package/dist/store/schema.js.map +1 -0
  298. package/dist/store/writer.d.ts +116 -0
  299. package/dist/store/writer.d.ts.map +1 -0
  300. package/dist/store/writer.js +279 -0
  301. package/dist/store/writer.js.map +1 -0
  302. package/dist/tiers/certify.d.ts +375 -0
  303. package/dist/tiers/certify.d.ts.map +1 -0
  304. package/dist/tiers/certify.js +434 -0
  305. package/dist/tiers/certify.js.map +1 -0
  306. package/dist/tiers/index.d.ts +5 -0
  307. package/dist/tiers/index.d.ts.map +1 -0
  308. package/dist/tiers/index.js +3 -0
  309. package/dist/tiers/index.js.map +1 -0
  310. package/dist/tiers/ladder.d.ts +73 -0
  311. package/dist/tiers/ladder.d.ts.map +1 -0
  312. package/dist/tiers/ladder.js +197 -0
  313. package/dist/tiers/ladder.js.map +1 -0
  314. package/dist/validation/config-graph.d.ts +104 -0
  315. package/dist/validation/config-graph.d.ts.map +1 -0
  316. package/dist/validation/config-graph.js +205 -0
  317. package/dist/validation/config-graph.js.map +1 -0
  318. package/dist/validation/env.d.ts +243 -0
  319. package/dist/validation/env.d.ts.map +1 -0
  320. package/dist/validation/env.js +447 -0
  321. package/dist/validation/env.js.map +1 -0
  322. package/dist/validation/index.d.ts +16 -0
  323. package/dist/validation/index.d.ts.map +1 -0
  324. package/dist/validation/index.js +9 -0
  325. package/dist/validation/index.js.map +1 -0
  326. package/dist/validation/join-substitution.d.ts +186 -0
  327. package/dist/validation/join-substitution.d.ts.map +1 -0
  328. package/dist/validation/join-substitution.js +191 -0
  329. package/dist/validation/join-substitution.js.map +1 -0
  330. package/dist/validation/migrations.d.ts +133 -0
  331. package/dist/validation/migrations.d.ts.map +1 -0
  332. package/dist/validation/migrations.js +315 -0
  333. package/dist/validation/migrations.js.map +1 -0
  334. package/dist/validation/nodes.d.ts +32 -0
  335. package/dist/validation/nodes.d.ts.map +1 -0
  336. package/dist/validation/nodes.js +45 -0
  337. package/dist/validation/nodes.js.map +1 -0
  338. package/dist/validation/rollback.d.ts +124 -0
  339. package/dist/validation/rollback.d.ts.map +1 -0
  340. package/dist/validation/rollback.js +302 -0
  341. package/dist/validation/rollback.js.map +1 -0
  342. package/dist/validation/route-drift.d.ts +108 -0
  343. package/dist/validation/route-drift.d.ts.map +1 -0
  344. package/dist/validation/route-drift.js +103 -0
  345. package/dist/validation/route-drift.js.map +1 -0
  346. package/dist/validation/sources.d.ts +153 -0
  347. package/dist/validation/sources.d.ts.map +1 -0
  348. package/dist/validation/sources.js +409 -0
  349. package/dist/validation/sources.js.map +1 -0
  350. package/dist/worker/index.d.ts +5 -0
  351. package/dist/worker/index.d.ts.map +1 -0
  352. package/dist/worker/index.js +3 -0
  353. package/dist/worker/index.js.map +1 -0
  354. package/dist/worker/pool.d.ts +73 -0
  355. package/dist/worker/pool.d.ts.map +1 -0
  356. package/dist/worker/pool.js +203 -0
  357. package/dist/worker/pool.js.map +1 -0
  358. package/dist/worker/protocol.d.ts +91 -0
  359. package/dist/worker/protocol.d.ts.map +1 -0
  360. package/dist/worker/protocol.js +19 -0
  361. package/dist/worker/protocol.js.map +1 -0
  362. package/dist/worker/traversal.worker.d.ts +25 -0
  363. package/dist/worker/traversal.worker.d.ts.map +1 -0
  364. package/dist/worker/traversal.worker.js +124 -0
  365. package/dist/worker/traversal.worker.js.map +1 -0
  366. package/package.json +29 -0
@@ -0,0 +1,315 @@
1
+ /**
2
+ * The format half of §15.3's rollback-readiness check — migrations read from the
3
+ * repository as text.
4
+ *
5
+ * Same argument as `sources.ts`: DDL is a **format, not a language**, so reading
6
+ * it names nothing the Canonical IR boundary forbids. Same limit, too — this half
7
+ * sees only what is written as DDL, and DEC-122 measured exactly how little that
8
+ * is: **zero `.sql` files inside a migration directory across fifteen reference
9
+ * repositories**, against 3,301 migrations written as program code. The code half
10
+ * arrives through `attrs.migrationOps` and is an adapter's to produce.
11
+ *
12
+ * ## The scope fence, which is what makes this Class A
13
+ *
14
+ * Appendix B.3 settles rollback readiness as Class A against two sources that
15
+ * called it B, and the resolution turns entirely on what is claimed:
16
+ *
17
+ * > **"this migration contains a destructive operation"** — a fact, and a
18
+ * > deterministic pattern match establishes it.
19
+ * >
20
+ * > **"this migration is unsafe to roll back"** — an inference, requiring the
21
+ * > consumer-impact analysis §15.3 explicitly separates this check from.
22
+ *
23
+ * Every sentence produced here is written to stay behind that fence. The finding
24
+ * names the operation, the object and the line; it does not characterise risk.
25
+ *
26
+ * ## What counts as destructive, and the things deliberately left out
27
+ *
28
+ * Only operations that **destroy data**. `DROP INDEX`, `DROP CONSTRAINT`,
29
+ * `DROP VIEW`, `DROP TRIGGER` and `DROP FUNCTION` are all recoverable by
30
+ * re-running the definition and none of them loses a row, so including them
31
+ * would triple the finding count with statements nobody needs to see. A rename
32
+ * is carried separately: the data survives, so it is not the same claim as a
33
+ * drop, but every reader of the old name breaks.
34
+ *
35
+ * ## Section detection is tool-blind on purpose
36
+ *
37
+ * Directional migrations mark their halves with a comment directive. Matching a
38
+ * specific tool's spelling would put that tool's name in engine code — rule 1,
39
+ * the violation the boundary lint already caught once in this directory. So the
40
+ * **shape** is matched instead: a comment carrying a directive word followed by
41
+ * an up/down keyword, in either the `+name Up` form or a bare `-- Up`. Any tool
42
+ * using that shape works; none of them is named.
43
+ */
44
+ import { readFileSync, readdirSync, statSync } from "node:fs";
45
+ import { join, relative, sep } from "node:path";
46
+ import { skipDirectory } from "./sources.js";
47
+ const DEFAULT_MAX_DEPTH = 8;
48
+ const DEFAULT_MAX_FILES = 20_000;
49
+ /**
50
+ * A directory holding migrations.
51
+ *
52
+ * Path-based rather than content-based, and named after what the directory *is*
53
+ * rather than after any tool that creates it. A `.sql` file in a `schema/`
54
+ * directory is a definition, not a change, and reading it as one would report
55
+ * every `CREATE`-then-`DROP` setup script in the repository.
56
+ */
57
+ const MIGRATION_DIRECTORY = /(^|\/)(migrations?|migrate|versions|changelogs?)(\/|$)/i;
58
+ /** A directive comment carrying a direction, in either common shape. */
59
+ const SECTION_MARKER = /^\s*--\s*(?:\+\w+\s+)?(up|down)\b/i;
60
+ /**
61
+ * Split DDL on `;`, ignoring separators inside strings, quoted identifiers and
62
+ * comments.
63
+ *
64
+ * A plain split would cut a statement in half at the first semicolon inside a
65
+ * default value, which is a real thing to find in a migration.
66
+ *
67
+ * **This duplicates the splitter in `adapter-sql`, deliberately and with the
68
+ * cost recorded** (DEC-122). `@descryy/core` cannot depend on an adapter —
69
+ * adapters depend on core — so the alternative to a second copy is inverting the
70
+ * boundary the repository split exists to hold. If a third caller appears, the
71
+ * right home is `@descryy/ir`.
72
+ */
73
+ export function statements(sql) {
74
+ const found = [];
75
+ let buffer = "";
76
+ let line = 1;
77
+ let startLine = 1;
78
+ let quote = null;
79
+ let comment = null;
80
+ const flush = () => {
81
+ if (buffer.trim() !== "")
82
+ found.push({ text: buffer.trim(), line: startLine });
83
+ buffer = "";
84
+ startLine = line;
85
+ };
86
+ for (let i = 0; i < sql.length; i += 1) {
87
+ const char = sql[i];
88
+ const next = sql[i + 1];
89
+ if (char === "\n")
90
+ line += 1;
91
+ if (comment === "line") {
92
+ if (char === "\n")
93
+ comment = null;
94
+ continue;
95
+ }
96
+ if (comment === "block") {
97
+ if (char === "*" && next === "/") {
98
+ comment = null;
99
+ i += 1;
100
+ }
101
+ continue;
102
+ }
103
+ if (quote !== null) {
104
+ buffer += char;
105
+ if (char === quote)
106
+ quote = null;
107
+ continue;
108
+ }
109
+ if (char === "-" && next === "-") {
110
+ comment = "line";
111
+ continue;
112
+ }
113
+ if (char === "/" && next === "*") {
114
+ comment = "block";
115
+ i += 1;
116
+ continue;
117
+ }
118
+ if (char === "'" || char === '"' || char === "`") {
119
+ quote = char;
120
+ buffer += char;
121
+ continue;
122
+ }
123
+ if (char === ";") {
124
+ flush();
125
+ continue;
126
+ }
127
+ if (buffer.trim() === "" && char.trim() === "") {
128
+ startLine = line;
129
+ continue;
130
+ }
131
+ buffer += char;
132
+ }
133
+ flush();
134
+ return found;
135
+ }
136
+ function unquote(identifier) {
137
+ return identifier.replace(/^["`[]+|["`\]]+$/g, "").toLowerCase();
138
+ }
139
+ /**
140
+ * Classify one statement.
141
+ *
142
+ * Returns `null` for everything unrecognised, which is the overwhelming
143
+ * majority and is correct: an unclassified statement is not a silent pass, it is
144
+ * counted by the caller and disclosed.
145
+ */
146
+ export function classifyStatement(text, line, section) {
147
+ const flat = text.replace(/\s+/g, " ").trim();
148
+ const guarded = /\bIF\s+EXISTS\b/i.test(flat);
149
+ // ALTER TABLE … DROP COLUMN — checked before the bare DROP forms, because
150
+ // "ALTER TABLE x DROP COLUMN y" also contains the substring "DROP".
151
+ //
152
+ // The negative lookahead is not decoration. `ALTER TABLE t DROP CONSTRAINT c`
153
+ // has the same shape with the keyword omitted, and without the guard the
154
+ // constraint name is read as a column name — a data-loss claim about a
155
+ // statement that loses no data. Found by a test, which is where it belongs.
156
+ const dropColumn = /^ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?([\w."`[\]]+)\s+DROP\s+(?:COLUMN\s+)?(?:IF\s+EXISTS\s+)?(?!CONSTRAINT\b|INDEX\b|CHECK\b|PRIMARY\b|FOREIGN\b|UNIQUE\b|DEFAULT\b|NOT\b|PARTITION\b)([\w."`[\]]+)/i.exec(flat);
157
+ if (dropColumn !== null) {
158
+ return {
159
+ kind: "DROP_COLUMN",
160
+ target: `${unquote(dropColumn[1])}.${unquote(dropColumn[2])}`,
161
+ line,
162
+ section,
163
+ guarded,
164
+ };
165
+ }
166
+ const rename = /^ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?([\w."`[\]]+)\s+RENAME\s+(?:COLUMN\s+)?([\w."`[\]]+)?/i.exec(flat);
167
+ if (rename !== null) {
168
+ const object = rename[2];
169
+ return {
170
+ kind: "RENAME",
171
+ target: object === undefined
172
+ ? unquote(rename[1])
173
+ : `${unquote(rename[1])}.${unquote(object)}`,
174
+ line,
175
+ section,
176
+ guarded,
177
+ };
178
+ }
179
+ const dropTable = /^DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?([\w."`[\]]+)/i.exec(flat);
180
+ if (dropTable !== null) {
181
+ return { kind: "DROP_TABLE", target: unquote(dropTable[1]), line, section, guarded };
182
+ }
183
+ const dropSchema = /^DROP\s+SCHEMA\s+(?:IF\s+EXISTS\s+)?([\w."`[\]]+)/i.exec(flat);
184
+ if (dropSchema !== null) {
185
+ return { kind: "DROP_SCHEMA", target: unquote(dropSchema[1]), line, section, guarded };
186
+ }
187
+ const truncate = /^TRUNCATE\s+(?:TABLE\s+)?(?:ONLY\s+)?([\w."`[\]]+)/i.exec(flat);
188
+ if (truncate !== null) {
189
+ return { kind: "TRUNCATE", target: unquote(truncate[1]), line, section, guarded };
190
+ }
191
+ return null;
192
+ }
193
+ /** Objects a statement brings into existence, so a later drop can be discounted. */
194
+ function created(text) {
195
+ const flat = text.replace(/\s+/g, " ").trim();
196
+ const table = /^CREATE\s+(?:\w+\s+)*TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([\w."`[\]]+)/i.exec(flat);
197
+ if (table !== null)
198
+ return unquote(table[1]);
199
+ const schema = /^CREATE\s+SCHEMA\s+(?:IF\s+NOT\s+EXISTS\s+)?([\w."`[\]]+)/i.exec(flat);
200
+ if (schema !== null)
201
+ return unquote(schema[1]);
202
+ return null;
203
+ }
204
+ /** Read one migration file's operations, tracking which section each sits in. */
205
+ export function readMigration(text) {
206
+ const lines = text.split(/\r?\n/);
207
+ // Section boundaries are line-based, because the marker is a comment and the
208
+ // splitter discards comments. Built first, then applied by line number.
209
+ const boundaries = [];
210
+ for (let i = 0; i < lines.length; i += 1) {
211
+ const marker = SECTION_MARKER.exec(lines[i] ?? "");
212
+ if (marker === null)
213
+ continue;
214
+ boundaries.push({
215
+ line: i + 1,
216
+ section: marker[1].toLowerCase() === "down" ? "reverse" : "forward",
217
+ });
218
+ }
219
+ const directional = boundaries.length > 0;
220
+ const sectionAt = (line) => {
221
+ if (!directional)
222
+ return "unknown";
223
+ let current = "unknown";
224
+ for (const boundary of boundaries) {
225
+ if (boundary.line > line)
226
+ break;
227
+ current = boundary.section;
228
+ }
229
+ return current;
230
+ };
231
+ const ops = [];
232
+ const creates = [];
233
+ for (const statement of statements(text)) {
234
+ const create = created(statement.text);
235
+ if (create !== null) {
236
+ creates.push({ name: create, line: statement.line });
237
+ continue;
238
+ }
239
+ const op = classifyStatement(statement.text, statement.line, sectionAt(statement.line));
240
+ if (op !== null)
241
+ ops.push(op);
242
+ }
243
+ return { ops, creates, directional };
244
+ }
245
+ /** Walk the repository for migration files written as DDL. */
246
+ export function scanMigrations(root, options = {}) {
247
+ const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
248
+ const maxFiles = options.maxFiles ?? DEFAULT_MAX_FILES;
249
+ const noiseDirectories = options.noiseDirectories ?? [];
250
+ const files = [];
251
+ const unreadable = [];
252
+ let seen = 0;
253
+ let truncated = false;
254
+ let unparsed = 0;
255
+ const walk = (dir, depth) => {
256
+ if (truncated || depth > maxDepth)
257
+ return;
258
+ let entries;
259
+ try {
260
+ entries = readdirSync(dir).sort();
261
+ }
262
+ catch {
263
+ unreadable.push(rel(root, dir));
264
+ return;
265
+ }
266
+ for (const entry of entries) {
267
+ if (truncated)
268
+ return;
269
+ const full = join(dir, entry);
270
+ let directory = false;
271
+ try {
272
+ directory = statSync(full).isDirectory();
273
+ }
274
+ catch {
275
+ continue;
276
+ }
277
+ if (directory) {
278
+ if (!skipDirectory(entry, noiseDirectories))
279
+ walk(full, depth + 1);
280
+ continue;
281
+ }
282
+ if (++seen > maxFiles) {
283
+ truncated = true;
284
+ return;
285
+ }
286
+ if (!/\.sql$/i.test(entry))
287
+ continue;
288
+ const path = rel(root, full);
289
+ if (!MIGRATION_DIRECTORY.test(path))
290
+ continue;
291
+ let text;
292
+ try {
293
+ text = readFileSync(full, "utf8");
294
+ }
295
+ catch {
296
+ unreadable.push(path);
297
+ continue;
298
+ }
299
+ const parsed = readMigration(text);
300
+ if (parsed.ops.length === 0) {
301
+ unparsed += 1;
302
+ continue;
303
+ }
304
+ files.push({ file: path, ...parsed });
305
+ }
306
+ };
307
+ walk(root, 0);
308
+ files.sort((a, b) => a.file.localeCompare(b.file));
309
+ return { files, unreadable, truncated, unparsed };
310
+ }
311
+ function rel(root, full) {
312
+ const r = relative(root, full);
313
+ return r === "" ? "." : r.split(sep).join("/");
314
+ }
315
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/validation/migrations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Which node stands for a file — a question, not a value.
3
+ *
4
+ * Split into its own module because all three checks in this directory ask it,
5
+ * and because the answer was wrong in all three for a day. See below.
6
+ */
7
+ import type { IRNode } from "@descryy/ir";
8
+ import type { AdjacencyProvider } from "../query/provider.ts";
9
+ /**
10
+ * The node types that stand for a whole file.
11
+ *
12
+ * **Every shipped adapter emits `MODULE` for a file and not one of them emits
13
+ * `FILE`** — verified across all nine, not assumed. The checks in this directory
14
+ * were written against `FILE` alone, their tests minted `FILE` nodes, their
15
+ * benches minted `FILE` nodes, and all three gates passed while the graph half of
16
+ * every check was unable to fire on any real repository. The number stayed right
17
+ * and the reason for it had stopped being true.
18
+ *
19
+ * Asking for a list of types is what rule 8 warns about — *"a node type is a
20
+ * question, not a value"* — and the correct home for the question is a predicate
21
+ * in `@descryy/ir` beside `isTypeLikeNodeType` and `isCallableNodeType`. That is a
22
+ * shared-package change, so it is **requested rather than taken**: see
23
+ * `REQUEST-D-file-scoped-nodes.md`. This constant is the local stand-in and it
24
+ * carries the debt visibly rather than hiding it.
25
+ */
26
+ export declare const FILE_SCOPED_NODE_TYPES: readonly ["MODULE", "FILE"];
27
+ /** Every file-scoped node, across the types that carry one. */
28
+ export declare function fileScopedNodes(provider: AdjacencyProvider, limit?: number): {
29
+ readonly nodes: readonly IRNode[];
30
+ readonly truncated: boolean;
31
+ };
32
+ //# sourceMappingURL=nodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../../src/validation/nodes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,sBAAsB,6BAA8B,CAAC;AAElE,+DAA+D;AAC/D,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,CAAC,EAAE,MAAM,GACb;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAgBpE"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Which node stands for a file — a question, not a value.
3
+ *
4
+ * Split into its own module because all three checks in this directory ask it,
5
+ * and because the answer was wrong in all three for a day. See below.
6
+ */
7
+ /**
8
+ * The node types that stand for a whole file.
9
+ *
10
+ * **Every shipped adapter emits `MODULE` for a file and not one of them emits
11
+ * `FILE`** — verified across all nine, not assumed. The checks in this directory
12
+ * were written against `FILE` alone, their tests minted `FILE` nodes, their
13
+ * benches minted `FILE` nodes, and all three gates passed while the graph half of
14
+ * every check was unable to fire on any real repository. The number stayed right
15
+ * and the reason for it had stopped being true.
16
+ *
17
+ * Asking for a list of types is what rule 8 warns about — *"a node type is a
18
+ * question, not a value"* — and the correct home for the question is a predicate
19
+ * in `@descryy/ir` beside `isTypeLikeNodeType` and `isCallableNodeType`. That is a
20
+ * shared-package change, so it is **requested rather than taken**: see
21
+ * `REQUEST-D-file-scoped-nodes.md`. This constant is the local stand-in and it
22
+ * carries the debt visibly rather than hiding it.
23
+ */
24
+ export const FILE_SCOPED_NODE_TYPES = ["MODULE", "FILE"];
25
+ /** Every file-scoped node, across the types that carry one. */
26
+ export function fileScopedNodes(provider, limit) {
27
+ const nodes = [];
28
+ let truncated = false;
29
+ const seen = new Set();
30
+ for (const type of FILE_SCOPED_NODE_TYPES) {
31
+ const set = limit === undefined ? provider.nodesOfType(type) : provider.nodesOfType(type, limit);
32
+ truncated = truncated || set.truncated;
33
+ for (const node of set.nodes) {
34
+ // A repository with both types would otherwise count a path twice, and a
35
+ // dependent count is a set property.
36
+ if (node.file !== null && seen.has(node.file))
37
+ continue;
38
+ if (node.file !== null)
39
+ seen.add(node.file);
40
+ nodes.push(node);
41
+ }
42
+ }
43
+ return { nodes, truncated };
44
+ }
45
+ //# sourceMappingURL=nodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodes.js","sourceRoot":"","sources":["../../src/validation/nodes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAU,CAAC;AAElE,+DAA+D;AAC/D,MAAM,UAAU,eAAe,CAC7B,QAA2B,EAC3B,KAAc;IAEd,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,sBAAsB,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACjG,SAAS,GAAG,SAAS,IAAI,GAAG,CAAC,SAAS,CAAC;QACvC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC7B,yEAAyE;YACzE,qCAAqC;YACrC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,SAAS;YACxD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;gBAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * §15.3's rollback-readiness check — *"pattern-match migrations against a known
3
+ * list of destructive operations"*.
4
+ *
5
+ * Class A at R0, and **deliberately the easy half of consumer impact**: a
6
+ * destructive operation is a pattern in a migration, not an inference about who
7
+ * reads the column. The scope fence that makes that classification safe is stated
8
+ * in `migrations.ts` and every sentence below stays behind it.
9
+ *
10
+ * ## The trap, measured before this was written
11
+ *
12
+ * The env check's trap was a variable read and never declared. This one is
13
+ * larger, and DEC-122 counted it:
14
+ *
15
+ * | repository | migrations | with a reverse section |
16
+ * | --- | --- | --- |
17
+ * | `outline` | 300 | **300** |
18
+ * | `dispatch` | 162 | **162** |
19
+ * | `directus` | 112 | 110 |
20
+ *
21
+ * **Effectively every migration in these projects declares a reverse, and a
22
+ * destructive operation in the reverse is supposed to be there** — it undoes the
23
+ * forward migration. A check that matched destructive operations without knowing
24
+ * which half it was reading would report `outline`'s 202 destructive files, and
25
+ * most of those matches are a drop that undoes a create three lines above.
26
+ *
27
+ * So `section` is to this check what `required` was to the env check: the field
28
+ * without which the whole thing is wrong on nearly every file it sees. And
29
+ * `unknown` is not a synonym for `forward`. Two of the reference repositories
30
+ * declare no direction at all — they hand the framework a reversal callback — and
31
+ * their operations are **counted and disclosed, never reported**. That refusal
32
+ * alone withholds 192 files' worth of matches, and it is the honest treatment:
33
+ * an operation whose half cannot be determined is not evidence of a forward
34
+ * destructive change.
35
+ *
36
+ * ## Two further refusals, both from the only real DDL in the corpus
37
+ *
38
+ * - **`DROP … IF EXISTS` paired with a `CREATE` of the same object** is an
39
+ * idempotent setup script, not a data-losing change. Both destructive lines in
40
+ * the one genuine `.sql` file found across fifteen repositories are exactly
41
+ * this shape.
42
+ * - **Dropping an object created in the same migration** is not a finding. The
43
+ * object did not exist before the file ran.
44
+ *
45
+ * ## Where the input comes from
46
+ *
47
+ * Two sources, and DEC-122 measured that the one the architecture implies is the
48
+ * smaller: **0 `.sql` files inside a migration directory** across the reference
49
+ * corpus, against **3,301** migrations written as program code. The format half
50
+ * runs today and needs no adapter; the code half arrives as `attrs.migrationOps`
51
+ * and is an adapter's to produce. When neither is present the check says so and
52
+ * does not report a clean result.
53
+ */
54
+ import type { ResolutionLevel } from "@descryy/ir";
55
+ import type { AdjacencyProvider, QueryResult } from "../query/provider.ts";
56
+ import type { DestructiveKind, MigrationOp, MigrationScan } from "./migrations.ts";
57
+ export interface RollbackFinding {
58
+ readonly kind: DestructiveKind;
59
+ /** The table, column or schema named by the statement. */
60
+ readonly target: string;
61
+ readonly file: string;
62
+ readonly line: number;
63
+ /**
64
+ * The sentence a developer reads.
65
+ *
66
+ * Stays behind the §15.3 fence: it states that the operation is present, never
67
+ * that the migration is unsafe to roll back.
68
+ */
69
+ readonly detail: string;
70
+ readonly resolution: ResolutionLevel;
71
+ }
72
+ export interface RollbackReport {
73
+ readonly findings: readonly RollbackFinding[];
74
+ /** The count before `maxFindings` capped it — P27's disclosed remainder: a structured field, not only a prose note. */
75
+ readonly findingsTotal: number;
76
+ readonly examined: {
77
+ /** Migration files read as DDL from the repository. */
78
+ readonly fromSource: number;
79
+ /** Migration files whose operations came from an adapter. */
80
+ readonly fromGraph: number;
81
+ /** Destructive operations seen, before any refusal. */
82
+ readonly operations: number;
83
+ };
84
+ /**
85
+ * Every operation the check declined to report, by reason.
86
+ *
87
+ * The counts are the point: they are the size of what this check chose not to
88
+ * say, and each has a different cause a reader can act on.
89
+ */
90
+ readonly withheld: {
91
+ /** In a reverse section — undoing a forward migration. */
92
+ readonly reverse: number;
93
+ /** The file declares no direction, so the half is unknown. */
94
+ readonly undirected: number;
95
+ /** Guarded by `IF EXISTS` alongside a create of the same object. */
96
+ readonly idempotent: number;
97
+ /** The object was created by the same migration. */
98
+ readonly selfCreated: number;
99
+ };
100
+ /** True when at least one source supplied operations. */
101
+ readonly ran: boolean;
102
+ /** Named, in plain words, when `ran` is false. */
103
+ readonly blockers: readonly string[];
104
+ }
105
+ export interface RollbackOptions {
106
+ readonly maxFindings?: number;
107
+ /** Restrict to these repo-relative files — the scoped-subgraph run. */
108
+ readonly files?: readonly string[];
109
+ readonly limit?: number;
110
+ }
111
+ /**
112
+ * Pull `attrs.migrationOps` off a file node, refusing anything malformed.
113
+ *
114
+ * A row with no `section`, or an unrecognised one, is **dropped rather than
115
+ * treated as forward**. Defaulting it would manufacture exactly the claim the
116
+ * reverse-section fence exists to withhold, on a corpus where the reverse
117
+ * section is present in effectively every file.
118
+ */
119
+ export declare function readMigrationOps(attrs: Readonly<Record<string, unknown>>): {
120
+ readonly ops: readonly MigrationOp[];
121
+ readonly malformed: number;
122
+ };
123
+ export declare function checkRollbackReadiness(provider: AdjacencyProvider, scan: MigrationScan, options?: RollbackOptions): QueryResult<RollbackReport>;
124
+ //# sourceMappingURL=rollback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/validation/rollback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,KAAK,EAAE,iBAAiB,EAAc,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEvF,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,aAAa,EAEd,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,uHAAuH;IACvH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE;QACjB,uDAAuD;QACvD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,6DAA6D;QAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,uDAAuD;QACvD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE;QACjB,0DAA0D;QAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,8DAA8D;QAC9D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,oEAAoE;QACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,oDAAoD;QACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,yDAAyD;IACzD,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAgBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC;IAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,WAAW,EAAE,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAsCtE;AASD,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,eAAoB,GAC5B,WAAW,CAAC,cAAc,CAAC,CAoN7B"}