@mailwoman/resolver-wof-sqlite 9.1.0 → 9.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (501) hide show
  1. package/README.md +36 -20
  2. package/lib/address/index.ts +9 -0
  3. package/{address-point-interpolation.ts → lib/address/point-interpolation.ts} +40 -28
  4. package/{address-point-schema.ts → lib/address/point-schema.ts} +34 -8
  5. package/lib/address/point.ts +280 -0
  6. package/{ancestry-backfill.ts → lib/ancestry/backfill.ts} +14 -19
  7. package/{ancestry.ts → lib/ancestry/index.ts} +13 -8
  8. package/{build-candidate.ts → lib/build-candidate.ts} +243 -199
  9. package/{build-slim.ts → lib/build-slim.ts} +153 -168
  10. package/lib/candidate/alias-bags.ts +56 -0
  11. package/lib/candidate/ancestors-sidecar.ts +204 -0
  12. package/lib/candidate/country-display-names.ts +79 -0
  13. package/lib/candidate/extract-fold.ts +138 -0
  14. package/lib/candidate/name-roles.ts +238 -0
  15. package/lib/candidate/own-name.ts +146 -0
  16. package/lib/candidate/place-attrs.ts +44 -0
  17. package/lib/candidate-ancestors-schema.ts +195 -0
  18. package/{candidate-fts.ts → lib/candidate-fts.ts} +7 -5
  19. package/{candidate-importance.ts → lib/candidate-importance.ts} +54 -57
  20. package/lib/candidate-lookup.ts +976 -0
  21. package/{candidate-schema.ts → lib/candidate-schema.ts} +34 -6
  22. package/lib/candidate-scoring.ts +261 -0
  23. package/lib/capital-schema.ts +89 -0
  24. package/lib/capitals.ts +148 -0
  25. package/{coincident-roles.ts → lib/coincident-roles.ts} +75 -19
  26. package/{convention.ts → lib/convention/index.ts} +5 -5
  27. package/lib/convention/schema.ts +72 -0
  28. package/{coverage-manifest-schema.ts → lib/coverage-manifest-schema.ts} +15 -16
  29. package/lib/currency-backfill.ts +334 -0
  30. package/lib/env.ts +50 -0
  31. package/lib/exact-match.ts +113 -0
  32. package/{sharding.ts → lib/extracts.ts} +63 -60
  33. package/lib/fst/autocomplete.ts +176 -0
  34. package/{fst-builder.ts → lib/fst/builder.ts} +30 -27
  35. package/{fst-deserialize-web.ts → lib/fst/deserialize-web.ts} +27 -87
  36. package/lib/fst/format.ts +106 -0
  37. package/{fst-freshness.ts → lib/fst/freshness.ts} +42 -75
  38. package/lib/fst/index.ts +14 -0
  39. package/{fst-matcher.ts → lib/fst/matcher.ts} +1 -1
  40. package/{fst-serialize.ts → lib/fst/serialize.ts} +37 -115
  41. package/{fst-types.ts → lib/fst/types.ts} +4 -2
  42. package/{fts.ts → lib/fts/index.ts} +28 -23
  43. package/{fts-query.ts → lib/fts/query.ts} +2 -2
  44. package/{geonames-aliases.ts → lib/geonames/aliases.ts} +13 -13
  45. package/lib/geonames/index.ts +8 -0
  46. package/{geonames-postal.ts → lib/geonames/postal.ts} +16 -15
  47. package/{index.ts → lib/index.ts} +52 -48
  48. package/{interpolation.ts → lib/interpolation.ts} +137 -41
  49. package/lib/lookup.ts +861 -0
  50. package/{name-score.ts → lib/name-score.ts} +6 -4
  51. package/lib/nsul/index.ts +8 -0
  52. package/lib/nsul/lookup.ts +144 -0
  53. package/lib/nsul/schema.ts +130 -0
  54. package/{place-importance-schema.ts → lib/place-importance-schema.ts} +70 -22
  55. package/lib/poi/index.ts +8 -0
  56. package/{poi-lookup.ts → lib/poi/lookup.ts} +32 -39
  57. package/{poi-schema.ts → lib/poi/schema.ts} +10 -6
  58. package/lib/polygon-schema.ts +47 -0
  59. package/{postal-city-alias-lookup.ts → lib/postal/city-alias-lookup.ts} +15 -21
  60. package/{postal-city-candidate-schema.ts → lib/postal/city-candidate-schema.ts} +4 -2
  61. package/lib/postal/index.ts +9 -0
  62. package/{postcode-point-lookup.ts → lib/postcode-point-lookup.ts} +17 -15
  63. package/lib/primary-preference.ts +226 -0
  64. package/lib/proximity-rerank.ts +120 -0
  65. package/{ranking-weights.ts → lib/ranking-weights.ts} +30 -4
  66. package/lib/region-keys.ts +144 -0
  67. package/{reverse.ts → lib/reverse.ts} +45 -56
  68. package/{schema.ts → lib/schema.ts} +11 -1
  69. package/lib/search-fetch.ts +257 -0
  70. package/{sqlite-convention-source.ts → lib/sqlite-convention-source.ts} +9 -10
  71. package/lib/sqlite-utils.ts +83 -0
  72. package/{street-centroid-schema.ts → lib/street/centroid-schema.ts} +12 -6
  73. package/{street-centroid.ts → lib/street/centroid.ts} +26 -28
  74. package/lib/street/index.ts +13 -0
  75. package/{street-morphology-fst-builder.ts → lib/street/morphology-fst-builder.ts} +24 -14
  76. package/{street-morphology-fst-loader.ts → lib/street/morphology-fst-loader.ts} +14 -12
  77. package/{street-name-lookup.ts → lib/street/name-lookup.ts} +14 -30
  78. package/lib/street/normalize.ts +572 -0
  79. package/{street-segment-schema.ts → lib/street/segment-schema.ts} +13 -8
  80. package/{types.ts → lib/types.ts} +49 -9
  81. package/{unified-schema.ts → lib/unified-schema.ts} +21 -25
  82. package/lib/uprn/existence.ts +84 -0
  83. package/lib/uprn/index.ts +9 -0
  84. package/lib/uprn/lookup.ts +206 -0
  85. package/lib/uprn/schema.ts +124 -0
  86. package/lib/weights-overlay-linker.ts +878 -0
  87. package/out/address/index.d.ts +9 -0
  88. package/out/address/index.d.ts.map +1 -0
  89. package/out/address/index.js +9 -0
  90. package/out/address/index.js.map +1 -0
  91. package/out/{address-point-interpolation.d.ts → address/point-interpolation.d.ts} +11 -10
  92. package/out/address/point-interpolation.d.ts.map +1 -0
  93. package/out/{address-point-interpolation.js → address/point-interpolation.js} +29 -23
  94. package/out/address/point-interpolation.js.map +1 -0
  95. package/out/{address-point-schema.d.ts → address/point-schema.d.ts} +30 -10
  96. package/out/address/point-schema.d.ts.map +1 -0
  97. package/out/{address-point-schema.js → address/point-schema.js} +7 -3
  98. package/out/address/point-schema.js.map +1 -0
  99. package/out/{address-point.d.ts → address/point.d.ts} +16 -8
  100. package/out/address/point.d.ts.map +1 -0
  101. package/out/address/point.js +191 -0
  102. package/out/address/point.js.map +1 -0
  103. package/out/{ancestry-backfill.d.ts → ancestry/backfill.d.ts} +7 -5
  104. package/out/ancestry/backfill.d.ts.map +1 -0
  105. package/out/{ancestry-backfill.js → ancestry/backfill.js} +12 -16
  106. package/out/ancestry/backfill.js.map +1 -0
  107. package/out/{ancestry.d.ts → ancestry/index.d.ts} +6 -5
  108. package/out/ancestry/index.d.ts.map +1 -0
  109. package/out/{ancestry.js → ancestry/index.js} +7 -7
  110. package/out/ancestry/index.js.map +1 -0
  111. package/out/build-candidate.d.ts +88 -7
  112. package/out/build-candidate.d.ts.map +1 -1
  113. package/out/build-candidate.js +145 -149
  114. package/out/build-candidate.js.map +1 -1
  115. package/out/build-slim.d.ts +5 -5
  116. package/out/build-slim.d.ts.map +1 -1
  117. package/out/build-slim.js +127 -142
  118. package/out/build-slim.js.map +1 -1
  119. package/out/candidate/alias-bags.d.ts +19 -0
  120. package/out/candidate/alias-bags.d.ts.map +1 -0
  121. package/out/candidate/alias-bags.js +39 -0
  122. package/out/candidate/alias-bags.js.map +1 -0
  123. package/out/candidate/ancestors-sidecar.d.ts +32 -0
  124. package/out/candidate/ancestors-sidecar.d.ts.map +1 -0
  125. package/out/candidate/ancestors-sidecar.js +140 -0
  126. package/out/candidate/ancestors-sidecar.js.map +1 -0
  127. package/out/candidate/country-display-names.d.ts +35 -0
  128. package/out/candidate/country-display-names.d.ts.map +1 -0
  129. package/out/candidate/country-display-names.js +59 -0
  130. package/out/candidate/country-display-names.js.map +1 -0
  131. package/out/candidate/extract-fold.d.ts +32 -0
  132. package/out/candidate/extract-fold.d.ts.map +1 -0
  133. package/out/candidate/extract-fold.js +104 -0
  134. package/out/candidate/extract-fold.js.map +1 -0
  135. package/out/candidate/name-roles.d.ts +57 -0
  136. package/out/candidate/name-roles.d.ts.map +1 -0
  137. package/out/candidate/name-roles.js +166 -0
  138. package/out/candidate/name-roles.js.map +1 -0
  139. package/out/candidate/own-name.d.ts +50 -0
  140. package/out/candidate/own-name.d.ts.map +1 -0
  141. package/out/candidate/own-name.js +132 -0
  142. package/out/candidate/own-name.js.map +1 -0
  143. package/out/candidate/place-attrs.d.ts +43 -0
  144. package/out/candidate/place-attrs.d.ts.map +1 -0
  145. package/out/candidate/place-attrs.js +15 -0
  146. package/out/candidate/place-attrs.js.map +1 -0
  147. package/out/candidate-ancestors-schema.d.ts +150 -0
  148. package/out/candidate-ancestors-schema.d.ts.map +1 -0
  149. package/out/candidate-ancestors-schema.js +123 -0
  150. package/out/candidate-ancestors-schema.js.map +1 -0
  151. package/out/candidate-fts.d.ts +7 -5
  152. package/out/candidate-fts.d.ts.map +1 -1
  153. package/out/candidate-fts.js +5 -3
  154. package/out/candidate-fts.js.map +1 -1
  155. package/out/candidate-importance.d.ts +16 -16
  156. package/out/candidate-importance.d.ts.map +1 -1
  157. package/out/candidate-importance.js +47 -52
  158. package/out/candidate-importance.js.map +1 -1
  159. package/out/candidate-lookup.d.ts +31 -52
  160. package/out/candidate-lookup.d.ts.map +1 -1
  161. package/out/candidate-lookup.js +380 -172
  162. package/out/candidate-lookup.js.map +1 -1
  163. package/out/candidate-schema.d.ts +31 -7
  164. package/out/candidate-schema.d.ts.map +1 -1
  165. package/out/candidate-schema.js +3 -0
  166. package/out/candidate-schema.js.map +1 -1
  167. package/out/candidate-scoring.d.ts +34 -0
  168. package/out/candidate-scoring.d.ts.map +1 -0
  169. package/out/candidate-scoring.js +196 -0
  170. package/out/candidate-scoring.js.map +1 -0
  171. package/out/capital-schema.d.ts +51 -0
  172. package/out/capital-schema.d.ts.map +1 -0
  173. package/out/capital-schema.js +63 -0
  174. package/out/capital-schema.js.map +1 -0
  175. package/out/capitals.d.ts +69 -0
  176. package/out/capitals.d.ts.map +1 -0
  177. package/out/capitals.js +98 -0
  178. package/out/capitals.js.map +1 -0
  179. package/out/coincident-roles.d.ts +12 -4
  180. package/out/coincident-roles.d.ts.map +1 -1
  181. package/out/coincident-roles.js +43 -11
  182. package/out/coincident-roles.js.map +1 -1
  183. package/out/{convention.d.ts → convention/index.d.ts} +5 -5
  184. package/out/convention/index.d.ts.map +1 -0
  185. package/out/{convention.js → convention/index.js} +4 -4
  186. package/out/convention/index.js.map +1 -0
  187. package/out/convention/schema.d.ts +51 -0
  188. package/out/convention/schema.d.ts.map +1 -0
  189. package/out/convention/schema.js +34 -0
  190. package/out/convention/schema.js.map +1 -0
  191. package/out/coverage-manifest-schema.d.ts +8 -8
  192. package/out/coverage-manifest-schema.d.ts.map +1 -1
  193. package/out/coverage-manifest-schema.js +6 -10
  194. package/out/coverage-manifest-schema.js.map +1 -1
  195. package/out/currency-backfill.d.ts +90 -0
  196. package/out/currency-backfill.d.ts.map +1 -0
  197. package/out/currency-backfill.js +196 -0
  198. package/out/currency-backfill.js.map +1 -0
  199. package/out/env.d.ts +43 -0
  200. package/out/env.d.ts.map +1 -0
  201. package/out/env.js +48 -0
  202. package/out/env.js.map +1 -0
  203. package/out/exact-match.d.ts +25 -0
  204. package/out/exact-match.d.ts.map +1 -0
  205. package/out/exact-match.js +88 -0
  206. package/out/exact-match.js.map +1 -0
  207. package/out/extracts.d.ts +114 -0
  208. package/out/extracts.d.ts.map +1 -0
  209. package/out/{sharding.js → extracts.js} +38 -38
  210. package/out/extracts.js.map +1 -0
  211. package/out/{fst-autocomplete.d.ts → fst/autocomplete.d.ts} +13 -13
  212. package/out/fst/autocomplete.d.ts.map +1 -0
  213. package/out/fst/autocomplete.js +113 -0
  214. package/out/fst/autocomplete.js.map +1 -0
  215. package/out/{fst-builder.d.ts → fst/builder.d.ts} +5 -5
  216. package/out/fst/builder.d.ts.map +1 -0
  217. package/out/{fst-builder.js → fst/builder.js} +24 -24
  218. package/out/fst/builder.js.map +1 -0
  219. package/out/{fst-deserialize-web.d.ts → fst/deserialize-web.d.ts} +3 -3
  220. package/out/fst/deserialize-web.d.ts.map +1 -0
  221. package/out/{fst-deserialize-web.js → fst/deserialize-web.js} +10 -74
  222. package/out/fst/deserialize-web.js.map +1 -0
  223. package/out/fst/format.d.ts +80 -0
  224. package/out/fst/format.d.ts.map +1 -0
  225. package/out/fst/format.js +91 -0
  226. package/out/fst/format.js.map +1 -0
  227. package/out/{fst-freshness.d.ts → fst/freshness.d.ts} +11 -14
  228. package/out/fst/freshness.d.ts.map +1 -0
  229. package/out/{fst-freshness.js → fst/freshness.js} +42 -74
  230. package/out/fst/freshness.js.map +1 -0
  231. package/out/fst/index.d.ts +14 -0
  232. package/out/fst/index.d.ts.map +1 -0
  233. package/out/fst/index.js +14 -0
  234. package/out/fst/index.js.map +1 -0
  235. package/out/{fst-matcher.d.ts → fst/matcher.d.ts} +2 -2
  236. package/out/fst/matcher.d.ts.map +1 -0
  237. package/out/{fst-matcher.js → fst/matcher.js} +1 -1
  238. package/out/fst/matcher.js.map +1 -0
  239. package/out/{fst-serialize.d.ts → fst/serialize.d.ts} +5 -10
  240. package/out/fst/serialize.d.ts.map +1 -0
  241. package/out/{fst-serialize.js → fst/serialize.js} +18 -98
  242. package/out/fst/serialize.js.map +1 -0
  243. package/out/{fst-types.d.ts → fst/types.d.ts} +4 -3
  244. package/out/fst/types.d.ts.map +1 -0
  245. package/out/{fst-types.js → fst/types.js} +1 -1
  246. package/out/fst/types.js.map +1 -0
  247. package/out/{fts.d.ts → fts/index.d.ts} +20 -13
  248. package/out/fts/index.d.ts.map +1 -0
  249. package/out/{fts.js → fts/index.js} +20 -15
  250. package/out/fts/index.js.map +1 -0
  251. package/out/{fts-query.d.ts → fts/query.d.ts} +2 -2
  252. package/out/fts/query.d.ts.map +1 -0
  253. package/out/{fts-query.js → fts/query.js} +2 -2
  254. package/out/fts/query.js.map +1 -0
  255. package/out/{geonames-aliases.d.ts → geonames/aliases.d.ts} +8 -6
  256. package/out/geonames/aliases.d.ts.map +1 -0
  257. package/out/{geonames-aliases.js → geonames/aliases.js} +7 -7
  258. package/out/geonames/aliases.js.map +1 -0
  259. package/out/geonames/index.d.ts +8 -0
  260. package/out/geonames/index.d.ts.map +1 -0
  261. package/out/geonames/index.js +8 -0
  262. package/out/geonames/index.js.map +1 -0
  263. package/out/{geonames-postal.d.ts → geonames/postal.d.ts} +12 -10
  264. package/out/geonames/postal.d.ts.map +1 -0
  265. package/out/{geonames-postal.js → geonames/postal.js} +11 -11
  266. package/out/geonames/postal.js.map +1 -0
  267. package/out/index.d.ts +32 -31
  268. package/out/index.d.ts.map +1 -1
  269. package/out/index.js +24 -24
  270. package/out/index.js.map +1 -1
  271. package/out/interpolation.d.ts +18 -9
  272. package/out/interpolation.d.ts.map +1 -1
  273. package/out/interpolation.js +108 -36
  274. package/out/interpolation.js.map +1 -1
  275. package/out/lookup.d.ts +25 -25
  276. package/out/lookup.d.ts.map +1 -1
  277. package/out/lookup.js +174 -558
  278. package/out/lookup.js.map +1 -1
  279. package/out/name-score.d.ts +0 -10
  280. package/out/name-score.d.ts.map +1 -1
  281. package/out/name-score.js +6 -4
  282. package/out/name-score.js.map +1 -1
  283. package/out/nsul/index.d.ts +8 -0
  284. package/out/nsul/index.d.ts.map +1 -0
  285. package/out/nsul/index.js +8 -0
  286. package/out/nsul/index.js.map +1 -0
  287. package/out/nsul/lookup.d.ts +83 -0
  288. package/out/nsul/lookup.d.ts.map +1 -0
  289. package/out/nsul/lookup.js +80 -0
  290. package/out/nsul/lookup.js.map +1 -0
  291. package/out/nsul/schema.d.ts +100 -0
  292. package/out/nsul/schema.d.ts.map +1 -0
  293. package/out/nsul/schema.js +78 -0
  294. package/out/nsul/schema.js.map +1 -0
  295. package/out/place-importance-schema.d.ts +47 -10
  296. package/out/place-importance-schema.d.ts.map +1 -1
  297. package/out/place-importance-schema.js +56 -10
  298. package/out/place-importance-schema.js.map +1 -1
  299. package/out/poi/index.d.ts +8 -0
  300. package/out/poi/index.d.ts.map +1 -0
  301. package/out/poi/index.js +8 -0
  302. package/out/poi/index.js.map +1 -0
  303. package/out/{poi-lookup.d.ts → poi/lookup.d.ts} +8 -10
  304. package/out/poi/lookup.d.ts.map +1 -0
  305. package/out/{poi-lookup.js → poi/lookup.js} +24 -29
  306. package/out/poi/lookup.js.map +1 -0
  307. package/out/{poi-schema.d.ts → poi/schema.d.ts} +10 -6
  308. package/out/poi/schema.d.ts.map +1 -0
  309. package/out/{poi-schema.js → poi/schema.js} +1 -1
  310. package/out/poi/schema.js.map +1 -0
  311. package/out/polygon-schema.d.ts +37 -0
  312. package/out/polygon-schema.d.ts.map +1 -0
  313. package/out/polygon-schema.js +23 -0
  314. package/out/polygon-schema.js.map +1 -0
  315. package/out/{postal-city-alias-lookup.d.ts → postal/city-alias-lookup.d.ts} +7 -6
  316. package/out/postal/city-alias-lookup.d.ts.map +1 -0
  317. package/out/{postal-city-alias-lookup.js → postal/city-alias-lookup.js} +12 -16
  318. package/out/postal/city-alias-lookup.js.map +1 -0
  319. package/out/{postal-city-alias-schema.d.ts → postal/city-alias-schema.d.ts} +1 -1
  320. package/out/{postal-city-alias-schema.d.ts.map → postal/city-alias-schema.d.ts.map} +1 -1
  321. package/out/{postal-city-alias-schema.js → postal/city-alias-schema.js} +1 -1
  322. package/out/{postal-city-alias-schema.js.map → postal/city-alias-schema.js.map} +1 -1
  323. package/out/{postal-city-candidate-schema.d.ts → postal/city-candidate-schema.d.ts} +4 -3
  324. package/out/postal/city-candidate-schema.d.ts.map +1 -0
  325. package/out/{postal-city-candidate-schema.js → postal/city-candidate-schema.js} +2 -2
  326. package/out/{postal-city-candidate-schema.js.map → postal/city-candidate-schema.js.map} +1 -1
  327. package/out/postal/index.d.ts +9 -0
  328. package/out/postal/index.d.ts.map +1 -0
  329. package/out/postal/index.js +9 -0
  330. package/out/postal/index.js.map +1 -0
  331. package/out/postcode-point-lookup.d.ts +10 -10
  332. package/out/postcode-point-lookup.d.ts.map +1 -1
  333. package/out/postcode-point-lookup.js +13 -13
  334. package/out/postcode-point-lookup.js.map +1 -1
  335. package/out/primary-preference.d.ts +133 -0
  336. package/out/primary-preference.d.ts.map +1 -0
  337. package/out/primary-preference.js +146 -0
  338. package/out/primary-preference.js.map +1 -0
  339. package/out/proximity-rerank.d.ts +77 -0
  340. package/out/proximity-rerank.d.ts.map +1 -0
  341. package/out/proximity-rerank.js +86 -0
  342. package/out/proximity-rerank.js.map +1 -0
  343. package/out/ranking-weights.d.ts +15 -3
  344. package/out/ranking-weights.d.ts.map +1 -1
  345. package/out/ranking-weights.js +21 -3
  346. package/out/ranking-weights.js.map +1 -1
  347. package/out/region-keys.d.ts +47 -0
  348. package/out/region-keys.d.ts.map +1 -0
  349. package/out/region-keys.js +121 -0
  350. package/out/region-keys.js.map +1 -0
  351. package/out/reverse.d.ts +6 -6
  352. package/out/reverse.d.ts.map +1 -1
  353. package/out/reverse.js +23 -35
  354. package/out/reverse.js.map +1 -1
  355. package/out/schema.d.ts +10 -1
  356. package/out/schema.d.ts.map +1 -1
  357. package/out/schema.js.map +1 -1
  358. package/out/search-fetch.d.ts +59 -0
  359. package/out/search-fetch.d.ts.map +1 -0
  360. package/out/search-fetch.js +184 -0
  361. package/out/search-fetch.js.map +1 -0
  362. package/out/sqlite-convention-source.d.ts +7 -7
  363. package/out/sqlite-convention-source.d.ts.map +1 -1
  364. package/out/sqlite-convention-source.js +5 -5
  365. package/out/sqlite-convention-source.js.map +1 -1
  366. package/out/sqlite-utils.d.ts +24 -6
  367. package/out/sqlite-utils.d.ts.map +1 -1
  368. package/out/sqlite-utils.js +24 -7
  369. package/out/sqlite-utils.js.map +1 -1
  370. package/out/{street-centroid-schema.d.ts → street/centroid-schema.d.ts} +12 -7
  371. package/out/street/centroid-schema.d.ts.map +1 -0
  372. package/out/{street-centroid-schema.js → street/centroid-schema.js} +5 -5
  373. package/out/{street-centroid-schema.js.map → street/centroid-schema.js.map} +1 -1
  374. package/out/{street-centroid.d.ts → street/centroid.d.ts} +6 -6
  375. package/out/street/centroid.d.ts.map +1 -0
  376. package/out/{street-centroid.js → street/centroid.js} +18 -24
  377. package/out/street/centroid.js.map +1 -0
  378. package/out/street/index.d.ts +13 -0
  379. package/out/street/index.d.ts.map +1 -0
  380. package/out/street/index.js +13 -0
  381. package/out/street/index.js.map +1 -0
  382. package/out/{street-morphology-fst-builder.d.ts → street/morphology-fst-builder.d.ts} +4 -4
  383. package/out/street/morphology-fst-builder.d.ts.map +1 -0
  384. package/out/{street-morphology-fst-builder.js → street/morphology-fst-builder.js} +18 -13
  385. package/out/street/morphology-fst-builder.js.map +1 -0
  386. package/out/{street-morphology-fst-loader.d.ts → street/morphology-fst-loader.d.ts} +5 -5
  387. package/out/street/morphology-fst-loader.d.ts.map +1 -0
  388. package/out/{street-morphology-fst-loader.js → street/morphology-fst-loader.js} +11 -10
  389. package/out/street/morphology-fst-loader.js.map +1 -0
  390. package/out/{street-name-lookup.d.ts → street/name-lookup.d.ts} +4 -7
  391. package/out/street/name-lookup.d.ts.map +1 -0
  392. package/out/{street-name-lookup.js → street/name-lookup.js} +9 -23
  393. package/out/street/name-lookup.js.map +1 -0
  394. package/out/street/normalize.d.ts +179 -0
  395. package/out/street/normalize.d.ts.map +1 -0
  396. package/out/street/normalize.js +457 -0
  397. package/out/street/normalize.js.map +1 -0
  398. package/out/{street-segment-schema.d.ts → street/segment-schema.d.ts} +13 -9
  399. package/out/street/segment-schema.d.ts.map +1 -0
  400. package/out/{street-segment-schema.js → street/segment-schema.js} +4 -4
  401. package/out/{street-segment-schema.js.map → street/segment-schema.js.map} +1 -1
  402. package/out/types.d.ts +49 -9
  403. package/out/types.d.ts.map +1 -1
  404. package/out/types.js.map +1 -1
  405. package/out/unified-schema.d.ts +6 -5
  406. package/out/unified-schema.d.ts.map +1 -1
  407. package/out/unified-schema.js +16 -19
  408. package/out/unified-schema.js.map +1 -1
  409. package/out/uprn/existence.d.ts +53 -0
  410. package/out/uprn/existence.d.ts.map +1 -0
  411. package/out/uprn/existence.js +61 -0
  412. package/out/uprn/existence.js.map +1 -0
  413. package/out/uprn/index.d.ts +9 -0
  414. package/out/uprn/index.d.ts.map +1 -0
  415. package/out/uprn/index.js +9 -0
  416. package/out/uprn/index.js.map +1 -0
  417. package/out/uprn/lookup.d.ts +85 -0
  418. package/out/uprn/lookup.d.ts.map +1 -0
  419. package/out/uprn/lookup.js +149 -0
  420. package/out/uprn/lookup.js.map +1 -0
  421. package/out/uprn/schema.d.ts +93 -0
  422. package/out/uprn/schema.d.ts.map +1 -0
  423. package/out/uprn/schema.js +78 -0
  424. package/out/uprn/schema.js.map +1 -0
  425. package/out/weights-overlay-linker.d.ts +299 -0
  426. package/out/weights-overlay-linker.d.ts.map +1 -0
  427. package/out/weights-overlay-linker.js +511 -0
  428. package/out/weights-overlay-linker.js.map +1 -0
  429. package/package.json +622 -154
  430. package/address-point.ts +0 -125
  431. package/candidate-lookup.ts +0 -720
  432. package/fst-autocomplete.ts +0 -204
  433. package/geo.ts +0 -121
  434. package/lookup.ts +0 -1354
  435. package/out/address-point-interpolation.d.ts.map +0 -1
  436. package/out/address-point-interpolation.js.map +0 -1
  437. package/out/address-point-schema.d.ts.map +0 -1
  438. package/out/address-point-schema.js.map +0 -1
  439. package/out/address-point.d.ts.map +0 -1
  440. package/out/address-point.js +0 -84
  441. package/out/address-point.js.map +0 -1
  442. package/out/ancestry-backfill.d.ts.map +0 -1
  443. package/out/ancestry-backfill.js.map +0 -1
  444. package/out/ancestry.d.ts.map +0 -1
  445. package/out/ancestry.js.map +0 -1
  446. package/out/convention.d.ts.map +0 -1
  447. package/out/convention.js.map +0 -1
  448. package/out/fst-autocomplete.d.ts.map +0 -1
  449. package/out/fst-autocomplete.js +0 -130
  450. package/out/fst-autocomplete.js.map +0 -1
  451. package/out/fst-builder.d.ts.map +0 -1
  452. package/out/fst-builder.js.map +0 -1
  453. package/out/fst-deserialize-web.d.ts.map +0 -1
  454. package/out/fst-deserialize-web.js.map +0 -1
  455. package/out/fst-freshness.d.ts.map +0 -1
  456. package/out/fst-freshness.js.map +0 -1
  457. package/out/fst-matcher.d.ts.map +0 -1
  458. package/out/fst-matcher.js.map +0 -1
  459. package/out/fst-serialize.d.ts.map +0 -1
  460. package/out/fst-serialize.js.map +0 -1
  461. package/out/fst-types.d.ts.map +0 -1
  462. package/out/fst-types.js.map +0 -1
  463. package/out/fts-query.d.ts.map +0 -1
  464. package/out/fts-query.js.map +0 -1
  465. package/out/fts.d.ts.map +0 -1
  466. package/out/fts.js.map +0 -1
  467. package/out/geo.d.ts +0 -74
  468. package/out/geo.d.ts.map +0 -1
  469. package/out/geo.js +0 -71
  470. package/out/geo.js.map +0 -1
  471. package/out/geonames-aliases.d.ts.map +0 -1
  472. package/out/geonames-aliases.js.map +0 -1
  473. package/out/geonames-postal.d.ts.map +0 -1
  474. package/out/geonames-postal.js.map +0 -1
  475. package/out/poi-lookup.d.ts.map +0 -1
  476. package/out/poi-lookup.js.map +0 -1
  477. package/out/poi-schema.d.ts.map +0 -1
  478. package/out/poi-schema.js.map +0 -1
  479. package/out/postal-city-alias-lookup.d.ts.map +0 -1
  480. package/out/postal-city-alias-lookup.js.map +0 -1
  481. package/out/postal-city-candidate-schema.d.ts.map +0 -1
  482. package/out/sharding.d.ts +0 -114
  483. package/out/sharding.d.ts.map +0 -1
  484. package/out/sharding.js.map +0 -1
  485. package/out/street-centroid-schema.d.ts.map +0 -1
  486. package/out/street-centroid.d.ts.map +0 -1
  487. package/out/street-centroid.js.map +0 -1
  488. package/out/street-morphology-fst-builder.d.ts.map +0 -1
  489. package/out/street-morphology-fst-builder.js.map +0 -1
  490. package/out/street-morphology-fst-loader.d.ts.map +0 -1
  491. package/out/street-morphology-fst-loader.js.map +0 -1
  492. package/out/street-name-lookup.d.ts.map +0 -1
  493. package/out/street-name-lookup.js.map +0 -1
  494. package/out/street-normalize.d.ts +0 -95
  495. package/out/street-normalize.d.ts.map +0 -1
  496. package/out/street-normalize.js +0 -272
  497. package/out/street-normalize.js.map +0 -1
  498. package/out/street-segment-schema.d.ts.map +0 -1
  499. package/sqlite-utils.ts +0 -46
  500. package/street-normalize.ts +0 -318
  501. /package/{postal-city-alias-schema.ts → lib/postal/city-alias-schema.ts} +0 -0
