/** * @copyright Sister Software * @license AGPL-3.0 * @author Teffen Ellis, et al. * * Shared scaffolding for the synthetic-corpus SHARD RECIPES — the common bits the 16 * `build-*-shard.mjs` scripts each re-implemented: the seeded LCG PRNG, the tuple reader, and the * canonical → `alignRow` → `LabeledRow` JSONL emit step. A recipe ({@link ShardRecipe}) supplies * only its synthesis + filter; the `mailwoman corpus shard ` command supplies the I/O. */ import type { PathBuilderLike } from "path-ts"; import type { AsyncChunkIterator, AsyncDataResource } from "spliterator"; import { AsyncSequence } from "spliterator"; /** * {@link stableSourceID}, but accepting arbitrary disambiguator keys (e.g. a variant index `v`) that aren't * `ComponentTag`s. `stableSourceID` sorts + hashes EVERY key it's given, so passing extra keys is how the legacy * builders kept per-variant ids unique — the strict typing is just too narrow for that. Centralizes the one cast. */ export declare function shardSourceID(adapterID: string, parts: Record): string; /** * A (locality, region, postcode, country) source tuple — the input to tuples-mode recipes. */ export interface ShardTuple { locality?: string; region?: string; postcode?: string; country?: string; [k: string]: unknown; } /** * The two seeded generators the legacy `build-*-shard` scripts used, re-exported from their home in * `@mailwoman/core/utils` so a recipe keeps importing everything it needs from this one scaffold module. * * - `makeLcg` (`s = s*1664525 + 1013904223 mod 2^32`) — what the street/po-box/anchor builders seeded. * - `makeMulberry32` — what the MAJORITY of them used (german, locale, boundary-stress, unit, fr-order, country-balanced, * intersection, fr-admin-split, street-affix, street-bare, po-box-cedex). * * A recipe must seed the same one its `.mjs` did, the same way it did (usually `seed`, but some derive a per-stream * seed), or `--seed N` stops being byte-reproducible. */ export { makeLcg, mulberry32 as makeMulberry32, makeLcg as makeRandom } from "@mailwoman/core/utils"; /** * One CSV record, keyed by its lower-cased header name, every value trimmed. A column the header does not declare reads * as `undefined`; a column the header declares but this record does not reach reads as `""`. */ export type CSVRecord = Record; /** * Read a CSV as header-keyed records. * * Returns the spliterator's own {@linkcode AsyncSequence}, so a caller composes `take`/`drop`/`filter` onto it — those * ops fuse into one pull loop, and a `take` that is satisfied closes the source's file handle on the way out. Wrapping * this in an `async function*` costs an async frame per row and takes those ops away; don't. * * A source at or below the spliterator's 128 KiB bulk threshold is read whole and parsed by the synchronous engine, so * this is also the right reader for small sources — there is no buffered variant to reach for. */ export declare function readCSVRecords(source: AsyncDataResource | AsyncChunkIterator): AsyncSequence; /** * {@link readCSVRecords} over one member of a zip archive — what every recipe reading a cached OA source wants. * * A source a checkout has not cached yields nothing, after saying so. A lab holds the archives for the countries it has * built, so a recipe naming ten sources routinely finds three, and the `unzip -p` subprocesses these replaced behaved * the same way by accident — a non-zero exit warned and returned no rows. A recipe that ends up with NO tuples at all * still throws; that is the case where the cache, not the recipe, is the problem. */ export declare function readZippedCSVRecords(archivePath: PathBuilderLike, entryName: string): AsyncSequence; /** * Stream-parse a tuples JSONL file, yielding each parsed object (blank/invalid lines skipped). */ export declare function readTuples(input: string): AsyncGenerator; /** * A canonical row as the recipes assemble it, before `alignRow` turns it into a `LabeledRow`. */ export interface CanonicalShardRow { raw: string; components: Record; country: string; locale?: string; source: string; source_id: string; corpus_version?: string; license?: string; } /** * Run a canonical row through `alignRow` and, on success, write the `LabeledRow` (+ `synth_method` / `synth_base_id`) * as one JSONL line. Returns true if emitted, false if alignment quarantined it. */ export declare function alignAndWrite(write: (line: string) => void, canonical: CanonicalShardRow, synthMethod: string, synthBaseID?: string | null): boolean; /** * Parsed options a recipe's `run` receives. Common fields + the union of recipe-specific flags. */ export interface ShardRecipeOpts { output: string; seed: number; variants: number; input?: string; count?: number; golden?: boolean; sourceName?: string; houseNumberProb?: number; pmbRatio?: number; militaryRatio?: number; reversedFraction?: number; edgesDir?: string; country?: string; intlFraction?: number; /** * `locale`: fraction of rows that append an explicit country surface form + a `country` component. Default 0. */ countryFraction?: number; /** * `locale`: tri-state override of the per-part `districtAsLocality` mapping for this invocation. `undefined` (flag * absent) leaves each `COUNTRY_SOURCES` part's own value untouched — every existing locale build stays * byte-identical. `true`/`false` forces that value on every part read this run. ES's pedanía shard * (`synth-es-pedania`) additionally uses `true` to select {@link LocaleCountrySource.pedaniaParts} instead of the * default `parts` — see `locale.ts`. */ districtAsLocality?: boolean; bareProb?: number; hnProb?: number; communes?: string; /** * `fr-lieudit`: BAN `adresses-.csv` directory. Default `$MAILWOMAN_DATA_ROOT/corpus/sources/ban`. */ banDir?: string; multilocaleCount?: number; /** * `fr-fragment` / `no-fragment` / `no-street-led`: the eval board's reserved street-surface list. REQUIRED for those * recipes — a shard that trains on its own eval set measures memorization. See their docstrings. */ excludeSurfaces?: string; /** * `no-fragment`: share of rows that are counter-distribution (bare locality OR bare postcode). */ counterProb?: number; /** * `no-fragment` knob 3: emit N copies of each street+number row whose number has >= longNumberMinDigits digits * (oversample the failing long-number class). Default 1 = no boost. */ longNumberBoost?: number; /** * `no-fragment` knob 3: minimum digit count for a number to count as "long" and be boosted. Default 3. */ longNumberMinDigits?: number; /** * `sub-venue`: the sub-venue lexicon JSON. Default = the committed `corpus/data/sub-venue-lexicon.json`, resolved * through the package manifest so it works from the source tree and from `out/`. */ lexicon?: string; /** * `sub-venue`: directory of `sub-venue-extract` JSONLs, one per region. Default * `$MAILWOMAN_DATA_ROOT/sub-venue/extracts`. */ extractsDir?: string; /** * `sub-venue`: the `poi.db` spatial layer, read for the en-US and fr-FR venue + confound pools (the two of poi.db's * four countries this shard has legs for). Default `$MAILWOMAN_DATA_ROOT/poi/poi.db`. */ poiDb?: string; /** * `sub-venue`: GB/US/FR address-context tuples JSONL. Default the house-venue v3 tuples * (`$MAILWOMAN_DATA_ROOT/corpus/intermediate/house-venue-tuples-v3.jsonl`); DE and ES read OpenAddresses directly. */ subVenueTuples?: string; /** * `sub-venue`: share of emitted rows that are confound NEGATIVES. Default 0.3. */ negativeFraction?: number; } /** * Tally a recipe returns. */ export interface ShardStats { read?: number; emitted: number; skipped: number; /** * Rows dropped because their street SURFACE is reserved by an eval board (`--exclude-surfaces`). Separate from * `skipped` on purpose: a nonzero value is the audit trail that the train/eval split actually fired. Zero when a * recipe has no board split. */ contaminated?: number; } /** * A single declared recipe-specific option flag (for the command's --help). */ export interface ShardRecipeOption { flag: string; description: string; } /** * A shard recipe: its identity, input mode, and its synthesis `run`. */ export interface ShardRecipe { /** * Recipe id, e.g. "street", "po-box" — the `` positional. */ name: string; /** * One-line description for `--list` / help. */ description: string; /** * `tuples` reads `--input` JSONL; `generate` self-generates `--count` rows. */ mode: "tuples" | "generate"; /** * Recipe-specific flags this recipe honors (documentation only). */ options?: ShardRecipeOption[]; /** * Do the build: create the recipe's PRNG from `opts.seed` (its LEGACY generator — `makeLcg` or `makeMulberry32` — for * byte-reproducibility), synthesize, and emit each row via `write`. */ run(opts: ShardRecipeOpts, write: (line: string) => void): Promise; } //# sourceMappingURL=scaffold.d.ts.map