@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,12 +1,13 @@
1
- import { v } from 'convex/values';
2
- import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, hasProjectedOpinionChanged, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, readOpinionFromRecord } from '@lucern/confidence';
3
1
  import { requireScopeWriteAccess } from '@lucern/access-control/access';
2
+ import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, readOpinionFromRecord, hasProjectedOpinionChanged } from '@lucern/confidence';
4
3
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
5
- import { componentsGeneric, internalMutationGeneric, anyApi } from 'convex/server';
4
+ import { v } from 'convex/values';
6
5
  import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
7
- import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
6
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
7
+ import { componentsGeneric, internalMutationGeneric } from 'convex/server';
8
8
  import '@lucern/access-control/audience';
9
9
  import '@lucern/access-control/auth';
10
+ import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
10
11
 
11
12
  // src/epistemicBeliefs.confidence.ts
12
13
 
@@ -130,10 +131,6 @@ function promoteBeliefStatusAfterScoring(status, opts) {
130
131
  }
131
132
  return status;
132
133
  }
133
- var api = anyApi;
134
- componentsGeneric();
135
- var internal = anyApi;
136
- var internalMutation = internalMutationGeneric;
137
134
 
138
135
  // src/edges/contains.ts
139
136
  var containsPropagationSpec = {
@@ -270,7 +267,7 @@ var dependsOnPropagationSpec = {
270
267
  description: "Structural gating. Textbook conditional deduction when edge conditionals exist, otherwise damped dependency cascade through downstream chains."
271
268
  };
272
269
 
273
- // src/edges/derivedFrom.ts
270
+ // src/edges/derived-from.ts
274
271
  var derivedFromPropagationSpec = {
275
272
  edgeType: "derived_from",
276
273
  direction: "incoming",
@@ -323,7 +320,7 @@ var informsPropagationSpec = {
323
320
  description: "Evidence-bearing influence. Informs can chain through the graph with light per-hop damping."
324
321
  };
325
322
 
326
- // src/edges/propagationTypes.ts
323
+ // src/edges/propagation-types.ts
327
324
  function isPropagationTraversalDirection(direction) {
328
325
  return direction === "outgoing" || direction === "incoming";
329
326
  }
@@ -396,6 +393,9 @@ var testsPropagationSpec = {
396
393
  };
397
394
 
398
395
  // src/edges/index.ts
396
+ var canContinueTransitively2 = canContinueTransitively;
397
+ var canTraverseHop2 = canTraverseHop;
398
+ var isPropagationTraversalDirection2 = isPropagationTraversalDirection;
399
399
  var EDGE_PROPAGATION_SPECS = [
400
400
  supportsPropagationSpec,
401
401
  informsPropagationSpec,
@@ -412,11 +412,18 @@ function getEdgePropagationSpecs() {
412
412
  return EDGE_PROPAGATION_SPECS;
413
413
  }
414
414
  function getTraversalDirections(direction) {
415
- if (isPropagationTraversalDirection(direction)) {
415
+ if (isPropagationTraversalDirection2(direction)) {
416
416
  return [direction];
417
417
  }
418
418
  return ["outgoing", "incoming"];
419
419
  }
420
+ var unsafeApi = unsafeConvexAnyApi(
421
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
422
+ );
423
+ var api = unsafeApi;
424
+ componentsGeneric();
425
+ var internal = unsafeApi;
426
+ var internalMutation = internalMutationGeneric;
420
427
 
421
428
  // src/debug.ts
422
429
  function isGraphPrimitiveDebugEnabled() {
@@ -465,13 +472,15 @@ function asMappedProjectId(topic) {
465
472
  if (!topic) {
466
473
  return;
467
474
  }
468
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
475
+ const directLegacyProjectId = normalizeScopeValue(
476
+ topic[LEGACY_SCOPE_FIELD]
477
+ );
469
478
  if (directLegacyProjectId) {
470
479
  return directLegacyProjectId;
471
480
  }
472
481
  const metadata = topic.metadata || {};
473
482
  const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
474
- return candidate ? candidate : void 0;
483
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
475
484
  }
476
485
  function normalizeScopeValue(value) {
477
486
  if (typeof value !== "string") {
@@ -496,8 +505,9 @@ function pickPrimaryTopic(candidates) {
496
505
  })[0];
497
506
  }
498
507
  async function findTopicsByScopeAlias(ctx, scopeId) {
508
+ const query = ctx.db.query("topics");
499
509
  try {
500
- return await ctx.db.query("topics").withIndex(
510
+ return await query.withIndex(
501
511
  "by_graph_scope_project",
502
512
  (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
503
513
  ).collect();
@@ -509,7 +519,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
509
519
  scopeId
510
520
  }
511
521
  );
512
- const topics = await ctx.db.query("topics").collect();
522
+ const topics = await query.collect();
513
523
  return topics.filter((topic) => {
514
524
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
515
525
  const mappedProjectId = asMappedProjectId(topic);
@@ -565,137 +575,115 @@ async function resolveInheritedWorkspaceScope(ctx, topic) {
565
575
  let current = topic;
566
576
  for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
567
577
  current = await ctx.db.get(current.parentTopicId);
568
- if (!current) break;
578
+ if (!current) {
579
+ break;
580
+ }
569
581
  if (!tenantId) {
570
582
  tenantId = normalizeScopeValue(current.tenantId);
571
583
  }
572
584
  if (!workspaceId) {
573
585
  workspaceId = normalizeScopeValue(current.workspaceId);
574
586
  }
575
- if (tenantId && workspaceId) break;
587
+ if (tenantId && workspaceId) {
588
+ break;
589
+ }
576
590
  }
577
591
  return { tenantId, workspaceId };
578
592
  }
579
593
  async function resolveTopicProjectScope(ctx, args) {
580
594
  if (args.topicId) {
581
- let topic = null;
582
- try {
583
- topic = await ctx.db.get(
584
- args.topicId
585
- );
586
- } catch (error) {
587
- debugGraphPrimitiveFallback(
588
- "[topicScope] Failed to load topic by direct id",
589
- {
590
- error,
591
- topicId: args.topicId
592
- }
593
- );
594
- }
595
- if (!topic) {
596
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
597
- }
598
- if (!topic) {
599
- topic = pickPrimaryTopic(
600
- await findTopicsByScopeAlias(ctx, String(args.topicId))
601
- ) ?? null;
602
- }
603
- if (!topic) {
604
- const nodeScope = await resolveTopicNodeScopeOrNull(
605
- ctx,
606
- String(args.topicId)
607
- );
608
- if (nodeScope) {
609
- return nodeScope;
610
- }
611
- throw new Error(`Topic not found: ${String(args.topicId)}`);
612
- }
613
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
614
- const mapped = asMappedProjectId(topic);
615
- if (mapped) {
616
- return {
617
- topicId: topic._id,
618
- projectId: mapped,
619
- tenantId: inherited.tenantId,
620
- workspaceId: inherited.workspaceId,
621
- source: "topic"
622
- };
623
- }
624
- return {
625
- topicId: topic._id,
626
- tenantId: inherited.tenantId,
627
- workspaceId: inherited.workspaceId,
628
- source: "topic"
629
- };
595
+ return await resolveScopeFromTopicId(ctx, args.topicId);
630
596
  }
631
597
  if (args.projectId) {
632
- let directTopic = null;
633
- try {
634
- directTopic = await ctx.db.get(
635
- args.projectId
636
- );
637
- } catch (error) {
638
- debugGraphPrimitiveFallback(
639
- "[topicScope] Failed to load direct project topic",
640
- {
641
- error,
642
- projectId: args.projectId
643
- }
644
- );
645
- }
646
- if (directTopic) {
647
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
648
- const mapped = asMappedProjectId(directTopic);
649
- return {
650
- topicId: directTopic._id,
651
- projectId: mapped ?? args.projectId,
652
- tenantId: inherited.tenantId,
653
- workspaceId: inherited.workspaceId,
654
- source: "topic_inferred"
655
- };
656
- }
657
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
658
- if (directTopic) {
659
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
660
- const mapped = asMappedProjectId(directTopic);
661
- return {
662
- topicId: directTopic._id,
663
- projectId: mapped ?? args.projectId,
664
- tenantId: inherited.tenantId,
665
- workspaceId: inherited.workspaceId,
666
- source: "topic_inferred"
667
- };
668
- }
669
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
670
- const primary = pickPrimaryTopic(topics);
671
- if (primary) {
672
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
673
- return {
674
- topicId: primary._id,
675
- projectId: args.projectId,
676
- tenantId: inherited.tenantId,
677
- workspaceId: inherited.workspaceId,
678
- source: "project_mapped_topic"
679
- };
680
- }
681
- const nodeScope = await resolveTopicNodeScopeOrNull(
682
- ctx,
683
- String(args.projectId)
684
- );
685
- if (nodeScope) {
686
- return {
687
- ...nodeScope,
688
- projectId: nodeScope.projectId ?? String(args.projectId)
689
- };
690
- }
691
- throw new Error(
692
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
693
- );
598
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
694
599
  }
695
600
  throw new Error(
696
601
  "Missing scope: provide topicId (preferred) or legacy projectId alias."
697
602
  );
698
603
  }
604
+ async function resolveScopeFromTopicId(ctx, topicId) {
605
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
606
+ if (topic) {
607
+ return await buildTopicScope(ctx, topic, "topic");
608
+ }
609
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
610
+ if (nodeScope) {
611
+ return nodeScope;
612
+ }
613
+ throw new Error(`Topic not found: ${String(topicId)}`);
614
+ }
615
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
616
+ const direct = await tryReadTopicDoc(ctx, topicId, {
617
+ failureLog: "[topicScope] Failed to load topic by direct id",
618
+ idLogKey: "topicId"
619
+ });
620
+ if (direct) {
621
+ return direct;
622
+ }
623
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
624
+ if (hostTopic) {
625
+ return hostTopic;
626
+ }
627
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
628
+ }
629
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
630
+ const directTopic = await resolveDirectLegacyProjectTopic(
631
+ ctx,
632
+ legacyProjectId
633
+ );
634
+ if (directTopic) {
635
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
636
+ fallbackProjectId: legacyProjectId
637
+ });
638
+ }
639
+ const primary = pickPrimaryTopic(
640
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
641
+ );
642
+ if (primary) {
643
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
644
+ fallbackProjectId: legacyProjectId
645
+ });
646
+ }
647
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
648
+ if (nodeScope) {
649
+ return {
650
+ ...nodeScope,
651
+ projectId: nodeScope.projectId ?? legacyProjectId
652
+ };
653
+ }
654
+ throw new Error(
655
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
656
+ );
657
+ }
658
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
659
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
660
+ failureLog: "[topicScope] Failed to load direct project topic",
661
+ idLogKey: "projectId"
662
+ });
663
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
664
+ }
665
+ async function tryReadTopicDoc(ctx, id, log) {
666
+ try {
667
+ return await ctx.db.get(id);
668
+ } catch (error) {
669
+ debugGraphPrimitiveFallback(log.failureLog, {
670
+ error,
671
+ [log.idLogKey]: id
672
+ });
673
+ return null;
674
+ }
675
+ }
676
+ async function buildTopicScope(ctx, topic, source, options = {}) {
677
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
678
+ const mapped = asMappedProjectId(topic);
679
+ return {
680
+ topicId: topic._id,
681
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
682
+ tenantId: inherited.tenantId,
683
+ workspaceId: inherited.workspaceId,
684
+ source
685
+ };
686
+ }
699
687
  ({
700
688
  projectId: v.optional(v.string()),
701
689
  topicId: v.optional(v.string())
@@ -765,9 +753,10 @@ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
765
753
  if (resolved.tenantId || resolved.workspaceId) {
766
754
  return resolved;
767
755
  }
768
- if (node.topicId) {
756
+ const topicId = normalizeScopeValue2(node.topicId);
757
+ if (topicId) {
769
758
  const topicScope = await resolveTopicProjectScope(ctx, {
770
- topicId: node.topicId
759
+ topicId
771
760
  });
772
761
  return {
773
762
  ...resolved,
@@ -789,9 +778,8 @@ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
789
778
  }
790
779
 
791
780
  // src/confidencePropagationDispatch.ts
792
- function resolveTraversalTargetNodeId(edge, direction) {
793
- const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
794
- return targetNodeId ?? void 0;
781
+ function nodeIdToCacheKey(nodeId) {
782
+ return String(nodeId);
795
783
  }
796
784
  function readNodeOpinion(node) {
797
785
  const metadata = node.metadata ?? {};
@@ -807,112 +795,168 @@ function readNodeOpinion(node) {
807
795
  return mkOpinion(0, 0, 1, 0.5);
808
796
  }
809
797
  }
798
+ function resolveTraversalTargetNodeId(edge, direction) {
799
+ const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
800
+ return targetNodeId ?? void 0;
801
+ }
802
+ function buildInitialState(sourceNodeId, sourceOpinion) {
803
+ return {
804
+ nodeId: sourceNodeId,
805
+ opinion: sourceOpinion,
806
+ hop: 0,
807
+ visitedNodeIds: /* @__PURE__ */ new Set([nodeIdToCacheKey(sourceNodeId)])
808
+ };
809
+ }
810
+ function extendVisited(currentVisited, targetNodeId) {
811
+ return /* @__PURE__ */ new Set([...currentVisited, nodeIdToCacheKey(targetNodeId)]);
812
+ }
813
+ function makeTransitiveState(current, targetNodeId, projectedOpinion, nextHop) {
814
+ return {
815
+ nodeId: targetNodeId,
816
+ opinion: projectedOpinion,
817
+ hop: nextHop,
818
+ visitedNodeIds: extendVisited(current.visitedNodeIds, targetNodeId)
819
+ };
820
+ }
821
+ function makeDispatchRecord(targetNodeId, spec, direction, edge, projectedOpinion, nextHop, result, existingDispatch) {
822
+ return {
823
+ targetNodeId,
824
+ edgeType: spec.edgeType,
825
+ traversedDirection: direction,
826
+ weight: edge.weight ?? 1,
827
+ opinion: projectedOpinion,
828
+ operator: result.operator,
829
+ rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
830
+ hop: nextHop
831
+ };
832
+ }
833
+ async function loadCachedNode(scope, nodeId) {
834
+ const cacheKey = nodeIdToCacheKey(nodeId);
835
+ if (!scope.nodeCache.has(cacheKey)) {
836
+ scope.nodeCache.set(cacheKey, await scope.args.getNode(nodeId));
837
+ }
838
+ return scope.nodeCache.get(cacheKey) ?? null;
839
+ }
840
+ async function collectTargetDispatch(state, nextHop, spec, direction, edge, queue, scope) {
841
+ const sourceScope = scope.args.sourceScope;
842
+ if (sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, sourceScope)) {
843
+ return;
844
+ }
845
+ const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
846
+ if (!targetNodeId) {
847
+ return;
848
+ }
849
+ const targetNodeIdKey = nodeIdToCacheKey(targetNodeId);
850
+ if (state.visitedNodeIds.has(targetNodeIdKey)) {
851
+ return;
852
+ }
853
+ const targetNode = await loadCachedNode(scope, targetNodeId);
854
+ if (targetNode?.nodeType !== "belief") {
855
+ return;
856
+ }
857
+ if (sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, sourceScope)) {
858
+ return;
859
+ }
860
+ const targetOpinion = scope.opinionCache.get(targetNodeIdKey) ?? readNodeOpinion(targetNode);
861
+ const result = spec.operator(state.opinion, targetOpinion, edge, {
862
+ hop: nextHop,
863
+ sourceNodeId: state.nodeId,
864
+ targetNodeId,
865
+ traversedDirection: direction,
866
+ spec
867
+ });
868
+ if (!(result && hasProjectedOpinionChanged(targetOpinion, result.opinion))) {
869
+ return;
870
+ }
871
+ const projectedOpinion = mkOpinion(
872
+ result.opinion.b,
873
+ result.opinion.d,
874
+ result.opinion.u,
875
+ result.opinion.a
876
+ );
877
+ scope.opinionCache.set(targetNodeIdKey, projectedOpinion);
878
+ const existingDispatch = scope.dispatchesByTargetId.get(targetNodeIdKey);
879
+ scope.dispatchesByTargetId.set(
880
+ targetNodeIdKey,
881
+ makeDispatchRecord(
882
+ targetNodeId,
883
+ spec,
884
+ direction,
885
+ edge,
886
+ projectedOpinion,
887
+ nextHop,
888
+ result,
889
+ existingDispatch
890
+ )
891
+ );
892
+ if (canContinueTransitively2(spec, nextHop)) {
893
+ queue.push(
894
+ makeTransitiveState(state, targetNodeId, projectedOpinion, nextHop)
895
+ );
896
+ }
897
+ }
898
+ async function processTraversalSpec(state, nextHop, spec, queue, scope) {
899
+ const sourceNodeId = state.nodeId;
900
+ for (const direction of getTraversalDirections(spec.direction)) {
901
+ const edges = await scope.args.queryEdges({
902
+ nodeId: sourceNodeId,
903
+ spec,
904
+ direction,
905
+ hop: nextHop
906
+ });
907
+ for (const edge of edges) {
908
+ await collectTargetDispatch(
909
+ state,
910
+ nextHop,
911
+ spec,
912
+ direction,
913
+ edge,
914
+ queue,
915
+ scope
916
+ );
917
+ }
918
+ }
919
+ }
920
+ async function processQueuedState(state, queue, scope) {
921
+ const nextHop = state.hop + 1;
922
+ for (const spec of scope.traversalSpecs) {
923
+ if (!canTraverseHop2(spec, nextHop)) {
924
+ continue;
925
+ }
926
+ await processTraversalSpec(state, nextHop, spec, queue, scope);
927
+ }
928
+ }
929
+ function sortDispatches(dispatches) {
930
+ return Array.from(dispatches).sort((left, right) => {
931
+ if (left.hop !== right.hop) {
932
+ return left.hop - right.hop;
933
+ }
934
+ return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
935
+ });
936
+ }
810
937
  async function collectConfidencePropagationDispatches(args) {
811
938
  const dispatchesByTargetId = /* @__PURE__ */ new Map();
812
939
  const opinionCache = /* @__PURE__ */ new Map();
813
940
  const nodeCache = /* @__PURE__ */ new Map();
814
941
  const traversalSpecs = args.traversalSpecs ?? getEdgePropagationSpecs();
942
+ const scope = {
943
+ args,
944
+ dispatchesByTargetId,
945
+ opinionCache,
946
+ nodeCache,
947
+ traversalSpecs
948
+ };
815
949
  const queue = [
816
- {
817
- nodeId: args.sourceNodeId,
818
- opinion: args.sourceOpinion,
819
- hop: 0,
820
- visitedNodeIds: /* @__PURE__ */ new Set([String(args.sourceNodeId)])
821
- }
950
+ buildInitialState(args.sourceNodeId, args.sourceOpinion)
822
951
  ];
823
- const loadNode = async (nodeId) => {
824
- const cacheKey = String(nodeId);
825
- if (!nodeCache.has(cacheKey)) {
826
- nodeCache.set(cacheKey, await args.getNode(nodeId));
827
- }
828
- return nodeCache.get(cacheKey) ?? null;
829
- };
830
952
  while (queue.length > 0) {
831
953
  const state = queue.shift();
832
954
  if (!state) {
833
955
  continue;
834
956
  }
835
- for (const spec of traversalSpecs) {
836
- const nextHop = state.hop + 1;
837
- if (!canTraverseHop(spec, nextHop)) {
838
- continue;
839
- }
840
- for (const direction of getTraversalDirections(spec.direction)) {
841
- const edges = await args.queryEdges({
842
- nodeId: state.nodeId,
843
- spec,
844
- direction,
845
- hop: nextHop
846
- });
847
- for (const edge of edges) {
848
- if (args.sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, args.sourceScope)) {
849
- continue;
850
- }
851
- const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
852
- if (!targetNodeId) {
853
- continue;
854
- }
855
- if (state.visitedNodeIds.has(String(targetNodeId))) {
856
- continue;
857
- }
858
- const targetNode = await loadNode(targetNodeId);
859
- if (!targetNode || targetNode.nodeType !== "belief") {
860
- continue;
861
- }
862
- if (args.sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, args.sourceScope)) {
863
- continue;
864
- }
865
- const cacheKey = String(targetNodeId);
866
- const targetOpinion = opinionCache.get(cacheKey) ?? readNodeOpinion(targetNode);
867
- const result = spec.operator(state.opinion, targetOpinion, edge, {
868
- hop: nextHop,
869
- sourceNodeId: state.nodeId,
870
- targetNodeId,
871
- traversedDirection: direction,
872
- spec
873
- });
874
- if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
875
- continue;
876
- }
877
- const projectedOpinion = mkOpinion(
878
- result.opinion.b,
879
- result.opinion.d,
880
- result.opinion.u,
881
- result.opinion.a
882
- );
883
- opinionCache.set(cacheKey, projectedOpinion);
884
- const existingDispatch = dispatchesByTargetId.get(cacheKey);
885
- dispatchesByTargetId.set(cacheKey, {
886
- targetNodeId,
887
- edgeType: spec.edgeType,
888
- traversedDirection: direction,
889
- weight: edge.weight ?? 1,
890
- opinion: projectedOpinion,
891
- operator: result.operator,
892
- rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
893
- hop: nextHop
894
- });
895
- if (canContinueTransitively(spec, nextHop)) {
896
- queue.push({
897
- nodeId: targetNodeId,
898
- opinion: projectedOpinion,
899
- hop: nextHop,
900
- visitedNodeIds: /* @__PURE__ */ new Set([
901
- ...state.visitedNodeIds,
902
- String(targetNodeId)
903
- ])
904
- });
905
- }
906
- }
907
- }
908
- }
957
+ await processQueuedState(state, queue, scope);
909
958
  }
910
- return Array.from(dispatchesByTargetId.values()).sort((left, right) => {
911
- if (left.hop !== right.hop) {
912
- return left.hop - right.hop;
913
- }
914
- return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
915
- });
959
+ return sortDispatches(dispatchesByTargetId.values());
916
960
  }
