@lucern/graph-primitives 1.0.29 → 1.0.31

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,614 +1,201 @@
1
- import { v } from 'convex/values';
2
- import { requireScopeWriteAccess, checkProjectAccess } from '@lucern/access-control/access';
1
+ import { checkProjectAccess, requireScopeWriteAccess } from '@lucern/access-control/access';
3
2
  import { getCurrentUserId } from '@lucern/access-control/auth';
4
3
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
5
- import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, hasProjectedOpinionChanged, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, deriveContractModulationPlan, deriveContractStatus, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, readOpinionFromRecord, parseEvidentialEvaluatorConfig, compareMetricValue, buildEvidentialRationale, parseMetricCheckerConfig, getEvaluatorInputRecord, pickFiniteNumber, resolveComparisonResult, buildComparisonRationale, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, parseMarketIndexComparatorConfig, createInheritedContractRecord } from '@lucern/confidence';
6
- import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
4
+ import { v } from 'convex/values';
5
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
6
+ import { componentsGeneric, internalMutationGeneric, queryGeneric, mutationGeneric } from 'convex/server';
7
+ import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, deriveContractModulationPlan, deriveContractStatus, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, readOpinionFromRecord, parseEvidentialEvaluatorConfig, compareMetricValue, resolveComparisonResult, buildEvidentialRationale, parseMetricCheckerConfig, getEvaluatorInputRecord, pickFiniteNumber, buildComparisonRationale, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, parseMarketIndexComparatorConfig, hasProjectedOpinionChanged, createInheritedContractRecord } from '@lucern/confidence';
7
8
  import '@lucern/access-control/audience';
8
- import { componentsGeneric, internalMutationGeneric, anyApi, queryGeneric, mutationGeneric } from 'convex/server';
9
+ import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
9
10
  import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
10
11
  import { generateGlobalId } from '@lucern/contracts/ids';
11
12
 
12
13
  // src/epistemicContracts.handlers.ts
14
+ var unsafeApi = unsafeConvexAnyApi(
15
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
16
+ );
17
+ var api = unsafeApi;
18
+ componentsGeneric();
19
+ var internal = unsafeApi;
20
+ var internalMutation = internalMutationGeneric;
21
+ var mutation = mutationGeneric;
22
+ var query = queryGeneric;
13
23
 
