@lucern/graph-primitives 1.0.29 → 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 +395 -225
  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 +854 -480
  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 +365 -166
  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 -289
  80. package/dist/epistemicBeliefs.backfills.js.map +1 -1
  81. package/dist/epistemicBeliefs.confidence.d.ts +19 -15
  82. package/dist/epistemicBeliefs.confidence.js +633 -386
  83. package/dist/epistemicBeliefs.confidence.js.map +1 -1
  84. package/dist/epistemicBeliefs.core.d.ts +6 -6
  85. package/dist/epistemicBeliefs.core.js +717 -371
  86. package/dist/epistemicBeliefs.core.js.map +1 -1
  87. package/dist/epistemicBeliefs.d.ts +11 -9
  88. package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
  89. package/dist/epistemicBeliefs.forkEvidence.js +8 -8
  90. package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
  91. package/dist/epistemicBeliefs.helpers.d.ts +68 -49
  92. package/dist/epistemicBeliefs.helpers.js +358 -211
  93. package/dist/epistemicBeliefs.helpers.js.map +1 -1
  94. package/dist/epistemicBeliefs.internal.d.ts +5 -5
  95. package/dist/epistemicBeliefs.internal.js +1248 -1026
  96. package/dist/epistemicBeliefs.internal.js.map +1 -1
  97. package/dist/epistemicBeliefs.js +4942 -3590
  98. package/dist/epistemicBeliefs.js.map +1 -1
  99. package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
  100. package/dist/epistemicBeliefs.lifecycle.js +1138 -781
  101. package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
  102. package/dist/epistemicBeliefs.links.d.ts +7 -7
  103. package/dist/epistemicBeliefs.links.js +404 -267
  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 +1062 -576
  114. package/dist/epistemicContracts.evaluators.js.map +1 -1
  115. package/dist/epistemicContracts.handlers.d.ts +15 -32
  116. package/dist/epistemicContracts.handlers.js +1829 -1351
  117. package/dist/epistemicContracts.handlers.js.map +1 -1
  118. package/dist/epistemicContracts.js +1131 -636
  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 +1966 -1202
  136. package/dist/epistemicEdges.js.map +1 -1
  137. package/dist/epistemicEdges.mutations.d.ts +7 -7
  138. package/dist/epistemicEdges.mutations.js +956 -579
  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 +933 -532
  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 +840 -692
  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 +700 -504
  180. package/dist/epistemicNodes.js.map +1 -1
  181. package/dist/epistemicNodes.mutations.d.ts +6 -6
  182. package/dist/epistemicNodes.mutations.js +560 -463
  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 +351 -311
  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 +86 -83
  245. package/dist/index.js +16914 -11760
  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,551 +1,143 @@
1
- import { v } from 'convex/values';
1
+ import { requireScopeWriteAccess } from '@lucern/access-control/access';
2
2
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
3
- import { componentsGeneric, anyApi, internalMutationGeneric, mutationGeneric } from 'convex/server';
3
+ import { v } from 'convex/values';
4
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
5
+ import { componentsGeneric, internalMutationGeneric, mutationGeneric } from 'convex/server';
6
+ import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, readOpinionFromRecord, hasProjectedOpinionChanged } from '@lucern/confidence';
4
7
  import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
5
- import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, hasProjectedOpinionChanged, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, readOpinionFromRecord } from '@lucern/confidence';
6
- import { requireScopeWriteAccess } from '@lucern/access-control/access';
7
- import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
8
8
  import '@lucern/access-control/audience';
9
9
  import { getCurrentUserId } from '@lucern/access-control/auth';
10
+ import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
10
11
 
11
12
  // src/epistemicBeliefs.lifecycle.ts
12
- var api = anyApi;
13
+ var unsafeApi = unsafeConvexAnyApi(
14
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
15
+ );
16
+ var api = unsafeApi;
13
17
  componentsGeneric();
14
- var internal = anyApi;
18
+ var internal = unsafeApi;
15
19
  var internalMutation = internalMutationGeneric;
16
20
  var mutation = mutationGeneric;
17
21
 
