@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,14 +1,25 @@
1
1
  import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
2
- import { componentsGeneric, anyApi, mutationGeneric, internalMutationGeneric, queryGeneric, internalQueryGeneric } from 'convex/server';
2
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
3
+ import { componentsGeneric, mutationGeneric, internalMutationGeneric, queryGeneric, internalQueryGeneric } from 'convex/server';
3
4
  import { v } from 'convex/values';
4
- import { requireProjectAccess, checkProjectAccess, checkScopeAccess } from '@lucern/access-control/access';
5
+ import { requireScopeWriteAccess, checkScopeAccess } from '@lucern/access-control/access';
6
+ import { EVIDENCE_SOURCE_QUALITY_VALUES, EVIDENCE_METHODOLOGY_VALUES, EVIDENCE_INFORMATION_ASYMMETRY_VALUES, assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
5
7
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
6
8
  import { generateGlobalId, assertUuidV7Identity, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
7
9
  import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
8
- import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
9
10
  import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
10
11
 
11
12
  // src/epistemicEvidenceHelpers.ts
13
+ var unsafeApi = unsafeConvexAnyApi(
14
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
15
+ );
16
+ var api = unsafeApi;
17
+ componentsGeneric();
18
+ var internal = unsafeApi;
19
+ var internalMutation = internalMutationGeneric;
20
+ var internalQuery = internalQueryGeneric;
21
+ var mutation = mutationGeneric;
22
+ var query = queryGeneric;
12
23
 
13
24
  // src/debug.ts
14
25
  function isGraphPrimitiveDebugEnabled() {
@@ -21,13 +32,6 @@ function debugGraphPrimitiveFallback(message, context) {
21
32
  }
22
33
  console.debug(message, context ?? {});
23
34
  }
24
- var api = anyApi;
25
- componentsGeneric();
26
- var internal = anyApi;
27
- var internalMutation = internalMutationGeneric;
28
- var internalQuery = internalQueryGeneric;
29
- var mutation = mutationGeneric;
30
- var query = queryGeneric;
31
35
 
32
36
  // src/topicProjectOverlay.ts
33
37
  var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
@@ -47,6 +51,10 @@ function readStringArray(value) {
47
51
  function readMetadata(topic) {
48
52
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
49
53
  }
54
+ function omitMetadataKey(metadata, key) {
55
+ const { [key]: _omitted, ...rest } = metadata;
56
+ return rest;
57
+ }
50
58
  function readLegacyProjectId(value) {
51
59
  if (!value) {
52
60
  return;
@@ -127,9 +135,12 @@ async function resolveTopicDoc(ctx, scopeId) {
127
135
  );
128
136
  }
129
137
  try {
130
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
131
- projectId: String(scopeId)
132
- });
138
+ const topic = await ctx.runQuery(
139
+ api.topics.getByLegacyScopeId,
140
+ {
141
+ projectId: String(scopeId)
142
+ }
143
+ );
133
144
  if (topic?.name !== void 0 && topic?.type !== void 0) {
134
145
  return topic;
135
146
  }
@@ -149,8 +160,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
149
160
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
150
161
  const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
151
162
  const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
152
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
153
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
163
+ let createdAt = 0;
164
+ if (typeof topic.createdAt === "number") {
165
+ createdAt = topic.createdAt;
166
+ } else if (typeof topic._creationTime === "number") {
167
+ createdAt = topic._creationTime;
168
+ }
169
+ let updatedAt = createdAt;
170
+ if (typeof topic.updatedAt === "number") {
171
+ updatedAt = topic.updatedAt;
172
+ } else if (typeof metadata.updatedAt === "number") {
173
+ updatedAt = metadata.updatedAt;
174
+ }
154
175
  return {
155
176
  ...metadata,
156
177
  _id: outwardId,
@@ -219,90 +240,113 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
219
240
  if (!topic) {
220
241
  return null;
221
242
  }
222
- const nextMetadata = { ...readMetadata(topic) };
223
- const patch = {};
224
- const topicUpdateArgs = {
225
- id: String(topic._id)
243
+ const plan = buildTopicProjectOverlayPatchPlan(topic, value);
244
+ await applyTopicProjectOverlayPatch(ctx, topic, plan);
245
+ return materializeTopicProjectOverlay({
246
+ ...topic,
247
+ ...plan.patch,
248
+ metadata: plan.nextMetadata
249
+ });
250
+ }
251
+ function buildTopicProjectOverlayPatchPlan(topic, value) {
252
+ const plan = {
253
+ nextMetadata: { ...readMetadata(topic) },
254
+ patch: {},
255
+ topicUpdateArgs: {
256
+ id: String(topic._id)
257
+ }
226
258
  };
227
259
  for (const [key, rawValue] of Object.entries(value)) {
228
- switch (key) {
229
- case "_id":
230
- case "projectId":
231
- case "topicId":
232
- case "legacyProjectId":
233
- case "storageProjectId":
234
- break;
235
- case "name":
236
- case "description":
237
- patch[key] = rawValue;
238
- topicUpdateArgs[key] = rawValue;
239
- break;
240
- case "tenantId":
241
- case "workspaceId":
242
- case "ownerId":
243
- throw new Error(
244
- `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
245
- );
246
- case "status": {
247
- const status = coerceStatus(rawValue);
248
- if (status) {
249
- patch.status = status;
250
- topicUpdateArgs.status = status;
251
- }
252
- break;
253
- }
254
- case "visibility": {
255
- const visibility = coerceVisibility(rawValue);
256
- if (visibility) {
257
- patch.visibility = visibility;
258
- topicUpdateArgs.visibility = visibility;
259
- }
260
- break;
261
- }
262
- case "type": {
263
- const projectType = readNonEmptyString(rawValue);
264
- if (projectType) {
265
- nextMetadata.projectType = projectType;
266
- } else {
267
- delete nextMetadata.projectType;
268
- }
269
- break;
270
- }
271
- case "updatedAt":
272
- case "createdAt":
273
- break;
274
- default:
275
- if (rawValue === void 0) {
276
- delete nextMetadata[key];
277
- } else {
278
- nextMetadata[key] = rawValue;
279
- }
280
- }
260
+ applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
281
261
  }
282
- patch.updatedAt = Date.now();
283
- patch.metadata = nextMetadata;
284
- topicUpdateArgs.metadata = nextMetadata;
262
+ plan.patch.updatedAt = Date.now();
263
+ plan.patch.metadata = plan.nextMetadata;
264
+ plan.topicUpdateArgs.metadata = plan.nextMetadata;
265
+ return plan;
266
+ }
267
+ function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
268
+ switch (key) {
269
+ case "_id":
270
+ case "projectId":
271
+ case "topicId":
272
+ case "legacyProjectId":
273
+ case "storageProjectId":
274
+ case "updatedAt":
275
+ case "createdAt":
276
+ return;
277
+ case "name":
278
+ case "description":
279
+ plan.patch[key] = rawValue;
280
+ plan.topicUpdateArgs[key] = rawValue;
281
+ return;
282
+ case "tenantId":
283
+ case "workspaceId":
284
+ case "ownerId":
285
+ throw new Error(
286
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
287
+ );
288
+ case "status":
289
+ applyTopicStatusPatch(plan, rawValue);
290
+ return;
291
+ case "visibility":
292
+ applyTopicVisibilityPatch(plan, rawValue);
293
+ return;
294
+ case "type":
295
+ applyTopicProjectTypePatch(plan, rawValue);
296
+ return;
297
+ default:
298
+ applyTopicMetadataPatch(plan, key, rawValue);
299
+ }
300
+ }
301
+ function applyTopicStatusPatch(plan, rawValue) {
302
+ const status = coerceStatus(rawValue);
303
+ if (status) {
304
+ plan.patch.status = status;
305
+ plan.topicUpdateArgs.status = status;
306
+ }
307
+ }
308
+ function applyTopicVisibilityPatch(plan, rawValue) {
309
+ const visibility = coerceVisibility(rawValue);
310
+ if (visibility) {
311
+ plan.patch.visibility = visibility;
312
+ plan.topicUpdateArgs.visibility = visibility;
313
+ }
314
+ }
315
+ function applyTopicProjectTypePatch(plan, rawValue) {
316
+ const projectType = readNonEmptyString(rawValue);
317
+ if (projectType) {
318
+ plan.nextMetadata.projectType = projectType;
319
+ return;
320
+ }
321
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
322
+ }
323
+ function applyTopicMetadataPatch(plan, key, rawValue) {
324
+ if (rawValue === void 0) {
325
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
326
+ return;
327
+ }
328
+ plan.nextMetadata[key] = rawValue;
329
+ }
330
+ async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
285
331
  if (typeof ctx.runMutation === "function") {
286
332
  try {
287
- await ctx.runMutation(api.topics.update, topicUpdateArgs);
333
+ await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
288
334
  } catch (error) {
289
- if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
335
+ if (!canPatchTopicViaLocalDb(ctx, error)) {
290
336
  throw error;
291
337
  }
292
- await ctx.db.patch(String(topic._id), patch);
338
+ await ctx.db.patch(topic._id, plan.patch);
293
339
  }
294
340
  } else if (ctx?.db && typeof ctx.db.patch === "function") {
295
- await ctx.db.patch(String(topic._id), patch);
341
+ await ctx.db.patch(topic._id, plan.patch);
296
342
  } else {
297
343
  throw new Error(
298
344
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
299
345
  );
300
346
  }
301
- return materializeTopicProjectOverlay({
302
- ...topic,
303
- ...patch,
304
- metadata: nextMetadata
305
- });
347
+ }
348
+ function canPatchTopicViaLocalDb(ctx, error) {
349
+ return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
306
350
  }
307
351
 
308
352
  // src/resolvers.ts
@@ -330,7 +374,7 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
330
374
  try {
331
375
  await patchTopicProjectOverlay(ctx, projectId, value);
332
376
  } catch (error) {
333
- if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
377
+ if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
334
378
  throw error;
335
379
  }
336
380
  console.warn(
@@ -397,13 +441,15 @@ function asMappedProjectId(topic) {
397
441
  if (!topic) {
398
442
  return;
399
443
  }
400
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD2]);
444
+ const directLegacyProjectId = normalizeScopeValue(
445
+ topic[LEGACY_SCOPE_FIELD2]
446
+ );
401
447
  if (directLegacyProjectId) {
402
448
  return directLegacyProjectId;
403
449
  }
404
450
  const metadata = topic.metadata || {};
405
451
  const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
406
- return candidate ? candidate : void 0;
452
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
407
453
  }
408
454
  function normalizeScopeValue(value) {
409
455
  if (typeof value !== "string") {
@@ -428,8 +474,9 @@ function pickPrimaryTopic(candidates) {
428
474
  })[0];
429
475
  }
430
476
  async function findTopicsByScopeAlias(ctx, scopeId) {
477
+ const query2 = ctx.db.query("topics");
431
478
  try {
432
- return await ctx.db.query("topics").withIndex(
479
+ return await query2.withIndex(
433
480
  "by_graph_scope_project",
434
481
  (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
435
482
  ).collect();
@@ -441,7 +488,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
441
488
  scopeId
442
489
  }
443
490
  );
444
- const topics = await ctx.db.query("topics").collect();
491
+ const topics = await query2.collect();
445
492
  return topics.filter((topic) => {
446
493
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
447
494
  const mappedProjectId = asMappedProjectId(topic);
@@ -497,137 +544,115 @@ async function resolveInheritedWorkspaceScope(ctx, topic) {
497
544
  let current = topic;
498
545
  for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
499
546
  current = await ctx.db.get(current.parentTopicId);
500
- if (!current) break;
547
+ if (!current) {
548
+ break;
549
+ }
501
550
  if (!tenantId) {
502
551
  tenantId = normalizeScopeValue(current.tenantId);
503
552
  }
504
553
  if (!workspaceId) {
505
554
  workspaceId = normalizeScopeValue(current.workspaceId);
506
555
  }
507
- if (tenantId && workspaceId) break;
556
+ if (tenantId && workspaceId) {
557
+ break;
558
+ }
508
559
  }
509
560
  return { tenantId, workspaceId };
510
561
  }
511
562
  async function resolveTopicProjectScope(ctx, args) {
512
563
  if (args.topicId) {
513
- let topic = null;
514
- try {
515
- topic = await ctx.db.get(
516
- args.topicId
517
- );
518
- } catch (error) {
519
- debugGraphPrimitiveFallback(
520
- "[topicScope] Failed to load topic by direct id",
521
- {
522
- error,
523
- topicId: args.topicId
524
- }
525
- );
526
- }
527
- if (!topic) {
528
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
529
- }
530
- if (!topic) {
531
- topic = pickPrimaryTopic(
532
- await findTopicsByScopeAlias(ctx, String(args.topicId))
533
- ) ?? null;
534
- }
535
- if (!topic) {
536
- const nodeScope = await resolveTopicNodeScopeOrNull(
537
- ctx,
538
- String(args.topicId)
539
- );
540
- if (nodeScope) {
541
- return nodeScope;
542
- }
543
- throw new Error(`Topic not found: ${String(args.topicId)}`);
544
- }
545
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
546
- const mapped = asMappedProjectId(topic);
547
- if (mapped) {
548
- return {
549
- topicId: topic._id,
550
- projectId: mapped,
551
- tenantId: inherited.tenantId,
552
- workspaceId: inherited.workspaceId,
553
- source: "topic"
554
- };
555
- }
556
- return {
557
- topicId: topic._id,
558
- tenantId: inherited.tenantId,
559
- workspaceId: inherited.workspaceId,
560
- source: "topic"
561
- };
564
+ return await resolveScopeFromTopicId(ctx, args.topicId);
562
565
  }
563
566
  if (args.projectId) {
564
- let directTopic = null;
565
- try {
566
- directTopic = await ctx.db.get(
567
- args.projectId
568
- );
569
- } catch (error) {
570
- debugGraphPrimitiveFallback(
571
- "[topicScope] Failed to load direct project topic",
572
- {
573
- error,
574
- projectId: args.projectId
575
- }
576
- );
577
- }
578
- if (directTopic) {
579
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
580
- const mapped = asMappedProjectId(directTopic);
581
- return {
582
- topicId: directTopic._id,
583
- projectId: mapped ?? args.projectId,
584
- tenantId: inherited.tenantId,
585
- workspaceId: inherited.workspaceId,
586
- source: "topic_inferred"
587
- };
588
- }
589
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
590
- if (directTopic) {
591
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
592
- const mapped = asMappedProjectId(directTopic);
593
- return {
594
- topicId: directTopic._id,
595
- projectId: mapped ?? args.projectId,
596
- tenantId: inherited.tenantId,
597
- workspaceId: inherited.workspaceId,
598
- source: "topic_inferred"
599
- };
600
- }
601
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
602
- const primary = pickPrimaryTopic(topics);
603
- if (primary) {
604
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
605
- return {
606
- topicId: primary._id,
607
- projectId: args.projectId,
608
- tenantId: inherited.tenantId,
609
- workspaceId: inherited.workspaceId,
610
- source: "project_mapped_topic"
611
- };
612
- }
613
- const nodeScope = await resolveTopicNodeScopeOrNull(
614
- ctx,
615
- String(args.projectId)
616
- );
617
- if (nodeScope) {
618
- return {
619
- ...nodeScope,
620
- projectId: nodeScope.projectId ?? String(args.projectId)
621
- };
622
- }
623
- throw new Error(
624
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
625
- );
567
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
626
568
  }
627
569
  throw new Error(
628
570
  "Missing scope: provide topicId (preferred) or legacy projectId alias."
629
571
  );
630
572
  }
573
+ async function resolveScopeFromTopicId(ctx, topicId) {
574
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
575
+ if (topic) {
576
+ return await buildTopicScope(ctx, topic, "topic");
577
+ }
578
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
579
+ if (nodeScope) {
580
+ return nodeScope;
581
+ }
582
+ throw new Error(`Topic not found: ${String(topicId)}`);
583
+ }
584
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
585
+ const direct = await tryReadTopicDoc(ctx, topicId, {
586
+ failureLog: "[topicScope] Failed to load topic by direct id",
587
+ idLogKey: "topicId"
588
+ });
589
+ if (direct) {
590
+ return direct;
591
+ }
592
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
593
+ if (hostTopic) {
594
+ return hostTopic;
595
+ }
596
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
597
+ }
598
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
599
+ const directTopic = await resolveDirectLegacyProjectTopic(
600
+ ctx,
601
+ legacyProjectId
602
+ );
603
+ if (directTopic) {
604
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
605
+ fallbackProjectId: legacyProjectId
606
+ });
607
+ }
608
+ const primary = pickPrimaryTopic(
609
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
610
+ );
611
+ if (primary) {
612
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
613
+ fallbackProjectId: legacyProjectId
614
+ });
615
+ }
616
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
617
+ if (nodeScope) {
618
+ return {
619
+ ...nodeScope,
620
+ projectId: nodeScope.projectId ?? legacyProjectId
621
+ };
622
+ }
623
+ throw new Error(
624
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
625
+ );
626
+ }
627
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
628
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
629
+ failureLog: "[topicScope] Failed to load direct project topic",
630
+ idLogKey: "projectId"
631
+ });
632
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
633
+ }
634
+ async function tryReadTopicDoc(ctx, id, log) {
635
+ try {
636
+ return await ctx.db.get(id);
637
+ } catch (error) {
638
+ debugGraphPrimitiveFallback(log.failureLog, {
639
+ error,
640
+ [log.idLogKey]: id
641
+ });
642
+ return null;
643
+ }
644
+ }
645
+ async function buildTopicScope(ctx, topic, source, options = {}) {
646
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
647
+ const mapped = asMappedProjectId(topic);
648
+ return {
649
+ topicId: topic._id,
650
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
651
+ tenantId: inherited.tenantId,
652
+ workspaceId: inherited.workspaceId,
653
+ source
654
+ };
655
+ }
631
656
  var optionalScopeArgs = {
632
657
  projectId: v.optional(v.string()),
633
658
  topicId: v.optional(v.string())
@@ -670,7 +695,7 @@ function normalizeSourceType(sourceType) {
670
695
  async function markProjectGraphDirty(ctx, projectId, topicId) {
671
696
  const normalizedProjectId = typeof projectId === "string" && projectId.trim().length > 0 ? projectId : void 0;
672
697
  const normalizedTopicId = typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
673
- if (!normalizedProjectId && !normalizedTopicId) {
698
+ if (!(normalizedProjectId || normalizedTopicId)) {
674
699
  return;
675
700
  }
676
701
  if (normalizedProjectId) {
@@ -691,9 +716,15 @@ async function markProjectGraphDirty(ctx, projectId, topicId) {
691
716
  }
692
717
  );
693
718
  }
719
+ const activityScopeId = normalizedTopicId ?? normalizedProjectId;
720
+ if (!activityScopeId) {
721
+ throw new Error(
722
+ "Expected evidence graph dirty scope to include a topic or project id."
723
+ );
724
+ }
694
725
  await resolveGraphPrimitivesAppResolvers().patchProject(
695
726
  ctx,
696
- normalizedTopicId ?? normalizedProjectId,
727
+ activityScopeId,
697
728
  {
698
729
  lastActivityAt: Date.now()
699
730
  }
@@ -722,7 +753,15 @@ function dedupeEvidenceNodes(nodes) {
722
753
  return deduped;
723
754
  }
724
755
  function evidenceMatchesScope(node, scope) {
725
- return scope.topicId !== void 0 && node.topicId === scope.topicId || scope.projectId !== void 0 && node.projectId === scope.projectId;
756
+ const record = node && typeof node === "object" && !Array.isArray(node) ? node : null;
757
+ if (!record) {
758
+ return false;
759
+ }
760
+ const nodeTopicId = typeof record.topicId === "string" ? record.topicId : void 0;
761
+ const nodeProjectId = typeof record.projectId === "string" ? record.projectId : void 0;
762
+ const scopeTopicId = scope.topicId === void 0 ? void 0 : String(scope.topicId);
763
+ const scopeProjectId = scope.projectId === void 0 ? void 0 : String(scope.projectId);
764
+ return scopeTopicId !== void 0 && nodeTopicId === scopeTopicId || scopeProjectId !== void 0 && nodeProjectId === scopeProjectId;
726
765
  }
727
766
  function resolveEvidenceLinkedWorktreeId(metadata) {
728
767
  const worktreeId = metadata?.linkedWorktreeId;
@@ -733,7 +772,7 @@ function resolveEvidenceLinkedWorktreeId(metadata) {
733
772
  return typeof sprintId === "string" && sprintId.trim().length > 0 ? sprintId : void 0;
734
773
  }
735
774
  async function resolveEvidenceScopeOrNull(ctx, args) {
736
- if (!args.projectId && !args.topicId) {
775
+ if (!(args.projectId || args.topicId)) {
737
776
  return null;
738
777
  }
739
778
  try {
@@ -829,22 +868,19 @@ function formatEvidenceNode(n) {
829
868
  }
830
869
 
831
870
  // src/embeddingTrigger.ts
871
+ var embeddingActionRef = "embeddingActions:generateEpistemicNodeEmbedding";
832
872
  async function scheduleEmbeddingGeneration(args) {
833
873
  try {
834
- await args.ctx.scheduler.runAfter(
835
- 0,
836
- "embeddingActions:generateEpistemicNodeEmbedding",
837
- {
838
- nodeId: args.nodeId,
839
- projectId: args.projectId ? String(args.projectId) : void 0,
840
- topicId: args.topicId ? String(args.topicId) : void 0,
841
- createdBy: args.createdBy,
842
- nodeType: args.nodeType,
843
- text: args.text.slice(0, 2e4),
844
- hasAnswer: args.hasAnswer,
845
- confidence: args.confidence
846
- }
847
- );
874
+ await args.ctx.scheduler.runAfter(0, embeddingActionRef, {
875
+ nodeId: args.nodeId,
876
+ projectId: args.projectId ? String(args.projectId) : void 0,
877
+ topicId: args.topicId ? String(args.topicId) : void 0,
878
+ createdBy: args.createdBy,
879
+ nodeType: args.nodeType,
880
+ text: args.text.slice(0, 2e4),
881
+ hasAnswer: args.hasAnswer,
882
+ confidence: args.confidence
883
+ });
848
884
  } catch (error) {
849
885
  debugGraphPrimitiveFallback(
850
886
  "[embeddingTrigger] Failed to schedule embedding generation",
@@ -856,6 +892,55 @@ async function scheduleEmbeddingGeneration(args) {
856
892
  );
857
893
  }
858
894
  }
895
+ function insertEpistemicNode(ctx, doc) {
896
+ assertUuidV7Identity("epistemicNodes", doc.globalId);
897
+ return ctx.db.insert("epistemicNodes", doc);
898
+ }
899
+ async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
900
+ assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
901
+ const node = await ctx.db.query("epistemicNodes").withIndex(
902
+ "by_globalId",
903
+ (q) => q.eq("globalId", endpoint)
904
+ ).first();
905
+ if (!node) {
906
+ throw new Error(
907
+ `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
908
+ );
909
+ }
910
+ }
911
+ async function insertEpistemicEdge(ctx, doc) {
912
+ assertUuidV7Identity("epistemicEdges", doc.globalId);
913
+ assertStorageEdgeVocabulary(doc.edgeType);
914
+ if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
915
+ throw new Error(
916
+ "edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
917
+ );
918
+ }
919
+ if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
920
+ throw new Error(
921
+ "edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
922
+ );
923
+ }
924
+ await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
925
+ await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
926
+ if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
927
+ assertEdgePolicyAllowed(
928
+ edgePolicyManifest,
929
+ doc.edgeType,
930
+ {
931
+ kind: "epistemic_node",
932
+ nodeId: doc.fromNodeId,
933
+ nodeType: doc.fromNodeType
934
+ },
935
+ {
936
+ kind: "epistemic_node",
937
+ nodeId: doc.toNodeId,
938
+ nodeType: doc.toNodeType
939
+ }
940
+ );
941
+ }
942
+ return ctx.db.insert("epistemicEdges", doc);
943
+ }
859
944
  function normalizeScopeValue2(value) {
860
945
  if (typeof value !== "string") {
861
946
  return;
@@ -917,7 +1002,7 @@ function nodeMatchesWorkspaceReasoningScope(node, scope) {
917
1002
  return scopeWorkspaceId === nodeWorkspaceId;
918
1003
  }
919
1004
  function resolveRuntimePackMutationContext(args) {
920
- if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
1005
+ if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
921
1006
  return;
922
1007
  }
923
1008
  return {
@@ -949,54 +1034,118 @@ function assertTenantPackWorkspaceMutationAllowed(args) {
949
1034
  }
950
1035
  });
951
1036
  }
952
- async function insertEpistemicNode(ctx, doc) {
953
- assertUuidV7Identity("epistemicNodes", doc.globalId);
954
- return ctx.db.insert("epistemicNodes", doc);
1037
+
1038
+ // src/epistemicEvidenceMutations.ts
1039
+ var EMBEDDING_GENERATION_ACTION = "embeddingActions:generateEpistemicNodeEmbedding";
1040
+ function isRecord(value) {
1041
+ return typeof value === "object" && value !== null && !Array.isArray(value);
955
1042
  }
956
- async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
957
- assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
958
- const node = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", endpoint)).first();
959
- if (!node) {
960
- throw new Error(
961
- `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
962
- );
1043
+ function metadataRecord(value) {
1044
+ return isRecord(value) ? value : {};
1045
+ }
1046
+ function readOptionalString(value) {
1047
+ if (typeof value !== "string") {
1048
+ return;
963
1049
  }
1050
+ const trimmed = value.trim();
1051
+ return trimmed.length > 0 ? trimmed : void 0;
964
1052
  }
965
- async function insertEpistemicEdge(ctx, doc) {
966
- assertUuidV7Identity("epistemicEdges", doc.globalId);
967
- assertStorageEdgeVocabulary(doc.edgeType);
968
- if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
969
- throw new Error(
970
- "edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
971
- );
1053
+ function readConvexId(value) {
1054
+ const normalized = readOptionalString(value);
1055
+ return normalized;
1056
+ }
1057
+ function assertBeliefNode(node, errorMessage) {
1058
+ if (!isRecord(node) || node.nodeType !== "belief" || typeof node.globalId !== "string") {
1059
+ throw new Error(errorMessage);
972
1060
  }
973
- if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
974
- throw new Error(
975
- "edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
976
- );
1061
+ return node;
1062
+ }
1063
+ function assertEvidenceNode(node, errorMessage) {
1064
+ if (!isRecord(node)) {
1065
+ throw new Error(errorMessage);
977
1066
  }
978
- await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
979
- await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
980
- if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
981
- assertEdgePolicyAllowed(
982
- edgePolicyManifest,
983
- doc.edgeType,
984
- {
985
- kind: "epistemic_node",
986
- nodeId: doc.fromNodeId,
987
- nodeType: doc.fromNodeType
988
- },
989
- {
990
- kind: "epistemic_node",
991
- nodeId: doc.toNodeId,
992
- nodeType: doc.toNodeType
1067
+ const id = readConvexId(node._id);
1068
+ if (!(id && node.nodeType === "evidence")) {
1069
+ throw new Error(errorMessage);
1070
+ }
1071
+ const evidence = { _id: id, nodeType: "evidence" };
1072
+ const canonicalText = readOptionalString(node.canonicalText);
1073
+ if (canonicalText !== void 0) {
1074
+ evidence.canonicalText = canonicalText;
1075
+ }
1076
+ const createdBy = readOptionalString(node.createdBy);
1077
+ if (createdBy !== void 0) {
1078
+ evidence.createdBy = createdBy;
1079
+ }
1080
+ if ("metadata" in node) {
1081
+ evidence.metadata = node.metadata;
1082
+ }
1083
+ const projectId = readOptionalString(node.projectId);
1084
+ if (projectId !== void 0) {
1085
+ evidence.projectId = projectId;
1086
+ }
1087
+ const status = readOptionalString(node.status);
1088
+ if (status !== void 0) {
1089
+ evidence.status = status;
1090
+ }
1091
+ const topicId = readOptionalString(node.topicId);
1092
+ if (topicId !== void 0) {
1093
+ evidence.topicId = topicId;
1094
+ }
1095
+ return evidence;
1096
+ }
1097
+ function readEvidenceNodeOrNull(node) {
1098
+ if (!isRecord(node) || node.nodeType !== "evidence") {
1099
+ return null;
1100
+ }
1101
+ try {
1102
+ return assertEvidenceNode(node, "Evidence node not found");
1103
+ } catch {
1104
+ return null;
1105
+ }
1106
+ }
1107
+ function optionalTrimmedString(value) {
1108
+ if (typeof value !== "string") {
1109
+ return;
1110
+ }
1111
+ const trimmed = value.trim();
1112
+ return trimmed.length > 0 ? trimmed : void 0;
1113
+ }
1114
+ async function resolveEvidenceNodeId(ctx, args) {
1115
+ if (args.nodeId) {
1116
+ return args.nodeId;
1117
+ }
1118
+ const insightId = readOptionalString(args.insightId);
1119
+ if (!insightId) {
1120
+ throw new Error("Either nodeId or insightId is required");
1121
+ }
1122
+ const normalizedId = ctx.db.normalizeId?.("epistemicNodes", insightId) ?? readConvexId(insightId);
1123
+ if (normalizedId) {
1124
+ try {
1125
+ const direct = readEvidenceNodeOrNull(await ctx.db.get(normalizedId));
1126
+ if (direct) {
1127
+ return direct._id;
993
1128
  }
994
- );
1129
+ } catch {
1130
+ }
995
1131
  }
996
- return ctx.db.insert("epistemicEdges", doc);
1132
+ const byGlobalId = readEvidenceNodeOrNull(
1133
+ await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", insightId)).first()
1134
+ );
1135
+ if (!byGlobalId) {
1136
+ throw new Error("Evidence node not found");
1137
+ }
1138
+ return byGlobalId._id;
1139
+ }
1140
+ function optionalLiteral(values, value, fieldName) {
1141
+ if (typeof value !== "string" || value.length === 0) {
1142
+ return;
1143
+ }
1144
+ if (values.includes(value)) {
1145
+ return value;
1146
+ }
1147
+ throw new Error(`Evidence ${fieldName} must be one of: ${values.join(", ")}`);
997
1148
  }
998
-
999
- // src/epistemicEvidenceMutations.ts
1000
1149
  function assertSignedImpactScore(value, context) {
1001
1150
  if (typeof value !== "number" || !Number.isFinite(value) || value === 0 || value < -1 || value > 1) {
1002
1151
  throw new Error(`${context} requires explicit nonzero weight in [-1, 1]`);
@@ -1009,12 +1158,121 @@ function normalizeEvidenceRelation(relation, weight, context) {
1009
1158
  throw new Error(`${context} supports relation requires positive weight`);
1010
1159
  }
1011
1160
  if (relation === "contradicts" && weight > 0) {
1012
- throw new Error(`${context} contradicts relation requires negative weight`);
1161
+ throw new Error(
1162
+ `${context} contradicts relation requires negative weight`
1163
+ );
1013
1164
  }
1014
1165
  return relation;
1015
1166
  }
1016
1167
  return weight < 0 ? "contradicts" : "supports";
1017
1168
  }
1169
+ function planEvidenceImpact(args, context) {
1170
+ const weight = assertSignedImpactScore(args.weight, context);
1171
+ const signedImpact = args.signedImpact === void 0 ? weight : assertSignedImpactScore(args.signedImpact, `${context} signedImpact`);
1172
+ return {
1173
+ confidence: Math.abs(weight),
1174
+ evidenceRelation: normalizeEvidenceRelation(
1175
+ args.evidenceRelation,
1176
+ weight,
1177
+ context
1178
+ ),
1179
+ signedImpact,
1180
+ weight
1181
+ };
1182
+ }
1183
+ function evidenceTaxonomyProjection(args) {
1184
+ const sourceRef = optionalTrimmedString(args.sourceRef);
1185
+ const sourceQuality = optionalLiteral(
1186
+ EVIDENCE_SOURCE_QUALITY_VALUES,
1187
+ args.sourceQuality,
1188
+ "sourceQuality"
1189
+ );
1190
+ const methodology = optionalLiteral(
1191
+ EVIDENCE_METHODOLOGY_VALUES,
1192
+ args.methodology,
1193
+ "methodology"
1194
+ );
1195
+ const informationAsymmetry = optionalLiteral(
1196
+ EVIDENCE_INFORMATION_ASYMMETRY_VALUES,
1197
+ args.informationAsymmetry,
1198
+ "informationAsymmetry"
1199
+ );
1200
+ const sourceDescription = optionalTrimmedString(args.sourceDescription);
1201
+ return {
1202
+ ...sourceRef ? { sourceRef } : {},
1203
+ ...sourceQuality ? { sourceQuality } : {},
1204
+ ...methodology ? { methodology } : {},
1205
+ ...informationAsymmetry ? { informationAsymmetry } : {},
1206
+ ...sourceDescription ? { sourceDescription } : {}
1207
+ };
1208
+ }
1209
+ function evidenceTextProjection(args) {
1210
+ const title = optionalTrimmedString(args.title);
1211
+ const contentType = optionalTrimmedString(args.contentType);
1212
+ return {
1213
+ ...title ? { title } : {},
1214
+ ...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
1215
+ ...contentType ? { contentType } : {}
1216
+ };
1217
+ }
1218
+ function evidenceMetadata(args, impact, kind, profile) {
1219
+ const base = {
1220
+ kind,
1221
+ tags: args.tags || [],
1222
+ linkedBeliefNodeId: args.linkedBeliefNodeId,
1223
+ evidenceRelation: impact.evidenceRelation,
1224
+ confidence: impact.confidence,
1225
+ weight: impact.weight,
1226
+ impactScore: impact.weight
1227
+ };
1228
+ const sourceContext = profile === "createAndLink" ? {} : {
1229
+ externalSourceType: args.externalSourceType,
1230
+ sourceUrl: args.sourceUrl,
1231
+ sourceQuestionId: args.sourceQuestionId,
1232
+ rationale: args.rationale
1233
+ };
1234
+ const publicCreateTaxonomy = profile === "create" ? {
1235
+ methodology: args.methodology,
1236
+ informationAsymmetry: args.informationAsymmetry,
1237
+ sourceDescription: args.sourceDescription
1238
+ } : {};
1239
+ return {
1240
+ ...base,
1241
+ ...sourceContext,
1242
+ ...publicCreateTaxonomy,
1243
+ ...metadataRecord(args.metadata)
1244
+ };
1245
+ }
1246
+ function buildEvidenceNodeInsert(args) {
1247
+ return {
1248
+ globalId: args.globalId,
1249
+ topicId: args.scope.topicId,
1250
+ projectId: args.scope.projectId,
1251
+ tenantId: args.scope.tenantId,
1252
+ workspaceId: args.scope.workspaceId,
1253
+ nodeType: "evidence",
1254
+ canonicalText: args.write.text,
1255
+ contentHash: generateContentHash(args.write.text),
1256
+ ...evidenceTextProjection(args.write),
1257
+ status: "active",
1258
+ epistemicLayer: "L2",
1259
+ sourceType: args.sourceType,
1260
+ // RC.1 taxonomy fields — top-level projection
1261
+ evidenceRelation: args.impact.evidenceRelation,
1262
+ signedImpact: args.impact.signedImpact,
1263
+ targetBeliefId: String(args.linkedBeliefNodeId),
1264
+ ...evidenceTaxonomyProjection(args.write),
1265
+ createdAt: args.now,
1266
+ updatedAt: args.now,
1267
+ createdBy: args.write.userId,
1268
+ metadata: evidenceMetadata(
1269
+ args.write,
1270
+ args.impact,
1271
+ args.kind,
1272
+ args.metadataProfile
1273
+ )
1274
+ };
1275
+ }
1018
1276
  async function createEvidenceBeliefEdge(ctx, args) {
1019
1277
  const edgeGlobalId = generateGlobalId();
1020
1278
  const confidence = Math.abs(args.weight);
@@ -1135,70 +1393,31 @@ var create = mutation({
1135
1393
  mutationName: "epistemicEvidence.create"
1136
1394
  });
1137
1395
  if (scope.projectId) {
1138
- await requireProjectAccess(ctx, scope.projectId, args.userId);
1396
+ await requireScopeWriteAccess(ctx, scope.projectId, args.userId);
1139
1397
  }
1140
1398
  const now = Date.now();
1141
1399
  const globalId = generateGlobalId();
1142
- const contentHash = generateContentHash(args.text);
1143
1400
  const kind = normalizeKind(args.kind);
1144
1401
  const sourceType = normalizeSourceType(args.sourceType);
1145
- const weight = assertSignedImpactScore(args.weight, "Evidence creation");
1146
- const signedImpact = args.signedImpact !== void 0 ? assertSignedImpactScore(args.signedImpact, "Evidence creation signedImpact") : weight;
1147
- const evidenceRelation = normalizeEvidenceRelation(
1148
- args.evidenceRelation,
1149
- weight,
1150
- "Evidence creation"
1402
+ const impact = planEvidenceImpact(args, "Evidence creation");
1403
+ const linkedBeliefNode = assertBeliefNode(
1404
+ await ctx.db.get(args.linkedBeliefNodeId),
1405
+ "Evidence creation requires a linked belief node"
1151
1406
  );
1152
- const linkedBeliefNode = await ctx.db.get(args.linkedBeliefNodeId);
1153
- if (!linkedBeliefNode || linkedBeliefNode.nodeType !== "belief") {
1154
- throw new Error("Evidence creation requires a linked belief node");
1155
- }
1156
- const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
1157
- const nodeId = await insertEpistemicNode(ctx, {
1158
- globalId,
1159
- topicId: scope.topicId,
1160
- projectId: scope.projectId,
1161
- tenantId: scope.tenantId,
1162
- workspaceId: scope.workspaceId,
1163
- nodeType: "evidence",
1164
- canonicalText: args.text,
1165
- contentHash,
1166
- ...typeof args.title === "string" && args.title.trim().length > 0 ? { title: args.title.trim() } : {},
1167
- ...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
1168
- ...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
1169
- status: "active",
1170
- epistemicLayer: "L2",
1171
- sourceType,
1172
- // RC.1 taxonomy fields — top-level projection
1173
- evidenceRelation,
1174
- signedImpact,
1175
- targetBeliefId: String(args.linkedBeliefNodeId),
1176
- ...typeof args.sourceRef === "string" && args.sourceRef.trim().length > 0 ? { sourceRef: args.sourceRef.trim() } : {},
1177
- ...typeof args.sourceQuality === "string" && args.sourceQuality.length > 0 ? { sourceQuality: args.sourceQuality } : {},
1178
- ...typeof args.methodology === "string" && args.methodology.length > 0 ? { methodology: args.methodology } : {},
1179
- ...typeof args.informationAsymmetry === "string" && args.informationAsymmetry.length > 0 ? { informationAsymmetry: args.informationAsymmetry } : {},
1180
- ...typeof args.sourceDescription === "string" && args.sourceDescription.trim().length > 0 ? { sourceDescription: args.sourceDescription.trim() } : {},
1181
- createdAt: now,
1182
- updatedAt: now,
1183
- createdBy: args.userId,
1184
- metadata: {
1407
+ const nodeId = await insertEpistemicNode(
1408
+ ctx,
1409
+ buildEvidenceNodeInsert({
1410
+ globalId,
1411
+ impact,
1185
1412
  kind,
1186
- tags: args.tags || [],
1187
- externalSourceType: args.externalSourceType,
1188
- sourceUrl: args.sourceUrl,
1189
- sourceQuestionId: args.sourceQuestionId,
1190
- rationale: args.rationale,
1191
1413
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1192
- evidenceRelation,
1193
- confidence: Math.abs(weight),
1194
- weight,
1195
- impactScore: weight,
1196
- methodology: args.methodology,
1197
- informationAsymmetry: args.informationAsymmetry,
1198
- sourceDescription: args.sourceDescription,
1199
- ...additionalMetadata
1200
- }
1201
- });
1414
+ metadataProfile: "create",
1415
+ now,
1416
+ scope,
1417
+ sourceType,
1418
+ write: args
1419
+ })
1420
+ );
1202
1421
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1203
1422
  nodeId,
1204
1423
  operation: "upsert"
@@ -1216,8 +1435,8 @@ var create = mutation({
1216
1435
  evidenceGlobalId: globalId,
1217
1436
  beliefNodeId: args.linkedBeliefNodeId,
1218
1437
  beliefGlobalId: linkedBeliefNode.globalId,
1219
- relation: evidenceRelation,
1220
- weight,
1438
+ relation: impact.evidenceRelation,
1439
+ weight: impact.weight,
1221
1440
  userId: args.userId,
1222
1441
  topicId: scope.topicId ? String(scope.topicId) : void 0,
1223
1442
  projectId: scope.projectId ? String(scope.projectId) : void 0,
@@ -1237,23 +1456,19 @@ var create = mutation({
1237
1456
  kind,
1238
1457
  sourceType,
1239
1458
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1240
- evidenceRelation,
1241
- weight
1459
+ evidenceRelation: impact.evidenceRelation,
1460
+ weight: impact.weight
1242
1461
  }
1243
1462
  });
1244
1463
  if (scope.projectId || scope.topicId) {
1245
- await ctx.scheduler.runAfter(
1246
- 0,
1247
- "embeddingActions:generateEpistemicNodeEmbedding",
1248
- {
1249
- nodeId,
1250
- projectId: scope.projectId,
1251
- topicId: scope.topicId ? String(scope.topicId) : void 0,
1252
- createdBy: args.userId,
1253
- nodeType: "evidence",
1254
- text: args.text
1255
- }
1256
- );
1464
+ await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
1465
+ nodeId,
1466
+ projectId: scope.projectId,
1467
+ topicId: scope.topicId ? String(scope.topicId) : void 0,
1468
+ createdBy: args.userId,
1469
+ nodeType: "evidence",
1470
+ text: args.text
1471
+ });
1257
1472
  }
1258
1473
  if (scope.projectId || scope.topicId) {
1259
1474
  await ctx.scheduler.runAfter(
@@ -1267,7 +1482,11 @@ var create = mutation({
1267
1482
  }
1268
1483
  );
1269
1484
  }
1270
- await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
1485
+ await markProjectGraphDirty(
1486
+ ctx,
1487
+ scope.projectId,
1488
+ scope.topicId ? String(scope.topicId) : void 0
1489
+ );
1271
1490
  return { nodeId };
1272
1491
  }
1273
1492
  });
@@ -1305,58 +1524,39 @@ var createAndLink = mutation({
1305
1524
  if (!scope) {
1306
1525
  throw new Error("Invalid scope: projectId or topicId is required");
1307
1526
  }
1308
- await requireProjectAccess(ctx, String(scope.topicId), args.userId);
1527
+ const accessScopeId = scope.projectId ?? (scope.topicId ? String(scope.topicId) : void 0);
1528
+ if (!accessScopeId) {
1529
+ throw new Error("Resolved evidence scope has no access-control id");
1530
+ }
1531
+ await requireScopeWriteAccess(ctx, accessScopeId, args.userId);
1309
1532
  const now = Date.now();
1310
1533
  const globalId = generateGlobalId();
1311
- const contentHash = generateContentHash(args.text);
1312
1534
  const kind = normalizeKind(args.kind);
1313
1535
  const sourceType = normalizeSourceType(args.sourceType);
1314
- const weight = assertSignedImpactScore(args.weight, "Evidence createAndLink");
1315
- const signedImpact = args.signedImpact !== void 0 ? assertSignedImpactScore(args.signedImpact, "Evidence createAndLink signedImpact") : weight;
1316
- const relation = normalizeEvidenceRelation(
1317
- args.relation,
1318
- weight,
1319
- "Evidence createAndLink"
1536
+ const write = {
1537
+ ...args,
1538
+ evidenceRelation: args.relation,
1539
+ linkedBeliefNodeId: args.beliefNodeId
1540
+ };
1541
+ const impact = planEvidenceImpact(write, "Evidence createAndLink");
1542
+ const beliefNode = assertBeliefNode(
1543
+ await ctx.db.get(args.beliefNodeId),
1544
+ "Belief node not found for edge creation"
1320
1545
  );
1321
- const confidence = Math.abs(weight);
1322
- const beliefNode = await ctx.db.get(args.beliefNodeId);
1323
- if (!beliefNode || beliefNode.nodeType !== "belief") {
1324
- throw new Error("Belief node not found for edge creation");
1325
- }
1326
- const nodeId = await insertEpistemicNode(ctx, {
1327
- globalId,
1328
- topicId: scope.topicId,
1329
- projectId: scope.projectId,
1330
- tenantId: scope.tenantId,
1331
- workspaceId: scope.workspaceId,
1332
- nodeType: "evidence",
1333
- canonicalText: args.text,
1334
- contentHash,
1335
- status: "active",
1336
- epistemicLayer: "L2",
1337
- sourceType,
1338
- // RC.1 taxonomy fields — top-level projection
1339
- evidenceRelation: relation,
1340
- signedImpact,
1341
- targetBeliefId: String(args.beliefNodeId),
1342
- ...typeof args.sourceRef === "string" && args.sourceRef.trim().length > 0 ? { sourceRef: args.sourceRef.trim() } : {},
1343
- ...typeof args.sourceQuality === "string" && args.sourceQuality.length > 0 ? { sourceQuality: args.sourceQuality } : {},
1344
- ...typeof args.methodology === "string" && args.methodology.length > 0 ? { methodology: args.methodology } : {},
1345
- ...typeof args.informationAsymmetry === "string" && args.informationAsymmetry.length > 0 ? { informationAsymmetry: args.informationAsymmetry } : {},
1346
- ...typeof args.sourceDescription === "string" && args.sourceDescription.trim().length > 0 ? { sourceDescription: args.sourceDescription.trim() } : {},
1347
- createdAt: now,
1348
- updatedAt: now,
1349
- createdBy: args.userId,
1350
- metadata: {
1546
+ const nodeId = await insertEpistemicNode(
1547
+ ctx,
1548
+ buildEvidenceNodeInsert({
1549
+ globalId,
1550
+ impact,
1351
1551
  kind,
1352
- tags: args.tags || [],
1353
1552
  linkedBeliefNodeId: args.beliefNodeId,
1354
- evidenceRelation: relation,
1355
- confidence,
1356
- weight,
1357
- impactScore: weight
1358
- }
1359
- });
1553
+ metadataProfile: "createAndLink",
1554
+ now,
1555
+ scope,
1556
+ sourceType,
1557
+ write
1558
+ })
1559
+ );
1360
1560
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1361
1561
  nodeId,
1362
1562
  operation: "upsert"
@@ -1365,13 +1565,17 @@ var createAndLink = mutation({
1365
1565
  evidenceGlobalId: globalId,
1366
1566
  beliefNodeId: args.beliefNodeId,
1367
1567
  beliefGlobalId: beliefNode.globalId,
1368
- relation,
1369
- weight,
1568
+ relation: impact.evidenceRelation,
1569
+ weight: impact.weight,
1370
1570
  userId: args.userId,
1371
1571
  topicId: scope.topicId ? String(scope.topicId) : void 0,
1372
1572
  projectId: scope.projectId ? String(scope.projectId) : void 0
1373
1573
  });
1374
- await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
1574
+ await markProjectGraphDirty(
1575
+ ctx,
1576
+ scope.projectId,
1577
+ scope.topicId ? String(scope.topicId) : void 0
1578
+ );
1375
1579
  return { nodeId, edgeGlobalId };
1376
1580
  }
1377
1581
  });
@@ -1387,10 +1591,10 @@ var updateStatus = mutation({
1387
1591
  },
1388
1592
  returns: permissiveReturn,
1389
1593
  handler: async (ctx, args) => {
1390
- const node = await ctx.db.get(args.nodeId);
1391
- if (!node || node.nodeType !== "evidence") {
1392
- throw new Error("Evidence not found");
1393
- }
1594
+ const node = assertEvidenceNode(
1595
+ await ctx.db.get(args.nodeId),
1596
+ "Evidence not found"
1597
+ );
1394
1598
  const now = Date.now();
1395
1599
  await ctx.db.patch(args.nodeId, {
1396
1600
  status: args.status,
@@ -1479,63 +1683,27 @@ var internalCreate = internalMutation({
1479
1683
  mutationName: "epistemicEvidence.internalCreate"
1480
1684
  });
1481
1685
  const globalId = generateGlobalId();
1482
- const contentHash = generateContentHash(args.text);
1483
1686
  const kind = normalizeKind(args.kind);
1484
1687
  const sourceType = normalizeSourceType(args.sourceType);
1485
- const weight = assertSignedImpactScore(args.weight, "Internal evidence creation");
1486
- const signedImpact = args.signedImpact !== void 0 ? assertSignedImpactScore(args.signedImpact, "Internal evidence creation signedImpact") : weight;
1487
- const evidenceRelation = normalizeEvidenceRelation(
1488
- args.evidenceRelation,
1489
- weight,
1490
- "Internal evidence creation"
1688
+ const impact = planEvidenceImpact(args, "Internal evidence creation");
1689
+ const linkedBeliefNode = assertBeliefNode(
1690
+ await ctx.db.get(args.linkedBeliefNodeId),
1691
+ "Internal evidence creation requires a linked belief node"
1491
1692
  );
1492
- const linkedBeliefNode = await ctx.db.get(args.linkedBeliefNodeId);
1493
- if (!linkedBeliefNode || linkedBeliefNode.nodeType !== "belief") {
1494
- throw new Error("Internal evidence creation requires a linked belief node");
1495
- }
1496
- const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
1497
- const nodeId = await insertEpistemicNode(ctx, {
1498
- globalId,
1499
- topicId: scope.topicId,
1500
- projectId: scope.projectId,
1501
- tenantId: scope.tenantId,
1502
- workspaceId: scope.workspaceId,
1503
- nodeType: "evidence",
1504
- canonicalText: args.text,
1505
- contentHash,
1506
- ...typeof args.title === "string" && args.title.trim().length > 0 ? { title: args.title.trim() } : {},
1507
- ...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
1508
- ...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
1509
- status: "active",
1510
- epistemicLayer: "L2",
1511
- sourceType,
1512
- // RC.1 taxonomy fields — top-level projection
1513
- evidenceRelation,
1514
- signedImpact,
1515
- targetBeliefId: String(args.linkedBeliefNodeId),
1516
- ...typeof args.sourceRef === "string" && args.sourceRef.trim().length > 0 ? { sourceRef: args.sourceRef.trim() } : {},
1517
- ...typeof args.sourceQuality === "string" && args.sourceQuality.length > 0 ? { sourceQuality: args.sourceQuality } : {},
1518
- ...typeof args.methodology === "string" && args.methodology.length > 0 ? { methodology: args.methodology } : {},
1519
- ...typeof args.informationAsymmetry === "string" && args.informationAsymmetry.length > 0 ? { informationAsymmetry: args.informationAsymmetry } : {},
1520
- ...typeof args.sourceDescription === "string" && args.sourceDescription.trim().length > 0 ? { sourceDescription: args.sourceDescription.trim() } : {},
1521
- createdAt: now,
1522
- updatedAt: now,
1523
- createdBy: args.userId,
1524
- metadata: {
1693
+ const nodeId = await insertEpistemicNode(
1694
+ ctx,
1695
+ buildEvidenceNodeInsert({
1696
+ globalId,
1697
+ impact,
1525
1698
  kind,
1526
- tags: args.tags || [],
1527
- externalSourceType: args.externalSourceType,
1528
- sourceUrl: args.sourceUrl,
1529
- sourceQuestionId: args.sourceQuestionId,
1530
- rationale: args.rationale,
1531
1699
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1532
- evidenceRelation,
1533
- confidence: Math.abs(weight),
1534
- weight,
1535
- impactScore: weight,
1536
- ...additionalMetadata
1537
- }
1538
- });
1700
+ metadataProfile: "internalCreate",
1701
+ now,
1702
+ scope,
1703
+ sourceType,
1704
+ write: args
1705
+ })
1706
+ );
1539
1707
  await ctx.db.insert("epistemicAudit", {
1540
1708
  entityType: "evidence",
1541
1709
  entityId: String(nodeId),
@@ -1552,9 +1720,9 @@ var internalCreate = internalMutation({
1552
1720
  externalSourceType: args.externalSourceType,
1553
1721
  sourceUrl: args.sourceUrl,
1554
1722
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1555
- evidenceRelation,
1556
- confidence: Math.abs(weight),
1557
- weight
1723
+ evidenceRelation: impact.evidenceRelation,
1724
+ confidence: impact.confidence,
1725
+ weight: impact.weight
1558
1726
  },
1559
1727
  triggeringAction: "epistemicEvidence.internalCreate"
1560
1728
  });
@@ -1566,28 +1734,28 @@ var internalCreate = internalMutation({
1566
1734
  evidenceGlobalId: globalId,
1567
1735
  beliefNodeId: args.linkedBeliefNodeId,
1568
1736
  beliefGlobalId: linkedBeliefNode.globalId,
1569
- relation: evidenceRelation,
1570
- weight,
1737
+ relation: impact.evidenceRelation,
1738
+ weight: impact.weight,
1571
1739
  userId: args.userId,
1572
1740
  topicId: scope.topicId ? String(scope.topicId) : void 0,
1573
1741
  projectId: scope.projectId ? String(scope.projectId) : void 0,
1574
1742
  rationale: args.rationale
1575
1743
  });
1576
1744
  if (scope.projectId || scope.topicId) {
1577
- await ctx.scheduler.runAfter(
1578
- 0,
1579
- "embeddingActions:generateEpistemicNodeEmbedding",
1580
- {
1581
- nodeId,
1582
- projectId: scope.projectId,
1583
- topicId: scope.topicId ? String(scope.topicId) : void 0,
1584
- createdBy: args.userId,
1585
- nodeType: "evidence",
1586
- text: args.text
1587
- }
1588
- );
1745
+ await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
1746
+ nodeId,
1747
+ projectId: scope.projectId,
1748
+ topicId: scope.topicId ? String(scope.topicId) : void 0,
1749
+ createdBy: args.userId,
1750
+ nodeType: "evidence",
1751
+ text: args.text
1752
+ });
1589
1753
  }
1590
- await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
1754
+ await markProjectGraphDirty(
1755
+ ctx,
1756
+ scope.projectId,
1757
+ scope.topicId ? String(scope.topicId) : void 0
1758
+ );
1591
1759
  return { nodeId };
1592
1760
  }
1593
1761
  });
@@ -1600,11 +1768,11 @@ var updateVerificationStatus = mutation({
1600
1768
  },
1601
1769
  returns: permissiveReturn,
1602
1770
  handler: async (ctx, args) => {
1603
- const node = await ctx.db.get(args.nodeId);
1604
- if (!node || node.nodeType !== "evidence") {
1605
- throw new Error("Evidence node not found");
1606
- }
1607
- const metadata = node.metadata || {};
1771
+ const node = assertEvidenceNode(
1772
+ await ctx.db.get(args.nodeId),
1773
+ "Evidence node not found"
1774
+ );
1775
+ const metadata = metadataRecord(node.metadata);
1608
1776
  await ctx.db.patch(args.nodeId, {
1609
1777
  metadata: {
1610
1778
  ...metadata,
@@ -1630,20 +1798,17 @@ var update = mutation({
1630
1798
  },
1631
1799
  returns: permissiveReturn,
1632
1800
  handler: async (ctx, args) => {
1633
- const resolvedId = args.nodeId ?? args.insightId;
1634
- if (!resolvedId) {
1635
- throw new Error("Either nodeId or insightId is required");
1636
- }
1637
- const node = await ctx.db.get(resolvedId);
1638
- if (!node || node.nodeType !== "evidence") {
1639
- throw new Error("Evidence node not found");
1640
- }
1801
+ const resolvedId = await resolveEvidenceNodeId(ctx, args);
1802
+ const node = assertEvidenceNode(
1803
+ await ctx.db.get(resolvedId),
1804
+ "Evidence node not found"
1805
+ );
1641
1806
  if (!node.projectId) {
1642
1807
  throw new Error("Evidence has no project scope");
1643
1808
  }
1644
- await checkProjectAccess(ctx, node.projectId, args.userId);
1809
+ await requireScopeWriteAccess(ctx, node.projectId, args.userId);
1645
1810
  const now = Date.now();
1646
- const existingMeta = node.metadata || {};
1811
+ const existingMeta = metadataRecord(node.metadata);
1647
1812
  const metaUpdates = { ...existingMeta };
1648
1813
  if (args.kind !== void 0) {
1649
1814
  metaUpdates.kind = args.kind;
@@ -1675,17 +1840,13 @@ var update = mutation({
1675
1840
  newState: { text: (args.text ?? node.canonicalText)?.slice(0, 200) }
1676
1841
  });
1677
1842
  if (args.text !== void 0) {
1678
- await ctx.scheduler.runAfter(
1679
- 0,
1680
- "embeddingActions:generateEpistemicNodeEmbedding",
1681
- {
1682
- nodeId: resolvedId,
1683
- topicId: node.projectId,
1684
- createdBy: node.createdBy,
1685
- nodeType: "evidence",
1686
- text: args.text
1687
- }
1688
- );
1843
+ await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
1844
+ nodeId: resolvedId,
1845
+ topicId: node.projectId,
1846
+ createdBy: node.createdBy ?? args.userId,
1847
+ nodeType: "evidence",
1848
+ text: args.text
1849
+ });
1689
1850
  }
1690
1851
  await markProjectGraphDirty(ctx, node.projectId, node.topicId);
1691
1852
  return { nodeId: resolvedId };
@@ -1701,15 +1862,15 @@ var flagAsIncorrect = mutation({
1701
1862
  returns: permissiveReturn,
1702
1863
  handler: async (ctx, args) => {
1703
1864
  const now = Date.now();
1704
- const node = await ctx.db.get(args.insightId);
1705
- if (!node || node.nodeType !== "evidence") {
1706
- throw new Error("Evidence not found in epistemic spine");
1707
- }
1865
+ const node = assertEvidenceNode(
1866
+ await ctx.db.get(args.insightId),
1867
+ "Evidence not found in epistemic spine"
1868
+ );
1708
1869
  if (!node.projectId) {
1709
1870
  throw new Error("Evidence has no project scope");
1710
1871
  }
1711
- await checkProjectAccess(ctx, node.projectId, args.userId);
1712
- const existingMeta = node.metadata || {};
1872
+ await requireScopeWriteAccess(ctx, node.projectId, args.userId);
1873
+ const existingMeta = metadataRecord(node.metadata);
1713
1874
  await ctx.db.patch(node._id, {
1714
1875
  verificationStatus: "contradicted",
1715
1876
  metadata: {
@@ -1765,14 +1926,11 @@ var remove = mutation({
1765
1926
  },
1766
1927
  returns: permissiveReturn,
1767
1928
  handler: async (ctx, args) => {
1768
- const resolvedId = args.nodeId ?? args.insightId;
1769
- if (!resolvedId) {
1770
- throw new Error("Either nodeId or insightId is required");
1771
- }
1772
- const node = await ctx.db.get(resolvedId);
1773
- if (!node || node.nodeType !== "evidence") {
1774
- throw new Error("Evidence node not found");
1775
- }
1929
+ const resolvedId = await resolveEvidenceNodeId(ctx, args);
1930
+ const node = assertEvidenceNode(
1931
+ await ctx.db.get(resolvedId),
1932
+ "Evidence node not found"
1933
+ );
1776
1934
  if (node.createdBy !== args.userId) {
1777
1935
  throw new Error("Only the creator can archive this evidence");
1778
1936
  }
@@ -1800,6 +1958,224 @@ var remove = mutation({
1800
1958
  return { nodeId: resolvedId };
1801
1959
  }
1802
1960
  });
1961
+ function readOptionalString2(value) {
1962
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1963
+ }
1964
+ function readOptionalNumber(value) {
1965
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1966
+ }
1967
+ function readConvexId2(value) {
1968
+ const normalized = readOptionalString2(value);
1969
+ return normalized;
1970
+ }
1971
+ function readRecord(value) {
1972
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
1973
+ }
1974
+ function readOptionalStringArray(value) {
1975
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
1976
+ }
1977
+ function readEvidenceNodeRow(value, fallbackProjectId) {
1978
+ const record = readRecord(value);
1979
+ if (!record) {
1980
+ return null;
1981
+ }
1982
+ const id = readConvexId2(record._id);
1983
+ const canonicalText = readOptionalString2(record.canonicalText);
1984
+ const createdAt = readOptionalNumber(record.createdAt);
1985
+ const createdBy = readOptionalString2(record.createdBy);
1986
+ const nodeType = readOptionalString2(record.nodeType);
1987
+ const sourceType = readOptionalString2(record.sourceType);
1988
+ const status = readOptionalString2(record.status);
1989
+ const updatedAt = readOptionalNumber(record.updatedAt);
1990
+ if (!(id && canonicalText && createdAt !== void 0 && createdBy && nodeType === "evidence" && sourceType && status && updatedAt !== void 0)) {
1991
+ return null;
1992
+ }
1993
+ const metadata = readRecord(record.metadata) ?? void 0;
1994
+ const node = {
1995
+ ...record,
1996
+ _id: id,
1997
+ canonicalText,
1998
+ createdAt,
1999
+ createdBy,
2000
+ nodeType: "evidence",
2001
+ sourceType,
2002
+ status,
2003
+ updatedAt
2004
+ };
2005
+ const projectId = readOptionalString2(record.projectId) ?? readOptionalString2(fallbackProjectId);
2006
+ if (projectId !== void 0) {
2007
+ node.projectId = projectId;
2008
+ }
2009
+ const topicId = readOptionalString2(record.topicId);
2010
+ if (topicId !== void 0) {
2011
+ node.topicId = topicId;
2012
+ }
2013
+ const tenantId = readOptionalString2(record.tenantId);
2014
+ if (tenantId !== void 0) {
2015
+ node.tenantId = tenantId;
2016
+ }
2017
+ const workspaceId = readOptionalString2(record.workspaceId);
2018
+ if (workspaceId !== void 0) {
2019
+ node.workspaceId = workspaceId;
2020
+ }
2021
+ const globalId = readOptionalString2(record.globalId);
2022
+ if (globalId !== void 0) {
2023
+ node.globalId = globalId;
2024
+ }
2025
+ const title = readOptionalString2(record.title);
2026
+ if (title !== void 0) {
2027
+ node.title = title;
2028
+ }
2029
+ const audienceLabel = readOptionalString2(record.audienceLabel);
2030
+ if (audienceLabel !== void 0) {
2031
+ node.audienceLabel = audienceLabel;
2032
+ }
2033
+ const epistemicLayer = readOptionalString2(record.epistemicLayer);
2034
+ if (epistemicLayer !== void 0) {
2035
+ node.epistemicLayer = epistemicLayer;
2036
+ }
2037
+ const sensitivityTier = readOptionalString2(record.sensitivityTier);
2038
+ if (sensitivityTier !== void 0) {
2039
+ node.sensitivityTier = sensitivityTier;
2040
+ }
2041
+ const exportClass = readOptionalString2(record.exportClass);
2042
+ if (exportClass !== void 0) {
2043
+ node.exportClass = exportClass;
2044
+ }
2045
+ const policyTags = readOptionalStringArray(record.policyTags);
2046
+ if (policyTags !== void 0) {
2047
+ node.policyTags = policyTags;
2048
+ }
2049
+ if (metadata !== void 0) {
2050
+ node.metadata = metadata;
2051
+ }
2052
+ return node;
2053
+ }
2054
+ function readEvidenceNodeRows(values, fallbackProjectId) {
2055
+ return values.flatMap((value) => {
2056
+ const node = readEvidenceNodeRow(value, fallbackProjectId);
2057
+ return node ? [node] : [];
2058
+ });
2059
+ }
2060
+ function dedupeEvidenceNodeRows(nodes) {
2061
+ const seen = /* @__PURE__ */ new Set();
2062
+ const deduped = [];
2063
+ for (const node of nodes) {
2064
+ const id = String(node._id);
2065
+ if (seen.has(id)) {
2066
+ continue;
2067
+ }
2068
+ seen.add(id);
2069
+ deduped.push(node);
2070
+ }
2071
+ return deduped;
2072
+ }
2073
+ function readEvidenceEdgeRow(value) {
2074
+ const record = readRecord(value);
2075
+ if (!record) {
2076
+ return null;
2077
+ }
2078
+ const id = readConvexId2(record._id);
2079
+ const edgeType = readOptionalString2(record.edgeType);
2080
+ if (!(id && edgeType)) {
2081
+ return null;
2082
+ }
2083
+ const edge = { _id: id, edgeType };
2084
+ const weight = readOptionalNumber(record.weight);
2085
+ if (weight !== void 0) {
2086
+ edge.weight = weight;
2087
+ }
2088
+ for (const field of [
2089
+ "fromNodeId",
2090
+ "toNodeId",
2091
+ "sourceGlobalId",
2092
+ "targetGlobalId",
2093
+ "fromGlobalId",
2094
+ "toGlobalId",
2095
+ "fromLayer",
2096
+ "toLayer",
2097
+ "topicId"
2098
+ ]) {
2099
+ const valueForField = readOptionalString2(record[field]);
2100
+ if (valueForField !== void 0) {
2101
+ edge[field] = valueForField;
2102
+ }
2103
+ }
2104
+ return edge;
2105
+ }
2106
+ function readEvidenceEdgeRows(values) {
2107
+ return values.flatMap((value) => {
2108
+ const edge = readEvidenceEdgeRow(value);
2109
+ return edge ? [edge] : [];
2110
+ });
2111
+ }
2112
+ function dedupeEvidenceEdges(edges) {
2113
+ const seen = /* @__PURE__ */ new Set();
2114
+ const deduped = [];
2115
+ for (const edge of edges) {
2116
+ const id = String(edge._id);
2117
+ if (seen.has(id)) {
2118
+ continue;
2119
+ }
2120
+ seen.add(id);
2121
+ deduped.push(edge);
2122
+ }
2123
+ return deduped;
2124
+ }
2125
+ function evidenceSourceRef(edge) {
2126
+ return edge.sourceGlobalId ?? edge.fromGlobalId ?? edge.fromNodeId;
2127
+ }
2128
+ async function resolveEvidenceNodeSoft(ctx, nodeRef) {
2129
+ const normalizedId = ctx.db.normalizeId?.("epistemicNodes", nodeRef) ?? readConvexId2(nodeRef);
2130
+ if (normalizedId) {
2131
+ try {
2132
+ const direct = readEvidenceNodeRow(await ctx.db.get(normalizedId));
2133
+ if (direct) {
2134
+ return direct;
2135
+ }
2136
+ } catch (error) {
2137
+ debugGraphPrimitiveFallback(
2138
+ "[epistemicEvidence] Direct evidence lookup failed",
2139
+ { error, nodeRef }
2140
+ );
2141
+ }
2142
+ }
2143
+ return readEvidenceNodeRow(
2144
+ await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", nodeRef)).first()
2145
+ );
2146
+ }
2147
+ async function collectNodeReferenceIds(ctx, nodeId) {
2148
+ const refs = /* @__PURE__ */ new Set([String(nodeId)]);
2149
+ const node = await ctx.db.get(nodeId);
2150
+ const globalId = readOptionalString2(readRecord(node)?.globalId);
2151
+ if (globalId) {
2152
+ refs.add(globalId);
2153
+ }
2154
+ return [...refs];
2155
+ }
2156
+ async function collectInformsEdgesToNode(ctx, nodeId) {
2157
+ const refs = await collectNodeReferenceIds(ctx, nodeId);
2158
+ const reads = [];
2159
+ for (const ref of refs) {
2160
+ reads.push(
2161
+ ctx.db.query("epistemicEdges").withIndex(
2162
+ "by_to_type",
2163
+ (q) => q.eq("toNodeId", ref).eq("edgeType", "informs")
2164
+ ).collect(),
2165
+ ctx.db.query("epistemicEdges").withIndex(
2166
+ "by_target_global_id",
2167
+ (q) => q.eq("targetGlobalId", ref)
2168
+ ).collect()
2169
+ );
2170
+ }
2171
+ const edges = readEvidenceEdgeRows((await Promise.all(reads)).flat()).filter(
2172
+ (edge) => edge.edgeType === "informs"
2173
+ );
2174
+ return dedupeEvidenceEdges(edges);
2175
+ }
2176
+ function hasProjectId(node) {
2177
+ return typeof node.projectId === "string" && node.projectId.length > 0;
2178
+ }
1803
2179
  var getById = query({
1804
2180
  args: {
1805
2181
  nodeId: v.optional(v.id("epistemicNodes")),
@@ -1812,11 +2188,7 @@ var getById = query({
1812
2188
  if (!id) {
1813
2189
  return null;
1814
2190
  }
1815
- const node = await ctx.db.get(id);
1816
- if (!node || node.nodeType !== "evidence") {
1817
- return null;
1818
- }
1819
- return node;
2191
+ return await resolveEvidenceNodeSoft(ctx, String(id));
1820
2192
  }
1821
2193
  });
1822
2194
  var getByProject = query({
@@ -1828,7 +2200,7 @@ var getByProject = query({
1828
2200
  },
1829
2201
  returns: permissiveReturn,
1830
2202
  handler: async (ctx, args) => {
1831
- if (!args.projectId && !args.topicId) {
2203
+ if (!(args.projectId || args.topicId)) {
1832
2204
  return [];
1833
2205
  }
1834
2206
  const pageSize = clampEvidenceLimit(args.limit);
@@ -1864,9 +2236,9 @@ var getByProject = query({
1864
2236
  "by_topic_type",
1865
2237
  (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
1866
2238
  ).order("desc").take(scanLimit);
1867
- const scopedNodes = dedupeEvidenceNodes(topicNodes).filter(
1868
- (node) => evidenceMatchesScope(node, scope)
1869
- );
2239
+ const scopedNodes = dedupeEvidenceNodeRows(
2240
+ readEvidenceNodeRows(topicNodes, scope.projectId)
2241
+ ).filter((node) => evidenceMatchesScope(node, scope));
1870
2242
  const filteredNodes = args.status ? scopedNodes.filter((node) => node.status === args.status) : scopedNodes;
1871
2243
  return filteredNodes.map(flattenEvidenceNode).slice(0, pageSize);
1872
2244
  }
@@ -1889,9 +2261,9 @@ var getByTopic = query({
1889
2261
  "by_topic_type",
1890
2262
  (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
1891
2263
  ).order("desc").take(scanLimit);
1892
- const scopedNodes = dedupeEvidenceNodes(topicNodes).filter(
1893
- (node) => evidenceMatchesScope(node, scope)
1894
- );
2264
+ const scopedNodes = dedupeEvidenceNodeRows(
2265
+ readEvidenceNodeRows(topicNodes, scope.projectId)
2266
+ ).filter((node) => evidenceMatchesScope(node, scope));
1895
2267
  const filteredNodes = args.status ? scopedNodes.filter((node) => node.status === args.status) : scopedNodes;
1896
2268
  return filteredNodes.map(flattenEvidenceNode).slice(0, pageSize);
1897
2269
  }
@@ -1902,20 +2274,29 @@ var getForBelief = query({
1902
2274
  },
1903
2275
  returns: permissiveReturn,
1904
2276
  handler: async (ctx, args) => {
1905
- const edges = await ctx.db.query("epistemicEdges").withIndex(
1906
- "by_to_type",
1907
- (q) => q.eq("toNodeId", args.beliefNodeId).eq("edgeType", "informs")
1908
- ).collect();
1909
- const evidenceNodeIds = edges.map((e) => e.fromNodeId);
2277
+ const edges = await collectInformsEdgesToNode(ctx, args.beliefNodeId);
2278
+ const evidenceNodeIds = edges.flatMap((edge) => {
2279
+ const sourceRef = evidenceSourceRef(edge);
2280
+ return sourceRef ? [sourceRef] : [];
2281
+ });
1910
2282
  const evidenceNodes = await Promise.all(
1911
- evidenceNodeIds.map((id) => ctx.db.get(id))
2283
+ evidenceNodeIds.map((id) => resolveEvidenceNodeSoft(ctx, id))
1912
2284
  );
1913
- return evidenceNodes.filter((e) => e !== null && e.nodeType === "evidence").map((e, i) => ({
1914
- ...e,
1915
- relation: (edges[i]?.weight ?? 0) >= 0 ? "supports" : "contradicts",
1916
- confidence: Math.abs(edges[i]?.weight ?? 0),
1917
- edgeId: edges[i]?._id
1918
- }));
2285
+ return evidenceNodes.flatMap((e, i) => {
2286
+ const edge = edges[i];
2287
+ if (!(e && edge)) {
2288
+ return [];
2289
+ }
2290
+ const weight = edge.weight ?? 0;
2291
+ return [
2292
+ {
2293
+ ...e,
2294
+ relation: weight >= 0 ? "supports" : "contradicts",
2295
+ confidence: Math.abs(weight),
2296
+ edgeId: edge._id
2297
+ }
2298
+ ];
2299
+ });
1919
2300
  }
1920
2301
  });
1921
2302
  var internalGetByProject = internalQuery({
@@ -1934,21 +2315,30 @@ var internalGetByProject = internalQuery({
1934
2315
  return [];
1935
2316
  }
1936
2317
  const audienceMode = args.audienceMode ?? "internal";
2318
+ const projectScopeId = scope.topicId ? String(scope.topicId) : scope.projectId;
2319
+ if (!projectScopeId) {
2320
+ return [];
2321
+ }
1937
2322
  const project = await resolveGraphPrimitivesAppResolvers().getProject(
1938
2323
  ctx,
1939
- scope.topicId ? String(scope.topicId) : scope.projectId
2324
+ projectScopeId
1940
2325
  );
2326
+ const tenantId = project?.tenantId;
2327
+ const workspaceId = project?.workspaceId;
1941
2328
  const registryRows = await listAudienceRegistryRows(ctx, {
1942
- tenantId: project?.tenantId,
1943
- workspaceId: project?.workspaceId
2329
+ tenantId,
2330
+ workspaceId
1944
2331
  });
1945
2332
  const resolveAudienceClass = createEvidenceAudienceResolver(registryRows);
1946
2333
  const viewerClass = resolveAudienceClass(audienceMode, "public");
1947
- const nodes = await getEvidenceNodesForScope(ctx, scope, { scanLimit });
2334
+ const nodes = readEvidenceNodeRows(
2335
+ await getEvidenceNodesForScope(ctx, scope, { scanLimit }),
2336
+ scope.projectId
2337
+ );
1948
2338
  const workspaceScopedNodes = nodes.filter(
1949
2339
  (node) => nodeMatchesWorkspaceReasoningScope(node, {
1950
- tenantId: project?.tenantId,
1951
- workspaceId: project?.workspaceId
2340
+ tenantId,
2341
+ workspaceId
1952
2342
  })
1953
2343
  );
1954
2344
  return workspaceScopedNodes.filter(
@@ -2007,7 +2397,10 @@ var internalGetByTopic = internalQuery({
2007
2397
  "by_topic_type",
2008
2398
  (q) => q.eq("topicId", args.topicId).eq("nodeType", "evidence")
2009
2399
  ).order("desc").take(scanLimit);
2010
- const workspaceScopedNodes = nodes.filter(
2400
+ const workspaceScopedNodes = readEvidenceNodeRows(
2401
+ nodes,
2402
+ scope.projectId
2403
+ ).filter(
2011
2404
  (node) => nodeMatchesWorkspaceReasoningScope(node, {
2012
2405
  tenantId: scope.tenantId,
2013
2406
  workspaceId: scope.workspaceId
@@ -2058,13 +2451,16 @@ var getByProjectSystem = query({
2058
2451
  if (!scope) {
2059
2452
  return [];
2060
2453
  }
2061
- const nodes = await getEvidenceNodesForScope(ctx, scope, { scanLimit });
2454
+ const nodes = readEvidenceNodeRows(
2455
+ await getEvidenceNodesForScope(ctx, scope, { scanLimit }),
2456
+ scope.projectId
2457
+ );
2062
2458
  const filtered = args.kind ? nodes.filter((n) => {
2063
2459
  const meta = n.metadata || {};
2064
2460
  return meta.kind === args.kind;
2065
2461
  }) : nodes;
2066
2462
  filtered.sort((a, b) => b.createdAt - a.createdAt);
2067
- return filtered.slice(0, pageSize).map((n) => formatEvidenceNode(n));
2463
+ return filtered.filter(hasProjectId).slice(0, pageSize).map((n) => formatEvidenceNode(n));
2068
2464
  }
2069
2465
  });
2070
2466
  var getEvidenceBalance = query({
@@ -2078,16 +2474,21 @@ var getEvidenceBalance = query({
2078
2474
  topicId: args.topicId,
2079
2475
  projectId: args.projectId
2080
2476
  });
2081
- const hasAccess = await checkScopeAccess(
2082
- ctx,
2083
- scope.topicId ? String(scope.topicId) : scope.projectId,
2084
- args.userId
2085
- );
2477
+ const scopeId = scope.topicId ? String(scope.topicId) : scope.projectId;
2478
+ if (!scopeId) {
2479
+ return { supporting: 0, challenging: 0, total: 0 };
2480
+ }
2481
+ const hasAccess = await checkScopeAccess(ctx, scopeId, args.userId);
2086
2482
  if (!hasAccess) {
2087
2483
  return { supporting: 0, challenging: 0, total: 0 };
2088
2484
  }
2089
2485
  const resolvedTopicId = scope.topicId || scope.projectId;
2090
- const edges = resolvedTopicId ? await ctx.db.query("epistemicEdges").withIndex("by_topic", (q) => q.eq("topicId", resolvedTopicId)).collect() : [];
2486
+ const edges = resolvedTopicId ? readEvidenceEdgeRows(
2487
+ await ctx.db.query("epistemicEdges").withIndex(
2488
+ "by_topic",
2489
+ (q) => q.eq("topicId", resolvedTopicId)
2490
+ ).collect()
2491
+ ) : [];
2091
2492
  const evidenceEdges = edges.filter(
2092
2493
  (e) => e.edgeType === "informs" && e.fromLayer === "L2" && e.toLayer === "L3"
2093
2494
  );