@remnic/core 9.3.749 → 9.3.751

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 (271) hide show
  1. package/dist/access-boundary.d.ts +8 -8
  2. package/dist/access-boundary.js +15 -15
  3. package/dist/access-cli.js +39 -39
  4. package/dist/access-http.d.ts +8 -8
  5. package/dist/access-http.js +20 -20
  6. package/dist/access-mcp.d.ts +8 -8
  7. package/dist/access-mcp.js +19 -19
  8. package/dist/access-operations-batch.js +16 -16
  9. package/dist/access-operations.d.ts +8 -8
  10. package/dist/access-operations.js +18 -18
  11. package/dist/access-schema.d.ts +2 -2
  12. package/dist/access-schema.js +5 -5
  13. package/dist/{access-service-5-EVpt3v.d.ts → access-service-DmAEOJdJ.d.ts} +11 -3
  14. package/dist/access-service.d.ts +5 -5
  15. package/dist/access-service.js +14 -14
  16. package/dist/access-surface-catalog.d.ts +8 -8
  17. package/dist/action-confidence.d.ts +1 -1
  18. package/dist/active-memory-bridge.d.ts +1 -1
  19. package/dist/active-recall.d.ts +1 -1
  20. package/dist/active-recall.js +8 -1
  21. package/dist/active-recall.js.map +1 -1
  22. package/dist/behavior-learner.d.ts +1 -1
  23. package/dist/behavior-signals.d.ts +1 -1
  24. package/dist/bootstrap.d.ts +7 -7
  25. package/dist/briefing.d.ts +1 -1
  26. package/dist/briefing.js +7 -7
  27. package/dist/buffer-surprise-report.d.ts +1 -1
  28. package/dist/buffer.d.ts +1 -1
  29. package/dist/calibration.d.ts +1 -1
  30. package/dist/capabilities.d.ts +1 -1
  31. package/dist/{catalog-D_ZDxu8Y.d.ts → catalog-BpOcwHdE.d.ts} +1 -1
  32. package/dist/causal-behavior.d.ts +1 -1
  33. package/dist/causal-consolidation.d.ts +1 -1
  34. package/dist/causal-consolidation.js +8 -8
  35. package/dist/causal-trajectory-graph.d.ts +1 -1
  36. package/dist/{chunk-C5WN74HH.js → chunk-2HAG7JOI.js} +8 -2
  37. package/dist/chunk-2HAG7JOI.js.map +1 -0
  38. package/dist/{chunk-GKRLPHPU.js → chunk-2KK5WNQB.js} +2 -2
  39. package/dist/{chunk-JRDPT6DA.js → chunk-4NWIGAIC.js} +2 -2
  40. package/dist/{chunk-OBJUKYDO.js → chunk-4XL3CVII.js} +2 -2
  41. package/dist/{chunk-WWVXXSLF.js → chunk-5PZCDUJ6.js} +4 -4
  42. package/dist/{chunk-URQLO7BX.js → chunk-6FNZ3NMS.js} +2 -2
  43. package/dist/{chunk-DRUDC2UX.js → chunk-6MMONPHM.js} +2 -2
  44. package/dist/{chunk-RB6A7OUN.js → chunk-6SXNQFHB.js} +2 -2
  45. package/dist/{chunk-ZGZNLRKF.js → chunk-7TWA7DKP.js} +5 -5
  46. package/dist/{chunk-KMNYXLPL.js → chunk-B35L45HZ.js} +2 -2
  47. package/dist/{chunk-SIV3JZPP.js → chunk-CGZWGVQF.js} +5 -5
  48. package/dist/{chunk-CKFLLAIS.js → chunk-DANV2HTH.js} +3 -3
  49. package/dist/{chunk-NVYF5OB6.js → chunk-DBRVU5PR.js} +3 -3
  50. package/dist/{chunk-LMFS64GY.js → chunk-E4PFDD3N.js} +4 -4
  51. package/dist/{chunk-DIHCFJVV.js → chunk-HYI2GP3F.js} +4 -4
  52. package/dist/{chunk-UIKZZ242.js → chunk-IKHKHADN.js} +2 -2
  53. package/dist/{chunk-PUR2CKX2.js → chunk-JS2HKKOK.js} +1 -1
  54. package/dist/{chunk-PUR2CKX2.js.map → chunk-JS2HKKOK.js.map} +1 -1
  55. package/dist/{chunk-R2OAN6IP.js → chunk-K2JM4DZZ.js} +2 -2
  56. package/dist/{chunk-3IJGF6K2.js → chunk-K2R3DEEH.js} +2 -2
  57. package/dist/{chunk-HIHCB2S6.js → chunk-QRRBXD24.js} +2 -2
  58. package/dist/{chunk-PNUOQYRJ.js → chunk-RWZB6MAY.js} +1953 -2172
  59. package/dist/chunk-RWZB6MAY.js.map +1 -0
  60. package/dist/{chunk-ZPZ4VVLT.js → chunk-SD34EK4Z.js} +2 -2
  61. package/dist/{chunk-WK3NK6SP.js → chunk-SNEXVX3U.js} +6 -6
  62. package/dist/{chunk-FVZ2ISIX.js → chunk-TPLE6SNY.js} +7 -7
  63. package/dist/{chunk-24YDB5QP.js → chunk-UETBEHBA.js} +44 -24
  64. package/dist/chunk-UETBEHBA.js.map +1 -0
  65. package/dist/{chunk-5IN26V6W.js → chunk-UU32EAIY.js} +5 -5
  66. package/dist/{chunk-ZGAJB74V.js → chunk-W3BFT5OJ.js} +2 -2
  67. package/dist/{chunk-L4N7SVNN.js → chunk-WA7FECSG.js} +11 -11
  68. package/dist/{chunk-Q3X7GUAQ.js → chunk-WOX2UW4K.js} +2 -2
  69. package/dist/{chunk-XTEWVF3C.js → chunk-WWSXVOGY.js} +2 -2
  70. package/dist/{chunk-PWWWLD7D.js → chunk-X64YLC24.js} +153 -27
  71. package/dist/chunk-X64YLC24.js.map +1 -0
  72. package/dist/{chunk-P4FW3ZU5.js → chunk-YGGXUNS4.js} +20 -20
  73. package/dist/{chunk-JHQUIH3W.js → chunk-ZBVQ4ZM4.js} +19 -19
  74. package/dist/{cli-DuWWjaKT.d.ts → cli-lmf5RGyQ.d.ts} +3 -3
  75. package/dist/cli.d.ts +9 -9
  76. package/dist/cli.js +33 -33
  77. package/dist/compounding/engine.d.ts +1 -1
  78. package/dist/compounding/engine.js +7 -7
  79. package/dist/compounding/preference-consolidator.d.ts +1 -1
  80. package/dist/compression-optimizer.d.ts +1 -1
  81. package/dist/config.d.ts +1 -1
  82. package/dist/config.js +8 -1
  83. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  84. package/dist/connectors/codex-materialize-runner.js +7 -7
  85. package/dist/connectors/codex-materialize.d.ts +1 -1
  86. package/dist/connectors/index.d.ts +1 -1
  87. package/dist/connectors/index.js +7 -7
  88. package/dist/consolidation-provenance-check.d.ts +1 -1
  89. package/dist/consolidation-undo.d.ts +1 -1
  90. package/dist/contradiction/index.d.ts +1 -1
  91. package/dist/conversation-index/backend.d.ts +1 -1
  92. package/dist/conversation-index/chunker.d.ts +1 -1
  93. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  94. package/dist/conversation-index/indexer.d.ts +1 -1
  95. package/dist/conversation-index/search.d.ts +1 -1
  96. package/dist/day-summary.d.ts +1 -1
  97. package/dist/delinearize.d.ts +1 -1
  98. package/dist/direct-answer-wiring.d.ts +1 -1
  99. package/dist/direct-answer.d.ts +1 -1
  100. package/dist/embedding-fallback.d.ts +1 -1
  101. package/dist/enrichment/index.d.ts +1 -1
  102. package/dist/entity-retrieval.d.ts +1 -1
  103. package/dist/entity-retrieval.js +7 -7
  104. package/dist/entity-schema.d.ts +1 -1
  105. package/dist/explicit-capture.d.ts +7 -7
  106. package/dist/extraction-faithfulness.d.ts +1 -1
  107. package/dist/extraction-judge-telemetry.d.ts +1 -1
  108. package/dist/extraction-judge-training.d.ts +1 -1
  109. package/dist/extraction-judge.d.ts +1 -1
  110. package/dist/extraction.d.ts +1 -1
  111. package/dist/fallback-llm.d.ts +1 -1
  112. package/dist/graph-dashboard-diff.d.ts +1 -1
  113. package/dist/graph-dashboard-key.d.ts +1 -1
  114. package/dist/graph-dashboard-parser.d.ts +1 -1
  115. package/dist/graph-edge-reinforcement.d.ts +1 -1
  116. package/dist/graph-snapshot.d.ts +1 -1
  117. package/dist/graph.d.ts +1 -1
  118. package/dist/identity-continuity.d.ts +1 -1
  119. package/dist/importance.d.ts +1 -1
  120. package/dist/index.d.ts +10 -10
  121. package/dist/index.js +76 -72
  122. package/dist/intent.d.ts +1 -1
  123. package/dist/lcm/engine.d.ts +1 -1
  124. package/dist/lcm/index.d.ts +1 -1
  125. package/dist/lcm/tools.d.ts +1 -1
  126. package/dist/lifecycle.d.ts +1 -1
  127. package/dist/live-connectors-runner.d.ts +1 -1
  128. package/dist/local-llm.d.ts +1 -1
  129. package/dist/local-model-endpoint.d.ts +1 -1
  130. package/dist/maintenance/memory-governance.d.ts +1 -1
  131. package/dist/maintenance/memory-governance.js +7 -7
  132. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +7 -7
  133. package/dist/maintenance/rebuild-memory-projection.js +8 -8
  134. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  135. package/dist/memory-action-policy.d.ts +1 -1
  136. package/dist/memory-cache.d.ts +1 -1
  137. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  138. package/dist/memory-projection-store.d.ts +1 -1
  139. package/dist/memory-provenance.d.ts +1 -1
  140. package/dist/memory-worth-outcomes.d.ts +1 -1
  141. package/dist/models-json.d.ts +1 -1
  142. package/dist/namespaces/migrate.d.ts +2 -2
  143. package/dist/namespaces/migrate.js +8 -8
  144. package/dist/namespaces/principal.d.ts +1 -1
  145. package/dist/namespaces/search.d.ts +1 -1
  146. package/dist/namespaces/search.js +1 -1
  147. package/dist/namespaces/storage.d.ts +2 -2
  148. package/dist/namespaces/storage.js +7 -7
  149. package/dist/native-knowledge.d.ts +1 -1
  150. package/dist/offline-sync.d.ts +108 -1
  151. package/dist/offline-sync.js +7 -1
  152. package/dist/operator-toolkit.d.ts +1 -1
  153. package/dist/operator-toolkit.js +15 -12
  154. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  155. package/dist/orchestration/maintenance.d.ts +2 -2
  156. package/dist/orchestration/maintenance.js +9 -9
  157. package/dist/{orchestrator-CZI6hO_R.d.ts → orchestrator-D7bb8ZGp.d.ts} +193 -201
  158. package/dist/orchestrator.d.ts +5 -5
  159. package/dist/orchestrator.js +51 -41
  160. package/dist/patterns-cli.d.ts +1 -1
  161. package/dist/policy-runtime.d.ts +1 -1
  162. package/dist/provenance.d.ts +1 -1
  163. package/dist/qmd-recall-cache.d.ts +1 -1
  164. package/dist/qmd.d.ts +1 -1
  165. package/dist/recall-disclosure-escalation.d.ts +1 -1
  166. package/dist/recall-explain-renderer.d.ts +1 -1
  167. package/dist/recall-explain-renderer.js +3 -3
  168. package/dist/recall-planner-llm.d.ts +1 -1
  169. package/dist/recall-state.d.ts +1 -1
  170. package/dist/recall-tag-filter.d.ts +1 -1
  171. package/dist/recall-xray-cli.d.ts +1 -1
  172. package/dist/recall-xray-cli.js +4 -4
  173. package/dist/recall-xray-renderer.d.ts +1 -1
  174. package/dist/recall-xray-renderer.js +3 -3
  175. package/dist/recall-xray.d.ts +1 -1
  176. package/dist/recall-xray.js +2 -2
  177. package/dist/resolve-auth-token.d.ts +1 -1
  178. package/dist/resume-bundles.js +9 -2
  179. package/dist/retrieval-agents.d.ts +1 -1
  180. package/dist/retrieval-tiers.d.ts +1 -1
  181. package/dist/routing/engine.d.ts +1 -1
  182. package/dist/routing/store.d.ts +1 -1
  183. package/dist/schemas.d.ts +22 -22
  184. package/dist/search/embed-helper.d.ts +1 -1
  185. package/dist/search/factory.d.ts +1 -1
  186. package/dist/search/factory.js +1 -1
  187. package/dist/search/index.d.ts +1 -1
  188. package/dist/search/index.js +1 -1
  189. package/dist/search/lancedb-backend.d.ts +1 -1
  190. package/dist/search/lancedb-backend.js +1 -1
  191. package/dist/search/meilisearch-backend.d.ts +1 -1
  192. package/dist/search/meilisearch-backend.js +1 -1
  193. package/dist/search/noop-backend.d.ts +1 -1
  194. package/dist/search/orama-backend.d.ts +1 -1
  195. package/dist/search/orama-backend.js +1 -1
  196. package/dist/search/port.d.ts +1 -1
  197. package/dist/search/remote-backend.d.ts +1 -1
  198. package/dist/{semantic-consolidation-D3aSiu9t.d.ts → semantic-consolidation-CTfbVwCA.d.ts} +1 -1
  199. package/dist/semantic-consolidation.d.ts +2 -2
  200. package/dist/semantic-consolidation.js +8 -8
  201. package/dist/semantic-rule-promotion.js +7 -7
  202. package/dist/semantic-rule-verifier.d.ts +1 -1
  203. package/dist/semantic-rule-verifier.js +7 -7
  204. package/dist/session-observer-bands.d.ts +1 -1
  205. package/dist/session-observer-state.d.ts +1 -1
  206. package/dist/shared-context/manager.d.ts +1 -1
  207. package/dist/signal.d.ts +1 -1
  208. package/dist/storage.d.ts +1 -1
  209. package/dist/storage.js +6 -6
  210. package/dist/summarizer.d.ts +1 -1
  211. package/dist/summary-snapshot.d.ts +1 -1
  212. package/dist/temporal-supersession.d.ts +1 -1
  213. package/dist/temporal-validity.d.ts +1 -1
  214. package/dist/threading.d.ts +1 -1
  215. package/dist/tier-migration.d.ts +1 -1
  216. package/dist/tier-routing.d.ts +1 -1
  217. package/dist/topics.d.ts +1 -1
  218. package/dist/transcript.d.ts +1 -1
  219. package/dist/transfer/types.d.ts +12 -12
  220. package/dist/trust-score-stage.d.ts +1 -1
  221. package/dist/trust-score.d.ts +1 -1
  222. package/dist/{types-CZm6rx9-.d.ts → types-D4NYDtXI.d.ts} +7 -0
  223. package/dist/types.d.ts +1 -1
  224. package/dist/types.js +1 -1
  225. package/dist/utility-runtime.d.ts +1 -1
  226. package/dist/verified-recall.js +7 -7
  227. package/package.json +2 -2
  228. package/src/access-service.ts +22 -0
  229. package/src/config.ts +5 -0
  230. package/src/index.ts +3 -1
  231. package/src/offline-sync.test.ts +354 -52
  232. package/src/offline-sync.ts +332 -24
  233. package/src/orchestration/extraction-run.ts +4 -34
  234. package/src/orchestration/namespace-read-fanout.ts +484 -0
  235. package/src/orchestration/orchestrator-helpers.ts +1130 -0
  236. package/src/orchestration/self-deps.ts +50 -0
  237. package/src/orchestration/workspace-ops.ts +789 -0
  238. package/src/orchestrator.ts +177 -2296
  239. package/src/types.ts +9 -0
  240. package/dist/chunk-24YDB5QP.js.map +0 -1
  241. package/dist/chunk-C5WN74HH.js.map +0 -1
  242. package/dist/chunk-PNUOQYRJ.js.map +0 -1
  243. package/dist/chunk-PWWWLD7D.js.map +0 -1
  244. /package/dist/{chunk-GKRLPHPU.js.map → chunk-2KK5WNQB.js.map} +0 -0
  245. /package/dist/{chunk-JRDPT6DA.js.map → chunk-4NWIGAIC.js.map} +0 -0
  246. /package/dist/{chunk-OBJUKYDO.js.map → chunk-4XL3CVII.js.map} +0 -0
  247. /package/dist/{chunk-WWVXXSLF.js.map → chunk-5PZCDUJ6.js.map} +0 -0
  248. /package/dist/{chunk-URQLO7BX.js.map → chunk-6FNZ3NMS.js.map} +0 -0
  249. /package/dist/{chunk-DRUDC2UX.js.map → chunk-6MMONPHM.js.map} +0 -0
  250. /package/dist/{chunk-RB6A7OUN.js.map → chunk-6SXNQFHB.js.map} +0 -0
  251. /package/dist/{chunk-ZGZNLRKF.js.map → chunk-7TWA7DKP.js.map} +0 -0
  252. /package/dist/{chunk-KMNYXLPL.js.map → chunk-B35L45HZ.js.map} +0 -0
  253. /package/dist/{chunk-SIV3JZPP.js.map → chunk-CGZWGVQF.js.map} +0 -0
  254. /package/dist/{chunk-CKFLLAIS.js.map → chunk-DANV2HTH.js.map} +0 -0
  255. /package/dist/{chunk-NVYF5OB6.js.map → chunk-DBRVU5PR.js.map} +0 -0
  256. /package/dist/{chunk-LMFS64GY.js.map → chunk-E4PFDD3N.js.map} +0 -0
  257. /package/dist/{chunk-DIHCFJVV.js.map → chunk-HYI2GP3F.js.map} +0 -0
  258. /package/dist/{chunk-UIKZZ242.js.map → chunk-IKHKHADN.js.map} +0 -0
  259. /package/dist/{chunk-R2OAN6IP.js.map → chunk-K2JM4DZZ.js.map} +0 -0
  260. /package/dist/{chunk-3IJGF6K2.js.map → chunk-K2R3DEEH.js.map} +0 -0
  261. /package/dist/{chunk-HIHCB2S6.js.map → chunk-QRRBXD24.js.map} +0 -0
  262. /package/dist/{chunk-ZPZ4VVLT.js.map → chunk-SD34EK4Z.js.map} +0 -0
  263. /package/dist/{chunk-WK3NK6SP.js.map → chunk-SNEXVX3U.js.map} +0 -0
  264. /package/dist/{chunk-FVZ2ISIX.js.map → chunk-TPLE6SNY.js.map} +0 -0
  265. /package/dist/{chunk-5IN26V6W.js.map → chunk-UU32EAIY.js.map} +0 -0
  266. /package/dist/{chunk-ZGAJB74V.js.map → chunk-W3BFT5OJ.js.map} +0 -0
  267. /package/dist/{chunk-L4N7SVNN.js.map → chunk-WA7FECSG.js.map} +0 -0
  268. /package/dist/{chunk-Q3X7GUAQ.js.map → chunk-WOX2UW4K.js.map} +0 -0
  269. /package/dist/{chunk-XTEWVF3C.js.map → chunk-WWSXVOGY.js.map} +0 -0
  270. /package/dist/{chunk-P4FW3ZU5.js.map → chunk-YGGXUNS4.js.map} +0 -0
  271. /package/dist/{chunk-JHQUIH3W.js.map → chunk-ZBVQ4ZM4.js.map} +0 -0
