@mailwoman/corpus 8.3.0 → 8.4.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.
@@ -1 +1 @@
1
- {"version":3,"file":"synthesize-house-venue.d.ts","sourceRoot":"","sources":["../../src/synthesize-house-venue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,kBAAkB,GAC3B,oBAAoB,GACpB,qBAAqB,CAAA;AAIxB,MAAM,WAAW,uBAAuB;IACvC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,kBAAkB,CAAA;CAClC;AAED,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,CAAA;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,kBAAkB,CAAA;CAC5B;AA4GD,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,mBAAmB,EACzB,IAAI,GAAE,uBAA4B,GAChC,wBAAwB,GAAG,IAAI,CAqCjC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,GAAG,OAAO,CAEtF"}
1
+ {"version":3,"file":"synthesize-house-venue.d.ts","sourceRoot":"","sources":["../../src/synthesize-house-venue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,kBAAkB,GAC3B,oBAAoB,GACpB,qBAAqB,CAAA;AAIxB,MAAM,WAAW,uBAAuB;IACvC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,kBAAkB,CAAA;CAClC;AAED,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,CAAA;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,kBAAkB,CAAA;CAC5B;AAkLD,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,mBAAmB,EACzB,IAAI,GAAE,uBAA4B,GAChC,wBAAwB,GAAG,IAAI,CAmEjC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,GAAG,OAAO,CAEtF"}
@@ -65,6 +65,42 @@ const PLAIN_VENUES = [
65
65
  "Pinecrest Veterinary",
66
66
  "Westwood Realty",
67
67
  ];
68
+ /**
69
+ * GB-flavored venue names (#1366): institutional forms (Club/Centre/House/Arms/Station), the "Ye" archaic register, and
70
+ * brand–dash–place compounds — INCLUDING directional-led names, because the target class is venues that open with
71
+ * compass words ("New North Health Centre", "Southfields Station") and the base model reads those as locality/street
72
+ * evidence. The six #1366 gauntlet fixtures' own venue names are deliberately ABSENT — the fixtures stay held-out.
73
+ */
74
+ const GB_VENUES = [
75
+ "Ye Olde Cheshire Cheese",
76
+ "Ye Old Mitre",
77
+ "The Red Lion",
78
+ "The Crown & Anchor",
79
+ "The King's Arms",
80
+ "The White Hart",
81
+ "The Royal Oak",
82
+ "North End Road Market",
83
+ "Northfields Community Centre",
84
+ "South Bank Tavern",
85
+ "Southgate Dental Practice",
86
+ "West End Barbers",
87
+ "East Street Pharmacy",
88
+ "New Cross Learning Centre",
89
+ "Old Street Works",
90
+ "Upper Crust - Waterloo",
91
+ "Pret a Manger - Leadenhall",
92
+ "Greggs - Camden High Street",
93
+ "The Ivy - Chelsea Garden",
94
+ "Marks & Spencer Simply Food",
95
+ "Chapel Market Fishmongers",
96
+ "Victoria Coach Station",
97
+ "Highbury Fields Tennis Club",
98
+ "The Carpenters Arms",
99
+ "St Bride's Institute",
100
+ "Albion House",
101
+ "Imperial Dry Cleaners",
102
+ "Golden Dragon 金龍饭店",
103
+ ];
68
104
  //#endregion
69
105
  //#region Fallback street pool
70
106
  /**
@@ -120,26 +156,81 @@ function countryToLocale(country) {
120
156
  }
121
157
  //#endregion
122
158
  //#region Synthesis
159
+ /**
160
+ * Fraction of GB rows drawing from {@link GB_VENUES} instead of the shared pool. 0.7 mirrors the register mix in real
161
+ * GB listings data (institutional names dominate, international/generic names still appear) — pre-registered in the
162
+ * #1366 memo.
163
+ */
164
+ const GB_VENUE_POOL_RATE = 0.7;
165
+ /**
166
+ * Fraction of GB rows whose house number widens into a range ("287-293"). Real GB venue addresses frequently span
167
+ * buildings; 0.15 keeps ranges a minority register — pre-registered in the #1366 memo.
168
+ */
169
+ const GB_RANGE_NUMBER_RATE = 0.15;
170
+ /**
171
+ * Fraction of rows (EVERY template order) rendered with a trailing country surface, tagged `country`. The 2026-08-01
172
+ * operator probe set proved the mechanism: the FR control row ("…, 75004 Paris, France") fails on a model trained only
173
+ * on country-less venue rows while its country-less twin passes — a trailing country makes the whole template OOD
174
+ * (Addendum 3 of the #1366 pre-registration). 0.3 keeps the country-less register dominant.
175
+ */
176
+ const COUNTRY_APPEND_RATE = 0.3;
177
+ /**
178
+ * Trailing country surfaces by tuple country — the register mixes formal and short forms where both are common.
179
+ */
180
+ const COUNTRY_SURFACES = {
181
+ US: ["United States", "USA"],
182
+ GB: ["United Kingdom", "United Kingdom", "United Kingdom", "UK"],
183
+ FR: ["France"],
184
+ CA: ["Canada"],
185
+ AU: ["Australia"],
186
+ DE: ["Germany", "Deutschland"],
187
+ };
123
188
  export function synthesizeHouseVenueRow(base, opts = {}) {
124
189
  const random = opts.random ?? Math.random;
125
190
  const locale = countryToLocale(base.country);
126
191
  const template = opts.forceTemplate ?? (random() < 0.5 ? "venue-after-street" : "venue-before-street");
127
- const venue = pick(PLAIN_VENUES, random);
128
- const street = base.street ?? pick(FALLBACK_STREETS, random);
129
- const houseNumber = base.houseNumber ?? randomHouseNumber(random);
130
192
  // FR renders postcode-before-locality with NO region ("MR & MRS CRAB, 20 Rue de la Huchette,
131
193
  // 75005 Paris" — the v4.0.0 gauntlet's venue-led failure family, the run-2 contingency's exact
132
- // target shape). Every other country keeps the original US-order tail.
194
+ // target shape). GB (#1366) renders locality-then-postcode with NO region and NO comma between
195
+ // them ("Ye Three Lords, 27 Minories, London EC3N 1DE" — the third tail the shard must teach).
196
+ // Every other country keeps the original US-order tail.
133
197
  const frOrder = base.country === "FR";
198
+ const gbOrder = base.country === "GB";
199
+ // GB rows draw from the GB pool 70% of the time (institutional/archaic/brand-dash-place forms,
200
+ // incl. directional-led names — the #1366 target class) and the shared pool otherwise; real GB
201
+ // registers mix both. Other locales keep the shared pool (which already carries the FR flavor).
202
+ const venue = gbOrder && random() < GB_VENUE_POOL_RATE ? pick(GB_VENUES, random) : pick(PLAIN_VENUES, random);
203
+ const street = base.street ?? pick(FALLBACK_STREETS, random);
204
+ let houseNumber = base.houseNumber ?? randomHouseNumber(random);
205
+ // GB range numbers ("287-293 New N Rd"): real GB venue addresses frequently span buildings.
206
+ // 15% of GB rows widen the number into a range (same parity, small span — the register's real
207
+ // shape). Pre-registered in the #1366 memo; the base pool's no-ranges stance stays for other
208
+ // locales.
209
+ if (gbOrder && random() < GB_RANGE_NUMBER_RATE && /^\d+$/.test(houseNumber)) {
210
+ const start = Number.parseInt(houseNumber, 10);
211
+ const span = (1 + Math.floor(random() * 4)) * 2;
212
+ houseNumber = `${start}-${start + span}`;
213
+ }
134
214
  const components = {
135
215
  house_number: houseNumber,
136
216
  street,
137
217
  venue,
138
218
  locality: base.locality,
139
- ...(frOrder ? {} : { region: base.region }),
219
+ ...(frOrder || gbOrder ? {} : { region: base.region }),
140
220
  postcode: base.postcode,
141
221
  };
142
- const tail = frOrder ? `${base.postcode} ${base.locality}` : `${base.locality}, ${base.region} ${base.postcode}`;
222
+ let tail = frOrder
223
+ ? `${base.postcode} ${base.locality}`
224
+ : gbOrder
225
+ ? `${base.locality} ${base.postcode}`
226
+ : `${base.locality}, ${base.region} ${base.postcode}`;
227
+ // Trailing country surface (Addendum 3): appended AFTER the tail in every order, tagged.
228
+ const countrySurfaces = COUNTRY_SURFACES[base.country];
229
+ if (countrySurfaces && random() < COUNTRY_APPEND_RATE) {
230
+ const countrySurface = pick(countrySurfaces, random);
231
+ components.country = countrySurface;
232
+ tail = `${tail}, ${countrySurface}`;
233
+ }
143
234
  let raw;
144
235
  switch (template) {
145
236
  case "venue-after-street":
@@ -1 +1 @@
1
- {"version":3,"file":"synthesize-house-venue.js","sourceRoot":"","sources":["../../src/synthesize-house-venue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"synthesize-house-venue.js","sourceRoot":"","sources":["../../src/synthesize-house-venue.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mailwoman/corpus",
3
- "version": "8.3.0",
3
+ "version": "8.4.0",
4
4
  "description": "Mailwoman corpus pipeline: BIO-labeled dataset builder for the neural classifier.",
5
5
  "license": "AGPL-3.0-only OR LicenseRef-Commercial",
6
6
  "repository": {
@@ -91,10 +91,10 @@
91
91
  },
92
92
  "dependencies": {
93
93
  "@dsnp/parquetjs": "1.8.9",
94
- "@mailwoman/ban": "8.3.0",
95
- "@mailwoman/codex": "8.3.0",
96
- "@mailwoman/core": "8.3.0",
97
- "@mailwoman/formatter": "8.3.0",
94
+ "@mailwoman/ban": "8.4.0",
95
+ "@mailwoman/codex": "8.4.0",
96
+ "@mailwoman/core": "8.4.0",
97
+ "@mailwoman/formatter": "8.4.0",
98
98
  "csv-parse": "^7.0.1",
99
99
  "fast-glob": "^3.3.3",
100
100
  "fastest-levenshtein": "^1.0.16",
@@ -97,6 +97,43 @@ const PLAIN_VENUES: ReadonlyArray<string> = [
97
97
  "Westwood Realty",
98
98
  ]
99
99
 
100
+ /**
101
+ * GB-flavored venue names (#1366): institutional forms (Club/Centre/House/Arms/Station), the "Ye" archaic register, and
102
+ * brand–dash–place compounds — INCLUDING directional-led names, because the target class is venues that open with
103
+ * compass words ("New North Health Centre", "Southfields Station") and the base model reads those as locality/street
104
+ * evidence. The six #1366 gauntlet fixtures' own venue names are deliberately ABSENT — the fixtures stay held-out.
105
+ */
106
+ const GB_VENUES: ReadonlyArray<string> = [
107
+ "Ye Olde Cheshire Cheese",
108
+ "Ye Old Mitre",
109
+ "The Red Lion",
110
+ "The Crown & Anchor",
111
+ "The King's Arms",
112
+ "The White Hart",
113
+ "The Royal Oak",
114
+ "North End Road Market",
115
+ "Northfields Community Centre",
116
+ "South Bank Tavern",
117
+ "Southgate Dental Practice",
118
+ "West End Barbers",
119
+ "East Street Pharmacy",
120
+ "New Cross Learning Centre",
121
+ "Old Street Works",
122
+ "Upper Crust - Waterloo",
123
+ "Pret a Manger - Leadenhall",
124
+ "Greggs - Camden High Street",
125
+ "The Ivy - Chelsea Garden",
126
+ "Marks & Spencer Simply Food",
127
+ "Chapel Market Fishmongers",
128
+ "Victoria Coach Station",
129
+ "Highbury Fields Tennis Club",
130
+ "The Carpenters Arms",
131
+ "St Bride's Institute",
132
+ "Albion House",
133
+ "Imperial Dry Cleaners",
134
+ "Golden Dragon 金龍饭店",
135
+ ]
136
+
100
137
  //#endregion
101
138
 
102
139
  //#region Fallback street pool
@@ -163,6 +200,39 @@ function countryToLocale(country: string): string {
163
200
 
164
201
  //#region Synthesis
165
202
 
203
+ /**
204
+ * Fraction of GB rows drawing from {@link GB_VENUES} instead of the shared pool. 0.7 mirrors the register mix in real
205
+ * GB listings data (institutional names dominate, international/generic names still appear) — pre-registered in the
206
+ * #1366 memo.
207
+ */
208
+ const GB_VENUE_POOL_RATE = 0.7
209
+
210
+ /**
211
+ * Fraction of GB rows whose house number widens into a range ("287-293"). Real GB venue addresses frequently span
212
+ * buildings; 0.15 keeps ranges a minority register — pre-registered in the #1366 memo.
213
+ */
214
+ const GB_RANGE_NUMBER_RATE = 0.15
215
+
216
+ /**
217
+ * Fraction of rows (EVERY template order) rendered with a trailing country surface, tagged `country`. The 2026-08-01
218
+ * operator probe set proved the mechanism: the FR control row ("…, 75004 Paris, France") fails on a model trained only
219
+ * on country-less venue rows while its country-less twin passes — a trailing country makes the whole template OOD
220
+ * (Addendum 3 of the #1366 pre-registration). 0.3 keeps the country-less register dominant.
221
+ */
222
+ const COUNTRY_APPEND_RATE = 0.3
223
+
224
+ /**
225
+ * Trailing country surfaces by tuple country — the register mixes formal and short forms where both are common.
226
+ */
227
+ const COUNTRY_SURFACES: Readonly<Record<string, ReadonlyArray<string>>> = {
228
+ US: ["United States", "USA"],
229
+ GB: ["United Kingdom", "United Kingdom", "United Kingdom", "UK"],
230
+ FR: ["France"],
231
+ CA: ["Canada"],
232
+ AU: ["Australia"],
233
+ DE: ["Germany", "Deutschland"],
234
+ }
235
+
166
236
  export function synthesizeHouseVenueRow(
167
237
  base: HouseVenueBaseTuple,
168
238
  opts: HouseVenueSynthesisOpts = {}
@@ -171,25 +241,55 @@ export function synthesizeHouseVenueRow(
171
241
  const locale = countryToLocale(base.country)
172
242
  const template = opts.forceTemplate ?? (random() < 0.5 ? "venue-after-street" : "venue-before-street")
173
243
 
174
- const venue = pick(PLAIN_VENUES, random)
175
- const street = base.street ?? pick(FALLBACK_STREETS, random)
176
- const houseNumber = base.houseNumber ?? randomHouseNumber(random)
177
-
178
244
  // FR renders postcode-before-locality with NO region ("MR & MRS CRAB, 20 Rue de la Huchette,
179
245
  // 75005 Paris" — the v4.0.0 gauntlet's venue-led failure family, the run-2 contingency's exact
180
- // target shape). Every other country keeps the original US-order tail.
246
+ // target shape). GB (#1366) renders locality-then-postcode with NO region and NO comma between
247
+ // them ("Ye Three Lords, 27 Minories, London EC3N 1DE" — the third tail the shard must teach).
248
+ // Every other country keeps the original US-order tail.
181
249
  const frOrder = base.country === "FR"
250
+ const gbOrder = base.country === "GB"
251
+
252
+ // GB rows draw from the GB pool 70% of the time (institutional/archaic/brand-dash-place forms,
253
+ // incl. directional-led names — the #1366 target class) and the shared pool otherwise; real GB
254
+ // registers mix both. Other locales keep the shared pool (which already carries the FR flavor).
255
+ const venue = gbOrder && random() < GB_VENUE_POOL_RATE ? pick(GB_VENUES, random) : pick(PLAIN_VENUES, random)
256
+ const street = base.street ?? pick(FALLBACK_STREETS, random)
257
+ let houseNumber = base.houseNumber ?? randomHouseNumber(random)
258
+
259
+ // GB range numbers ("287-293 New N Rd"): real GB venue addresses frequently span buildings.
260
+ // 15% of GB rows widen the number into a range (same parity, small span — the register's real
261
+ // shape). Pre-registered in the #1366 memo; the base pool's no-ranges stance stays for other
262
+ // locales.
263
+ if (gbOrder && random() < GB_RANGE_NUMBER_RATE && /^\d+$/.test(houseNumber)) {
264
+ const start = Number.parseInt(houseNumber, 10)
265
+ const span = (1 + Math.floor(random() * 4)) * 2
266
+
267
+ houseNumber = `${start}-${start + span}`
268
+ }
182
269
 
183
270
  const components: CanonicalRow["components"] = {
184
271
  house_number: houseNumber,
185
272
  street,
186
273
  venue,
187
274
  locality: base.locality,
188
- ...(frOrder ? {} : { region: base.region }),
275
+ ...(frOrder || gbOrder ? {} : { region: base.region }),
189
276
  postcode: base.postcode,
190
277
  }
191
278
 
192
- const tail = frOrder ? `${base.postcode} ${base.locality}` : `${base.locality}, ${base.region} ${base.postcode}`
279
+ let tail = frOrder
280
+ ? `${base.postcode} ${base.locality}`
281
+ : gbOrder
282
+ ? `${base.locality} ${base.postcode}`
283
+ : `${base.locality}, ${base.region} ${base.postcode}`
284
+
285
+ // Trailing country surface (Addendum 3): appended AFTER the tail in every order, tagged.
286
+ const countrySurfaces = COUNTRY_SURFACES[base.country]
287
+
288
+ if (countrySurfaces && random() < COUNTRY_APPEND_RATE) {
289
+ const countrySurface = pick(countrySurfaces, random)
290
+ components.country = countrySurface
291
+ tail = `${tail}, ${countrySurface}`
292
+ }
193
293
 
194
294
  let raw: string
195
295