/** * @copyright Sister Software * @license AGPL-3.0 * @author Teffen Ellis, et al. * * Stage 2.7 span proposer — mechanisms M2 + M3 from the punctuation survey * (`docs/articles/reviews/2026-06-11-punctuation-survey.md`), the structural half of the * sub-premise direction note (`docs/articles/plan/2026-06-11-subpremise-proposer-direction.md`). * * A pure function over the raw input emitting TYPED span proposals from three cue families: * * 1. **Paired delimiters (M2)** — balanced `()`, `[]`, `""`, `«»`, `„“` groups propose * `ANNOTATION_SPAN` / `QUOTED_SPAN`. Unbalanced delimiters of a class produce NO proposal * for that class — the proposer never guesses a missing pair (graceful degradation to * today's behavior, per the survey's unbalanced-class read). * 2. **Designator + identifier** — the sub-premise grammar (`Apt 4B`, `Suite 500`, `PO Box 19`): a * closed-vocabulary leader from the injected codex-backed lexicon followed by a short * identifier proposes `UNIT_PHRASE` / `LEVEL_PHRASE` / `PO_BOX_PHRASE`. * 3. **Dual-path numeric punctuation (M3, the Pelias PR #56 mechanism)** — `2/14`, `14-16`, `123 1/2` * adjacent to a number context emit BOTH readings as alternatives sharing an * `alternativeGroup`: the fused single-value reading (`FUSED_NUMBER`) AND the * designator-split reading (`SPLIT_UNIT` + `SPLIT_HOUSE_NUMBER`), locale-conditioned by * which codex systems the lexicon was built from (the AU/NZ `Flat 2/14` split exists only * when those tables are loaded). The proposer never decides between readings — downstream * consumers weigh them. * * The proposals are INFORMATION, not decisions (the #464 lesson): consumers treat them as phrase * priors the classifier conditions on and as structural boundaries the decode-side span bridge * must not merge across. The classifier can always disagree. * * Like the phrase grouper's rules, the cues here are structural + provenance-tracked vocabulary * (codex tables injected by the caller) — no place names, no guessed designators. Core stays * codex-free: `@mailwoman/neural` builds the {@link SpanProposerLexicon} from `@mailwoman/codex` * (see `neural/span-proposer-lexicon.ts`). */ /** * Typed kinds a span proposal may carry. See the module doc for the three cue families. */ export type ProposedSpanKind = /** A balanced `()`/`[]` group whose content reads as an aside about the address. */ "ANNOTATION_SPAN" /** A balanced quote group — the content is likely a NAME (venue/unit); typing is the classifier's job. */ | "QUOTED_SPAN" /** Delivery-service designator + identifier ("PO Box 19", "GPO Box 2890", "Private Bag 7"). */ | "PO_BOX_PHRASE" /** Secondary-unit designator + identifier ("Apt 4B", "Suite 500"). */ | "UNIT_PHRASE" /** Level-class designator + identifier ("Floor 3", "FL 12"). */ | "LEVEL_PHRASE" /** Dual-path FUSED reading: the punctuated numeric is ONE value ("123 1/2", "69-10", "14/2"). */ | "FUSED_NUMBER" /** Dual-path SPLIT reading, left side: the sub-premise ("Flat 2" of "Flat 2/14", "3" of "3/45"). */ | "SPLIT_UNIT" /** Dual-path SPLIT reading, right side: the house number ("14" of "Flat 2/14"). */ | "SPLIT_HOUSE_NUMBER"; /** * One typed span proposal. Char offsets into the raw input; `end` exclusive. */ export interface ProposedSpan { start: number; end: number; kind: ProposedSpanKind; /** * 0..1. Confidence is shape-derived; consumers weight or floor it (it is never a verdict). */ confidence: number; /** * Alternative readings of ONE surface share a group id (M3 dual-path: the fused and split readings of `2/14` carry * the same group). Absent for single-reading proposals. */ alternativeGroup?: number; /** * Provenance: which cue family + rule emitted this ("paired:()", "designator:unit", "slash:au-split"). */ source: string; } /** * Vocabulary the proposer conditions on — built from `@mailwoman/codex` tables by the caller (`buildCodexSpanLexicon` * in `@mailwoman/neural`). All token sets are lowercase. An empty lexicon (the default) limits the proposer to the * paired-delimiter cue family. */ export interface SpanProposerLexicon { /** * Codex system codes the lexicon was built from ("us", "au", "nz", …) — drives M3 locale conditioning. */ systems: ReadonlySet; /** * Leading secondary-unit designator tokens (USPS Pub-28 C2 variants: "apt", "ste", "unit", …). */ unitDesignators: ReadonlySet; /** * Level-class designator tokens ("floor", "fl", "bsmt", "ph", …) — typed LEVEL_PHRASE. */ levelDesignators: ReadonlySet; /** * Descriptive designators ("building", "rear", "side", …) that, inside a bracketed group, read as annotation content * rather than a unit ("[Building A]" describes; "[Suite 9]" addresses). */ weakDesignators: ReadonlySet; /** * The subset of {@link unitDesignators} naming venue-INTERIOR structure ("concourse", "terminal", "wing", "gate", …) * rather than a postal secondary unit. Sourced from WOF placetypes + OSM `aeroway`, never from a mail standard — see * `@mailwoman/neural`'s `venue-structure.ts`. * * Membership is carried through to the proposal's `source` so the consuming prior can weight the two provenances * differently. It has to: measured 2026-08-02, the model's margin against `I-unit` on a sub-venue IDENTIFIER runs * 4.6–5.0 nats (`B` after `Concourse` scores `B-venue` 4.24 while `I-unit` sits 17th of 33), which the shipped * unit-designator scale cannot reach — while raising that shared scale far enough drags quote marks and commas into * unit spans elsewhere in the corpus. The two classes need different magnitudes because the model has different * opinions about them, so the lexicon has to keep them distinguishable. */ venueStructureDesignators: ReadonlySet; /** * Positional words that may PRECEDE a designator ("West Wing", "Upper Concourse") — the mirror of the * designator+identifier shape, where the qualifier leads instead of following. */ venueStructureModifiers: ReadonlySet; /** * The subset of {@link venueStructureDesignators} that may take a preceding modifier. Narrower than the full set * because some designators form ordinary STREET names in exactly this shape — "East Gate" is a street, "West Wing" is * not — so a rule spanning all of them converts correct street parses into sub-venue ones. */ modifierEligibleStructureDesignators: ReadonlySet; /** * Global scan regex for delivery-service designator+identifier phrases, built from the codex po_box / * delivery-service tables. Must carry the `g` flag. */ deliveryService?: RegExp; } /** * Empty lexicon — paired-delimiter proposals only. */ export declare const EMPTY_SPAN_PROPOSER_LEXICON: SpanProposerLexicon; /** * Propose typed spans over `text`. Pure and synchronous; safe to run on every parse. Proposals may overlap freely * ("possibilities not constraints"); alternatives of one surface share an `alternativeGroup`. Sorted by `start`, then * descending confidence. * * Designator and numeric proposals fully inside a confident (≥ 0.6) `ANNOTATION_SPAN` are suppressed — bracketed asides * describe the address ("(Apt 4 around back)"), and the annotation proposal already carries the span. Content inside * QUOTED_SPANs is NOT suppressed (quotes wrap names, not asides). */ export declare function proposeSpans(text: string, lexicon?: SpanProposerLexicon): ProposedSpan[]; //# sourceMappingURL=span-proposer.d.ts.map