@mailwoman/corpus 7.2.0 → 7.2.1

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 (103) hide show
  1. package/package.json +59 -27
  2. package/src/adapter.ts +153 -0
  3. package/src/adapters/ban/adapter.ts +189 -0
  4. package/src/adapters/ban/street-decompose.ts +98 -0
  5. package/src/adapters/fcc-bdc/adapter.ts +188 -0
  6. package/src/adapters/geonames/adapter.ts +185 -0
  7. package/src/adapters/geonames-postal/adapter.ts +111 -0
  8. package/src/adapters/gnaf/adapter.ts +139 -0
  9. package/src/adapters/gnaf/assemble.ts +200 -0
  10. package/src/adapters/index.ts +135 -0
  11. package/src/adapters/openaddresses/adapter.ts +237 -0
  12. package/src/adapters/overture/adapter.ts +149 -0
  13. package/src/adapters/state-hi-schools/adapter.ts +171 -0
  14. package/src/adapters/state-ia-contractors/adapter.ts +148 -0
  15. package/src/adapters/state-ny-notaries/adapter.ts +169 -0
  16. package/src/adapters/state-tx-notaries/adapter.ts +160 -0
  17. package/src/adapters/synth-po-box/adapter.ts +197 -0
  18. package/src/adapters/tiger/adapter.ts +232 -0
  19. package/src/adapters/tiger/street-decompose.ts +120 -0
  20. package/src/adapters/usgov-hrsa-fqhc/adapter.ts +189 -0
  21. package/src/adapters/usgov-imls-pls/adapter.ts +152 -0
  22. package/src/adapters/usgov-irs-bmf/adapter.ts +155 -0
  23. package/src/adapters/usgov-nad/adapter.ts +338 -0
  24. package/src/adapters/usgov-nppes/adapter.ts +169 -0
  25. package/src/adapters/usgov-samhsa-treatment-locator/adapter.ts +211 -0
  26. package/src/adapters/wof-admin-jp/adapter.ts +176 -0
  27. package/src/adapters/wof-admin-json/adapter.ts +280 -0
  28. package/src/adapters/wof-postalcode-json/adapter.ts +209 -0
  29. package/src/align.ts +317 -0
  30. package/src/build.ts +348 -0
  31. package/src/codex/us-fips-state.ts +109 -0
  32. package/src/format.ts +14 -0
  33. package/src/golden.ts +147 -0
  34. package/src/index.ts +28 -0
  35. package/src/license.ts +48 -0
  36. package/src/parquet-wrapper/index.ts +9 -0
  37. package/src/parquet-wrapper/reader.ts +67 -0
  38. package/src/parquet-wrapper/schema.ts +80 -0
  39. package/src/parquet-wrapper/writer.ts +102 -0
  40. package/src/parquet.ts +360 -0
  41. package/src/runner.ts +283 -0
  42. package/src/shard-recipes/anchor-absorption.ts +86 -0
  43. package/src/shard-recipes/boundary-stress.ts +87 -0
  44. package/src/shard-recipes/country-balanced.ts +471 -0
  45. package/src/shard-recipes/cz-pcfirst-preposition.ts +83 -0
  46. package/src/shard-recipes/fr-admin-split.ts +212 -0
  47. package/src/shard-recipes/fr-bare-street.ts +85 -0
  48. package/src/shard-recipes/fr-fragment.ts +304 -0
  49. package/src/shard-recipes/fr-order.ts +283 -0
  50. package/src/shard-recipes/german.ts +206 -0
  51. package/src/shard-recipes/house-venue.ts +78 -0
  52. package/src/shard-recipes/index.ts +76 -0
  53. package/src/shard-recipes/intersection.ts +617 -0
  54. package/src/shard-recipes/locale.ts +415 -0
  55. package/src/shard-recipes/nl-postcode.ts +105 -0
  56. package/src/shard-recipes/no-fragment.ts +206 -0
  57. package/src/shard-recipes/no-street-led.ts +130 -0
  58. package/src/shard-recipes/no-street.ts +78 -0
  59. package/src/shard-recipes/po-box-cedex.ts +853 -0
  60. package/src/shard-recipes/po-box.ts +111 -0
  61. package/src/shard-recipes/scaffold.ts +187 -0
  62. package/src/shard-recipes/si-bare-village.ts +88 -0
  63. package/src/shard-recipes/street-affix.ts +549 -0
  64. package/src/shard-recipes/street-bare.ts +90 -0
  65. package/src/shard-recipes/street.ts +74 -0
  66. package/src/shard-recipes/unit.ts +315 -0
  67. package/src/split.ts +251 -0
  68. package/src/synthesize-anchor-absorption.ts +263 -0
  69. package/src/synthesize-boundary-stress.ts +504 -0
  70. package/src/synthesize-german.ts +227 -0
  71. package/src/synthesize-house-venue.ts +192 -0
  72. package/src/synthesize-intersection.ts +205 -0
  73. package/src/synthesize-no-street.ts +341 -0
  74. package/src/synthesize-po-box.ts +307 -0
  75. package/src/synthesize-street.ts +264 -0
  76. package/src/synthesize.ts +872 -0
  77. package/src/tokenize.ts +68 -0
  78. package/src/tools/align-shard.ts +67 -0
  79. package/src/tools/audit.ts +352 -0
  80. package/src/tools/corpus-stats.ts +183 -0
  81. package/src/tools/fetch/ban.ts +288 -0
  82. package/src/tools/fetch/download.ts +119 -0
  83. package/src/tools/fetch/hrsa.ts +65 -0
  84. package/src/tools/fetch/imls-pls.ts +162 -0
  85. package/src/tools/fetch/index.ts +121 -0
  86. package/src/tools/fetch/nad.ts +304 -0
  87. package/src/tools/fetch/nppes.ts +177 -0
  88. package/src/tools/fetch/openaddresses.ts +380 -0
  89. package/src/tools/fetch/state-hi-schools.ts +217 -0
  90. package/src/tools/fetch/state-sources.ts +142 -0
  91. package/src/tools/fetch/tiger-full.ts +318 -0
  92. package/src/tools/golden-expand.ts +524 -0
  93. package/src/tools/golden-promote.ts +304 -0
  94. package/src/tools/index.ts +24 -0
  95. package/src/tools/ingest-csv.ts +420 -0
  96. package/src/tools/jsonl-to-parquet.ts +200 -0
  97. package/src/tools/lint-shard-vocab.ts +357 -0
  98. package/src/tools/lint-shard.ts +502 -0
  99. package/src/tools/overlay-manifest.ts +141 -0
  100. package/src/tools/shard-kryptonite.ts +131 -0
  101. package/src/tools/shard-translit.ts +244 -0
  102. package/src/types.ts +213 -0
  103. package/src/wof-json.ts +236 -0
