@mailwoman/phrase-grouper 4.0.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.
package/out/group.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `groupPhrases` — Stage 2.7 entry point.
7
+ *
8
+ * Composes per-kind rules over the normalized input + QueryShape and emits one `PhraseProposal` per
9
+ * fired rule. Overlapping proposals are expected — the reconciler (Stage 5) picks the best
10
+ * non-overlapping subset.
11
+ *
12
+ * See `docs/articles/concepts/the-knowledge-ladder.md` § Phrase grouper for the design rationale,
13
+ * and `phrase-grouper/rules.ts` for per-rule documentation.
14
+ */
15
+ import type { GroupPhrasesOpts, LocaleHint, NormalizedInputLite, PhraseProposal, QueryShapeLike } from "./types.js";
16
+ /**
17
+ * Synchronous, pure rule-based implementation. The async wrapper matches the pipeline contract.
18
+ *
19
+ * Emits overlapping proposals freely — the consumer (Stage 5 reconcile) picks the best
20
+ * non-overlapping subset under semantic+hierarchical constraints. Confidence is a [0,1] score per
21
+ * proposal; relative ordering is what matters more than absolute calibration at v0.5.0.
22
+ *
23
+ * The `_locale` parameter is reserved for future locale-aware rule packs (Japanese
24
+ * postcode/honorific patterns, French preposition-bound localities) — currently unused.
25
+ */
26
+ export declare function groupPhrasesSync(input: NormalizedInputLite, shape: QueryShapeLike, _locale?: LocaleHint, _opts?: GroupPhrasesOpts): PhraseProposal[];
27
+ /**
28
+ * Async variant matching `RuntimePipelineStages.groupPhrases`. Wraps the sync impl so the pipeline
29
+ * coordinator can use it as-is.
30
+ */
31
+ export declare function groupPhrases(input: NormalizedInputLite, shape: QueryShapeLike, locale?: LocaleHint, opts?: GroupPhrasesOpts): Promise<PhraseProposal[]>;
32
+ //# sourceMappingURL=group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../group.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,mBAAmB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AA0BnH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,UAAU,EACpB,KAAK,GAAE,gBAAqB,GAC1B,cAAc,EAAE,CA4BlB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,cAAc,EACrB,MAAM,CAAC,EAAE,UAAU,EACnB,IAAI,CAAC,EAAE,gBAAgB,GACrB,OAAO,CAAC,cAAc,EAAE,CAAC,CAE3B"}
package/out/group.js ADDED
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `groupPhrases` — Stage 2.7 entry point.
7
+ *
8
+ * Composes per-kind rules over the normalized input + QueryShape and emits one `PhraseProposal` per
9
+ * fired rule. Overlapping proposals are expected — the reconciler (Stage 5) picks the best
10
+ * non-overlapping subset.
11
+ *
12
+ * See `docs/articles/concepts/the-knowledge-ladder.md` § Phrase grouper for the design rationale,
13
+ * and `phrase-grouper/rules.ts` for per-rule documentation.
14
+ */
15
+ import { scoreHyphenatedCompound, scoreLocalityPhrase, scoreNumeric, scorePostcode, scoreRegionAbbreviation, scoreStreetPhrase, scoreVenuePhrase, tokenizeSegment, } from "./rules.js";
16
+ /**
17
+ * Walk every QueryShape segment and emit one `tokens-by-segment` list. Falls back to treating the
18
+ * whole input as a single segment when QueryShape didn't supply segmentation (e.g. callers wiring
19
+ * the grouper into a path that bypasses QueryShape).
20
+ */
21
+ function tokensPerSegment(text, shape) {
22
+ const segs = shape.segments;
23
+ if (segs && segs.length > 0) {
24
+ return segs.map((s, idx) => {
25
+ const start = s.span?.start ?? 0;
26
+ const end = s.span?.end ?? text.length;
27
+ return {
28
+ tokens: tokenizeSegment(text.slice(start, end), start),
29
+ isFirst: idx === 0,
30
+ isLast: idx === segs.length - 1,
31
+ };
32
+ });
33
+ }
34
+ return [{ tokens: tokenizeSegment(text, 0), isFirst: true, isLast: true }];
35
+ }
36
+ /**
37
+ * Synchronous, pure rule-based implementation. The async wrapper matches the pipeline contract.
38
+ *
39
+ * Emits overlapping proposals freely — the consumer (Stage 5 reconcile) picks the best
40
+ * non-overlapping subset under semantic+hierarchical constraints. Confidence is a [0,1] score per
41
+ * proposal; relative ordering is what matters more than absolute calibration at v0.5.0.
42
+ *
43
+ * The `_locale` parameter is reserved for future locale-aware rule packs (Japanese
44
+ * postcode/honorific patterns, French preposition-bound localities) — currently unused.
45
+ */
46
+ export function groupPhrasesSync(input, shape, _locale, _opts = {}) {
47
+ const text = input.normalized;
48
+ if (text.length === 0)
49
+ return [];
50
+ const proposals = [];
51
+ // Postcode rule consumes QueryShape directly (segment-agnostic).
52
+ proposals.push(...scorePostcode(shape, text));
53
+ // Per-segment rules.
54
+ for (const { tokens, isFirst, isLast } of tokensPerSegment(text, shape)) {
55
+ if (tokens.length === 0)
56
+ continue;
57
+ proposals.push(...scoreNumeric(tokens, text));
58
+ proposals.push(...scoreRegionAbbreviation(tokens, text, isLast));
59
+ proposals.push(...scoreHyphenatedCompound(tokens, text));
60
+ proposals.push(...scoreStreetPhrase(tokens, text));
61
+ proposals.push(...scoreLocalityPhrase(tokens, text, isLast));
62
+ proposals.push(...scoreVenuePhrase(tokens, text, isFirst));
63
+ }
64
+ // Sort: descending confidence, ties broken by span start (left-to-right). Downstream Stage 5
65
+ // can rely on this ordering for top-k selection without re-sorting.
66
+ proposals.sort((a, b) => {
67
+ if (a.confidence !== b.confidence)
68
+ return b.confidence - a.confidence;
69
+ return a.span.start - b.span.start;
70
+ });
71
+ return proposals;
72
+ }
73
+ /**
74
+ * Async variant matching `RuntimePipelineStages.groupPhrases`. Wraps the sync impl so the pipeline
75
+ * coordinator can use it as-is.
76
+ */
77
+ export async function groupPhrases(input, shape, locale, opts) {
78
+ return groupPhrasesSync(input, shape, locale, opts);
79
+ }
80
+ //# sourceMappingURL=group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.js","sourceRoot":"","sources":["../group.ts"],"names":[],"mappings":"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"}
package/out/index.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `@mailwoman/phrase-grouper` — Stage 2.7 of the runtime pipeline.
7
+ *
8
+ * Proposes coherent input units (boundary discovery) with a structural kind hypothesis +
9
+ * confidence. Decouples boundary discovery from type classification: Stage 3 conditions on these
10
+ * proposals so it answers the simpler "what type is this proposed span?" rather than jointly
11
+ * discovering boundaries and types. Stage 5 consumes the proposals as boundary candidates for
12
+ * joint decoding.
13
+ *
14
+ * Bitter-lesson-safe: only universal structural cues (proximity, punctuation, capitalization,
15
+ * hyphenation, format-shape repetition) — never place-name dictionaries. v0.5.0 ships the
16
+ * rule-based v1; learned 1-2M-param span proposer reserved for v0.5.1.
17
+ *
18
+ * See `docs/articles/concepts/the-knowledge-ladder.md` § Phrase grouper for the design rationale
19
+ * and `docs/articles/plan/phases/PHASE_8_v0_5_0_fresh_slate.md` § E for the v0.5.0 thread.
20
+ */
21
+ export { groupPhrases, groupPhrasesSync } from "./group.js";
22
+ export { scoreHyphenatedCompound, scoreLocalityPhrase, scoreNumeric, scorePostcode, scoreRegionAbbreviation, scoreStreetPhrase, scoreVenuePhrase, tokenizeSegment, } from "./rules.js";
23
+ export type { SegmentToken } from "./rules.js";
24
+ export type { GroupPhrasesOpts, LocaleHint, NormalizedInputLite, PhraseGrouper, PhraseKind, PhraseProposal, QueryShapeLike, Section, } from "./types.js";
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC3D,OAAO,EACN,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,GACf,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,YAAY,EACX,gBAAgB,EAChB,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,cAAc,EACd,cAAc,EACd,OAAO,GACP,MAAM,YAAY,CAAA"}
package/out/index.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `@mailwoman/phrase-grouper` — Stage 2.7 of the runtime pipeline.
7
+ *
8
+ * Proposes coherent input units (boundary discovery) with a structural kind hypothesis +
9
+ * confidence. Decouples boundary discovery from type classification: Stage 3 conditions on these
10
+ * proposals so it answers the simpler "what type is this proposed span?" rather than jointly
11
+ * discovering boundaries and types. Stage 5 consumes the proposals as boundary candidates for
12
+ * joint decoding.
13
+ *
14
+ * Bitter-lesson-safe: only universal structural cues (proximity, punctuation, capitalization,
15
+ * hyphenation, format-shape repetition) — never place-name dictionaries. v0.5.0 ships the
16
+ * rule-based v1; learned 1-2M-param span proposer reserved for v0.5.1.
17
+ *
18
+ * See `docs/articles/concepts/the-knowledge-ladder.md` § Phrase grouper for the design rationale
19
+ * and `docs/articles/plan/phases/PHASE_8_v0_5_0_fresh_slate.md` § E for the v0.5.0 thread.
20
+ */
21
+ export { groupPhrases, groupPhrasesSync } from "./group.js";
22
+ export { scoreHyphenatedCompound, scoreLocalityPhrase, scoreNumeric, scorePostcode, scoreRegionAbbreviation, scoreStreetPhrase, scoreVenuePhrase, tokenizeSegment, } from "./rules.js";
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC3D,OAAO,EACN,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,GACf,MAAM,YAAY,CAAA"}
package/out/rules.d.ts ADDED
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Rule-based scorers for Stage 2.7 phrase grouping. Each rule inspects the tokenized segment +
7
+ * QueryShape priors and emits zero or more `PhraseProposal`s with a confidence in [0, 1].
8
+ *
9
+ * Bitter-lesson-safe: only universal structural cues (proximity, punctuation, capitalization,
10
+ * hyphenation, format-shape repetition). No place-name dictionaries — a `LOCALITY_PHRASE`
11
+ * proposal means "this looks shaped like a multi-word capitalized run that COULD be a city name",
12
+ * not "this IS a city name". Typing the span is the classifier's job; this layer only answers "do
13
+ * these tokens belong together?".
14
+ *
15
+ * Per "possibilities not constraints", rules emit overlapping proposals freely. The reconciler
16
+ * (Stage 5) picks the best non-overlapping subset.
17
+ */
18
+ import type { PhraseProposal, QueryShapeLike } from "./types.js";
19
+ /**
20
+ * One token within a segment — absolute offsets into the normalized input. Built by
21
+ * `tokenizeSegment` from a (segment-text, segment-start) pair.
22
+ */
23
+ export interface SegmentToken {
24
+ body: string;
25
+ start: number;
26
+ end: number;
27
+ }
28
+ /**
29
+ * Split a segment body into whitespace-separated tokens. Offsets are absolute into the original
30
+ * input (caller supplies the segment's `start` offset).
31
+ */
32
+ export declare function tokenizeSegment(segmentBody: string, segmentStart: number): SegmentToken[];
33
+ /**
34
+ * `NUMERIC` rule: emit one proposal per all-digit token. House numbers, postcodes (when no format
35
+ * hit), unit numbers all surface here as a base hypothesis.
36
+ *
37
+ * Confidence drops for very long runs (5+ digits) where POSTCODE will typically win; the reconciler
38
+ * does the final pick.
39
+ */
40
+ export declare function scoreNumeric(tokens: ReadonlyArray<SegmentToken>, text: string): PhraseProposal[];
41
+ /**
42
+ * `POSTCODE` rule: lift each `QueryShape.knownFormats` postcode hit directly. The QueryShape stage
43
+ * already did the format-shape recognition — Stage 2.7's job is just to publish the spans as phrase
44
+ * proposals so the reconciler can use them.
45
+ */
46
+ export declare function scorePostcode(shape: QueryShapeLike, text: string): PhraseProposal[];
47
+ /**
48
+ * `REGION_ABBREVIATION` rule: 2-3 uppercase Latin letters. Tail-of-segment position boosts
49
+ * confidence because that's the canonical "City, ST ZIP" shape.
50
+ */
51
+ export declare function scoreRegionAbbreviation(tokens: ReadonlyArray<SegmentToken>, text: string, segmentIsLast: boolean): PhraseProposal[];
52
+ /**
53
+ * `HYPHENATED_COMPOUND` rule: tokens containing an internal hyphen. Captures `NY-NY` (venue
54
+ * disambiguation case), `Saint-Denis` (French locality compound), `10118-1234` (ZIP+4 written as a
55
+ * single token).
56
+ *
57
+ * Internal hyphen is the cue; the rule doesn't pre-judge what the compound MEANS — that's typing
58
+ * (classifier) or reconcile work. A high confidence here just says "this is one unit, not two".
59
+ */
60
+ export declare function scoreHyphenatedCompound(tokens: ReadonlyArray<SegmentToken>, text: string): PhraseProposal[];
61
+ /**
62
+ * `STREET_PHRASE` rule: a token run that contains a street-type suffix. The span covers a leading
63
+ * numeric (house number) when present, through the suffix token.
64
+ *
65
+ * Confidence reflects how canonical the run looks: NUMERIC + 1-3 capitalized words + SUFFIX scores
66
+ * highest; suffix-only or non-leading-numeric variants score lower but still emit.
67
+ */
68
+ export declare function scoreStreetPhrase(tokens: ReadonlyArray<SegmentToken>, text: string): PhraseProposal[];
69
+ /**
70
+ * `LOCALITY_PHRASE` rule: runs of contiguous capitalized words (1-4 long). Emits multiple
71
+ * overlapping proposals so the reconciler can choose between e.g. `Saint Petersburg` as one phrase
72
+ * vs `Saint` + `Petersburg` as two.
73
+ *
74
+ * Confidence scales with: run length (2-3 best), tail-of-segment position, and whether the
75
+ * preceding token is a comma or segment boundary.
76
+ */
77
+ export declare function scoreLocalityPhrase(tokens: ReadonlyArray<SegmentToken>, text: string, segmentIsLast: boolean): PhraseProposal[];
78
+ /**
79
+ * `VENUE_PHRASE` rule: capitalized run containing a venue-marker noun (Steakhouse, Hotel, etc.) OR
80
+ * containing a hyphenated compound + ≥1 capitalized word.
81
+ *
82
+ * The shape "NY-NY Steakhouse" — the kryptonite case the reconciler eventually needs to lift the NY
83
+ * tokens off REGION — surfaces here as a `VENUE_PHRASE` proposal at moderate-high confidence.
84
+ *
85
+ * Also includes a venue-by-exclusion positional prior: multi-word capitalized run in the first
86
+ * segment with no street suffix, no house number, and no unit marker → weak VENUE_PHRASE at
87
+ * 0.50-0.55. The idea: if we can't identify what something IS, but it's in the venue slot (first
88
+ * segment) and doesn't look like any other component, it might be a venue name.
89
+ */
90
+ export declare function scoreVenuePhrase(tokens: ReadonlyArray<SegmentToken>, text: string, segmentIsFirst?: boolean): PhraseProposal[];
91
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhE;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACX;AA+CD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,YAAY,EAAE,CAezF;AAmLD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAehG;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAcnF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,OAAO,GACpB,cAAc,EAAE,CAiBlB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAc3G;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CA+BrG;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,OAAO,GACpB,cAAc,EAAE,CA2ClB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,cAAc,CAAC,EAAE,OAAO,GACtB,cAAc,EAAE,CA2ClB"}
package/out/rules.js ADDED
@@ -0,0 +1,498 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Rule-based scorers for Stage 2.7 phrase grouping. Each rule inspects the tokenized segment +
7
+ * QueryShape priors and emits zero or more `PhraseProposal`s with a confidence in [0, 1].
8
+ *
9
+ * Bitter-lesson-safe: only universal structural cues (proximity, punctuation, capitalization,
10
+ * hyphenation, format-shape repetition). No place-name dictionaries — a `LOCALITY_PHRASE`
11
+ * proposal means "this looks shaped like a multi-word capitalized run that COULD be a city name",
12
+ * not "this IS a city name". Typing the span is the classifier's job; this layer only answers "do
13
+ * these tokens belong together?".
14
+ *
15
+ * Per "possibilities not constraints", rules emit overlapping proposals freely. The reconciler
16
+ * (Stage 5) picks the best non-overlapping subset.
17
+ */
18
+ import { Span } from "@mailwoman/core/tokenization";
19
+ const WHITESPACE = /\s+/;
20
+ const US_REGION_NAMES = new Set([
21
+ "alabama",
22
+ "alaska",
23
+ "arizona",
24
+ "arkansas",
25
+ "california",
26
+ "colorado",
27
+ "connecticut",
28
+ "delaware",
29
+ "florida",
30
+ "georgia",
31
+ "hawaii",
32
+ "idaho",
33
+ "illinois",
34
+ "indiana",
35
+ "iowa",
36
+ "kansas",
37
+ "kentucky",
38
+ "louisiana",
39
+ "maine",
40
+ "maryland",
41
+ "massachusetts",
42
+ "michigan",
43
+ "minnesota",
44
+ "mississippi",
45
+ "missouri",
46
+ "montana",
47
+ "nebraska",
48
+ "nevada",
49
+ "ohio",
50
+ "oklahoma",
51
+ "oregon",
52
+ "pennsylvania",
53
+ "tennessee",
54
+ "texas",
55
+ "utah",
56
+ "vermont",
57
+ "virginia",
58
+ "washington",
59
+ "wisconsin",
60
+ "wyoming",
61
+ ]);
62
+ /**
63
+ * Split a segment body into whitespace-separated tokens. Offsets are absolute into the original
64
+ * input (caller supplies the segment's `start` offset).
65
+ */
66
+ export function tokenizeSegment(segmentBody, segmentStart) {
67
+ const tokens = [];
68
+ let i = 0;
69
+ while (i < segmentBody.length) {
70
+ while (i < segmentBody.length && WHITESPACE.test(segmentBody[i]))
71
+ i++;
72
+ if (i >= segmentBody.length)
73
+ break;
74
+ const start = i;
75
+ while (i < segmentBody.length && !WHITESPACE.test(segmentBody[i]))
76
+ i++;
77
+ tokens.push({
78
+ body: segmentBody.slice(start, i),
79
+ start: segmentStart + start,
80
+ end: segmentStart + i,
81
+ });
82
+ }
83
+ return tokens;
84
+ }
85
+ /** Build a `Section` (Span instance) from absolute offsets into the original text. */
86
+ function makeSection(text, start, end) {
87
+ return Span.from(text.slice(start, end), { start });
88
+ }
89
+ /** True when token body is non-empty digits only. */
90
+ function isAllDigit(s) {
91
+ return s.length > 0 && /^[0-9]+$/.test(s);
92
+ }
93
+ /** True when token body is 2-3 uppercase Latin letters (US state, Canadian province abbreviation). */
94
+ function isRegionAbbreviation(s) {
95
+ return /^[A-Z]{2,3}$/.test(s);
96
+ }
97
+ /** True when token starts with an uppercase letter — common Western proper-noun shape. */
98
+ function startsCapitalized(s) {
99
+ return /^[A-Z]/.test(s);
100
+ }
101
+ /**
102
+ * Common street-type suffixes (en-US + en-GB + abbreviated forms). Match case-insensitively against
103
+ * the raw token body. The set is intentionally short — coverage extension belongs in a future
104
+ * per-locale rule pack, not as a 500-entry dictionary in this rule.
105
+ */
106
+ const STREET_SUFFIXES = new Set([
107
+ "st",
108
+ "st.",
109
+ "street",
110
+ "ave",
111
+ "ave.",
112
+ "avenue",
113
+ "blvd",
114
+ "blvd.",
115
+ "boulevard",
116
+ "rd",
117
+ "rd.",
118
+ "road",
119
+ "ln",
120
+ "ln.",
121
+ "lane",
122
+ "dr",
123
+ "dr.",
124
+ "drive",
125
+ "way",
126
+ "pl",
127
+ "pl.",
128
+ "place",
129
+ "ct",
130
+ "ct.",
131
+ "court",
132
+ "pkwy",
133
+ "parkway",
134
+ "hwy",
135
+ "highway",
136
+ "ter",
137
+ "terrace",
138
+ "cir",
139
+ "circle",
140
+ "sq",
141
+ "square",
142
+ "trl",
143
+ "trail",
144
+ ]);
145
+ function isStreetSuffix(token) {
146
+ return STREET_SUFFIXES.has(token.toLowerCase());
147
+ }
148
+ /**
149
+ * Venue-marker nouns with per-term confidence weights. Same caveat as STREET_SUFFIXES — universal
150
+ * structural markers, not a places dictionary. Higher weight = stronger venue signal.
151
+ */
152
+ const VENUE_MARKERS = new Map([
153
+ // Dining (0.90 — unambiguous venue markers)
154
+ ["steakhouse", 0.9],
155
+ ["restaurant", 0.9],
156
+ ["bistro", 0.9],
157
+ ["diner", 0.85],
158
+ ["cafe", 0.85],
159
+ ["café", 0.85],
160
+ ["grill", 0.8],
161
+ ["pizzeria", 0.9],
162
+ ["bakery", 0.85],
163
+ ["brewery", 0.85],
164
+ ["winery", 0.85],
165
+ ["tavern", 0.8],
166
+ ["pub", 0.75],
167
+ ["bar", 0.7],
168
+ // Lodging
169
+ ["hotel", 0.9],
170
+ ["motel", 0.9],
171
+ ["inn", 0.75],
172
+ ["resort", 0.85],
173
+ ["lodge", 0.75],
174
+ ["hostel", 0.85],
175
+ // Entertainment / culture
176
+ ["theater", 0.85],
177
+ ["theatre", 0.85],
178
+ ["cinema", 0.85],
179
+ ["stadium", 0.9],
180
+ ["arena", 0.85],
181
+ ["museum", 0.85],
182
+ ["gallery", 0.75],
183
+ ["casino", 0.85],
184
+ ["lounge", 0.7],
185
+ // Retail / commercial
186
+ ["market", 0.7],
187
+ ["mall", 0.8],
188
+ ["plaza", 0.7],
189
+ ["tower", 0.65],
190
+ ["center", 0.6],
191
+ ["centre", 0.6],
192
+ // Medical / institutional
193
+ ["hospital", 0.9],
194
+ ["clinic", 0.85],
195
+ ["pharmacy", 0.85],
196
+ // Education
197
+ ["university", 0.9],
198
+ ["college", 0.85],
199
+ ["school", 0.8],
200
+ ["academy", 0.8],
201
+ // Civic / religious
202
+ ["church", 0.8],
203
+ ["temple", 0.8],
204
+ ["mosque", 0.8],
205
+ ["synagogue", 0.85],
206
+ ["cathedral", 0.85],
207
+ ["chapel", 0.75],
208
+ ["library", 0.85],
209
+ // Outdoor
210
+ ["park", 0.6],
211
+ ["gardens", 0.65],
212
+ ["ranch", 0.7],
213
+ ["farm", 0.65],
214
+ ]);
215
+ /**
216
+ * Unit-designator tokens that gate the venue-by-exclusion heuristic. When any token in a segment
217
+ * matches one of these, the segment is likely a unit/suite line, not a venue name.
218
+ */
219
+ const UNIT_MARKERS = new Set([
220
+ "apt",
221
+ "apt.",
222
+ "apartment",
223
+ "unit",
224
+ "ste",
225
+ "ste.",
226
+ "suite",
227
+ "room",
228
+ "rm",
229
+ "rm.",
230
+ "floor",
231
+ "fl",
232
+ "fl.",
233
+ "bldg",
234
+ "bldg.",
235
+ "building",
236
+ "dept",
237
+ "dept.",
238
+ "department",
239
+ "#",
240
+ ]);
241
+ function venueMarkerWeight(tokens) {
242
+ let maxWeight = 0;
243
+ for (const t of tokens) {
244
+ const w = VENUE_MARKERS.get(t.body.toLowerCase());
245
+ if (w !== undefined && w > maxWeight)
246
+ maxWeight = w;
247
+ }
248
+ return maxWeight;
249
+ }
250
+ function hasUnitMarker(tokens) {
251
+ return tokens.some((t) => UNIT_MARKERS.has(t.body.toLowerCase()));
252
+ }
253
+ /**
254
+ * `NUMERIC` rule: emit one proposal per all-digit token. House numbers, postcodes (when no format
255
+ * hit), unit numbers all surface here as a base hypothesis.
256
+ *
257
+ * Confidence drops for very long runs (5+ digits) where POSTCODE will typically win; the reconciler
258
+ * does the final pick.
259
+ */
260
+ export function scoreNumeric(tokens, text) {
261
+ const out = [];
262
+ for (const t of tokens) {
263
+ if (!isAllDigit(t.body))
264
+ continue;
265
+ const len = t.body.length;
266
+ // 1-4 digit pure-numerics are clearly NUMERIC (house number). 5+ are ambiguous with POSTCODE
267
+ // — emit anyway at lower confidence so the reconciler sees both options.
268
+ const confidence = len <= 4 ? 0.95 : 0.55;
269
+ out.push({
270
+ span: makeSection(text, t.start, t.end),
271
+ kindHypothesis: "NUMERIC",
272
+ confidence,
273
+ });
274
+ }
275
+ return out;
276
+ }
277
+ /**
278
+ * `POSTCODE` rule: lift each `QueryShape.knownFormats` postcode hit directly. The QueryShape stage
279
+ * already did the format-shape recognition — Stage 2.7's job is just to publish the spans as phrase
280
+ * proposals so the reconciler can use them.
281
+ */
282
+ export function scorePostcode(shape, text) {
283
+ const out = [];
284
+ for (const hit of shape.knownFormats) {
285
+ // `po_box` is not a postcode; the kind classifier owns that signal. Skip non-postcode
286
+ // formats here so we don't pollute POSTCODE proposals.
287
+ if (hit.format === "po_box")
288
+ continue;
289
+ out.push({
290
+ span: makeSection(text, hit.span.start, hit.span.end),
291
+ kindHypothesis: "POSTCODE",
292
+ // Lift the format-hit confidence directly — Stage 5 can weight it against alternatives.
293
+ confidence: hit.confidence,
294
+ });
295
+ }
296
+ return out;
297
+ }
298
+ /**
299
+ * `REGION_ABBREVIATION` rule: 2-3 uppercase Latin letters. Tail-of-segment position boosts
300
+ * confidence because that's the canonical "City, ST ZIP" shape.
301
+ */
302
+ export function scoreRegionAbbreviation(tokens, text, segmentIsLast) {
303
+ const out = [];
304
+ for (let i = 0; i < tokens.length; i++) {
305
+ const t = tokens[i];
306
+ if (!isRegionAbbreviation(t.body))
307
+ continue;
308
+ // Position cue: last token in a segment (canonical region slot) → high confidence. Anywhere
309
+ // else, moderate. Anywhere in the LAST segment → slightly elevated (region is canonically the
310
+ // final non-postcode component).
311
+ const atTail = i === tokens.length - 1;
312
+ const confidence = atTail ? 0.85 : segmentIsLast ? 0.7 : 0.55;
313
+ out.push({
314
+ span: makeSection(text, t.start, t.end),
315
+ kindHypothesis: "REGION_ABBREVIATION",
316
+ confidence,
317
+ });
318
+ }
319
+ return out;
320
+ }
321
+ /**
322
+ * `HYPHENATED_COMPOUND` rule: tokens containing an internal hyphen. Captures `NY-NY` (venue
323
+ * disambiguation case), `Saint-Denis` (French locality compound), `10118-1234` (ZIP+4 written as a
324
+ * single token).
325
+ *
326
+ * Internal hyphen is the cue; the rule doesn't pre-judge what the compound MEANS — that's typing
327
+ * (classifier) or reconcile work. A high confidence here just says "this is one unit, not two".
328
+ */
329
+ export function scoreHyphenatedCompound(tokens, text) {
330
+ const out = [];
331
+ for (const t of tokens) {
332
+ if (!t.body.includes("-"))
333
+ continue;
334
+ // Skip leading/trailing hyphens (likely punctuation drift) — require an interior hyphen
335
+ // surrounded by non-hyphen characters.
336
+ if (!/[^-]-[^-]/.test(t.body))
337
+ continue;
338
+ out.push({
339
+ span: makeSection(text, t.start, t.end),
340
+ kindHypothesis: "HYPHENATED_COMPOUND",
341
+ confidence: 0.88,
342
+ });
343
+ }
344
+ return out;
345
+ }
346
+ /**
347
+ * `STREET_PHRASE` rule: a token run that contains a street-type suffix. The span covers a leading
348
+ * numeric (house number) when present, through the suffix token.
349
+ *
350
+ * Confidence reflects how canonical the run looks: NUMERIC + 1-3 capitalized words + SUFFIX scores
351
+ * highest; suffix-only or non-leading-numeric variants score lower but still emit.
352
+ */
353
+ export function scoreStreetPhrase(tokens, text) {
354
+ const out = [];
355
+ for (let suffixIdx = 0; suffixIdx < tokens.length; suffixIdx++) {
356
+ if (!isStreetSuffix(tokens[suffixIdx].body))
357
+ continue;
358
+ // Walk left from the suffix gathering capitalized/numeric/ordinal tokens. Stop when we hit
359
+ // something un-street-y (lowercase non-suffix, another suffix, etc.).
360
+ let start = suffixIdx;
361
+ for (let i = suffixIdx - 1; i >= 0; i--) {
362
+ const body = tokens[i].body;
363
+ if (isAllDigit(body) || /^\d+(st|nd|rd|th)$/i.test(body) || startsCapitalized(body)) {
364
+ start = i;
365
+ }
366
+ else {
367
+ break;
368
+ }
369
+ }
370
+ // Need at least one preceding token (or a numeric house number) for STREET_PHRASE — a
371
+ // suffix-only token "Street" alone isn't a street phrase.
372
+ if (start === suffixIdx)
373
+ continue;
374
+ const startTok = tokens[start];
375
+ const endTok = tokens[suffixIdx];
376
+ const hasLeadingNumeric = isAllDigit(startTok.body) || /^\d+(st|nd|rd|th)$/i.test(startTok.body);
377
+ // Canonical NUMERIC + capitalized + SUFFIX scores high; capitalized-run + SUFFIX scores
378
+ // slightly lower since it could also be a venue.
379
+ const confidence = hasLeadingNumeric ? 0.9 : 0.75;
380
+ out.push({
381
+ span: makeSection(text, startTok.start, endTok.end),
382
+ kindHypothesis: "STREET_PHRASE",
383
+ confidence,
384
+ });
385
+ }
386
+ return out;
387
+ }
388
+ /**
389
+ * `LOCALITY_PHRASE` rule: runs of contiguous capitalized words (1-4 long). Emits multiple
390
+ * overlapping proposals so the reconciler can choose between e.g. `Saint Petersburg` as one phrase
391
+ * vs `Saint` + `Petersburg` as two.
392
+ *
393
+ * Confidence scales with: run length (2-3 best), tail-of-segment position, and whether the
394
+ * preceding token is a comma or segment boundary.
395
+ */
396
+ export function scoreLocalityPhrase(tokens, text, segmentIsLast) {
397
+ const out = [];
398
+ for (let i = 0; i < tokens.length; i++) {
399
+ if (!startsCapitalized(tokens[i].body))
400
+ continue;
401
+ // Skip pure region abbreviations as standalone LOCALITY_PHRASE — they own REGION_ABBREVIATION
402
+ // at higher confidence.
403
+ if (isRegionAbbreviation(tokens[i].body))
404
+ continue;
405
+ // Walk forward grabbing additional capitalized tokens. Stop on lowercase, digit-only, or
406
+ // region-abbreviation tokens.
407
+ let j = i;
408
+ while (j + 1 < tokens.length &&
409
+ startsCapitalized(tokens[j + 1].body) &&
410
+ !isRegionAbbreviation(tokens[j + 1].body) &&
411
+ !isAllDigit(tokens[j + 1].body) &&
412
+ !isStreetSuffix(tokens[j + 1].body)) {
413
+ j++;
414
+ }
415
+ // Emit proposals for every prefix-length of the run starting at i, capped at 4 tokens.
416
+ // Each starting i contributes at most 4 proposals, so the rule stays O(n) per segment.
417
+ const maxLen = Math.min(j - i + 1, 4);
418
+ for (let len = 1; len <= maxLen; len++) {
419
+ const startTok = tokens[i];
420
+ const endTok = tokens[i + len - 1];
421
+ const spanText = text.slice(startTok.start, endTok.end);
422
+ const isRegionName = len === 1 && US_REGION_NAMES.has(spanText.toLowerCase());
423
+ const atTail = i + len - 1 === tokens.length - 1;
424
+ let confidence = 0.55 + (len === 2 ? 0.15 : 0) + (len === 3 ? 0.1 : 0);
425
+ if (isRegionName && !atTail)
426
+ confidence -= 0.2;
427
+ if (atTail && segmentIsLast)
428
+ confidence += 0.1;
429
+ if (atTail)
430
+ confidence += 0.05;
431
+ out.push({
432
+ span: makeSection(text, startTok.start, endTok.end),
433
+ kindHypothesis: "LOCALITY_PHRASE",
434
+ confidence: Math.min(0.95, confidence),
435
+ });
436
+ }
437
+ // Do NOT skip past the run — let i++ advance normally so every capitalized token gets a
438
+ // chance to emit single-token proposals from its own starting position. (Saint Petersburg
439
+ // needs `Saint`, `Petersburg`, AND `Saint Petersburg`; a run-skip would lose `Petersburg`.)
440
+ }
441
+ return out;
442
+ }
443
+ /**
444
+ * `VENUE_PHRASE` rule: capitalized run containing a venue-marker noun (Steakhouse, Hotel, etc.) OR
445
+ * containing a hyphenated compound + ≥1 capitalized word.
446
+ *
447
+ * The shape "NY-NY Steakhouse" — the kryptonite case the reconciler eventually needs to lift the NY
448
+ * tokens off REGION — surfaces here as a `VENUE_PHRASE` proposal at moderate-high confidence.
449
+ *
450
+ * Also includes a venue-by-exclusion positional prior: multi-word capitalized run in the first
451
+ * segment with no street suffix, no house number, and no unit marker → weak VENUE_PHRASE at
452
+ * 0.50-0.55. The idea: if we can't identify what something IS, but it's in the venue slot (first
453
+ * segment) and doesn't look like any other component, it might be a venue name.
454
+ */
455
+ export function scoreVenuePhrase(tokens, text, segmentIsFirst) {
456
+ const out = [];
457
+ let i = 0;
458
+ while (i < tokens.length) {
459
+ if (!startsCapitalized(tokens[i].body)) {
460
+ i++;
461
+ continue;
462
+ }
463
+ let j = i;
464
+ while (j + 1 < tokens.length && (startsCapitalized(tokens[j + 1].body) || tokens[j + 1].body.includes("-"))) {
465
+ j++;
466
+ }
467
+ const run = tokens.slice(i, j + 1);
468
+ const markerWeight = venueMarkerWeight(run);
469
+ const hasHyphenCompound = run.some((t) => /[^-]-[^-]/.test(t.body));
470
+ if (markerWeight > 0 || (hasHyphenCompound && run.length >= 2)) {
471
+ const startTok = run[0];
472
+ const endTok = run[run.length - 1];
473
+ const confidence = markerWeight > 0 ? markerWeight : 0.65;
474
+ out.push({
475
+ span: makeSection(text, startTok.start, endTok.end),
476
+ kindHypothesis: "VENUE_PHRASE",
477
+ confidence,
478
+ });
479
+ }
480
+ else if (segmentIsFirst && run.length >= 2) {
481
+ const hasStreet = run.some((t) => isStreetSuffix(t.body));
482
+ const hasLeadingNum = isAllDigit(run[0].body);
483
+ const hasUnit = hasUnitMarker(run);
484
+ if (!hasStreet && !hasLeadingNum && !hasUnit) {
485
+ const startTok = run[0];
486
+ const endTok = run[run.length - 1];
487
+ out.push({
488
+ span: makeSection(text, startTok.start, endTok.end),
489
+ kindHypothesis: "VENUE_PHRASE",
490
+ confidence: run.length >= 3 ? 0.55 : 0.5,
491
+ });
492
+ }
493
+ }
494
+ i = j + 1;
495
+ }
496
+ return out;
497
+ }
498
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../rules.ts"],"names":[],"mappings":"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"}
package/out/types.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ /** Re-exports of the canonical types from `@mailwoman/core/pipeline`. */
7
+ export type { LocaleHint, PhraseGrouper, PhraseKind, PhraseProposal } from "@mailwoman/core/pipeline";
8
+ /** Re-export of the canonical `Section` type from `@mailwoman/core/types`. `Section = Span`. */
9
+ export type { Section } from "@mailwoman/core/types";
10
+ /**
11
+ * Minimal `NormalizedInput` shape consumed by `groupPhrases`. Compatible with
12
+ * `@mailwoman/normalize`'s output.
13
+ */
14
+ export interface NormalizedInputLite {
15
+ raw: string;
16
+ normalized: string;
17
+ appliedLocale?: string;
18
+ }
19
+ /**
20
+ * Minimal `QueryShape` shape consumed by `groupPhrases`. Compatible with `@mailwoman/query-shape`'s
21
+ * output.
22
+ */
23
+ export interface QueryShapeLike {
24
+ knownFormats: ReadonlyArray<{
25
+ format: string;
26
+ span: {
27
+ start: number;
28
+ end: number;
29
+ };
30
+ confidence: number;
31
+ }>;
32
+ segments?: ReadonlyArray<{
33
+ body: string;
34
+ index: number;
35
+ span?: {
36
+ start: number;
37
+ end: number;
38
+ };
39
+ }>;
40
+ tokenClasses?: ReadonlyArray<{
41
+ span: {
42
+ start: number;
43
+ end: number;
44
+ body: string;
45
+ };
46
+ class: string;
47
+ length: number;
48
+ }>;
49
+ characterClass?: string;
50
+ totalLength?: number;
51
+ }
52
+ export interface GroupPhrasesOpts {
53
+ /** Reserved for future tunables (e.g. confidence floor, per-kind biasing). Currently unused. */
54
+ confidenceFloor?: number;
55
+ }
56
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yEAAyE;AACzE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAErG,gGAAgG;AAChG,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAEpD;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,YAAY,EAAE,aAAa,CAAC;QAC3B,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;QACpC,UAAU,EAAE,MAAM,CAAA;KAClB,CAAC,CAAA;IACF,QAAQ,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAA;IAChG,YAAY,CAAC,EAAE,aAAa,CAAC;QAC5B,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;QAClD,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;KACd,CAAC,CAAA;IACF,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,gBAAgB;IAChC,gGAAgG;IAChG,eAAe,CAAC,EAAE,MAAM,CAAA;CACxB"}
package/out/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@mailwoman/phrase-grouper",
3
+ "version": "4.0.0",
4
+ "description": "Stage 2.7 of the runtime pipeline — propose coherent input units (boundary discovery) with a structural kind hypothesis + confidence. Rule-based v1 (port of v1 section/sub-section logic); learned 1-2M-param span proposer reserved for v0.5.1.",
5
+ "license": "AGPL-3.0-only",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/sister-software/mailwoman.git",
9
+ "directory": "phrase-grouper"
10
+ },
11
+ "type": "module",
12
+ "exports": {
13
+ "./package.json": "./package.json",
14
+ ".": "./out/index.js"
15
+ },
16
+ "dependencies": {
17
+ "@mailwoman/core": "4.0.0"
18
+ },
19
+ "files": [
20
+ "out/**/*.js",
21
+ "out/**/*.js.map",
22
+ "out/**/*.d.ts",
23
+ "out/**/*.d.ts.map"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ }
28
+ }