paqad-ai 1.55.0 → 1.56.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # paqad-ai
2
2
 
3
+ ## 1.56.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 997bbc0: RAG retrieval was dark: local-model cosine scores on hybrid-fused results rarely reached the 0.75 precision floor, so every query fell back below-floor and the model never received a slice. Retrieval now uses floor-with-relief — the 0.75 floor still marks high-confidence hits, but when nothing clears it the top slices at or above a new `rag_relief_floor` (default 0.35, chosen from live probe data) are delivered tagged low-confidence instead of nothing. When retrieval still finds nothing, the session-context artifact carries one honest line naming the best score instead of silently omitting the section.
8
+
9
+ Also wires the previously-defined-but-never-recorded `used` RAG-evidence event: the background context worker now records what it actually delivered into the artifact (injected sections, slice/pointer counts, top score, bytes) into the per-feature `.paqad/ledger/feature-evidence/<feature>/rag.jsonl`, so you can see whether RAG was used — not just that retrieval ran. Adds a `paqad-ai rag probe "<query>"` verb that prints pre-floor top-10 fused scores for diagnosis.
10
+
3
11
  ## 1.55.0
4
12
 
5
13
  ### Minor Changes
package/dist/cli/index.js CHANGED
@@ -344,6 +344,11 @@ function defaultIntelligenceConfig() {
344
344
  return {
345
345
  rag_enabled: false,
346
346
  rag_similarity_threshold: 0.75,
347
+ // Issue #354 — chosen from live probe data on this repo: genuine on-target queries
348
+ // top out at 0.37-0.52 (local MiniLM cosine on hybrid-fused results), while a truly
349
+ // irrelevant query ("kubernetes ingress") tops at 0.32. 0.35 sits between: it
350
+ // delivers the weakest real hit and darkens the negative control.
351
+ rag_relief_floor: 0.35,
347
352
  rag_top_n: 20,
348
353
  rag_max_file_size: 153600,
349
354
  benchmark_gates: { ...DEFAULT_BENCHMARK_GATES },
@@ -368,6 +373,7 @@ function normalizeIntelligenceConfig(input3) {
368
373
  embedding_provider: provider,
369
374
  embedding_model: input3.embedding_model ?? (provider ? getDefaultEmbeddingModel(provider) : void 0),
370
375
  rag_similarity_threshold: input3.rag_similarity_threshold ?? defaults.rag_similarity_threshold,
376
+ rag_relief_floor: input3.rag_relief_floor ?? defaults.rag_relief_floor,
371
377
  rag_top_n: input3.rag_top_n ?? defaults.rag_top_n,
372
378
  rag_max_file_size: input3.rag_max_file_size ?? defaults.rag_max_file_size,
373
379
  rag_base_branch: input3.rag_base_branch ?? defaults.rag_base_branch,
@@ -648,6 +654,7 @@ function resolveFrameworkConfigFromMap(raw) {
648
654
  embedding_provider: provider,
649
655
  embedding_model: embeddingModel,
650
656
  rag_similarity_threshold: rn("rag_similarity_threshold"),
657
+ rag_relief_floor: rn("rag_relief_floor"),
651
658
  rag_top_n: rn("rag_top_n"),
652
659
  rag_max_file_size: rn("rag_max_file_size"),
653
660
  rag_base_branch: raw.get("rag_base_branch")?.trim() || void 0
@@ -1008,6 +1015,7 @@ function frameworkOverridesToFlat(overrides) {
1008
1015
  i.rag_similarity_threshold,
1009
1016
  d.intelligence.rag_similarity_threshold
1010
1017
  );
1018
+ put("rag_relief_floor", i.rag_relief_floor, d.intelligence.rag_relief_floor);
1011
1019
  put("rag_top_n", i.rag_top_n, d.intelligence.rag_top_n);
1012
1020
  put("rag_max_file_size", i.rag_max_file_size, d.intelligence.rag_max_file_size);
1013
1021
  put("rag_base_branch", i.rag_base_branch, d.intelligence.rag_base_branch);
@@ -1309,6 +1317,15 @@ var init_framework_config = __esm({
1309
1317
  section: "Intelligence / RAG",
1310
1318
  comment: "Minimum cosine similarity for a chunk to be retrieved."
1311
1319
  },
1320
+ {
1321
+ key: "rag_relief_floor",
1322
+ env: "PAQAD_RAG_RELIEF_FLOOR",
1323
+ type: "number",
1324
+ default: 0.35,
1325
+ group: "rag",
1326
+ section: "Intelligence / RAG",
1327
+ comment: "Relief band for floor-with-relief. When nothing clears rag_similarity_threshold, the top slices at or above this lower score are delivered tagged low-confidence."
1328
+ },
1312
1329
  {
1313
1330
  key: "rag_top_n",
1314
1331
  env: "PAQAD_RAG_TOP_N",
@@ -1586,6 +1603,7 @@ var init_framework_config = __esm({
1586
1603
  "rag_embedding_provider",
1587
1604
  "rag_embedding_model",
1588
1605
  "rag_similarity_threshold",
1606
+ "rag_relief_floor",
1589
1607
  "rag_top_n",
1590
1608
  "rag_max_file_size",
1591
1609
  "rag_base_branch"
@@ -3578,6 +3596,7 @@ var init_project_profile_schema = __esm({
3578
3596
  },
3579
3597
  embedding_model: { type: "string" },
3580
3598
  rag_similarity_threshold: { type: "number" },
3599
+ rag_relief_floor: { type: "number" },
3581
3600
  rag_top_n: { type: "integer", minimum: 1 },
3582
3601
  rag_max_file_size: { type: "integer", minimum: 1 },
3583
3602
  rag_base_branch: { type: "string" },
@@ -10403,6 +10422,21 @@ import { existsSync as existsSync18, statSync as statSync3 } from "fs";
10403
10422
  import { mkdir as mkdir9, readdir, rename as rename3, rm as rm3 } from "fs/promises";
10404
10423
  import { homedir as homedir7 } from "os";
10405
10424
  import { extname, join as join36, resolve as resolve3, sep as sep2 } from "path";
10425
+ function toRetrievalResult(candidates, extra) {
10426
+ return {
10427
+ vector_scores: new Map(candidates.map((candidate) => [candidate.id, candidate.score])),
10428
+ chunks_retrieved: candidates.length,
10429
+ retrieved_chunk_ids: candidates.map((candidate) => candidate.id),
10430
+ retrieved_source_files: candidates.map((candidate) => candidate.source_file),
10431
+ retrieved_chunks: candidates.map((candidate) => ({
10432
+ id: candidate.id,
10433
+ source_file: candidate.source_file,
10434
+ content: candidate.content
10435
+ })),
10436
+ best_score: extra.bestScore,
10437
+ low_confidence: extra.lowConfidence
10438
+ };
10439
+ }
10406
10440
  function queryTextFromTask(taskDescription, keywords = [], targetFilePath, symbols = []) {
10407
10441
  const parts = [taskDescription, ...keywords, targetFilePath, ...symbols].filter(Boolean);
10408
10442
  return parts.join("\n");
@@ -10450,7 +10484,7 @@ function fuseHybridRanking(dense, queryText) {
10450
10484
  const fused = reciprocalRankFusion([denseOrder, lexical]);
10451
10485
  return fused.map((entry) => byId.get(entry.id)).filter((hit) => hit !== void 0);
10452
10486
  }
10453
- var VISION_MAX_CHUNK_CHARS, CRS_EMBED_BATCH_SIZE, HYBRID_FUSION_POOL_MULTIPLIER, CRS_REVERT_RETENTION_MS, PARTIAL_VECTOR_INDEX, PARTIAL_VECTOR_META, RagService;
10487
+ var VISION_MAX_CHUNK_CHARS, CRS_EMBED_BATCH_SIZE, HYBRID_FUSION_POOL_MULTIPLIER, RELIEF_SLICE_CAP, CRS_REVERT_RETENTION_MS, PARTIAL_VECTOR_INDEX, PARTIAL_VECTOR_META, RagService;
10454
10488
  var init_service = __esm({
10455
10489
  "src/rag/service.ts"() {
10456
10490
  "use strict";
@@ -10484,6 +10518,7 @@ var init_service = __esm({
10484
10518
  VISION_MAX_CHUNK_CHARS = 2e3;
10485
10519
  CRS_EMBED_BATCH_SIZE = 32;
10486
10520
  HYBRID_FUSION_POOL_MULTIPLIER = 4;
10521
+ RELIEF_SLICE_CAP = 2;
10487
10522
  CRS_REVERT_RETENTION_MS = 24 * 60 * 60 * 1e3;
10488
10523
  PARTIAL_VECTOR_INDEX = PATHS.VECTOR_INDEX.replace(/\.json$/, ".partial.json");
10489
10524
  PARTIAL_VECTOR_META = PATHS.VECTOR_META.replace(/\.json$/, ".partial.json");
@@ -10789,59 +10824,30 @@ var init_service = __esm({
10789
10824
  if (!skipSync) {
10790
10825
  await this.syncVectorIndex(syncResult, intelligence);
10791
10826
  }
10792
- const provider = await this.providerFactory(this.projectRoot, intelligence);
10793
- const [queryVector] = await provider.embed(
10794
- queryTextFromTask(
10795
- input3.taskDescription,
10796
- input3.keywords,
10797
- input3.targetFilePath,
10798
- input3.symbolReferences ?? []
10799
- )
10800
- );
10801
10827
  const limit = topN ?? intelligence.rag_top_n;
10802
- const pool = limit * HYBRID_FUSION_POOL_MULTIPLIER;
10803
- const [fileResults, visionResults] = await Promise.all([
10804
- this.vectorIndex.query(this.projectRoot, queryVector, pool),
10805
- this.visionVectorIndex.query(this.projectRoot, queryVector, pool)
10806
- ]);
10807
- const dense = [...fileResults, ...visionResults].sort(
10808
- (left, right) => right.score - left.score
10809
- );
10810
- const queryText = queryTextFromTask(
10811
- input3.taskDescription,
10812
- input3.keywords,
10813
- input3.targetFilePath,
10814
- input3.symbolReferences ?? []
10828
+ const scored = await this.scoreCandidates(input3, limit, intelligence);
10829
+ const bestScore = scored.length > 0 ? scored[0].score : void 0;
10830
+ const aboveFloor = scored.filter(
10831
+ (candidate) => candidate.score >= intelligence.rag_similarity_threshold
10815
10832
  );
10816
- const fused = fuseHybridRanking(dense, queryText);
10817
- const reranked = await this.applyReranking(queryText, fused, intelligence.reranking);
10818
- const results = reranked.slice(0, limit);
10819
- const filtered = results.filter(
10820
- (result) => result.score >= intelligence.rag_similarity_threshold
10821
- );
10822
- if (filtered.length === 0) {
10823
- appendRagAudit(this.projectRoot, "WARN", "rag-fallback", {
10824
- reason: "below-similarity-threshold"
10825
- });
10826
- return {
10827
- vector_scores: /* @__PURE__ */ new Map(),
10828
- chunks_retrieved: 0,
10829
- retrieved_chunk_ids: [],
10830
- retrieved_source_files: [],
10831
- retrieved_chunks: [],
10832
- fallback_reason: "below-similarity-threshold"
10833
- };
10833
+ if (aboveFloor.length > 0) {
10834
+ return toRetrievalResult(aboveFloor, { bestScore, lowConfidence: false });
10835
+ }
10836
+ const relief = scored.filter((candidate) => candidate.score >= intelligence.rag_relief_floor).slice(0, RELIEF_SLICE_CAP);
10837
+ if (relief.length > 0) {
10838
+ return toRetrievalResult(relief, { bestScore, lowConfidence: true });
10834
10839
  }
10840
+ appendRagAudit(this.projectRoot, "WARN", "rag-fallback", {
10841
+ reason: "below-similarity-threshold"
10842
+ });
10835
10843
  return {
10836
- vector_scores: new Map(filtered.map((result) => [result.item.id, result.score])),
10837
- chunks_retrieved: filtered.length,
10838
- retrieved_chunk_ids: filtered.map((result) => result.item.id),
10839
- retrieved_source_files: filtered.map((result) => result.item.source_file),
10840
- retrieved_chunks: filtered.map((result) => ({
10841
- id: result.item.id,
10842
- source_file: result.item.source_file,
10843
- content: result.item.content
10844
- }))
10844
+ vector_scores: /* @__PURE__ */ new Map(),
10845
+ chunks_retrieved: 0,
10846
+ retrieved_chunk_ids: [],
10847
+ retrieved_source_files: [],
10848
+ retrieved_chunks: [],
10849
+ fallback_reason: "below-similarity-threshold",
10850
+ best_score: bestScore
10845
10851
  };
10846
10852
  } catch (error) {
10847
10853
  appendRagAudit(this.projectRoot, "WARN", "rag-fallback", {
@@ -10865,6 +10871,63 @@ var init_service = __esm({
10865
10871
  const syncResult = await this.refreshContext();
10866
10872
  return this.retrieveWithSyncPolicy(syncResult, input3, topN, true);
10867
10873
  }
10874
+ /**
10875
+ * Embed the query, query the file + vision indexes over a widened pool, fuse the
10876
+ * dense and lexical (BM25) legs, optionally rerank, and return the top-`limit`
10877
+ * candidates with their scores — BEFORE any similarity/relief floor is applied.
10878
+ *
10879
+ * This is the single canonical scoring path (RULE-04a1): both floor-with-relief
10880
+ * retrieval ({@link retrieveWithSyncPolicy}) and the `probe` diagnostic call it, so
10881
+ * a probe reports exactly the scores retrieval sees. Assumes the index is present
10882
+ * and valid — callers check {@link getStatus} first.
10883
+ */
10884
+ async scoreCandidates(input3, limit, intelligence) {
10885
+ const provider = await this.providerFactory(this.projectRoot, intelligence);
10886
+ const queryText = queryTextFromTask(
10887
+ input3.taskDescription,
10888
+ input3.keywords,
10889
+ input3.targetFilePath,
10890
+ input3.symbolReferences ?? []
10891
+ );
10892
+ const [queryVector] = await provider.embed(queryText);
10893
+ const pool = limit * HYBRID_FUSION_POOL_MULTIPLIER;
10894
+ const [fileResults, visionResults] = await Promise.all([
10895
+ this.vectorIndex.query(this.projectRoot, queryVector, pool),
10896
+ this.visionVectorIndex.query(this.projectRoot, queryVector, pool)
10897
+ ]);
10898
+ const dense = [...fileResults, ...visionResults].sort(
10899
+ (left, right) => right.score - left.score
10900
+ );
10901
+ const fused = fuseHybridRanking(dense, queryText);
10902
+ const reranked = await this.applyReranking(queryText, fused, intelligence.reranking);
10903
+ return reranked.slice(0, limit).map((result) => ({
10904
+ id: result.item.id,
10905
+ source_file: result.item.source_file,
10906
+ content: result.item.content,
10907
+ score: result.score
10908
+ }));
10909
+ }
10910
+ /**
10911
+ * Issue #354 diagnostic — return the top-`limit` scored candidates for a query
10912
+ * BEFORE the similarity/relief floor, so `paqad-ai rag probe` can show how far real
10913
+ * scores sit from the floor on a live repo (the gap that made retrieval dark).
10914
+ * Refreshes the index internally like {@link retrieveForEval}. Returns `[]` when rag
10915
+ * is off or the index is missing/invalid.
10916
+ */
10917
+ async probe(input3, topN) {
10918
+ const intelligence = normalizeIntelligenceConfig(
10919
+ readProjectProfile(this.projectRoot)?.intelligence
10920
+ );
10921
+ if (!intelligence.rag_enabled || !intelligence.embedding_provider) {
10922
+ return [];
10923
+ }
10924
+ await this.refreshContext();
10925
+ const status = await this.getStatus();
10926
+ if (!status.index_present || !status.valid) {
10927
+ return [];
10928
+ }
10929
+ return this.scoreCandidates(input3, topN ?? intelligence.rag_top_n, intelligence);
10930
+ }
10868
10931
  /**
10869
10932
  * Accept plain text a consumer extracted from an image (via OCR, captioning,
10870
10933
  * etc.) into the retrieval index. The engine never reads the image itself; it
@@ -29306,7 +29369,7 @@ init_cancelled_error();
29306
29369
  init_events();
29307
29370
 
29308
29371
  // src/index.ts
29309
- var VERSION = "1.55.0";
29372
+ var VERSION = "1.56.0";
29310
29373
 
29311
29374
  // src/cli/commands/audit.ts
29312
29375
  init_esm_shims();
@@ -40710,9 +40773,6 @@ function truncateSlice(content) {
40710
40773
  return `${body.slice(0, MAX_SLICE_CHARS)}
40711
40774
  \u2026[slice truncated at ${MAX_SLICE_CHARS} chars]`;
40712
40775
  }
40713
- function applyPrecisionFloor(slices, floor) {
40714
- return slices.filter((slice) => typeof slice.score === "number" && slice.score >= floor);
40715
- }
40716
40776
  function formatScore(score) {
40717
40777
  if (typeof score !== "number") {
40718
40778
  return "";
@@ -40730,11 +40790,19 @@ function dedupeSlices(slices) {
40730
40790
  }
40731
40791
  return unique;
40732
40792
  }
40733
- function composeRetrievalSection(slices) {
40793
+ function composeRetrievalSection(slices, opts = {}) {
40734
40794
  if (slices.length === 0) {
40795
+ if (typeof opts.bestScore === "number") {
40796
+ return `## Retrieved context \u2014 none above the confidence floor (best match ${Math.round(
40797
+ opts.bestScore * 100
40798
+ )}%)
40799
+ > The index had no slice confident enough to inject for the files in play; read the live files directly.
40800
+ `;
40801
+ }
40735
40802
  return "";
40736
40803
  }
40737
40804
  const capped = dedupeSlices(slices).slice(0, MAX_RETRIEVAL_SLICES);
40805
+ const lowConfidence = capped.some((slice) => slice.lowConfidence);
40738
40806
  const blocks = capped.map(
40739
40807
  (slice) => `### ${slice.source_file}${formatScore(slice.score)}
40740
40808
  \`\`\`
@@ -40744,8 +40812,10 @@ ${truncateSlice(
40744
40812
  \`\`\``
40745
40813
  ).join("\n\n");
40746
40814
  const noun = capped.length === 1 ? "slice" : "slices";
40747
- return `## Retrieved context \u2014 ${capped.length} ${noun} relevant to the files in play
40748
- > Advisory hints retrieved from the index, not ground truth. Re-read the live files before relying on them; the match % is the index's confidence, not correctness.
40815
+ const heading = lowConfidence ? `## Retrieved context \u2014 ${capped.length} low-confidence ${noun} (nothing cleared the confidence floor)` : `## Retrieved context \u2014 ${capped.length} ${noun} relevant to the files in play`;
40816
+ const guidance = lowConfidence ? `> Weak matches, below the confidence floor \u2014 treat as loose leads only and verify against the live files before relying on them.` : `> Advisory hints retrieved from the index, not ground truth. Re-read the live files before relying on them; the match % is the index's confidence, not correctness.`;
40817
+ return `${heading}
40818
+ ${guidance}
40749
40819
 
40750
40820
  ${blocks}
40751
40821
  `;
@@ -40775,7 +40845,7 @@ async function gatherWorkingSetSlices(projectRoot, options = {}) {
40775
40845
  const changedPaths = options.changedPaths ?? (await loadChangeEvidence(projectRoot)).files;
40776
40846
  const promptQuery = options.query?.trim();
40777
40847
  if (changedPaths.length === 0 && !promptQuery) {
40778
- return [];
40848
+ return { slices: [], bestScore: null };
40779
40849
  }
40780
40850
  const intelligence = normalizeIntelligenceConfig(readProjectProfile(projectRoot)?.intelligence);
40781
40851
  let effectiveTopN = options.topN;
@@ -40783,7 +40853,7 @@ async function gatherWorkingSetSlices(projectRoot, options = {}) {
40783
40853
  const routing = options.routing ?? { scope: deriveScopeFromWorkingSet(changedPaths) };
40784
40854
  const gate = gateRetrieval({ ...routing, baseTopN: intelligence.rag_top_n });
40785
40855
  if (gate.skip) {
40786
- return [];
40856
+ return { slices: [], bestScore: null };
40787
40857
  }
40788
40858
  effectiveTopN = gate.topN;
40789
40859
  }
@@ -40793,15 +40863,15 @@ async function gatherWorkingSetSlices(projectRoot, options = {}) {
40793
40863
  try {
40794
40864
  result = await service.retrieveForEval(retrievalInput, effectiveTopN);
40795
40865
  } catch {
40796
- return [];
40866
+ return { slices: [], bestScore: null };
40797
40867
  }
40798
40868
  const slices = result.retrieved_chunks.map((chunk) => ({
40799
40869
  source_file: chunk.source_file,
40800
40870
  content: chunk.content,
40801
- score: result.vector_scores.get(chunk.id)
40871
+ score: result.vector_scores.get(chunk.id),
40872
+ lowConfidence: result.low_confidence === true
40802
40873
  }));
40803
- const floor = options.precisionFloor ?? intelligence.rag_similarity_threshold;
40804
- const aboveFloor = applyPrecisionFloor(slices, floor);
40874
+ const bestScore = typeof result.best_score === "number" ? result.best_score : null;
40805
40875
  const scope = options.scope ?? scopeForWorkflow(options.routing?.workflow);
40806
40876
  if (options.recordEvidence) {
40807
40877
  recordRagEvidence(
@@ -40819,7 +40889,7 @@ async function gatherWorkingSetSlices(projectRoot, options = {}) {
40819
40889
  }
40820
40890
  );
40821
40891
  }
40822
- return filterToScope(aboveFloor, scope);
40892
+ return { slices: filterToScope(slices, scope), bestScore };
40823
40893
  }
40824
40894
 
40825
40895
  // src/pipeline/session-route.ts
@@ -40858,6 +40928,9 @@ function readSessionRoute(projectRoot) {
40858
40928
  }
40859
40929
  }
40860
40930
 
40931
+ // src/cli/commands/rag.ts
40932
+ init_recorder();
40933
+
40861
40934
  // src/rag/background-sync.ts
40862
40935
  init_esm_shims();
40863
40936
  import { join as join196 } from "path";
@@ -41465,6 +41538,42 @@ function createRagCommand() {
41465
41538
  process.stdout.write(`${JSON.stringify(await service.getStatus(), null, 2)}
41466
41539
  `);
41467
41540
  });
41541
+ command.command("probe <query>").description(
41542
+ "Print the top pre-floor retrieval scores for a query (diagnostic; no floor filter)"
41543
+ ).option("--project-root <path>", "Project root", process.cwd()).option("--top-n <n>", "How many candidates to show", "10").action(async (query, options) => {
41544
+ const service = new RagService(options.projectRoot);
41545
+ const { intelligence } = resolveFrameworkConfig(options.projectRoot);
41546
+ const floor = intelligence.rag_similarity_threshold;
41547
+ const reliefFloor = intelligence.rag_relief_floor;
41548
+ const topN = Number.parseInt(options.topN, 10);
41549
+ const candidates = await service.probe(
41550
+ { taskDescription: query, keywords: [] },
41551
+ Number.isFinite(topN) && topN > 0 ? topN : 10
41552
+ );
41553
+ const rows = candidates.map((candidate, index) => ({
41554
+ rank: index + 1,
41555
+ source_file: candidate.source_file,
41556
+ score: Number(candidate.score.toFixed(4)),
41557
+ above_floor: candidate.score >= floor,
41558
+ above_relief: candidate.score >= reliefFloor,
41559
+ gap_to_floor: Number((floor - candidate.score).toFixed(4))
41560
+ }));
41561
+ process.stdout.write(
41562
+ `${JSON.stringify(
41563
+ {
41564
+ query,
41565
+ similarity_threshold: floor,
41566
+ relief_floor: reliefFloor,
41567
+ candidates: rows.length,
41568
+ best_score: rows[0]?.score ?? null,
41569
+ rows
41570
+ },
41571
+ null,
41572
+ 2
41573
+ )}
41574
+ `
41575
+ );
41576
+ });
41468
41577
  command.command("refresh-context").description(
41469
41578
  "Sync the index, retrieve slices, and recompose session context (background worker)"
41470
41579
  ).option("--project-root <path>", "Project root", process.cwd()).option("--quiet", "Suppress output (used by the background trigger)").action(async (options) => {
@@ -41486,24 +41595,24 @@ function createRagCommand() {
41486
41595
  return;
41487
41596
  }
41488
41597
  const sync = await backgroundIndexSync(options.projectRoot);
41489
- const slices = retrieves ? await gatherWorkingSetSlices(options.projectRoot, {
41598
+ const { slices, bestScore } = retrieves ? await gatherWorkingSetSlices(options.projectRoot, {
41490
41599
  recordEvidence: { adapter: "engine" },
41491
41600
  query: route?.query
41492
- }) : [];
41493
- const retrievalSection = slices.length > MAX_RETRIEVAL_SLICES ? composeContextPack(
41494
- distillSlices(slices, {
41495
- readFile: (path11) => {
41496
- try {
41497
- return readFileSync99(
41498
- isAbsolute10(path11) ? path11 : join198(options.projectRoot, path11),
41499
- "utf8"
41500
- );
41501
- } catch {
41502
- return void 0;
41503
- }
41601
+ }) : { slices: [], bestScore: null };
41602
+ const usesContextPack = slices.length > MAX_RETRIEVAL_SLICES;
41603
+ const packEntries = usesContextPack ? distillSlices(slices, {
41604
+ readFile: (path11) => {
41605
+ try {
41606
+ return readFileSync99(
41607
+ isAbsolute10(path11) ? path11 : join198(options.projectRoot, path11),
41608
+ "utf8"
41609
+ );
41610
+ } catch {
41611
+ return void 0;
41504
41612
  }
41505
- })
41506
- ) : composeRetrievalSection(slices);
41613
+ }
41614
+ }) : [];
41615
+ const retrievalSection = usesContextPack ? composeContextPack(packEntries) : composeRetrievalSection(slices, { bestScore });
41507
41616
  const memorySection = retrieves ? gatherCodebaseMemory(options.projectRoot) : "";
41508
41617
  let driftSection = "";
41509
41618
  if (retrieves) {
@@ -41516,6 +41625,31 @@ function createRagCommand() {
41516
41625
  driftSection,
41517
41626
  loadRules
41518
41627
  });
41628
+ if (retrieves) {
41629
+ const sliceCount = usesContextPack ? 0 : slices.length;
41630
+ const pointerCount = usesContextPack ? packEntries.length : 0;
41631
+ const injectedSections = [];
41632
+ if (loadRules) injectedSections.push("rules");
41633
+ if (sliceCount > 0 || pointerCount > 0) injectedSections.push("retrieval");
41634
+ if (memorySection) injectedSections.push("memory");
41635
+ if (driftSection) injectedSections.push("drift");
41636
+ recordRagEvidence(
41637
+ options.projectRoot,
41638
+ "used",
41639
+ {
41640
+ injected: sliceCount > 0 || pointerCount > 0 || Boolean(memorySection) || Boolean(driftSection),
41641
+ injected_sections: injectedSections,
41642
+ slice_count: sliceCount,
41643
+ pointer_count: pointerCount,
41644
+ score_top: bestScore,
41645
+ bytes_injected: Buffer.byteLength(
41646
+ `${retrievalSection}${memorySection}${driftSection}`,
41647
+ "utf8"
41648
+ )
41649
+ },
41650
+ { ragEnabled: true, adapter: "engine" }
41651
+ );
41652
+ }
41519
41653
  if (!options.quiet) {
41520
41654
  process.stdout.write(
41521
41655
  `${target ? `wrote ${target}` : "nothing to compose"}; index sync: ${sync.synced ? "done" : sync.reason}; slices: ${slices.length}