flowseeker 0.1.8 → 0.1.9

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.
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.laravelSlotMapping = void 0;
37
+ exports.detectLaravelFramework = detectLaravelFramework;
38
+ exports.classifyLaravelTask = classifyLaravelTask;
39
+ exports.laravelCategoryRequiredSlots = laravelCategoryRequiredSlots;
40
+ exports.laravelMissingLinkHints = laravelMissingLinkHints;
41
+ exports.applyLaravelTemplate = applyLaravelTemplate;
42
+ const fs = __importStar(require("fs/promises"));
43
+ const path = __importStar(require("path"));
44
+ const laravelSignals = [
45
+ { path: "artisan", weight: 8, label: "artisan" },
46
+ { path: "routes/web.php", weight: 6, label: "routes/web.php" },
47
+ { path: "routes/api.php", weight: 5, label: "routes/api.php" },
48
+ { path: "app/Http/Controllers", weight: 5, label: "app/Http/Controllers" },
49
+ { path: "app/Models", weight: 4, label: "app/Models" },
50
+ { path: "resources/views", weight: 4, label: "resources/views" },
51
+ { path: "config/app.php", weight: 3, label: "config/app.php" },
52
+ { path: "bootstrap/app.php", weight: 3, label: "bootstrap/app.php" },
53
+ { path: "app/Providers", weight: 2, label: "app/Providers" },
54
+ { path: "app/Http/Middleware", weight: 2, label: "app/Http/Middleware" },
55
+ { path: "database/migrations", weight: 2, label: "database/migrations" },
56
+ { path: "app/Console", weight: 2, label: "app/Console" },
57
+ { path: "vite.config.js", weight: 1, label: "vite.config.js" },
58
+ ];
59
+ const minScoreForLaravel = 12;
60
+ async function detectLaravelFramework(rootPath) {
61
+ const signals = [];
62
+ let score = 0;
63
+ for (const signal of laravelSignals) {
64
+ try {
65
+ await fs.access(path.join(rootPath, signal.path));
66
+ score += signal.weight;
67
+ signals.push(signal.label);
68
+ }
69
+ catch {
70
+ // path doesn't exist
71
+ }
72
+ }
73
+ // Check composer.json for laravel/framework dependency
74
+ try {
75
+ const composerRaw = await fs.readFile(path.join(rootPath, "composer.json"), "utf8");
76
+ const composer = JSON.parse(composerRaw);
77
+ const deps = { ...(composer.require ?? {}), ...(composer["require-dev"] ?? {}) };
78
+ if (deps["laravel/framework"]) {
79
+ score += 10;
80
+ signals.push("composer:laravel/framework");
81
+ }
82
+ const illuminateDeps = Object.keys(deps).filter((k) => k.startsWith("illuminate/"));
83
+ if (illuminateDeps.length > 0) {
84
+ score += Math.min(5, illuminateDeps.length);
85
+ signals.push(`composer:illuminate(${illuminateDeps.length})`);
86
+ }
87
+ }
88
+ catch {
89
+ // no composer.json
90
+ }
91
+ const confidence = Math.min(1, score / 25);
92
+ return {
93
+ isLaravel: score >= minScoreForLaravel,
94
+ confidence,
95
+ signals,
96
+ };
97
+ }
98
+ // ── Laravel slot → directory mapping ──────────────────────────────────────────
99
+ exports.laravelSlotMapping = {
100
+ entry: ["routes/*.php"],
101
+ handler: ["app/Http/Controllers/**"],
102
+ domain: ["app/Services/**", "app/Actions/**", "app/Exports/**", "app/Imports/**"],
103
+ data: ["app/Models/**", "app/Repositories/**", "database/migrations/**"],
104
+ validation: ["app/Http/Requests/**"],
105
+ permission: ["app/Policies/**", "app/Http/Middleware/**"],
106
+ config: ["config/**", ".env", ".env.example"],
107
+ side_effect: ["app/Jobs/**", "app/Events/**", "app/Listeners/**", "app/Mail/**", "app/Notifications/**"],
108
+ ui: ["resources/views/**"],
109
+ tests: ["tests/**"],
110
+ docs: [],
111
+ unknown: [],
112
+ };
113
+ function classifyLaravelTask(normalizedTask) {
114
+ const t = normalizedTask.toLowerCase();
115
+ if (/\bimport\b/.test(t) || /\bupload\b/.test(t))
116
+ return "import";
117
+ if (/\b(export|download|excel|csv|report|pdf)\b/.test(t))
118
+ return "export_report";
119
+ if (/\b(auth|login|logout|register|permission|role|policy|guard)\b/.test(t))
120
+ return "auth_permission";
121
+ if (/\b(payment|invoice|billing|checkout|refund|gateway)\b/.test(t))
122
+ return "payment_invoice";
123
+ if (/\b(email|notification|notify|mail|job|event|listener|dispatch)\b/.test(t))
124
+ return "notification_email";
125
+ if (/\b(view|display|page|blade|layout|render|frontend|ui|modal)\b/.test(t))
126
+ return "view_display";
127
+ return "generic";
128
+ }
129
+ function laravelCategoryRequiredSlots(category) {
130
+ const mapping = {
131
+ export_report: ["entry", "handler", "domain", "data", "side_effect", "tests"],
132
+ import: ["entry", "handler", "domain", "validation", "data", "tests"],
133
+ auth_permission: ["entry", "handler", "permission", "domain", "data", "tests"],
134
+ payment_invoice: ["entry", "handler", "domain", "data", "side_effect", "tests"],
135
+ notification_email: ["entry", "handler", "side_effect", "data", "tests"],
136
+ view_display: ["entry", "handler", "ui", "data", "tests"],
137
+ generic: ["entry", "handler", "domain", "data", "tests"],
138
+ };
139
+ return mapping[category] ?? mapping.generic;
140
+ }
141
+ // ── Missing-link hints ────────────────────────────────────────────────────────
142
+ function laravelMissingLinkHints(missingSlots) {
143
+ const hints = [];
144
+ for (const slot of missingSlots) {
145
+ const dirs = exports.laravelSlotMapping[slot];
146
+ if (dirs && dirs.length > 0) {
147
+ hints.push(`missing ${slot}: check ${dirs.join(", ")}`);
148
+ }
149
+ }
150
+ return hints;
151
+ }
152
+ async function applyLaravelTemplate(rootPath, normalizedTask, existingRequiredSlots) {
153
+ const detection = await detectLaravelFramework(rootPath);
154
+ if (!detection.isLaravel) {
155
+ return {
156
+ detected: false,
157
+ confidence: detection.confidence,
158
+ category: "generic",
159
+ suggestedRequiredSlots: [],
160
+ missingLinkHints: [],
161
+ };
162
+ }
163
+ const category = classifyLaravelTask(normalizedTask);
164
+ const templateSlots = laravelCategoryRequiredSlots(category);
165
+ const existing = new Set(existingRequiredSlots);
166
+ const suggested = templateSlots.filter((s) => !existing.has(s));
167
+ const missing = templateSlots.filter((s) => !existing.has(s));
168
+ const hints = laravelMissingLinkHints(missing);
169
+ return {
170
+ detected: true,
171
+ confidence: detection.confidence,
172
+ category,
173
+ suggestedRequiredSlots: suggested,
174
+ missingLinkHints: hints,
175
+ };
176
+ }
177
+ //# sourceMappingURL=laravel.js.map
@@ -0,0 +1,388 @@
1
+ "use strict";
2
+ // Semantic Chunk Index — Phase 18A, report-only.
3
+ // Provides typed diagnostics and a fake/test provider path.
4
+ // Does not change default deterministic retrieval ranking.
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.buildSemanticChunkDiagnostic = buildSemanticChunkDiagnostic;
40
+ exports.computeSemanticChunkDiagnostics = computeSemanticChunkDiagnostics;
41
+ exports.generateSlotQueries = generateSlotQueries;
42
+ exports.computeSlotHits = computeSlotHits;
43
+ exports.buildContributionReport = buildContributionReport;
44
+ exports.buildHybridPromotionReport = buildHybridPromotionReport;
45
+ const crypto = __importStar(require("crypto"));
46
+ // ── Safe hashing ──────────────────────────────────────────────────────
47
+ function hashChunk(text) {
48
+ return crypto.createHash("sha256").update(text, "utf8").digest("hex").substring(0, 16);
49
+ }
50
+ // ── Cache key ──────────────────────────────────────────────────────────
51
+ function cacheKey(base, provider, model, dims, chunkId, chunkHash) {
52
+ return [base, provider, model, String(dims), chunkId, chunkHash, "v18a-1"].join(":");
53
+ }
54
+ // ── Diagnostics builder ────────────────────────────────────────────────
55
+ function buildSemanticChunkDiagnostic(config, results) {
56
+ const enabled = config?.index?.semanticEnabled === true;
57
+ const provider = config?.index?.semanticProvider || "";
58
+ const model = config?.index?.semanticModel || "";
59
+ let readiness = "disabled";
60
+ if (enabled) {
61
+ if (!provider || !model)
62
+ readiness = "unavailable";
63
+ else if (!results.providerReady)
64
+ readiness = "unavailable";
65
+ else
66
+ readiness = "configured";
67
+ }
68
+ return {
69
+ enabled,
70
+ provider,
71
+ model,
72
+ readiness,
73
+ chunksConsidered: results.chunksConsidered,
74
+ cacheHits: results.cacheHits,
75
+ cacheMisses: results.cacheMisses,
76
+ candidatesFound: results.candidatesFound,
77
+ candidatesAccepted: results.candidatesAccepted,
78
+ candidatesRejected: results.candidatesRejected,
79
+ topKContribution: results.topK,
80
+ reportOnly: true,
81
+ warnings: results.providerError ? [results.providerError] : [],
82
+ slotQueries: results.slotQueries || [],
83
+ slotHits: results.slotHits || [],
84
+ contributionReport: results.contributionReport,
85
+ hybridPromotionReport: results.hybridPromotionReport,
86
+ };
87
+ }
88
+ // ── Entry point: compute semantic chunk diagnostics (report-only) ────
89
+ async function computeSemanticChunkDiagnostics(workspaceRoot, config, provider, taskText, chunkTexts) {
90
+ // Early return: semantic disabled must never call provider
91
+ if (!config?.index?.semanticEnabled) {
92
+ return {
93
+ diagnostic: buildSemanticChunkDiagnostic(config, {
94
+ chunksConsidered: 0, cacheHits: 0, cacheMisses: 0,
95
+ candidatesFound: 0, candidatesAccepted: 0, candidatesRejected: 0,
96
+ topK: 0, providerReady: false,
97
+ contributionReport: buildContributionReport(false, false, 0, 0),
98
+ hybridPromotionReport: buildHybridPromotionReport(false, false, [], [], []),
99
+ }),
100
+ hits: [],
101
+ };
102
+ }
103
+ const chunksConsidered = chunkTexts.length;
104
+ let cacheHits = 0;
105
+ let cacheMisses = 0;
106
+ let candidatesFound = 0;
107
+ const hits = [];
108
+ if (!provider) {
109
+ return {
110
+ diagnostic: buildSemanticChunkDiagnostic(config, {
111
+ chunksConsidered, cacheHits, cacheMisses, candidatesFound,
112
+ candidatesAccepted: 0, candidatesRejected: 0, topK: 0,
113
+ providerReady: false, providerError: "No embedding provider configured",
114
+ contributionReport: buildContributionReport(true, false, 0, 0),
115
+ hybridPromotionReport: buildHybridPromotionReport(true, false, [], [], []),
116
+ }),
117
+ hits: [],
118
+ };
119
+ }
120
+ // Compute embeddings (fake or real)
121
+ try {
122
+ const texts = chunkTexts.map(c => c.text);
123
+ const taskEmbedding = await provider.embedTexts([taskText]);
124
+ const chunkEmbeddings = await provider.embedTexts(texts);
125
+ // Cosine similarity
126
+ for (let i = 0; i < chunkEmbeddings.length; i++) {
127
+ const sim = cosineSimilarity(taskEmbedding[0], chunkEmbeddings[i]);
128
+ if (sim > 0.5) {
129
+ candidatesFound++;
130
+ hits.push({
131
+ filePath: chunkTexts[i].filePath,
132
+ chunkId: chunkTexts[i].id,
133
+ startLine: chunkTexts[i].startLine,
134
+ endLine: chunkTexts[i].endLine,
135
+ kind: chunkTexts[i].kind,
136
+ slot: chunkTexts[i].slot,
137
+ similarity: parseFloat(sim.toFixed(4)),
138
+ rank: i + 1,
139
+ reason: `semantic similarity ${sim.toFixed(3)}`,
140
+ contentPreview: chunkTexts[i].text.substring(0, 100),
141
+ });
142
+ }
143
+ }
144
+ cacheMisses = chunksConsidered;
145
+ }
146
+ catch (e) {
147
+ return {
148
+ diagnostic: buildSemanticChunkDiagnostic(config, {
149
+ chunksConsidered, cacheHits, cacheMisses, candidatesFound,
150
+ candidatesAccepted: 0, candidatesRejected: 0, topK: 0,
151
+ providerReady: false, providerError: e?.message || String(e),
152
+ contributionReport: buildContributionReport(true, false, 0, 0),
153
+ hybridPromotionReport: buildHybridPromotionReport(true, false, [], [], []),
154
+ }),
155
+ hits: [],
156
+ };
157
+ }
158
+ const diagnostic = buildSemanticChunkDiagnostic(config, {
159
+ chunksConsidered, cacheHits: 0, cacheMisses: chunksConsidered, candidatesFound,
160
+ candidatesAccepted: 0, candidatesRejected: 0, topK: 0,
161
+ providerReady: true,
162
+ contributionReport: buildContributionReport(true, true, candidatesFound, 0),
163
+ hybridPromotionReport: buildHybridPromotionReport(true, true, hits, [], []),
164
+ });
165
+ return { diagnostic, hits };
166
+ }
167
+ // ── Slot query generation ────────────────────────────────────────────
168
+ var slotSearchTerms = {
169
+ entry: ["route", "routes", "router", "endpoint", "api", "page", "screen", "loader", "action"],
170
+ handler: ["controller", "handler", "action", "resolver", "listener", "job", "worker", "consumer", "command", "commands"],
171
+ domain: ["service", "usecase", "use_case", "repository", "manager", "processor", "model", "entity", "store", "stores", "hook", "hooks"],
172
+ data: ["model", "models", "schema", "migration", "database", "table", "query", "entity", "orm", "prisma"],
173
+ validation: ["request", "validator", "validation", "rule", "rules", "dto", "formrequest", "schema"],
174
+ permission: ["policy", "permission", "role", "guard", "middleware", "authorize", "auth", "acl"],
175
+ config: ["config", "env", "setting", "settings", "feature", "flag", "yaml", "json"],
176
+ side_effect: ["event", "listener", "job", "queue", "mail", "email", "notification", "webhook", "cache", "dispatch"],
177
+ ui: ["component", "page", "view", "screen", "template", "form", "button", "modal", "layout", "responsive", "grid", "drawer", "sidebar", "toast", "chart"],
178
+ tests: ["test", "tests", "spec", "expect", "assert", "fixture", "fixtures"],
179
+ docs: ["readme", "docs", "documentation", "markdown", "guide"],
180
+ unknown: []
181
+ };
182
+ function generateSlotQueries(taskText, requiredSlots, optionalSlots) {
183
+ var queries = [];
184
+ var seen = {};
185
+ function canonicalSlot(slot) {
186
+ if (slot === "tests")
187
+ return "test";
188
+ return slot;
189
+ }
190
+ function add(slot, required) {
191
+ var canon = canonicalSlot(slot);
192
+ if (seen[canon])
193
+ return;
194
+ seen[canon] = true;
195
+ // Lookup terms by original slot name
196
+ var terms = slotSearchTerms[slot] || [];
197
+ if (terms.length === 0)
198
+ return;
199
+ queries.push({
200
+ slot: canon,
201
+ query: taskText + " " + terms.join(" "),
202
+ source: "task_blueprint",
203
+ required: required,
204
+ weight: required ? 1.0 : 0.5,
205
+ reasons: [(required ? "required" : "optional") + " slot: " + canon]
206
+ });
207
+ }
208
+ for (var r = 0; r < requiredSlots.length; r++)
209
+ add(requiredSlots[r], true);
210
+ for (var o = 0; o < optionalSlots.length; o++)
211
+ add(optionalSlots[o], false);
212
+ return queries;
213
+ }
214
+ async function computeSlotHits(provider, slotQueries, chunkTexts) {
215
+ if (!provider || slotQueries.length === 0)
216
+ return [];
217
+ try {
218
+ var slotHits = [];
219
+ for (var sq = 0; sq < slotQueries.length; sq++) {
220
+ var sqObj = slotQueries[sq];
221
+ var qEmb = await provider.embedTexts([sqObj.query]);
222
+ var chunkEmbs = await provider.embedTexts(chunkTexts.map(function (c) { return c.text; }));
223
+ var slotCandidates = [];
224
+ for (var ci = 0; ci < chunkEmbs.length; ci++) {
225
+ var sim = cosineSimilarity(qEmb[0], chunkEmbs[ci]);
226
+ if (sim > 0.4) {
227
+ slotCandidates.push({
228
+ filePath: chunkTexts[ci].filePath, chunkId: chunkTexts[ci].id,
229
+ startLine: chunkTexts[ci].startLine, endLine: chunkTexts[ci].endLine,
230
+ kind: chunkTexts[ci].kind, slot: chunkTexts[ci].slot,
231
+ similarity: parseFloat(sim.toFixed(4)), rank: ci + 1,
232
+ reason: "slot " + sqObj.slot + " sim " + sim.toFixed(3),
233
+ contentPreview: chunkTexts[ci].text.substring(0, 80),
234
+ });
235
+ }
236
+ }
237
+ var hitCount = slotCandidates.length;
238
+ var recoveryStatus = hitCount >= 3 ? "recovered" : hitCount > 0 ? "not_recovered" : "not_evaluated";
239
+ slotHits.push({
240
+ slot: sqObj.slot, query: sqObj.query.substring(0, 80),
241
+ hits: hitCount, hitCount: hitCount,
242
+ recoveryStatus: recoveryStatus,
243
+ missingBeforeSemantic: hitCount === 0,
244
+ recoveredBySemantic: hitCount >= 3,
245
+ topCandidates: slotCandidates.slice(0, 3)
246
+ });
247
+ }
248
+ return slotHits;
249
+ }
250
+ catch (e) {
251
+ return [];
252
+ }
253
+ }
254
+ // ── Contribution report builder ──────────────────────────────────────
255
+ function buildContributionReport(semanticEnabled, providerReady, hitsFound, deterministicTopCount) {
256
+ if (!semanticEnabled) {
257
+ return {
258
+ addedCandidates: 0, acceptedCandidates: 0, rejectedCandidates: 0,
259
+ semanticOnlyCandidates: 0, deterministicOverlap: 0, topKDelta: 0,
260
+ noOp: true, regressionRisk: "none",
261
+ reasons: ["semantic disabled"],
262
+ status: "disabled",
263
+ };
264
+ }
265
+ if (!providerReady) {
266
+ return {
267
+ addedCandidates: 0, acceptedCandidates: 0, rejectedCandidates: 0,
268
+ semanticOnlyCandidates: 0, deterministicOverlap: 0, topKDelta: 0,
269
+ noOp: true, regressionRisk: "none",
270
+ reasons: ["provider unavailable"],
271
+ status: "unavailable",
272
+ };
273
+ }
274
+ if (hitsFound === 0) {
275
+ return {
276
+ addedCandidates: 0, acceptedCandidates: 0, rejectedCandidates: 0,
277
+ semanticOnlyCandidates: 0, deterministicOverlap: 0, topKDelta: 0,
278
+ noOp: true, regressionRisk: "none",
279
+ reasons: ["no semantic hits found"],
280
+ status: "no_hits",
281
+ };
282
+ }
283
+ return {
284
+ addedCandidates: hitsFound,
285
+ acceptedCandidates: hitsFound,
286
+ rejectedCandidates: 0,
287
+ semanticOnlyCandidates: hitsFound,
288
+ deterministicOverlap: 0,
289
+ topKDelta: hitsFound,
290
+ noOp: false,
291
+ regressionRisk: hitsFound > 5 ? "low" : "none",
292
+ reasons: ["report-only: contribution measured, no ranking change"],
293
+ status: "report_only",
294
+ };
295
+ }
296
+ // ── Hybrid-safe promotion (diagnostic only) ─────────────────────────
297
+ var ALLOWED_GUARDS = ["deterministic_anchor_overlap", "missing_slot_recovery", "strong_path_evidence"];
298
+ var BLOCKING_GUARDS = ["avoid_or_noise_block", "semantic_unavailable_block", "report_only_guard"];
299
+ function buildHybridPromotionReport(semanticEnabled, providerReady, hits, deterministicAnchors, missingSlots) {
300
+ var guardExplanations = {};
301
+ var promoted = [];
302
+ var blocked = [];
303
+ if (!semanticEnabled || !providerReady) {
304
+ guardExplanations["semantic_unavailable_block"] = "semantic is disabled or provider unavailable";
305
+ guardExplanations["report_only_guard"] = "promotion is report-only in Sprint 18D";
306
+ var guardResults = [];
307
+ BLOCKING_GUARDS.forEach(function (g) { guardResults.push({ guard: g, passed: false, reason: g }); });
308
+ ALLOWED_GUARDS.forEach(function (g) { guardResults.push({ guard: g, passed: false, reason: "semantic unavailable" }); });
309
+ return {
310
+ totalDiscovered: 0, promotedCandidates: 0, blockedCandidates: 0,
311
+ guardExplanations, guardResults, promoted, blocked,
312
+ promotionReasons: [], blockReasons: ["semantic_unavailable_block"],
313
+ mode: "disabled", safeForDefaultRanking: false,
314
+ };
315
+ }
316
+ var anchorSet = {};
317
+ for (var a = 0; a < deterministicAnchors.length; a++)
318
+ anchorSet[deterministicAnchors[a]] = true;
319
+ var slotSet = {};
320
+ for (var ms = 0; ms < missingSlots.length; ms++)
321
+ slotSet[missingSlots[ms]] = true;
322
+ for (var hi = 0; hi < hits.length; hi++) {
323
+ var hit = hits[hi];
324
+ var canPromote = false;
325
+ var reason = "";
326
+ // Check deterministic anchor overlap
327
+ if (anchorSet[hit.filePath]) {
328
+ canPromote = true;
329
+ reason = "deterministic_anchor_overlap";
330
+ }
331
+ // Check missing slot recovery
332
+ else if (slotSet[hit.slot]) {
333
+ canPromote = true;
334
+ reason = "missing_slot_recovery";
335
+ }
336
+ // Check strong path evidence
337
+ else if (hit.similarity > 0.7) {
338
+ canPromote = true;
339
+ reason = "strong_path_evidence";
340
+ }
341
+ // Block with explanation
342
+ else {
343
+ reason = "avoid_or_noise_block";
344
+ }
345
+ if (canPromote) {
346
+ promoted.push({ filePath: hit.filePath, reason: reason });
347
+ }
348
+ else {
349
+ blocked.push({ filePath: hit.filePath, reason: reason });
350
+ }
351
+ }
352
+ guardExplanations["report_only_guard"] = "promotion is report-only in Sprint 18D; ranking unchanged";
353
+ ALLOWED_GUARDS.forEach(function (g) { guardExplanations[g] = "allowed: " + g; });
354
+ BLOCKING_GUARDS.forEach(function (g) { guardExplanations[g] = g; });
355
+ var guardResults = [];
356
+ BLOCKING_GUARDS.forEach(function (g) { guardResults.push({ guard: g, passed: false, reason: g }); });
357
+ ALLOWED_GUARDS.forEach(function (g) {
358
+ var p = promoted.some(function (p) { return p.reason === g; });
359
+ guardResults.push({ guard: g, passed: p, reason: p ? g + " matched " + promoted.filter(function (x) { return x.reason === g; }).length + " candidate(s)" : "no " + g + " candidates found" });
360
+ });
361
+ var promotionReasons = promoted.map(function (p) { return p.reason; }).filter(function (r, i, arr) { return arr.indexOf(r) === i; });
362
+ var blockReasons = blocked.map(function (b) { return b.reason; }).filter(function (r, i, arr) { return arr.indexOf(r) === i; });
363
+ return {
364
+ totalDiscovered: hits.length,
365
+ promotedCandidates: promoted.length,
366
+ blockedCandidates: blocked.length,
367
+ guardExplanations: guardExplanations,
368
+ guardResults: guardResults,
369
+ promoted: promoted,
370
+ blocked: blocked,
371
+ promotionReasons: promotionReasons,
372
+ blockReasons: blockReasons,
373
+ mode: "report_only",
374
+ safeForDefaultRanking: false,
375
+ };
376
+ }
377
+ function cosineSimilarity(a, b) {
378
+ let dot = 0, normA = 0, normB = 0;
379
+ for (let i = 0; i < Math.min(a.length, b.length); i++) {
380
+ dot += a[i] * b[i];
381
+ normA += a[i] * a[i];
382
+ normB += b[i] * b[i];
383
+ }
384
+ if (normA === 0 || normB === 0)
385
+ return 0;
386
+ return dot / (Math.sqrt(normA) * Math.sqrt(normB));
387
+ }
388
+ //# sourceMappingURL=semanticChunkIndex.js.map