18
- // src/debug.ts
19
- function isGraphPrimitiveDebugEnabled() {
20
- const env = globalThis.process?.env;
21
- return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
22
+ // src/beliefLifecycle.ts
23
+ var BELIEF_STATUS_VALUES = [
24
+ "assumption",
25
+ "hypothesis",
26
+ "active",
27
+ "superseded",
28
+ "resolved_true",
29
+ "resolved_false"
30
+ ];
31
+ function isBeliefLifecycleStatus(value) {
32
+ return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
22
33
  }
23
- function debugGraphPrimitiveFallback(message, context) {
24
- if (!isGraphPrimitiveDebugEnabled()) {
25
- return;
34
+ function normalizeLegacyBeliefStatus(value) {
35
+ if (isBeliefLifecycleStatus(value)) {
36
+ return value;
26
37
  }
27
- console.debug(message, context ?? {});
28
- }
29
-
30
- // src/topicScope.ts
31
- var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
32
- async function resolveTopicNodeScopeOrNull(ctx, ref) {
33
- if (!ctx?.db || typeof ctx.db.query !== "function") {
34
- return null;
38
+ if (value === "belief" || value === "established" || value === "emerging") {
39
+ return "active";
35
40
  }
36
- let node = null;
37
- try {
38
- const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
39
- if (byGlobalId && byGlobalId.nodeType === "topic") {
40
- node = byGlobalId;
41
- }
42
- } catch (error) {
43
- debugGraphPrimitiveFallback(
44
- "[topicScope] topic-node scope lookup by globalId failed",
45
- { error, ref }
46
- );
41
+ if (value === "fact" || value === "confirmed") {
42
+ return "resolved_true";
47
43
  }
48
- if (!node) {
49
- return null;
44
+ if (value === "disconfirmed" || value === "expired") {
45
+ return "resolved_false";
50
46
  }
51
- const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
52
- if (!scopeKey) {
53
- return null;
47
+ if (value === "deprecated") {
48
+ return "superseded";
54
49
  }
55
- return {
56
- topicId: scopeKey,
57
- projectId: asMappedProjectId(node),
58
- source: "topic_node"
59
- };
50
+ return null;
60
51
  }
61
- function asMappedProjectId(topic) {
62
- if (!topic) {
63
- return;
52
+ function normalizeBeliefConfidence(confidence) {
53
+ if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
54
+ return null;
64
55
  }
65
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
66
- if (directLegacyProjectId) {
67
- return directLegacyProjectId;
56
+ if (confidence >= 0 && confidence <= 1) {
57
+ return confidence;
68
58
  }
69
- const metadata = topic.metadata || {};
70
- const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
71
- return candidate ? candidate : void 0;
72
- }
73
- function normalizeScopeValue(value) {
74
- if (typeof value !== "string") {
75
- return;
59
+ if (confidence > 1 && confidence <= 100) {
60
+ return confidence / 100;
76
61
  }
77
- const normalized = value.trim();
78
- return normalized.length > 0 ? normalized : void 0;
79
- }
80
- function pickPrimaryTopic(candidates) {
81
- return [...candidates].sort((a, b) => {
82
- const depthA = a.depth ?? 9999;
83
- const depthB = b.depth ?? 9999;
84
- if (depthA !== depthB) {
85
- return depthA - depthB;
86
- }
87
- const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
88
- const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
89
- if (createdA !== createdB) {
90
- return createdA - createdB;
91
- }
92
- return String(a.name || "").localeCompare(String(b.name || ""));
93
- })[0];
62
+ return null;
94
63
  }
95
- async function findTopicsByScopeAlias(ctx, scopeId) {
96
- try {
97
- return await ctx.db.query("topics").withIndex(
98
- "by_graph_scope_project",
99
- (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
100
- ).collect();
101
- } catch (error) {
102
- debugGraphPrimitiveFallback(
103
- "[topicScope] Failed to resolve scope alias via index",
104
- {
105
- error,
106
- scopeId
107
- }
108
- );
109
- const topics = await ctx.db.query("topics").collect();
110
- return topics.filter((topic) => {
111
- const normalizedGlobalId = normalizeScopeValue(topic.globalId);
112
- const mappedProjectId = asMappedProjectId(topic);
113
- return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
114
- });
64
+ function isResolvedByConfidence(confidence) {
65
+ const normalized = normalizeBeliefConfidence(confidence);
66
+ if (normalized === null) {
67
+ return false;
115
68
  }
69
+ return normalized <= 0 || normalized >= 1;
116
70
  }
117
- async function tryResolveHostTopicById(ctx, topicId) {
118
- if (typeof ctx.runQuery !== "function") {
71
+ function getPredictionMetaFromMetadata(metadata) {
72
+ return metadata?.predictionMeta;
73
+ }
74
+ function resolvedPredictionStatus(predictionMeta) {
75
+ if (!predictionMeta || typeof predictionMeta !== "object") {
119
76
  return null;
120
77
  }
121
- try {
122
- return await ctx.runQuery(api.topics.get, {
123
- id: topicId
124
- }) ?? null;
125
- } catch (error) {
126
- debugGraphPrimitiveFallback(
127
- "[topicScope] Failed to resolve topic by host query",
128
- {
129
- error,
130
- topicId
131
- }
132
- );
133
- return null;
78
+ const outcome = predictionMeta.outcome;
79
+ if (outcome === "confirmed") {
80
+ return "resolved_true";
81
+ }
82
+ if (outcome === "disconfirmed" || outcome === "expired") {
83
+ return "resolved_false";
134
84
  }
85
+ return null;
135
86
  }
136
- async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
137
- if (typeof ctx.runQuery !== "function") {
138
- return null;
87
+ function shouldTreatBeliefAsResolved(opts) {
88
+ if (isResolvedByConfidence(opts.confidence)) {
89
+ const normalized = normalizeBeliefConfidence(opts.confidence);
90
+ return normalized === 0 ? "resolved_false" : "resolved_true";
139
91
  }
140
- try {
141
- return await ctx.runQuery(api.topics.getByLegacyScopeId, {
142
- projectId: legacyScopeId
143
- }) ?? null;
144
- } catch (error) {
145
- debugGraphPrimitiveFallback(
146
- "[topicScope] Failed to resolve topic by legacy scope",
147
- {
148
- error,
149
- legacyScopeId
150
- }
151
- );
152
- return null;
92
+ const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
93
+ if (directPredictionStatus) {
94
+ return directPredictionStatus;
95
+ }
96
+ const metadataPredictionStatus = resolvedPredictionStatus(
97
+ getPredictionMetaFromMetadata(opts.metadata)
98
+ );
99
+ if (metadataPredictionStatus) {
100
+ return metadataPredictionStatus;
153
101
  }
102
+ return null;
154
103
  }
155
- async function resolveInheritedWorkspaceScope(ctx, topic) {
156
- const MAX_DEPTH = 10;
157
- let tenantId = normalizeScopeValue(topic.tenantId);
158
- let workspaceId = normalizeScopeValue(topic.workspaceId);
159
- if (tenantId && workspaceId) {
160
- return { tenantId, workspaceId };
104
+ function resolveBeliefLifecycleStatus(opts) {
105
+ const resolvedStatus = shouldTreatBeliefAsResolved(opts);
106
+ if (resolvedStatus) {
107
+ return resolvedStatus;
161
108
  }
162
- let current = topic;
163
- for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
164
- current = await ctx.db.get(current.parentTopicId);
165
- if (!current) break;
166
- if (!tenantId) {
167
- tenantId = normalizeScopeValue(current.tenantId);
109
+ const direct = opts.beliefStatus;
110
+ const normalizedDirect = normalizeLegacyBeliefStatus(direct);
111
+ if (normalizedDirect) {
112
+ const normalized = normalizeBeliefConfidence(opts.confidence);
113
+ if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
114
+ return "active";
168
115
  }
169
- if (!workspaceId) {
170
- workspaceId = normalizeScopeValue(current.workspaceId);
116
+ return normalizedDirect;
117
+ }
118
+ const metaStatus = opts.metadata?.beliefStatus;
119
+ const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
120
+ if (normalizedMetaStatus) {
121
+ const normalized = normalizeBeliefConfidence(opts.confidence);
122
+ if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
123
+ return "active";
171
124
  }
172
- if (tenantId && workspaceId) break;
125
+ return normalizedMetaStatus;
173
126
  }
174
- return { tenantId, workspaceId };
127
+ return "assumption";
175
128
  }
176
- async function resolveTopicProjectScope(ctx, args) {
177
- if (args.topicId) {
178
- let topic = null;
179
- try {
180
- topic = await ctx.db.get(
181
- args.topicId
182
- );
183
- } catch (error) {
184
- debugGraphPrimitiveFallback(
185
- "[topicScope] Failed to load topic by direct id",
186
- {
187
- error,
188
- topicId: args.topicId
189
- }
190
- );
191
- }
192
- if (!topic) {
193
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
194
- }
195
- if (!topic) {
196
- topic = pickPrimaryTopic(
197
- await findTopicsByScopeAlias(ctx, String(args.topicId))
198
- ) ?? null;
199
- }
200
- if (!topic) {
201
- const nodeScope = await resolveTopicNodeScopeOrNull(
202
- ctx,
203
- String(args.topicId)
204
- );
205
- if (nodeScope) {
206
- return nodeScope;
207
- }
208
- throw new Error(`Topic not found: ${String(args.topicId)}`);
209
- }
210
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
211
- const mapped = asMappedProjectId(topic);
212
- if (mapped) {
213
- return {
214
- topicId: topic._id,
215
- projectId: mapped,
216
- tenantId: inherited.tenantId,
217
- workspaceId: inherited.workspaceId,
218
- source: "topic"
219
- };
220
- }
221
- return {
222
- topicId: topic._id,
223
- tenantId: inherited.tenantId,
224
- workspaceId: inherited.workspaceId,
225
- source: "topic"
226
- };
129
+ function isPreValidationBeliefStatus(status) {
130
+ return status === "assumption" || status === "hypothesis";
131
+ }
132
+ function promoteBeliefStatusAfterScoring(status, opts) {
133
+ const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
134
+ if (resolvedStatus) {
135
+ return resolvedStatus;
227
136
  }
228
- if (args.projectId) {
229
- let directTopic = null;
230
- try {
231
- directTopic = await ctx.db.get(
232
- args.projectId
233
- );
234
- } catch (error) {
235
- debugGraphPrimitiveFallback(
236
- "[topicScope] Failed to load direct project topic",
237
- {
238
- error,
239
- projectId: args.projectId
240
- }
241
- );
242
- }
243
- if (directTopic) {
244
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
245
- const mapped = asMappedProjectId(directTopic);
246
- return {
247
- topicId: directTopic._id,
248
- projectId: mapped ?? args.projectId,
249
- tenantId: inherited.tenantId,
250
- workspaceId: inherited.workspaceId,
251
- source: "topic_inferred"
252
- };
253
- }
254
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
255
- if (directTopic) {
256
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
257
- const mapped = asMappedProjectId(directTopic);
258
- return {
259
- topicId: directTopic._id,
260
- projectId: mapped ?? args.projectId,
261
- tenantId: inherited.tenantId,
262
- workspaceId: inherited.workspaceId,
263
- source: "topic_inferred"
264
- };
265
- }
266
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
267
- const primary = pickPrimaryTopic(topics);
268
- if (primary) {
269
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
270
- return {
271
- topicId: primary._id,
272
- projectId: args.projectId,
273
- tenantId: inherited.tenantId,
274
- workspaceId: inherited.workspaceId,
275
- source: "project_mapped_topic"
276
- };
277
- }
278
- const nodeScope = await resolveTopicNodeScopeOrNull(
279
- ctx,
280
- String(args.projectId)
281
- );
282
- if (nodeScope) {
283
- return {
284
- ...nodeScope,
285
- projectId: nodeScope.projectId ?? String(args.projectId)
286
- };
287
- }
288
- throw new Error(
289
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
290
- );
137
+ if (isPreValidationBeliefStatus(status)) {
138
+ return "active";
291
139
  }
292
- throw new Error(
293
- "Missing scope: provide topicId (preferred) or legacy projectId alias."
294
- );
295
- }
296
- ({
297
- projectId: v.optional(v.string()),
298
- topicId: v.optional(v.string())
299
- });
300
-
301
- // src/workspaceIsolation.ts
302
- function normalizeScopeValue2(value) {
303
- if (typeof value !== "string") {
304
- return;
305
- }
306
- const normalized = value.trim();
307
- return normalized.length > 0 ? normalized : void 0;
308
- }
309
- function throwWorkspaceIsolationError(args) {
310
- const error = new Error(args.message);
311
- error.status = 409;
312
- error.code = "INVARIANT_VIOLATION";
313
- error.invariantCode = args.invariantCode;
314
- error.suggestion = args.suggestion;
315
- error.details = args.details;
316
- throw error;
317
- }
318
- function nodeMatchesWorkspaceReasoningScope(node, scope) {
319
- if (!node) {
320
- return false;
321
- }
322
- const scopeTenantId = normalizeScopeValue2(scope.tenantId);
323
- const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
324
- const nodeTenantId = normalizeScopeValue2(node.tenantId);
325
- const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
326
- const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
327
- if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
328
- return false;
329
- }
330
- if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
331
- return true;
332
- }
333
- if (!scopeWorkspaceId && node.publicationStatus === "published") {
334
- return true;
335
- }
336
- if (!scopeWorkspaceId) {
337
- return nodeWorkspaceId === void 0;
338
- }
339
- return scopeWorkspaceId === nodeWorkspaceId;
340
- }
341
- function edgeMatchesWorkspaceReasoningScope(edge, scope) {
342
- if (!edge) {
343
- return false;
344
- }
345
- const scopeTenantId = normalizeScopeValue2(scope.tenantId);
346
- const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
347
- const edgeTenantId = normalizeScopeValue2(edge.tenantId);
348
- const edgeWorkspaceId = normalizeScopeValue2(edge.workspaceId);
349
- if (scopeTenantId && edgeTenantId && scopeTenantId !== edgeTenantId) {
350
- return false;
351
- }
352
- if (!scopeWorkspaceId) {
353
- return edgeWorkspaceId === void 0;
354
- }
355
- return scopeWorkspaceId === edgeWorkspaceId;
356
- }
357
- async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
358
- const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
359
- const resolved = {
360
- tenantId: normalizeScopeValue2(node?.tenantId),
361
- workspaceId: normalizeScopeValue2(node?.workspaceId),
362
- epistemicLayer,
363
- nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
364
- };
365
- if (!node) {
366
- return resolved;
367
- }
368
- if (resolved.epistemicLayer === "ontological") {
369
- return resolved;
370
- }
371
- if (resolved.tenantId || resolved.workspaceId) {
372
- return resolved;
373
- }
374
- if (node.topicId) {
375
- const topicScope = await resolveTopicProjectScope(ctx, {
376
- topicId: node.topicId
377
- });
378
- return {
379
- ...resolved,
380
- tenantId: topicScope.tenantId,
381
- workspaceId: topicScope.workspaceId
382
- };
383
- }
384
- if (node.projectId) {
385
- const topicScope = await resolveTopicProjectScope(ctx, {
386
- projectId: String(node.projectId)
387
- });
388
- return {
389
- ...resolved,
390
- tenantId: topicScope.tenantId,
391
- workspaceId: topicScope.workspaceId
392
- };
393
- }
394
- return resolved;
395
- }
396
- function resolveRuntimePackMutationContext(args) {
397
- if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
398
- return;
399
- }
400
- return {
401
- toolName: args.runtimeToolName,
402
- packKey: args.runtimePackKey,
403
- packInstallScope: args.runtimePackInstallScope
404
- };
405
- }
406
- function assertTenantPackWorkspaceMutationAllowed(args) {
407
- if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
408
- return;
409
- }
410
- const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
411
- const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
412
- if (!targetWorkspaceId || targetLayer === "ontological") {
413
- return;
414
- }
415
- throwWorkspaceIsolationError({
416
- message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
417
- invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
418
- suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
419
- details: {
420
- mutationName: args.mutationName,
421
- toolName: args.runtime.toolName,
422
- packKey: args.runtime.packKey,
423
- targetWorkspaceId,
424
- targetNodeType: args.target.nodeType,
425
- targetLayer
426
- }
427
- });
428
- }
429
-
430
- // src/beliefLifecycle.ts
431
- var BELIEF_STATUS_VALUES = [
432
- "assumption",
433
- "hypothesis",
434
- "active",
435
- "superseded",
436
- "resolved_true",
437
- "resolved_false"
438
- ];
439
- function isBeliefLifecycleStatus(value) {
440
- return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
441
- }
442
- function normalizeLegacyBeliefStatus(value) {
443
- if (isBeliefLifecycleStatus(value)) {
444
- return value;
445
- }
446
- if (value === "belief" || value === "established" || value === "emerging") {
447
- return "active";
448
- }
449
- if (value === "fact" || value === "confirmed") {
450
- return "resolved_true";
451
- }
452
- if (value === "disconfirmed" || value === "expired") {
453
- return "resolved_false";
454
- }
455
- if (value === "deprecated") {
456
- return "superseded";
457
- }
458
- return null;
459
- }
460
- function normalizeBeliefConfidence(confidence) {
461
- if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
462
- return null;
463
- }
464
- if (confidence >= 0 && confidence <= 1) {
465
- return confidence;
466
- }
467
- if (confidence > 1 && confidence <= 100) {
468
- return confidence / 100;
469
- }
470
- return null;
471
- }
472
- function isResolvedByConfidence(confidence) {
473
- const normalized = normalizeBeliefConfidence(confidence);
474
- if (normalized === null) {
475
- return false;
476
- }
477
- return normalized <= 0 || normalized >= 1;
478
- }
479
- function getPredictionMetaFromMetadata(metadata) {
480
- return metadata?.predictionMeta;
481
- }
482
- function resolvedPredictionStatus(predictionMeta) {
483
- if (!predictionMeta || typeof predictionMeta !== "object") {
484
- return null;
485
- }
486
- const outcome = predictionMeta.outcome;
487
- if (outcome === "confirmed") {
488
- return "resolved_true";
489
- }
490
- if (outcome === "disconfirmed" || outcome === "expired") {
491
- return "resolved_false";
492
- }
493
- return null;
494
- }
495
- function shouldTreatBeliefAsResolved(opts) {
496
- if (isResolvedByConfidence(opts.confidence)) {
497
- const normalized = normalizeBeliefConfidence(opts.confidence);
498
- return normalized === 0 ? "resolved_false" : "resolved_true";
499
- }
500
- const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
501
- if (directPredictionStatus) {
502
- return directPredictionStatus;
503
- }
504
- const metadataPredictionStatus = resolvedPredictionStatus(
505
- getPredictionMetaFromMetadata(opts.metadata)
506
- );
507
- if (metadataPredictionStatus) {
508
- return metadataPredictionStatus;
509
- }
510
- return null;
511
- }
512
- function resolveBeliefLifecycleStatus(opts) {
513
- const resolvedStatus = shouldTreatBeliefAsResolved(opts);
514
- if (resolvedStatus) {
515
- return resolvedStatus;
516
- }
517
- const direct = opts.beliefStatus;
518
- const normalizedDirect = normalizeLegacyBeliefStatus(direct);
519
- if (normalizedDirect) {
520
- const normalized = normalizeBeliefConfidence(opts.confidence);
521
- if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
522
- return "active";
523
- }
524
- return normalizedDirect;
525
- }
526
- const metaStatus = opts.metadata?.beliefStatus;
527
- const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
528
- if (normalizedMetaStatus) {
529
- const normalized = normalizeBeliefConfidence(opts.confidence);
530
- if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
531
- return "active";
532
- }
533
- return normalizedMetaStatus;
534
- }
535
- return "assumption";
536
- }
537
- function isPreValidationBeliefStatus(status) {
538
- return status === "assumption" || status === "hypothesis";
539
- }
540
- function promoteBeliefStatusAfterScoring(status, opts) {
541
- const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
542
- if (resolvedStatus) {
543
- return resolvedStatus;
544
- }
545
- if (isPreValidationBeliefStatus(status)) {
546
- return "active";
547
- }
548
- return status;
140
+ return status;
549
141
  }
550
142
 
551
143
  // src/edges/contains.ts
@@ -683,7 +275,7 @@ var dependsOnPropagationSpec = {
683
275
  description: "Structural gating. Textbook conditional deduction when edge conditionals exist, otherwise damped dependency cascade through downstream chains."
684
276
  };
685
277
 
686
- // src/edges/derivedFrom.ts
278
+ // src/edges/derived-from.ts
687
279
  var derivedFromPropagationSpec = {
688
280
  edgeType: "derived_from",
689
281
  direction: "incoming",
@@ -736,7 +328,7 @@ var informsPropagationSpec = {
736
328
  description: "Evidence-bearing influence. Informs can chain through the graph with light per-hop damping."
737
329
  };
738
330
 
739
- // src/edges/propagationTypes.ts
331
+ // src/edges/propagation-types.ts
740
332
  function isPropagationTraversalDirection(direction) {
741
333
  return direction === "outgoing" || direction === "incoming";
742
334
  }
@@ -809,6 +401,9 @@ var testsPropagationSpec = {
809
401
  };
810
402
 
811
403
  // src/edges/index.ts
404
+ var canContinueTransitively2 = canContinueTransitively;
405
+ var canTraverseHop2 = canTraverseHop;
406
+ var isPropagationTraversalDirection2 = isPropagationTraversalDirection;
812
407
  var EDGE_PROPAGATION_SPECS = [
813
408
  supportsPropagationSpec,
814
409
  informsPropagationSpec,
@@ -825,16 +420,409 @@ function getEdgePropagationSpecs() {
825
420
  return EDGE_PROPAGATION_SPECS;
826
421
  }
827
422
  function getTraversalDirections(direction) {
828
- if (isPropagationTraversalDirection(direction)) {
423
+ if (isPropagationTraversalDirection2(direction)) {
829
424
  return [direction];
830
425
  }
831
- return ["outgoing", "incoming"];
426
+ return ["outgoing", "incoming"];
427
+ }
428
+
429
+ // src/debug.ts
430
+ function isGraphPrimitiveDebugEnabled() {
431
+ const env = globalThis.process?.env;
432
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
433
+ }
434
+ function debugGraphPrimitiveFallback(message, context) {
435
+ if (!isGraphPrimitiveDebugEnabled()) {
436
+ return;
437
+ }
438
+ console.debug(message, context ?? {});
439
+ }
440
+
441
+ // src/topicScope.ts
442
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
443
+ async function resolveTopicNodeScopeOrNull(ctx, ref) {
444
+ if (!ctx?.db || typeof ctx.db.query !== "function") {
445
+ return null;
446
+ }
447
+ let node = null;
448
+ try {
449
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
450
+ if (byGlobalId && byGlobalId.nodeType === "topic") {
451
+ node = byGlobalId;
452
+ }
453
+ } catch (error) {
454
+ debugGraphPrimitiveFallback(
455
+ "[topicScope] topic-node scope lookup by globalId failed",
456
+ { error, ref }
457
+ );
458
+ }
459
+ if (!node) {
460
+ return null;
461
+ }
462
+ const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
463
+ if (!scopeKey) {
464
+ return null;
465
+ }
466
+ return {
467
+ topicId: scopeKey,
468
+ projectId: asMappedProjectId(node),
469
+ source: "topic_node"
470
+ };
471
+ }
472
+ function asMappedProjectId(topic) {
473
+ if (!topic) {
474
+ return;
475
+ }
476
+ const directLegacyProjectId = normalizeScopeValue(
477
+ topic[LEGACY_SCOPE_FIELD]
478
+ );
479
+ if (directLegacyProjectId) {
480
+ return directLegacyProjectId;
481
+ }
482
+ const metadata = topic.metadata || {};
483
+ const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
484
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
485
+ }
486
+ function normalizeScopeValue(value) {
487
+ if (typeof value !== "string") {
488
+ return;
489
+ }
490
+ const normalized = value.trim();
491
+ return normalized.length > 0 ? normalized : void 0;
492
+ }
493
+ function pickPrimaryTopic(candidates) {
494
+ return [...candidates].sort((a, b) => {
495
+ const depthA = a.depth ?? 9999;
496
+ const depthB = b.depth ?? 9999;
497
+ if (depthA !== depthB) {
498
+ return depthA - depthB;
499
+ }
500
+ const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
501
+ const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
502
+ if (createdA !== createdB) {
503
+ return createdA - createdB;
504
+ }
505
+ return String(a.name || "").localeCompare(String(b.name || ""));
506
+ })[0];
507
+ }
508
+ async function findTopicsByScopeAlias(ctx, scopeId) {
509
+ const query = ctx.db.query("topics");
510
+ try {
511
+ return await query.withIndex(
512
+ "by_graph_scope_project",
513
+ (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
514
+ ).collect();
515
+ } catch (error) {
516
+ debugGraphPrimitiveFallback(
517
+ "[topicScope] Failed to resolve scope alias via index",
518
+ {
519
+ error,
520
+ scopeId
521
+ }
522
+ );
523
+ const topics = await query.collect();
524
+ return topics.filter((topic) => {
525
+ const normalizedGlobalId = normalizeScopeValue(topic.globalId);
526
+ const mappedProjectId = asMappedProjectId(topic);
527
+ return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
528
+ });
529
+ }
530
+ }
531
+ async function tryResolveHostTopicById(ctx, topicId) {
532
+ if (typeof ctx.runQuery !== "function") {
533
+ return null;
534
+ }
535
+ try {
536
+ return await ctx.runQuery(api.topics.get, {
537
+ id: topicId
538
+ }) ?? null;
539
+ } catch (error) {
540
+ debugGraphPrimitiveFallback(
541
+ "[topicScope] Failed to resolve topic by host query",
542
+ {
543
+ error,
544
+ topicId
545
+ }
546
+ );
547
+ return null;
548
+ }
549
+ }
550
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
551
+ if (typeof ctx.runQuery !== "function") {
552
+ return null;
553
+ }
554
+ try {
555
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
556
+ projectId: legacyScopeId
557
+ }) ?? null;
558
+ } catch (error) {
559
+ debugGraphPrimitiveFallback(
560
+ "[topicScope] Failed to resolve topic by legacy scope",
561
+ {
562
+ error,
563
+ legacyScopeId
564
+ }
565
+ );
566
+ return null;
567
+ }
568
+ }
569
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
570
+ const MAX_DEPTH = 10;
571
+ let tenantId = normalizeScopeValue(topic.tenantId);
572
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
573
+ if (tenantId && workspaceId) {
574
+ return { tenantId, workspaceId };
575
+ }
576
+ let current = topic;
577
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
578
+ current = await ctx.db.get(current.parentTopicId);
579
+ if (!current) {
580
+ break;
581
+ }
582
+ if (!tenantId) {
583
+ tenantId = normalizeScopeValue(current.tenantId);
584
+ }
585
+ if (!workspaceId) {
586
+ workspaceId = normalizeScopeValue(current.workspaceId);
587
+ }
588
+ if (tenantId && workspaceId) {
589
+ break;
590
+ }
591
+ }
592
+ return { tenantId, workspaceId };
593
+ }
594
+ async function resolveTopicProjectScope(ctx, args) {
595
+ if (args.topicId) {
596
+ return await resolveScopeFromTopicId(ctx, args.topicId);
597
+ }
598
+ if (args.projectId) {
599
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
600
+ }
601
+ throw new Error(
602
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
603
+ );
604
+ }
605
+ async function resolveScopeFromTopicId(ctx, topicId) {
606
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
607
+ if (topic) {
608
+ return await buildTopicScope(ctx, topic, "topic");
609
+ }
610
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
611
+ if (nodeScope) {
612
+ return nodeScope;
613
+ }
614
+ throw new Error(`Topic not found: ${String(topicId)}`);
615
+ }
616
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
617
+ const direct = await tryReadTopicDoc(ctx, topicId, {
618
+ failureLog: "[topicScope] Failed to load topic by direct id",
619
+ idLogKey: "topicId"
620
+ });
621
+ if (direct) {
622
+ return direct;
623
+ }
624
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
625
+ if (hostTopic) {
626
+ return hostTopic;
627
+ }
628
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
629
+ }
630
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
631
+ const directTopic = await resolveDirectLegacyProjectTopic(
632
+ ctx,
633
+ legacyProjectId
634
+ );
635
+ if (directTopic) {
636
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
637
+ fallbackProjectId: legacyProjectId
638
+ });
639
+ }
640
+ const primary = pickPrimaryTopic(
641
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
642
+ );
643
+ if (primary) {
644
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
645
+ fallbackProjectId: legacyProjectId
646
+ });
647
+ }
648
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
649
+ if (nodeScope) {
650
+ return {
651
+ ...nodeScope,
652
+ projectId: nodeScope.projectId ?? legacyProjectId
653
+ };
654
+ }
655
+ throw new Error(
656
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
657
+ );
658
+ }
659
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
660
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
661
+ failureLog: "[topicScope] Failed to load direct project topic",
662
+ idLogKey: "projectId"
663
+ });
664
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
665
+ }
666
+ async function tryReadTopicDoc(ctx, id, log) {
667
+ try {
668
+ return await ctx.db.get(id);
669
+ } catch (error) {
670
+ debugGraphPrimitiveFallback(log.failureLog, {
671
+ error,
672
+ [log.idLogKey]: id
673
+ });
674
+ return null;
675
+ }
676
+ }
677
+ async function buildTopicScope(ctx, topic, source, options = {}) {
678
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
679
+ const mapped = asMappedProjectId(topic);
680
+ return {
681
+ topicId: topic._id,
682
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
683
+ tenantId: inherited.tenantId,
684
+ workspaceId: inherited.workspaceId,
685
+ source
686
+ };
687
+ }
688
+ ({
689
+ projectId: v.optional(v.string()),
690
+ topicId: v.optional(v.string())
691
+ });
692
+
693
+ // src/workspaceIsolation.ts
694
+ function normalizeScopeValue2(value) {
695
+ if (typeof value !== "string") {
696
+ return;
697
+ }
698
+ const normalized = value.trim();
699
+ return normalized.length > 0 ? normalized : void 0;
700
+ }
701
+ function throwWorkspaceIsolationError(args) {
702
+ const error = new Error(args.message);
703
+ error.status = 409;
704
+ error.code = "INVARIANT_VIOLATION";
705
+ error.invariantCode = args.invariantCode;
706
+ error.suggestion = args.suggestion;
707
+ error.details = args.details;
708
+ throw error;
709
+ }
710
+ function nodeMatchesWorkspaceReasoningScope(node, scope) {
711
+ if (!node) {
712
+ return false;
713
+ }
714
+ const scopeTenantId = normalizeScopeValue2(scope.tenantId);
715
+ const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
716
+ const nodeTenantId = normalizeScopeValue2(node.tenantId);
717
+ const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
718
+ const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
719
+ if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
720
+ return false;
721
+ }
722
+ if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
723
+ return true;
724
+ }
725
+ if (!scopeWorkspaceId && node.publicationStatus === "published") {
726
+ return true;
727
+ }
728
+ if (!scopeWorkspaceId) {
729
+ return nodeWorkspaceId === void 0;
730
+ }
731
+ return scopeWorkspaceId === nodeWorkspaceId;
732
+ }
733
+ function edgeMatchesWorkspaceReasoningScope(edge, scope) {
734
+ if (!edge) {
735
+ return false;
736
+ }
737
+ const scopeTenantId = normalizeScopeValue2(scope.tenantId);
738
+ const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
739
+ const edgeTenantId = normalizeScopeValue2(edge.tenantId);
740
+ const edgeWorkspaceId = normalizeScopeValue2(edge.workspaceId);
741
+ if (scopeTenantId && edgeTenantId && scopeTenantId !== edgeTenantId) {
742
+ return false;
743
+ }
744
+ if (!scopeWorkspaceId) {
745
+ return edgeWorkspaceId === void 0;
746
+ }
747
+ return scopeWorkspaceId === edgeWorkspaceId;
748
+ }
749
+ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
750
+ const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
751
+ const resolved = {
752
+ tenantId: normalizeScopeValue2(node?.tenantId),
753
+ workspaceId: normalizeScopeValue2(node?.workspaceId),
754
+ epistemicLayer,
755
+ nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
756
+ };
757
+ if (!node) {
758
+ return resolved;
759
+ }
760
+ if (resolved.epistemicLayer === "ontological") {
761
+ return resolved;
762
+ }
763
+ if (resolved.tenantId || resolved.workspaceId) {
764
+ return resolved;
765
+ }
766
+ const topicId = normalizeScopeValue2(node.topicId);
767
+ if (topicId) {
768
+ const topicScope = await resolveTopicProjectScope(ctx, {
769
+ topicId
770
+ });
771
+ return {
772
+ ...resolved,
773
+ tenantId: topicScope.tenantId,
774
+ workspaceId: topicScope.workspaceId
775
+ };
776
+ }
777
+ if (node.projectId) {
778
+ const topicScope = await resolveTopicProjectScope(ctx, {
779
+ projectId: String(node.projectId)
780
+ });
781
+ return {
782
+ ...resolved,
783
+ tenantId: topicScope.tenantId,
784
+ workspaceId: topicScope.workspaceId
785
+ };
786
+ }
787
+ return resolved;
788
+ }
789
+ function resolveRuntimePackMutationContext(args) {
790
+ if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
791
+ return;
792
+ }
793
+ return {
794
+ toolName: args.runtimeToolName,
795
+ packKey: args.runtimePackKey,
796
+ packInstallScope: args.runtimePackInstallScope
797
+ };
798
+ }
799
+ function assertTenantPackWorkspaceMutationAllowed(args) {
800
+ if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
801
+ return;
802
+ }
803
+ const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
804
+ const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
805
+ if (!targetWorkspaceId || targetLayer === "ontological") {
806
+ return;
807
+ }
808
+ throwWorkspaceIsolationError({
809
+ message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
810
+ invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
811
+ suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
812
+ details: {
813
+ mutationName: args.mutationName,
814
+ toolName: args.runtime.toolName,
815
+ packKey: args.runtime.packKey,
816
+ targetWorkspaceId,
817
+ targetNodeType: args.target.nodeType,
818
+ targetLayer
819
+ }
820
+ });
832
821
  }
