We fed the parser its postcode. German came halfway back.
Date: 2026-06-06 Scope: the de-risk pilot for 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.-anchor conditioning channel (#239/#240) — does feeding the parser a structured 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. signal break the German end-of-string collapse that self-conditioningself-conditioningAn auxiliary model head that predicts the input's locale (language/country) and then FiLM-modulates the encoder so parsing adapts to the detected locale. Structural facts like word order still need explicit training on both orders. alone couldn't?
Update (same day): most of the collapse this pilot fights turned out to be an evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. artifact. Our German de-sample renders addresses in US word order; the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' trained on German order. Re-rendered in native German order, this same anchor-on checkpointcheckpointA saved snapshot of the model weights and optimizer state during training. Mailwoman saves a checkpoint periodically so training can resume after a GPU hang. scores 83.8% localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. and beats v0/PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor. (78.7%). The Correction section at the end revises the "gated by 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. ambiguity" reading below it — keep reading; the pilot story stands as the record of what we believed at the time.
The hypothesis was sharp: the German collapse — trailing citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. → O, localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. and 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. fragmenting at end-of-string — is a local emission failure, and self-conditioningself-conditioningAn auxiliary model head that predicts the input's locale (language/country) and then FiLM-modulates the encoder so parsing adapts to the detected locale. Structural facts like word order still need explicit training on both orders.'s global soft localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. posterior was always going to miss it (it did, twice). A postcode anchoranchor inferenceA technique where structured knowledge (postcode locations, gazetteer place names) is injected into the model as soft input features — not as deterministic overrides. The model still decides the final labels, but the anchor signal biases it toward correct admin tags. is local, near-hard, and sits right at the collapse site. So we built it, end to end, and ran the A/B.
What's done and proven
The whole trainingtrainingThe process of adjusting a model's parameters so its predictions match labeled examples, by repeatedly measuring error and nudging the weights to reduce it. Distinct from inference, when the trained model is run on new input.-side pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package. works, validated on a live GPU run: the per-tokentokenOne word or subword in the tokenized input. For the neural classifier, tokens come from SentencePiece (subword units); for the rule classifiers, tokens are whitespace- and punctuation-separated words. anchor injection at 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. spanspanA contiguous range of characters or tokens in the input string, tagged with an address component type (street, locality, postcode, etc.). Parsed addresses are represented as collections of spans, possibly nested in a tree. (composing with the existing self-conditioningself-conditioningAn auxiliary model head that predicts the input's locale (language/country) and then FiLM-modulates the encoder so parsing adapts to the detected locale. Structural facts like word order still need explicit training on both orders. FiLM), the gold-spanspanA contiguous range of characters or tokens in the input string, tagged with an address component type (street, locality, postcode, etc.). Parsed addresses are represented as collections of spans, possibly nested in a tree. → sub-tokentokenOne word or subword in the tokenized input. For the neural classifier, tokens come from SentencePiece (subword units); for the rule classifiers, tokens are whitespace- and punctuation-separated words. alignmentalignmentThe step in the corpus pipeline that takes a (raw, components) pair from an adapter and produces a (raw, tokens, BIO labels) row by finding each component's text inside the raw string and labeling the matching tokens. that reuses the labelcomponent tagOne of the 33 labels in Mailwoman's address schema — street, locality, region, postcode, house_number, unit, po_box, country, venue, intersection, and others. Each parsed span carries exactly one component tag. projection so it can't drift, the JSON 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. lookup, and the confidence curriculum (no [NO-ANCHOR] tokentokenOne word or subword in the tokenized input. For the neural classifier, tokens come from SentencePiece (subword units); for the rule classifiers, tokens are whitespace- and punctuation-separated words. — "absent" is the c=0 tail of a continuum). A 20k-step from-scratch run trained clean — no NaNNaN (not a number). A floating-point result for an undefined operation (log of a negative, 0/0). Appearing in the training loss usually halts the run; recovering from it follows the NaN protocol., no destabilization. Everything from the DeepSeek design to the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' code to the tests to ModalModalA cloud GPU platform (modal.com) where Mailwoman trains its neural models on NVIDIA A100 GPUs. Training runs are launched via scripts/modal/train_remote.py and typically complete in ~1 hour. is connected and runs.
The collapse is real (the premise is locked)
We confirmed the failure exists for this exact code and seed, on real 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. German addresses through 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.:
| modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' (DE localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.-match, real OA) | result |
|---|---|
| control @3k (self-cond, anchor-off) | 29.3% |
| anchor-on @20k, anchor not fed | 35.9% |
| v0 (PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor.) / the target | ~83% / ~77% |
The control sits squarely on the established collapse (~25.6%). No A/B drift — the recipe collapses, as designed, so the anchor has something real to fix.
The verdict: the anchor is real, and partial
We then built the 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.-side channel — ONNXONNX (Open Neural Network Exchange). An open format for machine learning models that enables interoperability between training frameworks and inference runtimes. Mailwoman ships its trained model as an ONNX file so it can run in Node.js and the browser via onnxruntime. export with the anchor inputs, OnnxRunner + NeuralAddressClassifier feeding them, and a TS featurefeatureAn input signal a model conditions on. Beyond the raw tokens, Mailwoman feeds soft features — gazetteer-membership channels and the postcode anchor — that inform predictions without overriding them. builder whose layout is pinned to the Python trainingtrainingThe process of adjusting a model's parameters so its predictions match labeled examples, by repeatedly measuring error and nudging the weights to reduce it. Distinct from inference, when the trained model is run on new input. function by a cross-language test — and ran the DE 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. A/B with the anchor fed:
| DE localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.-match (real OA) | result |
|---|---|
| control @3k (anchor-off) | 29.3% |
| anchor-on @20k, anchor not fed | 35.9% |
| anchor-on @20k, anchor fed | 45.8% |
| v0 (PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor.) / target | 83.4% / ~77% |
The clean, unconfounded number is the same checkpointcheckpointA saved snapshot of the model weights and optimizer state during training. Mailwoman saves a checkpoint periodically so training can resume after a GPU hang. with the anchor off vs on: 35.9% → 45.8%, +9.9pp purely from feeding the anchor, nothing else changed. The modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' leans on the signal — the architecture's premise holds, end to end.
It is a partial fix. 45.8% is well short of ~77%, so the anchor helps real and measurably but doesn't fully reverse the collapse at this pilot scale.
The per-stateregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality. split is the mechanism — and points at the next lever. Sachsen (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. 01xxx–09xxx, little US collision) jumps 37.1% → 54.9% (+17.8pp); Berlin (10xxx, colliding hard with US ZIPs) barely moves, 34.7% → 36.7% (+2pp). The anchor's recovery is gated by 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. ambiguity: where the code pins the countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. it works strongly; where the posterior is a DE/US collision the uniform distribution can't decide and the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' stays collapsed. Disambiguating the colliding ranges is where a full fix lives.
Correction: most of the "collapse" was us measuring German in the wrong order
Here's the part that stings. We spent this pilot fighting a collapse, and a good chunk of it was our own evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. handing the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' German addresses in an order Germans don't write.
Our 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. German de-sample renders every row US-style: 27 Straußstraße, Berlin, Berlin 12623, house numberhouse numberThe numeric or alphanumeric identifier of a building on a street. Mailwoman's house_number component; its position relative to the street name flips between locales. first, 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. trailing after the citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.. The modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' trained on the German convention, Straußstraße 27, 12623 Berlin, streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. then house numberhouse numberThe numeric or alphanumeric identifier of a building on a street. Mailwoman's house_number component; its position relative to the street name flips between locales., 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. before the citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.. So when the evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. said "localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. 45%," it was partly grading the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' on a layout it had every reason never to expect.
So we re-rendered the exact same 3,000 addresses (same components, same 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., same anchor-on checkpointcheckpointA saved snapshot of the model weights and optimizer state during training. Mailwoman saves a checkpoint periodically so training can resume after a GPU hang.) into native German order and ran it again:
| same 3,000 DE addresses, same modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' | neural localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. | v0 (PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor.) | neural resolved |
|---|---|---|---|
| US order (how our de-sample ships) | 45.5% | 82.6% | 67.5% |
| native German order | 83.8% | 78.7% | 99.9% |
Only the word order changed. The modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' jumps +38pp and clears PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor.. Watch PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor. drift the other way, 82.6% → 78.7%: it's a US-lineage parser too, so native German order costs it a little. In the order German addresses actually arrive, our neural parser reads them better than the rules system we've been chasing.
The per-stateregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality. split is where the old story comes apart. The verdict above pinned Berlin's failure on 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. ambiguity: 10xxx collides with real US ZIPs, the uniform {DE,US} posterior can't choose, the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' stalls. Then you re-render, and:
| neural localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. | US order | native German order |
|---|---|---|
Berlin (10xxx) | 36.1% | 100.0% |
Sachsen (01–09xxx) | 54.9% | 67.6% |
Berlin's 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. still collide with US ZIPs in German order. Nothing about the ambiguity changed, and the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' gets the citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. right every single time. The collision was never what held Berlin back; the layout was. Once the citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. sits where German puts it, the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' knows it's a citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy., ZIP-shaped 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. or not.
So what was the anchor actually fixing?
We should be clear about what this does to the +9.9pp. The anchor's win was measured entirely on US-order German, the broken rendering, and it was real: same weightsparameterA single learned number inside a model — one weight or bias. Mailwoman's encoder has roughly 30 million of them; training is the search for good values., off versus on, nothing else moved. It helped the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' survive an order it wasn't trained for. But its value in the order that matters is now an open question we haven't measured. The 83.8% run had the anchor fed throughout, and we never ran native-order anchor-off to isolate it. The anchor earns its place elsewhere — 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.-side centroid already cut coord p99 from 330 to 46 km — yet "the anchor recovers German" needs re-testing against an evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. that isn't rendering the language wrong.
Premodel or training?
Both, and naming the layerslayerOne 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. is the fix.
The "collapse" headline is a measurement bug, premodel, living in the evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error.. We render German in an order it doesn't use, then grade the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' down for it. Point the evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. at native order (ideally both) and most of the collapse evaporates: 83.8%, beating PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor..
Order robustness is a trainingtrainingThe process of adjusting a model's parameters so its predictions match labeled examples, by repeatedly measuring error and nudging the weights to reduce it. Distinct from inference, when the trained model is run on new input. problem. A production geocoder really does see German both ways: native from German sources, US-ish from international feeds like the 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. dump we evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. on. The fix is data. Render the German trainingtrainingThe process of adjusting a model's parameters so its predictions match labeled examples, by repeatedly measuring error and nudging the weights to reduce it. Distinct from inference, when the trained model is run on new input. shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. in both orders for the same components, so the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' learns a German address can land either way. No new architecture, no anchor required for this part. The German synthesizer (synthesizeLocaleRow) now takes an order: "native" | "international" switch and the shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. builder mixes the two.
Cheapest first: fix the evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. (done, that's the table above), then ship the both-order shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. and retrain. Measuring first is what kept us from scaling an anchor to chase a number that was partly a rendering artifact of our own making.
What it means for multi-locale
It un-blocks it. The German "wall" that survived three retrains — the order-shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. collapse, two self-conditioningself-conditioningAn auxiliary model head that predicts the input's locale (language/country) and then FiLM-modulates the encoder so parsing adapts to the detected locale. Structural facts like word order still need explicit training on both orders. attempts, and this anchor pilot — was substantially a mirror: our evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. reflecting a layout we built. The parser reads native German better than PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor., which is the target, hit in the localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. we'd written off as our worst. The caveat is that native order is the easy direction; international-order German, the out-of-distribution case, is still 45%, and the both-order retrain is what closes it. The ceiling sits far higher than the collapse let us see.
Next levers
- Fix the evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error., then retrain on both orders — the de-sample renders German US-style; test native order (the Correction table) and most of the collapse is gone. Then ship the both-order shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. (
synthesizeLocaleRow({ order })) and retrain so the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' handles either layout. This is the real fix; the itemsexpectation-maximizationAn iterative algorithm that estimates model parameters when some variables are unobserved. In Mailwoman's matcher, EM learns the Fellegi-Sunter m and u parameters from unlabeled data — no training labels needed. below are now secondary. - Re-isolate the anchor on a correct evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. — the +9.9pp was measured on US-order German. Run native-order anchor-off vs anchor-on to learn what the anchor is worth once the evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. isn't rendering the language wrong.
- Strategic check — 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. already does German at ~83% (v0 parseaddress 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. → 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.), and the neural parser now beats it in native order. The parser-anchor (multi-localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. universal parser) and 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.-side centroid (already cut coord p99 330 → 46 km) remain separable bets.
Artifacts: configs v0.9.1-pilot-anchor-{off,on}.yaml; eval_de + export_onnx (ModalModalA cloud GPU platform (modal.com) where Mailwoman trains its neural models on NVIDIA A100 GPUs. Training runs are launched via scripts/modal/train_remote.py and typically complete in ~1 hour.); lookup scripts/build-pilot-anchor-lookup.py; the both-order synthesizer switch lands in the follow-up synthesizeLocaleRow({ order }); consult notes .agents/skills/deepseek-consult/session-notes-2026-06-05-anchor-pilot.md.