@@ -4,7 +4,7 @@
4
4
  * @author Teffen Ellis, et al.
5
5
  */
6
6
 
7
- export type { FindPlaceQuery, GeoBbox, GeoPoint, PlaceCandidate, PlaceLookup, WOFPlacetype } from "./types.ts"
7
+ export type { FindPlaceQuery, GeoBbox, GeoPoint, PlaceCandidate, PlaceLookup, WOFPlacetype } from "#types"
8
8
 
9
9
  export type {
10
10
  AncestorsTable,
@@ -17,20 +17,37 @@ export type {
17
17
  PlaceSearchTable,
18
18
  SprTable,
19
19
  WOFDatabase,
20
- } from "./schema.ts"
20
+ } from "#schema"
21
21
 
22
- export { WOFSqlitePlaceLookup, type RankingWeights, type WOFSqlitePlaceLookupOpts } from "./lookup.ts"
22
+ export { WOFSQLitePlaceLookup, type RankingWeights, type WOFSQLitePlaceLookupOpts } from "#lookup"
23
23
 
24
- export { CANDIDATE_FTS_TABLE, createCandidateFTS } from "./candidate-fts.ts"
24
+ export {
25
+ CANDIDATE_ANCESTOR_COLUMNS,
26
+ CANDIDATE_ANCESTOR_TABLE,
27
+ CANDIDATE_INTERVAL_TABLE,
28
+ createCandidateAncestorTable,
29
+ createCandidateIntervalTable,
30
+ intervalContains,
31
+ MAX_ANCESTOR_DEPTH,
32
+ } from "#candidate-ancestors-schema"
33
+
34
+ export type {
35
+ CandidateAncestorsDatabase,
36
+ CandidateAncestorTable,
37
+ CandidateIntervalTable,
38
+ IntervalLabel,
39
+ } from "#candidate-ancestors-schema"
40
+
41
+ export { CANDIDATE_FTS_TABLE, createCandidateFTS } from "#candidate-fts"
25
42
 