833
822
 
834
823
  // src/confidencePropagationDispatch.ts
835
- function resolveTraversalTargetNodeId(edge, direction) {
836
- const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
837
- return targetNodeId ?? void 0;
824
+ function nodeIdToCacheKey(nodeId) {
825
+ return String(nodeId);
838
826
  }
839
827
  function readNodeOpinion(node) {
840
828
  const metadata = node.metadata ?? {};
@@ -850,118 +838,282 @@ function readNodeOpinion(node) {
850
838
  return mkOpinion(0, 0, 1, 0.5);
851
839
  }
852
840
  }
841
+ function resolveTraversalTargetNodeId(edge, direction) {
842
+ const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
843
+ return targetNodeId ?? void 0;
844
+ }
845
+ function buildInitialState(sourceNodeId, sourceOpinion) {
846
+ return {
847
+ nodeId: sourceNodeId,
848
+ opinion: sourceOpinion,
849
+ hop: 0,
850
+ visitedNodeIds: /* @__PURE__ */ new Set([nodeIdToCacheKey(sourceNodeId)])
851
+ };
852
+ }
853
+ function extendVisited(currentVisited, targetNodeId) {
854
+ return /* @__PURE__ */ new Set([...currentVisited, nodeIdToCacheKey(targetNodeId)]);
855
+ }
856
+ function makeTransitiveState(current, targetNodeId, projectedOpinion, nextHop) {
857
+ return {
858
+ nodeId: targetNodeId,
859
+ opinion: projectedOpinion,
860
+ hop: nextHop,
861
+ visitedNodeIds: extendVisited(current.visitedNodeIds, targetNodeId)
862
+ };
863
+ }
864
+ function makeDispatchRecord(targetNodeId, spec, direction, edge, projectedOpinion, nextHop, result, existingDispatch) {
865
+ return {
866
+ targetNodeId,
867
+ edgeType: spec.edgeType,
868
+ traversedDirection: direction,
869
+ weight: edge.weight ?? 1,
870
+ opinion: projectedOpinion,
871
+ operator: result.operator,
872
+ rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
873
+ hop: nextHop
874
+ };
875
+ }
876
+ async function loadCachedNode(scope, nodeId) {
877
+ const cacheKey = nodeIdToCacheKey(nodeId);
878
+ if (!scope.nodeCache.has(cacheKey)) {
879
+ scope.nodeCache.set(cacheKey, await scope.args.getNode(nodeId));
880
+ }
881
+ return scope.nodeCache.get(cacheKey) ?? null;
882
+ }
883
+ async function collectTargetDispatch(state, nextHop, spec, direction, edge, queue, scope) {
884
+ const sourceScope = scope.args.sourceScope;
885
+ if (sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, sourceScope)) {
886
+ return;
887
+ }
888
+ const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
889
+ if (!targetNodeId) {
890
+ return;
891
+ }
892
+ const targetNodeIdKey = nodeIdToCacheKey(targetNodeId);
893
+ if (state.visitedNodeIds.has(targetNodeIdKey)) {
894
+ return;
895
+ }
896
+ const targetNode = await loadCachedNode(scope, targetNodeId);
897
+ if (targetNode?.nodeType !== "belief") {
898
+ return;
899
+ }
900
+ if (sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, sourceScope)) {
901
+ return;
902
+ }
903
+ const targetOpinion = scope.opinionCache.get(targetNodeIdKey) ?? readNodeOpinion(targetNode);
904
+ const result = spec.operator(state.opinion, targetOpinion, edge, {
905
+ hop: nextHop,
906
+ sourceNodeId: state.nodeId,
907
+ targetNodeId,
908
+ traversedDirection: direction,
909
+ spec
910
+ });
911
+ if (!(result && hasProjectedOpinionChanged(targetOpinion, result.opinion))) {
912
+ return;
913
+ }
914
+ const projectedOpinion = mkOpinion(
915
+ result.opinion.b,
916
+ result.opinion.d,
917
+ result.opinion.u,
918
+ result.opinion.a
919
+ );
920
+ scope.opinionCache.set(targetNodeIdKey, projectedOpinion);
921
+ const existingDispatch = scope.dispatchesByTargetId.get(targetNodeIdKey);
922
+ scope.dispatchesByTargetId.set(
923
+ targetNodeIdKey,
924
+ makeDispatchRecord(
925
+ targetNodeId,
926
+ spec,
927
+ direction,
928
+ edge,
929
+ projectedOpinion,
930
+ nextHop,
931
+ result,
932
+ existingDispatch
933
+ )
934
+ );
935
+ if (canContinueTransitively2(spec, nextHop)) {
936
+ queue.push(
937
+ makeTransitiveState(state, targetNodeId, projectedOpinion, nextHop)
938
+ );
939
+ }
940
+ }
941
+ async function processTraversalSpec(state, nextHop, spec, queue, scope) {
942
+ const sourceNodeId = state.nodeId;
943
+ for (const direction of getTraversalDirections(spec.direction)) {
944
+ const edges = await scope.args.queryEdges({
945
+ nodeId: sourceNodeId,
946
+ spec,
947
+ direction,
948
+ hop: nextHop
949
+ });
950
+ for (const edge of edges) {
951
+ await collectTargetDispatch(
952
+ state,
953
+ nextHop,
954
+ spec,
955
+ direction,
956
+ edge,
957
+ queue,
958
+ scope
959
+ );
960
+ }
961
+ }
962
+ }
963
+ async function processQueuedState(state, queue, scope) {
964
+ const nextHop = state.hop + 1;
965
+ for (const spec of scope.traversalSpecs) {
966
+ if (!canTraverseHop2(spec, nextHop)) {
967
+ continue;
968
+ }
969
+ await processTraversalSpec(state, nextHop, spec, queue, scope);
970
+ }
971
+ }
972
+ function sortDispatches(dispatches) {
973
+ return Array.from(dispatches).sort((left, right) => {
974
+ if (left.hop !== right.hop) {
975
+ return left.hop - right.hop;
976
+ }
977
+ return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
978
+ });
979
+ }
853
980
  async function collectConfidencePropagationDispatches(args) {
854
981
  const dispatchesByTargetId = /* @__PURE__ */ new Map();
855
982
  const opinionCache = /* @__PURE__ */ new Map();
856
983
  const nodeCache = /* @__PURE__ */ new Map();
857
984
  const traversalSpecs = args.traversalSpecs ?? getEdgePropagationSpecs();
985
+ const scope = {
986
+ args,
987
+ dispatchesByTargetId,
988
+ opinionCache,
989
+ nodeCache,
990
+ traversalSpecs
991
+ };
858
992
  const queue = [
859
- {
860
- nodeId: args.sourceNodeId,
861
- opinion: args.sourceOpinion,
862
- hop: 0,
863
- visitedNodeIds: /* @__PURE__ */ new Set([String(args.sourceNodeId)])
864
- }
993
+ buildInitialState(args.sourceNodeId, args.sourceOpinion)
865
994
  ];
866
- const loadNode = async (nodeId) => {
867
- const cacheKey = String(nodeId);
868
- if (!nodeCache.has(cacheKey)) {
869
- nodeCache.set(cacheKey, await args.getNode(nodeId));
870
- }
871
- return nodeCache.get(cacheKey) ?? null;
872
- };
873
995
  while (queue.length > 0) {
874
996
  const state = queue.shift();
875
997
  if (!state) {
876
998
  continue;
877
999
  }
878
- for (const spec of traversalSpecs) {
879
- const nextHop = state.hop + 1;
880
- if (!canTraverseHop(spec, nextHop)) {
881
- continue;
882
- }
883
- for (const direction of getTraversalDirections(spec.direction)) {
884
- const edges = await args.queryEdges({
885
- nodeId: state.nodeId,
886
- spec,
887
- direction,
888
- hop: nextHop
889
- });
890
- for (const edge of edges) {
891
- if (args.sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, args.sourceScope)) {
892
- continue;
893
- }
894
- const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
895
- if (!targetNodeId) {
896
- continue;
897
- }
898
- if (state.visitedNodeIds.has(String(targetNodeId))) {
899
- continue;
900
- }
901
- const targetNode = await loadNode(targetNodeId);
902
- if (!targetNode || targetNode.nodeType !== "belief") {
903
- continue;
904
- }
905
- if (args.sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, args.sourceScope)) {
906
- continue;
907
- }
908
- const cacheKey = String(targetNodeId);
909
- const targetOpinion = opinionCache.get(cacheKey) ?? readNodeOpinion(targetNode);
910
- const result = spec.operator(state.opinion, targetOpinion, edge, {
911
- hop: nextHop,
912
- sourceNodeId: state.nodeId,
913
- targetNodeId,
914
- traversedDirection: direction,
915
- spec
916
- });
917
- if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
918
- continue;
919
- }
920
- const projectedOpinion = mkOpinion(
921
- result.opinion.b,
922
- result.opinion.d,
923
- result.opinion.u,
924
- result.opinion.a
925
- );
926
- opinionCache.set(cacheKey, projectedOpinion);
927
- const existingDispatch = dispatchesByTargetId.get(cacheKey);
928
- dispatchesByTargetId.set(cacheKey, {
929
- targetNodeId,
930
- edgeType: spec.edgeType,
931
- traversedDirection: direction,
932
- weight: edge.weight ?? 1,
933
- opinion: projectedOpinion,
934
- operator: result.operator,
935
- rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
936
- hop: nextHop
937
- });
938
- if (canContinueTransitively(spec, nextHop)) {
939
- queue.push({
940
- nodeId: targetNodeId,
941
- opinion: projectedOpinion,
942
- hop: nextHop,
943
- visitedNodeIds: /* @__PURE__ */ new Set([
944
- ...state.visitedNodeIds,
945
- String(targetNodeId)
946
- ])
947
- });
948
- }
949
- }
950
- }
951
- }
1000
+ await processQueuedState(state, queue, scope);
952
1001
  }
