@mailwoman/corpus 6.3.0 → 6.5.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.
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `fr-fragment` shard recipe (#727 T2) — the HOUSE-NUMBER-LICENCE lever.
7
+ *
8
+ * The measured problem (T1c, `2026-07-16-t1c-fragment-board-verdict.md`): the shipped model scores
9
+ * **0.925** on `<n> Rue X` and **0.215** on `Rue X`. Same streets, same model; the only difference
10
+ * is a leading number. It has learned that a house number LICENSES a street reading at all — strip
11
+ * it and a designator-led phrase parses as a locality, designator included:
12
+ *
13
+ * ```
14
+ * "Rue Montmartre" -> locality="Rue Montmartre"
15
+ * "Allee Poque" -> locality="Allee Poque"
16
+ * ```
17
+ *
18
+ * `Rue` can only mean street in French. The model is not mislabelling an ambiguous toponym; it is
19
+ * mislabelling `Rue`.
20
+ *
21
+ * WHY THE EXISTING RECIPE DOESN'T COVER THIS. {@link frBareStreetRecipe} (#251) mints
22
+ * `<n> Rue <name>, <City>` — the bare COMMA form, no postcode. It targets postcode-anchoring
23
+ * imbalance, and every row it emits still carries a house number AND a locality. It cannot teach
24
+ * the class above, because it never shows the model a street standing alone.
25
+ *
26
+ * WHAT THIS MINTS. Five street forms — the first three carry NO house number and NO locality, which
27
+ * is the whole point — plus the counter-distribution:
28
+ *
29
+ * 1. `bare-street` "Rue Montmartre"
30
+ * 2. `street-particle` "Rue de la Paix"
31
+ * 3. `date-name` "Allee du 11 Novembre 1918"
32
+ * 4. `street-housenumber` "12 Rue Montmartre" — the anchor, so the licence isn't UNLEARNED
33
+ * 5. `alnum-housenumber` "12 bis Rue Montmartre"
34
+ * 6. `bare-locality` "Mery-sur-Oise" — NEGATIVE: a bare toponym that IS a locality
35
+ *
36
+ * The **admin/street homonym** class (`Rue de Rome`) is deliberately NOT a separate form. Homonym
37
+ * streets are already in the register and fall into 1–3 naturally; there is nothing different to
38
+ * teach about them, because the lesson is identical — the designator makes it a street. The
39
+ * fragment board scores them separately (they need measuring, not minting), and the recipe would
40
+ * need a second pass over the commune set to label them, buying a `synth_method` string and no
41
+ * training signal.
42
+ *
43
+ * FORM 7 IS NOT OPTIONAL. T1c's standing prediction: the board's `bare-locality` cell reads 0.980
44
+ * for the WRONG REASON — the model calls everything without a house number a locality, and on bare
45
+ * localities that is accidentally right. Teach bare streets alone and the model has every incentive
46
+ * to flip that default rather than learn the distinction, trading a 0.215 for a 0.980. The shard
47
+ * must show BOTH bare forms so the discriminating evidence is the designator, which is the only
48
+ * thing that actually distinguishes them. This is the same counter-distribution principle
49
+ * {@link noStreetRecipe} established after synth-street pushed the model into "decompose mode".
50
+ *
51
+ * SPLIT. `--exclude-surfaces` takes the fragment board's reserved surface list
52
+ * (`mailwoman/eval-harness/fixtures/ban-fragments-fr.surfaces.txt`). Every listed surface is
53
+ * skipped — source-disjoint by normalized street SURFACE, never by record row. Row-disjoint leaks
54
+ * the surface across the boundary and measures memorization of `Rue de Rivoli` while claiming
55
+ * generalization to unseen streets. The recipe REFUSES to run without the list rather than
56
+ * silently minting a contaminated shard.
57
+ *
58
+ * MIX. The shard is ~145K rows off a 120K-tuple draw; the intended corpus mix is **5–10%**, set at
59
+ * assembly time by shard weight rather than by row count. Keep the cap: a shard that fixes fragments
60
+ * by degrading full addresses has moved the failure, not fixed it — which is what
61
+ * `street-housenumber` / `alnum-housenumber` on the fragment board and the global parity floor are
62
+ * there to catch. `date-name` is ~0.5% of the shard because BAN only holds ~1,418 date-name streets
63
+ * after filtering and the tuple extractor already takes every one; if that class needs more, the
64
+ * lever is shard weight, not invented data.
65
+ *
66
+ * ⚠ Convention loss-mask: like {@link frBareStreetRecipe}, this recipe TEACHES FR `street_prefix`.
67
+ * The conventions loss-mask forbids it for FR and will `-inf` these gold labels (the v1.6.0 ~7M-loss
68
+ * blow-up). Disable that mask for any run including this shard.
69
+ */
70
+ import { type ShardRecipe } from "./scaffold.ts";
71
+ export declare function frTitleCase(value: string): string;
72
+ export declare const frFragmentRecipe: ShardRecipe;
73
+ //# sourceMappingURL=fr-fragment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fr-fragment.d.ts","sourceRoot":"","sources":["../../../src/shard-recipes/fr-fragment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAKH,OAAO,EAA6C,KAAK,WAAW,EAAiB,MAAM,eAAe,CAAA;AA4C1G,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAajD;AAQD,eAAO,MAAM,gBAAgB,EAAE,WAmK9B,CAAA"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `fr-fragment` shard recipe (#727 T2) — the HOUSE-NUMBER-LICENCE lever.
7
+ *
8
+ * The measured problem (T1c, `2026-07-16-t1c-fragment-board-verdict.md`): the shipped model scores
9
+ * **0.925** on `<n> Rue X` and **0.215** on `Rue X`. Same streets, same model; the only difference
10
+ * is a leading number. It has learned that a house number LICENSES a street reading at all — strip
11
+ * it and a designator-led phrase parses as a locality, designator included:
12
+ *
13
+ * ```
14
+ * "Rue Montmartre" -> locality="Rue Montmartre"
15
+ * "Allee Poque" -> locality="Allee Poque"
16
+ * ```
17
+ *
18
+ * `Rue` can only mean street in French. The model is not mislabelling an ambiguous toponym; it is
19
+ * mislabelling `Rue`.
20
+ *
21
+ * WHY THE EXISTING RECIPE DOESN'T COVER THIS. {@link frBareStreetRecipe} (#251) mints
22
+ * `<n> Rue <name>, <City>` — the bare COMMA form, no postcode. It targets postcode-anchoring
23
+ * imbalance, and every row it emits still carries a house number AND a locality. It cannot teach
24
+ * the class above, because it never shows the model a street standing alone.
25
+ *
26
+ * WHAT THIS MINTS. Five street forms — the first three carry NO house number and NO locality, which
27
+ * is the whole point — plus the counter-distribution:
28
+ *
29
+ * 1. `bare-street` "Rue Montmartre"
30
+ * 2. `street-particle` "Rue de la Paix"
31
+ * 3. `date-name` "Allee du 11 Novembre 1918"
32
+ * 4. `street-housenumber` "12 Rue Montmartre" — the anchor, so the licence isn't UNLEARNED
33
+ * 5. `alnum-housenumber` "12 bis Rue Montmartre"
34
+ * 6. `bare-locality` "Mery-sur-Oise" — NEGATIVE: a bare toponym that IS a locality
35
+ *
36
+ * The **admin/street homonym** class (`Rue de Rome`) is deliberately NOT a separate form. Homonym
37
+ * streets are already in the register and fall into 1–3 naturally; there is nothing different to
38
+ * teach about them, because the lesson is identical — the designator makes it a street. The
39
+ * fragment board scores them separately (they need measuring, not minting), and the recipe would
40
+ * need a second pass over the commune set to label them, buying a `synth_method` string and no
41
+ * training signal.
42
+ *
43
+ * FORM 7 IS NOT OPTIONAL. T1c's standing prediction: the board's `bare-locality` cell reads 0.980
44
+ * for the WRONG REASON — the model calls everything without a house number a locality, and on bare
45
+ * localities that is accidentally right. Teach bare streets alone and the model has every incentive
46
+ * to flip that default rather than learn the distinction, trading a 0.215 for a 0.980. The shard
47
+ * must show BOTH bare forms so the discriminating evidence is the designator, which is the only
48
+ * thing that actually distinguishes them. This is the same counter-distribution principle
49
+ * {@link noStreetRecipe} established after synth-street pushed the model into "decompose mode".
50
+ *
51
+ * SPLIT. `--exclude-surfaces` takes the fragment board's reserved surface list
52
+ * (`mailwoman/eval-harness/fixtures/ban-fragments-fr.surfaces.txt`). Every listed surface is
53
+ * skipped — source-disjoint by normalized street SURFACE, never by record row. Row-disjoint leaks
54
+ * the surface across the boundary and measures memorization of `Rue de Rivoli` while claiming
55
+ * generalization to unseen streets. The recipe REFUSES to run without the list rather than
56
+ * silently minting a contaminated shard.
57
+ *
58
+ * MIX. The shard is ~145K rows off a 120K-tuple draw; the intended corpus mix is **5–10%**, set at
59
+ * assembly time by shard weight rather than by row count. Keep the cap: a shard that fixes fragments
60
+ * by degrading full addresses has moved the failure, not fixed it — which is what
61
+ * `street-housenumber` / `alnum-housenumber` on the fragment board and the global parity floor are
62
+ * there to catch. `date-name` is ~0.5% of the shard because BAN only holds ~1,418 date-name streets
63
+ * after filtering and the tuple extractor already takes every one; if that class needs more, the
64
+ * lever is shard weight, not invented data.
65
+ *
66
+ * ⚠ Convention loss-mask: like {@link frBareStreetRecipe}, this recipe TEACHES FR `street_prefix`.
67
+ * The conventions loss-mask forbids it for FR and will `-inf` these gold labels (the v1.6.0 ~7M-loss
68
+ * blow-up). Disable that mask for any run including this shard.
69
+ */
70
+ import { readFileSync } from "node:fs";
71
+ import { decomposeFrStreet } from "../adapters/ban/street-decompose.js";
72
+ import { alignAndWrite, makeMulberry32, readTuples, shardSourceID } from "./scaffold.js";
73
+ /** House numbers, weighted toward the small values that dominate real BAN rows. */
74
+ const HOUSE_NUMBERS = [
75
+ 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 24, 27, 30, 33, 42, 57, 68, 84, 102, 115, 140,
76
+ ];
77
+ /** FR alphanumeric house-number forms. `bis`/`ter` are separated; a bare letter is suffixed. */
78
+ const ALNUM_SUFFIXES = ["bis", "ter", "A", "B"];
79
+ const norm = (value) => value
80
+ .normalize("NFD")
81
+ .replace(/[̀-ͯ]/g, "")
82
+ .toLowerCase()
83
+ .replace(/\s+/g, " ")
84
+ .trim();
85
+ /**
86
+ * French commune convention: capitalize each element, leave the joining particles lowercase. `saint-jean-de-luz` →
87
+ * `Saint-Jean-de-Luz`, not `Saint-Jean-De-Luz`.
88
+ *
89
+ * Needed because BAN's sharded DBs keep only `locality_base` — normalized, lowercase, accent-stripped. Emitting that
90
+ * verbatim would teach the counter-distribution that a lowercase accent-stripped string is a locality, which is not a
91
+ * fact about French and would not match the fragment board (which reconstructs the same casing). The accents are gone
92
+ * from the source and cannot be recovered here; the casing can.
93
+ */
94
+ const FR_LOWER = new Set([
95
+ "le",
96
+ "la",
97
+ "les",
98
+ "de",
99
+ "du",
100
+ "des",
101
+ "d",
102
+ "l",
103
+ "sur",
104
+ "sous",
105
+ "en",
106
+ "aux",
107
+ "au",
108
+ "et",
109
+ "lez",
110
+ ]);
111
+ export function frTitleCase(value) {
112
+ const cap = (token, first) => !first && FR_LOWER.has(token) ? token : token.charAt(0).toUpperCase() + token.slice(1);
113
+ return value
114
+ .split(" ")
115
+ .map((word, wordIndex) => word
116
+ .split("-")
117
+ .map((bit, bitIndex) => cap(bit, wordIndex === 0 && bitIndex === 0))
118
+ .join("-"))
119
+ .join(" ");
120
+ }
121
+ /** Does the street name carry a particle? Decides the particle vs bare classification. */
122
+ const PARTICLE = /\b(de la|de l'|du|des|de|d'|le|la|les)\b/i;
123
+ /** Does the street name carry date material (a year, or a day + French month)? */
124
+ const DATEISH = /\b(1[0-9]|20)\d{2}\b|\b\d{1,2}\s+(janvier|f[ée]vrier|mars|avril|mai|juin|juillet|ao[ûu]t|septembre|octobre|novembre|d[ée]cembre)\b/i;
125
+ export const frFragmentRecipe = {
126
+ name: "fr-fragment",
127
+ description: "FR street fragments with NO house number (#727 T2): the house-number-licence lever — bare/particle/date-name/homonym + the bare-locality counter",
128
+ mode: "tuples",
129
+ options: [
130
+ {
131
+ flag: "--exclude-surfaces <path>",
132
+ description: "REQUIRED. The fragment board's reserved surface list; every listed street is skipped.",
133
+ },
134
+ {
135
+ flag: "--hn-prob <n>",
136
+ description: "Share of rows carrying a house number (default 0.35 — the anchor, not the point)",
137
+ },
138
+ {
139
+ flag: "--bare-prob <n>",
140
+ description: "Share of NO-house-number rows that are bare LOCALITIES (default 0.25 — the counter)",
141
+ },
142
+ ],
143
+ async run(opts, write) {
144
+ const random = makeMulberry32(opts.seed);
145
+ const excludePath = opts.excludeSurfaces;
146
+ if (!excludePath) {
147
+ throw new Error("fr-fragment: --exclude-surfaces is REQUIRED. Pass the fragment board's reserved list " +
148
+ "(mailwoman/eval-harness/fixtures/ban-fragments-fr.surfaces.txt) or this shard trains on its own eval set. " +
149
+ "Source-disjoint by street SURFACE is the split discipline; there is no safe default.");
150
+ }
151
+ const excluded = new Set(readFileSync(excludePath, "utf8")
152
+ .split("\n")
153
+ .map((line) => line.trim())
154
+ .filter((line) => line && !line.startsWith("#")));
155
+ if (!excluded.size)
156
+ throw new Error(`fr-fragment: --exclude-surfaces "${excludePath}" listed no surfaces`);
157
+ const hnProb = opts.hnProb ?? 0.35;
158
+ const bareLocalityProb = opts.bareProb ?? 0.25;
159
+ // The locality pool is harvested from the tuples themselves — every BAN row carries its
160
+ // commune, so the counter-distribution needs no second source.
161
+ const localities = new Set();
162
+ let read = 0;
163
+ let emitted = 0;
164
+ let skipped = 0;
165
+ let contaminated = 0;
166
+ for await (const tuple of readTuples(opts.input)) {
167
+ read++;
168
+ const fullStreet = String(tuple.street ?? "").trim();
169
+ const locality = String(tuple.locality ?? "").trim();
170
+ if (locality)
171
+ localities.add(locality);
172
+ if (!fullStreet) {
173
+ skipped++;
174
+ continue;
175
+ }
176
+ // THE SPLIT. A surface on the fragment board never enters training.
177
+ if (excluded.has(norm(fullStreet))) {
178
+ contaminated++;
179
+ continue;
180
+ }
181
+ const { prefix, street } = decomposeFrStreet(fullStreet);
182
+ // The failing class is the designator-led street. A no-prefix nom_voie ("La Ville Mois")
183
+ // is a different problem and would muddy the signal.
184
+ if (!prefix || !street) {
185
+ skipped++;
186
+ continue;
187
+ }
188
+ const carriesNumber = random() < hnProb;
189
+ const components = { street_prefix: prefix, street };
190
+ let raw = `${prefix} ${street}`;
191
+ let klass = DATEISH.test(street) ? "date-name" : PARTICLE.test(street) ? "street-particle" : "bare-street";
192
+ if (carriesNumber) {
193
+ const number = HOUSE_NUMBERS[Math.floor(random() * HOUSE_NUMBERS.length)];
194
+ const alnum = random() < 0.25;
195
+ const suffix = ALNUM_SUFFIXES[Math.floor(random() * ALNUM_SUFFIXES.length)];
196
+ const houseNumber = alnum
197
+ ? suffix === "bis" || suffix === "ter"
198
+ ? `${number} ${suffix}`
199
+ : `${number}${suffix}`
200
+ : String(number);
201
+ components.house_number = houseNumber;
202
+ raw = `${houseNumber} ${prefix} ${street}`;
203
+ klass = alnum ? "alnum-housenumber" : "street-housenumber";
204
+ }
205
+ const sourceID = shardSourceID("synth-fr-fragment", { ...components, v: String(read) });
206
+ if (alignAndWrite(write, {
207
+ raw,
208
+ components,
209
+ country: "FR",
210
+ locale: "fr-FR",
211
+ source: "synth-fr-fragment",
212
+ source_id: sourceID,
213
+ corpus_version: "0.9.4",
214
+ license: "Synthetic — fr-fragment; (street, commune) from BAN (Base Adresse Nationale, Licence Ouverte)",
215
+ }, `fr-fragment:${klass}`)) {
216
+ emitted++;
217
+ }
218
+ else {
219
+ skipped++;
220
+ }
221
+ }
222
+ // ---- the counter-distribution: bare localities, NO street anywhere in the row -------------
223
+ // Minted last so the locality pool is complete. Without these the model can satisfy every row
224
+ // above by flipping its default from "bare => locality" to "bare => street", which trades one
225
+ // broken prior for another and would show up as bare-locality collapsing on the board.
226
+ const pool = [...localities].sort();
227
+ const wanted = Math.round((emitted / Math.max(1, 1 - bareLocalityProb)) * bareLocalityProb);
228
+ for (let i = 0; i < wanted && pool.length; i++) {
229
+ // BAN gives `locality_base` normalized; restore the casing the fragment board also
230
+ // reconstructs, so train and eval show the model the same shape of French.
231
+ const name = frTitleCase(pool[Math.floor(random() * pool.length)]);
232
+ const sourceID = shardSourceID("synth-fr-fragment", { locality: name, v: `neg-${i}` });
233
+ if (alignAndWrite(write, {
234
+ raw: name,
235
+ components: { locality: name },
236
+ country: "FR",
237
+ locale: "fr-FR",
238
+ source: "synth-fr-fragment",
239
+ source_id: sourceID,
240
+ corpus_version: "0.9.4",
241
+ license: "Synthetic — fr-fragment counter-distribution; commune from BAN (Licence Ouverte)",
242
+ }, "fr-fragment:bare-locality")) {
243
+ emitted++;
244
+ }
245
+ else {
246
+ skipped++;
247
+ }
248
+ }
249
+ if (contaminated) {
250
+ console.error(`fr-fragment: skipped ${contaminated} rows whose street surface is reserved by the fragment board`);
251
+ }
252
+ return { read, emitted, skipped };
253
+ },
254
+ };
255
+ //# sourceMappingURL=fr-fragment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fr-fragment.js","sourceRoot":"","sources":["../../../src/shard-recipes/fr-fragment.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shard-recipes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkBH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAOhD,cAAc,eAAe,CAAA;AA2B7B,4BAA4B;AAC5B,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAA4C,CAAA;AAEvG,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEpE;AAED,yCAAyC;AACzC,wBAAgB,gBAAgB,IAAI,SAAS,WAAW,EAAE,CAEzD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shard-recipes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoBH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAOhD,cAAc,eAAe,CAAA;AA6B7B,4BAA4B;AAC5B,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAA4C,CAAA;AAEvG,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEpE;AAED,yCAAyC;AACzC,wBAAgB,gBAAgB,IAAI,SAAS,WAAW,EAAE,CAEzD"}
@@ -13,12 +13,14 @@ import { countryBalancedRecipe } from "./country-balanced.js";
13
13
  import { czPcFirstPrepositionRecipe } from "./cz-pcfirst-preposition.js";
14
14
  import { frAdminSplitRecipe } from "./fr-admin-split.js";
15
15
  import { frBareStreetRecipe } from "./fr-bare-street.js";
16
+ import { frFragmentRecipe } from "./fr-fragment.js";
16
17
  import { frOrderRecipe } from "./fr-order.js";
17
18
  import { germanRecipe } from "./german.js";
18
19
  import { houseVenueRecipe } from "./house-venue.js";
19
20
  import { intersectionRecipe } from "./intersection.js";
20
21
  import { localeRecipe } from "./locale.js";
21
22
  import { nlPostcodeRecipe } from "./nl-postcode.js";
23
+ import { noFragmentRecipe } from "./no-fragment.js";
22
24
  import { noStreetLedRecipe } from "./no-street-led.js";
23
25
  import { noStreetRecipe } from "./no-street.js";
24
26
  import { poBoxCedexRecipe } from "./po-box-cedex.js";
@@ -45,9 +47,11 @@ const RECIPES = [
45
47
  frOrderRecipe,
46
48
  frAdminSplitRecipe,
47
49
  frBareStreetRecipe,
50
+ frFragmentRecipe,
48
51
  czPcFirstPrepositionRecipe,
49
52
  nlPostcodeRecipe,
50
53
  noStreetLedRecipe,
54
+ noFragmentRecipe,
51
55
  siBareVillageRecipe,
52
56
  countryBalancedRecipe,
53
57
  boundaryStressRecipe,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shard-recipes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC,cAAc,eAAe,CAAA;AAE7B,iDAAiD;AACjD,MAAM,OAAO,GAA2B;IACvC,YAAY;IACZ,gBAAgB;IAChB,iBAAiB;IACjB,cAAc;IACd,gBAAgB;IAChB,WAAW;IACX,gBAAgB;IAChB,UAAU;IACV,kBAAkB;IAClB,YAAY;IACZ,YAAY;IACZ,aAAa;IACb,kBAAkB;IAClB,kBAAkB;IAClB,0BAA0B;IAC1B,gBAAgB;IAChB,iBAAiB;IACjB,mBAAmB;IACnB,qBAAqB;IACrB,oBAAoB;IACpB,sBAAsB;CACtB,CAAA;AAED,4BAA4B;AAC5B,MAAM,CAAC,MAAM,aAAa,GAAqC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;AAEvG,+CAA+C;AAC/C,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAC/B,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,gBAAgB;IAC/B,OAAO,OAAO,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shard-recipes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC,cAAc,eAAe,CAAA;AAE7B,iDAAiD;AACjD,MAAM,OAAO,GAA2B;IACvC,YAAY;IACZ,gBAAgB;IAChB,iBAAiB;IACjB,cAAc;IACd,gBAAgB;IAChB,WAAW;IACX,gBAAgB;IAChB,UAAU;IACV,kBAAkB;IAClB,YAAY;IACZ,YAAY;IACZ,aAAa;IACb,kBAAkB;IAClB,kBAAkB;IAClB,gBAAgB;IAChB,0BAA0B;IAC1B,gBAAgB;IAChB,iBAAiB;IACjB,gBAAgB;IAChB,mBAAmB;IACnB,qBAAqB;IACrB,oBAAoB;IACpB,sBAAsB;CACtB,CAAA;AAED,4BAA4B;AAC5B,MAAM,CAAC,MAAM,aAAa,GAAqC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;AAEvG,+CAA+C;AAC/C,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAC/B,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,gBAAgB;IAC/B,OAAO,OAAO,CAAA;AACf,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `no-fragment` — the Norwegian house-number-licence lever (Track B, 2026-07-16). The mirror of
7
+ * `fr-fragment`, which earned +50pp on the same defect shape in French.
8
+ *
9
+ * WHY THIS EXISTS AND `no-street-led` DOES NOT SUFFICE. Board 3 (the NO digit board) measured that
10
+ * `synth-no-street-led`'s three forms — all carrying postcode+city — are ALREADY at 0.940-0.968 on
11
+ * a model with zero Norwegian rows. The headroom is in the forms that shard never emits:
12
+ *
13
+ * bare-street-hn "Hallingrudveien 32" 0.693 — no postcode competing, still fails 31%
14
+ * slash-hn "Øvrabø 124/1" 0.650 — cadastral gnr/bnr, ONE component
15
+ *
16
+ * THE MECHANISM the board exposed: `Hallingrudveien 32` -> locality + postcode, while
17
+ * `Hallingrudveien 32, 3370 Vikersund` parses perfectly. The street loses its street reading and
18
+ * the digit loses its anchor TOGETHER. That is Track A's bare-street LICENCE in Norwegian — the
19
+ * model will not read a street without its postcode/locality partner — not a digit-ownership prior.
20
+ * fr-fragment fixed exactly this in French by teaching the street WITHOUT its partners.
21
+ *
22
+ * THE COUNTER-DISTRIBUTION IS THE POINT (fr-fragment's lesson, and board 2's bare-locality guard).
23
+ * Teaching bare `{street} {number}` alone lets the model satisfy every row by flipping its default
24
+ * from "bare toponym -> locality" to "bare toponym -> street", trading one broken prior for
25
+ * another. Two counter-classes hold the line:
26
+ * - bare LOCALITIES (no street) so "bare -> street" is not free.
27
+ * - bare POSTCODES so the model does not learn to stop emitting postcode to win the digit — the
28
+ * board 3 bare-pc negative class (1.000) must HOLD.
29
+ *
30
+ * SLASH HAZARD, pinned deliberately: NO `124/1` is ONE house_number (cadastral gnr/bnr). AU
31
+ * `12/345` is TWO (unit + house_number). This shard teaches the Norwegian reading; a future AU
32
+ * intra-word-split shard (B5) must not generalize over it. The two are locale-gated by design.
33
+ *
34
+ * SPLIT: `--exclude-surfaces` REQUIRED (throws otherwise) — the digit board's reserved surface
35
+ * list. Diacritic-KEEPING normalizer, matching the board (see the norm docstring).
36
+ */
37
+ import { type ShardRecipe } from "./scaffold.ts";
38
+ export declare const noFragmentRecipe: ShardRecipe;
39
+ //# sourceMappingURL=no-fragment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-fragment.d.ts","sourceRoot":"","sources":["../../../src/shard-recipes/no-fragment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAIH,OAAO,EAA6C,KAAK,WAAW,EAAiB,MAAM,eAAe,CAAA;AAgB1G,eAAO,MAAM,gBAAgB,EAAE,WA8I9B,CAAA"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `no-fragment` — the Norwegian house-number-licence lever (Track B, 2026-07-16). The mirror of
7
+ * `fr-fragment`, which earned +50pp on the same defect shape in French.
8
+ *
9
+ * WHY THIS EXISTS AND `no-street-led` DOES NOT SUFFICE. Board 3 (the NO digit board) measured that
10
+ * `synth-no-street-led`'s three forms — all carrying postcode+city — are ALREADY at 0.940-0.968 on
11
+ * a model with zero Norwegian rows. The headroom is in the forms that shard never emits:
12
+ *
13
+ * bare-street-hn "Hallingrudveien 32" 0.693 — no postcode competing, still fails 31%
14
+ * slash-hn "Øvrabø 124/1" 0.650 — cadastral gnr/bnr, ONE component
15
+ *
16
+ * THE MECHANISM the board exposed: `Hallingrudveien 32` -> locality + postcode, while
17
+ * `Hallingrudveien 32, 3370 Vikersund` parses perfectly. The street loses its street reading and
18
+ * the digit loses its anchor TOGETHER. That is Track A's bare-street LICENCE in Norwegian — the
19
+ * model will not read a street without its postcode/locality partner — not a digit-ownership prior.
20
+ * fr-fragment fixed exactly this in French by teaching the street WITHOUT its partners.
21
+ *
22
+ * THE COUNTER-DISTRIBUTION IS THE POINT (fr-fragment's lesson, and board 2's bare-locality guard).
23
+ * Teaching bare `{street} {number}` alone lets the model satisfy every row by flipping its default
24
+ * from "bare toponym -> locality" to "bare toponym -> street", trading one broken prior for
25
+ * another. Two counter-classes hold the line:
26
+ * - bare LOCALITIES (no street) so "bare -> street" is not free.
27
+ * - bare POSTCODES so the model does not learn to stop emitting postcode to win the digit — the
28
+ * board 3 bare-pc negative class (1.000) must HOLD.
29
+ *
30
+ * SLASH HAZARD, pinned deliberately: NO `124/1` is ONE house_number (cadastral gnr/bnr). AU
31
+ * `12/345` is TWO (unit + house_number). This shard teaches the Norwegian reading; a future AU
32
+ * intra-word-split shard (B5) must not generalize over it. The two are locale-gated by design.
33
+ *
34
+ * SPLIT: `--exclude-surfaces` REQUIRED (throws otherwise) — the digit board's reserved surface
35
+ * list. Diacritic-KEEPING normalizer, matching the board (see the norm docstring).
36
+ */
37
+ import { readFileSync } from "node:fs";
38
+ import { alignAndWrite, makeMulberry32, readTuples, shardSourceID } from "./scaffold.js";
39
+ /**
40
+ * The surface key — MUST match the NO digit board's `norm_surface` and `no-street-led`'s `norm`: NFC, lowercase,
41
+ * collapse whitespace, KEEP diacritics. Stripping them (fr-fragment's norm) would fold `Tømmerlien` -> `tommerlien`,
42
+ * miss the board's reserved `tømmerlien`, and leak the surface.
43
+ */
44
+ const norm = (value) => value.normalize("NFC").toLowerCase().replace(/\s+/g, " ").trim();
45
+ /** Title-case a Kartverket ALL-CAPS locality (HELLVIK -> Hellvik); #690, all-caps is OOD. */
46
+ const titleNO = (value) => value
47
+ .split(/\s+/)
48
+ .map((w) => (w ? w[0].toUpperCase() + w.slice(1).toLowerCase() : w))
49
+ .join(" ");
50
+ export const noFragmentRecipe = {
51
+ name: "no-fragment",
52
+ description: "NO street fragments — the house-number-licence lever (Track B): '«st» «n»' / bare «st» with NO postcode partner, + bare-locality & bare-postcode counters",
53
+ mode: "tuples",
54
+ options: [
55
+ {
56
+ flag: "--exclude-surfaces <path>",
57
+ description: "REQUIRED. The NO digit board's reserved surface list (mailwoman/eval-harness/fixtures/no-digits.surfaces.txt).",
58
+ },
59
+ {
60
+ flag: "--bare-street-prob <n>",
61
+ description: "Share of street rows emitted as a BARE street, no number (default 0.30 — the pure licence signal)",
62
+ },
63
+ {
64
+ flag: "--counter-prob <n>",
65
+ description: "Share of ALL rows that are counter-distribution (bare locality OR bare postcode) (default 0.30)",
66
+ },
67
+ {
68
+ flag: "--long-number-boost <n>",
69
+ description: "knob 3: emit N copies of each street+number row whose number has >= --long-number-min-digits digits — oversample the failing long-number class the model calls a postcode (default 1 = no boost)",
70
+ },
71
+ {
72
+ flag: "--long-number-min-digits <n>",
73
+ description: "knob 3: minimum digit count for a number to be 'long' and boosted (default 3)",
74
+ },
75
+ ],
76
+ async run(opts, write) {
77
+ const random = makeMulberry32(opts.seed);
78
+ const excludePath = opts.excludeSurfaces;
79
+ if (!excludePath) {
80
+ throw new Error("no-fragment: --exclude-surfaces is REQUIRED. Pass the NO digit board's reserved list " +
81
+ "(mailwoman/eval-harness/fixtures/no-digits.surfaces.txt) or this shard trains on its own eval set. " +
82
+ "Source-disjoint by street SURFACE is the split discipline; there is no safe default.");
83
+ }
84
+ const excluded = new Set(readFileSync(excludePath, "utf8")
85
+ .split("\n")
86
+ .map((line) => line.trim())
87
+ .filter((line) => line && !line.startsWith("#")));
88
+ if (!excluded.size)
89
+ throw new Error(`no-fragment: --exclude-surfaces "${excludePath}" listed no surfaces`);
90
+ const bareStreetProb = opts.bareProb ?? 0.3;
91
+ const counterProb = opts.counterProb ?? 0.3;
92
+ const longNumberBoost = Math.max(1, Math.floor(opts.longNumberBoost ?? 1));
93
+ const longNumberMinDigits = opts.longNumberMinDigits ?? 3;
94
+ // Harvested from the tuples — every NO row carries its locality and postcode, so the two
95
+ // counter-classes need no second source.
96
+ const localities = new Set();
97
+ const postcodes = new Set();
98
+ let read = 0;
99
+ let emitted = 0;
100
+ let skipped = 0;
101
+ let contaminated = 0;
102
+ let emitSeq = 0;
103
+ const emit = (raw, components, klass) => {
104
+ // emitSeq keeps every emit distinct — knob 3 emits N copies of one long-number row, and
105
+ // (components, read) alone would collide their source_id and let downstream dedup drop the boost.
106
+ const source_id = shardSourceID("synth-no-fragment", { ...components, k: klass, v: `${read}:${emitSeq++}` });
107
+ const canonical = {
108
+ raw,
109
+ components,
110
+ country: "NO",
111
+ locale: "nb-NO",
112
+ source: "synth-no-fragment",
113
+ source_id,
114
+ corpus_version: "0.11.0",
115
+ license: "Synthetic — no-fragment; (street, number, postcode, city) from OpenAddresses NO / Kartverket",
116
+ };
117
+ if (alignAndWrite(write, canonical, "no-fragment"))
118
+ emitted++;
119
+ else
120
+ skipped++;
121
+ };
122
+ for await (const tuple of readTuples(opts.input)) {
123
+ read++;
124
+ const street = String(tuple.street ?? "").trim();
125
+ const locality = titleNO(String(tuple.locality ?? "").trim());
126
+ const number = String(tuple.number ?? "").trim();
127
+ const postcode = String(tuple.postcode ?? "").trim();
128
+ if (locality)
129
+ localities.add(locality);
130
+ if (postcode)
131
+ postcodes.add(postcode);
132
+ if (!street) {
133
+ skipped++;
134
+ continue;
135
+ }
136
+ // THE SPLIT. A surface on the digit board never enters training.
137
+ if (excluded.has(norm(street))) {
138
+ contaminated++;
139
+ continue;
140
+ }
141
+ // COUNTER-DISTRIBUTION — drawn from the harvested pools, not this row's street. Half bare
142
+ // localities (so "bare -> street" is not free), half bare postcodes (so the model does not
143
+ // stop emitting postcode to win the digit — board 3's bare-pc must hold).
144
+ if (random() < counterProb) {
145
+ if (random() < 0.5 && localities.size) {
146
+ const loc = [...localities][Math.floor(random() * localities.size)];
147
+ emit(loc, { locality: loc }, "counter-bare-locality");
148
+ }
149
+ else if (postcodes.size) {
150
+ const pc = [...postcodes][Math.floor(random() * postcodes.size)];
151
+ emit(pc, { postcode: pc }, "counter-bare-postcode");
152
+ }
153
+ continue;
154
+ }
155
+ // THE SIGNAL. A street with NO postcode/locality partner. Either bare, or street+number —
156
+ // both are the forms board 3 measured as the headroom (bare-street-hn 0.693, slash-hn 0.650).
157
+ if (!number || random() < bareStreetProb) {
158
+ emit(street, { street }, "bare-street");
159
+ }
160
+ else {
161
+ const klass = number.includes("/") ? "slash-hn" : "street-hn";
162
+ // knob 3: the failing class is street + LONG number (Leppdalsvegen 1285 -> postcode). The
163
+ // digit count, not the slash, is what tips the length prior toward postcode. Oversample
164
+ // those rows to fight the prior with volume and teach the street/number boundary directly.
165
+ const digits = (number.match(/\d/g) ?? []).length;
166
+ const copies = digits >= longNumberMinDigits ? longNumberBoost : 1;
167
+ for (let c = 0; c < copies; c++) {
168
+ emit(`${street} ${number}`, { street, house_number: number }, klass);
169
+ }
170
+ }
171
+ }
172
+ return { read, emitted, skipped, contaminated };
173
+ },
174
+ };
175
+ //# sourceMappingURL=no-fragment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-fragment.js","sourceRoot":"","sources":["../../../src/shard-recipes/no-fragment.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"no-street-led.d.ts","sourceRoot":"","sources":["../../../src/shard-recipes/no-street-led.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAA6C,KAAK,WAAW,EAAiB,MAAM,eAAe,CAAA;AAE1G,eAAO,MAAM,iBAAiB,EAAE,WA2D/B,CAAA"}
1
+ {"version":3,"file":"no-street-led.d.ts","sourceRoot":"","sources":["../../../src/shard-recipes/no-street-led.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAA6C,KAAK,WAAW,EAAiB,MAAM,eAAe,CAAA;AAW1G,eAAO,MAAM,iBAAiB,EAAE,WAkG/B,CAAA"}
@@ -15,16 +15,49 @@
15
15
  * 2. city-first "«city», «pc», «st» «n»"
16
16
  * 3. pc-first "«pc» «city», «st» «n»" (the 7% floor — the anchor the others converge to)
17
17
  */
18
+ import { readFileSync } from "node:fs";
18
19
  import { alignAndWrite, makeMulberry32, readTuples, shardSourceID } from "./scaffold.js";
20
+ /**
21
+ * The surface key. MUST match the NO digit board's `norm_surface` (scratchpad/build-no-board.py): NFC, lowercase,
22
+ * collapse whitespace — and critically, KEEP diacritics. fr-fragment's `norm` strips them (NFD + combining-mark
23
+ * removal), which is right for French but would collapse `Tømmerlien` → `tommerlien` here, so the shard's exclusion
24
+ * check would never match the board's reserved `tømmerlien` and the split would leak silently. Diacritic street heads
25
+ * (…vegen/…veien with ø/å/æ) are the whole point of this shard's boundary; folding them away is not an option.
26
+ */
27
+ const norm = (value) => value.normalize("NFC").toLowerCase().replace(/\s+/g, " ").trim();
19
28
  export const noStreetLedRecipe = {
20
29
  name: "no-street-led",
21
30
  description: "NO street-led boundary form (#901 family): '«st» «n», «pc» «city»' — diacritic street heads",
22
31
  mode: "tuples",
32
+ options: [
33
+ {
34
+ flag: "--exclude-surfaces <path>",
35
+ description: "REQUIRED. The NO digit board's reserved surface list " +
36
+ "(mailwoman/eval-harness/fixtures/no-digits.surfaces.txt); every listed street is skipped.",
37
+ },
38
+ ],
23
39
  async run(opts, write) {
24
40
  makeMulberry32(opts.seed);
41
+ // THE SPLIT (ported from fr-fragment, #727 T2). Without it this shard trains on all 10,697
42
+ // NO surfaces, 1,952 of which the digit board reserves — so a Norway retrain would grade
43
+ // memorization of `Hallingrudveien` while claiming to measure the boundary form. There is no
44
+ // safe default: source-disjoint by street SURFACE is the discipline, so the flag throws.
45
+ const excludePath = opts.excludeSurfaces;
46
+ if (!excludePath) {
47
+ throw new Error("no-street-led: --exclude-surfaces is REQUIRED. Pass the NO digit board's reserved list " +
48
+ "(mailwoman/eval-harness/fixtures/no-digits.surfaces.txt) or this shard trains on its own eval set. " +
49
+ "Source-disjoint by street SURFACE is the split discipline; there is no safe default.");
50
+ }
51
+ const excluded = new Set(readFileSync(excludePath, "utf8")
52
+ .split("\n")
53
+ .map((line) => line.trim())
54
+ .filter((line) => line && !line.startsWith("#")));
55
+ if (!excluded.size)
56
+ throw new Error(`no-street-led: --exclude-surfaces "${excludePath}" listed no surfaces`);
25
57
  let read = 0;
26
58
  let emitted = 0;
27
59
  let skipped = 0;
60
+ let contaminated = 0;
28
61
  for await (const t of readTuples(opts.input)) {
29
62
  read++;
30
63
  const street = String(t.street ?? "").trim();
@@ -35,6 +68,11 @@ export const noStreetLedRecipe = {
35
68
  skipped++;
36
69
  continue;
37
70
  }
71
+ // A surface on the digit board never enters training.
72
+ if (excluded.has(norm(street))) {
73
+ contaminated++;
74
+ continue;
75
+ }
38
76
  const order = read % 3;
39
77
  let raw;
40
78
  const components = {
@@ -70,7 +108,7 @@ export const noStreetLedRecipe = {
70
108
  skipped++;
71
109
  }
72
110
  }
73
- return { read, emitted, skipped };
111
+ return { read, emitted, skipped, contaminated };
74
112
  },
75
113
  };
76
114
  //# sourceMappingURL=no-street-led.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-street-led.js","sourceRoot":"","sources":["../../../src/shard-recipes/no-street-led.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAoB,aAAa,EAAE,MAAM,eAAe,CAAA;AAE1G,MAAM,CAAC,MAAM,iBAAiB,GAAgB;IAC7C,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,6FAA6F;IAC1G,IAAI,EAAE,QAAQ;IACd,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK;QACpB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzB,IAAI,IAAI,GAAG,CAAC,CAAA;QACZ,IAAI,OAAO,GAAG,CAAC,CAAA;QACf,IAAI,OAAO,GAAG,CAAC,CAAA;QAEf,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,KAAM,CAAC,EAAE,CAAC;YAC/C,IAAI,EAAE,CAAA;YACN,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;YAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;YAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;YAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;YAEhD,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC9C,OAAO,EAAE,CAAA;gBACT,SAAQ;YACT,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAA;YACtB,IAAI,GAAW,CAAA;YACf,MAAM,UAAU,GAA2B;gBAC1C,MAAM;gBACN,YAAY,EAAE,MAAM;gBACpB,QAAQ;gBACR,QAAQ,EAAE,IAAI;aACd,CAAA;YAED,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACjB,GAAG,GAAG,GAAG,MAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,IAAI,EAAE,CAAA;YACjD,CAAC;iBAAM,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACxB,GAAG,GAAG,GAAG,IAAI,KAAK,QAAQ,KAAK,MAAM,IAAI,MAAM,EAAE,CAAA;YAClD,CAAC;iBAAM,CAAC;gBACP,GAAG,GAAG,GAAG,QAAQ,IAAI,IAAI,KAAK,MAAM,IAAI,MAAM,EAAE,CAAA;YACjD,CAAC;YACD,MAAM,SAAS,GAAG,aAAa,CAAC,qBAAqB,EAAE,EAAE,GAAG,UAAU,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC5G,MAAM,SAAS,GAAG;gBACjB,GAAG;gBACH,UAAU;gBACV,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,OAAO;gBACf,MAAM,EAAE,qBAAqB;gBAC7B,SAAS;gBACT,cAAc,EAAE,QAAQ;gBACxB,OAAO,EACN,8HAA8H;aAC/H,CAAA;YAED,IAAI,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,eAAe,CAAC,EAAE,CAAC;gBACtD,OAAO,EAAE,CAAA;YACV,CAAC;iBAAM,CAAC;gBACP,OAAO,EAAE,CAAA;YACV,CAAC;QACF,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAA;IAClC,CAAC;CACD,CAAA"}
1
+ {"version":3,"file":"no-street-led.js","sourceRoot":"","sources":["../../../src/shard-recipes/no-street-led.ts"],"names":[],"mappings":"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"}
@@ -73,12 +73,32 @@ export interface ShardRecipeOpts {
73
73
  hnProb?: number;
74
74
  communes?: string;
75
75
  multilocaleCount?: number;
76
+ /**
77
+ * `fr-fragment` / `no-fragment` / `no-street-led`: the eval board's reserved street-surface list. REQUIRED for those
78
+ * recipes — a shard that trains on its own eval set measures memorization. See their docstrings.
79
+ */
80
+ excludeSurfaces?: string;
81
+ /** `no-fragment`: share of rows that are counter-distribution (bare locality OR bare postcode). */
82
+ counterProb?: number;
83
+ /**
84
+ * `no-fragment` knob 3: emit N copies of each street+number row whose number has >= longNumberMinDigits digits
85
+ * (oversample the failing long-number class). Default 1 = no boost.
86
+ */
87
+ longNumberBoost?: number;
88
+ /** `no-fragment` knob 3: minimum digit count for a number to count as "long" and be boosted. Default 3. */
89
+ longNumberMinDigits?: number;
76
90
  }
77
91
  /** Tally a recipe returns. */
78
92
  export interface ShardStats {
79
93
  read?: number;
80
94
  emitted: number;
81
95
  skipped: number;
96
+ /**
97
+ * Rows dropped because their street SURFACE is reserved by an eval board (`--exclude-surfaces`). Separate from
98
+ * `skipped` on purpose: a nonzero value is the audit trail that the train/eval split actually fired. Zero when a
99
+ * recipe has no board split.
100
+ */
101
+ contaminated?: number;
82
102
  }
83
103
  /** A single declared recipe-specific option flag (for the command's --help). */
84
104
  export interface ShardRecipeOption {
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/shard-recipes/scaffold.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/shard-recipes/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAElG;AAED,+FAA+F;AAC/F,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACpB;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAQlD;AAED,6CAA6C;AAC7C,eAAO,MAAM,UAAU,gBAAU,CAAA;AAEjC;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAUzD;AAED,mGAAmG;AACnG,wBAAuB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAgB3E;AAED,kGAAkG;AAClG,MAAM,WAAW,iBAAiB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC7B,SAAS,EAAE,iBAAiB,EAC5B,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,MAAM,GAAG,IAAW,GAC/B,OAAO,CAOT;AAED,oGAAoG;AACpG,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mGAAmG;IACnG,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,2GAA2G;IAC3G,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,8BAA8B;AAC9B,MAAM,WAAW,UAAU;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,gFAAgF;AAChF,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACnB;AAED,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC3B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAA;IACZ,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAA;IACnB,gFAAgF;IAChF,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAA;IAC3B,qEAAqE;IACrE,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAA;IAC7B;;;OAGG;IACH,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CAC9E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mailwoman/corpus",
3
- "version": "6.3.0",
3
+ "version": "6.5.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": {
@@ -82,14 +82,14 @@
82
82
  },
83
83
  "dependencies": {
84
84
  "@dsnp/parquetjs": "1.8.8",
85
- "@mailwoman/codex": "6.3.0",
86
- "@mailwoman/core": "6.3.0",
87
- "@mailwoman/formatter": "6.3.0",
85
+ "@mailwoman/codex": "6.5.0",
86
+ "@mailwoman/core": "6.5.0",
87
+ "@mailwoman/formatter": "6.5.0",
88
88
  "csv-parse": "^7.0.1",
89
89
  "fast-glob": "^3.3.3",
90
90
  "fastest-levenshtein": "^1.0.16",
91
91
  "lru-cache": "^11.5.2",
92
- "spliterator": "^3.2.0"
92
+ "spliterator": "^4.0.0"
93
93
  },
94
94
  "devDependencies": {
95
95
  "@types/node": ">=26.1.1"