@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,16 +1,20 @@
1
- import { v } from 'convex/values';
2
- import { requireProjectAccess, checkProjectAccess } from '@lucern/access-control/access';
1
+ import { requireScopeWriteAccess } from '@lucern/access-control/access';
2
+ import { EVIDENCE_SOURCE_QUALITY_VALUES, EVIDENCE_METHODOLOGY_VALUES, EVIDENCE_INFORMATION_ASYMMETRY_VALUES, assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
3
3
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
4
- import { componentsGeneric, anyApi, mutationGeneric, internalMutationGeneric } from 'convex/server';
4
+ import { v } from 'convex/values';
5
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
6
+ import { componentsGeneric, mutationGeneric, internalMutationGeneric } from 'convex/server';
7
+ import '@lucern/access-control/audience';
5
8
  import { generateGlobalId, assertUuidV7Identity, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
6
9
  import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
7
- import '@lucern/access-control/audience';
8
- import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
9
10
 
10
11
  // src/epistemicEvidenceMutations.ts
11
- var api = anyApi;
12
+ var unsafeApi = unsafeConvexAnyApi(
13
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
14
+ );
15
+ var api = unsafeApi;
12
16
  componentsGeneric();
13
- var internal = anyApi;
17
+ var internal = unsafeApi;
14
18
  var internalMutation = internalMutationGeneric;
15
19
  var mutation = mutationGeneric;
16
20
 
@@ -27,22 +31,19 @@ function debugGraphPrimitiveFallback(message, context) {
27
31
  }
28
32
 
29
33
  // src/embeddingTrigger.ts
34
+ var embeddingActionRef = "embeddingActions:generateEpistemicNodeEmbedding";
30
35
  async function scheduleEmbeddingGeneration(args) {
31
36
  try {
32
- await args.ctx.scheduler.runAfter(
33
- 0,
34
- "embeddingActions:generateEpistemicNodeEmbedding",
35
- {
36
- nodeId: args.nodeId,
37
- projectId: args.projectId ? String(args.projectId) : void 0,
38
- topicId: args.topicId ? String(args.topicId) : void 0,
39
- createdBy: args.createdBy,
40
- nodeType: args.nodeType,
41
- text: args.text.slice(0, 2e4),
42
- hasAnswer: args.hasAnswer,
43
- confidence: args.confidence
44
- }
45
- );
37
+ await args.ctx.scheduler.runAfter(0, embeddingActionRef, {
38
+ nodeId: args.nodeId,
39
+ projectId: args.projectId ? String(args.projectId) : void 0,
40
+ topicId: args.topicId ? String(args.topicId) : void 0,
41
+ createdBy: args.createdBy,
42
+ nodeType: args.nodeType,
43
+ text: args.text.slice(0, 2e4),
44
+ hasAnswer: args.hasAnswer,
45
+ confidence: args.confidence
46
+ });
46
47
  } catch (error) {
47
48
  debugGraphPrimitiveFallback(
48
49
  "[embeddingTrigger] Failed to schedule embedding generation",
@@ -54,350 +55,9 @@ async function scheduleEmbeddingGeneration(args) {
54
55
  );
55
56
  }
56
57
  }
57
- var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
58
- async function resolveTopicNodeScopeOrNull(ctx, ref) {
59
- if (!ctx?.db || typeof ctx.db.query !== "function") {
60
- return null;
61
- }
62
- let node = null;
63
- try {
64
- const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
65
- if (byGlobalId && byGlobalId.nodeType === "topic") {
66
- node = byGlobalId;
67
- }
68
- } catch (error) {
69
- debugGraphPrimitiveFallback(
70
- "[topicScope] topic-node scope lookup by globalId failed",
71
- { error, ref }
72
- );
73
- }
74
- if (!node) {
75
- return null;
76
- }
77
- const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
78
- if (!scopeKey) {
79
- return null;
80
- }
81
- return {
82
- topicId: scopeKey,
83
- projectId: asMappedProjectId(node),
84
- source: "topic_node"
85
- };
86
- }
87
- function asMappedProjectId(topic) {
88
- if (!topic) {
89
- return;
90
- }
91
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
92
- if (directLegacyProjectId) {
93
- return directLegacyProjectId;
94
- }
95
- const metadata = topic.metadata || {};
96
- const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
97
- return candidate ? candidate : void 0;
98
- }
99
- function normalizeScopeValue(value) {
100
- if (typeof value !== "string") {
101
- return;
102
- }
103
- const normalized = value.trim();
104
- return normalized.length > 0 ? normalized : void 0;
105
- }
106
- function pickPrimaryTopic(candidates) {
107
- return [...candidates].sort((a, b) => {
108
- const depthA = a.depth ?? 9999;
109
- const depthB = b.depth ?? 9999;
110
- if (depthA !== depthB) {
111
- return depthA - depthB;
112
- }
113
- const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
114
- const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
115
- if (createdA !== createdB) {
116
- return createdA - createdB;
117
- }
118
- return String(a.name || "").localeCompare(String(b.name || ""));
119
- })[0];
120
- }
121
- async function findTopicsByScopeAlias(ctx, scopeId) {
122
- try {
123
- return await ctx.db.query("topics").withIndex(
124
- "by_graph_scope_project",
125
- (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
126
- ).collect();
127
- } catch (error) {
128
- debugGraphPrimitiveFallback(
129
- "[topicScope] Failed to resolve scope alias via index",
130
- {
131
- error,
132
- scopeId
133
- }
134
- );
135
- const topics = await ctx.db.query("topics").collect();
136
- return topics.filter((topic) => {
137
- const normalizedGlobalId = normalizeScopeValue(topic.globalId);
138
- const mappedProjectId = asMappedProjectId(topic);
139
- return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
140
- });
141
- }
142
- }
143
- async function tryResolveHostTopicById(ctx, topicId) {
144
- if (typeof ctx.runQuery !== "function") {
145
- return null;
146
- }
147
- try {
148
- return await ctx.runQuery(api.topics.get, {
149
- id: topicId
150
- }) ?? null;
151
- } catch (error) {
152
- debugGraphPrimitiveFallback(
153
- "[topicScope] Failed to resolve topic by host query",
154
- {
155
- error,
156
- topicId
157
- }
158
- );
159
- return null;
160
- }
161
- }
162
- async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
163
- if (typeof ctx.runQuery !== "function") {
164
- return null;
165
- }
166
- try {
167
- return await ctx.runQuery(api.topics.getByLegacyScopeId, {
168
- projectId: legacyScopeId
169
- }) ?? null;
170
- } catch (error) {
171
- debugGraphPrimitiveFallback(
172
- "[topicScope] Failed to resolve topic by legacy scope",
173
- {
174
- error,
175
- legacyScopeId
176
- }
177
- );
178
- return null;
179
- }
180
- }
181
- async function resolveInheritedWorkspaceScope(ctx, topic) {
182
- const MAX_DEPTH = 10;
183
- let tenantId = normalizeScopeValue(topic.tenantId);
184
- let workspaceId = normalizeScopeValue(topic.workspaceId);
185
- if (tenantId && workspaceId) {
186
- return { tenantId, workspaceId };
187
- }
188
- let current = topic;
189
- for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
190
- current = await ctx.db.get(current.parentTopicId);
191
- if (!current) break;
192
- if (!tenantId) {
193
- tenantId = normalizeScopeValue(current.tenantId);
194
- }
195
- if (!workspaceId) {
196
- workspaceId = normalizeScopeValue(current.workspaceId);
197
- }
198
- if (tenantId && workspaceId) break;
199
- }
200
- return { tenantId, workspaceId };
201
- }
202
- async function resolveTopicProjectScope(ctx, args) {
203
- if (args.topicId) {
204
- let topic = null;
205
- try {
206
- topic = await ctx.db.get(
207
- args.topicId
208
- );
209
- } catch (error) {
210
- debugGraphPrimitiveFallback(
211
- "[topicScope] Failed to load topic by direct id",
212
- {
213
- error,
214
- topicId: args.topicId
215
- }
216
- );
217
- }
218
- if (!topic) {
219
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
220
- }
221
- if (!topic) {
222
- topic = pickPrimaryTopic(
223
- await findTopicsByScopeAlias(ctx, String(args.topicId))
224
- ) ?? null;
225
- }
226
- if (!topic) {
227
- const nodeScope = await resolveTopicNodeScopeOrNull(
228
- ctx,
229
- String(args.topicId)
230
- );
231
- if (nodeScope) {
232
- return nodeScope;
233
- }
234
- throw new Error(`Topic not found: ${String(args.topicId)}`);
235
- }
236
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
237
- const mapped = asMappedProjectId(topic);
238
- if (mapped) {
239
- return {
240
- topicId: topic._id,
241
- projectId: mapped,
242
- tenantId: inherited.tenantId,
243
- workspaceId: inherited.workspaceId,
244
- source: "topic"
245
- };
246
- }
247
- return {
248
- topicId: topic._id,
249
- tenantId: inherited.tenantId,
250
- workspaceId: inherited.workspaceId,
251
- source: "topic"
252
- };
253
- }
254
- if (args.projectId) {
255
- let directTopic = null;
256
- try {
257
- directTopic = await ctx.db.get(
258
- args.projectId
259
- );
260
- } catch (error) {
261
- debugGraphPrimitiveFallback(
262
- "[topicScope] Failed to load direct project topic",
263
- {
264
- error,
265
- projectId: args.projectId
266
- }
267
- );
268
- }
269
- if (directTopic) {
270
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
271
- const mapped = asMappedProjectId(directTopic);
272
- return {
273
- topicId: directTopic._id,
274
- projectId: mapped ?? args.projectId,
275
- tenantId: inherited.tenantId,
276
- workspaceId: inherited.workspaceId,
277
- source: "topic_inferred"
278
- };
279
- }
280
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
281
- if (directTopic) {
282
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
283
- const mapped = asMappedProjectId(directTopic);
284
- return {
285
- topicId: directTopic._id,
286
- projectId: mapped ?? args.projectId,
287
- tenantId: inherited.tenantId,
288
- workspaceId: inherited.workspaceId,
289
- source: "topic_inferred"
290
- };
291
- }
292
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
293
- const primary = pickPrimaryTopic(topics);
294
- if (primary) {
295
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
296
- return {
297
- topicId: primary._id,
298
- projectId: args.projectId,
299
- tenantId: inherited.tenantId,
300
- workspaceId: inherited.workspaceId,
301
- source: "project_mapped_topic"
302
- };
303
- }
304
- const nodeScope = await resolveTopicNodeScopeOrNull(
305
- ctx,
306
- String(args.projectId)
307
- );
308
- if (nodeScope) {
309
- return {
310
- ...nodeScope,
311
- projectId: nodeScope.projectId ?? String(args.projectId)
312
- };
313
- }
314
- throw new Error(
315
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
316
- );
317
- }
318
- throw new Error(
319
- "Missing scope: provide topicId (preferred) or legacy projectId alias."
320
- );
321
- }
322
- var optionalScopeArgs = {
323
- projectId: v.optional(v.string()),
324
- topicId: v.optional(v.string())
325
- };
326
-
327
- // src/workspaceIsolation.ts
328
- function normalizeScopeValue2(value) {
329
- if (typeof value !== "string") {
330
- return;
331
- }
332
- const normalized = value.trim();
333
- return normalized.length > 0 ? normalized : void 0;
334
- }
335
- function throwWorkspaceIsolationError(args) {
336
- const error = new Error(args.message);
337
- error.status = 409;
338
- error.code = "INVARIANT_VIOLATION";
339
- error.invariantCode = args.invariantCode;
340
- error.suggestion = args.suggestion;
341
- error.details = args.details;
342
- throw error;
343
- }
344
- function assertWorkspaceScopedEpistemicNodeScope(args) {
345
- const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
346
- if (layer === "ontological") {
347
- return;
348
- }
349
- const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
350
- if (workspaceId) {
351
- return;
352
- }
353
- throwWorkspaceIsolationError({
354
- message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
355
- invariantCode: "workspace.scope_required_for_epistemic_nodes",
356
- suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
357
- details: {
358
- mutationName: args.mutationName,
359
- nodeType: args.nodeType,
360
- topicId: args.scope.topicId,
361
- projectId: args.scope.projectId
362
- }
363
- });
364
- }
365
- function resolveRuntimePackMutationContext(args) {
366
- if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
367
- return;
368
- }
369
- return {
370
- toolName: args.runtimeToolName,
371
- packKey: args.runtimePackKey,
372
- packInstallScope: args.runtimePackInstallScope
373
- };
374
- }
375
- function assertTenantPackWorkspaceMutationAllowed(args) {
376
- if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
377
- return;
378
- }
379
- const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
380
- const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
381
- if (!targetWorkspaceId || targetLayer === "ontological") {
382
- return;
383
- }
384
- throwWorkspaceIsolationError({
385
- message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
386
- invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
387
- suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
388
- details: {
389
- mutationName: args.mutationName,
390
- toolName: args.runtime.toolName,
391
- packKey: args.runtime.packKey,
392
- targetWorkspaceId,
393
- targetNodeType: args.target.nodeType,
394
- targetLayer
395
- }
396
- });
397
- }
398
58
 
