@remnic/core 9.3.654 → 9.3.656
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/dist/access-cli.js +29 -29
- package/dist/access-http.d.ts +4 -4
- package/dist/access-http.js +17 -17
- package/dist/access-mcp.d.ts +4 -4
- package/dist/access-mcp.js +16 -16
- package/dist/access-schema.d.ts +10 -10
- package/dist/{access-service-C8A5hoXJ.d.ts → access-service-D_nbpexW.d.ts} +33 -2
- package/dist/access-service.d.ts +4 -4
- package/dist/access-service.js +15 -15
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +3 -3
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +4 -4
- package/dist/{chunk-JMQSYGXS.js → chunk-2BD7DG37.js} +2 -2
- package/dist/{chunk-FVRBLJP6.js → chunk-2MXEVL75.js} +2 -2
- package/dist/{chunk-LJCEWTG3.js → chunk-4UL7VPTD.js} +277 -58
- package/dist/chunk-4UL7VPTD.js.map +1 -0
- package/dist/{chunk-JYN7QNTA.js → chunk-54XF2FY7.js} +17 -17
- package/dist/{chunk-7WEB3FLJ.js → chunk-5PLUC5OB.js} +2 -2
- package/dist/{chunk-JX2RINDR.js → chunk-6G5JEN55.js} +2 -2
- package/dist/{chunk-ZCORQM74.js → chunk-AGJKWOKV.js} +2 -2
- package/dist/{chunk-NE2JBMLN.js → chunk-AZBV4RRY.js} +1 -1
- package/dist/chunk-AZBV4RRY.js.map +1 -0
- package/dist/{chunk-YLZLPVKK.js → chunk-CTAV55JM.js} +344 -1
- package/dist/chunk-CTAV55JM.js.map +1 -0
- package/dist/{chunk-2DSTAWNZ.js → chunk-DIBWFCLA.js} +3 -3
- package/dist/{chunk-NAZWHTYV.js → chunk-DR67OK4E.js} +5 -5
- package/dist/{chunk-XBIACVCO.js → chunk-EC2AYKRX.js} +2 -2
- package/dist/{chunk-JVRPJ7D4.js → chunk-EKQMQQ3U.js} +48 -12
- package/dist/chunk-EKQMQQ3U.js.map +1 -0
- package/dist/{chunk-RGPUQ66K.js → chunk-GCYFUTUC.js} +2 -2
- package/dist/{chunk-JBHXMCYN.js → chunk-GRYAECRV.js} +2 -2
- package/dist/{chunk-BJA6DQOC.js → chunk-GSHW5VVD.js} +5 -5
- package/dist/chunk-GYSYLGNE.js +650 -0
- package/dist/chunk-GYSYLGNE.js.map +1 -0
- package/dist/{chunk-NCGWXCSW.js → chunk-IOZ5WBWD.js} +2 -2
- package/dist/{chunk-QKK64Z6M.js → chunk-JSVFEHLL.js} +7 -5
- package/dist/chunk-JSVFEHLL.js.map +1 -0
- package/dist/{chunk-7LWRCOP7.js → chunk-LZTFCAKE.js} +2 -2
- package/dist/{chunk-2DGQLOOM.js → chunk-M3VYPE2H.js} +1 -1
- package/dist/{chunk-2DGQLOOM.js.map → chunk-M3VYPE2H.js.map} +1 -1
- package/dist/{chunk-6CVI6BP6.js → chunk-NXCK7DO7.js} +2 -2
- package/dist/{chunk-Z5MQI7K2.js → chunk-PEPHBH2W.js} +2 -2
- package/dist/{chunk-PYWNNF2I.js → chunk-QRSKPI62.js} +99 -66
- package/dist/chunk-QRSKPI62.js.map +1 -0
- package/dist/{chunk-XWQ6ERUG.js → chunk-QZRKNA5F.js} +2 -2
- package/dist/{chunk-PS3SYNHP.js → chunk-R5DB26G6.js} +2 -2
- package/dist/{chunk-OL2364SB.js → chunk-RDW5G6DO.js} +1502 -335
- package/dist/chunk-RDW5G6DO.js.map +1 -0
- package/dist/{chunk-YM3LR4LS.js → chunk-SSSXWIBP.js} +5 -5
- package/dist/{chunk-T2C6QJG2.js → chunk-SWDHVH2P.js} +2 -2
- package/dist/{chunk-DBM2BD22.js → chunk-SXYCVRLK.js} +3 -3
- package/dist/{chunk-K6X553JB.js → chunk-TFFZUFEP.js} +7 -5
- package/dist/chunk-TFFZUFEP.js.map +1 -0
- package/dist/{chunk-ENV6RDTD.js → chunk-TIJYQXDI.js} +2 -2
- package/dist/{chunk-BP2EV6W5.js → chunk-VAEAGTEQ.js} +4 -4
- package/dist/{chunk-3RACUBII.js → chunk-WIKMCJUR.js} +2 -2
- package/dist/{chunk-QW6JZO5P.js → chunk-WWMHAMAY.js} +2 -2
- package/dist/{chunk-GPW2E4LN.js → chunk-YEZHZCUO.js} +4 -4
- package/dist/{chunk-5FOCXX5E.js → chunk-YVVQUAOO.js} +3 -3
- package/dist/{chunk-5FOCXX5E.js.map → chunk-YVVQUAOO.js.map} +1 -1
- package/dist/{chunk-3XGWCZ63.js → chunk-YXLT4EMM.js} +2 -2
- package/dist/{chunk-Y2RIIF6H.js → chunk-Z6UDTNY6.js} +2 -2
- package/dist/{cli-uQgvDFNE.d.ts → cli-aYxSuPvP.d.ts} +3 -3
- package/dist/cli.d.ts +5 -5
- package/dist/cli.js +29 -29
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +3 -3
- package/dist/explicit-cue-recall.js +2 -2
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/focused-list-recall.js +2 -2
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +121 -121
- package/dist/index.js +39 -39
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lcm-fallback-read.js +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +4 -4
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +1 -1
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +15 -4
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.d.ts +1 -1
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +14 -14
- package/dist/{orchestrator-B4Y4sWQH.d.ts → orchestrator-D1wcmPNj.d.ts} +17 -14
- package/dist/orchestrator.d.ts +3 -3
- package/dist/orchestrator.js +25 -25
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +5 -1
- package/dist/qmd.js +2 -2
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/response-guidance-recall.js +2 -2
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +22 -22
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +6 -6
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +6 -6
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +2 -2
- package/dist/search/port.d.ts +17 -1
- package/dist/search/port.js +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BKd0Pype.d.ts → semantic-consolidation-MWOdNtSE.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +3 -2
- package/dist/semantic-rule-verifier.js +5 -3
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/targeted-fact-recall.js +2 -2
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/{types-BgChEr0M.d.ts → types-CgcCpUrf.d.ts} +51 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.d.ts +2 -1
- package/dist/verified-recall.js +5 -3
- package/package.json +1 -1
- package/src/access-service-observe-lcm-parity.test.ts +86 -1
- package/src/access-service-observe-scope.test.ts +283 -1
- package/src/access-service-raw-excerpt-read-gate.test.ts +53 -0
- package/src/access-service.ts +391 -93
- package/src/coding/coding-namespace.ts +0 -3
- package/src/config.test.ts +69 -0
- package/src/config.ts +417 -0
- package/src/lcm-fallback-read.ts +2 -6
- package/src/maintenance/namespace-planner.test.ts +1120 -0
- package/src/maintenance/namespace-planner.ts +893 -0
- package/src/namespaces/scope-profiles.test.ts +1074 -0
- package/src/namespaces/scope-profiles.ts +456 -0
- package/src/namespaces/search.test.ts +130 -2
- package/src/namespaces/search.ts +71 -10
- package/src/orchestrator-flush.test.ts +606 -44
- package/src/orchestrator-source-attribution.test.ts +73 -0
- package/src/orchestrator.ts +932 -229
- package/src/qmd-client.test.ts +59 -0
- package/src/qmd.ts +124 -84
- package/src/search/port.ts +16 -0
- package/src/semantic-rule-verifier.ts +13 -6
- package/src/types.ts +64 -0
- package/src/verified-recall.ts +10 -6
- package/dist/chunk-JVRPJ7D4.js.map +0 -1
- package/dist/chunk-K6X553JB.js.map +0 -1
- package/dist/chunk-LJCEWTG3.js.map +0 -1
- package/dist/chunk-MMJANTJX.js +0 -339
- package/dist/chunk-MMJANTJX.js.map +0 -1
- package/dist/chunk-NE2JBMLN.js.map +0 -1
- package/dist/chunk-OL2364SB.js.map +0 -1
- package/dist/chunk-PYWNNF2I.js.map +0 -1
- package/dist/chunk-QKK64Z6M.js.map +0 -1
- package/dist/chunk-YLZLPVKK.js.map +0 -1
- /package/dist/{chunk-JMQSYGXS.js.map → chunk-2BD7DG37.js.map} +0 -0
- /package/dist/{chunk-FVRBLJP6.js.map → chunk-2MXEVL75.js.map} +0 -0
- /package/dist/{chunk-JYN7QNTA.js.map → chunk-54XF2FY7.js.map} +0 -0
- /package/dist/{chunk-7WEB3FLJ.js.map → chunk-5PLUC5OB.js.map} +0 -0
- /package/dist/{chunk-JX2RINDR.js.map → chunk-6G5JEN55.js.map} +0 -0
- /package/dist/{chunk-ZCORQM74.js.map → chunk-AGJKWOKV.js.map} +0 -0
- /package/dist/{chunk-2DSTAWNZ.js.map → chunk-DIBWFCLA.js.map} +0 -0
- /package/dist/{chunk-NAZWHTYV.js.map → chunk-DR67OK4E.js.map} +0 -0
- /package/dist/{chunk-XBIACVCO.js.map → chunk-EC2AYKRX.js.map} +0 -0
- /package/dist/{chunk-RGPUQ66K.js.map → chunk-GCYFUTUC.js.map} +0 -0
- /package/dist/{chunk-JBHXMCYN.js.map → chunk-GRYAECRV.js.map} +0 -0
- /package/dist/{chunk-BJA6DQOC.js.map → chunk-GSHW5VVD.js.map} +0 -0
- /package/dist/{chunk-NCGWXCSW.js.map → chunk-IOZ5WBWD.js.map} +0 -0
- /package/dist/{chunk-7LWRCOP7.js.map → chunk-LZTFCAKE.js.map} +0 -0
- /package/dist/{chunk-6CVI6BP6.js.map → chunk-NXCK7DO7.js.map} +0 -0
- /package/dist/{chunk-Z5MQI7K2.js.map → chunk-PEPHBH2W.js.map} +0 -0
- /package/dist/{chunk-XWQ6ERUG.js.map → chunk-QZRKNA5F.js.map} +0 -0
- /package/dist/{chunk-PS3SYNHP.js.map → chunk-R5DB26G6.js.map} +0 -0
- /package/dist/{chunk-YM3LR4LS.js.map → chunk-SSSXWIBP.js.map} +0 -0
- /package/dist/{chunk-T2C6QJG2.js.map → chunk-SWDHVH2P.js.map} +0 -0
- /package/dist/{chunk-DBM2BD22.js.map → chunk-SXYCVRLK.js.map} +0 -0
- /package/dist/{chunk-ENV6RDTD.js.map → chunk-TIJYQXDI.js.map} +0 -0
- /package/dist/{chunk-BP2EV6W5.js.map → chunk-VAEAGTEQ.js.map} +0 -0
- /package/dist/{chunk-3RACUBII.js.map → chunk-WIKMCJUR.js.map} +0 -0
- /package/dist/{chunk-QW6JZO5P.js.map → chunk-WWMHAMAY.js.map} +0 -0
- /package/dist/{chunk-GPW2E4LN.js.map → chunk-YEZHZCUO.js.map} +0 -0
- /package/dist/{chunk-3XGWCZ63.js.map → chunk-YXLT4EMM.js.map} +0 -0
- /package/dist/{chunk-Y2RIIF6H.js.map → chunk-Z6UDTNY6.js.map} +0 -0
package/src/qmd-client.test.ts
CHANGED
|
@@ -70,6 +70,65 @@ function captureSubprocessArgs(client: QmdClient): string[][] {
|
|
|
70
70
|
return calls;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
test("updateStrict respects QMD update min-interval throttles", async () => {
|
|
74
|
+
const client = new QmdClient("memories", 3, { updateMinIntervalMs: 60_000 });
|
|
75
|
+
client.resetUpdateThrottles();
|
|
76
|
+
const calls = captureSubprocessArgs(client);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
await client.updateStrict();
|
|
80
|
+
await assert.rejects(
|
|
81
|
+
() => client.updateStrict(),
|
|
82
|
+
/QMD update skipped by min-interval gate|QMD update skipped by global min-interval gate/,
|
|
83
|
+
);
|
|
84
|
+
} finally {
|
|
85
|
+
client.resetUpdateThrottles();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
assert.equal(calls.length, 1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("embedCollectionStrict rejects QMD embed subprocess failures", async () => {
|
|
92
|
+
const client = new QmdClient("memories", 3, { updateMinIntervalMs: 60_000 });
|
|
93
|
+
client.resetUpdateThrottles();
|
|
94
|
+
const internals = client as unknown as SubprocessInternals;
|
|
95
|
+
const calls: string[][] = [];
|
|
96
|
+
internals.available = true;
|
|
97
|
+
internals.runQmdCommand = async (args: string[]) => {
|
|
98
|
+
calls.push(args);
|
|
99
|
+
throw new Error("embed subprocess failed");
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
await assert.rejects(
|
|
104
|
+
() => client.embedCollectionStrict("memories--project"),
|
|
105
|
+
/embed subprocess failed/,
|
|
106
|
+
);
|
|
107
|
+
} finally {
|
|
108
|
+
client.resetUpdateThrottles();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
assert.deepEqual(calls, [["embed", "-c", "memories--project"]]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("embedCollectionStrict respects QMD embed min-interval throttles", async () => {
|
|
115
|
+
const client = new QmdClient("memories", 3, { updateMinIntervalMs: 60_000 });
|
|
116
|
+
client.resetUpdateThrottles();
|
|
117
|
+
const calls = captureSubprocessArgs(client);
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await client.embedCollectionStrict("memories--project");
|
|
121
|
+
await assert.rejects(
|
|
122
|
+
() => client.embedCollectionStrict("memories--project"),
|
|
123
|
+
/QMD embed skipped by per-collection min-interval gate/,
|
|
124
|
+
);
|
|
125
|
+
} finally {
|
|
126
|
+
client.resetUpdateThrottles();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
assert.equal(calls.length, 1);
|
|
130
|
+
});
|
|
131
|
+
|
|
73
132
|
test("ensureCollection treats cancelled auto-create as unknown", async () => {
|
|
74
133
|
const client = new QmdClient("memories", 3, {});
|
|
75
134
|
const internals = client as unknown as SubprocessInternals & {
|
package/src/qmd.ts
CHANGED
|
@@ -1232,9 +1232,14 @@ export class QmdClient implements SearchBackend {
|
|
|
1232
1232
|
resetUpdateThrottles(): void {
|
|
1233
1233
|
this._lastUpdateFailAtMs = null;
|
|
1234
1234
|
this.lastUpdateRunAtMs = null;
|
|
1235
|
+
this.lastEmbedFailAtMs = null;
|
|
1235
1236
|
const gs = getGlobalQmdState();
|
|
1236
1237
|
gs.lastGlobalUpdateRunAtMs = null;
|
|
1237
1238
|
gs.lastGlobalUpdateFailAtMs = null;
|
|
1239
|
+
gs.lastGlobalEmbedRunAtMs = null;
|
|
1240
|
+
gs.lastGlobalEmbedFailAtMs = null;
|
|
1241
|
+
gs.lastEmbedByCollectionMs = {};
|
|
1242
|
+
gs.lastEmbedFailByCollectionMs = {};
|
|
1238
1243
|
}
|
|
1239
1244
|
|
|
1240
1245
|
private readonly updateTimeoutMs: number;
|
|
@@ -2493,6 +2498,14 @@ export class QmdClient implements SearchBackend {
|
|
|
2493
2498
|
);
|
|
2494
2499
|
}
|
|
2495
2500
|
|
|
2501
|
+
async updateStrict(execution?: SearchExecutionOptions): Promise<void> {
|
|
2502
|
+
await this.runUpdateForCollection(
|
|
2503
|
+
this.collection,
|
|
2504
|
+
{ perCollectionThrottle: false, strict: true },
|
|
2505
|
+
execution?.signal,
|
|
2506
|
+
);
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2496
2509
|
async updateCollection(
|
|
2497
2510
|
collection: string,
|
|
2498
2511
|
execution?: SearchExecutionOptions,
|
|
@@ -2510,7 +2523,7 @@ export class QmdClient implements SearchBackend {
|
|
|
2510
2523
|
): Promise<void> {
|
|
2511
2524
|
await this.runUpdateForCollection(
|
|
2512
2525
|
collection,
|
|
2513
|
-
{ perCollectionThrottle: true, strict: true },
|
|
2526
|
+
{ perCollectionThrottle: true, strict: true, force: true },
|
|
2514
2527
|
execution?.signal,
|
|
2515
2528
|
);
|
|
2516
2529
|
}
|
|
@@ -2521,7 +2534,7 @@ export class QmdClient implements SearchBackend {
|
|
|
2521
2534
|
|
|
2522
2535
|
private async runUpdateForCollection(
|
|
2523
2536
|
collection: string,
|
|
2524
|
-
options: { perCollectionThrottle: boolean; strict?: boolean },
|
|
2537
|
+
options: { perCollectionThrottle: boolean; strict?: boolean; force?: boolean },
|
|
2525
2538
|
signal?: AbortSignal,
|
|
2526
2539
|
): Promise<void> {
|
|
2527
2540
|
if (this.available === false) {
|
|
@@ -2539,12 +2552,13 @@ export class QmdClient implements SearchBackend {
|
|
|
2539
2552
|
}
|
|
2540
2553
|
const globalState = getGlobalQmdState();
|
|
2541
2554
|
const now = Date.now();
|
|
2542
|
-
if (!options.
|
|
2555
|
+
if (!options.force && options.perCollectionThrottle) {
|
|
2543
2556
|
if (
|
|
2544
2557
|
globalState.lastGlobalUpdateFailAtMs &&
|
|
2545
2558
|
now - globalState.lastGlobalUpdateFailAtMs < QMD_UPDATE_BACKOFF_MS
|
|
2546
2559
|
) {
|
|
2547
2560
|
log.debug("QMD update: suppressed by global failure backoff");
|
|
2561
|
+
if (options.strict) throw new Error("QMD update skipped by global failure backoff");
|
|
2548
2562
|
return;
|
|
2549
2563
|
}
|
|
2550
2564
|
const lastCollectionRun = globalState.lastUpdateByCollectionMs[name];
|
|
@@ -2553,6 +2567,7 @@ export class QmdClient implements SearchBackend {
|
|
|
2553
2567
|
now - lastCollectionRun < this.updateMinIntervalMs
|
|
2554
2568
|
) {
|
|
2555
2569
|
log.debug(`QMD update: suppressed by per-collection min-interval gate (${name})`);
|
|
2570
|
+
if (options.strict) throw new Error("QMD update skipped by per-collection min-interval gate");
|
|
2556
2571
|
return;
|
|
2557
2572
|
}
|
|
2558
2573
|
const lastCollectionFail = globalState.lastUpdateFailByCollectionMs[name];
|
|
@@ -2561,14 +2576,16 @@ export class QmdClient implements SearchBackend {
|
|
|
2561
2576
|
now - lastCollectionFail < QMD_UPDATE_BACKOFF_MS
|
|
2562
2577
|
) {
|
|
2563
2578
|
log.debug(`QMD update: suppressed by per-collection failure backoff (${name})`);
|
|
2579
|
+
if (options.strict) throw new Error("QMD update skipped by per-collection failure backoff");
|
|
2564
2580
|
return;
|
|
2565
2581
|
}
|
|
2566
|
-
} else if (!options.
|
|
2582
|
+
} else if (!options.force) {
|
|
2567
2583
|
if (
|
|
2568
2584
|
this.lastUpdateRunAtMs &&
|
|
2569
2585
|
now - this.lastUpdateRunAtMs < this.updateMinIntervalMs
|
|
2570
2586
|
) {
|
|
2571
2587
|
log.debug("QMD update: suppressed due to min-interval gate");
|
|
2588
|
+
if (options.strict) throw new Error("QMD update skipped by min-interval gate");
|
|
2572
2589
|
return;
|
|
2573
2590
|
}
|
|
2574
2591
|
if (
|
|
@@ -2576,6 +2593,7 @@ export class QmdClient implements SearchBackend {
|
|
|
2576
2593
|
now - this._lastUpdateFailAtMs < QMD_UPDATE_BACKOFF_MS
|
|
2577
2594
|
) {
|
|
2578
2595
|
log.debug("QMD update: suppressed due to recent failures (backoff)");
|
|
2596
|
+
if (options.strict) throw new Error("QMD update skipped by recent failure backoff");
|
|
2579
2597
|
return;
|
|
2580
2598
|
}
|
|
2581
2599
|
if (
|
|
@@ -2583,6 +2601,7 @@ export class QmdClient implements SearchBackend {
|
|
|
2583
2601
|
now - globalState.lastGlobalUpdateRunAtMs < this.updateMinIntervalMs
|
|
2584
2602
|
) {
|
|
2585
2603
|
log.debug("QMD update: suppressed by global min-interval gate");
|
|
2604
|
+
if (options.strict) throw new Error("QMD update skipped by global min-interval gate");
|
|
2586
2605
|
return;
|
|
2587
2606
|
}
|
|
2588
2607
|
if (
|
|
@@ -2590,6 +2609,7 @@ export class QmdClient implements SearchBackend {
|
|
|
2590
2609
|
now - globalState.lastGlobalUpdateFailAtMs < QMD_UPDATE_BACKOFF_MS
|
|
2591
2610
|
) {
|
|
2592
2611
|
log.debug("QMD update: suppressed by global failure backoff");
|
|
2612
|
+
if (options.strict) throw new Error("QMD update skipped by global failure backoff");
|
|
2593
2613
|
return;
|
|
2594
2614
|
}
|
|
2595
2615
|
}
|
|
@@ -2633,117 +2653,137 @@ export class QmdClient implements SearchBackend {
|
|
|
2633
2653
|
}
|
|
2634
2654
|
|
|
2635
2655
|
async embed(): Promise<void> {
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2656
|
+
await this.runEmbedForCollection(this.collection, { perCollectionThrottle: false });
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
async embedStrict(): Promise<void> {
|
|
2660
|
+
await this.runEmbedForCollection(this.collection, { perCollectionThrottle: false, strict: true });
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
async embedCollection(collection: string): Promise<void> {
|
|
2664
|
+
await this.runEmbedForCollection(collection, { perCollectionThrottle: true });
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2667
|
+
async embedCollectionStrict(collection: string): Promise<void> {
|
|
2668
|
+
await this.runEmbedForCollection(collection, { perCollectionThrottle: true, strict: true });
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
private async runEmbedForCollection(
|
|
2672
|
+
collection: string,
|
|
2673
|
+
options: { perCollectionThrottle: boolean; strict?: boolean },
|
|
2674
|
+
): Promise<void> {
|
|
2675
|
+
if (this.available === false) {
|
|
2676
|
+
if (options.strict) throw new Error("QMD unavailable");
|
|
2643
2677
|
return;
|
|
2644
2678
|
}
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
) {
|
|
2649
|
-
log.debug("QMD embed: suppressed by global min-interval gate");
|
|
2679
|
+
const name = collection.trim();
|
|
2680
|
+
if (!name) {
|
|
2681
|
+
if (options.strict) throw new Error("QMD collection name is required");
|
|
2650
2682
|
return;
|
|
2651
2683
|
}
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2684
|
+
const globalState = getGlobalQmdState();
|
|
2685
|
+
const now = Date.now();
|
|
2686
|
+
if (options.perCollectionThrottle) {
|
|
2687
|
+
if (
|
|
2688
|
+
globalState.lastGlobalEmbedFailAtMs &&
|
|
2689
|
+
now - globalState.lastGlobalEmbedFailAtMs < QMD_EMBED_BACKOFF_MS
|
|
2690
|
+
) {
|
|
2691
|
+
log.debug(`QMD embed: suppressed by global failure backoff (${name})`);
|
|
2692
|
+
if (options.strict) throw new Error("QMD embed skipped by global failure backoff");
|
|
2693
|
+
return;
|
|
2694
|
+
}
|
|
2695
|
+
const lastCollectionRun = globalState.lastEmbedByCollectionMs[name];
|
|
2696
|
+
if (
|
|
2697
|
+
Number.isFinite(lastCollectionRun) &&
|
|
2698
|
+
now - lastCollectionRun < this.updateMinIntervalMs
|
|
2699
|
+
) {
|
|
2700
|
+
log.debug(`QMD embed: suppressed by per-collection min-interval gate (${name})`);
|
|
2701
|
+
if (options.strict) throw new Error("QMD embed skipped by per-collection min-interval gate");
|
|
2702
|
+
return;
|
|
2703
|
+
}
|
|
2704
|
+
const lastCollectionFail = globalState.lastEmbedFailByCollectionMs[name];
|
|
2705
|
+
if (
|
|
2706
|
+
Number.isFinite(lastCollectionFail) &&
|
|
2707
|
+
now - lastCollectionFail < QMD_EMBED_BACKOFF_MS
|
|
2708
|
+
) {
|
|
2709
|
+
log.debug(`QMD embed: suppressed by per-collection failure backoff (${name})`);
|
|
2710
|
+
if (options.strict) throw new Error("QMD embed skipped by per-collection failure backoff");
|
|
2711
|
+
return;
|
|
2712
|
+
}
|
|
2713
|
+
} else {
|
|
2714
|
+
if (
|
|
2715
|
+
this.lastEmbedFailAtMs &&
|
|
2716
|
+
now - this.lastEmbedFailAtMs < QMD_EMBED_BACKOFF_MS
|
|
2717
|
+
) {
|
|
2718
|
+
log.debug("QMD embed: suppressed due to recent failures (backoff)");
|
|
2719
|
+
if (options.strict) throw new Error("QMD embed skipped by recent failure backoff");
|
|
2720
|
+
return;
|
|
2721
|
+
}
|
|
2722
|
+
if (
|
|
2723
|
+
globalState.lastGlobalEmbedRunAtMs &&
|
|
2724
|
+
now - globalState.lastGlobalEmbedRunAtMs < this.updateMinIntervalMs
|
|
2725
|
+
) {
|
|
2726
|
+
log.debug("QMD embed: suppressed by global min-interval gate");
|
|
2727
|
+
if (options.strict) throw new Error("QMD embed skipped by global min-interval gate");
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2730
|
+
if (
|
|
2731
|
+
globalState.lastGlobalEmbedFailAtMs &&
|
|
2732
|
+
now - globalState.lastGlobalEmbedFailAtMs < QMD_EMBED_BACKOFF_MS
|
|
2733
|
+
) {
|
|
2734
|
+
log.debug("QMD embed: suppressed by global failure backoff");
|
|
2735
|
+
if (options.strict) throw new Error("QMD embed skipped by global failure backoff");
|
|
2736
|
+
return;
|
|
2737
|
+
}
|
|
2658
2738
|
}
|
|
2659
2739
|
try {
|
|
2660
2740
|
const startedAtMs = Date.now();
|
|
2661
|
-
await this.runQmdCommand(this.buildEmbedArgs(
|
|
2741
|
+
await this.runQmdCommand(this.buildEmbedArgs(name), 300_000);
|
|
2662
2742
|
const durationMs = Date.now() - startedAtMs;
|
|
2663
2743
|
if (this.slowLog?.enabled && durationMs >= this.slowLog.thresholdMs) {
|
|
2664
2744
|
log.warn(`SLOW QMD embed: durationMs=${durationMs}`);
|
|
2665
2745
|
}
|
|
2666
|
-
globalState.lastGlobalEmbedRunAtMs = Date.now();
|
|
2667
|
-
log.debug("QMD embed completed");
|
|
2668
|
-
} catch (err) {
|
|
2669
|
-
if (isVectorDimensionMismatchError(err)) {
|
|
2670
|
-
try {
|
|
2671
|
-
log.warn("QMD embed hit a vector dimension mismatch; retrying with force re-embed");
|
|
2672
|
-
await this.runQmdCommand(this.buildEmbedArgs(this.collection, true), 300_000);
|
|
2673
|
-
globalState.lastGlobalEmbedRunAtMs = Date.now();
|
|
2674
|
-
this.lastEmbedFailAtMs = null;
|
|
2675
|
-
globalState.lastGlobalEmbedFailAtMs = null;
|
|
2676
|
-
log.warn("QMD embed recovered by forcing a full vector rebuild");
|
|
2677
|
-
return;
|
|
2678
|
-
} catch (retryErr) {
|
|
2679
|
-
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
2680
|
-
log.warn(`QMD force re-embed failed after dimension mismatch: ${retryMsg}`);
|
|
2681
|
-
}
|
|
2682
|
-
}
|
|
2683
|
-
const now = Date.now();
|
|
2684
|
-
this.lastEmbedFailAtMs = now;
|
|
2685
|
-
globalState.lastGlobalEmbedFailAtMs = now;
|
|
2686
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2687
|
-
log.warn(`QMD embed failed: ${msg}`);
|
|
2688
|
-
}
|
|
2689
|
-
}
|
|
2690
|
-
|
|
2691
|
-
async embedCollection(collection: string): Promise<void> {
|
|
2692
|
-
if (this.available === false) return;
|
|
2693
|
-
const name = collection.trim();
|
|
2694
|
-
if (!name) return;
|
|
2695
|
-
const globalState = getGlobalQmdState();
|
|
2696
|
-
const now = Date.now();
|
|
2697
|
-
if (
|
|
2698
|
-
globalState.lastGlobalEmbedFailAtMs &&
|
|
2699
|
-
now - globalState.lastGlobalEmbedFailAtMs < QMD_EMBED_BACKOFF_MS
|
|
2700
|
-
) {
|
|
2701
|
-
log.debug(`QMD embed: suppressed by global failure backoff (${name})`);
|
|
2702
|
-
return;
|
|
2703
|
-
}
|
|
2704
|
-
const lastCollectionRun = globalState.lastEmbedByCollectionMs[name];
|
|
2705
|
-
if (
|
|
2706
|
-
Number.isFinite(lastCollectionRun) &&
|
|
2707
|
-
now - lastCollectionRun < this.updateMinIntervalMs
|
|
2708
|
-
) {
|
|
2709
|
-
log.debug(`QMD embed: suppressed by per-collection min-interval gate (${name})`);
|
|
2710
|
-
return;
|
|
2711
|
-
}
|
|
2712
|
-
const lastCollectionFail = globalState.lastEmbedFailByCollectionMs[name];
|
|
2713
|
-
if (
|
|
2714
|
-
Number.isFinite(lastCollectionFail) &&
|
|
2715
|
-
now - lastCollectionFail < QMD_EMBED_BACKOFF_MS
|
|
2716
|
-
) {
|
|
2717
|
-
log.debug(`QMD embed: suppressed by per-collection failure backoff (${name})`);
|
|
2718
|
-
return;
|
|
2719
|
-
}
|
|
2720
|
-
try {
|
|
2721
|
-
await this.runQmdCommand(this.buildEmbedArgs(name), 300_000);
|
|
2722
2746
|
const at = Date.now();
|
|
2723
|
-
|
|
2747
|
+
if (options.perCollectionThrottle) {
|
|
2748
|
+
globalState.lastEmbedByCollectionMs[name] = at;
|
|
2749
|
+
}
|
|
2724
2750
|
globalState.lastGlobalEmbedRunAtMs = at;
|
|
2751
|
+
log.debug(`QMD embed completed for collection=${name}`);
|
|
2725
2752
|
} catch (err) {
|
|
2753
|
+
let failure: unknown = err;
|
|
2726
2754
|
if (isVectorDimensionMismatchError(err)) {
|
|
2727
2755
|
try {
|
|
2728
2756
|
log.warn(`QMD embed for collection ${name} hit a vector dimension mismatch; retrying with force re-embed`);
|
|
2729
2757
|
await this.runQmdCommand(this.buildEmbedArgs(name, true), 300_000);
|
|
2730
2758
|
const recoveredAt = Date.now();
|
|
2731
|
-
|
|
2759
|
+
if (options.perCollectionThrottle) {
|
|
2760
|
+
globalState.lastEmbedByCollectionMs[name] = recoveredAt;
|
|
2761
|
+
delete globalState.lastEmbedFailByCollectionMs[name];
|
|
2762
|
+
} else {
|
|
2763
|
+
this.lastEmbedFailAtMs = null;
|
|
2764
|
+
}
|
|
2732
2765
|
globalState.lastGlobalEmbedRunAtMs = recoveredAt;
|
|
2733
|
-
delete globalState.lastEmbedFailByCollectionMs[name];
|
|
2734
2766
|
globalState.lastGlobalEmbedFailAtMs = null;
|
|
2735
2767
|
log.warn(`QMD embed for collection ${name} recovered by forcing a full vector rebuild`);
|
|
2736
2768
|
return;
|
|
2737
2769
|
} catch (retryErr) {
|
|
2770
|
+
failure = retryErr;
|
|
2738
2771
|
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
2739
2772
|
log.warn(`QMD force re-embed failed for collection ${name}: ${retryMsg}`);
|
|
2740
2773
|
}
|
|
2741
2774
|
}
|
|
2742
2775
|
const at = Date.now();
|
|
2743
|
-
|
|
2776
|
+
if (options.perCollectionThrottle) {
|
|
2777
|
+
globalState.lastEmbedFailByCollectionMs[name] = at;
|
|
2778
|
+
} else {
|
|
2779
|
+
this.lastEmbedFailAtMs = at;
|
|
2780
|
+
}
|
|
2744
2781
|
globalState.lastGlobalEmbedFailAtMs = at;
|
|
2745
|
-
const msg =
|
|
2782
|
+
const msg = failure instanceof Error ? failure.message : String(failure);
|
|
2746
2783
|
log.warn(`QMD embed failed for collection ${name}: ${msg}`);
|
|
2784
|
+
if (options.strict) {
|
|
2785
|
+
throw failure;
|
|
2786
|
+
}
|
|
2747
2787
|
}
|
|
2748
2788
|
}
|
|
2749
2789
|
|
package/src/search/port.ts
CHANGED
|
@@ -81,6 +81,12 @@ export interface SearchBackend {
|
|
|
81
81
|
|
|
82
82
|
// ── Maintenance ──
|
|
83
83
|
update(execution?: SearchExecutionOptions): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Optional strict refresh used by callers that must know whether the backend
|
|
86
|
+
* was actually refreshed before writing success markers. Ordinary update
|
|
87
|
+
* calls remain fail-open for migration/maintenance resilience.
|
|
88
|
+
*/
|
|
89
|
+
updateStrict?(execution?: SearchExecutionOptions): Promise<void>;
|
|
84
90
|
updateCollection(collection: string, execution?: SearchExecutionOptions): Promise<void>;
|
|
85
91
|
updateCollectionFromDir?(collection: string, memoryDir: string, execution?: SearchExecutionOptions): Promise<void>;
|
|
86
92
|
/**
|
|
@@ -96,7 +102,17 @@ export interface SearchBackend {
|
|
|
96
102
|
*/
|
|
97
103
|
updateCollectionStrict?(collection: string, execution?: SearchExecutionOptions): Promise<void>;
|
|
98
104
|
embed(): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Optional strict embed used by callers that must know vectors were actually
|
|
107
|
+
* refreshed before writing success markers.
|
|
108
|
+
*/
|
|
109
|
+
embedStrict?(): Promise<void>;
|
|
99
110
|
embedCollection(collection: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Optional strict collection embed used by callers that must know vectors were
|
|
113
|
+
* actually refreshed before writing success markers.
|
|
114
|
+
*/
|
|
115
|
+
embedCollectionStrict?(collection: string): Promise<void>;
|
|
100
116
|
|
|
101
117
|
// ── Collection management ──
|
|
102
118
|
/**
|
|
@@ -99,6 +99,18 @@ function scoreVerifiedSemanticRuleCandidate(
|
|
|
99
99
|
return { score, matchedFields };
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
export function compareVerifiedSemanticRuleResults(
|
|
103
|
+
left: VerifiedSemanticRuleResult,
|
|
104
|
+
right: VerifiedSemanticRuleResult,
|
|
105
|
+
): number {
|
|
106
|
+
return (
|
|
107
|
+
right.score - left.score ||
|
|
108
|
+
right.effectiveConfidence - left.effectiveConfidence ||
|
|
109
|
+
right.rule.frontmatter.updated.localeCompare(left.rule.frontmatter.updated) ||
|
|
110
|
+
left.rule.frontmatter.id.localeCompare(right.rule.frontmatter.id)
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
102
114
|
export async function searchVerifiedSemanticRules(options: {
|
|
103
115
|
memoryDir: string;
|
|
104
116
|
query: string;
|
|
@@ -150,11 +162,6 @@ export async function searchVerifiedSemanticRules(options: {
|
|
|
150
162
|
}
|
|
151
163
|
|
|
152
164
|
return candidates
|
|
153
|
-
.sort(
|
|
154
|
-
(left, right) =>
|
|
155
|
-
right.score - left.score
|
|
156
|
-
|| right.effectiveConfidence - left.effectiveConfidence
|
|
157
|
-
|| right.rule.frontmatter.updated.localeCompare(left.rule.frontmatter.updated),
|
|
158
|
-
)
|
|
165
|
+
.sort(compareVerifiedSemanticRuleResults)
|
|
159
166
|
.slice(0, options.maxResults);
|
|
160
167
|
}
|
package/src/types.ts
CHANGED
|
@@ -442,6 +442,55 @@ export interface CodingContext {
|
|
|
442
442
|
defaultBranch: string | null;
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
export type ScopeProfileLayerId =
|
|
446
|
+
| "userProject"
|
|
447
|
+
| "teamProject"
|
|
448
|
+
| "userGlobal"
|
|
449
|
+
| "serverShared";
|
|
450
|
+
|
|
451
|
+
export type ScopeProfilePromotionTarget =
|
|
452
|
+
| ScopeProfileLayerId
|
|
453
|
+
| "serverShared"
|
|
454
|
+
| "teamProject"
|
|
455
|
+
| "userGlobal";
|
|
456
|
+
|
|
457
|
+
export interface ScopeProfileTeamProjectConfig {
|
|
458
|
+
/**
|
|
459
|
+
* Namespace template for team-project layers. Supported placeholders:
|
|
460
|
+
* `{teamId}`, `{principal}`, `{projectId}`, `{projectHash}`, and
|
|
461
|
+
* `{projectNamespace}`. The resolved namespace is validated at use time.
|
|
462
|
+
*/
|
|
463
|
+
namespaceTemplate?: string;
|
|
464
|
+
/**
|
|
465
|
+
* Optional trusted team id for this profile. When omitted, the resolver uses
|
|
466
|
+
* the first configured team whose principal lists include the caller.
|
|
467
|
+
*/
|
|
468
|
+
teamId?: string;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export interface ScopeProfileAutoPromoteConfig {
|
|
472
|
+
enabled: boolean;
|
|
473
|
+
targets: ScopeProfilePromotionTarget[];
|
|
474
|
+
categories: Array<"fact" | "correction" | "decision" | "preference" | "rule" | "procedure">;
|
|
475
|
+
minConfidenceTier: ConfidenceTier;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export interface ScopeProfileConfig {
|
|
479
|
+
readOrder: ScopeProfileLayerId[];
|
|
480
|
+
writeDefault: ScopeProfileLayerId;
|
|
481
|
+
promotionTargets: ScopeProfilePromotionTarget[];
|
|
482
|
+
teamProject?: ScopeProfileTeamProjectConfig;
|
|
483
|
+
autoPromote: ScopeProfileAutoPromoteConfig;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export interface ScopeTeamConfig {
|
|
487
|
+
principals: string[];
|
|
488
|
+
projectNamespaceTemplate?: string;
|
|
489
|
+
read: string[];
|
|
490
|
+
write: string[];
|
|
491
|
+
promote: string[];
|
|
492
|
+
}
|
|
493
|
+
|
|
445
494
|
/** Configuration for the nightly contradiction-scan cron (issue #520). */
|
|
446
495
|
export interface ContradictionScanConfig {
|
|
447
496
|
/** Master switch for the contradiction scan cron. Default true. */
|
|
@@ -1216,6 +1265,18 @@ export interface PluginConfig {
|
|
|
1216
1265
|
// QMD maintenance (debounced singleflight)
|
|
1217
1266
|
qmdMaintenanceEnabled: boolean;
|
|
1218
1267
|
qmdMaintenanceDebounceMs: number;
|
|
1268
|
+
/**
|
|
1269
|
+
* Namespace-aware maintenance fanout (issue #1500). When namespaces are
|
|
1270
|
+
* enabled, background maintenance jobs use the rebuildable namespace catalog
|
|
1271
|
+
* to discover dynamic project/team namespaces rather than only processing the
|
|
1272
|
+
* configured default/shared/policy set.
|
|
1273
|
+
*/
|
|
1274
|
+
maintenanceNamespaceFanoutEnabled: boolean;
|
|
1275
|
+
maintenanceMaxNamespacesPerCycle: number;
|
|
1276
|
+
maintenanceIncludeProjectNamespaces: boolean;
|
|
1277
|
+
maintenanceIncludeBranchNamespaces: boolean;
|
|
1278
|
+
maintenanceIncludeTeamProjectNamespaces: boolean;
|
|
1279
|
+
maintenanceNamespaceLockStaleMs: number;
|
|
1219
1280
|
qmdAutoEmbedEnabled: boolean;
|
|
1220
1281
|
qmdEmbedMinIntervalMs: number;
|
|
1221
1282
|
qmdUpdateTimeoutMs: number;
|
|
@@ -1309,6 +1370,9 @@ export interface PluginConfig {
|
|
|
1309
1370
|
principalFromSessionKeyRules: PrincipalRule[];
|
|
1310
1371
|
namespacePolicies: NamespacePolicy[];
|
|
1311
1372
|
defaultRecallNamespaces: Array<"self" | "shared">;
|
|
1373
|
+
scopeProfiles: Record<string, ScopeProfileConfig>;
|
|
1374
|
+
defaultScopeProfile: string | undefined;
|
|
1375
|
+
teams: Record<string, ScopeTeamConfig>;
|
|
1312
1376
|
cronRecallMode: CronRecallMode;
|
|
1313
1377
|
cronRecallAllowlist: string[];
|
|
1314
1378
|
cronRecallPolicyEnabled: boolean;
|
package/src/verified-recall.ts
CHANGED
|
@@ -84,6 +84,15 @@ function resolveVerifiedEpisodeMemoriesFromMap(
|
|
|
84
84
|
return verified;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
export function compareVerifiedEpisodeResults(left: VerifiedEpisodeResult, right: VerifiedEpisodeResult): number {
|
|
88
|
+
return (
|
|
89
|
+
right.score - left.score ||
|
|
90
|
+
right.verifiedEpisodeCount - left.verifiedEpisodeCount ||
|
|
91
|
+
right.box.sealedAt.localeCompare(left.box.sealedAt) ||
|
|
92
|
+
left.box.id.localeCompare(right.box.id)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
87
96
|
export async function searchVerifiedEpisodes(options: {
|
|
88
97
|
memoryDir: string;
|
|
89
98
|
query: string;
|
|
@@ -128,11 +137,6 @@ export async function searchVerifiedEpisodes(options: {
|
|
|
128
137
|
verifiedMemoryIds: candidate.verifiedMemories.map((memory) => memory.frontmatter.id),
|
|
129
138
|
matchedFields: [...candidate.matchedFields].sort(),
|
|
130
139
|
}))
|
|
131
|
-
.sort(
|
|
132
|
-
(left, right) =>
|
|
133
|
-
right.score - left.score
|
|
134
|
-
|| right.verifiedEpisodeCount - left.verifiedEpisodeCount
|
|
135
|
-
|| right.box.sealedAt.localeCompare(left.box.sealedAt),
|
|
136
|
-
)
|
|
140
|
+
.sort(compareVerifiedEpisodeResults)
|
|
137
141
|
.slice(0, options.maxResults);
|
|
138
142
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/namespaces/search.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { PluginConfig, QmdSearchResult } from \"../types.js\";\nimport type {\n SearchBackend,\n SearchExecutionOptions,\n SearchQueryOptions,\n} from \"../search/port.js\";\nimport { createSearchBackend } from \"../search/factory.js\";\nimport { namespaceIdentityToken, normalizeNamespaceIdentity } from \"./identity.js\";\n\nconst NESTED_NAMESPACE_FILTER_OVERFETCH_FACTOR = 4;\nconst NESTED_NAMESPACE_FILTER_OVERFETCH_MIN = 50;\n\nexport function namespaceCollectionName(\n baseCollection: string,\n namespace: string,\n options?: {\n defaultNamespace?: string;\n useLegacyDefaultCollection?: boolean;\n },\n): string {\n const trimmed = normalizeNamespaceIdentity(namespace);\n const defaultNamespace = normalizeNamespaceIdentity(options?.defaultNamespace ?? \"\") || \"default\";\n if (\n options?.useLegacyDefaultCollection === true &&\n trimmed === defaultNamespace\n ) {\n return baseCollection;\n }\n\n return `${baseCollection}--${namespaceIdentityToken(trimmed || defaultNamespace)}`;\n}\n\ntype StorageRouterLike = {\n storageFor(namespace: string): Promise<{ dir: string }>;\n};\n\ntype NamespaceBackendRecord = {\n backend: SearchBackend;\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: CollectionState;\n filtersNestedNamespaces: boolean;\n};\n\nexport type CollectionState = \"present\" | \"missing\" | \"unknown\" | \"skipped\";\n\nexport interface NamespaceSearchHealth {\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: CollectionState;\n debugStatus: string;\n installedVersion: string | null;\n supportedVersion: string | null;\n supported: boolean | null;\n upgradeAvailable: boolean | null;\n doctorAvailable: boolean | null;\n daemonMode: boolean | null;\n}\n\ntype NamespaceScopedSearchConfig = PluginConfig & {\n hostEmbeddingProviderScope?: string;\n};\n\ntype BackendRecordOptions = {\n autoCreateCollection: boolean;\n abortAsUnavailable: boolean;\n failOpenMissingGuardedCollection: boolean;\n};\n\nexport class NamespaceSearchRouter {\n private readonly cache = new Map<string, Promise<NamespaceBackendRecord>>();\n\n constructor(\n private readonly config: PluginConfig,\n private readonly storageRouter: StorageRouterLike,\n private readonly createBackend: (config: PluginConfig) => SearchBackend = createSearchBackend,\n ) {}\n\n async collectionForNamespace(namespace: string): Promise<string> {\n return (await this.backendRecordFor(namespace)).collection;\n }\n\n async searchAcrossNamespaces(options: {\n query: string;\n namespaces: string[];\n maxResults?: number;\n mode?: \"search\" | \"hybrid\" | \"bm25\" | \"vector\";\n searchOptions?: SearchQueryOptions;\n execution?: SearchExecutionOptions;\n }): Promise<QmdSearchResult[]> {\n const query = options.query.trim();\n if (!query) return [];\n const maxResults = Math.max(0, Math.floor(options.maxResults ?? this.config.qmdMaxResults));\n if (maxResults === 0) return [];\n\n const method = options.mode ?? \"search\";\n const namespaces = Array.from(new Set(options.namespaces.map((value) => value.trim()).filter(Boolean)));\n if (namespaces.length === 0) return [];\n\n const resultsByNamespace = await Promise.all(\n namespaces.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") {\n return { namespace, results: [] as QmdSearchResult[] };\n }\n const backendLimit = backendSearchLimit(record, maxResults);\n let results: QmdSearchResult[];\n switch (method) {\n case \"hybrid\":\n results = await record.backend.hybridSearch(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n case \"bm25\":\n results = await record.backend.bm25Search(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n case \"vector\":\n results = await record.backend.vectorSearch(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n default:\n results = await record.backend.search(\n query,\n record.collection,\n backendLimit,\n options.searchOptions,\n options.execution,\n );\n break;\n }\n results = filterNamespaceSubtreeResults(record, results);\n return { namespace, results };\n }),\n );\n\n return mergeNamespaceSearchResults(resultsByNamespace, maxResults);\n }\n\n /**\n * Update all namespace backends.\n * Returns the number of backends for which an update was attempted\n * (i.e., available and collection present). Callers can treat 0 as a\n * signal that no backend was eligible — useful for success-verification in\n * startup-sync when namespacesEnabled is true.\n */\n async updateNamespaces(\n namespaces: string[],\n execution?: SearchExecutionOptions,\n ): Promise<number> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n const eligible = (await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n return record.available && record.collectionState !== \"missing\"\n ? record\n : null;\n }),\n )).filter((record): record is NamespaceBackendRecord => record !== null);\n\n const globalRecord = eligible.find((record) => record.backend.updatesAllCollections?.() === true);\n const scopedRecords = globalRecord\n ? eligible.filter((record) => record.backend.updatesAllCollections?.() !== true)\n : eligible;\n\n await Promise.all([\n globalRecord ? globalRecord.backend.update(execution) : Promise.resolve(),\n ...scopedRecords.map((record) => record.backend.update(execution)),\n ]);\n\n return (globalRecord ? 1 : 0) + scopedRecords.length;\n }\n\n async embedNamespaces(namespaces: string[]): Promise<void> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") return;\n await record.backend.embed();\n }),\n );\n }\n\n async ensureNamespaceCollection(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<\"present\" | \"missing\" | \"unknown\" | \"skipped\"> {\n const record = await this.backendRecordFor(namespace, execution);\n return record.collectionState;\n }\n\n async healthForNamespace(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceSearchHealth> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const record = await this.createBackendRecordFor(\n key,\n execution,\n {\n autoCreateCollection: false,\n abortAsUnavailable: true,\n failOpenMissingGuardedCollection: false,\n },\n );\n try {\n const liveRecord = await this.liveCachedRecordForHealth(key, record, execution);\n const diagnosticBackend = liveRecord?.backend ?? record.backend;\n const versionStatus =\n \"getVersionStatus\" in diagnosticBackend &&\n typeof diagnosticBackend.getVersionStatus === \"function\"\n ? diagnosticBackend.getVersionStatus()\n : null;\n const daemonMode = daemonModeForBackend(diagnosticBackend);\n const collectionState =\n liveRecord?.collectionState === \"missing\"\n ? \"missing\"\n : record.collectionState;\n\n return {\n collection: record.collection,\n memoryDir: record.memoryDir,\n available: liveRecord?.available ?? record.available,\n collectionState,\n debugStatus: diagnosticBackend.debugStatus(),\n installedVersion: versionStatus?.installedVersion ?? null,\n supportedVersion: versionStatus?.supportedVersion ?? null,\n supported: versionStatus?.supported ?? null,\n upgradeAvailable: versionStatus?.upgradeAvailable ?? null,\n doctorAvailable: versionStatus?.capabilities?.doctor ?? null,\n daemonMode,\n };\n } finally {\n const dispose = (record.backend as { dispose?: () => void | Promise<void> }).dispose;\n await dispose?.call(record.backend);\n }\n }\n\n private async liveCachedRecordForHealth(\n key: string,\n disposableRecord: NamespaceBackendRecord,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord | null> {\n const pending = this.cache.get(key);\n if (!pending) return null;\n const cachedRecord = await awaitWithAbort(pending, execution?.signal).catch(() => null);\n if (!cachedRecord) return null;\n if (cachedRecord.collection !== disposableRecord.collection) return null;\n if (cachedRecord.memoryDir !== disposableRecord.memoryDir) return null;\n return cachedRecord;\n }\n\n /** Clear cached backend records so the next access re-probes availability. */\n clearCache(): void {\n this.cache.clear();\n }\n\n /** Release any per-namespace backend handles held by cached records. */\n async dispose(): Promise<void> {\n const pendingRecords = Array.from(this.cache.values());\n this.cache.clear();\n const settled = await Promise.allSettled(pendingRecords);\n await Promise.allSettled(\n settled.flatMap((entry) => {\n if (entry.status !== \"fulfilled\") return [];\n const dispose = (entry.value.backend as { dispose?: () => void | Promise<void> }).dispose;\n return dispose ? [dispose.call(entry.value.backend)] : [];\n }),\n );\n }\n\n private async backendRecordFor(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const existing = this.cache.get(key);\n if (existing) return await existing;\n\n const pending = this.createBackendRecordFor(key, execution, {\n autoCreateCollection: true,\n abortAsUnavailable: false,\n failOpenMissingGuardedCollection: true,\n }).catch((error) => {\n this.cache.delete(key);\n throw error;\n });\n\n this.cache.set(key, pending);\n return await pending;\n }\n\n private async createBackendRecordFor(\n namespace: string,\n execution: SearchExecutionOptions | undefined,\n options: BackendRecordOptions,\n ): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const storage = await this.storageRouter.storageFor(key);\n const useLegacyDefaultCollection =\n key === this.config.defaultNamespace && storage.dir === this.config.memoryDir;\n const filtersNestedNamespaces =\n this.config.namespacesEnabled === true && useLegacyDefaultCollection;\n const rootHostEmbeddingScope =\n (this.config as NamespaceScopedSearchConfig).hostEmbeddingProviderScope ??\n this.config.memoryDir;\n const scopedConfig: NamespaceScopedSearchConfig = {\n ...this.config,\n memoryDir: storage.dir,\n hostEmbeddingProviderScope: rootHostEmbeddingScope,\n qmdCollection: namespaceCollectionName(this.config.qmdCollection, key, {\n defaultNamespace: this.config.defaultNamespace,\n useLegacyDefaultCollection,\n }),\n };\n\n const backend = this.createBackend(scopedConfig);\n try {\n const availabilityProbe =\n options.autoCreateCollection || typeof backend.checkAvailability !== \"function\"\n ? backend.probe()\n : backend.checkAvailability({ signal: execution?.signal });\n const available = await awaitWithAbort(availabilityProbe, execution?.signal).catch((error) => {\n if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {\n throw error;\n }\n return false;\n });\n const collectionState = available\n ? await awaitWithAbort(\n this.collectionStateForBackend(backend, storage.dir, scopedConfig.qmdCollection, {\n autoCreate: options.autoCreateCollection,\n failOpenMissingGuardedCollection: options.failOpenMissingGuardedCollection,\n skipAutoCreate: filtersNestedNamespaces,\n execution,\n }),\n execution?.signal,\n ).catch((error) => {\n if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {\n throw error;\n }\n return \"unknown\" as const;\n })\n : \"unknown\";\n return {\n backend,\n collection: scopedConfig.qmdCollection,\n memoryDir: storage.dir,\n available,\n collectionState,\n filtersNestedNamespaces,\n };\n } catch (error) {\n const dispose = (backend as { dispose?: () => void | Promise<void> }).dispose;\n if (dispose) {\n await Promise.resolve(dispose.call(backend)).catch(() => {});\n }\n throw error;\n }\n }\n\n private async collectionStateForBackend(\n backend: SearchBackend,\n memoryDir: string,\n collection: string,\n options: {\n autoCreate: boolean;\n failOpenMissingGuardedCollection: boolean;\n skipAutoCreate: boolean;\n execution?: SearchExecutionOptions;\n },\n ): Promise<CollectionState> {\n if (!options.autoCreate || options.skipAutoCreate) {\n if (!backend.checkCollection) return \"unknown\";\n const collectionState = await backend\n .checkCollection(collection, options.execution)\n .catch(() => \"unknown\" as const);\n return options.failOpenMissingGuardedCollection && collectionState === \"missing\"\n ? \"unknown\"\n : collectionState;\n }\n return await backend.ensureCollection(memoryDir, collection, options.execution).catch(() => \"unknown\" as const);\n }\n}\n\nclass NamespaceSearchAbortError extends Error {\n constructor() {\n super(\"operation aborted\");\n }\n}\n\nfunction awaitWithAbort<T>(operation: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return operation;\n if (signal.aborted) return Promise.reject(new NamespaceSearchAbortError());\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(new NamespaceSearchAbortError());\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n operation.then(resolve, reject).finally(() => {\n signal.removeEventListener(\"abort\", onAbort);\n });\n });\n}\n\nfunction filterNamespaceSubtreeResults(\n record: NamespaceBackendRecord,\n results: QmdSearchResult[],\n): QmdSearchResult[] {\n if (!record.filtersNestedNamespaces) return results;\n return results.filter((result) =>\n !pathIsInsideNamespaceSubtree(record.memoryDir, record.collection, result.path)\n );\n}\n\nfunction backendSearchLimit(\n record: NamespaceBackendRecord,\n maxResults: number,\n): number {\n if (!record.filtersNestedNamespaces) return maxResults;\n return Math.max(\n maxResults,\n maxResults * NESTED_NAMESPACE_FILTER_OVERFETCH_FACTOR,\n NESTED_NAMESPACE_FILTER_OVERFETCH_MIN,\n );\n}\n\nfunction daemonModeForBackend(backend: SearchBackend): boolean | null {\n return \"isDaemonMode\" in backend && typeof backend.isDaemonMode === \"function\"\n ? backend.isDaemonMode() === true\n : null;\n}\n\nfunction pathIsInsideNamespaceSubtree(\n memoryDir: string,\n collection: string,\n resultPath: string | undefined,\n): boolean {\n if (!resultPath) return false;\n const normalizedResultPath = normalizeQmdResultPath(resultPath, collection);\n const memoryRoot = path.resolve(memoryDir);\n const namespacesRoot = path.join(memoryRoot, \"namespaces\");\n const candidate = path.isAbsolute(normalizedResultPath)\n ? path.normalize(normalizedResultPath)\n : path.resolve(memoryRoot, normalizedResultPath);\n const relative = path.relative(namespacesRoot, candidate);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction normalizeQmdResultPath(resultPath: string, collection: string): string {\n let value = resultPath.trim();\n if (value.startsWith(\"qmd://\")) {\n try {\n const parsed = new URL(value);\n if (parsed.protocol === \"qmd:\" && parsed.hostname === collection) {\n value = decodeURIComponent(parsed.pathname.replace(/^\\/+/, \"\"));\n }\n } catch {\n const remainder = value.slice(\"qmd://\".length);\n const slashIndex = remainder.indexOf(\"/\");\n if (slashIndex !== -1) {\n value = remainder.slice(slashIndex + 1);\n }\n }\n }\n\n const collectionPrefix = `${collection}/`;\n if (value.startsWith(collectionPrefix)) {\n value = value.slice(collectionPrefix.length);\n }\n return value;\n}\n\nfunction mergeNamespaceSearchResults(\n lists: Array<{ namespace: string; results: QmdSearchResult[] }>,\n maxResults: number,\n): QmdSearchResult[] {\n const merged = new Map<string, QmdSearchResult>();\n\n for (const { namespace, results } of lists) {\n for (const result of results) {\n const key = `${namespace}\\0${result.path || result.docid}`;\n const existing = merged.get(key);\n if (!existing) {\n merged.set(key, result);\n continue;\n }\n if (result.score > existing.score) {\n merged.set(key, {\n ...result,\n snippet: existing.snippet || result.snippet || \"\",\n });\n }\n }\n }\n\n return [...merged.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/semantic-rule-verifier.ts"],"sourcesContent":["import { getCachedRuleMemories, setCachedRuleMemories } from \"./memory-cache.js\";\nimport { StorageManager } from \"./storage.js\";\nimport type { MemoryFile } from \"./types.js\";\nimport { countRecallTokenOverlap, normalizeRecallTokens } from \"./recall-tokenization.js\";\n\nexport type SemanticRuleVerificationStatus =\n | \"verified\"\n | \"source-memory-missing\"\n | \"source-memory-archived\"\n | \"source-memory-forgotten\"\n | \"source-memory-not-episode\";\n\nexport interface VerifiedSemanticRuleResult {\n rule: MemoryFile;\n score: number;\n sourceMemoryId: string;\n verificationStatus: SemanticRuleVerificationStatus;\n effectiveConfidence: number;\n matchedFields: string[];\n}\n\nconst DEFAULT_MIN_EFFECTIVE_CONFIDENCE = 0.45;\n\nfunction verificationConfidenceMultiplier(status: SemanticRuleVerificationStatus): number {\n switch (status) {\n case \"verified\":\n return 1;\n case \"source-memory-not-episode\":\n return 0.45;\n case \"source-memory-archived\":\n return 0.4;\n case \"source-memory-forgotten\":\n return 0.3;\n case \"source-memory-missing\":\n return 0.35;\n default:\n return 0.35;\n }\n}\n\nfunction resolveVerificationStatus(sourceMemory: MemoryFile | undefined): SemanticRuleVerificationStatus {\n if (!sourceMemory) return \"source-memory-missing\";\n if (sourceMemory.frontmatter.status === \"archived\") {\n return \"source-memory-archived\";\n }\n if (sourceMemory.frontmatter.status === \"forgotten\") return \"source-memory-forgotten\";\n if (sourceMemory.frontmatter.memoryKind !== \"episode\") return \"source-memory-not-episode\";\n return \"verified\";\n}\n\nfunction resolveEffectiveConfidence(rule: MemoryFile, sourceMemory: MemoryFile | undefined): {\n status: SemanticRuleVerificationStatus;\n effectiveConfidence: number;\n} {\n const status = resolveVerificationStatus(sourceMemory);\n const ruleConfidence = Number.isFinite(rule.frontmatter.confidence) ? rule.frontmatter.confidence : 0.8;\n const sourceConfidence = Number.isFinite(sourceMemory?.frontmatter.confidence)\n ? sourceMemory!.frontmatter.confidence\n : ruleConfidence;\n const anchoredConfidence = Math.min(ruleConfidence, sourceConfidence);\n const effectiveConfidence = Math.max(\n 0,\n Math.min(1, anchoredConfidence * verificationConfidenceMultiplier(status)),\n );\n return { status, effectiveConfidence };\n}\n\nfunction scoreVerifiedSemanticRuleCandidate(\n rule: MemoryFile,\n sourceMemory: MemoryFile | undefined,\n queryTokens: Set<string>,\n effectiveConfidence: number,\n): { score: number; matchedFields: Set<string> } {\n const matchedFields = new Set<string>();\n let score = 0;\n\n const ruleContentMatches = countRecallTokenOverlap(queryTokens, rule.content);\n if (ruleContentMatches > 0) {\n score += ruleContentMatches * 5;\n matchedFields.add(\"ruleContent\");\n }\n\n const tagMatches = countRecallTokenOverlap(queryTokens, rule.frontmatter.tags?.join(\" \"));\n if (tagMatches > 0) {\n score += tagMatches * 2;\n matchedFields.add(\"tags\");\n }\n\n const sourceContentMatches = countRecallTokenOverlap(queryTokens, sourceMemory?.content);\n if (sourceContentMatches > 0) {\n score += sourceContentMatches * 2;\n matchedFields.add(\"sourceContent\");\n }\n\n if (score > 0) {\n score += effectiveConfidence;\n }\n\n return { score, matchedFields };\n}\n\nexport async function searchVerifiedSemanticRules(options: {\n memoryDir: string;\n query: string;\n maxResults: number;\n minEffectiveConfidence?: number;\n}): Promise<VerifiedSemanticRuleResult[]> {\n const queryTokens = new Set(normalizeRecallTokens(options.query, [\"what\", \"which\"]));\n if (queryTokens.size === 0 || options.maxResults <= 0) return [];\n\n const storage = new StorageManager(options.memoryDir);\n const version = storage.getMemoryStatusVersion();\n\n // Use derived rule cache to avoid O(146K) iteration on every call.\n let cachedRules = getCachedRuleMemories(storage.dir, version);\n if (!cachedRules) {\n const allMems = await storage.readAllMemories();\n cachedRules = setCachedRuleMemories(storage.dir, allMems, version);\n }\n const { all: ruleMemories, byId: memoryById } = cachedRules;\n const minEffectiveConfidence = options.minEffectiveConfidence ?? DEFAULT_MIN_EFFECTIVE_CONFIDENCE;\n\n const candidates: VerifiedSemanticRuleResult[] = [];\n // ruleMemories is pre-filtered to category=rule and recall-hidden statuses.\n for (const memory of ruleMemories) {\n if (memory.frontmatter.source !== \"semantic-rule-promotion\") continue;\n const sourceMemoryId = memory.frontmatter.sourceMemoryId;\n if (!sourceMemoryId) continue;\n\n const sourceMemory = memoryById.get(sourceMemoryId);\n const { status, effectiveConfidence } = resolveEffectiveConfidence(memory, sourceMemory);\n if (effectiveConfidence < minEffectiveConfidence) continue;\n\n const { score, matchedFields } = scoreVerifiedSemanticRuleCandidate(\n memory,\n sourceMemory,\n queryTokens,\n effectiveConfidence,\n );\n if (score <= 0) continue;\n\n candidates.push({\n rule: memory,\n score,\n sourceMemoryId,\n verificationStatus: status,\n effectiveConfidence,\n matchedFields: [...matchedFields].sort(),\n });\n }\n\n return candidates\n .sort(\n (left, right) =>\n right.score - left.score\n || right.effectiveConfidence - left.effectiveConfidence\n || right.rule.frontmatter.updated.localeCompare(left.rule.frontmatter.updated),\n )\n .slice(0, options.maxResults);\n}\n"],"mappings":"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","names":[]}
|