@mailwoman/kind-classifier 9.0.0 → 9.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAWpE,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAa,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAiB7G;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,GAAG,eAAe,CAenG;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,CA2BtG"}
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"}
package/out/classify.js CHANGED
@@ -5,14 +5,19 @@
5
5
  *
6
6
  * `classifyKind` — entry point for Stage 2.5 (kind classification).
7
7
  *
8
- * Composes the per-kind rules from `rules.ts` and picks the winner. Returns alternatives sorted by
9
- * confidence so the coordinator can offer fallback paths when the top kind isn't actionable.
8
+ * Composes the per-kind rules from `rules.ts` and `intent-rules.ts` and picks the winner. Returns
9
+ * alternatives sorted by confidence so the coordinator can offer fallback paths when the top kind
10
+ * isn't actionable.
10
11
  *
11
12
  * Per the project's "possibilities not constraints" principle, every kind that fires above 0
12
13
  * surfaces in `alternatives` — the caller decides whether to act on the top kind only or consider
13
- * runner-ups.
14
+ * runner-ups. The ROAD_TO_V9 §4 intent vocabulary leans on that: `bare_toponym` and `route_pair`
15
+ * are scored below their structural incumbent precisely so they land in `alternatives`, where they
16
+ * inform the markers without moving the routing decision.
14
17
  */