14
- // src/epistemicContracts.metrics.ts
15
- var ACTIVE_CONTRADICTION_STATUSES = /* @__PURE__ */ new Set([
16
- "unresolved",
17
- "investigating",
18
- "accepted_as_permanent"
19
- ]);
20
- var DEPENDENT_EDGE_TYPES = /* @__PURE__ */ new Set([
21
- "depends_on"
22
- ]);
23
- function classifyContradictionStatus(status) {
24
- if (typeof status !== "string") {
25
- return "active";
24
+ // src/debug.ts
25
+ function isGraphPrimitiveDebugEnabled() {
26
+ const env = globalThis.process?.env;
27
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
28
+ }
29
+ function debugGraphPrimitiveFallback(message, context) {
30
+ if (!isGraphPrimitiveDebugEnabled()) {
31
+ return;
26
32
  }
27
- if (ACTIVE_CONTRADICTION_STATUSES.has(status)) {
33
+ console.debug(message, context ?? {});
34
+ }
35
+
36
+ // src/beliefLifecycle.ts
37
+ var BELIEF_STATUS_VALUES = [
38
+ "assumption",
39
+ "hypothesis",
40
+ "active",
41
+ "superseded",
42
+ "resolved_true",
43
+ "resolved_false"
44
+ ];
45
+ function isBeliefLifecycleStatus(value) {
46
+ return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
47
+ }
48
+ function normalizeLegacyBeliefStatus(value) {
49
+ if (isBeliefLifecycleStatus(value)) {
50
+ return value;
51
+ }
52
+ if (value === "belief" || value === "established" || value === "emerging") {
28
53
  return "active";
29
54
  }
30
- if (status === "resolved_support" || status === "resolved_contra" || status === "belief_forked") {
31
- return "resolved";
55
+ if (value === "fact" || value === "confirmed") {
56
+ return "resolved_true";
32
57
  }
33
- return "resolved";
58
+ if (value === "disconfirmed" || value === "expired") {
59
+ return "resolved_false";
60
+ }
61
+ if (value === "deprecated") {
62
+ return "superseded";
63
+ }
64
+ return null;
34
65
  }
35
- function getEdgeTimestamp(edge) {
36
- if (typeof edge.updatedAt === "number") {
37
- return edge.updatedAt;
66
+ function normalizeBeliefConfidence(confidence) {
67
+ if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
68
+ return null;
38
69
  }
39
- if (typeof edge.createdAt === "number") {
40
- return edge.createdAt;
70
+ if (confidence >= 0 && confidence <= 1) {
71
+ return confidence;
41
72
  }
42
- if (typeof edge._creationTime === "number") {
43
- return edge._creationTime;
73
+ if (confidence > 1 && confidence <= 100) {
74
+ return confidence / 100;
44
75
  }
45
76
  return null;
46
77
  }
47
- async function getEvidenceLinks(ctx, beliefNodeId) {
48
- const edges = await ctx.db.query("epistemicEdges").withIndex(
49
- "by_to_type",
50
- (q) => q.eq("toNodeId", beliefNodeId).eq("edgeType", "informs")
51
- ).collect();
52
- if (edges.length === 0) {
53
- return [];
78
+ function isResolvedByConfidence(confidence) {
79
+ const normalized = normalizeBeliefConfidence(confidence);
80
+ if (normalized === null) {
81
+ return false;
54
82
  }
55
- const nodes = await Promise.all(edges.map((edge) => ctx.db.get(edge.fromNodeId)));
56
- return edges.flatMap((edge, index) => {
57
- const node = nodes[index];
58
- if (!node || node.nodeType !== "evidence" || node.status === "archived") {
59
- return [];
60
- }
61
- return [{ edge, node }];
62
- });
83
+ return normalized <= 0 || normalized >= 1;
63
84
  }
64
- function getEvidenceTags(node) {
65
- const metadata = node.metadata && typeof node.metadata === "object" ? node.metadata : null;
66
- const tags = metadata?.tags;
67
- if (!Array.isArray(tags)) {
68
- return [];
85
+ function getPredictionMetaFromMetadata(metadata) {
86
+ return metadata?.predictionMeta;
87
+ }
88
+ function resolvedPredictionStatus(predictionMeta) {
89
+ if (!predictionMeta || typeof predictionMeta !== "object") {
90
+ return null;
69
91
  }
70
- return tags.filter((tag) => typeof tag === "string");
92
+ const outcome = predictionMeta.outcome;
93
+ if (outcome === "confirmed") {
94
+ return "resolved_true";
95
+ }
96
+ if (outcome === "disconfirmed" || outcome === "expired") {
97
+ return "resolved_false";
98
+ }
99
+ return null;
71
100
  }
72
- async function computeEvidenceCountMetric(ctx, beliefNodeId) {
73
- return (await getEvidenceLinks(ctx, beliefNodeId)).length;
101
+ function shouldTreatBeliefAsResolved(opts) {
102
+ if (isResolvedByConfidence(opts.confidence)) {
103
+ const normalized = normalizeBeliefConfidence(opts.confidence);
104
+ return normalized === 0 ? "resolved_false" : "resolved_true";
105
+ }
106
+ const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
107
+ if (directPredictionStatus) {
108
+ return directPredictionStatus;
109
+ }
110
+ const metadataPredictionStatus = resolvedPredictionStatus(
111
+ getPredictionMetaFromMetadata(opts.metadata)
112
+ );
113
+ if (metadataPredictionStatus) {
114
+ return metadataPredictionStatus;
115
+ }
116
+ return null;
74
117
  }
75
- async function computeTaggedEvidenceCount(args) {
76
- const expectedTag = args.caseSensitive ? args.tag : args.tag.toLowerCase();
77
- const matchedEvidenceIds = (await getEvidenceLinks(args.ctx, args.beliefNodeId)).filter(
78
- ({ node }) => getEvidenceTags(node).some(
79
- (tag) => (args.caseSensitive ? tag : tag.toLowerCase()) === expectedTag
80
- )
81
- ).map(({ node }) => String(node._id));
82
- return {
83
- count: matchedEvidenceIds.length,
84
- matchedEvidenceIds
85
- };
118
+ function resolveBeliefLifecycleStatus(opts) {
119
+ const resolvedStatus = shouldTreatBeliefAsResolved(opts);
120
+ if (resolvedStatus) {
121
+ return resolvedStatus;
122
+ }
123
+ const direct = opts.beliefStatus;
124
+ const normalizedDirect = normalizeLegacyBeliefStatus(direct);
125
+ if (normalizedDirect) {
126
+ const normalized = normalizeBeliefConfidence(opts.confidence);
127
+ if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
128
+ return "active";
129
+ }
130
+ return normalizedDirect;
131
+ }
132
+ const metaStatus = opts.metadata?.beliefStatus;
133
+ const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
134
+ if (normalizedMetaStatus) {
135
+ const normalized = normalizeBeliefConfidence(opts.confidence);
136
+ if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
137
+ return "active";
138
+ }
139
+ return normalizedMetaStatus;
140
+ }
141
+ return "assumption";
86
142
  }
87
- async function computeContradictionCounts(ctx, beliefNodeId) {
88
- const contradictions = await ctx.db.query("contradictions").withIndex("by_beliefId", (q) => q.eq("beliefId", beliefNodeId)).collect();
89
- return contradictions.reduce(
90
- (counts, contradiction) => {
91
- const status = contradiction.resolutionStatus ?? contradiction.status ?? "unresolved";
92
- if (classifyContradictionStatus(status) === "active") {
93
- counts.activeCount += 1;
94
- } else {
95
- counts.resolvedCount += 1;
96
- }
97
- return counts;
98
- },
99
- { activeCount: 0, resolvedCount: 0 }
100
- );
143
+ function isPreValidationBeliefStatus(status) {
144
+ return status === "assumption" || status === "hypothesis";
101
145
  }
102
- async function computeEvidenceFreshness(ctx, beliefNodeId, now = Date.now()) {
103
- const timestamps = (await getEvidenceLinks(ctx, beliefNodeId)).map(({ edge }) => getEdgeTimestamp(edge)).filter((value) => value !== null);
104
- if (timestamps.length === 0) {
105
- return {
106
- newestAgeMs: null,
107
- oldestAgeMs: null,
108
- newestEdgeAt: null,
109
- oldestEdgeAt: null,
110
- edgeCount: 0
111
- };
146
+ function promoteBeliefStatusAfterScoring(status, opts) {
147
+ const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
148
+ if (resolvedStatus) {
149
+ return resolvedStatus;
150
+ }
151
+ if (isPreValidationBeliefStatus(status)) {
152
+ return "active";
153
+ }
154
+ return status;
155
+ }
156
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
157
+ async function resolveTopicNodeScopeOrNull(ctx, ref) {
158
+ if (!ctx?.db || typeof ctx.db.query !== "function") {
159
+ return null;
160
+ }
161
+ let node = null;
162
+ try {
163
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
164
+ if (byGlobalId && byGlobalId.nodeType === "topic") {
165
+ node = byGlobalId;
166
+ }
167
+ } catch (error) {
168
+ debugGraphPrimitiveFallback(
169
+ "[topicScope] topic-node scope lookup by globalId failed",
170
+ { error, ref }
171
+ );
172
+ }
173
+ if (!node) {
174
+ return null;
175
+ }
176
+ const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
177
+ if (!scopeKey) {
178
+ return null;
112
179
  }
113
- const newestEdgeAt = Math.max(...timestamps);
114
- const oldestEdgeAt = Math.min(...timestamps);
115
180
  return {
116
- newestAgeMs: Math.max(0, now - newestEdgeAt),
117
- oldestAgeMs: Math.max(0, now - oldestEdgeAt),
118
- newestEdgeAt,
119
- oldestEdgeAt,
120
- edgeCount: timestamps.length
181
+ topicId: scopeKey,
182
+ projectId: asMappedProjectId(node),
183
+ source: "topic_node"
121
184
  };
122
185
  }
123
- async function computeDependentBeliefCount(ctx, beliefNodeId) {
124
- const incomingEdges = await ctx.db.query("epistemicEdges").withIndex("by_to", (q) => q.eq("toNodeId", beliefNodeId)).collect();
125
- const dependencyEdges = incomingEdges.filter(
126
- (edge) => DEPENDENT_EDGE_TYPES.has(edge.edgeType)
127
- );
128
- if (dependencyEdges.length === 0) {
129
- return 0;
186
+ function asMappedProjectId(topic) {
187
+ if (!topic) {
188
+ return;
130
189
  }
131
- const dependentBeliefs = await Promise.all(
132
- dependencyEdges.map((edge) => ctx.db.get(edge.fromNodeId))
190
+ const directLegacyProjectId = normalizeScopeValue(
191
+ topic[LEGACY_SCOPE_FIELD]
133
192
  );
134
- const uniqueBeliefIds = /* @__PURE__ */ new Set();
135
- for (const node of dependentBeliefs) {
136
- if (node && node.nodeType === "belief" && node.status !== "archived" && node.status !== "deleted") {
137
- uniqueBeliefIds.add(String(node._id));
138
- }
193
+ if (directLegacyProjectId) {
194
+ return directLegacyProjectId;
139
195
  }
140
- return uniqueBeliefIds.size;
141
- }
142
- async function snapshotEvidentialMetric(args) {
143
- switch (args.metric) {
144
- case "evidence_count": {
145
- const count = await computeEvidenceCountMetric(args.ctx, args.beliefNodeId);
146
- return {
147
- metric: args.metric,
148
- value: count,
149
- data: { evidenceCount: count }
150
- };
151
- }
152
- case "contradiction_status": {
153
- const counts = await computeContradictionCounts(args.ctx, args.beliefNodeId);
154
- return {
155
- metric: args.metric,
156
- value: counts.activeCount,
157
- data: counts
158
- };
159
- }
160
- case "edge_freshness": {
161
- const freshness = await computeEvidenceFreshness(
162
- args.ctx,
163
- args.beliefNodeId,
164
- args.now
165
- );
166
- return {
167
- metric: args.metric,
168
- value: freshness.newestAgeMs,
169
- data: freshness
170
- };
171
- }
172
- case "dependent_count": {
173
- const count = await computeDependentBeliefCount(args.ctx, args.beliefNodeId);
174
- return {
175
- metric: args.metric,
176
- value: count,
177
- data: { dependentCount: count }
178
- };
179
- }
180
- default:
181
- return {
182
- metric: args.metric,
183
- value: null,
184
- data: {}
185
- };
186
- }
187
- }
188
- async function evaluateBuiltInEvidentialContract(args) {
189
- const config = parseEvidentialEvaluatorConfig(args.contract.condition.evaluatorConfig);
190
- const snapshot = await snapshotEvidentialMetric({
191
- ctx: args.ctx,
192
- beliefNodeId: args.belief._id,
193
- metric: config.metric,
194
- now: args.now
195
- });
196
- const comparisonSatisfied = snapshot.value !== null && compareMetricValue(config.operator, snapshot.value, config.threshold);
197
- const result = args.contract.direction === "falsifies" ? comparisonSatisfied ? "disconfirmed" : "confirmed" : comparisonSatisfied ? "confirmed" : "disconfirmed";
198
- return {
199
- result,
200
- rationale: buildEvidentialRationale({
201
- config,
202
- snapshot,
203
- comparisonSatisfied,
204
- result
205
- }),
206
- data: {
207
- ...snapshot.data,
208
- metric: config.metric,
209
- observedValue: snapshot.value,
210
- operator: config.operator,
211
- threshold: config.threshold,
212
- action: config.action ?? "append_sl_scoring",
213
- actionParams: config.actionParams
214
- }
215
- };
216
- }
217
- async function evaluateMetricCheckerContract(args) {
218
- const config = parseMetricCheckerConfig(args.contract.condition.evaluatorConfig);
219
- const input = getEvaluatorInputRecord(args.inputData, "metricData");
220
- const metric = typeof input.metric === "string" && input.metric.length > 0 ? input.metric : config.metric;
221
- const observedValue = pickFiniteNumber(input, [
222
- "observedValue",
223
- "currentValue",
224
- "metricValue",
225
- "value"
226
- ]) ?? config.observedValue ?? config.currentValue ?? config.metricValue ?? null;
227
- if (observedValue === null) {
228
- return {
229
- result: "inconclusive",
230
- rationale: `metric_checker is awaiting data for ${metric ?? args.contract.condition.expression}.`,
231
- data: {
232
- metric,
233
- observedValue: null,
234
- operator: config.operator,
235
- threshold: config.threshold,
236
- unit: config.unit
237
- }
238
- };
239
- }
240
- const comparisonSatisfied = compareMetricValue(
241
- config.operator,
242
- observedValue,
243
- config.threshold
244
- );
245
- const result = resolveComparisonResult(args.contract.direction, comparisonSatisfied);
246
- return {
247
- result,
248
- rationale: buildComparisonRationale({
249
- label: metric ?? "metric",
250
- observedValue,
251
- operator: config.operator,
252
- threshold: config.threshold,
253
- comparisonSatisfied,
254
- result,
255
- unit: config.unit
256
- }),
257
- data: {
258
- metric,
259
- observedValue,
260
- operator: config.operator,
261
- threshold: config.threshold,
262
- unit: config.unit
263
- }
264
- };
265
- }
266
- async function evaluateReferenceCheckCounterContract(args) {
267
- const config = parseReferenceCheckCounterConfig(args.contract.condition.evaluatorConfig);
268
- const input = getEvaluatorInputRecord(args.inputData, "referenceCheckData");
269
- const tag = typeof input.tag === "string" && input.tag.trim().length > 0 ? input.tag.trim() : config.tag;
270
- const snapshot = await computeTaggedEvidenceCount({
271
- ctx: args.ctx,
272
- beliefNodeId: args.belief._id,
273
- tag,
274
- caseSensitive: config.caseSensitive
275
- });
276
- const comparisonSatisfied = compareMetricValue(
277
- config.operator,
278
- snapshot.count,
279
- config.threshold
280
- );
281
- const result = resolveComparisonResult(args.contract.direction, comparisonSatisfied);
282
- return {
283
- result,
284
- rationale: buildComparisonRationale({
285
- label: `reference checks tagged "${tag}"`,
286
- observedValue: snapshot.count,
287
- operator: config.operator,
288
- threshold: config.threshold,
289
- comparisonSatisfied,
290
- result
291
- }),
292
- data: {
293
- tag,
294
- observedValue: snapshot.count,
295
- referenceCheckCount: snapshot.count,
296
- matchedEvidenceIds: snapshot.matchedEvidenceIds,
297
- operator: config.operator,
298
- threshold: config.threshold,
299
- caseSensitive: config.caseSensitive ?? false
300
- }
301
- };
302
- }
303
- async function evaluateTemporalDeadlineContract(args) {
304
- if (typeof args.contract.deadline !== "number" || !Number.isFinite(args.contract.deadline)) {
305
- throw new Error(
306
- "temporal_deadline requires contract.deadline to be set to a finite timestamp."
307
- );
308
- }
309
- const config = parseTemporalDeadlineConfig(args.contract.condition.evaluatorConfig);
310
- const input = getEvaluatorInputRecord(args.inputData, "temporalData");
311
- const label = (typeof input.label === "string" && input.label.length > 0 ? input.label : config.label) ?? args.contract.title ?? args.contract.condition.expression;
312
- const completedAt = pickFiniteNumber(input, [
313
- "completedAt",
314
- "observedAt",
315
- "satisfiedAt",
316
- "achievedAt"
317
- ]) ?? config.completedAt ?? config.observedAt ?? config.satisfiedAt ?? config.achievedAt;
318
- const completed = input.completed === true || config.completed === true || completedAt !== void 0;
319
- if (completed) {
320
- if (completedAt !== void 0 && completedAt > args.contract.deadline) {
321
- return {
322
- result: "expired",
323
- rationale: `${label} completed at ${completedAt}, after deadline ${args.contract.deadline}.`,
324
- data: {
325
- label,
326
- deadline: args.contract.deadline,
327
- completed: true,
328
- completedAt,
329
- missedDeadline: true,
330
- overdueByMs: completedAt - args.contract.deadline
331
- }
332
- };
333
- }
334
- const result = args.contract.direction === "falsifies" ? "disconfirmed" : "confirmed";
335
- return {
336
- result,
337
- rationale: `${label} completed before deadline ${args.contract.deadline}.`,
338
- data: {
339
- label,
340
- deadline: args.contract.deadline,
341
- completed: true,
342
- completedAt: completedAt ?? null,
343
- missedDeadline: false
344
- }
345
- };
346
- }
347
- if (args.now > args.contract.deadline) {
348
- return {
349
- result: "expired",
350
- rationale: `${label} missed deadline ${args.contract.deadline}; temporal contract expired.`,
351
- data: {
352
- label,
353
- deadline: args.contract.deadline,
354
- completed: false,
355
- overdueByMs: args.now - args.contract.deadline
356
- }
357
- };
358
- }
359
- return {
360
- result: "inconclusive",
361
- rationale: `${label} is still before deadline ${args.contract.deadline}; awaiting outcome.`,
362
- data: {
363
- label,
364
- deadline: args.contract.deadline,
365
- completed: false,
366
- timeRemainingMs: args.contract.deadline - args.now
367
- }
368
- };
369
- }
370
- async function evaluateMarketIndexComparatorContract(args) {
371
- const config = parseMarketIndexComparatorConfig(args.contract.condition.evaluatorConfig);
372
- const input = getEvaluatorInputRecord(args.inputData, "marketIndexData");
373
- const subject = typeof input.subject === "string" && input.subject.length > 0 ? input.subject : config.subject;
374
- const benchmark = typeof input.benchmark === "string" && input.benchmark.length > 0 ? input.benchmark : config.benchmark;
375
- const subjectValue = pickFiniteNumber(input, ["subjectValue", "primaryValue", "leftValue"]) ?? config.subjectValue ?? config.primaryValue ?? null;
376
- const benchmarkValue = pickFiniteNumber(input, ["benchmarkValue", "comparisonValue", "rightValue"]) ?? config.benchmarkValue ?? config.comparisonValue ?? null;
377
- if (subjectValue === null || benchmarkValue === null) {
378
- return {
379
- result: "inconclusive",
380
- rationale: "market_index_comparator is awaiting both subject and benchmark values.",
381
- data: {
382
- subject,
383
- subjectValue,
384
- benchmark,
385
- benchmarkValue,
386
- operator: config.operator,
387
- threshold: config.threshold
388
- }
389
- };
390
- }
391
- if (benchmarkValue === 0) {
392
- throw new Error(
393
- "market_index_comparator cannot compare against a zero benchmark value."
394
- );
395
- }
396
- const differentialPercent = (subjectValue - benchmarkValue) / Math.abs(benchmarkValue) * 100;
397
- const comparisonSatisfied = compareMetricValue(
398
- config.operator,
399
- differentialPercent,
400
- config.threshold
401
- );
402
- const result = resolveComparisonResult(args.contract.direction, comparisonSatisfied);
403
- return {
404
- result,
405
- rationale: buildComparisonRationale({
406
- label: `${subject ?? "subject"} vs ${benchmark ?? "benchmark"} differential`,
407
- observedValue: differentialPercent,
408
- operator: config.operator,
409
- threshold: config.threshold,
410
- comparisonSatisfied,
411
- result,
412
- unit: "%"
413
- }),
414
- data: {
415
- subject,
416
- subjectValue,
417
- benchmark,
418
- benchmarkValue,
419
- differentialPercent,
420
- operator: config.operator,
421
- threshold: config.threshold
422
- }
423
- };
424
- }
425
- var METRIC_COMPARATOR_EVALUATOR_NAMES = {
426
- evidentialAliases: /* @__PURE__ */ new Set(["evidential", "built_in_evidential", "builtin_evidential"]),
427
- metricChecker: "metric_checker",
428
- referenceCheckCounter: "reference_check_counter",
429
- temporalDeadline: "temporal_deadline",
430
- marketIndexComparator: "market_index_comparator"
431
- };
432
-
433
- // src/beliefLifecycle.ts
434
- var BELIEF_STATUS_VALUES = [
435
- "assumption",
436
- "hypothesis",
437
- "active",
438
- "superseded",
439
- "resolved_true",
440
- "resolved_false"
441
- ];
442
- function isBeliefLifecycleStatus(value) {
443
- return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
444
- }
445
- function normalizeLegacyBeliefStatus(value) {
446
- if (isBeliefLifecycleStatus(value)) {
447
- return value;
448
- }
449
- if (value === "belief" || value === "established" || value === "emerging") {
450
- return "active";
451
- }
452
- if (value === "fact" || value === "confirmed") {
453
- return "resolved_true";
454
- }
455
- if (value === "disconfirmed" || value === "expired") {
456
- return "resolved_false";
457
- }
458
- if (value === "deprecated") {
459
- return "superseded";
460
- }
461
- return null;
462
- }
463
- function normalizeBeliefConfidence(confidence) {
464
- if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
465
- return null;
466
- }
467
- if (confidence >= 0 && confidence <= 1) {
468
- return confidence;
469
- }
470
- if (confidence > 1 && confidence <= 100) {
471
- return confidence / 100;
472
- }
473
- return null;
474
- }
475
- function isResolvedByConfidence(confidence) {
476
- const normalized = normalizeBeliefConfidence(confidence);
477
- if (normalized === null) {
478
- return false;
479
- }
480
- return normalized <= 0 || normalized >= 1;
481
- }
482
- function getPredictionMetaFromMetadata(metadata) {
483
- return metadata?.predictionMeta;
484
- }
485
- function resolvedPredictionStatus(predictionMeta) {
486
- if (!predictionMeta || typeof predictionMeta !== "object") {
487
- return null;
488
- }
489
- const outcome = predictionMeta.outcome;
490
- if (outcome === "confirmed") {
491
- return "resolved_true";
492
- }
493
- if (outcome === "disconfirmed" || outcome === "expired") {
494
- return "resolved_false";
495
- }
496
- return null;
497
- }
498
- function shouldTreatBeliefAsResolved(opts) {
499
- if (isResolvedByConfidence(opts.confidence)) {
500
- const normalized = normalizeBeliefConfidence(opts.confidence);
501
- return normalized === 0 ? "resolved_false" : "resolved_true";
502
- }
503
- const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
504
- if (directPredictionStatus) {
505
- return directPredictionStatus;
506
- }
507
- const metadataPredictionStatus = resolvedPredictionStatus(
508
- getPredictionMetaFromMetadata(opts.metadata)
509
- );
510
- if (metadataPredictionStatus) {
511
- return metadataPredictionStatus;
512
- }
513
- return null;
514
- }
515
- function resolveBeliefLifecycleStatus(opts) {
516
- const resolvedStatus = shouldTreatBeliefAsResolved(opts);
517
- if (resolvedStatus) {
518
- return resolvedStatus;
519
- }
520
- const direct = opts.beliefStatus;
521
- const normalizedDirect = normalizeLegacyBeliefStatus(direct);
522
- if (normalizedDirect) {
523
- const normalized = normalizeBeliefConfidence(opts.confidence);
524
- if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
525
- return "active";
526
- }
527
- return normalizedDirect;
528
- }
529
- const metaStatus = opts.metadata?.beliefStatus;
530
- const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
531
- if (normalizedMetaStatus) {
532
- const normalized = normalizeBeliefConfidence(opts.confidence);
533
- if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
534
- return "active";
535
- }
536
- return normalizedMetaStatus;
537
- }
538
- return "assumption";
539
- }
540
- function isPreValidationBeliefStatus(status) {
541
- return status === "assumption" || status === "hypothesis";
542
- }
543
- function promoteBeliefStatusAfterScoring(status, opts) {
544
- const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
545
- if (resolvedStatus) {
546
- return resolvedStatus;
547
- }
548
- if (isPreValidationBeliefStatus(status)) {
549
- return "active";
550
- }
551
- return status;
552
- }
553
- var api = anyApi;
554
- componentsGeneric();
555
- var internal = anyApi;
556
- var internalMutation = internalMutationGeneric;
557
- var mutation = mutationGeneric;
558
- var query = queryGeneric;
559
-
560
- // src/debug.ts
561
- function isGraphPrimitiveDebugEnabled() {
562
- const env = globalThis.process?.env;
563
- return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
564
- }
565
- function debugGraphPrimitiveFallback(message, context) {
566
- if (!isGraphPrimitiveDebugEnabled()) {
567
- return;
568
- }
569
- console.debug(message, context ?? {});
570
- }
571
- var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
572
- async function resolveTopicNodeScopeOrNull(ctx, ref) {
573
- if (!ctx?.db || typeof ctx.db.query !== "function") {
574
- return null;
575
- }
576
- let node = null;
577
- try {
578
- const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
579
- if (byGlobalId && byGlobalId.nodeType === "topic") {
580
- node = byGlobalId;
581
- }
582
- } catch (error) {
583
- debugGraphPrimitiveFallback(
584
- "[topicScope] topic-node scope lookup by globalId failed",
585
- { error, ref }
586
- );
587
- }
588
- if (!node) {
589
- return null;
590
- }
591
- const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
592
- if (!scopeKey) {
593
- return null;
594
- }
595
- return {
596
- topicId: scopeKey,
597
- projectId: asMappedProjectId(node),
598
- source: "topic_node"
599
- };
600
- }
601
- function asMappedProjectId(topic) {
602
- if (!topic) {
603
- return;
604
- }
605
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
606
- if (directLegacyProjectId) {
607
- return directLegacyProjectId;
608
- }
609
- const metadata = topic.metadata || {};
610
- const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
611
- return candidate ? candidate : void 0;
196
+ const metadata = topic.metadata || {};
197
+ const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
198
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
612
199
  }
613
200
  function normalizeScopeValue(value) {
614
201
  if (typeof value !== "string") {
@@ -633,8 +220,9 @@ function pickPrimaryTopic(candidates) {
633
220
  })[0];
634
221
  }
635
222
  async function findTopicsByScopeAlias(ctx, scopeId) {
223
+ const query2 = ctx.db.query("topics");
636
224
  try {
637
- return await ctx.db.query("topics").withIndex(
225
+ return await query2.withIndex(
638
226
  "by_graph_scope_project",
639
227
  (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
640
228
  ).collect();
@@ -646,7 +234,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
646
234
  scopeId
647
235
  }
648
236
  );
649
- const topics = await ctx.db.query("topics").collect();
237
+ const topics = await query2.collect();
650
238
  return topics.filter((topic) => {
651
239
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
652
240
  const mappedProjectId = asMappedProjectId(topic);
@@ -691,148 +279,126 @@ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
691
279
  );
692
280
  return null;
693
281
  }
694
- }
695
- async function resolveInheritedWorkspaceScope(ctx, topic) {
696
- const MAX_DEPTH = 10;
697
- let tenantId = normalizeScopeValue(topic.tenantId);
698
- let workspaceId = normalizeScopeValue(topic.workspaceId);
699
- if (tenantId && workspaceId) {
700
- return { tenantId, workspaceId };
701
- }
702
- let current = topic;
703
- for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
704
- current = await ctx.db.get(current.parentTopicId);
705
- if (!current) break;
706
- if (!tenantId) {
707
- tenantId = normalizeScopeValue(current.tenantId);
708
- }
709
- if (!workspaceId) {
710
- workspaceId = normalizeScopeValue(current.workspaceId);
711
- }
712
- if (tenantId && workspaceId) break;
713
- }
714
- return { tenantId, workspaceId };
715
- }
716
- async function resolveTopicProjectScope(ctx, args) {
717
- if (args.topicId) {
718
- let topic = null;
719
- try {
720
- topic = await ctx.db.get(
721
- args.topicId
722
- );
723
- } catch (error) {
724
- debugGraphPrimitiveFallback(
725
- "[topicScope] Failed to load topic by direct id",
726
- {
727
- error,
728
- topicId: args.topicId
729
- }
730
- );
731
- }
732
- if (!topic) {
733
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
734
- }
735
- if (!topic) {
736
- topic = pickPrimaryTopic(
737
- await findTopicsByScopeAlias(ctx, String(args.topicId))
738
- ) ?? null;
739
- }
740
- if (!topic) {
741
- const nodeScope = await resolveTopicNodeScopeOrNull(
742
- ctx,
743
- String(args.topicId)
744
- );
745
- if (nodeScope) {
746
- return nodeScope;
747
- }
748
- throw new Error(`Topic not found: ${String(args.topicId)}`);
749
- }
750
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
751
- const mapped = asMappedProjectId(topic);
752
- if (mapped) {
753
- return {
754
- topicId: topic._id,
755
- projectId: mapped,
756
- tenantId: inherited.tenantId,
757
- workspaceId: inherited.workspaceId,
758
- source: "topic"
759
- };
760
- }
761
- return {
762
- topicId: topic._id,
763
- tenantId: inherited.tenantId,
764
- workspaceId: inherited.workspaceId,
765
- source: "topic"
766
- };
767
- }
768
- if (args.projectId) {
769
- let directTopic = null;
770
- try {
771
- directTopic = await ctx.db.get(
772
- args.projectId
773
- );
774
- } catch (error) {
775
- debugGraphPrimitiveFallback(
776
- "[topicScope] Failed to load direct project topic",
777
- {
778
- error,
779
- projectId: args.projectId
780
- }
781
- );
782
- }
783
- if (directTopic) {
784
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
785
- const mapped = asMappedProjectId(directTopic);
786
- return {
787
- topicId: directTopic._id,
788
- projectId: mapped ?? args.projectId,
789
- tenantId: inherited.tenantId,
790
- workspaceId: inherited.workspaceId,
791
- source: "topic_inferred"
792
- };
282
+ }
283
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
284
+ const MAX_DEPTH = 10;
285
+ let tenantId = normalizeScopeValue(topic.tenantId);
286
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
287
+ if (tenantId && workspaceId) {
288
+ return { tenantId, workspaceId };
289
+ }
290
+ let current = topic;
291
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
292
+ current = await ctx.db.get(current.parentTopicId);
293
+ if (!current) {
294
+ break;
793
295
  }
794
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
795
- if (directTopic) {
796
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
797
- const mapped = asMappedProjectId(directTopic);
798
- return {
799
- topicId: directTopic._id,
800
- projectId: mapped ?? args.projectId,
801
- tenantId: inherited.tenantId,
802
- workspaceId: inherited.workspaceId,
803
- source: "topic_inferred"
804
- };
296
+ if (!tenantId) {
297
+ tenantId = normalizeScopeValue(current.tenantId);
805
298
  }
806
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
807
- const primary = pickPrimaryTopic(topics);
808
- if (primary) {
809
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
810
- return {
811
- topicId: primary._id,
812
- projectId: args.projectId,
813
- tenantId: inherited.tenantId,
814
- workspaceId: inherited.workspaceId,
815
- source: "project_mapped_topic"
816
- };
299
+ if (!workspaceId) {
300
+ workspaceId = normalizeScopeValue(current.workspaceId);
817
301
  }
818
- const nodeScope = await resolveTopicNodeScopeOrNull(
819
- ctx,
820
- String(args.projectId)
821
- );
822
- if (nodeScope) {
823
- return {
824
- ...nodeScope,
825
- projectId: nodeScope.projectId ?? String(args.projectId)
826
- };
302
+ if (tenantId && workspaceId) {
303
+ break;
827
304
  }
828
- throw new Error(
829
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
830
- );
305
+ }
306
+ return { tenantId, workspaceId };
307
+ }
308
+ async function resolveTopicProjectScope(ctx, args) {
309
+ if (args.topicId) {
310
+ return await resolveScopeFromTopicId(ctx, args.topicId);
311
+ }
312
+ if (args.projectId) {
313
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
831
314
  }
832
315
  throw new Error(
833
316
  "Missing scope: provide topicId (preferred) or legacy projectId alias."
834
317
  );
835
318
  }
319
+ async function resolveScopeFromTopicId(ctx, topicId) {
320
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
321
+ if (topic) {
322
+ return await buildTopicScope(ctx, topic, "topic");
323
+ }
324
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
325
+ if (nodeScope) {
326
+ return nodeScope;
327
+ }
328
+ throw new Error(`Topic not found: ${String(topicId)}`);
329
+ }
330
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
331
+ const direct = await tryReadTopicDoc(ctx, topicId, {
332
+ failureLog: "[topicScope] Failed to load topic by direct id",
333
+ idLogKey: "topicId"
334
+ });
335
+ if (direct) {
336
+ return direct;
337
+ }
338
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
339
+ if (hostTopic) {
340
+ return hostTopic;
341
+ }
342
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
343
+ }
344
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
345
+ const directTopic = await resolveDirectLegacyProjectTopic(
346
+ ctx,
347
+ legacyProjectId
348
+ );
349
+ if (directTopic) {
350
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
351
+ fallbackProjectId: legacyProjectId
352
+ });
353
+ }
354
+ const primary = pickPrimaryTopic(
355
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
356
+ );
357
+ if (primary) {
358
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
359
+ fallbackProjectId: legacyProjectId
360
+ });
361
+ }
362
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
363
+ if (nodeScope) {
364
+ return {
365
+ ...nodeScope,
366
+ projectId: nodeScope.projectId ?? legacyProjectId
367
+ };
368
+ }
369
+ throw new Error(
370
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
371
+ );
372
+ }
373
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
374
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
375
+ failureLog: "[topicScope] Failed to load direct project topic",
376
+ idLogKey: "projectId"
377
+ });
378
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
379
+ }
380
+ async function tryReadTopicDoc(ctx, id, log) {
381
+ try {
382
+ return await ctx.db.get(id);
383
+ } catch (error) {
384
+ debugGraphPrimitiveFallback(log.failureLog, {
385
+ error,
386
+ [log.idLogKey]: id
387
+ });
388
+ return null;
389
+ }
390
+ }
391
+ async function buildTopicScope(ctx, topic, source, options = {}) {
392
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
393
+ const mapped = asMappedProjectId(topic);
394
+ return {
395
+ topicId: topic._id,
396
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
397
+ tenantId: inherited.tenantId,
398
+ workspaceId: inherited.workspaceId,
399
+ source
400
+ };
401
+ }
836
402
  ({
837
403
  projectId: v.optional(v.string()),
838
404
  topicId: v.optional(v.string())
@@ -900,9 +466,10 @@ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
900
466
  if (resolved.tenantId || resolved.workspaceId) {
901
467
  return resolved;
902
468
  }
903
- if (node.topicId) {
469
+ const topicId = normalizeScopeValue2(node.topicId);
470
+ if (topicId) {
904
471
  const topicScope = await resolveTopicProjectScope(ctx, {
905
- topicId: node.topicId
472
+ topicId
906
473
  });
907
474
  return {
908
475
  ...resolved,
@@ -922,8 +489,6 @@ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
922
489
  }
923
490
  return resolved;
924
491
  }
925
-
926
- // src/epistemicBeliefs.helpers.ts
927
492
  v.id("epistemicNodes");
928
493
  var DEFAULT_CONFIDENCE_POLICY = {
929
494
  scoringMode: "after_worktree",
@@ -1003,7 +568,10 @@ function resolveBeliefStatus(node, metadata) {
1003
568
  });
1004
569
  }
1005
570
  async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
1006
- const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex("by_belief", (q) => q.eq("beliefId", beliefNodeId)).collect();
571
+ const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
572
+ "by_belief",
573
+ (q) => q.eq("beliefId", beliefNodeId)
574
+ ).collect();
1007
575
  for (const membership of clusterMembership) {
1008
576
  const worktree = await ctx.db.get(membership.worktreeId);
1009
577
  if (worktree?.status === "completed" || worktree?.status === "merged") {
@@ -1014,7 +582,10 @@ async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
1014
582
  }
1015
583
  async function getActiveConfidencePolicy(ctx) {
1016
584
  try {
1017
- const activeConfig = await ctx.db.query("logicSprintScoring").withIndex("by_active", (q) => q.eq("isActive", true)).first();
585
+ const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
586
+ "by_active",
587
+ (q) => q.eq("isActive", true)
588
+ ).first();
1018
589
  return {
1019
590
  scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
1020
591
  tupleContradiction: normalizeTupleContradictionPolicy(
@@ -1167,7 +738,7 @@ var dependsOnPropagationSpec = {
1167
738
  description: "Structural gating. Textbook conditional deduction when edge conditionals exist, otherwise damped dependency cascade through downstream chains."
1168
739
  };
1169
740
 
1170
- // src/edges/derivedFrom.ts
741
+ // src/edges/derived-from.ts
1171
742
  var derivedFromPropagationSpec = {
1172
743
  edgeType: "derived_from",
1173
744
  direction: "incoming",
@@ -1220,7 +791,7 @@ var informsPropagationSpec = {
1220
791
  description: "Evidence-bearing influence. Informs can chain through the graph with light per-hop damping."
1221
792
  };
1222
793
 
1223
- // src/edges/propagationTypes.ts
794
+ // src/edges/propagation-types.ts
1224
795
  function isPropagationTraversalDirection(direction) {
1225
796
  return direction === "outgoing" || direction === "incoming";
1226
797
  }
@@ -1293,6 +864,9 @@ var testsPropagationSpec = {
1293
864
  };
1294
865
 
1295
866
  // src/edges/index.ts
867
+ var canContinueTransitively2 = canContinueTransitively;
868
+ var canTraverseHop2 = canTraverseHop;
869
+ var isPropagationTraversalDirection2 = isPropagationTraversalDirection;
1296
870
  var EDGE_PROPAGATION_SPECS = [
1297
871
  supportsPropagationSpec,
1298
872
  informsPropagationSpec,
@@ -1309,16 +883,15 @@ function getEdgePropagationSpecs() {
1309
883
  return EDGE_PROPAGATION_SPECS;
1310
884
  }
1311
885
  function getTraversalDirections(direction) {
1312
- if (isPropagationTraversalDirection(direction)) {
886
+ if (isPropagationTraversalDirection2(direction)) {
1313
887
  return [direction];
1314
888
  }
1315
889
  return ["outgoing", "incoming"];
1316
890
  }
1317
891
 
1318
892
  // src/confidencePropagationDispatch.ts
1319
- function resolveTraversalTargetNodeId(edge, direction) {
1320
- const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
1321
- return targetNodeId ?? void 0;
893
+ function nodeIdToCacheKey(nodeId) {
894
+ return String(nodeId);
1322
895
  }
1323
896
  function readNodeOpinion(node) {
1324
897
  const metadata = node.metadata ?? {};
@@ -1334,118 +907,354 @@ function readNodeOpinion(node) {
1334
907
  return mkOpinion(0, 0, 1, 0.5);
1335
908
  }
1336
909
  }
910
+ function resolveTraversalTargetNodeId(edge, direction) {
911
+ const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
912
+ return targetNodeId ?? void 0;
913
+ }
914
+ function buildInitialState(sourceNodeId, sourceOpinion) {
915
+ return {
916
+ nodeId: sourceNodeId,
917
+ opinion: sourceOpinion,
918
+ hop: 0,
919
+ visitedNodeIds: /* @__PURE__ */ new Set([nodeIdToCacheKey(sourceNodeId)])
920
+ };
921
+ }
922
+ function extendVisited(currentVisited, targetNodeId) {
923
+ return /* @__PURE__ */ new Set([...currentVisited, nodeIdToCacheKey(targetNodeId)]);
924
+ }
925
+ function makeTransitiveState(current, targetNodeId, projectedOpinion, nextHop) {
926
+ return {
927
+ nodeId: targetNodeId,
928
+ opinion: projectedOpinion,
929
+ hop: nextHop,
930
+ visitedNodeIds: extendVisited(current.visitedNodeIds, targetNodeId)
931
+ };
932
+ }
933
+ function makeDispatchRecord(targetNodeId, spec, direction, edge, projectedOpinion, nextHop, result, existingDispatch) {
934
+ return {
935
+ targetNodeId,
936
+ edgeType: spec.edgeType,
937
+ traversedDirection: direction,
938
+ weight: edge.weight ?? 1,
939
+ opinion: projectedOpinion,
940
+ operator: result.operator,
941
+ rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
942
+ hop: nextHop
943
+ };
944
+ }
945
+ async function loadCachedNode(scope, nodeId) {
946
+ const cacheKey = nodeIdToCacheKey(nodeId);
947
+ if (!scope.nodeCache.has(cacheKey)) {
948
+ scope.nodeCache.set(cacheKey, await scope.args.getNode(nodeId));
949
+ }
950
+ return scope.nodeCache.get(cacheKey) ?? null;
951
+ }
952
+ async function collectTargetDispatch(state, nextHop, spec, direction, edge, queue, scope) {
953
+ const sourceScope = scope.args.sourceScope;
954
+ if (sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, sourceScope)) {
955
+ return;
956
+ }
957
+ const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
958
+ if (!targetNodeId) {
959
+ return;
960
+ }
961
+ const targetNodeIdKey = nodeIdToCacheKey(targetNodeId);
962
+ if (state.visitedNodeIds.has(targetNodeIdKey)) {
963
+ return;
964
+ }
965
+ const targetNode = await loadCachedNode(scope, targetNodeId);
966
+ if (targetNode?.nodeType !== "belief") {
967
+ return;
968
+ }
969
+ if (sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, sourceScope)) {
970
+ return;
971
+ }
972
+ const targetOpinion = scope.opinionCache.get(targetNodeIdKey) ?? readNodeOpinion(targetNode);
973
+ const result = spec.operator(state.opinion, targetOpinion, edge, {
974
+ hop: nextHop,
975
+ sourceNodeId: state.nodeId,
976
+ targetNodeId,
977
+ traversedDirection: direction,
978
+ spec
979
+ });
980
+ if (!(result && hasProjectedOpinionChanged(targetOpinion, result.opinion))) {
981
+ return;
982
+ }
983
+ const projectedOpinion = mkOpinion(
984
+ result.opinion.b,
985
+ result.opinion.d,
986
+ result.opinion.u,
987
+ result.opinion.a
988
+ );
989
+ scope.opinionCache.set(targetNodeIdKey, projectedOpinion);
990
+ const existingDispatch = scope.dispatchesByTargetId.get(targetNodeIdKey);
991
+ scope.dispatchesByTargetId.set(
992
+ targetNodeIdKey,
993
+ makeDispatchRecord(
994
+ targetNodeId,
995
+ spec,
996
+ direction,
997
+ edge,
998
+ projectedOpinion,
999
+ nextHop,
1000
+ result,
1001
+ existingDispatch
1002
+ )
1003
+ );
1004
+ if (canContinueTransitively2(spec, nextHop)) {
1005
+ queue.push(
1006
+ makeTransitiveState(state, targetNodeId, projectedOpinion, nextHop)
1007
+ );
1008
+ }
1009
+ }
1010
+ async function processTraversalSpec(state, nextHop, spec, queue, scope) {
1011
+ const sourceNodeId = state.nodeId;
1012
+ for (const direction of getTraversalDirections(spec.direction)) {
1013
+ const edges = await scope.args.queryEdges({
1014
+ nodeId: sourceNodeId,
1015
+ spec,
1016
+ direction,
1017
+ hop: nextHop
1018
+ });
1019
+ for (const edge of edges) {
1020
+ await collectTargetDispatch(
1021
+ state,
1022
+ nextHop,
1023
+ spec,
1024
+ direction,
1025
+ edge,
1026
+ queue,
1027
+ scope
1028
+ );
1029
+ }
1030
+ }
1031
+ }
1032
+ async function processQueuedState(state, queue, scope) {
1033
+ const nextHop = state.hop + 1;
1034
+ for (const spec of scope.traversalSpecs) {
1035
+ if (!canTraverseHop2(spec, nextHop)) {
1036
+ continue;
1037
+ }
1038
+ await processTraversalSpec(state, nextHop, spec, queue, scope);
1039
+ }
1040
+ }
1041
+ function sortDispatches(dispatches) {
1042
+ return Array.from(dispatches).sort((left, right) => {
1043
+ if (left.hop !== right.hop) {
1044
+ return left.hop - right.hop;
1045
+ }
1046
+ return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
1047
+ });
1048
+ }
1337
1049
  async function collectConfidencePropagationDispatches(args) {
1338
1050
  const dispatchesByTargetId = /* @__PURE__ */ new Map();
1339
1051
  const opinionCache = /* @__PURE__ */ new Map();
1340
1052
  const nodeCache = /* @__PURE__ */ new Map();
1341
1053
  const traversalSpecs = args.traversalSpecs ?? getEdgePropagationSpecs();
1054
+ const scope = {
1055
+ args,
1056
+ dispatchesByTargetId,
1057
+ opinionCache,
1058
+ nodeCache,
1059
+ traversalSpecs
1060
+ };
1342
1061
  const queue = [
1343
- {
1344
- nodeId: args.sourceNodeId,
1345
- opinion: args.sourceOpinion,
1346
- hop: 0,
1347
- visitedNodeIds: /* @__PURE__ */ new Set([String(args.sourceNodeId)])
1348
- }
1062
+ buildInitialState(args.sourceNodeId, args.sourceOpinion)
1349
1063
  ];
1350
- const loadNode = async (nodeId) => {
1351
- const cacheKey = String(nodeId);
1352
- if (!nodeCache.has(cacheKey)) {
1353
- nodeCache.set(cacheKey, await args.getNode(nodeId));
1354
- }
1355
- return nodeCache.get(cacheKey) ?? null;
1356
- };
1357
1064
  while (queue.length > 0) {
1358
1065
  const state = queue.shift();
1359
1066
  if (!state) {
1360
1067
  continue;
1361
1068
  }
1362
- for (const spec of traversalSpecs) {
1363
- const nextHop = state.hop + 1;
1364
- if (!canTraverseHop(spec, nextHop)) {
1365
- continue;
1366
- }
1367
- for (const direction of getTraversalDirections(spec.direction)) {
1368
- const edges = await args.queryEdges({
1369
- nodeId: state.nodeId,
1370
- spec,
1371
- direction,
1372
- hop: nextHop
1373
- });
1374
- for (const edge of edges) {
1375
- if (args.sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, args.sourceScope)) {
1376
- continue;
1377
- }
1378
- const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
1379
- if (!targetNodeId) {
1380
- continue;
1381
- }
1382
- if (state.visitedNodeIds.has(String(targetNodeId))) {
1383
- continue;
1384
- }
1385
- const targetNode = await loadNode(targetNodeId);
1386
- if (!targetNode || targetNode.nodeType !== "belief") {
1387
- continue;
1388
- }
1389
- if (args.sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, args.sourceScope)) {
1390
- continue;
1391
- }
1392
- const cacheKey = String(targetNodeId);
1393
- const targetOpinion = opinionCache.get(cacheKey) ?? readNodeOpinion(targetNode);
1394
- const result = spec.operator(state.opinion, targetOpinion, edge, {
1395
- hop: nextHop,
1396
- sourceNodeId: state.nodeId,
1397
- targetNodeId,
1398
- traversedDirection: direction,
1399
- spec
1400
- });
1401
- if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
1402
- continue;
1403
- }
1404
- const projectedOpinion = mkOpinion(
1405
- result.opinion.b,
1406
- result.opinion.d,
1407
- result.opinion.u,
1408
- result.opinion.a
1409
- );
1410
- opinionCache.set(cacheKey, projectedOpinion);
1411
- const existingDispatch = dispatchesByTargetId.get(cacheKey);
1412
- dispatchesByTargetId.set(cacheKey, {
1413
- targetNodeId,
1414
- edgeType: spec.edgeType,
1415
- traversedDirection: direction,
1416
- weight: edge.weight ?? 1,
1417
- opinion: projectedOpinion,
1418
- operator: result.operator,
1419
- rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
1420
- hop: nextHop
1421
- });
1422
- if (canContinueTransitively(spec, nextHop)) {
1423
- queue.push({
1424
- nodeId: targetNodeId,
1425
- opinion: projectedOpinion,
1426
- hop: nextHop,
1427
- visitedNodeIds: /* @__PURE__ */ new Set([
1428
- ...state.visitedNodeIds,
1429
- String(targetNodeId)
1430
- ])
1431
- });
1432
- }
1433
- }
1434
- }
1435
- }
1069
+ await processQueuedState(state, queue, scope);
1436
1070
  }
1437
- return Array.from(dispatchesByTargetId.values()).sort((left, right) => {
1438
- if (left.hop !== right.hop) {
1439
- return left.hop - right.hop;
1440
- }
1441
- return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
1442
- });
1071
+ return sortDispatches(dispatchesByTargetId.values());
1443
1072
  }
1444
1073
 
1445
1074
  // src/epistemicBeliefs.confidence.ts
1075
+ function isRecord(value) {
1076
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1077
+ }
1078
+ function readConvexId(value) {
1079
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1080
+ }
1081
+ function readOptionalBoolean(value) {
1082
+ return typeof value === "boolean" ? value : void 0;
1083
+ }
1084
+ function readOptionalNumber(value) {
1085
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1086
+ }
1087
+ function readOptionalString(value) {
1088
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1089
+ }
1090
+ function readRecord(value) {
1091
+ return isRecord(value) ? value : void 0;
1092
+ }
1093
+ function readConfidenceBeliefNode(value) {
1094
+ if (!isRecord(value)) {
1095
+ return null;
1096
+ }
1097
+ const id = readConvexId(value._id);
1098
+ const nodeType = readOptionalString(value.nodeType);
1099
+ const projectId = readOptionalString(value.projectId);
1100
+ if (!(id && nodeType === "belief" && projectId)) {
1101
+ return null;
1102
+ }
1103
+ const node = {
1104
+ _id: id,
1105
+ nodeType,
1106
+ projectId
1107
+ };
1108
+ const confidence = readOptionalNumber(value.confidence);
1109
+ const epistemicLayer = readOptionalString(value.epistemicLayer);
1110
+ const globalId = readOptionalString(value.globalId);
1111
+ const metadata = readRecord(value.metadata);
1112
+ const opinionA = readOptionalNumber(value.opinion_a);
1113
+ const opinionB = readOptionalNumber(value.opinion_b);
1114
+ const opinionD = readOptionalNumber(value.opinion_d);
1115
+ const opinionU = readOptionalNumber(value.opinion_u);
1116
+ const predictionMeta = readRecord(value.predictionMeta);
1117
+ const publicationStatus = readOptionalString(value.publicationStatus);
1118
+ const status = readOptionalString(value.status);
1119
+ const tenantId = readOptionalString(value.tenantId);
1120
+ const topicId = readOptionalString(value.topicId);
1121
+ const tupleContradicted = readOptionalBoolean(value.tupleContradicted);
1122
+ const workspaceId = readOptionalString(value.workspaceId);
1123
+ if (confidence !== void 0) {
1124
+ node.confidence = confidence;
1125
+ }
1126
+ if (epistemicLayer !== void 0) {
1127
+ node.epistemicLayer = epistemicLayer;
1128
+ }
1129
+ if (globalId !== void 0) {
1130
+ node.globalId = globalId;
1131
+ }
1132
+ if (metadata !== void 0) {
1133
+ node.metadata = metadata;
1134
+ }
1135
+ if (opinionA !== void 0) {
1136
+ node.opinion_a = opinionA;
1137
+ }
1138
+ if (opinionB !== void 0) {
1139
+ node.opinion_b = opinionB;
1140
+ }
1141
+ if (opinionD !== void 0) {
1142
+ node.opinion_d = opinionD;
1143
+ }
1144
+ if (opinionU !== void 0) {
1145
+ node.opinion_u = opinionU;
1146
+ }
1147
+ if (predictionMeta !== void 0) {
1148
+ node.predictionMeta = predictionMeta;
1149
+ }
1150
+ if (publicationStatus !== void 0) {
1151
+ node.publicationStatus = publicationStatus;
1152
+ }
1153
+ if (status !== void 0) {
1154
+ node.status = status;
1155
+ }
1156
+ if (tenantId !== void 0) {
1157
+ node.tenantId = tenantId;
1158
+ }
1159
+ if (topicId !== void 0) {
1160
+ node.topicId = topicId;
1161
+ }
1162
+ if (tupleContradicted !== void 0) {
1163
+ node.tupleContradicted = tupleContradicted;
1164
+ }
1165
+ if (workspaceId !== void 0) {
1166
+ node.workspaceId = workspaceId;
1167
+ }
1168
+ return node;
1169
+ }
1170
+ function readPropagationEdge(value) {
1171
+ if (!isRecord(value)) {
1172
+ return null;
1173
+ }
1174
+ const edgeType = readOptionalString(value.edgeType);
1175
+ if (!edgeType) {
1176
+ return null;
1177
+ }
1178
+ const edge = { edgeType };
1179
+ const fromNodeId = readConvexId(value.fromNodeId);
1180
+ const tenantId = readOptionalString(value.tenantId);
1181
+ const toNodeId = readConvexId(value.toNodeId);
1182
+ const weight = readOptionalNumber(value.weight);
1183
+ const workspaceId = readOptionalString(value.workspaceId);
1184
+ if (fromNodeId !== void 0) {
1185
+ edge.fromNodeId = fromNodeId;
1186
+ }
1187
+ if (tenantId !== void 0) {
1188
+ edge.tenantId = tenantId;
1189
+ }
1190
+ if (toNodeId !== void 0) {
1191
+ edge.toNodeId = toNodeId;
1192
+ }
1193
+ if (weight !== void 0) {
1194
+ edge.weight = weight;
1195
+ }
1196
+ if (workspaceId !== void 0) {
1197
+ edge.workspaceId = workspaceId;
1198
+ }
1199
+ return edge;
1200
+ }
1201
+ function readRowList(values, reader) {
1202
+ return values.flatMap((value) => {
1203
+ const row = reader(value);
1204
+ return row ? [row] : [];
1205
+ });
1206
+ }
1446
1207
  async function applyBeliefConfidenceChange(ctx, args) {
1447
1208
  const now = Date.now();
1448
- const node = await ctx.db.get(args.nodeId);
1209
+ const node = await requireConfidenceBeliefNode(ctx, args);
1210
+ const state = await buildConfidenceChangeState(ctx, node, args);
1211
+ await assertConfidenceScoringPolicySatisfied(ctx, args, state);
1212
+ const tupleContradictionId = await createTupleContradictionIfNeeded(
1213
+ ctx,
1214
+ args,
1215
+ node,
1216
+ state
1217
+ );
1218
+ await patchBeliefConfidenceState(ctx, args, state);
1219
+ await scheduleFirstScoringThemeEdges(ctx, args, node, state);
1220
+ const beliefConfidenceId = await insertBeliefConfidenceRecord(
1221
+ ctx,
1222
+ args,
1223
+ state,
1224
+ tupleContradictionId,
1225
+ now
1226
+ );
1227
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1228
+ nodeId: args.nodeId,
1229
+ operation: "upsert"
1230
+ });
1231
+ await insertConfidenceAudit(
1232
+ ctx,
1233
+ args,
1234
+ node,
1235
+ state,
1236
+ tupleContradictionId,
1237
+ now
1238
+ );
1239
+ await insertTupleTransitionAuditIfNeeded(
1240
+ ctx,
1241
+ args,
1242
+ node,
1243
+ state,
1244
+ tupleContradictionId,
1245
+ now
1246
+ );
1247
+ await scheduleConfidenceFollowups(ctx, args, node, state);
1248
+ return {
1249
+ nodeId: args.nodeId,
1250
+ previousConfidence: state.previousConfidence,
1251
+ newConfidence: state.derivedConfidence,
1252
+ opinion: state.nextOpinion,
1253
+ beliefConfidenceId
1254
+ };
1255
+ }
1256
+ async function requireConfidenceBeliefNode(ctx, args) {
1257
+ const node = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
1449
1258
  if (!node) {
1450
1259
  throwStructuredMutationError({
1451
1260
  message: "Node not found.",
@@ -1456,59 +1265,28 @@ async function applyBeliefConfidenceChange(ctx, args) {
1456
1265
  details: { nodeId: args.nodeId }
1457
1266
  });
1458
1267
  }
1459
- if (node.nodeType !== "belief") {
1460
- throwStructuredMutationError({
1461
- 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.`,
1462
- status: 400,
1463
- code: "INVALID_ARGUMENT",
1464
- invariantCode: "entity.no_confidence",
1465
- suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
1466
- details: { nodeId: args.nodeId, nodeType: node.nodeType }
1467
- });
1468
- }
1469
- if (!node.projectId) {
1470
- throwStructuredMutationError({
1471
- message: "Belief has no project scope.",
1472
- status: 400,
1473
- code: "MISSING_SCOPE",
1474
- invariantCode: "belief.project_required",
1475
- suggestion: "Belief must have a projectId before SL scoring can be appended.",
1476
- details: { nodeId: args.nodeId }
1477
- });
1478
- }
1479
- await requireScopeWriteAccess(
1480
- ctx,
1481
- node.projectId,
1482
- args.authenticatedUserId
1483
- );
1484
- const existingMetadata = node.metadata || {};
1268
+ await requireScopeWriteAccess(ctx, node.projectId, args.authenticatedUserId);
1269
+ return node;
1270
+ }
1271
+ async function buildConfidenceChangeState(ctx, node, args) {
1272
+ const existingMetadata = readNodeMetadata(node);
1485
1273
  const currentBeliefStatus = resolveBeliefStatus(node, existingMetadata);
1486
1274
  const confidencePolicy = await getActiveConfidencePolicy(ctx);
1487
- if (confidencePolicy.scoringMode === "after_worktree" && isPreValidationBeliefStatus(currentBeliefStatus)) {
1488
- const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
1489
- ctx,
1490
- args.nodeId
1491
- );
1492
- if (!hasCompletedWorktree) {
1493
- throwStructuredMutationError({
1494
- message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
1495
- status: 409,
1496
- code: "CONFLICT",
1497
- invariantCode: "belief.confidence_append_only",
1498
- suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
1499
- details: { nodeId: args.nodeId }
1500
- });
1501
- }
1502
- }
1503
1275
  const previousConfidence = node.confidence || 0.5;
1504
1276
  const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
1505
1277
  const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
1506
- const slB = args.belief;
1507
- const slD = args.disbelief;
1508
- const slU = args.uncertainty;
1509
- const slA = args.baseRate ?? 0.5;
1510
- const nextOpinion = { b: slB, d: slD, u: slU, a: slA };
1511
- const derivedConfidence = confidenceFromSL(slB, slD, slU, slA);
1278
+ const nextOpinion = {
1279
+ b: args.belief,
1280
+ d: args.disbelief,
1281
+ u: args.uncertainty,
1282
+ a: args.baseRate ?? 0.5
1283
+ };
1284
+ const derivedConfidence = confidenceFromSL(
1285
+ nextOpinion.b,
1286
+ nextOpinion.d,
1287
+ nextOpinion.u,
1288
+ nextOpinion.a
1289
+ );
1512
1290
  const isFirstScoring = typeof node.confidence !== "number" || !Number.isFinite(node.confidence);
1513
1291
  const previousTupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(existingMetadata.tupleContradicted) ?? detectTupleContradiction(
1514
1292
  previousOpinion,
@@ -1529,79 +1307,121 @@ async function applyBeliefConfidenceChange(ctx, args) {
1529
1307
  predictionMeta,
1530
1308
  metadata: existingMetadata
1531
1309
  });
1532
- let tupleContradictionId;
1533
- if (tupleTransition.crossedIntoTupleContradiction) {
1534
- tupleContradictionId = await ctx.runMutation(
1535
- "contradictions:create",
1536
- {
1537
- projectId: node.projectId,
1538
- topicId: node.topicId,
1539
- beliefId: args.nodeId,
1540
- beliefBId: args.nodeId,
1541
- supportingInsightIds: [],
1542
- contradictingInsightIds: [],
1543
- severity: deriveTupleContradictionSeverity(node),
1544
- source: "tuple_space",
1545
- detectionMethod: "agent",
1546
- description: tupleContradictionDescription,
1547
- createdBy: args.authenticatedUserId
1548
- }
1549
- );
1310
+ const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
1311
+ return {
1312
+ confidencePolicy,
1313
+ currentBeliefStatus,
1314
+ derivedConfidence,
1315
+ existingMetadata,
1316
+ isFirstScoring,
1317
+ newBeliefStatus,
1318
+ nextOpinion,
1319
+ previousConfidence,
1320
+ previousTupleContradicted,
1321
+ storedRationale,
1322
+ tupleContradictionDescription,
1323
+ tupleTransition
1324
+ };
1325
+ }
1326
+ function readNodeMetadata(node) {
1327
+ return node.metadata ?? {};
1328
+ }
1329
+ async function assertConfidenceScoringPolicySatisfied(ctx, args, state) {
1330
+ if (state.confidencePolicy.scoringMode !== "after_worktree" || !isPreValidationBeliefStatus(state.currentBeliefStatus)) {
1331
+ return;
1332
+ }
1333
+ const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
1334
+ ctx,
1335
+ args.nodeId
1336
+ );
1337
+ if (hasCompletedWorktree) {
1338
+ return;
1550
1339
  }
1340
+ throwStructuredMutationError({
1341
+ message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
1342
+ status: 409,
1343
+ code: "CONFLICT",
1344
+ invariantCode: "belief.confidence_append_only",
1345
+ suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
1346
+ details: { nodeId: args.nodeId }
1347
+ });
1348
+ }
1349
+ async function createTupleContradictionIfNeeded(ctx, args, node, state) {
1350
+ if (!state.tupleTransition.crossedIntoTupleContradiction) {
1351
+ return;
1352
+ }
1353
+ return await ctx.runMutation("contradictions:create", {
1354
+ projectId: node.projectId,
1355
+ topicId: node.topicId,
1356
+ beliefId: args.nodeId,
1357
+ beliefBId: args.nodeId,
1358
+ supportingInsightIds: [],
1359
+ contradictingInsightIds: [],
1360
+ severity: deriveTupleContradictionSeverity(node),
1361
+ source: "tuple_space",
1362
+ detectionMethod: "agent",
1363
+ description: state.tupleContradictionDescription,
1364
+ createdBy: args.authenticatedUserId
1365
+ });
1366
+ }
1367
+ async function patchBeliefConfidenceState(ctx, args, state) {
1551
1368
  await ctx.db.patch(args.nodeId, {
1552
- confidence: derivedConfidence,
1553
- beliefStatus: newBeliefStatus,
1554
- tupleContradicted: tupleTransition.tupleContradicted,
1555
- updatedAt: now,
1556
- // Store SL opinion fields at node level for fast access
1557
- opinion_b: slB,
1558
- opinion_d: slD,
1559
- opinion_u: slU,
1560
- opinion_a: slA,
1369
+ confidence: state.derivedConfidence,
1370
+ beliefStatus: state.newBeliefStatus,
1371
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1372
+ updatedAt: Date.now(),
1373
+ opinion_b: state.nextOpinion.b,
1374
+ opinion_d: state.nextOpinion.d,
1375
+ opinion_u: state.nextOpinion.u,
1376
+ opinion_a: state.nextOpinion.a,
1561
1377
  metadata: {
1562
- ...existingMetadata,
1563
- beliefStatus: newBeliefStatus,
1564
- slBelief: slB,
1565
- slDisbelief: slD,
1566
- slUncertainty: slU,
1567
- slBaseRate: slA,
1568
- tupleContradicted: tupleTransition.tupleContradicted
1378
+ ...state.existingMetadata,
1379
+ beliefStatus: state.newBeliefStatus,
1380
+ slBelief: state.nextOpinion.b,
1381
+ slDisbelief: state.nextOpinion.d,
1382
+ slUncertainty: state.nextOpinion.u,
1383
+ slBaseRate: state.nextOpinion.a,
1384
+ tupleContradicted: state.tupleTransition.tupleContradicted
1569
1385
  }
1570
1386
  });
1571
- if (isFirstScoring) {
1572
- const nodeTopicId = node.topicId;
1573
- const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
1574
- "by_topic",
1575
- (q) => q.eq("topicId", nodeTopicId || node.projectId)
1576
- ).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
1577
- for (const theme of themeNodes) {
1578
- if (theme.globalId && node.globalId) {
1579
- await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
1580
- globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
1581
- fromGlobalId: node.globalId,
1582
- toGlobalId: theme.globalId,
1583
- edgeType: "relates_to_thesis",
1584
- weight: derivedConfidence,
1585
- createdBy: args.authenticatedUserId,
1586
- topicId: String(node.projectId),
1587
- fromNodeType: "belief",
1588
- toNodeType: "theme",
1589
- fromLayer: "L3",
1590
- toLayer: "L3"
1591
- });
1592
- }
1387
+ }
1388
+ async function scheduleFirstScoringThemeEdges(ctx, args, node, state) {
1389
+ if (!state.isFirstScoring) {
1390
+ return;
1391
+ }
1392
+ const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
1393
+ "by_topic",
1394
+ (q) => q.eq("topicId", node.topicId || node.projectId)
1395
+ ).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
1396
+ for (const theme of themeNodes) {
1397
+ if (!(theme.globalId && node.globalId)) {
1398
+ continue;
1593
1399
  }
1400
+ await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
1401
+ globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
1402
+ fromGlobalId: node.globalId,
1403
+ toGlobalId: theme.globalId,
1404
+ edgeType: "relates_to_thesis",
1405
+ weight: state.derivedConfidence,
1406
+ createdBy: args.authenticatedUserId,
1407
+ topicId: String(node.projectId),
1408
+ fromNodeType: "belief",
1409
+ toNodeType: "theme",
1410
+ fromLayer: "L3",
1411
+ toLayer: "L3"
1412
+ });
1594
1413
  }
1595
- const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
1596
- const beliefConfidenceId = await ctx.db.insert("beliefConfidence", {
1414
+ }
1415
+ async function insertBeliefConfidenceRecord(ctx, args, state, tupleContradictionId, now) {
1416
+ return await ctx.db.insert("beliefConfidence", {
1597
1417
  ...buildBeliefConfidenceRow({
1598
1418
  beliefId: args.nodeId,
1599
- belief: slB,
1600
- disbelief: slD,
1601
- uncertainty: slU,
1602
- baseRate: slA,
1419
+ belief: state.nextOpinion.b,
1420
+ disbelief: state.nextOpinion.d,
1421
+ uncertainty: state.nextOpinion.u,
1422
+ baseRate: state.nextOpinion.a,
1603
1423
  trigger: args.trigger,
1604
- rationale: storedRationale,
1424
+ rationale: state.storedRationale,
1605
1425
  assessedBy: args.authenticatedUserId,
1606
1426
  assessedAt: now,
1607
1427
  slOperator: args.slOperator,
@@ -1610,55 +1430,64 @@ async function applyBeliefConfidenceChange(ctx, args) {
1610
1430
  triggeringWorktreeId: args.triggeringWorktreeId
1611
1431
  })
1612
1432
  });
1613
- await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1614
- nodeId: args.nodeId,
1615
- operation: "upsert"
1433
+ }
1434
+ async function insertConfidenceAudit(ctx, args, node, state, tupleContradictionId, now) {
1435
+ await ctx.db.insert("epistemicAudit", {
1436
+ entityType: "belief",
1437
+ entityId: args.nodeId,
1438
+ changeType: "confidence_changed",
1439
+ previousState: {
1440
+ confidence: state.previousConfidence,
1441
+ tupleContradicted: state.previousTupleContradicted
1442
+ },
1443
+ newState: {
1444
+ opinion: state.nextOpinion,
1445
+ confidence: state.derivedConfidence,
1446
+ trigger: args.trigger,
1447
+ rationale: state.storedRationale,
1448
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1449
+ tupleContradictionPolicy: state.tupleTransition.policy,
1450
+ ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1451
+ },
1452
+ changedBy: args.authenticatedUserId,
1453
+ isAgent: false,
1454
+ changedAt: now,
1455
+ projectId: node.projectId,
1456
+ topicId: node.topicId
1616
1457
  });
1458
+ }
1459
+ async function insertTupleTransitionAuditIfNeeded(ctx, args, node, state, tupleContradictionId, now) {
1460
+ if (!(state.tupleTransition.crossedIntoTupleContradiction || state.tupleTransition.crossedOutOfTupleContradiction)) {
1461
+ return;
1462
+ }
1617
1463
  await ctx.db.insert("epistemicAudit", {
1618
1464
  entityType: "belief",
1619
1465
  entityId: args.nodeId,
1620
- changeType: "confidence_changed",
1621
- previousState: {
1622
- confidence: previousConfidence,
1623
- tupleContradicted: previousTupleContradicted
1624
- },
1466
+ changeType: "updated",
1467
+ previousState: { tupleContradicted: state.previousTupleContradicted },
1625
1468
  newState: {
1626
- opinion: nextOpinion,
1627
- confidence: derivedConfidence,
1628
- trigger: args.trigger,
1629
- rationale: storedRationale,
1630
- tupleContradicted: tupleTransition.tupleContradicted,
1631
- tupleContradictionPolicy: tupleTransition.policy,
1469
+ tupleContradicted: state.tupleTransition.tupleContradicted,
1470
+ action: state.tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
1471
+ opinion: state.nextOpinion,
1472
+ tupleContradictionPolicy: state.tupleTransition.policy,
1632
1473
  ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1633
1474
  },
1475
+ rationale: tupleAuditRationale(state),
1634
1476
  changedBy: args.authenticatedUserId,
1635
1477
  isAgent: false,
1636
1478
  changedAt: now,
1637
1479
  projectId: node.projectId,
1638
1480
  topicId: node.topicId
1639
1481
  });
1640
- if (tupleTransition.crossedIntoTupleContradiction || tupleTransition.crossedOutOfTupleContradiction) {
1641
- await ctx.db.insert("epistemicAudit", {
1642
- entityType: "belief",
1643
- entityId: args.nodeId,
1644
- changeType: "updated",
1645
- previousState: { tupleContradicted: previousTupleContradicted },
1646
- newState: {
1647
- tupleContradicted: tupleTransition.tupleContradicted,
1648
- action: tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
1649
- opinion: nextOpinion,
1650
- tupleContradictionPolicy: tupleTransition.policy,
1651
- ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1652
- },
1653
- 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.`,
1654
- changedBy: args.authenticatedUserId,
1655
- isAgent: false,
1656
- changedAt: now,
1657
- projectId: node.projectId,
1658
- topicId: node.topicId
1659
- });
1482
+ }
1483
+ function tupleAuditRationale(state) {
1484
+ if (state.tupleTransition.crossedIntoTupleContradiction) {
1485
+ return state.tupleContradictionDescription;
1660
1486
  }
1661
- if (Math.abs(derivedConfidence - previousConfidence) >= 0.15) {
1487
+ return `Tuple-space contradiction cleared: b=${state.nextOpinion.b.toFixed(2)}, d=${state.nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`;
1488
+ }
1489
+ async function scheduleConfidenceFollowups(ctx, args, node, state) {
1490
+ if (Math.abs(state.derivedConfidence - state.previousConfidence) >= 0.15) {
1662
1491
  await ctx.scheduler.runAfter(
1663
1492
  5e3,
1664
1493
  internal.bi.contradictionSemanticDetector.scanAffectedBeliefs,
@@ -1675,13 +1504,6 @@ async function applyBeliefConfidenceChange(ctx, args) {
1675
1504
  { nodeId: args.nodeId }
1676
1505
  );
1677
1506
  }
1678
- return {
1679
- nodeId: args.nodeId,
1680
- previousConfidence,
1681
- newConfidence: derivedConfidence,
1682
- opinion: { b: slB, d: slD, u: slU, a: slA },
1683
- beliefConfidenceId
1684
- };
1685
1507
  }
1686
1508
  function propagationPressureLabel(edgeType, weight) {
1687
1509
  if (edgeType === "contradicts" || edgeType === "refutes") {
@@ -1709,7 +1531,7 @@ internalMutation({
1709
1531
  args.opinion_u,
1710
1532
  args.opinion_a
1711
1533
  );
1712
- const sourceNode = await ctx.db.get(args.nodeId);
1534
+ const sourceNode = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
1713
1535
  const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
1714
1536
  ctx,
1715
1537
  sourceNode
@@ -1718,16 +1540,20 @@ internalMutation({
1718
1540
  sourceNodeId: args.nodeId,
1719
1541
  sourceOpinion,
1720
1542
  sourceScope,
1721
- queryEdges: async ({ nodeId, spec, direction }) => {
1722
- return await ctx.db.query("epistemicEdges").withIndex(
1543
+ queryEdges: async ({ nodeId, spec, direction }) => readRowList(
1544
+ await ctx.db.query("epistemicEdges").withIndex(
1723
1545
  direction === "outgoing" ? "by_from_type" : "by_to_type",
1724
1546
  (q) => direction === "outgoing" ? q.eq("fromNodeId", nodeId).eq("edgeType", spec.edgeType) : q.eq("toNodeId", nodeId).eq("edgeType", spec.edgeType)
1725
- ).collect();
1726
- },
1727
- getNode: async (nodeId) => await ctx.db.get(nodeId)
1547
+ ).collect(),
1548
+ readPropagationEdge
1549
+ ),
1550
+ getNode: async (nodeId) => readConfidenceBeliefNode(await ctx.db.get(nodeId))
1728
1551
  });
1729
1552
  for (const dispatch of dispatches) {
1730
- const pressureLabel = propagationPressureLabel(dispatch.edgeType, dispatch.weight);
1553
+ const pressureLabel = propagationPressureLabel(
1554
+ dispatch.edgeType,
1555
+ dispatch.weight
1556
+ );
1731
1557
  await applyBeliefConfidenceChange(ctx, {
1732
1558
  nodeId: dispatch.targetNodeId,
1733
1559
  belief: dispatch.opinion.b,
@@ -1751,253 +1577,645 @@ internalMutation({
1751
1577
  }
1752
1578
  });
1753
1579
 
1754
- // src/epistemicContracts.evaluators.ts
1755
- var evaluatorRegistry = /* @__PURE__ */ new Map();
1756
- var BUILT_IN_EVIDENTIAL_ALIASES2 = METRIC_COMPARATOR_EVALUATOR_NAMES.evidentialAliases;
1757
- var BUILT_IN_METRIC_CHECKER2 = METRIC_COMPARATOR_EVALUATOR_NAMES.metricChecker;
1758
- var BUILT_IN_REFERENCE_CHECK_COUNTER2 = METRIC_COMPARATOR_EVALUATOR_NAMES.referenceCheckCounter;
1759
- var BUILT_IN_TEMPORAL_DEADLINE2 = METRIC_COMPARATOR_EVALUATOR_NAMES.temporalDeadline;
1760
- var BUILT_IN_MARKET_INDEX_COMPARATOR2 = METRIC_COMPARATOR_EVALUATOR_NAMES.marketIndexComparator;
1761
- var MAX_CONTRACT_EVALUATION_BATCH_SIZE = 50;
1762
- function ensureBuiltInEvaluators() {
1763
- for (const name of BUILT_IN_EVIDENTIAL_ALIASES2) {
1764
- if (evaluatorRegistry.has(name)) {
1765
- continue;
1580
+ // src/epistemicContracts.metrics.ts
1581
+ var ACTIVE_CONTRADICTION_STATUSES = /* @__PURE__ */ new Set([
1582
+ "unresolved",
1583
+ "investigating",
1584
+ "accepted_as_permanent"
1585
+ ]);
1586
+ var DEPENDENT_EDGE_TYPES = /* @__PURE__ */ new Set(["depends_on"]);
1587
+ function classifyContradictionStatus(status) {
1588
+ if (typeof status !== "string") {
1589
+ return "active";
1590
+ }
1591
+ if (ACTIVE_CONTRADICTION_STATUSES.has(status)) {
1592
+ return "active";
1593
+ }
1594
+ if (status === "resolved_support" || status === "resolved_contra" || status === "belief_forked") {
1595
+ return "resolved";
1596
+ }
1597
+ return "resolved";
1598
+ }
1599
+ function isRecord2(value) {
1600
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1601
+ }
1602
+ function readOptionalNumber2(value) {
1603
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1604
+ }
1605
+ function readOptionalString2(value) {
1606
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1607
+ }
1608
+ function readConvexId2(value) {
1609
+ const normalized = readOptionalString2(value);
1610
+ return normalized;
1611
+ }
1612
+ function readMetricNodeDoc(value) {
1613
+ if (!isRecord2(value)) {
1614
+ return null;
1615
+ }
1616
+ const id = readConvexId2(value._id);
1617
+ const nodeType = readOptionalString2(value.nodeType);
1618
+ if (!(id && nodeType)) {
1619
+ return null;
1620
+ }
1621
+ const node = { _id: id, nodeType };
1622
+ const globalId = readOptionalString2(value.globalId);
1623
+ if (globalId !== void 0) {
1624
+ node.globalId = globalId;
1625
+ }
1626
+ if ("metadata" in value) {
1627
+ node.metadata = value.metadata;
1628
+ }
1629
+ const status = readOptionalString2(value.status);
1630
+ if (status !== void 0) {
1631
+ node.status = status;
1632
+ }
1633
+ return node;
1634
+ }
1635
+ function readIncomingEdgeRow(value) {
1636
+ if (!isRecord2(value)) {
1637
+ return null;
1638
+ }
1639
+ const fromNodeId = readOptionalString2(value.fromNodeId);
1640
+ if (!fromNodeId) {
1641
+ return null;
1642
+ }
1643
+ const edge = { fromNodeId };
1644
+ const id = readConvexId2(value._id);
1645
+ if (id !== void 0) {
1646
+ edge._id = id;
1647
+ }
1648
+ const edgeType = readOptionalString2(value.edgeType);
1649
+ if (edgeType !== void 0) {
1650
+ edge.edgeType = edgeType;
1651
+ }
1652
+ const fromGlobalId = readOptionalString2(value.fromGlobalId);
1653
+ if (fromGlobalId !== void 0) {
1654
+ edge.fromGlobalId = fromGlobalId;
1655
+ }
1656
+ const fromUuid = readOptionalString2(value.fromUuid);
1657
+ if (fromUuid !== void 0) {
1658
+ edge.fromUuid = fromUuid;
1659
+ }
1660
+ const sourceGlobalId = readOptionalString2(value.sourceGlobalId);
1661
+ if (sourceGlobalId !== void 0) {
1662
+ edge.sourceGlobalId = sourceGlobalId;
1663
+ }
1664
+ const targetGlobalId = readOptionalString2(value.targetGlobalId);
1665
+ if (targetGlobalId !== void 0) {
1666
+ edge.targetGlobalId = targetGlobalId;
1667
+ }
1668
+ const toGlobalId = readOptionalString2(value.toGlobalId);
1669
+ if (toGlobalId !== void 0) {
1670
+ edge.toGlobalId = toGlobalId;
1671
+ }
1672
+ const toNodeId = readOptionalString2(value.toNodeId);
1673
+ if (toNodeId !== void 0) {
1674
+ edge.toNodeId = toNodeId;
1675
+ }
1676
+ const toUuid = readOptionalString2(value.toUuid);
1677
+ if (toUuid !== void 0) {
1678
+ edge.toUuid = toUuid;
1679
+ }
1680
+ const weight = readOptionalNumber2(value.weight);
1681
+ if (weight !== void 0) {
1682
+ edge.weight = weight;
1683
+ }
1684
+ for (const timestampField of ["_creationTime", "createdAt", "updatedAt"]) {
1685
+ const timestamp = readOptionalNumber2(value[timestampField]);
1686
+ if (timestamp !== void 0) {
1687
+ edge[timestampField] = timestamp;
1766
1688
  }
1767
- evaluatorRegistry.set(name, {
1768
- name,
1769
- evaluate: evaluateBuiltInEvidentialContract
1770
- });
1771
1689
  }
1772
- for (const evaluator of ENGINEERING_EPISTEMIC_EVALUATORS) {
1773
- if (evaluatorRegistry.has(evaluator.name)) {
1774
- continue;
1690
+ return edge;
1691
+ }
1692
+ function getEdgeTimestamp(edge) {
1693
+ if (typeof edge.updatedAt === "number") {
1694
+ return edge.updatedAt;
1695
+ }
1696
+ if (typeof edge.createdAt === "number") {
1697
+ return edge.createdAt;
1698
+ }
1699
+ if (typeof edge._creationTime === "number") {
1700
+ return edge._creationTime;
1701
+ }
1702
+ return null;
1703
+ }
1704
+ async function collectNodeEndpointRefs(ctx, nodeId) {
1705
+ const refs = /* @__PURE__ */ new Set([String(nodeId)]);
1706
+ const node = readMetricNodeDoc(await ctx.db.get(nodeId));
1707
+ if (node?.globalId) {
1708
+ refs.add(node.globalId);
1709
+ }
1710
+ return [...refs];
1711
+ }
1712
+ async function collectIncomingEdgeRows(ctx, nodeId, edgeType) {
1713
+ const refs = await collectNodeEndpointRefs(ctx, nodeId);
1714
+ const seen = /* @__PURE__ */ new Set();
1715
+ const edges = [];
1716
+ for (const ref of refs) {
1717
+ const rows = edgeType === void 0 ? await ctx.db.query("epistemicEdges").withIndex("by_to", (q) => q.eq("toNodeId", ref)).collect() : await ctx.db.query("epistemicEdges").withIndex(
1718
+ "by_to_type",
1719
+ (q) => q.eq("toNodeId", ref).eq("edgeType", edgeType)
1720
+ ).collect();
1721
+ for (const row of rows) {
1722
+ const edge = readIncomingEdgeRow(row);
1723
+ if (!edge) {
1724
+ continue;
1725
+ }
1726
+ if (edgeType !== void 0 && edge.edgeType !== edgeType) {
1727
+ continue;
1728
+ }
1729
+ const key = edge._id === void 0 ? `${edge.fromNodeId}->${edge.toNodeId ?? ref}:${edge.edgeType ?? ""}` : String(edge._id);
1730
+ if (seen.has(key)) {
1731
+ continue;
1732
+ }
1733
+ seen.add(key);
1734
+ edges.push(edge);
1775
1735
  }
1776
- evaluatorRegistry.set(evaluator.name, evaluator);
1777
1736
  }
1778
- const researchEvaluators = [
1779
- [BUILT_IN_METRIC_CHECKER2, evaluateMetricCheckerContract],
1780
- [BUILT_IN_REFERENCE_CHECK_COUNTER2, evaluateReferenceCheckCounterContract],
1781
- [BUILT_IN_TEMPORAL_DEADLINE2, evaluateTemporalDeadlineContract],
1782
- [BUILT_IN_MARKET_INDEX_COMPARATOR2, evaluateMarketIndexComparatorContract]
1783
- ];
1784
- for (const [name, evaluate] of researchEvaluators) {
1785
- if (evaluatorRegistry.has(name)) {
1786
- continue;
1737
+ return edges;
1738
+ }
1739
+ function sourceEndpointRefs(edge) {
1740
+ return [
1741
+ edge.fromNodeId,
1742
+ edge.sourceGlobalId,
1743
+ edge.fromGlobalId,
1744
+ edge.fromUuid
1745
+ ].filter((value) => value !== void 0);
1746
+ }
1747
+ async function resolveEndpointNode(ctx, refs) {
1748
+ const candidates = refs.map((value) => value.trim()).filter(
1749
+ (value, index, values) => value.length > 0 && values.indexOf(value) === index
1750
+ );
1751
+ for (const candidate of candidates) {
1752
+ try {
1753
+ const direct = readMetricNodeDoc(
1754
+ await ctx.db.get(candidate)
1755
+ );
1756
+ if (direct) {
1757
+ return direct;
1758
+ }
1759
+ } catch {
1760
+ }
1761
+ const byGlobalId = readMetricNodeDoc(
1762
+ await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first()
1763
+ );
1764
+ if (byGlobalId) {
1765
+ return byGlobalId;
1787
1766
  }
1788
- evaluatorRegistry.set(name, { name, evaluate });
1789
1767
  }
1768
+ return null;
1790
1769
  }
1791
- function normalizeTrigger(trigger) {
1792
- if (trigger === "evidence_added") {
1793
- return "evidence_added";
1770
+ async function getEvidenceLinks(ctx, beliefNodeId) {
1771
+ const edges = await collectIncomingEdgeRows(ctx, beliefNodeId, "informs");
1772
+ if (edges.length === 0) {
1773
+ return [];
1794
1774
  }
1795
- if (trigger === "periodic") {
1796
- return "periodic";
1775
+ const links = [];
1776
+ for (const edge of edges) {
1777
+ const node = await resolveEndpointNode(ctx, sourceEndpointRefs(edge));
1778
+ if (node?.nodeType !== "evidence" || node.status === "archived") {
1779
+ continue;
1780
+ }
1781
+ links.push({ edge, node });
1797
1782
  }
1798
- if (trigger === "manual") {
1799
- return "manual";
1783
+ return links;
1784
+ }
1785
+ function getEvidenceTags(node) {
1786
+ const metadata = node.metadata && typeof node.metadata === "object" ? node.metadata : null;
1787
+ const tags = metadata?.tags;
1788
+ if (!Array.isArray(tags)) {
1789
+ return [];
1800
1790
  }
1801
- return "event_driven";
1791
+ return tags.filter((tag) => typeof tag === "string");
1802
1792
  }
1803
- function resolveSchedulesForTrigger(trigger) {
1804
- if (trigger === "evidence_added") {
1805
- return /* @__PURE__ */ new Set(["on_evidence", "event_driven"]);
1793
+ async function computeEvidenceCountMetric(ctx, beliefNodeId) {
1794
+ return (await getEvidenceLinks(ctx, beliefNodeId)).length;
1795
+ }
1796
+ async function computeTaggedEvidenceCount(args) {
1797
+ const expectedTag = args.caseSensitive ? args.tag : args.tag.toLowerCase();
1798
+ const matchedEvidenceIds = (await getEvidenceLinks(args.ctx, args.beliefNodeId)).filter(
1799
+ ({ node }) => getEvidenceTags(node).some(
1800
+ (tag) => (args.caseSensitive ? tag : tag.toLowerCase()) === expectedTag
1801
+ )
1802
+ ).map(({ node }) => String(node._id));
1803
+ return {
1804
+ count: matchedEvidenceIds.length,
1805
+ matchedEvidenceIds
1806
+ };
1807
+ }
1808
+ async function computeContradictionCounts(ctx, beliefNodeId) {
1809
+ const contradictionDb = ctx.db;
1810
+ const contradictions = await contradictionDb.query("contradictions").withIndex("by_beliefId", (q) => q.eq("beliefId", beliefNodeId)).collect();
1811
+ return contradictions.reduce(
1812
+ (counts, contradiction) => {
1813
+ const status = contradiction.resolutionStatus ?? contradiction.status ?? "unresolved";
1814
+ if (classifyContradictionStatus(status) === "active") {
1815
+ counts.activeCount += 1;
1816
+ } else {
1817
+ counts.resolvedCount += 1;
1818
+ }
1819
+ return counts;
1820
+ },
1821
+ { activeCount: 0, resolvedCount: 0 }
1822
+ );
1823
+ }
1824
+ async function computeEvidenceFreshness(ctx, beliefNodeId, now = Date.now()) {
1825
+ const timestamps = (await getEvidenceLinks(ctx, beliefNodeId)).map(({ edge }) => getEdgeTimestamp(edge)).filter((value) => value !== null);
1826
+ if (timestamps.length === 0) {
1827
+ return {
1828
+ newestAgeMs: null,
1829
+ oldestAgeMs: null,
1830
+ newestEdgeAt: null,
1831
+ oldestEdgeAt: null,
1832
+ edgeCount: 0
1833
+ };
1806
1834
  }
1807
- if (trigger === "periodic") {
1808
- return /* @__PURE__ */ new Set(["periodic"]);
1835
+ const newestEdgeAt = Math.max(...timestamps);
1836
+ const oldestEdgeAt = Math.min(...timestamps);
1837
+ return {
1838
+ newestAgeMs: Math.max(0, now - newestEdgeAt),
1839
+ oldestAgeMs: Math.max(0, now - oldestEdgeAt),
1840
+ newestEdgeAt,
1841
+ oldestEdgeAt,
1842
+ edgeCount: timestamps.length
1843
+ };
1844
+ }
1845
+ async function computeDependentBeliefCount(ctx, beliefNodeId) {
1846
+ const incomingEdges = await collectIncomingEdgeRows(ctx, beliefNodeId);
1847
+ const dependencyEdges = incomingEdges.filter(
1848
+ (edge) => edge.edgeType ? DEPENDENT_EDGE_TYPES.has(edge.edgeType) : false
1849
+ );
1850
+ if (dependencyEdges.length === 0) {
1851
+ return 0;
1809
1852
  }
1810
- if (trigger === "manual") {
1811
- return /* @__PURE__ */ new Set(["on_demand", "event_driven"]);
1853
+ const uniqueBeliefIds = /* @__PURE__ */ new Set();
1854
+ for (const edge of dependencyEdges) {
1855
+ const node = await resolveEndpointNode(ctx, sourceEndpointRefs(edge));
1856
+ if (node && node.nodeType === "belief" && node.status !== "archived" && node.status !== "deleted") {
1857
+ uniqueBeliefIds.add(String(node._id));
1858
+ }
1812
1859
  }
1813
- return /* @__PURE__ */ new Set(["event_driven"]);
1860
+ return uniqueBeliefIds.size;
1814
1861
  }
1815
- async function executeContractEvaluation(args) {
1816
- ensureBuiltInEvaluators();
1817
- const evaluator = evaluatorRegistry.get(args.contract.condition.evaluator);
1818
- let evaluation;
1819
- if (evaluator) {
1820
- try {
1821
- evaluation = await evaluator.evaluate({
1822
- belief: args.belief,
1823
- contract: args.contract,
1824
- ctx: args.ctx,
1825
- now: args.now,
1826
- resultData: args.resultData,
1827
- trigger: args.trigger,
1828
- inputData: args.inputData
1829
- });
1830
- } catch (error) {
1831
- evaluation = {
1832
- result: "error",
1833
- rationale: error instanceof Error ? error.message : "Unknown evaluator error."
1862
+ async function snapshotEvidentialMetric(args) {
1863
+ switch (args.metric) {
1864
+ case "evidence_count": {
1865
+ const count = await computeEvidenceCountMetric(
1866
+ args.ctx,
1867
+ args.beliefNodeId
1868
+ );
1869
+ return {
1870
+ metric: args.metric,
1871
+ value: count,
1872
+ data: { evidenceCount: count }
1873
+ };
1874
+ }
1875
+ case "contradiction_status": {
1876
+ const counts = await computeContradictionCounts(
1877
+ args.ctx,
1878
+ args.beliefNodeId
1879
+ );
1880
+ return {
1881
+ metric: args.metric,
1882
+ value: counts.activeCount,
1883
+ data: counts
1884
+ };
1885
+ }
1886
+ case "edge_freshness": {
1887
+ const freshness = await computeEvidenceFreshness(
1888
+ args.ctx,
1889
+ args.beliefNodeId,
1890
+ args.now
1891
+ );
1892
+ return {
1893
+ metric: args.metric,
1894
+ value: freshness.newestAgeMs,
1895
+ data: freshness
1834
1896
  };
1835
1897
  }
1836
- } else {
1837
- evaluation = {
1838
- result: "error",
1839
- rationale: `No epistemic evaluator registered for "${args.contract.condition.evaluator}".`
1840
- };
1841
- }
1842
- const confidenceBefore = typeof args.currentConfidence === "number" ? args.currentConfidence : typeof args.belief.confidence === "number" ? args.belief.confidence : 0.5;
1843
- const modulationPlan = deriveContractModulationPlan({
1844
- currentConfidence: confidenceBefore,
1845
- modulation: args.contract.modulation,
1846
- result: evaluation.result,
1847
- resultConfidence: evaluation.confidence
1848
- });
1849
- let beliefConfidenceId;
1850
- let confidenceAfter = confidenceBefore;
1851
- if (modulationPlan) {
1852
- const contractB = Math.max(0, Math.min(1, modulationPlan.confidenceAfter));
1853
- const modulationResult = await applyBeliefConfidenceChange(args.ctx, {
1854
- nodeId: args.contract.beliefNodeId,
1855
- belief: contractB,
1856
- disbelief: 1 - contractB,
1857
- uncertainty: 0,
1858
- baseRate: 0.5,
1859
- trigger: modulationPlan.trigger,
1860
- rationale: `Epistemic contract "${args.contract.title}" ${evaluation.result}: ${evaluation.rationale}`,
1861
- authenticatedUserId: args.authenticatedUserId
1862
- });
1863
- beliefConfidenceId = modulationResult.beliefConfidenceId;
1864
- confidenceAfter = typeof modulationResult.newConfidence === "number" ? modulationResult.newConfidence : modulationPlan.confidenceAfter;
1898
+ case "dependent_count": {
1899
+ const count = await computeDependentBeliefCount(
1900
+ args.ctx,
1901
+ args.beliefNodeId
1902
+ );
1903
+ return {
1904
+ metric: args.metric,
1905
+ value: count,
1906
+ data: { dependentCount: count }
1907
+ };
1908
+ }
1909
+ default:
1910
+ return {
1911
+ metric: args.metric,
1912
+ value: null,
1913
+ data: {}
1914
+ };
1865
1915
  }
1866
- const evaluationId = await args.ctx.db.insert("contractEvaluations", {
1867
- contractId: args.contract.contractId,
1868
- beliefNodeId: args.contract.beliefNodeId,
1869
- result: evaluation.result,
1870
- evaluatedAt: args.now,
1871
- evaluator: args.contract.condition.evaluator,
1872
- trigger: args.trigger,
1873
- resultData: evaluation.data,
1874
- modulationApplied: Boolean(modulationPlan),
1875
- confidenceDelta: modulationPlan?.confidenceDelta,
1876
- confidenceBefore: modulationPlan?.confidenceBefore,
1877
- confidenceAfter: modulationPlan ? confidenceAfter : void 0,
1878
- beliefConfidenceId,
1879
- modulationRationale: evaluation.rationale,
1880
- topicId: args.contract.topicId
1916
+ }
1917
+ async function evaluateBuiltInEvidentialContract(args) {
1918
+ const config = parseEvidentialEvaluatorConfig(
1919
+ args.contract.condition.evaluatorConfig
1920
+ );
1921
+ const snapshot = await snapshotEvidentialMetric({
1922
+ ctx: args.ctx,
1923
+ beliefNodeId: args.belief._id,
1924
+ metric: config.metric,
1925
+ now: args.now
1881
1926
  });
1882
- const nextStatus = deriveContractStatus(evaluation.result, args.contract.status);
1883
- await args.ctx.db.patch(
1884
- args.contract._id,
1885
- {
1886
- status: nextStatus,
1887
- lastEvaluatedAt: args.now,
1888
- evaluationCount: (args.contract.evaluationCount ?? 0) + 1,
1889
- updatedAt: args.now
1890
- }
1927
+ const comparisonSatisfied = snapshot.value !== null && compareMetricValue(config.operator, snapshot.value, config.threshold);
1928
+ const result = resolveComparisonResult(
1929
+ args.contract.direction,
1930
+ comparisonSatisfied
1891
1931
  );
1892
1932
  return {
1893
- evaluationId,
1894
- result: evaluation.result,
1895
- status: nextStatus,
1896
- confidenceBefore,
1897
- confidenceAfter,
1898
- rationale: evaluation.rationale,
1899
- data: evaluation.data,
1900
- currentConfidence: confidenceAfter
1933
+ result,
1934
+ rationale: buildEvidentialRationale({
1935
+ config,
1936
+ snapshot,
1937
+ comparisonSatisfied,
1938
+ result
1939
+ }),
1940
+ data: {
1941
+ ...snapshot.data,
1942
+ metric: config.metric,
1943
+ observedValue: snapshot.value,
1944
+ operator: config.operator,
1945
+ threshold: config.threshold,
1946
+ action: config.action ?? "append_sl_scoring",
1947
+ actionParams: config.actionParams
1948
+ }
1901
1949
  };
1902
1950
  }
1903
- async function evaluateContractsForTriggerBatch(args) {
1904
- const startedAt = Date.now();
1905
- const contracts = await loadContractsForTrigger({
1951
+ function evaluateMetricCheckerContract(args) {
1952
+ return Promise.resolve().then(() => {
1953
+ const config = parseMetricCheckerConfig(
1954
+ args.contract.condition.evaluatorConfig
1955
+ );
1956
+ const input = getEvaluatorInputRecord(args.inputData, "metricData");
1957
+ const metric = typeof input.metric === "string" && input.metric.length > 0 ? input.metric : config.metric;
1958
+ const observedValue = pickFiniteNumber(input, [
1959
+ "observedValue",
1960
+ "currentValue",
1961
+ "metricValue",
1962
+ "value"
1963
+ ]) ?? config.observedValue ?? config.currentValue ?? config.metricValue ?? null;
1964
+ if (observedValue === null) {
1965
+ return {
1966
+ result: "inconclusive",
1967
+ rationale: `metric_checker is awaiting data for ${metric ?? args.contract.condition.expression}.`,
1968
+ data: {
1969
+ metric,
1970
+ observedValue: null,
1971
+ operator: config.operator,
1972
+ threshold: config.threshold,
1973
+ unit: config.unit
1974
+ }
1975
+ };
1976
+ }
1977
+ const comparisonSatisfied = compareMetricValue(
1978
+ config.operator,
1979
+ observedValue,
1980
+ config.threshold
1981
+ );
1982
+ const result = resolveComparisonResult(
1983
+ args.contract.direction,
1984
+ comparisonSatisfied
1985
+ );
1986
+ return {
1987
+ result,
1988
+ rationale: buildComparisonRationale({
1989
+ label: metric ?? "metric",
1990
+ observedValue,
1991
+ operator: config.operator,
1992
+ threshold: config.threshold,
1993
+ comparisonSatisfied,
1994
+ result,
1995
+ unit: config.unit
1996
+ }),
1997
+ data: {
1998
+ metric,
1999
+ observedValue,
2000
+ operator: config.operator,
2001
+ threshold: config.threshold,
2002
+ unit: config.unit
2003
+ }
2004
+ };
2005
+ });
2006
+ }
2007
+ async function evaluateReferenceCheckCounterContract(args) {
2008
+ const config = parseReferenceCheckCounterConfig(
2009
+ args.contract.condition.evaluatorConfig
2010
+ );
2011
+ const input = getEvaluatorInputRecord(args.inputData, "referenceCheckData");
2012
+ const tag = typeof input.tag === "string" && input.tag.trim().length > 0 ? input.tag.trim() : config.tag;
2013
+ const snapshot = await computeTaggedEvidenceCount({
1906
2014
  ctx: args.ctx,
1907
2015
  beliefNodeId: args.belief._id,
1908
- trigger: normalizeTrigger(args.trigger),
1909
- contractIds: args.contractIds
2016
+ tag,
2017
+ caseSensitive: config.caseSensitive
1910
2018
  });
1911
- const batchLimit = Math.max(
1912
- 1,
1913
- Math.min(
1914
- args.maxBatchSize ?? MAX_CONTRACT_EVALUATION_BATCH_SIZE,
1915
- MAX_CONTRACT_EVALUATION_BATCH_SIZE
1916
- )
2019
+ const comparisonSatisfied = compareMetricValue(
2020
+ config.operator,
2021
+ snapshot.count,
2022
+ config.threshold
1917
2023
  );
1918
- const currentBatch = contracts.slice(0, batchLimit);
1919
- const overflowContracts = contracts.slice(batchLimit);
1920
- let runningConfidence = typeof args.belief.confidence === "number" ? args.belief.confidence : 0.5;
1921
- const results = [];
1922
- for (const contract of currentBatch) {
1923
- const evaluation = await executeContractEvaluation({
1924
- ctx: args.ctx,
1925
- belief: args.belief,
1926
- contract,
1927
- now: Date.now(),
1928
- trigger: normalizeTrigger(args.trigger),
1929
- inputData: args.inputData,
1930
- authenticatedUserId: args.authenticatedUserId,
1931
- currentConfidence: runningConfidence
1932
- });
1933
- runningConfidence = evaluation.currentConfidence;
1934
- args.belief.confidence = runningConfidence;
1935
- results.push({
1936
- contractId: contract.contractId,
1937
- result: evaluation.result,
1938
- status: evaluation.status,
1939
- confidenceAfter: evaluation.confidenceAfter
1940
- });
1941
- }
1942
- if (overflowContracts.length > 0) {
1943
- await args.ctx.scheduler.runAfter(
1944
- 0,
1945
- "epistemicContracts.processContractEvaluationOverflow",
1946
- {
1947
- beliefNodeId: args.belief._id,
1948
- trigger: normalizeTrigger(args.trigger),
1949
- contractIds: overflowContracts.map((contract) => contract.contractId),
1950
- inputData: args.inputData,
1951
- authenticatedUserId: args.authenticatedUserId,
1952
- maxBatchSize: batchLimit
2024
+ const result = resolveComparisonResult(
2025
+ args.contract.direction,
2026
+ comparisonSatisfied
2027
+ );
2028
+ return {
2029
+ result,
2030
+ rationale: buildComparisonRationale({
2031
+ label: `reference checks tagged "${tag}"`,
2032
+ observedValue: snapshot.count,
2033
+ operator: config.operator,
2034
+ threshold: config.threshold,
2035
+ comparisonSatisfied,
2036
+ result
2037
+ }),
2038
+ data: {
2039
+ tag,
2040
+ observedValue: snapshot.count,
2041
+ referenceCheckCount: snapshot.count,
2042
+ matchedEvidenceIds: snapshot.matchedEvidenceIds,
2043
+ operator: config.operator,
2044
+ threshold: config.threshold,
2045
+ caseSensitive: config.caseSensitive ?? false
2046
+ }
2047
+ };
2048
+ }
2049
+ function resolveCompletedTemporalDeadlineResult(args) {
2050
+ const { completedAt, context, deadline, label } = args;
2051
+ if (completedAt !== void 0 && completedAt > deadline) {
2052
+ return {
2053
+ result: "expired",
2054
+ rationale: `${label} completed at ${completedAt}, after deadline ${deadline}.`,
2055
+ data: {
2056
+ label,
2057
+ deadline,
2058
+ completed: true,
2059
+ completedAt,
2060
+ missedDeadline: true,
2061
+ overdueByMs: completedAt - deadline
1953
2062
  }
1954
- );
2063
+ };
1955
2064
  }
1956
- const executionTimeMs = Date.now() - startedAt;
1957
- console.info("[epistemicContracts] processed contract evaluation batch", {
1958
- beliefNodeId: String(args.belief._id),
1959
- trigger: normalizeTrigger(args.trigger),
1960
- batchSize: currentBatch.length,
1961
- overflowCount: overflowContracts.length,
1962
- executionTimeMs
1963
- });
2065
+ const result = context.contract.direction === "falsifies" ? "disconfirmed" : "confirmed";
1964
2066
  return {
1965
- totalContracts: contracts.length,
1966
- processedCount: currentBatch.length,
1967
- overflowCount: overflowContracts.length,
1968
- scheduledOverflow: overflowContracts.length > 0,
1969
- batchSize: currentBatch.length,
1970
- executionTimeMs,
1971
- trigger: normalizeTrigger(args.trigger),
1972
- results
2067
+ result,
2068
+ rationale: `${label} completed before deadline ${deadline}.`,
2069
+ data: {
2070
+ label,
2071
+ deadline,
2072
+ completed: true,
2073
+ completedAt: completedAt ?? null,
2074
+ missedDeadline: false
2075
+ }
1973
2076
  };
1974
2077
  }
1975
- async function loadContractsForBelief(args) {
1976
- return await args.ctx.db.query("epistemicContracts").withIndex("by_belief", (q) => q.eq("beliefNodeId", args.beliefNodeId)).collect();
1977
- }
1978
- async function loadContractsForTrigger(args) {
1979
- const contracts = await loadContractsForBelief(args);
1980
- ensureBuiltInEvaluators();
1981
- const allowedSchedules = resolveSchedulesForTrigger(args.trigger);
1982
- const contractIdFilter = args.contractIds && args.contractIds.length > 0 ? new Set(args.contractIds) : null;
1983
- return contracts.filter((contract) => {
1984
- if (contract.status === "archived") {
1985
- return false;
2078
+ function resolveOpenTemporalDeadlineResult(args) {
2079
+ const { context, deadline, label } = args;
2080
+ if (context.now > deadline) {
2081
+ return {
2082
+ result: "expired",
2083
+ rationale: `${label} missed deadline ${deadline}; temporal contract expired.`,
2084
+ data: {
2085
+ label,
2086
+ deadline,
2087
+ completed: false,
2088
+ overdueByMs: context.now - deadline
2089
+ }
2090
+ };
2091
+ }
2092
+ return {
2093
+ result: "inconclusive",
2094
+ rationale: `${label} is still before deadline ${deadline}; awaiting outcome.`,
2095
+ data: {
2096
+ label,
2097
+ deadline,
2098
+ completed: false,
2099
+ timeRemainingMs: deadline - context.now
1986
2100
  }
1987
- if (contract.conditionType === "composite") {
1988
- return false;
2101
+ };
2102
+ }
2103
+ function evaluateTemporalDeadlineContract(args) {
2104
+ return Promise.resolve().then(() => {
2105
+ if (typeof args.contract.deadline !== "number" || !Number.isFinite(args.contract.deadline)) {
2106
+ throw new Error(
2107
+ "temporal_deadline requires contract.deadline to be set to a finite timestamp."
2108
+ );
1989
2109
  }
1990
- if (!evaluatorRegistry.has(contract.condition.evaluator)) {
1991
- return false;
2110
+ const deadline = args.contract.deadline;
2111
+ const config = parseTemporalDeadlineConfig(
2112
+ args.contract.condition.evaluatorConfig
2113
+ );
2114
+ const input = getEvaluatorInputRecord(args.inputData, "temporalData");
2115
+ const label = (typeof input.label === "string" && input.label.length > 0 ? input.label : config.label) ?? args.contract.title ?? args.contract.condition.expression;
2116
+ const completedAt = pickFiniteNumber(input, [
2117
+ "completedAt",
2118
+ "observedAt",
2119
+ "satisfiedAt",
2120
+ "achievedAt"
2121
+ ]) ?? config.completedAt ?? config.observedAt ?? config.satisfiedAt ?? config.achievedAt;
2122
+ const completed = input.completed === true || config.completed === true || completedAt !== void 0;
2123
+ if (completed) {
2124
+ return resolveCompletedTemporalDeadlineResult({
2125
+ completedAt,
2126
+ context: args,
2127
+ deadline,
2128
+ label
2129
+ });
1992
2130
  }
1993
- if (contractIdFilter) {
1994
- return contractIdFilter.has(contract.contractId);
2131
+ return resolveOpenTemporalDeadlineResult({
2132
+ context: args,
2133
+ deadline,
2134
+ label
2135
+ });
2136
+ });
2137
+ }
2138
+ function evaluateMarketIndexComparatorContract(args) {
2139
+ return Promise.resolve().then(() => {
2140
+ const config = parseMarketIndexComparatorConfig(
2141
+ args.contract.condition.evaluatorConfig
2142
+ );
2143
+ const input = getEvaluatorInputRecord(args.inputData, "marketIndexData");
2144
+ const subject = typeof input.subject === "string" && input.subject.length > 0 ? input.subject : config.subject;
2145
+ const benchmark = typeof input.benchmark === "string" && input.benchmark.length > 0 ? input.benchmark : config.benchmark;
2146
+ const subjectValue = pickFiniteNumber(input, ["subjectValue", "primaryValue", "leftValue"]) ?? config.subjectValue ?? config.primaryValue ?? null;
2147
+ const benchmarkValue = pickFiniteNumber(input, [
2148
+ "benchmarkValue",
2149
+ "comparisonValue",
2150
+ "rightValue"
2151
+ ]) ?? config.benchmarkValue ?? config.comparisonValue ?? null;
2152
+ if (subjectValue === null || benchmarkValue === null) {
2153
+ return {
2154
+ result: "inconclusive",
2155
+ rationale: "market_index_comparator is awaiting both subject and benchmark values.",
2156
+ data: {
2157
+ subject,
2158
+ subjectValue,
2159
+ benchmark,
2160
+ benchmarkValue,
2161
+ operator: config.operator,
2162
+ threshold: config.threshold
2163
+ }
2164
+ };
1995
2165
  }
1996
- return allowedSchedules.has(contract.evaluationSchedule);
2166
+ if (benchmarkValue === 0) {
2167
+ throw new Error(
2168
+ "market_index_comparator cannot compare against a zero benchmark value."
2169
+ );
2170
+ }
2171
+ const differentialPercent = (subjectValue - benchmarkValue) / Math.abs(benchmarkValue) * 100;
2172
+ const comparisonSatisfied = compareMetricValue(
2173
+ config.operator,
2174
+ differentialPercent,
2175
+ config.threshold
2176
+ );
2177
+ const result = resolveComparisonResult(
2178
+ args.contract.direction,
2179
+ comparisonSatisfied
2180
+ );
2181
+ return {
2182
+ result,
2183
+ rationale: buildComparisonRationale({
2184
+ label: `${subject ?? "subject"} vs ${benchmark ?? "benchmark"} differential`,
2185
+ observedValue: differentialPercent,
2186
+ operator: config.operator,
2187
+ threshold: config.threshold,
2188
+ comparisonSatisfied,
2189
+ result,
2190
+ unit: "%"
2191
+ }),
2192
+ data: {
2193
+ subject,
2194
+ subjectValue,
2195
+ benchmark,
2196
+ benchmarkValue,
2197
+ differentialPercent,
2198
+ operator: config.operator,
2199
+ threshold: config.threshold
2200
+ }
2201
+ };
1997
2202
  });
1998
2203
  }
2204
+ var METRIC_COMPARATOR_EVALUATOR_NAMES = {
2205
+ evidentialAliases: /* @__PURE__ */ new Set([
2206
+ "evidential",
2207
+ "built_in_evidential",
2208
+ "builtin_evidential"
2209
+ ]),
2210
+ metricChecker: "metric_checker",
2211
+ referenceCheckCounter: "reference_check_counter",
2212
+ temporalDeadline: "temporal_deadline",
2213
+ marketIndexComparator: "market_index_comparator"
2214
+ };
1999
2215
 
2000
2216
  // src/evaluators/shared.ts
2217
+ var WINDOWS_PATH_SEPARATORS = /\\/g;
2218
+ var LEADING_DOT_SLASH = /^\.\//;
2001
2219
  function asArray(value) {
2002
2220
  return Array.isArray(value) ? value : [];
2003
2221
  }
@@ -2039,7 +2257,7 @@ function extractTextCandidates(value) {
2039
2257
  return Array.from(new Set(candidates));
2040
2258
  }
2041
2259
  function normalizeFilePath(value) {
2042
- return value.replace(/\\/g, "/").replace(/^\.\//, "");
2260
+ return value.replace(WINDOWS_PATH_SEPARATORS, "/").replace(LEADING_DOT_SLASH, "");
2043
2261
  }
2044
2262
  function normalizeToolResultEnvelope(value) {
2045
2263
  const record = asRecord(value);
@@ -2093,7 +2311,7 @@ function somePatternMatches(filePath, patterns) {
2093
2311
  return patterns.some((pattern) => patternMatchesPath(filePath, pattern));
2094
2312
  }
2095
2313
 
2096
- // src/evaluators/lintCheckerEvaluator.ts
2314
+ // src/evaluators/lint-checker-evaluator.ts
2097
2315
  function parseConfig(condition) {
2098
2316
  const record = asRecord(condition.evaluatorConfig);
2099
2317
  if (!record) {
@@ -2165,7 +2383,10 @@ var lintCheckerEvaluator = {
2165
2383
  }
2166
2384
  const envelope = normalizeToolResultEnvelope(args.resultData);
2167
2385
  const exitCode = asNumber(envelope.exitCode);
2168
- const matchedDiagnostics = getMatchedDiagnostics(args.contract, args.resultData);
2386
+ const matchedDiagnostics = getMatchedDiagnostics(
2387
+ args.contract,
2388
+ args.resultData
2389
+ );
2169
2390
  if (matchedDiagnostics.length === 0 && exitCode !== 0 && exitCode !== null) {
2170
2391
  return {
2171
2392
  result: "inconclusive",
@@ -2191,7 +2412,7 @@ var lintCheckerEvaluator = {
2191
2412
  }
2192
2413
  };
2193
2414
 
2194
- // src/evaluators/sentryCheckerEvaluator.ts
2415
+ // src/evaluators/sentry-checker-evaluator.ts
2195
2416
  function parseConfig2(condition) {
2196
2417
  const record = asRecord(condition.evaluatorConfig);
2197
2418
  if (!record) {
@@ -2276,7 +2497,7 @@ var sentryCheckerEvaluator = {
2276
2497
  }
2277
2498
  };
2278
2499
 
2279
- // src/evaluators/testRunnerEvaluator.ts
2500
+ // src/evaluators/test-runner-evaluator.ts
2280
2501
  function parseConfig3(condition) {
2281
2502
  const record = asRecord(condition.evaluatorConfig);
2282
2503
  if (!record) {
@@ -2422,7 +2643,7 @@ var testRunnerEvaluator = {
2422
2643
  }
2423
2644
  };
2424
2645
 
2425
- // src/evaluators/tscCheckerEvaluator.ts
2646
+ // src/evaluators/tsc-checker-evaluator.ts
2426
2647
  function parseConfig4(condition) {
2427
2648
  const record = asRecord(condition.evaluatorConfig);
2428
2649
  if (!record) {
@@ -2434,118 +2655,383 @@ function parseConfig4(condition) {
2434
2655
  if (filePatterns.length === 0) {
2435
2656
  throw new Error("tsc_checker requires at least one file pattern.");
2436
2657
  }
2437
- return { filePatterns };
2658
+ return { filePatterns };
2659
+ }
2660
+ function parseStructuredDiagnostics(resultData) {
2661
+ const envelope = normalizeToolResultEnvelope(resultData);
2662
+ const record = asRecord(envelope.report) ?? asRecord(envelope.data) ?? asRecord(resultData);
2663
+ if (!record) {
2664
+ return [];
2665
+ }
2666
+ return asArray(record.diagnostics).flatMap((entry) => {
2667
+ const diagnostic = asRecord(entry);
2668
+ if (!diagnostic) {
2669
+ return [];
2670
+ }
2671
+ const filePath = asString(diagnostic.filePath) ?? asString(diagnostic.file) ?? asString(asRecord(diagnostic.location)?.filePath) ?? asString(asRecord(asRecord(diagnostic.location)?.path)?.file);
2672
+ const message = asString(diagnostic.message) ?? "TypeScript error";
2673
+ return [
2674
+ {
2675
+ code: asString(diagnostic.code) ?? void 0,
2676
+ filePath: filePath ? normalizeFilePath(filePath) : null,
2677
+ message
2678
+ }
2679
+ ];
2680
+ });
2681
+ }
2682
+ function parseTextDiagnostics(resultData) {
2683
+ const diagnostics = [];
2684
+ const patterns = [
2685
+ /^(.+?)\((\d+),(\d+)\): error TS(\d+): (.+)$/gm,
2686
+ /^(.+?):(\d+):(\d+) - error TS(\d+): (.+)$/gm
2687
+ ];
2688
+ for (const text of extractTextCandidates(resultData)) {
2689
+ for (const pattern of patterns) {
2690
+ for (const match of text.matchAll(pattern)) {
2691
+ diagnostics.push({
2692
+ code: match[4],
2693
+ filePath: normalizeFilePath(match[1] ?? ""),
2694
+ message: match[5] ?? "TypeScript error"
2695
+ });
2696
+ }
2697
+ }
2698
+ }
2699
+ return diagnostics;
2700
+ }
2701
+ function parseDiagnostics2(resultData) {
2702
+ const structured = parseStructuredDiagnostics(resultData);
2703
+ return structured.length > 0 ? structured : parseTextDiagnostics(resultData);
2704
+ }
2705
+ function getMatchedDiagnostics2(contract, resultData) {
2706
+ const config = parseConfig4(contract.condition);
2707
+ return parseDiagnostics2(resultData).filter(
2708
+ (diagnostic) => somePatternMatches(diagnostic.filePath, config.filePatterns)
2709
+ );
2710
+ }
2711
+ var tscCheckerEvaluator = {
2712
+ name: "tsc_checker",
2713
+ matches({ contract, resultData }) {
2714
+ const envelope = normalizeToolResultEnvelope(resultData);
2715
+ const exitCode = asNumber(envelope.exitCode);
2716
+ if (exitCode === 0) {
2717
+ return true;
2718
+ }
2719
+ return getMatchedDiagnostics2(contract, resultData).length > 0;
2720
+ },
2721
+ evaluate(args) {
2722
+ const config = parseConfig4(args.contract.condition);
2723
+ if (!args.resultData) {
2724
+ return {
2725
+ result: "error",
2726
+ rationale: "tsc_checker requires TypeScript diagnostic resultData."
2727
+ };
2728
+ }
2729
+ const envelope = normalizeToolResultEnvelope(args.resultData);
2730
+ const exitCode = asNumber(envelope.exitCode);
2731
+ const matchedDiagnostics = getMatchedDiagnostics2(
2732
+ args.contract,
2733
+ args.resultData
2734
+ );
2735
+ if (matchedDiagnostics.length === 0 && exitCode !== 0 && exitCode !== null) {
2736
+ return {
2737
+ result: "inconclusive",
2738
+ rationale: "TypeScript reported errors, but none matched the configured file patterns."
2739
+ };
2740
+ }
2741
+ const conditionSatisfied = exitCode === 0 || exitCode !== null && matchedDiagnostics.length === 0;
2742
+ return {
2743
+ result: deriveDirectionalResult(
2744
+ args.contract.direction,
2745
+ conditionSatisfied
2746
+ ),
2747
+ rationale: conditionSatisfied ? `TypeScript reported no matching diagnostics for ${config.filePatterns.join(", ")}.` : `TypeScript found ${matchedDiagnostics.length} matching diagnostic(s): ${matchedDiagnostics.map(
2748
+ (diagnostic) => diagnostic.filePath ? `${diagnostic.filePath}${diagnostic.code ? ` (TS${diagnostic.code})` : ""}` : diagnostic.message
2749
+ ).join(", ")}.`,
2750
+ data: {
2751
+ exitCode,
2752
+ filePatterns: config.filePatterns,
2753
+ matchedDiagnostics
2754
+ }
2755
+ };
2756
+ }
2757
+ };
2758
+
2759
+ // src/evaluators/index.ts
2760
+ var ENGINEERING_EPISTEMIC_EVALUATORS = [
2761
+ testRunnerEvaluator,
2762
+ tscCheckerEvaluator,
2763
+ lintCheckerEvaluator,
2764
+ sentryCheckerEvaluator
2765
+ ];
2766
+ var ENGINEERING_EVALUATOR_NAMES = new Set(
2767
+ ENGINEERING_EPISTEMIC_EVALUATORS.map((evaluator) => evaluator.name)
2768
+ );
2769
+ function getEngineeringEpistemicEvaluator(name) {
2770
+ return ENGINEERING_EPISTEMIC_EVALUATORS.find(
2771
+ (evaluator) => evaluator.name === name
2772
+ );
2773
+ }
2774
+
2775
+ // src/epistemicContracts.evaluators.ts
2776
+ var evaluatorRegistry = /* @__PURE__ */ new Map();
2777
+ var BUILT_IN_EVIDENTIAL_ALIASES2 = METRIC_COMPARATOR_EVALUATOR_NAMES.evidentialAliases;
2778
+ var BUILT_IN_METRIC_CHECKER2 = METRIC_COMPARATOR_EVALUATOR_NAMES.metricChecker;
2779
+ var BUILT_IN_REFERENCE_CHECK_COUNTER2 = METRIC_COMPARATOR_EVALUATOR_NAMES.referenceCheckCounter;
2780
+ var BUILT_IN_TEMPORAL_DEADLINE2 = METRIC_COMPARATOR_EVALUATOR_NAMES.temporalDeadline;
2781
+ var BUILT_IN_MARKET_INDEX_COMPARATOR2 = METRIC_COMPARATOR_EVALUATOR_NAMES.marketIndexComparator;
2782
+ var MAX_CONTRACT_EVALUATION_BATCH_SIZE = 50;
2783
+ function confidenceSeed(args) {
2784
+ if (typeof args.currentConfidence === "number") {
2785
+ return args.currentConfidence;
2786
+ }
2787
+ if (typeof args.beliefConfidence === "number") {
2788
+ return args.beliefConfidence;
2789
+ }
2790
+ return 0.5;
2791
+ }
2792
+ function contractDocId(contract) {
2793
+ return contract._id;
2794
+ }
2795
+ function ensureBuiltInEvaluators() {
2796
+ for (const name of BUILT_IN_EVIDENTIAL_ALIASES2) {
2797
+ if (evaluatorRegistry.has(name)) {
2798
+ continue;
2799
+ }
2800
+ evaluatorRegistry.set(name, {
2801
+ name,
2802
+ evaluate: evaluateBuiltInEvidentialContract
2803
+ });
2804
+ }
2805
+ for (const evaluator of ENGINEERING_EPISTEMIC_EVALUATORS) {
2806
+ if (evaluatorRegistry.has(evaluator.name)) {
2807
+ continue;
2808
+ }
2809
+ evaluatorRegistry.set(evaluator.name, evaluator);
2810
+ }
2811
+ const researchEvaluators = [
2812
+ [BUILT_IN_METRIC_CHECKER2, evaluateMetricCheckerContract],
2813
+ [BUILT_IN_REFERENCE_CHECK_COUNTER2, evaluateReferenceCheckCounterContract],
2814
+ [BUILT_IN_TEMPORAL_DEADLINE2, evaluateTemporalDeadlineContract],
2815
+ [BUILT_IN_MARKET_INDEX_COMPARATOR2, evaluateMarketIndexComparatorContract]
2816
+ ];
2817
+ for (const [name, evaluate] of researchEvaluators) {
2818
+ if (evaluatorRegistry.has(name)) {
2819
+ continue;
2820
+ }
2821
+ evaluatorRegistry.set(name, { name, evaluate });
2822
+ }
2823
+ }
2824
+ function normalizeTrigger(trigger) {
2825
+ if (trigger === "evidence_added") {
2826
+ return "evidence_added";
2827
+ }
2828
+ if (trigger === "periodic") {
2829
+ return "periodic";
2830
+ }
2831
+ if (trigger === "manual") {
2832
+ return "manual";
2833
+ }
2834
+ return "event_driven";
2835
+ }
2836
+ function resolveSchedulesForTrigger(trigger) {
2837
+ if (trigger === "evidence_added") {
2838
+ return /* @__PURE__ */ new Set(["on_evidence", "event_driven"]);
2839
+ }
2840
+ if (trigger === "periodic") {
2841
+ return /* @__PURE__ */ new Set(["periodic"]);
2842
+ }
2843
+ if (trigger === "manual") {
2844
+ return /* @__PURE__ */ new Set(["on_demand", "event_driven"]);
2845
+ }
2846
+ return /* @__PURE__ */ new Set(["event_driven"]);
2847
+ }
2848
+ async function executeContractEvaluation(args) {
2849
+ ensureBuiltInEvaluators();
2850
+ const evaluator = evaluatorRegistry.get(args.contract.condition.evaluator);
2851
+ let evaluation;
2852
+ if (evaluator) {
2853
+ try {
2854
+ evaluation = await evaluator.evaluate({
2855
+ belief: args.belief,
2856
+ contract: args.contract,
2857
+ ctx: args.ctx,
2858
+ now: args.now,
2859
+ resultData: args.resultData,
2860
+ trigger: args.trigger,
2861
+ inputData: args.inputData
2862
+ });
2863
+ } catch (error) {
2864
+ evaluation = {
2865
+ result: "error",
2866
+ rationale: error instanceof Error ? error.message : "Unknown evaluator error."
2867
+ };
2868
+ }
2869
+ } else {
2870
+ evaluation = {
2871
+ result: "error",
2872
+ rationale: `No epistemic evaluator registered for "${args.contract.condition.evaluator}".`
2873
+ };
2874
+ }
2875
+ const confidenceBefore = confidenceSeed({
2876
+ beliefConfidence: args.belief.confidence,
2877
+ currentConfidence: args.currentConfidence
2878
+ });
2879
+ const modulationPlan = deriveContractModulationPlan({
2880
+ currentConfidence: confidenceBefore,
2881
+ modulation: args.contract.modulation,
2882
+ result: evaluation.result,
2883
+ resultConfidence: evaluation.confidence
2884
+ });
2885
+ let beliefConfidenceId;
2886
+ let confidenceAfter = confidenceBefore;
2887
+ if (modulationPlan) {
2888
+ const contractB = Math.max(0, Math.min(1, modulationPlan.confidenceAfter));
2889
+ const modulationResult = await applyBeliefConfidenceChange(args.ctx, {
2890
+ nodeId: args.contract.beliefNodeId,
2891
+ belief: contractB,
2892
+ disbelief: 1 - contractB,
2893
+ uncertainty: 0,
2894
+ baseRate: 0.5,
2895
+ trigger: modulationPlan.trigger,
2896
+ rationale: `Epistemic contract "${args.contract.title}" ${evaluation.result}: ${evaluation.rationale}`,
2897
+ authenticatedUserId: args.authenticatedUserId
2898
+ });
2899
+ beliefConfidenceId = modulationResult.beliefConfidenceId;
2900
+ confidenceAfter = typeof modulationResult.newConfidence === "number" ? modulationResult.newConfidence : modulationPlan.confidenceAfter;
2901
+ }
2902
+ const evaluationId = await args.ctx.db.insert("contractEvaluations", {
2903
+ contractId: args.contract.contractId,
2904
+ beliefNodeId: args.contract.beliefNodeId,
2905
+ result: evaluation.result,
2906
+ evaluatedAt: args.now,
2907
+ evaluator: args.contract.condition.evaluator,
2908
+ trigger: args.trigger,
2909
+ resultData: evaluation.data,
2910
+ modulationApplied: Boolean(modulationPlan),
2911
+ confidenceDelta: modulationPlan?.confidenceDelta,
2912
+ confidenceBefore: modulationPlan?.confidenceBefore,
2913
+ confidenceAfter: modulationPlan ? confidenceAfter : void 0,
2914
+ beliefConfidenceId,
2915
+ modulationRationale: evaluation.rationale,
2916
+ topicId: args.contract.topicId
2917
+ });
2918
+ const nextStatus = deriveContractStatus(
2919
+ evaluation.result,
2920
+ args.contract.status
2921
+ );
2922
+ await args.ctx.db.patch(contractDocId(args.contract), {
2923
+ status: nextStatus,
2924
+ lastEvaluatedAt: args.now,
2925
+ evaluationCount: (args.contract.evaluationCount ?? 0) + 1,
2926
+ updatedAt: args.now
2927
+ });
2928
+ return {
2929
+ evaluationId,
2930
+ result: evaluation.result,
2931
+ status: nextStatus,
2932
+ confidenceBefore,
2933
+ confidenceAfter,
2934
+ rationale: evaluation.rationale,
2935
+ data: evaluation.data,
2936
+ currentConfidence: confidenceAfter
2937
+ };
2438
2938
  }
2439
- function parseStructuredDiagnostics(resultData) {
2440
- const envelope = normalizeToolResultEnvelope(resultData);
2441
- const record = asRecord(envelope.report) ?? asRecord(envelope.data) ?? asRecord(resultData);
2442
- if (!record) {
2443
- return [];
2939
+ async function evaluateContractsForTriggerBatch(args) {
2940
+ const startedAt = Date.now();
2941
+ const contracts = await loadContractsForTrigger({
2942
+ ctx: args.ctx,
2943
+ beliefNodeId: args.belief._id,
2944
+ trigger: normalizeTrigger(args.trigger),
2945
+ contractIds: args.contractIds
2946
+ });
2947
+ const batchLimit = Math.max(
2948
+ 1,
2949
+ Math.min(
2950
+ args.maxBatchSize ?? MAX_CONTRACT_EVALUATION_BATCH_SIZE,
2951
+ MAX_CONTRACT_EVALUATION_BATCH_SIZE
2952
+ )
2953
+ );
2954
+ const currentBatch = contracts.slice(0, batchLimit);
2955
+ const overflowContracts = contracts.slice(batchLimit);
2956
+ let runningConfidence = typeof args.belief.confidence === "number" ? args.belief.confidence : 0.5;
2957
+ const results = [];
2958
+ for (const contract of currentBatch) {
2959
+ const evaluation = await executeContractEvaluation({
2960
+ ctx: args.ctx,
2961
+ belief: args.belief,
2962
+ contract,
2963
+ now: Date.now(),
2964
+ trigger: normalizeTrigger(args.trigger),
2965
+ inputData: args.inputData,
2966
+ authenticatedUserId: args.authenticatedUserId,
2967
+ currentConfidence: runningConfidence
2968
+ });
2969
+ runningConfidence = evaluation.currentConfidence;
2970
+ args.belief.confidence = runningConfidence;
2971
+ results.push({
2972
+ contractId: contract.contractId,
2973
+ result: evaluation.result,
2974
+ status: evaluation.status,
2975
+ confidenceAfter: evaluation.confidenceAfter
2976
+ });
2444
2977
  }
2445
- return asArray(record.diagnostics).flatMap((entry) => {
2446
- const diagnostic = asRecord(entry);
2447
- if (!diagnostic) {
2448
- return [];
2449
- }
2450
- const filePath = asString(diagnostic.filePath) ?? asString(diagnostic.file) ?? asString(asRecord(diagnostic.location)?.filePath) ?? asString(asRecord(asRecord(diagnostic.location)?.path)?.file);
2451
- const message = asString(diagnostic.message) ?? "TypeScript error";
2452
- return [
2978
+ if (overflowContracts.length > 0) {
2979
+ await args.ctx.scheduler.runAfter(
2980
+ 0,
2981
+ "epistemicContracts.processContractEvaluationOverflow",
2453
2982
  {
2454
- code: asString(diagnostic.code) ?? void 0,
2455
- filePath: filePath ? normalizeFilePath(filePath) : null,
2456
- message
2457
- }
2458
- ];
2459
- });
2460
- }
2461
- function parseTextDiagnostics(resultData) {
2462
- const diagnostics = [];
2463
- const patterns = [
2464
- /^(.+?)\((\d+),(\d+)\): error TS(\d+): (.+)$/gm,
2465
- /^(.+?):(\d+):(\d+) - error TS(\d+): (.+)$/gm
2466
- ];
2467
- for (const text of extractTextCandidates(resultData)) {
2468
- for (const pattern of patterns) {
2469
- for (const match of text.matchAll(pattern)) {
2470
- diagnostics.push({
2471
- code: match[4],
2472
- filePath: normalizeFilePath(match[1] ?? ""),
2473
- message: match[5] ?? "TypeScript error"
2474
- });
2983
+ beliefNodeId: args.belief._id,
2984
+ trigger: normalizeTrigger(args.trigger),
2985
+ contractIds: overflowContracts.map((contract) => contract.contractId),
2986
+ inputData: args.inputData,
2987
+ authenticatedUserId: args.authenticatedUserId,
2988
+ maxBatchSize: batchLimit
2475
2989
  }
2476
- }
2990
+ );
2477
2991
  }
2478
- return diagnostics;
2479
- }
2480
- function parseDiagnostics2(resultData) {
2481
- const structured = parseStructuredDiagnostics(resultData);
2482
- return structured.length > 0 ? structured : parseTextDiagnostics(resultData);
2992
+ const executionTimeMs = Date.now() - startedAt;
2993
+ console.info("[epistemicContracts] processed contract evaluation batch", {
2994
+ beliefNodeId: String(args.belief._id),
2995
+ trigger: normalizeTrigger(args.trigger),
2996
+ batchSize: currentBatch.length,
2997
+ overflowCount: overflowContracts.length,
2998
+ executionTimeMs
2999
+ });
3000
+ return {
3001
+ totalContracts: contracts.length,
3002
+ processedCount: currentBatch.length,
3003
+ overflowCount: overflowContracts.length,
3004
+ scheduledOverflow: overflowContracts.length > 0,
3005
+ batchSize: currentBatch.length,
3006
+ executionTimeMs,
3007
+ trigger: normalizeTrigger(args.trigger),
3008
+ results
3009
+ };
2483
3010
  }
2484
- function getMatchedDiagnostics2(contract, resultData) {
2485
- const config = parseConfig4(contract.condition);
2486
- return parseDiagnostics2(resultData).filter(
2487
- (diagnostic) => somePatternMatches(diagnostic.filePath, config.filePatterns)
2488
- );
3011
+ async function loadContractsForBelief(args) {
3012
+ const rows = await args.ctx.db.query("epistemicContracts").withIndex("by_belief", (q) => q.eq("beliefNodeId", args.beliefNodeId)).collect();
3013
+ return rows;
2489
3014
  }
2490
- var tscCheckerEvaluator = {
2491
- name: "tsc_checker",
2492
- matches({ contract, resultData }) {
2493
- const envelope = normalizeToolResultEnvelope(resultData);
2494
- const exitCode = asNumber(envelope.exitCode);
2495
- if (exitCode === 0) {
2496
- return true;
3015
+ async function loadContractsForTrigger(args) {
3016
+ const contracts = await loadContractsForBelief(args);
3017
+ ensureBuiltInEvaluators();
3018
+ const allowedSchedules = resolveSchedulesForTrigger(args.trigger);
3019
+ const contractIdFilter = args.contractIds && args.contractIds.length > 0 ? new Set(args.contractIds) : null;
3020
+ return contracts.filter((contract) => {
3021
+ if (contract.status === "archived") {
3022
+ return false;
2497
3023
  }
2498
- return getMatchedDiagnostics2(contract, resultData).length > 0;
2499
- },
2500
- evaluate(args) {
2501
- const config = parseConfig4(args.contract.condition);
2502
- if (!args.resultData) {
2503
- return {
2504
- result: "error",
2505
- rationale: "tsc_checker requires TypeScript diagnostic resultData."
2506
- };
3024
+ if (contract.conditionType === "composite") {
3025
+ return false;
2507
3026
  }
2508
- const envelope = normalizeToolResultEnvelope(args.resultData);
2509
- const exitCode = asNumber(envelope.exitCode);
2510
- const matchedDiagnostics = getMatchedDiagnostics2(args.contract, args.resultData);
2511
- if (matchedDiagnostics.length === 0 && exitCode !== 0 && exitCode !== null) {
2512
- return {
2513
- result: "inconclusive",
2514
- rationale: "TypeScript reported errors, but none matched the configured file patterns."
2515
- };
3027
+ if (!evaluatorRegistry.has(contract.condition.evaluator)) {
3028
+ return false;
2516
3029
  }
2517
- const conditionSatisfied = exitCode === 0 || exitCode !== null && matchedDiagnostics.length === 0;
2518
- return {
2519
- result: deriveDirectionalResult(
2520
- args.contract.direction,
2521
- conditionSatisfied
2522
- ),
2523
- rationale: conditionSatisfied ? `TypeScript reported no matching diagnostics for ${config.filePatterns.join(", ")}.` : `TypeScript found ${matchedDiagnostics.length} matching diagnostic(s): ${matchedDiagnostics.map(
2524
- (diagnostic) => diagnostic.filePath ? `${diagnostic.filePath}${diagnostic.code ? ` (TS${diagnostic.code})` : ""}` : diagnostic.message
2525
- ).join(", ")}.`,
2526
- data: {
2527
- exitCode,
2528
- filePatterns: config.filePatterns,
2529
- matchedDiagnostics
2530
- }
2531
- };
2532
- }
2533
- };
2534
-
2535
- // src/evaluators/index.ts
2536
- var ENGINEERING_EPISTEMIC_EVALUATORS = [
2537
- testRunnerEvaluator,
2538
- tscCheckerEvaluator,
2539
- lintCheckerEvaluator,
2540
- sentryCheckerEvaluator
2541
- ];
2542
- var ENGINEERING_EVALUATOR_NAMES = new Set(
2543
- ENGINEERING_EPISTEMIC_EVALUATORS.map((evaluator) => evaluator.name)
2544
- );
2545
- function getEngineeringEpistemicEvaluator(name) {
2546
- return ENGINEERING_EPISTEMIC_EVALUATORS.find(
2547
- (evaluator) => evaluator.name === name
2548
- );
3030
+ if (contractIdFilter) {
3031
+ return contractIdFilter.has(contract.contractId);
3032
+ }
3033
+ return allowedSchedules.has(contract.evaluationSchedule);
3034
+ });
2549
3035
  }
2550
3036
 
2551
3037
  // src/epistemicContracts.handlers.ts
@@ -2561,6 +3047,24 @@ function resolveSchedulesForTrigger2(trigger) {
2561
3047
  }
2562
3048
  return /* @__PURE__ */ new Set(["event_driven"]);
2563
3049
  }
3050
+ function contractTables(ctx) {
3051
+ return ctx.db;
3052
+ }
3053
+ function assertBeliefNode(value, message = "Belief not found.") {
3054
+ if (!value || typeof value !== "object" || value.nodeType !== "belief") {
3055
+ throw new Error(message);
3056
+ }
3057
+ return value;
3058
+ }
3059
+ function normalizeEngineeringTrigger(trigger) {
3060
+ if (trigger === "manual") {
3061
+ return "manual";
3062
+ }
3063
+ if (trigger === "evidence_added") {
3064
+ return "evidence_added";
3065
+ }
3066
+ return trigger;
3067
+ }
2564
3068
  async function requireAuth(ctx) {
2565
3069
  const userId = await getCurrentUserId(ctx);
2566
3070
  if (!userId) {
@@ -2596,17 +3100,21 @@ async function requireTopicReadAccess(ctx, beliefs, userId) {
2596
3100
  projectIds.add(belief.projectId);
2597
3101
  }
2598
3102
  for (const projectId of projectIds) {
2599
- const hasAccess = await checkProjectAccess(ctx, projectId, userId);
3103
+ const hasAccess = await checkProjectAccess(
3104
+ ctx,
3105
+ projectId,
3106
+ userId
3107
+ );
2600
3108
  if (!hasAccess) {
2601
3109
  throw new Error("Project access required.");
2602
3110
  }
2603
3111
  }
2604
3112
  }
2605
3113
  async function getContractByContractId(ctx, contractId) {
2606
- return await ctx.db.query("epistemicContracts").withIndex("by_contractId", (q) => q.eq("contractId", contractId)).first();
3114
+ return await contractTables(ctx).query("epistemicContracts").withIndex("by_contractId", (q) => q.eq("contractId", contractId)).first();
2607
3115
  }
2608
3116
  async function getLatestEvaluation(ctx, contractId) {
2609
- const evaluations = await ctx.db.query("contractEvaluations").withIndex("by_contract_time", (q) => q.eq("contractId", contractId)).order("desc").take(1);
3117
+ const evaluations = await contractTables(ctx).query("contractEvaluations").withIndex("by_contract_time", (q) => q.eq("contractId", contractId)).order("desc").take(1);
2610
3118
  return evaluations[0] ?? null;
2611
3119
  }
2612
3120
  var evaluateEvidenceCount = query({
@@ -2616,10 +3124,7 @@ var evaluateEvidenceCount = query({
2616
3124
  returns: permissiveReturn,
2617
3125
  handler: async (ctx, args) => {
2618
3126
  const userId = await requireAuth(ctx);
2619
- const belief = await ctx.db.get(args.beliefNodeId);
2620
- if (!belief || belief.nodeType !== "belief") {
2621
- throw new Error("Belief not found.");
2622
- }
3127
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2623
3128
  await requireBeliefProjectAccess(ctx, belief, userId);
2624
3129
  return await computeEvidenceCountMetric(ctx, args.beliefNodeId);
2625
3130
  }
@@ -2631,10 +3136,7 @@ var evaluateContradictionStatus = query({
2631
3136
  returns: permissiveReturn,
2632
3137
  handler: async (ctx, args) => {
2633
3138
  const userId = await requireAuth(ctx);
2634
- const belief = await ctx.db.get(args.beliefNodeId);
2635
- if (!belief || belief.nodeType !== "belief") {
2636
- throw new Error("Belief not found.");
2637
- }
3139
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2638
3140
  await requireBeliefProjectAccess(ctx, belief, userId);
2639
3141
  return await computeContradictionCounts(ctx, args.beliefNodeId);
2640
3142
  }
@@ -2646,10 +3148,7 @@ var evaluateEdgeFreshness = query({
2646
3148
  returns: permissiveReturn,
2647
3149
  handler: async (ctx, args) => {
2648
3150
  const userId = await requireAuth(ctx);
2649
- const belief = await ctx.db.get(args.beliefNodeId);
2650
- if (!belief || belief.nodeType !== "belief") {
2651
- throw new Error("Belief not found.");
2652
- }
3151
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2653
3152
  await requireBeliefProjectAccess(ctx, belief, userId);
2654
3153
  return await computeEvidenceFreshness(ctx, args.beliefNodeId);
2655
3154
  }
@@ -2661,10 +3160,7 @@ var evaluateDependentBeliefCount = query({
2661
3160
  returns: permissiveReturn,
2662
3161
  handler: async (ctx, args) => {
2663
3162
  const userId = await requireAuth(ctx);
2664
- const belief = await ctx.db.get(args.beliefNodeId);
2665
- if (!belief || belief.nodeType !== "belief") {
2666
- throw new Error("Belief not found.");
2667
- }
3163
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2668
3164
  await requireBeliefProjectAccess(ctx, belief, userId);
2669
3165
  return await computeDependentBeliefCount(ctx, args.beliefNodeId);
2670
3166
  }
@@ -2728,10 +3224,7 @@ var createEpistemicContract = mutation({
2728
3224
  ctx,
2729
3225
  args.authenticatedUserId
2730
3226
  );
2731
- const belief = await ctx.db.get(args.beliefNodeId);
2732
- if (!belief || belief.nodeType !== "belief") {
2733
- throw new Error("Belief not found.");
2734
- }
3227
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2735
3228
  await requireBeliefProjectAccess(ctx, belief, userId);
2736
3229
  const now = Date.now();
2737
3230
  const contractId = generateGlobalId();
@@ -2786,10 +3279,10 @@ var evaluateContract = mutation({
2786
3279
  if (contract.status === "archived") {
2787
3280
  throw new Error("Archived contracts cannot be evaluated.");
2788
3281
  }
2789
- const belief = await ctx.db.get(contract.beliefNodeId);
2790
- if (!belief || belief.nodeType !== "belief") {
2791
- throw new Error("Belief not found for contract.");
2792
- }
3282
+ const belief = assertBeliefNode(
3283
+ await ctx.db.get(contract.beliefNodeId),
3284
+ "Belief not found for contract."
3285
+ );
2793
3286
  await requireBeliefProjectAccess(ctx, belief, userId);
2794
3287
  const evaluation = await executeContractEvaluation({
2795
3288
  ctx,
@@ -2827,14 +3320,11 @@ var evaluateEngineeringContracts = mutation({
2827
3320
  ctx,
2828
3321
  args.authenticatedUserId
2829
3322
  );
2830
- const belief = await ctx.db.get(args.beliefNodeId);
2831
- if (!belief || belief.nodeType !== "belief") {
2832
- throw new Error("Belief not found.");
2833
- }
3323
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2834
3324
  await requireBeliefProjectAccess(ctx, belief, userId);
2835
3325
  const trigger = args.trigger ?? "event_driven";
2836
3326
  const allowedSchedules = resolveSchedulesForTrigger2(
2837
- trigger === "manual" ? "manual" : trigger === "evidence_added" ? "evidence_added" : trigger
3327
+ normalizeEngineeringTrigger(trigger)
2838
3328
  );
2839
3329
  const payloadByEvaluator = /* @__PURE__ */ new Map([
2840
3330
  ["test_runner", args.testOutput],
@@ -2913,10 +3403,7 @@ var evaluateContractsForTrigger = mutation({
2913
3403
  ctx,
2914
3404
  args.authenticatedUserId
2915
3405
  );
2916
- const belief = await ctx.db.get(args.beliefNodeId);
2917
- if (!belief || belief.nodeType !== "belief") {
2918
- throw new Error("Belief not found.");
2919
- }
3406
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2920
3407
  await requireBeliefProjectAccess(ctx, belief, userId);
2921
3408
  return await evaluateContractsForTriggerBatch({
2922
3409
  ctx,
@@ -2939,10 +3426,7 @@ var processContractEvaluationOverflow = internalMutation({
2939
3426
  },
2940
3427
  returns: permissiveReturn,
2941
3428
  handler: async (ctx, args) => {
2942
- const belief = await ctx.db.get(args.beliefNodeId);
2943
- if (!belief || belief.nodeType !== "belief") {
2944
- throw new Error("Belief not found.");
2945
- }
3429
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2946
3430
  return await evaluateContractsForTriggerBatch({
2947
3431
  ctx,
2948
3432
  belief,
@@ -2981,15 +3465,9 @@ var getContractStatus = query({
2981
3465
  const contract = await getContractByContractId(ctx, args.contractId);
2982
3466
  contracts = contract ? [contract] : [];
2983
3467
  } else if (args.beliefNodeId) {
2984
- const belief = await ctx.db.get(args.beliefNodeId);
2985
- if (!belief || belief.nodeType !== "belief") {
2986
- throw new Error("Belief not found.");
2987
- }
3468
+ const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
2988
3469
  await requireBeliefProjectAccess(ctx, belief, userId);
2989
- contracts = await ctx.db.query("epistemicContracts").withIndex(
2990
- "by_belief",
2991
- (q) => q.eq("beliefNodeId", args.beliefNodeId)
2992
- ).collect();
3470
+ contracts = await contractTables(ctx).query("epistemicContracts").withIndex("by_belief", (q) => q.eq("beliefNodeId", args.beliefNodeId)).collect();
2993
3471
  }
2994
3472
  if (contracts.length > 0) {
2995
3473
  const contractBeliefDocs = await Promise.all(
@@ -2997,15 +3475,14 @@ var getContractStatus = query({
2997
3475
  );
2998
3476
  const contractBeliefs = [];
2999
3477
  for (const belief of contractBeliefDocs) {
3000
- if (!belief || belief.nodeType !== "belief") {
3001
- throw new Error("Belief not found.");
3002
- }
3003
- contractBeliefs.push(belief);
3478
+ contractBeliefs.push(assertBeliefNode(belief));
3004
3479
  }
3005
3480
  await requireTopicReadAccess(ctx, contractBeliefs, userId);
3006
3481
  }
3007
3482
  if (args.status) {
3008
- contracts = contracts.filter((contract) => contract.status === args.status);
3483
+ contracts = contracts.filter(
3484
+ (contract) => contract.status === args.status
3485
+ );
3009
3486
  }
3010
3487
  const rows = await Promise.all(
3011
3488
  contracts.map(async (contract) => ({
@@ -3024,21 +3501,22 @@ var getContractCoverage = query({
3024
3501
  },
3025
3502
  returns: permissiveReturn,
3026
3503
  handler: async (ctx, args) => {
3027
- const contracts = await ctx.db.query("epistemicContracts").withIndex("by_topic", (q) => q.eq("topicId", args.topicId)).collect();
3504
+ const contracts = await contractTables(ctx).query("epistemicContracts").withIndex("by_topic", (q) => q.eq("topicId", args.topicId)).collect();
3028
3505
  const userId = await resolveAuthenticatedUserId(
3029
3506
  ctx,
3030
3507
  args.authenticatedUserId
3031
3508
  );
3032
- const beliefs = await ctx.db.query("epistemicNodes").withIndex(
3509
+ const beliefRows = await ctx.db.query("epistemicNodes").withIndex(
3033
3510
  "by_topic_type",
3034
3511
  (q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
3035
3512
  ).collect();
3513
+ const beliefs = beliefRows.map((belief) => assertBeliefNode(belief));
3036
3514
  await requireTopicReadAccess(ctx, beliefs, userId);
3037
3515
  const recentEvaluationLimit = Math.max(
3038
3516
  0,
3039
3517
  Math.min(args.recentEvaluationLimit ?? 5, 25)
3040
3518
  );
3041
- const recentEvaluations = recentEvaluationLimit === 0 ? [] : await ctx.db.query("contractEvaluations").withIndex("by_topic_time", (q) => q.eq("topicId", args.topicId)).order("desc").take(recentEvaluationLimit) ?? [];
3519
+ const recentEvaluations = recentEvaluationLimit === 0 ? [] : await contractTables(ctx).query("contractEvaluations").withIndex("by_topic_time", (q) => q.eq("topicId", args.topicId)).order("desc").take(recentEvaluationLimit);
3042
3520
  const contractBeliefIds = new Set(
3043
3521
  contracts.filter((contract) => contract.status !== "archived").map((contract) => String(contract.beliefNodeId))
3044
3522
  );