953
- return Array.from(dispatchesByTargetId.values()).sort((left, right) => {
954
- if (left.hop !== right.hop) {
955
- return left.hop - right.hop;
956
- }
957
- return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
958
- });
1002
+ return sortDispatches(dispatchesByTargetId.values());
959
1003
  }
960
1004
  v.id("epistemicNodes");
961
1005
  var DEFAULT_CONFIDENCE_POLICY = {
962
1006
  scoringMode: "after_worktree",
963
1007
  tupleContradiction: normalizeTupleContradictionPolicy()
964
1008
  };
1009
+ function readFiniteNumber(value) {
1010
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1011
+ }
1012
+ function isRecord(value) {
1013
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1014
+ }
1015
+ function readOptionalString(value) {
1016
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1017
+ }
1018
+ function readStringArray(value) {
1019
+ if (!Array.isArray(value)) {
1020
+ return;
1021
+ }
1022
+ const strings = value.filter(
1023
+ (item) => typeof item === "string" && item.length > 0
1024
+ );
1025
+ return strings.length === value.length ? strings : void 0;
1026
+ }
1027
+ function readRecord(value) {
1028
+ return isRecord(value) ? value : void 0;
1029
+ }
1030
+ function readBeliefNodeView(value) {
1031
+ if (!isRecord(value)) {
1032
+ return null;
1033
+ }
1034
+ const id = readOptionalString(value._id);
1035
+ const nodeType = readOptionalString(value.nodeType);
1036
+ if (!(id && nodeType === "belief")) {
1037
+ return null;
1038
+ }
1039
+ const node = {
1040
+ _id: id,
1041
+ nodeType
1042
+ };
1043
+ const creationTime = readFiniteNumber(value._creationTime);
1044
+ if (creationTime !== void 0) {
1045
+ node._creationTime = creationTime;
1046
+ }
1047
+ const metadata = readRecord(value.metadata);
1048
+ if (metadata !== void 0) {
1049
+ node.metadata = metadata;
1050
+ }
1051
+ const opinionA = readFiniteNumber(value.opinion_a);
1052
+ if (opinionA !== void 0) {
1053
+ node.opinion_a = opinionA;
1054
+ }
1055
+ const opinionB = readFiniteNumber(value.opinion_b);
1056
+ if (opinionB !== void 0) {
1057
+ node.opinion_b = opinionB;
1058
+ }
1059
+ const opinionD = readFiniteNumber(value.opinion_d);
1060
+ if (opinionD !== void 0) {
1061
+ node.opinion_d = opinionD;
1062
+ }
1063
+ const opinionU = readFiniteNumber(value.opinion_u);
1064
+ if (opinionU !== void 0) {
1065
+ node.opinion_u = opinionU;
1066
+ }
1067
+ const tupleContradicted = typeof value.tupleContradicted === "boolean" ? value.tupleContradicted : void 0;
1068
+ if (tupleContradicted !== void 0) {
1069
+ node.tupleContradicted = tupleContradicted;
1070
+ }
1071
+ const stringFields = {
1072
+ anonymizationClass: value.anonymizationClass,
1073
+ audienceLabel: value.audienceLabel,
1074
+ canonicalText: value.canonicalText,
1075
+ createdBy: value.createdBy,
1076
+ epistemicLayer: value.epistemicLayer,
1077
+ exportClass: value.exportClass,
1078
+ globalId: value.globalId,
1079
+ projectId: value.projectId,
1080
+ publicationStatus: value.publicationStatus,
1081
+ sensitivityTier: value.sensitivityTier,
1082
+ status: value.status,
1083
+ tenantId: value.tenantId,
1084
+ topicId: value.topicId,
1085
+ userId: value.userId,
1086
+ workspaceId: value.workspaceId
1087
+ };
1088
+ for (const [field, fieldValue] of Object.entries(stringFields)) {
1089
+ const normalized = readOptionalString(fieldValue);
1090
+ if (normalized !== void 0) {
1091
+ node[field] = normalized;
1092
+ }
1093
+ }
1094
+ const createdAt = readFiniteNumber(value.createdAt);
1095
+ if (createdAt !== void 0) {
1096
+ node.createdAt = createdAt;
1097
+ }
1098
+ const updatedAt = readFiniteNumber(value.updatedAt);
1099
+ if (updatedAt !== void 0) {
1100
+ node.updatedAt = updatedAt;
1101
+ }
1102
+ if (value.beliefStatus !== void 0) {
1103
+ node.beliefStatus = value.beliefStatus;
1104
+ }
1105
+ if (value.confidence !== void 0) {
1106
+ node.confidence = value.confidence;
1107
+ }
1108
+ if (value.predictionMeta !== void 0) {
1109
+ node.predictionMeta = value.predictionMeta;
1110
+ }
1111
+ const policyTags = readStringArray(value.policyTags);
1112
+ if (policyTags !== void 0) {
1113
+ node.policyTags = policyTags;
1114
+ }
1115
+ return node;
1116
+ }
965
1117
  function buildBeliefConfidenceRow(args) {
966
1118
  return {
967
1119
  beliefId: args.beliefId,
@@ -1036,7 +1188,10 @@ function resolveBeliefStatus(node, metadata) {
1036
1188
  });
1037
1189
  }
