@lucern/graph-primitives 1.0.28 → 1.0.30

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 (319) hide show
  1. package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
  2. package/dist/beliefDecay.d.ts +1 -1
  3. package/dist/beliefDecay.js +448 -314
  4. package/dist/beliefDecay.js.map +1 -1
  5. package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
  6. package/dist/beliefEvidenceLinks.d.ts +1 -1
  7. package/dist/beliefEvidenceLinks.js +843 -624
  8. package/dist/beliefEvidenceLinks.js.map +1 -1
  9. package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
  10. package/dist/beliefEvidenceLinks.operational.js +91 -18
  11. package/dist/beliefEvidenceLinks.operational.js.map +1 -1
  12. package/dist/beliefLifecycle.js.map +1 -1
  13. package/dist/confidencePropagationDispatch.d.ts +28 -27
  14. package/dist/confidencePropagationDispatch.js +157 -99
  15. package/dist/confidencePropagationDispatch.js.map +1 -1
  16. package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
  17. package/dist/contradictions.d.ts +1 -1
  18. package/dist/contradictions.js +398 -228
  19. package/dist/contradictions.js.map +1 -1
  20. package/dist/convex.d.ts +65 -30
  21. package/dist/convex.js +7 -3
  22. package/dist/convex.js.map +1 -1
  23. package/dist/debug.js.map +1 -1
  24. package/dist/edgeValidation.js +293 -85
  25. package/dist/edgeValidation.js.map +1 -1
  26. package/dist/edges/contains.d.ts +1 -1
  27. package/dist/edges/contains.js.map +1 -1
  28. package/dist/edges/contradicts.d.ts +1 -1
  29. package/dist/edges/contradicts.js.map +1 -1
  30. package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
  31. package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
  32. package/dist/edges/depends-on.js.map +1 -0
  33. package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
  34. package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
  35. package/dist/edges/derived-from.js.map +1 -0
  36. package/dist/edges/elaborates.d.ts +1 -1
  37. package/dist/edges/elaborates.js.map +1 -1
  38. package/dist/edges/index.d.ts +7 -3
  39. package/dist/edges/index.js +7 -4
  40. package/dist/edges/index.js.map +1 -1
  41. package/dist/edges/informs.d.ts +1 -1
  42. package/dist/edges/informs.js.map +1 -1
  43. package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
  44. package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
  45. package/dist/edges/propagation-types.js.map +1 -0
  46. package/dist/edges/refutes.d.ts +1 -1
  47. package/dist/edges/refutes.js.map +1 -1
  48. package/dist/edges/supports.d.ts +1 -1
  49. package/dist/edges/supports.js.map +1 -1
  50. package/dist/edges/tests.d.ts +1 -1
  51. package/dist/edges/tests.js.map +1 -1
  52. package/dist/edges/utils.d.ts +1 -1
  53. package/dist/edges/utils.js.map +1 -1
  54. package/dist/embeddingTrigger.d.ts +14 -6
  55. package/dist/embeddingTrigger.js +11 -14
  56. package/dist/embeddingTrigger.js.map +1 -1
  57. package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
  58. package/dist/entityBridge.d.ts +1 -1
  59. package/dist/entityBridge.js +602 -225
  60. package/dist/entityBridge.js.map +1 -1
  61. package/dist/entityCanonicalMatch.d.ts +14 -12
  62. package/dist/entityCanonicalMatch.js.map +1 -1
  63. package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
  64. package/dist/entityLifecycle.d.ts +1 -1
  65. package/dist/entityLifecycle.js +857 -515
  66. package/dist/entityLifecycle.js.map +1 -1
  67. package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
  68. package/dist/entityValidation.d.ts +3 -1
  69. package/dist/entityValidation.js +60 -8
  70. package/dist/entityValidation.js.map +1 -1
  71. package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
  72. package/dist/epistemicAnswers.d.ts +1 -1
  73. package/dist/epistemicAnswers.js +587 -545
  74. package/dist/epistemicAnswers.js.map +1 -1
  75. package/dist/epistemicBeliefs.admin.d.ts +8 -8
  76. package/dist/epistemicBeliefs.admin.js +366 -203
  77. package/dist/epistemicBeliefs.admin.js.map +1 -1
  78. package/dist/epistemicBeliefs.backfills.d.ts +8 -8
  79. package/dist/epistemicBeliefs.backfills.js +655 -308
  80. package/dist/epistemicBeliefs.backfills.js.map +1 -1
  81. package/dist/epistemicBeliefs.confidence.d.ts +19 -14
  82. package/dist/epistemicBeliefs.confidence.js +634 -423
  83. package/dist/epistemicBeliefs.confidence.js.map +1 -1
  84. package/dist/epistemicBeliefs.core.d.ts +6 -6
  85. package/dist/epistemicBeliefs.core.js +719 -411
  86. package/dist/epistemicBeliefs.core.js.map +1 -1
  87. package/dist/epistemicBeliefs.d.ts +11 -8
  88. package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
  89. package/dist/epistemicBeliefs.forkEvidence.js +8 -28
  90. package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
  91. package/dist/epistemicBeliefs.helpers.d.ts +69 -74
  92. package/dist/epistemicBeliefs.helpers.js +359 -248
  93. package/dist/epistemicBeliefs.helpers.js.map +1 -1
  94. package/dist/epistemicBeliefs.internal.d.ts +5 -5
  95. package/dist/epistemicBeliefs.internal.js +1246 -1044
  96. package/dist/epistemicBeliefs.internal.js.map +1 -1
  97. package/dist/epistemicBeliefs.js +4922 -3608
  98. package/dist/epistemicBeliefs.js.map +1 -1
  99. package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
  100. package/dist/epistemicBeliefs.lifecycle.js +1137 -818
  101. package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
  102. package/dist/epistemicBeliefs.links.d.ts +7 -7
  103. package/dist/epistemicBeliefs.links.js +408 -307
  104. package/dist/epistemicBeliefs.links.js.map +1 -1
  105. package/dist/epistemicBeliefs.queries.d.ts +4 -4
  106. package/dist/epistemicBeliefs.queries.js +175 -20
  107. package/dist/epistemicBeliefs.queries.js.map +1 -1
  108. package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
  109. package/dist/epistemicBeliefs.topicAnchor.js +12 -5
  110. package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
  111. package/dist/epistemicContracts.d.ts +28 -3
  112. package/dist/epistemicContracts.evaluators.d.ts +2 -0
  113. package/dist/epistemicContracts.evaluators.js +1063 -613
  114. package/dist/epistemicContracts.evaluators.js.map +1 -1
  115. package/dist/epistemicContracts.handlers.d.ts +15 -32
  116. package/dist/epistemicContracts.handlers.js +2086 -1644
  117. package/dist/epistemicContracts.handlers.js.map +1 -1
  118. package/dist/epistemicContracts.js +1131 -672
  119. package/dist/epistemicContracts.js.map +1 -1
  120. package/dist/epistemicContracts.metrics.d.ts +2 -0
  121. package/dist/epistemicContracts.metrics.js +375 -158
  122. package/dist/epistemicContracts.metrics.js.map +1 -1
  123. package/dist/epistemicContracts.types.d.ts +87 -81
  124. package/dist/epistemicEdgeCreation.d.ts +2 -0
  125. package/dist/epistemicEdgeCreation.js +87 -16
  126. package/dist/epistemicEdgeCreation.js.map +1 -1
  127. package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
  128. package/dist/epistemicEdges.d.ts +6 -5
  129. package/dist/epistemicEdges.handlers.d.ts +3 -3
  130. package/dist/epistemicEdges.handlers.js +129 -24
  131. package/dist/epistemicEdges.handlers.js.map +1 -1
  132. package/dist/epistemicEdges.helpers.d.ts +6 -4
  133. package/dist/epistemicEdges.helpers.js +37 -2
  134. package/dist/epistemicEdges.helpers.js.map +1 -1
  135. package/dist/epistemicEdges.js +1969 -1205
  136. package/dist/epistemicEdges.js.map +1 -1
  137. package/dist/epistemicEdges.mutations.d.ts +7 -7
  138. package/dist/epistemicEdges.mutations.js +960 -583
  139. package/dist/epistemicEdges.mutations.js.map +1 -1
  140. package/dist/epistemicEdges.queries.d.ts +16 -16
  141. package/dist/epistemicEdges.queries.js +639 -367
  142. package/dist/epistemicEdges.queries.js.map +1 -1
  143. package/dist/epistemicEdges.types.d.ts +10 -8
  144. package/dist/epistemicEvidence.d.ts +4 -1
  145. package/dist/epistemicEvidence.js +937 -536
  146. package/dist/epistemicEvidence.js.map +1 -1
  147. package/dist/epistemicEvidenceHelpers.d.ts +26 -10
  148. package/dist/epistemicEvidenceHelpers.js +239 -200
  149. package/dist/epistemicEvidenceHelpers.js.map +1 -1
  150. package/dist/epistemicEvidenceMutations.d.ts +8 -8
  151. package/dist/epistemicEvidenceMutations.js +844 -696
  152. package/dist/epistemicEvidenceMutations.js.map +1 -1
  153. package/dist/epistemicEvidenceQueries.d.ts +8 -8
  154. package/dist/epistemicEvidenceQueries.js +514 -238
  155. package/dist/epistemicEvidenceQueries.js.map +1 -1
  156. package/dist/epistemicHelpers.d.ts +4 -2
  157. package/dist/epistemicHelpers.js +308 -134
  158. package/dist/epistemicHelpers.js.map +1 -1
  159. package/dist/epistemicInsert.d.ts +16 -4
  160. package/dist/epistemicInsert.js +6 -3
  161. package/dist/epistemicInsert.js.map +1 -1
  162. package/dist/epistemicLayerRules.d.ts +10 -8
  163. package/dist/epistemicLayerRules.js +1 -5
  164. package/dist/epistemicLayerRules.js.map +1 -1
  165. package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
  166. package/dist/epistemicLinking.d.ts +1 -1
  167. package/dist/epistemicLinking.js +177 -100
  168. package/dist/epistemicLinking.js.map +1 -1
  169. package/dist/epistemicNodeCreation.d.ts +2 -0
  170. package/dist/epistemicNodeCreation.js +203 -40
  171. package/dist/epistemicNodeCreation.js.map +1 -1
  172. package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
  173. package/dist/epistemicNodes.d.ts +3 -3
  174. package/dist/epistemicNodes.helpers.d.ts +24 -15
  175. package/dist/epistemicNodes.helpers.js.map +1 -1
  176. package/dist/epistemicNodes.internal.d.ts +6 -6
  177. package/dist/epistemicNodes.internal.js +389 -319
  178. package/dist/epistemicNodes.internal.js.map +1 -1
  179. package/dist/epistemicNodes.js +704 -508
  180. package/dist/epistemicNodes.js.map +1 -1
  181. package/dist/epistemicNodes.mutations.d.ts +6 -6
  182. package/dist/epistemicNodes.mutations.js +564 -467
  183. package/dist/epistemicNodes.mutations.js.map +1 -1
  184. package/dist/epistemicNodes.queries.d.ts +8 -8
  185. package/dist/epistemicNodes.queries.js +311 -314
  186. package/dist/epistemicNodes.queries.js.map +1 -1
  187. package/dist/epistemicNodes.validators.d.ts +2 -2
  188. package/dist/epistemicNodes.validators.js.map +1 -1
  189. package/dist/epistemicQuestions.conviction.d.ts +8 -8
  190. package/dist/epistemicQuestions.conviction.js +665 -484
  191. package/dist/epistemicQuestions.conviction.js.map +1 -1
  192. package/dist/epistemicQuestions.create.d.ts +4 -4
  193. package/dist/epistemicQuestions.create.js +640 -612
  194. package/dist/epistemicQuestions.create.js.map +1 -1
  195. package/dist/epistemicQuestions.d.ts +8 -5
  196. package/dist/epistemicQuestions.evidence.d.ts +2 -2
  197. package/dist/epistemicQuestions.evidence.js +475 -383
  198. package/dist/epistemicQuestions.evidence.js.map +1 -1
  199. package/dist/epistemicQuestions.helpers.d.ts +125 -24
  200. package/dist/epistemicQuestions.helpers.js +240 -209
  201. package/dist/epistemicQuestions.helpers.js.map +1 -1
  202. package/dist/epistemicQuestions.js +3474 -2823
  203. package/dist/epistemicQuestions.js.map +1 -1
  204. package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
  205. package/dist/epistemicQuestions.lifecycle.js +607 -546
  206. package/dist/epistemicQuestions.lifecycle.js.map +1 -1
  207. package/dist/epistemicQuestions.queries.d.ts +12 -7
  208. package/dist/epistemicQuestions.queries.js +305 -244
  209. package/dist/epistemicQuestions.queries.js.map +1 -1
  210. package/dist/epistemicQuestions.sprint.d.ts +2 -2
  211. package/dist/epistemicQuestions.sprint.js +600 -394
  212. package/dist/epistemicQuestions.sprint.js.map +1 -1
  213. package/dist/epistemicQuestions.tail.d.ts +6 -6
  214. package/dist/epistemicQuestions.tail.js +572 -433
  215. package/dist/epistemicQuestions.tail.js.map +1 -1
  216. package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
  217. package/dist/epistemicSources.d.ts +1 -1
  218. package/dist/epistemicSources.js +352 -312
  219. package/dist/epistemicSources.js.map +1 -1
  220. package/dist/evaluators/index.d.ts +8 -6
  221. package/dist/evaluators/index.js +399 -167
  222. package/dist/evaluators/index.js.map +1 -1
  223. package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
  224. package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
  225. package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
  226. package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
  227. package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
  228. package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
  229. package/dist/evaluators/shared.d.ts +2 -2
  230. package/dist/evaluators/shared.js +3 -1
  231. package/dist/evaluators/shared.js.map +1 -1
  232. package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
  233. package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
  234. package/dist/evaluators/test-runner-evaluator.js.map +1 -0
  235. package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
  236. package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
  237. package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
  238. package/dist/graphTypes.js +6 -2
  239. package/dist/graphTypes.js.map +1 -1
  240. package/dist/helpers.d.ts +2 -0
  241. package/dist/helpers.js +313 -93
  242. package/dist/helpers.js.map +1 -1
  243. package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
  244. package/dist/index.d.ts +87 -83
  245. package/dist/index.js +15677 -10594
  246. package/dist/index.js.map +1 -1
  247. package/dist/invariantEnforcement.d.ts +3 -3
  248. package/dist/invariantEnforcement.js.map +1 -1
  249. package/dist/logicalRoleInference.d.ts +2 -0
  250. package/dist/logicalRoleInference.js +1 -1
  251. package/dist/logicalRoleInference.js.map +1 -1
  252. package/dist/matcherFeedbackUtils.d.ts +2 -2
  253. package/dist/matcherFeedbackUtils.js.map +1 -1
  254. package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
  255. package/dist/ontology-matching.d.ts +1 -1
  256. package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
  257. package/dist/ontologyApproval.d.ts +1 -1
  258. package/dist/ontologyApproval.js +7 -1
  259. package/dist/ontologyApproval.js.map +1 -1
  260. package/dist/ontologyDefinitions.d.ts +14 -24
  261. package/dist/ontologyDefinitions.js +269 -34
  262. package/dist/ontologyDefinitions.js.map +1 -1
  263. package/dist/ontologyHelpers.d.ts +13 -13
  264. package/dist/ontologyHelpers.js.map +1 -1
  265. package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
  266. package/dist/ontologyRegistry.d.ts +1 -1
  267. package/dist/ontologyRegistry.js +34 -6
  268. package/dist/ontologyRegistry.js.map +1 -1
  269. package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
  270. package/dist/projectionReconciliation.d.ts +1 -1
  271. package/dist/projectionReconciliation.js +57 -10
  272. package/dist/projectionReconciliation.js.map +1 -1
  273. package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
  274. package/dist/projectionStaleness.d.ts +1 -1
  275. package/dist/projectionStaleness.js +8 -2
  276. package/dist/projectionStaleness.js.map +1 -1
  277. package/dist/proof-attestation.json +1 -1
  278. package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
  279. package/dist/questionEvidenceLinks.d.ts +1 -1
  280. package/dist/questionEvidenceLinks.js +564 -347
  281. package/dist/questionEvidenceLinks.js.map +1 -1
  282. package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
  283. package/dist/resolverTypes.d.ts +4 -2
  284. package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
  285. package/dist/resolvers.d.ts +5 -3
  286. package/dist/resolvers.js +121 -77
  287. package/dist/resolvers.js.map +1 -1
  288. package/dist/scopeResolverCompat.d.ts +10 -7
  289. package/dist/scopeResolverCompat.js +106 -123
  290. package/dist/scopeResolverCompat.js.map +1 -1
  291. package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
  292. package/dist/text-matching.d.ts +1 -1
  293. package/dist/topicOntologyResolver.d.ts +22 -21
  294. package/dist/topicOntologyResolver.js +54 -32
  295. package/dist/topicOntologyResolver.js.map +1 -1
  296. package/dist/topicProjectOverlay.d.ts +30 -20
  297. package/dist/topicProjectOverlay.js +120 -76
  298. package/dist/topicProjectOverlay.js.map +1 -1
  299. package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
  300. package/dist/topicScope.d.ts +3 -1
  301. package/dist/topicScope.js +104 -119
  302. package/dist/topicScope.js.map +1 -1
  303. package/dist/workflowBridge.d.ts +26 -15
  304. package/dist/workflowBridge.js +140 -144
  305. package/dist/workflowBridge.js.map +1 -1
  306. package/dist/workspaceIsolation.d.ts +14 -12
  307. package/dist/workspaceIsolation.js +108 -122
  308. package/dist/workspaceIsolation.js.map +1 -1
  309. package/package.json +4 -4
  310. package/dist/edges/dependsOn.js.map +0 -1
  311. package/dist/edges/derivedFrom.js.map +0 -1
  312. package/dist/edges/propagationTypes.js.map +0 -1
  313. package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
  314. package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
  315. package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
  316. package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
  317. package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
  318. package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
  319. package/dist/{epistemicQuestions-bwHd2FWE.d.ts → epistemicQuestions-Do1fhYm5.d.ts} +4 -4
