@remnic/core 10.0.17 → 10.0.18

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 (203) hide show
  1. package/dist/access-admin-ops-surface.js +15 -15
  2. package/dist/access-authorization-probe.js +16 -16
  3. package/dist/access-boundary.js +15 -15
  4. package/dist/access-cli.js +56 -56
  5. package/dist/access-extraction-force-flush.js +15 -15
  6. package/dist/access-http-briefing.js +16 -16
  7. package/dist/access-http-query.js +17 -17
  8. package/dist/access-http.js +32 -32
  9. package/dist/access-identity-continuity-surface.js +15 -15
  10. package/dist/access-lcm-surface.js +15 -15
  11. package/dist/access-mcp.js +25 -25
  12. package/dist/access-namespace-preflight.js +15 -15
  13. package/dist/access-observe-write-surface.js +15 -15
  14. package/dist/access-operations-batch.js +16 -16
  15. package/dist/access-operations.js +23 -23
  16. package/dist/access-recall-concurrency.js +15 -15
  17. package/dist/access-recall-diagnostics.js +2 -2
  18. package/dist/access-recall-response.js +15 -15
  19. package/dist/access-recall-surface.js +15 -15
  20. package/dist/access-service.js +15 -15
  21. package/dist/access-surface-catalog.js +17 -17
  22. package/dist/active-recall.js +2 -2
  23. package/dist/briefing.js +3 -3
  24. package/dist/causal-consolidation.js +4 -4
  25. package/dist/{chunk-2PYHLSXK.js → chunk-2C5YAVHA.js} +2 -2
  26. package/dist/{chunk-GWVNGDJW.js → chunk-2I3OREMR.js} +2 -2
  27. package/dist/{chunk-GCVDFX66.js → chunk-2JGBX5XY.js} +2 -2
  28. package/dist/{chunk-PEF5LHQU.js → chunk-32FVH5OQ.js} +5 -5
  29. package/dist/{chunk-XYGQSDTH.js → chunk-3K6J5GO5.js} +3 -3
  30. package/dist/{chunk-3MO4LWYU.js → chunk-466EGMFQ.js} +1 -1
  31. package/dist/{chunk-3MO4LWYU.js.map → chunk-466EGMFQ.js.map} +1 -1
  32. package/dist/{chunk-HQSK2INQ.js → chunk-4OEBL5T3.js} +2 -2
  33. package/dist/{chunk-IJMDBYCO.js → chunk-5JXNXKKV.js} +2 -2
  34. package/dist/{chunk-CQOIWJ5E.js → chunk-5NO42IYF.js} +3 -3
  35. package/dist/{chunk-NHUX6GXA.js → chunk-62CRBI5B.js} +2 -2
  36. package/dist/{chunk-5ATSXCAG.js → chunk-6VWCL2IZ.js} +3 -3
  37. package/dist/{chunk-CXOYUANR.js → chunk-7UHCV5B3.js} +2 -2
  38. package/dist/{chunk-BK2BVLZW.js → chunk-A2IJEV5L.js} +2 -2
  39. package/dist/{chunk-EH4BQ7LT.js → chunk-AAQ77A44.js} +2 -2
  40. package/dist/{chunk-R2H4ZFBJ.js → chunk-BI3CIDIH.js} +3 -3
  41. package/dist/{chunk-GFWRXPF6.js → chunk-CA2R2AD4.js} +12 -12
  42. package/dist/{chunk-4SCZZ3U7.js → chunk-D42L5SQF.js} +2 -2
  43. package/dist/{chunk-C6JMGAMO.js → chunk-DJMGVSST.js} +2 -2
  44. package/dist/{chunk-H5IUN433.js → chunk-EML6HJE6.js} +2 -2
  45. package/dist/{chunk-ZZTOURJI.js → chunk-EVWDNKQA.js} +13 -4
  46. package/dist/chunk-EVWDNKQA.js.map +1 -0
  47. package/dist/{chunk-MJIOGYKX.js → chunk-FBNL4BYD.js} +2 -2
  48. package/dist/{chunk-5KGYTX5O.js → chunk-GXVLEXIX.js} +2 -2
  49. package/dist/{chunk-6YEPGWUP.js → chunk-HVIXRLXJ.js} +2 -2
  50. package/dist/{chunk-AZDTDWS2.js → chunk-IBGRIAE5.js} +2 -2
  51. package/dist/{chunk-YDBIWGNI.js → chunk-IIK2PD3F.js} +8 -2
  52. package/dist/{chunk-YDBIWGNI.js.map → chunk-IIK2PD3F.js.map} +1 -1
  53. package/dist/{chunk-YR4COAEC.js → chunk-INBB7D3V.js} +2 -2
  54. package/dist/{chunk-VW6VIJOS.js → chunk-IVUCF3QO.js} +2 -2
  55. package/dist/{chunk-UGYUBENJ.js → chunk-LDZD3OQG.js} +2 -2
  56. package/dist/{chunk-VNZMZPAC.js → chunk-LT4SMGE4.js} +2 -2
  57. package/dist/{chunk-7VQ6AI7H.js → chunk-N36PBG4A.js} +2 -2
  58. package/dist/{chunk-G3UUAQOD.js → chunk-NFB5QTOH.js} +2 -2
  59. package/dist/{chunk-F2772ATT.js → chunk-NIS3FOMD.js} +2 -2
  60. package/dist/{chunk-4PDTVVSW.js → chunk-O6ADSFGY.js} +2 -2
  61. package/dist/{chunk-MAVYEZKM.js → chunk-OFQOOLQQ.js} +2 -2
  62. package/dist/{chunk-O2YPCFJT.js → chunk-OPNSIFFU.js} +7 -7
  63. package/dist/{chunk-W3FVQBGF.js → chunk-PDFAX4PK.js} +2 -2
  64. package/dist/{chunk-NAGMQXWV.js → chunk-QC5TJUSP.js} +2 -2
  65. package/dist/{chunk-2PTH4PRL.js → chunk-QZ7WOCME.js} +2 -2
  66. package/dist/{chunk-5MLGY6IY.js → chunk-RQMSD4CN.js} +56 -35
  67. package/dist/chunk-RQMSD4CN.js.map +1 -0
  68. package/dist/{chunk-TN4EA4X4.js → chunk-RTV3DB4I.js} +2 -2
  69. package/dist/{chunk-NZCKG25S.js → chunk-SSUTJLCF.js} +2 -2
  70. package/dist/{chunk-GUY6L6LL.js → chunk-TXE55Z3X.js} +2 -2
  71. package/dist/{chunk-XKRXN63M.js → chunk-UHBZK3CK.js} +2 -2
  72. package/dist/{chunk-PRU7OF3Y.js → chunk-UXXLP2PD.js} +3 -3
  73. package/dist/{chunk-V3TXIXXY.js → chunk-VOEBHBWG.js} +2 -2
  74. package/dist/{chunk-RI2KCQHP.js → chunk-VUBVNY3W.js} +2 -2
  75. package/dist/{chunk-QSEUUQUF.js → chunk-VVSPHTSU.js} +2 -2
  76. package/dist/{chunk-OXNTOHL6.js → chunk-VYVQZRXF.js} +2 -2
  77. package/dist/{chunk-L6AZOEXV.js → chunk-W3GFSWKE.js} +4 -4
  78. package/dist/{chunk-MXV2MY6C.js → chunk-W7NVMERN.js} +2 -2
  79. package/dist/{chunk-Q7DWEXG2.js → chunk-XKPLERHV.js} +19 -19
  80. package/dist/{chunk-KLJVTZ3R.js → chunk-YRKKW4KT.js} +3 -3
  81. package/dist/{chunk-DQR2LD3V.js → chunk-YW4ZYASS.js} +2 -2
  82. package/dist/{chunk-QS3OLP5I.js → chunk-ZDDDWTC7.js} +2 -2
  83. package/dist/{chunk-JZTEOBOR.js → chunk-ZDUMF4H6.js} +12 -12
  84. package/dist/{chunk-H6FREOYX.js → chunk-ZUCNOTNF.js} +7 -7
  85. package/dist/cli.js +43 -43
  86. package/dist/coding/export-okf-codegraph.js +2 -2
  87. package/dist/compounding/engine.js +4 -4
  88. package/dist/config.js +2 -2
  89. package/dist/connectors/codex-materialize-runner.js +3 -3
  90. package/dist/connectors/index.js +3 -3
  91. package/dist/convergence-refresh.js +5 -5
  92. package/dist/corpus-watermark.js +5 -5
  93. package/dist/entity-retrieval.js +3 -3
  94. package/dist/external-wiki-access.js +16 -16
  95. package/dist/extraction.js +3 -3
  96. package/dist/harmonic-retrieval.js +3 -3
  97. package/dist/index.js +56 -56
  98. package/dist/location/index.js +5 -5
  99. package/dist/maintenance/memory-governance.js +3 -3
  100. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  101. package/dist/maintenance/rebuild-memory-projection-runner.js +5 -5
  102. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  103. package/dist/memory-browse-operations.js +16 -16
  104. package/dist/namespaces/migrate.js +4 -4
  105. package/dist/namespaces/storage.js +3 -3
  106. package/dist/operator-doctor-corpus.js +6 -6
  107. package/dist/operator-toolkit.js +11 -11
  108. package/dist/orchestration/maintenance.js +13 -13
  109. package/dist/orchestration/recall-rerank-coordinator.d.ts.map +1 -1
  110. package/dist/orchestrator.js +56 -56
  111. package/dist/preferences/drift-recall.d.ts.map +1 -1
  112. package/dist/reasoning-trace-recall.d.ts +2 -0
  113. package/dist/reasoning-trace-recall.d.ts.map +1 -1
  114. package/dist/reasoning-trace-recall.js +1 -1
  115. package/dist/recall-explain-renderer.js +3 -3
  116. package/dist/recall-mmr.d.ts +5 -0
  117. package/dist/recall-mmr.d.ts.map +1 -1
  118. package/dist/recall-mmr.js +1 -1
  119. package/dist/recall-navigate-access.js +2 -2
  120. package/dist/recall-navigate-disclosure.js +2 -2
  121. package/dist/recall-navigate.js +2 -2
  122. package/dist/recall-navigation-operations.js +16 -16
  123. package/dist/recall-navigation.js +15 -15
  124. package/dist/recall-xray-cli.js +4 -4
  125. package/dist/recall-xray-renderer.js +3 -3
  126. package/dist/recall-xray.js +2 -2
  127. package/dist/resume-bundles.js +2 -2
  128. package/dist/semantic-consolidation.js +4 -4
  129. package/dist/semantic-rule-promotion.js +3 -3
  130. package/dist/semantic-rule-verifier.js +3 -3
  131. package/dist/source-agent-qualifier.js +3 -3
  132. package/dist/standup/build.js +3 -3
  133. package/dist/storage.js +2 -2
  134. package/dist/support-passport/index.js +18 -18
  135. package/dist/transfer/export-okf.js +3 -3
  136. package/dist/types.d.ts +5 -0
  137. package/dist/types.d.ts.map +1 -1
  138. package/dist/types.js +1 -1
  139. package/dist/verified-recall.js +3 -3
  140. package/dist/who-knows-cli.js +4 -4
  141. package/dist/who-knows.js +3 -3
  142. package/package.json +2 -2
  143. package/src/orchestration/recall-rerank-coordinator.ts +46 -14
  144. package/src/preferences/drift-recall.ts +14 -8
  145. package/src/preferences/preference-drift.test.ts +15 -0
  146. package/src/reasoning-trace-recall.ts +33 -8
  147. package/src/recall-mmr.ts +17 -1
  148. package/src/recall-rerank-coordinator.test.ts +275 -0
  149. package/src/types.ts +5 -0
  150. package/dist/chunk-5MLGY6IY.js.map +0 -1
  151. package/dist/chunk-ZZTOURJI.js.map +0 -1
  152. /package/dist/{chunk-2PYHLSXK.js.map → chunk-2C5YAVHA.js.map} +0 -0
  153. /package/dist/{chunk-GWVNGDJW.js.map → chunk-2I3OREMR.js.map} +0 -0
  154. /package/dist/{chunk-GCVDFX66.js.map → chunk-2JGBX5XY.js.map} +0 -0
  155. /package/dist/{chunk-PEF5LHQU.js.map → chunk-32FVH5OQ.js.map} +0 -0
  156. /package/dist/{chunk-XYGQSDTH.js.map → chunk-3K6J5GO5.js.map} +0 -0
  157. /package/dist/{chunk-HQSK2INQ.js.map → chunk-4OEBL5T3.js.map} +0 -0
  158. /package/dist/{chunk-IJMDBYCO.js.map → chunk-5JXNXKKV.js.map} +0 -0
  159. /package/dist/{chunk-CQOIWJ5E.js.map → chunk-5NO42IYF.js.map} +0 -0
  160. /package/dist/{chunk-NHUX6GXA.js.map → chunk-62CRBI5B.js.map} +0 -0
  161. /package/dist/{chunk-5ATSXCAG.js.map → chunk-6VWCL2IZ.js.map} +0 -0
  162. /package/dist/{chunk-CXOYUANR.js.map → chunk-7UHCV5B3.js.map} +0 -0
  163. /package/dist/{chunk-BK2BVLZW.js.map → chunk-A2IJEV5L.js.map} +0 -0
  164. /package/dist/{chunk-EH4BQ7LT.js.map → chunk-AAQ77A44.js.map} +0 -0
  165. /package/dist/{chunk-R2H4ZFBJ.js.map → chunk-BI3CIDIH.js.map} +0 -0
  166. /package/dist/{chunk-GFWRXPF6.js.map → chunk-CA2R2AD4.js.map} +0 -0
  167. /package/dist/{chunk-4SCZZ3U7.js.map → chunk-D42L5SQF.js.map} +0 -0
  168. /package/dist/{chunk-C6JMGAMO.js.map → chunk-DJMGVSST.js.map} +0 -0
  169. /package/dist/{chunk-H5IUN433.js.map → chunk-EML6HJE6.js.map} +0 -0
  170. /package/dist/{chunk-MJIOGYKX.js.map → chunk-FBNL4BYD.js.map} +0 -0
  171. /package/dist/{chunk-5KGYTX5O.js.map → chunk-GXVLEXIX.js.map} +0 -0
  172. /package/dist/{chunk-6YEPGWUP.js.map → chunk-HVIXRLXJ.js.map} +0 -0
  173. /package/dist/{chunk-AZDTDWS2.js.map → chunk-IBGRIAE5.js.map} +0 -0
  174. /package/dist/{chunk-YR4COAEC.js.map → chunk-INBB7D3V.js.map} +0 -0
  175. /package/dist/{chunk-VW6VIJOS.js.map → chunk-IVUCF3QO.js.map} +0 -0
  176. /package/dist/{chunk-UGYUBENJ.js.map → chunk-LDZD3OQG.js.map} +0 -0
  177. /package/dist/{chunk-VNZMZPAC.js.map → chunk-LT4SMGE4.js.map} +0 -0
  178. /package/dist/{chunk-7VQ6AI7H.js.map → chunk-N36PBG4A.js.map} +0 -0
  179. /package/dist/{chunk-G3UUAQOD.js.map → chunk-NFB5QTOH.js.map} +0 -0
  180. /package/dist/{chunk-F2772ATT.js.map → chunk-NIS3FOMD.js.map} +0 -0
  181. /package/dist/{chunk-4PDTVVSW.js.map → chunk-O6ADSFGY.js.map} +0 -0
  182. /package/dist/{chunk-MAVYEZKM.js.map → chunk-OFQOOLQQ.js.map} +0 -0
  183. /package/dist/{chunk-O2YPCFJT.js.map → chunk-OPNSIFFU.js.map} +0 -0
  184. /package/dist/{chunk-W3FVQBGF.js.map → chunk-PDFAX4PK.js.map} +0 -0
  185. /package/dist/{chunk-NAGMQXWV.js.map → chunk-QC5TJUSP.js.map} +0 -0
  186. /package/dist/{chunk-2PTH4PRL.js.map → chunk-QZ7WOCME.js.map} +0 -0
  187. /package/dist/{chunk-TN4EA4X4.js.map → chunk-RTV3DB4I.js.map} +0 -0
  188. /package/dist/{chunk-NZCKG25S.js.map → chunk-SSUTJLCF.js.map} +0 -0
  189. /package/dist/{chunk-GUY6L6LL.js.map → chunk-TXE55Z3X.js.map} +0 -0
  190. /package/dist/{chunk-XKRXN63M.js.map → chunk-UHBZK3CK.js.map} +0 -0
  191. /package/dist/{chunk-PRU7OF3Y.js.map → chunk-UXXLP2PD.js.map} +0 -0
  192. /package/dist/{chunk-V3TXIXXY.js.map → chunk-VOEBHBWG.js.map} +0 -0
  193. /package/dist/{chunk-RI2KCQHP.js.map → chunk-VUBVNY3W.js.map} +0 -0
  194. /package/dist/{chunk-QSEUUQUF.js.map → chunk-VVSPHTSU.js.map} +0 -0
  195. /package/dist/{chunk-OXNTOHL6.js.map → chunk-VYVQZRXF.js.map} +0 -0
  196. /package/dist/{chunk-L6AZOEXV.js.map → chunk-W3GFSWKE.js.map} +0 -0
  197. /package/dist/{chunk-MXV2MY6C.js.map → chunk-W7NVMERN.js.map} +0 -0
  198. /package/dist/{chunk-Q7DWEXG2.js.map → chunk-XKPLERHV.js.map} +0 -0
  199. /package/dist/{chunk-KLJVTZ3R.js.map → chunk-YRKKW4KT.js.map} +0 -0
  200. /package/dist/{chunk-DQR2LD3V.js.map → chunk-YW4ZYASS.js.map} +0 -0
  201. /package/dist/{chunk-QS3OLP5I.js.map → chunk-ZDDDWTC7.js.map} +0 -0
  202. /package/dist/{chunk-JZTEOBOR.js.map → chunk-ZDUMF4H6.js.map} +0 -0
  203. /package/dist/{chunk-H6FREOYX.js.map → chunk-ZUCNOTNF.js.map} +0 -0
