PR3 Pilot A — self-conditioning decisive eval
Date: 2026-06-04
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.': v0.9.0-pilot-selfcond-s42, step-20000 (early gate), fp32fp32 / fp1632-bit and 16-bit floating-point formats. Mailwoman trains in bf16 (a 16-bit variant) and exports the ONNX model in int8 for size. 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.
Baseline: v0.7.2 (/tmp/v072-eval/model.onnx), fp32fp32 / fp1632-bit and 16-bit floating-point formats. Mailwoman trains in bf16 (a 16-bit variant) and exports the ONNX model in int8 for size., same v0.6.0-a0 tokenizertokenizerThe component that converts a raw address string into a sequence of numeric token IDs the model can process. Mailwoman's tokenizer is a SentencePiece unigram model trained specifically on postal addresses., same 33-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. schema
Verdict: Do not promote. Clean negative result. 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. did not prevent the German end-of-string localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. collapse.
What the pilot tested
One hypothesis (design doc: docs/articles/plan/2026-06-04-pr3-self-conditioned-retrain.md): a from-scratch 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.' with an auxiliary localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. headattention headOne of several parallel attention computations in a layer, each free to focus on a different kind of relationship between tokens. Their outputs are concatenated — 'multi-head attention'. Mailwoman uses 4 heads. over the pooled sequence + zero-init FiLM modulationFiLM modulation (Feature-wise Linear Modulation). A parameter-efficient adaptation that scales and shifts feature vectors by learned per-example multipliers and biases. Used in self-conditioning to make parsing decisions locale-aware without retraining the whole model. of its own 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. reps would learn German word order without triggering the v0.8.0 Saint-AlbansBAN (Base Adresse Nationale). France's authoritative open national address register — the highest-quality training source for French addresses, with full component structure. 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. collapse. Single variable on the v0.7.2-proven recipe (1.5e-4 constant, ls 0.1, CRFCRF (Conditional Random Field). A statistical modeling method that predicts structured outputs by modeling dependencies between adjacent labels. Mailwoman uses a linear-chain CRF as the Viterbi decoder at inference time to enforce BIO label consistency — a B-street must be followed by I-street or O, never I-locality. off); the only addition is the conditioning. CorpuscorpusThe BIO-labeled training data used to train Mailwoman's neural classifier. Assembled from real sources (OpenAddresses, National Address Database) and synthetic shards (boundary stress, order variants, negative space). Managed by @mailwoman/corpus. v0.4.1-de: v0.4.0 (US/FR) base + a 200K-row synth-german overlay (~18% of the mix).
The pre-registered gate, and the result
| Gate (from the design doc) | Target | Result | Pass? |
|---|---|---|---|
| DE localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. — 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. match | ≥ 70% and rising | 25.6% | ❌ |
| DE localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. — 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. F1 (held-out golden) | ≥ 70% | 34.8% | ❌ |
| US/FR 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. utility vs v0.7.2 | within ~1pp | US localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. −1.6pp | ⚠️ (confounded by 20k-vs-100k) |
| cross_pollution per localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. (live) | < 1% | 0.00% throughout | ✅ (but blind — see below) |
DE — the headline locale collapsed
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. evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. (the pre-registered judge), German OA sample, n=3000, --default-country DE, 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 on. Figures self-emitted to /tmp/pilot-eval/resolver-{pilot,v072}-de.md.
| parser | localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.-match | regionregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality.-match | resolved | coord p50 (anchor) |
|---|---|---|---|---|
| v0.7.2 (baseline) | 77.4% | 43.6% | 99.4% | 1.3 km |
| Pilot A (self-cond) | 25.6% | 0.0% | 37.1% | 1.3 km |
| v0 (PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor. rules) | 79.4% | 99.3% | 99.3% | — |
Per-stateregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality.: Pilot Berlin 34.2% / Sachsen 16.9%, against v0.7.2's Berlin 100.0% / Sachsen 54.7%. −51.8pp on DE localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.. The 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. still pins the coordinate (p50 1.3 km) because it extracts 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. independently of the parser — but the admin match is gone, because the localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. 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. itself is gone.
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. F1 on the held-out German golden (1500 rows, data/eval/external/openaddresses-de-golden.jsonl) tells the same story and adds the texture:
| tag | Pilot A | v0.7.2 | Δ |
|---|---|---|---|
| localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. | 34.8% | 72.5% | −37.7 |
| 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. | 31.4% | 89.0% | −57.6 |
| streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. | 41.3% | 19.1% | +22.2 |
| house_number | 35.5% | 14.6% | +20.9 |
| exact-match | 28.7% | 11.3% | +17.4 |
That shape — streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. and house_number up, 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. down, exact-match up — is the v0.8.0 Saint-AlbansBAN (Base Adresse Nationale). France's authoritative open national address register — the highest-quality training source for French addresses, with full component structure. signature exactly. The pilot learned German streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. order (v0.7.2 mangles German streetsstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. under its US-order prior); it paid for it by dropping the trailing citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy..
What the collapse actually looks like
Raw parsesaddress 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., pilot vs v0.7.2 (scripts/diag-de-pilot.ts):
Davoser Straße 22 A, Berlin
pilot: street="Davoser Straße 2" house_number="2 A" ← "Berlin" dropped
v072 : locality="Davoser Straße" postcode="22" locality="Berlin" street="A"
Prager Straße 8, 01069 Dresden
pilot: street="Prager Straße 8" postcode="01069" ← "Dresden" dropped
v072 : locality="Dresden" street="Prager Straße 8" postcode="01069"
Bautzner Straße 101, 01099 Dresden
pilot: street="Bautzner Straße 10" house_number="1" postcode="01099" ← "Dresden" dropped
v072 : locality="Dresden" street="Bautzner Straße 101" postcode="01099"
The pilot drops the trailing citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. (localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. → O) once it has committed to street house [postcode]. The aux localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. headattention headOne of several parallel attention computations in a layer, each free to focus on a different kind of relationship between tokens. Their outputs are concatenated — 'multi-head attention'. Mailwoman uses 4 heads. correctly identifies German (locale_acc 0.95–0.97 throughout 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.) — but a FiLM scale/shift over 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. featuresfeatureAn 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. never imposes "a localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. must still live at the end of this string." Knowing 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. is not the same as keeping the citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy..
US — healthy, the failure is German-specific
US 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. evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error., n=2000, --default-country US:
| parser | localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.-match | regionregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality.-match | resolved |
|---|---|---|---|
| v0.7.2 | 97.7% | 99.9% | 100.0% |
| Pilot A | 96.1% | 99.8% | 100.0% |
| v0 (rules) | 95.8% | 99.5% | 99.7% |
The pilot is within 1.6pp of v0.7.2 on US localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. and still beats the rules parser — at 20k from-scratch steps against v0.7.2's 100k. The US streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. 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.-F1 regression (−18pp) doesn't reach 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. because US localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. is position-robust. So the conditioning architecture didn't poison the dominant localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for.; the damage is confined to German order. That localizes the problem cleanly: this is the boundary bug, not 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. blow-up.
The corpus is correct — this is not garbage-in
Every 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. row labelscomponent 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. the trailing citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. properly (/tmp/german-train.jsonl):
Dommitzscher Straße 19, Torgau → … 19|B-house_number Torgau|B-locality
Am Westhang 7, 01734 Rabenau Sachs → … 01734|B-postcode Rabenau|B-locality Sachs|I-locality
Grünsteinweg 45 H, Berlin → … 45|B-house_number H|I-house_number Berlin|B-locality
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.' was shown the right answer 200K times and still learned to drop it. The hypothesis got a fair test; it failed on its own terms.
Why the live tripwires stayed green
Two blind spots let 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. look healthy to the dashboard while German was breaking:
cross_pollutionmeasured the wrong failure. It counts gold citylocalityThe 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.-start tokenstokenOne 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. predicted as 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. (B/I-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.). The actual collapse is citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. → O (dropped), not citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. → 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.. So the metric read 0.00% the whole run while localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. recallrecallOf the spans whose gold label is a given tag, the fraction the model found. High recall means few misses. Paired with precision to compute F1. cratered. A live DE-localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.-recallrecallOf the spans whose gold label is a given tag, the fraction the model found. High recall means few misses. Paired with precision to compute F1. (or citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.→O) tripwire would have fired.- Aggregate val F1 hid it. The headline val localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. F1 was 0.829 — but that's US-dominated (US is ~82% of the mix). The German-specific localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. was never in the headline. Per-localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. val F1, streamed live, is the fix.
Shipped from this run regardless
- Export bug fix (
corpus-python/src/mailwoman_train/model.py). The FiLM split used.chunk(2, dim=-1), which the dynamo exporter emits as an opset-18Split(num_outputs=2)node. onnxruntimeONNX (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.-node — and the WASM/WebGPU web runtime — reject it:Unrecognized attribute: num_outputs. v0.7.2 had no FiLM so it never hit this. Replaced with two explicit slices (film[..., :H],film[..., H:]) — mathematically identical, same trained 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., every runtime loads it. Any future self-conditioned export needs this. 11 PR3 CPU tests stay green.
Decisions made
- Did not promote the pilot to
releases.json/ HF. Gate failed by ~45pp on the headline metric; 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.' is not on disk anywhere a consumer would pick it up. - Did not launch the 100k follow-up. That was conditional on the gate passing. At 25.6% (vs a 70% bar), and with the 10k-vs-20k slope flat (German localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. pinned — see above), extending to 100k would not cross the bar. Not justified by this data.
- Did not launch another from-scratch German pilot autonomously. This is the 2nd reproduction of the same end-of-string localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. collapse via a new mechanism (v0.8.0 continue-train was the 1st), on correct data. The evidence now points away from recipe/conditioning tweaks. The next direction is the operator's call.
The slope: flat, not rising — the recipe is not salvageable by more steps
Exported step-10000 and re-ran the same DE evalsevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. to test whether German localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. is climbing across steps. It is not:
| metric | step-10000 | step-20000 | Δ |
|---|---|---|---|
| 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. localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.-match | 25.5% | 25.6% | +0.1 |
| DE 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. localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. F1 | 35.4% | 34.8% | −0.6 |
| Berlin localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. | 34.2% | 34.2% | 0.0 |
| Sachsen localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. | 16.8% | 16.9% | +0.1 |
Doubling the 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. moved German localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. essentially zero — Berlin is pinned at 34.2% at both checkpointscheckpointA saved snapshot of the model weights and optimizer state during training. Mailwoman saves a checkpoint periodically so training can resume after a GPU hang.. The collapse is a converged failure mode 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.' settled into by step-10000 and stays in, not an undertraining artifact. A 100k run of this recipe would not cross the 70% bar. So "just train longer" is off the table, and the fix has to be structural.
Open questions for the operator
- Structural vs. statistical fix. A FiLM scale/shift can't enforce structure. Candidates that can: a trained CRFCRF (Conditional Random Field). A statistical modeling method that predicts structured outputs by modeling dependencies between adjacent labels. Mailwoman uses a linear-chain CRF as the Viterbi decoder at inference time to enforce BIO label consistency — a B-street must be followed by I-street or O, never I-locality. transition prior (was off here — the bf16bf16 (bfloat16). A 16-bit floating-point format used during training. Half the memory of fp32 with similar numeric range, which lets the training batch fit on the lab's GPU. 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. history), a positional "last content 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. is rarely O" constraint, or the anchor-based 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. direction (DeepSeek-signed,
project-anchor-based-parsing-direction) — 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.-as-anchor → country posteriorcountry posteriorA country → probability map (derived from postcodes or the coarse-placer) that re-ranks resolver candidates as a soft prior, never a hard filter. → soft channel — which doesn't depend on the parser recovering localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. from raw spansspanA 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. at all. The last is the standing LEAD. - Does 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 paper over this? With the 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. pinning coordinates at p50 1.3 km even when localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.-match is 25.6%, how much does the dropped citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. actually cost a production lookup? Worth quantifying before deciding how hard to chase the parser fix.
Numbers
| 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. spend (pilot train, prior session) | ~$2–3 |
| 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. spend (3 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. exports this session) | ~$0.45 |
| Local evalevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. compute | ~18 min (CPU 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.) |
| Modelsneural 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.' promoted | 0 |
| Bugs fixed | 1 (FiLM chunk→Split export) |
| 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. incidents | 0 |