Resolver and Who's On First
Parsingaddress parsingThe process of decomposing a free-text postal address string into structured components — house number, street name, locality, region, postcode, and country — so a geocoder can resolve them to coordinates. answers "what kind of thing is each part of this string?". Resolving answers "where is the resulting place?". They are different jobs and Mailwoman keeps them apart on purpose.
This article explains what the resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. does, why we use Who's On First as the gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture., and the design of the SQLite distribution that powers both the server-side and browser-side resolversresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon..
Two-step model
Splitting the responsibility:
- The parser is localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for.-aware and structure-aware. It does not need to know that "New York" is a place. It needs to know that "New York" is being used as a localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy..
- The resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. is data-driven. It does not need to understand grammar. It needs a fast index that maps "New York" + "NY" + "10118" to a single canonical place.
This split is also what lets the parser and resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. evolve independently. The parser can be retrained without touching the gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture.. The gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. can be updated without retraining the parser.
Why Who's On First
Who's On First (WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations.) is an open gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. maintained by SFO Museum. It covers ~30 million places worldwide with stable IDs, polygon geometries, hierarchical relationships, and multi-language names.
Reasons Mailwoman picked WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations.:
- Open licence (CC-BY 4.0). Compatible with Mailwoman's own AGPL licence.
- Stable IDs. A place's WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. ID does not change when its name changes or its borders shift. This is essential for cross-referencing.
- Hierarchy. Every place has a parent (Brooklyn → Kings County → NY → US). Useful for resolving ambiguous queries.
- Multi-language names. Each place has a primary name plus translations and historical names. "Munich" / "München" / "Monaco di Baviera" all resolve to the same WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. ID.
- Used by PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor.. Mailwoman inherited the choice from PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor.'s design.
The WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. data is published as GeoJSON files (one per place), which is great for archival but slow for inferenceinferenceRunning the trained model on new input to get predictions, as opposed to training, which produces the model. In Mailwoman that means a small transformer encoder reads an address string and classifies every token — house number, street, locality, region, postcode, and the rest. A Who's On First gazetteer can feed soft location hints into the pass, but the model makes the final call on every label. Where a generative model writes text token by token, Mailwoman's output is a retrieval-augmented token classification: one label per input piece.. Mailwoman uses the SQLite distribution (data.geocode.earth/wof/dist/sqlite/) prepared by the PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor. team — same data, but in a single indexed SQLite database that responds to queries in microseconds.
What the resolver does
Given the parsed components, the resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon.:
- Builds a query prioritizing the most-specific available component. PostcodepostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one. > localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. > regionregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality.. A
(postcode=10010)query is more specific than(locality=New York)which is more specific than(region=NY). - Runs a candidate search against the WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. SQLite database, optionally using full-text searchFTS5SQLite's built-in full-text-search module (with BM25 ranking). Mailwoman uses it for prefix and name matching against the gazetteer. on the localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. name. The result is a ranked list of candidate places.
- Scores candidates using signals like population (more populous places rank higher), match strength (exact matchexact matchThe share of eval items whose every component is correct (compared per-span or per-token). Stricter than per-tag F1, which credits partial correctness. beats fuzzy match), and component agreement (if both the postcodepostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one. and the localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. match the same WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. place, that's a strong signal).
- Returns the top candidate plus its bounding box and coordinates.
The candidate-search step is where the indexes pay off. Mailwoman's WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. distribution has:
- A FTS5FTS5SQLite's built-in full-text-search module (with BM25 ranking). Mailwoman uses it for prefix and name matching against the gazetteer. full-text index on names with prefix-query support ("New Yo*" matches "New York").
- An R*TreeR*TreeSQLite's spatial index of bounding boxes, enabling fast geographic range and nearest-neighbour queries in the resolver. spatial indexR*TreeSQLite's spatial index of bounding boxes, enabling fast geographic range and nearest-neighbour queries in the resolver. for proximity queries (which places are near these coordinates?).
- A column index on
wof:populationfor population-weighted ranking. - Multi-shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. support so different subsets (postcodespostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one., localities, countries) can live in separate database files.
These were shipped through PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 4 of the implementation plan; see PHASE_4_resolver.md and its subphase files for the details.
Slim distribution for browsers
The full WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. SQLite database is about 1.5 GB. That is too large to ship to a browser.
Mailwoman built a slim distribution for the browser demo:
- Top 1,000 US localities by population.
- All US postcodespostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one. (~42,000 entries).
- Just the columns the resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. actually uses (name, parent IDs, coordinates, bounding box, population).
- Output: ~35 MB compressed, ~80 MB uncompressed.
The slim build is generated by corpus/scripts/build-wof-slim.ts and the demo loads it via @mailwoman/resolver-wof-wasm (which wraps sqlite-wasm).
The full distribution is what the server-side resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. uses; the slim is what the browser uses. Both expose the same query API.
22% postcode placeholder problem
Worth knowing because it has bitten Mailwoman's evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. scores: WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. ships placeholder lat/lon (0, 0) for about 22% of US postcodespostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one. — a known WOF data-model quirk. The data quality is on WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations.'s roadmap to fix but the placeholders are real today.
Mailwoman's resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. drops any candidate whose coordinates are (0, 0) from results. The demo's FailureDiagnostic panel surfaces this case explicitly when a postcodepostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one.-only query returns no usable hits ("WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. ships placeholder lat/lon for ~22% of US postcodespostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one. — known issue").
What the resolver does not do
- RooftoprooftopGeocoding precision at the building or parcel level — coordinates within a few metres — the highest tier of the geocode cascade. Sourced from address-point and situs data. precisionprecisionOf the spans the model labeled as a given tag, the fraction it got right. High precision means few false positives. Paired with recall to compute F1. outside the covered registers. Where an address-point shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. exists, the resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. returns the exact address point, not a locality centroidlocality centroidThe representative centre point of a city or locality, used as a coarse coordinate when no exact address point is available — the coarsest tier of the geocode cascade., at 1 m reported uncertainty: the US situssitusThe physical site address of a property, as opposed to the owner's mailing address. Parcel records often carry both; the divergence is a real-world data-quality challenge. layerlayerOne transformer block — attention plus a feed-forward network, with normalization and residual connections — applied to every position. Stacking layers lets the model build up richer representations; Mailwoman's encoder has 6. (~125M points, built from NADNAD (National Address Database). A US Department of Transportation dataset of structured address points, added to the training corpus as a major source of real US addresses. and OpenAddressesOpenAddresses (OA). A global open aggregation of address points collected from many official sources. A primary source of component-supervised training data outside proprietary registries.) and the French BANBAN (Base Adresse Nationale). France's authoritative open national address register — the highest-quality training source for French addresses, with full component structure. register (26M points) are the two live shardsshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. today. Outside that coveragecoverageThe fraction of a population or region for which a data source has real, non-placeholder entries — e.g. 47% rooftop coverage on Texas addresses. Distinct from accuracy on the rows that are present., the ladder falls back to interpolationinterpolationA geocoding technique that estimates a coordinate along a street segment based on the house number range. Used as the middle tier of Mailwoman's geocode cascade when exact address-point data is unavailable., then a streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. or admin centroid. How Mailwoman resolves a place walks the full precisionprecisionOf the spans the model labeled as a given tag, the fraction it got right. High precision means few false positives. Paired with recall to compute F1. ladder and what each rung promises.
- Reverse geocodinggeocodingThe process of converting an address into geographic coordinates (latitude and longitude). Mailwoman geocodes in a multi-tier cascade: exact address-point match → street interpolation → locality centroid. Each tier is progressively coarser but more widely available.. "What place is at coordinates (40.7128, -74.0060)?" is a separate query shapequery shapeStage 1.5 of the runtime pipeline: computes a structural fingerprint of the input — script class, segmentation, known-format hits (postcode regexes, state abbreviations) — in microseconds without ML. Used by downstream stages for locale detection and kind classification.. The R*TreeR*TreeSQLite's spatial index of bounding boxes, enabling fast geographic range and nearest-neighbour queries in the resolver. index supports it but the public Mailwoman API does not expose a reverse-geocode endpoint today.
- Routing. "How do I get from A to B?" is a graph problem on the road network, not a gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. query.
Where this lives in the code
- Server resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon.:
resolver-wof-sqlite/(usesnode:sqlite) - Browser resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon.:
resolver-wof-wasm/(uses@sqlite.org/sqlite-wasm) - Slim builder:
corpus/scripts/build-wof-slim.ts - Demo integration:
docs/src/pages/demo/index.tsx(the cascade + theFailureDiagnosticpanel) - PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). plan: PHASE_4_resolver.md + subphasesphaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary).
See also
- What is an address? — the components the resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. receives
- How Mailwoman resolves a place — the full walk from parsed components to a coordinate, including the precisionprecisionOf the spans the model labeled as a given tag, the fraction it got right. High precision means few false positives. Paired with recall to compute F1. ladder
- How it works now — where the resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. fits in the live demo flow