@remnic/core 9.3.732 → 9.3.734

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 (294) hide show
  1. package/dist/access-boundary.d.ts +10 -10
  2. package/dist/access-boundary.js +9 -9
  3. package/dist/access-cli.js +25 -23
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +10 -10
  6. package/dist/access-http.js +14 -14
  7. package/dist/access-mcp.d.ts +10 -10
  8. package/dist/access-mcp.js +13 -13
  9. package/dist/access-operations-batch.js +11 -11
  10. package/dist/access-operations.d.ts +10 -10
  11. package/dist/access-operations.js +12 -12
  12. package/dist/{access-service-Byoe3HsT.d.ts → access-service-rjFfmfKB.d.ts} +4 -4
  13. package/dist/access-service.d.ts +10 -10
  14. package/dist/access-service.js +8 -8
  15. package/dist/access-surface-catalog.d.ts +10 -10
  16. package/dist/action-confidence.d.ts +1 -1
  17. package/dist/active-memory-bridge.d.ts +1 -1
  18. package/dist/active-memory-bridge.js +3 -2
  19. package/dist/active-recall.d.ts +1 -1
  20. package/dist/behavior-learner.d.ts +1 -1
  21. package/dist/behavior-signals.d.ts +1 -1
  22. package/dist/bootstrap.d.ts +9 -9
  23. package/dist/briefing.d.ts +1 -1
  24. package/dist/buffer-surprise-report.d.ts +1 -1
  25. package/dist/buffer.d.ts +1 -1
  26. package/dist/calibration.d.ts +1 -1
  27. package/dist/capabilities.d.ts +97 -2
  28. package/dist/capabilities.js +11 -3
  29. package/dist/{catalog-DM1nk7cM.d.ts → catalog-DHYXzM4-.d.ts} +2 -2
  30. package/dist/causal-behavior.d.ts +1 -1
  31. package/dist/causal-consolidation.d.ts +1 -1
  32. package/dist/causal-trajectory-graph.d.ts +1 -1
  33. package/dist/{chunk-24D66MMN.js → chunk-2L5RTVMO.js} +7 -4
  34. package/dist/chunk-2L5RTVMO.js.map +1 -0
  35. package/dist/{chunk-KQYGNGON.js → chunk-3QETM5NG.js} +6 -3
  36. package/dist/chunk-3QETM5NG.js.map +1 -0
  37. package/dist/{chunk-ZQUAVZNG.js → chunk-54RCE5Z3.js} +7 -4
  38. package/dist/chunk-54RCE5Z3.js.map +1 -0
  39. package/dist/{chunk-NOU77OHX.js → chunk-5DIKZKOD.js} +2 -2
  40. package/dist/{chunk-CGPHMNL4.js → chunk-5OYHJIJN.js} +10 -6
  41. package/dist/chunk-5OYHJIJN.js.map +1 -0
  42. package/dist/{chunk-LUCARK4W.js → chunk-6U7TES2M.js} +29 -28
  43. package/dist/chunk-6U7TES2M.js.map +1 -0
  44. package/dist/{chunk-FFUCCKPN.js → chunk-7FPJFCXL.js} +10 -7
  45. package/dist/chunk-7FPJFCXL.js.map +1 -0
  46. package/dist/{chunk-PMAQRUN4.js → chunk-CILX2XW7.js} +5 -2
  47. package/dist/chunk-CILX2XW7.js.map +1 -0
  48. package/dist/{chunk-ZVHRSR2R.js → chunk-ET5HXSQL.js} +6 -3
  49. package/dist/chunk-ET5HXSQL.js.map +1 -0
  50. package/dist/{chunk-KSJCXXOU.js → chunk-FAGERSH2.js} +6 -3
  51. package/dist/chunk-FAGERSH2.js.map +1 -0
  52. package/dist/{chunk-FYWUNVFZ.js → chunk-IDIXGGDN.js} +6 -6
  53. package/dist/{chunk-CX77GNMB.js → chunk-IWMGBNXY.js} +6 -3
  54. package/dist/chunk-IWMGBNXY.js.map +1 -0
  55. package/dist/{chunk-GGL34GCW.js → chunk-IZLTOS5L.js} +7 -4
  56. package/dist/chunk-IZLTOS5L.js.map +1 -0
  57. package/dist/{chunk-HHNSLPX7.js → chunk-K7PAILHO.js} +10 -9
  58. package/dist/chunk-K7PAILHO.js.map +1 -0
  59. package/dist/{chunk-UZYLX7M6.js → chunk-LV32K4OP.js} +9 -6
  60. package/dist/chunk-LV32K4OP.js.map +1 -0
  61. package/dist/{chunk-HJWQJUKQ.js → chunk-NDYQIN6C.js} +3 -3
  62. package/dist/{chunk-DKT3X5C3.js → chunk-PEF2XOIV.js} +7 -4
  63. package/dist/chunk-PEF2XOIV.js.map +1 -0
  64. package/dist/{chunk-646B5ERJ.js → chunk-PKO5NJ65.js} +51 -48
  65. package/dist/chunk-PKO5NJ65.js.map +1 -0
  66. package/dist/{chunk-QZHF4BWN.js → chunk-Q5LGXWNG.js} +6 -6
  67. package/dist/{chunk-ESF7TRYJ.js → chunk-SHJGBAIW.js} +37 -2
  68. package/dist/{chunk-ESF7TRYJ.js.map → chunk-SHJGBAIW.js.map} +1 -1
  69. package/dist/{chunk-O4ZIBPIW.js → chunk-T7CGPTFU.js} +3 -3
  70. package/dist/{chunk-PLBIPT6I.js → chunk-TJSQHO4Q.js} +7 -4
  71. package/dist/chunk-TJSQHO4Q.js.map +1 -0
  72. package/dist/{chunk-6TUWSUUD.js → chunk-UF3N7IRP.js} +26 -24
  73. package/dist/chunk-UF3N7IRP.js.map +1 -0
  74. package/dist/{chunk-P3VJCTVE.js → chunk-UH3NYOHN.js} +4 -3
  75. package/dist/chunk-UH3NYOHN.js.map +1 -0
  76. package/dist/{chunk-J6BH2OBA.js → chunk-UK6U5C3N.js} +8 -5
  77. package/dist/chunk-UK6U5C3N.js.map +1 -0
  78. package/dist/{chunk-OTQE66IX.js → chunk-V5OVSGB6.js} +6 -3
  79. package/dist/chunk-V5OVSGB6.js.map +1 -0
  80. package/dist/{chunk-H3MB3F62.js → chunk-WHQ2JB35.js} +4 -3
  81. package/dist/chunk-WHQ2JB35.js.map +1 -0
  82. package/dist/{chunk-NIZQH6AU.js → chunk-WTTVFSCO.js} +8 -7
  83. package/dist/chunk-WTTVFSCO.js.map +1 -0
  84. package/dist/{chunk-OUITHS6V.js → chunk-Z7J3OAPR.js} +357 -325
  85. package/dist/chunk-Z7J3OAPR.js.map +1 -0
  86. package/dist/{cli-Dt-tuiYH.d.ts → cli-XVpmSoQs.d.ts} +3 -3
  87. package/dist/cli.d.ts +11 -11
  88. package/dist/cli.js +20 -20
  89. package/dist/compounding/engine.d.ts +3 -2
  90. package/dist/compounding/engine.js +2 -1
  91. package/dist/compounding/preference-consolidator.d.ts +1 -1
  92. package/dist/compression-optimizer.d.ts +1 -1
  93. package/dist/config.d.ts +1 -1
  94. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  95. package/dist/connectors/codex-materialize.d.ts +1 -1
  96. package/dist/connectors/index.d.ts +1 -1
  97. package/dist/consolidation-provenance-check.d.ts +1 -1
  98. package/dist/consolidation-undo.d.ts +1 -1
  99. package/dist/contradiction/index.d.ts +2 -2
  100. package/dist/contradiction/index.js +2 -1
  101. package/dist/{contradiction-scan-HWGEOUDS.js → contradiction-scan-OUHMCUBT.js} +3 -2
  102. package/dist/conversation-index/backend.d.ts +1 -1
  103. package/dist/conversation-index/chunker.d.ts +1 -1
  104. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  105. package/dist/conversation-index/indexer.d.ts +1 -1
  106. package/dist/conversation-index/search.d.ts +1 -1
  107. package/dist/day-summary.d.ts +1 -1
  108. package/dist/delinearize.d.ts +1 -1
  109. package/dist/direct-answer-wiring.d.ts +1 -1
  110. package/dist/direct-answer.d.ts +1 -1
  111. package/dist/embedding-fallback.d.ts +1 -1
  112. package/dist/embedding-fallback.js +2 -2
  113. package/dist/enrichment/index.d.ts +1 -1
  114. package/dist/entity-retrieval.d.ts +1 -1
  115. package/dist/entity-retrieval.js +2 -1
  116. package/dist/entity-schema.d.ts +1 -1
  117. package/dist/explicit-capture.d.ts +9 -9
  118. package/dist/explicit-capture.js +2 -1
  119. package/dist/extraction-faithfulness.d.ts +1 -1
  120. package/dist/extraction-judge-telemetry.d.ts +1 -1
  121. package/dist/extraction-judge-training.d.ts +1 -1
  122. package/dist/extraction-judge.d.ts +1 -1
  123. package/dist/extraction.d.ts +1 -1
  124. package/dist/extraction.js +3 -3
  125. package/dist/fallback-llm.d.ts +1 -1
  126. package/dist/{first-start-migration-OOR57AYR.js → first-start-migration-W4U6XDKI.js} +7 -6
  127. package/dist/first-start-migration-W4U6XDKI.js.map +1 -0
  128. package/dist/graph-dashboard-diff.d.ts +1 -1
  129. package/dist/graph-dashboard-key.d.ts +1 -1
  130. package/dist/graph-dashboard-parser.d.ts +1 -1
  131. package/dist/graph-edge-reinforcement.d.ts +1 -1
  132. package/dist/graph-snapshot.d.ts +1 -1
  133. package/dist/graph.d.ts +1 -1
  134. package/dist/identity-continuity.d.ts +1 -1
  135. package/dist/importance.d.ts +1 -1
  136. package/dist/index.d.ts +12 -12
  137. package/dist/index.js +43 -43
  138. package/dist/intent.d.ts +1 -1
  139. package/dist/lcm/engine.d.ts +1 -1
  140. package/dist/lcm/index.d.ts +1 -1
  141. package/dist/lcm/tools.d.ts +1 -1
  142. package/dist/lifecycle.d.ts +1 -1
  143. package/dist/live-connectors-runner.d.ts +1 -1
  144. package/dist/local-llm.d.ts +1 -1
  145. package/dist/local-llm.js +2 -1
  146. package/dist/local-model-endpoint.d.ts +1 -1
  147. package/dist/maintenance/memory-governance.d.ts +1 -1
  148. package/dist/mcp-memory-inspector-app.d.ts +10 -10
  149. package/dist/memory-action-policy.d.ts +1 -1
  150. package/dist/memory-cache.d.ts +1 -1
  151. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  152. package/dist/memory-projection-store.d.ts +1 -1
  153. package/dist/memory-provenance.d.ts +1 -1
  154. package/dist/memory-worth-outcomes.d.ts +1 -1
  155. package/dist/models-json.d.ts +1 -1
  156. package/dist/namespaces/migrate.d.ts +2 -2
  157. package/dist/namespaces/migrate.js +6 -6
  158. package/dist/namespaces/principal.d.ts +1 -1
  159. package/dist/namespaces/principal.js +2 -1
  160. package/dist/namespaces/search.d.ts +1 -1
  161. package/dist/namespaces/search.js +4 -4
  162. package/dist/namespaces/storage.d.ts +2 -2
  163. package/dist/namespaces/storage.js +2 -1
  164. package/dist/native-knowledge.d.ts +1 -1
  165. package/dist/operator-toolkit.d.ts +1 -1
  166. package/dist/operator-toolkit.js +11 -11
  167. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  168. package/dist/orchestration/maintenance.d.ts +2 -2
  169. package/dist/orchestration/maintenance.js +6 -5
  170. package/dist/{orchestrator-B4KjaOtY.d.ts → orchestrator-BXi-gadS.d.ts} +66 -5
  171. package/dist/orchestrator.d.ts +5 -5
  172. package/dist/orchestrator.js +20 -18
  173. package/dist/patterns-cli.d.ts +1 -1
  174. package/dist/policy-runtime.d.ts +1 -1
  175. package/dist/provenance.d.ts +1 -1
  176. package/dist/qmd-recall-cache.d.ts +1 -1
  177. package/dist/qmd.d.ts +1 -1
  178. package/dist/recall-disclosure-escalation.d.ts +1 -1
  179. package/dist/recall-explain-renderer.d.ts +1 -1
  180. package/dist/recall-planner-llm.d.ts +1 -1
  181. package/dist/recall-state.d.ts +1 -1
  182. package/dist/recall-tag-filter.d.ts +1 -1
  183. package/dist/recall-xray-cli.d.ts +1 -1
  184. package/dist/recall-xray-renderer.d.ts +1 -1
  185. package/dist/recall-xray.d.ts +1 -1
  186. package/dist/resolve-auth-token.d.ts +1 -1
  187. package/dist/retrieval-agents.d.ts +1 -1
  188. package/dist/retrieval-tiers.d.ts +1 -1
  189. package/dist/routing/engine.d.ts +1 -1
  190. package/dist/routing/store.d.ts +1 -1
  191. package/dist/schemas.d.ts +22 -22
  192. package/dist/search/embed-helper.d.ts +1 -1
  193. package/dist/search/embed-helper.js +2 -2
  194. package/dist/search/factory.d.ts +1 -1
  195. package/dist/search/factory.js +3 -3
  196. package/dist/search/index.d.ts +1 -1
  197. package/dist/search/index.js +3 -3
  198. package/dist/search/lancedb-backend.d.ts +1 -1
  199. package/dist/search/meilisearch-backend.d.ts +1 -1
  200. package/dist/search/noop-backend.d.ts +1 -1
  201. package/dist/search/orama-backend.d.ts +1 -1
  202. package/dist/search/port.d.ts +1 -1
  203. package/dist/search/remote-backend.d.ts +1 -1
  204. package/dist/{semantic-SLAa_prH.d.ts → semantic-DJR8_DMQ.d.ts} +1 -1
  205. package/dist/{semantic-consolidation-CstTvHPo.d.ts → semantic-consolidation-DeL5grLx.d.ts} +1 -1
  206. package/dist/semantic-consolidation.d.ts +2 -2
  207. package/dist/semantic-rule-verifier.d.ts +1 -1
  208. package/dist/session-observer-bands.d.ts +1 -1
  209. package/dist/session-observer-state.d.ts +1 -1
  210. package/dist/shared-context/manager.d.ts +1 -1
  211. package/dist/signal.d.ts +1 -1
  212. package/dist/storage.d.ts +1 -1
  213. package/dist/summarizer.d.ts +1 -1
  214. package/dist/summarizer.js +3 -2
  215. package/dist/summary-snapshot.d.ts +1 -1
  216. package/dist/temporal-supersession.d.ts +1 -1
  217. package/dist/temporal-validity.d.ts +1 -1
  218. package/dist/threading.d.ts +1 -1
  219. package/dist/tier-migration.d.ts +1 -1
  220. package/dist/tier-routing.d.ts +1 -1
  221. package/dist/{tier-stats-3LYQ3VV5.js → tier-stats-LSM35HZY.js} +5 -2
  222. package/dist/tier-stats-LSM35HZY.js.map +1 -0
  223. package/dist/topics.d.ts +1 -1
  224. package/dist/transcript.d.ts +1 -1
  225. package/dist/transfer/types.d.ts +12 -12
  226. package/dist/trust-score-stage.d.ts +1 -1
  227. package/dist/trust-score.d.ts +1 -1
  228. package/dist/{types-VkxElCHR.d.ts → types-CpFz51Pv.d.ts} +1 -1
  229. package/dist/types.d.ts +1 -1
  230. package/dist/utility-runtime.d.ts +1 -1
  231. package/package.json +2 -2
  232. package/src/access-service.ts +42 -37
  233. package/src/active-memory-bridge.ts +2 -1
  234. package/src/admin/admin-surfaces.ts +2 -1
  235. package/src/capabilities.test.ts +178 -0
  236. package/src/capabilities.ts +197 -0
  237. package/src/cli.ts +13 -9
  238. package/src/compounding/engine.ts +4 -3
  239. package/src/contradiction/contradiction-scan.ts +4 -3
  240. package/src/embedding-fallback.ts +5 -2
  241. package/src/entity-retrieval.ts +3 -2
  242. package/src/explicit-capture.ts +2 -1
  243. package/src/extraction.ts +6 -3
  244. package/src/local-llm.ts +4 -3
  245. package/src/maintenance/first-start-migration.ts +6 -3
  246. package/src/maintenance/namespace-maintenance-fanout.ts +2 -1
  247. package/src/maintenance/namespace-planner.ts +4 -3
  248. package/src/maintenance/tier-stats.ts +2 -1
  249. package/src/namespaces/catalog.ts +2 -1
  250. package/src/namespaces/migrate.ts +2 -1
  251. package/src/namespaces/principal.ts +6 -5
  252. package/src/namespaces/scope-profiles.ts +2 -1
  253. package/src/namespaces/search.ts +2 -1
  254. package/src/namespaces/storage.ts +4 -3
  255. package/src/operator-toolkit.ts +19 -18
  256. package/src/orchestration/maintenance.ts +8 -4
  257. package/src/orchestration/semantic-consolidation-coordinator.ts +454 -0
  258. package/src/orchestration/tier-migration-coordinator.ts +5 -4
  259. package/src/orchestrator.ts +78 -417
  260. package/src/scopes/scope-plan.ts +3 -2
  261. package/src/search/embed-helper.ts +5 -2
  262. package/src/search/factory.ts +9 -6
  263. package/src/summarizer.ts +3 -2
  264. package/dist/chunk-24D66MMN.js.map +0 -1
  265. package/dist/chunk-646B5ERJ.js.map +0 -1
  266. package/dist/chunk-6TUWSUUD.js.map +0 -1
  267. package/dist/chunk-CGPHMNL4.js.map +0 -1
  268. package/dist/chunk-CX77GNMB.js.map +0 -1
  269. package/dist/chunk-DKT3X5C3.js.map +0 -1
  270. package/dist/chunk-FFUCCKPN.js.map +0 -1
  271. package/dist/chunk-GGL34GCW.js.map +0 -1
  272. package/dist/chunk-H3MB3F62.js.map +0 -1
  273. package/dist/chunk-HHNSLPX7.js.map +0 -1
  274. package/dist/chunk-J6BH2OBA.js.map +0 -1
  275. package/dist/chunk-KQYGNGON.js.map +0 -1
  276. package/dist/chunk-KSJCXXOU.js.map +0 -1
  277. package/dist/chunk-LUCARK4W.js.map +0 -1
  278. package/dist/chunk-NIZQH6AU.js.map +0 -1
  279. package/dist/chunk-OTQE66IX.js.map +0 -1
  280. package/dist/chunk-OUITHS6V.js.map +0 -1
  281. package/dist/chunk-P3VJCTVE.js.map +0 -1
  282. package/dist/chunk-PLBIPT6I.js.map +0 -1
  283. package/dist/chunk-PMAQRUN4.js.map +0 -1
  284. package/dist/chunk-UZYLX7M6.js.map +0 -1
  285. package/dist/chunk-ZQUAVZNG.js.map +0 -1
  286. package/dist/chunk-ZVHRSR2R.js.map +0 -1
  287. package/dist/first-start-migration-OOR57AYR.js.map +0 -1
  288. package/dist/tier-stats-3LYQ3VV5.js.map +0 -1
  289. /package/dist/{chunk-NOU77OHX.js.map → chunk-5DIKZKOD.js.map} +0 -0
  290. /package/dist/{chunk-FYWUNVFZ.js.map → chunk-IDIXGGDN.js.map} +0 -0
  291. /package/dist/{chunk-HJWQJUKQ.js.map → chunk-NDYQIN6C.js.map} +0 -0
  292. /package/dist/{chunk-QZHF4BWN.js.map → chunk-Q5LGXWNG.js.map} +0 -0
  293. /package/dist/{chunk-O4ZIBPIW.js.map → chunk-T7CGPTFU.js.map} +0 -0
  294. /package/dist/{contradiction-scan-HWGEOUDS.js.map → contradiction-scan-OUHMCUBT.js.map} +0 -0
