@mailwoman/resolver-wof-sqlite 10.0.0 → 10.2.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 (477) hide show
  1. package/README.md +9 -8
  2. package/lib/address/point/interpolation.ts +45 -39
  3. package/lib/address/point/schema.ts +17 -40
  4. package/lib/address/point.ts +316 -0
  5. package/lib/{address/index.ts → address.ts} +1 -1
  6. package/lib/ancestry/backfill.ts +20 -86
  7. package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
  8. package/lib/build/candidate.ts +122 -174
  9. package/lib/build/population-corrections.ts +64 -0
  10. package/lib/build/slim.ts +44 -114
  11. package/lib/candidate/alias-bags.ts +16 -17
  12. package/lib/candidate/ancestors/schema.ts +77 -61
  13. package/lib/candidate/ancestors/sidecar.ts +15 -22
  14. package/lib/candidate/country-display-names.ts +6 -20
  15. package/lib/candidate/extract-fold.ts +10 -55
  16. package/lib/candidate/fts.ts +5 -23
  17. package/lib/candidate/importance.ts +65 -68
  18. package/lib/candidate/lookup.ts +124 -415
  19. package/lib/candidate/name-roles.ts +15 -33
  20. package/lib/candidate/own-name.ts +35 -32
  21. package/lib/candidate/place-attrs.ts +20 -13
  22. package/lib/candidate/schema.ts +29 -65
  23. package/lib/candidate/scoring.ts +54 -93
  24. package/lib/capital-schema.ts +21 -17
  25. package/lib/capitals.ts +29 -27
  26. package/lib/coincident-roles.ts +85 -55
  27. package/lib/convention/schema.ts +15 -16
  28. package/lib/convention.ts +144 -0
  29. package/lib/coverage-manifest-schema.ts +40 -45
  30. package/lib/currency-backfill.ts +34 -79
  31. package/lib/env.ts +1 -1
  32. package/lib/exact-match.ts +32 -21
  33. package/lib/extracts.ts +97 -74
  34. package/lib/fst/autocomplete.ts +54 -37
  35. package/lib/fst/builder.ts +37 -41
  36. package/lib/fst/deserialize-web.ts +16 -17
  37. package/lib/fst/format.ts +41 -23
  38. package/lib/fst/freshness.ts +43 -120
  39. package/lib/fst/matcher.ts +7 -5
  40. package/lib/fst/serialize.ts +54 -74
  41. package/lib/fst/types.ts +78 -75
  42. package/lib/{fst/index.ts → fst.ts} +1 -0
  43. package/lib/fts/query.ts +5 -36
  44. package/lib/fts.ts +280 -0
  45. package/lib/geonames/aliases.ts +73 -144
  46. package/lib/geonames/postal.ts +162 -71
  47. package/lib/index.ts +9 -8
  48. package/lib/interpolation.ts +48 -100
  49. package/lib/lookup.ts +155 -270
  50. package/lib/name-score.ts +9 -7
  51. package/lib/nsul/lookup.ts +37 -54
  52. package/lib/nsul/schema.ts +16 -43
  53. package/lib/paths.ts +159 -0
  54. package/lib/place-importance-schema.ts +62 -169
  55. package/lib/poi/lookup.ts +104 -121
  56. package/lib/poi/schema.ts +42 -26
  57. package/lib/polygon-schema.ts +10 -6
  58. package/lib/postal/city/alias/lookup.ts +22 -40
  59. package/lib/postal/city/alias/schema.ts +14 -10
  60. package/lib/postal/city/candidate-schema.ts +26 -20
  61. package/lib/postcode-point-lookup.ts +8 -27
  62. package/lib/primary-preference.ts +46 -126
  63. package/lib/proximity-rerank.ts +44 -33
  64. package/lib/ranking-weights.ts +105 -78
  65. package/lib/region-keys.ts +70 -42
  66. package/lib/reverse.ts +149 -86
  67. package/lib/schema.ts +73 -50
  68. package/lib/search-fetch.ts +90 -68
  69. package/lib/sqlite/convention-source.ts +15 -23
  70. package/lib/sqlite/utils.ts +19 -22
  71. package/lib/street/centroid/schema.ts +37 -42
  72. package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
  73. package/lib/street/morphology/fst/builder.ts +60 -42
  74. package/lib/street/morphology/fst/loader.ts +40 -32
  75. package/lib/street/name-lookup.ts +45 -41
  76. package/lib/street/normalize.ts +88 -219
  77. package/lib/street/segment-schema.ts +116 -43
  78. package/lib/{street/index.ts → street.ts} +1 -1
  79. package/lib/types.ts +109 -150
  80. package/lib/unified-schema.ts +29 -29
  81. package/lib/uprn/existence.ts +30 -19
  82. package/lib/uprn/lookup.ts +29 -68
  83. package/lib/uprn/schema.ts +18 -40
  84. package/lib/weights-overlay-linker.ts +236 -252
  85. package/out/address/point/interpolation.d.ts +20 -23
  86. package/out/address/point/interpolation.d.ts.map +1 -1
  87. package/out/address/point/interpolation.js +42 -39
  88. package/out/address/point/interpolation.js.map +1 -1
  89. package/out/address/point/schema.d.ts +12 -35
  90. package/out/address/point/schema.d.ts.map +1 -1
  91. package/out/address/point/schema.js +3 -19
  92. package/out/address/point/schema.js.map +1 -1
  93. package/out/address/point.d.ts +57 -0
  94. package/out/address/point.d.ts.map +1 -0
  95. package/out/address/point.js +206 -0
  96. package/out/address/point.js.map +1 -0
  97. package/out/{address/index.js → address.d.ts} +2 -2
  98. package/out/address.d.ts.map +1 -0
  99. package/out/{address/index.d.ts → address.js} +2 -2
  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 +14 -74
  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 +82 -112
  110. package/out/build/candidate.d.ts.map +1 -1
  111. package/out/build/candidate.js +17 -100
  112. package/out/build/candidate.js.map +1 -1
  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 +8 -44
  118. package/out/build/slim.d.ts.map +1 -1
  119. package/out/build/slim.js +33 -94
  120. package/out/build/slim.js.map +1 -1
  121. package/out/candidate/alias-bags.d.ts +6 -6
  122. package/out/candidate/alias-bags.d.ts.map +1 -1
  123. package/out/candidate/alias-bags.js +16 -17
  124. package/out/candidate/alias-bags.js.map +1 -1
  125. package/out/candidate/ancestors/schema.d.ts +73 -57
  126. package/out/candidate/ancestors/schema.d.ts.map +1 -1
  127. package/out/candidate/ancestors/schema.js +56 -48
  128. package/out/candidate/ancestors/schema.js.map +1 -1
  129. package/out/candidate/ancestors/sidecar.d.ts +3 -8
  130. package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
  131. package/out/candidate/ancestors/sidecar.js +15 -22
  132. package/out/candidate/ancestors/sidecar.js.map +1 -1
  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 +7 -15
  138. package/out/candidate/extract-fold.d.ts.map +1 -1
  139. package/out/candidate/extract-fold.js +5 -47
  140. package/out/candidate/extract-fold.js.map +1 -1
  141. package/out/candidate/fts.d.ts +5 -23
  142. package/out/candidate/fts.d.ts.map +1 -1
  143. package/out/candidate/fts.js +5 -23
  144. package/out/candidate/fts.js.map +1 -1
  145. package/out/candidate/importance.d.ts +60 -65
  146. package/out/candidate/importance.d.ts.map +1 -1
  147. package/out/candidate/importance.js +56 -63
  148. package/out/candidate/importance.js.map +1 -1
  149. package/out/candidate/lookup.d.ts +18 -55
  150. package/out/candidate/lookup.d.ts.map +1 -1
  151. package/out/candidate/lookup.js +82 -385
  152. package/out/candidate/lookup.js.map +1 -1
  153. package/out/candidate/name-roles.d.ts +9 -21
  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 +35 -32
  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 +27 -62
  166. package/out/candidate/schema.d.ts.map +1 -1
  167. package/out/candidate/schema.js +10 -22
  168. package/out/candidate/schema.js.map +1 -1
  169. package/out/candidate/scoring.d.ts +7 -8
  170. package/out/candidate/scoring.d.ts.map +1 -1
  171. package/out/candidate/scoring.js +52 -89
  172. package/out/candidate/scoring.js.map +1 -1
  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 +27 -25
  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 +72 -50
  184. package/out/coincident-roles.js.map +1 -1
  185. package/out/convention/schema.d.ts +14 -14
  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 +34 -39
  194. package/out/coverage-manifest-schema.d.ts.map +1 -1
  195. package/out/coverage-manifest-schema.js +25 -34
  196. package/out/coverage-manifest-schema.js.map +1 -1
  197. package/out/currency-backfill.d.ts +16 -38
  198. package/out/currency-backfill.d.ts.map +1 -1
  199. package/out/currency-backfill.js +19 -46
  200. package/out/currency-backfill.js.map +1 -1
  201. package/out/env.d.ts +1 -1
  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 +32 -21
  206. package/out/exact-match.js.map +1 -1
  207. package/out/extracts.d.ts +66 -55
  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 +29 -21
  212. package/out/fst/autocomplete.d.ts.map +1 -1
  213. package/out/fst/autocomplete.js +39 -28
  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 +37 -41
  217. package/out/fst/builder.js.map +1 -1
  218. package/out/fst/deserialize-web.d.ts +4 -4
  219. package/out/fst/deserialize-web.d.ts.map +1 -1
  220. package/out/fst/deserialize-web.js +15 -16
  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 +19 -81
  227. package/out/fst/freshness.d.ts.map +1 -1
  228. package/out/fst/freshness.js +31 -94
  229. package/out/fst/freshness.js.map +1 -1
  230. package/out/fst/matcher.d.ts +5 -4
  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 +28 -28
  235. package/out/fst/serialize.d.ts.map +1 -1
  236. package/out/fst/serialize.js +53 -71
  237. package/out/fst/serialize.js.map +1 -1
  238. package/out/fst/types.d.ts +78 -74
  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} +2 -1
  243. package/out/fst.d.ts.map +1 -0
  244. package/out/{fst/index.d.ts → fst.js} +2 -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 -62
  255. package/out/geonames/aliases.d.ts.map +1 -1
  256. package/out/geonames/aliases.js +45 -117
  257. package/out/geonames/aliases.js.map +1 -1
  258. package/out/geonames/postal.d.ts +84 -44
  259. package/out/geonames/postal.d.ts.map +1 -1
  260. package/out/geonames/postal.js +115 -73
  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 +9 -8
  267. package/out/index.d.ts.map +1 -1
  268. package/out/index.js +6 -5
  269. package/out/index.js.map +1 -1
  270. package/out/interpolation.d.ts +18 -55
  271. package/out/interpolation.d.ts.map +1 -1
  272. package/out/interpolation.js +27 -69
  273. package/out/interpolation.js.map +1 -1
  274. package/out/lookup.d.ts +23 -51
  275. package/out/lookup.d.ts.map +1 -1
  276. package/out/lookup.js +136 -234
  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 +51 -143
  299. package/out/place-importance-schema.d.ts.map +1 -1
  300. package/out/place-importance-schema.js +28 -143
  301. package/out/place-importance-schema.js.map +1 -1
  302. package/out/poi/lookup.d.ts +40 -47
  303. package/out/poi/lookup.d.ts.map +1 -1
  304. package/out/poi/lookup.js +69 -96
  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 +20 -23
  319. package/out/postal/city/alias/lookup.d.ts.map +1 -1
  320. package/out/postal/city/alias/lookup.js +17 -30
  321. package/out/postal/city/alias/lookup.js.map +1 -1
  322. package/out/postal/city/alias/schema.d.ts +14 -10
  323. package/out/postal/city/alias/schema.d.ts.map +1 -1
  324. package/out/postal/city/alias/schema.js +10 -8
  325. package/out/postal/city/alias/schema.js.map +1 -1
  326. package/out/postal/city/candidate-schema.d.ts +25 -19
  327. package/out/postal/city/candidate-schema.d.ts.map +1 -1
  328. package/out/postal/city/candidate-schema.js +21 -17
  329. package/out/postal/city/candidate-schema.js.map +1 -1
  330. package/out/{postal/index.d.ts → postal.d.ts} +1 -1
  331. package/out/postal.d.ts.map +1 -0
  332. package/out/{postal/index.js → postal.js} +1 -1
  333. package/out/postal.js.map +1 -0
  334. package/out/postcode-point-lookup.d.ts +6 -24
  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 +38 -92
  339. package/out/primary-preference.d.ts.map +1 -1
  340. package/out/primary-preference.js +15 -99
  341. package/out/primary-preference.js.map +1 -1
  342. package/out/proximity-rerank.d.ts +41 -30
  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 +98 -64
  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 +50 -31
  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 +78 -50
  355. package/out/reverse.d.ts.map +1 -1
  356. package/out/reverse.js +98 -61
  357. package/out/reverse.js.map +1 -1
  358. package/out/schema.d.ts +72 -49
  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 +12 -16
  367. package/out/sqlite/convention-source.d.ts.map +1 -1
  368. package/out/sqlite/convention-source.js +13 -22
  369. package/out/sqlite/convention-source.js.map +1 -1
  370. package/out/sqlite/utils.d.ts +19 -19
  371. package/out/sqlite/utils.d.ts.map +1 -1
  372. package/out/sqlite/utils.js +14 -15
  373. package/out/sqlite/utils.js.map +1 -1
  374. package/out/street/centroid/schema.d.ts +37 -42
  375. package/out/street/centroid/schema.d.ts.map +1 -1
  376. package/out/street/centroid/schema.js +9 -21
  377. package/out/street/centroid/schema.js.map +1 -1
  378. package/out/street/centroid.d.ts +30 -0
  379. package/out/street/centroid.d.ts.map +1 -0
  380. package/out/street/{centroid/index.js → centroid.js} +13 -24
  381. package/out/street/centroid.js.map +1 -0
  382. package/out/street/morphology/fst/builder.d.ts +20 -10
  383. package/out/street/morphology/fst/builder.d.ts.map +1 -1
  384. package/out/street/morphology/fst/builder.js +44 -34
  385. package/out/street/morphology/fst/builder.js.map +1 -1
  386. package/out/street/morphology/fst/loader.d.ts +33 -26
  387. package/out/street/morphology/fst/loader.d.ts.map +1 -1
  388. package/out/street/morphology/fst/loader.js +23 -22
  389. package/out/street/morphology/fst/loader.js.map +1 -1
  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 +34 -35
  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 +77 -194
  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.js → street.d.ts} +2 -2
  403. package/out/street.d.ts.map +1 -0
  404. package/out/{street/index.d.ts → street.js} +2 -2
  405. package/out/street.js.map +1 -0
  406. package/out/types.d.ts +84 -149
  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 +21 -57
  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 +138 -144
  431. package/out/weights-overlay-linker.d.ts.map +1 -1
  432. package/out/weights-overlay-linker.js +105 -159
  433. package/out/weights-overlay-linker.js.map +1 -1
  434. package/package.json +91 -596
  435. package/lib/address/point/index.ts +0 -328
  436. package/lib/convention/index.ts +0 -154
  437. package/lib/fts/index.ts +0 -361
  438. package/out/address/index.d.ts.map +0 -1
  439. package/out/address/index.js.map +0 -1
  440. package/out/address/point/index.d.ts +0 -53
  441. package/out/address/point/index.d.ts.map +0 -1
  442. package/out/address/point/index.js +0 -222
  443. package/out/address/point/index.js.map +0 -1
  444. package/out/ancestry/index.d.ts +0 -45
  445. package/out/ancestry/index.d.ts.map +0 -1
  446. package/out/ancestry/index.js +0 -55
  447. package/out/ancestry/index.js.map +0 -1
  448. package/out/convention/index.d.ts +0 -106
  449. package/out/convention/index.d.ts.map +0 -1
  450. package/out/convention/index.js +0 -93
  451. package/out/convention/index.js.map +0 -1
  452. package/out/fst/index.d.ts.map +0 -1
  453. package/out/fst/index.js.map +0 -1
  454. package/out/fts/index.d.ts +0 -184
  455. package/out/fts/index.d.ts.map +0 -1
  456. package/out/fts/index.js +0 -277
  457. package/out/fts/index.js.map +0 -1
  458. package/out/geonames/index.d.ts.map +0 -1
  459. package/out/geonames/index.js.map +0 -1
  460. package/out/nsul/index.d.ts.map +0 -1
  461. package/out/nsul/index.js.map +0 -1
  462. package/out/poi/index.d.ts.map +0 -1
  463. package/out/poi/index.js.map +0 -1
  464. package/out/postal/index.d.ts.map +0 -1
  465. package/out/postal/index.js.map +0 -1
  466. package/out/street/centroid/index.d.ts +0 -40
  467. package/out/street/centroid/index.d.ts.map +0 -1
  468. package/out/street/centroid/index.js.map +0 -1
  469. package/out/street/index.d.ts.map +0 -1
  470. package/out/street/index.js.map +0 -1
  471. package/out/uprn/index.d.ts.map +0 -1
  472. package/out/uprn/index.js.map +0 -1
  473. /package/lib/{geonames/index.ts → geonames.ts} +0 -0
  474. /package/lib/{nsul/index.ts → nsul.ts} +0 -0
  475. /package/lib/{poi/index.ts → poi.ts} +0 -0
  476. /package/lib/{postal/index.ts → postal.ts} +0 -0
  477. /package/lib/{uprn/index.ts → uprn.ts} +0 -0