26
43
  export {
27
44
  ImportanceIndex,
28
- IMPORTANCE_JOIN_GATE_KM,
45
+ IMPORTANCE_JOIN_RADIUS_KM,
29
46
  type ImportanceIndexStats,
30
47
  loadImportanceIndex,
31
- } from "./candidate-importance.ts"
48
+ } from "#candidate-importance"
32
49
 
33
- export { WOFCandidateTableLookup, type WOFCandidateTableLookupOpts } from "./candidate-lookup.ts"
50
+ export { WOFCandidateTableLookup, type WOFCandidateTableLookupOpts } from "#candidate-lookup"
34
51
 
35
52
  export {
36
53
  COUNTRY_BBOX_TABLE,
@@ -39,38 +56,38 @@ export {
39
56
  createCountryCoverageTable,
40
57
  readGazetteerCoverageManifest,
41
58
  writeGazetteerCoverageManifest,
42
- } from "./coverage-manifest-schema.ts"
59
+ } from "#coverage-manifest-schema"
43
60
 
44
- export type { CountryBBoxTable, CountryCoverageTable, GazetteerCoverageDatabase } from "./coverage-manifest-schema.ts"
45
- export { SQLiteStreetNameLookup, type SQLiteStreetNameLookupOpts } from "./street-name-lookup.ts"
61
+ export type { CountryBBoxTable, CountryCoverageTable, GazetteerCoverageDatabase } from "#coverage-manifest-schema"
62
+ export { SQLiteStreetNameLookup, type SQLiteStreetNameLookupOpts } from "#street/name-lookup"
46
63
 
