@mailwoman/resolver-wof-sqlite 9.4.0 → 10.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 (548) hide show
  1. package/README.md +8 -8
  2. package/lib/address/{point-interpolation.ts → point/interpolation.ts} +40 -38
  3. package/lib/address/point/schema.ts +132 -0
  4. package/lib/address/point.ts +68 -81
  5. package/lib/{address/index.ts → address.ts} +2 -2
  6. package/lib/ancestry/backfill.ts +24 -88
  7. package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
  8. package/lib/build/candidate.ts +608 -0
  9. package/lib/build/population-corrections.ts +64 -0
  10. package/lib/build/slim.ts +338 -0
  11. package/lib/candidate/alias-bags.ts +74 -14
  12. package/lib/candidate/ancestors/schema.ts +211 -0
  13. package/lib/candidate/{ancestors-sidecar.ts → ancestors/sidecar.ts} +17 -24
  14. package/lib/candidate/country-display-names.ts +6 -20
  15. package/lib/candidate/extract-fold.ts +12 -57
  16. package/lib/candidate/fts.ts +28 -0
  17. package/lib/candidate/importance.ts +221 -0
  18. package/lib/candidate/lookup.ts +669 -0
  19. package/lib/candidate/name-roles.ts +16 -34
  20. package/lib/candidate/own-name.ts +34 -31
  21. package/lib/candidate/place-attrs.ts +20 -13
  22. package/lib/candidate/schema.ts +211 -0
  23. package/lib/candidate/scoring.ts +222 -0
  24. package/lib/capital-schema.ts +21 -17
  25. package/lib/capitals.ts +26 -24
  26. package/lib/coincident-roles.ts +74 -55
  27. package/lib/convention/schema.ts +13 -7
  28. package/lib/convention.ts +144 -0
  29. package/lib/coverage-manifest-schema.ts +34 -39
  30. package/lib/currency-backfill.ts +24 -69
  31. package/lib/env.ts +1 -1
  32. package/lib/exact-match.ts +31 -20
  33. package/lib/extracts.ts +96 -73
  34. package/lib/fst/autocomplete.ts +52 -35
  35. package/lib/fst/builder.ts +30 -36
  36. package/lib/fst/deserialize-web.ts +8 -9
  37. package/lib/fst/format.ts +41 -23
  38. package/lib/fst/freshness.ts +17 -95
  39. package/lib/fst/matcher.ts +2 -2
  40. package/lib/fst/serialize.ts +45 -60
  41. package/lib/fst/types.ts +71 -59
  42. package/lib/fts/query.ts +5 -36
  43. package/lib/fts.ts +280 -0
  44. package/lib/geonames/aliases.ts +72 -149
  45. package/lib/geonames/postal.ts +162 -77
  46. package/lib/index.ts +20 -27
  47. package/lib/interpolation.ts +43 -96
  48. package/lib/lookup.ts +137 -257
  49. package/lib/name-score.ts +9 -7
  50. package/lib/nsul/lookup.ts +36 -53
  51. package/lib/nsul/schema.ts +16 -43
  52. package/lib/paths.ts +159 -0
  53. package/lib/place-importance-schema.ts +57 -164
  54. package/lib/poi/lookup.ts +100 -109
  55. package/lib/poi/schema.ts +42 -26
  56. package/lib/polygon-schema.ts +10 -6
  57. package/lib/postal/city/alias/lookup.ts +79 -0
  58. package/lib/postal/{city-alias-schema.ts → city/alias/schema.ts} +14 -10
  59. package/lib/postal/{city-candidate-schema.ts → city/candidate-schema.ts} +26 -20
  60. package/lib/postal.ts +9 -0
  61. package/lib/postcode-point-lookup.ts +9 -19
  62. package/lib/primary-preference.ts +45 -125
  63. package/lib/proximity-rerank.ts +43 -32
  64. package/lib/ranking-weights.ts +98 -76
  65. package/lib/region-keys.ts +68 -40
  66. package/lib/reverse.ts +108 -72
  67. package/lib/schema.ts +74 -42
  68. package/lib/search-fetch.ts +90 -68
  69. package/lib/sqlite/convention-source.ts +57 -0
  70. package/lib/sqlite/utils.ts +79 -0
  71. package/lib/street/centroid/schema.ts +149 -0
  72. package/lib/street/centroid.ts +16 -25
  73. package/lib/street/{morphology-fst-builder.ts → morphology/fst/builder.ts} +56 -41
  74. package/lib/street/{morphology-fst-loader.ts → morphology/fst/loader.ts} +36 -29
  75. package/lib/street/name-lookup.ts +43 -35
  76. package/lib/street/normalize.ts +85 -216
  77. package/lib/street/segment-schema.ts +116 -43
  78. package/lib/{street/index.ts → street.ts} +3 -3
  79. package/lib/types.ts +94 -140
  80. package/lib/unified-schema.ts +29 -29
  81. package/lib/uprn/existence.ts +30 -19
  82. package/lib/uprn/lookup.ts +28 -67
  83. package/lib/uprn/schema.ts +18 -40
  84. package/lib/weights-overlay-linker.ts +204 -232
  85. package/out/address/point/interpolation.d.ts +45 -0
  86. package/out/address/point/interpolation.d.ts.map +1 -0
  87. package/out/address/{point-interpolation.js → point/interpolation.js} +38 -38
  88. package/out/address/point/interpolation.js.map +1 -0
  89. package/out/address/point/schema.d.ts +74 -0
  90. package/out/address/point/schema.d.ts.map +1 -0
  91. package/out/address/{point-schema.js → point/schema.js} +4 -20
  92. package/out/address/point/schema.js.map +1 -0
  93. package/out/address/point.d.ts +24 -21
  94. package/out/address/point.d.ts.map +1 -1
  95. package/out/address/point.js +60 -77
  96. package/out/address/point.js.map +1 -1
  97. package/out/{address/index.js → address.d.ts} +3 -3
  98. package/out/address.d.ts.map +1 -0
  99. package/out/{address/index.d.ts → address.js} +3 -3
  100. package/out/address.js.map +1 -0
  101. package/out/ancestry/backfill.d.ts +11 -64
  102. package/out/ancestry/backfill.d.ts.map +1 -1
  103. package/out/ancestry/backfill.js +18 -76
  104. package/out/ancestry/backfill.js.map +1 -1
  105. package/out/ancestry.d.ts +49 -0
  106. package/out/ancestry.d.ts.map +1 -0
  107. package/out/ancestry.js +59 -0
  108. package/out/ancestry.js.map +1 -0
  109. package/out/build/candidate.d.ts +170 -0
  110. package/out/build/candidate.d.ts.map +1 -0
  111. package/out/{build-candidate.js → build/candidate.js} +33 -102
  112. package/out/build/candidate.js.map +1 -0
  113. package/out/build/population-corrections.d.ts +52 -0
  114. package/out/build/population-corrections.d.ts.map +1 -0
  115. package/out/build/population-corrections.js +40 -0
  116. package/out/build/population-corrections.js.map +1 -0
  117. package/out/build/slim.d.ts +44 -0
  118. package/out/build/slim.d.ts.map +1 -0
  119. package/out/{build-slim.js → build/slim.js} +33 -94
  120. package/out/build/slim.js.map +1 -0
  121. package/out/candidate/alias-bags.d.ts +13 -5
  122. package/out/candidate/alias-bags.d.ts.map +1 -1
  123. package/out/candidate/alias-bags.js +55 -12
  124. package/out/candidate/alias-bags.js.map +1 -1
  125. package/out/candidate/ancestors/schema.d.ts +166 -0
  126. package/out/candidate/ancestors/schema.d.ts.map +1 -0
  127. package/out/candidate/ancestors/schema.js +131 -0
  128. package/out/candidate/ancestors/schema.js.map +1 -0
  129. package/out/candidate/ancestors/sidecar.d.ts +27 -0
  130. package/out/candidate/ancestors/sidecar.d.ts.map +1 -0
  131. package/out/candidate/{ancestors-sidecar.js → ancestors/sidecar.js} +17 -24
  132. package/out/candidate/ancestors/sidecar.js.map +1 -0
  133. package/out/candidate/country-display-names.d.ts +5 -15
  134. package/out/candidate/country-display-names.d.ts.map +1 -1
  135. package/out/candidate/country-display-names.js +6 -20
  136. package/out/candidate/country-display-names.js.map +1 -1
  137. package/out/candidate/extract-fold.d.ts +8 -16
  138. package/out/candidate/extract-fold.d.ts.map +1 -1
  139. package/out/candidate/extract-fold.js +6 -48
  140. package/out/candidate/extract-fold.js.map +1 -1
  141. package/out/candidate/fts.d.ts +19 -0
  142. package/out/candidate/fts.d.ts.map +1 -0
  143. package/out/candidate/fts.js +22 -0
  144. package/out/candidate/fts.js.map +1 -0
  145. package/out/candidate/importance.d.ts +127 -0
  146. package/out/candidate/importance.d.ts.map +1 -0
  147. package/out/candidate/importance.js +162 -0
  148. package/out/candidate/importance.js.map +1 -0
  149. package/out/candidate/lookup.d.ts +36 -0
  150. package/out/candidate/lookup.d.ts.map +1 -0
  151. package/out/candidate/lookup.js +456 -0
  152. package/out/candidate/lookup.js.map +1 -0
  153. package/out/candidate/name-roles.d.ts +10 -22
  154. package/out/candidate/name-roles.d.ts.map +1 -1
  155. package/out/candidate/name-roles.js +15 -33
  156. package/out/candidate/name-roles.js.map +1 -1
  157. package/out/candidate/own-name.d.ts +23 -25
  158. package/out/candidate/own-name.d.ts.map +1 -1
  159. package/out/candidate/own-name.js +34 -31
  160. package/out/candidate/own-name.js.map +1 -1
  161. package/out/candidate/place-attrs.d.ts +20 -13
  162. package/out/candidate/place-attrs.d.ts.map +1 -1
  163. package/out/candidate/place-attrs.js +4 -5
  164. package/out/candidate/place-attrs.js.map +1 -1
  165. package/out/candidate/schema.d.ts +120 -0
  166. package/out/candidate/schema.d.ts.map +1 -0
  167. package/out/{candidate-schema.js → candidate/schema.js} +11 -23
  168. package/out/candidate/schema.js.map +1 -0
  169. package/out/{candidate-scoring.d.ts → candidate/scoring.d.ts} +8 -9
  170. package/out/candidate/scoring.d.ts.map +1 -0
  171. package/out/candidate/scoring.js +157 -0
  172. package/out/candidate/scoring.js.map +1 -0
  173. package/out/capital-schema.d.ts +21 -17
  174. package/out/capital-schema.d.ts.map +1 -1
  175. package/out/capital-schema.js +17 -15
  176. package/out/capital-schema.js.map +1 -1
  177. package/out/capitals.d.ts +26 -24
  178. package/out/capitals.d.ts.map +1 -1
  179. package/out/capitals.js +23 -21
  180. package/out/capitals.js.map +1 -1
  181. package/out/coincident-roles.d.ts +60 -43
  182. package/out/coincident-roles.d.ts.map +1 -1
  183. package/out/coincident-roles.js +61 -50
  184. package/out/coincident-roles.js.map +1 -1
  185. package/out/convention/schema.d.ts +12 -6
  186. package/out/convention/schema.d.ts.map +1 -1
  187. package/out/convention/schema.js +6 -4
  188. package/out/convention/schema.js.map +1 -1
  189. package/out/convention.d.ts +97 -0
  190. package/out/convention.d.ts.map +1 -0
  191. package/out/convention.js +81 -0
  192. package/out/convention.js.map +1 -0
  193. package/out/coverage-manifest-schema.d.ts +33 -38
  194. package/out/coverage-manifest-schema.d.ts.map +1 -1
  195. package/out/coverage-manifest-schema.js +20 -29
  196. package/out/coverage-manifest-schema.js.map +1 -1
  197. package/out/currency-backfill.d.ts +13 -35
  198. package/out/currency-backfill.d.ts.map +1 -1
  199. package/out/currency-backfill.js +12 -39
  200. package/out/currency-backfill.js.map +1 -1
  201. package/out/env.d.ts +2 -2
  202. package/out/env.js +1 -1
  203. package/out/exact-match.d.ts +19 -10
  204. package/out/exact-match.d.ts.map +1 -1
  205. package/out/exact-match.js +31 -20
  206. package/out/exact-match.js.map +1 -1
  207. package/out/extracts.d.ts +65 -54
  208. package/out/extracts.d.ts.map +1 -1
  209. package/out/extracts.js +63 -55
  210. package/out/extracts.js.map +1 -1
  211. package/out/fst/autocomplete.d.ts +28 -20
  212. package/out/fst/autocomplete.d.ts.map +1 -1
  213. package/out/fst/autocomplete.js +38 -27
  214. package/out/fst/autocomplete.js.map +1 -1
  215. package/out/fst/builder.d.ts.map +1 -1
  216. package/out/fst/builder.js +30 -36
  217. package/out/fst/builder.js.map +1 -1
  218. package/out/fst/deserialize-web.d.ts +3 -3
  219. package/out/fst/deserialize-web.d.ts.map +1 -1
  220. package/out/fst/deserialize-web.js +8 -9
  221. package/out/fst/deserialize-web.js.map +1 -1
  222. package/out/fst/format.d.ts +41 -23
  223. package/out/fst/format.d.ts.map +1 -1
  224. package/out/fst/format.js +41 -23
  225. package/out/fst/format.js.map +1 -1
  226. package/out/fst/freshness.d.ts +11 -73
  227. package/out/fst/freshness.d.ts.map +1 -1
  228. package/out/fst/freshness.js +12 -76
  229. package/out/fst/freshness.js.map +1 -1
  230. package/out/fst/matcher.d.ts +1 -1
  231. package/out/fst/matcher.d.ts.map +1 -1
  232. package/out/fst/matcher.js +2 -2
  233. package/out/fst/matcher.js.map +1 -1
  234. package/out/fst/serialize.d.ts +30 -26
  235. package/out/fst/serialize.d.ts.map +1 -1
  236. package/out/fst/serialize.js +44 -58
  237. package/out/fst/serialize.js.map +1 -1
  238. package/out/fst/types.d.ts +71 -59
  239. package/out/fst/types.d.ts.map +1 -1
  240. package/out/fst/types.js +1 -4
  241. package/out/fst/types.js.map +1 -1
  242. package/out/{fst/index.js → fst.d.ts} +1 -1
  243. package/out/fst.d.ts.map +1 -0
  244. package/out/{fst/index.d.ts → fst.js} +1 -1
  245. package/out/fst.js.map +1 -0
  246. package/out/fts/query.d.ts +2 -27
  247. package/out/fts/query.d.ts.map +1 -1
  248. package/out/fts/query.js +5 -36
  249. package/out/fts/query.js.map +1 -1
  250. package/out/fts.d.ts +126 -0
  251. package/out/fts.d.ts.map +1 -0
  252. package/out/fts.js +188 -0
  253. package/out/fts.js.map +1 -0
  254. package/out/geonames/aliases.d.ts +26 -67
  255. package/out/geonames/aliases.d.ts.map +1 -1
  256. package/out/geonames/aliases.js +44 -121
  257. package/out/geonames/aliases.js.map +1 -1
  258. package/out/geonames/postal.d.ts +84 -50
  259. package/out/geonames/postal.d.ts.map +1 -1
  260. package/out/geonames/postal.js +115 -78
  261. package/out/geonames/postal.js.map +1 -1
  262. package/out/{geonames/index.js → geonames.d.ts} +1 -1
  263. package/out/geonames.d.ts.map +1 -0
  264. package/out/{geonames/index.d.ts → geonames.js} +1 -1
  265. package/out/geonames.js.map +1 -0
  266. package/out/index.d.ts +20 -21
  267. package/out/index.d.ts.map +1 -1
  268. package/out/index.js +14 -15
  269. package/out/index.js.map +1 -1
  270. package/out/interpolation.d.ts +15 -52
  271. package/out/interpolation.d.ts.map +1 -1
  272. package/out/interpolation.js +25 -68
  273. package/out/interpolation.js.map +1 -1
  274. package/out/lookup.d.ts +24 -53
  275. package/out/lookup.d.ts.map +1 -1
  276. package/out/lookup.js +117 -223
  277. package/out/lookup.js.map +1 -1
  278. package/out/name-score.d.ts +2 -2
  279. package/out/name-score.d.ts.map +1 -1
  280. package/out/name-score.js +9 -7
  281. package/out/name-score.js.map +1 -1
  282. package/out/nsul/lookup.d.ts +33 -34
  283. package/out/nsul/lookup.d.ts.map +1 -1
  284. package/out/nsul/lookup.js +26 -40
  285. package/out/nsul/lookup.js.map +1 -1
  286. package/out/nsul/schema.d.ts +16 -43
  287. package/out/nsul/schema.d.ts.map +1 -1
  288. package/out/nsul/schema.js +9 -35
  289. package/out/nsul/schema.js.map +1 -1
  290. package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
  291. package/out/nsul.d.ts.map +1 -0
  292. package/out/{nsul/index.js → nsul.js} +1 -1
  293. package/out/nsul.js.map +1 -0
  294. package/out/paths.d.ts +124 -0
  295. package/out/paths.d.ts.map +1 -0
  296. package/out/paths.js +104 -0
  297. package/out/paths.js.map +1 -0
  298. package/out/place-importance-schema.d.ts +49 -141
  299. package/out/place-importance-schema.d.ts.map +1 -1
  300. package/out/place-importance-schema.js +25 -140
  301. package/out/place-importance-schema.js.map +1 -1
  302. package/out/poi/lookup.d.ts +38 -42
  303. package/out/poi/lookup.d.ts.map +1 -1
  304. package/out/poi/lookup.js +67 -90
  305. package/out/poi/lookup.js.map +1 -1
  306. package/out/poi/schema.d.ts +41 -25
  307. package/out/poi/schema.d.ts.map +1 -1
  308. package/out/poi/schema.js +25 -17
  309. package/out/poi/schema.js.map +1 -1
  310. package/out/{poi/index.js → poi.d.ts} +1 -1
  311. package/out/poi.d.ts.map +1 -0
  312. package/out/{poi/index.d.ts → poi.js} +1 -1
  313. package/out/poi.js.map +1 -0
  314. package/out/polygon-schema.d.ts +10 -6
  315. package/out/polygon-schema.d.ts.map +1 -1
  316. package/out/polygon-schema.js +2 -2
  317. package/out/polygon-schema.js.map +1 -1
  318. package/out/postal/{city-alias-lookup.d.ts → city/alias/lookup.d.ts} +22 -25
  319. package/out/postal/city/alias/lookup.d.ts.map +1 -0
  320. package/out/postal/city/alias/lookup.js +49 -0
  321. package/out/postal/city/alias/lookup.js.map +1 -0
  322. package/out/postal/{city-alias-schema.d.ts → city/alias/schema.d.ts} +15 -11
  323. package/out/postal/city/alias/schema.d.ts.map +1 -0
  324. package/out/postal/{city-alias-schema.js → city/alias/schema.js} +11 -9
  325. package/out/postal/city/alias/schema.js.map +1 -0
  326. package/out/postal/city/candidate-schema.d.ts +72 -0
  327. package/out/postal/city/candidate-schema.d.ts.map +1 -0
  328. package/out/postal/city/candidate-schema.js +60 -0
  329. package/out/postal/city/candidate-schema.js.map +1 -0
  330. package/out/postal.d.ts +9 -0
  331. package/out/postal.d.ts.map +1 -0
  332. package/out/postal.js +9 -0
  333. package/out/postal.js.map +1 -0
  334. package/out/postcode-point-lookup.d.ts +9 -19
  335. package/out/postcode-point-lookup.d.ts.map +1 -1
  336. package/out/postcode-point-lookup.js +5 -17
  337. package/out/postcode-point-lookup.js.map +1 -1
  338. package/out/primary-preference.d.ts +39 -93
  339. package/out/primary-preference.d.ts.map +1 -1
  340. package/out/primary-preference.js +13 -97
  341. package/out/primary-preference.js.map +1 -1
  342. package/out/proximity-rerank.d.ts +40 -29
  343. package/out/proximity-rerank.d.ts.map +1 -1
  344. package/out/proximity-rerank.js +38 -29
  345. package/out/proximity-rerank.js.map +1 -1
  346. package/out/ranking-weights.d.ts +91 -62
  347. package/out/ranking-weights.d.ts.map +1 -1
  348. package/out/ranking-weights.js +26 -25
  349. package/out/ranking-weights.js.map +1 -1
  350. package/out/region-keys.d.ts +48 -29
  351. package/out/region-keys.d.ts.map +1 -1
  352. package/out/region-keys.js +68 -40
  353. package/out/region-keys.js.map +1 -1
  354. package/out/reverse.d.ts +75 -50
  355. package/out/reverse.d.ts.map +1 -1
  356. package/out/reverse.js +61 -49
  357. package/out/reverse.js.map +1 -1
  358. package/out/schema.d.ts +74 -42
  359. package/out/schema.d.ts.map +1 -1
  360. package/out/schema.js +4 -5
  361. package/out/schema.js.map +1 -1
  362. package/out/search-fetch.d.ts +16 -12
  363. package/out/search-fetch.d.ts.map +1 -1
  364. package/out/search-fetch.js +83 -63
  365. package/out/search-fetch.js.map +1 -1
  366. package/out/sqlite/convention-source.d.ts +25 -0
  367. package/out/sqlite/convention-source.d.ts.map +1 -0
  368. package/out/sqlite/convention-source.js +48 -0
  369. package/out/sqlite/convention-source.js.map +1 -0
  370. package/out/sqlite/utils.d.ts +45 -0
  371. package/out/sqlite/utils.d.ts.map +1 -0
  372. package/out/sqlite/utils.js +56 -0
  373. package/out/sqlite/utils.js.map +1 -0
  374. package/out/street/centroid/schema.d.ts +100 -0
  375. package/out/street/centroid/schema.d.ts.map +1 -0
  376. package/out/street/centroid/schema.js +66 -0
  377. package/out/street/centroid/schema.js.map +1 -0
  378. package/out/street/centroid.d.ts +9 -19
  379. package/out/street/centroid.d.ts.map +1 -1
  380. package/out/street/centroid.js +11 -22
  381. package/out/street/centroid.js.map +1 -1
  382. package/out/street/{morphology-fst-builder.d.ts → morphology/fst/builder.d.ts} +21 -11
  383. package/out/street/morphology/fst/builder.d.ts.map +1 -0
  384. package/out/street/{morphology-fst-builder.js → morphology/fst/builder.js} +40 -34
  385. package/out/street/morphology/fst/builder.js.map +1 -0
  386. package/out/street/morphology/fst/loader.d.ts +74 -0
  387. package/out/street/morphology/fst/loader.d.ts.map +1 -0
  388. package/out/street/{morphology-fst-loader.js → morphology/fst/loader.js} +21 -21
  389. package/out/street/morphology/fst/loader.js.map +1 -0
  390. package/out/street/name-lookup.d.ts +24 -18
  391. package/out/street/name-lookup.d.ts.map +1 -1
  392. package/out/street/name-lookup.js +32 -31
  393. package/out/street/name-lookup.js.map +1 -1
  394. package/out/street/normalize.d.ts +35 -136
  395. package/out/street/normalize.d.ts.map +1 -1
  396. package/out/street/normalize.js +74 -191
  397. package/out/street/normalize.js.map +1 -1
  398. package/out/street/segment-schema.d.ts +79 -39
  399. package/out/street/segment-schema.d.ts.map +1 -1
  400. package/out/street/segment-schema.js +71 -21
  401. package/out/street/segment-schema.js.map +1 -1
  402. package/out/{street/index.d.ts → street.d.ts} +4 -4
  403. package/out/street.d.ts.map +1 -0
  404. package/out/{street/index.js → street.js} +4 -4
  405. package/out/street.js.map +1 -0
  406. package/out/types.d.ts +69 -138
  407. package/out/types.d.ts.map +1 -1
  408. package/out/types.js +0 -6
  409. package/out/types.js.map +1 -1
  410. package/out/unified-schema.d.ts +8 -12
  411. package/out/unified-schema.d.ts.map +1 -1
  412. package/out/unified-schema.js +29 -29
  413. package/out/unified-schema.js.map +1 -1
  414. package/out/uprn/existence.d.ts +28 -17
  415. package/out/uprn/existence.d.ts.map +1 -1
  416. package/out/uprn/existence.js +26 -16
  417. package/out/uprn/existence.js.map +1 -1
  418. package/out/uprn/lookup.d.ts +14 -44
  419. package/out/uprn/lookup.d.ts.map +1 -1
  420. package/out/uprn/lookup.js +20 -56
  421. package/out/uprn/lookup.js.map +1 -1
  422. package/out/uprn/schema.d.ts +18 -40
  423. package/out/uprn/schema.d.ts.map +1 -1
  424. package/out/uprn/schema.js +10 -32
  425. package/out/uprn/schema.js.map +1 -1
  426. package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
  427. package/out/uprn.d.ts.map +1 -0
  428. package/out/{uprn/index.js → uprn.js} +1 -1
  429. package/out/uprn.js.map +1 -0
  430. package/out/weights-overlay-linker.d.ts +132 -141
  431. package/out/weights-overlay-linker.d.ts.map +1 -1
  432. package/out/weights-overlay-linker.js +86 -154
  433. package/out/weights-overlay-linker.js.map +1 -1
  434. package/package.json +94 -599
  435. package/lib/address/point-schema.ts +0 -155
  436. package/lib/build-candidate.ts +0 -632
  437. package/lib/build-slim.ts +0 -408
  438. package/lib/candidate-ancestors-schema.ts +0 -195
  439. package/lib/candidate-fts.ts +0 -46
  440. package/lib/candidate-importance.ts +0 -224
  441. package/lib/candidate-lookup.ts +0 -977
  442. package/lib/candidate-schema.ts +0 -247
  443. package/lib/candidate-scoring.ts +0 -261
  444. package/lib/convention/index.ts +0 -154
  445. package/lib/fts/index.ts +0 -361
  446. package/lib/postal/city-alias-lookup.ts +0 -97
  447. package/lib/postal/index.ts +0 -9
  448. package/lib/sqlite-convention-source.ts +0 -65
  449. package/lib/sqlite-utils.ts +0 -82
  450. package/lib/street/centroid-schema.ts +0 -154
  451. package/out/address/index.d.ts.map +0 -1
  452. package/out/address/index.js.map +0 -1
  453. package/out/address/point-interpolation.d.ts +0 -49
  454. package/out/address/point-interpolation.d.ts.map +0 -1
  455. package/out/address/point-interpolation.js.map +0 -1
  456. package/out/address/point-schema.d.ts +0 -97
  457. package/out/address/point-schema.d.ts.map +0 -1
  458. package/out/address/point-schema.js.map +0 -1
  459. package/out/ancestry/index.d.ts +0 -45
  460. package/out/ancestry/index.d.ts.map +0 -1
  461. package/out/ancestry/index.js +0 -55
  462. package/out/ancestry/index.js.map +0 -1
  463. package/out/build-candidate.d.ts +0 -184
  464. package/out/build-candidate.d.ts.map +0 -1
  465. package/out/build-candidate.js.map +0 -1
  466. package/out/build-slim.d.ts +0 -80
  467. package/out/build-slim.d.ts.map +0 -1
  468. package/out/build-slim.js.map +0 -1
  469. package/out/candidate/ancestors-sidecar.d.ts +0 -32
  470. package/out/candidate/ancestors-sidecar.d.ts.map +0 -1
  471. package/out/candidate/ancestors-sidecar.js.map +0 -1
  472. package/out/candidate-ancestors-schema.d.ts +0 -150
  473. package/out/candidate-ancestors-schema.d.ts.map +0 -1
  474. package/out/candidate-ancestors-schema.js +0 -123
  475. package/out/candidate-ancestors-schema.js.map +0 -1
  476. package/out/candidate-fts.d.ts +0 -37
  477. package/out/candidate-fts.d.ts.map +0 -1
  478. package/out/candidate-fts.js +0 -40
  479. package/out/candidate-fts.js.map +0 -1
  480. package/out/candidate-importance.d.ts +0 -132
  481. package/out/candidate-importance.d.ts.map +0 -1
  482. package/out/candidate-importance.js +0 -169
  483. package/out/candidate-importance.js.map +0 -1
  484. package/out/candidate-lookup.d.ts +0 -76
  485. package/out/candidate-lookup.d.ts.map +0 -1
  486. package/out/candidate-lookup.js +0 -768
  487. package/out/candidate-lookup.js.map +0 -1
  488. package/out/candidate-schema.d.ts +0 -155
  489. package/out/candidate-schema.d.ts.map +0 -1
  490. package/out/candidate-schema.js.map +0 -1
  491. package/out/candidate-scoring.d.ts.map +0 -1
  492. package/out/candidate-scoring.js +0 -196
  493. package/out/candidate-scoring.js.map +0 -1
  494. package/out/convention/index.d.ts +0 -106
  495. package/out/convention/index.d.ts.map +0 -1
  496. package/out/convention/index.js +0 -93
  497. package/out/convention/index.js.map +0 -1
  498. package/out/fst/index.d.ts.map +0 -1
  499. package/out/fst/index.js.map +0 -1
  500. package/out/fts/index.d.ts +0 -184
  501. package/out/fts/index.d.ts.map +0 -1
  502. package/out/fts/index.js +0 -277
  503. package/out/fts/index.js.map +0 -1
  504. package/out/geonames/index.d.ts.map +0 -1
  505. package/out/geonames/index.js.map +0 -1
  506. package/out/nsul/index.d.ts.map +0 -1
  507. package/out/nsul/index.js.map +0 -1
  508. package/out/poi/index.d.ts.map +0 -1
  509. package/out/poi/index.js.map +0 -1
  510. package/out/postal/city-alias-lookup.d.ts.map +0 -1
  511. package/out/postal/city-alias-lookup.js +0 -62
  512. package/out/postal/city-alias-lookup.js.map +0 -1
  513. package/out/postal/city-alias-schema.d.ts.map +0 -1
  514. package/out/postal/city-alias-schema.js.map +0 -1
  515. package/out/postal/city-candidate-schema.d.ts +0 -66
  516. package/out/postal/city-candidate-schema.d.ts.map +0 -1
  517. package/out/postal/city-candidate-schema.js +0 -56
  518. package/out/postal/city-candidate-schema.js.map +0 -1
  519. package/out/postal/index.d.ts +0 -9
  520. package/out/postal/index.d.ts.map +0 -1
  521. package/out/postal/index.js +0 -9
  522. package/out/postal/index.js.map +0 -1
  523. package/out/sqlite-convention-source.d.ts +0 -29
  524. package/out/sqlite-convention-source.d.ts.map +0 -1
  525. package/out/sqlite-convention-source.js +0 -57
  526. package/out/sqlite-convention-source.js.map +0 -1
  527. package/out/sqlite-utils.d.ts +0 -45
  528. package/out/sqlite-utils.d.ts.map +0 -1
  529. package/out/sqlite-utils.js +0 -57
  530. package/out/sqlite-utils.js.map +0 -1
  531. package/out/street/centroid-schema.d.ts +0 -105
  532. package/out/street/centroid-schema.d.ts.map +0 -1
  533. package/out/street/centroid-schema.js +0 -78
  534. package/out/street/centroid-schema.js.map +0 -1
  535. package/out/street/index.d.ts.map +0 -1
  536. package/out/street/index.js.map +0 -1
  537. package/out/street/morphology-fst-builder.d.ts.map +0 -1
  538. package/out/street/morphology-fst-builder.js.map +0 -1
  539. package/out/street/morphology-fst-loader.d.ts +0 -67
  540. package/out/street/morphology-fst-loader.d.ts.map +0 -1
  541. package/out/street/morphology-fst-loader.js.map +0 -1
  542. package/out/uprn/index.d.ts.map +0 -1
  543. package/out/uprn/index.js.map +0 -1
  544. /package/lib/{fst/index.ts → fst.ts} +0 -0
  545. /package/lib/{geonames/index.ts → geonames.ts} +0 -0
  546. /package/lib/{nsul/index.ts → nsul.ts} +0 -0
  547. /package/lib/{poi/index.ts → poi.ts} +0 -0
  548. /package/lib/{uprn/index.ts → uprn.ts} +0 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file Defines resolution conventions as per-polygon profiles merged along a place's ancestor chain.
