@mailwoman/neural 4.16.2 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/out/address-system.d.ts +4 -5
  2. package/out/address-system.d.ts.map +1 -1
  3. package/out/address-system.js +4 -5
  4. package/out/address-system.js.map +1 -1
  5. package/out/anchor-inference.d.ts +16 -18
  6. package/out/anchor-inference.d.ts.map +1 -1
  7. package/out/anchor-inference.js +16 -18
  8. package/out/anchor-inference.js.map +1 -1
  9. package/out/browser.js +1 -1
  10. package/out/case-normalize.d.ts +13 -8
  11. package/out/case-normalize.d.ts.map +1 -1
  12. package/out/case-normalize.js +18 -11
  13. package/out/case-normalize.js.map +1 -1
  14. package/out/classifier.d.ts +125 -134
  15. package/out/classifier.d.ts.map +1 -1
  16. package/out/classifier.js +46 -49
  17. package/out/classifier.js.map +1 -1
  18. package/out/fst-prior.d.ts +19 -21
  19. package/out/fst-prior.d.ts.map +1 -1
  20. package/out/fst-prior.js +13 -14
  21. package/out/fst-prior.js.map +1 -1
  22. package/out/gazetteer-inference.d.ts +13 -16
  23. package/out/gazetteer-inference.d.ts.map +1 -1
  24. package/out/gazetteer-inference.js +13 -16
  25. package/out/gazetteer-inference.js.map +1 -1
  26. package/out/index.d.ts +1 -1
  27. package/out/index.js +1 -1
  28. package/out/labels.d.ts +9 -10
  29. package/out/labels.d.ts.map +1 -1
  30. package/out/labels.js +5 -6
  31. package/out/labels.js.map +1 -1
  32. package/out/onnx-runner.d.ts +33 -21
  33. package/out/onnx-runner.d.ts.map +1 -1
  34. package/out/onnx-runner.js +39 -19
  35. package/out/onnx-runner.js.map +1 -1
  36. package/out/postcode-anchor.d.ts +28 -34
  37. package/out/postcode-anchor.d.ts.map +1 -1
  38. package/out/postcode-anchor.js +48 -55
  39. package/out/postcode-anchor.js.map +1 -1
  40. package/out/postcode-binary-resolver.d.ts +10 -13
  41. package/out/postcode-binary-resolver.d.ts.map +1 -1
  42. package/out/postcode-binary-resolver.js +12 -15
  43. package/out/postcode-binary-resolver.js.map +1 -1
  44. package/out/postcode-repair.d.ts +5 -5
  45. package/out/postcode-repair.d.ts.map +1 -1
  46. package/out/postcode-repair.js +9 -10
  47. package/out/postcode-repair.js.map +1 -1
  48. package/out/proposal-classifier.d.ts +3 -3
  49. package/out/proposal-classifier.d.ts.map +1 -1
  50. package/out/proposal-classifier.js.map +1 -1
  51. package/out/query-shape-prior.d.ts +10 -11
  52. package/out/query-shape-prior.d.ts.map +1 -1
  53. package/out/query-shape-prior.js +12 -15
  54. package/out/query-shape-prior.js.map +1 -1
  55. package/out/scorer.d.ts +28 -31
  56. package/out/scorer.d.ts.map +1 -1
  57. package/out/scorer.js +39 -44
  58. package/out/scorer.js.map +1 -1
  59. package/out/soft-features.d.ts +12 -14
  60. package/out/soft-features.d.ts.map +1 -1
  61. package/out/soft-features.js +5 -6
  62. package/out/soft-features.js.map +1 -1
  63. package/out/span-bridge.d.ts +9 -11
  64. package/out/span-bridge.d.ts.map +1 -1
  65. package/out/span-bridge.js +8 -10
  66. package/out/span-bridge.js.map +1 -1
  67. package/out/span-proposal-prior.d.ts +13 -15
  68. package/out/span-proposal-prior.d.ts.map +1 -1
  69. package/out/span-proposal-prior.js +2 -2
  70. package/out/span-proposal-prior.js.map +1 -1
  71. package/out/span-proposer-lexicon.d.ts +2 -3
  72. package/out/span-proposer-lexicon.d.ts.map +1 -1
  73. package/out/span-proposer-lexicon.js +9 -10
  74. package/out/span-proposer-lexicon.js.map +1 -1
  75. package/out/street-morphology-prior.d.ts +11 -12
  76. package/out/street-morphology-prior.d.ts.map +1 -1
  77. package/out/street-morphology-prior.js +8 -9
  78. package/out/street-morphology-prior.js.map +1 -1
  79. package/out/tokenizer.d.ts +6 -7
  80. package/out/tokenizer.d.ts.map +1 -1
  81. package/out/tokenizer.js +6 -7
  82. package/out/tokenizer.js.map +1 -1
  83. package/out/unit-repair.d.ts +2 -2
  84. package/out/unit-repair.d.ts.map +1 -1
  85. package/out/unit-repair.js +11 -14
  86. package/out/unit-repair.js.map +1 -1
  87. package/out/viterbi.d.ts +13 -13
  88. package/out/viterbi.d.ts.map +1 -1
  89. package/out/viterbi.js +12 -12
  90. package/out/viterbi.js.map +1 -1
  91. package/out/vitest.config.d.ts.map +1 -1
  92. package/out/vitest.config.js.map +1 -1
  93. package/out/weights.d.ts +62 -71
  94. package/out/weights.d.ts.map +1 -1
  95. package/out/weights.js +33 -37
  96. package/out/weights.js.map +1 -1
  97. package/out/word-consistency.d.ts +4 -4
  98. package/out/word-consistency.d.ts.map +1 -1
  99. package/out/word-consistency.js +4 -4
  100. package/out/word-consistency.js.map +1 -1
  101. package/package.json +13 -13