1038
1190
  async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
1039
- const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex("by_belief", (q) => q.eq("beliefId", beliefNodeId)).collect();
1191
+ const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
1192
+ "by_belief",
1193
+ (q) => q.eq("beliefId", beliefNodeId)
1194
+ ).collect();
1040
1195
  for (const membership of clusterMembership) {
1041
1196
  const worktree = await ctx.db.get(membership.worktreeId);
1042
1197
  if (worktree?.status === "completed" || worktree?.status === "merged") {
@@ -1047,7 +1202,10 @@ async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
1047
1202
  }
1048
1203
  async function getActiveConfidencePolicy(ctx) {
1049
1204
  try {
1050
- const activeConfig = await ctx.db.query("logicSprintScoring").withIndex("by_active", (q) => q.eq("isActive", true)).first();
1205
+ const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
1206
+ "by_active",
1207
+ (q) => q.eq("isActive", true)
1208
+ ).first();
1051
1209
  return {
1052
1210
  scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
1053
1211
  tupleContradiction: normalizeTupleContradictionPolicy(
@@ -1081,9 +1239,189 @@ async function requireAuthenticatedUserId(ctx) {
1081
1239
  }
1082
1240
 
1083
1241
  // src/epistemicBeliefs.confidence.ts
1242
+ function isRecord2(value) {
1243
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1244
+ }
1245
+ function readConvexId(value) {
1246
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1247
+ }
1248
+ function readOptionalBoolean(value) {
1249
+ return typeof value === "boolean" ? value : void 0;
1250
+ }
1251
+ function readOptionalNumber(value) {
1252
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1253
+ }
1254
+ function readOptionalString2(value) {
1255
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1256
+ }
1257
+ function readRecord2(value) {
1258
+ return isRecord2(value) ? value : void 0;
1259
+ }
1260
+ function readConfidenceBeliefNode(value) {
1261
+ if (!isRecord2(value)) {
1262
+ return null;
1263
+ }
1264
+ const id = readConvexId(value._id);
1265
+ const nodeType = readOptionalString2(value.nodeType);
1266
+ const projectId = readOptionalString2(value.projectId);
1267
+ if (!(id && nodeType === "belief" && projectId)) {
1268
+ return null;
1269
+ }
1270
+ const node = {
1271
+ _id: id,
1272
+ nodeType,
1273
+ projectId
1274
+ };
1275
+ const confidence = readOptionalNumber(value.confidence);
1276
+ const epistemicLayer = readOptionalString2(value.epistemicLayer);
1277
+ const globalId = readOptionalString2(value.globalId);
1278
+ const metadata = readRecord2(value.metadata);
1279
+ const opinionA = readOptionalNumber(value.opinion_a);
1280
+ const opinionB = readOptionalNumber(value.opinion_b);
1281
+ const opinionD = readOptionalNumber(value.opinion_d);
1282
+ const opinionU = readOptionalNumber(value.opinion_u);
1283
+ const predictionMeta = readRecord2(value.predictionMeta);
1284
+ const publicationStatus = readOptionalString2(value.publicationStatus);
1285
+ const status = readOptionalString2(value.status);
1286
+ const tenantId = readOptionalString2(value.tenantId);
1287
+ const topicId = readOptionalString2(value.topicId);
1288
+ const tupleContradicted = readOptionalBoolean(value.tupleContradicted);
1289
+ const workspaceId = readOptionalString2(value.workspaceId);
1290
+ if (confidence !== void 0) {
1291
+ node.confidence = confidence;
1292
+ }
1293
+ if (epistemicLayer !== void 0) {
1294
+ node.epistemicLayer = epistemicLayer;
1295
+ }
1296
+ if (globalId !== void 0) {
1297
+ node.globalId = globalId;
1298
+ }
1299
+ if (metadata !== void 0) {
1300
+ node.metadata = metadata;
1301
+ }
1302
+ if (opinionA !== void 0) {
1303
+ node.opinion_a = opinionA;
1304
+ }
1305
+ if (opinionB !== void 0) {
1306
+ node.opinion_b = opinionB;
1307
+ }
1308
+ if (opinionD !== void 0) {
1309
+ node.opinion_d = opinionD;
1310
+ }
1311
+ if (opinionU !== void 0) {
1312
+ node.opinion_u = opinionU;
1313
+ }
1314
+ if (predictionMeta !== void 0) {
1315
+ node.predictionMeta = predictionMeta;
1316
+ }
1317
+ if (publicationStatus !== void 0) {
1318
+ node.publicationStatus = publicationStatus;
1319
+ }
1320
+ if (status !== void 0) {
1321
+ node.status = status;
1322
+ }
1323
+ if (tenantId !== void 0) {
1324
+ node.tenantId = tenantId;
1325
+ }
1326
+ if (topicId !== void 0) {
1327
+ node.topicId = topicId;
1328
+ }
1329
+ if (tupleContradicted !== void 0) {
1330
+ node.tupleContradicted = tupleContradicted;
1331
+ }
1332
+ if (workspaceId !== void 0) {
1333
+ node.workspaceId = workspaceId;
1334
+ }
1335
+ return node;
1336
+ }
1337
+ function readPropagationEdge(value) {
1338
+ if (!isRecord2(value)) {
1339
+ return null;
1340
+ }
1341
+ const edgeType = readOptionalString2(value.edgeType);
1342
+ if (!edgeType) {
1343
+ return null;
1344
+ }
1345
+ const edge = { edgeType };
1346
+ const fromNodeId = readConvexId(value.fromNodeId);
1347
+ const tenantId = readOptionalString2(value.tenantId);
1348
+ const toNodeId = readConvexId(value.toNodeId);
1349
+ const weight = readOptionalNumber(value.weight);
1350
+ const workspaceId = readOptionalString2(value.workspaceId);
1351
+ if (fromNodeId !== void 0) {
1352
+ edge.fromNodeId = fromNodeId;
1353
+ }
1354
+ if (tenantId !== void 0) {
1355
+ edge.tenantId = tenantId;
1356
+ }
1357
+ if (toNodeId !== void 0) {
1358
+ edge.toNodeId = toNodeId;
1359
+ }
1360
+ if (weight !== void 0) {
1361
+ edge.weight = weight;
1362
+ }
1363
+ if (workspaceId !== void 0) {
1364
+ edge.workspaceId = workspaceId;
1365
+ }
1366
+ return edge;
1367
+ }
1368
+ function readRowList(values, reader) {
1369
+ return values.flatMap((value) => {
1370
+ const row = reader(value);
1371
+ return row ? [row] : [];
1372
+ });
1373
+ }
1084
1374
  async function applyBeliefConfidenceChange(ctx, args) {
1085
1375
  const now = Date.now();
1086
- const node = await ctx.db.get(args.nodeId);
1376
+ const node = await requireConfidenceBeliefNode(ctx, args);
1377
+ const state = await buildConfidenceChangeState(ctx, node, args);
1378
+ await assertConfidenceScoringPolicySatisfied(ctx, args, state);
1379
+ const tupleContradictionId = await createTupleContradictionIfNeeded(
1380
+ ctx,
1381
+ args,
1382
+ node,
1383
+ state
1384
+ );
1385
+ await patchBeliefConfidenceState(ctx, args, state);
1386
+ await scheduleFirstScoringThemeEdges(ctx, args, node, state);
1387
+ const beliefConfidenceId = await insertBeliefConfidenceRecord(
1388
+ ctx,
1389
+ args,
1390
+ state,
1391
+ tupleContradictionId,
1392
+ now
1393
+ );
1394
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1395
+ nodeId: args.nodeId,
1396
+ operation: "upsert"
1397
+ });
1398
+ await insertConfidenceAudit(
1399
+ ctx,
1400
+ args,
1401
+ node,
1402
+ state,
1403
+ tupleContradictionId,
1404
+ now
1405
+ );
1406
+ await insertTupleTransitionAuditIfNeeded(
1407
+ ctx,
1408
+ args,
1409
+ node,
1410
+ state,
1411
+ tupleContradictionId,
1412
+ now
1413
+ );
1414
+ await scheduleConfidenceFollowups(ctx, args, node, state);
1415
+ return {
1416
+ nodeId: args.nodeId,
1417
+ previousConfidence: state.previousConfidence,
1418
+ newConfidence: state.derivedConfidence,
1419
+ opinion: state.nextOpinion,
1420
+ beliefConfidenceId
1421
+ };
1422
+ }
1423
+ async function requireConfidenceBeliefNode(ctx, args) {
1424
+ const node = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
1087
1425
  if (!node) {
1088
1426
  throwStructuredMutationError({
1089
1427
  message: "Node not found.",
@@ -1094,59 +1432,28 @@ async function applyBeliefConfidenceChange(ctx, args) {
1094
1432
  details: { nodeId: args.nodeId }
1095
1433
  });
1096
1434
  }
1097
- if (node.nodeType !== "belief") {
1098
- throwStructuredMutationError({
1099
- message: `appendSlScoring only applies to belief nodes. Received nodeType "${node.nodeType}". Entity nodes (company, person, investor, etc.) do not have confidence \u2014 use entityLifecycle.updateEntityAttributes for mutable entity data.`,
1100
- status: 400,
1101
- code: "INVALID_ARGUMENT",
1102
- invariantCode: "entity.no_confidence",
1103
- suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
1104
- details: { nodeId: args.nodeId, nodeType: node.nodeType }
1105
- });
1106
- }
1107
- if (!node.projectId) {
1108
- throwStructuredMutationError({
1109
- message: "Belief has no project scope.",
1110
- status: 400,
1111
- code: "MISSING_SCOPE",
1112
- invariantCode: "belief.project_required",
1113
- suggestion: "Belief must have a projectId before SL scoring can be appended.",
1114
- details: { nodeId: args.nodeId }
1115
- });
1116
- }
1117
- await requireScopeWriteAccess(
1118
- ctx,
1119
- node.projectId,
1120
- args.authenticatedUserId
1121
- );
1122
- const existingMetadata = node.metadata || {};
1435
+ await requireScopeWriteAccess(ctx, node.projectId, args.authenticatedUserId);
1436
+ return node;
1437
+ }
1438
+ async function buildConfidenceChangeState(ctx, node, args) {
1439
+ const existingMetadata = readNodeMetadata(node);
1123
1440
  const currentBeliefStatus = resolveBeliefStatus(node, existingMetadata);
1124
1441
  const confidencePolicy = await getActiveConfidencePolicy(ctx);
1125
- if (confidencePolicy.scoringMode === "after_worktree" && isPreValidationBeliefStatus(currentBeliefStatus)) {
1126
- const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
1127
- ctx,
1128
- args.nodeId
1129
- );
1130
- if (!hasCompletedWorktree) {
1131
- throwStructuredMutationError({
1132
- message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
1133
- status: 409,
1134
- code: "CONFLICT",
1135
- invariantCode: "belief.confidence_append_only",
1136
- suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
1137
- details: { nodeId: args.nodeId }
1138
- });
1139
- }
1140
- }
1141
1442
  const previousConfidence = node.confidence || 0.5;
1142
1443
  const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
1143
1444
  const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
1144
- const slB = args.belief;
1145
- const slD = args.disbelief;
1146
- const slU = args.uncertainty;
1147
- const slA = args.baseRate ?? 0.5;
1148
- const nextOpinion = { b: slB, d: slD, u: slU, a: slA };
1149
- const derivedConfidence = confidenceFromSL(slB, slD, slU, slA);
1445
+ const nextOpinion = {
1446
+ b: args.belief,
1447
+ d: args.disbelief,
1448
+ u: args.uncertainty,
1449
+ a: args.baseRate ?? 0.5
1450
+ };
1451
+ const derivedConfidence = confidenceFromSL(
1452
+ nextOpinion.b,
1453
+ nextOpinion.d,
1454
+ nextOpinion.u,
1455
+ nextOpinion.a
1456
+ );
1150
1457
  const isFirstScoring = typeof node.confidence !== "number" || !Number.isFinite(node.confidence);
1151
1458
  const previousTupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(existingMetadata.tupleContradicted) ?? detectTupleContradiction(
1152
1459
  previousOpinion,
@@ -1167,79 +1474,121 @@ async function applyBeliefConfidenceChange(ctx, args) {
1167
1474
  predictionMeta,
1168
1475
  metadata: existingMetadata
1169
1476
  });
1170
- let tupleContradictionId;
1171
- if (tupleTransition.crossedIntoTupleContradiction) {
1172
- tupleContradictionId = await ctx.runMutation(
1173
- "contradictions:create",
1174
- {
1175
- projectId: node.projectId,
1176
- topicId: node.topicId,
1177
- beliefId: args.nodeId,
1178
- beliefBId: args.nodeId,
1179
- supportingInsightIds: [],
1180
- contradictingInsightIds: [],
1181
- severity: deriveTupleContradictionSeverity(node),
1182
- source: "tuple_space",
1183
- detectionMethod: "agent",
1184
- description: tupleContradictionDescription,
1185
- createdBy: args.authenticatedUserId
1186
- }
1187
- );
1477
+ const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
1478
+ return {
1479
+ confidencePolicy,
1480
+ currentBeliefStatus,
1481
+ derivedConfidence,
1482
+ existingMetadata,
1483
+ isFirstScoring,
1484
+ newBeliefStatus,
1485
+ nextOpinion,
1486
+ previousConfidence,
1487
+ previousTupleContradicted,
1488
+ storedRationale,
1489
+ tupleContradictionDescription,
1490
+ tupleTransition
1491
+ };
1492
+ }
1493
+ function readNodeMetadata(node) {
1494
+ return node.metadata ?? {};
1495
+ }
1496
+ async function assertConfidenceScoringPolicySatisfied(ctx, args, state) {
1497
+ if (state.confidencePolicy.scoringMode !== "after_worktree" || !isPreValidationBeliefStatus(state.currentBeliefStatus)) {
1498
+ return;
1499
+ }
1500
+ const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
1501
+ ctx,
1502
+ args.nodeId
1503
+ );
1504
+ if (hasCompletedWorktree) {
1505
+ return;
1188
1506
  }
1507
+ throwStructuredMutationError({
1508
+ message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
1509
+ status: 409,
1510
+ code: "CONFLICT",
1511
+ invariantCode: "belief.confidence_append_only",
1512
+ suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
1513
+ details: { nodeId: args.nodeId }
1514
+ });
1515
+ }
1516
+ async function createTupleContradictionIfNeeded(ctx, args, node, state) {
1517
+ if (!state.tupleTransition.crossedIntoTupleContradiction) {
1518
+ return;
1519
+ }
1520
+ return await ctx.runMutation("contradictions:create", {
1521
+ projectId: node.projectId,
1522
+ topicId: node.topicId,
1523
+ beliefId: args.nodeId,
1524
+ beliefBId: args.nodeId,
1525
+ supportingInsightIds: [],
1526
+ contradictingInsightIds: [],
1527
+ severity: deriveTupleContradictionSeverity(node),
1528
+ source: "tuple_space",
1529
+ detectionMethod: "agent",
1530
+ description: state.tupleContradictionDescription,
1531
+ createdBy: args.authenticatedUserId
1532
+ });
1533
+ }
1534
+ async function patchBeliefConfidenceState(ctx, args, state) {
1189
1535
  await ctx.db.patch(args.nodeId, {
1190
- confidence: derivedConfidence,
1191
- beliefStatus: newBeliefStatus,
1192
- tupleContradicted: tupleTransition.tupleContradicted,
1193
- updatedAt: now,
1194
- // Store SL opinion fields at node level for fast access
1195
- opinion_b: slB,
1196
- opinion_d: slD,
1197
- opinion_u: slU,
1198
- opinion_a: slA,
1536
+ confidence: state.derivedConfidence,
1537
+ beliefStatus: state.newBeliefStatus,
1538
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1539
+ updatedAt: Date.now(),
1540
+ opinion_b: state.nextOpinion.b,
1541
+ opinion_d: state.nextOpinion.d,
1542
+ opinion_u: state.nextOpinion.u,
1543
+ opinion_a: state.nextOpinion.a,
1199
1544
  metadata: {
1200
- ...existingMetadata,
1201
- beliefStatus: newBeliefStatus,
1202
- slBelief: slB,
1203
- slDisbelief: slD,
1204
- slUncertainty: slU,
1205
- slBaseRate: slA,
1206
- tupleContradicted: tupleTransition.tupleContradicted
1545
+ ...state.existingMetadata,
1546
+ beliefStatus: state.newBeliefStatus,
1547
+ slBelief: state.nextOpinion.b,
1548
+ slDisbelief: state.nextOpinion.d,
1549
+ slUncertainty: state.nextOpinion.u,
1550
+ slBaseRate: state.nextOpinion.a,
1551
+ tupleContradicted: state.tupleTransition.tupleContradicted
1207
1552
  }
1208
1553
  });
1209
- if (isFirstScoring) {
1210
- const nodeTopicId = node.topicId;
1211
- const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
1212
- "by_topic",
1213
- (q) => q.eq("topicId", nodeTopicId || node.projectId)
1214
- ).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
1215
- for (const theme of themeNodes) {
1216
- if (theme.globalId && node.globalId) {
1217
- await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
1218
- globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
1219
- fromGlobalId: node.globalId,
1220
- toGlobalId: theme.globalId,
1221
- edgeType: "relates_to_thesis",
1222
- weight: derivedConfidence,
1223
- createdBy: args.authenticatedUserId,
1224
- topicId: String(node.projectId),
1225
- fromNodeType: "belief",
1226
- toNodeType: "theme",
1227
- fromLayer: "L3",
1228
- toLayer: "L3"
1229
- });
1230
- }
1554
+ }
1555
+ async function scheduleFirstScoringThemeEdges(ctx, args, node, state) {
1556
+ if (!state.isFirstScoring) {
1557
+ return;
1558
+ }
1559
+ const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
1560
+ "by_topic",
1561
+ (q) => q.eq("topicId", node.topicId || node.projectId)
1562
+ ).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
1563
+ for (const theme of themeNodes) {
1564
+ if (!(theme.globalId && node.globalId)) {
1565
+ continue;
1231
1566
  }
1567
+ await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
1568
+ globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
1569
+ fromGlobalId: node.globalId,
1570
+ toGlobalId: theme.globalId,
1571
+ edgeType: "relates_to_thesis",
1572
+ weight: state.derivedConfidence,
1573
+ createdBy: args.authenticatedUserId,
1574
+ topicId: String(node.projectId),
1575
+ fromNodeType: "belief",
1576
+ toNodeType: "theme",
1577
+ fromLayer: "L3",
1578
+ toLayer: "L3"
1579
+ });
1232
1580
  }