15
- import { createScorePOIQuery } from "./poi.js";
18
+ import { deriveIntentMarkers } from "./intent-markers.js";
19
+ import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "./intent-rules.js";
20
+ import { createScorePOICategory, createScorePOIQuery } from "./poi.js";
16
21
  import { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "./rules.js";
17
22
  const SCORERS = [
18
23
  { kind: "po_box", score: scorePoBox },
@@ -21,23 +26,53 @@ const SCORERS = [
21
26
  { kind: "postcode_only", score: scorePostcodeOnly },
22
27
  { kind: "locality_only", score: scoreLocalityOnly },
23
28
  { kind: "structured_address", score: scoreStructuredAddress },
29
+ // ROAD_TO_V9 §4. Ordinary members of the same list — intent is vocabulary, not a stage. `bare_toponym` and
30
+ // `route_pair` are scored under `locality_only` on purpose (see `intent-rules.ts`), so their position here is
31
+ // cosmetic; the sort below is what decides.
32
+ { kind: "bare_toponym", score: scoreBareToponym },
33
+ { kind: "route_pair", score: scoreRoutePair },
34
+ { kind: "near_me", score: scoreNearMe },
24
35
  { kind: "vague", score: scoreVague },
25
36
  ];
26
37
  /**
27
- * Classify the query shape into a `QueryKind`. Synchronous + pure produces the same result for the same `(input,
28
- * shape)` pair.
38
+ * Rank a scored list and shape it into a verdict. Shared by the lexicon-free and lexicon-wired paths so the two cannot
39
+ * drift in how they break ties or build `alternatives`.
29
40
  */
30
- export function classifyKindSync(input, shape) {
31
- const scored = SCORERS.map((s) => ({ kind: s.kind, confidence: s.score(input, shape) })).filter((s) => s.confidence > 0);
41
+ function rank(scored) {
32
42
  scored.sort((a, b) => b.confidence - a.confidence);
33
43
  const top = scored[0] ?? { kind: "vague", confidence: 0.3 };
34
- const alternatives = scored.slice(1).map((s) => ({ kind: s.kind, confidence: s.confidence }));
35
44
  return {
36
45
  kind: top.kind,
37
46
  confidence: top.confidence,
38
- alternatives,
47
+ alternatives: scored.slice(1).map((s) => ({ kind: s.kind, confidence: s.confidence })),
39
48
  };
40
49
  }
50
+ /**
51
+ * Every kind whose verdict carries `intentMarkers`. Checked before the marker builder runs so the hot path — a
52
+ * structured address, where none of these fire — pays one set membership test per kind and nothing else.
53
+ */
54
+ const MARKER_BEARING_KINDS = new Set(["route_pair", "near_me", "poi_category"]);
55
+ /**
56
+ * Attach markers to a verdict, or return it untouched. Separate from {@link rank} because the lexicon-wired path needs
57
+ * to merge `poi_query`/`poi_category` in first.
58
+ */
59
+ function withIntentMarkers(verdict, input, poiLexicon, locale) {
60
+ const kinds = [{ kind: verdict.kind, confidence: verdict.confidence }, ...verdict.alternatives];
61
+ if (!kinds.some((k) => MARKER_BEARING_KINDS.has(k.kind)))
62
+ return verdict;
63
+ const intentMarkers = deriveIntentMarkers(kinds, { input, poiLexicon, locale });
64
+ if (!intentMarkers.length)
65
+ return verdict;
66
+ return { ...verdict, intentMarkers };
67
+ }
68
+ /**
69
+ * Classify the query shape into a `QueryKind`. Synchronous + pure — produces the same result for the same `(input,
70
+ * shape)` pair.
71
+ */
72
+ export function classifyKindSync(input, shape) {
73
+ const scored = SCORERS.map((s) => ({ kind: s.kind, confidence: s.score(input, shape) })).filter((s) => s.confidence > 0);
74
+ return withIntentMarkers(rank(scored), input);
75
+ }
41
76
  /**
42
77
  * Async variant matching the runtime-pipeline's `classifyKind` contract.
43
78
  *
@@ -48,30 +83,33 @@ export async function classifyKind(input, shape, _locale) {
48
83
  }
49
84
  /**
50
85
  * Build a kind classifier. Without opts this is exactly the default {@link classifyKind}; with a `poiLexicon` it
51
- * additionally scores `poi_query` and merges it into the ranked result.
86
+ * additionally scores `poi_query` + `poi_category` (ROAD_TO_V9 §4.4) and merges them into the ranked result.
52
87
  */
53
88
  export function createKindClassifier(opts = {}) {
54
89
  const { poiLexicon } = opts;
55
90
  if (!poiLexicon)
56
91
  return classifyKind;
57
92
  return async (input, shape, locale) => {
93
+ const localeTag = locale?.locale;
58
94
  const base = classifyKindSync(input, shape);
59
- const poiConfidence = createScorePOIQuery(poiLexicon, locale?.locale)(input, shape);
60
- if (poiConfidence <= 0)
95
+ const poiConfidence = createScorePOIQuery(poiLexicon, localeTag)(input, shape);
96
+ const categoryConfidence = createScorePOICategory(poiLexicon, localeTag)(input, shape);
97
+ if (poiConfidence <= 0 && categoryConfidence <= 0)
61
98
  return base;
62
- if (poiConfidence > base.confidence) {
63
- return {
64
- kind: "poi_query",
65
- confidence: poiConfidence,
66
- alternatives: [{ kind: base.kind, confidence: base.confidence }, ...base.alternatives],
67
- };
99
+ // Re-rank over the union rather than special-casing "did POI beat the base?". The base verdict's own
100
+ // alternatives are preserved, which is what keeps `bare_toponym` / `route_pair` visible to the marker builder
101
+ // even when a POI kind takes the top slot.
102
+ const merged = [
103
+ { kind: base.kind, confidence: base.confidence },
104
+ ...base.alternatives,
105
+ ];
106
+ if (poiConfidence > 0) {
107
+ merged.push({ kind: "poi_query", confidence: poiConfidence });
108
+ }
109
+ if (categoryConfidence > 0) {
110
+ merged.push({ kind: "poi_category", confidence: categoryConfidence });
68
111
  }
69
- // The literal needs the contextual element type — a bare array literal widens `kind` to string.
70
- const poiAlternative = { kind: "poi_query", confidence: poiConfidence };
71
- return {
72
- ...base,
73
- alternatives: [...base.alternatives, poiAlternative].toSorted((a, b) => b.confidence - a.confidence),
74
- };
112
+ return withIntentMarkers(rank(merged), input, poiLexicon, localeTag);
75
113
  };
76
114
  }
77
115
  //# sourceMappingURL=classify.js.map
@@ -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":["../classify.ts"],"names":[],"mappings":"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"}
package/out/index.d.ts CHANGED
@@ -14,8 +14,12 @@
14
14
  */
15
15
  export { classifyKind, classifyKindSync, createKindClassifier } from "./classify.ts";
16
16
  export type { KindClassifierOpts } from "./classify.ts";
17
- export { matchPOISubject } from "./poi.ts";
18
- export type { POIPhraseMatch, POIPhraseLookup, POISubjectMatch } from "./poi.ts";
19
- export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, } from "./rules.ts";
20
- export type { LocaleHint, NormalizedInputLite, QueryKind, QueryKindResult, QueryShapeLike } from "./types.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, POIQuerySpan, POISpatialRelation, 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";
21
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,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,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,GACV,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
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,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAElH,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"}
package/out/index.js CHANGED
@@ -13,6 +13,9 @@
13
13
  * See `docs/engineering/reference/STAGES.md` § Stage 2.5 for the contract.
14
14
  */
15
15
  export { classifyKind, classifyKindSync, createKindClassifier } from "./classify.js";
16
- export { matchPOISubject } from "./poi.js";
17
- export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, } from "./rules.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";
18
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,eAAe,EAAE,MAAM,UAAU,CAAA;AAG1C,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,GACV,MAAM,YAAY,CAAA"}
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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Marker derivation for the ROAD_TO_V9 §4 intent vocabulary. Pure, synchronous, and the ONLY place
7
+ * the classifier turns a fired rule into something a caller reads.
8
+ *
9
+ * Three of the four intent kinds can raise their marker here, from the string alone. The fourth —
10
+ * `bare_toponym`'s `declared_ambiguity` — cannot: its trigger is the dominance margin of the
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
13
+ * deliberate and it is why this module never emits `declared_ambiguity`: a marker that asserted
14
+ * ambiguity from the string alone would be declaring that every bare city name is ambiguous, which
15
+ * is false 89.1% of the time (the measured table behind `DECISIVE_MARGIN_LOG10`).
16
+ */
17
+ import { type POIPhraseLookup } from "./poi.ts";
18
+ import type { NormalizedInputLite, QueryIntentMarker, QueryKind } from "./types.ts";
19
+ /**
20
+ * Context the marker builder needs beyond the scored kinds.
21
+ */
22
+ export interface IntentMarkerContext {
23
+ input: NormalizedInputLite;
24
+ /**
25
+ * The injected POI lexicon, when one was wired. Absent → no `poi_category` marker can be built, which is consistent
26
+ * because the kind cannot fire without it either.
27
+ */
28
+ poiLexicon?: POIPhraseLookup;
29
+ locale?: string;
30
+ }
31
+ /**
32
+ * Build the advisories for one classified query.
33
+ *
34
+ * `kinds` is the FULL verdict — top plus alternatives — because two of the four intent kinds live in `alternatives` by
35
+ * design (see `intent-rules.ts`). Reading only the top kind would make them invisible, which is the mistake this
36
+ * signature exists to prevent.
37
+ *
38
+ * Returns `[]` when no intent kind fired. Callers surface that empty array rather than dropping the field: an empty
39
+ * array is the classifier stating it looked.
40
+ */
41
+ export declare function deriveIntentMarkers(kinds: ReadonlyArray<{
42
+ kind: QueryKind;
43
+ confidence: number;
44
+ }>, ctx: IntentMarkerContext): QueryIntentMarker[];
45
+ //# sourceMappingURL=intent-markers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-markers.d.ts","sourceRoot":"","sources":["../intent-markers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEnF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,mBAAmB,CAAA;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,EAC7D,GAAG,EAAE,mBAAmB,GACtB,iBAAiB,EAAE,CA8DrB"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Marker derivation for the ROAD_TO_V9 §4 intent vocabulary. Pure, synchronous, and the ONLY place
7
+ * the classifier turns a fired rule into something a caller reads.
8
+ *
9
+ * Three of the four intent kinds can raise their marker here, from the string alone. The fourth —
10
+ * `bare_toponym`'s `declared_ambiguity` — cannot: its trigger is the dominance margin of the
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
13
+ * deliberate and it is why this module never emits `declared_ambiguity`: a marker that asserted
14
+ * ambiguity from the string alone would be declaring that every bare city name is ambiguous, which
15
+ * is false 89.1% of the time (the measured table behind `DECISIVE_MARGIN_LOG10`).
16
+ */
17
+ import { nearMeSubject } from "./intent-rules.js";
18
+ import { matchPOICategory } from "./poi.js";
19
+ /**
20
+ * Build the advisories for one classified query.
21
+ *
22
+ * `kinds` is the FULL verdict — top plus alternatives — because two of the four intent kinds live in `alternatives` by
23
+ * design (see `intent-rules.ts`). Reading only the top kind would make them invisible, which is the mistake this
24
+ * signature exists to prevent.
25
+ *
26
+ * Returns `[]` when no intent kind fired. Callers surface that empty array rather than dropping the field: an empty
27
+ * array is the classifier stating it looked.
28
+ */
29
+ export function deriveIntentMarkers(kinds, ctx) {
30
+ const fired = new Set(kinds.map((k) => k.kind));
31
+ const markers = [];
32
+ if (fired.has("route_pair")) {
33
+ const tokens = ctx.input.normalized.trim().split(/\s+/);
34
+ markers.push({
35
+ kind: "route_pair",
36
+ code: "declared_fork",
37
+ mechanism: "kind:route_pair",
38
+ message: `"${tokens.join(" ")}" reads two ways and the pipeline is not choosing between them: two distinct places, or one place with its admin context.`,
39
+ evidence: {
40
+ tokens,
41
+ /**
42
+ * Both readings, named. The order is stable (pair first, then the admin reading) so a consumer can index it; it
43
+ * is NOT a ranking, and nothing downstream reads it as one.
44
+ */
45
+ interpretations: ["two_toponyms", "locality_with_admin_context"],
46
+ },
47
+ });
48
+ }
49
+ if (fired.has("near_me")) {
50
+ const subject = nearMeSubject(ctx.input);
51
+ markers.push({
52
+ kind: "near_me",
53
+ code: "focus_point_required",
54
+ mechanism: "kind:near_me",
55
+ message: `"${subject}" was asked for relative to the asker, and no focus point was supplied.`,
56
+ evidence: {
57
+ subject,
58
+ /**
59
+ * The SEAM, named but not wired (ROAD_TO_V9 §4.4 scopes v9 to classification). Photon's `/api` already accepts
60
+ * `lat`/`lon` location-bias params — `photon/` is the eventual consumer of this marker, and this string is the
61
+ * note that says where it plugs in.
62
+ */
63
+ focusParameter: "photon:lat/lon",
64
+ },
65
+ });
66
+ }
67
+ if (fired.has("poi_category") && ctx.poiLexicon) {
68
+ const match = matchPOICategory(ctx.input.normalized, ctx.locale ?? ctx.input.appliedLocale, ctx.poiLexicon);
69
+ if (match) {
70
+ markers.push({
71
+ kind: "poi_category",
72
+ code: "poi_category",
73
+ mechanism: "poi-taxonomy:synonym",
74
+ message: `"${match.matchedPhrase}" is a POI category with no place to search; resolution against poi.db is out of scope.`,
75
+ evidence: {
76
+ categoryID: match.categoryID,
77
+ matchedPhrase: match.matchedPhrase,
78
+ ...(match.wikidata ? { wikidata: match.wikidata } : {}),
79
+ },
80
+ });
81
+ }
82
+ }
83
+ return markers;
84
+ }
85
+ //# sourceMappingURL=intent-markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-markers.js","sourceRoot":"","sources":["../intent-markers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAwB,MAAM,UAAU,CAAA;AAgBjE;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAClC,KAA6D,EAC7D,GAAwB;IAExB,MAAM,KAAK,GAAG,IAAI,GAAG,CAAY,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAwB,EAAE,CAAA;IAEvC,IAAI,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAEvD,OAAO,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,iBAAiB;YAC5B,OAAO,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,2HAA2H;YACxJ,QAAQ,EAAE;gBACT,MAAM;gBACN;;;mBAGG;gBACH,eAAe,EAAE,CAAC,cAAc,EAAE,6BAA6B,CAAC;aAChE;SACD,CAAC,CAAA;IACH,CAAC;IAED,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAExC,OAAO,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,sBAAsB;YAC5B,SAAS,EAAE,cAAc;YACzB,OAAO,EAAE,IAAI,OAAO,yEAAyE;YAC7F,QAAQ,EAAE;gBACT,OAAO;gBACP;;;;mBAIG;gBACH,cAAc,EAAE,gBAAgB;aAChC;SACD,CAAC,CAAA;IACH,CAAC;IAED,IAAI,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,UAAU,CAAC,CAAA;QAE3G,IAAI,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,sBAAsB;gBACjC,OAAO,EAAE,IAAI,KAAK,CAAC,aAAa,yFAAyF;gBACzH,QAAQ,EAAE;oBACT,UAAU,EAAE,KAAK,CAAC,UAAU;oBAC5B,aAAa,EAAE,KAAK,CAAC,aAAa;oBAClC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACvD;aACD,CAAC,CAAA;QACH,CAAC;IACF,CAAC;IAED,OAAO,OAAO,CAAA;AACf,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * ROAD_TO_V9 §4 — the query-INTENT rules. Same contract as `rules.ts` (a `(input, shape) => number`
7
+ * in [0, 1], 0 when the rule does not fire) and the same bitter-lesson invariant: universal
8
+ * structural patterns and bounded linguistic categories only, never a place-name dictionary. The
9
+ * one lexicon these kinds consult — the POI synonym table — is INJECTED, exactly as `poi.ts`
10
+ * already does it.
11
+ *
12
+ * ## Why two of these three deliberately lose
13
+ *
14
+ * `bare_toponym` and `route_pair` are scored BELOW the structural kind that already owns their
15
+ * population (`locality_only`, 0.85). They therefore surface in `QueryKindResult.alternatives` and
16
+ * never as the top kind. That is not timidity — it is the D-rule discharge. The top kind is the
17
+ * only thing the coordinator routes on (`deriveInputMode`, `canShortCircuit`, the POI branch), so
18
+ * pinning it is what makes these additions provably answer-neutral on the bare-city-name register,
19
+ * which is the single largest population in map search. The intent they carry travels on the
20
+ * marker instead, where it is advisory by construction.
21
+ *
22
+ * `near_me` DOES win its top slot (0.91), because there is no incumbent worth preserving: a query
23
+ * ending "near me" is not a locality and answering it as one is the bug.
24
+ */
25
+ import type { NormalizedInputLite, QueryShapeLike } from "./types.ts";
26
+ /**
27
+ * `bare_toponym` rule: a single coherent place-name carrying no address grammar.
28
+ *
29
+ * Feeds the declared-ambiguity path. The rule itself asserts nothing about WHICH place — that is the resolver's
30
+ * question, and `mailwoman/query-intent.ts` is where the answer's dominance margin decides whether the ambiguity gets
31
+ * declared.
32
+ */
33
+ export declare function scoreBareToponym(input: NormalizedInputLite, shape: QueryShapeLike): number;
34
+ /**
35
+ * `route_pair` rule: exactly two toponym-shaped tokens with nothing between them.
36
+ *
37
+ * **The known confound is structural and unfixable here.** "Paris London" and "Moscow Idaho" are the same string shape
38
+ * — two bare capitalized words — and separating them needs to know that Idaho is a region, which is a gazetteer fact,
39
+ * not a structural one. The hard-slice board's 18 `comma_free` rows are that population, and they fire this rule. That
40
+ * is the reason ROAD_TO_V9 §4.3 specifies **classification + a declared fork, never a router**: both readings are named
41
+ * in the marker, neither wins, and the resolver keeps answering exactly as it did.
42
+ *
43
+ * The one class that IS separable structurally is the two-token SINGLE name — "New York", "Fort Worth", "San Francisco"
44
+ * — because those carry a toponymic head particle. That guard is what keeps the fork off the common case.
45
+ */
46
+ export declare function scoreRoutePair(input: NormalizedInputLite, shape: QueryShapeLike): number;
47
+ /**
48
+ * `near_me` rule: a subject plus a deictic locator, with no anchor.
49
+ *
50
+ * Requires a non-empty subject before the locator, so a bare "near me" stays with the `landmark` leaders rule rather
51
+ * than claiming to be a category search with a missing focus point.
52
+ */
53
+ export declare function scoreNearMe(input: NormalizedInputLite, _shape: QueryShapeLike): number;
54
+ /**
55
+ * The subject of a `near_me` query — the category or thing the asker wants, with the locator stripped. Empty string
56
+ * when the rule would not have fired. Used to build the marker's evidence, never to route.
57
+ */
58
+ export declare function nearMeSubject(input: NormalizedInputLite): string;
59
+ //# sourceMappingURL=intent-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-rules.d.ts","sourceRoot":"","sources":["../intent-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAsNrE;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAE1F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAgBxF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAYtF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAQhE"}