47
64
  export {
48
65
  GEONAMES_ID_BASE,
49
66
  type GeonamesIngestProgress,
50
67
  ingestGeonamesAliases,
51
68
  purgeGeonamesAliasRange,
52
- } from "./geonames-aliases.ts"
69
+ } from "#geonames/aliases"
53
70
 
54
- export { GEONAMES_POSTAL_ID_BASE } from "./geonames-postal.ts"
71
+ export { GEONAMES_POSTAL_ID_BASE } from "#geonames/postal"
55
72
 
56
- export { ADDRESS_POINT_COLUMNS, createAddressPointIndexes, createAddressPointTable } from "./address-point-schema.ts"
57
- export type { AddressPointDatabase, AddressPointTable } from "./address-point-schema.ts"
73
+ export { ADDRESS_POINT_COLUMNS, createAddressPointIndexes, createAddressPointTable } from "#address/point-schema"
74
+ export type { AddressPointDatabase, AddressPointTable } from "#address/point-schema"
58
75
 
59
76
  export {
60
77
  WOFPostalCityAliasLookup,
61
78
  type PostalCityAlias,
62
79
  type WOFPostalCityAliasLookupOpts,
63
- } from "./postal-city-alias-lookup.ts"
80
+ } from "#postal/city-alias-lookup"
64
81
 