@@ -1,13 +1,17 @@
1
- import { v } from 'convex/values';
2
1
  import { getCurrentUserId } from '@lucern/access-control/auth';
3
2
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
4
- import { componentsGeneric, anyApi, mutationGeneric } from 'convex/server';
3
+ import { v } from 'convex/values';
4
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
5
+ import { componentsGeneric, mutationGeneric } from 'convex/server';
5
6
  import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
6
7
 
7
8
  // src/epistemicQuestions.lifecycle.ts
8
- var api = anyApi;
9
+ var unsafeApi = unsafeConvexAnyApi(
10
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
11
+ );
12
+ var api = unsafeApi;
9
13
  componentsGeneric();
10
- var internal = anyApi;
14
+ var internal = unsafeApi;
11
15
  var mutation = mutationGeneric;
12
16
 
13
17
  // src/debug.ts
@@ -22,369 +26,8 @@ function debugGraphPrimitiveFallback(message, context) {
22
26
  console.debug(message, context ?? {});
23
27
  }
24
28
 
25
- // src/topicScope.ts
26
- var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
27
- async function resolveTopicNodeScopeOrNull(ctx, ref) {
28
- if (!ctx?.db || typeof ctx.db.query !== "function") {
29
- return null;
30
- }
31
- let node = null;
32
- try {
33
- const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
34
- if (byGlobalId && byGlobalId.nodeType === "topic") {
35
- node = byGlobalId;
36
- }
37
- } catch (error) {
38
- debugGraphPrimitiveFallback(
39
- "[topicScope] topic-node scope lookup by globalId failed",
40
- { error, ref }
41
- );
42
- }
43
- if (!node) {
44
- return null;
45
- }
46
- const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
47
- if (!scopeKey) {
48
- return null;
49
- }
50
- return {
51
- topicId: scopeKey,
52
- projectId: asMappedProjectId(node),
53
- source: "topic_node"
54
- };
55
- }
56
- function asMappedProjectId(topic) {
57
- if (!topic) {
58
- return;
59
- }
60
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
61
- if (directLegacyProjectId) {
62
- return directLegacyProjectId;
63
- }
64
- const metadata = topic.metadata || {};
65
- const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
66
- return candidate ? candidate : void 0;
67
- }
68
- function normalizeScopeValue(value) {
69
- if (typeof value !== "string") {
70
- return;
71
- }
72
- const normalized = value.trim();
73
- return normalized.length > 0 ? normalized : void 0;
74
- }
75
- function pickPrimaryTopic(candidates) {
76
- return [...candidates].sort((a, b) => {
77
- const depthA = a.depth ?? 9999;
78
- const depthB = b.depth ?? 9999;
79
- if (depthA !== depthB) {
80
- return depthA - depthB;
81
- }
82
- const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
83
- const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
84
- if (createdA !== createdB) {
85
- return createdA - createdB;
86
- }
87
- return String(a.name || "").localeCompare(String(b.name || ""));
88
- })[0];
89
- }
90
- async function findTopicsByScopeAlias(ctx, scopeId) {
91
- try {
92
- return await ctx.db.query("topics").withIndex(
93
- "by_graph_scope_project",
94
- (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
95
- ).collect();
96
- } catch (error) {
97
- debugGraphPrimitiveFallback(
98
- "[topicScope] Failed to resolve scope alias via index",
99
- {
100
- error,
101
- scopeId
102
- }
103
- );
104
- const topics = await ctx.db.query("topics").collect();
105
- return topics.filter((topic) => {
106
- const normalizedGlobalId = normalizeScopeValue(topic.globalId);
107
- const mappedProjectId = asMappedProjectId(topic);
108
- return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
109
- });
110
- }
111
- }
112
- async function tryResolveHostTopicById(ctx, topicId) {
113
- if (typeof ctx.runQuery !== "function") {
114
- return null;
115
- }
116
- try {
117
- return await ctx.runQuery(api.topics.get, {
118
- id: topicId
119
- }) ?? null;
120
- } catch (error) {
121
- debugGraphPrimitiveFallback(
122
- "[topicScope] Failed to resolve topic by host query",
123
- {
124
- error,
125
- topicId
126
- }
127
- );
128
- return null;
129
- }
130
- }
131
- async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
132
- if (typeof ctx.runQuery !== "function") {
133
- return null;
134
- }
135
- try {
136
- return await ctx.runQuery(api.topics.getByLegacyScopeId, {
137
- projectId: legacyScopeId
138
- }) ?? null;
139
- } catch (error) {
140
- debugGraphPrimitiveFallback(
141
- "[topicScope] Failed to resolve topic by legacy scope",
142
- {
143
- error,
144
- legacyScopeId
145
- }
146
- );
147
- return null;
148
- }
149
- }
150
- async function resolveInheritedWorkspaceScope(ctx, topic) {
151
- const MAX_DEPTH = 10;
152
- let tenantId = normalizeScopeValue(topic.tenantId);
153
- let workspaceId = normalizeScopeValue(topic.workspaceId);
154
- if (tenantId && workspaceId) {
155
- return { tenantId, workspaceId };
156
- }
157
- let current = topic;
158
- for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
159
- current = await ctx.db.get(current.parentTopicId);
160
- if (!current) break;
161
- if (!tenantId) {
162
- tenantId = normalizeScopeValue(current.tenantId);
163
- }
164
- if (!workspaceId) {
165
- workspaceId = normalizeScopeValue(current.workspaceId);
166
- }
167
- if (tenantId && workspaceId) break;
168
- }
169
- return { tenantId, workspaceId };
170
- }
171
- async function resolveTopicProjectScope(ctx, args) {
172
- if (args.topicId) {
173
- let topic = null;
174
- try {
175
- topic = await ctx.db.get(
176
- args.topicId
177
- );
178
- } catch (error) {
179
- debugGraphPrimitiveFallback(
180
- "[topicScope] Failed to load topic by direct id",
181
- {
182
- error,
183
- topicId: args.topicId
184
- }
185
- );
186
- }
187
- if (!topic) {
188
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
189
- }
190
- if (!topic) {
191
- topic = pickPrimaryTopic(
192
- await findTopicsByScopeAlias(ctx, String(args.topicId))
193
- ) ?? null;
194
- }
195
- if (!topic) {
196
- const nodeScope = await resolveTopicNodeScopeOrNull(
197
- ctx,
198
- String(args.topicId)
199
- );
200
- if (nodeScope) {
201
- return nodeScope;
202
- }
203
- throw new Error(`Topic not found: ${String(args.topicId)}`);
204
- }
205
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
206
- const mapped = asMappedProjectId(topic);
207
- if (mapped) {
208
- return {
209
- topicId: topic._id,
210
- projectId: mapped,
211
- tenantId: inherited.tenantId,
212
- workspaceId: inherited.workspaceId,
213
- source: "topic"
214
- };
215
- }
216
- return {
217
- topicId: topic._id,
218
- tenantId: inherited.tenantId,
219
- workspaceId: inherited.workspaceId,
220
- source: "topic"
221
- };
222
- }
223
- if (args.projectId) {
224
- let directTopic = null;
225
- try {
226
- directTopic = await ctx.db.get(
227
- args.projectId
228
- );
229
- } catch (error) {
230
- debugGraphPrimitiveFallback(
231
- "[topicScope] Failed to load direct project topic",
232
- {
233
- error,
234
- projectId: args.projectId
235
- }
236
- );
237
- }
238
- if (directTopic) {
239
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
240
- const mapped = asMappedProjectId(directTopic);
241
- return {
242
- topicId: directTopic._id,
243
- projectId: mapped ?? args.projectId,
244
- tenantId: inherited.tenantId,
245
- workspaceId: inherited.workspaceId,
246
- source: "topic_inferred"
247
- };
248
- }
249
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
250
- if (directTopic) {
251
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
252
- const mapped = asMappedProjectId(directTopic);
253
- return {
254
- topicId: directTopic._id,
255
- projectId: mapped ?? args.projectId,
256
- tenantId: inherited.tenantId,
257
- workspaceId: inherited.workspaceId,
258
- source: "topic_inferred"
259
- };
260
- }
261
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
262
- const primary = pickPrimaryTopic(topics);
263
- if (primary) {
264
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
265
- return {
266
- topicId: primary._id,
267
- projectId: args.projectId,
268
- tenantId: inherited.tenantId,
269
- workspaceId: inherited.workspaceId,
270
- source: "project_mapped_topic"
271
- };
272
- }
273
- const nodeScope = await resolveTopicNodeScopeOrNull(
274
- ctx,
275
- String(args.projectId)
276
- );
277
- if (nodeScope) {
278
- return {
279
- ...nodeScope,
280
- projectId: nodeScope.projectId ?? String(args.projectId)
281
- };
282
- }
283
- throw new Error(
284
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
285
- );
286
- }
287
- throw new Error(
288
- "Missing scope: provide topicId (preferred) or legacy projectId alias."
289
- );
290
- }
291
- ({
292
- projectId: v.optional(v.string()),
293
- topicId: v.optional(v.string())
294
- });
295
-
296
- // src/workspaceIsolation.ts
297
- function normalizeScopeValue2(value) {
298
- if (typeof value !== "string") {
299
- return;
300
- }
301
- const normalized = value.trim();
302
- return normalized.length > 0 ? normalized : void 0;
303
- }
304
- function throwWorkspaceIsolationError(args) {
305
- const error = new Error(args.message);
306
- error.status = 409;
307
- error.code = "INVARIANT_VIOLATION";
308
- error.invariantCode = args.invariantCode;
309
- error.suggestion = args.suggestion;
310
- error.details = args.details;
311
- throw error;
312
- }
313
- async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
314
- const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
315
- const resolved = {
316
- tenantId: normalizeScopeValue2(node?.tenantId),
317
- workspaceId: normalizeScopeValue2(node?.workspaceId),
318
- epistemicLayer,
319
- nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
320
- };
321
- if (!node) {
322
- return resolved;
323
- }
324
- if (resolved.epistemicLayer === "ontological") {
325
- return resolved;
326
- }
327
- if (resolved.tenantId || resolved.workspaceId) {
328
- return resolved;
329
- }
330
- if (node.topicId) {
331
- const topicScope = await resolveTopicProjectScope(ctx, {
332
- topicId: node.topicId
333
- });
334
- return {
335
- ...resolved,
336
- tenantId: topicScope.tenantId,
337
- workspaceId: topicScope.workspaceId
338
- };
339
- }
340
- if (node.projectId) {
341
- const topicScope = await resolveTopicProjectScope(ctx, {
342
- projectId: String(node.projectId)
343
- });
344
- return {
345
- ...resolved,
346
- tenantId: topicScope.tenantId,
347
- workspaceId: topicScope.workspaceId
348
- };
349
- }
350
- return resolved;
351
- }
352
- function resolveRuntimePackMutationContext(args) {
353
- if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
354
- return;
355
- }
356
- return {
357
- toolName: args.runtimeToolName,
358
- packKey: args.runtimePackKey,
359
- packInstallScope: args.runtimePackInstallScope
360
- };
361
- }
362
- function assertTenantPackWorkspaceMutationAllowed(args) {
363
- if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
364
- return;
365
- }
366
- const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
367
- const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
368
- if (!targetWorkspaceId || targetLayer === "ontological") {
369
- return;
370
- }
371
- throwWorkspaceIsolationError({
372
- message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
373
- invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
374
- suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
375
- details: {
376
- mutationName: args.mutationName,
377
- toolName: args.runtime.toolName,
378
- packKey: args.runtime.packKey,
379
- targetWorkspaceId,
380
- targetNodeType: args.target.nodeType,
381
- targetLayer
382
- }
383
- });
384
- }
385
-
386
29
  // src/topicProjectOverlay.ts