1233
- const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
1234
- const beliefConfidenceId = await ctx.db.insert("beliefConfidence", {
1581
+ }
1582
+ async function insertBeliefConfidenceRecord(ctx, args, state, tupleContradictionId, now) {
1583
+ return await ctx.db.insert("beliefConfidence", {
1235
1584
  ...buildBeliefConfidenceRow({
1236
1585
  beliefId: args.nodeId,
1237
- belief: slB,
1238
- disbelief: slD,
1239
- uncertainty: slU,
1240
- baseRate: slA,
1586
+ belief: state.nextOpinion.b,
1587
+ disbelief: state.nextOpinion.d,
1588
+ uncertainty: state.nextOpinion.u,
1589
+ baseRate: state.nextOpinion.a,
1241
1590
  trigger: args.trigger,
1242
- rationale: storedRationale,
1591
+ rationale: state.storedRationale,
1243
1592
  assessedBy: args.authenticatedUserId,
1244
1593
  assessedAt: now,
1245
1594
  slOperator: args.slOperator,
@@ -1248,25 +1597,23 @@ async function applyBeliefConfidenceChange(ctx, args) {
1248
1597
  triggeringWorktreeId: args.triggeringWorktreeId
1249
1598
  })
1250
1599
  });
1251
- await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1252
- nodeId: args.nodeId,
1253
- operation: "upsert"
1254
- });
1600
+ }
1601
+ async function insertConfidenceAudit(ctx, args, node, state, tupleContradictionId, now) {
1255
1602
  await ctx.db.insert("epistemicAudit", {
1256
1603
  entityType: "belief",
1257
1604
  entityId: args.nodeId,
1258
1605
  changeType: "confidence_changed",
1259
1606
  previousState: {
1260
- confidence: previousConfidence,
1261
- tupleContradicted: previousTupleContradicted
1607
+ confidence: state.previousConfidence,
1608
+ tupleContradicted: state.previousTupleContradicted
1262
1609
  },
1263
1610
  newState: {
1264
- opinion: nextOpinion,
1265
- confidence: derivedConfidence,
1611
+ opinion: state.nextOpinion,
1612
+ confidence: state.derivedConfidence,
1266
1613
  trigger: args.trigger,
1267
- rationale: storedRationale,
1268
- tupleContradicted: tupleTransition.tupleContradicted,
1269
- tupleContradictionPolicy: tupleTransition.policy,
1614
+ rationale: state.storedRationale,
1615
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1616
+ tupleContradictionPolicy: state.tupleTransition.policy,
1270
1617
  ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1271
1618
  },
1272
1619
  changedBy: args.authenticatedUserId,
@@ -1275,28 +1622,39 @@ async function applyBeliefConfidenceChange(ctx, args) {
1275
1622
  projectId: node.projectId,
1276
1623
  topicId: node.topicId
1277
1624
  });
1278
- if (tupleTransition.crossedIntoTupleContradiction || tupleTransition.crossedOutOfTupleContradiction) {
1279
- await ctx.db.insert("epistemicAudit", {
1280
- entityType: "belief",
1281
- entityId: args.nodeId,
1282
- changeType: "updated",
1283
- previousState: { tupleContradicted: previousTupleContradicted },
1284
- newState: {
1285
- tupleContradicted: tupleTransition.tupleContradicted,
1286
- action: tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
1287
- opinion: nextOpinion,
1288
- tupleContradictionPolicy: tupleTransition.policy,
1289
- ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1290
- },
1291
- rationale: tupleTransition.crossedIntoTupleContradiction ? tupleContradictionDescription : `Tuple-space contradiction cleared: b=${nextOpinion.b.toFixed(2)}, d=${nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`,
1292
- changedBy: args.authenticatedUserId,
1293
- isAgent: false,
1294
- changedAt: now,
1295
- projectId: node.projectId,
1296
- topicId: node.topicId
1297
- });
1625
+ }
1626
+ async function insertTupleTransitionAuditIfNeeded(ctx, args, node, state, tupleContradictionId, now) {
1627
+ if (!(state.tupleTransition.crossedIntoTupleContradiction || state.tupleTransition.crossedOutOfTupleContradiction)) {
1628
+ return;
1629
+ }
1630
+ await ctx.db.insert("epistemicAudit", {
1631
+ entityType: "belief",
1632
+ entityId: args.nodeId,
1633
+ changeType: "updated",
1634
+ previousState: { tupleContradicted: state.previousTupleContradicted },
1635
+ newState: {
1636
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1637
+ action: state.tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
1638
+ opinion: state.nextOpinion,
1639
+ tupleContradictionPolicy: state.tupleTransition.policy,
1640
+ ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1641
+ },
1642
+ rationale: tupleAuditRationale(state),
1643
+ changedBy: args.authenticatedUserId,
1644
+ isAgent: false,
1645
+ changedAt: now,
1646
+ projectId: node.projectId,
1647
+ topicId: node.topicId
1648
+ });
1649
+ }
1650
+ function tupleAuditRationale(state) {
1651
+ if (state.tupleTransition.crossedIntoTupleContradiction) {
1652
+ return state.tupleContradictionDescription;
1298
1653
  }
1299
- if (Math.abs(derivedConfidence - previousConfidence) >= 0.15) {
1654
+ return `Tuple-space contradiction cleared: b=${state.nextOpinion.b.toFixed(2)}, d=${state.nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`;
1655
+ }
1656
+ async function scheduleConfidenceFollowups(ctx, args, node, state) {
1657
+ if (Math.abs(state.derivedConfidence - state.previousConfidence) >= 0.15) {
1300
1658
  await ctx.scheduler.runAfter(
1301
1659
  5e3,
1302
1660
  internal.bi.contradictionSemanticDetector.scanAffectedBeliefs,
@@ -1313,13 +1671,6 @@ async function applyBeliefConfidenceChange(ctx, args) {
1313
1671
  { nodeId: args.nodeId }
1314
1672
  );
1315
1673
  }
1316
- return {
1317
- nodeId: args.nodeId,
1318
- previousConfidence,
1319
- newConfidence: derivedConfidence,
1320
- opinion: { b: slB, d: slD, u: slU, a: slA },
1321
- beliefConfidenceId
1322
- };
1323
1674
  }
1324
1675
  function propagationPressureLabel(edgeType, weight) {
1325
1676
  if (edgeType === "contradicts" || edgeType === "refutes") {
@@ -1347,7 +1698,7 @@ internalMutation({
1347
1698
  args.opinion_u,
1348
1699
  args.opinion_a
1349
1700
  );
1350
- const sourceNode = await ctx.db.get(args.nodeId);
1701
+ const sourceNode = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
1351
1702
  const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
1352
1703
  ctx,
1353
1704
  sourceNode
@@ -1356,16 +1707,20 @@ internalMutation({
1356
1707
  sourceNodeId: args.nodeId,
1357
1708
  sourceOpinion,
1358
1709
  sourceScope,
1359
- queryEdges: async ({ nodeId, spec, direction }) => {
1360
- return await ctx.db.query("epistemicEdges").withIndex(
1710
+ queryEdges: async ({ nodeId, spec, direction }) => readRowList(
1711
+ await ctx.db.query("epistemicEdges").withIndex(
1361
1712
  direction === "outgoing" ? "by_from_type" : "by_to_type",
1362
1713
  (q) => direction === "outgoing" ? q.eq("fromNodeId", nodeId).eq("edgeType", spec.edgeType) : q.eq("toNodeId", nodeId).eq("edgeType", spec.edgeType)
1363
- ).collect();
1364
- },
1365
- getNode: async (nodeId) => await ctx.db.get(nodeId)
1714
+ ).collect(),
1715
+ readPropagationEdge
1716
+ ),
1717
+ getNode: async (nodeId) => readConfidenceBeliefNode(await ctx.db.get(nodeId))
1366
1718
  });
1367
1719
  for (const dispatch of dispatches) {
1368
- const pressureLabel = propagationPressureLabel(dispatch.edgeType, dispatch.weight);
1720
+ const pressureLabel = propagationPressureLabel(
1721
+ dispatch.edgeType,
1722
+ dispatch.weight
1723
+ );
1369
1724
  await applyBeliefConfidenceChange(ctx, {
1370
1725
  nodeId: dispatch.targetNodeId,
1371
1726
  belief: dispatch.opinion.b,
@@ -1388,6 +1743,8 @@ internalMutation({
1388
1743
  };
1389
1744
  }
1390
1745
  });
1746
+
1747
+ // src/epistemicBeliefs.lifecycle.ts
1391
1748
  var appendSlScoring = mutation({
1392
1749
  args: {
1393
1750
  nodeId: v.id("epistemicNodes"),
@@ -1486,8 +1843,8 @@ var updateStatus = mutation({
1486
1843
  handler: async (ctx, args) => {
1487
1844
  const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1488
1845
  const now = Date.now();
1489
- const node = await ctx.db.get(args.nodeId);
1490
- if (!node || node.nodeType !== "belief") {
1846
+ const node = readBeliefNodeView(await ctx.db.get(args.nodeId));
1847
+ if (!node) {
1491
1848
  throw new Error("Belief not found");
1492
1849
  }
1493
1850
  if (!node.projectId) {
@@ -1495,7 +1852,7 @@ var updateStatus = mutation({
1495
1852
  }
1496
1853
  await requireScopeWriteAccess(ctx, node.projectId, authenticatedUserId);
1497
1854
  const previousStatus = node.status;
1498
- const metadata = node.metadata || {};
1855
+ const metadata = node.metadata ?? {};
1499
1856
  await ctx.db.patch(args.nodeId, {
1500
1857
  status: args.status,
1501
1858
  updatedAt: now,
@@ -1531,8 +1888,8 @@ var archive = mutation({
1531
1888
  returns: permissiveReturn,
1532
1889
  handler: async (ctx, args) => {
1533
1890
  const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1534
- const node = await ctx.db.get(args.nodeId);
1535
- if (!node || node.nodeType !== "belief") {
1891
+ const node = readBeliefNodeView(await ctx.db.get(args.nodeId));
1892
+ if (!node) {
1536
1893
  throw new Error("Belief not found");
1537
1894
  }
1538
1895
  if (!node.projectId) {
@@ -1561,15 +1918,15 @@ var updateRationale = mutation({
1561
1918
  handler: async (ctx, args) => {
1562
1919
  const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1563
1920
  const now = Date.now();
1564
- const node = await ctx.db.get(args.nodeId);
1565
- if (!node || node.nodeType !== "belief") {
1921
+ const node = readBeliefNodeView(await ctx.db.get(args.nodeId));
1922
+ if (!node) {
1566
1923
  throw new Error("Belief not found");
1567
1924
  }
1568
1925
  if (!node.projectId) {
1569
1926
  throw new Error("Belief has no project scope");
1570
1927
  }
1571
1928
  await requireScopeWriteAccess(ctx, node.projectId, authenticatedUserId);
1572
- const metadata = node.metadata || {};
1929
+ const metadata = node.metadata ?? {};
1573
1930
  const previousRationale = typeof metadata.rationale === "string" ? metadata.rationale : void 0;
1574
1931
  const nextRationale = args.rationale?.trim();
1575
1932
  await ctx.db.patch(args.nodeId, {
@@ -1622,8 +1979,8 @@ var updateStatusInternal = internalMutation({
1622
1979
  returns: permissiveReturn,
1623
1980
  handler: async (ctx, args) => {
1624
1981
  const now = Date.now();
1625
- const node = await ctx.db.get(args.nodeId);
1626
- if (!node || node.nodeType !== "belief") {
1982
+ const node = readBeliefNodeView(await ctx.db.get(args.nodeId));
1983
+ if (!node) {
1627
1984
  throw new Error("Belief not found");
1628
1985
  }
1629
1986
  assertTenantPackWorkspaceMutationAllowed({