@untangle-code/search 0.0.0-stage → 0.1.1

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.
Files changed (140) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +90 -0
  3. package/README.md +433 -2
  4. package/THIRD_PARTY_LICENSES.md +29 -0
  5. package/dist/benchmark-integrity.d.ts +12 -0
  6. package/dist/benchmark-integrity.d.ts.map +1 -0
  7. package/dist/benchmark-integrity.js +10 -0
  8. package/dist/benchmark-integrity.js.map +1 -0
  9. package/dist/bm25.d.ts +46 -0
  10. package/dist/bm25.d.ts.map +1 -0
  11. package/dist/bm25.js +105 -0
  12. package/dist/bm25.js.map +1 -0
  13. package/dist/deadline.d.ts +4 -0
  14. package/dist/deadline.d.ts.map +1 -0
  15. package/dist/deadline.js +54 -0
  16. package/dist/deadline.js.map +1 -0
  17. package/dist/dedupe.d.ts +48 -0
  18. package/dist/dedupe.d.ts.map +1 -0
  19. package/dist/dedupe.js +58 -0
  20. package/dist/dedupe.js.map +1 -0
  21. package/dist/diversify.d.ts +45 -0
  22. package/dist/diversify.d.ts.map +1 -0
  23. package/dist/diversify.js +30 -0
  24. package/dist/diversify.js.map +1 -0
  25. package/dist/engine.d.ts +157 -0
  26. package/dist/engine.d.ts.map +1 -0
  27. package/dist/engine.js +1498 -0
  28. package/dist/engine.js.map +1 -0
  29. package/dist/enrichment.d.ts +16 -0
  30. package/dist/enrichment.d.ts.map +1 -0
  31. package/dist/enrichment.js +92 -0
  32. package/dist/enrichment.js.map +1 -0
  33. package/dist/filter.d.ts +86 -0
  34. package/dist/filter.d.ts.map +1 -0
  35. package/dist/filter.js +166 -0
  36. package/dist/filter.js.map +1 -0
  37. package/dist/findability.d.ts +144 -0
  38. package/dist/findability.d.ts.map +1 -0
  39. package/dist/findability.js +393 -0
  40. package/dist/findability.js.map +1 -0
  41. package/dist/format.d.ts +28 -0
  42. package/dist/format.d.ts.map +1 -0
  43. package/dist/format.js +172 -0
  44. package/dist/format.js.map +1 -0
  45. package/dist/fusion.d.ts +47 -0
  46. package/dist/fusion.d.ts.map +1 -0
  47. package/dist/fusion.js +84 -0
  48. package/dist/fusion.js.map +1 -0
  49. package/dist/glob.d.ts +50 -0
  50. package/dist/glob.d.ts.map +1 -0
  51. package/dist/glob.js +144 -0
  52. package/dist/glob.js.map +1 -0
  53. package/dist/grep.d.ts +76 -0
  54. package/dist/grep.d.ts.map +1 -0
  55. package/dist/grep.js +475 -0
  56. package/dist/grep.js.map +1 -0
  57. package/dist/index.d.ts +42 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +63 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/ledger.d.ts +45 -0
  62. package/dist/ledger.d.ts.map +1 -0
  63. package/dist/ledger.js +39 -0
  64. package/dist/ledger.js.map +1 -0
  65. package/dist/payload.d.ts +108 -0
  66. package/dist/payload.d.ts.map +1 -0
  67. package/dist/payload.js +263 -0
  68. package/dist/payload.js.map +1 -0
  69. package/dist/port.d.ts +112 -0
  70. package/dist/port.d.ts.map +1 -0
  71. package/dist/port.js +2 -0
  72. package/dist/port.js.map +1 -0
  73. package/dist/product-complexity.d.ts +89 -0
  74. package/dist/product-complexity.d.ts.map +1 -0
  75. package/dist/product-complexity.js +1367 -0
  76. package/dist/product-complexity.js.map +1 -0
  77. package/dist/regex-safety.d.ts +75 -0
  78. package/dist/regex-safety.d.ts.map +1 -0
  79. package/dist/regex-safety.js +902 -0
  80. package/dist/regex-safety.js.map +1 -0
  81. package/dist/relevance-prerequisites.d.ts +21 -0
  82. package/dist/relevance-prerequisites.d.ts.map +1 -0
  83. package/dist/relevance-prerequisites.js +47 -0
  84. package/dist/relevance-prerequisites.js.map +1 -0
  85. package/dist/relevance.d.ts +107 -0
  86. package/dist/relevance.d.ts.map +1 -0
  87. package/dist/relevance.js +199 -0
  88. package/dist/relevance.js.map +1 -0
  89. package/dist/retrieval.d.ts +46 -0
  90. package/dist/retrieval.d.ts.map +1 -0
  91. package/dist/retrieval.js +182 -0
  92. package/dist/retrieval.js.map +1 -0
  93. package/dist/scoring.d.ts +102 -0
  94. package/dist/scoring.d.ts.map +1 -0
  95. package/dist/scoring.js +175 -0
  96. package/dist/scoring.js.map +1 -0
  97. package/dist/sort.d.ts +21 -0
  98. package/dist/sort.d.ts.map +1 -0
  99. package/dist/sort.js +53 -0
  100. package/dist/sort.js.map +1 -0
  101. package/dist/symbol-match.d.ts +21 -0
  102. package/dist/symbol-match.d.ts.map +1 -0
  103. package/dist/symbol-match.js +72 -0
  104. package/dist/symbol-match.js.map +1 -0
  105. package/dist/tokenize.d.ts +41 -0
  106. package/dist/tokenize.d.ts.map +1 -0
  107. package/dist/tokenize.js +202 -0
  108. package/dist/tokenize.js.map +1 -0
  109. package/dist/types.d.ts +173 -0
  110. package/dist/types.d.ts.map +1 -0
  111. package/dist/types.js +42 -0
  112. package/dist/types.js.map +1 -0
  113. package/package.json +61 -3
  114. package/src/benchmark-integrity.ts +25 -0
  115. package/src/bm25.ts +135 -0
  116. package/src/deadline.ts +59 -0
  117. package/src/dedupe.ts +99 -0
  118. package/src/diversify.ts +71 -0
  119. package/src/engine.ts +1957 -0
  120. package/src/enrichment.ts +115 -0
  121. package/src/filter.ts +267 -0
  122. package/src/findability.ts +580 -0
  123. package/src/format.ts +228 -0
  124. package/src/fusion.ts +121 -0
  125. package/src/glob.ts +151 -0
  126. package/src/grep.ts +618 -0
  127. package/src/index.ts +83 -0
  128. package/src/ledger.ts +72 -0
  129. package/src/payload.ts +382 -0
  130. package/src/port.ts +133 -0
  131. package/src/product-complexity.ts +2168 -0
  132. package/src/regex-safety.ts +1002 -0
  133. package/src/relevance-prerequisites.ts +83 -0
  134. package/src/relevance.ts +328 -0
  135. package/src/retrieval.ts +299 -0
  136. package/src/scoring.ts +321 -0
  137. package/src/sort.ts +86 -0
  138. package/src/symbol-match.ts +87 -0
  139. package/src/tokenize.ts +213 -0
  140. package/src/types.ts +206 -0