65
- export type { PostalCityAliasDatabase, PostalCityAliasTable } from "./postal-city-alias-schema.ts"
82
+ export type { PostalCityAliasDatabase, PostalCityAliasTable } from "#postal/city-alias-schema"
66
83
 
67
84
  export {
68
85
  POSTAL_CITY_CANDIDATE_COLUMNS,
69
86
  POSTAL_CITY_CANDIDATE_TABLE,
70
87
  createPostalCityCandidateTable,
71
- } from "./postal-city-candidate-schema.ts"
88
+ } from "#postal/city-candidate-schema"
72
89
 
73
- export type { PostalCityCandidateDatabase, PostalCityCandidateTable } from "./postal-city-candidate-schema.ts"
90
+ export type { PostalCityCandidateDatabase, PostalCityCandidateTable } from "#postal/city-candidate-schema"
74
91
 
75
92
  export {
76
93
  ADDRESS_CONVENTION_TABLE,
@@ -84,11 +101,11 @@ export {
84
101
  type ResolvedConvention,
85
102
  type ScoringWeights,
86
103
  type Strategy,
87
- } from "./convention.ts"
104
+ } from "#convention/index"
88
105
 
89
- export { SqliteConventionSource } from "./sqlite-convention-source.ts"
106
+ export { SqliteConventionSource } from "#sqlite-convention-source"
90
107
 