@@ -0,0 +1,484 @@
1
+ /**
2
+ * Namespace read-fanout coordinator — extracted from the orchestrator
3
+ * (issue #1526, seam 26).
4
+ *
5
+ * Owns namespace-scoped READ fanout (never namespace RESOLUTION — the
6
+ * ScopePlan resolver from #1521 stays the single authority for that):
7
+ * - storage-dir hint loading from the catalog
8
+ * - cross-namespace search and memory/archive reads
9
+ * - scoped memory candidate search and artifact recall fanout
10
+ * - artifact source status resolution (with per-storage cache)
11
+ * - path→namespace and storage-dir→namespace mapping helpers
12
+ *
13
+ * Behavior-preserving move from orchestrator.ts (late-binding deps rule,
14
+ * seams 18–25).
15
+ */
16
+
17
+ import { existsSync, readFileSync } from "node:fs";
18
+ import { stat } from "node:fs/promises";
19
+ import path from "node:path";
20
+ import { resolveNamespaceCapabilities } from "../capabilities.js";
21
+ import { StorageManager } from "../index.js";
22
+ import { NamespaceCatalog } from "../namespaces/catalog.js";
23
+ import { namespaceIdentityFromToken, namespaceIdentityToken, normalizeNamespaceIdentity } from "../namespaces/identity.js";
24
+ import { NamespaceSearchRouter } from "../namespaces/search.js";
25
+ import { NamespaceStorageRouter } from "../namespaces/storage.js";
26
+ import { mergeArtifactRecallCandidates, tokenizeRecallQuery } from "./orchestrator-helpers.js";
27
+ import { qmdCollectionPathParts } from "./qmd-result-resolver.js";
28
+ import { resolveNamespaceFromStorageDir } from "../scopes/scope-plan.js";
29
+ import type { SearchBackend, SearchExecutionOptions, SearchQueryOptions } from "../search/port.js";
30
+ import type { MemoryFile, PluginConfig, QmdSearchResult } from "../types.js";
31
+ import {
32
+ Orchestrator,
33
+ } from "../orchestrator.js";
34
+
35
+ export interface NamespaceReadFanoutDeps {
36
+ readonly artifactSourceStatusCache: WeakMap<StorageManager, { loadedAtMs: number; statusVersion: number; statuses: Map<string, "active" | "superseded" | "archived" | "missing"> }>;
37
+ readonly config: PluginConfig;
38
+ configuredNamespaceList(): string[];
39
+ fetchActiveArtifactsForNamespace(
40
+ namespace: string,
41
+ prompt: string,
42
+ targetCount: number,
43
+ ): Promise<MemoryFile[]>;
44
+ loadNamespaceStorageDirHintsFromCatalog(): void;
45
+ readonly namespaceCatalog: NamespaceCatalog;
46
+ namespaceFromPath(p: string): string;
47
+ readonly namespaceSearchRouter: NamespaceSearchRouter;
48
+ namespaceStorageDirHintOwnershipRank(
49
+ record: { namespace: string },
50
+ resolvedStorageDir: string,
51
+ configured: Set<string>,
52
+ ): number;
53
+ readonly namespaceStorageDirHints: Map<string, Set<string>>;
54
+ namespaceStorageDirHintsLoaded: boolean;
55
+ preferNamespaceStorageDirHintOwner(
56
+ current: { namespace: string; identityToken: string; storageDir: string },
57
+ candidate: { namespace: string; identityToken: string; storageDir: string },
58
+ resolvedStorageDir: string,
59
+ configured: Set<string>,
60
+ ): { namespace: string; identityToken: string; storageDir: string };
61
+ readonly qmd: SearchBackend;
62
+ qmdCollectionNamespaceFromPrefix(collectionPrefix: string): string | null;
63
+ rememberNamespaceStorageDirHint(namespace: string, storageDir?: string): void;
64
+ storageDirMatchesNamespaceHint(namespace: string, storageDir: string): boolean;
65
+ readonly storageRouter: NamespaceStorageRouter;
66
+ }
67
+
68
+ export class NamespaceReadFanoutCoordinator {
69
+ constructor(
70
+ private readonly deps: NamespaceReadFanoutDeps,
71
+ ) {}
72
+
73
+ preferNamespaceStorageDirHintOwner(
74
+ current: { namespace: string; identityToken: string; storageDir: string },
75
+ candidate: { namespace: string; identityToken: string; storageDir: string },
76
+ resolvedStorageDir: string,
77
+ configured: Set<string>,
78
+ ): { namespace: string; identityToken: string; storageDir: string } {
79
+ const currentRank = this.deps.namespaceStorageDirHintOwnershipRank(
80
+ current,
81
+ resolvedStorageDir,
82
+ configured,
83
+ );
84
+ const candidateRank = this.deps.namespaceStorageDirHintOwnershipRank(
85
+ candidate,
86
+ resolvedStorageDir,
87
+ configured,
88
+ );
89
+ if (candidateRank < currentRank) return candidate;
90
+ if (candidateRank > currentRank) return current;
91
+
92
+ const byName = candidate.namespace.localeCompare(current.namespace);
93
+ if (byName < 0) return candidate;
94
+ if (byName > 0) return current;
95
+ return candidate.identityToken.localeCompare(current.identityToken) < 0
96
+ ? candidate
97
+ : current;
98
+ }
99
+
100
+ loadNamespaceStorageDirHintsFromCatalog(): void {
101
+ if (this.deps.namespaceStorageDirHintsLoaded || !this.deps.namespaceCatalog.enabled) return;
102
+ this.deps.namespaceStorageDirHintsLoaded = true;
103
+ const catalogPath = path.join(this.deps.config.memoryDir, "state", "namespaces.jsonl");
104
+ if (!existsSync(catalogPath)) return;
105
+
106
+ let body: string;
107
+ try {
108
+ body = readFileSync(catalogPath, "utf8");
109
+ } catch {
110
+ return;
111
+ }
112
+
113
+ const compactedByNamespace = new Map<
114
+ string,
115
+ { namespace: string; identityToken: string; storageDir: string }
116
+ >();
117
+ for (const line of body.split(/\r?\n/)) {
118
+ const trimmed = line.trim();
119
+ if (!trimmed) continue;
120
+ try {
121
+ const parsed = JSON.parse(trimmed) as unknown;
122
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
123
+ const record = parsed as Record<string, unknown>;
124
+ if (
125
+ typeof record.namespace !== "string" ||
126
+ typeof record.storageDir !== "string" ||
127
+ typeof record.identityToken !== "string"
128
+ ) {
129
+ continue;
130
+ }
131
+ const namespace = normalizeNamespaceIdentity(record.namespace);
132
+ if (!namespace || record.identityToken !== namespaceIdentityToken(namespace)) continue;
133
+ compactedByNamespace.set(namespace, {
134
+ namespace,
135
+ identityToken: record.identityToken,
136
+ storageDir: record.storageDir,
137
+ });
138
+ } catch {
139
+ // Catalog hints are best-effort. The catalog reader still owns full recovery.
140
+ }
141
+ }
142
+
143
+ const configured = new Set(
144
+ this.deps.configuredNamespaceList().map((namespace) => normalizeNamespaceIdentity(namespace)),
145
+ );
146
+ const preferredByStorageDir = new Map<
147
+ string,
148
+ { namespace: string; identityToken: string; storageDir: string }
149
+ >();
150
+ for (const record of compactedByNamespace.values()) {
151
+ if (!this.deps.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
152
+ continue;
153
+ }
154
+ const resolvedStorageDir = path.resolve(record.storageDir);
155
+ const current = preferredByStorageDir.get(resolvedStorageDir);
156
+ preferredByStorageDir.set(
157
+ resolvedStorageDir,
158
+ current
159
+ ? this.deps.preferNamespaceStorageDirHintOwner(
160
+ current,
161
+ record,
162
+ resolvedStorageDir,
163
+ configured,
164
+ )
165
+ : record,
166
+ );
167
+ }
168
+ for (const record of preferredByStorageDir.values()) {
169
+ this.deps.rememberNamespaceStorageDirHint(record.namespace, record.storageDir);
170
+ }
171
+ }
172
+
173
+ async searchAcrossNamespaces(options: {
174
+ query: string;
175
+ namespaces?: string[];
176
+ maxResults?: number;
177
+ mode?: "search" | "hybrid" | "bm25" | "vector";
178
+ searchOptions?: SearchQueryOptions;
179
+ execution?: SearchExecutionOptions;
180
+ }): Promise<QmdSearchResult[]> {
181
+ if (
182
+ resolveNamespaceCapabilities(this.deps.config).namespaces &&
183
+ options.namespaces !== undefined &&
184
+ options.namespaces.length === 0
185
+ ) {
186
+ return [];
187
+ }
188
+ const namespaces = resolveNamespaceCapabilities(this.deps.config).namespaces
189
+ ? Array.from(
190
+ new Set(
191
+ (options.namespaces?.length
192
+ ? options.namespaces
193
+ : this.deps.configuredNamespaceList()
194
+ )
195
+ .map((value) => value.trim())
196
+ .filter(Boolean),
197
+ ),
198
+ )
199
+ : [this.deps.config.defaultNamespace];
200
+
201
+ if (!resolveNamespaceCapabilities(this.deps.config).namespaces) {
202
+ switch (options.mode) {
203
+ case "hybrid":
204
+ return await this.deps.qmd.hybridSearch(
205
+ options.query,
206
+ undefined,
207
+ options.maxResults,
208
+ options.execution,
209
+ );
210
+ case "bm25":
211
+ return await this.deps.qmd.bm25Search(
212
+ options.query,
213
+ undefined,
214
+ options.maxResults,
215
+ options.execution,
216
+ );
217
+ case "vector":
218
+ return await this.deps.qmd.vectorSearch(
219
+ options.query,
220
+ undefined,
221
+ options.maxResults,
222
+ options.execution,
223
+ );
224
+ default:
225
+ return await this.deps.qmd.search(
226
+ options.query,
227
+ undefined,
228
+ options.maxResults,
229
+ options.searchOptions,
230
+ options.execution,
231
+ );
232
+ }
233
+ }
234
+
235
+ return await this.deps.namespaceSearchRouter.searchAcrossNamespaces({
236
+ query: options.query,
237
+ namespaces,
238
+ maxResults: options.maxResults,
239
+ mode: options.mode,
240
+ searchOptions: options.searchOptions,
241
+ execution: options.execution,
242
+ });
243
+ }
244
+
245
+ async resolveArtifactSourceStatuses(
246
+ storage: StorageManager,
247
+ sourceIds: string[],
248
+ ): Promise<Map<string, "active" | "superseded" | "archived" | "missing">> {
249
+ const currentStatusVersion = storage.getMemoryStatusVersion();
250
+ const cached = this.deps.artifactSourceStatusCache.get(storage);
251
+ let snapshot = cached;
252
+ const isFresh =
253
+ snapshot !== undefined &&
254
+ Date.now() - snapshot.loadedAtMs <=
255
+ Orchestrator.ARTIFACT_STATUS_CACHE_TTL_MS &&
256
+ snapshot.statusVersion === currentStatusVersion;
257
+
258
+ const rebuildSnapshot = async () => {
259
+ const MAX_STABLE_READ_ATTEMPTS = 3;
260
+ let latestStatuses = new Map<
261
+ string,
262
+ "active" | "superseded" | "archived" | "missing"
263
+ >();
264
+ let latestVersionAfter = storage.getMemoryStatusVersion();
265
+
266
+ for (let attempt = 0; attempt < MAX_STABLE_READ_ATTEMPTS; attempt += 1) {
267
+ const versionBefore = storage.getMemoryStatusVersion();
268
+ const allMemories = await storage.readAllMemories();
269
+ const versionAfter = storage.getMemoryStatusVersion();
270
+ latestVersionAfter = versionAfter;
271
+ latestStatuses = new Map(
272
+ allMemories.map((m) => [
273
+ m.frontmatter.id,
274
+ (m.frontmatter.status ?? "active") as
275
+ | "active"
276
+ | "superseded"
277
+ | "archived"
278
+ | "missing",
279
+ ]),
280
+ );
281
+
282
+ if (versionAfter === versionBefore) {
283
+ const rebuilt = {
284
+ loadedAtMs: Date.now(),
285
+ statusVersion: versionAfter,
286
+ statuses: latestStatuses,
287
+ };
288
+ this.deps.artifactSourceStatusCache.set(storage, rebuilt);
289
+ return rebuilt;
290
+ }
291
+ }
292
+
293
+ // Sustained write churn: return latest read without caching a potentially torn snapshot.
294
+ return {
295
+ loadedAtMs: Date.now(),
296
+ statusVersion: latestVersionAfter,
297
+ statuses: latestStatuses,
298
+ };
299
+ };
300
+
301
+ if (!isFresh) {
302
+ snapshot = await rebuildSnapshot();
303
+ } else {
304
+ // Warm cache may miss brand-new sourceMemoryId values created after snapshot build.
305
+ // Refresh once on-demand when unseen IDs are requested.
306
+ const hasUnknownSourceIds = sourceIds.some(
307
+ (id) => !snapshot?.statuses.has(id),
308
+ );
309
+ if (hasUnknownSourceIds) {
310
+ snapshot = await rebuildSnapshot();
311
+ }
312
+ }
313
+
314
+ // Persist negative lookups in the cached snapshot so stale source IDs do not
315
+ // trigger repeated full snapshot rebuilds on every matching recall.
316
+ for (const id of sourceIds) {
317
+ if (!snapshot?.statuses.has(id)) {
318
+ snapshot?.statuses.set(id, "missing");
319
+ }
320
+ }
321
+
322
+ const statuses = new Map<
323
+ string,
324
+ "active" | "superseded" | "archived" | "missing"
325
+ >();
326
+ for (const id of sourceIds) {
327
+ const status = snapshot?.statuses.get(id);
328
+ if (status) {
329
+ statuses.set(id, status);
330
+ } else {
331
+ statuses.set(id, "missing");
332
+ }
333
+ }
334
+ return statuses;
335
+ }
336
+
337
+ async recallArtifactsAcrossNamespaces(
338
+ prompt: string,
339
+ recallNamespaces: string[],
340
+ targetCount: number,
341
+ ): Promise<MemoryFile[]> {
342
+ if (targetCount <= 0) return [];
343
+ const namespaces = Array.from(new Set(recallNamespaces));
344
+ const filteredByNamespace = await Promise.all(
345
+ namespaces.map((namespace) =>
346
+ this.deps.fetchActiveArtifactsForNamespace(namespace, prompt, targetCount),
347
+ ),
348
+ );
349
+
350
+ return mergeArtifactRecallCandidates(filteredByNamespace, targetCount);
351
+ }
352
+
353
+ async searchScopedMemoryCandidates(
354
+ candidatePaths: Set<string>,
355
+ query: string,
356
+ limit: number,
357
+ options?: {
358
+ allowArchived?: boolean;
359
+ },
360
+ ): Promise<QmdSearchResult[]> {
361
+ const cappedLimit = Math.max(0, limit);
362
+ if (cappedLimit === 0 || candidatePaths.size === 0) return [];
363
+
364
+ const tokens = Array.from(new Set(tokenizeRecallQuery(query)));
365
+ const memories = (
366
+ await Promise.all(
367
+ Array.from(candidatePaths).map(async (memoryPath) => {
368
+ const namespace = resolveNamespaceCapabilities(this.deps.config).namespaces
369
+ ? this.deps.namespaceFromPath(memoryPath)
370
+ : this.deps.config.defaultNamespace;
371
+ const storage = await this.deps.storageRouter.storageFor(namespace);
372
+ return await storage.readMemoryByPath(memoryPath);
373
+ }),
374
+ )
375
+ ).filter((memory): memory is MemoryFile => memory !== null);
376
+
377
+ const results: QmdSearchResult[] = [];
378
+ for (const memory of memories) {
379
+ const status = memory.frontmatter.status ?? "active";
380
+ if (!options?.allowArchived && status !== "active") continue;
381
+
382
+ const haystack = [
383
+ memory.content,
384
+ memory.frontmatter.category,
385
+ ...(memory.frontmatter.tags ?? []),
386
+ ]
387
+ .join(" ")
388
+ .toLowerCase();
389
+ let hits = 0;
390
+ for (const token of tokens) {
391
+ if (haystack.includes(token)) hits += 1;
392
+ }
393
+ const score = tokens.length > 0 ? hits / tokens.length : 0.01;
394
+ if (tokens.length > 0 && hits === 0) continue;
395
+
396
+ results.push({
397
+ docid: memory.frontmatter.id,
398
+ path: memory.path,
399
+ score,
400
+ snippet: memory.content.slice(0, 400).replace(/\n/g, " "),
401
+ transport: "scoped_prefilter",
402
+ });
403
+ }
404
+
405
+ return results.sort((a, b) => b.score - a.score).slice(0, cappedLimit);
406
+ }
407
+
408
+ async resolveStateDirForNamespace(
409
+ namespace: string,
410
+ ): Promise<string> {
411
+ if (!resolveNamespaceCapabilities(this.deps.config).namespaces) {
412
+ return path.join(this.deps.config.memoryDir, "state");
413
+ }
414
+ if (namespace !== this.deps.config.defaultNamespace) {
415
+ return path.join(this.deps.config.memoryDir, "namespaces", namespace, "state");
416
+ }
417
+ const candidate = path.join(
418
+ this.deps.config.memoryDir,
419
+ "namespaces",
420
+ this.deps.config.defaultNamespace,
421
+ );
422
+ try {
423
+ const candidateStat = await stat(candidate);
424
+ if (candidateStat.isDirectory()) {
425
+ return path.join(candidate, "state");
426
+ }
427
+ } catch {
428
+ // Fall back to the legacy root when the migrated default namespace directory is absent.
429
+ }
430
+ return path.join(this.deps.config.memoryDir, "state");
431
+ }
432
+
433
+ namespaceFromPath(p: string): string {
434
+ if (!resolveNamespaceCapabilities(this.deps.config).namespaces) return this.deps.config.defaultNamespace;
435
+ const parts = qmdCollectionPathParts(p);
436
+ const collectionNamespace = parts
437
+ ? this.deps.qmdCollectionNamespaceFromPrefix(parts.collection)
438
+ : null;
439
+ if (collectionNamespace) return collectionNamespace;
440
+ const m = p.match(/[\\/]+namespaces[\\/]+([^\\/]+)(?:[\\/]|$)/);
441
+ if (!m?.[1]) return this.deps.config.defaultNamespace;
442
+ return namespaceIdentityFromToken(m[1]) ?? m[1];
443
+ }
444
+
445
+ storageDirNamespace(storageDir: string): string {
446
+ // #1521: delegates to the scope-module resolver. The inline dir→namespace
447
+ // derivation (token round-trip guard, catalog hints) is retired so the
448
+ // adHocNamespaceResolutions ratchet no longer counts this site. Hints are
449
+ // loaded lazily via the callback (only after early returns, matching the
450
+ // original behavior — codex P2).
451
+ return resolveNamespaceFromStorageDir(storageDir, {
452
+ config: this.deps.config,
453
+ configuredNamespaces: this.deps.configuredNamespaceList(),
454
+ hints: this.deps.namespaceStorageDirHints,
455
+ loadHints: () => this.deps.loadNamespaceStorageDirHintsFromCatalog(),
456
+ });
457
+ }
458
+
459
+ async readAllMemoriesForNamespaces(
460
+ namespaces: string[],
461
+ ): Promise<MemoryFile[]> {
462
+ const uniq = Array.from(new Set(namespaces.filter(Boolean)));
463
+ const lists = await Promise.all(
464
+ uniq.map(async (ns) => {
465
+ const sm = await this.deps.storageRouter.storageFor(ns);
466
+ return sm.readAllMemories();
467
+ }),
468
+ );
469
+ return lists.flat();
470
+ }
471
+
472
+ async readArchivedMemoriesForNamespaces(
473
+ namespaces: string[],
474
+ ): Promise<MemoryFile[]> {
475
+ const uniq = Array.from(new Set(namespaces.filter(Boolean)));
476
+ const lists = await Promise.all(
477
+ uniq.map(async (ns) => {
478
+ const sm = await this.deps.storageRouter.storageFor(ns);
479
+ return sm.readArchivedMemories();
480
+ }),
481
+ );
482
+ return lists.flat();
483
+ }
484
+ }