@@ -5,7 +5,12 @@ import { readdirSync, unlinkSync } from "node:fs";
5
5
  import { createHash } from "node:crypto";
6
6
  import { ZodError } from "zod";
7
7
  import { AccessIdempotencyStore, hashAccessIdempotencyPayload } from "./access-idempotency.js";
8
- import { resolveMemoryLifecycleCapabilities } from "./capabilities.js";
8
+ import {
9
+ resolveNamespaceCapabilities,
10
+ resolveMemoryLifecycleCapabilities,
11
+ resolveQmdCapabilities,
12
+ resolveIdentityContinuityCapabilities,
13
+ } from "./capabilities.js";
9
14
  import { AccessAuditAdapter, type AccessAuditConfig, type AccessAuditResult } from "./access-audit.js";
10
15
  import type { AnomalyDetectorResult } from "./recall-audit-anomaly.js";
11
16
  import { resolveGitContext } from "./coding/git-context.js";
@@ -1339,7 +1344,7 @@ export class EngramAccessService {
1339
1344
  private resolveNamespace(namespace?: string): string {
1340
1345
  const requested = namespace?.trim();
1341
1346
  if (!requested) return this.orchestrator.config.defaultNamespace;
1342
- if (!this.orchestrator.config.namespacesEnabled && requested !== this.orchestrator.config.defaultNamespace) {
1347
+ if (!resolveNamespaceCapabilities(this.orchestrator.config).namespaces && requested !== this.orchestrator.config.defaultNamespace) {
1343
1348
  throw new EngramAccessInputError(`unsupported namespace: ${requested}`);
1344
1349
  }
1345
1350
  return requested;
@@ -1458,14 +1463,14 @@ export class EngramAccessService {
1458
1463
  typeof request.sessionKey === "string" && request.sessionKey.length > 0;
1459
1464
  const codingContext =
1460
1465
  hasSession &&
1461
- this.orchestrator.config.namespacesEnabled &&
1466
+ resolveNamespaceCapabilities(this.orchestrator.config).namespaces &&
1462
1467
  this.orchestrator.config.codingMode?.projectScope
1463
1468
  ? this.orchestrator.getCodingContextForSession(request.sessionKey) ??
1464
1469
  (await this.resolveCodingContextFromOptions(request))
1465
1470
  : null;
1466
1471
  const overlay =
1467
1472
  hasSession &&
1468
- this.orchestrator.config.namespacesEnabled &&
1473
+ resolveNamespaceCapabilities(this.orchestrator.config).namespaces &&
1469
1474
  this.orchestrator.config.codingMode?.projectScope
1470
1475
  ? resolveCodingNamespaceOverlay(
1471
1476
  codingContext,
@@ -1686,7 +1691,7 @@ export class EngramAccessService {
1686
1691
  typeof request.sessionKey === "string" && request.sessionKey.length > 0;
1687
1692
  const overlayEligible =
1688
1693
  hasSession &&
1689
- this.orchestrator.config.namespacesEnabled === true &&
1694
+ resolveNamespaceCapabilities(this.orchestrator.config).namespaces === true &&
1690
1695
  this.orchestrator.config.codingMode?.projectScope === true;
1691
1696
 
1692
1697
  // Resolve the coding context the overlay must use: the session's ATTACHED
@@ -1822,7 +1827,7 @@ export class EngramAccessService {
1822
1827
  this.orchestrator.config.objectiveStateSnapshotWritesEnabled === true;
1823
1828
  if (
1824
1829
  willWriteObjectiveState &&
1825
- this.orchestrator.config.namespacesEnabled === true &&
1830
+ resolveNamespaceCapabilities(this.orchestrator.config).namespaces === true &&
1826
1831
  !canWriteNamespace(principal, baseNamespace, this.orchestrator.config)
1827
1832
  ) {
1828
1833
  clearSeededContext();
@@ -1897,7 +1902,7 @@ export class EngramAccessService {
1897
1902
  memoryDir: string;
1898
1903
  objectiveStateStoreDir?: string;
1899
1904
  }> {
1900
- if (!this.orchestrator.config.namespacesEnabled) {
1905
+ if (!resolveNamespaceCapabilities(this.orchestrator.config).namespaces) {
1901
1906
  return {
1902
1907
  memoryDir: this.orchestrator.config.memoryDir,
1903
1908
  objectiveStateStoreDir: this.orchestrator.config.objectiveStateStoreDir,
@@ -1909,7 +1914,7 @@ export class EngramAccessService {
1909
1914
  objectiveStateStoreDir: objectiveStateStoreOverrideForNamespace({
1910
1915
  memoryDir: this.orchestrator.config.memoryDir,
1911
1916
  configuredStoreDir: this.orchestrator.config.objectiveStateStoreDir,
1912
- namespacesEnabled: this.orchestrator.config.namespacesEnabled,
1917
+ namespacesEnabled: resolveNamespaceCapabilities(this.orchestrator.config).namespaces,
1913
1918
  namespace,
1914
1919
  }),
1915
1920
  };
@@ -1917,7 +1922,7 @@ export class EngramAccessService {
1917
1922
 
1918
1923
  private resolveReadableNamespace(namespace: string | undefined, principal?: string): string {
1919
1924
  const resolved = this.resolveNamespace(namespace);
1920
- const namespacesEnabled = this.orchestrator.config.namespacesEnabled;
1925
+ const namespacesEnabled = resolveNamespaceCapabilities(this.orchestrator.config).namespaces;
1921
1926
 
1922
1927
  if (!namespacesEnabled) {
1923
1928
  // Namespaces are disabled globally — no ACL needed for any caller.
@@ -1946,7 +1951,7 @@ export class EngramAccessService {
1946
1951
  return [this.resolveReadableNamespace(requested, principal)];
1947
1952
  }
1948
1953
 
1949
- if (!this.orchestrator.config.namespacesEnabled) {
1954
+ if (!resolveNamespaceCapabilities(this.orchestrator.config).namespaces) {
1950
1955
  return [this.resolveNamespace(undefined)];
1951
1956
  }
1952
1957
 
@@ -1998,7 +2003,7 @@ export class EngramAccessService {
1998
2003
  namespaces: string[],
1999
2004
  collectionPrincipal?: string,
2000
2005
  ): string[] {
2001
- if (!this.orchestrator.config.namespacesEnabled) {
2006
+ if (!resolveNamespaceCapabilities(this.orchestrator.config).namespaces) {
2002
2007
  return namespaces;
2003
2008
  }
2004
2009
 
@@ -2702,7 +2707,7 @@ export class EngramAccessService {
2702
2707
  const resolvedNamespace = this.resolveNamespace(namespace);
2703
2708
  const storage = await this.orchestrator.getStorage(resolvedNamespace);
2704
2709
  const searchBackend = this.orchestrator.config.searchBackend ?? "qmd";
2705
- const qmdEnabled = this.orchestrator.config.qmdEnabled === true;
2710
+ const qmdEnabled = resolveQmdCapabilities(this.orchestrator.config).qmd === true;
2706
2711
  let projectionAvailable = false;
2707
2712
  try {
2708
2713
  await stat(getMemoryProjectionPath(storage.dir));
@@ -2714,7 +2719,7 @@ export class EngramAccessService {
2714
2719
  return {
2715
2720
  ok: true,
2716
2721
  memoryDir: storage.dir,
2717
- namespacesEnabled: this.orchestrator.config.namespacesEnabled === true,
2722
+ namespacesEnabled: resolveNamespaceCapabilities(this.orchestrator.config).namespaces === true,
2718
2723
  defaultNamespace: this.orchestrator.config.defaultNamespace,
2719
2724
  searchBackend,
2720
2725
  qmdEnabled,
@@ -2730,7 +2735,7 @@ export class EngramAccessService {
2730
2735
  }
2731
2736
 
2732
2737
  private qmdCollectionForHealth(namespace: string, storageDir: string): string {
2733
- if (this.orchestrator.config.namespacesEnabled !== true) {
2738
+ if (resolveNamespaceCapabilities(this.orchestrator.config).namespaces !== true) {
2734
2739
  return this.orchestrator.config.qmdCollection;
2735
2740
  }
2736
2741
 
@@ -2766,7 +2771,7 @@ export class EngramAccessService {
2766
2771
  };
2767
2772
  }
2768
2773
 
2769
- if (this.orchestrator.config.namespacesEnabled === true) {
2774
+ if (resolveNamespaceCapabilities(this.orchestrator.config).namespaces === true) {
2770
2775
  const namespaceHealth = await this.namespaceQmdHealth(searchBackend, qmdEnabled, namespace, collection);
2771
2776
  if (namespaceHealth) return namespaceHealth;
2772
2777
  }
@@ -3224,7 +3229,7 @@ export class EngramAccessService {
3224
3229
  const normalizedRequest = { ...request, query };
3225
3230
  const authenticatedPrincipal = request.authenticatedPrincipal?.trim();
3226
3231
  const principal = this.resolveRequestPrincipal(request.sessionKey, authenticatedPrincipal);
3227
- if (this.orchestrator.config.namespacesEnabled && !principal) {
3232
+ if (resolveNamespaceCapabilities(this.orchestrator.config).namespaces && !principal) {
3228
3233
  throw new EngramAccessInputError(
3229
3234
  "authentication required: namespaces are enabled and no principal was supplied",
3230
3235
  );
@@ -3307,7 +3312,7 @@ export class EngramAccessService {
3307
3312
  // accounting (Codex P1: budget recorded before mode validation).
3308
3313
  const mode = this.normalizeRecallMode(request.mode);
3309
3314
  const maybePrincipal = this.resolveRequestPrincipal(request.sessionKey, authenticatedPrincipal);
3310
- if (this.orchestrator.config.namespacesEnabled && !maybePrincipal) {
3315
+ if (resolveNamespaceCapabilities(this.orchestrator.config).namespaces && !maybePrincipal) {
3311
3316
  throw new EngramAccessInputError(
3312
3317
  "authentication required: namespaces are enabled and no principal was supplied",
3313
3318
  );
@@ -3321,7 +3326,7 @@ export class EngramAccessService {
3321
3326
  const profileCodingOverlay =
3322
3327
  !namespaceOverride &&
3323
3328
  profileCodingContext &&
3324
- this.orchestrator.config.namespacesEnabled &&
3329
+ resolveNamespaceCapabilities(this.orchestrator.config).namespaces &&
3325
3330
  this.orchestrator.config.codingMode?.projectScope
3326
3331
  ? resolveCodingNamespaceOverlay(
3327
3332
  profileCodingContext,
@@ -3725,7 +3730,7 @@ export class EngramAccessService {
3725
3730
  return { found: false };
3726
3731
  }
3727
3732
  } else if (
3728
- this.orchestrator.config.namespacesEnabled
3733
+ resolveNamespaceCapabilities(this.orchestrator.config).namespaces
3729
3734
  && !principal
3730
3735
  ) {
3731
3736
  return { found: false };
@@ -3744,7 +3749,7 @@ export class EngramAccessService {
3744
3749
  return candidate.namespace === requestedNamespace ? candidate : null;
3745
3750
  })();
3746
3751
  const readableSnapshot = (() => {
3747
- if (!snapshot || !this.orchestrator.config.namespacesEnabled) return snapshot;
3752
+ if (!snapshot || !resolveNamespaceCapabilities(this.orchestrator.config).namespaces) return snapshot;
3748
3753
  const snapshotNamespace = snapshot.namespace ?? this.orchestrator.config.defaultNamespace;
3749
3754
  return canReadNamespace(principal, snapshotNamespace, this.orchestrator.config)
3750
3755
  ? snapshot
@@ -3754,7 +3759,7 @@ export class EngramAccessService {
3754
3759
  if (requestedNamespace) return requestedNamespace;
3755
3760
  if (readableSnapshot?.namespace) return readableSnapshot.namespace;
3756
3761
  const fallbackNamespace = this.orchestrator.config.defaultNamespace;
3757
- if (!this.orchestrator.config.namespacesEnabled) return fallbackNamespace;
3762
+ if (!resolveNamespaceCapabilities(this.orchestrator.config).namespaces) return fallbackNamespace;
3758
3763
  return canReadNamespace(principal, fallbackNamespace, this.orchestrator.config)
3759
3764
  ? fallbackNamespace
3760
3765
  : null;
@@ -3773,7 +3778,7 @@ export class EngramAccessService {
3773
3778
  namespace?: string,
3774
3779
  authenticatedPrincipal?: string,
3775
3780
  ) {
3776
- const namespacesEnabled = this.orchestrator.config.namespacesEnabled;
3781
+ const namespacesEnabled = resolveNamespaceCapabilities(this.orchestrator.config).namespaces;
3777
3782
  const requestedNamespace = namespace?.trim()
3778
3783
  ? this.resolveNamespace(namespace)
3779
3784
  : undefined;
@@ -3882,7 +3887,7 @@ export class EngramAccessService {
3882
3887
  );
3883
3888
  }
3884
3889
 
3885
- const namespacesEnabled = this.orchestrator.config.namespacesEnabled;
3890
+ const namespacesEnabled = resolveNamespaceCapabilities(this.orchestrator.config).namespaces;
3886
3891
  const requestedNamespace = request.namespace?.trim()
3887
3892
  ? this.resolveNamespace(request.namespace)
3888
3893
  : undefined;
@@ -5983,7 +5988,7 @@ export class EngramAccessService {
5983
5988
  // namespace to one store, so leaving the override undefined preserves the
5984
5989
  // existing single-store routing byte-for-byte.
5985
5990
  const writeNamespaceOverride =
5986
- this.orchestrator.config.namespacesEnabled === true
5991
+ resolveNamespaceCapabilities(this.orchestrator.config).namespaces === true
5987
5992
  ? writeNamespace
5988
5993
  : undefined;
5989
5994
  // Pin provenance PRINCIPAL to the scope plan's resolved principal (#1505
@@ -6188,7 +6193,7 @@ export class EngramAccessService {
6188
6193
  (typeof request.sessionKey === "string" &&
6189
6194
  request.sessionKey.length > 0) ||
6190
6195
  lcmSessionPrefixes.some((prefix) => typeof prefix === "string" && prefix.length > 0);
6191
- if (!hasScopedSession && this.orchestrator.config.namespacesEnabled === true) {
6196
+ if (!hasScopedSession && resolveNamespaceCapabilities(this.orchestrator.config).namespaces === true) {
6192
6197
  return {
6193
6198
  query: request.query,
6194
6199
  namespace,
@@ -6483,7 +6488,7 @@ export class EngramAccessService {
6483
6488
  principal: string | undefined,
6484
6489
  ): string | undefined {
6485
6490
  const config = this.orchestrator.config;
6486
- if (!config.namespacesEnabled) return config.defaultNamespace;
6491
+ if (!resolveNamespaceCapabilities(config).namespaces) return config.defaultNamespace;
6487
6492
  // PROCEED when `default` is readable (single-store / readable-default flows)
6488
6493
  // — the LCM prefix resolves to the overlay when self-authorized, else the
6489
6494
  // default raw key.
@@ -6824,7 +6829,7 @@ export class EngramAccessService {
6824
6829
  period?: "weekly" | "monthly";
6825
6830
  key?: string;
6826
6831
  }): Promise<{ enabled: boolean; reason?: string; period?: string; key?: string; reportPath?: string }> {
6827
- if (!this.orchestrator.config.identityContinuityEnabled) {
6832
+ if (!resolveIdentityContinuityCapabilities(this.orchestrator.config).identityContinuity) {
6828
6833
  return { enabled: false, reason: "Identity continuity is disabled. Enable `identityContinuityEnabled: true`." };
6829
6834
  }
6830
6835
  if (!this.orchestrator.config.continuityAuditEnabled) {
@@ -6846,7 +6851,7 @@ export class EngramAccessService {
6846
6851
  triggerWindow?: string;
6847
6852
  suspectedCause?: string;
6848
6853
  }): Promise<unknown> {
6849
- if (!this.orchestrator.config.identityContinuityEnabled) {
6854
+ if (!resolveIdentityContinuityCapabilities(this.orchestrator.config).identityContinuity) {
6850
6855
  return { enabled: false, reason: "Identity continuity is disabled. Enable `identityContinuityEnabled: true`." };
6851
6856
  }
6852
6857
  if (!this.orchestrator.config.continuityIncidentLoggingEnabled) {
@@ -6872,7 +6877,7 @@ export class EngramAccessService {
6872
6877
  verificationResult: string;
6873
6878
  preventiveRule?: string;
6874
6879
  }): Promise<unknown> {
6875
- if (!this.orchestrator.config.identityContinuityEnabled) {
6880
+ if (!resolveIdentityContinuityCapabilities(this.orchestrator.config).identityContinuity) {
6876
6881
  return { enabled: false, reason: "Identity continuity is disabled." };
6877
6882
  }
6878
6883
  if (!this.orchestrator.config.continuityIncidentLoggingEnabled) {
@@ -6901,7 +6906,7 @@ export class EngramAccessService {
6901
6906
  principal?: string;
6902
6907
  limit?: number;
6903
6908
  }): Promise<unknown> {
6904
- if (!this.orchestrator.config.identityContinuityEnabled) {
6909
+ if (!resolveIdentityContinuityCapabilities(this.orchestrator.config).identityContinuity) {
6905
6910
  return { enabled: false, reason: "Identity continuity is disabled." };
6906
6911
  }
6907
6912
  const state = request.state === "closed" || request.state === "all" ? request.state : "open";
@@ -6923,7 +6928,7 @@ export class EngramAccessService {
6923
6928
  lastReviewed?: string;
6924
6929
  notes?: string;
6925
6930
  }): Promise<unknown> {
6926
- if (!this.orchestrator.config.identityContinuityEnabled) {
6931
+ if (!resolveIdentityContinuityCapabilities(this.orchestrator.config).identityContinuity) {
6927
6932
  return { enabled: false, reason: "Identity continuity is disabled." };
6928
6933
  }
6929
6934
  const resolvedNs = this.writableNamespaceFor(request.namespace, undefined, request.principal);
@@ -6948,7 +6953,7 @@ export class EngramAccessService {
6948
6953
  notes?: string;
6949
6954
  reviewedAt?: string;
6950
6955
  }): Promise<unknown> {
6951
- if (!this.orchestrator.config.identityContinuityEnabled) {
6956
+ if (!resolveIdentityContinuityCapabilities(this.orchestrator.config).identityContinuity) {
6952
6957
  return { enabled: false, reason: "Identity continuity is disabled." };
6953
6958
  }
6954
6959
  const id = request.id?.trim();
@@ -6968,7 +6973,7 @@ export class EngramAccessService {
6968
6973
  namespace?: string;
6969
6974
  principal?: string;
6970
6975
  }): Promise<unknown> {
6971
- if (!this.orchestrator.config.identityContinuityEnabled) {
6976
+ if (!resolveIdentityContinuityCapabilities(this.orchestrator.config).identityContinuity) {
6972
6977
  return { enabled: false, reason: "Identity continuity is disabled." };
6973
6978
  }
6974
6979
  const resolvedNs = this.resolveReadableNamespace(request.namespace, request.principal);
@@ -6994,7 +6999,7 @@ export class EngramAccessService {
6994
6999
  operatingPrinciples?: string;
6995
7000
  continuityNotes?: string;
6996
7001
  }): Promise<unknown> {
6997
- if (!this.orchestrator.config.identityContinuityEnabled) {
7002
+ if (!resolveIdentityContinuityCapabilities(this.orchestrator.config).identityContinuity) {
6998
7003
  return { enabled: false, reason: "Identity continuity is disabled." };
6999
7004
  }
7000
7005
 
@@ -7419,7 +7424,7 @@ export class EngramAccessService {
7419
7424
  }
7420
7425
 
7421
7426
  let results: Array<{ path: string; score: number; snippet?: string }>;
7422
- if (!this.orchestrator.config.namespacesEnabled) {
7427
+ if (!resolveNamespaceCapabilities(this.orchestrator.config).namespaces) {
7423
7428
  this.resolveReadableNamespace(namespace, principal);
7424
7429
  results = collection === "global"
7425
7430
  ? await this.orchestrator.qmd.searchGlobal(query, maxResults)
@@ -8162,7 +8167,7 @@ export class EngramAccessService {
8162
8167
  namespace: string;
8163
8168
  storage: StorageManager;
8164
8169
  }> {
8165
- if (this.orchestrator.config.namespacesEnabled && !principal?.trim()) {
8170
+ if (resolveNamespaceCapabilities(this.orchestrator.config).namespaces && !principal?.trim()) {
8166
8171
  throw new EngramAccessInputError(
8167
8172
  "authentication required: namespaces are enabled and no principal was supplied",
8168
8173
  );
@@ -8902,7 +8907,7 @@ export class EngramAccessService {
8902
8907
  actor?: never; // ignored — actor is derived from the authenticated principal
8903
8908
  }) {
8904
8909
  const config = this.orchestrator.config;
8905
- const namespacesEnabled = config.namespacesEnabled === true;
8910
+ const namespacesEnabled = resolveNamespaceCapabilities(config).namespaces === true;
8906
8911
  // Fix OdCl3: when no namespace is supplied, resolve the source via the
8907
8912
  // scope plan (principal self / scope-profile write layer / coding overlay)
8908
8913
  // instead of falling through to config.defaultNamespace. This matches the
@@ -1,3 +1,4 @@
1
+ import { resolveNamespaceCapabilities } from "./capabilities.js";
1
2
  import { canReadNamespace, defaultNamespaceForPrincipal, resolvePrincipal } from "./namespaces/principal.js";
2
3
  import type { MemoryFile, PluginConfig } from "./types.js";
3
4
  import { collapseWhitespace, truncateCodePointSafe } from "./whitespace.js";
@@ -106,7 +107,7 @@ function resolveActiveMemoryNamespace(
106
107
  typeof orchestrator.resolvePrincipal === "function"
107
108
  ? orchestrator.resolvePrincipal(sessionKey)
108
109
  : resolvePrincipal(sessionKey, config);
109
- if (config.namespacesEnabled && !principal) {
110
+ if (resolveNamespaceCapabilities(config).namespaces && !principal) {
110
111
  throw new Error("authentication required: namespaces are enabled and no principal was supplied");
111
112
  }
112
113
  if (explicitNamespace) {
@@ -23,6 +23,7 @@
23
23
  * NamespaceSearchRouter health. No new scope-resolution or namespace-listing
24
24
  * logic is introduced.
25
25
  */
26
+ import { resolveNamespaceCapabilities } from "../capabilities.js";
26
27
  import path from "node:path";
27
28
  import type { NamespaceCatalog, NamespaceRecord } from "../namespaces/catalog.js";
28
29
  import { canReadNamespace, canWriteNamespace } from "../namespaces/principal.js";
@@ -190,7 +191,7 @@ export function inspectScope(options: InspectScopeOptions): ScopeInspection {
190
191
  const { config } = options;
191
192
  // Honour the pre-read flag when the caller supplied one (avoids a scattered
192
193
  // read here); fall back to the config flag for direct callers (tests/CLI).
193
- const namespacesEnabled = options.namespacesEnabled ?? config.namespacesEnabled === true;
194
+ const namespacesEnabled = options.namespacesEnabled ?? resolveNamespaceCapabilities(config).namespaces === true;
194
195
 
195
196
  const plan = resolveScopePlan({
196
197
  config,
@@ -5,8 +5,16 @@ import { parseConfig } from "./config.js";
5
5
  import {
6
6
  resolveCapabilities,
7
7
  resolveAccessSetupCapabilities,
8
+ resolveNamespaceCapabilities,
9
+ resolveQmdCapabilities,
10
+ resolveIdentityContinuityCapabilities,
11
+ resolveLocalLlmCapabilities,
8
12
  type CapabilitySet,
9
13
  type AccessSetupCapabilitySet,
14
+ type NamespaceCapabilitySet,
15
+ type QmdCapabilitySet,
16
+ type IdentityContinuityCapabilitySet,
17
+ type LocalLlmCapabilitySet,
10
18
  } from "./capabilities.js";
11
19
 
12
20
  /**
@@ -646,3 +654,173 @@ test("resolveCreationMemoryCapabilities matches pre-migration config reads (pari
646
654
  }
647
655
  }
648
656
  });
657
+
658
+ // ---------------------------------------------------------------------------
659
+ // Namespace capability set parity tests (issue #1523 batch 5).
660
+ //
661
+ // Guard: resolveNamespaceCapabilities(config).namespaces must always equal
662
+ // config.namespacesEnabled. The flag is a non-optional boolean so no default
663
+ // coercion is needed.
664
+ // ---------------------------------------------------------------------------
665
+
666
+ test("resolveNamespaceCapabilities: namespaces === config.namespacesEnabled (parity)", () => {
667
+ const cases = [
668
+ { label: "on", overrides: { namespacesEnabled: true } },
669
+ { label: "off", overrides: { namespacesEnabled: false } },
670
+ ];
671
+
672
+ for (const { label, overrides } of cases) {
673
+ const config = parseConfig(overrides);
674
+ const caps = resolveNamespaceCapabilities(config);
675
+ assert.equal(
676
+ caps.namespaces,
677
+ config.namespacesEnabled,
678
+ `[${label}] caps.namespaces must equal config.namespacesEnabled`,
679
+ );
680
+ }
681
+ });
682
+
683
+ test("resolveNamespaceCapabilities: result is frozen", () => {
684
+ const config = parseConfig({ namespacesEnabled: true });
685
+ const caps = resolveNamespaceCapabilities(config);
686
+ assert.ok(Object.isFrozen(caps), "NamespaceCapabilitySet must be frozen");
687
+ });
688
+
689
+ // ---------------------------------------------------------------------------
690
+ // QmdCapabilitySet — gate-parity tests (issue #1523 batch 6).
691
+ //
692
+ // Same invariant: every caps field must project from its `<field>Enabled`
693
+ // config flag. All twelve flags are required booleans on PluginConfig (defaults
694
+ // resolved at the parse boundary), so the projection is pure passthrough.
695
+ // ---------------------------------------------------------------------------
696
+
697
+ const QMD_FIELD_TO_FLAG: Record<keyof QmdCapabilitySet, string> = {
698
+ qmd: "qmdEnabled",
699
+ qmdTierMigration: "qmdTierMigrationEnabled",
700
+ qmdTierAutoBackfill: "qmdTierAutoBackfillEnabled",
701
+ qmdAutoEmbed: "qmdAutoEmbedEnabled",
702
+ qmdMaintenance: "qmdMaintenanceEnabled",
703
+ qmdColdTier: "qmdColdTierEnabled",
704
+ qmdDaemon: "qmdDaemonEnabled",
705
+ qmdTierParityGraph: "qmdTierParityGraphEnabled",
706
+ qmdQueryRerank: "qmdQueryRerankEnabled",
707
+ qmdIntentHints: "qmdIntentHintsEnabled",
708
+ qmdExplain: "qmdExplainEnabled",
709
+ qmdAutoUpgrade: "qmdAutoUpgradeEnabled",
710
+ };
711
+
712
+ const QMD_FIELDS = Object.keys(QMD_FIELD_TO_FLAG) as Array<keyof QmdCapabilitySet>;
713
+
714
+ test("resolveQmdCapabilities projects every field from its flag (true variant)", () => {
715
+ const overrides: Record<string, boolean> = {};
716
+ for (const flag of Object.values(QMD_FIELD_TO_FLAG)) overrides[flag] = true;
717
+ const config = parseConfig(overrides);
718
+ const caps = resolveQmdCapabilities(config);
719
+
720
+ for (const field of QMD_FIELDS) {
721
+ const flag = QMD_FIELD_TO_FLAG[field];
722
+ assert.equal(caps[field], true, `caps.${field} must be true when ${flag}=true`);
723
+ }
724
+ });
725
+
726
+ test("resolveQmdCapabilities projects every field from its flag (false variant)", () => {
727
+ const overrides: Record<string, boolean> = {};
728
+ for (const flag of Object.values(QMD_FIELD_TO_FLAG)) overrides[flag] = false;
729
+ const config = parseConfig(overrides);
730
+ const caps = resolveQmdCapabilities(config);
731
+
732
+ for (const field of QMD_FIELDS) {
733
+ const flag = QMD_FIELD_TO_FLAG[field];
734
+ assert.equal(caps[field], false, `caps.${field} must be false when ${flag}=false`);
735
+ }
736
+ });
737
+
738
+ test("resolveQmdCapabilities returns a frozen object", () => {
739
+ const config = parseConfig({});
740
+ const caps = resolveQmdCapabilities(config);
741
+ assert.equal(Object.isFrozen(caps), true);
742
+ });
743
+
744
+ test("resolveQmdCapabilities matches pre-migration config reads (parity contract)", () => {
745
+ const cases: Record<string, Record<string, boolean>> = {
746
+ "all-off": Object.fromEntries(Object.values(QMD_FIELD_TO_FLAG).map((f) => [f, false])),
747
+ "all-on": Object.fromEntries(Object.values(QMD_FIELD_TO_FLAG).map((f) => [f, true])),
748
+ "qmd-on-rest-off": {
749
+ ...Object.fromEntries(Object.values(QMD_FIELD_TO_FLAG).map((f) => [f, false])),
750
+ qmdEnabled: true,
751
+ },
752
+ "tiers-on-qmd-off": {
753
+ ...Object.fromEntries(Object.values(QMD_FIELD_TO_FLAG).map((f) => [f, false])),
754
+ qmdTierMigrationEnabled: true,
755
+ qmdColdTierEnabled: true,
756
+ },
757
+ };
758
+
759
+ for (const [label, overrides] of Object.entries(cases)) {
760
+ const config = parseConfig(overrides);
761
+ const caps = resolveQmdCapabilities(config);
762
+
763
+ for (const field of QMD_FIELDS) {
764
+ const flag = QMD_FIELD_TO_FLAG[field];
765
+ assert.equal(
766
+ caps[field],
767
+ (config as unknown as Record<string, boolean>)[flag],
768
+ `[${label}] caps.${field} must equal config.${flag}`,
769
+ );
770
+ }
771
+ }
772
+ });
773
+
774
+ // ---------------------------------------------------------------------------
775
+ // IdentityContinuityCapabilitySet — gate-parity tests (issue #1523 batch 6).
776
+ // ---------------------------------------------------------------------------
777
+
778
+ test("resolveIdentityContinuityCapabilities: identityContinuity === config.identityContinuityEnabled (parity)", () => {
779
+ const cases = [
780
+ { label: "on", overrides: { identityContinuityEnabled: true } },
781
+ { label: "off", overrides: { identityContinuityEnabled: false } },
782
+ ];
783
+
784
+ for (const { label, overrides } of cases) {
785
+ const config = parseConfig(overrides);
786
+ const caps = resolveIdentityContinuityCapabilities(config);
787
+ assert.equal(
788
+ caps.identityContinuity,
789
+ config.identityContinuityEnabled,
790
+ `[${label}] caps.identityContinuity must equal config.identityContinuityEnabled`,
791
+ );
792
+ }
793
+ });
794
+
795
+ test("resolveIdentityContinuityCapabilities: result is frozen", () => {
796
+ const config = parseConfig({ identityContinuityEnabled: true });
797
+ const caps = resolveIdentityContinuityCapabilities(config);
798
+ assert.ok(Object.isFrozen(caps), "IdentityContinuityCapabilitySet must be frozen");
799
+ });
800
+
801
+ // ---------------------------------------------------------------------------
802
+ // LocalLlmCapabilitySet — gate-parity tests (issue #1523 batch 6).
803
+ // ---------------------------------------------------------------------------
804
+
805
+ test("resolveLocalLlmCapabilities: localLlm === config.localLlmEnabled (parity)", () => {
806
+ const cases = [
807
+ { label: "on", overrides: { localLlmEnabled: true } },
808
+ { label: "off", overrides: { localLlmEnabled: false } },
809
+ ];
810
+
811
+ for (const { label, overrides } of cases) {
812
+ const config = parseConfig(overrides);
813
+ const caps = resolveLocalLlmCapabilities(config);
814
+ assert.equal(
815
+ caps.localLlm,
816
+ config.localLlmEnabled,
817
+ `[${label}] caps.localLlm must equal config.localLlmEnabled`,
818
+ );
819
+ }
820
+ });
821
+
822
+ test("resolveLocalLlmCapabilities: result is frozen", () => {
823
+ const config = parseConfig({ localLlmEnabled: true });
824
+ const caps = resolveLocalLlmCapabilities(config);
825
+ assert.ok(Object.isFrozen(caps), "LocalLlmCapabilitySet must be frozen");
826
+ });