399
59
  // src/topicProjectOverlay.ts
400
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
60
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
401
61
  function readNonEmptyString(value) {
402
62
  if (typeof value !== "string") {
403
63
  return;
@@ -414,11 +74,15 @@ function readStringArray(value) {
414
74
  function readMetadata(topic) {
415
75
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
416
76
  }
77
+ function omitMetadataKey(metadata, key) {
78
+ const { [key]: _omitted, ...rest } = metadata;
79
+ return rest;
80
+ }
417
81
  function readLegacyProjectId(value) {
418
82
  if (!value) {
419
83
  return;
420
84
  }
421
- return readNonEmptyString(value[LEGACY_SCOPE_FIELD2]);
85
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
422
86
  }
423
87
  function coerceVisibility(value) {
424
88
  return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
@@ -494,9 +158,12 @@ async function resolveTopicDoc(ctx, scopeId) {
494
158
  );
495
159
  }
496
160
  try {
497
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
498
- projectId: String(scopeId)
499
- });
161
+ const topic = await ctx.runQuery(
162
+ api.topics.getByLegacyScopeId,
163
+ {
164
+ projectId: String(scopeId)
165
+ }
166
+ );
500
167
  if (topic?.name !== void 0 && topic?.type !== void 0) {
501
168
  return topic;
502
169
  }
@@ -516,8 +183,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
516
183
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
517
184
  const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
518
185
  const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
519
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
520
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
186
+ let createdAt = 0;
187
+ if (typeof topic.createdAt === "number") {
188
+ createdAt = topic.createdAt;
189
+ } else if (typeof topic._creationTime === "number") {
190
+ createdAt = topic._creationTime;
191
+ }
192
+ let updatedAt = createdAt;
193
+ if (typeof topic.updatedAt === "number") {
194
+ updatedAt = topic.updatedAt;
195
+ } else if (typeof metadata.updatedAt === "number") {
196
+ updatedAt = metadata.updatedAt;
197
+ }
521
198
  return {
522
199
  ...metadata,
523
200
  _id: outwardId,
@@ -586,90 +263,113 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
586
263
  if (!topic) {
587
264
  return null;
588
265
  }
589
- const nextMetadata = { ...readMetadata(topic) };
590
- const patch = {};
591
- const topicUpdateArgs = {
592
- id: String(topic._id)
266
+ const plan = buildTopicProjectOverlayPatchPlan(topic, value);
267
+ await applyTopicProjectOverlayPatch(ctx, topic, plan);
268
+ return materializeTopicProjectOverlay({
269
+ ...topic,
270
+ ...plan.patch,
271
+ metadata: plan.nextMetadata
272
+ });
273
+ }
274
+ function buildTopicProjectOverlayPatchPlan(topic, value) {
275
+ const plan = {
276
+ nextMetadata: { ...readMetadata(topic) },
277
+ patch: {},
278
+ topicUpdateArgs: {
279
+ id: String(topic._id)
280
+ }
593
281
  };
594
282
  for (const [key, rawValue] of Object.entries(value)) {
595
- switch (key) {
596
- case "_id":
597
- case "projectId":
598
- case "topicId":
599
- case "legacyProjectId":
600
- case "storageProjectId":
601
- break;
602
- case "name":
603
- case "description":
604
- patch[key] = rawValue;
605
- topicUpdateArgs[key] = rawValue;
606
- break;
607
- case "tenantId":
608
- case "workspaceId":
609
- case "ownerId":
610
- throw new Error(
611
- `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
612
- );
613
- case "status": {
614
- const status = coerceStatus(rawValue);
615
- if (status) {
616
- patch.status = status;
617
- topicUpdateArgs.status = status;
618
- }
619
- break;
620
- }
621
- case "visibility": {
622
- const visibility = coerceVisibility(rawValue);
623
- if (visibility) {
624
- patch.visibility = visibility;
625
- topicUpdateArgs.visibility = visibility;
626
- }
627
- break;
628
- }
629
- case "type": {
630
- const projectType = readNonEmptyString(rawValue);
631
- if (projectType) {
632
- nextMetadata.projectType = projectType;
633
- } else {
634
- delete nextMetadata.projectType;
635
- }
636
- break;
637
- }
638
- case "updatedAt":
639
- case "createdAt":
640
- break;
641
- default:
642
- if (rawValue === void 0) {
643
- delete nextMetadata[key];
644
- } else {
645
- nextMetadata[key] = rawValue;
646
- }
647
- }
283
+ applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
284
+ }
285
+ plan.patch.updatedAt = Date.now();
286
+ plan.patch.metadata = plan.nextMetadata;
287
+ plan.topicUpdateArgs.metadata = plan.nextMetadata;
288
+ return plan;
289
+ }
290
+ function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
291
+ switch (key) {
292
+ case "_id":
293
+ case "projectId":
294
+ case "topicId":
295
+ case "legacyProjectId":
296
+ case "storageProjectId":
297
+ case "updatedAt":
298
+ case "createdAt":
299
+ return;
300
+ case "name":
301
+ case "description":
302
+ plan.patch[key] = rawValue;
303
+ plan.topicUpdateArgs[key] = rawValue;
304
+ return;
305
+ case "tenantId":
306
+ case "workspaceId":
307
+ case "ownerId":
308
+ throw new Error(
309
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
310
+ );
311
+ case "status":
312
+ applyTopicStatusPatch(plan, rawValue);
313
+ return;
314
+ case "visibility":
315
+ applyTopicVisibilityPatch(plan, rawValue);
316
+ return;
317
+ case "type":
318
+ applyTopicProjectTypePatch(plan, rawValue);
319
+ return;
320
+ default:
321
+ applyTopicMetadataPatch(plan, key, rawValue);
322
+ }
323
+ }
324
+ function applyTopicStatusPatch(plan, rawValue) {
325
+ const status = coerceStatus(rawValue);
326
+ if (status) {
327
+ plan.patch.status = status;
328
+ plan.topicUpdateArgs.status = status;
648
329
  }
649
- patch.updatedAt = Date.now();
650
- patch.metadata = nextMetadata;
651
- topicUpdateArgs.metadata = nextMetadata;
330
+ }
331
+ function applyTopicVisibilityPatch(plan, rawValue) {
332
+ const visibility = coerceVisibility(rawValue);
333
+ if (visibility) {
334
+ plan.patch.visibility = visibility;
335
+ plan.topicUpdateArgs.visibility = visibility;
336
+ }
337
+ }
338
+ function applyTopicProjectTypePatch(plan, rawValue) {
339
+ const projectType = readNonEmptyString(rawValue);
340
+ if (projectType) {
341
+ plan.nextMetadata.projectType = projectType;
342
+ return;
343
+ }
344
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
345
+ }
346
+ function applyTopicMetadataPatch(plan, key, rawValue) {
347
+ if (rawValue === void 0) {
348
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
349
+ return;
350
+ }
351
+ plan.nextMetadata[key] = rawValue;
352
+ }
353
+ async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
652
354
  if (typeof ctx.runMutation === "function") {
653
355
  try {
654
- await ctx.runMutation(api.topics.update, topicUpdateArgs);
356
+ await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
655
357
  } catch (error) {
656
- if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
358
+ if (!canPatchTopicViaLocalDb(ctx, error)) {
657
359
  throw error;
658
360
  }
659
- await ctx.db.patch(String(topic._id), patch);
361
+ await ctx.db.patch(topic._id, plan.patch);
660
362
  }
661
363
  } else if (ctx?.db && typeof ctx.db.patch === "function") {
662
- await ctx.db.patch(String(topic._id), patch);
364
+ await ctx.db.patch(topic._id, plan.patch);
663
365
  } else {
664
366
  throw new Error(
665
367
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
666
368
  );
667
369
  }
668
- return materializeTopicProjectOverlay({
669
- ...topic,
670
- ...patch,
671
- metadata: nextMetadata
672
- });
370
+ }
371
+ function canPatchTopicViaLocalDb(ctx, error) {
372
+ return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
673
373
  }
674
374
 
675
375
  // src/resolvers.ts
@@ -697,7 +397,7 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
697
397
  try {
698
398
  await patchTopicProjectOverlay(ctx, projectId, value);
699
399
  } catch (error) {
700
- if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
400
+ if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
701
401
  throw error;
702
402
  }
703
403
  console.warn(
@@ -710,26 +410,276 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
710
410
  );
711
411
  }
712
412
  }
713
- function defaultResolvers() {
714
- return {
715
- getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
716
- idMode: "legacy",
717
- projectLikeOnly: false
718
- }),
719
- patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
720
- listTopics: (ctx) => listTopicProjectOverlays(ctx, {
721
- idMode: "legacy"
722
- }),
723
- getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
724
- };
413
+ function defaultResolvers() {
414
+ return {
415
+ getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
416
+ idMode: "legacy",
417
+ projectLikeOnly: false
418
+ }),
419
+ patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
420
+ listTopics: (ctx) => listTopicProjectOverlays(ctx, {
421
+ idMode: "legacy"
422
+ }),
423
+ getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
424
+ };
425
+ }
426
+ var resolverOverrides = {};
427
+ function resolveGraphPrimitivesAppResolvers(_ctx) {
428
+ return {
429
+ ...defaultResolvers(),
430
+ ...resolverOverrides
431
+ };
432
+ }
433
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
434
+ async function resolveTopicNodeScopeOrNull(ctx, ref) {
435
+ if (!ctx?.db || typeof ctx.db.query !== "function") {
436
+ return null;
437
+ }
438
+ let node = null;
439
+ try {
440
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
441
+ if (byGlobalId && byGlobalId.nodeType === "topic") {
442
+ node = byGlobalId;
443
+ }
444
+ } catch (error) {
445
+ debugGraphPrimitiveFallback(
446
+ "[topicScope] topic-node scope lookup by globalId failed",
447
+ { error, ref }
448
+ );
449
+ }
450
+ if (!node) {
451
+ return null;
452
+ }
453
+ const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
454
+ if (!scopeKey) {
455
+ return null;
456
+ }
457
+ return {
458
+ topicId: scopeKey,
459
+ projectId: asMappedProjectId(node),
460
+ source: "topic_node"
461
+ };
462
+ }
463
+ function asMappedProjectId(topic) {
464
+ if (!topic) {
465
+ return;
466
+ }
467
+ const directLegacyProjectId = normalizeScopeValue(
468
+ topic[LEGACY_SCOPE_FIELD2]
469
+ );
470
+ if (directLegacyProjectId) {
471
+ return directLegacyProjectId;
472
+ }
473
+ const metadata = topic.metadata || {};
474
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
475
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
476
+ }
477
+ function normalizeScopeValue(value) {
478
+ if (typeof value !== "string") {
479
+ return;
480
+ }
481
+ const normalized = value.trim();
482
+ return normalized.length > 0 ? normalized : void 0;
483
+ }
484
+ function pickPrimaryTopic(candidates) {
485
+ return [...candidates].sort((a, b) => {
486
+ const depthA = a.depth ?? 9999;
487
+ const depthB = b.depth ?? 9999;
488
+ if (depthA !== depthB) {
489
+ return depthA - depthB;
490
+ }
491
+ const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
492
+ const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
493
+ if (createdA !== createdB) {
494
+ return createdA - createdB;
495
+ }
496
+ return String(a.name || "").localeCompare(String(b.name || ""));
497
+ })[0];
498
+ }
499
+ async function findTopicsByScopeAlias(ctx, scopeId) {
500
+ const query = ctx.db.query("topics");
501
+ try {
502
+ return await query.withIndex(
503
+ "by_graph_scope_project",
504
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
505
+ ).collect();
506
+ } catch (error) {
507
+ debugGraphPrimitiveFallback(
508
+ "[topicScope] Failed to resolve scope alias via index",
509
+ {
510
+ error,
511
+ scopeId
512
+ }
513
+ );
514
+ const topics = await query.collect();
515
+ return topics.filter((topic) => {
516
+ const normalizedGlobalId = normalizeScopeValue(topic.globalId);
517
+ const mappedProjectId = asMappedProjectId(topic);
518
+ return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
519
+ });
520
+ }
521
+ }
522
+ async function tryResolveHostTopicById(ctx, topicId) {
523
+ if (typeof ctx.runQuery !== "function") {
524
+ return null;
525
+ }
526
+ try {
527
+ return await ctx.runQuery(api.topics.get, {
528
+ id: topicId
529
+ }) ?? null;
530
+ } catch (error) {
531
+ debugGraphPrimitiveFallback(
532
+ "[topicScope] Failed to resolve topic by host query",
533
+ {
534
+ error,
535
+ topicId
536
+ }
537
+ );
538
+ return null;
539
+ }
540
+ }
541
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
542
+ if (typeof ctx.runQuery !== "function") {
543
+ return null;
544
+ }
545
+ try {
546
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
547
+ projectId: legacyScopeId
548
+ }) ?? null;
549
+ } catch (error) {
550
+ debugGraphPrimitiveFallback(
551
+ "[topicScope] Failed to resolve topic by legacy scope",
552
+ {
553
+ error,
554
+ legacyScopeId
555
+ }
556
+ );
557
+ return null;
558
+ }
559
+ }
560
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
561
+ const MAX_DEPTH = 10;
562
+ let tenantId = normalizeScopeValue(topic.tenantId);
563
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
564
+ if (tenantId && workspaceId) {
565
+ return { tenantId, workspaceId };
566
+ }
567
+ let current = topic;
568
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
569
+ current = await ctx.db.get(current.parentTopicId);
570
+ if (!current) {
571
+ break;
572
+ }
573
+ if (!tenantId) {
574
+ tenantId = normalizeScopeValue(current.tenantId);
575
+ }
576
+ if (!workspaceId) {
577
+ workspaceId = normalizeScopeValue(current.workspaceId);
578
+ }
579
+ if (tenantId && workspaceId) {
580
+ break;
581
+ }
582
+ }
583
+ return { tenantId, workspaceId };
584
+ }
585
+ async function resolveTopicProjectScope(ctx, args) {
586
+ if (args.topicId) {
587
+ return await resolveScopeFromTopicId(ctx, args.topicId);
588
+ }
589
+ if (args.projectId) {
590
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
591
+ }
592
+ throw new Error(
593
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
594
+ );
595
+ }
596
+ async function resolveScopeFromTopicId(ctx, topicId) {
597
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
598
+ if (topic) {
599
+ return await buildTopicScope(ctx, topic, "topic");
600
+ }
601
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
602
+ if (nodeScope) {
603
+ return nodeScope;
604
+ }
605
+ throw new Error(`Topic not found: ${String(topicId)}`);
606
+ }
607
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
608
+ const direct = await tryReadTopicDoc(ctx, topicId, {
609
+ failureLog: "[topicScope] Failed to load topic by direct id",
610
+ idLogKey: "topicId"
611
+ });
612
+ if (direct) {
613
+ return direct;
614
+ }
615
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
616
+ if (hostTopic) {
617
+ return hostTopic;
618
+ }
619
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
620
+ }
621
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
622
+ const directTopic = await resolveDirectLegacyProjectTopic(
623
+ ctx,
624
+ legacyProjectId
625
+ );
626
+ if (directTopic) {
627
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
628
+ fallbackProjectId: legacyProjectId
629
+ });
630
+ }
631
+ const primary = pickPrimaryTopic(
632
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
633
+ );
634
+ if (primary) {
635
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
636
+ fallbackProjectId: legacyProjectId
637
+ });
638
+ }
639
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
640
+ if (nodeScope) {
641
+ return {
642
+ ...nodeScope,
643
+ projectId: nodeScope.projectId ?? legacyProjectId
644
+ };
645
+ }
646
+ throw new Error(
647
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
648
+ );
649
+ }
650
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
651
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
652
+ failureLog: "[topicScope] Failed to load direct project topic",
653
+ idLogKey: "projectId"
654
+ });
655
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
725
656
  }
726
- var resolverOverrides = {};
727
- function resolveGraphPrimitivesAppResolvers(_ctx) {
657
+ async function tryReadTopicDoc(ctx, id, log) {
658
+ try {
659
+ return await ctx.db.get(id);
660
+ } catch (error) {
661
+ debugGraphPrimitiveFallback(log.failureLog, {
662
+ error,
663
+ [log.idLogKey]: id
664
+ });
665
+ return null;
666
+ }
667
+ }
668
+ async function buildTopicScope(ctx, topic, source, options = {}) {
669
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
670
+ const mapped = asMappedProjectId(topic);
728
671
  return {
729
- ...defaultResolvers(),
730
- ...resolverOverrides
672
+ topicId: topic._id,
673
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
674
+ tenantId: inherited.tenantId,
675
+ workspaceId: inherited.workspaceId,
676
+ source
731
677
  };
732
678
  }
679
+ var optionalScopeArgs = {
680
+ projectId: v.optional(v.string()),
681
+ topicId: v.optional(v.string())
682
+ };
733
683
 
734
684
  // src/epistemicEvidenceHelpers.ts
735
685
  var optionalEvidenceScopeArgs = optionalScopeArgs;
@@ -765,7 +715,7 @@ function normalizeSourceType(sourceType) {
765
715
  async function markProjectGraphDirty(ctx, projectId, topicId) {
766
716
  const normalizedProjectId = typeof projectId === "string" && projectId.trim().length > 0 ? projectId : void 0;
767
717
  const normalizedTopicId = typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
768
- if (!normalizedProjectId && !normalizedTopicId) {
718
+ if (!(normalizedProjectId || normalizedTopicId)) {
769
719
  return;
770
720
  }
771
721
  if (normalizedProjectId) {
@@ -786,16 +736,22 @@ async function markProjectGraphDirty(ctx, projectId, topicId) {
786
736
  }
787
737
  );
788
738
  }
739
+ const activityScopeId = normalizedTopicId ?? normalizedProjectId;
740
+ if (!activityScopeId) {
741
+ throw new Error(
742
+ "Expected evidence graph dirty scope to include a topic or project id."
743
+ );
744
+ }
789
745
  await resolveGraphPrimitivesAppResolvers().patchProject(
790
746
  ctx,
791
- normalizedTopicId ?? normalizedProjectId,
747
+ activityScopeId,
792
748
  {
793
749
  lastActivityAt: Date.now()
794
750
  }
795
751
  );
796
752
  }
797
753
  async function resolveEvidenceScopeOrNull(ctx, args) {
798
- if (!args.projectId && !args.topicId) {
754
+ if (!(args.projectId || args.topicId)) {
799
755
  return null;
800
756
  }
801
757
  try {
@@ -815,13 +771,16 @@ async function resolveEvidenceScopeOrNull(ctx, args) {
815
771
  return null;
816
772
  }
817
773
  }
818
- async function insertEpistemicNode(ctx, doc) {
774
+ function insertEpistemicNode(ctx, doc) {
819
775
  assertUuidV7Identity("epistemicNodes", doc.globalId);
820
776
  return ctx.db.insert("epistemicNodes", doc);
821
777
  }
822
778
  async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
823
779
  assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
824
- const node = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", endpoint)).first();
780
+ const node = await ctx.db.query("epistemicNodes").withIndex(
781
+ "by_globalId",
782
+ (q) => q.eq("globalId", endpoint)
783
+ ).first();
825
784
  if (!node) {
826
785
  throw new Error(
827
786
  `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
@@ -861,8 +820,188 @@ async function insertEpistemicEdge(ctx, doc) {
861
820
  }
862
821
  return ctx.db.insert("epistemicEdges", doc);
863
822
  }
823
+ function normalizeScopeValue2(value) {
824
+ if (typeof value !== "string") {
825
+ return;
826
+ }
827
+ const normalized = value.trim();
828
+ return normalized.length > 0 ? normalized : void 0;
829
+ }
830
+ function throwWorkspaceIsolationError(args) {
831
+ const error = new Error(args.message);
832
+ error.status = 409;
833
+ error.code = "INVARIANT_VIOLATION";
834
+ error.invariantCode = args.invariantCode;
835
+ error.suggestion = args.suggestion;
836
+ error.details = args.details;
837
+ throw error;
838
+ }
839
+ function assertWorkspaceScopedEpistemicNodeScope(args) {
840
+ const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
841
+ if (layer === "ontological") {
842
+ return;
843
+ }
844
+ const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
845
+ if (workspaceId) {
846
+ return;
847
+ }
848
+ throwWorkspaceIsolationError({
849
+ message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
850
+ invariantCode: "workspace.scope_required_for_epistemic_nodes",
851
+ suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
852
+ details: {
853
+ mutationName: args.mutationName,
854
+ nodeType: args.nodeType,
855
+ topicId: args.scope.topicId,
856
+ projectId: args.scope.projectId
857
+ }
858
+ });
859
+ }
860
+ function resolveRuntimePackMutationContext(args) {
861
+ if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
862
+ return;
863
+ }
864
+ return {
865
+ toolName: args.runtimeToolName,
866
+ packKey: args.runtimePackKey,
867
+ packInstallScope: args.runtimePackInstallScope
868
+ };
869
+ }
870
+ function assertTenantPackWorkspaceMutationAllowed(args) {
871
+ if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
872
+ return;
873
+ }
874
+ const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
875
+ const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
876
+ if (!targetWorkspaceId || targetLayer === "ontological") {
877
+ return;
878
+ }
879
+ throwWorkspaceIsolationError({
880
+ message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
881
+ invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
882
+ suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
883
+ details: {
884
+ mutationName: args.mutationName,
885
+ toolName: args.runtime.toolName,
886
+ packKey: args.runtime.packKey,
887
+ targetWorkspaceId,
888
+ targetNodeType: args.target.nodeType,
889
+ targetLayer
890
+ }
891
+ });
892
+ }
864
893
 
865
894
  // src/epistemicEvidenceMutations.ts
895
+ var EMBEDDING_GENERATION_ACTION = "embeddingActions:generateEpistemicNodeEmbedding";
896
+ function isRecord(value) {
897
+ return typeof value === "object" && value !== null && !Array.isArray(value);
898
+ }
899
+ function metadataRecord(value) {
900
+ return isRecord(value) ? value : {};
901
+ }
902
+ function readOptionalString(value) {
903
+ if (typeof value !== "string") {
904
+ return;
905
+ }
906
+ const trimmed = value.trim();
907
+ return trimmed.length > 0 ? trimmed : void 0;
908
+ }
909
+ function readConvexId(value) {
910
+ const normalized = readOptionalString(value);
911
+ return normalized;
912
+ }
913
+ function assertBeliefNode(node, errorMessage) {
914
+ if (!isRecord(node) || node.nodeType !== "belief" || typeof node.globalId !== "string") {
915
+ throw new Error(errorMessage);
916
+ }
917
+ return node;
918
+ }
919
+ function assertEvidenceNode(node, errorMessage) {
920
+ if (!isRecord(node)) {
921
+ throw new Error(errorMessage);
922
+ }
923
+ const id = readConvexId(node._id);
924
+ if (!(id && node.nodeType === "evidence")) {
925
+ throw new Error(errorMessage);
926
+ }
927
+ const evidence = { _id: id, nodeType: "evidence" };
928
+ const canonicalText = readOptionalString(node.canonicalText);
929
+ if (canonicalText !== void 0) {
930
+ evidence.canonicalText = canonicalText;
931
+ }
932
+ const createdBy = readOptionalString(node.createdBy);
933
+ if (createdBy !== void 0) {
934
+ evidence.createdBy = createdBy;
935
+ }
936
+ if ("metadata" in node) {
937
+ evidence.metadata = node.metadata;
938
+ }
939
+ const projectId = readOptionalString(node.projectId);
940
+ if (projectId !== void 0) {
941
+ evidence.projectId = projectId;
942
+ }
943
+ const status = readOptionalString(node.status);
944
+ if (status !== void 0) {
945
+ evidence.status = status;
946
+ }
947
+ const topicId = readOptionalString(node.topicId);
948
+ if (topicId !== void 0) {
949
+ evidence.topicId = topicId;
950
+ }
951
+ return evidence;
952
+ }
953
+ function readEvidenceNodeOrNull(node) {
954
+ if (!isRecord(node) || node.nodeType !== "evidence") {
955
+ return null;
956
+ }
957
+ try {
958
+ return assertEvidenceNode(node, "Evidence node not found");
959
+ } catch {
960
+ return null;
961
+ }
962
+ }
963
+ function optionalTrimmedString(value) {
964
+ if (typeof value !== "string") {
965
+ return;
966
+ }
967
+ const trimmed = value.trim();
968
+ return trimmed.length > 0 ? trimmed : void 0;
969
+ }
970
+ async function resolveEvidenceNodeId(ctx, args) {
971
+ if (args.nodeId) {
972
+ return args.nodeId;
973
+ }
974
+ const insightId = readOptionalString(args.insightId);
975
+ if (!insightId) {
976
+ throw new Error("Either nodeId or insightId is required");
977
+ }
978
+ const normalizedId = ctx.db.normalizeId?.("epistemicNodes", insightId) ?? readConvexId(insightId);
979
+ if (normalizedId) {
980
+ try {
981
+ const direct = readEvidenceNodeOrNull(await ctx.db.get(normalizedId));
982
+ if (direct) {
983
+ return direct._id;
984
+ }
985
+ } catch {
986
+ }
987
+ }
988
+ const byGlobalId = readEvidenceNodeOrNull(
989
+ await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", insightId)).first()
990
+ );
991
+ if (!byGlobalId) {
992
+ throw new Error("Evidence node not found");
993
+ }
994
+ return byGlobalId._id;
995
+ }
996
+ function optionalLiteral(values, value, fieldName) {
997
+ if (typeof value !== "string" || value.length === 0) {
998
+ return;
999
+ }
1000
+ if (values.includes(value)) {
1001
+ return value;
1002
+ }
1003
+ throw new Error(`Evidence ${fieldName} must be one of: ${values.join(", ")}`);
1004
+ }
866
1005
  function assertSignedImpactScore(value, context) {
867
1006
  if (typeof value !== "number" || !Number.isFinite(value) || value === 0 || value < -1 || value > 1) {
868
1007
  throw new Error(`${context} requires explicit nonzero weight in [-1, 1]`);
@@ -875,12 +1014,121 @@ function normalizeEvidenceRelation(relation, weight, context) {
875
1014
  throw new Error(`${context} supports relation requires positive weight`);
876
1015
  }
877
1016
  if (relation === "contradicts" && weight > 0) {
878
- throw new Error(`${context} contradicts relation requires negative weight`);
1017
+ throw new Error(
1018
+ `${context} contradicts relation requires negative weight`
1019
+ );
879
1020
  }
880
1021
  return relation;
881
1022
  }
882
1023
  return weight < 0 ? "contradicts" : "supports";
883
1024
  }
1025
+ function planEvidenceImpact(args, context) {
1026
+ const weight = assertSignedImpactScore(args.weight, context);
1027
+ const signedImpact = args.signedImpact === void 0 ? weight : assertSignedImpactScore(args.signedImpact, `${context} signedImpact`);
1028
+ return {
1029
+ confidence: Math.abs(weight),
1030
+ evidenceRelation: normalizeEvidenceRelation(
1031
+ args.evidenceRelation,
1032
+ weight,
1033
+ context
1034
+ ),
1035
+ signedImpact,
1036
+ weight
1037
+ };
1038
+ }
1039
+ function evidenceTaxonomyProjection(args) {
1040
+ const sourceRef = optionalTrimmedString(args.sourceRef);
1041
+ const sourceQuality = optionalLiteral(
1042
+ EVIDENCE_SOURCE_QUALITY_VALUES,
1043
+ args.sourceQuality,
1044
+ "sourceQuality"
1045
+ );
1046
+ const methodology = optionalLiteral(
1047
+ EVIDENCE_METHODOLOGY_VALUES,
1048
+ args.methodology,
1049
+ "methodology"
1050
+ );
1051
+ const informationAsymmetry = optionalLiteral(
1052
+ EVIDENCE_INFORMATION_ASYMMETRY_VALUES,
1053
+ args.informationAsymmetry,
1054
+ "informationAsymmetry"
1055
+ );
1056
+ const sourceDescription = optionalTrimmedString(args.sourceDescription);
1057
+ return {
1058
+ ...sourceRef ? { sourceRef } : {},
1059
+ ...sourceQuality ? { sourceQuality } : {},
1060
+ ...methodology ? { methodology } : {},
1061
+ ...informationAsymmetry ? { informationAsymmetry } : {},
1062
+ ...sourceDescription ? { sourceDescription } : {}
1063
+ };
1064
+ }
1065
+ function evidenceTextProjection(args) {
1066
+ const title = optionalTrimmedString(args.title);
1067
+ const contentType = optionalTrimmedString(args.contentType);
1068
+ return {
1069
+ ...title ? { title } : {},
1070
+ ...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
1071
+ ...contentType ? { contentType } : {}
1072
+ };
1073
+ }
1074
+ function evidenceMetadata(args, impact, kind, profile) {
1075
+ const base = {
1076
+ kind,
1077
+ tags: args.tags || [],
1078
+ linkedBeliefNodeId: args.linkedBeliefNodeId,
1079
+ evidenceRelation: impact.evidenceRelation,
1080
+ confidence: impact.confidence,
1081
+ weight: impact.weight,
1082
+ impactScore: impact.weight
1083
+ };
1084
+ const sourceContext = profile === "createAndLink" ? {} : {
1085
+ externalSourceType: args.externalSourceType,
1086
+ sourceUrl: args.sourceUrl,
1087
+ sourceQuestionId: args.sourceQuestionId,
1088
+ rationale: args.rationale
1089
+ };
1090
+ const publicCreateTaxonomy = profile === "create" ? {
1091
+ methodology: args.methodology,
1092
+ informationAsymmetry: args.informationAsymmetry,
1093
+ sourceDescription: args.sourceDescription
1094
+ } : {};
1095
+ return {
1096
+ ...base,
1097
+ ...sourceContext,
1098
+ ...publicCreateTaxonomy,
1099
+ ...metadataRecord(args.metadata)
1100
+ };
1101
+ }
1102
+ function buildEvidenceNodeInsert(args) {
1103
+ return {
1104
+ globalId: args.globalId,
1105
+ topicId: args.scope.topicId,
1106
+ projectId: args.scope.projectId,
1107
+ tenantId: args.scope.tenantId,
1108
+ workspaceId: args.scope.workspaceId,
1109
+ nodeType: "evidence",
1110
+ canonicalText: args.write.text,
1111
+ contentHash: generateContentHash(args.write.text),
1112
+ ...evidenceTextProjection(args.write),
1113
+ status: "active",
1114
+ epistemicLayer: "L2",
1115
+ sourceType: args.sourceType,
1116
+ // RC.1 taxonomy fields — top-level projection
1117
+ evidenceRelation: args.impact.evidenceRelation,
1118
+ signedImpact: args.impact.signedImpact,
1119
+ targetBeliefId: String(args.linkedBeliefNodeId),
1120
+ ...evidenceTaxonomyProjection(args.write),
1121
+ createdAt: args.now,
1122
+ updatedAt: args.now,
1123
+ createdBy: args.write.userId,
1124
+ metadata: evidenceMetadata(
1125
+ args.write,
1126
+ args.impact,
1127
+ args.kind,
1128
+ args.metadataProfile
1129
+ )
1130
+ };
1131
+ }
884
1132
  async function createEvidenceBeliefEdge(ctx, args) {
885
1133
  const edgeGlobalId = generateGlobalId();
886
1134
  const confidence = Math.abs(args.weight);
@@ -1001,70 +1249,31 @@ var create = mutation({
1001
1249
  mutationName: "epistemicEvidence.create"
1002
1250
  });
1003
1251
  if (scope.projectId) {
1004
- await requireProjectAccess(ctx, scope.projectId, args.userId);
1252
+ await requireScopeWriteAccess(ctx, scope.projectId, args.userId);
1005
1253
  }
1006
1254
  const now = Date.now();
1007
1255
  const globalId = generateGlobalId();
1008
- const contentHash = generateContentHash(args.text);
1009
1256
  const kind = normalizeKind(args.kind);
1010
1257
  const sourceType = normalizeSourceType(args.sourceType);
1011
- const weight = assertSignedImpactScore(args.weight, "Evidence creation");
1012
- const signedImpact = args.signedImpact !== void 0 ? assertSignedImpactScore(args.signedImpact, "Evidence creation signedImpact") : weight;
1013
- const evidenceRelation = normalizeEvidenceRelation(
1014
- args.evidenceRelation,
1015
- weight,
1016
- "Evidence creation"
1258
+ const impact = planEvidenceImpact(args, "Evidence creation");
1259
+ const linkedBeliefNode = assertBeliefNode(
1260
+ await ctx.db.get(args.linkedBeliefNodeId),
1261
+ "Evidence creation requires a linked belief node"
1017
1262
  );
1018
- const linkedBeliefNode = await ctx.db.get(args.linkedBeliefNodeId);
1019
- if (!linkedBeliefNode || linkedBeliefNode.nodeType !== "belief") {
1020
- throw new Error("Evidence creation requires a linked belief node");
1021
- }
1022
- const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
1023
- const nodeId = await insertEpistemicNode(ctx, {
1024
- globalId,
1025
- topicId: scope.topicId,
1026
- projectId: scope.projectId,
1027
- tenantId: scope.tenantId,
1028
- workspaceId: scope.workspaceId,
1029
- nodeType: "evidence",
1030
- canonicalText: args.text,
1031
- contentHash,
1032
- ...typeof args.title === "string" && args.title.trim().length > 0 ? { title: args.title.trim() } : {},
1033
- ...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
1034
- ...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
1035
- status: "active",
1036
- epistemicLayer: "L2",
1037
- sourceType,
1038
- // RC.1 taxonomy fields — top-level projection
1039
- evidenceRelation,
1040
- signedImpact,
1041
- targetBeliefId: String(args.linkedBeliefNodeId),
1042
- ...typeof args.sourceRef === "string" && args.sourceRef.trim().length > 0 ? { sourceRef: args.sourceRef.trim() } : {},
1043
- ...typeof args.sourceQuality === "string" && args.sourceQuality.length > 0 ? { sourceQuality: args.sourceQuality } : {},
1044
- ...typeof args.methodology === "string" && args.methodology.length > 0 ? { methodology: args.methodology } : {},
1045
- ...typeof args.informationAsymmetry === "string" && args.informationAsymmetry.length > 0 ? { informationAsymmetry: args.informationAsymmetry } : {},
1046
- ...typeof args.sourceDescription === "string" && args.sourceDescription.trim().length > 0 ? { sourceDescription: args.sourceDescription.trim() } : {},
1047
- createdAt: now,
1048
- updatedAt: now,
1049
- createdBy: args.userId,
1050
- metadata: {
1263
+ const nodeId = await insertEpistemicNode(
1264
+ ctx,
1265
+ buildEvidenceNodeInsert({
1266
+ globalId,
1267
+ impact,
1051
1268
  kind,
1052
- tags: args.tags || [],
1053
- externalSourceType: args.externalSourceType,
1054
- sourceUrl: args.sourceUrl,
1055
- sourceQuestionId: args.sourceQuestionId,
1056
- rationale: args.rationale,
1057
1269
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1058
- evidenceRelation,
1059
- confidence: Math.abs(weight),
1060
- weight,
1061
- impactScore: weight,
1062
- methodology: args.methodology,
1063
- informationAsymmetry: args.informationAsymmetry,
1064
- sourceDescription: args.sourceDescription,
1065
- ...additionalMetadata
1066
- }
1067
- });
1270
+ metadataProfile: "create",
1271
+ now,
1272
+ scope,
1273
+ sourceType,
1274
+ write: args
1275
+ })
1276
+ );
1068
1277
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1069
1278
  nodeId,
1070
1279
  operation: "upsert"
@@ -1082,8 +1291,8 @@ var create = mutation({
1082
1291
  evidenceGlobalId: globalId,
1083
1292
  beliefNodeId: args.linkedBeliefNodeId,
1084
1293
  beliefGlobalId: linkedBeliefNode.globalId,
1085
- relation: evidenceRelation,
1086
- weight,
1294
+ relation: impact.evidenceRelation,
1295
+ weight: impact.weight,
1087
1296
  userId: args.userId,
1088
1297
  topicId: scope.topicId ? String(scope.topicId) : void 0,
1089
1298
  projectId: scope.projectId ? String(scope.projectId) : void 0,
@@ -1103,23 +1312,19 @@ var create = mutation({
1103
1312
  kind,
1104
1313
  sourceType,
1105
1314
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1106
- evidenceRelation,
1107
- weight
1315
+ evidenceRelation: impact.evidenceRelation,
1316
+ weight: impact.weight
1108
1317
  }
1109
1318
  });
1110
1319
  if (scope.projectId || scope.topicId) {
1111
- await ctx.scheduler.runAfter(
1112
- 0,
1113
- "embeddingActions:generateEpistemicNodeEmbedding",
1114
- {
1115
- nodeId,
1116
- projectId: scope.projectId,
1117
- topicId: scope.topicId ? String(scope.topicId) : void 0,
1118
- createdBy: args.userId,
1119
- nodeType: "evidence",
1120
- text: args.text
1121
- }
1122
- );
1320
+ await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
1321
+ nodeId,
1322
+ projectId: scope.projectId,
1323
+ topicId: scope.topicId ? String(scope.topicId) : void 0,
1324
+ createdBy: args.userId,
1325
+ nodeType: "evidence",
1326
+ text: args.text
1327
+ });
1123
1328
  }
1124
1329
  if (scope.projectId || scope.topicId) {
1125
1330
  await ctx.scheduler.runAfter(
@@ -1133,7 +1338,11 @@ var create = mutation({
1133
1338
  }
1134
1339
  );
1135
1340
  }
1136
- await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
1341
+ await markProjectGraphDirty(
1342
+ ctx,
1343
+ scope.projectId,
1344
+ scope.topicId ? String(scope.topicId) : void 0
1345
+ );
1137
1346
  return { nodeId };
1138
1347
  }
1139
1348
  });
@@ -1171,58 +1380,39 @@ var createAndLink = mutation({
1171
1380
  if (!scope) {
1172
1381
  throw new Error("Invalid scope: projectId or topicId is required");
1173
1382
  }
1174
- await requireProjectAccess(ctx, String(scope.topicId), args.userId);
1383
+ const accessScopeId = scope.projectId ?? (scope.topicId ? String(scope.topicId) : void 0);
1384
+ if (!accessScopeId) {
1385
+ throw new Error("Resolved evidence scope has no access-control id");
1386
+ }
1387
+ await requireScopeWriteAccess(ctx, accessScopeId, args.userId);
1175
1388
  const now = Date.now();
1176
1389
  const globalId = generateGlobalId();
1177
- const contentHash = generateContentHash(args.text);
1178
1390
  const kind = normalizeKind(args.kind);
1179
1391
  const sourceType = normalizeSourceType(args.sourceType);
1180
- const weight = assertSignedImpactScore(args.weight, "Evidence createAndLink");
1181
- const signedImpact = args.signedImpact !== void 0 ? assertSignedImpactScore(args.signedImpact, "Evidence createAndLink signedImpact") : weight;
1182
- const relation = normalizeEvidenceRelation(
1183
- args.relation,
1184
- weight,
1185
- "Evidence createAndLink"
1392
+ const write = {
1393
+ ...args,
1394
+ evidenceRelation: args.relation,
1395
+ linkedBeliefNodeId: args.beliefNodeId
1396
+ };
1397
+ const impact = planEvidenceImpact(write, "Evidence createAndLink");
1398
+ const beliefNode = assertBeliefNode(
1399
+ await ctx.db.get(args.beliefNodeId),
1400
+ "Belief node not found for edge creation"
1186
1401
  );
1187
- const confidence = Math.abs(weight);
1188
- const beliefNode = await ctx.db.get(args.beliefNodeId);
1189
- if (!beliefNode || beliefNode.nodeType !== "belief") {
1190
- throw new Error("Belief node not found for edge creation");
1191
- }
1192
- const nodeId = await insertEpistemicNode(ctx, {
1193
- globalId,
1194
- topicId: scope.topicId,
1195
- projectId: scope.projectId,
1196
- tenantId: scope.tenantId,
1197
- workspaceId: scope.workspaceId,
1198
- nodeType: "evidence",
1199
- canonicalText: args.text,
1200
- contentHash,
1201
- status: "active",
1202
- epistemicLayer: "L2",
1203
- sourceType,
1204
- // RC.1 taxonomy fields — top-level projection
1205
- evidenceRelation: relation,
1206
- signedImpact,
1207
- targetBeliefId: String(args.beliefNodeId),
1208
- ...typeof args.sourceRef === "string" && args.sourceRef.trim().length > 0 ? { sourceRef: args.sourceRef.trim() } : {},
1209
- ...typeof args.sourceQuality === "string" && args.sourceQuality.length > 0 ? { sourceQuality: args.sourceQuality } : {},
1210
- ...typeof args.methodology === "string" && args.methodology.length > 0 ? { methodology: args.methodology } : {},
1211
- ...typeof args.informationAsymmetry === "string" && args.informationAsymmetry.length > 0 ? { informationAsymmetry: args.informationAsymmetry } : {},
1212
- ...typeof args.sourceDescription === "string" && args.sourceDescription.trim().length > 0 ? { sourceDescription: args.sourceDescription.trim() } : {},
1213
- createdAt: now,
1214
- updatedAt: now,
1215
- createdBy: args.userId,
1216
- metadata: {
1402
+ const nodeId = await insertEpistemicNode(
1403
+ ctx,
1404
+ buildEvidenceNodeInsert({
1405
+ globalId,
1406
+ impact,
1217
1407
  kind,
1218
- tags: args.tags || [],
1219
1408
  linkedBeliefNodeId: args.beliefNodeId,
1220
- evidenceRelation: relation,
1221
- confidence,
1222
- weight,
1223
- impactScore: weight
1224
- }
1225
- });
1409
+ metadataProfile: "createAndLink",
1410
+ now,
1411
+ scope,
1412
+ sourceType,
1413
+ write
1414
+ })
1415
+ );
1226
1416
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1227
1417
  nodeId,
1228
1418
  operation: "upsert"
@@ -1231,13 +1421,17 @@ var createAndLink = mutation({
1231
1421
  evidenceGlobalId: globalId,
1232
1422
  beliefNodeId: args.beliefNodeId,
1233
1423
  beliefGlobalId: beliefNode.globalId,
1234
- relation,
1235
- weight,
1424
+ relation: impact.evidenceRelation,
1425
+ weight: impact.weight,
1236
1426
  userId: args.userId,
1237
1427
  topicId: scope.topicId ? String(scope.topicId) : void 0,
1238
1428
  projectId: scope.projectId ? String(scope.projectId) : void 0
1239
1429
  });
1240
- await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
1430
+ await markProjectGraphDirty(
1431
+ ctx,
1432
+ scope.projectId,
1433
+ scope.topicId ? String(scope.topicId) : void 0
1434
+ );
1241
1435
  return { nodeId, edgeGlobalId };
1242
1436
  }
1243
1437
  });
@@ -1253,10 +1447,10 @@ var updateStatus = mutation({
1253
1447
  },
1254
1448
  returns: permissiveReturn,
1255
1449
  handler: async (ctx, args) => {
1256
- const node = await ctx.db.get(args.nodeId);
1257
- if (!node || node.nodeType !== "evidence") {
1258
- throw new Error("Evidence not found");
1259
- }
1450
+ const node = assertEvidenceNode(
1451
+ await ctx.db.get(args.nodeId),
1452
+ "Evidence not found"
1453
+ );
1260
1454
  const now = Date.now();
1261
1455
  await ctx.db.patch(args.nodeId, {
1262
1456
  status: args.status,
@@ -1345,63 +1539,27 @@ var internalCreate = internalMutation({
1345
1539
  mutationName: "epistemicEvidence.internalCreate"
1346
1540
  });
1347
1541
  const globalId = generateGlobalId();
1348
- const contentHash = generateContentHash(args.text);
1349
1542
  const kind = normalizeKind(args.kind);
1350
1543
  const sourceType = normalizeSourceType(args.sourceType);
1351
- const weight = assertSignedImpactScore(args.weight, "Internal evidence creation");
1352
- const signedImpact = args.signedImpact !== void 0 ? assertSignedImpactScore(args.signedImpact, "Internal evidence creation signedImpact") : weight;
1353
- const evidenceRelation = normalizeEvidenceRelation(
1354
- args.evidenceRelation,
1355
- weight,
1356
- "Internal evidence creation"
1544
+ const impact = planEvidenceImpact(args, "Internal evidence creation");
1545
+ const linkedBeliefNode = assertBeliefNode(
1546
+ await ctx.db.get(args.linkedBeliefNodeId),
1547
+ "Internal evidence creation requires a linked belief node"
1357
1548
  );
1358
- const linkedBeliefNode = await ctx.db.get(args.linkedBeliefNodeId);
1359
- if (!linkedBeliefNode || linkedBeliefNode.nodeType !== "belief") {
1360
- throw new Error("Internal evidence creation requires a linked belief node");
1361
- }
1362
- const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
1363
- const nodeId = await insertEpistemicNode(ctx, {
1364
- globalId,
1365
- topicId: scope.topicId,
1366
- projectId: scope.projectId,
1367
- tenantId: scope.tenantId,
1368
- workspaceId: scope.workspaceId,
1369
- nodeType: "evidence",
1370
- canonicalText: args.text,
1371
- contentHash,
1372
- ...typeof args.title === "string" && args.title.trim().length > 0 ? { title: args.title.trim() } : {},
1373
- ...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
1374
- ...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
1375
- status: "active",
1376
- epistemicLayer: "L2",
1377
- sourceType,
1378
- // RC.1 taxonomy fields — top-level projection
1379
- evidenceRelation,
1380
- signedImpact,
1381
- targetBeliefId: String(args.linkedBeliefNodeId),
1382
- ...typeof args.sourceRef === "string" && args.sourceRef.trim().length > 0 ? { sourceRef: args.sourceRef.trim() } : {},
1383
- ...typeof args.sourceQuality === "string" && args.sourceQuality.length > 0 ? { sourceQuality: args.sourceQuality } : {},
1384
- ...typeof args.methodology === "string" && args.methodology.length > 0 ? { methodology: args.methodology } : {},
1385
- ...typeof args.informationAsymmetry === "string" && args.informationAsymmetry.length > 0 ? { informationAsymmetry: args.informationAsymmetry } : {},
1386
- ...typeof args.sourceDescription === "string" && args.sourceDescription.trim().length > 0 ? { sourceDescription: args.sourceDescription.trim() } : {},
1387
- createdAt: now,
1388
- updatedAt: now,
1389
- createdBy: args.userId,
1390
- metadata: {
1549
+ const nodeId = await insertEpistemicNode(
1550
+ ctx,
1551
+ buildEvidenceNodeInsert({
1552
+ globalId,
1553
+ impact,
1391
1554
  kind,
1392
- tags: args.tags || [],
1393
- externalSourceType: args.externalSourceType,
1394
- sourceUrl: args.sourceUrl,
1395
- sourceQuestionId: args.sourceQuestionId,
1396
- rationale: args.rationale,
1397
1555
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1398
- evidenceRelation,
1399
- confidence: Math.abs(weight),
1400
- weight,
1401
- impactScore: weight,
1402
- ...additionalMetadata
1403
- }
1404
- });
1556
+ metadataProfile: "internalCreate",
1557
+ now,
1558
+ scope,
1559
+ sourceType,
1560
+ write: args
1561
+ })
1562
+ );
1405
1563
  await ctx.db.insert("epistemicAudit", {
1406
1564
  entityType: "evidence",
1407
1565
  entityId: String(nodeId),
@@ -1418,9 +1576,9 @@ var internalCreate = internalMutation({
1418
1576
  externalSourceType: args.externalSourceType,
1419
1577
  sourceUrl: args.sourceUrl,
1420
1578
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1421
- evidenceRelation,
1422
- confidence: Math.abs(weight),
1423
- weight
1579
+ evidenceRelation: impact.evidenceRelation,
1580
+ confidence: impact.confidence,
1581
+ weight: impact.weight
1424
1582
  },
1425
1583
  triggeringAction: "epistemicEvidence.internalCreate"
1426
1584
  });
@@ -1432,28 +1590,28 @@ var internalCreate = internalMutation({
1432
1590
  evidenceGlobalId: globalId,
1433
1591
  beliefNodeId: args.linkedBeliefNodeId,
1434
1592
  beliefGlobalId: linkedBeliefNode.globalId,
1435
- relation: evidenceRelation,
1436
- weight,
1593
+ relation: impact.evidenceRelation,
1594
+ weight: impact.weight,
1437
1595
  userId: args.userId,
1438
1596
  topicId: scope.topicId ? String(scope.topicId) : void 0,
1439
1597
  projectId: scope.projectId ? String(scope.projectId) : void 0,
1440
1598
  rationale: args.rationale
1441
1599
  });
1442
1600
  if (scope.projectId || scope.topicId) {
1443
- await ctx.scheduler.runAfter(
1444
- 0,
1445
- "embeddingActions:generateEpistemicNodeEmbedding",
1446
- {
1447
- nodeId,
1448
- projectId: scope.projectId,
1449
- topicId: scope.topicId ? String(scope.topicId) : void 0,
1450
- createdBy: args.userId,
1451
- nodeType: "evidence",
1452
- text: args.text
1453
- }
1454
- );
1601
+ await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
1602
+ nodeId,
1603
+ projectId: scope.projectId,
1604
+ topicId: scope.topicId ? String(scope.topicId) : void 0,
1605
+ createdBy: args.userId,
1606
+ nodeType: "evidence",
1607
+ text: args.text
1608
+ });
1455
1609
  }
1456
- await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
1610
+ await markProjectGraphDirty(
1611
+ ctx,
1612
+ scope.projectId,
1613
+ scope.topicId ? String(scope.topicId) : void 0
1614
+ );
1457
1615
  return { nodeId };
1458
1616
  }
1459
1617
  });
@@ -1466,11 +1624,11 @@ var updateVerificationStatus = mutation({
1466
1624
  },
1467
1625
  returns: permissiveReturn,
1468
1626
  handler: async (ctx, args) => {
1469
- const node = await ctx.db.get(args.nodeId);
1470
- if (!node || node.nodeType !== "evidence") {
1471
- throw new Error("Evidence node not found");
1472
- }
1473
- const metadata = node.metadata || {};
1627
+ const node = assertEvidenceNode(
1628
+ await ctx.db.get(args.nodeId),
1629
+ "Evidence node not found"
1630
+ );
1631
+ const metadata = metadataRecord(node.metadata);
1474
1632
  await ctx.db.patch(args.nodeId, {
1475
1633
  metadata: {
1476
1634
  ...metadata,
@@ -1496,20 +1654,17 @@ var update = mutation({
1496
1654
  },
1497
1655
  returns: permissiveReturn,
1498
1656
  handler: async (ctx, args) => {
1499
- const resolvedId = args.nodeId ?? args.insightId;
1500
- if (!resolvedId) {
1501
- throw new Error("Either nodeId or insightId is required");
1502
- }
1503
- const node = await ctx.db.get(resolvedId);
1504
- if (!node || node.nodeType !== "evidence") {
1505
- throw new Error("Evidence node not found");
1506
- }
1657
+ const resolvedId = await resolveEvidenceNodeId(ctx, args);
1658
+ const node = assertEvidenceNode(
1659
+ await ctx.db.get(resolvedId),
1660
+ "Evidence node not found"
1661
+ );
1507
1662
  if (!node.projectId) {
1508
1663
  throw new Error("Evidence has no project scope");
1509
1664
  }
1510
- await checkProjectAccess(ctx, node.projectId, args.userId);
1665
+ await requireScopeWriteAccess(ctx, node.projectId, args.userId);
1511
1666
  const now = Date.now();
1512
- const existingMeta = node.metadata || {};
1667
+ const existingMeta = metadataRecord(node.metadata);
1513
1668
  const metaUpdates = { ...existingMeta };
1514
1669
  if (args.kind !== void 0) {
1515
1670
  metaUpdates.kind = args.kind;
@@ -1541,17 +1696,13 @@ var update = mutation({
1541
1696
  newState: { text: (args.text ?? node.canonicalText)?.slice(0, 200) }
1542
1697
  });
1543
1698
  if (args.text !== void 0) {
1544
- await ctx.scheduler.runAfter(
1545
- 0,
1546
- "embeddingActions:generateEpistemicNodeEmbedding",
1547
- {
1548
- nodeId: resolvedId,
1549
- topicId: node.projectId,
1550
- createdBy: node.createdBy,
1551
- nodeType: "evidence",
1552
- text: args.text
1553
- }
1554
- );
1699
+ await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
1700
+ nodeId: resolvedId,
1701
+ topicId: node.projectId,
1702
+ createdBy: node.createdBy ?? args.userId,
1703
+ nodeType: "evidence",
1704
+ text: args.text
1705
+ });
1555
1706
  }
1556
1707
  await markProjectGraphDirty(ctx, node.projectId, node.topicId);
1557
1708
  return { nodeId: resolvedId };
@@ -1567,15 +1718,15 @@ var flagAsIncorrect = mutation({
1567
1718
  returns: permissiveReturn,
1568
1719
  handler: async (ctx, args) => {
1569
1720
  const now = Date.now();
1570
- const node = await ctx.db.get(args.insightId);
1571
- if (!node || node.nodeType !== "evidence") {
1572
- throw new Error("Evidence not found in epistemic spine");
1573
- }
1721
+ const node = assertEvidenceNode(
1722
+ await ctx.db.get(args.insightId),
1723
+ "Evidence not found in epistemic spine"
1724
+ );
1574
1725
  if (!node.projectId) {
1575
1726
  throw new Error("Evidence has no project scope");
1576
1727
  }
1577
- await checkProjectAccess(ctx, node.projectId, args.userId);
1578
- const existingMeta = node.metadata || {};
1728
+ await requireScopeWriteAccess(ctx, node.projectId, args.userId);
1729
+ const existingMeta = metadataRecord(node.metadata);
1579
1730
  await ctx.db.patch(node._id, {
1580
1731
  verificationStatus: "contradicted",
1581
1732
  metadata: {
@@ -1631,14 +1782,11 @@ var remove = mutation({
1631
1782
  },
1632
1783
  returns: permissiveReturn,
1633
1784
  handler: async (ctx, args) => {
1634
- const resolvedId = args.nodeId ?? args.insightId;
1635
- if (!resolvedId) {
1636
- throw new Error("Either nodeId or insightId is required");
1637
- }
1638
- const node = await ctx.db.get(resolvedId);
1639
- if (!node || node.nodeType !== "evidence") {
1640
- throw new Error("Evidence node not found");
1641
- }
1785
+ const resolvedId = await resolveEvidenceNodeId(ctx, args);
1786
+ const node = assertEvidenceNode(
1787
+ await ctx.db.get(resolvedId),
1788
+ "Evidence node not found"
1789
+ );
1642
1790
  if (node.createdBy !== args.userId) {
1643
1791
  throw new Error("Only the creator can archive this evidence");
1644
1792
  }