@@ -88,6 +88,8 @@ export interface BoostableResult {
88
88
  path: string;
89
89
  score: number;
90
90
  docid?: string;
91
+ /** Effective relevance carried forward by an upstream rerank stage. */
92
+ effectiveScore?: number;
91
93
  }
92
94
 
93
95
  /**
@@ -118,6 +120,17 @@ export interface ApplyReasoningTraceBoostOptions {
118
120
  boost?: number;
119
121
  }
120
122
 
123
+ /**
124
+ * The relevance a row is compared on: its effective relevance when a rerank
125
+ * stage left one (MMR ranks on the same basis), else the raw retrieval score.
126
+ */
127
+ function comparisonRelevance(row: BoostableResult): number {
128
+ if (typeof row.effectiveScore === "number" && Number.isFinite(row.effectiveScore)) {
129
+ return row.effectiveScore;
130
+ }
131
+ return typeof row.score === "number" && Number.isFinite(row.score) ? row.score : 0;
132
+ }
133
+
121
134
  /**
122
135
  * Apply a score boost to results whose path sits under reasoning-traces/
123
136
  * when the query looks like a problem-solving ask. Returns a new array;
@@ -167,7 +180,18 @@ export function applyReasoningTraceBoost<R extends BoostableResult>(
167
180
  if (isReasoningTracePath(r.path)) {
168
181
  changed = true;
169
182
  const baseScore = typeof r.score === "number" && Number.isFinite(r.score) ? r.score : 0;
170
- boosted.push({ ...r, score: baseScore + boostAmount } as R);
183
+ // Compose the boost into the effective relevance too: a downstream MMR
184
+ // pass prefers it over the raw score, so a stale value would drop the
185
+ // boost.
186
+ const effective =
187
+ typeof r.effectiveScore === "number" && Number.isFinite(r.effectiveScore)
188
+ ? r.effectiveScore + boostAmount
189
+ : undefined;
190
+ boosted.push(
191
+ effective === undefined
192
+ ? ({ ...r, score: baseScore + boostAmount } as R)
193
+ : ({ ...r, score: baseScore + boostAmount, effectiveScore: effective } as R),
194
+ );
171
195
  } else {
172
196
  boosted.push(r);
173
197
  }
@@ -175,21 +199,22 @@ export function applyReasoningTraceBoost<R extends BoostableResult>(
175
199
  if (!changed) return boosted;
176
200
 
177
201
  // Step 2: promote each boosted trace upward past any non-trace neighbor
178
- // whose score is strictly lower than the boosted score. Non-trace items
179
- // never move past each other, so reranker-driven ordering on non-trace
180
- // items is preserved.
202
+ // whose relevance is strictly lower than the boosted trace's. The
203
+ // comparison uses the SAME basis MMR ranks on — the effective relevance a
204
+ // rerank stage left behind, else the raw score — so the boost cannot
205
+ // promote a trace the pipeline deliberately demoted. Non-trace items never
206
+ // move past each other, so reranker-driven ordering on non-trace items is
207
+ // preserved.
181
208
  const out = boosted.slice();
182
209
  for (let i = 0; i < out.length; i++) {
183
210
  if (!isReasoningTracePath(out[i].path)) continue;
184
211
  const trace = out[i];
185
- const traceScore =
186
- typeof trace.score === "number" && Number.isFinite(trace.score) ? trace.score : 0;
212
+ const traceScore = comparisonRelevance(trace);
187
213
  let j = i;
188
214
  while (j > 0) {
189
215
  const prev = out[j - 1];
190
216
  if (isReasoningTracePath(prev.path)) break; // don't reorder traces vs each other
191
- const prevScore =
192
- typeof prev.score === "number" && Number.isFinite(prev.score) ? prev.score : 0;
217
+ const prevScore = comparisonRelevance(prev);
193
218
  if (prevScore >= traceScore) break;
194
219
  out[j] = prev;
195
220
  j -= 1;
package/src/recall-mmr.ts CHANGED
@@ -459,6 +459,11 @@ export interface MmrRecallResult {
459
459
  readonly path?: string;
460
460
  readonly snippet?: string;
461
461
  readonly score?: number;
462
+ /**
463
+ * Effective relevance carried forward by the rerank stage that last
464
+ * adjusted the result. Preferred over `score` for MMR's relevance term.
465
+ */
466
+ readonly effectiveScore?: number;
462
467
  }
