@mailwoman/kind-classifier 9.1.0 → 9.3.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/README.md CHANGED
@@ -46,7 +46,7 @@ scoreVague(shape: QueryShapeLike): number
46
46
  ## Pipeline position
47
47
 
48
48
  ```
49
- locale-gate → kind-classifier → phrase-grouper → classifier → ...
49
+ locale-hint → kind-classifier → phrase-grouper → classifier → ...
50
50
  ```
51
51
 
52
52
  ## Design
@@ -59,7 +59,7 @@ locale-gate → kind-classifier → phrase-grouper → classifier → ...
59
59
  ## Related
60
60
 
61
61
  - [`@mailwoman/query-shape`](../query-shape) — feeds structural data into this stage
62
- - [`@mailwoman/locale-gate`](../locale-gate) — feeds locale context
62
+ - [`@mailwoman/locale-hint`](../locale-hint) — feeds locale context
63
63
  - [`@mailwoman/phrase-grouper`](../phrase-grouper) — Stage 2.7, next in the pipeline
64
64
  - [Staged Pipeline Contract](https://github.com/sister-software/mailwoman/blob/main/docs/engineering/reference/STAGES.mdx)
65
65
 
@@ -16,9 +16,9 @@
16
16
  * inform the markers without moving the routing decision.
17
17
  */
18
18
 
19
- import { deriveIntentMarkers } from "./intent-markers.ts"
20
- import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "./intent-rules.ts"
21
- import { createScorePOICategory, createScorePOIQuery, type POIPhraseLookup } from "./poi.ts"
19
+ import { deriveIntentMarkers } from "#intent-markers"
20
+ import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules"
21
+ import { createScorePOICategory, createScorePOIQuery, type POIPhraseLookup } from "#poi"
22
22
  import {
23
23
  scoreIntersection,
24
24
  scoreLandmark,
@@ -28,7 +28,7 @@ import {
28
28
  scoreStructuredAddress,
29
29
  scoreVague,
30
30
  scoreVenueLandmark,
31
- } from "./rules.ts"
31
+ } from "#rules"
32
32
  import type {
33
33
  LocaleHint,
34
34
  NormalizedInputLite,
@@ -36,7 +36,7 @@ import type {
36
36
  QueryKind,
37
37
  QueryKindResult,
38
38
  QueryShapeLike,
39
- } from "./types.ts"
39
+ } from "#types"
40
40
 
41
41
  interface KindScorer {
42
42
  kind: QueryKind
@@ -13,13 +13,13 @@
13
13
  * See `docs/engineering/reference/STAGES.md` § Stage 2.5 for the contract.
14
14
  */
15
15
 
16
- export { classifyKind, classifyKindSync, createKindClassifier } from "./classify.ts"
17
- export type { KindClassifierOpts } from "./classify.ts"
18
- export { deriveIntentMarkers } from "./intent-markers.ts"
19
- export type { IntentMarkerContext } from "./intent-markers.ts"
20
- export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "./intent-rules.ts"
21
- export { matchPOICategory, matchPOISubject } from "./poi.ts"
22
- export type { POIPhraseMatch, POIPhraseLookup, POISubjectMatch } from "./poi.ts"
16
+ export { classifyKind, classifyKindSync, createKindClassifier } from "#classify"
17
+ export type { KindClassifierOpts } from "#classify"
18
+ export { deriveIntentMarkers } from "#intent-markers"
19
+ export type { IntentMarkerContext } from "#intent-markers"
20
+ export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules"
21
+ export { matchPOICategory, matchPOISubject } from "#poi"
22
+ export type { POIPhraseMatch, POIPhraseLookup, POIQuerySpan, POISpatialRelation, POISubjectMatch } from "#poi"
23
23
 
24
24
  export {
25
25
  scoreIntersection,
@@ -30,9 +30,9 @@ export {
30
30
  scoreStructuredAddress,
31
31
  scoreVague,
32
32
  scoreVenueLandmark,
33
- } from "./rules.ts"
33
+ } from "#rules"
34
34
 
35
- export { QueryIntentCode } from "./types.ts"
35
+ export { QueryIntentCode } from "#types"
36
36
 
37
37
  export type {
38
38
  LocaleHint,
@@ -41,4 +41,4 @@ export type {
41
41
  QueryKind,
42
42
  QueryKindResult,
43
43
  QueryShapeLike,
44
- } from "./types.ts"
44
+ } from "#types"
@@ -9,15 +9,15 @@
9
9
  * Three of the four intent kinds can raise their marker here, from the string alone. The fourth —
10
10
  * `bare_toponym`'s `declared_ambiguity` — cannot: its trigger is the dominance margin of the
11
11
  * RESOLVED candidate list, which does not exist yet at Stage 2.5. That one is raised by
12
- * `mailwoman/query-intent.ts` after the resolve, against the measured 0.5-log10 cut. The split is
12
+ * `mailwoman/query-intent.ts` after the resolve, against the measured 0.5-log10 threshold. The split is
13
13
  * deliberate and it is why this module never emits `declared_ambiguity`: a marker that asserted
14
14
  * ambiguity from the string alone would be declaring that every bare city name is ambiguous, which
15
15
  * is false 89.1% of the time (the measured table behind `DECISIVE_MARGIN_LOG10`).
16
16
  */
17
17
 
18
- import { nearMeSubject } from "./intent-rules.ts"
19
- import { matchPOICategory, type POIPhraseLookup } from "./poi.ts"
20
- import type { NormalizedInputLite, QueryIntentMarker, QueryKind } from "./types.ts"
18
+ import { nearMeSubject } from "#intent-rules"
19
+ import { matchPOICategory, type POIPhraseLookup } from "#poi"
20
+ import type { NormalizedInputLite, QueryIntentMarker, QueryKind } from "#types"
21
21
 
22
22
  /**
23
23
  * Context the marker builder needs beyond the scored kinds.
@@ -50,6 +50,8 @@ export function deriveIntentMarkers(
50
50
  const markers: QueryIntentMarker[] = []
51
51
 
52
52
  if (fired.has("route_pair")) {
53
+ // Whitespace-only split, not `wordsOf`: `route_pair` inputs are comma-free by construction (a comma
54
+ // disqualifies the kind), and the tokens are re-joined verbatim into the message.
53
55
  const tokens = ctx.input.normalized.trim().split(/\s+/)
54
56
 
55
57
  markers.push({
@@ -79,9 +81,9 @@ export function deriveIntentMarkers(
79
81
  evidence: {
80
82
  subject,
81
83
  /**
82
- * The SEAM, named but not wired (ROAD_TO_V9 §4.4 scopes v9 to classification). Photon's `/api` already accepts
83
- * `lat`/`lon` location-bias params — `photon/` is the eventual consumer of this marker, and this string is the
84
- * note that says where it plugs in.
84
+ * THE PLUG POINT, named but not wired (ROAD_TO_V9 §4.4 scopes v9 to classification). Photon's `/api` already
85
+ * accepts `lat`/`lon` location-bias params — `photon/` is the eventual consumer of this marker, and this string
86
+ * is the note that says where it plugs in.
85
87
  */
86
88
  focusParameter: "photon:lat/lon",
87
89
  },
@@ -23,8 +23,8 @@
23
23
  * ending "near me" is not a locality and answering it as one is the bug.
24
24
  */
25
25
 
26
- import { MAX_LOCALITY_ONLY_LENGTH, STREET_SUFFIXES } from "./rules.ts"
27
- import type { NormalizedInputLite, QueryShapeLike } from "./types.ts"
26
+ import { isDisqualifyingStreetSuffix, MAX_LOCALITY_ONLY_LENGTH, wordsOf } from "#rules"
27
+ import type { NormalizedInputLite, QueryShapeLike } from "#types"
28
28
 
29
29
  /**
30
30
  * `locality_only` scores 0.85. Both refinement kinds sit under it by a whole confidence step so no float-comparison
@@ -186,13 +186,6 @@ const DEICTIC_LOCATOR_TAIL =
186
186
  const DEICTIC_ADVERB_TAIL =
187
187
  /\b(?:nearby|near\s?by|close\s+by|around\s+here|in\s+my\s+(?:area|neighborhood|neighbourhood))\s*$/
188
188
 
189
- /**
190
- * Split on whitespace + commas, the way the other rules in this package do.
191
- */
192
- function wordsOf(text: string): string[] {
193
- return text.split(/[\s,]+/).filter(Boolean)
194
- }
195
-
196
189
  /**
197
190
  * True when the input carries a deictic locator tail in EITHER form.
198
191
  */
@@ -201,12 +194,12 @@ function hasDeicticTail(lowercased: string): boolean {
201
194
  }
202
195
 
203
196
  /**
204
- * The gates `bare_toponym` and `route_pair` share: no address grammar of any kind, one segment, alpha throughout.
197
+ * The conditions `bare_toponym` and `route_pair` share: no address grammar of any kind, one segment, alpha throughout.
205
198
  *
206
199
  * Returns the word list when the input clears them, `null` when it does not. Deliberately a SUPERSET of
207
- * `scoreLocalityOnly`'s gates (which admits two segments), so `bare_toponym` is a strict refinement of `locality_only`
208
- * and can never fire where `locality_only` did not — the property `intent-rules.test.ts` asserts and the reason the
209
- * ranking discipline above is enough to keep the top kind pinned.
200
+ * `scoreLocalityOnly`'s conditions (which admit two segments), so `bare_toponym` is a strict refinement of
201
+ * `locality_only` and can never fire where `locality_only` did not — the property `intent-rules.test.ts` asserts and
202
+ * the reason the ranking discipline above is enough to keep the top kind pinned.
210
203
  */
211
204
  function bareNameWords(input: NormalizedInputLite, shape: QueryShapeLike): string[] | null {
212
205
  const text = input.normalized.trim()
@@ -232,7 +225,7 @@ function bareNameWords(input: NormalizedInputLite, shape: QueryShapeLike): strin
232
225
  if (!words.length || words.length > MAX_BARE_TOPONYM_WORDS) return null
233
226
 
234
227
  for (const word of words) {
235
- if (STREET_SUFFIXES.has(word.toLowerCase())) return null
228
+ if (isDisqualifyingStreetSuffix(word)) return null
236
229
  }
237
230
 
238
231
  return words
@@ -9,7 +9,7 @@
9
9
  * `poiQueryKind` flag (default-ON since 2026-07-20). Spec §3.1.
10
10
  */
11
11
 
12
- import type { NormalizedInputLite, QueryShapeLike } from "./types.ts"
12
+ import type { NormalizedInputLite, QueryShapeLike } from "#types"
13
13
 
14
14
  /**
15
15
  * Comma-segment ceiling for a POI-led query. Past it the input is a venue plus a full address (`X, 350 5th Ave, New
@@ -22,22 +22,49 @@ const MAX_POI_SEGMENTS = 3
22
22
  */
23
23
  export interface POIPhraseMatch {
24
24
  /**
25
- * The matched subject's identifier string. For `kind: "category"`, a `@mailwoman/poi-taxonomy` category id. For
26
- * `kind: "brand"`, the brand's canonical display name (NOT a taxonomy id) — `matchPOISubject` never reads this field
27
- * itself, so the caller (`mailwoman`'s `poi-intent.ts`) is the one that interprets it per `kind`.
25
+ * The matched subject's identifier string. For `kind: "category"`, a `@mailwoman/poi-taxonomy` category id; for
26
+ * `kind: "brand"` or `kind: "name"`, the canonical display name. `matchPOISubject` treats it opaquely; the caller
27
+ * (`mailwoman`'s `poi-intent.ts`) interprets it per `kind`.
28
28
  */
29
29
  categoryID: string
30
30
  matchedPhrase: string
31
31
  confidence: number
32
+ mechanism?: "exact" | "locale_normalized" | "typo"
33
+ inputPhrase?: string
32
34
  /**
33
35
  * Absent = "category" (the pre-brand shape) — optional so pre-7.3 POIPhraseLookup implementors stay
34
36
  * source-compatible.
35
37
  */
36
- kind?: "category" | "brand"
38
+ kind?: "category" | "brand" | "name"
37
39
  /**
38
40
  * Wikidata QID, when known. `kind: "brand"` only — absent when a brand resolved by name alone (no QID match).
39
41
  */
40
42
  wikidata?: string
43
+ /**
44
+ * Whether this hit is one member of a set the caller must search TOGETHER, rather than one candidate in a preference
45
+ * list.
46
+ *
47
+ * A lookup returning several hits means two different things, and the difference decides whether narrowing to the
48
+ * first is an answer or an invented ordering. A phrase index returns the categories one typed phrase could name, the
49
+ * curated reading first (`credit union` → the `bank` rollup its synonym redirects to, then the standalone
50
+ * `credit_union` category), and the first entry IS the subject. An affordance rung returns every entity kind that
51
+ * affords ONE activity, in a stable enumeration that is not a preference, and taking the first picks a winner nobody
52
+ * authored.
53
+ *
54
+ * Set on every member of such a set. {@link matchPOISubject} then carries them all, the POI branch searches their
55
+ * union, and the candidate ordering the resolver already owns decides the answer. Absent — the committed lexicon's
56
+ * shape — keeps the first-hit reading unchanged.
57
+ */
58
+ searchAsSet?: boolean
59
+ /**
60
+ * ISO 3166-1 alpha-2 countries the authority behind this hit scopes its claim to. Absent = the claim holds
61
+ * everywhere.
62
+ *
63
+ * A scope is a statement about ESTABLISHMENTS, so it is judged against the country of the place being searched, not
64
+ * the caller's locale: the locale is the lens the phrase is read through, and it says nothing about where the claim
65
+ * holds. `matchPOISubject` carries the value untouched; the POI intent stage binds it once the anchor has resolved.
66
+ */
67
+ countryScope?: readonly string[]
41
68
  }
42
69
 
43
70
  /**
@@ -45,24 +72,54 @@ export interface POIPhraseMatch {
45
72
  */
46
73
  export type POIPhraseLookup = (phrase: string, locale?: string) => ReadonlyArray<POIPhraseMatch>
47
74
 
75
+ export type POISpatialRelation = "comma" | "near" | "in" | "at" | "around" | "to"
76
+
77
+ export interface POIQuerySpan {
78
+ text: string
79
+ /**
80
+ * Half-open character offsets into the normalized input.
81
+ */
82
+ start: number
83
+ end: number
84
+ }
85
+
48
86
  /**
49
87
  * Which lexicon this hit came from. Existing category lookups set `"category"` (backward-compatible default).
50
88
  */
51
89
  export interface POISubjectMatch {
90
+ /**
91
+ * The hit the subject SCORES under — its kind and its confidence. Always `matches[0]`; the two are built together in
92
+ * one place so they cannot disagree.
93
+ */
52
94
  match: POIPhraseMatch
95
+ /**
96
+ * Every category the subject reaches, `match` first.
97
+ *
98
+ * One entry unless the lookup returned a {@link POIPhraseMatch.searchAsSet} set, in which case it holds the whole set
99
+ * and the POI branch searches their union. The order is the order the lookup returned and states no preference:
100
+ * nothing downstream may read position as rank.
101
+ */
102
+ matches: POIPhraseMatch[]
53
103
  /**
54
104
  * The matched subject text as it appeared in the query.
55
105
  */
56
106
  subject: string
107
+ subjectSpan: POIQuerySpan
108
+ /**
109
+ * The relation crossing from the subject span to the anchor span.
110
+ */
111
+ relation?: POISpatialRelation
112
+ relationSpan?: POIQuerySpan
57
113
  /**
58
114
  * The anchor remainder after the separator; `""` when the whole input matched.
59
115
  */
60
116
  remainder: string
117
+ anchorSpan?: POIQuerySpan
61
118
  }
62
119
 
63
120
  /**
64
- * Anchor separator between subject and place: comma, or near/in/at/around — scanned left-to-right until a prefix hits
65
- * the lexicon.
121
+ * Anchor separator between subject and place: comma, or near/in/at/around/to — scanned left-to-right until a prefix
122
+ * hits the lexicon.
66
123
  *
67
124
  * Linear by construction (no polynomial ReDoS): neither alternative places an unbounded whitespace quantifier _before_
68
125
  * its required literal — the classic `\s*`/`\s+`-then-literal backtracking shape that CodeQL's `js/polynomial-redos`
@@ -78,18 +135,33 @@ export interface POISubjectMatch {
78
135
  * lastIndex) identical, preserving the exact subsequent-match sequence. Verified: 0 divergences across 22.7k inputs
79
136
  * (systematic + fuzzed adversarial whitespace + shared-whitespace anchor/comma chains).
80
137
  */
81
- const ANCHOR_SEPARATOR = /,\s*|\s(?:near|in|at|around)\s+/gi
138
+ const ANCHOR_SEPARATOR = /,\s*|\s(near|in|at|around|to)\s+/gi
139
+
140
+ /**
141
+ * Longest subject we accept, in tokens. Eight covers compound taxonomy phrases while bounding lexicon probes.
142
+ */
143
+ const MAX_SUBJECT_TOKENS = 8
82
144
 
83
145
  /**
84
- * Longest subject we accept, in tokens. Lexicon phrases are short; 4 covers the table.
146
+ * The categories one candidate subject reaches, from the hits the lookup returned for it.
147
+ *
148
+ * The whole array when the first hit declares {@link POIPhraseMatch.searchAsSet} — carried as the lookup returned it,
149
+ * never filtered, so a rung that flagged only some of its members loses nothing here and the inconsistency stays
150
+ * visible to whoever reads the set. Otherwise the first hit alone, which is the preference-list reading the committed
151
+ * phrase index has always had.
85
152
  */
86
- const MAX_SUBJECT_TOKENS = 4
153
+ function reachedMatches(hits: ReadonlyArray<POIPhraseMatch>): POIPhraseMatch[] {
154
+ return hits[0]!.searchAsSet ? [...hits] : [hits[0]!]
155
+ }
87
156
 
88
157
  /**
89
158
  * Match a POI subject: the whole input, or the text before the FIRST anchor separator WHOSE PREFIX HITS THE LEXICON (≤
90
- * 4 tokens). Scans separator occurrences left-to-right — a lexicon phrase may itself contain a bare separator word
159
+ * 8 tokens). Scans separator occurrences left-to-right — a lexicon phrase may itself contain a bare separator word
91
160
  * (e.g. "walk in clinic"), so the first separator isn't necessarily the right split point. Returns null when the
92
161
  * lexicon never fires — including comma-ridden full addresses whose leading segment isn't a lexicon phrase.
162
+ *
163
+ * The winning candidate's hits are carried per {@link reachedMatches}: the first hit, or the whole set when the lookup
164
+ * declared one.
93
165
  */
94
166
  export function matchPOISubject(
95
167
  text: string,
@@ -97,13 +169,22 @@ export function matchPOISubject(
97
169
  lookup: POIPhraseLookup
98
170
  ): POISubjectMatch | null {
99
171
  const trimmed = text.trim()
172
+ const inputStart = text.indexOf(trimmed)
100
173
 
101
174
  if (!trimmed) return null
102
175
 
103
176
  const whole = lookup(trimmed, locale)
104
177
 
105
178
  if (whole.length) {
106
- return { match: whole[0]!, subject: trimmed, remainder: "" }
179
+ const matches = reachedMatches(whole)
180
+
181
+ return {
182
+ match: matches[0]!,
183
+ matches,
184
+ subject: trimmed,
185
+ subjectSpan: { text: trimmed, start: inputStart, end: inputStart + trimmed.length },
186
+ remainder: "",
187
+ }
107
188
  }
108
189
 
109
190
  for (const separator of trimmed.matchAll(ANCHOR_SEPARATOR)) {
@@ -111,7 +192,8 @@ export function matchPOISubject(
111
192
 
112
193
  const subject = trimmed.slice(0, separator.index).trim()
113
194
 
114
- // Subjects only grow as the scan moves right — once over budget, later splits are too.
195
+ // Subjects only grow as the scan moves right — once over budget, later splits are too. Whitespace-only
196
+ // split, not `wordsOf`: a comma inside a subject is real content here, not a separator to erase.
115
197
  if (subject.split(/\s+/).length > MAX_SUBJECT_TOKENS) break
116
198
 
117
199
  const hits = lookup(subject, locale)
@@ -120,7 +202,36 @@ export function matchPOISubject(
120
202
 
121
203
  const remainder = trimmed.slice(separator.index + separator[0].length).trim()
122
204
 
123
- return { match: hits[0]!, subject, remainder }
205
+ if (!remainder) continue
206
+
207
+ const subjectOffset = trimmed.slice(0, separator.index).indexOf(subject)
208
+ const anchorOffset = trimmed.indexOf(remainder, separator.index + separator[0].length)
209
+ const relationText = separator[1] ?? ","
210
+ const relationOffset = separator[1] ? separator.index + separator[0].indexOf(separator[1]) : separator.index
211
+ const matches = reachedMatches(hits)
212
+
213
+ return {
214
+ match: matches[0]!,
215
+ matches,
216
+ subject,
217
+ subjectSpan: {
218
+ text: subject,
219
+ start: inputStart + subjectOffset,
220
+ end: inputStart + subjectOffset + subject.length,
221
+ },
222
+ relation: relationText === "," ? "comma" : (relationText.toLowerCase() as POISpatialRelation),
223
+ relationSpan: {
224
+ text: relationText,
225
+ start: inputStart + relationOffset,
226
+ end: inputStart + relationOffset + relationText.length,
227
+ },
228
+ remainder,
229
+ anchorSpan: {
230
+ text: remainder,
231
+ start: inputStart + anchorOffset,
232
+ end: inputStart + anchorOffset + remainder.length,
233
+ },
234
+ }
124
235
  }
125
236
 
126
237
  return null
@@ -188,7 +299,7 @@ export function createScorePOICategory(
188
299
 
189
300
  /**
190
301
  * The whole-input category hit behind a `poi_category` verdict, for the marker's evidence. `null` when the input is not
191
- * a bare category — same gates as {@link createScorePOICategory}, so the two cannot disagree.
302
+ * a bare category — same conditions as {@link createScorePOICategory}, so the two cannot disagree.
192
303
  */
193
304
  export function matchPOICategory(
194
305
  text: string,
@@ -10,7 +10,9 @@
10
10
  * regex set per new locale, not 50K dictionary entries.
11
11
  */
12
12
 
13
- import type { NormalizedInputLite, QueryShapeLike } from "./types.ts"
13
+ import { NAME_PRONE_US_SUFFIXES, US_STREET_SUFFIX_LOOKUP } from "@mailwoman/codex/us/street-suffix"
14
+
15
+ import type { NormalizedInputLite, QueryShapeLike } from "#types"
14
16
 
15
17
  /**
16
18
  * Longest input still plausible as a bare venue or landmark name. Beyond it the query is carrying an address as well,
@@ -128,34 +130,25 @@ export function scoreLandmark(input: NormalizedInputLite, _shape: QueryShapeLike
128
130
  }
129
131
 
130
132
  /**
131
- * Street-suffix tokens that indicate an address, not a venue name. Shared with `intent-rules.ts` the intent kinds
132
- * disqualify on the same vocabulary, and a second copy would drift.
133
+ * Split on whitespace + commas and drop empty words the word grammar shared with `intent-rules.ts`. Dropping empties
134
+ * matters: a trailing comma or doubled separator otherwise yields an empty string that inflates the word count and
135
+ * falsifies every-word predicates like the proper-case check below.
133
136
  */
134
- export const STREET_SUFFIXES: ReadonlySet<string> = new Set([
135
- "st",
136
- "street",
137
- "ave",
138
- "avenue",
139
- "blvd",
140
- "boulevard",
141
- "rd",
142
- "road",
143
- "dr",
144
- "drive",
145
- "ln",
146
- "lane",
147
- "ct",
148
- "court",
149
- "pl",
150
- "place",
151
- "way",
152
- "pkwy",
153
- "parkway",
154
- "hwy",
155
- "highway",
156
- "cir",
157
- "circle",
158
- ])
137
+ export function wordsOf(text: string): string[] {
138
+ return text.split(/[\s,]+/).filter((word) => word.length > 0)
139
+ }
140
+
141
+ /**
142
+ * True when a word is USPS street-suffix vocabulary that unambiguously signals an address — the full Pub-28 table via
143
+ * `@mailwoman/codex`, minus its curated name-prone canonicals (PARK, FIELD, HILL, LAKE, …). Those double as ordinary
144
+ * proper-name heads ("Wrigley Field", "Menlo Park"), and disqualifying on them would reject the very venue and place
145
+ * names the rules below exist to capture. Shared with `intent-rules.ts` so both rule sets read one definition.
146
+ */
147
+ export function isDisqualifyingStreetSuffix(word: string): boolean {
148
+ const canonical = US_STREET_SUFFIX_LOOKUP.get(word.trim().toLowerCase())
149
+
150
+ return canonical !== undefined && !NAME_PRONE_US_SUFFIXES.has(canonical)
151
+ }
159
152
 
160
153
  /**
161
154
  * `landmark` rule (venue/named-place variant): short capitalized input with no street suffixes, no postcode hits, and
@@ -181,11 +174,11 @@ export function scoreVenueLandmark(input: NormalizedInputLite, shape: QueryShape
181
174
 
182
175
  if (segCount > 2) return 0
183
176
 
184
- // Reject if any word is a street suffix.
185
- const words = text.split(/[\s,]+/)
177
+ // Reject if any word is an unambiguous street suffix.
178
+ const words = wordsOf(text)
186
179
 
187
180
  for (const w of words) {
188
- if (STREET_SUFFIXES.has(w.toLowerCase())) return 0
181
+ if (isDisqualifyingStreetSuffix(w)) return 0
189
182
  }
190
183
 
191
184
  // Reject if the first token is a pure number (house-number-leading pattern).
@@ -228,6 +221,10 @@ const POSTCODE_FORMATS: ReadonlySet<string> = new Set([
228
221
  "ca_postcode",
229
222
  "jp_postcode",
230
223
  "nl_postcode",
224
+ "cz_postcode",
225
+ "sk_postcode",
226
+ "se_postcode",
227
+ "gr_postcode",
231
228
  ])
232
229
 
233
230
  /**
package/lib/types.ts ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+
7
+ /**
8
+ * Re-exports of the canonical types from `@mailwoman/core/pipeline`.
9
+ */
10
+ export type { LocaleHint, QueryIntentMarker, QueryKind, QueryKindResult } from "@mailwoman/core/pipeline"
11
+ export { QueryIntentCode } from "@mailwoman/core/pipeline"
12
+
13
+ /**
14
+ * The minimal input shapes consumed by `classifyKind` come from `@mailwoman/query-shape` — one declaration shared by
15
+ * every Stage-2.x consumer. `QueryShapeLike` stays this package's public name for its narrow read-only view.
16
+ */
17
+ export type { NormalizedInputLite, QueryShapeSegmentsView as QueryShapeLike } from "@mailwoman/query-shape"
package/out/classify.d.ts CHANGED
@@ -15,8 +15,8 @@
15
15
  * are scored below their structural incumbent precisely so they land in `alternatives`, where they
16
16
  * inform the markers without moving the routing decision.
17
17
  */
18
- import { type POIPhraseLookup } from "./poi.ts";
19
- import type { LocaleHint, NormalizedInputLite, QueryKindResult, QueryShapeLike } from "./types.ts";
18
+ import { type POIPhraseLookup } from "#poi";
19
+ import type { LocaleHint, NormalizedInputLite, QueryKindResult, QueryShapeLike } from "#types";
20
20
  /**
21
21
  * Classify the query shape into a `QueryKind`. Synchronous + pure — produces the same result for the same `(input,
22
22
  * shape)` pair.
@@ -1 +1 @@
1
- {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAA+C,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAW5F,OAAO,KAAK,EACX,UAAU,EACV,mBAAmB,EAGnB,eAAe,EACf,cAAc,EACd,MAAM,YAAY,CAAA;AAkEnB;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,GAAG,eAAe,CAMnG;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CACjC,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,eAAe,CAAC,CAE1B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,GAAE,kBAAuB,GAC3B,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,eAAe,CAAC,CA+BtG"}
1
+ {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../lib/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAA+C,KAAK,eAAe,EAAE,MAAM,MAAM,CAAA;AAWxF,OAAO,KAAK,EACX,UAAU,EACV,mBAAmB,EAGnB,eAAe,EACf,cAAc,EACd,MAAM,QAAQ,CAAA;AAkEf;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,GAAG,eAAe,CAMnG;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CACjC,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,eAAe,CAAC,CAE1B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,GAAE,kBAAuB,GAC3B,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,eAAe,CAAC,CA+BtG"}
package/out/classify.js CHANGED
@@ -15,10 +15,10 @@
15
15
  * are scored below their structural incumbent precisely so they land in `alternatives`, where they
16
16
  * inform the markers without moving the routing decision.
17
17
  */
18
- import { deriveIntentMarkers } from "./intent-markers.js";
19
- import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "./intent-rules.js";
20
- import { createScorePOICategory, createScorePOIQuery } from "./poi.js";
21
- import { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "./rules.js";
18
+ import { deriveIntentMarkers } from "#intent-markers";
19
+ import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules";
20
+ import { createScorePOICategory, createScorePOIQuery } from "#poi";
21
+ import { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "#rules";
22
22
  const SCORERS = [
23
23
  { kind: "po_box", score: scorePoBox },
24
24
  { kind: "landmark", score: (i, s) => Math.max(scoreLandmark(i, s), scoreVenueLandmark(i, s)) },
@@ -1 +1 @@
1
- {"version":3,"file":"classify.js","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"classify.js","sourceRoot":"","sources":["../lib/classify.ts"],"names":[],"mappings":"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"}
package/out/index.d.ts CHANGED
@@ -12,14 +12,14 @@
12
12
  *
13
13
  * See `docs/engineering/reference/STAGES.md` § Stage 2.5 for the contract.
14
14
  */
15
- export { classifyKind, classifyKindSync, createKindClassifier } from "./classify.ts";
16
- export type { KindClassifierOpts } from "./classify.ts";
17
- export { deriveIntentMarkers } from "./intent-markers.ts";
18
- export type { IntentMarkerContext } from "./intent-markers.ts";
19
- export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "./intent-rules.ts";
20
- export { matchPOICategory, matchPOISubject } from "./poi.ts";
21
- export type { POIPhraseMatch, POIPhraseLookup, POISubjectMatch } from "./poi.ts";
22
- export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "./rules.ts";
23
- export { QueryIntentCode } from "./types.ts";
24
- export type { LocaleHint, NormalizedInputLite, QueryIntentMarker, QueryKind, QueryKindResult, QueryShapeLike, } from "./types.ts";
15
+ export { classifyKind, classifyKindSync, createKindClassifier } from "#classify";
16
+ export type { KindClassifierOpts } from "#classify";
17
+ export { deriveIntentMarkers } from "#intent-markers";
18
+ export type { IntentMarkerContext } from "#intent-markers";
19
+ export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules";
20
+ export { matchPOICategory, matchPOISubject } from "#poi";
21
+ export type { POIPhraseMatch, POIPhraseLookup, POIQuerySpan, POISpatialRelation, POISubjectMatch } from "#poi";
22
+ export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "#rules";
23
+ export { QueryIntentCode } from "#types";
24
+ export type { LocaleHint, NormalizedInputLite, QueryIntentMarker, QueryKind, QueryKindResult, QueryShapeLike, } from "#types";
25
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACpF,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAChG,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC5D,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAEhF,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,GAClB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5C,YAAY,EACX,UAAU,EACV,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,cAAc,GACd,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChF,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AACxD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAE9G,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,GAClB,MAAM,QAAQ,CAAA;AAEf,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AAExC,YAAY,EACX,UAAU,EACV,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,cAAc,GACd,MAAM,QAAQ,CAAA"}
package/out/index.js CHANGED
@@ -12,10 +12,10 @@
12
12
  *
13
13
  * See `docs/engineering/reference/STAGES.md` § Stage 2.5 for the contract.
14
14
  */
15
- export { classifyKind, classifyKindSync, createKindClassifier } from "./classify.js";
16
- export { deriveIntentMarkers } from "./intent-markers.js";
17
- export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "./intent-rules.js";
18
- export { matchPOICategory, matchPOISubject } from "./poi.js";
19
- export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "./rules.js";
20
- export { QueryIntentCode } from "./types.js";
15
+ export { classifyKind, classifyKindSync, createKindClassifier } from "#classify";
16
+ export { deriveIntentMarkers } from "#intent-markers";
17
+ export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules";
18
+ export { matchPOICategory, matchPOISubject } from "#poi";
19
+ export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "#rules";
20
+ export { QueryIntentCode } from "#types";
21
21
  //# sourceMappingURL=index.js.map
package/out/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAEzD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAChG,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG5D,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,GAClB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAEhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAErD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAGxD,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,GAClB,MAAM,QAAQ,CAAA;AAEf,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA"}