917
961
  v.id("epistemicNodes");
918
962
  var DEFAULT_CONFIDENCE_POLICY = {
@@ -993,7 +1037,10 @@ function resolveBeliefStatus(node, metadata) {
993
1037
  });
994
1038
  }
995
1039
  async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
996
- const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex("by_belief", (q) => q.eq("beliefId", beliefNodeId)).collect();
1040
+ const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
1041
+ "by_belief",
1042
+ (q) => q.eq("beliefId", beliefNodeId)
1043
+ ).collect();
997
1044
  for (const membership of clusterMembership) {
998
1045
  const worktree = await ctx.db.get(membership.worktreeId);
999
1046
  if (worktree?.status === "completed" || worktree?.status === "merged") {
@@ -1004,7 +1051,10 @@ async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
1004
1051
  }
1005
1052
  async function getActiveConfidencePolicy(ctx) {
1006
1053
  try {
1007
- const activeConfig = await ctx.db.query("logicSprintScoring").withIndex("by_active", (q) => q.eq("isActive", true)).first();
1054
+ const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
1055
+ "by_active",
1056
+ (q) => q.eq("isActive", true)
1057
+ ).first();
1008
1058
  return {
1009
1059
  scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
1010
1060
  tupleContradiction: normalizeTupleContradictionPolicy(
@@ -1023,9 +1073,189 @@ async function getActiveConfidencePolicy(ctx) {
1023
1073
  }
1024
1074
 
1025
1075
  // src/epistemicBeliefs.confidence.ts
1076
+ function isRecord(value) {
1077
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1078
+ }
1079
+ function readConvexId(value) {
1080
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1081
+ }
1082
+ function readOptionalBoolean(value) {
1083
+ return typeof value === "boolean" ? value : void 0;
1084
+ }
1085
+ function readOptionalNumber(value) {
1086
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1087
+ }
1088
+ function readOptionalString(value) {
1089
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1090
+ }
1091
+ function readRecord(value) {
1092
+ return isRecord(value) ? value : void 0;
1093
+ }
1094
+ function readConfidenceBeliefNode(value) {
1095
+ if (!isRecord(value)) {
1096
+ return null;
1097
+ }
1098
+ const id = readConvexId(value._id);
1099
+ const nodeType = readOptionalString(value.nodeType);
1100
+ const projectId = readOptionalString(value.projectId);
1101
+ if (!(id && nodeType === "belief" && projectId)) {
1102
+ return null;
1103
+ }
1104
+ const node = {
1105
+ _id: id,
1106
+ nodeType,
1107
+ projectId
1108
+ };
1109
+ const confidence = readOptionalNumber(value.confidence);
1110
+ const epistemicLayer = readOptionalString(value.epistemicLayer);
1111
+ const globalId = readOptionalString(value.globalId);
1112
+ const metadata = readRecord(value.metadata);
1113
+ const opinionA = readOptionalNumber(value.opinion_a);
1114
+ const opinionB = readOptionalNumber(value.opinion_b);
1115
+ const opinionD = readOptionalNumber(value.opinion_d);
1116
+ const opinionU = readOptionalNumber(value.opinion_u);
1117
+ const predictionMeta = readRecord(value.predictionMeta);
1118
+ const publicationStatus = readOptionalString(value.publicationStatus);
1119
+ const status = readOptionalString(value.status);
1120
+ const tenantId = readOptionalString(value.tenantId);
1121
+ const topicId = readOptionalString(value.topicId);
1122
+ const tupleContradicted = readOptionalBoolean(value.tupleContradicted);
1123
+ const workspaceId = readOptionalString(value.workspaceId);
1124
+ if (confidence !== void 0) {
1125
+ node.confidence = confidence;
1126
+ }
1127
+ if (epistemicLayer !== void 0) {
1128
+ node.epistemicLayer = epistemicLayer;
1129
+ }
1130
+ if (globalId !== void 0) {
1131
+ node.globalId = globalId;
1132
+ }
1133
+ if (metadata !== void 0) {
1134
+ node.metadata = metadata;
1135
+ }
1136
+ if (opinionA !== void 0) {
1137
+ node.opinion_a = opinionA;
1138
+ }
1139
+ if (opinionB !== void 0) {
1140
+ node.opinion_b = opinionB;
1141
+ }
1142
+ if (opinionD !== void 0) {
1143
+ node.opinion_d = opinionD;
1144
+ }
1145
+ if (opinionU !== void 0) {
1146
+ node.opinion_u = opinionU;
1147
+ }
1148
+ if (predictionMeta !== void 0) {
1149
+ node.predictionMeta = predictionMeta;
1150
+ }
1151
+ if (publicationStatus !== void 0) {
1152
+ node.publicationStatus = publicationStatus;
1153
+ }
1154
+ if (status !== void 0) {
1155
+ node.status = status;
1156
+ }
1157
+ if (tenantId !== void 0) {
1158
+ node.tenantId = tenantId;
1159
+ }
1160
+ if (topicId !== void 0) {
1161
+ node.topicId = topicId;
1162
+ }
1163
+ if (tupleContradicted !== void 0) {
1164
+ node.tupleContradicted = tupleContradicted;
1165
+ }
1166
+ if (workspaceId !== void 0) {
1167
+ node.workspaceId = workspaceId;
1168
+ }
1169
+ return node;
1170
+ }
1171
+ function readPropagationEdge(value) {
1172
+ if (!isRecord(value)) {
1173
+ return null;
1174
+ }
1175
+ const edgeType = readOptionalString(value.edgeType);
1176
+ if (!edgeType) {
1177
+ return null;
1178
+ }
1179
+ const edge = { edgeType };
1180
+ const fromNodeId = readConvexId(value.fromNodeId);
1181
+ const tenantId = readOptionalString(value.tenantId);
1182
+ const toNodeId = readConvexId(value.toNodeId);
1183
+ const weight = readOptionalNumber(value.weight);
1184
+ const workspaceId = readOptionalString(value.workspaceId);
1185
+ if (fromNodeId !== void 0) {
1186
+ edge.fromNodeId = fromNodeId;
1187
+ }
1188
+ if (tenantId !== void 0) {
1189
+ edge.tenantId = tenantId;
1190
+ }
1191
+ if (toNodeId !== void 0) {
1192
+ edge.toNodeId = toNodeId;
1193
+ }
1194
+ if (weight !== void 0) {
1195
+ edge.weight = weight;
1196
+ }
1197
+ if (workspaceId !== void 0) {
1198
+ edge.workspaceId = workspaceId;
1199
+ }
1200
+ return edge;
1201
+ }
1202
+ function readRowList(values, reader) {
1203
+ return values.flatMap((value) => {
1204
+ const row = reader(value);
1205
+ return row ? [row] : [];
1206
+ });
1207
+ }
1026
1208
  async function applyBeliefConfidenceChange(ctx, args) {
1027
1209
  const now = Date.now();
1028
- const node = await ctx.db.get(args.nodeId);
1210
+ const node = await requireConfidenceBeliefNode(ctx, args);
1211
+ const state = await buildConfidenceChangeState(ctx, node, args);
1212
+ await assertConfidenceScoringPolicySatisfied(ctx, args, state);
1213
+ const tupleContradictionId = await createTupleContradictionIfNeeded(
1214
+ ctx,
1215
+ args,
1216
+ node,
1217
+ state
1218
+ );
1219
+ await patchBeliefConfidenceState(ctx, args, state);
1220
+ await scheduleFirstScoringThemeEdges(ctx, args, node, state);
1221
+ const beliefConfidenceId = await insertBeliefConfidenceRecord(
1222
+ ctx,
1223
+ args,
1224
+ state,
1225
+ tupleContradictionId,
1226
+ now
1227
+ );
1228
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1229
+ nodeId: args.nodeId,
1230
+ operation: "upsert"
1231
+ });
1232
+ await insertConfidenceAudit(
1233
+ ctx,
1234
+ args,
1235
+ node,
1236
+ state,
1237
+ tupleContradictionId,
1238
+ now
1239
+ );
1240
+ await insertTupleTransitionAuditIfNeeded(
1241
+ ctx,
1242
+ args,
1243
+ node,
1244
+ state,
1245
+ tupleContradictionId,
1246
+ now
1247
+ );
1248
+ await scheduleConfidenceFollowups(ctx, args, node, state);
1249
+ return {
1250
+ nodeId: args.nodeId,
1251
+ previousConfidence: state.previousConfidence,
1252
+ newConfidence: state.derivedConfidence,
1253
+ opinion: state.nextOpinion,
1254
+ beliefConfidenceId
1255
+ };
1256
+ }
1257
+ async function requireConfidenceBeliefNode(ctx, args) {
1258
+ const node = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
1029
1259
  if (!node) {
1030
1260
  throwStructuredMutationError({
1031
1261
  message: "Node not found.",
@@ -1036,59 +1266,28 @@ async function applyBeliefConfidenceChange(ctx, args) {
1036
1266
  details: { nodeId: args.nodeId }
1037
1267
  });
1038
1268
  }
1039
- if (node.nodeType !== "belief") {
1040
- throwStructuredMutationError({
1041
- 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.`,
1042
- status: 400,
1043
- code: "INVALID_ARGUMENT",
1044
- invariantCode: "entity.no_confidence",
1045
- suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
1046
- details: { nodeId: args.nodeId, nodeType: node.nodeType }
1047
- });
1048
- }
1049
- if (!node.projectId) {
1050
- throwStructuredMutationError({
1051
- message: "Belief has no project scope.",
1052
- status: 400,
1053
- code: "MISSING_SCOPE",
1054
- invariantCode: "belief.project_required",
1055
- suggestion: "Belief must have a projectId before SL scoring can be appended.",
1056
- details: { nodeId: args.nodeId }
1057
- });
1058
- }
1059
- await requireScopeWriteAccess(
1060
- ctx,
1061
- node.projectId,
1062
- args.authenticatedUserId
1063
- );
1064
- const existingMetadata = node.metadata || {};
1269
+ await requireScopeWriteAccess(ctx, node.projectId, args.authenticatedUserId);
1270
+ return node;
1271
+ }
1272
+ async function buildConfidenceChangeState(ctx, node, args) {
1273
+ const existingMetadata = readNodeMetadata(node);
1065
1274
  const currentBeliefStatus = resolveBeliefStatus(node, existingMetadata);
1066
1275
  const confidencePolicy = await getActiveConfidencePolicy(ctx);
1067
- if (confidencePolicy.scoringMode === "after_worktree" && isPreValidationBeliefStatus(currentBeliefStatus)) {
1068
- const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
1069
- ctx,
1070
- args.nodeId
1071
- );
1072
- if (!hasCompletedWorktree) {
1073
- throwStructuredMutationError({
1074
- message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
1075
- status: 409,
1076
- code: "CONFLICT",
1077
- invariantCode: "belief.confidence_append_only",
1078
- suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
1079
- details: { nodeId: args.nodeId }
1080
- });
1081
- }
1082
- }
1083
1276
  const previousConfidence = node.confidence || 0.5;
1084
1277
  const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
1085
1278
  const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
1086
- const slB = args.belief;
1087
- const slD = args.disbelief;
1088
- const slU = args.uncertainty;
1089
- const slA = args.baseRate ?? 0.5;
1090
- const nextOpinion = { b: slB, d: slD, u: slU, a: slA };
1091
- const derivedConfidence = confidenceFromSL(slB, slD, slU, slA);
1279
+ const nextOpinion = {
1280
+ b: args.belief,
1281
+ d: args.disbelief,
1282
+ u: args.uncertainty,
1283
+ a: args.baseRate ?? 0.5
1284
+ };
1285
+ const derivedConfidence = confidenceFromSL(
1286
+ nextOpinion.b,
1287
+ nextOpinion.d,
1288
+ nextOpinion.u,
1289
+ nextOpinion.a
1290
+ );
1092
1291
  const isFirstScoring = typeof node.confidence !== "number" || !Number.isFinite(node.confidence);
1093
1292
  const previousTupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(existingMetadata.tupleContradicted) ?? detectTupleContradiction(
1094
1293
  previousOpinion,
@@ -1109,79 +1308,121 @@ async function applyBeliefConfidenceChange(ctx, args) {
1109
1308
  predictionMeta,
1110
1309
  metadata: existingMetadata
1111
1310
  });
1112
- let tupleContradictionId;
1113
- if (tupleTransition.crossedIntoTupleContradiction) {
1114
- tupleContradictionId = await ctx.runMutation(
1115
- "contradictions:create",
1116
- {
1117
- projectId: node.projectId,
1118
- topicId: node.topicId,
1119
- beliefId: args.nodeId,
1120
- beliefBId: args.nodeId,
1121
- supportingInsightIds: [],
1122
- contradictingInsightIds: [],
1123
- severity: deriveTupleContradictionSeverity(node),
1124
- source: "tuple_space",
1125
- detectionMethod: "agent",
1126
- description: tupleContradictionDescription,
1127
- createdBy: args.authenticatedUserId
1128
- }
1129
- );
1311
+ const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
1312
+ return {
1313
+ confidencePolicy,
1314
+ currentBeliefStatus,
1315
+ derivedConfidence,
1316
+ existingMetadata,
1317
+ isFirstScoring,
1318
+ newBeliefStatus,
1319
+ nextOpinion,
1320
+ previousConfidence,
1321
+ previousTupleContradicted,
1322
+ storedRationale,
1323
+ tupleContradictionDescription,
1324
+ tupleTransition
1325
+ };
1326
+ }
1327
+ function readNodeMetadata(node) {
1328
+ return node.metadata ?? {};
1329
+ }
1330
+ async function assertConfidenceScoringPolicySatisfied(ctx, args, state) {
1331
+ if (state.confidencePolicy.scoringMode !== "after_worktree" || !isPreValidationBeliefStatus(state.currentBeliefStatus)) {
1332
+ return;
1130
1333
  }
1334
+ const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
1335
+ ctx,
1336
+ args.nodeId
1337
+ );
1338
+ if (hasCompletedWorktree) {
1339
+ return;
1340
+ }
1341
+ throwStructuredMutationError({
1342
+ message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
1343
+ status: 409,
1344
+ code: "CONFLICT",
1345
+ invariantCode: "belief.confidence_append_only",
1346
+ suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
1347
+ details: { nodeId: args.nodeId }
1348
+ });
1349
+ }
1350
+ async function createTupleContradictionIfNeeded(ctx, args, node, state) {
1351
+ if (!state.tupleTransition.crossedIntoTupleContradiction) {
1352
+ return;
1353
+ }
1354
+ return await ctx.runMutation("contradictions:create", {
1355
+ projectId: node.projectId,
1356
+ topicId: node.topicId,
1357
+ beliefId: args.nodeId,
1358
+ beliefBId: args.nodeId,
1359
+ supportingInsightIds: [],
1360
+ contradictingInsightIds: [],
1361
+ severity: deriveTupleContradictionSeverity(node),
1362
+ source: "tuple_space",
1363
+ detectionMethod: "agent",
1364
+ description: state.tupleContradictionDescription,
1365
+ createdBy: args.authenticatedUserId
1366
+ });
1367
+ }
1368
+ async function patchBeliefConfidenceState(ctx, args, state) {
1131
1369
  await ctx.db.patch(args.nodeId, {
1132
- confidence: derivedConfidence,
1133
- beliefStatus: newBeliefStatus,
1134
- tupleContradicted: tupleTransition.tupleContradicted,
1135
- updatedAt: now,
1136
- // Store SL opinion fields at node level for fast access
1137
- opinion_b: slB,
1138
- opinion_d: slD,
1139
- opinion_u: slU,
1140
- opinion_a: slA,
1370
+ confidence: state.derivedConfidence,
1371
+ beliefStatus: state.newBeliefStatus,
1372
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1373
+ updatedAt: Date.now(),
1374
+ opinion_b: state.nextOpinion.b,
1375
+ opinion_d: state.nextOpinion.d,
1376
+ opinion_u: state.nextOpinion.u,
1377
+ opinion_a: state.nextOpinion.a,
1141
1378
  metadata: {
1142
- ...existingMetadata,
1143
- beliefStatus: newBeliefStatus,
1144
- slBelief: slB,
1145
- slDisbelief: slD,
1146
- slUncertainty: slU,
1147
- slBaseRate: slA,
1148
- tupleContradicted: tupleTransition.tupleContradicted
1379
+ ...state.existingMetadata,
1380
+ beliefStatus: state.newBeliefStatus,
1381
+ slBelief: state.nextOpinion.b,
1382
+ slDisbelief: state.nextOpinion.d,
1383
+ slUncertainty: state.nextOpinion.u,
1384
+ slBaseRate: state.nextOpinion.a,
1385
+ tupleContradicted: state.tupleTransition.tupleContradicted
1149
1386
  }
1150
1387
  });
1151
- if (isFirstScoring) {
1152
- const nodeTopicId = node.topicId;
1153
- const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
1154
- "by_topic",
1155
- (q) => q.eq("topicId", nodeTopicId || node.projectId)
1156
- ).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
1157
- for (const theme of themeNodes) {
1158
- if (theme.globalId && node.globalId) {
1159
- await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
1160
- globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
1161
- fromGlobalId: node.globalId,
1162
- toGlobalId: theme.globalId,
1163
- edgeType: "relates_to_thesis",
1164
- weight: derivedConfidence,
1165
- createdBy: args.authenticatedUserId,
1166
- topicId: String(node.projectId),
1167
- fromNodeType: "belief",
1168
- toNodeType: "theme",
1169
- fromLayer: "L3",
1170
- toLayer: "L3"
1171
- });
1172
- }
1388
+ }
1389
+ async function scheduleFirstScoringThemeEdges(ctx, args, node, state) {
1390
+ if (!state.isFirstScoring) {
1391
+ return;
1392
+ }
1393
+ const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
1394
+ "by_topic",
1395
+ (q) => q.eq("topicId", node.topicId || node.projectId)
1396
+ ).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
1397
+ for (const theme of themeNodes) {
1398
+ if (!(theme.globalId && node.globalId)) {
1399
+ continue;
1173
1400
  }
1401
+ await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
1402
+ globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
1403
+ fromGlobalId: node.globalId,
1404
+ toGlobalId: theme.globalId,
1405
+ edgeType: "relates_to_thesis",
1406
+ weight: state.derivedConfidence,
1407
+ createdBy: args.authenticatedUserId,
1408
+ topicId: String(node.projectId),
1409
+ fromNodeType: "belief",
1410
+ toNodeType: "theme",
1411
+ fromLayer: "L3",
1412
+ toLayer: "L3"
1413
+ });
1174
1414
  }
1175
- const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
1176
- const beliefConfidenceId = await ctx.db.insert("beliefConfidence", {
1415
+ }
1416
+ async function insertBeliefConfidenceRecord(ctx, args, state, tupleContradictionId, now) {
1417
+ return await ctx.db.insert("beliefConfidence", {
1177
1418
  ...buildBeliefConfidenceRow({
1178
1419
  beliefId: args.nodeId,
1179
- belief: slB,
1180
- disbelief: slD,
1181
- uncertainty: slU,
1182
- baseRate: slA,
1420
+ belief: state.nextOpinion.b,
1421
+ disbelief: state.nextOpinion.d,
1422
+ uncertainty: state.nextOpinion.u,
1423
+ baseRate: state.nextOpinion.a,
1183
1424
  trigger: args.trigger,
1184
- rationale: storedRationale,
1425
+ rationale: state.storedRationale,
1185
1426
  assessedBy: args.authenticatedUserId,
1186
1427
  assessedAt: now,
1187
1428
  slOperator: args.slOperator,
@@ -1190,25 +1431,23 @@ async function applyBeliefConfidenceChange(ctx, args) {
1190
1431
  triggeringWorktreeId: args.triggeringWorktreeId
1191
1432
  })
1192
1433
  });
1193
- await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1194
- nodeId: args.nodeId,
1195
- operation: "upsert"
1196
- });
1434
+ }
1435
+ async function insertConfidenceAudit(ctx, args, node, state, tupleContradictionId, now) {
1197
1436
  await ctx.db.insert("epistemicAudit", {
1198
1437
  entityType: "belief",
1199
1438
  entityId: args.nodeId,
1200
1439
  changeType: "confidence_changed",
1201
1440
  previousState: {
1202
- confidence: previousConfidence,
1203
- tupleContradicted: previousTupleContradicted
1441
+ confidence: state.previousConfidence,
1442
+ tupleContradicted: state.previousTupleContradicted
1204
1443
  },
1205
1444
  newState: {
1206
- opinion: nextOpinion,
1207
- confidence: derivedConfidence,
1445
+ opinion: state.nextOpinion,
1446
+ confidence: state.derivedConfidence,
1208
1447
  trigger: args.trigger,
1209
- rationale: storedRationale,
1210
- tupleContradicted: tupleTransition.tupleContradicted,
1211
- tupleContradictionPolicy: tupleTransition.policy,
1448
+ rationale: state.storedRationale,
1449
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1450
+ tupleContradictionPolicy: state.tupleTransition.policy,
1212
1451
  ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1213
1452
  },
1214
1453
  changedBy: args.authenticatedUserId,
@@ -1217,28 +1456,39 @@ async function applyBeliefConfidenceChange(ctx, args) {
1217
1456
  projectId: node.projectId,
1218
1457
  topicId: node.topicId
1219
1458
  });
1220
- if (tupleTransition.crossedIntoTupleContradiction || tupleTransition.crossedOutOfTupleContradiction) {
1221
- await ctx.db.insert("epistemicAudit", {
1222
- entityType: "belief",
1223
- entityId: args.nodeId,
1224
- changeType: "updated",
1225
- previousState: { tupleContradicted: previousTupleContradicted },
1226
- newState: {
1227
- tupleContradicted: tupleTransition.tupleContradicted,
1228
- action: tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
1229
- opinion: nextOpinion,
1230
- tupleContradictionPolicy: tupleTransition.policy,
1231
- ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1232
- },
1233
- 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.`,
1234
- changedBy: args.authenticatedUserId,
1235
- isAgent: false,
1236
- changedAt: now,
1237
- projectId: node.projectId,
1238
- topicId: node.topicId
1239
- });
1459
+ }
1460
+ async function insertTupleTransitionAuditIfNeeded(ctx, args, node, state, tupleContradictionId, now) {
1461
+ if (!(state.tupleTransition.crossedIntoTupleContradiction || state.tupleTransition.crossedOutOfTupleContradiction)) {
1462
+ return;
1240
1463
  }
1241
- if (Math.abs(derivedConfidence - previousConfidence) >= 0.15) {
1464
+ await ctx.db.insert("epistemicAudit", {
1465
+ entityType: "belief",
1466
+ entityId: args.nodeId,
1467
+ changeType: "updated",
1468
+ previousState: { tupleContradicted: state.previousTupleContradicted },
1469
+ newState: {
1470
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1471
+ action: state.tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
1472
+ opinion: state.nextOpinion,
1473
+ tupleContradictionPolicy: state.tupleTransition.policy,
1474
+ ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1475
+ },
1476
+ rationale: tupleAuditRationale(state),
1477
+ changedBy: args.authenticatedUserId,
1478
+ isAgent: false,
1479
+ changedAt: now,
1480
+ projectId: node.projectId,
1481
+ topicId: node.topicId
1482
+ });
1483
+ }
1484
+ function tupleAuditRationale(state) {
1485
+ if (state.tupleTransition.crossedIntoTupleContradiction) {
1486
+ return state.tupleContradictionDescription;
1487
+ }
1488
+ return `Tuple-space contradiction cleared: b=${state.nextOpinion.b.toFixed(2)}, d=${state.nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`;
1489
+ }
1490
+ async function scheduleConfidenceFollowups(ctx, args, node, state) {
1491
+ if (Math.abs(state.derivedConfidence - state.previousConfidence) >= 0.15) {
1242
1492
  await ctx.scheduler.runAfter(
1243
1493
  5e3,
1244
1494
  internal.bi.contradictionSemanticDetector.scanAffectedBeliefs,
@@ -1255,13 +1505,6 @@ async function applyBeliefConfidenceChange(ctx, args) {
1255
1505
  { nodeId: args.nodeId }
1256
1506
  );
1257
1507
  }
1258
- return {
1259
- nodeId: args.nodeId,
1260
- previousConfidence,
1261
- newConfidence: derivedConfidence,
1262
- opinion: { b: slB, d: slD, u: slU, a: slA },
1263
- beliefConfidenceId
1264
- };
1265
1508
  }
1266
1509
  function propagationPressureLabel(edgeType, weight) {
1267
1510
  if (edgeType === "contradicts" || edgeType === "refutes") {
@@ -1289,7 +1532,7 @@ var propagateConfidenceChange = internalMutation({
1289
1532
  args.opinion_u,
1290
1533
  args.opinion_a
1291
1534
  );
1292
- const sourceNode = await ctx.db.get(args.nodeId);
1535
+ const sourceNode = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
1293
1536
  const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
1294
1537
  ctx,
1295
1538
  sourceNode
@@ -1298,16 +1541,20 @@ var propagateConfidenceChange = internalMutation({
1298
1541
  sourceNodeId: args.nodeId,
1299
1542
  sourceOpinion,
1300
1543
  sourceScope,
1301
- queryEdges: async ({ nodeId, spec, direction }) => {
1302
- return await ctx.db.query("epistemicEdges").withIndex(
1544
+ queryEdges: async ({ nodeId, spec, direction }) => readRowList(
1545
+ await ctx.db.query("epistemicEdges").withIndex(
1303
1546
  direction === "outgoing" ? "by_from_type" : "by_to_type",
1304
1547
  (q) => direction === "outgoing" ? q.eq("fromNodeId", nodeId).eq("edgeType", spec.edgeType) : q.eq("toNodeId", nodeId).eq("edgeType", spec.edgeType)
1305
- ).collect();
1306
- },
1307
- getNode: async (nodeId) => await ctx.db.get(nodeId)
1548
+ ).collect(),
1549
+ readPropagationEdge
1550
+ ),
1551
+ getNode: async (nodeId) => readConfidenceBeliefNode(await ctx.db.get(nodeId))
1308
1552
  });
1309
1553
  for (const dispatch of dispatches) {
1310
- const pressureLabel = propagationPressureLabel(dispatch.edgeType, dispatch.weight);
1554
+ const pressureLabel = propagationPressureLabel(
1555
+ dispatch.edgeType,
1556
+ dispatch.weight
1557
+ );
1311
1558
  await applyBeliefConfidenceChange(ctx, {
1312
1559
  nodeId: dispatch.targetNodeId,
1313
1560
  belief: dispatch.opinion.b,