463
468
 
464
469
  export interface ReorderRecallResultsOptions {
@@ -545,7 +550,7 @@ export function reorderRecallResultsWithMmr<R extends MmrRecallResult>(
545
550
  const candidates: MmrCandidate[] = results.map((r, index) => ({
546
551
  id: makeRecallKey(r, index),
547
552
  content: r.snippet ?? "",
548
- score: typeof r.score === "number" ? r.score : 0,
553
+ score: effectiveRelevance(r),
549
554
  embedding: null,
550
555
  }));
551
556
  // Index lookup by id so we can map MMR-selected candidates back to their
@@ -601,6 +606,17 @@ export function reorderRecallResultsWithMmr<R extends MmrRecallResult>(
601
606
  return { reordered, diversity, lambda };
602
607
  }
603
608
 
609
+ /**
610
+ * Relevance for MMR's `sim(d, query)` term: the effective relevance an
611
+ * upstream rerank stage carried forward, else the raw retrieval score.
612
+ */
613
+ function effectiveRelevance(r: MmrRecallResult): number {
614
+ if (typeof r.effectiveScore === "number" && Number.isFinite(r.effectiveScore)) {
615
+ return r.effectiveScore;
616
+ }
617
+ return typeof r.score === "number" ? r.score : 0;
618
+ }
619
+
604
620
  function makeRecallKey(r: MmrRecallResult, index: number): string {
605
621
  const baseKey = r.path || r.docid || "";
606
622
  return `${baseKey}::${index}`;
@@ -24,6 +24,8 @@ import test from "node:test";
24
24
  import { parseConfig } from "./config.js";
25
25
  import { resolveCapabilities } from "./capabilities.js";
26
26
  import { RecallRerankCoordinator } from "./orchestration/recall-rerank-coordinator.js";
27
+ import { applyReasoningTraceBoost } from "./reasoning-trace-recall.js";
28
+ import { DRIFT_DETECTION_DEFAULTS } from "./preferences/drift-config.js";
27
29
  import { Orchestrator } from "./orchestrator.js";
28
30
  import type { PluginConfig, QmdSearchResult, MemoryFile } from "./types.js";
29
31
  import type { StorageManager } from "./index.js";
@@ -720,3 +722,276 @@ test("#2859 linkless superseded status does not consume a packet slot", () => {
720
722
  "status-only superseded rows are rejected before the packet cap",
721
723
  );
722
724
  });
725
+
726
+
727
+ // ─── #3226 — the rerank stages' relevance survives the MMR pass ───────────
728
+ /**
729
+ * The rerank stages decide an order, but the MMR pass re-derived relevance
730
+ * from the RAW retrieval score and undid it. Each stage now carries its own
731
+ * relevance (`QmdSearchResult.effectiveScore`) forward and MMR ranks by that.
732
+ *
733
+ * The raw scores are WIDELY SEPARATED (100 vs 0.1) on purpose: a fix that
734
+ * approximates the stage's decision with `raw score × multiplier` still fails.
735
+ */
736
+
737
+ /** Frontmatter double at an explicit path (the cast mirrors `mem` above). */
738
+ function memAt(memPath: string, frontmatter: Record<string, unknown>): MemoryFile {
739
+ return { path: memPath, frontmatter: frontmatter as unknown as MemoryFile["frontmatter"], content: memPath };
740
+ }
741
+
742
+ /** `/facts/<id>.md` frontmatter map from `[id, mw_success?, mw_fail?]` rows. */
743
+ function facts(rows: Array<[string, number?, number?]>): Map<string, MemoryFile> {
744
+ return new Map(rows.map(([id, ok, fail]) => [`/facts/${id}.md`, mem(id, ok, fail)]));
745
+ }
746
+
747
+ function coordinatorFor(config: PluginConfig): RecallRerankCoordinator {
748
+ const corpus = makeFakes([]);
749
+ return new RecallRerankCoordinator({
750
+ getConfig: () => config,
751
+ getStorage: corpus.getStorage,
752
+ readQmdResultMemory: async () => null,
753
+ });
754
+ }
755
+
756
+ const WORTH_RESULTS = [result("bad", 100), result("good", 0.1)];
757
+ const WORTH_FM = facts([["bad", 0, 10], ["good", 10, 0]]);
758
+ const TRUST_CONFIG = { recallMemoryWorthFilterEnabled: false, trustScoreEnabled: true, recallMmrEnabled: true, recallMmrLambda: 1 };
759
+
760
+ for (const lambda of [1, 0.7]) {
761
+ test(`#3226: a Memory-Worth promotion survives MMR (lambda ${lambda})`, async () => {
762
+ const coord = coordinatorFor(await baseConfig({ recallMmrEnabled: true, recallMmrLambda: lambda }));
763
+ const before = WORTH_RESULTS.map((r) => ({ ...r }));
764
+ const staged = await coord.applyMemoryWorthRerank(WORTH_RESULTS, ["default"], WORTH_FM);
765
+ const applied = coord.diversifyAndLimitRecallResults("memories", staged, 1);
766
+ assert.deepEqual(applied.map((r) => r.path), ["/facts/good.md"], "MMR must not undo the promotion");
767
+ assert.deepEqual(WORTH_RESULTS, before, "the stage must not mutate its input");
768
+ });
769
+ }
770
+
771
+ type Scenario = {
772
+ name: string;
773
+ config: Partial<PluginConfig>;
774
+ stage: (c: RecallRerankCoordinator, r: QmdSearchResult[], p: Map<string, MemoryFile>) => Promise<QmdSearchResult[]>;
775
+ results: QmdSearchResult[];
776
+ preloaded: Map<string, MemoryFile>;
777
+ applied: string[];
778
+ };
779
+
780
+ const SCENARIOS: Scenario[] = [
781
+ {
782
+ name: "a TrustScore demotion survives MMR",
783
+ config: TRUST_CONFIG,
784
+ stage: async (c, r, p) => (await c.applyTrustScoreRerank(r, ["default"], p)).results,
785
+ results: [result("untrusted", 100), result("trusted", 1), result("plain", 0.1)],
786
+ preloaded: facts([["untrusted", 0, 10], ["trusted", 10, 0], ["plain"]]),
787
+ applied: ["/facts/trusted.md"],
788
+ },
789
+ {
790
+ name: "a quarantined memory is not resurrected by MMR",
791
+ config: TRUST_CONFIG,
792
+ stage: async (c, r, p) => (await c.applyTrustScoreRerank(r, ["default"], p)).results,
793
+ results: [result("contradicted", 100), result("kept", 0.1)],
794
+ preloaded: new Map([
795
+ ["/facts/contradicted.md", memAt("/facts/contradicted.md", { faithfulness: { verdict: "contradicted" } })],
796
+ ["/facts/kept.md", mem("kept")],
797
+ ]),
798
+ applied: ["/facts/kept.md"],
799
+ },
800
+ {
801
+ name: "preference-drift damping survives MMR",
802
+ config: { recallMmrEnabled: true, recallMmrLambda: 1, driftDetection: { ...DRIFT_DETECTION_DEFAULTS, recallDamping: true, stalePenalty: 0.25 } },
803
+ stage: (c, r, p) => c.applyPreferenceDriftStage(r, ["default"], p),
804
+ results: [result("stale", 100), result("fresh", 0.1)],
805
+ preloaded: new Map([
806
+ ["/facts/stale.md", memAt("/facts/stale.md", { category: "preference", driftState: "stale" })],
807
+ ["/facts/fresh.md", memAt("/facts/fresh.md", { category: "fact" })],
808
+ ]),
809
+ applied: ["/facts/fresh.md"],
810
+ },
811
+ ];
812
+
813
+ for (const scenario of SCENARIOS) {
814
+ test(`#3226: ${scenario.name}`, async () => {
815
+ const coord = coordinatorFor(await baseConfig(scenario.config));
816
+ const before = scenario.results.map((r) => ({ ...r }));
817
+ const staged = await scenario.stage(coord, scenario.results, scenario.preloaded);
818
+ const applied = coord.diversifyAndLimitRecallResults("memories", staged, 1);
819
+ assert.deepEqual(applied.map((r) => r.path), scenario.applied, "MMR must not undo the stage");
820
+ assert.deepEqual(scenario.results, before, "the stage must not mutate its input");
821
+ });
822
+ }
823
+
824
+ test("#3226: MMR off leaves the branch order verbatim", async () => {
825
+ const coord = coordinatorFor(await baseConfig({ recallMmrEnabled: false }));
826
+ // Two near-duplicates plus one orthogonal candidate: with MMR on, lambda 0.3
827
+ // promotes the orthogonal candidate into slot 2 — this pins that MMR was off.
828
+ const branch: QmdSearchResult[] = [
829
+ { docid: "d1", path: "p/d1", snippet: "rocket thrust vectoring", score: 0.99 },
830
+ { docid: "d2", path: "p/d2", snippet: "rocket thrust vectoring", score: 0.98 },
831
+ { docid: "o1", path: "p/o1", snippet: "coffee brewing at high altitude", score: 0.4 },
832
+ ];
833
+ const applied = coord.diversifyAndLimitRecallResults("memories", branch, 2);
834
+ assert.deepEqual(applied.map((r) => r.docid), ["d1", "d2"], "MMR off: the branch order is the applied order");
835
+ });
836
+
837
+ test("#3226: without a rerank stage MMR keeps using the raw score", async () => {
838
+ const config = await baseConfig({ recallMemoryWorthFilterEnabled: false, trustScoreEnabled: false });
839
+ const coord = coordinatorFor(config);
840
+ const results = [result("a", 0.9), result("b", 0.8)];
841
+ const outcome = await coord.applyTrustScoreToBranch(results, ["default"], resolveCapabilities(config), "test");
842
+ assert.deepEqual(outcome.results, results, "no stage ran: the results come back untouched");
843
+ for (const r of outcome.results) assert.equal(r.effectiveScore, undefined, "no relevance is attached");
844
+ });
845
+
846
+ test("#3226: a no-op stage leaves the results byte-identical", async () => {
847
+ const coord = coordinatorFor(await baseConfig());
848
+ const results = [result("a", 0.9), result("b", 0.8)];
849
+ const staged = await coord.applyMemoryWorthRerank(results, ["default"], facts([["a"], ["b"]]));
850
+ assert.deepEqual(staged, results, "a neutral stage returns the input unchanged");
851
+ for (const r of staged) assert.equal(r.effectiveScore, undefined, "a no-op stage attaches no relevance");
852
+ });
853
+
854
+ test("#3226: an annotation-only drift stage keeps the upstream effective relevance", async () => {
855
+ const config = await baseConfig({ driftDetection: { ...DRIFT_DETECTION_DEFAULTS, annotateAfterDays: 30 } });
856
+ const coord = coordinatorFor(config);
857
+ const preloaded = new Map<string, MemoryFile>([
858
+ ["/facts/bad.md", memAt("/facts/bad.md", { mw_success: 0, mw_fail: 10 })],
859
+ ["/facts/good.md", memAt("/facts/good.md", { mw_success: 10, mw_fail: 0, category: "preference", lastCorroborated: "2020-01-01" })],
860
+ ]);
861
+ const staged = await coord.applyMemoryWorthRerank(WORTH_RESULTS, ["default"], preloaded);
862
+ const annotated = await coord.applyPreferenceDriftStage(staged, ["default"], preloaded);
863
+ assert.deepEqual(annotated.map((r) => r.path), ["/facts/good.md", "/facts/bad.md"], "the order is unchanged");
864
+ assert.ok(annotated[0]?.driftNote, "the age note is still attached");
865
+ assert.equal(typeof staged[0]?.effectiveScore, "number", "the stage attached a relevance");
866
+ assert.equal(annotated[0]?.effectiveScore, staged[0]?.effectiveScore, "the upstream relevance survives");
867
+ });
868
+
869
+ for (const boostCase of [
870
+ {
871
+ name: "a strongly demoted trace does not leapfrog a high-effective fact",
872
+ frontmatter: { mw_success: 0, mw_fail: 10 },
873
+ applied: "/facts/fact.md",
874
+ },
875
+ {
876
+ name: "a near-equal effective relevance lets the boost promote the trace",
877
+ frontmatter: { mw_success: 1000, mw_fail: 0 },
878
+ applied: "/reasoning-traces/trace.md",
879
+ },
880
+ ]) {
881
+ test(`#3226: the reasoning-trace boost — ${boostCase.name}`, async () => {
882
+ // The boost capability is off here: the boost is applied explicitly so the
883
+ // MMR pass sees exactly the boosted array.
884
+ const coord = coordinatorFor(await baseConfig({ recallMmrEnabled: true, recallMmrLambda: 1 }));
885
+ const staged = await coord.applyMemoryWorthRerank(
886
+ [
887
+ { ...result("fact", 0.9), path: "/facts/fact.md" },
888
+ { ...result("trace", 0.8), path: "/reasoning-traces/trace.md" },
889
+ ],
890
+ ["default"],
891
+ new Map([
892
+ ["/facts/fact.md", memAt("/facts/fact.md", {})],
893
+ ["/reasoning-traces/trace.md", memAt("/reasoning-traces/trace.md", boostCase.frontmatter)],
894
+ ]),
895
+ );
896
+ const trace = staged.find((r) => r.path === "/reasoning-traces/trace.md");
897
+ assert.ok(trace, "the trace is staged");
898
+ const boosted = applyReasoningTraceBoost(staged, { enabled: true, query: "how do I fix the build?" });
899
+ const boostedTrace = boosted.find((r) => r.path === "/reasoning-traces/trace.md");
900
+ assert.ok(boostedTrace, "the trace survives the boost");
901
+ assert.equal(boostedTrace.score, trace.score + 0.15, "the raw score keeps its boost");
902
+ assert.equal(
903
+ boostedTrace.effectiveScore,
904
+ trace.effectiveScore! + 0.15,
905
+ "the exact adjustment is attached to the effective relevance",
906
+ );
907
+ const applied = coord.diversifyAndLimitRecallResults("memories", boosted, 1);
908
+ assert.deepEqual(
909
+ applied.map((r) => r.path),
910
+ [boostCase.applied],
911
+ "the final order follows the effective relevance",
912
+ );
913
+ });
914
+ }
915
+
916
+ for (const poolSize of [10, 40]) {
917
+ test(`#3226: reasoning boost keeps its scale in a ${poolSize}-candidate adjusted pool`, async () => {
918
+ const coord = coordinatorFor(await baseConfig({ recallMmrEnabled: true, recallMmrLambda: 1 }));
919
+ const candidates = [
920
+ result("fact", 0.9),
921
+ { ...result("trace", 0.8), path: "/reasoning-traces/trace.md" },
922
+ ...Array.from({ length: poolSize - 3 }, (_, index) => result(`plain-${index}`, 0.7)),
923
+ result("bad", 0.1),
924
+ ];
925
+ const frontmatter = new Map(candidates.map((candidate) => [
926
+ candidate.path,
927
+ memAt(candidate.path, candidate.path === "/facts/bad.md" ? { mw_success: 0, mw_fail: 10 } : {}),
928
+ ]));
929
+ const staged = await coord.applyMemoryWorthRerank(candidates, ["default"], frontmatter);
930
+ const boosted = applyReasoningTraceBoost(staged, { enabled: true, query: "how do I fix this?" });
931
+ assert.equal(
932
+ coord.diversifyAndLimitRecallResults("memories", boosted, 1)[0]?.path,
933
+ "/reasoning-traces/trace.md",
934
+ "a neutral adjacent trace must retain a meaningful boost when another candidate is adjusted",
935
+ );
936
+ });
937
+ }
938
+
939
+ test("#3226: quarantined prefixes do not compress survivor relevance", async () => {
940
+ const coord = coordinatorFor(await baseConfig(TRUST_CONFIG));
941
+ const survivors = [result("trusted", 0.9), result("untrusted", 0.8)];
942
+ const quarantined = Array.from({ length: 20 }, (_, index) => result(`quarantined-${index}`, 1));
943
+ const frontmatter = new Map([
944
+ ...facts([["trusted", 10, 0], ["untrusted", 0, 10]]),
945
+ ...quarantined.map((candidate) => [
946
+ candidate.path,
947
+ memAt(candidate.path, { faithfulness: { verdict: "contradicted" } }),
948
+ ] as const),
949
+ ]);
950
+ const baseline = (await coord.applyTrustScoreRerank(survivors, ["default"], frontmatter)).results;
951
+ const prefixed = (await coord.applyTrustScoreRerank([...quarantined, ...survivors], ["default"], frontmatter)).results;
952
+ assert.deepEqual(
953
+ prefixed.map((candidate) => [candidate.path, candidate.effectiveScore]),
954
+ baseline.map((candidate) => [candidate.path, candidate.effectiveScore]),
955
+ "excluded candidates must not change the surviving pool's relevance scale",
956
+ );
957
+ });
958
+
959
+ test("#3226: quarantine placement does not change survivor relevance", async () => {
960
+ const coord = coordinatorFor(await baseConfig(TRUST_CONFIG));
961
+ const survivors = [result("trusted", 0.9), result("untrusted", 0.8), result("plain", 0.7)];
962
+ const excluded = Array.from({ length: 20 }, (_, index) => result(`excluded-${index}`, 1));
963
+ const frontmatter = new Map([
964
+ ...facts([["trusted", 10, 0], ["untrusted", 0, 10], ["plain"]]),
965
+ ...excluded.map((candidate) => [
966
+ candidate.path, memAt(candidate.path, { faithfulness: { verdict: "contradicted" } }),
967
+ ] as const),
968
+ ]);
969
+ const baseline = (await coord.applyTrustScoreRerank(survivors, ["default"], frontmatter)).results;
970
+ for (const split of [0, 1, 2, 3]) {
971
+ const input = [...survivors.slice(0, split), ...excluded, ...survivors.slice(split)];
972
+ const admitted = (await coord.applyTrustScoreRerank(input, ["default"], frontmatter)).results;
973
+ assert.deepEqual(
974
+ admitted.map((candidate) => [candidate.path, candidate.effectiveScore]),
975
+ baseline.map((candidate) => [candidate.path, candidate.effectiveScore]),
976
+ `excluded rows at position ${split} must not leave rank holes`,
977
+ );
978
+ }
979
+ });
980
+
981
+ test("#3226: active drift damping composes upstream effective relevance", async () => {
982
+ const coord = coordinatorFor(await baseConfig({
983
+ driftDetection: { ...DRIFT_DETECTION_DEFAULTS, recallDamping: true, stalePenalty: 0.25 },
984
+ }));
985
+ const candidates = [
986
+ { ...result("top", 0.1), effectiveScore: 0.95 },
987
+ { ...result("stale", 100), effectiveScore: 0.9 },
988
+ { ...result("tail", 0.8), effectiveScore: 0.1 },
989
+ ];
990
+ const frontmatter = new Map(candidates.map((candidate) => [
991
+ candidate.path,
992
+ memAt(candidate.path, candidate.path === "/facts/stale.md" ? { category: "preference", driftState: "stale" } : {}),
993
+ ]));
994
+ const damped = await coord.applyPreferenceDriftStage(candidates, ["default"], frontmatter);
995
+ assert.deepEqual(damped.map((candidate) => candidate.effectiveScore), [0.95, 0.9 * 0.25, 0.1]);
996
+ assert.deepEqual(candidates.map((candidate) => candidate.effectiveScore), [0.95, 0.9, 0.1], "inputs remain unmodified");
997
+ });
package/src/types.ts CHANGED
@@ -3460,6 +3460,11 @@ export interface QmdSearchResult extends OriginMetadata, RecallDriftAnnotation,
3460
3460
  path: string;
3461
3461
  snippet: string;
3462
3462
  score: number;
3463
+ /**
3464
+ * Pool-normalized rank × multiplier from the last adjusted rerank stage.
3465
+ * MMR prefers it over `score`; additive boosts compose on this scale.
3466
+ */
3467
+ effectiveScore?: number;
3463
3468
  line?: number;
3464
3469
  explain?: QmdSearchExplain;
3465
3470
  transport?: "daemon" | "subprocess" | "hybrid" | "scoped_prefilter";