91
- export { WOFPostcodeLookup, type PostcodePlace } from "./postcode-point-lookup.ts"
108
+ export { WOFPostcodeLookup, type PostcodePlace } from "#postcode-point-lookup"
92
109
 
93
110
  export {
94
111
  PLACE_BBOX_TABLE,
@@ -98,22 +115,9 @@ export {
98
115
  placeSearchFTSExists,
99
116
  type BuildPlaceSearchFTSOpts,
100
117
  type BuildPlaceSearchFTSResult,
101
- } from "./fts.ts"
118
+ } from "#fts/index"
102
119
 
103
- export {
104
- bboxAround,
105
- geometryContains,
106
- haversineKm,
107
- pointInPolygonRings,
108
- pointInRing,
109
- type Bbox,
110
- type GeojsonGeometry,
111
- type GeojsonMultiPolygon,
112
- type GeojsonPolygon,
113
- type GeojsonPosition,
114
- } from "./geo.ts"
115
-
116
- export { PLACETYPE_DEPTH, ancestorLineage, placetypeDepth, type AncestorPlaceRow } from "./ancestry.ts"
120
+ export { PLACETYPE_DEPTH, ancestorLineage, placetypeDepth, type AncestorPlaceRow } from "#ancestry/index"
117
121
 
118
122
  export {
119
123
  WOFReverseGeocoder,
@@ -121,31 +125,31 @@ export {
121
125
  type ReverseGeocodeOpts,
122
126
  type ReverseGeocodeResult,
123
127
  type WOFReverseGeocoderOpts,
124
- } from "./reverse.ts"
128
+ } from "#reverse"
125
129
 
126
- export { AddressPointInterpolator } from "./address-point-interpolation.ts"
127
- export { AddressPointSqliteLookup } from "./address-point.ts"
130
+ export { AddressPointInterpolator } from "#address/point-interpolation"
131
+ export { AddressPointSqliteLookup } from "#address/point"
128
132
 
129
133
  export {
130
134
  STREET_CENTROID_COLUMNS,
131
135
  createStreetCentroidIndexes,
132
136
  createStreetCentroidTable,
133
- } from "./street-centroid-schema.ts"
137
+ } from "#street/centroid-schema"
134
138
 
135
- export type { StreetCentroidDatabase, StreetCentroidTable } from "./street-centroid-schema.ts"
136
- export { StreetCentroidSqliteLookup } from "./street-centroid.ts"
139
+ export type { StreetCentroidDatabase, StreetCentroidTable } from "#street/centroid-schema"
140
+ export { StreetCentroidSqliteLookup } from "#street/centroid"
137
141
 
138
142
  export {
139
143
  StreetInterpolator,
140
144
  type InterpolatedHit,
141
145
  type InterpolationMethod,
142
146
  type InterpolationQuery,
143
- } from "./interpolation.ts"
147
+ } from "#interpolation"
144
148
 
145
149
  export {
146
150
  deriveSchemaName,
147
- pickShardForPlacetype,
148
- resolveShards,
149
- type ResolvedShard,
150
- type ShardConfig,
151
- } from "./sharding.ts"
151
+ pickExtractForPlacetype,
152
+ resolveExtracts,
153
+ type ResolvedExtract,
154
+ type ExtractConfig,
155
+ } from "#extracts"
@@ -8,7 +8,7 @@
8
8
  * then linear interpolation along the segment polyline. Design:
9
9
  * `docs/articles/plan/2026-06-11-interpolation-design.md`.
10
10
  *