6
+ *
7
+ * The strategy implementations live in `lookup.ts` and are registered by name.
8
+ */
9
+
10
+ import type { FindPlaceQuery, PlaceCandidate } from "#types"
11
+
12
+ /**
13
+ * Soft-scoring weights for the `postcode_area_resolution` strategy: `pc·S_pc + name·S_name + pop·S_pop`.
14
+ */
15
+ export interface ScoringWeights {
16
+ pc: number
17
+ name: number
18
+ pop: number
19
+ }
20
+
21
+ /**
22
+ * A resolution profile attached to a Who's On First admin polygon.
23
+ */
24
+ export interface Convention {
25
+ /**
26
+ * The strategies that the dispatcher runs in order, by registered name.
27
+ * The first strategy that returns a non-null result wins.
28
+ */
29
+ candidateStrategies?: string[]
30
+ /**
31
+ * Weights for the `postcode_area_resolution` soft score.
32
+ *
33
+ * A layer may set some weights and inherit the rest from the layers below it.
34
+ */
35
+ scoringWeights?: Partial<ScoringWeights>
36
+ }
37
+
38
+ /**
39
+ * A convention with every field set, as `resolveConvention` returns it to strategies.
40
+ */
41
+ export interface ResolvedConvention {
42
+ candidateStrategies: string[]
43
+ scoringWeights: ScoringWeights
44
+ }
45
+
46
+ /**
47
+ * The base layer that every ancestor chain starts from.
48
+ *
49
+ * It tries `postcode_area_resolution` and then falls back to fuzzy name matching.
50
+ * Every place without a convention override uses these values, so a change here
51
+ * changes resolution in every such country.
52
+ */
53
+ export const WORLD_DEFAULT: ResolvedConvention = {
54
+ candidateStrategies: ["postcode_area_resolution", "fallback_fuzzy_name_match"],
55
+ scoringWeights: { pc: 0.6, name: 0.3, pop: 0.1 },
56
+ }
57
+
58
+ /**
59
+ * The names of the strategies that the backend registers.
60
+ *
61
+ * The dispatch registry and the build-time validator share this list, so the build
62
+ * rejects a convention that lists an unknown strategy.
63
+ */
64
+ export const BUILTIN_STRATEGY_NAMES = ["postcode_area_resolution", "fallback_fuzzy_name_match"] as const
65
+
66
+ /**
67
+ * The table name for the convention asset, shared by the build script,
68
+ * the runtime source and extract detection.
69
+ */
70
+ export const ADDRESS_CONVENTION_TABLE = "address_convention"
71
+
72
+ /**
73
+ * A resolution strategy selected by name.
74
+ *
75
+ * @returns `null` to abstain, so the dispatcher tries the next strategy,
76
+ * or an array, possibly empty, to claim the result.
77
+ */
78
+ export type Strategy = (query: FindPlaceQuery, convention: ResolvedConvention) => Promise<PlaceCandidate[] | null>
79
+
80
+ /**
81
+ * Looks up a convention by WOF polygon id.
82
+ * `get` returns `undefined` when the polygon has no override.
83
+ */
84
+ export interface ConventionSource {
85
+ get(wofID: number): Convention | undefined
86
+ }
87
+
88
+ /**
89
+ * An in-memory convention source built from a `{ wofID: Convention }` map.
90
+ */
91
+ export class SeedConventionSource implements ConventionSource {
92
+ readonly #rows: Map<number, Convention>
93
+
94
+ constructor(rows: Record<number, Convention> = {}) {
95
+ this.#rows = new Map(Object.entries(rows).map(([k, v]) => [Number(k), v]))
96
+ }
97
+
98
+ get(wofID: number): Convention | undefined {
99
+ return this.#rows.get(wofID)
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Merges convention layers, with later, more specific layers winning per field.
105
+ *
106
+ * A layer's `candidateStrategies` replaces the whole list.
107
+ * `scoringWeights` merges key by key, so a layer can change one weight without restating the others.
108
+ */
109
+ export function mergeConventions(base: Convention, ...overrides: Array<Convention | undefined>): Convention {
110
+ const out: Convention = {
111
+ candidateStrategies: base.candidateStrategies ? [...base.candidateStrategies] : undefined,
112
+ scoringWeights: base.scoringWeights ? { ...base.scoringWeights } : undefined,
113
+ }
114
+
115
+ for (const o of overrides) {
116
+ if (!o) continue
117
+
118
+ if (o.candidateStrategies !== undefined) {
119
+ out.candidateStrategies = [...o.candidateStrategies]
120
+ }
121
+
122
+ if (o.scoringWeights !== undefined) {
123
+ out.scoringWeights = { ...(out.scoringWeights ?? WORLD_DEFAULT.scoringWeights), ...o.scoringWeights }
124
+ }
125
+ }
126
+
127
+ return out
128
+ }
129
+
130
+ /**
131
+ * Resolves the effective convention for a place from its ancestor ids,
132
+ * ordered from most general to most specific.
133
+ *
134
+ * The merge starts from `WORLD_DEFAULT`, so every field is defined.
135
+ */
136
+ export function resolveConvention(source: ConventionSource, ancestorIDs: readonly number[]): ResolvedConvention {
137
+ const layers = ancestorIDs.map((id) => source.get(id))
138
+ const merged = mergeConventions(WORLD_DEFAULT, ...layers)
139
+
140
+ return {
141
+ candidateStrategies: merged.candidateStrategies ?? WORLD_DEFAULT.candidateStrategies,
142
+ scoringWeights: { ...WORLD_DEFAULT.scoringWeights, ...merged.scoringWeights },
143
+ }
144
+ }
@@ -2,25 +2,11 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
+ * @file Schema and read/write helpers for the candidate gazetteer's coverage manifest.
5
6
  *
6
- * Typed schema + read/write helpers for the candidate gazetteer's COVERAGE MANIFEST — the two
7
- * country-keyed tables through which the artifact declares facts about ITSELF, so those facts are
8
- * updated at gazetteer REBUILD, not by a hand-edited code PR after someone remembers:
9
- *
10
- * - `country_coverage`: the hard-country-filter coverage record (#743/#194) — per-country
11
- * promotion-eval verdicts + the measured hard-resolve rates that used to live in a code comment on
12
- * `HARD_PLACE_COUNTRY_SAFELIST`. Presence = measured; `hard_filter_safe = 0` = measured and
13
- * FAILED the check (FI 69.5%, PL 77.8%) — distinguishable from a country never measured at all
14
- * (the meaning-of-zero rule, `docs/engineering/reference/layer-contract.mdx`).
15
- * - `country_bbox`: the coarse guard-B plausibility boxes that used to live in
16
- * `resolver/plausibility.ts`'s `COUNTRY_BBOX`. An absent row fails open (never trips the guard),
17
- * exactly like an absent key in the constant.
18
- *
19
- * Emission happens at build time (`mailwoman/gazetteer-pipeline/coverage-manifest.ts` owns the
20
- * measured record and calls {@link writeGazetteerCoverageManifest} before the DB is sealed — never
21
- * patch a shipped DB, rebuild). The read happens at open time ({@link WOFCandidateTableLookup}
22
- * calls {@link readGazetteerCoverageManifest} in its constructor); an artifact that predates the
23
- * manifest returns `undefined` and every consumer falls back to the code constants byte-identically.
7
+ * The manifest holds two country-keyed tables. `country_coverage` records each measured country's hard-filter
8
+ * verdict. A missing row means the country was never measured. `hard_filter_safe = 0` means measurement found the
9
+ * filter unsafe. `country_bbox` holds coarse plausibility boxes. A missing bbox row never trips the guard.
24
10
  */
25
11
 
26
12
  import {
@@ -36,41 +22,45 @@ import { sql, type Kysely } from "kysely"
36
22
  import { hasTable } from "#sqlite-utils"
37
23
 
38
24
  /**
39
- * One country's hard-filter coverage measurement — the storage form of {@link CountryCoverageFact}.
25
+ * The stored form of {@link CountryCoverageFact}, one row per country.
40
26
  */
41
27
  export interface CountryCoverageTable {
42
28
  /**
43
- * ISO 3166-1 alpha-2, uppercase (PK).
29
+ * The upper-case ISO 3166-1 alpha-2 code.
30
+ * This field is the primary key.
44
31
  */
45
32
  country: string
46
33
  /**
47
- * 0/1 — the promotion-eval verdict (a verdict column, NOT re-derived from the rate; see the fact type's docstring).
34
+ * The promotion-eval verdict as 0 or 1.
35
+ *
36
+ * It is stored directly because the rate by itself does not decide it.
48
37
  */
49
38
  hard_filter_safe: number
50
39
  /**
51
- * Measured hard-resolve rate 0..1 on the panel named in `source`; NULL when the receipt recorded none.
40
+ * The hard-resolve rate from 0 to 1 on the panel given in `source`, or NULL when none was recorded.
52
41
  */
53
42
  hard_resolve_rate: number | null
54
43
  /**
55
- * Panel size behind `hard_resolve_rate`; NULL when unrecorded.
44
+ * The panel size behind `hard_resolve_rate`, or NULL when none was recorded.
56
45
  */
57
46
  sample_size: number | null
58
47
  /**
59
- * ISO-8601 date of the measurement / promote eval.
48
+ * The ISO 8601 date of the measurement.
60
49
  */
61
50
  measured_at: string
62
51
  /**
63
- * The receipt: which panel/check produced this row.
52
+ * The panel or check that produced this row.
64
53
  */
65
54
  source: string
66
55
  }
67
56
 
68
57
  /**
69
- * One country's coarse guard-B bounding box — the storage form of {@link CountryBBoxFact}.
58
+ * The stored form of {@link CountryBBoxFact}, one coarse bounding box per country.
70
59
  */
71
60
  export interface CountryBBoxTable {
72
61
  /**
73
- * ISO 3166-1 alpha-2, uppercase (PK).
62
+ * The upper-case ISO 3166-1 alpha-2 code.
63
+ * This field is the primary key.
74
64
  */
75
65
  country: string
76
66
  lat_min: number
@@ -78,7 +68,7 @@ export interface CountryBBoxTable {
78
68
  lon_min: number
79
69
  lon_max: number
80
70
  /**
81
- * Provenance of the box (harness + date).
71
+ * The provenance of the box.
82
72
  */
83
73
  source: string
84
74
  }
@@ -92,16 +82,17 @@ export interface GazetteerCoverageDatabase {
92
82
  }
93
83
 
94
84
  /**
95
- * Table names the lookup probes (existence-restricted, so a candidate.db built before the manifest is byte-stable).
85
+ * The name of the per-country coverage table.
86
+ * Readers check that it exists before querying it.
96
87
  */
97
88
  export const COUNTRY_COVERAGE_TABLE = "country_coverage"
98
89
  /**
99
- * Table of per-country bounding boxes, used to reject a placement that fell outside its own country.
90
+ * The name of the per-country bounding-box table, used to reject a placement outside its own country.
100
91
  */
101
92
  export const COUNTRY_BBOX_TABLE = "country_bbox"
102
93
 
103
94
  /**
104
- * Create `country_coverage` — a handful of small PK-probed rows, the WITHOUT ROWID sweet spot.
95
+ * Creates the `country_coverage` table as a `WITHOUT ROWID` table keyed by country.
105
96
  */
106
97
  export async function createCountryCoverageTable(db: Kysely<GazetteerCoverageDatabase>): Promise<void> {
107
98
  await db.schema
@@ -113,13 +104,13 @@ export async function createCountryCoverageTable(db: Kysely<GazetteerCoverageDat
113
104
  .addColumn("sample_size", "integer")
114
105
  .addColumn("measured_at", "text", (c) => c.notNull())
115
106
  .addColumn("source", "text", (c) => c.notNull())
116
- // `WITHOUT ROWID` has no first-class builder; the raw modifier is the idiomatic fallback.
107
+ // Kysely has no builder method for `without rowid`.
117
108
  .modifyEnd(sql`without rowid`)
118
109
  .execute()
119
110
  }
120
111
 
121
112
  /**
122
- * Create `country_bbox` — same shape discipline as {@link createCountryCoverageTable}.
113
+ * Creates the `country_bbox` table as a `WITHOUT ROWID` table keyed by country.
123
114
  */
124
115
  export async function createCountryBBoxTable(db: Kysely<GazetteerCoverageDatabase>): Promise<void> {
125
116
  await db.schema
@@ -136,8 +127,10 @@ export async function createCountryBBoxTable(db: Kysely<GazetteerCoverageDatabas
136
127
  }
137
128
 
138
129
  /**
139
- * Write the coverage manifest into a candidate DB UNDER CONSTRUCTION (pre-seal — a shipped DB is never patched, rebuild
140
- * instead). Creates both tables and inserts the facts; call exactly once, from the gazetteer build.
130
+ * Creates both manifest tables in a candidate database under construction and inserts the facts.
131
+ *
132
+ * The gazetteer build calls it once.
133
+ * A shipped database is rebuilt instead of patched.
141
134
  */
142
135
  export async function writeGazetteerCoverageManifest(
143
136
  db: Kysely<GazetteerCoverageDatabase>,
@@ -180,10 +173,12 @@ export async function writeGazetteerCoverageManifest(
180
173
  }
181
174
 
182
175
  /**
183
- * Read the coverage manifest from an OPEN candidate DB, or `undefined` when the artifact predates it (neither table
184
- * present) — the signal for consumers to fall back to the code constants byte-identically. Synchronous raw reads on
185
- * purpose: this runs inside {@link WOFCandidateTableLookup}'s synchronous constructor (the sync-reader carve-out in
186
- * `AGENTS.md`), and the tables are a few dozen rows read once per open.
176
+ * Reads the coverage manifest from an open candidate database.
177
+ *
178
+ * It returns `undefined` when neither table exists.
179
+ * Consumers then fall back to the code constants.
180
+ *
181
+ * The reads are synchronous because the candidate lookup calls this from its constructor.
187
182
  */
188
183
  export function readGazetteerCoverageManifest<DB>(db: DatabaseClient<DB>): GazetteerArtifactCoverage | undefined {
189
184
  const hasCoverage = hasTable(db, COUNTRY_COVERAGE_TABLE)
@@ -3,59 +3,29 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Pass 1c of the candidate build (#1737): resurrect deprecated-with-no-successor WOF localities that a second
7
- * source independently attests. Extracted from `build-candidate.ts` as a cohesive unit — the checks, their measured
8
- * constants, and the GeoNames dump reader live together here; the build calls {@link resurrectCurrencyHoles} once,
9
- * between the primaries pass and the alias pass.
6
+ * Restores deprecated WOF localities only when an independent source attests them.
10
7
  */
11
8
 
12
9
  import { pathExists } from "@mailwoman/core/fs/readers"
13
10
  import { isStrictlyFiner } from "@mailwoman/core/resources/whosonfirst"
14
11
  import { haversineKm } from "@mailwoman/spatial"
15
12
  import type { DatabaseClient } from "@mailwoman/sqlite/client"
16
- import { resolvePath } from "path-ts"
13
+ import { type PathBuilderLike, resolvePath } from "path-ts"
17
14
  import { TSVSpliterator } from "spliterator"
18
15
 
19
- import type { loadImportanceIndex } from "#candidate-importance"
20
- import type { CandidateDatabase } from "#candidate-schema"
16
+ import type { loadImportanceIndex } from "#candidate/importance"
21
17
  import type { PlaceAttrs, StageRow } from "#candidate/place-attrs"
18
+ import type { CandidateDatabase } from "#candidate/schema"
22
19
  import type { WOFDatabase } from "#schema"
23
20
  import { normalizeLocalityForKey } from "#street/normalize"
24
21
 
25
- /**
26
- * Corroboration radius for the currency backfill (#1737), km — both for the live-near blocker and the GeoNames
27
- * attestation. Measured basis (2026-08-19 prototype, GB locality slice): at 10 km, 20 of 108 dead names resurrect —
28
- * Rochester (Kent), Aldershot, Staines, Telford, Ebbw Vale among them — while the `Birmingham/Wolverhampton/…`
29
- * conurbation blobs stay dead (no attestation) and Swansea/Wrexham stay out because a live same-name row already serves
30
- * them within the radius.
31
- */
32
22
  const CURRENCY_BACKFILL_RADIUS_KM = 10
33
23
 
34
- /**
35
- * Minimum attestor population for a resurrection. The same prototype measured 44 of 108 dead GB names attested but
36
- * under this floor — hamlet-scale ghosts whose absence from the index nobody has reported. A floor keeps the pass
37
- * answering the measured defect (real settlements) rather than re-importing the tail WOF chose to prune.
38
- */
39
24
  const CURRENCY_BACKFILL_POP_FLOOR = 1000
40
25
 
41
26
  /**
42
- * Pass 1c (#1737): resurrect deprecated-with-no-successor localities that a second source independently attests.
43
- *
44
- * WOF deprecations WITH a successor need nothing — the successor indexes. A deprecation with `is_superseded = 0` on a
45
- * populated place is the shape of an upstream mistake (Rochester Kent, Aldershot, Telford; 120 GB localities alone),
46
- * and it is indistinguishable from a correct pruning at this layer without outside evidence. So every resurrection
47
- * requires all three conditions, positive evidence only:
48
- *
49
- * 1. NO live same-name spr row of any placetype within {@link CURRENCY_BACKFILL_RADIUS_KM} of the dead record — a live row
50
- * means the place is alive (possibly under another placetype) and there is no hole. A DISTANT same-name row is a
51
- * namesake and does not block.
52
- * 2. A GeoNames feature-class-P attestation of the same folded name within the radius.
53
- * 3. The attestor at or above {@link CURRENCY_BACKFILL_POP_FLOOR}.
54
- *
55
- * The staged row keeps the WOF identity — id, name, centroid, bbox, region ancestry — because the dead record's own
56
- * data is not what is wrong with it. GeoNames contributes exactly two things: the attestation, and the population that
57
- * lets the row stand in prominence races (the dead record's own population is absent). Each name is judged once per
58
- * country; the resurrected place joins `attrs`, so the alias pass explodes its alt names like any primary's.
27
+ * Restore a deprecated locality only when no nearby live namesake exists and GeoNames
28
+ * attests the same folded name above {@link CURRENCY_BACKFILL_POP_FLOOR}.
59
29
  */
60
30
  export interface CurrencyBackfillOutcomes {
61
31
  judged: number
@@ -66,8 +36,8 @@ export interface CurrencyBackfillOutcomes {
66
36
  }
67
37
 
68
38
  /**
69
- * One country's read of the check — every dead name judged, by outcome and by the dead row's placetype — so a census
70
- * can say what a wider dead-row query admits before a build carries it.
39
+ * One country's read of the check — every dead name judged, by outcome and by the dead
40
+ * row's placetype — so a census can say what a wider query admits.
71
41
  */
72
42
  export interface CurrencyBackfillCountryReport extends CurrencyBackfillOutcomes {
73
43
  country: string
@@ -75,8 +45,7 @@ export interface CurrencyBackfillCountryReport extends CurrencyBackfillOutcomes
75
45
  dumpPresent: boolean
76
46
  byDeadPlacetype: Record<string, CurrencyBackfillOutcomes>
77
47
  /**
78
- * The first resurrected names, `placetype:name`, so a census reads what a wider query admits — capped, because the
79
- * report is a receipt and not the table.
48
+ * The first resurrected names, `placetype:name`, capped because the report is a receipt and not the table.
80
49
  */
81
50
  sample: string[]
82
51
  }
@@ -84,8 +53,7 @@ export interface CurrencyBackfillCountryReport extends CurrencyBackfillOutcomes
84
53
  const REPORT_SAMPLE_SIZE = 25
85
54
 
86
55
  /**
87
- * The placetypes a dead row may carry to be judged at all. `locality` is the shipped default; `localadmin` is the
88
- * second cause #1746 named (one GB row of seventeen) and is admitted through this option once its census is read.
56
+ * The placetypes a dead row may have to be judged at all; `locality` is the shipped default.
89
57
  */
90
58
  export const DEFAULT_DEAD_PLACETYPES: readonly string[] = ["locality"]
91
59
 
@@ -96,10 +64,10 @@ function emptyOutcomes(): CurrencyBackfillOutcomes {
96
64
  export async function resurrectCurrencyHoles(ctx: {
97
65
  src: DatabaseClient<WOFDatabase>
98
66
  /**
99
- * The candidate build's transaction. Required unless `dryRun` — a dry run judges every row and stages nothing.
67
+ * The candidate build's transaction, required unless `dryRun`.
100
68
  */
101
69
  tx?: DatabaseClient<CandidateDatabase>
102
- geonamesDir: string
70
+ geonamesDir: PathBuilderLike
103
71
  countries: readonly string[]
104
72
  attrs: Map<number, PlaceAttrs>
105
73
  ccID: (code: string | null) => number
@@ -108,12 +76,10 @@ export async function resurrectCurrencyHoles(ctx: {
108
76
  importance: ReturnType<typeof loadImportanceIndex> | undefined
109
77
  stageRow: StageRow
110
78
  progress: (phase: string, message: string) => void
111
- /**
112
- * Which dead placetypes are judged. Default {@link DEFAULT_DEAD_PLACETYPES}.
113
- */
79
+
114
80
  deadPlacetypes?: readonly string[]
115
81
  /**
116
- * Judge and count, stage nothing — the census mode. No transaction is opened.
82
+ * Judge and count while staging no row and opening no transaction.
117
83
  */
118
84
  dryRun?: boolean
119
85
  /**
@@ -163,9 +129,9 @@ export async function resurrectCurrencyHoles(ctx: {
163
129
  continue
164
130
  }
165
131
 
166
- // Dead rows FIRST: a country with no deprecated-no-successor localities needs no attestors at all, and
167
- // loading a national dump to judge zero rows is pure heap pressure on a build already near its ceiling
168
- // (the first live run OOM'd in a later pass with JP/KR dumps loaded for 0 dead names each).
132
+ // Read dead rows first.
133
+ // A country with no dead names then avoids loading its national dump.
134
+ // That avoids heap pressure on a build near its limit.
169
135
  const dead = deadStmt.all(cc, ...deadPlacetypes)
170
136
 
171
137
  if (!dead.length) {
@@ -175,8 +141,8 @@ export async function resurrectCurrencyHoles(ctx: {
175
141
  continue
176
142
  }
177
143
 
178
- // Only the dead names' own folded keys can ever be probed, so only those keys are worth holding —
179
- // the rest of the national dump streams through without residency.
144
+ // Only the dead names' own folded keys can ever be probed, so the rest of the
145
+ // national dump streams through without residency.
180
146
  const deadKeys = new Set<string>()
181
147
 
182
148
  for (const d of dead) {
@@ -187,8 +153,7 @@ export async function resurrectCurrencyHoles(ctx: {
187
153
  }
188
154
  }
189
155
 
190
- // Folded name → P-class attestors. GeoNames columns by index: 1 name, 2 ascii, 4 lat, 5 lon,
191
- // 6 feature_class, 14 population.
156
+ // GeoNames columns by index: 1 name, 2 ascii, 4 lat, 5 lon, 6 feature_class, 14 population.
192
157
  const attestors = new Map<string, { lat: number; lon: number; pop: number }[]>()
193
158
 
194
159
  for await (const f of TSVSpliterator.fromAsync(dumpPath, { header: false })) {
@@ -232,31 +197,21 @@ export async function resurrectCurrencyHoles(ctx: {
232
197
 
233
198
  if (!pkey || seen.has(pkey)) continue
234
199
  seen.add(pkey)
235
- // Read from the row: the query admits whatever `deadPlacetypes` names, and the rank comparison below must
236
- // judge each candidate against ITS dead rung, never a hardcoded one.
200
+ // The query admits whatever `deadPlacetypes` names, so the rank comparison
201
+ // judges each candidate against its own dead rung.
237
202
  const deadPlacetype = String(d.placetype ?? "locality")
238
203
 
239
204
  count(deadPlacetype, "judged")
240
205
  const dLat = Number(d.latitude)
241
206
  const dLon = Number(d.longitude)
242
207
 
243
- // A live row blocks only when it is AT LEAST AS COARSE as the dead one. The original check compared name and
244
- // distance alone, on the premise that a nearby same-name row means "the place is alive under another
245
- // placetype" — true for a place recorded twice, false for a placetype DEMOTION, which is the shape that
246
- // actually occurs: WOF retired `Gillingham` the locality (pop 101,187) and kept `Gillingham` the
247
- // neighbourhood 3.2 km away, and the check read the surviving CHILD as covering its own dead parent.
248
- // Sixteen of seventeen GB refusals had exactly that shape (#1746).
249
- //
250
- // An UNRANKED placetype blocks, which is the conservative direction: this check's failure mode is inventing
251
- // a place, so a row we cannot rank is treated as covering rather than waved through.
208
+ // A live row blocks unless it is strictly finer than the dead one.
209
+ // An unranked placetype also blocks because the failure mode is inventing a place.
252
210
  const liveNear = liveStmt.all(cc, name).some((row) => {
253
211
  if (haversineKm(dLat, dLon, Number(row.latitude), Number(row.longitude)) > CURRENCY_BACKFILL_RADIUS_KM) {
254
212
  return false
255
213
  }
256
214
 
257
- // Blocks UNLESS the live row is strictly finer. The equal rung must still block — a live `locality`
258
- // covers a dead `locality` — and an unranked placetype blocks too, since this check's failure mode
259
- // is inventing a place.
260
215
  return isStrictlyFiner(String(row.placetype ?? ""), deadPlacetype) !== true
261
216
  })
262
217
 
package/lib/env.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Environment variables naming the WOF SQLite artifacts this resolver opens, and the development weights the overlay
6
+ * Environment variables name the WOF SQLite artifacts this resolver opens and the development weights the overlay
7
7
  * linker materializes. CLI flags (`--resolve-db`, …) override these at the call site.
8
8
  */
9
9
 
@@ -3,20 +3,25 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * The exact-match tier's name probes — the two case-folded equality lookups that decide whether a
6
+ * The exact-match tier's name probes, the two case-folded equality lookups that decide whether a
7
7
  * candidate holds the query text as its own name, an alias, or an official name.
8
8
  */
9
9
 
10
10
  import type { DatabaseClient } from "@mailwoman/sqlite/client"
11
11
 
12
- import { aliasBagExactMatch, foldQueryText } from "#fts/index"
12
+ import { aliasBagExactMatch, foldQueryText } from "#fts"
13
13
 
14
14
  /**
15
- * Among `ids`, return the subset whose name OR any alias equals `text` case-insensitively — the exact-match tier for
16
- * ranking. One indexed query over `<schema>.names`. When the extract has no `names` table (a slim DB built with
17
- * `dropNames`, or a postcode-only extract), fall back to the self-contained `place_search` FTS content: its `alt_names`
18
- * column is the same alias set joined on the boundary-preserving `ALIAS_SEPARATOR` (#523), so `aliasBagExactMatch`
19
- * recovers the exact alias tier ("New York City" → New York) that the dropped `names` table used to provide.
15
+ * Among `ids`, return the subset whose name or any alias equals `text` case-insensitively,
16
+ * the exact-match tier for ranking.
17
+ *
18
+ * One indexed query over `<schema>.names`.
19
+ * When the extract has no `names` table (a slim database built with `dropNames`, or a postcode-only extract),
20
+ * fall back to the self-contained `place_search` FTS content.
21
+ *
22
+ * Its `alt_names` column is the same alias set joined on the boundary-preserving
23
+ * `ALIAS_SEPARATOR`, so `aliasBagExactMatch` recovers the exact alias tier
24
+ * ("New York City" → New York) that the dropped `names` table used to provide.
20
25
  */
21
26
  export function exactMatchIDs<DB>(
22
27
  db: DatabaseClient<DB>,
@@ -41,7 +46,8 @@ export function exactMatchIDs<DB>(
41
46
 
42
47
  return out
43
48
  } catch {
44
- // No `names` table on this extract — fall through to the place_search alias bag.
49
+ // No `names` table on this extract.
50
+ // Fall through to the place_search alias bag.
45
51
  }
46
52
 
47
53
  try {
@@ -57,12 +63,12 @@ export function exactMatchIDs<DB>(
57
63
  }
58
64
  }
59
65
 
60
- // Alias pass via the shared bag parser (#523). Separated bags (built since #523) get a true
61
- // per-alias equality check, unrestricted — matching the `names`-table branch above, where an
62
- // alias match counts as exact regardless of other candidates. Legacy bags (no separator)
63
- // fall back to padded containment, conditioned on "no canonical exact in the pool" because their
64
- // lost boundaries would otherwise false-promote interior fragments ("York" inside the alias
65
- // "New York City") or cross-alias fragments ("York New" across "…York" + "New City…").
66
+ // Alias pass via the shared bag parser.
67
+ // Separated bags get a true per-alias equality check, unrestricted, matching the `names`-table
68
+ // branch above where an alias match counts as exact regardless of other candidates.
69
+ // Legacy bags without a separator fall back to padded containment, conditioned on "no
70
+ // canonical exact in the pool" because their lost boundaries would otherwise false-promote
71
+ // interior fragments ("York" inside the alias "New York City") or cross-alias fragments.
66
72
  const anyCanonicalExact = out.size > 0
67
73
 
68
74
  for (const r of rows) {
@@ -71,17 +77,22 @@ export function exactMatchIDs<DB>(
71
77
  }
72
78
  }
73
79
  } catch {
74
- // Extract without place_search either → no exact-match tier. Falls back to weighted-sum order.
80
+ // Extract without place_search either, so there is no exact-match tier.
81
+ // The caller falls back to weighted-sum order.
75
82
  }
76
83
 
77
84
  return out
78
85
  }
79
86
 
80
87
  /**
81
- * Among `ids` (already known exact matches), the subset holding `text` as an OFFICIAL name (`names.official = 1`, the
82
- * #940 ingest bit). Same COLLATE NOCASE semantics as {@link WOFSQLitePlaceLookup.#exactMatchIDs} so the two probes
83
- * agree on what "equals the query" means. Fails soft on gazetteers built before #940 (no `official` column) — the
84
- * sub-tier then behaves exactly as if `officialNameExact` were off.
88
+ * Among `ids` (already known exact matches), the subset holding `text` as an
89
+ * official name (`names.official = 1`, the ingest bit).
90
+ *
91
+ * Same collate nocase semantics as {@link WOFSQLitePlaceLookup.#exactMatchIDs},
92
+ * so the two probes agree on what "equals the query" means.
93
+ * Fails soft on gazetteers built before the `official` column existed.
94
+ *
95
+ * The sub-tier then behaves exactly as if `officialNameExact` were off.
85
96
  */
86
97
  export function officialNameIDs<DB>(
87
98
  db: DatabaseClient<DB>,
@@ -106,7 +117,7 @@ export function officialNameIDs<DB>(
106
117
  out.add(r.id)
107
118
  }
108
119
  } catch {
109
- // Pre-#940 gazetteer (no `official` column) or a names-less slim extract — feature inert.
120
+ // A gazetteer without the `official` column, or a names-less slim extract, leaves the feature inert.
110
121
  }
111
122
 
112
123
  return out