@mailwoman/corpus 9.0.0 → 9.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.
- package/README.md +3 -3
- package/data/PROVENANCE.md +227 -0
- package/data/reviewed-ve-postcode-tuples.json +74 -0
- package/data/sub-venue-lexicon.json +18269 -0
- package/out/src/adapters/ban/adapter.d.ts +1 -1
- package/out/src/adapters/ban/adapter.d.ts.map +1 -1
- package/out/src/adapters/ban/adapter.js +5 -4
- package/out/src/adapters/ban/adapter.js.map +1 -1
- package/out/src/adapters/fcc-bdc/adapter.d.ts +1 -1
- package/out/src/adapters/fcc-bdc/adapter.d.ts.map +1 -1
- package/out/src/adapters/fcc-bdc/adapter.js +3 -3
- package/out/src/adapters/fcc-bdc/adapter.js.map +1 -1
- package/out/src/adapters/geonames/adapter.d.ts +1 -1
- package/out/src/adapters/geonames/adapter.d.ts.map +1 -1
- package/out/src/adapters/geonames/adapter.js +2 -2
- package/out/src/adapters/geonames/adapter.js.map +1 -1
- package/out/src/adapters/geonames-postal/adapter.d.ts +1 -1
- package/out/src/adapters/geonames-postal/adapter.d.ts.map +1 -1
- package/out/src/adapters/geonames-postal/adapter.js +3 -3
- package/out/src/adapters/geonames-postal/adapter.js.map +1 -1
- package/out/src/adapters/gnaf/adapter.d.ts +1 -1
- package/out/src/adapters/gnaf/adapter.d.ts.map +1 -1
- package/out/src/adapters/gnaf/adapter.js +2 -2
- package/out/src/adapters/gnaf/adapter.js.map +1 -1
- package/out/src/adapters/gnaf/assemble.js +1 -1
- package/out/src/adapters/gnaf/assemble.js.map +1 -1
- package/out/src/adapters/index.d.ts +1 -1
- package/out/src/adapters/index.d.ts.map +1 -1
- package/out/src/adapters/index.js +1 -1
- package/out/src/adapters/index.js.map +1 -1
- package/out/src/adapters/openaddresses/adapter.d.ts +1 -1
- package/out/src/adapters/openaddresses/adapter.d.ts.map +1 -1
- package/out/src/adapters/openaddresses/adapter.js +3 -3
- package/out/src/adapters/openaddresses/adapter.js.map +1 -1
- package/out/src/adapters/overture/adapter.d.ts +1 -1
- package/out/src/adapters/overture/adapter.d.ts.map +1 -1
- package/out/src/adapters/overture/adapter.js +2 -2
- package/out/src/adapters/overture/adapter.js.map +1 -1
- package/out/src/adapters/state-hi-schools/adapter.d.ts +1 -1
- package/out/src/adapters/state-hi-schools/adapter.d.ts.map +1 -1
- package/out/src/adapters/state-hi-schools/adapter.js +7 -6
- package/out/src/adapters/state-hi-schools/adapter.js.map +1 -1
- package/out/src/adapters/state-ia-contractors/adapter.d.ts +1 -1
- package/out/src/adapters/state-ia-contractors/adapter.d.ts.map +1 -1
- package/out/src/adapters/state-ia-contractors/adapter.js +12 -7
- package/out/src/adapters/state-ia-contractors/adapter.js.map +1 -1
- package/out/src/adapters/state-ny-notaries/adapter.d.ts +1 -1
- package/out/src/adapters/state-ny-notaries/adapter.d.ts.map +1 -1
- package/out/src/adapters/state-ny-notaries/adapter.js +12 -18
- package/out/src/adapters/state-ny-notaries/adapter.js.map +1 -1
- package/out/src/adapters/state-tx-notaries/adapter.d.ts +1 -1
- package/out/src/adapters/state-tx-notaries/adapter.d.ts.map +1 -1
- package/out/src/adapters/state-tx-notaries/adapter.js +12 -7
- package/out/src/adapters/state-tx-notaries/adapter.js.map +1 -1
- package/out/src/adapters/synth-po-box/adapter.d.ts +3 -3
- package/out/src/adapters/synth-po-box/adapter.d.ts.map +1 -1
- package/out/src/adapters/synth-po-box/adapter.js +3 -3
- package/out/src/adapters/synth-po-box/adapter.js.map +1 -1
- package/out/src/adapters/tiger/adapter.d.ts +1 -1
- package/out/src/adapters/tiger/adapter.d.ts.map +1 -1
- package/out/src/adapters/tiger/adapter.js +2 -2
- package/out/src/adapters/tiger/adapter.js.map +1 -1
- package/out/src/adapters/usgov-hrsa-fqhc/adapter.d.ts +1 -1
- package/out/src/adapters/usgov-hrsa-fqhc/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-hrsa-fqhc/adapter.js +7 -6
- package/out/src/adapters/usgov-hrsa-fqhc/adapter.js.map +1 -1
- package/out/src/adapters/usgov-imls-pls/adapter.d.ts +1 -1
- package/out/src/adapters/usgov-imls-pls/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-imls-pls/adapter.js +11 -7
- package/out/src/adapters/usgov-imls-pls/adapter.js.map +1 -1
- package/out/src/adapters/usgov-irs-bmf/adapter.d.ts +1 -1
- package/out/src/adapters/usgov-irs-bmf/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-irs-bmf/adapter.js +6 -5
- package/out/src/adapters/usgov-irs-bmf/adapter.js.map +1 -1
- package/out/src/adapters/usgov-nad/adapter.d.ts +1 -1
- package/out/src/adapters/usgov-nad/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-nad/adapter.js +8 -8
- package/out/src/adapters/usgov-nad/adapter.js.map +1 -1
- package/out/src/adapters/usgov-nppes/adapter.d.ts +1 -1
- package/out/src/adapters/usgov-nppes/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-nppes/adapter.js +10 -10
- package/out/src/adapters/usgov-nppes/adapter.js.map +1 -1
- package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.d.ts +1 -1
- package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.js +7 -6
- package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.js.map +1 -1
- package/out/src/{adapter.d.ts → adapters/utils/index.d.ts} +8 -2
- package/out/src/adapters/utils/index.d.ts.map +1 -0
- package/out/src/{adapter.js → adapters/utils/index.js} +11 -3
- package/out/src/adapters/utils/index.js.map +1 -0
- package/out/src/adapters/wof-admin-jp/adapter.d.ts +1 -1
- package/out/src/adapters/wof-admin-jp/adapter.d.ts.map +1 -1
- package/out/src/adapters/wof-admin-jp/adapter.js +5 -5
- package/out/src/adapters/wof-admin-jp/adapter.js.map +1 -1
- package/out/src/adapters/wof-admin-json/adapter.d.ts +4 -15
- package/out/src/adapters/wof-admin-json/adapter.d.ts.map +1 -1
- package/out/src/adapters/wof-admin-json/adapter.js +11 -35
- package/out/src/adapters/wof-admin-json/adapter.js.map +1 -1
- package/out/src/adapters/wof-json-rows.d.ts +32 -0
- package/out/src/adapters/wof-json-rows.d.ts.map +1 -0
- package/out/src/adapters/wof-json-rows.js +45 -0
- package/out/src/adapters/wof-json-rows.js.map +1 -0
- package/out/src/adapters/wof-postalcode-json/adapter.d.ts +4 -9
- package/out/src/adapters/wof-postalcode-json/adapter.d.ts.map +1 -1
- package/out/src/adapters/wof-postalcode-json/adapter.js +12 -37
- package/out/src/adapters/wof-postalcode-json/adapter.js.map +1 -1
- package/out/src/build.d.ts +4 -4
- package/out/src/build.d.ts.map +1 -1
- package/out/src/build.js +7 -7
- package/out/src/build.js.map +1 -1
- package/out/src/index.d.ts +3 -17
- package/out/src/index.d.ts.map +1 -1
- package/out/src/index.js +3 -17
- package/out/src/index.js.map +1 -1
- package/out/src/name-prone-us-suffixes.d.ts +12 -0
- package/out/src/name-prone-us-suffixes.d.ts.map +1 -0
- package/out/src/name-prone-us-suffixes.js +12 -0
- package/out/src/name-prone-us-suffixes.js.map +1 -0
- package/out/src/parquet-wrapper/reader.d.ts.map +1 -1
- package/out/src/parquet-wrapper/reader.js +5 -0
- package/out/src/parquet-wrapper/reader.js.map +1 -1
- package/out/src/runner.d.ts +2 -2
- package/out/src/runner.d.ts.map +1 -1
- package/out/src/runner.js +1 -1
- package/out/src/runner.js.map +1 -1
- package/out/src/shard-recipes/anchor-absorption.d.ts.map +1 -1
- package/out/src/shard-recipes/anchor-absorption.js +4 -5
- package/out/src/shard-recipes/anchor-absorption.js.map +1 -1
- package/out/src/shard-recipes/bare-country.d.ts +25 -0
- package/out/src/shard-recipes/bare-country.d.ts.map +1 -0
- package/out/src/shard-recipes/bare-country.js +87 -0
- package/out/src/shard-recipes/bare-country.js.map +1 -0
- package/out/src/shard-recipes/boundary-stress.d.ts.map +1 -1
- package/out/src/shard-recipes/boundary-stress.js +2 -2
- package/out/src/shard-recipes/boundary-stress.js.map +1 -1
- package/out/src/shard-recipes/country-balanced.d.ts.map +1 -1
- package/out/src/shard-recipes/country-balanced.js +14 -21
- package/out/src/shard-recipes/country-balanced.js.map +1 -1
- package/out/src/shard-recipes/cz-pcfirst-preposition.d.ts.map +1 -1
- package/out/src/shard-recipes/cz-pcfirst-preposition.js +28 -10
- package/out/src/shard-recipes/cz-pcfirst-preposition.js.map +1 -1
- package/out/src/shard-recipes/fr-admin-split.d.ts.map +1 -1
- package/out/src/shard-recipes/fr-admin-split.js +4 -3
- package/out/src/shard-recipes/fr-admin-split.js.map +1 -1
- package/out/src/shard-recipes/fr-bare-street.d.ts.map +1 -1
- package/out/src/shard-recipes/fr-bare-street.js +72 -11
- package/out/src/shard-recipes/fr-bare-street.js.map +1 -1
- package/out/src/shard-recipes/fr-lieudit.d.ts.map +1 -1
- package/out/src/shard-recipes/fr-lieudit.js +4 -3
- package/out/src/shard-recipes/fr-lieudit.js.map +1 -1
- package/out/src/shard-recipes/fr-order.d.ts.map +1 -1
- package/out/src/shard-recipes/fr-order.js +11 -20
- package/out/src/shard-recipes/fr-order.js.map +1 -1
- package/out/src/shard-recipes/german.d.ts.map +1 -1
- package/out/src/shard-recipes/german.js +8 -14
- package/out/src/shard-recipes/german.js.map +1 -1
- package/out/src/shard-recipes/house-venue.d.ts.map +1 -1
- package/out/src/shard-recipes/house-venue.js +1 -1
- package/out/src/shard-recipes/house-venue.js.map +1 -1
- package/out/src/shard-recipes/index.d.ts.map +1 -1
- package/out/src/shard-recipes/index.js +8 -1
- package/out/src/shard-recipes/index.js.map +1 -1
- package/out/src/shard-recipes/intersection.d.ts.map +1 -1
- package/out/src/shard-recipes/intersection.js +7 -13
- package/out/src/shard-recipes/intersection.js.map +1 -1
- package/out/src/shard-recipes/locale.d.ts +5 -5
- package/out/src/shard-recipes/locale.d.ts.map +1 -1
- package/out/src/shard-recipes/locale.js +13 -20
- package/out/src/shard-recipes/locale.js.map +1 -1
- package/out/src/shard-recipes/no-street.d.ts.map +1 -1
- package/out/src/shard-recipes/no-street.js +1 -1
- package/out/src/shard-recipes/no-street.js.map +1 -1
- package/out/src/shard-recipes/po-box-cedex.d.ts.map +1 -1
- package/out/src/shard-recipes/po-box-cedex.js +60 -43
- package/out/src/shard-recipes/po-box-cedex.js.map +1 -1
- package/out/src/shard-recipes/po-box.d.ts.map +1 -1
- package/out/src/shard-recipes/po-box.js +1 -1
- package/out/src/shard-recipes/po-box.js.map +1 -1
- package/out/src/shard-recipes/reviewed-postcode-tail.d.ts +47 -0
- package/out/src/shard-recipes/reviewed-postcode-tail.d.ts.map +1 -0
- package/out/src/shard-recipes/reviewed-postcode-tail.js +125 -0
- package/out/src/shard-recipes/reviewed-postcode-tail.js.map +1 -0
- package/out/src/shard-recipes/scaffold.d.ts +51 -23
- package/out/src/shard-recipes/scaffold.d.ts.map +1 -1
- package/out/src/shard-recipes/scaffold.js +59 -23
- package/out/src/shard-recipes/scaffold.js.map +1 -1
- package/out/src/shard-recipes/street-affix.d.ts +54 -0
- package/out/src/shard-recipes/street-affix.d.ts.map +1 -1
- package/out/src/shard-recipes/street-affix.js +203 -35
- package/out/src/shard-recipes/street-affix.js.map +1 -1
- package/out/src/shard-recipes/street-bare.d.ts.map +1 -1
- package/out/src/shard-recipes/street-bare.js +3 -3
- package/out/src/shard-recipes/street-bare.js.map +1 -1
- package/out/src/shard-recipes/street.d.ts.map +1 -1
- package/out/src/shard-recipes/street.js +2 -2
- package/out/src/shard-recipes/street.js.map +1 -1
- package/out/src/shard-recipes/sub-venue-sources.d.ts +3 -6
- package/out/src/shard-recipes/sub-venue-sources.d.ts.map +1 -1
- package/out/src/shard-recipes/sub-venue-sources.js +4 -9
- package/out/src/shard-recipes/sub-venue-sources.js.map +1 -1
- package/out/src/shard-recipes/sub-venue.d.ts +2 -2
- package/out/src/shard-recipes/sub-venue.d.ts.map +1 -1
- package/out/src/shard-recipes/sub-venue.js +7 -6
- package/out/src/shard-recipes/sub-venue.js.map +1 -1
- package/out/src/shard-recipes/trailing-region.d.ts +74 -0
- package/out/src/shard-recipes/trailing-region.d.ts.map +1 -0
- package/out/src/shard-recipes/trailing-region.js +157 -0
- package/out/src/shard-recipes/trailing-region.js.map +1 -0
- package/out/src/shard-recipes/unit.d.ts.map +1 -1
- package/out/src/shard-recipes/unit.js +6 -12
- package/out/src/shard-recipes/unit.js.map +1 -1
- package/out/src/{synthesize-anchor-absorption.d.ts → synthesizers/anchor-absorption.d.ts} +1 -1
- package/out/src/synthesizers/anchor-absorption.d.ts.map +1 -0
- package/out/src/{synthesize-anchor-absorption.js → synthesizers/anchor-absorption.js} +1 -1
- package/out/src/synthesizers/anchor-absorption.js.map +1 -0
- package/out/src/{synthesize-boundary-stress.d.ts → synthesizers/boundary-stress.d.ts} +3 -3
- package/out/src/synthesizers/boundary-stress.d.ts.map +1 -0
- package/out/src/{synthesize-boundary-stress.js → synthesizers/boundary-stress.js} +2 -2
- package/out/src/synthesizers/boundary-stress.js.map +1 -0
- package/out/src/{synthesize-german.d.ts → synthesizers/german.d.ts} +2 -2
- package/out/src/synthesizers/german.d.ts.map +1 -0
- package/out/src/{synthesize-german.js → synthesizers/german.js} +2 -2
- package/out/src/synthesizers/german.js.map +1 -0
- package/out/src/{synthesize-house-venue.d.ts → synthesizers/house-venue.d.ts} +4 -4
- package/out/src/synthesizers/house-venue.d.ts.map +1 -0
- package/out/src/{synthesize-house-venue.js → synthesizers/house-venue.js} +20 -6
- package/out/src/synthesizers/house-venue.js.map +1 -0
- package/out/src/{synthesize-intersection.d.ts → synthesizers/intersection.d.ts} +2 -2
- package/out/src/synthesizers/intersection.d.ts.map +1 -0
- package/out/src/{synthesize-intersection.js → synthesizers/intersection.js} +1 -1
- package/out/src/synthesizers/intersection.js.map +1 -0
- package/out/src/{synthesize-no-street.d.ts → synthesizers/no-street.d.ts} +3 -3
- package/out/src/synthesizers/no-street.d.ts.map +1 -0
- package/out/src/{synthesize-no-street.js → synthesizers/no-street.js} +2 -2
- package/out/src/synthesizers/no-street.js.map +1 -0
- package/out/src/{synthesize-po-box.d.ts → synthesizers/po-box.d.ts} +2 -2
- package/out/src/synthesizers/po-box.d.ts.map +1 -0
- package/out/src/{synthesize-po-box.js → synthesizers/po-box.js} +1 -1
- package/out/src/synthesizers/po-box.js.map +1 -0
- package/out/src/{synthesize-street.d.ts → synthesizers/street.d.ts} +2 -2
- package/out/src/synthesizers/street.d.ts.map +1 -0
- package/out/src/{synthesize-street.js → synthesizers/street.js} +4 -3
- package/out/src/synthesizers/street.js.map +1 -0
- package/out/src/{synthesize.d.ts → synthesizers/utils.d.ts} +3 -3
- package/out/src/synthesizers/utils.d.ts.map +1 -0
- package/out/src/{synthesize.js → synthesizers/utils.js} +5 -4
- package/out/src/synthesizers/utils.js.map +1 -0
- package/out/src/tools/align-shard.d.ts.map +1 -1
- package/out/src/tools/align-shard.js +2 -2
- package/out/src/tools/align-shard.js.map +1 -1
- package/out/src/tools/fetch/ban.d.ts.map +1 -1
- package/out/src/tools/fetch/ban.js +2 -18
- package/out/src/tools/fetch/ban.js.map +1 -1
- package/out/src/tools/fetch/download.d.ts +12 -3
- package/out/src/tools/fetch/download.d.ts.map +1 -1
- package/out/src/tools/fetch/download.js +20 -4
- package/out/src/tools/fetch/download.js.map +1 -1
- package/out/src/tools/fetch/geonames-dump.d.ts +87 -0
- package/out/src/tools/fetch/geonames-dump.d.ts.map +1 -0
- package/out/src/tools/fetch/geonames-dump.js +178 -0
- package/out/src/tools/fetch/geonames-dump.js.map +1 -0
- package/out/src/tools/fetch/geonames-postal.d.ts +76 -0
- package/out/src/tools/fetch/geonames-postal.d.ts.map +1 -0
- package/out/src/tools/fetch/geonames-postal.js +125 -0
- package/out/src/tools/fetch/geonames-postal.js.map +1 -0
- package/out/src/tools/fetch/imls-pls.d.ts.map +1 -1
- package/out/src/tools/fetch/imls-pls.js +5 -17
- package/out/src/tools/fetch/imls-pls.js.map +1 -1
- package/out/src/tools/fetch/index.d.ts +11 -0
- package/out/src/tools/fetch/index.d.ts.map +1 -1
- package/out/src/tools/fetch/index.js +11 -0
- package/out/src/tools/fetch/index.js.map +1 -1
- package/out/src/tools/fetch/nad.d.ts.map +1 -1
- package/out/src/tools/fetch/nad.js +20 -11
- package/out/src/tools/fetch/nad.js.map +1 -1
- package/out/src/tools/fetch/nppes.d.ts.map +1 -1
- package/out/src/tools/fetch/nppes.js +17 -22
- package/out/src/tools/fetch/nppes.js.map +1 -1
- package/out/src/tools/fetch/openaddresses.d.ts.map +1 -1
- package/out/src/tools/fetch/openaddresses.js +18 -17
- package/out/src/tools/fetch/openaddresses.js.map +1 -1
- package/out/src/tools/fetch/ourairports.d.ts.map +1 -1
- package/out/src/tools/fetch/ourairports.js +7 -2
- package/out/src/tools/fetch/ourairports.js.map +1 -1
- package/out/src/tools/fetch/ppd.d.ts +0 -4
- package/out/src/tools/fetch/ppd.d.ts.map +1 -1
- package/out/src/tools/fetch/ppd.js +1 -1
- package/out/src/tools/fetch/ppd.js.map +1 -1
- package/out/src/tools/fetch/state-hi-schools.d.ts.map +1 -1
- package/out/src/tools/fetch/state-hi-schools.js +3 -19
- package/out/src/tools/fetch/state-hi-schools.js.map +1 -1
- package/out/src/tools/fetch/state-sources.d.ts +4 -0
- package/out/src/tools/fetch/state-sources.d.ts.map +1 -1
- package/out/src/tools/fetch/state-sources.js +1 -5
- package/out/src/tools/fetch/state-sources.js.map +1 -1
- package/out/src/tools/fetch/tiger-full.d.ts.map +1 -1
- package/out/src/tools/fetch/tiger-full.js +15 -21
- package/out/src/tools/fetch/tiger-full.js.map +1 -1
- package/out/src/tools/golden-expand.d.ts.map +1 -1
- package/out/src/tools/golden-expand.js +34 -25
- package/out/src/tools/golden-expand.js.map +1 -1
- package/out/src/tools/golden-relabel-street.d.ts.map +1 -1
- package/out/src/tools/golden-relabel-street.js +4 -77
- package/out/src/tools/golden-relabel-street.js.map +1 -1
- package/out/src/tools/index.d.ts +2 -2
- package/out/src/tools/index.d.ts.map +1 -1
- package/out/src/tools/index.js +2 -2
- package/out/src/tools/index.js.map +1 -1
- package/out/src/tools/ingest-csv.d.ts.map +1 -1
- package/out/src/tools/ingest-csv.js +0 -11
- package/out/src/tools/ingest-csv.js.map +1 -1
- package/out/src/tools/overlay-manifest.d.ts +4 -0
- package/out/src/tools/overlay-manifest.d.ts.map +1 -1
- package/out/src/tools/overlay-manifest.js +16 -6
- package/out/src/tools/overlay-manifest.js.map +1 -1
- package/out/src/tools/postcode-triples.d.ts +175 -0
- package/out/src/tools/postcode-triples.d.ts.map +1 -0
- package/out/src/tools/postcode-triples.js +304 -0
- package/out/src/tools/postcode-triples.js.map +1 -0
- package/out/src/tools/shard-kryptonite.d.ts.map +1 -1
- package/out/src/tools/shard-kryptonite.js +1 -3
- package/out/src/tools/shard-kryptonite.js.map +1 -1
- package/out/src/tools/shard-translit.d.ts.map +1 -1
- package/out/src/tools/shard-translit.js +4 -27
- package/out/src/tools/shard-translit.js.map +1 -1
- package/out/src/tools/sub-venue/harvest.d.ts +100 -0
- package/out/src/tools/sub-venue/harvest.d.ts.map +1 -0
- package/out/src/tools/sub-venue/harvest.js +168 -0
- package/out/src/tools/sub-venue/harvest.js.map +1 -0
- package/out/src/tools/sub-venue/head-nouns.d.ts +50 -0
- package/out/src/tools/sub-venue/head-nouns.d.ts.map +1 -0
- package/out/src/tools/sub-venue/head-nouns.js +210 -0
- package/out/src/tools/sub-venue/head-nouns.js.map +1 -0
- package/out/src/tools/sub-venue/surfaces.d.ts +45 -0
- package/out/src/tools/sub-venue/surfaces.d.ts.map +1 -0
- package/out/src/tools/sub-venue/surfaces.js +77 -0
- package/out/src/tools/sub-venue/surfaces.js.map +1 -0
- package/out/src/tools/sub-venue/table.d.ts +229 -0
- package/out/src/tools/sub-venue/table.d.ts.map +1 -0
- package/out/src/tools/sub-venue/table.js +108 -0
- package/out/src/tools/sub-venue/table.js.map +1 -0
- package/out/src/tools/sub-venue/wikidata.d.ts +26 -0
- package/out/src/tools/sub-venue/wikidata.d.ts.map +1 -0
- package/out/src/tools/sub-venue/wikidata.js +62 -0
- package/out/src/tools/sub-venue/wikidata.js.map +1 -0
- package/out/src/tools/sub-venue-lexicon.d.ts +27 -378
- package/out/src/tools/sub-venue-lexicon.d.ts.map +1 -1
- package/out/src/tools/sub-venue-lexicon.js +30 -565
- package/out/src/tools/sub-venue-lexicon.js.map +1 -1
- package/out/src/{align.d.ts → utils/align.d.ts} +1 -1
- package/out/src/utils/align.d.ts.map +1 -0
- package/out/src/utils/align.js.map +1 -0
- package/out/src/utils/golden.d.ts.map +1 -0
- package/out/src/{golden.js → utils/golden.js} +2 -2
- package/out/src/utils/golden.js.map +1 -0
- package/out/src/utils/index.d.ts +14 -0
- package/out/src/utils/index.d.ts.map +1 -0
- package/out/src/utils/index.js +14 -0
- package/out/src/utils/index.js.map +1 -0
- package/out/src/utils/license.d.ts.map +1 -0
- package/out/src/{license.js → utils/license.js} +1 -1
- package/out/src/utils/license.js.map +1 -0
- package/out/src/{parquet.d.ts → utils/parquet.d.ts} +24 -5
- package/out/src/utils/parquet.d.ts.map +1 -0
- package/out/src/{parquet.js → utils/parquet.js} +6 -3
- package/out/src/utils/parquet.js.map +1 -0
- package/out/src/{split.d.ts → utils/split.d.ts} +1 -1
- package/out/src/utils/split.d.ts.map +1 -0
- package/out/src/{split.js → utils/split.js} +2 -2
- package/out/src/utils/split.js.map +1 -0
- package/out/src/utils/tokenize.d.ts.map +1 -0
- package/out/src/utils/tokenize.js.map +1 -0
- package/out/src/utils/wof-json.d.ts.map +1 -0
- package/out/src/utils/wof-json.js.map +1 -0
- package/package.json +287 -21
- package/src/adapters/ban/adapter.ts +7 -5
- package/src/adapters/fcc-bdc/adapter.ts +5 -4
- package/src/adapters/geonames/adapter.ts +3 -3
- package/src/adapters/geonames-postal/adapter.ts +4 -4
- package/src/adapters/gnaf/adapter.ts +3 -3
- package/src/adapters/gnaf/assemble.ts +1 -1
- package/src/adapters/index.ts +3 -2
- package/src/adapters/openaddresses/adapter.ts +4 -4
- package/src/adapters/overture/adapter.ts +3 -3
- package/src/adapters/state-hi-schools/adapter.ts +8 -7
- package/src/adapters/state-ia-contractors/adapter.ts +13 -8
- package/src/adapters/state-ny-notaries/adapter.ts +13 -32
- package/src/adapters/state-tx-notaries/adapter.ts +13 -8
- package/src/adapters/synth-po-box/adapter.ts +4 -4
- package/src/adapters/tiger/adapter.ts +5 -3
- package/src/adapters/usgov-hrsa-fqhc/adapter.ts +8 -7
- package/src/adapters/usgov-imls-pls/adapter.ts +12 -8
- package/src/adapters/usgov-irs-bmf/adapter.ts +7 -6
- package/src/adapters/usgov-nad/adapter.ts +9 -9
- package/src/adapters/usgov-nppes/adapter.ts +13 -12
- package/src/adapters/usgov-samhsa-treatment-locator/adapter.ts +8 -7
- package/src/{adapter.ts → adapters/utils/index.ts} +15 -3
- package/src/adapters/wof-admin-jp/adapter.ts +9 -12
- package/src/adapters/wof-admin-json/adapter.ts +15 -54
- package/src/adapters/wof-json-rows.ts +79 -0
- package/src/adapters/wof-postalcode-json/adapter.ts +16 -50
- package/src/build.ts +8 -8
- package/src/index.ts +3 -17
- package/src/name-prone-us-suffixes.ts +12 -0
- package/src/parquet-wrapper/reader.ts +9 -0
- package/src/runner.ts +2 -2
- package/src/shard-recipes/anchor-absorption.ts +5 -5
- package/src/shard-recipes/bare-country.ts +95 -0
- package/src/shard-recipes/boundary-stress.ts +3 -2
- package/src/shard-recipes/country-balanced.ts +16 -27
- package/src/shard-recipes/cz-pcfirst-preposition.ts +29 -10
- package/src/shard-recipes/fr-admin-split.ts +6 -4
- package/src/shard-recipes/fr-bare-street.ts +85 -10
- package/src/shard-recipes/fr-lieudit.ts +6 -4
- package/src/shard-recipes/fr-order.ts +13 -26
- package/src/shard-recipes/german.ts +9 -18
- package/src/shard-recipes/house-venue.ts +2 -1
- package/src/shard-recipes/index.ts +8 -1
- package/src/shard-recipes/intersection.ts +9 -17
- package/src/shard-recipes/locale.ts +16 -24
- package/src/shard-recipes/no-street.ts +2 -1
- package/src/shard-recipes/po-box-cedex.ts +76 -58
- package/src/shard-recipes/po-box.ts +2 -1
- package/src/shard-recipes/reviewed-postcode-tail.ts +189 -0
- package/src/shard-recipes/scaffold.ts +99 -24
- package/src/shard-recipes/street-affix.ts +284 -45
- package/src/shard-recipes/street-bare.ts +4 -3
- package/src/shard-recipes/street.ts +3 -2
- package/src/shard-recipes/sub-venue-sources.ts +13 -23
- package/src/shard-recipes/sub-venue.ts +11 -9
- package/src/shard-recipes/trailing-region.ts +183 -0
- package/src/shard-recipes/unit.ts +8 -17
- package/src/{synthesize-boundary-stress.ts → synthesizers/boundary-stress.ts} +2 -2
- package/src/{synthesize-german.ts → synthesizers/german.ts} +3 -2
- package/src/{synthesize-house-venue.ts → synthesizers/house-venue.ts} +20 -6
- package/src/{synthesize-intersection.ts → synthesizers/intersection.ts} +1 -1
- package/src/{synthesize-no-street.ts → synthesizers/no-street.ts} +2 -2
- package/src/{synthesize-po-box.ts → synthesizers/po-box.ts} +1 -1
- package/src/{synthesize-street.ts → synthesizers/street.ts} +5 -3
- package/src/{synthesize.ts → synthesizers/utils.ts} +6 -4
- package/src/tools/align-shard.ts +3 -2
- package/src/tools/fetch/ban.ts +2 -22
- package/src/tools/fetch/download.ts +22 -4
- package/src/tools/fetch/geonames-dump.ts +267 -0
- package/src/tools/fetch/geonames-postal.ts +180 -0
- package/src/tools/fetch/imls-pls.ts +6 -20
- package/src/tools/fetch/index.ts +11 -0
- package/src/tools/fetch/nad.ts +21 -10
- package/src/tools/fetch/nppes.ts +17 -23
- package/src/tools/fetch/openaddresses.ts +18 -22
- package/src/tools/fetch/ourairports.ts +7 -2
- package/src/tools/fetch/ppd.ts +1 -1
- package/src/tools/fetch/state-hi-schools.ts +3 -23
- package/src/tools/fetch/state-sources.ts +1 -1
- package/src/tools/fetch/tiger-full.ts +17 -24
- package/src/tools/golden-expand.ts +44 -33
- package/src/tools/golden-relabel-street.ts +5 -68
- package/src/tools/index.ts +2 -2
- package/src/tools/ingest-csv.ts +0 -13
- package/src/tools/overlay-manifest.ts +20 -8
- package/src/tools/postcode-triples.ts +375 -0
- package/src/tools/shard-kryptonite.ts +4 -5
- package/src/tools/shard-translit.ts +16 -35
- package/src/tools/sub-venue/harvest.ts +235 -0
- package/src/tools/sub-venue/head-nouns.ts +242 -0
- package/src/tools/sub-venue/surfaces.ts +95 -0
- package/src/tools/sub-venue/table.ts +281 -0
- package/src/tools/sub-venue/wikidata.ts +85 -0
- package/src/tools/sub-venue-lexicon.ts +67 -886
- package/src/{align.ts → utils/align.ts} +2 -1
- package/src/{golden.ts → utils/golden.ts} +2 -3
- package/src/utils/index.ts +14 -0
- package/src/{license.ts → utils/license.ts} +1 -1
- package/src/{parquet.ts → utils/parquet.ts} +22 -9
- package/src/{split.ts → utils/split.ts} +3 -3
- package/out/src/adapter.d.ts.map +0 -1
- package/out/src/adapter.js.map +0 -1
- package/out/src/align.d.ts.map +0 -1
- package/out/src/align.js.map +0 -1
- package/out/src/format.d.ts +0 -14
- package/out/src/format.d.ts.map +0 -1
- package/out/src/format.js +0 -14
- package/out/src/format.js.map +0 -1
- package/out/src/golden.d.ts.map +0 -1
- package/out/src/golden.js.map +0 -1
- package/out/src/license.d.ts.map +0 -1
- package/out/src/license.js.map +0 -1
- package/out/src/parquet.d.ts.map +0 -1
- package/out/src/parquet.js.map +0 -1
- package/out/src/split.d.ts.map +0 -1
- package/out/src/split.js.map +0 -1
- package/out/src/synthesize-anchor-absorption.d.ts.map +0 -1
- package/out/src/synthesize-anchor-absorption.js.map +0 -1
- package/out/src/synthesize-boundary-stress.d.ts.map +0 -1
- package/out/src/synthesize-boundary-stress.js.map +0 -1
- package/out/src/synthesize-german.d.ts.map +0 -1
- package/out/src/synthesize-german.js.map +0 -1
- package/out/src/synthesize-house-venue.d.ts.map +0 -1
- package/out/src/synthesize-house-venue.js.map +0 -1
- package/out/src/synthesize-intersection.d.ts.map +0 -1
- package/out/src/synthesize-intersection.js.map +0 -1
- package/out/src/synthesize-no-street.d.ts.map +0 -1
- package/out/src/synthesize-no-street.js.map +0 -1
- package/out/src/synthesize-po-box.d.ts.map +0 -1
- package/out/src/synthesize-po-box.js.map +0 -1
- package/out/src/synthesize-street.d.ts.map +0 -1
- package/out/src/synthesize-street.js.map +0 -1
- package/out/src/synthesize.d.ts.map +0 -1
- package/out/src/synthesize.js.map +0 -1
- package/out/src/tokenize.d.ts.map +0 -1
- package/out/src/tokenize.js.map +0 -1
- package/out/src/wof-json.d.ts.map +0 -1
- package/out/src/wof-json.js.map +0 -1
- package/src/format.ts +0 -14
- /package/out/src/{align.js → utils/align.js} +0 -0
- /package/out/src/{golden.d.ts → utils/golden.d.ts} +0 -0
- /package/out/src/{license.d.ts → utils/license.d.ts} +0 -0
- /package/out/src/{tokenize.d.ts → utils/tokenize.d.ts} +0 -0
- /package/out/src/{tokenize.js → utils/tokenize.js} +0 -0
- /package/out/src/{wof-json.d.ts → utils/wof-json.d.ts} +0 -0
- /package/out/src/{wof-json.js → utils/wof-json.js} +0 -0
- /package/src/{synthesize-anchor-absorption.ts → synthesizers/anchor-absorption.ts} +0 -0
- /package/src/{tokenize.ts → utils/tokenize.ts} +0 -0
- /package/src/{wof-json.ts → utils/wof-json.ts} +0 -0
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { readFileSync, statSync, writeFileSync } from "node:fs"
|
|
27
|
-
import { join } from "node:path"
|
|
27
|
+
import { basename, dirname, join } from "node:path"
|
|
28
28
|
|
|
29
29
|
import { parseJSONStrict } from "@mailwoman/core/objects"
|
|
30
30
|
import { sha256Hex } from "@mailwoman/core/utils"
|
|
@@ -96,6 +96,24 @@ export interface OverlayManifestOptions {
|
|
|
96
96
|
note: string
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Resolve a base manifest's shard path to the mounted corpus tree used by Modal.
|
|
101
|
+
*/
|
|
102
|
+
export function rerootBaseShardPath(path: string, baseManifestPath: string): string {
|
|
103
|
+
const versionedIndex = path.indexOf("/corpus/versioned/")
|
|
104
|
+
|
|
105
|
+
if (versionedIndex !== -1) return "/data" + path.slice(versionedIndex)
|
|
106
|
+
|
|
107
|
+
if (/^\/data\/(?:train|val|test)\//u.test(path)) {
|
|
108
|
+
const localBaseDir = dirname(baseManifestPath)
|
|
109
|
+
const baseModalRoot = `/data/corpus/versioned/${basename(dirname(localBaseDir))}/${basename(localBaseDir)}`
|
|
110
|
+
|
|
111
|
+
return baseModalRoot + path.slice("/data".length)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return path
|
|
115
|
+
}
|
|
116
|
+
|
|
99
117
|
export async function assembleOverlayManifest(args: OverlayManifestOptions): Promise<void> {
|
|
100
118
|
const base = parseJSONStrict<BaseManifest>(readFileSync(args.base, "utf8"))
|
|
101
119
|
|
|
@@ -103,13 +121,7 @@ export async function assembleOverlayManifest(args: OverlayManifestOptions): Pro
|
|
|
103
121
|
console.log(`WARN: base already contains source '${args.source}' — is this the right base?`)
|
|
104
122
|
}
|
|
105
123
|
|
|
106
|
-
const
|
|
107
|
-
const i = p.indexOf("/corpus/versioned/")
|
|
108
|
-
|
|
109
|
-
return i !== -1 ? "/data" + p.slice(i) : p
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const kept = base.shards.map((s) => ({ ...s, path: reroot(s.path) }))
|
|
124
|
+
const kept = base.shards.map((s) => ({ ...s, path: rerootBaseShardPath(s.path, args.base) }))
|
|
113
125
|
|
|
114
126
|
const newTrain = await descriptor(
|
|
115
127
|
join(args.newDir, "train", args.shardParquet),
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Extract `(postcode, locality, region, country)` tuples for the `trailing-region` shard.
|
|
7
|
+
*
|
|
8
|
+
* This step used to be a one-off. Its output survived — 17,908 rows at
|
|
9
|
+
* `$MAILWOMAN_DATA_ROOT/corpus/tuples/trailing-region-structured-tuples.jsonl` — but the code that produced it did
|
|
10
|
+
* not, so a note describing the join was the only record and it did not match what the databases contain. That is the
|
|
11
|
+
* reason this file exists: the shard is unbuildable for a new country without it.
|
|
12
|
+
*
|
|
13
|
+
* ## Two sources, because one route does not reach every country
|
|
14
|
+
*
|
|
15
|
+
* - **`postalcode-intl.db`** carries a real `parent_id` that resolves in the admin gazetteer. Measured share of rows
|
|
16
|
+
* with a parent: NL 97.5%, FR 90.7%, DE 66.1%, ES 34.9%, IT 27.4%; of those, 93.8–100% land on a `locality` or
|
|
17
|
+
* `localadmin`, and the region comes from that place's own ancestry. It is the ONLY shard with this — every
|
|
18
|
+
* `postalcode-geonames-*` and `postalcode-<cc>-overture.db` row reads `parent_id = 0`.
|
|
19
|
+
* - **GeoNames postal exports** carry the place and admin1 NAMES in columns 3 and 4, so there is nothing to join.
|
|
20
|
+
* `mailwoman corpus fetch geonames-postal` puts them on disk.
|
|
21
|
+
*
|
|
22
|
+
* A nearest-locality-centroid join was measured as the general fallback and REJECTED: scored against the `parent_id`
|
|
23
|
+
* truth, it agreed NL 81.1% / DE 44.7% / ES 35.1% / FR 29.0% / IT 13.5%. A locality's centroid sits at its middle, so
|
|
24
|
+
* an edge postcode is routinely nearer a neighbouring town's centroid. Do not reach for it again.
|
|
25
|
+
*
|
|
26
|
+
* ## The hub cap is PER COUNTRY, because a pooled one is a mixture
|
|
27
|
+
*
|
|
28
|
+
* A few localities act as catch-all parents — `Schwedt/Oder` claims 9,222 DE postcodes against a DE median of 1. Left
|
|
29
|
+
* in, a handful of places dominate the shard. But the distribution differs so much by country that one threshold is
|
|
30
|
+
* not one rule: a p99 pooled across the five countries lands at 522, which keeps 100% of ES and IT, 83% of FR, 49% of
|
|
31
|
+
* NL and 19% of DE.
|
|
32
|
+
*
|
|
33
|
+
* So the bound is a QUOTA and not a threshold. A threshold DELETES a locality that exceeds it, which removes exactly
|
|
34
|
+
* the largest cities — the places a parser most needs to have seen. A quota keeps every locality and bounds how many
|
|
35
|
+
* of its postcodes ride along, which is the balance the cap was reaching for without the deletion.
|
|
36
|
+
*
|
|
37
|
+
* ## Placement is data, not a formatting choice
|
|
38
|
+
*
|
|
39
|
+
* Each tuple is stamped with its country's {@link PostcodePlacement}. The same digits change tag with position, so a
|
|
40
|
+
* tuple that does not carry its placement teaches whichever convention the recipe happens to default to — see the
|
|
41
|
+
* recipe's header for the measurement.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import { existsSync } from "node:fs"
|
|
45
|
+
import { join } from "node:path"
|
|
46
|
+
import { DatabaseSync } from "node:sqlite"
|
|
47
|
+
|
|
48
|
+
import { dataRootPath } from "@mailwoman/core/utils"
|
|
49
|
+
import { TSVSpliterator } from "spliterator"
|
|
50
|
+
|
|
51
|
+
import type { PostcodePlacement } from "../shard-recipes/scaffold.ts"
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* One extracted tuple, in the shape `readTuples` yields and the recipe consumes.
|
|
55
|
+
*/
|
|
56
|
+
export interface PostcodeTriple {
|
|
57
|
+
postcode: string
|
|
58
|
+
/**
|
|
59
|
+
* The segment BEFORE the locality, when the source has one. Load-bearing rather than decorative: a shard whose every
|
|
60
|
+
* row begins with the locality teaches that the first named segment IS the locality, and that flips the model's
|
|
61
|
+
* default. Measured on the v4.8.0 candidate, which had no such segment — `Ye Three Lords, 27 Minories, London EC3N
|
|
62
|
+
* 1DE` came back `locality: "Ye Three Lords"` with the venue and the street both gone, and 11 of its 25 regressions
|
|
63
|
+
* were venue-led rows across seven countries.
|
|
64
|
+
*/
|
|
65
|
+
dependentLocality?: string
|
|
66
|
+
locality: string
|
|
67
|
+
region: string
|
|
68
|
+
country: string
|
|
69
|
+
cc: string
|
|
70
|
+
locale: string
|
|
71
|
+
postcodePlacement: PostcodePlacement
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Where a country writes the postcode, and the locale tag its rows carry.
|
|
76
|
+
*
|
|
77
|
+
* A country is in this table only when a gauntlet board row ATTESTS its surface. An absent country is not an oversight
|
|
78
|
+
* to be filled in by guessing: extracting it with the wrong placement teaches a convention that country does not use,
|
|
79
|
+
* which is worse than not teaching it at all. `LEADING_POSTCODE_COUNTRIES` in `@mailwoman/neural`'s
|
|
80
|
+
* `placetype-pair-prior.ts` draws the same line for the same reason.
|
|
81
|
+
*
|
|
82
|
+
* AU and ZA are the worked examples of the bar. Both look like obvious additions and neither qualifies: the board's AU
|
|
83
|
+
* rows are bare-city (`Melbourne`, `Sydney, Australia`) and carry no postcode at all, so nothing here says where AU
|
|
84
|
+
* writes it; and ZA's `14 Long St, Green Point, Cape Town, 8001` carries no REGION, which this shard requires — a fact
|
|
85
|
+
* its GeoNames export agrees with, at 100% place and 0% admin1.
|
|
86
|
+
*/
|
|
87
|
+
export const POSTCODE_CONVENTIONS: ReadonlyMap<string, { placement: PostcodePlacement; locale: string }> = new Map([
|
|
88
|
+
// `Rue de l'Église, 3, 29217 Plougonvelin, Bretagne, France` and its siblings — `fr_structured`, `de_structured`,
|
|
89
|
+
// `es_structured`, `it_structured`, `pt_structured`, `mx_supermanzana`, `nl-op4-p-r-sloterdijk`.
|
|
90
|
+
["FR", { placement: "leading", locale: "fr-FR" }],
|
|
91
|
+
["DE", { placement: "leading", locale: "de-DE" }],
|
|
92
|
+
["ES", { placement: "leading", locale: "es-ES" }],
|
|
93
|
+
["IT", { placement: "leading", locale: "it-IT" }],
|
|
94
|
+
["NL", { placement: "leading", locale: "nl-NL" }],
|
|
95
|
+
["PT", { placement: "leading", locale: "pt-PT" }],
|
|
96
|
+
["MX", { placement: "leading", locale: "es-MX" }],
|
|
97
|
+
// `…, Barcelona 6001, Anzoátegui, Venezuela` — the four `ve_city_postcode_trailing_state` rows. No postcode source
|
|
98
|
+
// on disk and GeoNames does not publish VE, so this entry currently yields nothing; it is here because the
|
|
99
|
+
// placement is what makes the absence legible.
|
|
100
|
+
["VE", { placement: "after_locality", locale: "es-VE" }],
|
|
101
|
+
// `12 MG Road, Indiranagar, Bengaluru, Karnataka 560038, India` — three `in_*` rows, and `AGENTS.md` says the same
|
|
102
|
+
// ("en-IN is absent BECAUSE the PIN goes last"). The one trailing placement with real data behind it.
|
|
103
|
+
["IN", { placement: "after_region", locale: "en-IN" }],
|
|
104
|
+
])
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* How many postcodes one locality may contribute.
|
|
108
|
+
*
|
|
109
|
+
* A quota rather than a cut-off — see the header. It bounds repetition without deleting a locality: a city with 9,222
|
|
110
|
+
* postcodes contributes this many and stays in the shard.
|
|
111
|
+
*/
|
|
112
|
+
export const DEFAULT_LOCALITY_QUOTA = 24
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Take at most `quota` tuples per locality, in the order they arrive.
|
|
116
|
+
*
|
|
117
|
+
* Order matters and is the caller's to choose: both readers below walk their source in id / file order, which is stable
|
|
118
|
+
* across runs, so the same quota selects the same rows.
|
|
119
|
+
*/
|
|
120
|
+
export function applyLocalityQuota(
|
|
121
|
+
triples: readonly PostcodeTriple[],
|
|
122
|
+
quota: number = DEFAULT_LOCALITY_QUOTA
|
|
123
|
+
): PostcodeTriple[] {
|
|
124
|
+
const seen = new Map<string, number>()
|
|
125
|
+
const kept: PostcodeTriple[] = []
|
|
126
|
+
|
|
127
|
+
for (const triple of triples) {
|
|
128
|
+
const key = `${triple.cc} ${triple.locality}`
|
|
129
|
+
const n = seen.get(key) ?? 0
|
|
130
|
+
|
|
131
|
+
if (n >= quota) continue
|
|
132
|
+
|
|
133
|
+
seen.set(key, n + 1)
|
|
134
|
+
kept.push(triple)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return kept
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Take at most `budget` tuples per COUNTRY, in the order they arrive.
|
|
142
|
+
*
|
|
143
|
+
* A per-locality quota bounds how often one place repeats; it cannot bound a country. IN has 128,152 distinct
|
|
144
|
+
* localities, so even at a quota of ONE it contributes 63,533 rows against 39,790 from the other seven combined — the
|
|
145
|
+
* shard would teach the trailing surface as an Indian fact rather than a general one, and at 103,323 rows it would take
|
|
146
|
+
* 30% of an 8,000-step run's sample budget at three reps per row.
|
|
147
|
+
*
|
|
148
|
+
* Applied AFTER {@link applyLocalityQuota}, so a country's budget is spent on breadth (many localities) rather than on
|
|
149
|
+
* one city's postcode list.
|
|
150
|
+
*/
|
|
151
|
+
export function applyCountryBudget(
|
|
152
|
+
triples: readonly PostcodeTriple[],
|
|
153
|
+
budget: number | ReadonlyMap<string, number>
|
|
154
|
+
): PostcodeTriple[] {
|
|
155
|
+
const spent = new Map<string, number>()
|
|
156
|
+
const kept: PostcodeTriple[] = []
|
|
157
|
+
|
|
158
|
+
for (const triple of triples) {
|
|
159
|
+
const cap = typeof budget === "number" ? budget : budget.get(triple.cc)
|
|
160
|
+
|
|
161
|
+
if (cap === undefined) continue
|
|
162
|
+
|
|
163
|
+
const n = spent.get(triple.cc) ?? 0
|
|
164
|
+
|
|
165
|
+
if (n >= cap) continue
|
|
166
|
+
|
|
167
|
+
spent.set(triple.cc, n + 1)
|
|
168
|
+
kept.push(triple)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return kept
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Read triples out of `postalcode-intl.db` by following each postcode's `parent_id` into the admin gazetteer and that
|
|
176
|
+
* place's ancestry to a region.
|
|
177
|
+
*
|
|
178
|
+
* A postcode whose parent does not resolve, or whose parent has no region ancestor, is DROPPED rather than emitted with
|
|
179
|
+
* a blank — the recipe already skips a tuple with no region, and a blank here would hide how much of the source is
|
|
180
|
+
* actually reachable.
|
|
181
|
+
*/
|
|
182
|
+
export function readTriplesFromParentJoin(
|
|
183
|
+
countries: readonly string[],
|
|
184
|
+
options: { postcodeDB?: string; adminDB?: string } = {}
|
|
185
|
+
): PostcodeTriple[] {
|
|
186
|
+
const postcodeDB = options.postcodeDB ?? String(dataRootPath("wof", "postalcode-intl.db"))
|
|
187
|
+
const adminDB = options.adminDB ?? String(dataRootPath("wof", "admin-global-priority-importance.db"))
|
|
188
|
+
|
|
189
|
+
if (!existsSync(postcodeDB) || !existsSync(adminDB)) return []
|
|
190
|
+
|
|
191
|
+
const db = new DatabaseSync(adminDB, { readOnly: true })
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
db.exec(`ATTACH DATABASE '${postcodeDB.replaceAll("'", "''")}' AS pc`)
|
|
195
|
+
|
|
196
|
+
const statement = db.prepare(`
|
|
197
|
+
SELECT p.name AS postcode, a.name AS locality, r.name AS region, c.name AS country, p.country AS cc
|
|
198
|
+
FROM pc.spr p
|
|
199
|
+
JOIN spr a ON a.id = p.parent_id AND a.placetype IN ('locality', 'localadmin')
|
|
200
|
+
JOIN ancestors anc ON anc.id = a.id AND anc.ancestor_placetype = 'region'
|
|
201
|
+
JOIN spr r ON r.id = anc.ancestor_id
|
|
202
|
+
JOIN ancestors cnc ON cnc.id = a.id AND cnc.ancestor_placetype = 'country'
|
|
203
|
+
JOIN spr c ON c.id = cnc.ancestor_id
|
|
204
|
+
WHERE p.country = ? AND p.parent_id > 0
|
|
205
|
+
ORDER BY p.id
|
|
206
|
+
`)
|
|
207
|
+
|
|
208
|
+
const out: PostcodeTriple[] = []
|
|
209
|
+
|
|
210
|
+
for (const cc of countries) {
|
|
211
|
+
const convention = POSTCODE_CONVENTIONS.get(cc)
|
|
212
|
+
|
|
213
|
+
if (!convention) continue
|
|
214
|
+
|
|
215
|
+
for (const row of statement.all(cc) as Array<Record<string, string>>) {
|
|
216
|
+
if (!row["postcode"] || !row["locality"] || !row["region"]) continue
|
|
217
|
+
|
|
218
|
+
out.push({
|
|
219
|
+
postcode: row["postcode"],
|
|
220
|
+
locality: row["locality"],
|
|
221
|
+
region: row["region"],
|
|
222
|
+
country: row["country"] ?? "",
|
|
223
|
+
cc,
|
|
224
|
+
locale: convention.locale,
|
|
225
|
+
postcodePlacement: convention.placement,
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return out
|
|
231
|
+
} finally {
|
|
232
|
+
db.close()
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* GeoNames postal columns (0-based), matching `@mailwoman/corpus`'s `geonames-postal` adapter.
|
|
238
|
+
*/
|
|
239
|
+
const GEONAMES_COL = { country: 0, postcode: 1, place: 2, admin1: 3, admin2: 5 } as const
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* A predicate answering whether a name is a LOCALITY the admin gazetteer knows, for one country.
|
|
243
|
+
*
|
|
244
|
+
* The parent-join reader gets this for free — its query restricts the parent to `locality`/`localadmin`, so every name
|
|
245
|
+
* it emits is one by construction. The GeoNames reader has no such guarantee, and the gap is large enough to matter:
|
|
246
|
+
* sampling 400 rows per country against the gazetteer, the share of GeoNames place names that name a locality we know
|
|
247
|
+
* is PT 75%, IN 62%, **MX 41%**. The Mexican misses are colonias — `Zona Centro`, `San Fernando INFONAVIT`, `FOVISSSTE
|
|
248
|
+
* 3a Sección` — and a row teaching one of those as `locality` trains the locality/dependent_locality boundary in the
|
|
249
|
+
* wrong direction. Dropping the row instead costs coverage and teaches nothing false, which is the better of the two.
|
|
250
|
+
*
|
|
251
|
+
* Returns a predicate that answers `true` for everything when the gazetteer is not on disk, so a checkout without it
|
|
252
|
+
* builds the same rows it did before rather than silently emitting none.
|
|
253
|
+
*/
|
|
254
|
+
export function createKnownLocalityGate(country: string, adminDB?: string): (name: string) => boolean {
|
|
255
|
+
const path = adminDB ?? String(dataRootPath("wof", "admin-global-priority-importance.db"))
|
|
256
|
+
|
|
257
|
+
if (!existsSync(path)) return () => true
|
|
258
|
+
|
|
259
|
+
const db = new DatabaseSync(path, { readOnly: true })
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
const names = new Set<string>()
|
|
263
|
+
|
|
264
|
+
for (const row of db
|
|
265
|
+
.prepare("SELECT name FROM spr WHERE country = ? AND placetype IN ('locality', 'localadmin')")
|
|
266
|
+
.all(country) as Array<{ name: string | null }>) {
|
|
267
|
+
if (row.name) {
|
|
268
|
+
names.add(row.name.toLowerCase())
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// An empty set means the gazetteer has no localities for this country at all, which is a coverage fact about the
|
|
273
|
+
// gazetteer rather than a verdict on the source — so gate nothing rather than drop everything.
|
|
274
|
+
if (!names.size) return () => true
|
|
275
|
+
|
|
276
|
+
return (name: string) => names.has(name.toLowerCase())
|
|
277
|
+
} finally {
|
|
278
|
+
db.close()
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Read triples straight out of a GeoNames `<CC>.txt` export — no join, the names are columns 3 and 4.
|
|
284
|
+
*
|
|
285
|
+
* COLUMN 3 IS NOT THE LOCALITY. It is the finest-grained named place for the code, and for `560001` that is `Mahatma
|
|
286
|
+
* Gandhi Road` — a STREET — while the city, `Bengaluru`, is column 5 (admin2). MX is the same shape (`Roma Norte` is a
|
|
287
|
+
* colonia inside `Cuauhtémoc`) and so is PT (`Abrigada` inside `Alenquer`). Reading column 3 as the locality is how the
|
|
288
|
+
* v4.8.0 shard came to teach street names as cities. So `admin2` is the locality, `admin1` the region, and column 3 the
|
|
289
|
+
* DEPENDENT locality — which is also the left context the shard needs.
|
|
290
|
+
*
|
|
291
|
+
* WHICH COUNTRIES THIS READER CAN SERVE. It needs `admin2` (the city) and `admin1` (the region), and a country can
|
|
292
|
+
* publish one without the other. Measured 2026-08-23 across the exports on disk:
|
|
293
|
+
*
|
|
294
|
+
* | country | rows | admin1 | admin2 | usable here |
|
|
295
|
+
* | ---------- | --------: | -----: | -----: | ------------------------------- |
|
|
296
|
+
* | PT, MX, IN | 145k–207k | 100% | 100% | yes |
|
|
297
|
+
* | BD, LK | 1.3k–1.8k | 100% | 100% | yes |
|
|
298
|
+
* | PH | 2,317 | 88% | 88% | yes, 88% of rows |
|
|
299
|
+
* | PK | 2,563 | 100% | **0%** | NO — no city column |
|
|
300
|
+
* | TH | 903 | 100% | **1%** | NO — effectively no city column |
|
|
301
|
+
* | ID | 81,058 | **0%** | 0% | NO — no region either |
|
|
302
|
+
* | ZA | 3,920 | **0%** | — | NO |
|
|
303
|
+
*
|
|
304
|
+
* A country in the NO rows yields zero from this reader, and that is the correct outcome rather than a gap to route
|
|
305
|
+
* around: taking column 3 as the locality is what made the v4.8.0 shard train `Mahatma Gandhi Road` as a city. If one
|
|
306
|
+
* of them is wanted, it needs a city column from somewhere else, not a relaxed mapping.
|
|
307
|
+
*
|
|
308
|
+
* NOT PUBLISHED AT ALL by GeoNames, checked the same day: VE, VN, NP, MM, KH. Those are acquisition questions, and for
|
|
309
|
+
* VE specifically OpenAddresses 404s too — see the arc retrospective.
|
|
310
|
+
*
|
|
311
|
+
* Three source properties a caller cannot see from a row count, all handled here. Hyphen-format countries publish each
|
|
312
|
+
* code TWICE (`3750-000` and `3750000`, exactly 2.00× for PT and PL), so the first surface of a code wins and its twin
|
|
313
|
+
* is dropped. Some countries populate the place but not admin1 — ZA is 100% place, 0% region — which yields nothing
|
|
314
|
+
* this shard can use, so those rows are dropped rather than emitted with a blank region. And the "place name" is often
|
|
315
|
+
* a SUB-locality, which {@link createKnownLocalityGate} filters.
|
|
316
|
+
*/
|
|
317
|
+
export async function readTriplesFromGeonames(
|
|
318
|
+
country: string,
|
|
319
|
+
path: string,
|
|
320
|
+
countryName: string,
|
|
321
|
+
options: { isKnownLocality?: (name: string) => boolean } = {}
|
|
322
|
+
): Promise<PostcodeTriple[]> {
|
|
323
|
+
const convention = POSTCODE_CONVENTIONS.get(country)
|
|
324
|
+
|
|
325
|
+
if (!convention || !existsSync(path)) return []
|
|
326
|
+
|
|
327
|
+
const isKnownLocality = options.isKnownLocality ?? createKnownLocalityGate(country)
|
|
328
|
+
const out: PostcodeTriple[] = []
|
|
329
|
+
const seen = new Set<string>()
|
|
330
|
+
|
|
331
|
+
for await (const cells of TSVSpliterator.fromAsync(path, { header: false }) as AsyncIterable<string[]>) {
|
|
332
|
+
const postcode = (cells[GEONAMES_COL.postcode] ?? "").trim()
|
|
333
|
+
const dependentLocality = (cells[GEONAMES_COL.place] ?? "").trim()
|
|
334
|
+
const locality = (cells[GEONAMES_COL.admin2] ?? "").trim()
|
|
335
|
+
const region = (cells[GEONAMES_COL.admin1] ?? "").trim()
|
|
336
|
+
|
|
337
|
+
if (!postcode || !locality || !region) continue
|
|
338
|
+
|
|
339
|
+
// The gate applies to the LOCALITY — admin2 — not to the fine-grained name, which is expected to be a street or
|
|
340
|
+
// a colonia and is emitted as the dependent locality rather than dropped.
|
|
341
|
+
if (!isKnownLocality(locality)) continue
|
|
342
|
+
|
|
343
|
+
// A dependent locality that merely repeats its parent teaches a doubled segment, not a boundary.
|
|
344
|
+
const dep = dependentLocality && dependentLocality !== locality ? dependentLocality : ""
|
|
345
|
+
|
|
346
|
+
// The bare twin of a punctuated code carries no new fact, and keeping both doubles the country's weight.
|
|
347
|
+
const key = `${postcode.replaceAll("-", "")} ${locality} ${dep}`
|
|
348
|
+
|
|
349
|
+
if (seen.has(key)) continue
|
|
350
|
+
|
|
351
|
+
seen.add(key)
|
|
352
|
+
|
|
353
|
+
out.push({
|
|
354
|
+
postcode,
|
|
355
|
+
...(dep ? { dependentLocality: dep } : {}),
|
|
356
|
+
locality,
|
|
357
|
+
region,
|
|
358
|
+
country: countryName,
|
|
359
|
+
cc: country,
|
|
360
|
+
locale: convention.locale,
|
|
361
|
+
postcodePlacement: convention.placement,
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return out
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Resolve a GeoNames export path under the standard fetch out-root.
|
|
370
|
+
*/
|
|
371
|
+
export function geonamesPostalPath(country: string, sourcesRoot?: string): string {
|
|
372
|
+
const root = sourcesRoot ?? String(dataRootPath("corpus", "sources"))
|
|
373
|
+
|
|
374
|
+
return join(root, "geonames-postal", `${country.toUpperCase()}.txt`)
|
|
375
|
+
}
|
|
@@ -23,10 +23,9 @@ import { join } from "node:path"
|
|
|
23
23
|
import { parseJSONStrict } from "@mailwoman/core/objects"
|
|
24
24
|
import { JSONSpliterator } from "spliterator"
|
|
25
25
|
|
|
26
|
-
import {
|
|
27
|
-
import
|
|
28
|
-
import {
|
|
29
|
-
import type { CanonicalRow, LabeledRow } from "../types.ts"
|
|
26
|
+
import type { CanonicalRow, LabeledRow } from "#types"
|
|
27
|
+
import { alignRow, PARQUET_COLUMNS, ROW_GROUP_SIZE, SHARD_COMPRESSION, writeShards } from "#utils"
|
|
28
|
+
import type { ShardManifest } from "#utils"
|
|
30
29
|
|
|
31
30
|
export interface ShardKryptoniteOptions {
|
|
32
31
|
jsonl: string
|
|
@@ -108,7 +107,7 @@ export async function buildKryptoniteShard(
|
|
|
108
107
|
// first_source_id-prefix inference). Without this, deepseek-kryptonite IDs would have
|
|
109
108
|
// to match a prefix in KNOWN_SOURCE_PREFIXES — we add it there too as a belt-and-braces.
|
|
110
109
|
for (const sh of newManifest.shards) {
|
|
111
|
-
|
|
110
|
+
sh.source = source
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
// Compose the final corpus-v0.4.0 manifest: every shard from base + the new shard(s).
|
|
@@ -36,11 +36,19 @@ import { parseJSONStrict } from "@mailwoman/core/objects"
|
|
|
36
36
|
import { mailwomanDataRoot, sha256File } from "@mailwoman/core/utils"
|
|
37
37
|
import { JSONSpliterator } from "spliterator"
|
|
38
38
|
|
|
39
|
-
import {
|
|
39
|
+
import type { CanonicalRow, LabeledRow } from "#types"
|
|
40
|
+
import {
|
|
41
|
+
alignRow,
|
|
42
|
+
appendShape,
|
|
43
|
+
LABELED_ROW_SCHEMA,
|
|
44
|
+
PARQUET_COLUMNS,
|
|
45
|
+
ROW_GROUP_SIZE,
|
|
46
|
+
rowToParquet,
|
|
47
|
+
SHARD_COMPRESSION,
|
|
48
|
+
} from "#utils"
|
|
49
|
+
import type { ParquetRow, ShardDescriptor, ShardManifest } from "#utils"
|
|
50
|
+
|
|
40
51
|
import { ParquetWriter } from "../parquet-wrapper/index.ts"
|
|
41
|
-
import type { ParquetRow, ShardDescriptor, ShardManifest } from "../parquet.ts"
|
|
42
|
-
import { LABELED_ROW_SCHEMA, PARQUET_COLUMNS, ROW_GROUP_SIZE, rowToParquet, SHARD_COMPRESSION } from "../parquet.ts"
|
|
43
|
-
import type { CanonicalRow, LabeledRow } from "../types.ts"
|
|
44
52
|
|
|
45
53
|
export interface ShardTranslitOptions {
|
|
46
54
|
jsonl: string
|
|
@@ -77,33 +85,6 @@ function toCanonicalRow(raw: Record<string, unknown>, corpusVersion: string): Ca
|
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
87
|
|
|
80
|
-
function appendShape(row: ParquetRow): Record<string, unknown> {
|
|
81
|
-
const out: Record<string, unknown> = {
|
|
82
|
-
raw: row.raw,
|
|
83
|
-
tokens: row.tokens,
|
|
84
|
-
labels: row.labels,
|
|
85
|
-
country: row.country,
|
|
86
|
-
source: row.source,
|
|
87
|
-
source_id: row.source_id,
|
|
88
|
-
corpus_version: row.corpus_version,
|
|
89
|
-
license: row.license,
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (row.locale !== null) {
|
|
93
|
-
out.locale = row.locale
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (row.synth_method !== null) {
|
|
97
|
-
out.synth_method = row.synth_method
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (row.synth_base_id !== null) {
|
|
101
|
-
out.synth_base_id = row.synth_base_id
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return out
|
|
105
|
-
}
|
|
106
|
-
|
|
107
88
|
/**
|
|
108
89
|
* Write one shard for a single source slug. Returns the populated ShardDescriptor + a list of quarantine reasons for
|
|
109
90
|
* rows that failed alignment.
|
|
@@ -127,7 +108,7 @@ async function writeOneShard(
|
|
|
127
108
|
|
|
128
109
|
for (const row of rows) {
|
|
129
110
|
const pq = rowToParquet(row)
|
|
130
|
-
await writer.appendRow(appendShape(pq)
|
|
111
|
+
await writer.appendRow(appendShape(pq))
|
|
131
112
|
|
|
132
113
|
if (firstSourceID === "") {
|
|
133
114
|
firstSourceID = row.source_id
|
|
@@ -151,9 +132,8 @@ async function writeOneShard(
|
|
|
151
132
|
sha256,
|
|
152
133
|
first_source_id: firstSourceID,
|
|
153
134
|
last_source_id: lastSourceID,
|
|
154
|
-
// Stamp source so audit.ts attributes the shard without falling back to filename-prefix
|
|
155
|
-
|
|
156
|
-
...({ source } as Record<string, string>),
|
|
135
|
+
// Stamp source so audit.ts attributes the shard without falling back to filename-prefix inference.
|
|
136
|
+
source,
|
|
157
137
|
}
|
|
158
138
|
}
|
|
159
139
|
|
|
@@ -168,6 +148,7 @@ export async function buildTranslitShard(
|
|
|
168
148
|
report?: (line: string) => void
|
|
169
149
|
): Promise<void> {
|
|
170
150
|
const corpusVersion = options.corpusVersion ?? "0.4.0"
|
|
151
|
+
// This is a portable manifest namespace, not a host filesystem default.
|
|
171
152
|
const canonicalPathPrefix = options.canonicalPathPrefix ?? "/data/"
|
|
172
153
|
const legacyPathPrefix = options.legacyPathPrefix ?? `${mailwomanDataRoot()}/`
|
|
173
154
|
|