@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,54 @@
1
+ /**
2
+ * `AdjacencyProvider` — the interface every traversal is written against.
3
+ *
4
+ * Not an abstraction for its own sake. Two consequences follow from it and both
5
+ * are structural:
6
+ *
7
+ * 1. **Most of the engine's tests need no database.** A traversal written
8
+ * against SQLite is a traversal that can only be tested with a file, a
9
+ * schema, a writer and eventually a worker thread. Written against this, the
10
+ * same code runs over an in-memory graph built in four lines.
11
+ *
12
+ * 2. **Traversal stays identical across backends.** §11.8 chose application-code
13
+ * traversal over recursive CTEs precisely so that decay scoring, budgets and
14
+ * per-edge weights work the same on SQLite and Postgres. That only holds if
15
+ * the traversal never sees which one it is talking to.
16
+ *
17
+ * `incoming()` takes a limit and a ranking rather than returning everything.
18
+ * That is not politeness: the prior-art graphs measured for this build have a
19
+ * max in-degree of **1,036** (`append`), and materialising every neighbour of a
20
+ * hub turns a 200-node budget into a 10,000-row read.
21
+ */
22
+ /** The cap `nodesOfType` applies when a caller names none. */
23
+ export const DEFAULT_NODE_SET_LIMIT = 5_000;
24
+ /**
25
+ * Rank edges the way every caller wants them: best evidence first, stably.
26
+ *
27
+ * Resolution outranks confidence because they are not the same axis — a
28
+ * type-checked edge at 0.8 is a better fact than a name-matched one at 0.95, and
29
+ * §11A.5 exists because v2.0 could not tell those apart. `from`/`to`/`type`
30
+ * break the final tie so the order is identical between runs.
31
+ */
32
+ export function rankEdges(edges) {
33
+ return [...edges].sort((a, b) => {
34
+ if (a.resolution !== b.resolution)
35
+ return b.resolution - a.resolution;
36
+ if (a.confidence !== b.confidence)
37
+ return b.confidence - a.confidence;
38
+ return `${a.from}${a.to}${a.type}`.localeCompare(`${b.from}${b.to}${b.type}`);
39
+ });
40
+ }
41
+ /** Apply type filter, confidence floor, ranking and limit. Shared by both providers. */
42
+ export function applyAdjacencyOptions(edges, options = {}) {
43
+ const types = options.types;
44
+ let filtered = types === undefined || types.length === 0
45
+ ? [...edges]
46
+ : edges.filter((e) => types.includes(e.type));
47
+ if (options.minConfidence !== undefined) {
48
+ const floor = options.minConfidence;
49
+ filtered = filtered.filter((e) => e.confidence >= floor);
50
+ }
51
+ const ranked = rankEdges(filtered);
52
+ return options.limit === undefined ? ranked : ranked.slice(0, Math.max(0, options.limit));
53
+ }
54
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/query/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAkGH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAE5C;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,KAAwB;IAChD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC9B,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU;YAAE,OAAO,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;QACtE,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU;YAAE,OAAO,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;QACtE,OAAO,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,qBAAqB,CACnC,KAAwB,EACxB,UAA4B,EAAE;IAE9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,IAAI,QAAQ,GACV,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QACvC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;QACZ,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC;QACpC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,KAAK,CAAC,CAAC;IAC3D,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACnC,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5F,CAAC"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The six query types of architecture §11.9, plus one added since: §18's
3
+ * `get_git_history`/`get_git_diff` named a real gap — `CHANGES_WITH` edges
4
+ * existed in the graph, produced by `analyze`'s git source, with no query
5
+ * reading them per node. `changesWith` (below) is that query. It is scoped to
6
+ * the stored co-change graph, never a live `git log`/`git diff` call — a new
7
+ * query over an existing edge type, not a new capability.
8
+ *
9
+ * Every one returns a `QueryResult`, so no caller can take the answer without
10
+ * the disclosure attached to it. That is the point of the envelope: §27.3's
11
+ * staleness rule and principle 3's resolution cap are not reporting concerns
12
+ * bolted on later, they are properties of the answer itself.
13
+ *
14
+ * One of the seven is **deliberately incomplete in this build** and says so —
15
+ * see `rootCauseSearch`. Reporting a partial answer as a whole one is the
16
+ * exact failure the honest-degradation rule exists to prevent.
17
+ */
18
+ import type { EdgeType, IRNode } from "@descryy/ir";
19
+ import type { AdjacencyProvider, QueryResult } from "./provider.ts";
20
+ import { type TraversalOptions } from "./traverse.ts";
21
+ export interface ImpactOptions extends TraversalOptions {
22
+ /** Score decay per hop. Step 12 replaces this with §12.4's real weights. */
23
+ readonly weightFor?: (edge: {
24
+ confidence: number;
25
+ type: EdgeType;
26
+ }) => number;
27
+ readonly minScore?: number;
28
+ }
29
+ export declare function impactOf(provider: AdjacencyProvider, seeds: readonly string[], options?: ImpactOptions): QueryResult<{
30
+ node: IRNode;
31
+ depth: number;
32
+ score: number;
33
+ }[]>;
34
+ export interface RootCauseMatch {
35
+ readonly incident: IRNode;
36
+ readonly via: EdgeType;
37
+ }
38
+ /**
39
+ * Incidents correlated with a node, by graph edges only.
40
+ *
41
+ * **Incomplete by design in this build, and the caller is told so.** §11.9's
42
+ * root-cause query is "incident **plus embedding match**", and this build has no
43
+ * vector store — `embeddings` is a pointer table, since §8.2 keeps vectors in
44
+ * pgvector or a local extension and a column of serialised floats with no index
45
+ * is a scan rather than a search.
46
+ *
47
+ * So this answers the structural half and discloses the other. Returning it
48
+ * silently as "root cause search" would report "we found no similar incident"
49
+ * when the truth is "we did not look the way we said we would" — §20.2 keeps
50
+ * those in different categories for a reason.
51
+ */
52
+ export declare function rootCauseSearch(provider: AdjacencyProvider, nodeId: string): QueryResult<RootCauseMatch[]>;
53
+ export declare function testsCovering(provider: AdjacencyProvider, nodeId: string, options?: {
54
+ maxDepth?: number;
55
+ budget?: number;
56
+ }): QueryResult<IRNode[]>;
57
+ /**
58
+ * The four edge types that carry data rather than control.
59
+ *
60
+ * Exported because a caller that discloses *what it walked* must name the same
61
+ * list this walk uses. A second copy in the MCP tool would drift, and the note
62
+ * would then describe a walk that did not run — the report-the-run rule applied
63
+ * to a constant instead of to a header.
64
+ */
65
+ export declare const DATA_FLOW_EDGE_TYPES: readonly ["PROPAGATES_TO", "READS", "WRITES", "RETURNS"];
66
+ export declare function dataFlowFrom(provider: AdjacencyProvider, nodeId: string, options?: TraversalOptions): QueryResult<{
67
+ node: IRNode;
68
+ depth: number;
69
+ score: number;
70
+ }[]>;
71
+ export declare function traceApi(provider: AdjacencyProvider, fromNodeId: string, toNodeId: string, options?: TraversalOptions): QueryResult<{
72
+ path: IRNode[];
73
+ hops: number;
74
+ }>;
75
+ export interface ChangeRisk {
76
+ readonly affected: {
77
+ node: IRNode;
78
+ depth: number;
79
+ score: number;
80
+ }[];
81
+ readonly tests: IRNode[];
82
+ readonly untested: IRNode[];
83
+ }
84
+ /**
85
+ * The scoped subgraph, ranked, intersected with `TESTS` edges.
86
+ *
87
+ * The ranking weights are Step 12's; this composes the primitives so that step
88
+ * supplies a weight function rather than a second traversal.
89
+ */
90
+ export declare function changeRisk(provider: AdjacencyProvider, changed: readonly string[], options?: ImpactOptions): QueryResult<ChangeRisk>;
91
+ export interface CoChange {
92
+ readonly node: IRNode;
93
+ /** Commits touching both files together, within the git source's own read window. */
94
+ readonly support: number;
95
+ /** `support` divided by the more-frequently-changed file's own total — DEC-036/§11.7. */
96
+ readonly confidence: number;
97
+ }
98
+ /**
99
+ * `CHANGES_WITH` edges touching one `FILE` node, in either direction.
100
+ *
101
+ * `CHANGES_WITH` is symmetric but stored once, `from` the lexicographically
102
+ * smaller path (DEC-036) — reading only `provider.outgoing` would silently
103
+ * miss every pair where this file sorts second. Both `outgoing` and
104
+ * `incoming` are read here so the caller never has to know which side of the
105
+ * pair this file landed on; `traverse.ts`'s `neighbours()` does the identical
106
+ * thing for `direction: "both"`, but a one-hop, unscored list is what this
107
+ * question actually asks — walking it through `bfs` would return `Reached`
108
+ * entries with no `support`/`confidence` to report, since those live in
109
+ * `attrs`, not in the traversal primitives' own `Reached` shape.
110
+ *
111
+ * Answers only what the stored graph holds: co-change is windowed by however
112
+ * far back the git source read (`GitSourceOptions`, not this function's
113
+ * concern), and a pair below `minSupport`/`minConfidence` at ingest time
114
+ * never became an edge at all — silence here does not mean the files never
115
+ * changed together, only that they did not clear the threshold recorded when
116
+ * the graph was built.
117
+ */
118
+ export declare function changesWith(provider: AdjacencyProvider, nodeId: string): QueryResult<CoChange[]>;
119
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/query/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,267 @@
1
+ /**
2
+ * The six query types of architecture §11.9, plus one added since: §18's
3
+ * `get_git_history`/`get_git_diff` named a real gap — `CHANGES_WITH` edges
4
+ * existed in the graph, produced by `analyze`'s git source, with no query
5
+ * reading them per node. `changesWith` (below) is that query. It is scoped to
6
+ * the stored co-change graph, never a live `git log`/`git diff` call — a new
7
+ * query over an existing edge type, not a new capability.
8
+ *
9
+ * Every one returns a `QueryResult`, so no caller can take the answer without
10
+ * the disclosure attached to it. That is the point of the envelope: §27.3's
11
+ * staleness rule and principle 3's resolution cap are not reporting concerns
12
+ * bolted on later, they are properties of the answer itself.
13
+ *
14
+ * One of the seven is **deliberately incomplete in this build** and says so —
15
+ * see `rootCauseSearch`. Reporting a partial answer as a whole one is the
16
+ * exact failure the honest-degradation rule exists to prevent.
17
+ */
18
+ import { bfs, findPath, weightedBfs } from "./traverse.js";
19
+ function stampFor(provider, resolutionFloor) {
20
+ return { ...provider.baseStamp(), resolutionFloor };
21
+ }
22
+ function result(provider, data, resolutionFloor, truncated, notes) {
23
+ if (truncated) {
24
+ notes.push("The node budget was reached, so this answer is partial. Nodes beyond the budget " +
25
+ "were not examined and are not reported as clean.");
26
+ }
27
+ return { data, stamp: stampFor(provider, resolutionFloor), truncated, notes };
28
+ }
29
+ /** Resolves reached ids to nodes, dropping any the provider no longer has. */
30
+ function hydrate(provider, reached) {
31
+ const out = [];
32
+ for (const entry of reached) {
33
+ const node = provider.node(entry.id);
34
+ if (node !== undefined)
35
+ out.push({ node, depth: entry.depth, score: entry.score });
36
+ }
37
+ return out;
38
+ }
39
+ export function impactOf(provider, seeds, options = {}) {
40
+ const outcome = weightedBfs(provider, seeds, {
41
+ direction: "in",
42
+ ...options,
43
+ ...(options.weightFor === undefined ? {} : { weightFor: options.weightFor }),
44
+ });
45
+ // Direction is `in` by default and that is not a typo: "what breaks if this
46
+ // changes" walks from the changed node to its *callers*, not its callees. A
47
+ // function's dependencies are unaffected by it changing; its dependents are
48
+ // the blast radius.
49
+ const notes = [];
50
+ if (outcome.resolutionFloor <= 1) {
51
+ notes.push(`This blast radius rests on edges resolved no better than R${outcome.resolutionFloor}. ` +
52
+ "Cross-file calls are not reliably resolved at that level, so the radius is a " +
53
+ "lower bound rather than a complete answer.");
54
+ }
55
+ return result(provider, hydrate(provider, outcome.reached), outcome.resolutionFloor, outcome.truncated, notes);
56
+ }
57
+ /**
58
+ * Incidents correlated with a node, by graph edges only.
59
+ *
60
+ * **Incomplete by design in this build, and the caller is told so.** §11.9's
61
+ * root-cause query is "incident **plus embedding match**", and this build has no
62
+ * vector store — `embeddings` is a pointer table, since §8.2 keeps vectors in
63
+ * pgvector or a local extension and a column of serialised floats with no index
64
+ * is a scan rather than a search.
65
+ *
66
+ * So this answers the structural half and discloses the other. Returning it
67
+ * silently as "root cause search" would report "we found no similar incident"
68
+ * when the truth is "we did not look the way we said we would" — §20.2 keeps
69
+ * those in different categories for a reason.
70
+ */
71
+ export function rootCauseSearch(provider, nodeId) {
72
+ const types = ["INCIDENT_CORRELATED", "FIXED_BY"];
73
+ const matches = [];
74
+ let floor = 4;
75
+ for (const edge of [...provider.incoming(nodeId, { types }), ...provider.outgoing(nodeId, { types })]) {
76
+ const otherId = edge.from === nodeId ? edge.to : edge.from;
77
+ const node = provider.node(otherId);
78
+ if (node === undefined)
79
+ continue;
80
+ if (node.type !== "INCIDENT" && node.type !== "FIX_PATTERN")
81
+ continue;
82
+ if (edge.resolution < floor)
83
+ floor = edge.resolution;
84
+ matches.push({ incident: node, via: edge.type });
85
+ }
86
+ return result(provider, matches, floor, false, [
87
+ "Structural incident links only. Embedding similarity was not run — this build has no " +
88
+ "vector store (§8.2), so a similar past incident with no graph edge to this node will " +
89
+ "not appear here. Absence is not evidence.",
90
+ ]);
91
+ }
92
+ // ---------------------------------------------------------------------------
93
+ // 3. Test discovery — "what tests cover this?"
94
+ // ---------------------------------------------------------------------------
95
+ export function testsCovering(provider, nodeId, options = {}) {
96
+ // `TESTS` edges inward, transitively: a test covering a handler also covers
97
+ // what the handler calls, and stopping at depth 1 would report a changed
98
+ // helper as untested when a test does exercise it.
99
+ const outcome = bfs(provider, [nodeId], {
100
+ direction: "in",
101
+ types: ["TESTS", "CALLS"],
102
+ maxDepth: options.maxDepth ?? 3,
103
+ ...(options.budget === undefined ? {} : { budget: options.budget }),
104
+ });
105
+ const tests = hydrate(provider, outcome.reached)
106
+ .map((r) => r.node)
107
+ .filter((n) => n.type === "TEST_CASE");
108
+ const notes = [];
109
+ if (outcome.resolutionFloor <= 1) {
110
+ notes.push(`Test discovery rests on R${outcome.resolutionFloor} edges. At that level cross-file calls ` +
111
+ "are unresolved, so tests reaching this node indirectly may be missing from this list.");
112
+ }
113
+ if (tests.length === 0) {
114
+ notes.push("No covering test was found. That is not the same as this code being untested — it may " +
115
+ "be exercised by a test the adapter could not link.");
116
+ }
117
+ return result(provider, tests, outcome.resolutionFloor, outcome.truncated, notes);
118
+ }
119
+ // ---------------------------------------------------------------------------
120
+ // 4. Data flow — "where does this field end up?"
121
+ // ---------------------------------------------------------------------------
122
+ /**
123
+ * The four edge types that carry data rather than control.
124
+ *
125
+ * Exported because a caller that discloses *what it walked* must name the same
126
+ * list this walk uses. A second copy in the MCP tool would drift, and the note
127
+ * would then describe a walk that did not run — the report-the-run rule applied
128
+ * to a constant instead of to a header.
129
+ */
130
+ export const DATA_FLOW_EDGE_TYPES = ["PROPAGATES_TO", "READS", "WRITES", "RETURNS"];
131
+ export function dataFlowFrom(provider, nodeId, options = {}) {
132
+ const outcome = bfs(provider, [nodeId], {
133
+ direction: "out",
134
+ types: [...DATA_FLOW_EDGE_TYPES],
135
+ ...options,
136
+ });
137
+ const notes = [];
138
+ if (outcome.resolutionFloor < 3) {
139
+ // §11A.6: data propagation compares *shapes*, not names, and shapes are an
140
+ // R3 capability. Below it the chain is path-level at best.
141
+ notes.push(`Field-level propagation requires R3; the edges here reach only R${outcome.resolutionFloor}. ` +
142
+ "This is a path-level answer — where data can flow, not which field arrives where.");
143
+ }
144
+ return result(provider, hydrate(provider, outcome.reached), outcome.resolutionFloor, outcome.truncated, notes);
145
+ }
146
+ // ---------------------------------------------------------------------------
147
+ // 5. API tracing — "how does this work end to end?"
148
+ // ---------------------------------------------------------------------------
149
+ export function traceApi(provider, fromNodeId, toNodeId, options = {}) {
150
+ const edges = findPath(provider, fromNodeId, toNodeId, { direction: "both", ...options });
151
+ const ids = edges.length === 0 ? [] : [fromNodeId];
152
+ for (const e of edges) {
153
+ // Each hop may be traversed in either direction, so the far end is
154
+ // whichever of the two is not wherever the walk actually is right now —
155
+ // tracked from `ids` itself, not re-derived from the previous edge's own
156
+ // `.to`, which is only correct when every hop happens to go forward.
157
+ // `direction: "both"` exists precisely so a hop can go either way (e.g.
158
+ // an incoming SERVES_API followed by an outgoing CALLS), and the old
159
+ // `edges[i - 1]!.to` comparison silently re-picked the node just left
160
+ // whenever the previous hop was traversed backward, duplicating it in
161
+ // the path instead of advancing.
162
+ const current = ids[ids.length - 1];
163
+ ids.push(e.from === current ? e.to : e.from);
164
+ }
165
+ const path = [];
166
+ for (const id of ids) {
167
+ const node = provider.node(id);
168
+ if (node !== undefined)
169
+ path.push(node);
170
+ }
171
+ let floor = 4;
172
+ for (const edge of edges)
173
+ if (edge.resolution < floor)
174
+ floor = edge.resolution;
175
+ const notes = edges.length === 0
176
+ ? ["No path found. The two nodes may be genuinely unconnected, or connected only by " +
177
+ "edges this resolution level cannot resolve."]
178
+ : [];
179
+ return result(provider, { path, hops: edges.length }, floor, false, notes);
180
+ }
181
+ /**
182
+ * The scoped subgraph, ranked, intersected with `TESTS` edges.
183
+ *
184
+ * The ranking weights are Step 12's; this composes the primitives so that step
185
+ * supplies a weight function rather than a second traversal.
186
+ */
187
+ export function changeRisk(provider, changed, options = {}) {
188
+ const impact = impactOf(provider, changed, options);
189
+ const tests = new Map();
190
+ const untested = [];
191
+ for (const entry of impact.data) {
192
+ if (entry.node.type === "TEST_CASE")
193
+ continue;
194
+ const covering = provider.incoming(entry.node.id, { types: ["TESTS"] });
195
+ if (covering.length === 0) {
196
+ untested.push(entry.node);
197
+ continue;
198
+ }
199
+ for (const edge of covering) {
200
+ const test = provider.node(edge.from);
201
+ if (test !== undefined)
202
+ tests.set(test.id, test);
203
+ }
204
+ }
205
+ const notes = [...impact.notes];
206
+ if (untested.length > 0) {
207
+ // §20.2's "not tested" category, populated rather than implied. This list is
208
+ // the honest half of the answer — the part a passing test run cannot cover.
209
+ notes.push(`${untested.length} affected node(s) have no covering test in the graph and cannot be ` +
210
+ "verified by re-running the suite.");
211
+ }
212
+ return {
213
+ data: { affected: impact.data, tests: [...tests.values()], untested },
214
+ stamp: impact.stamp,
215
+ truncated: impact.truncated,
216
+ notes,
217
+ };
218
+ }
219
+ /**
220
+ * `CHANGES_WITH` edges touching one `FILE` node, in either direction.
221
+ *
222
+ * `CHANGES_WITH` is symmetric but stored once, `from` the lexicographically
223
+ * smaller path (DEC-036) — reading only `provider.outgoing` would silently
224
+ * miss every pair where this file sorts second. Both `outgoing` and
225
+ * `incoming` are read here so the caller never has to know which side of the
226
+ * pair this file landed on; `traverse.ts`'s `neighbours()` does the identical
227
+ * thing for `direction: "both"`, but a one-hop, unscored list is what this
228
+ * question actually asks — walking it through `bfs` would return `Reached`
229
+ * entries with no `support`/`confidence` to report, since those live in
230
+ * `attrs`, not in the traversal primitives' own `Reached` shape.
231
+ *
232
+ * Answers only what the stored graph holds: co-change is windowed by however
233
+ * far back the git source read (`GitSourceOptions`, not this function's
234
+ * concern), and a pair below `minSupport`/`minConfidence` at ingest time
235
+ * never became an edge at all — silence here does not mean the files never
236
+ * changed together, only that they did not clear the threshold recorded when
237
+ * the graph was built.
238
+ */
239
+ export function changesWith(provider, nodeId) {
240
+ const edges = [
241
+ ...provider.outgoing(nodeId, { types: ["CHANGES_WITH"] }),
242
+ ...provider.incoming(nodeId, { types: ["CHANGES_WITH"] }),
243
+ ];
244
+ const byOther = new Map();
245
+ let floor = 4;
246
+ for (const edge of edges) {
247
+ const otherId = edge.from === nodeId ? edge.to : edge.from;
248
+ if (otherId === nodeId)
249
+ continue; // Self-pairs cannot occur (source dedupes per commit), guarded anyway.
250
+ const node = provider.node(otherId);
251
+ if (node === undefined)
252
+ continue;
253
+ if (edge.resolution < floor)
254
+ floor = edge.resolution;
255
+ const support = typeof edge.attrs?.["support"] === "number" ? edge.attrs["support"] : 0;
256
+ byOther.set(otherId, { node, support, confidence: edge.confidence });
257
+ }
258
+ const data = [...byOther.values()].sort((a, b) => b.support - a.support || a.node.id.localeCompare(b.node.id));
259
+ const notes = [];
260
+ if (data.length === 0) {
261
+ notes.push("No CHANGES_WITH edge touches this node. That may mean the file has no co-change history " +
262
+ "above the recorded support/confidence thresholds, or that git history was skipped when " +
263
+ "the graph was built — this query cannot tell the two apart from the graph alone.");
264
+ }
265
+ return result(provider, data, edges.length === 0 ? 0 : floor, false, notes);
266
+ }
267
+ //# sourceMappingURL=queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/query/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * The backing for `refusal_fetch` — `ai-tool-contract.md` §5.4, §8 endpoint 14.
3
+ *
4
+ * ## The premise this corrects
5
+ *
6
+ * `ai-layer-plan.md` §3 originally claimed this tool was cheap because
7
+ * "`askableHandle` exists in core and nothing serves it." Checked against
8
+ * `refusal-questions.ts` rather than taken on the plan's word, both halves
9
+ * were false: `askableHandle` is the *askable predicate* — `blockedBy` only
10
+ * for `refusalClass === "value-unknown"`, `null` for `capability-gap` /
11
+ * `out-of-scope` / `varies-per-call` / unset — and it is already served, by
12
+ * `packages/mcp/src/tools/questions.ts` via `groupRefusalsIntoQuestions`.
13
+ * The contract's own §5.4 records the correction; this module is the new
14
+ * work it points at.
15
+ *
16
+ * ## Why `groupRefusalsIntoQuestions` cannot be reused here
17
+ *
18
+ * That grouper drops every row that is not `value-unknown` **by design** —
19
+ * correct for its own purpose (a question queue only wants rows a human
20
+ * sentence can close), wrong for this one. A `refusal_fetch` that silently
21
+ * returned only the askable subset would be the empty-denominator defect
22
+ * (`ai-tool-contract.md` §1's "count over something that was not there,
23
+ * presented as a count of zero") wearing technique 4's clothes — the same
24
+ * defect class this project has already hit three times elsewhere
25
+ * (shopizer's 0-of-370 route count, airbyte's "not on disk", koa's silent
26
+ * `routers.size === 0`). This module therefore counts and pages **every**
27
+ * `UnresolvedRef`, of every `refusalClass` and unset alike.
28
+ *
29
+ * ## Call-site trap, named so it is not rediscovered the expensive way
30
+ *
31
+ * `store/reader.ts#unresolvedRefs` defaults `classified: true`, which
32
+ * restricts to `attrs IS NOT NULL` — exactly the rows a producer has
33
+ * classified at all. A caller that wires this module up to that reader
34
+ * without passing `{ classified: false }` will silently exclude every
35
+ * *unclassified* row from `count`, reproducing the same defect this module
36
+ * exists to prevent, one call site later. `summariseRefusals`/
37
+ * `fetchRefusalPage` cannot detect that mistake — they only know the
38
+ * population they were handed — so the honesty of `count` here is only as
39
+ * good as the completeness of what a caller passes in.
40
+ *
41
+ * ## The handle
42
+ *
43
+ * Stateless and self-describing (a base64url-encoded cursor plus a content
44
+ * fingerprint of the population it was issued against), not a session-cache
45
+ * lookup — so redemption is correct across process restarts and does not
46
+ * need this module to keep anything in memory between calls. An MCP surface
47
+ * that wants a prettier, shorter token (the contract's own illustrative
48
+ * `ref_9f2c1a`) is free to wrap this in a session cache; that is a
49
+ * presentation choice for P27, not a correctness requirement for this
50
+ * module.
51
+ *
52
+ * `UnresolvedRef` carries no stable id once it has crossed the store
53
+ * boundary (`store/reader.ts#toUnresolvedRef` does not carry the row's
54
+ * content-hash `id` column into the IR shape), so this module derives its
55
+ * own deterministic ordering key from the fields the type does carry. That
56
+ * key is what makes "same handle + same underlying population → same page
57
+ * ordering every time" true regardless of what order the caller's array
58
+ * happens to be in — a concatenation from several producers, or a
59
+ * differently-ordered SQL read, must not change which row lands on which
60
+ * page.
61
+ *
62
+ * Redeeming a handle that cannot be decoded, or whose population fingerprint
63
+ * no longer matches what is being read, is `refused` with a named reason —
64
+ * never a page that happens to be empty, and never a page silently drawn
65
+ * from the wrong cursor position. That is the rule the whole contract rests
66
+ * on (§1: `refused` is a fact about Descry, never a guess dressed as one),
67
+ * and this endpoint is the easiest place in the system to violate it
68
+ * silently.
69
+ */
70
+ import type { ResultState, UnresolvedRef } from "@descryy/ir";
71
+ /** `refusals` in the envelope (`ai-tool-contract.md` §5.4): `{ count, exemplar, handle }`. */
72
+ export interface RefusalSummary {
73
+ /** The honest denominator — every row in the population handed in, computed before any page cap. */
74
+ readonly count: number;
75
+ /** One row's `reason`, passed through unmodified — never re-worded, templated or truncated (contract §4). `null` only when `count === 0`. */
76
+ readonly exemplar: string | null;
77
+ /** Opaque; redeem with {@link fetchRefusalPage}. `null` only when `count === 0` — there is nothing to page through. */
78
+ readonly handle: string | null;
79
+ }
80
+ /**
81
+ * Summarise a population of refusal rows into the one-line shape the
82
+ * envelope carries. `refs` must already be the complete population the
83
+ * caller intends to disclose — see the module header's call-site trap for
84
+ * the classic way to under-supply it.
85
+ */
86
+ export declare function summariseRefusals(refs: readonly UnresolvedRef[], pageSize?: number): RefusalSummary;
87
+ export interface RefusalPageOk {
88
+ readonly state: Extract<ResultState, "ok">;
89
+ readonly items: readonly UnresolvedRef[];
90
+ /** The honest total, restated on every page — the truncation rule pointed the other way (contract §5.5). */
91
+ readonly total: number;
92
+ /** Redeem for the next page. `null` on the last page. */
93
+ readonly nextHandle: string | null;
94
+ }
95
+ export interface RefusalPageRefused {
96
+ readonly state: Extract<ResultState, "refused">;
97
+ /** Named and specific — never a generic "invalid handle" with nothing to act on. */
98
+ readonly reason: string;
99
+ }
100
+ export type RefusalPage = RefusalPageOk | RefusalPageRefused;
101
+ /**
102
+ * Redeem a handle against the current population. `refs` need not be
103
+ * pre-sorted or supplied in the same order as the call that minted the
104
+ * handle — ordering is re-derived deterministically every time.
105
+ *
106
+ * Three distinct ways to be `refused`, each named: the handle cannot be
107
+ * decoded at all; the population's content fingerprint no longer matches
108
+ * (the graph moved since the handle was issued); or the cursor position the
109
+ * handle names does not exist in the current population (only reachable via
110
+ * a handle not issued by this module's own chain, since a well-formed
111
+ * `nextHandle` is never offered past the end).
112
+ */
113
+ export declare function fetchRefusalPage(refs: readonly UnresolvedRef[], handle: string): RefusalPage;
114
+ //# sourceMappingURL=refusal-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refusal-fetch.d.ts","sourceRoot":"","sources":["../../src/query/refusal-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA8E9D,8FAA8F;AAC9F,MAAM,WAAW,cAAc;IAC7B,oGAAoG;IACpG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6IAA6I;IAC7I,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,uHAAuH;IACvH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,aAAa,EAAE,EAC9B,QAAQ,GAAE,MAA0B,GACnC,cAAc,CAgBhB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,4GAA4G;IAC5G,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAChD,oFAAoF;IACpF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAE7D;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,aAAa,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAoC5F"}