@@ -14,9 +14,8 @@
14
14
  */
15
15
  import type { SystemCode } from "@mailwoman/codex";
16
16
  /**
17
- * Locale-head class order — MUST mirror `corpus-python/src/mailwoman_train/labels.py`
18
- * `LOCALE_COUNTRIES` exactly (same never-reorder/append-only discipline; a drift here silently
19
- * mislabels every detection).
17
+ * Locale-head class order — MUST mirror `corpus-python/src/mailwoman_train/labels.py` `LOCALE_COUNTRIES` exactly (same
18
+ * never-reorder/append-only discipline; a drift here silently mislabels every detection).
20
19
  */
21
20
  export declare const LOCALE_COUNTRIES: readonly ["US", "FR", "DE", "CA", "GB", "JP", "ES", "IT", "NL"];
22
21
  export interface DetectedSystem {
@@ -28,8 +27,8 @@ export interface DetectedSystem {
28
27
  * Read the locale head's posterior into a confident `SystemCode`, or null.
29
28
  *
30
29
  * @param localeLogits The raw `locale_logits` output (LOCALE_COUNTRIES order).
31
- * @param threshold Minimum softmax probability to act on (default 0.8 — the head's held-out
32
- * accuracy is ~0.98, so 0.8 trades a little recall for never masking on a coin flip).
30
+ * @param threshold Minimum softmax probability to act on (default 0.8 — the head's held-out accuracy is ~0.98, so 0.8
31
+ * trades a little recall for never masking on a coin flip).
33
32
  */
34
33
  export declare function detectAddressSystem(localeLogits: readonly number[] | undefined, threshold?: number): DetectedSystem | null;
35
34
  //# sourceMappingURL=address-system.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"address-system.d.ts","sourceRoot":"","sources":["../address-system.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAIlD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,iEAAkE,CAAA;AAY/F,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,EAAE,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;IAC1C,UAAU,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAClC,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAC3C,SAAS,SAAM,GACb,cAAc,GAAG,IAAI,CAWvB"}
1
+ {"version":3,"file":"address-system.d.ts","sourceRoot":"","sources":["../address-system.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAIlD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,iEAAkE,CAAA;AAY/F,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,EAAE,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;IAC1C,UAAU,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAClC,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAC3C,SAAS,SAAM,GACb,cAAc,GAAG,IAAI,CAevB"}
@@ -14,9 +14,8 @@
14
14
  */
15
15
  import { softmax } from "./viterbi.js";
16
16
  /**
17
- * Locale-head class order — MUST mirror `corpus-python/src/mailwoman_train/labels.py`
18
- * `LOCALE_COUNTRIES` exactly (same never-reorder/append-only discipline; a drift here silently
19
- * mislabels every detection).
17
+ * Locale-head class order — MUST mirror `corpus-python/src/mailwoman_train/labels.py` `LOCALE_COUNTRIES` exactly (same
18
+ * never-reorder/append-only discipline; a drift here silently mislabels every detection).
20
19
  */
21
20
  export const LOCALE_COUNTRIES = ["US", "FR", "DE", "CA", "GB", "JP", "ES", "IT", "NL"];
22
21
  /** ISO-2 country → codex address-system slice. Unmapped locales have no conventions yet. */
@@ -32,8 +31,8 @@ const COUNTRY_TO_SYSTEM = {
32
31
  * Read the locale head's posterior into a confident `SystemCode`, or null.
33
32
  *
34
33
  * @param localeLogits The raw `locale_logits` output (LOCALE_COUNTRIES order).
35
- * @param threshold Minimum softmax probability to act on (default 0.8 — the head's held-out
36
- * accuracy is ~0.98, so 0.8 trades a little recall for never masking on a coin flip).
34
+ * @param threshold Minimum softmax probability to act on (default 0.8 — the head's held-out accuracy is ~0.98, so 0.8
35
+ * trades a little recall for never masking on a coin flip).
37
36
  */
38
37
  export function detectAddressSystem(localeLogits, threshold = 0.8) {
39
38
  if (!localeLogits || localeLogits.length !== LOCALE_COUNTRIES.length)
@@ -1 +1 @@
1
- {"version":3,"file":"address-system.js","sourceRoot":"","sources":["../address-system.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAA;AAE/F,4FAA4F;AAC5F,MAAM,iBAAiB,GAAmE;IACzF,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;CACR,CAAA;AAQD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAClC,YAA2C,EAC3C,SAAS,GAAG,GAAG;IAEf,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,gBAAgB,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACjF,MAAM,KAAK,GAAG,OAAO,CAAC,YAAwB,CAAC,CAAA;IAC/C,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,KAAK,CAAC,CAAC,CAAE,GAAG,KAAK,CAAC,IAAI,CAAE;YAAE,IAAI,GAAG,CAAC,CAAA;IAC7E,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAE,CAAA;IAC/B,IAAI,UAAU,GAAG,SAAS;QAAE,OAAO,IAAI,CAAA;IACvC,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAE,CAAA;IACvC,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IACzC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAA;AACvC,CAAC"}
1
+ {"version":3,"file":"address-system.js","sourceRoot":"","sources":["../address-system.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAA;AAE/F,4FAA4F;AAC5F,MAAM,iBAAiB,GAAmE;IACzF,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;CACR,CAAA;AAQD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAClC,YAA2C,EAC3C,SAAS,GAAG,GAAG;IAEf,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,gBAAgB,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACjF,MAAM,KAAK,GAAG,OAAO,CAAC,YAAwB,CAAC,CAAA;IAC/C,IAAI,IAAI,GAAG,CAAC,CAAA;IAEZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,KAAK,CAAC,CAAC,CAAE,GAAG,KAAK,CAAC,IAAI,CAAE;YAAE,IAAI,GAAG,CAAC,CAAA;IAC7E,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAE,CAAA;IAE/B,IAAI,UAAU,GAAG,SAAS;QAAE,OAAO,IAAI,CAAA;IACvC,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAE,CAAA;IACvC,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAEzC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAExB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAA;AACvC,CAAC"}
@@ -7,7 +7,7 @@
7
7
  * (`mailwoman_train/tokenizer.py::anchor_feature_vector` + `realign_anchor_to_pieces`). At
8
8
  * inference the model conditions on per-piece anchor features fed alongside `input_ids`; this
9
9
  * builds them from a raw address + its SentencePiece pieces, using the SAME postcode→anchor
10
- * lookup the model trained against (`scripts/build-pilot-anchor-lookup.py`), so the feature
10
+ * lookup the model trained against (`scripts/build-pilot-anchor-lookup.ts`), so the feature
11
11
  * layout matches byte-for-byte.
12
12
  *
13
13
  * The layout is ESSENTIAL and cross-language: a wrong locale order or centroid scale feeds the
@@ -16,9 +16,8 @@
16
16
  */
17
17
  import type { TokenizedPiece } from "./tokenizer.js";
18
18
  /**
19
- * The locale class order — MUST match Python `mailwoman_train/labels.py::LOCALE_COUNTRIES`. The
20
- * posterior occupies indices `[0, LOCALE_ORDER.length)`; the normalized centroid the last two.
21
- * (Pinned by the test; do not reorder.)
19
+ * The locale class order — MUST match Python `mailwoman_train/labels.py::LOCALE_COUNTRIES`. The posterior occupies
20
+ * indices `[0, LOCALE_ORDER.length)`; the normalized centroid the last two. (Pinned by the test; do not reorder.)
22
21
  */
23
22
  export declare const LOCALE_ORDER: readonly ["US", "FR", "DE", "CA", "GB", "JP", "ES", "IT", "NL"];
24
23
  /** Anchor feature width = posterior over the locale set + a 2-d centroid. */
@@ -31,27 +30,26 @@ export interface AnchorEntry {
31
30
  }
32
31
  export type AnchorLookup = Map<string, AnchorEntry>;
33
32
  /**
34
- * Build the fixed-width anchor feature vector — the exact mirror of Python `anchor_feature_vector`:
35
- * a uniform country posterior over {@linkcode LOCALE_ORDER} (renormalized over the in-set mass) + a
36
- * normalized centroid (`lat/90`, `lon/180` ∈ [-1, 1]).
33
+ * Build the fixed-width anchor feature vector — the exact mirror of Python `anchor_feature_vector`: a uniform country
34
+ * posterior over {@linkcode LOCALE_ORDER} (renormalized over the in-set mass) + a normalized centroid (`lat/90`,
35
+ * `lon/180` ∈ [-1, 1]).
37
36
  */
38
37
  export declare function anchorFeatureVector(posterior: Record<string, number>, lat: number, lon: number): number[];
39
38
  /**
40
- * Parse the pilot postcode→anchor lookup JSON (`{postcode: [posterior, lat, lon, source?]}`) into a
41
- * Map. The optional trailing `source` is the centroid's provenance label (#525 — `"wof"`,
42
- * `"census-zcta-2024"`, or `null` for a placeholder); build-side bookkeeping, ignored at inference.
43
- * Pure (takes the parsed object, not a path) so this module stays browser-safe the file read
44
- * lives in the Node-side caller (the eval).
39
+ * Parse the pilot postcode→anchor lookup JSON (`{postcode: [posterior, lat, lon, source?]}`) into a Map. The optional
40
+ * trailing `source` is the centroid's provenance label (#525 — `"wof"`, `"census-zcta-2024"`, or `null` for a
41
+ * placeholder); build-side bookkeeping, ignored at inference. Pure (takes the parsed object, not a path) so this module
42
+ * stays browser-safe the file read lives in the Node-side caller (the eval).
45
43
  */
46
44
  export declare function parseAnchorLookup(raw: Record<string, [Record<string, number>, number, number, (string | null)?]>): AnchorLookup;
47
45
  /**
48
- * Per-piece anchor features + confidence for `text`, projected onto its SP `pieces` by the SAME
49
- * char→piece rule the labels use (a piece takes the anchor of the postcode span its first
50
- * non-whitespace char falls inside) — so the anchor lands on exactly the postcode's sub-tokens.
46
+ * Per-piece anchor features + confidence for `text`, projected onto its SP `pieces` by the SAME char→piece rule the
47
+ * labels use (a piece takes the anchor of the postcode span its first non-whitespace char falls inside) — so the anchor
48
+ * lands on exactly the postcode's sub-tokens.
51
49
  *
52
- * Postcode spans are the alphanumeric runs in `text` that the lookup recognizes (gold-equivalent on
53
- * clean rendered addresses); a recognized span yields a confidence-1.0 anchor, like training's
54
- * gold-span. Returns `(pieces × ANCHOR_FEATURE_DIM)` features + `(pieces,)` confidence.
50
+ * Postcode spans are the alphanumeric runs in `text` that the lookup recognizes (gold-equivalent on clean rendered
51
+ * addresses); a recognized span yields a confidence-1.0 anchor, like training's gold-span. Returns `(pieces ×
52
+ * ANCHOR_FEATURE_DIM)` features + `(pieces,)` confidence.
55
53
  */
56
54
  export declare function buildAnchorFeatures(text: string, pieces: ReadonlyArray<TokenizedPiece>, lookup: AnchorLookup): {
57
55
  features: number[][];
@@ -1 +1 @@
1
- {"version":3,"file":"anchor-inference.d.ts","sourceRoot":"","sources":["../anchor-inference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD;;;;GAIG;AACH,eAAO,MAAM,YAAY,iEAAkE,CAAA;AAE3F,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB,QAA0B,CAAA;AAEzD,mGAAmG;AACnG,MAAM,WAAW,WAAW;IAC3B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACX;AAED,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;AAEnD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBzG;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAChC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAC7E,YAAY,CAId;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,EACrC,MAAM,EAAE,YAAY,GAClB;IAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CA0BhD"}
1
+ {"version":3,"file":"anchor-inference.d.ts","sourceRoot":"","sources":["../anchor-inference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD;;;GAGG;AACH,eAAO,MAAM,YAAY,iEAAkE,CAAA;AAE3F,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB,QAA0B,CAAA;AAEzD,mGAAmG;AACnG,MAAM,WAAW,WAAW;IAC3B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACX;AAED,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;AAEnD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAoBzG;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAC7E,YAAY,CAMd;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,EACrC,MAAM,EAAE,YAAY,GAClB;IAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CA+BhD"}
@@ -7,7 +7,7 @@
7
7
  * (`mailwoman_train/tokenizer.py::anchor_feature_vector` + `realign_anchor_to_pieces`). At
8
8
  * inference the model conditions on per-piece anchor features fed alongside `input_ids`; this
9
9
  * builds them from a raw address + its SentencePiece pieces, using the SAME postcode→anchor
10
- * lookup the model trained against (`scripts/build-pilot-anchor-lookup.py`), so the feature
10
+ * lookup the model trained against (`scripts/build-pilot-anchor-lookup.ts`), so the feature
11
11
  * layout matches byte-for-byte.
12
12
  *
13
13
  * The layout is ESSENTIAL and cross-language: a wrong locale order or centroid scale feeds the
@@ -15,17 +15,16 @@
15
15
  * emitted by the Python `anchor_feature_vector` — any drift fails the test.
16
16
  */
17
17
  /**
18
- * The locale class order — MUST match Python `mailwoman_train/labels.py::LOCALE_COUNTRIES`. The
19
- * posterior occupies indices `[0, LOCALE_ORDER.length)`; the normalized centroid the last two.
20
- * (Pinned by the test; do not reorder.)
18
+ * The locale class order — MUST match Python `mailwoman_train/labels.py::LOCALE_COUNTRIES`. The posterior occupies
19
+ * indices `[0, LOCALE_ORDER.length)`; the normalized centroid the last two. (Pinned by the test; do not reorder.)
21
20
  */
22
21
  export const LOCALE_ORDER = ["US", "FR", "DE", "CA", "GB", "JP", "ES", "IT", "NL"];
23
22
  /** Anchor feature width = posterior over the locale set + a 2-d centroid. */
24
23
  export const ANCHOR_FEATURE_DIM = LOCALE_ORDER.length + 2;
25
24
  /**
26
- * Build the fixed-width anchor feature vector — the exact mirror of Python `anchor_feature_vector`:
27
- * a uniform country posterior over {@linkcode LOCALE_ORDER} (renormalized over the in-set mass) + a
28
- * normalized centroid (`lat/90`, `lon/180` ∈ [-1, 1]).
25
+ * Build the fixed-width anchor feature vector — the exact mirror of Python `anchor_feature_vector`: a uniform country
26
+ * posterior over {@linkcode LOCALE_ORDER} (renormalized over the in-set mass) + a normalized centroid (`lat/90`,
27
+ * `lon/180` ∈ [-1, 1]).
29
28
  */
30
29
  export function anchorFeatureVector(posterior, lat, lon) {
31
30
  const vec = new Array(ANCHOR_FEATURE_DIM).fill(0);
@@ -46,11 +45,10 @@ export function anchorFeatureVector(posterior, lat, lon) {
46
45
  return vec;
47
46
  }
48
47
  /**
49
- * Parse the pilot postcode→anchor lookup JSON (`{postcode: [posterior, lat, lon, source?]}`) into a
50
- * Map. The optional trailing `source` is the centroid's provenance label (#525 — `"wof"`,
51
- * `"census-zcta-2024"`, or `null` for a placeholder); build-side bookkeeping, ignored at inference.
52
- * Pure (takes the parsed object, not a path) so this module stays browser-safe the file read
53
- * lives in the Node-side caller (the eval).
48
+ * Parse the pilot postcode→anchor lookup JSON (`{postcode: [posterior, lat, lon, source?]}`) into a Map. The optional
49
+ * trailing `source` is the centroid's provenance label (#525 — `"wof"`, `"census-zcta-2024"`, or `null` for a
50
+ * placeholder); build-side bookkeeping, ignored at inference. Pure (takes the parsed object, not a path) so this module
51
+ * stays browser-safe the file read lives in the Node-side caller (the eval).
54
52
  */
55
53
  export function parseAnchorLookup(raw) {
56
54
  const out = new Map();
@@ -59,13 +57,13 @@ export function parseAnchorLookup(raw) {
59
57
  return out;
60
58
  }
61
59
  /**
62
- * Per-piece anchor features + confidence for `text`, projected onto its SP `pieces` by the SAME
63
- * char→piece rule the labels use (a piece takes the anchor of the postcode span its first
64
- * non-whitespace char falls inside) — so the anchor lands on exactly the postcode's sub-tokens.
60
+ * Per-piece anchor features + confidence for `text`, projected onto its SP `pieces` by the SAME char→piece rule the
61
+ * labels use (a piece takes the anchor of the postcode span its first non-whitespace char falls inside) — so the anchor
62
+ * lands on exactly the postcode's sub-tokens.
65
63
  *
66
- * Postcode spans are the alphanumeric runs in `text` that the lookup recognizes (gold-equivalent on
67
- * clean rendered addresses); a recognized span yields a confidence-1.0 anchor, like training's
68
- * gold-span. Returns `(pieces × ANCHOR_FEATURE_DIM)` features + `(pieces,)` confidence.
64
+ * Postcode spans are the alphanumeric runs in `text` that the lookup recognizes (gold-equivalent on clean rendered
65
+ * addresses); a recognized span yields a confidence-1.0 anchor, like training's gold-span. Returns `(pieces ×
66
+ * ANCHOR_FEATURE_DIM)` features + `(pieces,)` confidence.
69
67
  */
70
68
  export function buildAnchorFeatures(text, pieces, lookup) {
71
69
  const features = pieces.map(() => new Array(ANCHOR_FEATURE_DIM).fill(0));
@@ -1 +1 @@
1
- {"version":3,"file":"anchor-inference.js","sourceRoot":"","sources":["../anchor-inference.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"anchor-inference.js","sourceRoot":"","sources":["../anchor-inference.ts"],"names":[],"mappings":"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"}
package/out/browser.js CHANGED
@@ -23,7 +23,7 @@ export * from "./postcode-binary-resolver.js";
23
23
  export * from "./gazetteer-inference.js";
24
24
  // Browser-safe soft-feature choreography (#718): the pure `buildSoftFeatures` that composes the
25
25
  // anchor + gazetteer channels (+ near-postcode suppression). No `fs`. The Node-only `./scorer` (which
26
- // constructs the OnnxRunner + reads the card/lookup/lexicon from disk) is deliberately NOT re-exported
26
+ // constructs the ONNXRunner + reads the card/lookup/lexicon from disk) is deliberately NOT re-exported
27
27
  // here.
28
28
  export * from "./soft-features.js";
29
29
  //# sourceMappingURL=browser.js.map
@@ -16,17 +16,22 @@
16
16
  * the model.
17
17
  */
18
18
  /**
19
- * True when `text` is PURE-ASCII ALL-CAPS: it has cased ASCII letters and ZERO lowercase, and NO
20
- * non-ASCII characters. The pure-ASCII requirement is deliberate — title-casing accented/non-Latin
21
- * text is locale-sensitive and can change length (`ß`→`SS`, Turkish dotted/dotless I), which would
22
- * break the token-offset invariant the caller relies on. So this fix targets ASCII registry data
23
- * only; accented or non-Latin input falls back to the model's current behavior. The 3-letter floor
24
- * avoids treating a digit/punctuation-only or tiny-token input as a whole shouting address.
19
+ * True when `text` is PURE-ASCII ALL-CAPS: it has cased ASCII letters and ZERO lowercase, and NO non-ASCII characters.
20
+ * The pure-ASCII requirement is deliberate — title-casing accented/non-Latin text is locale-sensitive and can change
21
+ * length (`ß`→`SS`, Turkish dotted/dotless I), which would break the token-offset invariant the caller relies on. So
22
+ * this fix targets ASCII registry data only; accented or non-Latin input falls back to the model's current behavior.
23
+ * The 3-letter floor avoids treating a digit/punctuation-only or tiny-token input as a whole shouting address.
25
24
  */
26
25
  export declare function isAllCapsInput(text: string): boolean;
27
26
  /**
28
- * Title-case each ASCII alphabetic run (`PALESTINE` → `Palestine`). Length-preserving token
29
- * offsets unchanged.
27
+ * Title-case each ASCII alphabetic run ≥3 letters (`PALESTINE` → `Palestine`), PRESERVING runs of ≤2 letters. The
28
+ * preserve is the #690→#252 fix (the Gauntlet's casing-invariance catch): an all-caps input title-cased BLINDLY turns a
29
+ * 2-letter region code into a non-region form the model mis-parses — `NY`→`Ny`, `DC`→`Dc` land as a _locality_, not a
30
+ * region, so `350 5TH AVE, NEW YORK, NY` lost its state. Every ≤2-letter all-caps token in a US address is an
31
+ * abbreviation the model already reads correctly all-caps (state codes NY/DC, directionals N/NW/SE, suffixes ST/RD), so
32
+ * keeping them shouting restores the model's correct input — `1600 PENNSYLVANIA AVE NW, WASHINGTON DC` now title-cases
33
+ * to exactly the mixed-case form that parses `region:DC`. Length-preserving — token offsets unchanged. The #690 benefit
34
+ * (≥3-letter locality/name recovery: PALESTINE→Palestine, ELKHART→Elkhart) is untouched.
30
35
  */
31
36
  export declare function titleCaseInput(text: string): string;
32
37
  /** Title-case the input iff it is all-caps; otherwise return it unchanged. The parser's #690 hook. */
@@ -1 +1 @@
1
- {"version":3,"file":"case-normalize.d.ts","sourceRoot":"","sources":["../case-normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CASpD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,sGAAsG;AACtG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD"}
1
+ {"version":3,"file":"case-normalize.d.ts","sourceRoot":"","sources":["../case-normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAgBpD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,sGAAsG;AACtG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD"}
@@ -16,32 +16,39 @@
16
16
  * the model.
17
17
  */
18
18
  /**
19
- * True when `text` is PURE-ASCII ALL-CAPS: it has cased ASCII letters and ZERO lowercase, and NO
20
- * non-ASCII characters. The pure-ASCII requirement is deliberate — title-casing accented/non-Latin
21
- * text is locale-sensitive and can change length (`ß`→`SS`, Turkish dotted/dotless I), which would
22
- * break the token-offset invariant the caller relies on. So this fix targets ASCII registry data
23
- * only; accented or non-Latin input falls back to the model's current behavior. The 3-letter floor
24
- * avoids treating a digit/punctuation-only or tiny-token input as a whole shouting address.
19
+ * True when `text` is PURE-ASCII ALL-CAPS: it has cased ASCII letters and ZERO lowercase, and NO non-ASCII characters.
20
+ * The pure-ASCII requirement is deliberate — title-casing accented/non-Latin text is locale-sensitive and can change
21
+ * length (`ß`→`SS`, Turkish dotted/dotless I), which would break the token-offset invariant the caller relies on. So
22
+ * this fix targets ASCII registry data only; accented or non-Latin input falls back to the model's current behavior.
23
+ * The 3-letter floor avoids treating a digit/punctuation-only or tiny-token input as a whole shouting address.
25
24
  */
26
25
  export function isAllCapsInput(text) {
27
26
  let upper = 0;
28
27
  for (let i = 0; i < text.length; i++) {
29
28
  const c = text.charCodeAt(i);
30
29
  if (c > 127)
31
- return false; // any non-ASCII (accented/non-Latin) → leave it alone
30
+ return false;
31
+ // any non-ASCII (accented/non-Latin) → leave it alone
32
32
  if (c >= 97 && c <= 122)
33
- return false; // any [a-z] → mixed case, leave it alone
33
+ return false;
34
+ // any [a-z] → mixed case, leave it alone
34
35
  if (c >= 65 && c <= 90)
35
36
  upper++;
36
37
  }
37
38
  return upper >= 3;
38
39
  }
39
40
  /**
40
- * Title-case each ASCII alphabetic run (`PALESTINE` → `Palestine`). Length-preserving token
41
- * offsets unchanged.
41
+ * Title-case each ASCII alphabetic run ≥3 letters (`PALESTINE` → `Palestine`), PRESERVING runs of ≤2 letters. The
42
+ * preserve is the #690→#252 fix (the Gauntlet's casing-invariance catch): an all-caps input title-cased BLINDLY turns a
43
+ * 2-letter region code into a non-region form the model mis-parses — `NY`→`Ny`, `DC`→`Dc` land as a _locality_, not a
44
+ * region, so `350 5TH AVE, NEW YORK, NY` lost its state. Every ≤2-letter all-caps token in a US address is an
45
+ * abbreviation the model already reads correctly all-caps (state codes NY/DC, directionals N/NW/SE, suffixes ST/RD), so
46
+ * keeping them shouting restores the model's correct input — `1600 PENNSYLVANIA AVE NW, WASHINGTON DC` now title-cases
47
+ * to exactly the mixed-case form that parses `region:DC`. Length-preserving — token offsets unchanged. The #690 benefit
48
+ * (≥3-letter locality/name recovery: PALESTINE→Palestine, ELKHART→Elkhart) is untouched.
42
49
  */
43
50
  export function titleCaseInput(text) {
44
- return text.replace(/[A-Za-z]+/g, (w) => w[0].toUpperCase() + w.slice(1).toLowerCase());
51
+ return text.replace(/[A-Za-z]+/g, (w) => (w.length <= 2 ? w : w[0].toUpperCase() + w.slice(1).toLowerCase()));
45
52
  }
46
53
  /** Title-case the input iff it is all-caps; otherwise return it unchanged. The parser's #690 hook. */
47
54
  export function normalizeInputCase(text) {
@@ -1 +1 @@
1
- {"version":3,"file":"case-normalize.js","sourceRoot":"","sources":["../case-normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QAC5B,IAAI,CAAC,GAAG,GAAG;YAAE,OAAO,KAAK,CAAA,CAAC,sDAAsD;QAChF,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG;YAAE,OAAO,KAAK,CAAA,CAAC,yCAAyC;QAC/E,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE,CAAA;IAChC,CAAC;IACD,OAAO,KAAK,IAAI,CAAC,CAAA;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;AACzF,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC9C,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC1D,CAAC"}
1
+ {"version":3,"file":"case-normalize.js","sourceRoot":"","sources":["../case-normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,IAAI,KAAK,GAAG,CAAC,CAAA;IAEb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QAE5B,IAAI,CAAC,GAAG,GAAG;YAAE,OAAO,KAAK,CAAA;QAEzB,sDAAsD;QACtD,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG;YAAE,OAAO,KAAK,CAAA;QAErC,yCAAyC;QACzC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE,CAAA;IAChC,CAAC;IAED,OAAO,KAAK,IAAI,CAAC,CAAA;AAClB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;AAC/G,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC9C,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC1D,CAAC"}