Skip to main content

Phase 3 — seg@1 on the production harness, and a correction to Phase 1's headline

PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 3 built the JS/WASM side: span_scores through ONNXRunnerNeuralParseTrace → a k-best semi-Markov decode (neural/semi-markov-decode.ts, 11 tests, brute-force verified like its Python twin). That unlocks the measurement PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 1 could not make: seg@1 with the anchor / 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. / 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. channels fed, against the real 0.573 baseline.

The headline, and it corrects me

PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 1 claimed the 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. 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. beats the 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. decode by +7.9pp. With channels fed, that margin is +0.75pp — two fixtures, inside noise.

triaged parity 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. (n=267)v264, BIO-summed 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. (night-3)v301, learned 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. (now)
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.@10.5730.5693
seg@10.4530.5768
oracle@50.6630.7228
oracle@100.7490.7753

PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 1's +7.9pp was measured in the channel-starvedstarvedA tag with too little training representation to learn — near-zero F1 — because the corpus adapter never emits examples of it (intersection tags sat at 0% until an intersection synthesizer existed). Python gate, where token@1 reads 0.4906 instead of 0.5693. A large part of that gap was the BIO 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.'s starvation, not the 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. 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.'s strength. Feed the channels and the BIO 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. recovers most of it. The Phase-1 doc flagged the absolutes as non-comparable; it did not anticipate that the margin would shrink this much, and the honest correction belongs at the top rather than in a footnote.

What survives the correction — and it's the part that matters

1. The trained scorer beats the summed-BIO stand-in by +12.4pp (seg@1 0.453 → 0.5768), on the same instrument, channels fed both times. That was PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 1's actual falsifier and it holds decisively.

2. The secondary read passed: oracle@10 rose 0.749 → 0.7753 (+2.6pp), oracle@5 0.663 → 0.7228 (+6.0pp). The config pre-registered this: "If seg@1 crosses but oracle@10 is flat, the scorer reshuffled the list without learning better 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.." It is not flat. The list genuinely improved.

3. On the class the arc targets, it is not close:

Paris fixture (n=63, bare-fragment heavy)v264v301 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. decode
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.@10.52380.5238
seg@10.7619 (+23.8pp)
oracle@50.9048

token@1 is byte-identical (33/63) to the v264 baseline, so this is a clean A/B on the same encoderencoderThe part of a transformer that turns input tokens into contextualized vector representations. Mailwoman's classifier is a small encoder-only transformer (~30M parameters). stateregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality.: +23.8pp at rank 1, and oracle@5 clears 0.90 on this fixture.

The synthesis

The 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. 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.'s value is concentrated exactly where the BIO 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. fails. On contextful addresses — most of the general 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. — BIO + channels already works and the 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. decode adds ~nothing at rank 1. On bare fragments it adds 24 points. That is a coherent result, not a disappointing one: it is the night-3 partition (66% of streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. failures are bare fragments) showing up in the ledger.

But it also means seg@1 alone does not justify shipping the decode. A +0.75pp aggregate margin is not a reason to change production. The case is the list: oracle@5 0.723 / oracle@10 0.775 against a shipped 0.573 is ~15–20 points of headroom that only a reranker can collect — which is PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 4, and which is now the load-bearing phasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). rather than a nice-to-have.

What shipped

  • ONNXRunner.InferResult.spanScores + maxSpan — optional, mirroring the localeLogits contract; a pre-v3 bundle has no span_scores output and the BIO path is untouched.
  • NeuralParseTrace.spanScores — threaded through traceParse.
  • neural/semi-markov-decode.tsdecodeSegmentationsKBest + parseSemiCRFTransitions. 11 tests: rank-1 vs brute-force argmax, the k-best list vs brute-force top-k in order, exact 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 O-length-1 rule under adversarial scores, and four sidecar-validation throws (a transition matrix that disagrees with segment_types, a non-O index 0, a missing max_span).
  • The segmentsegmentA punctuation-bounded chunk of the normalized input — the comma-separated parts of 'Portland, OR' — used to give downstream stages structural context.-type axis is read from semi-crf-transitions.json, never hardcoded (PLACETYPE_ORDER class).

yarn ci:test:fast: 3481 pass, 0 fail.

The browser side — done, and measured on the runtime that ships

WebONNXRunner reads span_scores with the same optional contract (pre-v3 bundles → undefined → BIO path byte-unaffected). The decoderdecoderIn a transformer encoder-decoder model, the part that produces output sequences. Mailwoman's classifier is encoder-only (no decoder); the 'CRF decoder' is a different thing — a structured-prediction layer that picks the best label sequence from the encoder's outputs. itself is pure TS with no ORT dependency, so one decoderdecoderIn a transformer encoder-decoder model, the part that produces output sequences. Mailwoman's classifier is encoder-only (no decoder); the 'CRF decoder' is a different thing — a structured-prediction layer that picks the best label sequence from the encoder's outputs. serves both hosts.

The read is now duplicated across neural/onnx-runner.ts and neural-web/web-onnx-runner.ts, which is a real drift hazard — a transposed unflatten in one host would mis-tag every 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. (the PLACETYPE_ORDER failure mode, one 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. down). A cross-runner parity test pins them: the same flat buffer must produce the same nested array on both sides.

#378 SLO, measured on onnxruntime-web's WASM EP — the runtime the demo actually runs, not the onnxruntime-node bench PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 2 used:

ms/inferspansspanA 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. read
v264 (shipped, no 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. output)14.74no
v301 (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. graph)14.82yes
delta+0.08 ms (+0.5%)

That is the full cost — this runner unflattens the 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. tensor on every 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., so it includes the decode-side marshalling, not just the graph. Reproducible via neural-web/span-slo.bench.test.ts (reported, never asserted — a wall-clock threshold in CI is a flake generator).

Combined with PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 2's size gate (+0.22 MB int8, +0.57%), the browser cost of carrying the 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. 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. is +0.5% latency and +0.6% download — and that is while reading the 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.. A browser that never decodes them pays neither.

Still not done, deliberately: the loader does not fetch semi-crf-transitions.json. Nothing consumes it in the browser yet — the rerank is PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 4 — and wiring a fetch for data with no consumer is the speculative structure this project keeps refusing (cf. the <= -0.5 importance band, #1142).

Next

PhasephaseA milestone in the implementation plan (Foundation, Corpus, Training, Integration, and forward-looking phases). Distinct from stage (runtime pipeline) and tier (model vocabulary). 4 is now the whole ballgame: 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. rerank over the k-best list + the isotonic calibrationisotonic calibrationA post-hoc calibration that fits a monotonic map from raw model scores to true probabilities without retraining (via PAVA). Mailwoman's confidence calibrator. for the ambiguity gate + option C (kind-posterior + 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.-weighted lossloss functionA number measuring how wrong the model's predictions are on a batch of examples. Training minimizes it. Mailwoman's loss combines per-token negative log-likelihood with the CRF sequence loss.) for the 17 localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.-refusals the 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. 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. provably does not fix. The headroom is measured (oracle@5 0.723 vs shipped 0.573); the question is how much of it evidence-based reranking can actually collect.