11
- * Reads the per-state shard built by `scripts/build-interpolation-shard.ts` (`street_segment`: one
11
+ * Reads the per-state extract built by `scripts/build-interpolation-extract.ts` (`street_segment`: one
12
12
  * row per TIGER edge SIDE — independent left/right ranges, ZIPs, parity). Query-side
13
13
  * normalization is THE shared normalizer (`street-normalize.ts`) — identical to build-side, by
14
14
  * construction.
@@ -26,20 +26,19 @@
26
26
  * `AddressPointLookup.find()` to keep that wiring mechanical.
27
27
  */
28
28
 
29
- import { DatabaseSync } from "node:sqlite"
30
-
31
- import { parseJSONStrict } from "@mailwoman/core/objects"
29
+ import { parseJSONStrict } from "@mailwoman/core/json"
32
30
  import type { InterpolationLookup } from "@mailwoman/resolver"
33
- import { clampFraction, pointAlong } from "@mailwoman/spatial"
31
+ import { clampFraction, haversineKm, pointAlong } from "@mailwoman/spatial"
32
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
34
33
 
35
- import { haversineKm } from "./geo.ts"
36
- import { hasTable } from "./sqlite-utils.ts"
37
- import { canonicalizeRouteKey, normalizeStreetForKey } from "./street-normalize.ts"
34
+ import { hasTable, prepareAll, type PreparedAll } from "#sqlite-utils"
35
+ import { canonicalizeRouteKey, type RouteKey, streetKeyVariants } from "#street/normalize"
36
+ import type { StreetSegmentDatabase } from "#street/segment-schema"
38
37
 
39
38
  /**
40
39
  * How an interpolated answer was computed (#483 Method 2):
41
40
  *
42
- * - `address_point` — bracketed/extrapolated between REAL neighbor points from the #476 shard
41
+ * - `address_point` — bracketed/extrapolated between REAL neighbor points from the #476 extract
43
42
  * (`AddressPointInterpolator`), replacing TIGER's uniform-spacing assumption with occupancy.
44
43
  * - `tiger_range` — linear position within a TIGER segment's theoretical house-number range (`StreetInterpolator`), the
45
44
  * fallback for streets too sparse to bracket.
@@ -92,8 +91,27 @@ export interface InterpolationQuery {
92
91
  * ZIP scope — strongly preferred; without it common street names abstain (see module doc).
93
92
  */
94
93
  postcode?: string
94
+ /**
95
+ * The resolved locality's coordinate — the tie-breaker when no postcode was given and the parity-preferred covering
96
+ * ranges still span several postcodes. See {@link NEAR_MAX_KM} for the acceptance geometry.
97
+ */
98
+ near?: { lat: number; lon: number }
95
99
  }
96
100
 