387
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
30
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
388
31
  function readNonEmptyString(value) {
389
32
  if (typeof value !== "string") {
390
33
  return;
@@ -401,11 +44,15 @@ function readStringArray(value) {
401
44
  function readMetadata(topic) {
402
45
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
403
46
  }
47
+ function omitMetadataKey(metadata, key) {
48
+ const { [key]: _omitted, ...rest } = metadata;
49
+ return rest;
50
+ }
404
51
  function readLegacyProjectId(value) {
405
52
  if (!value) {
406
53
  return;
407
54
  }
408
- return readNonEmptyString(value[LEGACY_SCOPE_FIELD2]);
55
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
409
56
  }
410
57
  function coerceVisibility(value) {
411
58
  return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
@@ -481,9 +128,12 @@ async function resolveTopicDoc(ctx, scopeId) {
481
128
  );
482
129
  }
483
130
  try {
484
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
485
- projectId: String(scopeId)
486
- });
131
+ const topic = await ctx.runQuery(
132
+ api.topics.getByLegacyScopeId,
133
+ {
134
+ projectId: String(scopeId)
135
+ }
136
+ );
487
137
  if (topic?.name !== void 0 && topic?.type !== void 0) {
488
138
  return topic;
489
139
  }
@@ -503,8 +153,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
503
153
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
504
154
  const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
505
155
  const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
506
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
507
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
156
+ let createdAt = 0;
157
+ if (typeof topic.createdAt === "number") {
158
+ createdAt = topic.createdAt;
159
+ } else if (typeof topic._creationTime === "number") {
160
+ createdAt = topic._creationTime;
161
+ }
162
+ let updatedAt = createdAt;
163
+ if (typeof topic.updatedAt === "number") {
164
+ updatedAt = topic.updatedAt;
165
+ } else if (typeof metadata.updatedAt === "number") {
166
+ updatedAt = metadata.updatedAt;
167
+ }
508
168
  return {
509
169
  ...metadata,
510
170
  _id: outwardId,
@@ -546,183 +206,457 @@ async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
546
206
  if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
547
207
  return null;
548
208
  }
549
- return materializeTopicProjectOverlay(topic, options.idMode);
209
+ return materializeTopicProjectOverlay(topic, options.idMode);
210
+ }
211
+ async function listTopicProjectOverlays(ctx, options = {}) {
212
+ let allTopics = [];
213
+ if (ctx?.db?.query && typeof ctx.db.query === "function") {
214
+ try {
215
+ allTopics = await ctx.db.query("topics").collect();
216
+ } catch (error) {
217
+ debugGraphPrimitiveFallback(
218
+ "[topicProjectOverlay] Failed to read topics table; falling back to API",
219
+ { error }
220
+ );
221
+ allTopics = [];
222
+ }
223
+ }
224
+ if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
225
+ allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
226
+ }
227
+ return allTopics.filter(
228
+ (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
229
+ ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
230
+ }
231
+ async function patchTopicProjectOverlay(ctx, scopeId, value) {
232
+ const topic = await resolveTopicDoc(ctx, scopeId);
233
+ if (!topic) {
234
+ return null;
235
+ }
236
+ const plan = buildTopicProjectOverlayPatchPlan(topic, value);
237
+ await applyTopicProjectOverlayPatch(ctx, topic, plan);
238
+ return materializeTopicProjectOverlay({
239
+ ...topic,
240
+ ...plan.patch,
241
+ metadata: plan.nextMetadata
242
+ });
243
+ }
244
+ function buildTopicProjectOverlayPatchPlan(topic, value) {
245
+ const plan = {
246
+ nextMetadata: { ...readMetadata(topic) },
247
+ patch: {},
248
+ topicUpdateArgs: {
249
+ id: String(topic._id)
250
+ }
251
+ };
252
+ for (const [key, rawValue] of Object.entries(value)) {
253
+ applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
254
+ }
255
+ plan.patch.updatedAt = Date.now();
256
+ plan.patch.metadata = plan.nextMetadata;
257
+ plan.topicUpdateArgs.metadata = plan.nextMetadata;
258
+ return plan;
259
+ }
260
+ function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
261
+ switch (key) {
262
+ case "_id":
263
+ case "projectId":
264
+ case "topicId":
265
+ case "legacyProjectId":
266
+ case "storageProjectId":
267
+ case "updatedAt":
268
+ case "createdAt":
269
+ return;
270
+ case "name":
271
+ case "description":
272
+ plan.patch[key] = rawValue;
273
+ plan.topicUpdateArgs[key] = rawValue;
274
+ return;
275
+ case "tenantId":
276
+ case "workspaceId":
277
+ case "ownerId":
278
+ throw new Error(
279
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
280
+ );
281
+ case "status":
282
+ applyTopicStatusPatch(plan, rawValue);
283
+ return;
284
+ case "visibility":
285
+ applyTopicVisibilityPatch(plan, rawValue);
286
+ return;
287
+ case "type":
288
+ applyTopicProjectTypePatch(plan, rawValue);
289
+ return;
290
+ default:
291
+ applyTopicMetadataPatch(plan, key, rawValue);
292
+ }
293
+ }
294
+ function applyTopicStatusPatch(plan, rawValue) {
295
+ const status = coerceStatus(rawValue);
296
+ if (status) {
297
+ plan.patch.status = status;
298
+ plan.topicUpdateArgs.status = status;
299
+ }
300
+ }
301
+ function applyTopicVisibilityPatch(plan, rawValue) {
302
+ const visibility = coerceVisibility(rawValue);
303
+ if (visibility) {
304
+ plan.patch.visibility = visibility;
305
+ plan.topicUpdateArgs.visibility = visibility;
306
+ }
307
+ }
308
+ function applyTopicProjectTypePatch(plan, rawValue) {
309
+ const projectType = readNonEmptyString(rawValue);
310
+ if (projectType) {
311
+ plan.nextMetadata.projectType = projectType;
312
+ return;
313
+ }
314
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
315
+ }
316
+ function applyTopicMetadataPatch(plan, key, rawValue) {
317
+ if (rawValue === void 0) {
318
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
319
+ return;
320
+ }
321
+ plan.nextMetadata[key] = rawValue;
322
+ }
323
+ async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
324
+ if (typeof ctx.runMutation === "function") {
325
+ try {
326
+ await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
327
+ } catch (error) {
328
+ if (!canPatchTopicViaLocalDb(ctx, error)) {
329
+ throw error;
330
+ }
331
+ await ctx.db.patch(topic._id, plan.patch);
332
+ }
333
+ } else if (ctx?.db && typeof ctx.db.patch === "function") {
334
+ await ctx.db.patch(topic._id, plan.patch);
335
+ } else {
336
+ throw new Error(
337
+ "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
338
+ );
339
+ }
340
+ }
341
+ function canPatchTopicViaLocalDb(ctx, error) {
342
+ return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
343
+ }
344
+
345
+ // src/resolvers.ts
346
+ function isMissingLucernChildComponentError2(error) {
347
+ const message = getErrorMessage2(error);
348
+ return message.includes(
349
+ 'Child component ComponentName(Identifier("lucern")) not found'
350
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
351
+ }
352
+ function getErrorMessage2(error) {
353
+ if (error instanceof Error) {
354
+ return error.message;
355
+ }
356
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
357
+ return error.message;
358
+ }
359
+ return "unknown error";
360
+ }
361
+ function isAdvisoryTopicPatch(value) {
362
+ const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
363
+ const keys = Object.keys(value);
364
+ return keys.length > 0 && keys.every((key) => advisoryKeys.has(key));
365
+ }
366
+ async function patchProjectWithTolerance(ctx, projectId, value) {
367
+ try {
368
+ await patchTopicProjectOverlay(ctx, projectId, value);
369
+ } catch (error) {
370
+ if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
371
+ throw error;
372
+ }
373
+ console.warn(
374
+ "[lucern graph-primitives] Non-fatal advisory topic patch failure",
375
+ {
376
+ projectId,
377
+ keys: Object.keys(value),
378
+ error: getErrorMessage2(error)
379
+ }
380
+ );
381
+ }
382
+ }
383
+ function defaultResolvers() {
384
+ return {
385
+ getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
386
+ idMode: "legacy",
387
+ projectLikeOnly: false
388
+ }),
389
+ patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
390
+ listTopics: (ctx) => listTopicProjectOverlays(ctx, {
391
+ idMode: "legacy"
392
+ }),
393
+ getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
394
+ };
395
+ }
396
+ var resolverOverrides = {};
397
+ function resolveGraphPrimitivesAppResolvers(_ctx) {
398
+ return {
399
+ ...defaultResolvers(),
400
+ ...resolverOverrides
401
+ };
402
+ }
403
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
404
+ async function resolveTopicNodeScopeOrNull(ctx, ref) {
405
+ if (!ctx?.db || typeof ctx.db.query !== "function") {
406
+ return null;
407
+ }
408
+ let node = null;
409
+ try {
410
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
411
+ if (byGlobalId && byGlobalId.nodeType === "topic") {
412
+ node = byGlobalId;
413
+ }
414
+ } catch (error) {
415
+ debugGraphPrimitiveFallback(
416
+ "[topicScope] topic-node scope lookup by globalId failed",
417
+ { error, ref }
418
+ );
419
+ }
420
+ if (!node) {
421
+ return null;
422
+ }
423
+ const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
424
+ if (!scopeKey) {
425
+ return null;
426
+ }
427
+ return {
428
+ topicId: scopeKey,
429
+ projectId: asMappedProjectId(node),
430
+ source: "topic_node"
431
+ };
432
+ }
433
+ function asMappedProjectId(topic) {
434
+ if (!topic) {
435
+ return;
436
+ }
437
+ const directLegacyProjectId = normalizeScopeValue(
438
+ topic[LEGACY_SCOPE_FIELD2]
439
+ );
440
+ if (directLegacyProjectId) {
441
+ return directLegacyProjectId;
442
+ }
443
+ const metadata = topic.metadata || {};
444
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
445
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
446
+ }
447
+ function normalizeScopeValue(value) {
448
+ if (typeof value !== "string") {
449
+ return;
450
+ }
451
+ const normalized = value.trim();
452
+ return normalized.length > 0 ? normalized : void 0;
453
+ }
454
+ function pickPrimaryTopic(candidates) {
455
+ return [...candidates].sort((a, b) => {
456
+ const depthA = a.depth ?? 9999;
457
+ const depthB = b.depth ?? 9999;
458
+ if (depthA !== depthB) {
459
+ return depthA - depthB;
460
+ }
461
+ const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
462
+ const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
463
+ if (createdA !== createdB) {
464
+ return createdA - createdB;
465
+ }
466
+ return String(a.name || "").localeCompare(String(b.name || ""));
467
+ })[0];
468
+ }
469
+ async function findTopicsByScopeAlias(ctx, scopeId) {
470
+ const query2 = ctx.db.query("topics");
471
+ try {
472
+ return await query2.withIndex(
473
+ "by_graph_scope_project",
474
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
475
+ ).collect();
476
+ } catch (error) {
477
+ debugGraphPrimitiveFallback(
478
+ "[topicScope] Failed to resolve scope alias via index",
479
+ {
480
+ error,
481
+ scopeId
482
+ }
483
+ );
484
+ const topics = await query2.collect();
485
+ return topics.filter((topic) => {
486
+ const normalizedGlobalId = normalizeScopeValue(topic.globalId);
487
+ const mappedProjectId = asMappedProjectId(topic);
488
+ return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
489
+ });
490
+ }
491
+ }
492
+ async function tryResolveHostTopicById(ctx, topicId) {
493
+ if (typeof ctx.runQuery !== "function") {
494
+ return null;
495
+ }
496
+ try {
497
+ return await ctx.runQuery(api.topics.get, {
498
+ id: topicId
499
+ }) ?? null;
500
+ } catch (error) {
501
+ debugGraphPrimitiveFallback(
502
+ "[topicScope] Failed to resolve topic by host query",
503
+ {
504
+ error,
505
+ topicId
506
+ }
507
+ );
508
+ return null;
509
+ }
510
+ }
511
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
512
+ if (typeof ctx.runQuery !== "function") {
513
+ return null;
514
+ }
515
+ try {
516
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
517
+ projectId: legacyScopeId
518
+ }) ?? null;
519
+ } catch (error) {
520
+ debugGraphPrimitiveFallback(
521
+ "[topicScope] Failed to resolve topic by legacy scope",
522
+ {
523
+ error,
524
+ legacyScopeId
525
+ }
526
+ );
527
+ return null;
528
+ }
550
529
  }
