@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,16 @@
1
- import { v, ConvexError } from 'convex/values';
2
- import { checkScopeAccess, checkProjectAccess } from '@lucern/access-control/access';
1
+ import { requireScopeWriteAccess, checkScopeAccess } from '@lucern/access-control/access';
3
2
  import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
4
3
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
5
- import { componentsGeneric, anyApi, mutationGeneric, queryGeneric } from 'convex/server';
6
- import { normalizeTupleContradictionPolicy, createInheritedContractRecord, confidenceFromSL } from '@lucern/confidence';
4
+ import { v } from 'convex/values';
5
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
6
+ import { componentsGeneric, mutationGeneric, queryGeneric } from 'convex/server';
7
7
  import '@lucern/access-control/audience';
8
8
  import { getCurrentUserId } from '@lucern/access-control/auth';
9
+ import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
10
+ import { normalizeTupleContradictionPolicy, createInheritedContractRecord, confidenceFromSL } from '@lucern/confidence';
9
11
  import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
10
- import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
11
12
  import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
13
+ import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
12
14
 
13
15
  // src/epistemicBeliefs.core.ts
14
16
 
@@ -122,9 +124,12 @@ function resolveBeliefLifecycleStatus(opts) {
122
124
  function isPreValidationBeliefStatus(status) {
123
125
  return status === "assumption" || status === "hypothesis";
124
126
  }
125
- var api = anyApi;
127
+ var unsafeApi = unsafeConvexAnyApi(
128
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
129
+ );
130
+ var api = unsafeApi;
126
131
  componentsGeneric();
127
- var internal = anyApi;
132
+ var internal = unsafeApi;
128
133
  var mutation = mutationGeneric;
129
134
  var query = queryGeneric;
130
135
 
@@ -140,6 +145,32 @@ function debugGraphPrimitiveFallback(message, context) {
140
145
  console.debug(message, context ?? {});
141
146
  }
142
147
 
148
+ // src/embeddingTrigger.ts
149
+ var embeddingActionRef = "embeddingActions:generateEpistemicNodeEmbedding";
150
+ async function scheduleEmbeddingGeneration(args) {
151
+ try {
152
+ await args.ctx.scheduler.runAfter(0, embeddingActionRef, {
153
+ nodeId: args.nodeId,
154
+ projectId: args.projectId ? String(args.projectId) : void 0,
155
+ topicId: args.topicId ? String(args.topicId) : void 0,
156
+ createdBy: args.createdBy,
157
+ nodeType: args.nodeType,
158
+ text: args.text.slice(0, 2e4),
159
+ hasAnswer: args.hasAnswer,
160
+ confidence: args.confidence
161
+ });
162
+ } catch (error) {
163
+ debugGraphPrimitiveFallback(
164
+ "[embeddingTrigger] Failed to schedule embedding generation",
165
+ {
166
+ error,
167
+ nodeId: String(args.nodeId),
168
+ nodeType: args.nodeType
169
+ }
170
+ );
171
+ }
172
+ }
173
+
143
174
  // src/topicProjectOverlay.ts
144
175
  var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
145
176
  function readNonEmptyString(value) {
@@ -158,6 +189,10 @@ function readStringArray(value) {
158
189
  function readMetadata(topic) {
159
190
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
160
191
  }
192
+ function omitMetadataKey(metadata, key) {
193
+ const { [key]: _omitted, ...rest } = metadata;
194
+ return rest;
195
+ }
161
196
  function readLegacyProjectId(value) {
162
197
  if (!value) {
163
198
  return;
@@ -238,9 +273,12 @@ async function resolveTopicDoc(ctx, scopeId) {
238
273
  );
239
274
  }
240
275
  try {
241
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
242
- projectId: String(scopeId)
243
- });
276
+ const topic = await ctx.runQuery(
277
+ api.topics.getByLegacyScopeId,
278
+ {
279
+ projectId: String(scopeId)
280
+ }
281
+ );
244
282
  if (topic?.name !== void 0 && topic?.type !== void 0) {
245
283
  return topic;
246
284
  }
@@ -260,8 +298,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
260
298
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
261
299
  const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
262
300
  const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
263
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
264
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
301
+ let createdAt = 0;
302
+ if (typeof topic.createdAt === "number") {
303
+ createdAt = topic.createdAt;
304
+ } else if (typeof topic._creationTime === "number") {
305
+ createdAt = topic._creationTime;
306
+ }
307
+ let updatedAt = createdAt;
308
+ if (typeof topic.updatedAt === "number") {
309
+ updatedAt = topic.updatedAt;
310
+ } else if (typeof metadata.updatedAt === "number") {
311
+ updatedAt = metadata.updatedAt;
312
+ }
265
313
  return {
266
314
  ...metadata,
267
315
  _id: outwardId,
@@ -330,90 +378,113 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
330
378
  if (!topic) {
331
379
  return null;
332
380
  }
333
- const nextMetadata = { ...readMetadata(topic) };
334
- const patch = {};
335
- const topicUpdateArgs = {
336
- id: String(topic._id)
381
+ const plan = buildTopicProjectOverlayPatchPlan(topic, value);
382
+ await applyTopicProjectOverlayPatch(ctx, topic, plan);
383
+ return materializeTopicProjectOverlay({
384
+ ...topic,
385
+ ...plan.patch,
386
+ metadata: plan.nextMetadata
387
+ });
388
+ }
389
+ function buildTopicProjectOverlayPatchPlan(topic, value) {
390
+ const plan = {
391
+ nextMetadata: { ...readMetadata(topic) },
392
+ patch: {},
393
+ topicUpdateArgs: {
394
+ id: String(topic._id)
395
+ }
337
396
  };
338
397
  for (const [key, rawValue] of Object.entries(value)) {
339
- switch (key) {
340
- case "_id":
341
- case "projectId":
342
- case "topicId":
343
- case "legacyProjectId":
344
- case "storageProjectId":
345
- break;
346
- case "name":
347
- case "description":
348
- patch[key] = rawValue;
349
- topicUpdateArgs[key] = rawValue;
350
- break;
351
- case "tenantId":
352
- case "workspaceId":
353
- case "ownerId":
354
- throw new Error(
355
- `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
356
- );
357
- case "status": {
358
- const status = coerceStatus(rawValue);
359
- if (status) {
360
- patch.status = status;
361
- topicUpdateArgs.status = status;
362
- }
363
- break;
364
- }
365
- case "visibility": {
366
- const visibility = coerceVisibility(rawValue);
367
- if (visibility) {
368
- patch.visibility = visibility;
369
- topicUpdateArgs.visibility = visibility;
370
- }
371
- break;
372
- }
373
- case "type": {
374
- const projectType = readNonEmptyString(rawValue);
375
- if (projectType) {
376
- nextMetadata.projectType = projectType;
377
- } else {
378
- delete nextMetadata.projectType;
379
- }
380
- break;
381
- }
382
- case "updatedAt":
383
- case "createdAt":
384
- break;
385
- default:
386
- if (rawValue === void 0) {
387
- delete nextMetadata[key];
388
- } else {
389
- nextMetadata[key] = rawValue;
390
- }
391
- }
398
+ applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
399
+ }
400
+ plan.patch.updatedAt = Date.now();
401
+ plan.patch.metadata = plan.nextMetadata;
402
+ plan.topicUpdateArgs.metadata = plan.nextMetadata;
403
+ return plan;
404
+ }
405
+ function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
406
+ switch (key) {
407
+ case "_id":
408
+ case "projectId":
409
+ case "topicId":
410
+ case "legacyProjectId":
411
+ case "storageProjectId":
412
+ case "updatedAt":
413
+ case "createdAt":
414
+ return;
415
+ case "name":
416
+ case "description":
417
+ plan.patch[key] = rawValue;
418
+ plan.topicUpdateArgs[key] = rawValue;
419
+ return;
420
+ case "tenantId":
421
+ case "workspaceId":
422
+ case "ownerId":
423
+ throw new Error(
424
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
425
+ );
426
+ case "status":
427
+ applyTopicStatusPatch(plan, rawValue);
428
+ return;
429
+ case "visibility":
430
+ applyTopicVisibilityPatch(plan, rawValue);
431
+ return;
432
+ case "type":
433
+ applyTopicProjectTypePatch(plan, rawValue);
434
+ return;
435
+ default:
436
+ applyTopicMetadataPatch(plan, key, rawValue);
437
+ }
438
+ }
439
+ function applyTopicStatusPatch(plan, rawValue) {
440
+ const status = coerceStatus(rawValue);
441
+ if (status) {
442
+ plan.patch.status = status;
443
+ plan.topicUpdateArgs.status = status;
444
+ }
445
+ }
446
+ function applyTopicVisibilityPatch(plan, rawValue) {
447
+ const visibility = coerceVisibility(rawValue);
448
+ if (visibility) {
449
+ plan.patch.visibility = visibility;
450
+ plan.topicUpdateArgs.visibility = visibility;
451
+ }
452
+ }
453
+ function applyTopicProjectTypePatch(plan, rawValue) {
454
+ const projectType = readNonEmptyString(rawValue);
455
+ if (projectType) {
456
+ plan.nextMetadata.projectType = projectType;
457
+ return;
458
+ }
459
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
460
+ }
461
+ function applyTopicMetadataPatch(plan, key, rawValue) {
462
+ if (rawValue === void 0) {
463
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
464
+ return;
392
465
  }
393
- patch.updatedAt = Date.now();
394
- patch.metadata = nextMetadata;
395
- topicUpdateArgs.metadata = nextMetadata;
466
+ plan.nextMetadata[key] = rawValue;
467
+ }
468
+ async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
396
469
  if (typeof ctx.runMutation === "function") {
397
470
  try {
398
- await ctx.runMutation(api.topics.update, topicUpdateArgs);
471
+ await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
399
472
  } catch (error) {
400
- if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
473
+ if (!canPatchTopicViaLocalDb(ctx, error)) {
401
474
  throw error;
402
475
  }
403
- await ctx.db.patch(String(topic._id), patch);
476
+ await ctx.db.patch(topic._id, plan.patch);
404
477
  }
405
478
  } else if (ctx?.db && typeof ctx.db.patch === "function") {
406
- await ctx.db.patch(String(topic._id), patch);
479
+ await ctx.db.patch(topic._id, plan.patch);
407
480
  } else {
408
481
  throw new Error(
409
482
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
410
483
  );
411
484
  }
412
- return materializeTopicProjectOverlay({
413
- ...topic,
414
- ...patch,
415
- metadata: nextMetadata
416
- });
485
+ }
486
+ function canPatchTopicViaLocalDb(ctx, error) {
487
+ return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
417
488
  }
418
489
 
419
490
  // src/resolvers.ts
@@ -441,7 +512,7 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
441
512
  try {
442
513
  await patchTopicProjectOverlay(ctx, projectId, value);
443
514
  } catch (error) {
444
- if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
515
+ if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
445
516
  throw error;
446
517
  }
447
518
  console.warn(
@@ -508,13 +579,15 @@ function asMappedProjectId(topic) {
508
579
  if (!topic) {
509
580
  return;
510
581
  }
511
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD2]);
582
+ const directLegacyProjectId = normalizeScopeValue(
583
+ topic[LEGACY_SCOPE_FIELD2]
584
+ );
512
585
  if (directLegacyProjectId) {
513
586
  return directLegacyProjectId;
514
587
  }
515
588
  const metadata = topic.metadata || {};
516
589
  const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
517
- return candidate ? candidate : void 0;
590
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
518
591
  }
519
592
  function normalizeScopeValue(value) {
520
593
  if (typeof value !== "string") {
@@ -539,8 +612,9 @@ function pickPrimaryTopic(candidates) {
539
612
  })[0];
540
613
  }
541
614
  async function findTopicsByScopeAlias(ctx, scopeId) {
615
+ const query2 = ctx.db.query("topics");
542
616
  try {
543
- return await ctx.db.query("topics").withIndex(
617
+ return await query2.withIndex(
544
618
  "by_graph_scope_project",
545
619
  (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
546
620
  ).collect();
@@ -552,7 +626,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
552
626
  scopeId
553
627
  }
554
628
  );
555
- const topics = await ctx.db.query("topics").collect();
629
+ const topics = await query2.collect();
556
630
  return topics.filter((topic) => {
557
631
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
558
632
  const mappedProjectId = asMappedProjectId(topic);
@@ -608,137 +682,115 @@ async function resolveInheritedWorkspaceScope(ctx, topic) {
608
682
  let current = topic;
609
683
  for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
610
684
  current = await ctx.db.get(current.parentTopicId);
611
- if (!current) break;
685
+ if (!current) {
686
+ break;
687
+ }
612
688
  if (!tenantId) {
613
689
  tenantId = normalizeScopeValue(current.tenantId);
614
690
  }
615
691
  if (!workspaceId) {
616
692
  workspaceId = normalizeScopeValue(current.workspaceId);
617
693
  }
618
- if (tenantId && workspaceId) break;
694
+ if (tenantId && workspaceId) {
695
+ break;
696
+ }
619
697
  }
620
698
  return { tenantId, workspaceId };
621
699
  }
622
700
  async function resolveTopicProjectScope(ctx, args) {
623
701
  if (args.topicId) {
624
- let topic = null;
625
- try {
626
- topic = await ctx.db.get(
627
- args.topicId
628
- );
629
- } catch (error) {
630
- debugGraphPrimitiveFallback(
631
- "[topicScope] Failed to load topic by direct id",
632
- {
633
- error,
634
- topicId: args.topicId
635
- }
636
- );
637
- }
638
- if (!topic) {
639
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
640
- }
641
- if (!topic) {
642
- topic = pickPrimaryTopic(
643
- await findTopicsByScopeAlias(ctx, String(args.topicId))
644
- ) ?? null;
645
- }
646
- if (!topic) {
647
- const nodeScope = await resolveTopicNodeScopeOrNull(
648
- ctx,
649
- String(args.topicId)
650
- );
651
- if (nodeScope) {
652
- return nodeScope;
653
- }
654
- throw new Error(`Topic not found: ${String(args.topicId)}`);
655
- }
656
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
657
- const mapped = asMappedProjectId(topic);
658
- if (mapped) {
659
- return {
660
- topicId: topic._id,
661
- projectId: mapped,
662
- tenantId: inherited.tenantId,
663
- workspaceId: inherited.workspaceId,
664
- source: "topic"
665
- };
666
- }
667
- return {
668
- topicId: topic._id,
669
- tenantId: inherited.tenantId,
670
- workspaceId: inherited.workspaceId,
671
- source: "topic"
672
- };
702
+ return await resolveScopeFromTopicId(ctx, args.topicId);
673
703
  }
674
704
  if (args.projectId) {
675
- let directTopic = null;
676
- try {
677
- directTopic = await ctx.db.get(
678
- args.projectId
679
- );
680
- } catch (error) {
681
- debugGraphPrimitiveFallback(
682
- "[topicScope] Failed to load direct project topic",
683
- {
684
- error,
685
- projectId: args.projectId
686
- }
687
- );
688
- }
689
- if (directTopic) {
690
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
691
- const mapped = asMappedProjectId(directTopic);
692
- return {
693
- topicId: directTopic._id,
694
- projectId: mapped ?? args.projectId,
695
- tenantId: inherited.tenantId,
696
- workspaceId: inherited.workspaceId,
697
- source: "topic_inferred"
698
- };
699
- }
700
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
701
- if (directTopic) {
702
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
703
- const mapped = asMappedProjectId(directTopic);
704
- return {
705
- topicId: directTopic._id,
706
- projectId: mapped ?? args.projectId,
707
- tenantId: inherited.tenantId,
708
- workspaceId: inherited.workspaceId,
709
- source: "topic_inferred"
710
- };
711
- }
712
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
713
- const primary = pickPrimaryTopic(topics);
714
- if (primary) {
715
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
716
- return {
717
- topicId: primary._id,
718
- projectId: args.projectId,
719
- tenantId: inherited.tenantId,
720
- workspaceId: inherited.workspaceId,
721
- source: "project_mapped_topic"
722
- };
723
- }
724
- const nodeScope = await resolveTopicNodeScopeOrNull(
725
- ctx,
726
- String(args.projectId)
727
- );
728
- if (nodeScope) {
729
- return {
730
- ...nodeScope,
731
- projectId: nodeScope.projectId ?? String(args.projectId)
732
- };
733
- }
734
- throw new Error(
735
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
736
- );
705
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
737
706
  }
738
707
  throw new Error(
739
708
  "Missing scope: provide topicId (preferred) or legacy projectId alias."
740
709
  );
741
710
  }
711
+ async function resolveScopeFromTopicId(ctx, topicId) {
712
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
713
+ if (topic) {
714
+ return await buildTopicScope(ctx, topic, "topic");
715
+ }
716
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
717
+ if (nodeScope) {
718
+ return nodeScope;
719
+ }
720
+ throw new Error(`Topic not found: ${String(topicId)}`);
721
+ }
722
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
723
+ const direct = await tryReadTopicDoc(ctx, topicId, {
724
+ failureLog: "[topicScope] Failed to load topic by direct id",
725
+ idLogKey: "topicId"
726
+ });
727
+ if (direct) {
728
+ return direct;
729
+ }
730
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
731
+ if (hostTopic) {
732
+ return hostTopic;
733
+ }
734
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
735
+ }
736
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
737
+ const directTopic = await resolveDirectLegacyProjectTopic(
738
+ ctx,
739
+ legacyProjectId
740
+ );
741
+ if (directTopic) {
742
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
743
+ fallbackProjectId: legacyProjectId
744
+ });
745
+ }
746
+ const primary = pickPrimaryTopic(
747
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
748
+ );
749
+ if (primary) {
750
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
751
+ fallbackProjectId: legacyProjectId
752
+ });
753
+ }
754
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
755
+ if (nodeScope) {
756
+ return {
757
+ ...nodeScope,
758
+ projectId: nodeScope.projectId ?? legacyProjectId
759
+ };
760
+ }
761
+ throw new Error(
762
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
763
+ );
764
+ }
765
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
766
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
767
+ failureLog: "[topicScope] Failed to load direct project topic",
768
+ idLogKey: "projectId"
769
+ });
770
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
771
+ }
772
+ async function tryReadTopicDoc(ctx, id, log) {
773
+ try {
774
+ return await ctx.db.get(id);
775
+ } catch (error) {
776
+ debugGraphPrimitiveFallback(log.failureLog, {
777
+ error,
778
+ [log.idLogKey]: id
779
+ });
780
+ return null;
781
+ }
782
+ }
783
+ async function buildTopicScope(ctx, topic, source, options = {}) {
784
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
785
+ const mapped = asMappedProjectId(topic);
786
+ return {
787
+ topicId: topic._id,
788
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
789
+ tenantId: inherited.tenantId,
790
+ workspaceId: inherited.workspaceId,
791
+ source
792
+ };
793
+ }
742
794
  var optionalScopeArgs = {
743
795
  projectId: v.optional(v.string()),
744
796
  topicId: v.optional(v.string())
@@ -803,8 +855,6 @@ function nodeMatchesWorkspaceReasoningScope(node, scope) {
803
855
  }
804
856
  return scopeWorkspaceId === nodeWorkspaceId;
805
857
  }
806
-
807
- // src/epistemicBeliefs.helpers.ts
808
858
  v.id("epistemicNodes");
809
859
  var DEFAULT_PROJECT_BELIEF_LIMIT = 250;
810
860
  var MAX_PROJECT_BELIEF_LIMIT = 1e3;
@@ -813,26 +863,6 @@ var DEFAULT_CONFIDENCE_POLICY = {
813
863
  scoringMode: "after_worktree",
814
864
  tupleContradiction: normalizeTupleContradictionPolicy()
815
865
  };
816
- function throwStructuredMutationError(args) {
817
- const data = {
818
- structuredMutationError: true,
819
- message: args.message,
820
- status: args.status,
821
- code: args.code,
822
- invariantCode: args.invariantCode,
823
- suggestion: args.suggestion,
824
- details: args.details
825
- };
826
- const error = new ConvexError(
827
- data
828
- );
829
- error.status = args.status;
830
- error.code = args.code;
831
- error.invariantCode = args.invariantCode;
832
- error.suggestion = args.suggestion;
833
- error.details = args.details;
834
- throw error;
835
- }
836
866
  function assertBaseRateInRange(baseRate, field = "baseRate") {
837
867
  if (baseRate < 0 || baseRate > 1) {
838
868
  throwStructuredMutationError({
@@ -916,7 +946,7 @@ function normalizePillar(pillar) {
916
946
  async function markBeliefGraphDirty(ctx, scope) {
917
947
  const projectId = typeof scope.projectId === "string" && scope.projectId.trim().length > 0 ? scope.projectId : void 0;
918
948
  const topicId = typeof scope.topicId === "string" && scope.topicId.trim().length > 0 ? scope.topicId : void 0;
919
- if (!projectId && !topicId) {
949
+ if (!(projectId || topicId)) {
920
950
  return;
921
951
  }
922
952
  if (projectId) {
@@ -933,9 +963,15 @@ async function markBeliefGraphDirty(ctx, scope) {
933
963
  { topicId }
934
964
  );
935
965
  }
966
+ const activityScopeId = topicId ?? projectId;
967
+ if (!activityScopeId) {
968
+ throw new Error(
969
+ "Expected belief graph dirty scope to include a topic or project id."
970
+ );
971
+ }
936
972
  await resolveGraphPrimitivesAppResolvers().patchProject(
937
973
  ctx,
938
- topicId ?? projectId,
974
+ activityScopeId,
939
975
  {
940
976
  lastActivityAt: Date.now()
941
977
  }
@@ -943,7 +979,10 @@ async function markBeliefGraphDirty(ctx, scope) {
943
979
  }
944
980
  async function getActiveConfidencePolicy(ctx) {
945
981
  try {
946
- const activeConfig = await ctx.db.query("logicSprintScoring").withIndex("by_active", (q) => q.eq("isActive", true)).first();
982
+ const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
983
+ "by_active",
984
+ (q) => q.eq("isActive", true)
985
+ ).first();
947
986
  return {
948
987
  scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
949
988
  tupleContradiction: normalizeTupleContradictionPolicy(
@@ -975,23 +1014,6 @@ async function requireAuthenticatedUserId(ctx) {
975
1014
  }
976
1015
  return userId;
977
1016
  }
978
- async function requireProjectWriteAccess(ctx, projectId, userId) {
979
- const hasAccess = await checkProjectAccess(
980
- ctx,
981
- projectId,
982
- userId
983
- );
984
- if (!hasAccess) {
985
- throwStructuredMutationError({
986
- message: `Project write access denied for topic ${projectId}.`,
987
- status: 403,
988
- code: "PROJECT_ACCESS_DENIED",
989
- invariantCode: "policy.scope_required",
990
- suggestion: "The acting principal lacks project-write access to this topic. Request a topic grant (or, if the principal created this topic, run the creator-grant backfill) and retry.",
991
- details: { topicId: projectId, principalId: userId }
992
- });
993
- }
994
- }
995
1017
 
996
1018
  // src/epistemicBeliefs.forkEvidence.ts
997
1019
  function normalizeForkTriggerRelation(value) {
@@ -1005,7 +1027,7 @@ function normalizeForkTriggerRelation(value) {
1005
1027
  }
1006
1028
  async function resolveForkTriggerEvidence(ctx, args) {
1007
1029
  const evidence = await ctx.db.get(args.triggeringEvidenceId);
1008
- if (!evidence || evidence.nodeType !== "evidence") {
1030
+ if (evidence?.nodeType !== "evidence") {
1009
1031
  throwStructuredMutationError({
1010
1032
  message: "Fork requires an existing evidence node.",
1011
1033
  status: 400,
@@ -1044,16 +1066,16 @@ async function resolveForkTriggerEvidence(ctx, args) {
1044
1066
  ].filter(Boolean)
1045
1067
  );
1046
1068
  let relation = null;
1047
- const linkedBeliefNodeId = String(
1048
- evidenceMetadata.linkedBeliefNodeId ?? ""
1049
- );
1069
+ const linkedBeliefNodeId = String(evidenceMetadata.linkedBeliefNodeId ?? "");
1050
1070
  if (linkedBeliefNodeId && parentRefs.has(linkedBeliefNodeId)) {
1051
1071
  relation = normalizeForkTriggerRelation(evidenceMetadata.evidenceRelation);
1052
1072
  }
1053
1073
  if (!relation) {
1054
1074
  for (const parentRef of parentRefs) {
1055
1075
  const links = await ctx.db.query("beliefEvidenceLinks").withIndex("by_beliefId", (q) => q.eq("beliefId", parentRef)).collect();
1056
- const matched = links.find((link) => evidenceRefs.has(String(link.insightId)));
1076
+ const matched = links.find(
1077
+ (link) => evidenceRefs.has(String(link.insightId))
1078
+ );
1057
1079
  if (matched) {
1058
1080
  relation = normalizeForkTriggerRelation(matched.relation);
1059
1081
  break;
@@ -1089,13 +1111,16 @@ async function resolveForkTriggerEvidence(ctx, args) {
1089
1111
  }
1090
1112
  return { evidenceNodeId: args.triggeringEvidenceId, relation };
1091
1113
  }
1092
- async function insertEpistemicNode(ctx, doc) {
1114
+ function insertEpistemicNode(ctx, doc) {
1093
1115
  assertUuidV7Identity("epistemicNodes", doc.globalId);
1094
1116
  return ctx.db.insert("epistemicNodes", doc);
1095
1117
  }
1096
1118
  async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
1097
1119
  assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
1098
- const node = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", endpoint)).first();
1120
+ const node = await ctx.db.query("epistemicNodes").withIndex(
1121
+ "by_globalId",
1122
+ (q) => q.eq("globalId", endpoint)
1123
+ ).first();
1099
1124
  if (!node) {
1100
1125
  throw new Error(
1101
1126
  `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
@@ -1161,7 +1186,7 @@ async function resolveRequiredTopicAnchor(ctx, topicRef) {
1161
1186
  if (direct?.nodeType === "topic" && cleanString(direct.globalId)) {
1162
1187
  return direct;
1163
1188
  }
1164
- } catch (_) {
1189
+ } catch {
1165
1190
  }
1166
1191
  const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
1167
1192
  if (byGlobalId?.nodeType === "topic" && cleanString(byGlobalId.globalId)) {
@@ -1246,36 +1271,279 @@ async function createRequiredBeliefTopicEdge(ctx, args) {
1246
1271
  });
1247
1272
  }
1248
1273
 
1249
- // src/embeddingTrigger.ts
1250
- async function scheduleEmbeddingGeneration(args) {
1251
- try {
1252
- await args.ctx.scheduler.runAfter(
1253
- 0,
1254
- "embeddingActions:generateEpistemicNodeEmbedding",
1255
- {
1256
- nodeId: args.nodeId,
1257
- projectId: args.projectId ? String(args.projectId) : void 0,
1258
- topicId: args.topicId ? String(args.topicId) : void 0,
1259
- createdBy: args.createdBy,
1260
- nodeType: args.nodeType,
1261
- text: args.text.slice(0, 2e4),
1262
- hasAnswer: args.hasAnswer,
1263
- confidence: args.confidence
1264
- }
1265
- );
1266
- } catch (error) {
1267
- debugGraphPrimitiveFallback(
1268
- "[embeddingTrigger] Failed to schedule embedding generation",
1269
- {
1270
- error,
1271
- nodeId: String(args.nodeId),
1272
- nodeType: args.nodeType
1273
- }
1274
- );
1274
+ // src/epistemicBeliefs.core.ts
1275
+ var CONTRACT_CONDITION_TYPES = /* @__PURE__ */ new Set(["assertion", "temporal", "evidential", "threshold", "composite"]);
1276
+ var CONTRACT_DIRECTIONS = /* @__PURE__ */ new Set([
1277
+ "confirms",
1278
+ "falsifies"
1279
+ ]);
1280
+ var CONTRACT_LINEAGE_SOURCES = /* @__PURE__ */ new Set(["declared", "inherited"]);
1281
+ var CONTRACT_SCHEDULES = /* @__PURE__ */ new Set([
1282
+ "on_demand",
1283
+ "on_evidence",
1284
+ "periodic",
1285
+ "event_driven"
1286
+ ]);
1287
+ var CONTRACT_STATUSES = /* @__PURE__ */ new Set([
1288
+ "active",
1289
+ "satisfied",
1290
+ "violated",
1291
+ "expired",
1292
+ "suspended",
1293
+ "archived"
1294
+ ]);
1295
+ function isRecord(value) {
1296
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1297
+ }
1298
+ function readConvexId(value) {
1299
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1300
+ }
1301
+ function readOptionalBoolean(value) {
1302
+ return typeof value === "boolean" ? value : void 0;
1303
+ }
1304
+ function readOptionalNumber(value) {
1305
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1306
+ }
1307
+ function readOptionalString(value) {
1308
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1309
+ }
1310
+ function readRecord(value) {
1311
+ return isRecord(value) ? value : void 0;
1312
+ }
1313
+ function readStringList(value) {
1314
+ if (!Array.isArray(value)) {
1315
+ return;
1275
1316
  }
1317
+ const strings = value.filter(
1318
+ (item) => typeof item === "string" && item.length > 0
1319
+ );
1320
+ return strings.length === value.length ? strings : void 0;
1321
+ }
1322
+ function readEnumValue(value, allowed) {
1323
+ return typeof value === "string" && allowed.has(value) ? value : void 0;
1324
+ }
1325
+ function readContractCondition(value) {
1326
+ const record = readRecord(value);
1327
+ const evaluator = readOptionalString(record?.evaluator);
1328
+ const expression = readOptionalString(record?.expression);
1329
+ if (!(record && evaluator && expression)) {
1330
+ return;
1331
+ }
1332
+ return {
1333
+ evaluator,
1334
+ expression,
1335
+ evaluatorConfig: record.evaluatorConfig
1336
+ };
1337
+ }
1338
+ function readContractModulation(value) {
1339
+ const record = readRecord(value);
1340
+ const onConfirmed = readRecord(record?.onConfirmed);
1341
+ const onDisconfirmed = readRecord(record?.onDisconfirmed);
1342
+ const confirmedDelta = readOptionalNumber(onConfirmed?.delta);
1343
+ const disconfirmedDelta = readOptionalNumber(onDisconfirmed?.delta);
1344
+ if (!(record && onConfirmed && onDisconfirmed)) {
1345
+ return;
1346
+ }
1347
+ if (confirmedDelta === void 0 || disconfirmedDelta === void 0) {
1348
+ return;
1349
+ }
1350
+ const modulation = {
1351
+ onConfirmed: { delta: confirmedDelta },
1352
+ onDisconfirmed: { delta: disconfirmedDelta }
1353
+ };
1354
+ const confirmedCeiling = readOptionalNumber(onConfirmed.ceiling);
1355
+ if (confirmedCeiling !== void 0) {
1356
+ modulation.onConfirmed.ceiling = confirmedCeiling;
1357
+ }
1358
+ const disconfirmedFloor = readOptionalNumber(onDisconfirmed.floor);
1359
+ if (disconfirmedFloor !== void 0) {
1360
+ modulation.onDisconfirmed.floor = disconfirmedFloor;
1361
+ }
1362
+ const onExpired = readRecord(record.onExpired);
1363
+ const expiredDelta = readOptionalNumber(onExpired?.delta);
1364
+ if (expiredDelta !== void 0) {
1365
+ modulation.onExpired = { delta: expiredDelta };
1366
+ }
1367
+ const onPartial = readRecord(record.onPartial);
1368
+ const partialDelta = readOptionalNumber(onPartial?.delta);
1369
+ const partialThreshold = readOptionalNumber(onPartial?.threshold);
1370
+ if (partialDelta !== void 0 && partialThreshold !== void 0) {
1371
+ modulation.onPartial = {
1372
+ delta: partialDelta,
1373
+ threshold: partialThreshold
1374
+ };
1375
+ }
1376
+ return modulation;
1377
+ }
1378
+ function readBeliefNodeDoc(value) {
1379
+ if (!isRecord(value)) {
1380
+ return null;
1381
+ }
1382
+ const id = readConvexId(value._id);
1383
+ const nodeType = readOptionalString(value.nodeType);
1384
+ const projectId = readOptionalString(value.projectId);
1385
+ if (!(id && nodeType === "belief" && projectId)) {
1386
+ return null;
1387
+ }
1388
+ const node = { _id: id, nodeType, projectId };
1389
+ const canonicalText = readOptionalString(value.canonicalText);
1390
+ const confidence = readOptionalNumber(value.confidence);
1391
+ const content = readOptionalString(value.content);
1392
+ const epistemicLayer = readOptionalString(value.epistemicLayer);
1393
+ const globalId = readOptionalString(value.globalId);
1394
+ const metadata = readRecord(value.metadata);
1395
+ const predictionMeta = readRecord(value.predictionMeta);
1396
+ const sourceType = readOptionalString(value.sourceType);
1397
+ const status = readOptionalString(value.status);
1398
+ const tenantId = readOptionalString(value.tenantId);
1399
+ const title = readOptionalString(value.title);
1400
+ const topicId = readConvexId(value.topicId);
1401
+ const tupleContradicted = readOptionalBoolean(value.tupleContradicted);
1402
+ const workspaceId = readOptionalString(value.workspaceId);
1403
+ if (canonicalText !== void 0) {
1404
+ node.canonicalText = canonicalText;
1405
+ }
1406
+ if (confidence !== void 0) {
1407
+ node.confidence = confidence;
1408
+ }
1409
+ if (content !== void 0) {
1410
+ node.content = content;
1411
+ }
1412
+ if (epistemicLayer !== void 0) {
1413
+ node.epistemicLayer = epistemicLayer;
1414
+ }
1415
+ if (globalId !== void 0) {
1416
+ node.globalId = globalId;
1417
+ }
1418
+ if (metadata !== void 0) {
1419
+ node.metadata = metadata;
1420
+ }
1421
+ if (predictionMeta !== void 0) {
1422
+ node.predictionMeta = predictionMeta;
1423
+ }
1424
+ if (sourceType !== void 0) {
1425
+ node.sourceType = sourceType;
1426
+ }
1427
+ if (status !== void 0) {
1428
+ node.status = status;
1429
+ }
1430
+ if (tenantId !== void 0) {
1431
+ node.tenantId = tenantId;
1432
+ }
1433
+ if (title !== void 0) {
1434
+ node.title = title;
1435
+ }
1436
+ if (topicId !== void 0) {
1437
+ node.topicId = topicId;
1438
+ }
1439
+ if (tupleContradicted !== void 0) {
1440
+ node.tupleContradicted = tupleContradicted;
1441
+ }
1442
+ if (workspaceId !== void 0) {
1443
+ node.workspaceId = workspaceId;
1444
+ }
1445
+ return node;
1446
+ }
1447
+ function readContractRow(value) {
1448
+ if (!isRecord(value)) {
1449
+ return null;
1450
+ }
1451
+ const beliefNodeId = readConvexId(value.beliefNodeId);
1452
+ const condition = readContractCondition(value.condition);
1453
+ const conditionType = readEnumValue(
1454
+ value.conditionType,
1455
+ CONTRACT_CONDITION_TYPES
1456
+ );
1457
+ const contractId = readOptionalString(value.contractId);
1458
+ const createdAt = readOptionalNumber(value.createdAt);
1459
+ const createdBy = readOptionalString(value.createdBy);
1460
+ const direction = readEnumValue(value.direction, CONTRACT_DIRECTIONS);
1461
+ const evaluationSchedule = readEnumValue(
1462
+ value.evaluationSchedule,
1463
+ CONTRACT_SCHEDULES
1464
+ );
1465
+ const lineageSource = readEnumValue(
1466
+ value.lineageSource,
1467
+ CONTRACT_LINEAGE_SOURCES
1468
+ );
1469
+ const modulation = readContractModulation(value.modulation);
1470
+ const status = readEnumValue(value.status, CONTRACT_STATUSES);
1471
+ const title = readOptionalString(value.title);
1472
+ const updatedAt = readOptionalNumber(value.updatedAt);
1473
+ if (!(beliefNodeId && condition && conditionType && contractId && createdAt !== void 0 && createdBy && direction && evaluationSchedule && lineageSource && modulation && status && title && updatedAt !== void 0)) {
1474
+ return null;
1475
+ }
1476
+ const row = {
1477
+ beliefNodeId,
1478
+ condition,
1479
+ conditionType,
1480
+ contractId,
1481
+ createdAt,
1482
+ createdBy,
1483
+ direction,
1484
+ evaluationSchedule,
1485
+ lineageSource,
1486
+ modulation,
1487
+ status,
1488
+ title,
1489
+ updatedAt
1490
+ };
1491
+ const compositeOf = readStringList(value.compositeOf);
1492
+ if (compositeOf !== void 0) {
1493
+ row.compositeOf = compositeOf;
1494
+ }
1495
+ const compositeOperator = readOptionalString(value.compositeOperator);
1496
+ if (compositeOperator === "all" || compositeOperator === "any" || compositeOperator === "majority") {
1497
+ row.compositeOperator = compositeOperator;
1498
+ }
1499
+ const deadline = readOptionalNumber(value.deadline);
1500
+ if (deadline !== void 0) {
1501
+ row.deadline = deadline;
1502
+ }
1503
+ const description = readOptionalString(value.description);
1504
+ if (description !== void 0) {
1505
+ row.description = description;
1506
+ }
1507
+ const evaluationCount = readOptionalNumber(value.evaluationCount);
1508
+ if (evaluationCount !== void 0) {
1509
+ row.evaluationCount = evaluationCount;
1510
+ }
1511
+ const inheritedAt = readOptionalNumber(value.inheritedAt);
1512
+ if (inheritedAt !== void 0) {
1513
+ row.inheritedAt = inheritedAt;
1514
+ }
1515
+ const inheritedFromBeliefNodeId = readConvexId(
1516
+ value.inheritedFromBeliefNodeId
1517
+ );
1518
+ if (inheritedFromBeliefNodeId !== void 0) {
1519
+ row.inheritedFromBeliefNodeId = inheritedFromBeliefNodeId;
1520
+ }
1521
+ const inheritedFromContractId = readOptionalString(
1522
+ value.inheritedFromContractId
1523
+ );
1524
+ if (inheritedFromContractId !== void 0) {
1525
+ row.inheritedFromContractId = inheritedFromContractId;
1526
+ }
1527
+ const lastEvaluatedAt = readOptionalNumber(value.lastEvaluatedAt);
1528
+ if (lastEvaluatedAt !== void 0) {
1529
+ row.lastEvaluatedAt = lastEvaluatedAt;
1530
+ }
1531
+ const periodicIntervalMs = readOptionalNumber(value.periodicIntervalMs);
1532
+ if (periodicIntervalMs !== void 0) {
1533
+ row.periodicIntervalMs = periodicIntervalMs;
1534
+ }
1535
+ const topicId = readConvexId(value.topicId) ?? readOptionalString(value.topicId);
1536
+ if (topicId !== void 0) {
1537
+ row.topicId = topicId;
1538
+ }
1539
+ return row;
1540
+ }
1541
+ function readRowList(values, reader) {
1542
+ return values.flatMap((value) => {
1543
+ const row = reader(value);
1544
+ return row ? [row] : [];
1545
+ });
1276
1546
  }
1277
-
1278
- // src/epistemicBeliefs.core.ts
1279
1547
  var create = mutation({
1280
1548
  args: {
1281
1549
  ...optionalBeliefScopeArgs,
@@ -1325,41 +1593,7 @@ var create = mutation({
1325
1593
  returns: permissiveReturn,
1326
1594
  handler: async (ctx, args) => {
1327
1595
  const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1328
- const topicRef = readTopicNodeRef(args);
1329
- if (!topicRef) {
1330
- throwStructuredMutationError({
1331
- message: "Belief creation requires an explicit topic epistemic node.",
1332
- status: 400,
1333
- code: "INVALID_ARGUMENT",
1334
- invariantCode: "belief.topic_node_required",
1335
- suggestion: "Pass topicGlobalId or topicNodeId for a topic in epistemicNodes before creating a belief.",
1336
- details: {
1337
- topicId: args.topicId,
1338
- topicNodeId: args.topicNodeId,
1339
- topicGlobalId: args.topicGlobalId
1340
- }
1341
- });
1342
- }
1343
- const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
1344
- const scope = scopeFromTopicAnchor(topicNode);
1345
- assertWorkspaceScopedEpistemicNodeScope({
1346
- scope,
1347
- nodeType: "belief",
1348
- mutationName: "epistemicBeliefs.create"
1349
- });
1350
- const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
1351
- category: "belief_type",
1352
- value: args.beliefType,
1353
- tenantId: scope.tenantId,
1354
- context: "epistemicBeliefs.create"
1355
- });
1356
- if (scope.projectId) {
1357
- await requireProjectWriteAccess(
1358
- ctx,
1359
- scope.projectId,
1360
- authenticatedUserId
1361
- );
1362
- }
1596
+ const { normalizedBeliefType, scope, topicNode } = await resolveCreateBeliefAdmission(ctx, args, authenticatedUserId);
1363
1597
  const now = Date.now();
1364
1598
  const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
1365
1599
  const initialBeliefStatus = args.worktreeId ? "hypothesis" : "assumption";
@@ -1371,7 +1605,7 @@ var create = mutation({
1371
1605
  opinion_a: baseRate
1372
1606
  };
1373
1607
  const pillar = normalizePillar(args.pillar);
1374
- const additionalMeta = args.metadata || {};
1608
+ const additionalMeta = readRecord(args.metadata) ?? {};
1375
1609
  const beliefGlobalId = generateGlobalId();
1376
1610
  const nodeId = await insertEpistemicNode(ctx, {
1377
1611
  globalId: beliefGlobalId,
@@ -1533,6 +1767,44 @@ Rationale: ${args.rationale}` : args.formulation
1533
1767
  return { nodeId };
1534
1768
  }
1535
1769
  });
1770
+ async function resolveCreateBeliefAdmission(ctx, args, authenticatedUserId) {
1771
+ const topicRef = readTopicNodeRef(args);
1772
+ if (!topicRef) {
1773
+ throwStructuredMutationError({
1774
+ message: "Belief creation requires an explicit topic epistemic node.",
1775
+ status: 400,
1776
+ code: "INVALID_ARGUMENT",
1777
+ invariantCode: "belief.topic_node_required",
1778
+ suggestion: "Pass topicGlobalId or topicNodeId for a topic in epistemicNodes before creating a belief.",
1779
+ details: {
1780
+ topicId: args.topicId,
1781
+ topicNodeId: args.topicNodeId,
1782
+ topicGlobalId: args.topicGlobalId
1783
+ }
1784
+ });
1785
+ }
1786
+ const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
1787
+ const anchoredScope = scopeFromTopicAnchor(topicNode);
1788
+ const scope = {
1789
+ ...anchoredScope,
1790
+ topicId: anchoredScope.topicId
1791
+ };
1792
+ assertWorkspaceScopedEpistemicNodeScope({
1793
+ scope,
1794
+ nodeType: "belief",
1795
+ mutationName: "epistemicBeliefs.create"
1796
+ });
1797
+ const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
1798
+ category: "belief_type",
1799
+ value: args.beliefType,
1800
+ tenantId: scope.tenantId,
1801
+ context: "epistemicBeliefs.create"
1802
+ });
1803
+ if (scope.projectId) {
1804
+ await requireScopeWriteAccess(ctx, scope.projectId, authenticatedUserId);
1805
+ }
1806
+ return { normalizedBeliefType, scope, topicNode };
1807
+ }
1536
1808
  var getById = query({
1537
1809
  args: {
1538
1810
  nodeId: v.optional(v.id("epistemicNodes")),
@@ -1544,8 +1816,8 @@ var getById = query({
1544
1816
  if (!id) {
1545
1817
  return null;
1546
1818
  }
1547
- const node = await ctx.db.get(id);
1548
- if (!node || node.nodeType !== "belief") {
1819
+ const node = readBeliefNodeDoc(await ctx.db.get(id));
1820
+ if (!node) {
1549
1821
  return null;
1550
1822
  }
1551
1823
  return node;
@@ -1563,48 +1835,8 @@ var refineBelief = mutation({
1563
1835
  handler: async (ctx, args) => {
1564
1836
  const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1565
1837
  const now = Date.now();
1566
- const node = await ctx.db.get(args.nodeId);
1567
- if (!node) {
1568
- throwStructuredMutationError({
1569
- message: "Belief not found.",
1570
- status: 404,
1571
- code: "NOT_FOUND",
1572
- invariantCode: "belief.exists",
1573
- suggestion: "Verify nodeId points to an existing belief before refining.",
1574
- details: { nodeId: args.nodeId }
1575
- });
1576
- }
1577
- if (node.nodeType !== "belief") {
1578
- throwStructuredMutationError({
1579
- message: `refineBelief only applies to belief nodes. Received nodeType "${node.nodeType}".`,
1580
- status: 400,
1581
- code: "INVALID_ARGUMENT",
1582
- invariantCode: "entity.no_refine",
1583
- suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations.",
1584
- details: { nodeId: args.nodeId, nodeType: node.nodeType }
1585
- });
1586
- }
1587
- if (!node.projectId) {
1588
- throwStructuredMutationError({
1589
- message: "Belief has no project scope.",
1590
- status: 400,
1591
- code: "MISSING_SCOPE",
1592
- invariantCode: "belief.project_required",
1593
- suggestion: "Belief must have a projectId to refine.",
1594
- details: { nodeId: args.nodeId }
1595
- });
1596
- }
1597
- await requireProjectWriteAccess(ctx, node.projectId, authenticatedUserId);
1598
- if (typeof node.confidence === "number" && Number.isFinite(node.confidence)) {
1599
- throwStructuredMutationError({
1600
- message: "Scored beliefs are immutable. Use forkBelief to evolve a scored belief.",
1601
- status: 409,
1602
- code: "CONFLICT",
1603
- invariantCode: "belief.versioning.scored_immutable",
1604
- suggestion: "Use forkBelief() to create a new version instead of refining in place.",
1605
- details: { nodeId: args.nodeId, confidence: node.confidence }
1606
- });
1607
- }
1838
+ const node = await requireRefinableBelief(ctx, args.nodeId);
1839
+ await requireScopeWriteAccess(ctx, node.projectId, authenticatedUserId);
1608
1840
  const nextText = typeof args.canonicalText === "string" && args.canonicalText.trim().length > 0 ? args.canonicalText.trim() : void 0;
1609
1841
  const nextTitle = typeof args.title === "string" && args.title.trim().length > 0 ? args.title.trim() : void 0;
1610
1842
  const patch = { updatedAt: now };
@@ -1665,6 +1897,110 @@ Rationale: ${args.rationale}` : nextText
1665
1897
  return { nodeId: args.nodeId };
1666
1898
  }
1667
1899
  });
1900
+ async function requireRefinableBelief(ctx, nodeId) {
1901
+ const node = await ctx.db.get(nodeId);
1902
+ if (!node) {
1903
+ throwStructuredMutationError({
1904
+ message: "Belief not found.",
1905
+ status: 404,
1906
+ code: "NOT_FOUND",
1907
+ invariantCode: "belief.exists",
1908
+ suggestion: "Verify nodeId points to an existing belief before refining.",
1909
+ details: { nodeId }
1910
+ });
1911
+ }
1912
+ const nodeType = isRecord(node) ? readOptionalString(node.nodeType) : void 0;
1913
+ if (nodeType !== "belief") {
1914
+ throwStructuredMutationError({
1915
+ message: `refineBelief only applies to belief nodes. Received nodeType "${nodeType}".`,
1916
+ status: 400,
1917
+ code: "INVALID_ARGUMENT",
1918
+ invariantCode: "entity.no_refine",
1919
+ suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations.",
1920
+ details: { nodeId, nodeType }
1921
+ });
1922
+ }
1923
+ const projectId = isRecord(node) ? readOptionalString(node.projectId) : void 0;
1924
+ if (!projectId) {
1925
+ throwStructuredMutationError({
1926
+ message: "Belief has no project scope.",
1927
+ status: 400,
1928
+ code: "MISSING_SCOPE",
1929
+ invariantCode: "belief.project_required",
1930
+ suggestion: "Belief must have a projectId to refine.",
1931
+ details: { nodeId }
1932
+ });
1933
+ }
1934
+ const confidence = isRecord(node) ? readOptionalNumber(node.confidence) : void 0;
1935
+ if (confidence !== void 0) {
1936
+ throwStructuredMutationError({
1937
+ message: "Scored beliefs are immutable. Use forkBelief to evolve a scored belief.",
1938
+ status: 409,
1939
+ code: "CONFLICT",
1940
+ invariantCode: "belief.versioning.scored_immutable",
1941
+ suggestion: "Use forkBelief() to create a new version instead of refining in place.",
1942
+ details: { nodeId, confidence }
1943
+ });
1944
+ }
1945
+ const beliefNode = readBeliefNodeDoc(node);
1946
+ if (!beliefNode) {
1947
+ throwStructuredMutationError({
1948
+ message: "Belief row is missing required typed fields.",
1949
+ status: 400,
1950
+ code: "MISSING_SCOPE",
1951
+ invariantCode: "belief.typed_row_required",
1952
+ suggestion: "Backfill belief project/topic/global scope before refining.",
1953
+ details: { nodeId }
1954
+ });
1955
+ }
1956
+ return beliefNode;
1957
+ }
1958
+ async function requireForkParentAdmission(ctx, args, authenticatedUserId) {
1959
+ const parentRaw = await ctx.db.get(args.parentNodeId);
1960
+ if (!parentRaw) {
1961
+ throwStructuredMutationError({
1962
+ message: "Parent node not found.",
1963
+ status: 404,
1964
+ code: "NOT_FOUND",
1965
+ invariantCode: "belief.exists",
1966
+ suggestion: "Verify parentNodeId points to an existing node before forking.",
1967
+ details: { parentNodeId: args.parentNodeId }
1968
+ });
1969
+ }
1970
+ const parent = readBeliefNodeDoc(parentRaw);
1971
+ const parentNodeType = isRecord(parentRaw) ? readOptionalString(parentRaw.nodeType) : void 0;
1972
+ if (!parent) {
1973
+ throwStructuredMutationError({
1974
+ message: `forkBelief only applies to fully scoped belief nodes. Received nodeType "${parentNodeType}". Entity nodes (company, person, investor, etc.) are mutable \u2014 use entityLifecycle.updateEntityAttributes instead of forking.`,
1975
+ status: 400,
1976
+ code: "INVALID_ARGUMENT",
1977
+ invariantCode: "entity.no_fork",
1978
+ suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. forkBelief is for belief nodes only, and parent beliefs must carry project scope.",
1979
+ details: {
1980
+ parentNodeId: args.parentNodeId,
1981
+ nodeType: parentNodeType
1982
+ }
1983
+ });
1984
+ }
1985
+ const parentGlobalId = parent.globalId;
1986
+ if (!parentGlobalId) {
1987
+ throwStructuredMutationError({
1988
+ message: "Parent belief has no globalId for lineage edge creation.",
1989
+ status: 400,
1990
+ code: "INVALID_ARGUMENT",
1991
+ invariantCode: "belief.global_id_required",
1992
+ suggestion: "Backfill parent belief globalId before forking so Neo4j lineage edges can use canonical endpoints.",
1993
+ details: { parentNodeId: args.parentNodeId }
1994
+ });
1995
+ }
1996
+ await requireScopeWriteAccess(ctx, parent.projectId, authenticatedUserId);
1997
+ return {
1998
+ metadata: parent.metadata,
1999
+ parent,
2000
+ parentGlobalId,
2001
+ parentRaw
2002
+ };
2003
+ }
1668
2004
  var getByProject = query({
1669
2005
  args: {
1670
2006
  ...optionalBeliefScopeArgs,
@@ -1680,7 +2016,7 @@ var getByProject = query({
1680
2016
  },
1681
2017
  returns: permissiveReturn,
1682
2018
  handler: async (ctx, args) => {
1683
- if (!args.projectId && !args.topicId) {
2019
+ if (!(args.projectId || args.topicId)) {
1684
2020
  return [];
1685
2021
  }
1686
2022
  const pageSize = clampBeliefLimit(args.limit);
@@ -1712,11 +2048,14 @@ var getByProject = query({
1712
2048
  return [];
1713
2049
  }
1714
2050
  }
1715
- const query3 = ctx.db.query("epistemicNodes").withIndex(
2051
+ const query2 = ctx.db.query("epistemicNodes").withIndex(
1716
2052
  "by_topic_type",
1717
2053
  (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
1718
2054
  );
1719
- const nodes = await query3.order("desc").take(scanLimit);
2055
+ const nodes = readRowList(
2056
+ await query2.order("desc").take(scanLimit),
2057
+ readBeliefNodeDoc
2058
+ );
1720
2059
  const scopedNodes = nodes.filter(
1721
2060
  (node) => nodeMatchesWorkspaceReasoningScope(node, scope)
1722
2061
  );
@@ -1746,11 +2085,14 @@ var getByTopic = query({
1746
2085
  const scope = await resolveTopicProjectScope(ctx, {
1747
2086
  topicId: args.topicId
1748
2087
  });
1749
- const query3 = ctx.db.query("epistemicNodes").withIndex(
2088
+ const query2 = ctx.db.query("epistemicNodes").withIndex(
1750
2089
  "by_topic_type",
1751
2090
  (q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
1752
2091
  );
1753
- const nodes = await query3.order("desc").take(scanLimit);
2092
+ const nodes = readRowList(
2093
+ await query2.order("desc").take(scanLimit),
2094
+ readBeliefNodeDoc
2095
+ );
1754
2096
  const scopedNodes = nodes.filter(
1755
2097
  (node) => nodeMatchesWorkspaceReasoningScope(node, {
1756
2098
  tenantId: scope.tenantId,
@@ -1783,44 +2125,12 @@ var forkBelief = mutation({
1783
2125
  const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1784
2126
  const now = Date.now();
1785
2127
  await getActiveConfidencePolicy(ctx);
1786
- const parent = await ctx.db.get(args.parentNodeId);
1787
- if (!parent) {
1788
- throwStructuredMutationError({
1789
- message: "Parent node not found.",
1790
- status: 404,
1791
- code: "NOT_FOUND",
1792
- invariantCode: "belief.exists",
1793
- suggestion: "Verify parentNodeId points to an existing node before forking.",
1794
- details: { parentNodeId: args.parentNodeId }
1795
- });
1796
- }
1797
- if (parent.nodeType !== "belief") {
1798
- throwStructuredMutationError({
1799
- message: `forkBelief only applies to belief nodes. Received nodeType "${parent.nodeType}". Entity nodes (company, person, investor, etc.) are mutable \u2014 use entityLifecycle.updateEntityAttributes instead of forking.`,
1800
- status: 400,
1801
- code: "INVALID_ARGUMENT",
1802
- invariantCode: "entity.no_fork",
1803
- suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. forkBelief is for belief nodes only.",
1804
- details: { parentNodeId: args.parentNodeId, nodeType: parent.nodeType }
1805
- });
1806
- }
1807
- if (!parent.projectId) {
1808
- throwStructuredMutationError({
1809
- message: "Parent belief has no project scope.",
1810
- status: 400,
1811
- code: "MISSING_SCOPE",
1812
- invariantCode: "belief.project_required",
1813
- suggestion: "Belief must have a projectId to fork.",
1814
- details: { parentNodeId: args.parentNodeId }
1815
- });
1816
- }
1817
- await requireProjectWriteAccess(ctx, parent.projectId, authenticatedUserId);
1818
- const metadata = parent.metadata;
2128
+ const { metadata, parent, parentGlobalId, parentRaw } = await requireForkParentAdmission(ctx, args, authenticatedUserId);
1819
2129
  const forkBeliefStatus = "hypothesis";
1820
2130
  const forkMode = args.forkMode ?? "supersede";
1821
2131
  const triggerEvidence = await resolveForkTriggerEvidence(ctx, {
1822
2132
  parentNodeId: args.parentNodeId,
1823
- parent,
2133
+ parent: parentRaw,
1824
2134
  triggeringEvidenceId: args.triggeringEvidenceId,
1825
2135
  forkMode
1826
2136
  });
@@ -1867,7 +2177,7 @@ var forkBelief = mutation({
1867
2177
  tupleContradicted: false
1868
2178
  },
1869
2179
  beliefStatus: forkBeliefStatus,
1870
- sourceType: parent.sourceType,
2180
+ sourceType: parent.sourceType ?? "human",
1871
2181
  confidence: void 0,
1872
2182
  tupleContradicted: false,
1873
2183
  verificationStatus: "unverified",
@@ -1899,23 +2209,21 @@ var forkBelief = mutation({
1899
2209
  operation: "upsert"
1900
2210
  });
1901
2211
  }
1902
- const inheritedContracts = await ctx.db.query("epistemicContracts").withIndex(
1903
- "by_belief",
1904
- (q) => q.eq("beliefNodeId", args.parentNodeId)
1905
- ).collect();
2212
+ const inheritedContracts = readRowList(
2213
+ await ctx.db.query("epistemicContracts").withIndex("by_belief", (q) => q.eq("beliefNodeId", args.parentNodeId)).collect(),
2214
+ readContractRow
2215
+ );
1906
2216
  for (const contract of inheritedContracts) {
1907
2217
  if (contract.status === "archived") {
1908
2218
  continue;
1909
2219
  }
1910
- await ctx.db.insert(
1911
- "epistemicContracts",
1912
- createInheritedContractRecord(contract, {
1913
- beliefNodeId: newNodeId,
1914
- topicId: parent.topicId,
1915
- createdBy: authenticatedUserId,
1916
- now
1917
- })
1918
- );
2220
+ const inheritedContract = createInheritedContractRecord(contract, {
2221
+ beliefNodeId: newNodeId,
2222
+ topicId: parent.topicId,
2223
+ createdBy: authenticatedUserId,
2224
+ now
2225
+ });
2226
+ await ctx.db.insert("epistemicContracts", { ...inheritedContract });
1919
2227
  }
1920
2228
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1921
2229
  nodeId: newNodeId,
@@ -1924,7 +2232,7 @@ var forkBelief = mutation({
1924
2232
  await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
1925
2233
  globalId: generateGlobalId(),
1926
2234
  fromGlobalId: newBeliefGlobalId,
1927
- toGlobalId: parent.globalId,
2235
+ toGlobalId: parentGlobalId,
1928
2236
  edgeType: forkMode === "supersede" ? "supersedes" : "derived_from",
1929
2237
  context: `Fork reason: ${args.forkReason}; triggering evidence: ${triggerEvidence.evidenceNodeId}`,
1930
2238
  createdBy: authenticatedUserId,