@@ -0,0 +1,182 @@
1
+ /** Independent recall branches, bounded provider calls and deterministic failure diagnostics. */
2
+ import { UntangleError, compareCodepoints, isUntangleError, } from "@untangle-code/domain";
3
+ import { withSearchBranchDeadline } from "./deadline.js";
4
+ import { buildSymbolNameFilter } from "./filter.js";
5
+ import { symbolNameFilterCandidates } from "./symbol-match.js";
6
+ /** The mode controls both recall and ranking, so it has one shared definition. */
7
+ export function branchesOfMode(mode) {
8
+ switch (mode) {
9
+ case "semantic":
10
+ return { dense: true, lexical: false, symbol: false };
11
+ case "lexical":
12
+ return { dense: false, lexical: true, symbol: false };
13
+ case "symbol":
14
+ return { dense: false, lexical: false, symbol: true };
15
+ case "hybrid":
16
+ return { dense: true, lexical: true, symbol: true };
17
+ }
18
+ }
19
+ /** Cancellation is control flow, never a degraded retrieval result. */
20
+ export function rethrowCancellation(error, options) {
21
+ options?.signal?.throwIfAborted();
22
+ if ((isUntangleError(error) && error.code === "JOB_CANCELLED") ||
23
+ (error instanceof Error && error.name === "AbortError")) {
24
+ throw error;
25
+ }
26
+ }
27
+ async function retrieveDense(request, options) {
28
+ const { target } = request;
29
+ const preparedQuery = `${target.embedder.profile.queryPrefix}${request.text}`;
30
+ const dense = await target.embedder.embedQuery(preparedQuery, options);
31
+ options.signal?.throwIfAborted();
32
+ return request.vectorStore.hybridQuery(target.collection, {
33
+ dense,
34
+ filter: request.filter,
35
+ limit: request.candidateLimit,
36
+ candidateLimit: request.candidateLimit,
37
+ withPayload: true,
38
+ }, options);
39
+ }
40
+ async function retrieveSparse(request, options) {
41
+ if (request.sparseVectorizer === undefined) {
42
+ throw new UntangleError("INDEX_INCOMPLETE", "no sparse vectorizer is wired", {
43
+ operation: "search_sparse_retrieval",
44
+ });
45
+ }
46
+ return request.vectorStore.hybridQuery(request.target.collection, {
47
+ sparse: request.sparseVectorizer(request.text),
48
+ filter: request.filter,
49
+ limit: request.candidateLimit,
50
+ candidateLimit: request.candidateLimit,
51
+ withPayload: true,
52
+ }, options);
53
+ }
54
+ async function retrieveSymbol(request, options) {
55
+ const filter = buildSymbolNameFilter(request.filter, symbolNameFilterCandidates(request.text));
56
+ if (filter === undefined)
57
+ return { points: [] };
58
+ return request.vectorStore.scroll(request.target.collection, { filter, limit: request.candidateLimit }, options);
59
+ }
60
+ /** Each branch produces an explicit outcome; a provider failure does not cancel its peers. */
61
+ async function executeBranch(branch, enabled, request, retrieve, options) {
62
+ if (!enabled)
63
+ return { branch, status: "not_requested" };
64
+ try {
65
+ const result = await withSearchBranchDeadline(branch, request.mode === "hybrid" ? request.branchTimeoutMs : undefined, retrieve.bind(undefined, request), options, request.vectorStore.backend === "lancedb" ? "LANCEDB_UNAVAILABLE" : "QDRANT_UNAVAILABLE");
66
+ options.signal?.throwIfAborted();
67
+ return { branch, status: "succeeded", result };
68
+ }
69
+ catch (error) {
70
+ rethrowCancellation(error, options);
71
+ return {
72
+ branch,
73
+ status: "failed",
74
+ error: isUntangleError(error) || branch === "dense" || request.vectorStore.backend !== "lancedb"
75
+ ? error
76
+ : new UntangleError("LANCEDB_UNAVAILABLE", error instanceof Error ? error.message : String(error), { operation: "search_retrieval", retryable: true, cause: error }),
77
+ };
78
+ }
79
+ }
80
+ function branchResult(outcome) {
81
+ return outcome.status === "succeeded" ? outcome.result : undefined;
82
+ }
83
+ function isFailedBranch(outcome) {
84
+ return outcome.status === "failed";
85
+ }
86
+ function branchFailureCode(failure) {
87
+ if (failure !== undefined && isUntangleError(failure.error))
88
+ return failure.error.code;
89
+ return failure?.branch === "dense" ? "EMBEDDING_UNAVAILABLE" : "QDRANT_UNAVAILABLE";
90
+ }
91
+ function timeoutDetails(error) {
92
+ if (!isUntangleError(error) || error.context["timedOut"] !== true)
93
+ return {};
94
+ return { timedOut: true, timeoutMs: error.context["timeoutMs"] };
95
+ }
96
+ /** Build evidence once in branch-name order, independent of completion timing. */
97
+ function failureDiagnostics(target, failures) {
98
+ const warnings = [];
99
+ const caveats = [];
100
+ const skipped = [];
101
+ for (const failure of failures) {
102
+ const { branch, error } = failure;
103
+ const message = error instanceof Error ? error.message : String(error);
104
+ const detail = `profile "${target.embeddingProfileId}" retrieval branch "${branch}" failed: ${message}`;
105
+ const timeout = timeoutDetails(error);
106
+ caveats.push(detail);
107
+ warnings.push({
108
+ code: "SEARCH_BRANCH_UNAVAILABLE",
109
+ message: detail,
110
+ details: {
111
+ embeddingProfileId: target.embeddingProfileId,
112
+ collection: target.collection,
113
+ branch,
114
+ causeCode: branchFailureCode(failure),
115
+ ...timeout,
116
+ },
117
+ });
118
+ if (timeout["timedOut"] === true) {
119
+ warnings.push({
120
+ code: "SEARCH_BRANCH_TIMEOUT",
121
+ message: detail,
122
+ details: { branch, timeoutMs: timeout["timeoutMs"] },
123
+ });
124
+ }
125
+ skipped.push({
126
+ subjectKind: "search_candidate",
127
+ subjectId: `${target.embeddingProfileId}:${branch}`,
128
+ reason: "provider_unavailable",
129
+ detail,
130
+ recoverable: true,
131
+ });
132
+ }
133
+ return { warnings, caveats, skipped };
134
+ }
135
+ /** Return all requested branch outcomes in fixed dense/sparse/symbol order. */
136
+ export async function retrieveIndependentBranches(request, options) {
137
+ options?.signal?.throwIfAborted();
138
+ const active = branchesOfMode(request.mode);
139
+ const controller = new AbortController();
140
+ const linkedOptions = {
141
+ ...options,
142
+ signal: options?.signal === undefined
143
+ ? controller.signal
144
+ : AbortSignal.any([options.signal, controller.signal]),
145
+ };
146
+ const [dense, sparse, symbol] = await Promise.all([
147
+ executeBranch("dense", active.dense, request, retrieveDense, linkedOptions),
148
+ executeBranch("sparse", active.lexical, request, retrieveSparse, linkedOptions),
149
+ executeBranch("symbol", active.symbol, request, retrieveSymbol, linkedOptions),
150
+ ]).finally(() => controller.abort());
151
+ options?.signal?.throwIfAborted();
152
+ const outcomes = [dense, sparse, symbol];
153
+ const failures = outcomes
154
+ .filter(isFailedBranch)
155
+ .sort((left, right) => compareCodepoints(left.branch, right.branch));
156
+ const completedBranches = new Set(outcomes.filter((outcome) => outcome.status === "succeeded").map((outcome) => outcome.branch));
157
+ const symbolPage = branchResult(symbol);
158
+ return {
159
+ densePoints: branchResult(dense) ?? [],
160
+ sparsePoints: branchResult(sparse) ?? [],
161
+ ...(symbolPage === undefined ? {} : { symbolPage }),
162
+ completedBranches,
163
+ failures,
164
+ ...failureDiagnostics(request.target, failures),
165
+ };
166
+ }
167
+ /** The caller first records diagnostics, then distinguishes total failure from empty success. */
168
+ export function assertCompletedRetrieval(result, target) {
169
+ if (result.completedBranches.size > 0)
170
+ return;
171
+ const first = result.failures[0];
172
+ throw new UntangleError(branchFailureCode(first), `all requested retrieval branches failed for profile "${target.embeddingProfileId}": ${result.warnings.map((warning) => warning.message).join("; ")}`, {
173
+ operation: "search_retrieval",
174
+ retryable: result.failures.some(({ error }) => !isUntangleError(error) || error.retryable),
175
+ context: {
176
+ collection: target.collection,
177
+ failedBranches: result.failures.map(({ branch }) => branch),
178
+ },
179
+ cause: first?.error,
180
+ });
181
+ }
182
+ //# sourceMappingURL=retrieval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieval.js","sourceRoot":"","sources":["../src/retrieval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Score-Zerlegung (spec.md §13.3).
3
+ *
4
+ * Das ist keine Debug-Ausgabe. Die Zerlegung ist oeffentliche API und die
5
+ * Grundlage der Findability-Diagnose (vision.md §1d): ohne sie laesst sich
6
+ * „der richtige Treffer rankt niedrig" nicht von „es gibt keinen Treffer"
7
+ * unterscheiden, und genau diese Unterscheidung ist die Aussage ueber den
8
+ * Code, nicht ueber die Suche.
9
+ *
10
+ * Aufbau:
11
+ *
12
+ * final = base_hybrid
13
+ * + exact_symbol_boost + exact_path_boost + repo_priority_boost
14
+ * + graph_proximity_boost + recency_boost
15
+ * + complexity_modifier
16
+ * - duplicate_penalty
17
+ *
18
+ * Jeder Bestandteil traegt `rawValue` (das normalisierte Signal), `weight`
19
+ * (das Gewicht aus der Konfiguration) und `contribution = rawValue * weight`.
20
+ * `validateScoreBreakdown()` aus der Domain prueft genau diese Identitaet und
21
+ * die Summenprobe — die Tests dieses Pakets rufen sie auf jedem erzeugten
22
+ * Treffer auf.
23
+ *
24
+ * BEGRENZUNG DER BOOSTS (spec.md §13.3: „Heuristische Boosts DUERFEN
25
+ * Dense/BM25 nicht vollstaendig ueberstimmen"): Uebersteigt die Summe der
26
+ * Betraege aller Nicht-Basis-Bestandteile den Anteil {@link MAX_BOOST_SHARE}
27
+ * des Basisbetrags, werden ALLE Nicht-Basis-Gewichte mit demselben Faktor
28
+ * verkleinert und `clamped`/`clampReason` gesetzt. Verkleinert wird das
29
+ * GEWICHT, nicht der Beitrag: nur so bleibt `contribution = rawValue * weight`
30
+ * wahr und das Signal (`rawValue`) sichtbar.
31
+ */
32
+ import type { CodeChunkPayloadV1, ScoreBreakdownV1, ScoreComponentV1 } from "@untangle-code/domain";
33
+ import type { FusionResult } from "./fusion.js";
34
+ import type { SearchCandidate } from "./payload.js";
35
+ import type { ComplexityBias } from "./types.js";
36
+ /**
37
+ * Hoechster zulaessiger Anteil aller Boosts/Strafen am Basisscore.
38
+ *
39
+ * 0.5 heisst: die Heuristik darf einen Treffer um hoechstens die Haelfte
40
+ * seines Basisscores verschieben. Damit bleibt der Basisanteil (`baseShare`
41
+ * aus `validateScoreBreakdown`) immer bei mindestens 1/1.5 ≈ 0.667 — der
42
+ * Basiszweig behaelt also strukturell die Mehrheit. Der Wert ist eine
43
+ * Politik-Entscheidung dieses Pakets und hier bewusst als benannte Konstante
44
+ * sichtbar statt als Zahl im Code verstreut.
45
+ */
46
+ export declare const MAX_BOOST_SHARE = 0.5;
47
+ /**
48
+ * Referenzwert der kognitiven Komplexitaet fuer den Komplexitaets-Modifikator.
49
+ * 25 ist der Punkt, ab dem der Modifikator seinen vollen Ausschlag erreicht;
50
+ * er ist eine Skalierungsgroesse fuer die Rangfolge und ausdruecklich KEINE
51
+ * Qualitaetsschwelle (Schwellen gehoeren in die Quality Gate, spec.md §18).
52
+ */
53
+ export declare const COMPLEXITY_REFERENCE_COGNITIVE = 25;
54
+ /** Gewichte der additiven Score-Bestandteile (Form aus `SearchConfig`). */
55
+ export interface BoostWeights {
56
+ exactSymbol: number;
57
+ exactPath: number;
58
+ repoPriority: number;
59
+ graphProximity: number;
60
+ recency: number;
61
+ duplicatePenalty: number;
62
+ }
63
+ /** Gewicht des Komplexitaets-Modifikators, wenn die Anfrage ihn anfordert. */
64
+ export declare const COMPLEXITY_MODIFIER_WEIGHT = 0.1;
65
+ /** Alles, was zur Bewertung eines einzelnen Kandidaten gebraucht wird. */
66
+ export interface ScoringContext {
67
+ queryText: string;
68
+ weights: BoostWeights;
69
+ complexityBias: ComplexityBias;
70
+ /** Repo-Prioritaet in [0, 1] je `repo_id`; fehlt = kein Bestandteil. */
71
+ repoPriorities: Readonly<Record<string, number>>;
72
+ /** Graph-Naehe in [0, 1] je `symbol_id`; fehlt = kein Bestandteil. */
73
+ graphProximity: ReadonlyMap<string, number>;
74
+ /** „Jetzt" in Epoch-Millisekunden, ueber den Clock-Port bezogen. */
75
+ nowEpochMs?: number;
76
+ /** Halbwertszeit des Recency-Boosts in Tagen. */
77
+ recencyHalfLifeDays: number;
78
+ }
79
+ /** Zeitzerfall in [0, 1]: 1 heisst „gerade eben", 0.5 nach einer Halbwertszeit. */
80
+ export declare function recencyDecay(ageMs: number, halfLifeDays: number): number;
81
+ /**
82
+ * Komplexitaets-Modifikator in [-1, 1]. Positiv, wenn der Treffer der
83
+ * angeforderten Richtung entspricht.
84
+ */
85
+ export declare function complexityModifierRawValue(payload: CodeChunkPayloadV1, bias: ComplexityBias): number | null;
86
+ /**
87
+ * Baut die vollstaendige Score-Zerlegung eines Kandidaten.
88
+ *
89
+ * `duplicatePenaltyRawValue` kommt aus der Diversifizierung (siehe
90
+ * `diversify.ts`) und ist bereits in [0, 1]; das Vorzeichen setzt diese
91
+ * Funktion, damit die Strafe an genau EINER Stelle negativ wird.
92
+ */
93
+ export declare function assembleScoreBreakdown(candidate: SearchCandidate, fusion: FusionResult, context: ScoringContext, duplicatePenaltyRawValue?: number): ScoreBreakdownV1;
94
+ interface ClampResult {
95
+ boosts: ScoreComponentV1[];
96
+ clamped: boolean;
97
+ reason?: string;
98
+ }
99
+ /** Setzt {@link MAX_BOOST_SHARE} durch (siehe Modulkommentar). */
100
+ export declare function clampBoosts(base: ScoreComponentV1, boosts: readonly ScoreComponentV1[]): ClampResult;
101
+ export {};
102
+ //# sourceMappingURL=scoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGpG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,8EAA8E;AAC9E,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,cAAc,EAAE,cAAc,CAAC;IAC/B,wEAAwE;IACxE,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,sEAAsE;IACtE,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AA2BD,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CASxE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,cAAc,GACnB,MAAM,GAAG,IAAI,CAUf;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,eAAe,EAC1B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,cAAc,EACvB,wBAAwB,SAAI,GAC3B,gBAAgB,CAkHlB;AAoBD,UAAU,WAAW;IACnB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CACzB,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAClC,WAAW,CAoBb"}
@@ -0,0 +1,175 @@
1
+ import { RANKER_VERSION } from "@untangle-code/domain";
2
+ import { readRawNumber } from "./payload.js";
3
+ import { matchSymbolName } from "./symbol-match.js";
4
+ /**
5
+ * Hoechster zulaessiger Anteil aller Boosts/Strafen am Basisscore.
6
+ *
7
+ * 0.5 heisst: die Heuristik darf einen Treffer um hoechstens die Haelfte
8
+ * seines Basisscores verschieben. Damit bleibt der Basisanteil (`baseShare`
9
+ * aus `validateScoreBreakdown`) immer bei mindestens 1/1.5 ≈ 0.667 — der
10
+ * Basiszweig behaelt also strukturell die Mehrheit. Der Wert ist eine
11
+ * Politik-Entscheidung dieses Pakets und hier bewusst als benannte Konstante
12
+ * sichtbar statt als Zahl im Code verstreut.
13
+ */
14
+ export const MAX_BOOST_SHARE = 0.5;
15
+ /**
16
+ * Referenzwert der kognitiven Komplexitaet fuer den Komplexitaets-Modifikator.
17
+ * 25 ist der Punkt, ab dem der Modifikator seinen vollen Ausschlag erreicht;
18
+ * er ist eine Skalierungsgroesse fuer die Rangfolge und ausdruecklich KEINE
19
+ * Qualitaetsschwelle (Schwellen gehoeren in die Quality Gate, spec.md §18).
20
+ */
21
+ export const COMPLEXITY_REFERENCE_COGNITIVE = 25;
22
+ /** Gewicht des Komplexitaets-Modifikators, wenn die Anfrage ihn anfordert. */
23
+ export const COMPLEXITY_MODIFIER_WEIGHT = 0.1;
24
+ function pathBoost(payload, queryText) {
25
+ const query = queryText.trim();
26
+ if (query === "") {
27
+ return null;
28
+ }
29
+ const path = payload.file_path;
30
+ const segments = path.split("/");
31
+ if (path === query) {
32
+ return raw("exact_path_boost", 1, `file_path == "${path}"`);
33
+ }
34
+ if (segments.includes(query)) {
35
+ return raw("exact_path_boost", 0.75, `path segment == "${query}"`);
36
+ }
37
+ if (path.includes(query)) {
38
+ return raw("exact_path_boost", 0.5, `file_path contains "${query}"`);
39
+ }
40
+ return null;
41
+ }
42
+ function raw(kind, rawValue, evidence) {
43
+ // `weight` wird erst in `assembleScoreBreakdown` gesetzt; hier steht das
44
+ // rohe Signal mit seinem Beleg.
45
+ return { kind, rawValue, weight: 0, contribution: 0, evidence };
46
+ }
47
+ /** Zeitzerfall in [0, 1]: 1 heisst „gerade eben", 0.5 nach einer Halbwertszeit. */
48
+ export function recencyDecay(ageMs, halfLifeDays) {
49
+ if (ageMs <= 0) {
50
+ return 1;
51
+ }
52
+ const halfLifeMs = halfLifeDays * 24 * 60 * 60 * 1000;
53
+ if (halfLifeMs <= 0) {
54
+ return 0;
55
+ }
56
+ return Math.pow(0.5, ageMs / halfLifeMs);
57
+ }
58
+ /**
59
+ * Komplexitaets-Modifikator in [-1, 1]. Positiv, wenn der Treffer der
60
+ * angeforderten Richtung entspricht.
61
+ */
62
+ export function complexityModifierRawValue(payload, bias) {
63
+ if (bias === "none") {
64
+ return null;
65
+ }
66
+ const cognitive = payload.cognitive;
67
+ if (cognitive === undefined) {
68
+ return null;
69
+ }
70
+ const normalized = Math.min(cognitive / COMPLEXITY_REFERENCE_COGNITIVE, 1);
71
+ return bias === "prefer-simple" ? 1 - 2 * normalized : 2 * normalized - 1;
72
+ }
73
+ /**
74
+ * Baut die vollstaendige Score-Zerlegung eines Kandidaten.
75
+ *
76
+ * `duplicatePenaltyRawValue` kommt aus der Diversifizierung (siehe
77
+ * `diversify.ts`) und ist bereits in [0, 1]; das Vorzeichen setzt diese
78
+ * Funktion, damit die Strafe an genau EINER Stelle negativ wird.
79
+ */
80
+ export function assembleScoreBreakdown(candidate, fusion, context, duplicatePenaltyRawValue = 0) {
81
+ const { payload } = candidate;
82
+ const base = {
83
+ kind: "base_hybrid",
84
+ rawValue: fusion.normalized,
85
+ weight: 1,
86
+ contribution: fusion.normalized,
87
+ evidence: describeBranches(fusion),
88
+ };
89
+ const boosts = [];
90
+ const symbolMatch = matchSymbolName(payload, context.queryText);
91
+ if (symbolMatch !== null) {
92
+ boosts.push(withWeight(raw("exact_symbol_boost", symbolMatch.strength, symbolMatch.evidence), context.weights.exactSymbol));
93
+ }
94
+ const pathComponent = pathBoost(payload, context.queryText);
95
+ if (pathComponent !== null) {
96
+ boosts.push(withWeight(pathComponent, context.weights.exactPath));
97
+ }
98
+ const priority = context.repoPriorities[payload.repo_id];
99
+ if (priority !== undefined && priority !== 0) {
100
+ boosts.push(withWeight(raw("repo_priority_boost", priority, `configured priority of repo "${payload.repo_id}"`), context.weights.repoPriority));
101
+ }
102
+ const proximity = payload.symbol_id === undefined ? undefined : context.graphProximity.get(payload.symbol_id);
103
+ if (proximity !== undefined && proximity !== 0) {
104
+ boosts.push(withWeight(raw("graph_proximity_boost", proximity, `graph proximity of symbol "${payload.symbol_id ?? ""}"`), context.weights.graphProximity));
105
+ }
106
+ const changedAt = readRawNumber(candidate.raw, "changed_at_epoch_ms");
107
+ if (changedAt !== undefined && context.nowEpochMs !== undefined) {
108
+ const decay = recencyDecay(context.nowEpochMs - changedAt, context.recencyHalfLifeDays);
109
+ if (decay > 0) {
110
+ boosts.push(withWeight(raw("recency_boost", decay, `changed_at_epoch_ms = ${changedAt}`), context.weights.recency));
111
+ }
112
+ }
113
+ const complexityRaw = complexityModifierRawValue(payload, context.complexityBias);
114
+ if (complexityRaw !== null) {
115
+ boosts.push(withWeight(raw("complexity_modifier", complexityRaw, `cognitive = ${String(payload.cognitive)} (bias "${context.complexityBias}", reference ${COMPLEXITY_REFERENCE_COGNITIVE})`), COMPLEXITY_MODIFIER_WEIGHT));
116
+ }
117
+ if (duplicatePenaltyRawValue > 0) {
118
+ boosts.push(withWeight(raw("duplicate_penalty", duplicatePenaltyRawValue, `file "${payload.file_path}" is already represented higher in the ranking`), -context.weights.duplicatePenalty));
119
+ }
120
+ const clamp = clampBoosts(base, boosts);
121
+ const components = [base, ...clamp.boosts];
122
+ const final = components.reduce((sum, component) => sum + component.contribution, 0);
123
+ return {
124
+ schemaVersion: 1,
125
+ final,
126
+ components,
127
+ inputs: {
128
+ ...(candidate.denseScore === undefined ? {} : { dense: candidate.denseScore }),
129
+ ...(candidate.denseRank === undefined ? {} : { denseRank: candidate.denseRank }),
130
+ ...(candidate.lexicalRank === undefined
131
+ ? {}
132
+ : { sparseRank: candidate.lexicalRank, lexicalRank: candidate.lexicalRank }),
133
+ ...(candidate.lexicalScore === undefined ? {} : { lexicalScore: candidate.lexicalScore }),
134
+ ...(candidate.symbolRank === undefined ? {} : { symbolRank: candidate.symbolRank }),
135
+ rrf: fusion.rrf,
136
+ },
137
+ rankerVersion: RANKER_VERSION,
138
+ clamped: clamp.clamped,
139
+ ...(clamp.reason === undefined ? {} : { clampReason: clamp.reason }),
140
+ };
141
+ }
142
+ function withWeight(component, weight) {
143
+ return { ...component, weight, contribution: component.rawValue * weight };
144
+ }
145
+ function describeBranches(fusion) {
146
+ const parts = [];
147
+ for (const branch of ["dense", "lexical", "symbol"]) {
148
+ const rank = fusion.ranks[branch];
149
+ if (rank !== undefined) {
150
+ const weight = fusion.weights?.[branch];
151
+ parts.push(weight === undefined ? `${branch}#${rank}` : `${branch}#${rank} x weight ${weight}`);
152
+ }
153
+ }
154
+ return parts.length === 0 ? "no branch contributed" : `RRF over ${parts.join(", ")}`;
155
+ }
156
+ /** Setzt {@link MAX_BOOST_SHARE} durch (siehe Modulkommentar). */
157
+ export function clampBoosts(base, boosts) {
158
+ const boostMagnitude = boosts.reduce((sum, component) => sum + Math.abs(component.contribution), 0);
159
+ const baseMagnitude = Math.abs(base.contribution);
160
+ const budget = baseMagnitude * MAX_BOOST_SHARE;
161
+ if (boostMagnitude <= budget || boostMagnitude === 0) {
162
+ return { boosts: [...boosts], clamped: false };
163
+ }
164
+ const factor = budget / boostMagnitude;
165
+ return {
166
+ boosts: boosts.map((component) => ({
167
+ ...component,
168
+ weight: component.weight * factor,
169
+ contribution: component.contribution * factor,
170
+ })),
171
+ clamped: true,
172
+ reason: `boost magnitude ${boostMagnitude.toFixed(6)} exceeded ${MAX_BOOST_SHARE} of the base score ${baseMagnitude.toFixed(6)}; all non-base weights scaled by ${factor.toFixed(6)} (spec.md §13.3)`,
173
+ };
174
+ }
175
+ //# sourceMappingURL=scoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"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"}
package/dist/sort.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Sortierung der Trefferliste (Nutzerwunsch A4: „Sortierung").
3
+ *
4
+ * Jede Sortierung ist zweistufig: erst das gewaehlte Kriterium, dann — IMMER —
5
+ * der Dedupe-Schluessel nach Codepoints. Der zweite Schritt ist nicht Kosmetik:
6
+ * ohne ihn haengt die Reihenfolge gleichbewerteter Treffer an der
7
+ * Antwortreihenfolge des Speichers, und dieselbe Anfrage liefert auf zwei
8
+ * Maschinen zwei Listen. `String#localeCompare` kommt dabei nie zum Einsatz
9
+ * (docs/BUILD_PLAN.md §3).
10
+ *
11
+ * Treffer ohne den jeweiligen Wert (keine Komplexitaet gemessen, keine
12
+ * Findability berechnet) landen ans ENDE der Liste, nicht an den Anfang: ein
13
+ * fehlender Wert ist kein Bestwert.
14
+ */
15
+ import type { SearchHitV1 } from "@untangle-code/domain";
16
+ import type { SearchSort } from "./types.js";
17
+ /** Sortiert eine Kopie der Treffer nach dem gewaehlten Kriterium. */
18
+ export declare function sortHits(hits: readonly SearchHitV1[], sort: SearchSort): SearchHitV1[];
19
+ /** Weist die 1-basierten Raenge INNERHALB einer Profilgruppe zu. */
20
+ export declare function assignRanks(hits: readonly SearchHitV1[]): SearchHitV1[];
21
+ //# sourceMappingURL=sort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../src/sort.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAuB7C,qEAAqE;AACrE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,EAAE,IAAI,EAAE,UAAU,GAAG,WAAW,EAAE,CAuCtF;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,CAEvE"}
package/dist/sort.js ADDED
@@ -0,0 +1,53 @@
1
+ import { compareCodepoints } from "@untangle-code/domain";
2
+ function tiebreak(a, b) {
3
+ return compareCodepoints(a.dedupeKey, b.dedupeKey);
4
+ }
5
+ function compareOptionalNumber(a, b, direction) {
6
+ if (a === undefined && b === undefined) {
7
+ return 0;
8
+ }
9
+ if (a === undefined) {
10
+ return 1;
11
+ }
12
+ if (b === undefined) {
13
+ return -1;
14
+ }
15
+ return direction === "asc" ? a - b : b - a;
16
+ }
17
+ /** Sortiert eine Kopie der Treffer nach dem gewaehlten Kriterium. */
18
+ export function sortHits(hits, sort) {
19
+ const copy = [...hits];
20
+ switch (sort) {
21
+ case "relevance":
22
+ copy.sort((a, b) => a.score.final === b.score.final ? tiebreak(a, b) : b.score.final - a.score.final);
23
+ break;
24
+ case "path":
25
+ copy.sort((a, b) => compareCodepoints(a.repoId, b.repoId) ||
26
+ compareCodepoints(a.filePath, b.filePath) ||
27
+ (a.range.startLine !== b.range.startLine
28
+ ? a.range.startLine - b.range.startLine
29
+ : tiebreak(a, b)));
30
+ break;
31
+ case "complexity-desc":
32
+ case "complexity-asc": {
33
+ const direction = sort === "complexity-asc" ? "asc" : "desc";
34
+ copy.sort((a, b) => {
35
+ const result = compareOptionalNumber(a.complexity?.cognitive, b.complexity?.cognitive, direction);
36
+ return result === 0 ? tiebreak(a, b) : result;
37
+ });
38
+ break;
39
+ }
40
+ case "findability-asc":
41
+ copy.sort((a, b) => {
42
+ const result = compareOptionalNumber(a.findability?.score, b.findability?.score, "asc");
43
+ return result === 0 ? tiebreak(a, b) : result;
44
+ });
45
+ break;
46
+ }
47
+ return copy;
48
+ }
49
+ /** Weist die 1-basierten Raenge INNERHALB einer Profilgruppe zu. */
50
+ export function assignRanks(hits) {
51
+ return hits.map((hit, index) => ({ ...hit, rank: index + 1 }));
52
+ }
53
+ //# sourceMappingURL=sort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort.js","sourceRoot":"","sources":["../src/sort.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { CodeChunkPayloadV1 } from "@untangle-code/domain";
2
+ /** Ergebnis eines Namensvergleichs. */
3
+ export interface SymbolMatch {
4
+ strength: number;
5
+ /** Beleg fuer die Score-Zerlegung, z. B. `symbol_name == "charge"`. */
6
+ evidence: string;
7
+ }
8
+ /** Vergleicht den Suchtext mit den Namensfeldern eines Chunks. */
9
+ export declare function matchSymbolName(payload: CodeChunkPayloadV1, queryText: string): SymbolMatch | null;
10
+ /**
11
+ * Kandidatenwerte fuer den Speicher-Filter auf `symbol_name`.
12
+ *
13
+ * Der Payload-Filter des Speichers kann nur exakte Werte vergleichen. Deshalb
14
+ * werden hier deterministisch die Schreibweisen erzeugt, die derselbe Name
15
+ * ueblicherweise hat: der Suchtext selbst, sein letztes Pfad-/FQN-Glied und —
16
+ * falls der Suchtext genau ein Wort ist — dieses Wort. Mehr NICHT: eine
17
+ * Kombinatorik ueber camelCase/snake_case-Varianten wuerde Treffer erfinden,
18
+ * die im Index gar nicht so heissen.
19
+ */
20
+ export declare function symbolNameFilterCandidates(queryText: string): string[];
21
+ //# sourceMappingURL=symbol-match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol-match.d.ts","sourceRoot":"","sources":["../src/symbol-match.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE,uCAAuC;AACvC,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,kEAAkE;AAClE,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,WAAW,GAAG,IAAI,CA4BpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAWtE"}