551
- async function listTopicProjectOverlays(ctx, options = {}) {
552
- let allTopics = [];
553
- if (ctx?.db?.query && typeof ctx.db.query === "function") {
554
- try {
555
- allTopics = await ctx.db.query("topics").collect();
556
- } catch (error) {
557
- debugGraphPrimitiveFallback(
558
- "[topicProjectOverlay] Failed to read topics table; falling back to API",
559
- { error }
560
- );
561
- allTopics = [];
562
- }
530
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
531
+ const MAX_DEPTH = 10;
532
+ let tenantId = normalizeScopeValue(topic.tenantId);
533
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
534
+ if (tenantId && workspaceId) {
535
+ return { tenantId, workspaceId };
563
536
  }
564
- if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
565
- allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
537
+ let current = topic;
538
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
539
+ current = await ctx.db.get(current.parentTopicId);
540
+ if (!current) {
541
+ break;
542
+ }
543
+ if (!tenantId) {
544
+ tenantId = normalizeScopeValue(current.tenantId);
545
+ }
546
+ if (!workspaceId) {
547
+ workspaceId = normalizeScopeValue(current.workspaceId);
548
+ }
549
+ if (tenantId && workspaceId) {
550
+ break;
551
+ }
566
552
  }
567
- return allTopics.filter(
568
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
569
- ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
553
+ return { tenantId, workspaceId };
570
554
  }
571
- async function patchTopicProjectOverlay(ctx, scopeId, value) {
572
- const topic = await resolveTopicDoc(ctx, scopeId);
573
- if (!topic) {
574
- return null;
555
+ async function resolveTopicProjectScope(ctx, args) {
556
+ if (args.topicId) {
557
+ return await resolveScopeFromTopicId(ctx, args.topicId);
575
558
  }
576
- const nextMetadata = { ...readMetadata(topic) };
577
- const patch = {};
578
- const topicUpdateArgs = {
579
- id: String(topic._id)
580
- };
581
- for (const [key, rawValue] of Object.entries(value)) {
582
- switch (key) {
583
- case "_id":
584
- case "projectId":
585
- case "topicId":
586
- case "legacyProjectId":
587
- case "storageProjectId":
588
- break;
589
- case "name":
590
- case "description":
591
- patch[key] = rawValue;
592
- topicUpdateArgs[key] = rawValue;
593
- break;
594
- case "tenantId":
595
- case "workspaceId":
596
- case "ownerId":
597
- throw new Error(
598
- `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
599
- );
600
- case "status": {
601
- const status = coerceStatus(rawValue);
602
- if (status) {
603
- patch.status = status;
604
- topicUpdateArgs.status = status;
605
- }
606
- break;
607
- }
608
- case "visibility": {
609
- const visibility = coerceVisibility(rawValue);
610
- if (visibility) {
611
- patch.visibility = visibility;
612
- topicUpdateArgs.visibility = visibility;
613
- }
614
- break;
615
- }
616
- case "type": {
617
- const projectType = readNonEmptyString(rawValue);
618
- if (projectType) {
619
- nextMetadata.projectType = projectType;
620
- } else {
621
- delete nextMetadata.projectType;
622
- }
623
- break;
624
- }
625
- case "updatedAt":
626
- case "createdAt":
627
- break;
628
- default:
629
- if (rawValue === void 0) {
630
- delete nextMetadata[key];
631
- } else {
632
- nextMetadata[key] = rawValue;
633
- }
634
- }
559
+ if (args.projectId) {
560
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
635
561
  }
636
- patch.updatedAt = Date.now();
637
- patch.metadata = nextMetadata;
638
- topicUpdateArgs.metadata = nextMetadata;
639
- if (typeof ctx.runMutation === "function") {
640
- try {
641
- await ctx.runMutation(api.topics.update, topicUpdateArgs);
642
- } catch (error) {
643
- if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
644
- throw error;
645
- }
646
- await ctx.db.patch(String(topic._id), patch);
647
- }
648
- } else if (ctx?.db && typeof ctx.db.patch === "function") {
649
- await ctx.db.patch(String(topic._id), patch);
650
- } else {
651
- throw new Error(
652
- "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
653
- );
562
+ throw new Error(
563
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
564
+ );
565
+ }
566
+ async function resolveScopeFromTopicId(ctx, topicId) {
567
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
568
+ if (topic) {
569
+ return await buildTopicScope(ctx, topic, "topic");
654
570
  }
655
- return materializeTopicProjectOverlay({
656
- ...topic,
657
- ...patch,
658
- metadata: nextMetadata
659
- });
571
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
572
+ if (nodeScope) {
573
+ return nodeScope;
574
+ }
575
+ throw new Error(`Topic not found: ${String(topicId)}`);
660
576
  }
661
-
662
- // src/resolvers.ts
663
- function isMissingLucernChildComponentError2(error) {
664
- const message = getErrorMessage2(error);
665
- return message.includes(
666
- 'Child component ComponentName(Identifier("lucern")) not found'
667
- ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
577
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
578
+ const direct = await tryReadTopicDoc(ctx, topicId, {
579
+ failureLog: "[topicScope] Failed to load topic by direct id",
580
+ idLogKey: "topicId"
581
+ });
582
+ if (direct) {
583
+ return direct;
584
+ }
585
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
586
+ if (hostTopic) {
587
+ return hostTopic;
588
+ }
589
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
668
590
  }
669
- function getErrorMessage2(error) {
670
- if (error instanceof Error) {
671
- return error.message;
591
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
592
+ const directTopic = await resolveDirectLegacyProjectTopic(
593
+ ctx,
594
+ legacyProjectId
595
+ );
596
+ if (directTopic) {
597
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
598
+ fallbackProjectId: legacyProjectId
599
+ });
672
600
  }
673
- if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
674
- return error.message;
601
+ const primary = pickPrimaryTopic(
602
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
603
+ );
604
+ if (primary) {
605
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
606
+ fallbackProjectId: legacyProjectId
607
+ });
675
608
  }
676
- return "unknown error";
609
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
610
+ if (nodeScope) {
611
+ return {
612
+ ...nodeScope,
613
+ projectId: nodeScope.projectId ?? legacyProjectId
614
+ };
615
+ }
616
+ throw new Error(
617
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
618
+ );
677
619
  }
678
- function isAdvisoryTopicPatch(value) {
679
- const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
680
- const keys = Object.keys(value);
681
- return keys.length > 0 && keys.every((key) => advisoryKeys.has(key));
620
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
621
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
622
+ failureLog: "[topicScope] Failed to load direct project topic",
623
+ idLogKey: "projectId"
624
+ });
625
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
682
626
  }
683
- async function patchProjectWithTolerance(ctx, projectId, value) {
627
+ async function tryReadTopicDoc(ctx, id, log) {
684
628
  try {
685
- await patchTopicProjectOverlay(ctx, projectId, value);
629
+ return await ctx.db.get(id);
686
630
  } catch (error) {
687
- if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
688
- throw error;
689
- }
690
- console.warn(
691
- "[lucern graph-primitives] Non-fatal advisory topic patch failure",
692
- {
693
- projectId,
694
- keys: Object.keys(value),
695
- error: getErrorMessage2(error)
696
- }
697
- );
631
+ debugGraphPrimitiveFallback(log.failureLog, {
632
+ error,
633
+ [log.idLogKey]: id
634
+ });
635
+ return null;
698
636
  }
699
637
  }
700
- function defaultResolvers() {
701
- return {
702
- getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
703
- idMode: "legacy",
704
- projectLikeOnly: false
705
- }),
706
- patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
707
- listTopics: (ctx) => listTopicProjectOverlays(ctx, {
708
- idMode: "legacy"
709
- }),
710
- getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
711
- };
712
- }
713
- var resolverOverrides = {};
714
- function resolveGraphPrimitivesAppResolvers(_ctx) {
638
+ async function buildTopicScope(ctx, topic, source, options = {}) {
639
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
640
+ const mapped = asMappedProjectId(topic);
715
641
  return {
716
- ...defaultResolvers(),
717
- ...resolverOverrides
642
+ topicId: topic._id,
643
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
644
+ tenantId: inherited.tenantId,
645
+ workspaceId: inherited.workspaceId,
646
+ source
718
647
  };
719
648
  }
649
+ ({
650
+ projectId: v.optional(v.string()),
651
+ topicId: v.optional(v.string())
652
+ });
720
653
 
721
654
  // src/epistemicQuestions.helpers.ts
722
655
  async function markProjectGraphDirty(ctx, projectId, topicId) {
656
+ const markCacheStaleByTopic = internal.graphAnalysisCache.markCacheStaleByTopic;
723
657
  const normalizedProjectId = typeof projectId === "string" && projectId.trim().length > 0 ? projectId : void 0;
724
658
  const normalizedTopicId = typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
725
- if (!normalizedProjectId && !normalizedTopicId) {
659
+ if (!(normalizedProjectId || normalizedTopicId)) {
726
660
  return;
727
661
  }
728
662
  if (normalizedProjectId) {
@@ -735,17 +669,17 @@ async function markProjectGraphDirty(ctx, projectId, topicId) {
735
669
  );
736
670
  }
737
671
  if (normalizedTopicId) {
738
- await ctx.scheduler.runAfter(
739
- 0,
740
- internal.graphAnalysisCache.markCacheStaleByTopic,
741
- {
742
- topicId: normalizedTopicId
743
- }
744
- );
672
+ await ctx.scheduler.runAfter(0, markCacheStaleByTopic, {
673
+ topicId: normalizedTopicId
674
+ });
675
+ }
676
+ const resolvedProjectId = normalizedTopicId ?? normalizedProjectId;
677
+ if (!resolvedProjectId) {
678
+ return;
745
679
  }
746
680
  await resolveGraphPrimitivesAppResolvers().patchProject(
747
681
  ctx,
748
- normalizedTopicId ?? normalizedProjectId,
682
+ resolvedProjectId,
749
683
  {
750
684
  lastActivityAt: Date.now()
751
685
  }
@@ -754,8 +688,144 @@ async function markProjectGraphDirty(ctx, projectId, topicId) {
754
688
  function normalizeQuestionTopicId(topicId) {
755
689
  return typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
756
690
  }
691
+ function normalizeScopeValue2(value) {
692
+ if (typeof value !== "string") {
693
+ return;
694
+ }
695
+ const normalized = value.trim();
696
+ return normalized.length > 0 ? normalized : void 0;
697
+ }
698
+ function throwWorkspaceIsolationError(args) {
699
+ const error = new Error(args.message);
700
+ error.status = 409;
701
+ error.code = "INVARIANT_VIOLATION";
702
+ error.invariantCode = args.invariantCode;
703
+ error.suggestion = args.suggestion;
704
+ error.details = args.details;
705
+ throw error;
706
+ }
707
+ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
708
+ const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
709
+ const resolved = {
710
+ tenantId: normalizeScopeValue2(node?.tenantId),
711
+ workspaceId: normalizeScopeValue2(node?.workspaceId),
712
+ epistemicLayer,
713
+ nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
714
+ };
715
+ if (!node) {
716
+ return resolved;
717
+ }
718
+ if (resolved.epistemicLayer === "ontological") {
719
+ return resolved;
720
+ }
721
+ if (resolved.tenantId || resolved.workspaceId) {
722
+ return resolved;
723
+ }
724
+ const topicId = normalizeScopeValue2(node.topicId);
725
+ if (topicId) {
726
+ const topicScope = await resolveTopicProjectScope(ctx, {
727
+ topicId
728
+ });
729
+ return {
730
+ ...resolved,
731
+ tenantId: topicScope.tenantId,
732
+ workspaceId: topicScope.workspaceId
733
+ };
734
+ }
735
+ if (node.projectId) {
736
+ const topicScope = await resolveTopicProjectScope(ctx, {
737
+ projectId: String(node.projectId)
738
+ });
739
+ return {
740
+ ...resolved,
741
+ tenantId: topicScope.tenantId,
742
+ workspaceId: topicScope.workspaceId
743
+ };
744
+ }
745
+ return resolved;
746
+ }
747
+ function resolveRuntimePackMutationContext(args) {
748
+ if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
749
+ return;
750
+ }
751
+ return {
752
+ toolName: args.runtimeToolName,
753
+ packKey: args.runtimePackKey,
754
+ packInstallScope: args.runtimePackInstallScope
755
+ };
756
+ }
757
+ function assertTenantPackWorkspaceMutationAllowed(args) {
758
+ if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
759
+ return;
760
+ }
761
+ const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
762
+ const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
763
+ if (!targetWorkspaceId || targetLayer === "ontological") {
764
+ return;
765
+ }
766
+ throwWorkspaceIsolationError({
767
+ message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
768
+ invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
769
+ suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
770
+ details: {
771
+ mutationName: args.mutationName,
772
+ toolName: args.runtime.toolName,
773
+ packKey: args.runtime.packKey,
774
+ targetWorkspaceId,
775
+ targetNodeType: args.target.nodeType,
776
+ targetLayer
777
+ }
778
+ });
779
+ }
757
780
 
758
781
  // src/epistemicQuestions.lifecycle.ts
782
+ function readOptionalString(value) {
783
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
784
+ }
785
+ function readConvexId(value) {
786
+ const normalized = readOptionalString(value);
787
+ return normalized ? normalized : null;
788
+ }
789
+ function readRecord(value) {
790
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
791
+ }
792
+ function readQuestionLifecycleNode(value) {
793
+ const record = readRecord(value);
794
+ if (!record) {
795
+ return null;
796
+ }
797
+ const nodeType = readOptionalString(record.nodeType);
798
+ if (!nodeType) {
799
+ return null;
800
+ }
801
+ const node = {
802
+ metadata: readRecord(record.metadata) ?? {},
803
+ nodeType
804
+ };
805
+ const projectId = readOptionalString(record.projectId);
806
+ if (projectId !== void 0) {
807
+ node.projectId = projectId;
808
+ }
809
+ const topicId = readOptionalString(record.topicId);
810
+ if (topicId !== void 0) {
811
+ node.topicId = topicId;
812
+ }
813
+ return node;
814
+ }
815
+ function requireQuestionLifecycleNode(value) {
816
+ const node = readQuestionLifecycleNode(value);
817
+ if (node?.nodeType !== "question") {
818
+ throw new Error("Question not found");
819
+ }
820
+ return node;
821
+ }
822
+ function resolveLifecycleNodeId(args) {
823
+ const nodeId = readConvexId(args.nodeId) ?? readConvexId(args.questionId);
824
+ if (!nodeId) {
825
+ throw new Error("Missing nodeId/questionId");
826
+ }
827
+ return nodeId;
828
+ }
759
829
  var updateStatus = mutation({
760
830
  args: {
761
831
  nodeId: v.optional(v.id("epistemicNodes")),
@@ -785,25 +855,19 @@ var updateStatus = mutation({
785
855
  },
786
856
  returns: permissiveReturn,
787
857
  handler: async (ctx, args) => {
788
- const resolvedNodeId = args.nodeId ?? args.questionId;
789
- if (!resolvedNodeId) {
790
- throw new Error("Missing nodeId/questionId");
791
- }
858
+ const resolvedNodeId = resolveLifecycleNodeId(args);
792
859
  const resolvedUserId = args.userId || await getCurrentUserId(ctx);
793
860
  if (!resolvedUserId) {
794
861
  throw new Error("Not authenticated");
795
862
  }
796
- const node = await ctx.db.get(resolvedNodeId);
797
- if (!node || node.nodeType !== "question") {
798
- throw new Error("Question not found");
799
- }
863
+ const node = requireQuestionLifecycleNode(await ctx.db.get(resolvedNodeId));
800
864
  assertTenantPackWorkspaceMutationAllowed({
801
865
  runtime: resolveRuntimePackMutationContext(args),
802
866
  target: await resolveNodeScopeForWorkspaceIsolation(ctx, node),
803
867
  mutationName: "epistemicQuestions.updateStatus"
804
868
  });
805
869
  const now = Date.now();
806
- const metadata = node.metadata || {};
870
+ const metadata = node.metadata;
807
871
  const previousStatus = metadata.questionStatus || "open";
808
872
  await ctx.db.patch(resolvedNodeId, {
809
873
  updatedAt: now,
@@ -857,12 +921,9 @@ var updatePriority = mutation({
857
921
  },
858
922
  returns: permissiveReturn,
859
923
  handler: async (ctx, args) => {
860
- const node = await ctx.db.get(args.nodeId);
861
- if (!node || node.nodeType !== "question") {
862
- throw new Error("Question not found");
863
- }
924
+ const node = requireQuestionLifecycleNode(await ctx.db.get(args.nodeId));
864
925
  const now = Date.now();
865
- const metadata = node.metadata || {};
926
+ const metadata = node.metadata;
866
927
  const previousPriority = metadata.priority || "medium";
867
928
  await ctx.db.patch(args.nodeId, {
868
929
  updatedAt: now,