101
+ /**
102
+ * Acceptance geometry for the `near` tie-break: the winning postcode group's closest segment must sit within this many
103
+ * kilometres of `near`, AND the runner-up group must be at least {@link NEAR_DOMINANCE} times farther. Both measured on
104
+ * the two live failures: Brooklyn's `st pauls place` 11226 segment is ~2 km from the Brooklyn centroid with Great
105
+ * Neck's 11021 at ~24 km (12×); Fraser's `east 13 mile road` 48026 is ~2 km with Mecosta's namesake ~190 km away. A
106
+ * near-tie between groups is genuine ambiguity and stays an abstention.
107
+ */
108
+ const NEAR_MAX_KM = 25
109
+
110
+ /**
111
+ * See {@link NEAR_MAX_KM}.
112
+ */
113
+ const NEAR_DOMINANCE = 2
114
+
97
115
  interface SegmentRow {
98
116
  from_hn: number
99
117
  to_hn: number
@@ -106,44 +124,94 @@ interface SegmentRow {
106
124
  release: string
107
125
  }
108
126
 
109
- export class StreetInterpolator implements InterpolationLookup {
110
- readonly #db: DatabaseSync
111
- readonly #ownsDB: boolean
112
- readonly #byPostcode: ReturnType<DatabaseSync["prepare"]> | undefined
113
- readonly #byStreet: ReturnType<DatabaseSync["prepare"]> | undefined
127
+ /**
128
+ * The postcode group nearest `near`, under the {@link NEAR_MAX_KM} dominance geometry — or null when no group qualifies
129
+ * (out of range, or the runner-up is too close to call). A group's distance is its closest segment's first polyline
130
+ * vertex; a segment whose geometry fails to parse prices as unreachable rather than aborting the tie-break.
131
+ */
132
+ function nearestPostcodeGroup(pool: readonly SegmentRow[], near: { lat: number; lon: number }): SegmentRow[] | null {
133
+ const groups = new Map<string, { rows: SegmentRow[]; km: number }>()
134
+
135
+ for (const row of pool) {
136
+ const key = row.postcode ?? ""
137
+ let km = Number.POSITIVE_INFINITY
138
+
139
+ try {
140
+ const [firstVertex] = parseJSONStrict<[number, number][]>(row.geometry)
141
+
142
+ if (firstVertex) {
143
+ km = haversineKm(near.lat, near.lon, firstVertex[1], firstVertex[0])
144
+ }
145
+ } catch {
146
+ // Unparseable geometry: this row cannot be sited, so it cannot win the tie-break.
147
+ }
148
+
149
+ const group = groups.get(key)
150
+
151
+ if (group) {
152
+ group.rows.push(row)
153
+ group.km = Math.min(group.km, km)
154
+ } else {
155
+ groups.set(key, { rows: [row], km })
156
+ }
157
+ }
158
+
159
+ const ranked = [...groups.values()].toSorted((a, b) => a.km - b.km)
160
+ const [winner, runnerUp] = ranked
161
+
162
+ if (!winner || winner.km > NEAR_MAX_KM) return null
163
+
164
+ if (runnerUp && runnerUp.km < winner.km * NEAR_DOMINANCE) return null
165
+
166
+ return winner.rows
167
+ }
168
+
169
+ export class StreetInterpolator<
170
+ DB extends StreetSegmentDatabase = StreetSegmentDatabase,
171
+ > implements InterpolationLookup {
172
+ readonly #db: DatabaseClient<DB>
173
+ /**
174
+ * Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
175
+ * ownership is membership rather than a flag a later branch has to check.
176
+ */
177
+ readonly #resources = new DisposableStack()
178
+ readonly #byPostcode:
179
+ | PreparedAll<[postcode: string, street: RouteKey, minNumber: number, maxNumber: number], SegmentRow>
180
+ | undefined
181
+ readonly #byStreet: PreparedAll<[street: RouteKey, minNumber: number, maxNumber: number], SegmentRow> | undefined
114
182
  readonly #radiusCalibration: number | undefined
115
183
 
116
- constructor(opts: { dbPath?: string; database?: DatabaseSync }) {
184
+ constructor(opts: { dbPath?: string; database?: DatabaseClient<DB> }) {
117
185
  if (opts.database) {
118
186
  this.#db = opts.database
119
- this.#ownsDB = false
120
187
  } else if (opts.dbPath) {
121
- this.#db = new DatabaseSync(opts.dbPath, { readOnly: true })
122
- this.#ownsDB = true
188
+ this.#db = this.#resources.use(new DatabaseClient<DB>(opts.dbPath, { readOnly: true }))
123
189
  } else {
124
190
  throw new Error("StreetInterpolator: one of dbPath or database is required")
125
191
  }
126
192
 
127
- // Degrade gracefully on an empty/tableless shard (interrupted build, stray 0-byte file): with no
193
+ // Degrade gracefully on an empty/tableless extract (interrupted build, stray 0-byte file): with no
128
194
  // `street_segment` table this interpolator is a no-op miss, not a crash that loses the state (#568).
129
195
  if (hasTable(this.#db, "street_segment")) {
130
196
  const columns = `from_hn, to_hn, min_hn, max_hn, parity, postcode, geometry, source, release`
131
197
 
132
- this.#byPostcode = this.#db.prepare(
198
+ this.#byPostcode = prepareAll(
199
+ this.#db,
133
200
  `SELECT ${columns} FROM street_segment
134
201
  WHERE postcode = ? AND street_norm = ? AND min_hn <= ? AND max_hn >= ?`
135
202
  )
136
203
 
137
- this.#byStreet = this.#db.prepare(
204
+ this.#byStreet = prepareAll(
205
+ this.#db,
138
206
  `SELECT ${columns} FROM street_segment
139
207
  WHERE street_norm = ? AND min_hn <= ? AND max_hn >= ?`
140
208
  )
141
209
  }
142
210
 
143
211
  // #374 doctrine: the conformal radius multiplier is a property of the calibration set the ARTIFACT was
144
- // built against, so it ships in the shard's `interp_calibration` metadata table (street-segment-schema.ts)
212
+ // built against, so it ships in the extract's `interp_calibration` metadata table (street-segment-schema.ts)
145
213
  // and is read here, once, at open time — sync raw `.prepare()` per the sync-by-interface doctrine
146
- // (AGENTS.md). Shards predating the table (the pre-2026-07 fleet) yield `undefined`; callers then fall
214
+ // (AGENTS.md). Extracts predating the table (the pre-2026-07 fleet) yield `undefined`; callers then fall
147
215
  // back to their in-code table, byte-identically.
148
216
  if (hasTable(this.#db, "interp_calibration")) {
149
217
  const row = this.#db.prepare("SELECT radius_multiplier FROM interp_calibration LIMIT 1").get() as
@@ -159,9 +227,9 @@ export class StreetInterpolator implements InterpolationLookup {
159
227
  }
160
228
 
161
229
  /**
162
- * The artifact's own conformal radius multiplier (#374), read from the shard's `interp_calibration` metadata table at
163
- * construction. `undefined` = the shard predates the table (or carries no valid row) — the resolver then applies no
164
- * artifact default and callers may supply a legacy fallback.
230
+ * The artifact's own conformal radius multiplier (#374), read from the extract's `interp_calibration` metadata table
231
+ * at construction. `undefined` = the extract predates the table (or carries no valid row) — the resolver then applies
232
+ * no artifact default and callers may supply a legacy fallback.
165
233
  */
166
234
  get radiusCalibration(): number | undefined {
167
235
  return this.#radiusCalibration
@@ -169,29 +237,41 @@ export class StreetInterpolator implements InterpolationLookup {
169
237
 
170
238
  find(query: InterpolationQuery): InterpolatedHit | null {
171
239
  if (!this.#byPostcode || !this.#byStreet) return null
172
- const streetNorm = canonicalizeRouteKey(normalizeStreetForKey(query.street))
173
240
  const numberRaw = query.number.trim()
174
241
 
175
242
  // Strictly-numeric house numbers only — this tier estimates, it doesn't guess at
176
243
  // hyphenated/alphanumeric schemes the ranges don't model.
177
- if (!streetNorm || !/^\d+$/.test(numberRaw)) return null
244
+ if (!/^\d+$/.test(numberRaw)) return null
178
245
  const n = Number(numberRaw)
179
246
 
180
- let rows: SegmentRow[]
247
+ // Key-variant ladder (see `streetKeyVariants`): the literal key first, then the doubled-type
248
+ // collapse and the saint↔st register swap. A variant advances the ladder when it produces no
249
+ // ANSWER, not merely no rows — a wrong-register key can cover the number in far-away towns and
250
+ // then fail the ambiguity check ("saint pauls place" reaches Nassau's rows; the Brooklyn answer
251
+ // lives under "st pauls place"), and stopping at rows would eclipse the right variant.
252
+ for (const variant of streetKeyVariants(query.street)) {
253
+ const streetNorm = canonicalizeRouteKey(variant)
181
254
 
182
- if (query.postcode) {
183
255
  // A given ZIP that scopes to nothing is a MISS, not a statewide guess: the retry was
184
256
  // measured (2026-06-11 VT eval) at +2.3pp coverage for a poisoned tail (p99 1.0 → 20.8
185
257
  // km, max 204 km — a unique name statewide can live in a far-away town).
186
- rows = this.#byPostcode.all(query.postcode.trim(), streetNorm, n, n) as unknown as SegmentRow[]
187
- } else {
188
- // No scope given: a name matching ranges across several ZIPs is ambiguous — abstain.
189
- rows = this.#byStreet.all(streetNorm, n, n) as unknown as SegmentRow[]
190
- const postcodes = new Set(rows.map((r) => r.postcode ?? ""))
258
+ const rows = query.postcode
259
+ ? this.#byPostcode(query.postcode.trim(), streetNorm, n, n)
260
+ : this.#byStreet(streetNorm, n, n)
261
+
262
+ const hit = this.#answerFromRows(rows, n, query)
191
263
 
192
- if (postcodes.size > 1) return null
264
+ if (hit) return hit
193
265
  }
194
266
 
267
+ return null
268
+ }
269
+
270
+ /**
271
+ * Resolve one key variant's covering rows to an answer, or null when they cannot honestly give one — the
272
+ * parity/ambiguity/tightest-range pipeline the module doc describes.
273
+ */
274
+ #answerFromRows(rows: SegmentRow[], n: number, query: InterpolationQuery): InterpolatedHit | null {
195
275
  if (!rows.length) return null
196
276
 
197
277
  // Parity preference: exact side first, then 'mixed' (matches either), then the
@@ -200,9 +280,27 @@ export class StreetInterpolator implements InterpolationLookup {
200
280
  const exact = rows.filter((r) => r.parity === (wantOdd ? "odd" : "even"))
201
281
  const mixed = rows.filter((r) => r.parity === "mixed")
202
282
  const preferred = exact.length ? exact : mixed
203
- const pool = preferred.length ? preferred : rows
283
+ let pool = preferred.length ? preferred : rows
204
284
  const parityMatched = preferred.length > 0
205
285
 
286
+ // No scope given: the covering ranges must agree on ONE postcode or the lookup abstains — a
287
+ // name spanning towns is ambiguity, not an answer. Counted over the PARITY pool, not all
288
+ // rows: a section-line boundary road carries a different ZIP per side ("east 13 mile road"
289
+ // is Fraser 48026 odd / Roseville 48066 even), and the opposite side can never hold the
290
+ // number it would otherwise veto. When several postcodes survive parity, the caller's
291
+ // resolved-locality coordinate breaks the tie by segment proximity under the dominance
292
+ // geometry of {@link NEAR_MAX_KM} — a near-tie stays an abstention.
293
+ if (!query.postcode) {
294
+ const postcodes = new Set(pool.map((r) => r.postcode ?? ""))
295
+
296
+ if (postcodes.size > 1) {
297
+ const scoped = query.near ? nearestPostcodeGroup(pool, query.near) : null
298
+
299
+ if (!scoped) return null
300
+ pool = scoped
301
+ }
302
+ }
303
+
206
304
  // Tightest range wins — the most specific claim about where this number lives.
207
305
  let best = pool[0]!
208
306
 
@@ -229,9 +327,7 @@ export class StreetInterpolator implements InterpolationLookup {
229
327
  }
230
328
  }
231
329
 
232
- close(): void {
233
- if (this.#ownsDB) {
234
- this.#db.close()
235
- }
330
+ [Symbol.dispose](): void {
331
+ this.#resources[Symbol.dispose]()
236
332
  }
237
333
  }