@@ -2,132 +2,78 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
- *
6
- * Bounded cross-country PRIMARY-NAME preference over a population-ordered candidate row set — the
7
- * `is_primary` ranking signal, PURE and platform-free so the Node candidate lookup
8
- * (`candidate-lookup.ts`) and the browser twin (`packages/resolver-wof-wasm/lib/httpvfs/resolver.ts`) rank with
9
- * the SAME function rather than two copies that drift (the #861 server↔browser parity contract).
10
- *
11
- * Only type imports and arithmetic live here: anything with a `node:` import stays out.
12
5
  */
13
6
  import type { CandidateTable } from "#candidate/schema";
14
7
  /**
15
- * The row shape the re-rank needs. `is_primary` is optional: a reader over an artifact vintage that predates the column
16
- * omits it from the SELECT, no row reads as primary, and the re-rank no-ops by construction — the exact degradation the
17
- * browser reader's vintage guard relies on.
8
+ * The candidate-row fields that {@link rankByPrimaryPreference} reads.
9
+ *
10
+ * `is_primary` is optional, so an older artifact without the column skips the re-rank without an error.
18
11
  */
19
12
  export type PrimaryPreferenceRow = Pick<CandidateTable, "neg_rank" | "country_id"> & Partial<Pick<CandidateTable, "is_primary" | "placetype_id" | "population" | "name_role">>;
20
13
  /**
21
- * Bounded PRIMARY-NAME preference across a CROSS-COUNTRY name collision (the `is_primary` ranking signal).
22
- *
23
- * The raw candidate order is population-first (`neg_rank ASC`) and treats an ALIAS row (a place's alt-name / exonym,
24
- * `is_primary=0`) and a PRIMARY-name row (`is_primary=1`) on equal footing. So a foreign place whose transliterated
25
- * exonym coincidentally normalizes to a query — Changchun CN stores the Turkish exonym "Çançun" (`name_key="cancun"`),
26
- * 4.19 M pop — outranks the PRIMARY-name place the query actually means (Cancún MX, 0.89 M pop). This penalty makes a
27
- * same-key alias have to clear a population MARGIN over a foreign primary before it wins.
14
+ * The log10-population penalty applied to an alias row when the top primary-name
15
+ * row for the same key is in another country.
28
16
  *
29
- * It is deliberately NOT a dominant sort key (no `ORDER BY is_primary DESC`, which would make every primary outrank
30
- * every alias and break the alt-names users depend on — "NYC"→New York, "LA"→Los Angeles, "Frisco"→San Francisco). Two
31
- * bounds keep it a soft prior:
32
- *
33
- * 1. **Cross-country only.** The penalty applies to an alias ONLY when the top-population primary sharing the key is in a
34
- * DIFFERENT country. A SAME-country nickname contest (San Francisco's alias "Frisco" vs the primary Frisco, TX —
35
- * both US) is left on pure population, so the legitimate alias still wins.
36
- * 2. **Population-bounded.** The penalty is {@link PRIMARY_PREFERENCE_LOG10} in log10-population units — an alias must be
37
- * at least 10x more populous than the foreign primary to still win. So a genuinely dominant alias keeps winning
38
- * ("Los Angeles" over La, Ghana — gap 1.6; "Las Vegas" over Vegas, Cuba — gap 2.4) while a near-tie coincidental
39
- * collision defers to the primary (Cancún over Changchun — gap 0.7).
17
+ * An alias at least 10 times as populous still wins, so alternate names such as "LA" keep working.
40
18
  */
41
19
  export declare const PRIMARY_PREFERENCE_LOG10 = 1;
42
20
  /**
43
- * Over-fetch cap for {@link rankByPrimaryPreference}: the candidate rows for one `name_key` (all same-name places
44
- * worldwide) are re-ranked in-process, so the probe fetches this many (population-ordered) before the re-rank rather
45
- * than the caller's small `limit`, ensuring the intended primary isn't pushed below the fold by a cluster of
46
- * more-populous foreign aliases. Bounded and small — a single contiguous B-tree scan.
21
+ * The number of population-ordered rows fetched per name key before
22
+ * {@link rankByPrimaryPreference} re-ranks them.
23
+ *
24
+ * A fetch of only the caller's `limit` could miss the intended primary behind more populous foreign aliases.
47
25
  */
48
26
  export declare const RERANK_FETCH = 64;
49
27
  /**
50
- * A candidate row annotated with the {@link rankByPrimaryPreference} effective rank + the exact-tier demotion flag.
28
+ * A candidate row with its re-ranked `effectiveNegRank` and its `demoted` flag.
51
29
  */
52
30
  export type RankedRow<R> = R & {
53
31
  /**
54
- * `neg_rank` plus the bounded cross-country alias penalty — the value the row is ORDERED by, and the base the emitted
55
- * `prominence` is derived from (so the resolver walk's `prominence ?? score` sort, `resolve.ts`, agrees with this
56
- * order; the raw `score`/`neg_rank` is left intact for the walk's `minWinningScore` floor).
32
+ * `neg_rank` plus any cross-country alias penalty.
33
+ *
34
+ * Rows are ordered by this value.
35
+ * The emitted `prominence` derives from it.
36
+ *
37
+ * The raw `neg_rank` stays on the row for the resolver's minimum winning score.
57
38
  */
58
39
  effectiveNegRank: number;
59
40
  /**
60
- * True when this row is a cross-country alias that LOST the bounded population contest to the same-key primary — a
61
- * coincidental foreign exonym (Changchun's "Çançun" for "Cancun"). Such a row is dropped out of the exact-match tier
62
- * (`exactMatch=false`) so the resolver walk's country pin — the model's `anchorPosterior`, which "never crosses the
63
- * exact/partial boundary" (`resolve.ts`) — can't ride a spurious posterior (CN 0.86 for "Cancun") back over the
64
- * primary. Only the LOSING foreign alias is demoted; a dominant alias (Los Angeles over La, Ghana) keeps its exact
65
- * tier, and a same-country nickname (San Francisco's "Frisco") is never touched.
41
+ * True when this row is a cross-country alias that the penalty moved behind
42
+ * the top primary for the same key.
43
+ *
44
+ * A demoted row loses `exactMatch`, so the resolver's country pin cannot promote
45
+ * a coincidental foreign exonym back over the primary.
46
+ * A dominant alias and a same-country alias are never demoted.
66
47
  */
67
48
  demoted: boolean;
68
49
  /**
69
- * True when this row came from the TYPO-CORRECTOR tier — the FTS5-trigram fallback that fires only after the exact
70
- * and qualifier-strip probes both missed. Such a row answers a query the gazetteer does not contain, so it is a fuzzy
71
- * match by construction and must not claim `exactMatch` (#17). Recall is unaffected: the row is still returned, still
72
- * ranked, still resolvable — it just stops asserting a match quality it does not have, which is what the FTS backend
73
- * has always done and what every `exactMatch`-filtering consumer assumed.
50
+ * True when this row came from the typo-correction fallback.
51
+ * The fallback runs only after the exact probes miss.
52
+ *
53
+ * The row is still returned and ranked, but it never claims `exactMatch`.
74
54
  */
75
55
  fuzzy?: boolean;
76
56
  /**
77
- * The admin-containment verdict (#1717 stage 2), stamped by `candidate-lookup.ts` when the query carried a
78
- * `regionQualifier` and the artifact carries the ancestors sidecar — the `fuzzy` precedent: a lookup-tier annotation
79
- * declared on the shared row shape. Tri-state like `ResolvedPlace.containedByQualifier`: absent means the question
80
- * was never asked, never "not contained".
57
+ * Whether the row lies inside the query's region qualifier.
58
+ *
59
+ * The candidate lookup sets it when the artifact has the ancestors sidecar.
60
+ *
61
+ * When the field is absent, containment was not checked.
81
62
  */
82
63
  containedByQualifier?: boolean;
83
64
  /**
84
- * The #1882 exemption's firing mark (#1893): this row would have taken the cross-country alias penalty and
85
- * `exemptVariantAliases` prevented it. PRESENT only when the exemption changed this row's treatment; absent on every
86
- * row it merely inspected — an in-country variant, a primary, a set with no foreign top primary. The winner-level
87
- * receipt downstream (`mechanism_fired_on.variant_alias_exemption`) counts this mark only when it survives onto the
88
- * selected candidate.
65
+ * Set only when the variant-alias exemption spared this row the cross-country alias penalty.
89
66
  */
90
67
  variantExempted?: true;
91
68
  };
92
69
  /**
93
- * Bounded cross-country primary-name preference (see {@link PRIMARY_PREFERENCE_LOG10}). Pure + total-ordered so
94
- * `candidate-lookup.test.ts` can exercise it on synthetic rows. `rows` arrive population-ordered (`neg_rank ASC`); an
95
- * alias (`is_primary=0`) is pushed back by `delta` in log10-population units ONLY when the top-population primary
96
- * sharing the key is in a different country, and is `demoted` out of the exact tier when that penalty leaves it BEHIND
97
- * the primary. Returns the top `limit` after the re-rank, each annotated.
98
- *
99
- * `placetypes` (the artifact's own `placetype_codes` map) enables the LAST tiebreak, the SEAT preference: when
100
- * `effectiveNegRank` and raw `neg_rank` both tie — two same-key rows population cannot separate at all — a
101
- * {@link SEAT_PLACETYPE} row carrying a real population outranks every other placetype. Omit the map and every row
102
- * scores 0, the term cancels, and the order is exactly the population-then-scan-order it was before.
103
- *
104
- * The tie it exists for is a DUPLICATE, not a contest. A district and its identically-named seat town are stored as two
105
- * rows carrying the SAME population, so `neg_rank` is equal to the bit and `referential` follows it
106
- * (`referentialFromPopulation` is a pure function of population). Turkey's `Of` is the measured case — locality
107
- * 8114738869649 and its parent county 8837168432019 both hold population 44212 — and 358 locality/parent-county pairs
108
- * across 15 countries share the shape in `admin-global-priority.db` (TR 162, CA 77, US 47, HR 24, DO 14). Without the
109
- * term their order is whatever the scan hands the sorter.
70
+ * Re-ranks population-ordered candidate rows.
110
71
  *
111
- * WHERE THE TERM DECIDES, AND WHERE IT CANNOT (#1729). It binds inside `findPlace`, so it orders every row set that
112
- * actually CONTAINS the tie — but the resolver walk's probes all carry a placetype filter, and
113
- * `PLACETYPE_FILTER_GROUPS` (core/resolver) never mixes `locality` with `county`: the `Of`-shape locality/county pair
114
- * is PARTITIONED before this ranker runs, the locality probe fetches one row, and the walk's own `locality` request
115
- * selects the seat by construction — the same winner, decided upstream. The tie that reaches an end-to-end answer
116
- * through this term is the IN-GROUP residue: a locality/localadmin (or borough) duplicate whose `importance` values
117
- * also tie. Downstream the resolver re-sorts by importance (`resolver/toponym-prior.ts`) but is stable on equal keys,
118
- * so the order stamped here is the order that answers — inverting this term moves bare `Pu-cheng-hsien` 1,100 km
119
- * (locality Pucheng over the 浦城县 localadmin, identical population and importance). Where importance separates the pair,
120
- * the fame prior overrides by design; a probe with NO placetype filter (the browser cascade's last resort, the dev
121
- * lookup tools) presents the full tie and this term is all that breaks it.
72
+ * A cross-country alias must beat the top primary by `delta` in log10 population.
73
+ * The function returns the top `limit` rows.
122
74
  *
123
- * BOTH CONDITIONS ARE required, and a plain "finer placetype wins" measured wrong before this shape was settled: it
124
- * moved the top slot on 11,377 keys in `candidate.db`, of which only 722 were the seat/district duplicate. The rest
125
- * were contests between genuinely distinct places that merely tie — 2,885 `locality → neighbourhood` (a bare city name
126
- * losing to a same-named hood), 2,973 `region → county`, 2,662 `postalcode → locality` — and 7,179 of the 11,377 sat at
127
- * population 0, where a tie means NO EVIDENCE rather than equal evidence. Requiring a real population keeps the term
128
- * off every no-evidence tie; promoting the populated-place tier specifically, rather than whatever is finer, keeps it
129
- * off the admin-tier and hood contests. It can never reach a pair population separates: it does not override a
130
- * population gap, it replaces an undetermined order with a stated one.
75
+ * When `placetypes` is given, an exact tie prefers a populated `locality`.
76
+ * This places a seat town ahead of a district with the same name and population.
131
77
  */
132
78
  export declare function rankByPrimaryPreference<R extends PrimaryPreferenceRow>(rows: readonly R[], limit: number, delta?: number, placetypes?: ReadonlyMap<number, string>, exemptVariantAliases?: boolean): Array<RankedRow<R>>;
133
79
  //# sourceMappingURL=primary-preference.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"primary-preference.d.ts","sourceRoot":"","sources":["../lib/primary-preference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,YAAY,CAAC,GACjF,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,CAAC,CAAC,CAAA;AAE1F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAA;AASzC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,KAAK,CAAA;AAE9B;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG;IAC9B;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,CAAA;IACxB;;;;;;;OAOG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,IAAI,CAAA;CACtB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,oBAAoB,EACrE,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,SAA2B,EAChC,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACxC,oBAAoB,UAAQ,GAC1B,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAoFrB"}
1
+ {"version":3,"file":"primary-preference.d.ts","sourceRoot":"","sources":["../lib/primary-preference.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,YAAY,CAAC,GACjF,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,CAAC,CAAC,CAAA;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAIzC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,KAAK,CAAA;AAE9B;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG;IAC9B;;;;;;;OAOG;IACH,gBAAgB,EAAE,MAAM,CAAA;IAExB;;;;;;;OAOG;IACH,OAAO,EAAE,OAAO,CAAA;IAEhB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IAEf;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAE9B;;OAEG;IACH,eAAe,CAAC,EAAE,IAAI,CAAA;CACtB,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,oBAAoB,EACrE,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,SAA2B,EAChC,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACxC,oBAAoB,UAAQ,GAC1B,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CA2DrB"}
@@ -2,116 +2,44 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
- *
6
- * Bounded cross-country PRIMARY-NAME preference over a population-ordered candidate row set — the
7
- * `is_primary` ranking signal, PURE and platform-free so the Node candidate lookup
8
- * (`candidate-lookup.ts`) and the browser twin (`packages/resolver-wof-wasm/lib/httpvfs/resolver.ts`) rank with
9
- * the SAME function rather than two copies that drift (the #861 server↔browser parity contract).
10
- *
11
- * Only type imports and arithmetic live here: anything with a `node:` import stays out.
12
5
  */
13
6
  /**
14
- * Bounded PRIMARY-NAME preference across a CROSS-COUNTRY name collision (the `is_primary` ranking signal).
15
- *
16
- * The raw candidate order is population-first (`neg_rank ASC`) and treats an ALIAS row (a place's alt-name / exonym,
17
- * `is_primary=0`) and a PRIMARY-name row (`is_primary=1`) on equal footing. So a foreign place whose transliterated
18
- * exonym coincidentally normalizes to a query — Changchun CN stores the Turkish exonym "Çançun" (`name_key="cancun"`),
19
- * 4.19 M pop — outranks the PRIMARY-name place the query actually means (Cancún MX, 0.89 M pop). This penalty makes a
20
- * same-key alias have to clear a population MARGIN over a foreign primary before it wins.
7
+ * The log10-population penalty applied to an alias row when the top primary-name
8
+ * row for the same key is in another country.
21
9
  *
22
- * It is deliberately NOT a dominant sort key (no `ORDER BY is_primary DESC`, which would make every primary outrank
23
- * every alias and break the alt-names users depend on — "NYC"→New York, "LA"→Los Angeles, "Frisco"→San Francisco). Two
24
- * bounds keep it a soft prior:
25
- *
26
- * 1. **Cross-country only.** The penalty applies to an alias ONLY when the top-population primary sharing the key is in a
27
- * DIFFERENT country. A SAME-country nickname contest (San Francisco's alias "Frisco" vs the primary Frisco, TX —
28
- * both US) is left on pure population, so the legitimate alias still wins.
29
- * 2. **Population-bounded.** The penalty is {@link PRIMARY_PREFERENCE_LOG10} in log10-population units — an alias must be
30
- * at least 10x more populous than the foreign primary to still win. So a genuinely dominant alias keeps winning
31
- * ("Los Angeles" over La, Ghana — gap 1.6; "Las Vegas" over Vegas, Cuba — gap 2.4) while a near-tie coincidental
32
- * collision defers to the primary (Cancún over Changchun — gap 0.7).
10
+ * An alias at least 10 times as populous still wins, so alternate names such as "LA" keep working.
33
11
  */
34
12
  export const PRIMARY_PREFERENCE_LOG10 = 1;
35
- /**
36
- * The placetype the seat preference promotes: the populated-place tier a district duplicate shares its name and its
37
- * population with. Named rather than inlined because narrowing the term to this ONE tier is what keeps it off the
38
- * region/county and locality/neighbourhood contests — see `rankByPrimaryPreference` for the measurement.
39
- */
40
13
  const SEAT_PLACETYPE = "locality";
41
14
  /**
42
- * Over-fetch cap for {@link rankByPrimaryPreference}: the candidate rows for one `name_key` (all same-name places
43
- * worldwide) are re-ranked in-process, so the probe fetches this many (population-ordered) before the re-rank rather
44
- * than the caller's small `limit`, ensuring the intended primary isn't pushed below the fold by a cluster of
45
- * more-populous foreign aliases. Bounded and small — a single contiguous B-tree scan.
15
+ * The number of population-ordered rows fetched per name key before
16
+ * {@link rankByPrimaryPreference} re-ranks them.
17
+ *
18
+ * A fetch of only the caller's `limit` could miss the intended primary behind more populous foreign aliases.
46
19
  */
47
20
  export const RERANK_FETCH = 64;
48
21
  /**
49
- * Bounded cross-country primary-name preference (see {@link PRIMARY_PREFERENCE_LOG10}). Pure + total-ordered so
50
- * `candidate-lookup.test.ts` can exercise it on synthetic rows. `rows` arrive population-ordered (`neg_rank ASC`); an
51
- * alias (`is_primary=0`) is pushed back by `delta` in log10-population units ONLY when the top-population primary
52
- * sharing the key is in a different country, and is `demoted` out of the exact tier when that penalty leaves it BEHIND
53
- * the primary. Returns the top `limit` after the re-rank, each annotated.
54
- *
55
- * `placetypes` (the artifact's own `placetype_codes` map) enables the LAST tiebreak, the SEAT preference: when
56
- * `effectiveNegRank` and raw `neg_rank` both tie — two same-key rows population cannot separate at all — a
57
- * {@link SEAT_PLACETYPE} row carrying a real population outranks every other placetype. Omit the map and every row
58
- * scores 0, the term cancels, and the order is exactly the population-then-scan-order it was before.
59
- *
60
- * The tie it exists for is a DUPLICATE, not a contest. A district and its identically-named seat town are stored as two
61
- * rows carrying the SAME population, so `neg_rank` is equal to the bit and `referential` follows it
62
- * (`referentialFromPopulation` is a pure function of population). Turkey's `Of` is the measured case — locality
63
- * 8114738869649 and its parent county 8837168432019 both hold population 44212 — and 358 locality/parent-county pairs
64
- * across 15 countries share the shape in `admin-global-priority.db` (TR 162, CA 77, US 47, HR 24, DO 14). Without the
65
- * term their order is whatever the scan hands the sorter.
22
+ * Re-ranks population-ordered candidate rows.
66
23
  *
67
- * WHERE THE TERM DECIDES, AND WHERE IT CANNOT (#1729). It binds inside `findPlace`, so it orders every row set that
68
- * actually CONTAINS the tie — but the resolver walk's probes all carry a placetype filter, and
69
- * `PLACETYPE_FILTER_GROUPS` (core/resolver) never mixes `locality` with `county`: the `Of`-shape locality/county pair
70
- * is PARTITIONED before this ranker runs, the locality probe fetches one row, and the walk's own `locality` request
71
- * selects the seat by construction — the same winner, decided upstream. The tie that reaches an end-to-end answer
72
- * through this term is the IN-GROUP residue: a locality/localadmin (or borough) duplicate whose `importance` values
73
- * also tie. Downstream the resolver re-sorts by importance (`resolver/toponym-prior.ts`) but is stable on equal keys,
74
- * so the order stamped here is the order that answers — inverting this term moves bare `Pu-cheng-hsien` 1,100 km
75
- * (locality Pucheng over the 浦城县 localadmin, identical population and importance). Where importance separates the pair,
76
- * the fame prior overrides by design; a probe with NO placetype filter (the browser cascade's last resort, the dev
77
- * lookup tools) presents the full tie and this term is all that breaks it.
24
+ * A cross-country alias must beat the top primary by `delta` in log10 population.
25
+ * The function returns the top `limit` rows.
78
26
  *
79
- * BOTH CONDITIONS ARE required, and a plain "finer placetype wins" measured wrong before this shape was settled: it
80
- * moved the top slot on 11,377 keys in `candidate.db`, of which only 722 were the seat/district duplicate. The rest
81
- * were contests between genuinely distinct places that merely tie — 2,885 `locality → neighbourhood` (a bare city name
82
- * losing to a same-named hood), 2,973 `region → county`, 2,662 `postalcode → locality` — and 7,179 of the 11,377 sat at
83
- * population 0, where a tie means NO EVIDENCE rather than equal evidence. Requiring a real population keeps the term
84
- * off every no-evidence tie; promoting the populated-place tier specifically, rather than whatever is finer, keeps it
85
- * off the admin-tier and hood contests. It can never reach a pair population separates: it does not override a
86
- * population gap, it replaces an undetermined order with a stated one.
27
+ * When `placetypes` is given, an exact tie prefers a populated `locality`.
28
+ * This places a seat town ahead of a district with the same name and population.
87
29
  */
88
30
  export function rankByPrimaryPreference(rows, limit, delta = PRIMARY_PREFERENCE_LOG10, placetypes, exemptVariantAliases = false) {
89
- // The primary the alias actually competes with for the top slot: highest population (min neg_rank). Undefined
90
- // when the set has no primary → nothing to prefer, penalty is 0, order stays population-first (today's behavior).
91
- let topPrimary;
31
+ let topPrimary = null;
92
32
  for (const r of rows) {
93
33
  if (r.is_primary === 1 && (topPrimary == null || r.neg_rank < topPrimary.neg_rank)) {
94
34
  topPrimary = r;
95
35
  }
96
36
  }
97
37
  const topCountry = topPrimary?.country_id;
98
- // A cross-country alias (different country than the top primary) is penalized; it is DEMOTED when even after — i.e.
99
- // the penalty leaves its effective rank behind the primary's raw rank (it lost the bounded population contest).
100
- //
101
- // #1882 exemption (opt-in): a `name_role = 'variant'` alias is the holder's OWN primary name in another
102
- // orthography (`Брэст` → `brest`, `George Town` → `georgetown` — the build's own-name detector), so the
103
- // query is naming THAT place, not colliding with it; the penalty exists for the coincidental-collision
104
- // class ("Çançun"/`cancun`), which the detector's measured threshold keeps un-stamped. An artifact
105
- // predating the role column carries no 'variant' rows, so the flag no-ops there by construction.
106
38
  const wouldPenalize = (r) => typeof topCountry === "number" && r.is_primary !== 1 && r.country_id !== topCountry;
107
39
  const isCrossCountryAlias = (r) => wouldPenalize(r) && !(exemptVariantAliases && r.name_role === "variant");
108
40
  const annotate = (r) => {
109
41
  const penalized = isCrossCountryAlias(r);
110
42
  const effectiveNegRank = r.neg_rank + (penalized ? delta : 0);
111
- // The firing mark (#1893): this row WOULD have taken the cross-country penalty and the exemption
112
- // prevented it — conditions the winner-level receipt needs, computed where the decision is made. A
113
- // variant row that was in-country, primary, or keyed under a set with no foreign primary never
114
- // fired, and stays unmarked.
115
43
  const exempted = !penalized && exemptVariantAliases && r.name_role === "variant" && wouldPenalize(r);
116
44
  return {
117
45
  ...r,
@@ -120,29 +48,17 @@ export function rankByPrimaryPreference(rows, limit, delta = PRIMARY_PREFERENCE_
120
48
  ...(exempted ? { variantExempted: true } : {}),
121
49
  };
122
50
  };
123
- // 1 for a populated-place row that can BE a district's seat, 0 for everything else — no code map, no
124
- // placetype on the row, an id the map does not carry, a placetype that is not the seat tier, or no
125
- // recorded population. Every row scoring 0 cancels the term, leaving exactly the
126
- // population-then-scan-order the sort had before it existed.
127
- const seatPreference = (r) => placetypes != null &&
51
+ const seatPreference = (r) => placetypes &&
128
52
  typeof r.placetype_id === "number" &&
129
53
  typeof r.population === "number" &&
130
54
  r.population > 0 &&
131
55
  placetypes.get(r.placetype_id) === SEAT_PLACETYPE
132
56
  ? 1
133
57
  : 0;
134
- // 1 for a PRIMARY-name row whose prominence is unmeasured (population 0), 0 for everything else. Two unmeasured
135
- // rows tie on `neg_rank`, and that tie used to fall through to scan order — the B-tree's `spr_id`, which is no
136
- // evidence about either place. A row that IS named X ranks ahead of one merely also-known-as X when nothing else
137
- // separates them: Taiwan's 溪州鄉 township row (its own name, unmeasured) over the village 溪洲 30 km away that
138
- // carries `溪州鄉` as an alias (unmeasured), which the lower WOF id had been winning. Populated ties are untouched —
139
- // a populated alias ("NYC") never reaches this term, and two populated rows keep the order they had.
140
58
  const unmeasuredPrimary = (r) => r.is_primary === 1 && typeof r.population === "number" && r.population === 0 ? 1 : 0;
141
59
  return (rows
142
60
  .map((r, i) => ({ row: annotate(r), i }))
143
- // Effective rank ASC; ties keep population order, then the seat preference DESC, then the primary name
144
- // among unmeasured rows, then original index (stable).
145
- // oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array; toSorted would double-allocate on a hot path
61
+ // oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array. toSorted would double-allocate on a hot path
146
62
  .sort((a, b) => a.row.effectiveNegRank - b.row.effectiveNegRank ||
147
63
  a.row.neg_rank - b.row.neg_rank ||
148
64
  seatPreference(b.row) - seatPreference(a.row) ||
@@ -1 +1 @@
1
- {"version":3,"file":"primary-preference.js","sourceRoot":"","sources":["../lib/primary-preference.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"primary-preference.js","sourceRoot":"","sources":["../lib/primary-preference.ts"],"names":[],"mappings":"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"}
@@ -3,23 +3,24 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * The proximity re-rank (#938): with bias hints — the demo's map viewport, a user location — re-order exact-match
7
- * candidates by population and nearness on one additive scale, so an in-view namesake wins a tie without a hard
8
- * filter. Byte-identical to plain population order when no bias is passed.
6
+ * Re-order exact-match candidates by population and nearness on one additive scale when bias hints
7
+ * are present (the demo's map viewport, a user location), so an in-view namesake wins a tie
8
+ * without a hard filter. With no bias the order is plain population order, byte-identical.
9
9
  *
10
- * This lives in its own platform-free module because it has to run identically in two places: the Node candidate
11
- * reader and the browser byte-range twin. That is the #861 server↔demo parity contract and the second thing
12
- * here held by construction rather than by comment (`primary-preference.ts` was the first). Constants alone were not
13
- * enough — the two copies agreed on every literal and still diverged on which field the population term reads and on
14
- * whether the combined value is written back, which is the half that actually decides the answer.
10
+ * This lives in its own platform-free module because it has to run identically in two places, the
11
+ * Node candidate reader and the browser byte-range twin. That is the server and demo parity
12
+ * interface held by construction. Constants by themselves were not enough, since the two copies agreed on
13
+ * every literal and still diverged on which field the population term reads and on whether the
14
+ * combined value is written back.
15
15
  *
16
16
  * Two properties are required and easy to lose when transcribing:
17
17
  *
18
- * 1. The population base is `prominence ?? score`, NOT `score`. `prominence` carries the bounded cross-country
19
- * primary preference, so reading raw score lets a coincidental foreign alias ride population back over a primary
20
- * whenever a viewport hint happens to be present.
21
- * 2. The combined value is PERSISTED into `prominence`. The resolver walk re-sorts by `prominence ?? score`, so a
22
- * caller that only returns the array in bias order has its ordering silently discarded downstream.
18
+ * 1. The population base is `prominence ?? score`. `prominence` contains the bounded cross-country
19
+ * primary preference, so reading raw score lets a coincidental foreign alias ride population
20
+ * back over a primary whenever a viewport hint happens to be present.
21
+ * 2. The combined value is persisted into `prominence`. The resolver walk re-sorts by
22
+ * `prominence ?? score`, so a caller that only returns the array in bias order has its
23
+ * ordering silently discarded downstream.
23
24
  */
24
25
  /**
25
26
  * Full magnitude of the nearness term at distance 0, before decay.
@@ -30,22 +31,25 @@ export declare const BIAS_BOOST = 4;
30
31
  */
31
32
  export declare const POP_BOOST = 4;
32
33
  /**
33
- * `log10(population + 1)` at which the population term saturates — 6 means a population of one million earns the whole
34
- * {@link POP_BOOST}, and larger populations earn no more.
34
+ * `log10(population + 1)` at which the population term saturates.
35
+ *
36
+ * A value of 6 means a population of one million warrants the whole {@link POP_BOOST},
37
+ * and larger populations warrant no more.
35
38
  */
36
39
  export declare const POP_SCALE_LOG10 = 6;
37
40
  /**
38
41
  * Distance at which the nearness term halves.
39
42
  *
40
- * SHARPER than the FTS reader's 100 km on purpose: the candidate backend's score is log-population ALONE, with no bm25
41
- * document term, so the population signal is weaker relative to the bias and a gentle 100 km decay let a 230 km-distant
42
- * alias-exact township ("Paris Township", OH) edge out a global city ("Paris", FR) from a nearby view. At ~30 km the
43
- * boost reaches only candidates the user is actually looking at: an in-view namesake still wins (Dublin, OH from an
44
- * Ohio view), a distant one no longer does (Paris stays FR from a Michigan view).
43
+ * Sharper than the FTS reader's 100 km on purpose, because the candidate backend's
44
+ * score is log-population by itself with no bm25 document term.
45
+ * This weakens the population signal relative to the bias.
46
+ *
47
+ * At around 30 km the boost reaches only candidates the user is looking at,
48
+ * so an in-view namesake still wins and a distant one does not.
45
49
  */
46
50
  export declare const PROX_SCALE_KM = 30;
47
51
  /**
48
- * One bias hint — a coordinate the user is looking at or standing on, optionally weighted.
52
+ * One bias hint, a coordinate the user is looking at or standing on, optionally weighted.
49
53
  */
50
54
  export interface ProximityBias {
51
55
  lat: number;
@@ -53,25 +57,32 @@ export interface ProximityBias {
53
57
  weight?: number;
54
58
  }
55
59
  /**
56
- * The candidate fields the re-rank reads and writes. Structural rather than a concrete candidate type, so the Node
57
- * reader's `PlaceCandidate` and the browser twin's row shape both satisfy it without an adapter.
60
+ * The candidate fields the re-rank reads and writes.
61
+ *
62
+ * This is structural, so the Node reader's `PlaceCandidate` and the browser twin's
63
+ * row shape both satisfy it without an adapter.
58
64
  */
59
65
  export interface ProximityRerankable {
60
66
  lat: number;
61
67
  lon: number;
62
68
  score: number;
63
- prominence?: number;
69
+ prominence?: number | null;
64
70
  }
65
71
  /**
66
- * Population plus nearness on one additive scale. Exported for tests and for a caller that wants the value without the
67
- * sort; ordinary callers want {@link applyProximityRerank}.
72
+ * Population plus nearness on one additive scale.
73
+ *
74
+ * Exported for tests and for a caller that wants the value without the sort.
75
+ * Ordinary callers want {@link applyProximityRerank}.
68
76
  */
69
77
  export declare function combinedProminence(candidate: ProximityRerankable, bias: readonly ProximityBias[]): number;
70
78
  /**
71
- * Re-order `candidates` in place by {@link combinedProminence}, persisting each combined value into `prominence` so the
72
- * resolver walk's own `prominence ?? score` sort carries the bias order rather than undoing it. Stable within equal
73
- * prominence, preserving the population order the index already gave. A caller with no bias hints must not call this —
74
- * the no-bias path is plain population order by construction.
79
+ * Re-order `candidates` in place by {@link combinedProminence}, persisting each
80
+ * combined value into `prominence` so the resolver walk's own `prominence ?? score`
81
+ * sort preserves the bias order rather than undoing it.
82
+ *
83
+ * Stable within equal prominence, preserving the population order the index already gave.
84
+ * A caller with no bias hints must not call this.
85
+ * The no-bias path is plain population order by construction.
75
86
  */
76
87
  export declare function applyProximityRerank<T extends ProximityRerankable>(candidates: T[], bias: readonly ProximityBias[]): T[];
77
88
  //# sourceMappingURL=proximity-rerank.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"proximity-rerank.d.ts","sourceRoot":"","sources":["../lib/proximity-rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH;;GAEG;AACH,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;GAEG;AACH,eAAO,MAAM,SAAS,IAAI,CAAA;AAE1B;;;GAGG;AACH,eAAO,MAAM,eAAe,IAAI,CAAA;AAEhC;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,KAAK,CAAA;AAE/B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAmBzG;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,mBAAmB,EACjE,UAAU,EAAE,CAAC,EAAE,EACf,IAAI,EAAE,SAAS,aAAa,EAAE,GAC5B,CAAC,EAAE,CAYL"}
1
+ {"version":3,"file":"proximity-rerank.d.ts","sourceRoot":"","sources":["../lib/proximity-rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH;;GAEG;AACH,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;GAEG;AACH,eAAO,MAAM,SAAS,IAAI,CAAA;AAE1B;;;;;GAKG;AACH,eAAO,MAAM,eAAe,IAAI,CAAA;AAEhC;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,KAAK,CAAA;AAE/B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAmBzG;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,mBAAmB,EACjE,UAAU,EAAE,CAAC,EAAE,EACf,IAAI,EAAE,SAAS,aAAa,EAAE,GAC5B,CAAC,EAAE,CAYL"}
@@ -3,23 +3,24 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * The proximity re-rank (#938): with bias hints — the demo's map viewport, a user location — re-order exact-match
7
- * candidates by population and nearness on one additive scale, so an in-view namesake wins a tie without a hard
8
- * filter. Byte-identical to plain population order when no bias is passed.
6
+ * Re-order exact-match candidates by population and nearness on one additive scale when bias hints
7
+ * are present (the demo's map viewport, a user location), so an in-view namesake wins a tie
8
+ * without a hard filter. With no bias the order is plain population order, byte-identical.
9
9
  *
10
- * This lives in its own platform-free module because it has to run identically in two places: the Node candidate
11
- * reader and the browser byte-range twin. That is the #861 server↔demo parity contract and the second thing
12
- * here held by construction rather than by comment (`primary-preference.ts` was the first). Constants alone were not
13
- * enough — the two copies agreed on every literal and still diverged on which field the population term reads and on
14
- * whether the combined value is written back, which is the half that actually decides the answer.
10
+ * This lives in its own platform-free module because it has to run identically in two places, the
11
+ * Node candidate reader and the browser byte-range twin. That is the server and demo parity
12
+ * interface held by construction. Constants by themselves were not enough, since the two copies agreed on
13
+ * every literal and still diverged on which field the population term reads and on whether the
14
+ * combined value is written back.
15
15
  *
16
16
  * Two properties are required and easy to lose when transcribing:
17
17
  *
18
- * 1. The population base is `prominence ?? score`, NOT `score`. `prominence` carries the bounded cross-country
19
- * primary preference, so reading raw score lets a coincidental foreign alias ride population back over a primary
20
- * whenever a viewport hint happens to be present.
21
- * 2. The combined value is PERSISTED into `prominence`. The resolver walk re-sorts by `prominence ?? score`, so a
22
- * caller that only returns the array in bias order has its ordering silently discarded downstream.
18
+ * 1. The population base is `prominence ?? score`. `prominence` contains the bounded cross-country
19
+ * primary preference, so reading raw score lets a coincidental foreign alias ride population
20
+ * back over a primary whenever a viewport hint happens to be present.
21
+ * 2. The combined value is persisted into `prominence`. The resolver walk re-sorts by
22
+ * `prominence ?? score`, so a caller that only returns the array in bias order has its
23
+ * ordering silently discarded downstream.
23
24
  */
24
25
  import { haversineKm } from "@mailwoman/spatial";
25
26
  /**
@@ -31,30 +32,35 @@ export const BIAS_BOOST = 4;
31
32
  */
32
33
  export const POP_BOOST = 4;
33
34
  /**
34
- * `log10(population + 1)` at which the population term saturates — 6 means a population of one million earns the whole
35
- * {@link POP_BOOST}, and larger populations earn no more.
35
+ * `log10(population + 1)` at which the population term saturates.
36
+ *
37
+ * A value of 6 means a population of one million warrants the whole {@link POP_BOOST},
38
+ * and larger populations warrant no more.
36
39
  */
37
40
  export const POP_SCALE_LOG10 = 6;
38
41
  /**
39
42
  * Distance at which the nearness term halves.
40
43
  *
41
- * SHARPER than the FTS reader's 100 km on purpose: the candidate backend's score is log-population ALONE, with no bm25
42
- * document term, so the population signal is weaker relative to the bias and a gentle 100 km decay let a 230 km-distant
43
- * alias-exact township ("Paris Township", OH) edge out a global city ("Paris", FR) from a nearby view. At ~30 km the
44
- * boost reaches only candidates the user is actually looking at: an in-view namesake still wins (Dublin, OH from an
45
- * Ohio view), a distant one no longer does (Paris stays FR from a Michigan view).
44
+ * Sharper than the FTS reader's 100 km on purpose, because the candidate backend's
45
+ * score is log-population by itself with no bm25 document term.
46
+ * This weakens the population signal relative to the bias.
47
+ *
48
+ * At around 30 km the boost reaches only candidates the user is looking at,
49
+ * so an in-view namesake still wins and a distant one does not.
46
50
  */
47
51
  export const PROX_SCALE_KM = 30;
48
52
  /**
49
- * Population plus nearness on one additive scale. Exported for tests and for a caller that wants the value without the
50
- * sort; ordinary callers want {@link applyProximityRerank}.
53
+ * Population plus nearness on one additive scale.
54
+ *
55
+ * Exported for tests and for a caller that wants the value without the sort.
56
+ * Ordinary callers want {@link applyProximityRerank}.
51
57
  */
52
58
  export function combinedProminence(candidate, bias) {
53
59
  const popBase = candidate.prominence ?? candidate.score;
54
60
  const popTerm = POP_BOOST * Math.min(1, Math.max(0, popBase) / POP_SCALE_LOG10);
55
61
  let proxTerm = 0;
56
- // A candidate at the null island has no coordinate, not a coordinate at 0,0 — it earns no nearness term rather
57
- // than an enormous one.
62
+ // A candidate at the null island has no coordinate, so it warrants no nearness term.
63
+ // A 0,0 pair interpreted as a real coordinate would receive an enormous score.
58
64
  if (!(candidate.lat === 0 && candidate.lon === 0)) {
59
65
  for (const b of bias) {
60
66
  const d = haversineKm(b.lat, b.lon, candidate.lat, candidate.lon);
@@ -67,10 +73,13 @@ export function combinedProminence(candidate, bias) {
67
73
  return popTerm + proxTerm;
68
74
  }
69
75
  /**
70
- * Re-order `candidates` in place by {@link combinedProminence}, persisting each combined value into `prominence` so the
71
- * resolver walk's own `prominence ?? score` sort carries the bias order rather than undoing it. Stable within equal
72
- * prominence, preserving the population order the index already gave. A caller with no bias hints must not call this —
73
- * the no-bias path is plain population order by construction.
76
+ * Re-order `candidates` in place by {@link combinedProminence}, persisting each
77
+ * combined value into `prominence` so the resolver walk's own `prominence ?? score`
78
+ * sort preserves the bias order rather than undoing it.
79
+ *
80
+ * Stable within equal prominence, preserving the population order the index already gave.
81
+ * A caller with no bias hints must not call this.
82
+ * The no-bias path is plain population order by construction.
74
83
  */
75
84
  export function applyProximityRerank(candidates, bias) {
76
85
  candidates
@@ -78,7 +87,7 @@ export function applyProximityRerank(candidates, bias) {
78
87
  c.prominence = combinedProminence(c, bias);
79
88
  return { c, i, p: c.prominence };
80
89
  })
81
- // oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array; toSorted would double-allocate on a hot path
90
+ // oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array. toSorted would double-allocate on a hot path
82
91
  .sort((a, b) => b.p - a.p || a.i - b.i)
83
92
  .forEach((x, j) => (candidates[j] = x.c));
84
93
  return candidates;