@@ -0,0 +1,264 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Street-decomposition synthesizer for Stage 3 training. Generates address rows where
7
+ * `street_prefix`, `street`, and `street_suffix` are emitted as separate BIO spans (instead of
8
+ * monolithic `street`). Mirrors the PO box synthesizer pattern.
9
+ *
10
+ * Why this exists: TIGER/NAD/BAN adapter changes (committed earlier tonight) emit decomposed
11
+ * components from raw source data, but the v0.4.0 parquet shards on Modal were built BEFORE those
12
+ * changes. Rebuilding the full corpus requires downloading raw TIGER/NAD/BAN data and re-running
13
+ * adapters end-to-end — out of scope for a single night shift. This synthesizer takes (locality,
14
+ * region, postcode) tuples and produces freshly-decomposed Stage 3 training rows, same shape as
15
+ * the PO box pipeline.
16
+ *
17
+ * Note: uses the SAME decomposition logic as TIGER's `decomposeStreet()` so the synthetic
18
+ * distribution matches what the model would see if/when TIGER shards are rebuilt with the new
19
+ * adapter.
20
+ */
21
+
22
+ import { decomposeStreet } from "./adapters/tiger/street-decompose.ts"
23
+ import type { CanonicalRow } from "./types.ts"
24
+
25
+ // Hand-curated US street name pool. Real frequency-weighted street names — sampled
26
+ // from US Census TIGER 2024 top-1000 by occurrence count. Keep ~50 entries so the
27
+ // synthesis distribution doesn't overfit to a tiny vocabulary.
28
+ const STREET_NAMES = [
29
+ "Main",
30
+ "Oak",
31
+ "Maple",
32
+ "Pine",
33
+ "Cedar",
34
+ "Elm",
35
+ "Washington",
36
+ "Lincoln",
37
+ "Jefferson",
38
+ "Park",
39
+ "Lake",
40
+ "Hill",
41
+ "Spring",
42
+ "Center",
43
+ "Church",
44
+ "Mill",
45
+ "School",
46
+ "River",
47
+ "Highland",
48
+ "Sunset",
49
+ "Forest",
50
+ "Meadow",
51
+ "Ridge",
52
+ "Valley",
53
+ "Lakeview",
54
+ "Hillcrest",
55
+ "1st",
56
+ "2nd",
57
+ "3rd",
58
+ "4th",
59
+ "5th",
60
+ "6th",
61
+ "7th",
62
+ "8th",
63
+ "9th",
64
+ "10th",
65
+ "Adams",
66
+ "Madison",
67
+ "Monroe",
68
+ "Jackson",
69
+ "Franklin",
70
+ "Kennedy",
71
+ "Roosevelt",
72
+ "Broadway",
73
+ "Market",
74
+ "Commerce",
75
+ "Industrial",
76
+ "Airport",
77
+ "Hospital",
78
+ "Sherman",
79
+ "Grant",
80
+ "Lee",
81
+ "Custer",
82
+ "Lewis",
83
+ "Clark",
84
+ ] as const
85
+
86
+ const STREET_SUFFIXES = [
87
+ "St",
88
+ "Street",
89
+ "Ave",
90
+ "Avenue",
91
+ "Rd",
92
+ "Road",
93
+ "Blvd",
94
+ "Boulevard",
95
+ "Dr",
96
+ "Drive",
97
+ "Ln",
98
+ "Lane",
99
+ "Way",
100
+ "Ct",
101
+ "Court",
102
+ "Pl",
103
+ "Place",
104
+ "Pkwy",
105
+ "Parkway",
106
+ "Ter",
107
+ "Terrace",
108
+ "Cir",
109
+ "Circle",
110
+ "Hwy",
111
+ "Highway",
112
+ ] as const
113
+
114
+ const DIRECTIONAL_PREFIXES = [
115
+ "",
116
+ "",
117
+ "",
118
+ "",
119
+ "", // 5 empty entries → 50% no prefix
120
+ "N",
121
+ "S",
122
+ "E",
123
+ "W",
124
+ "NE",
125
+ "NW",
126
+ "SE",
127
+ "SW",
128
+ "North",
129
+ "South",
130
+ "East",
131
+ "West",
132
+ ] as const
133
+
134
+ const TRAILING_DIRECTIONALS = [
135
+ "",
136
+ "",
137
+ "",
138
+ "",
139
+ "",
140
+ "",
141
+ "",
142
+ "", // 8 empty → 80% no trailing
143
+ "N",
144
+ "S",
145
+ "E",
146
+ "W",
147
+ "NE",
148
+ "NW",
149
+ "SE",
150
+ "SW",
151
+ ] as const
152
+
153
+ export interface StreetBaseTuple {
154
+ locality: string
155
+ region: string
156
+ postcode: string
157
+ country: string
158
+ }
159
+
160
+ export interface SynthesizedStreetRow {
161
+ raw: string
162
+ components: CanonicalRow["components"]
163
+ locale: string
164
+ }
165
+
166
+ export interface StreetSynthesisOpts {
167
+ random?: () => number
168
+ /** Probability of emitting house_number alongside the street. Default 0.85. */
169
+ includeHouseNumberProb?: number
170
+ /**
171
+ * Probability of emitting the street BARE — no `, City, ST ZIP` tail and no region/locality/ postcode components
172
+ * (just `street_prefix`/`street`/`street_suffix` + optional `house_number`). Default 0 (preserves the original
173
+ * full-address behavior exactly, including the RNG sequence). Set >0 to teach the model that a bare `10th Ave` /
174
+ * `Main St` is a STREET, not a locality — the functional-test failure cluster (bare streets mislabeled `locality`),
175
+ * the bare-format analogue of the v0.7.x intersection-bare fix.
176
+ */
177
+ bareProb?: number
178
+ }
179
+
180
+ function pick<T>(arr: ReadonlyArray<T>, random: () => number): T {
181
+ return arr[Math.floor(random() * arr.length)]!
182
+ }
183
+
184
+ function randomHouseNumber(random: () => number): string {
185
+ // US house number distribution: skewed low. 1-99 (30%), 100-999 (40%),
186
+ // 1000-9999 (25%), 10000+ (5%).
187
+ const r = random()
188
+
189
+ if (r < 0.3) return String(1 + Math.floor(random() * 99))
190
+
191
+ if (r < 0.7) return String(100 + Math.floor(random() * 900))
192
+
193
+ if (r < 0.95) return String(1000 + Math.floor(random() * 9000))
194
+
195
+ return String(10000 + Math.floor(random() * 89999))
196
+ }
197
+
198
+ /**
199
+ * Synthesize a US street address with decomposed Stage 3 components. The street is built from PREFIX + NAME + SUFFIX,
200
+ * then passed through the same `decomposeStreet()` utility the TIGER adapter uses — guarantees the synthetic
201
+ * distribution matches the canonical decomposition logic.
202
+ */
203
+ export function synthesizeStreetRow(
204
+ base: StreetBaseTuple,
205
+ opts: StreetSynthesisOpts = {}
206
+ ): SynthesizedStreetRow | null {
207
+ const random = opts.random ?? Math.random
208
+ const includeHN = opts.includeHouseNumberProb ?? 0.85
209
+
210
+ if (base.country !== "US") return null
211
+
212
+ const prefix = pick(DIRECTIONAL_PREFIXES, random)
213
+ const name = pick(STREET_NAMES, random)
214
+ const suffix = pick(STREET_SUFFIXES, random)
215
+ const trailing = pick(TRAILING_DIRECTIONALS, random)
216
+
217
+ // Build the "full" street string the adapter would receive from TIGER FULLNAME.
218
+ const parts = [prefix, name, suffix, trailing].filter(Boolean)
219
+ const fullStreet = parts.join(" ")
220
+
221
+ // Pass through the same decomposeStreet TIGER uses — match the training distribution.
222
+ const decomposed = decomposeStreet(fullStreet)
223
+
224
+ // NOTE: country is intentionally omitted. We don't emit "USA" or "US" in the raw
225
+ // string, and the aligner's fuzzy match (edit distance 2) will spuriously match
226
+ // "US" against any 2-char token (e.g. a house number "45" is exactly 2 substitutions
227
+ // from "US"). The PO box synthesizer skips country for the same reason.
228
+ // Bare mode is guarded by `> 0` so the default (bareProb=0) consumes no RNG and reproduces the
229
+ // original full-address output byte-for-byte.
230
+ const bareProb = opts.bareProb ?? 0
231
+ const bare = bareProb > 0 && random() < bareProb
232
+
233
+ const components: CanonicalRow["components"] = bare
234
+ ? {}
235
+ : {
236
+ region: base.region,
237
+ locality: base.locality,
238
+ postcode: base.postcode,
239
+ }
240
+
241
+ if (decomposed.prefix) {
242
+ components.street_prefix = decomposed.prefix
243
+ }
244
+
245
+ if (decomposed.street) {
246
+ components.street = decomposed.street
247
+ }
248
+
249
+ if (decomposed.suffix) {
250
+ components.street_suffix = decomposed.suffix
251
+ }
252
+
253
+ let raw: string
254
+
255
+ if (random() < includeHN) {
256
+ const hn = randomHouseNumber(random)
257
+ components.house_number = hn
258
+ raw = bare ? `${hn} ${fullStreet}` : `${hn} ${fullStreet}, ${base.locality}, ${base.region} ${base.postcode}`
259
+ } else {
260
+ raw = bare ? fullStreet : `${fullStreet}, ${base.locality}, ${base.region} ${base.postcode}`
261
+ }
262
+
263
+ return { raw, components, locale: "en-US" }
264
+ }