@lucern/graph-primitives 1.0.28 → 1.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
  2. package/dist/beliefDecay.d.ts +1 -1
  3. package/dist/beliefDecay.js +448 -314
  4. package/dist/beliefDecay.js.map +1 -1
  5. package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
  6. package/dist/beliefEvidenceLinks.d.ts +1 -1
  7. package/dist/beliefEvidenceLinks.js +843 -624
  8. package/dist/beliefEvidenceLinks.js.map +1 -1
  9. package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
  10. package/dist/beliefEvidenceLinks.operational.js +91 -18
  11. package/dist/beliefEvidenceLinks.operational.js.map +1 -1
  12. package/dist/beliefLifecycle.js.map +1 -1
  13. package/dist/confidencePropagationDispatch.d.ts +28 -27
  14. package/dist/confidencePropagationDispatch.js +157 -99
  15. package/dist/confidencePropagationDispatch.js.map +1 -1
  16. package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
  17. package/dist/contradictions.d.ts +1 -1
  18. package/dist/contradictions.js +398 -228
  19. package/dist/contradictions.js.map +1 -1
  20. package/dist/convex.d.ts +65 -30
  21. package/dist/convex.js +7 -3
  22. package/dist/convex.js.map +1 -1
  23. package/dist/debug.js.map +1 -1
  24. package/dist/edgeValidation.js +293 -85
  25. package/dist/edgeValidation.js.map +1 -1
  26. package/dist/edges/contains.d.ts +1 -1
  27. package/dist/edges/contains.js.map +1 -1
  28. package/dist/edges/contradicts.d.ts +1 -1
  29. package/dist/edges/contradicts.js.map +1 -1
  30. package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
  31. package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
  32. package/dist/edges/depends-on.js.map +1 -0
  33. package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
  34. package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
  35. package/dist/edges/derived-from.js.map +1 -0
  36. package/dist/edges/elaborates.d.ts +1 -1
  37. package/dist/edges/elaborates.js.map +1 -1
  38. package/dist/edges/index.d.ts +7 -3
  39. package/dist/edges/index.js +7 -4
  40. package/dist/edges/index.js.map +1 -1
  41. package/dist/edges/informs.d.ts +1 -1
  42. package/dist/edges/informs.js.map +1 -1
  43. package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
  44. package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
  45. package/dist/edges/propagation-types.js.map +1 -0
  46. package/dist/edges/refutes.d.ts +1 -1
  47. package/dist/edges/refutes.js.map +1 -1
  48. package/dist/edges/supports.d.ts +1 -1
  49. package/dist/edges/supports.js.map +1 -1
  50. package/dist/edges/tests.d.ts +1 -1
  51. package/dist/edges/tests.js.map +1 -1
  52. package/dist/edges/utils.d.ts +1 -1
  53. package/dist/edges/utils.js.map +1 -1
  54. package/dist/embeddingTrigger.d.ts +14 -6
  55. package/dist/embeddingTrigger.js +11 -14
  56. package/dist/embeddingTrigger.js.map +1 -1
  57. package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
  58. package/dist/entityBridge.d.ts +1 -1
  59. package/dist/entityBridge.js +602 -225
  60. package/dist/entityBridge.js.map +1 -1
  61. package/dist/entityCanonicalMatch.d.ts +14 -12
  62. package/dist/entityCanonicalMatch.js.map +1 -1
  63. package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
  64. package/dist/entityLifecycle.d.ts +1 -1
  65. package/dist/entityLifecycle.js +857 -515
  66. package/dist/entityLifecycle.js.map +1 -1
  67. package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
  68. package/dist/entityValidation.d.ts +3 -1
  69. package/dist/entityValidation.js +60 -8
  70. package/dist/entityValidation.js.map +1 -1
  71. package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
  72. package/dist/epistemicAnswers.d.ts +1 -1
  73. package/dist/epistemicAnswers.js +587 -545
  74. package/dist/epistemicAnswers.js.map +1 -1
  75. package/dist/epistemicBeliefs.admin.d.ts +8 -8
  76. package/dist/epistemicBeliefs.admin.js +366 -203
  77. package/dist/epistemicBeliefs.admin.js.map +1 -1
  78. package/dist/epistemicBeliefs.backfills.d.ts +8 -8
  79. package/dist/epistemicBeliefs.backfills.js +655 -308
  80. package/dist/epistemicBeliefs.backfills.js.map +1 -1
  81. package/dist/epistemicBeliefs.confidence.d.ts +19 -14
  82. package/dist/epistemicBeliefs.confidence.js +634 -423
  83. package/dist/epistemicBeliefs.confidence.js.map +1 -1
  84. package/dist/epistemicBeliefs.core.d.ts +6 -6
  85. package/dist/epistemicBeliefs.core.js +719 -411
  86. package/dist/epistemicBeliefs.core.js.map +1 -1
  87. package/dist/epistemicBeliefs.d.ts +11 -8
  88. package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
  89. package/dist/epistemicBeliefs.forkEvidence.js +8 -28
  90. package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
  91. package/dist/epistemicBeliefs.helpers.d.ts +69 -74
  92. package/dist/epistemicBeliefs.helpers.js +359 -248
  93. package/dist/epistemicBeliefs.helpers.js.map +1 -1
  94. package/dist/epistemicBeliefs.internal.d.ts +5 -5
  95. package/dist/epistemicBeliefs.internal.js +1246 -1044
  96. package/dist/epistemicBeliefs.internal.js.map +1 -1
  97. package/dist/epistemicBeliefs.js +4922 -3608
  98. package/dist/epistemicBeliefs.js.map +1 -1
  99. package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
  100. package/dist/epistemicBeliefs.lifecycle.js +1137 -818
  101. package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
  102. package/dist/epistemicBeliefs.links.d.ts +7 -7
  103. package/dist/epistemicBeliefs.links.js +408 -307
  104. package/dist/epistemicBeliefs.links.js.map +1 -1
  105. package/dist/epistemicBeliefs.queries.d.ts +4 -4
  106. package/dist/epistemicBeliefs.queries.js +175 -20
  107. package/dist/epistemicBeliefs.queries.js.map +1 -1
  108. package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
  109. package/dist/epistemicBeliefs.topicAnchor.js +12 -5
  110. package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
  111. package/dist/epistemicContracts.d.ts +28 -3
  112. package/dist/epistemicContracts.evaluators.d.ts +2 -0
  113. package/dist/epistemicContracts.evaluators.js +1063 -613
  114. package/dist/epistemicContracts.evaluators.js.map +1 -1
  115. package/dist/epistemicContracts.handlers.d.ts +15 -32
  116. package/dist/epistemicContracts.handlers.js +2086 -1644
  117. package/dist/epistemicContracts.handlers.js.map +1 -1
  118. package/dist/epistemicContracts.js +1131 -672
  119. package/dist/epistemicContracts.js.map +1 -1
  120. package/dist/epistemicContracts.metrics.d.ts +2 -0
  121. package/dist/epistemicContracts.metrics.js +375 -158
  122. package/dist/epistemicContracts.metrics.js.map +1 -1
  123. package/dist/epistemicContracts.types.d.ts +87 -81
  124. package/dist/epistemicEdgeCreation.d.ts +2 -0
  125. package/dist/epistemicEdgeCreation.js +87 -16
  126. package/dist/epistemicEdgeCreation.js.map +1 -1
  127. package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
  128. package/dist/epistemicEdges.d.ts +6 -5
  129. package/dist/epistemicEdges.handlers.d.ts +3 -3
  130. package/dist/epistemicEdges.handlers.js +129 -24
  131. package/dist/epistemicEdges.handlers.js.map +1 -1
  132. package/dist/epistemicEdges.helpers.d.ts +6 -4
  133. package/dist/epistemicEdges.helpers.js +37 -2
  134. package/dist/epistemicEdges.helpers.js.map +1 -1
  135. package/dist/epistemicEdges.js +1969 -1205
  136. package/dist/epistemicEdges.js.map +1 -1
  137. package/dist/epistemicEdges.mutations.d.ts +7 -7
  138. package/dist/epistemicEdges.mutations.js +960 -583
  139. package/dist/epistemicEdges.mutations.js.map +1 -1
  140. package/dist/epistemicEdges.queries.d.ts +16 -16
  141. package/dist/epistemicEdges.queries.js +639 -367
  142. package/dist/epistemicEdges.queries.js.map +1 -1
  143. package/dist/epistemicEdges.types.d.ts +10 -8
  144. package/dist/epistemicEvidence.d.ts +4 -1
  145. package/dist/epistemicEvidence.js +937 -536
  146. package/dist/epistemicEvidence.js.map +1 -1
  147. package/dist/epistemicEvidenceHelpers.d.ts +26 -10
  148. package/dist/epistemicEvidenceHelpers.js +239 -200
  149. package/dist/epistemicEvidenceHelpers.js.map +1 -1
  150. package/dist/epistemicEvidenceMutations.d.ts +8 -8
  151. package/dist/epistemicEvidenceMutations.js +844 -696
  152. package/dist/epistemicEvidenceMutations.js.map +1 -1
  153. package/dist/epistemicEvidenceQueries.d.ts +8 -8
  154. package/dist/epistemicEvidenceQueries.js +514 -238
  155. package/dist/epistemicEvidenceQueries.js.map +1 -1
  156. package/dist/epistemicHelpers.d.ts +4 -2
  157. package/dist/epistemicHelpers.js +308 -134
  158. package/dist/epistemicHelpers.js.map +1 -1
  159. package/dist/epistemicInsert.d.ts +16 -4
  160. package/dist/epistemicInsert.js +6 -3
  161. package/dist/epistemicInsert.js.map +1 -1
  162. package/dist/epistemicLayerRules.d.ts +10 -8
  163. package/dist/epistemicLayerRules.js +1 -5
  164. package/dist/epistemicLayerRules.js.map +1 -1
  165. package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
  166. package/dist/epistemicLinking.d.ts +1 -1
  167. package/dist/epistemicLinking.js +177 -100
  168. package/dist/epistemicLinking.js.map +1 -1
  169. package/dist/epistemicNodeCreation.d.ts +2 -0
  170. package/dist/epistemicNodeCreation.js +203 -40
  171. package/dist/epistemicNodeCreation.js.map +1 -1
  172. package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
  173. package/dist/epistemicNodes.d.ts +3 -3
  174. package/dist/epistemicNodes.helpers.d.ts +24 -15
  175. package/dist/epistemicNodes.helpers.js.map +1 -1
  176. package/dist/epistemicNodes.internal.d.ts +6 -6
  177. package/dist/epistemicNodes.internal.js +389 -319
  178. package/dist/epistemicNodes.internal.js.map +1 -1
  179. package/dist/epistemicNodes.js +704 -508
  180. package/dist/epistemicNodes.js.map +1 -1
  181. package/dist/epistemicNodes.mutations.d.ts +6 -6
  182. package/dist/epistemicNodes.mutations.js +564 -467
  183. package/dist/epistemicNodes.mutations.js.map +1 -1
  184. package/dist/epistemicNodes.queries.d.ts +8 -8
  185. package/dist/epistemicNodes.queries.js +311 -314
  186. package/dist/epistemicNodes.queries.js.map +1 -1
  187. package/dist/epistemicNodes.validators.d.ts +2 -2
  188. package/dist/epistemicNodes.validators.js.map +1 -1
  189. package/dist/epistemicQuestions.conviction.d.ts +8 -8
  190. package/dist/epistemicQuestions.conviction.js +665 -484
  191. package/dist/epistemicQuestions.conviction.js.map +1 -1
  192. package/dist/epistemicQuestions.create.d.ts +4 -4
  193. package/dist/epistemicQuestions.create.js +640 -612
  194. package/dist/epistemicQuestions.create.js.map +1 -1
  195. package/dist/epistemicQuestions.d.ts +8 -5
  196. package/dist/epistemicQuestions.evidence.d.ts +2 -2
  197. package/dist/epistemicQuestions.evidence.js +475 -383
  198. package/dist/epistemicQuestions.evidence.js.map +1 -1
  199. package/dist/epistemicQuestions.helpers.d.ts +125 -24
  200. package/dist/epistemicQuestions.helpers.js +240 -209
  201. package/dist/epistemicQuestions.helpers.js.map +1 -1
  202. package/dist/epistemicQuestions.js +3474 -2823
  203. package/dist/epistemicQuestions.js.map +1 -1
  204. package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
  205. package/dist/epistemicQuestions.lifecycle.js +607 -546
  206. package/dist/epistemicQuestions.lifecycle.js.map +1 -1
  207. package/dist/epistemicQuestions.queries.d.ts +12 -7
  208. package/dist/epistemicQuestions.queries.js +305 -244
  209. package/dist/epistemicQuestions.queries.js.map +1 -1
  210. package/dist/epistemicQuestions.sprint.d.ts +2 -2
  211. package/dist/epistemicQuestions.sprint.js +600 -394
  212. package/dist/epistemicQuestions.sprint.js.map +1 -1
  213. package/dist/epistemicQuestions.tail.d.ts +6 -6
  214. package/dist/epistemicQuestions.tail.js +572 -433
  215. package/dist/epistemicQuestions.tail.js.map +1 -1
  216. package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
  217. package/dist/epistemicSources.d.ts +1 -1
  218. package/dist/epistemicSources.js +352 -312
  219. package/dist/epistemicSources.js.map +1 -1
  220. package/dist/evaluators/index.d.ts +8 -6
  221. package/dist/evaluators/index.js +399 -167
  222. package/dist/evaluators/index.js.map +1 -1
  223. package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
  224. package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
  225. package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
  226. package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
  227. package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
  228. package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
  229. package/dist/evaluators/shared.d.ts +2 -2
  230. package/dist/evaluators/shared.js +3 -1
  231. package/dist/evaluators/shared.js.map +1 -1
  232. package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
  233. package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
  234. package/dist/evaluators/test-runner-evaluator.js.map +1 -0
  235. package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
  236. package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
  237. package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
  238. package/dist/graphTypes.js +6 -2
  239. package/dist/graphTypes.js.map +1 -1
  240. package/dist/helpers.d.ts +2 -0
  241. package/dist/helpers.js +313 -93
  242. package/dist/helpers.js.map +1 -1
  243. package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
  244. package/dist/index.d.ts +87 -83
  245. package/dist/index.js +15677 -10594
  246. package/dist/index.js.map +1 -1
  247. package/dist/invariantEnforcement.d.ts +3 -3
  248. package/dist/invariantEnforcement.js.map +1 -1
  249. package/dist/logicalRoleInference.d.ts +2 -0
  250. package/dist/logicalRoleInference.js +1 -1
  251. package/dist/logicalRoleInference.js.map +1 -1
  252. package/dist/matcherFeedbackUtils.d.ts +2 -2
  253. package/dist/matcherFeedbackUtils.js.map +1 -1
  254. package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
  255. package/dist/ontology-matching.d.ts +1 -1
  256. package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
  257. package/dist/ontologyApproval.d.ts +1 -1
  258. package/dist/ontologyApproval.js +7 -1
  259. package/dist/ontologyApproval.js.map +1 -1
  260. package/dist/ontologyDefinitions.d.ts +14 -24
  261. package/dist/ontologyDefinitions.js +269 -34
  262. package/dist/ontologyDefinitions.js.map +1 -1
  263. package/dist/ontologyHelpers.d.ts +13 -13
  264. package/dist/ontologyHelpers.js.map +1 -1
  265. package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
  266. package/dist/ontologyRegistry.d.ts +1 -1
  267. package/dist/ontologyRegistry.js +34 -6
  268. package/dist/ontologyRegistry.js.map +1 -1
  269. package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
  270. package/dist/projectionReconciliation.d.ts +1 -1
  271. package/dist/projectionReconciliation.js +57 -10
  272. package/dist/projectionReconciliation.js.map +1 -1
  273. package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
  274. package/dist/projectionStaleness.d.ts +1 -1
  275. package/dist/projectionStaleness.js +8 -2
  276. package/dist/projectionStaleness.js.map +1 -1
  277. package/dist/proof-attestation.json +1 -1
  278. package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
  279. package/dist/questionEvidenceLinks.d.ts +1 -1
  280. package/dist/questionEvidenceLinks.js +564 -347
  281. package/dist/questionEvidenceLinks.js.map +1 -1
  282. package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
  283. package/dist/resolverTypes.d.ts +4 -2
  284. package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
  285. package/dist/resolvers.d.ts +5 -3
  286. package/dist/resolvers.js +121 -77
  287. package/dist/resolvers.js.map +1 -1
  288. package/dist/scopeResolverCompat.d.ts +10 -7
  289. package/dist/scopeResolverCompat.js +106 -123
  290. package/dist/scopeResolverCompat.js.map +1 -1
  291. package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
  292. package/dist/text-matching.d.ts +1 -1
  293. package/dist/topicOntologyResolver.d.ts +22 -21
  294. package/dist/topicOntologyResolver.js +54 -32
  295. package/dist/topicOntologyResolver.js.map +1 -1
  296. package/dist/topicProjectOverlay.d.ts +30 -20
  297. package/dist/topicProjectOverlay.js +120 -76
  298. package/dist/topicProjectOverlay.js.map +1 -1
  299. package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
  300. package/dist/topicScope.d.ts +3 -1
  301. package/dist/topicScope.js +104 -119
  302. package/dist/topicScope.js.map +1 -1
  303. package/dist/workflowBridge.d.ts +26 -15
  304. package/dist/workflowBridge.js +140 -144
  305. package/dist/workflowBridge.js.map +1 -1
  306. package/dist/workspaceIsolation.d.ts +14 -12
  307. package/dist/workspaceIsolation.js +108 -122
  308. package/dist/workspaceIsolation.js.map +1 -1
  309. package/package.json +4 -4
  310. package/dist/edges/dependsOn.js.map +0 -1
  311. package/dist/edges/derivedFrom.js.map +0 -1
  312. package/dist/edges/propagationTypes.js.map +0 -1
  313. package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
  314. package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
  315. package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
  316. package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
  317. package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
  318. package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
  319. package/dist/{epistemicQuestions-bwHd2FWE.d.ts → epistemicQuestions-Do1fhYm5.d.ts} +4 -4
@@ -1,23 +1,138 @@
1
- import { v, ConvexError } from 'convex/values';
2
1
  import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
3
2
  import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
4
3
  import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
5
4
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
6
- import { componentsGeneric, anyApi, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
7
- import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
8
- import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
9
- import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
10
- import { normalizeTupleContradictionPolicy, confidenceFromSL } from '@lucern/confidence';
11
- import '@lucern/access-control/access';
5
+ import { v } from 'convex/values';
6
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
7
+ import { componentsGeneric, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
12
8
  import '@lucern/access-control/auth';
9
+ import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
10
+ import { normalizeTupleContradictionPolicy, confidenceFromSL } from '@lucern/confidence';
11
+ import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
12
+ import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
13
+ import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
13
14
 
14
15
  // src/epistemicBeliefs.internal.ts
15
- var api = anyApi;
16
+ var unsafeApi = unsafeConvexAnyApi(
17
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
18
+ );
19
+ var api = unsafeApi;
16
20
  componentsGeneric();
17
- var internal = anyApi;
21
+ var internal = unsafeApi;
18
22
  var internalMutation = internalMutationGeneric;
19
23
  var internalQuery = internalQueryGeneric;
20
24
 
25
+ // src/beliefLifecycle.ts
26
+ var BELIEF_STATUS_VALUES = [
27
+ "assumption",
28
+ "hypothesis",
29
+ "active",
30
+ "superseded",
31
+ "resolved_true",
32
+ "resolved_false"
33
+ ];
34
+ function isBeliefLifecycleStatus(value) {
35
+ return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
36
+ }
37
+ function normalizeLegacyBeliefStatus(value) {
38
+ if (isBeliefLifecycleStatus(value)) {
39
+ return value;
40
+ }
41
+ if (value === "belief" || value === "established" || value === "emerging") {
42
+ return "active";
43
+ }
44
+ if (value === "fact" || value === "confirmed") {
45
+ return "resolved_true";
46
+ }
47
+ if (value === "disconfirmed" || value === "expired") {
48
+ return "resolved_false";
49
+ }
50
+ if (value === "deprecated") {
51
+ return "superseded";
52
+ }
53
+ return null;
54
+ }
55
+ function normalizeBeliefConfidence(confidence) {
56
+ if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
57
+ return null;
58
+ }
59
+ if (confidence >= 0 && confidence <= 1) {
60
+ return confidence;
61
+ }
62
+ if (confidence > 1 && confidence <= 100) {
63
+ return confidence / 100;
64
+ }
65
+ return null;
66
+ }
67
+ function isResolvedByConfidence(confidence) {
68
+ const normalized = normalizeBeliefConfidence(confidence);
69
+ if (normalized === null) {
70
+ return false;
71
+ }
72
+ return normalized <= 0 || normalized >= 1;
73
+ }
74
+ function getPredictionMetaFromMetadata(metadata) {
75
+ return metadata?.predictionMeta;
76
+ }
77
+ function resolvedPredictionStatus(predictionMeta) {
78
+ if (!predictionMeta || typeof predictionMeta !== "object") {
79
+ return null;
80
+ }
81
+ const outcome = predictionMeta.outcome;
82
+ if (outcome === "confirmed") {
83
+ return "resolved_true";
84
+ }
85
+ if (outcome === "disconfirmed" || outcome === "expired") {
86
+ return "resolved_false";
87
+ }
88
+ return null;
89
+ }
90
+ function shouldTreatBeliefAsResolved(opts) {
91
+ if (isResolvedByConfidence(opts.confidence)) {
92
+ const normalized = normalizeBeliefConfidence(opts.confidence);
93
+ return normalized === 0 ? "resolved_false" : "resolved_true";
94
+ }
95
+ const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
96
+ if (directPredictionStatus) {
97
+ return directPredictionStatus;
98
+ }
99
+ const metadataPredictionStatus = resolvedPredictionStatus(
100
+ getPredictionMetaFromMetadata(opts.metadata)
101
+ );
102
+ if (metadataPredictionStatus) {
103
+ return metadataPredictionStatus;
104
+ }
105
+ return null;
106
+ }
107
+ function resolveBeliefLifecycleStatus(opts) {
108
+ const resolvedStatus = shouldTreatBeliefAsResolved(opts);
109
+ if (resolvedStatus) {
110
+ return resolvedStatus;
111
+ }
112
+ const direct = opts.beliefStatus;
113
+ const normalizedDirect = normalizeLegacyBeliefStatus(direct);
114
+ if (normalizedDirect) {
115
+ const normalized = normalizeBeliefConfidence(opts.confidence);
116
+ if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
117
+ return "active";
118
+ }
119
+ return normalizedDirect;
120
+ }
121
+ const metaStatus = opts.metadata?.beliefStatus;
122
+ const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
123
+ if (normalizedMetaStatus) {
124
+ const normalized = normalizeBeliefConfidence(opts.confidence);
125
+ if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
126
+ return "active";
127
+ }
128
+ return normalizedMetaStatus;
129
+ }
130
+ return "assumption";
131
+ }
132
+ function isPreValidationBeliefStatus(status) {
133
+ return status === "assumption" || status === "hypothesis";
134
+ }
135
+
21
136
  // src/debug.ts
22
137
  function isGraphPrimitiveDebugEnabled() {
23
138
  const env = globalThis.process?.env;
@@ -30,973 +145,723 @@ function debugGraphPrimitiveFallback(message, context) {
30
145
  console.debug(message, context ?? {});
31
146
  }
32
147
 
33
- // src/topicScope.ts
148
+ // src/topicProjectOverlay.ts
34
149
  var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
35
- async function resolveTopicNodeScopeOrNull(ctx, ref) {
36
- if (!ctx?.db || typeof ctx.db.query !== "function") {
37
- return null;
38
- }
39
- let node = null;
40
- try {
41
- const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
42
- if (byGlobalId && byGlobalId.nodeType === "topic") {
43
- node = byGlobalId;
44
- }
45
- } catch (error) {
46
- debugGraphPrimitiveFallback(
47
- "[topicScope] topic-node scope lookup by globalId failed",
48
- { error, ref }
49
- );
50
- }
51
- if (!node) {
52
- return null;
150
+ function readNonEmptyString(value) {
151
+ if (typeof value !== "string") {
152
+ return;
53
153
  }
54
- const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
55
- if (!scopeKey) {
56
- return null;
154
+ const normalized = value.trim();
155
+ return normalized.length > 0 ? normalized : void 0;
156
+ }
157
+ function readStringArray(value) {
158
+ if (!Array.isArray(value)) {
159
+ return [];
57
160
  }
58
- return {
59
- topicId: scopeKey,
60
- projectId: asMappedProjectId(node),
61
- source: "topic_node"
62
- };
161
+ return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
63
162
  }
64
- function asMappedProjectId(topic) {
65
- if (!topic) {
163
+ function readMetadata(topic) {
164
+ return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
165
+ }
166
+ function omitMetadataKey(metadata, key) {
167
+ const { [key]: _omitted, ...rest } = metadata;
168
+ return rest;
169
+ }
170
+ function readLegacyProjectId(value) {
171
+ if (!value) {
66
172
  return;
67
173
  }
68
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
69
- if (directLegacyProjectId) {
70
- return directLegacyProjectId;
174
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
175
+ }
176
+ function coerceVisibility(value) {
177
+ return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
178
+ }
179
+ function coerceStatus(value) {
180
+ return value === "active" || value === "archived" || value === "watching" ? value : void 0;
181
+ }
182
+ function mapProjectType(topic, metadata) {
183
+ const explicit = readNonEmptyString(metadata.projectType);
184
+ if (explicit) {
185
+ return explicit;
71
186
  }
72
- const metadata = topic.metadata || {};
73
- const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
74
- return candidate ? candidate : void 0;
187
+ if (topic.type === "theme") {
188
+ return "thematic";
189
+ }
190
+ return readNonEmptyString(topic.type) || "general";
75
191
  }
76
- function normalizeScopeValue(value) {
77
- if (typeof value !== "string") {
78
- return;
192
+ function isProjectLikeTopic(topic) {
193
+ const metadata = readMetadata(topic);
194
+ return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
195
+ }
196
+ function isMissingLucernChildComponentError(error) {
197
+ const message = getErrorMessage(error);
198
+ return message.includes(
199
+ 'Child component ComponentName(Identifier("lucern")) not found'
200
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
201
+ }
202
+ function getErrorMessage(error) {
203
+ if (error instanceof Error) {
204
+ return error.message;
79
205
  }
80
- const normalized = value.trim();
81
- return normalized.length > 0 ? normalized : void 0;
206
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
207
+ return error.message;
208
+ }
209
+ return "unknown error";
82
210
  }
83
- function pickPrimaryTopic(candidates) {
84
- return [...candidates].sort((a, b) => {
85
- const depthA = a.depth ?? 9999;
86
- const depthB = b.depth ?? 9999;
87
- if (depthA !== depthB) {
88
- return depthA - depthB;
89
- }
90
- const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
91
- const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
92
- if (createdA !== createdB) {
93
- return createdA - createdB;
211
+ async function resolveTopicDoc(ctx, scopeId) {
212
+ if (ctx?.db && typeof ctx.db.get === "function") {
213
+ try {
214
+ const directTopic = await ctx.db.get(
215
+ scopeId
216
+ );
217
+ if (directTopic) {
218
+ return directTopic;
219
+ }
220
+ } catch (error) {
221
+ debugGraphPrimitiveFallback(
222
+ "[topicProjectOverlay] Failed to resolve topic by direct ID",
223
+ {
224
+ error,
225
+ scopeId
226
+ }
227
+ );
94
228
  }
95
- return String(a.name || "").localeCompare(String(b.name || ""));
96
- })[0];
97
- }
98
- async function findTopicsByScopeAlias(ctx, scopeId) {
229
+ }
230
+ if (typeof ctx.runQuery !== "function") {
231
+ return null;
232
+ }
99
233
  try {
100
- return await ctx.db.query("topics").withIndex(
101
- "by_graph_scope_project",
102
- (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
103
- ).collect();
234
+ const topic = await ctx.runQuery(api.topics.get, {
235
+ id: String(scopeId)
236
+ });
237
+ if (topic?.name !== void 0 && topic?.type !== void 0) {
238
+ return topic;
239
+ }
104
240
  } catch (error) {
105
241
  debugGraphPrimitiveFallback(
106
- "[topicScope] Failed to resolve scope alias via index",
242
+ "[topicProjectOverlay] Failed to resolve topic by ID query",
107
243
  {
108
244
  error,
109
245
  scopeId
110
246
  }
111
247
  );
112
- const topics = await ctx.db.query("topics").collect();
113
- return topics.filter((topic) => {
114
- const normalizedGlobalId = normalizeScopeValue(topic.globalId);
115
- const mappedProjectId = asMappedProjectId(topic);
116
- return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
117
- });
118
- }
119
- }
120
- async function tryResolveHostTopicById(ctx, topicId) {
121
- if (typeof ctx.runQuery !== "function") {
122
- return null;
123
248
  }
124
249
  try {
125
- return await ctx.runQuery(api.topics.get, {
126
- id: topicId
127
- }) ?? null;
128
- } catch (error) {
129
- debugGraphPrimitiveFallback(
130
- "[topicScope] Failed to resolve topic by host query",
250
+ const topic = await ctx.runQuery(
251
+ api.topics.getByLegacyScopeId,
131
252
  {
132
- error,
133
- topicId
253
+ projectId: String(scopeId)
134
254
  }
135
255
  );
136
- return null;
137
- }
138
- }
139
- async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
140
- if (typeof ctx.runQuery !== "function") {
141
- return null;
142
- }
143
- try {
144
- return await ctx.runQuery(api.topics.getByLegacyScopeId, {
145
- projectId: legacyScopeId
146
- }) ?? null;
256
+ if (topic?.name !== void 0 && topic?.type !== void 0) {
257
+ return topic;
258
+ }
147
259
  } catch (error) {
148
260
  debugGraphPrimitiveFallback(
149
- "[topicScope] Failed to resolve topic by legacy scope",
150
- {
151
- error,
152
- legacyScopeId
153
- }
261
+ "[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
262
+ { error, scopeId }
154
263
  );
155
- return null;
156
264
  }
265
+ return null;
157
266
  }
158
- async function resolveInheritedWorkspaceScope(ctx, topic) {
159
- const MAX_DEPTH = 10;
160
- let tenantId = normalizeScopeValue(topic.tenantId);
161
- let workspaceId = normalizeScopeValue(topic.workspaceId);
162
- if (tenantId && workspaceId) {
163
- return { tenantId, workspaceId };
267
+ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
268
+ const metadata = readMetadata(topic);
269
+ const topicId = String(topic._id);
270
+ const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
271
+ const storageProjectId = legacyProjectId || topicId;
272
+ const outwardId = idMode === "topic" ? topicId : storageProjectId;
273
+ const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
274
+ const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
275
+ let createdAt = 0;
276
+ if (typeof topic.createdAt === "number") {
277
+ createdAt = topic.createdAt;
278
+ } else if (typeof topic._creationTime === "number") {
279
+ createdAt = topic._creationTime;
280
+ }
281
+ let updatedAt = createdAt;
282
+ if (typeof topic.updatedAt === "number") {
283
+ updatedAt = topic.updatedAt;
284
+ } else if (typeof metadata.updatedAt === "number") {
285
+ updatedAt = metadata.updatedAt;
164
286
  }
165
- let current = topic;
166
- for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
167
- current = await ctx.db.get(current.parentTopicId);
168
- if (!current) break;
169
- if (!tenantId) {
170
- tenantId = normalizeScopeValue(current.tenantId);
171
- }
172
- if (!workspaceId) {
173
- workspaceId = normalizeScopeValue(current.workspaceId);
174
- }
175
- if (tenantId && workspaceId) break;
287
+ return {
288
+ ...metadata,
289
+ _id: outwardId,
290
+ projectId: outwardId,
291
+ topicId,
292
+ storageProjectId,
293
+ legacyProjectId,
294
+ name: readNonEmptyString(topic.name) || "Untitled Theme",
295
+ type: mapProjectType(topic, metadata),
296
+ description: readNonEmptyString(topic.description),
297
+ ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
298
+ // FR.7 creator-grant: surface the principal-shaped owner field (column-first,
299
+ // metadata fallback for legacy rows that recorded it in metadata).
300
+ ownerPrincipalId: readNonEmptyString(topic.ownerPrincipalId) || readNonEmptyString(metadata.ownerPrincipalId),
301
+ // RR.1 carrier: preserve the nested metadata carrier so the kernel's
302
+ // `checkProjectAccessDetailed` metadata-PRIMARY read
303
+ // (`project.metadata?.ownerPrincipalId`) resolves the grant. The `...metadata`
304
+ // spread above only flattens keys; it does not leave a nested `metadata`.
305
+ metadata,
306
+ sharedWith: readStringArray(metadata.sharedWith),
307
+ visibility,
308
+ tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
309
+ workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
310
+ status,
311
+ tags: readStringArray(metadata.tags),
312
+ chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
313
+ artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
314
+ lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
315
+ _creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
316
+ createdAt,
317
+ updatedAt
318
+ };
319
+ }
320
+ async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
321
+ const topic = await resolveTopicDoc(ctx, scopeId);
322
+ if (!topic) {
323
+ return null;
176
324
  }
177
- return { tenantId, workspaceId };
325
+ if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
326
+ return null;
327
+ }
328
+ return materializeTopicProjectOverlay(topic, options.idMode);
178
329
  }
179
- async function resolveTopicProjectScope(ctx, args) {
180
- if (args.topicId) {
181
- let topic = null;
330
+ async function listTopicProjectOverlays(ctx, options = {}) {
331
+ let allTopics = [];
332
+ if (ctx?.db?.query && typeof ctx.db.query === "function") {
182
333
  try {
183
- topic = await ctx.db.get(
184
- args.topicId
185
- );
334
+ allTopics = await ctx.db.query("topics").collect();
186
335
  } catch (error) {
187
336
  debugGraphPrimitiveFallback(
188
- "[topicScope] Failed to load topic by direct id",
189
- {
190
- error,
191
- topicId: args.topicId
192
- }
337
+ "[topicProjectOverlay] Failed to read topics table; falling back to API",
338
+ { error }
193
339
  );
340
+ allTopics = [];
194
341
  }
195
- if (!topic) {
196
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
197
- }
198
- if (!topic) {
199
- topic = pickPrimaryTopic(
200
- await findTopicsByScopeAlias(ctx, String(args.topicId))
201
- ) ?? null;
342
+ }
343
+ if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
344
+ allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
345
+ }
346
+ return allTopics.filter(
347
+ (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
348
+ ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
349
+ }
350
+ async function patchTopicProjectOverlay(ctx, scopeId, value) {
351
+ const topic = await resolveTopicDoc(ctx, scopeId);
352
+ if (!topic) {
353
+ return null;
354
+ }
355
+ const plan = buildTopicProjectOverlayPatchPlan(topic, value);
356
+ await applyTopicProjectOverlayPatch(ctx, topic, plan);
357
+ return materializeTopicProjectOverlay({
358
+ ...topic,
359
+ ...plan.patch,
360
+ metadata: plan.nextMetadata
361
+ });
362
+ }
363
+ function buildTopicProjectOverlayPatchPlan(topic, value) {
364
+ const plan = {
365
+ nextMetadata: { ...readMetadata(topic) },
366
+ patch: {},
367
+ topicUpdateArgs: {
368
+ id: String(topic._id)
202
369
  }
203
- if (!topic) {
204
- const nodeScope = await resolveTopicNodeScopeOrNull(
205
- ctx,
206
- String(args.topicId)
370
+ };
371
+ for (const [key, rawValue] of Object.entries(value)) {
372
+ applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
373
+ }
374
+ plan.patch.updatedAt = Date.now();
375
+ plan.patch.metadata = plan.nextMetadata;
376
+ plan.topicUpdateArgs.metadata = plan.nextMetadata;
377
+ return plan;
378
+ }
379
+ function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
380
+ switch (key) {
381
+ case "_id":
382
+ case "projectId":
383
+ case "topicId":
384
+ case "legacyProjectId":
385
+ case "storageProjectId":
386
+ case "updatedAt":
387
+ case "createdAt":
388
+ return;
389
+ case "name":
390
+ case "description":
391
+ plan.patch[key] = rawValue;
392
+ plan.topicUpdateArgs[key] = rawValue;
393
+ return;
394
+ case "tenantId":
395
+ case "workspaceId":
396
+ case "ownerId":
397
+ throw new Error(
398
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
207
399
  );
208
- if (nodeScope) {
209
- return nodeScope;
210
- }
211
- throw new Error(`Topic not found: ${String(args.topicId)}`);
212
- }
213
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
214
- const mapped = asMappedProjectId(topic);
215
- if (mapped) {
216
- return {
217
- topicId: topic._id,
218
- projectId: mapped,
219
- tenantId: inherited.tenantId,
220
- workspaceId: inherited.workspaceId,
221
- source: "topic"
222
- };
223
- }
224
- return {
225
- topicId: topic._id,
226
- tenantId: inherited.tenantId,
227
- workspaceId: inherited.workspaceId,
228
- source: "topic"
229
- };
400
+ case "status":
401
+ applyTopicStatusPatch(plan, rawValue);
402
+ return;
403
+ case "visibility":
404
+ applyTopicVisibilityPatch(plan, rawValue);
405
+ return;
406
+ case "type":
407
+ applyTopicProjectTypePatch(plan, rawValue);
408
+ return;
409
+ default:
410
+ applyTopicMetadataPatch(plan, key, rawValue);
411
+ }
412
+ }
413
+ function applyTopicStatusPatch(plan, rawValue) {
414
+ const status = coerceStatus(rawValue);
415
+ if (status) {
416
+ plan.patch.status = status;
417
+ plan.topicUpdateArgs.status = status;
418
+ }
419
+ }
420
+ function applyTopicVisibilityPatch(plan, rawValue) {
421
+ const visibility = coerceVisibility(rawValue);
422
+ if (visibility) {
423
+ plan.patch.visibility = visibility;
424
+ plan.topicUpdateArgs.visibility = visibility;
425
+ }
426
+ }
427
+ function applyTopicProjectTypePatch(plan, rawValue) {
428
+ const projectType = readNonEmptyString(rawValue);
429
+ if (projectType) {
430
+ plan.nextMetadata.projectType = projectType;
431
+ return;
230
432
  }
231
- if (args.projectId) {
232
- let directTopic = null;
433
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
434
+ }
435
+ function applyTopicMetadataPatch(plan, key, rawValue) {
436
+ if (rawValue === void 0) {
437
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
438
+ return;
439
+ }
440
+ plan.nextMetadata[key] = rawValue;
441
+ }
442
+ async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
443
+ if (typeof ctx.runMutation === "function") {
233
444
  try {
234
- directTopic = await ctx.db.get(
235
- args.projectId
236
- );
445
+ await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
237
446
  } catch (error) {
238
- debugGraphPrimitiveFallback(
239
- "[topicScope] Failed to load direct project topic",
240
- {
241
- error,
242
- projectId: args.projectId
243
- }
244
- );
245
- }
246
- if (directTopic) {
247
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
248
- const mapped = asMappedProjectId(directTopic);
249
- return {
250
- topicId: directTopic._id,
251
- projectId: mapped ?? args.projectId,
252
- tenantId: inherited.tenantId,
253
- workspaceId: inherited.workspaceId,
254
- source: "topic_inferred"
255
- };
256
- }
257
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
258
- if (directTopic) {
259
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
260
- const mapped = asMappedProjectId(directTopic);
261
- return {
262
- topicId: directTopic._id,
263
- projectId: mapped ?? args.projectId,
264
- tenantId: inherited.tenantId,
265
- workspaceId: inherited.workspaceId,
266
- source: "topic_inferred"
267
- };
268
- }
269
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
270
- const primary = pickPrimaryTopic(topics);
271
- if (primary) {
272
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
273
- return {
274
- topicId: primary._id,
275
- projectId: args.projectId,
276
- tenantId: inherited.tenantId,
277
- workspaceId: inherited.workspaceId,
278
- source: "project_mapped_topic"
279
- };
280
- }
281
- const nodeScope = await resolveTopicNodeScopeOrNull(
282
- ctx,
283
- String(args.projectId)
284
- );
285
- if (nodeScope) {
286
- return {
287
- ...nodeScope,
288
- projectId: nodeScope.projectId ?? String(args.projectId)
289
- };
447
+ if (!canPatchTopicViaLocalDb(ctx, error)) {
448
+ throw error;
449
+ }
450
+ await ctx.db.patch(topic._id, plan.patch);
290
451
  }
452
+ } else if (ctx?.db && typeof ctx.db.patch === "function") {
453
+ await ctx.db.patch(topic._id, plan.patch);
454
+ } else {
291
455
  throw new Error(
292
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
456
+ "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
293
457
  );
294
458
  }
295
- throw new Error(
296
- "Missing scope: provide topicId (preferred) or legacy projectId alias."
297
- );
298
459
  }
299
- var optionalScopeArgs = {
300
- projectId: v.optional(v.string()),
301
- topicId: v.optional(v.string())
302
- };
303
- async function insertEpistemicNode(ctx, doc) {
304
- assertUuidV7Identity("epistemicNodes", doc.globalId);
305
- return ctx.db.insert("epistemicNodes", doc);
460
+ function canPatchTopicViaLocalDb(ctx, error) {
461
+ return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
306
462
  }
307
- async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
308
- assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
309
- const node = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", endpoint)).first();
310
- if (!node) {
311
- throw new Error(
312
- `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
313
- );
314
- }
463
+
464
+ // src/resolvers.ts
465
+ function isMissingLucernChildComponentError2(error) {
466
+ const message = getErrorMessage2(error);
467
+ return message.includes(
468
+ 'Child component ComponentName(Identifier("lucern")) not found'
469
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
315
470
  }
316
- async function insertEpistemicEdge(ctx, doc) {
317
- assertUuidV7Identity("epistemicEdges", doc.globalId);
318
- assertStorageEdgeVocabulary(doc.edgeType);
319
- if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
320
- throw new Error(
321
- "edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
322
- );
471
+ function getErrorMessage2(error) {
472
+ if (error instanceof Error) {
473
+ return error.message;
323
474
  }
324
- if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
325
- throw new Error(
326
- "edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
327
- );
475
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
476
+ return error.message;
328
477
  }
329
- await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
330
- await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
331
- if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
332
- assertEdgePolicyAllowed(
333
- edgePolicyManifest,
334
- doc.edgeType,
335
- {
336
- kind: "epistemic_node",
337
- nodeId: doc.fromNodeId,
338
- nodeType: doc.fromNodeType
339
- },
478
+ return "unknown error";
479
+ }
480
+ function isAdvisoryTopicPatch(value) {
481
+ const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
482
+ const keys = Object.keys(value);
483
+ return keys.length > 0 && keys.every((key) => advisoryKeys.has(key));
484
+ }
485
+ async function patchProjectWithTolerance(ctx, projectId, value) {
486
+ try {
487
+ await patchTopicProjectOverlay(ctx, projectId, value);
488
+ } catch (error) {
489
+ if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
490
+ throw error;
491
+ }
492
+ console.warn(
493
+ "[lucern graph-primitives] Non-fatal advisory topic patch failure",
340
494
  {
341
- kind: "epistemic_node",
342
- nodeId: doc.toNodeId,
343
- nodeType: doc.toNodeType
495
+ projectId,
496
+ keys: Object.keys(value),
497
+ error: getErrorMessage2(error)
344
498
  }
345
499
  );
346
500
  }
347
- return ctx.db.insert("epistemicEdges", doc);
348
501
  }
349
-
350
- // src/epistemicBeliefs.topicAnchor.ts
351
- function cleanString(value) {
352
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
502
+ function defaultResolvers() {
503
+ return {
504
+ getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
505
+ idMode: "legacy",
506
+ projectLikeOnly: false
507
+ }),
508
+ patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
509
+ listTopics: (ctx) => listTopicProjectOverlays(ctx, {
510
+ idMode: "legacy"
511
+ }),
512
+ getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
513
+ };
353
514
  }
354
- function topicNodeCandidates(topicRef) {
355
- const normalized = topicRef.trim();
356
- if (!normalized) {
357
- return [];
358
- }
359
- const candidates = [normalized];
360
- if (normalized.startsWith("top_")) {
361
- candidates.push(normalized.slice(4));
362
- }
363
- return [...new Set(candidates)];
364
- }
365
- function readTopicNodeRef(args) {
366
- return cleanString(args.topicGlobalId) ?? cleanString(args.topicNodeId) ?? cleanString(args.topicId);
367
- }
368
- async function resolveRequiredTopicAnchor(ctx, topicRef) {
369
- for (const candidate of topicNodeCandidates(topicRef)) {
370
- try {
371
- const direct = await ctx.db.get(candidate);
372
- if (direct?.nodeType === "topic" && cleanString(direct.globalId)) {
373
- return direct;
374
- }
375
- } catch (_) {
376
- }
377
- const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
378
- if (byGlobalId?.nodeType === "topic" && cleanString(byGlobalId.globalId)) {
379
- return byGlobalId;
380
- }
381
- }
382
- throw new Error(
383
- "Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes. Legacy topics-table IDs are not valid belief anchors."
384
- );
385
- }
386
- function scopeFromTopicAnchor(topicNode) {
515
+ var resolverOverrides = {};
516
+ function resolveGraphPrimitivesAppResolvers(_ctx) {
387
517
  return {
388
- topicId: topicNode.globalId,
389
- projectId: cleanString(topicNode.projectId),
390
- tenantId: cleanString(topicNode.tenantId),
391
- workspaceId: cleanString(topicNode.workspaceId),
392
- source: "topic"
518
+ ...defaultResolvers(),
519
+ ...resolverOverrides
393
520
  };
394
521
  }
395
- async function createRequiredBeliefTopicEdge(ctx, args) {
396
- const topicGlobalId = args.topicNode.globalId;
397
- const now = Date.now();
398
- const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
399
- "by_from_to",
400
- (q) => q.eq("fromNodeId", args.beliefGlobalId).eq("toNodeId", topicGlobalId)
401
- ).collect();
402
- const existing = existingEdges.find((edge) => edge.edgeType === "belongs_to");
403
- const edgeGlobalId = cleanString(existing?.globalId) ?? generateUuidV7();
404
- if (!existing) {
405
- await insertEpistemicEdge(ctx, {
406
- globalId: edgeGlobalId,
407
- fromNodeId: args.beliefGlobalId,
408
- toNodeId: topicGlobalId,
409
- sourceGlobalId: args.beliefGlobalId,
410
- targetGlobalId: topicGlobalId,
411
- edgeType: "belongs_to",
412
- weight: 1,
413
- confidence: 1,
414
- context: "Belief creation topic anchor invariant.",
415
- reasoningMethod: "implicit",
416
- derivationType: "topic_scope_invariant",
417
- metadata: {
418
- invariant: "belief.topic_edge_required",
419
- edgeUuid: edgeGlobalId,
420
- fromUuid: args.beliefGlobalId,
421
- toUuid: topicGlobalId
422
- },
423
- createdBy: args.createdBy,
424
- createdAt: now,
425
- updatedAt: now,
426
- projectId: cleanString(args.topicNode.projectId),
427
- topicId: topicGlobalId,
428
- tenantId: cleanString(args.topicNode.tenantId),
429
- workspaceId: cleanString(args.topicNode.workspaceId),
430
- fromNodeType: "belief",
431
- toNodeType: "topic",
432
- fromLayer: "L3",
433
- toLayer: args.topicNode.epistemicLayer ?? "ontological"
434
- });
522
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
523
+ async function resolveTopicNodeScopeOrNull(ctx, ref) {
524
+ if (!ctx?.db || typeof ctx.db.query !== "function") {
525
+ return null;
435
526
  }
436
- await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
437
- globalId: edgeGlobalId,
438
- fromGlobalId: args.beliefGlobalId,
439
- toGlobalId: topicGlobalId,
440
- edgeType: "belongs_to",
441
- weight: 1,
442
- confidence: 1,
443
- context: "Belief creation topic anchor invariant.",
444
- projectId: cleanString(args.topicNode.projectId),
445
- topicId: topicGlobalId,
446
- createdBy: args.createdBy,
447
- fromNodeType: "belief",
448
- toNodeType: "topic",
449
- fromLayer: "L3",
450
- toLayer: args.topicNode.epistemicLayer ?? "ontological",
451
- metadata: {
452
- invariant: "belief.topic_edge_required",
453
- edgeUuid: edgeGlobalId,
454
- fromUuid: args.beliefGlobalId,
455
- toUuid: topicGlobalId
527
+ let node = null;
528
+ try {
529
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
530
+ if (byGlobalId && byGlobalId.nodeType === "topic") {
531
+ node = byGlobalId;
456
532
  }
457
- });
458
- }
459
- function normalizeScopeValue2(value) {
460
- if (typeof value !== "string") {
461
- return;
462
- }
463
- const normalized = value.trim();
464
- return normalized.length > 0 ? normalized : void 0;
465
- }
466
- function throwWorkspaceIsolationError(args) {
467
- const error = new Error(args.message);
468
- error.status = 409;
469
- error.code = "INVARIANT_VIOLATION";
470
- error.invariantCode = args.invariantCode;
471
- error.suggestion = args.suggestion;
472
- error.details = args.details;
473
- throw error;
474
- }
475
- function assertWorkspaceScopedEpistemicNodeScope(args) {
476
- const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
477
- if (layer === "ontological") {
478
- return;
479
- }
480
- const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
481
- if (workspaceId) {
482
- return;
533
+ } catch (error) {
534
+ debugGraphPrimitiveFallback(
535
+ "[topicScope] topic-node scope lookup by globalId failed",
536
+ { error, ref }
537
+ );
483
538
  }
484
- throwWorkspaceIsolationError({
485
- message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
486
- invariantCode: "workspace.scope_required_for_epistemic_nodes",
487
- suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
488
- details: {
489
- mutationName: args.mutationName,
490
- nodeType: args.nodeType,
491
- topicId: args.scope.topicId,
492
- projectId: args.scope.projectId
493
- }
494
- });
495
- }
496
- function nodeMatchesWorkspaceReasoningScope(node, scope) {
497
539
  if (!node) {
498
- return false;
499
- }
500
- const scopeTenantId = normalizeScopeValue2(scope.tenantId);
501
- const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
502
- const nodeTenantId = normalizeScopeValue2(node.tenantId);
503
- const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
504
- const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
505
- if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
506
- return false;
507
- }
508
- if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
509
- return true;
510
- }
511
- if (!scopeWorkspaceId && node.publicationStatus === "published") {
512
- return true;
513
- }
514
- if (!scopeWorkspaceId) {
515
- return nodeWorkspaceId === void 0;
540
+ return null;
516
541
  }
517
- return scopeWorkspaceId === nodeWorkspaceId;
518
- }
519
- function resolveRuntimePackMutationContext(args) {
520
- if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
521
- return;
542
+ const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
543
+ if (!scopeKey) {
544
+ return null;
522
545
  }
523
546
  return {
524
- toolName: args.runtimeToolName,
525
- packKey: args.runtimePackKey,
526
- packInstallScope: args.runtimePackInstallScope
547
+ topicId: scopeKey,
548
+ projectId: asMappedProjectId(node),
549
+ source: "topic_node"
527
550
  };
528
551
  }
529
- function assertTenantPackWorkspaceMutationAllowed(args) {
530
- if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
531
- return;
532
- }
533
- const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
534
- const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
535
- if (!targetWorkspaceId || targetLayer === "ontological") {
552
+ function asMappedProjectId(topic) {
553
+ if (!topic) {
536
554
  return;
537
555
  }
538
- throwWorkspaceIsolationError({
539
- message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
540
- invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
541
- suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
542
- details: {
543
- mutationName: args.mutationName,
544
- toolName: args.runtime.toolName,
545
- packKey: args.runtime.packKey,
546
- targetWorkspaceId,
547
- targetNodeType: args.target.nodeType,
548
- targetLayer
549
- }
550
- });
551
- }
552
-
553
- // src/beliefLifecycle.ts
554
- var BELIEF_STATUS_VALUES = [
555
- "assumption",
556
- "hypothesis",
557
- "active",
558
- "superseded",
559
- "resolved_true",
560
- "resolved_false"
561
- ];
562
- function isBeliefLifecycleStatus(value) {
563
- return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
564
- }
565
- function normalizeLegacyBeliefStatus(value) {
566
- if (isBeliefLifecycleStatus(value)) {
567
- return value;
568
- }
569
- if (value === "belief" || value === "established" || value === "emerging") {
570
- return "active";
571
- }
572
- if (value === "fact" || value === "confirmed") {
573
- return "resolved_true";
574
- }
575
- if (value === "disconfirmed" || value === "expired") {
576
- return "resolved_false";
577
- }
578
- if (value === "deprecated") {
579
- return "superseded";
580
- }
581
- return null;
582
- }
583
- function normalizeBeliefConfidence(confidence) {
584
- if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
585
- return null;
586
- }
587
- if (confidence >= 0 && confidence <= 1) {
588
- return confidence;
589
- }
590
- if (confidence > 1 && confidence <= 100) {
591
- return confidence / 100;
592
- }
593
- return null;
594
- }
595
- function isResolvedByConfidence(confidence) {
596
- const normalized = normalizeBeliefConfidence(confidence);
597
- if (normalized === null) {
598
- return false;
599
- }
600
- return normalized <= 0 || normalized >= 1;
601
- }
602
- function getPredictionMetaFromMetadata(metadata) {
603
- return metadata?.predictionMeta;
604
- }
605
- function resolvedPredictionStatus(predictionMeta) {
606
- if (!predictionMeta || typeof predictionMeta !== "object") {
607
- return null;
608
- }
609
- const outcome = predictionMeta.outcome;
610
- if (outcome === "confirmed") {
611
- return "resolved_true";
612
- }
613
- if (outcome === "disconfirmed" || outcome === "expired") {
614
- return "resolved_false";
615
- }
616
- return null;
617
- }
618
- function shouldTreatBeliefAsResolved(opts) {
619
- if (isResolvedByConfidence(opts.confidence)) {
620
- const normalized = normalizeBeliefConfidence(opts.confidence);
621
- return normalized === 0 ? "resolved_false" : "resolved_true";
622
- }
623
- const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
624
- if (directPredictionStatus) {
625
- return directPredictionStatus;
626
- }
627
- const metadataPredictionStatus = resolvedPredictionStatus(
628
- getPredictionMetaFromMetadata(opts.metadata)
556
+ const directLegacyProjectId = normalizeScopeValue(
557
+ topic[LEGACY_SCOPE_FIELD2]
629
558
  );
630
- if (metadataPredictionStatus) {
631
- return metadataPredictionStatus;
632
- }
633
- return null;
634
- }
635
- function resolveBeliefLifecycleStatus(opts) {
636
- const resolvedStatus = shouldTreatBeliefAsResolved(opts);
637
- if (resolvedStatus) {
638
- return resolvedStatus;
639
- }
640
- const direct = opts.beliefStatus;
641
- const normalizedDirect = normalizeLegacyBeliefStatus(direct);
642
- if (normalizedDirect) {
643
- const normalized = normalizeBeliefConfidence(opts.confidence);
644
- if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
645
- return "active";
646
- }
647
- return normalizedDirect;
648
- }
649
- const metaStatus = opts.metadata?.beliefStatus;
650
- const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
651
- if (normalizedMetaStatus) {
652
- const normalized = normalizeBeliefConfidence(opts.confidence);
653
- if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
654
- return "active";
655
- }
656
- return normalizedMetaStatus;
559
+ if (directLegacyProjectId) {
560
+ return directLegacyProjectId;
657
561
  }
658
- return "assumption";
659
- }
660
- function isPreValidationBeliefStatus(status) {
661
- return status === "assumption" || status === "hypothesis";
562
+ const metadata = topic.metadata || {};
563
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
564
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
662
565
  }
663
-
664
- // src/topicProjectOverlay.ts
665
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
666
- function readNonEmptyString(value) {
566
+ function normalizeScopeValue(value) {
667
567
  if (typeof value !== "string") {
668
568
  return;
669
569
  }
670
570
  const normalized = value.trim();
671
571
  return normalized.length > 0 ? normalized : void 0;
672
572
  }
673
- function readStringArray(value) {
674
- if (!Array.isArray(value)) {
675
- return [];
676
- }
677
- return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
678
- }
679
- function readMetadata(topic) {
680
- return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
681
- }
682
- function readLegacyProjectId(value) {
683
- if (!value) {
684
- return;
685
- }
686
- return readNonEmptyString(value[LEGACY_SCOPE_FIELD2]);
687
- }
688
- function coerceVisibility(value) {
689
- return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
690
- }
691
- function coerceStatus(value) {
692
- return value === "active" || value === "archived" || value === "watching" ? value : void 0;
693
- }
694
- function mapProjectType(topic, metadata) {
695
- const explicit = readNonEmptyString(metadata.projectType);
696
- if (explicit) {
697
- return explicit;
698
- }
699
- if (topic.type === "theme") {
700
- return "thematic";
701
- }
702
- return readNonEmptyString(topic.type) || "general";
703
- }
704
- function isProjectLikeTopic(topic) {
705
- const metadata = readMetadata(topic);
706
- return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
707
- }
708
- function isMissingLucernChildComponentError(error) {
709
- const message = getErrorMessage(error);
710
- return message.includes(
711
- 'Child component ComponentName(Identifier("lucern")) not found'
712
- ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
713
- }
714
- function getErrorMessage(error) {
715
- if (error instanceof Error) {
716
- return error.message;
717
- }
718
- if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
719
- return error.message;
720
- }
721
- return "unknown error";
722
- }
723
- async function resolveTopicDoc(ctx, scopeId) {
724
- if (ctx?.db && typeof ctx.db.get === "function") {
725
- try {
726
- const directTopic = await ctx.db.get(
727
- scopeId
728
- );
729
- if (directTopic) {
730
- return directTopic;
731
- }
732
- } catch (error) {
733
- debugGraphPrimitiveFallback(
734
- "[topicProjectOverlay] Failed to resolve topic by direct ID",
735
- {
736
- error,
737
- scopeId
738
- }
739
- );
573
+ function pickPrimaryTopic(candidates) {
574
+ return [...candidates].sort((a, b) => {
575
+ const depthA = a.depth ?? 9999;
576
+ const depthB = b.depth ?? 9999;
577
+ if (depthA !== depthB) {
578
+ return depthA - depthB;
740
579
  }
741
- }
742
- if (typeof ctx.runQuery !== "function") {
743
- return null;
744
- }
745
- try {
746
- const topic = await ctx.runQuery(api.topics.get, {
747
- id: String(scopeId)
748
- });
749
- if (topic?.name !== void 0 && topic?.type !== void 0) {
750
- return topic;
580
+ const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
581
+ const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
582
+ if (createdA !== createdB) {
583
+ return createdA - createdB;
751
584
  }
585
+ return String(a.name || "").localeCompare(String(b.name || ""));
586
+ })[0];
587
+ }
588
+ async function findTopicsByScopeAlias(ctx, scopeId) {
589
+ const query = ctx.db.query("topics");
590
+ try {
591
+ return await query.withIndex(
592
+ "by_graph_scope_project",
593
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
594
+ ).collect();
752
595
  } catch (error) {
753
596
  debugGraphPrimitiveFallback(
754
- "[topicProjectOverlay] Failed to resolve topic by ID query",
597
+ "[topicScope] Failed to resolve scope alias via index",
755
598
  {
756
599
  error,
757
600
  scopeId
758
601
  }
759
602
  );
603
+ const topics = await query.collect();
604
+ return topics.filter((topic) => {
605
+ const normalizedGlobalId = normalizeScopeValue(topic.globalId);
606
+ const mappedProjectId = asMappedProjectId(topic);
607
+ return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
608
+ });
609
+ }
610
+ }
611
+ async function tryResolveHostTopicById(ctx, topicId) {
612
+ if (typeof ctx.runQuery !== "function") {
613
+ return null;
760
614
  }
761
615
  try {
762
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
763
- projectId: String(scopeId)
764
- });
765
- if (topic?.name !== void 0 && topic?.type !== void 0) {
766
- return topic;
767
- }
616
+ return await ctx.runQuery(api.topics.get, {
617
+ id: topicId
618
+ }) ?? null;
768
619
  } catch (error) {
769
620
  debugGraphPrimitiveFallback(
770
- "[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
771
- { error, scopeId }
621
+ "[topicScope] Failed to resolve topic by host query",
622
+ {
623
+ error,
624
+ topicId
625
+ }
772
626
  );
627
+ return null;
773
628
  }
774
- return null;
775
- }
776
- function materializeTopicProjectOverlay(topic, idMode = "legacy") {
777
- const metadata = readMetadata(topic);
778
- const topicId = String(topic._id);
779
- const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
780
- const storageProjectId = legacyProjectId || topicId;
781
- const outwardId = idMode === "topic" ? topicId : storageProjectId;
782
- const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
783
- const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
784
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
785
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
786
- return {
787
- ...metadata,
788
- _id: outwardId,
789
- projectId: outwardId,
790
- topicId,
791
- storageProjectId,
792
- legacyProjectId,
793
- name: readNonEmptyString(topic.name) || "Untitled Theme",
794
- type: mapProjectType(topic, metadata),
795
- description: readNonEmptyString(topic.description),
796
- ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
797
- // FR.7 creator-grant: surface the principal-shaped owner field (column-first,
798
- // metadata fallback for legacy rows that recorded it in metadata).
799
- ownerPrincipalId: readNonEmptyString(topic.ownerPrincipalId) || readNonEmptyString(metadata.ownerPrincipalId),
800
- // RR.1 carrier: preserve the nested metadata carrier so the kernel's
801
- // `checkProjectAccessDetailed` metadata-PRIMARY read
802
- // (`project.metadata?.ownerPrincipalId`) resolves the grant. The `...metadata`
803
- // spread above only flattens keys; it does not leave a nested `metadata`.
804
- metadata,
805
- sharedWith: readStringArray(metadata.sharedWith),
806
- visibility,
807
- tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
808
- workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
809
- status,
810
- tags: readStringArray(metadata.tags),
811
- chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
812
- artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
813
- lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
814
- _creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
815
- createdAt,
816
- updatedAt
817
- };
818
629
  }
819
- async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
820
- const topic = await resolveTopicDoc(ctx, scopeId);
821
- if (!topic) {
630
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
631
+ if (typeof ctx.runQuery !== "function") {
822
632
  return null;
823
633
  }
824
- if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
634
+ try {
635
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
636
+ projectId: legacyScopeId
637
+ }) ?? null;
638
+ } catch (error) {
639
+ debugGraphPrimitiveFallback(
640
+ "[topicScope] Failed to resolve topic by legacy scope",
641
+ {
642
+ error,
643
+ legacyScopeId
644
+ }
645
+ );
825
646
  return null;
826
647
  }
827
- return materializeTopicProjectOverlay(topic, options.idMode);
828
648
  }
829
- async function listTopicProjectOverlays(ctx, options = {}) {
830
- let allTopics = [];
831
- if (ctx?.db?.query && typeof ctx.db.query === "function") {
832
- try {
833
- allTopics = await ctx.db.query("topics").collect();
834
- } catch (error) {
835
- debugGraphPrimitiveFallback(
836
- "[topicProjectOverlay] Failed to read topics table; falling back to API",
837
- { error }
838
- );
839
- allTopics = [];
840
- }
649
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
650
+ const MAX_DEPTH = 10;
651
+ let tenantId = normalizeScopeValue(topic.tenantId);
652
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
653
+ if (tenantId && workspaceId) {
654
+ return { tenantId, workspaceId };
841
655
  }
842
- if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
843
- allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
656
+ let current = topic;
657
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
658
+ current = await ctx.db.get(current.parentTopicId);
659
+ if (!current) {
660
+ break;
661
+ }
662
+ if (!tenantId) {
663
+ tenantId = normalizeScopeValue(current.tenantId);
664
+ }
665
+ if (!workspaceId) {
666
+ workspaceId = normalizeScopeValue(current.workspaceId);
667
+ }
668
+ if (tenantId && workspaceId) {
669
+ break;
670
+ }
844
671
  }
845
- return allTopics.filter(
846
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
847
- ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
672
+ return { tenantId, workspaceId };
848
673
  }
849
- async function patchTopicProjectOverlay(ctx, scopeId, value) {
850
- const topic = await resolveTopicDoc(ctx, scopeId);
851
- if (!topic) {
852
- return null;
674
+ async function resolveTopicProjectScope(ctx, args) {
675
+ if (args.topicId) {
676
+ return await resolveScopeFromTopicId(ctx, args.topicId);
853
677
  }
854
- const nextMetadata = { ...readMetadata(topic) };
855
- const patch = {};
856
- const topicUpdateArgs = {
857
- id: String(topic._id)
858
- };
859
- for (const [key, rawValue] of Object.entries(value)) {
860
- switch (key) {
861
- case "_id":
862
- case "projectId":
863
- case "topicId":
864
- case "legacyProjectId":
865
- case "storageProjectId":
866
- break;
867
- case "name":
868
- case "description":
869
- patch[key] = rawValue;
870
- topicUpdateArgs[key] = rawValue;
871
- break;
872
- case "tenantId":
873
- case "workspaceId":
874
- case "ownerId":
875
- throw new Error(
876
- `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
877
- );
878
- case "status": {
879
- const status = coerceStatus(rawValue);
880
- if (status) {
881
- patch.status = status;
882
- topicUpdateArgs.status = status;
883
- }
884
- break;
885
- }
886
- case "visibility": {
887
- const visibility = coerceVisibility(rawValue);
888
- if (visibility) {
889
- patch.visibility = visibility;
890
- topicUpdateArgs.visibility = visibility;
891
- }
892
- break;
893
- }
894
- case "type": {
895
- const projectType = readNonEmptyString(rawValue);
896
- if (projectType) {
897
- nextMetadata.projectType = projectType;
898
- } else {
899
- delete nextMetadata.projectType;
900
- }
901
- break;
902
- }
903
- case "updatedAt":
904
- case "createdAt":
905
- break;
906
- default:
907
- if (rawValue === void 0) {
908
- delete nextMetadata[key];
909
- } else {
910
- nextMetadata[key] = rawValue;
911
- }
912
- }
678
+ if (args.projectId) {
679
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
913
680
  }
914
- patch.updatedAt = Date.now();
915
- patch.metadata = nextMetadata;
916
- topicUpdateArgs.metadata = nextMetadata;
917
- if (typeof ctx.runMutation === "function") {
918
- try {
919
- await ctx.runMutation(api.topics.update, topicUpdateArgs);
920
- } catch (error) {
921
- if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
922
- throw error;
923
- }
924
- await ctx.db.patch(String(topic._id), patch);
925
- }
926
- } else if (ctx?.db && typeof ctx.db.patch === "function") {
927
- await ctx.db.patch(String(topic._id), patch);
928
- } else {
929
- throw new Error(
930
- "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
931
- );
681
+ throw new Error(
682
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
683
+ );
684
+ }
685
+ async function resolveScopeFromTopicId(ctx, topicId) {
686
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
687
+ if (topic) {
688
+ return await buildTopicScope(ctx, topic, "topic");
932
689
  }
933
- return materializeTopicProjectOverlay({
934
- ...topic,
935
- ...patch,
936
- metadata: nextMetadata
937
- });
690
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
691
+ if (nodeScope) {
692
+ return nodeScope;
693
+ }
694
+ throw new Error(`Topic not found: ${String(topicId)}`);
938
695
  }
939
-
940
- // src/resolvers.ts
941
- function isMissingLucernChildComponentError2(error) {
942
- const message = getErrorMessage2(error);
943
- return message.includes(
944
- 'Child component ComponentName(Identifier("lucern")) not found'
945
- ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
696
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
697
+ const direct = await tryReadTopicDoc(ctx, topicId, {
698
+ failureLog: "[topicScope] Failed to load topic by direct id",
699
+ idLogKey: "topicId"
700
+ });
701
+ if (direct) {
702
+ return direct;
703
+ }
704
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
705
+ if (hostTopic) {
706
+ return hostTopic;
707
+ }
708
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
946
709
  }
947
- function getErrorMessage2(error) {
948
- if (error instanceof Error) {
949
- return error.message;
710
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
711
+ const directTopic = await resolveDirectLegacyProjectTopic(
712
+ ctx,
713
+ legacyProjectId
714
+ );
715
+ if (directTopic) {
716
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
717
+ fallbackProjectId: legacyProjectId
718
+ });
950
719
  }
951
- if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
952
- return error.message;
720
+ const primary = pickPrimaryTopic(
721
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
722
+ );
723
+ if (primary) {
724
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
725
+ fallbackProjectId: legacyProjectId
726
+ });
953
727
  }
954
- return "unknown error";
728
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
729
+ if (nodeScope) {
730
+ return {
731
+ ...nodeScope,
732
+ projectId: nodeScope.projectId ?? legacyProjectId
733
+ };
734
+ }
735
+ throw new Error(
736
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
737
+ );
955
738
  }
956
- function isAdvisoryTopicPatch(value) {
957
- const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
958
- const keys = Object.keys(value);
959
- return keys.length > 0 && keys.every((key) => advisoryKeys.has(key));
739
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
740
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
741
+ failureLog: "[topicScope] Failed to load direct project topic",
742
+ idLogKey: "projectId"
743
+ });
744
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
960
745
  }
961
- async function patchProjectWithTolerance(ctx, projectId, value) {
746
+ async function tryReadTopicDoc(ctx, id, log) {
962
747
  try {
963
- await patchTopicProjectOverlay(ctx, projectId, value);
748
+ return await ctx.db.get(id);
964
749
  } catch (error) {
965
- if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
966
- throw error;
967
- }
968
- console.warn(
969
- "[lucern graph-primitives] Non-fatal advisory topic patch failure",
970
- {
971
- projectId,
972
- keys: Object.keys(value),
973
- error: getErrorMessage2(error)
974
- }
975
- );
750
+ debugGraphPrimitiveFallback(log.failureLog, {
751
+ error,
752
+ [log.idLogKey]: id
753
+ });
754
+ return null;
976
755
  }
977
756
  }
978
- function defaultResolvers() {
757
+ async function buildTopicScope(ctx, topic, source, options = {}) {
758
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
759
+ const mapped = asMappedProjectId(topic);
979
760
  return {
980
- getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
981
- idMode: "legacy",
982
- projectLikeOnly: false
983
- }),
984
- patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
985
- listTopics: (ctx) => listTopicProjectOverlays(ctx, {
986
- idMode: "legacy"
987
- }),
988
- getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
761
+ topicId: topic._id,
762
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
763
+ tenantId: inherited.tenantId,
764
+ workspaceId: inherited.workspaceId,
765
+ source
989
766
  };
990
767
  }
991
- var resolverOverrides = {};
992
- function resolveGraphPrimitivesAppResolvers(_ctx) {
768
+ var optionalScopeArgs = {
769
+ projectId: v.optional(v.string()),
770
+ topicId: v.optional(v.string())
771
+ };
772
+ function normalizeScopeValue2(value) {
773
+ if (typeof value !== "string") {
774
+ return;
775
+ }
776
+ const normalized = value.trim();
777
+ return normalized.length > 0 ? normalized : void 0;
778
+ }
779
+ function throwWorkspaceIsolationError(args) {
780
+ const error = new Error(args.message);
781
+ error.status = 409;
782
+ error.code = "INVARIANT_VIOLATION";
783
+ error.invariantCode = args.invariantCode;
784
+ error.suggestion = args.suggestion;
785
+ error.details = args.details;
786
+ throw error;
787
+ }
788
+ function assertWorkspaceScopedEpistemicNodeScope(args) {
789
+ const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
790
+ if (layer === "ontological") {
791
+ return;
792
+ }
793
+ const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
794
+ if (workspaceId) {
795
+ return;
796
+ }
797
+ throwWorkspaceIsolationError({
798
+ message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
799
+ invariantCode: "workspace.scope_required_for_epistemic_nodes",
800
+ suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
801
+ details: {
802
+ mutationName: args.mutationName,
803
+ nodeType: args.nodeType,
804
+ topicId: args.scope.topicId,
805
+ projectId: args.scope.projectId
806
+ }
807
+ });
808
+ }
809
+ function nodeMatchesWorkspaceReasoningScope(node, scope) {
810
+ if (!node) {
811
+ return false;
812
+ }
813
+ const scopeTenantId = normalizeScopeValue2(scope.tenantId);
814
+ const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
815
+ const nodeTenantId = normalizeScopeValue2(node.tenantId);
816
+ const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
817
+ const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
818
+ if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
819
+ return false;
820
+ }
821
+ if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
822
+ return true;
823
+ }
824
+ if (!scopeWorkspaceId && node.publicationStatus === "published") {
825
+ return true;
826
+ }
827
+ if (!scopeWorkspaceId) {
828
+ return nodeWorkspaceId === void 0;
829
+ }
830
+ return scopeWorkspaceId === nodeWorkspaceId;
831
+ }
832
+ function resolveRuntimePackMutationContext(args) {
833
+ if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
834
+ return;
835
+ }
993
836
  return {
994
- ...defaultResolvers(),
995
- ...resolverOverrides
837
+ toolName: args.runtimeToolName,
838
+ packKey: args.runtimePackKey,
839
+ packInstallScope: args.runtimePackInstallScope
996
840
  };
997
841
  }
998
-
999
- // src/epistemicBeliefs.helpers.ts
842
+ function assertTenantPackWorkspaceMutationAllowed(args) {
843
+ if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
844
+ return;
845
+ }
846
+ const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
847
+ const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
848
+ if (!targetWorkspaceId || targetLayer === "ontological") {
849
+ return;
850
+ }
851
+ throwWorkspaceIsolationError({
852
+ message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
853
+ invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
854
+ suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
855
+ details: {
856
+ mutationName: args.mutationName,
857
+ toolName: args.runtime.toolName,
858
+ packKey: args.runtime.packKey,
859
+ targetWorkspaceId,
860
+ targetNodeType: args.target.nodeType,
861
+ targetLayer
862
+ }
863
+ });
864
+ }
1000
865
  v.id("epistemicNodes");
1001
866
  var DEFAULT_PROJECT_BELIEF_LIMIT = 250;
1002
867
  var MAX_PROJECT_BELIEF_LIMIT = 1e3;
@@ -1004,25 +869,119 @@ var optionalBeliefScopeArgs = optionalScopeArgs;
1004
869
  ({
1005
870
  tupleContradiction: normalizeTupleContradictionPolicy()
1006
871
  });
1007
- function throwStructuredMutationError(args) {
1008
- const data = {
1009
- structuredMutationError: true,
1010
- message: args.message,
1011
- status: args.status,
1012
- code: args.code,
1013
- invariantCode: args.invariantCode,
1014
- suggestion: args.suggestion,
1015
- details: args.details
872
+ function readFiniteNumber(value) {
873
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
874
+ }
875
+ function isRecord(value) {
876
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
877
+ }
878
+ function readOptionalString(value) {
879
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
880
+ }
881
+ function readStringArray2(value) {
882
+ if (!Array.isArray(value)) {
883
+ return;
884
+ }
885
+ const strings = value.filter(
886
+ (item) => typeof item === "string" && item.length > 0
887
+ );
888
+ return strings.length === value.length ? strings : void 0;
889
+ }
890
+ function readRecord(value) {
891
+ return isRecord(value) ? value : void 0;
892
+ }
893
+ function readBeliefNodeView(value) {
894
+ if (!isRecord(value)) {
895
+ return null;
896
+ }
897
+ const id = readOptionalString(value._id);
898
+ const nodeType = readOptionalString(value.nodeType);
899
+ if (!(id && nodeType === "belief")) {
900
+ return null;
901
+ }
902
+ const node = {
903
+ _id: id,
904
+ nodeType
1016
905
  };
1017
- const error = new ConvexError(
1018
- data
1019
- );
1020
- error.status = args.status;
1021
- error.code = args.code;
1022
- error.invariantCode = args.invariantCode;
1023
- error.suggestion = args.suggestion;
1024
- error.details = args.details;
1025
- throw error;
906
+ const creationTime = readFiniteNumber(value._creationTime);
907
+ if (creationTime !== void 0) {
908
+ node._creationTime = creationTime;
909
+ }
910
+ const metadata = readRecord(value.metadata);
911
+ if (metadata !== void 0) {
912
+ node.metadata = metadata;
913
+ }
914
+ const opinionA = readFiniteNumber(value.opinion_a);
915
+ if (opinionA !== void 0) {
916
+ node.opinion_a = opinionA;
917
+ }
918
+ const opinionB = readFiniteNumber(value.opinion_b);
919
+ if (opinionB !== void 0) {
920
+ node.opinion_b = opinionB;
921
+ }
922
+ const opinionD = readFiniteNumber(value.opinion_d);
923
+ if (opinionD !== void 0) {
924
+ node.opinion_d = opinionD;
925
+ }
926
+ const opinionU = readFiniteNumber(value.opinion_u);
927
+ if (opinionU !== void 0) {
928
+ node.opinion_u = opinionU;
929
+ }
930
+ const tupleContradicted = typeof value.tupleContradicted === "boolean" ? value.tupleContradicted : void 0;
931
+ if (tupleContradicted !== void 0) {
932
+ node.tupleContradicted = tupleContradicted;
933
+ }
934
+ const stringFields = {
935
+ anonymizationClass: value.anonymizationClass,
936
+ audienceLabel: value.audienceLabel,
937
+ canonicalText: value.canonicalText,
938
+ createdBy: value.createdBy,
939
+ epistemicLayer: value.epistemicLayer,
940
+ exportClass: value.exportClass,
941
+ globalId: value.globalId,
942
+ projectId: value.projectId,
943
+ publicationStatus: value.publicationStatus,
944
+ sensitivityTier: value.sensitivityTier,
945
+ status: value.status,
946
+ tenantId: value.tenantId,
947
+ topicId: value.topicId,
948
+ userId: value.userId,
949
+ workspaceId: value.workspaceId
950
+ };
951
+ for (const [field, fieldValue] of Object.entries(stringFields)) {
952
+ const normalized = readOptionalString(fieldValue);
953
+ if (normalized !== void 0) {
954
+ node[field] = normalized;
955
+ }
956
+ }
957
+ const createdAt = readFiniteNumber(value.createdAt);
958
+ if (createdAt !== void 0) {
959
+ node.createdAt = createdAt;
960
+ }
961
+ const updatedAt = readFiniteNumber(value.updatedAt);
962
+ if (updatedAt !== void 0) {
963
+ node.updatedAt = updatedAt;
964
+ }
965
+ if (value.beliefStatus !== void 0) {
966
+ node.beliefStatus = value.beliefStatus;
967
+ }
968
+ if (value.confidence !== void 0) {
969
+ node.confidence = value.confidence;
970
+ }
971
+ if (value.predictionMeta !== void 0) {
972
+ node.predictionMeta = value.predictionMeta;
973
+ }
974
+ const policyTags = readStringArray2(value.policyTags);
975
+ if (policyTags !== void 0) {
976
+ node.policyTags = policyTags;
977
+ }
978
+ return node;
979
+ }
980
+ function readBeliefNodeViews(values) {
981
+ return values.flatMap((value) => {
982
+ const node = readBeliefNodeView(value);
983
+ return node ? [node] : [];
984
+ });
1026
985
  }
1027
986
  function assertBaseRateInRange(baseRate, field = "baseRate") {
1028
987
  if (baseRate < 0 || baseRate > 1) {
@@ -1118,7 +1077,7 @@ function normalizePillar(pillar) {
1118
1077
  async function markBeliefGraphDirty(ctx, scope) {
1119
1078
  const projectId = typeof scope.projectId === "string" && scope.projectId.trim().length > 0 ? scope.projectId : void 0;
1120
1079
  const topicId = typeof scope.topicId === "string" && scope.topicId.trim().length > 0 ? scope.topicId : void 0;
1121
- if (!projectId && !topicId) {
1080
+ if (!(projectId || topicId)) {
1122
1081
  return;
1123
1082
  }
1124
1083
  if (projectId) {
@@ -1135,16 +1094,22 @@ async function markBeliefGraphDirty(ctx, scope) {
1135
1094
  { topicId }
1136
1095
  );
1137
1096
  }
1097
+ const activityScopeId = topicId ?? projectId;
1098
+ if (!activityScopeId) {
1099
+ throw new Error(
1100
+ "Expected belief graph dirty scope to include a topic or project id."
1101
+ );
1102
+ }
1138
1103
  await resolveGraphPrimitivesAppResolvers().patchProject(
1139
1104
  ctx,
1140
- topicId ?? projectId,
1105
+ activityScopeId,
1141
1106
  {
1142
1107
  lastActivityAt: Date.now()
1143
1108
  }
1144
1109
  );
1145
1110
  }
1146
1111
  async function resolveBeliefScopeOrNull(ctx, args) {
1147
- if (!args.projectId && !args.topicId) {
1112
+ if (!(args.projectId || args.topicId)) {
1148
1113
  return null;
1149
1114
  }
1150
1115
  try {
@@ -1169,14 +1134,17 @@ async function getBeliefNodesForScope(ctx, scope, args) {
1169
1134
  "by_topic_type",
1170
1135
  (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
1171
1136
  );
1172
- const nodes = typeof args?.scanLimit === "number" ? await baseQuery.order("desc").take(args.scanLimit) : await baseQuery.collect();
1137
+ const rows = typeof args?.scanLimit === "number" ? await baseQuery.order("desc").take(args.scanLimit) : await baseQuery.collect();
1138
+ const nodes = readBeliefNodeViews(rows);
1173
1139
  const scopedNodes = nodes.filter(
1174
1140
  (node) => nodeMatchesWorkspaceReasoningScope(node, scope)
1175
1141
  );
1176
1142
  if (!args?.status) {
1177
1143
  return scopedNodes;
1178
1144
  }
1179
- return scopedNodes.filter((node) => node.status === args.status);
1145
+ return scopedNodes.filter(
1146
+ (node) => node.status === args.status
1147
+ );
1180
1148
  }
1181
1149
  function createBeliefAudienceResolver(registryRows) {
1182
1150
  const audienceClassByKey = new Map(
@@ -1196,9 +1164,7 @@ function createBeliefAudienceResolver(registryRows) {
1196
1164
  function flattenBeliefNode(node) {
1197
1165
  const meta = node.metadata || {};
1198
1166
  const worktreeId = resolveBeliefWorktreeId(meta);
1199
- const tupleContradicted = readTupleContradictedFlag(
1200
- node.tupleContradicted
1201
- ) ?? readTupleContradictedFlag(meta.tupleContradicted) ?? false;
1167
+ const tupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(meta.tupleContradicted) ?? false;
1202
1168
  return {
1203
1169
  _id: node._id,
1204
1170
  _epistemicNodeId: node._id,
@@ -1243,8 +1209,172 @@ function resolveBeliefStatus(node, metadata) {
1243
1209
  metadata
1244
1210
  });
1245
1211
  }
1212
+ function insertEpistemicNode(ctx, doc) {
1213
+ assertUuidV7Identity("epistemicNodes", doc.globalId);
1214
+ return ctx.db.insert("epistemicNodes", doc);
1215
+ }
1216
+ async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
1217
+ assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
1218
+ const node = await ctx.db.query("epistemicNodes").withIndex(
1219
+ "by_globalId",
1220
+ (q) => q.eq("globalId", endpoint)
1221
+ ).first();
1222
+ if (!node) {
1223
+ throw new Error(
1224
+ `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
1225
+ );
1226
+ }
1227
+ }
1228
+ async function insertEpistemicEdge(ctx, doc) {
1229
+ assertUuidV7Identity("epistemicEdges", doc.globalId);
1230
+ assertStorageEdgeVocabulary(doc.edgeType);
1231
+ if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
1232
+ throw new Error(
1233
+ "edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
1234
+ );
1235
+ }
1236
+ if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
1237
+ throw new Error(
1238
+ "edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
1239
+ );
1240
+ }
1241
+ await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
1242
+ await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
1243
+ if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
1244
+ assertEdgePolicyAllowed(
1245
+ edgePolicyManifest,
1246
+ doc.edgeType,
1247
+ {
1248
+ kind: "epistemic_node",
1249
+ nodeId: doc.fromNodeId,
1250
+ nodeType: doc.fromNodeType
1251
+ },
1252
+ {
1253
+ kind: "epistemic_node",
1254
+ nodeId: doc.toNodeId,
1255
+ nodeType: doc.toNodeType
1256
+ }
1257
+ );
1258
+ }
1259
+ return ctx.db.insert("epistemicEdges", doc);
1260
+ }
1261
+
1262
+ // src/epistemicBeliefs.topicAnchor.ts
1263
+ function cleanString(value) {
1264
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
1265
+ }
1266
+ function topicNodeCandidates(topicRef) {
1267
+ const normalized = topicRef.trim();
1268
+ if (!normalized) {
1269
+ return [];
1270
+ }
1271
+ const candidates = [normalized];
1272
+ if (normalized.startsWith("top_")) {
1273
+ candidates.push(normalized.slice(4));
1274
+ }
1275
+ return [...new Set(candidates)];
1276
+ }
1277
+ function readTopicNodeRef(args) {
1278
+ return cleanString(args.topicGlobalId) ?? cleanString(args.topicNodeId) ?? cleanString(args.topicId);
1279
+ }
1280
+ async function resolveRequiredTopicAnchor(ctx, topicRef) {
1281
+ for (const candidate of topicNodeCandidates(topicRef)) {
1282
+ try {
1283
+ const direct = await ctx.db.get(candidate);
1284
+ if (direct?.nodeType === "topic" && cleanString(direct.globalId)) {
1285
+ return direct;
1286
+ }
1287
+ } catch {
1288
+ }
1289
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
1290
+ if (byGlobalId?.nodeType === "topic" && cleanString(byGlobalId.globalId)) {
1291
+ return byGlobalId;
1292
+ }
1293
+ }
1294
+ throw new Error(
1295
+ "Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes. Legacy topics-table IDs are not valid belief anchors."
1296
+ );
1297
+ }
1298
+ function scopeFromTopicAnchor(topicNode) {
1299
+ return {
1300
+ topicId: topicNode.globalId,
1301
+ projectId: cleanString(topicNode.projectId),
1302
+ tenantId: cleanString(topicNode.tenantId),
1303
+ workspaceId: cleanString(topicNode.workspaceId),
1304
+ source: "topic"
1305
+ };
1306
+ }
1307
+ async function createRequiredBeliefTopicEdge(ctx, args) {
1308
+ const topicGlobalId = args.topicNode.globalId;
1309
+ const now = Date.now();
1310
+ const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
1311
+ "by_from_to",
1312
+ (q) => q.eq("fromNodeId", args.beliefGlobalId).eq("toNodeId", topicGlobalId)
1313
+ ).collect();
1314
+ const existing = existingEdges.find((edge) => edge.edgeType === "belongs_to");
1315
+ const edgeGlobalId = cleanString(existing?.globalId) ?? generateUuidV7();
1316
+ if (!existing) {
1317
+ await insertEpistemicEdge(ctx, {
1318
+ globalId: edgeGlobalId,
1319
+ fromNodeId: args.beliefGlobalId,
1320
+ toNodeId: topicGlobalId,
1321
+ sourceGlobalId: args.beliefGlobalId,
1322
+ targetGlobalId: topicGlobalId,
1323
+ edgeType: "belongs_to",
1324
+ weight: 1,
1325
+ confidence: 1,
1326
+ context: "Belief creation topic anchor invariant.",
1327
+ reasoningMethod: "implicit",
1328
+ derivationType: "topic_scope_invariant",
1329
+ metadata: {
1330
+ invariant: "belief.topic_edge_required",
1331
+ edgeUuid: edgeGlobalId,
1332
+ fromUuid: args.beliefGlobalId,
1333
+ toUuid: topicGlobalId
1334
+ },
1335
+ createdBy: args.createdBy,
1336
+ createdAt: now,
1337
+ updatedAt: now,
1338
+ projectId: cleanString(args.topicNode.projectId),
1339
+ topicId: topicGlobalId,
1340
+ tenantId: cleanString(args.topicNode.tenantId),
1341
+ workspaceId: cleanString(args.topicNode.workspaceId),
1342
+ fromNodeType: "belief",
1343
+ toNodeType: "topic",
1344
+ fromLayer: "L3",
1345
+ toLayer: args.topicNode.epistemicLayer ?? "ontological"
1346
+ });
1347
+ }
1348
+ await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
1349
+ globalId: edgeGlobalId,
1350
+ fromGlobalId: args.beliefGlobalId,
1351
+ toGlobalId: topicGlobalId,
1352
+ edgeType: "belongs_to",
1353
+ weight: 1,
1354
+ confidence: 1,
1355
+ context: "Belief creation topic anchor invariant.",
1356
+ projectId: cleanString(args.topicNode.projectId),
1357
+ topicId: topicGlobalId,
1358
+ createdBy: args.createdBy,
1359
+ fromNodeType: "belief",
1360
+ toNodeType: "topic",
1361
+ fromLayer: "L3",
1362
+ toLayer: args.topicNode.epistemicLayer ?? "ontological",
1363
+ metadata: {
1364
+ invariant: "belief.topic_edge_required",
1365
+ edgeUuid: edgeGlobalId,
1366
+ fromUuid: args.beliefGlobalId,
1367
+ toUuid: topicGlobalId
1368
+ }
1369
+ });
1370
+ }
1246
1371
 
1247
1372
  // src/epistemicBeliefs.internal.ts
1373
+ var BELIEF_CATEGORIZATION_ACTION = "beliefCategorization:autoCategorizeBelief";
1374
+ var EMBEDDING_GENERATION_ACTION = "embeddingActions:generateEpistemicNodeEmbedding";
1375
+ function readOptionalString2(value) {
1376
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1377
+ }
1248
1378
  var internalGetByProject = internalQuery({
1249
1379
  args: {
1250
1380
  ...optionalBeliefScopeArgs,
@@ -1279,7 +1409,7 @@ var internalGetByProject = internalQuery({
1279
1409
  let filtered = nodes.filter(
1280
1410
  (node) => canAudienceClassAccess(
1281
1411
  viewerClass,
1282
- resolveAudienceClass(node.audienceLabel, "internal")
1412
+ resolveAudienceClass(readOptionalString2(node.audienceLabel), "internal")
1283
1413
  )
1284
1414
  );
1285
1415
  if (args.status) {
@@ -1318,15 +1448,18 @@ var internalGetByTopic = internalQuery({
1318
1448
  });
1319
1449
  const resolveAudienceClass = createBeliefAudienceResolver(registryRows);
1320
1450
  const viewerClass = resolveAudienceClass(audienceMode, "public");
1321
- const query3 = ctx.db.query("epistemicNodes").withIndex(
1451
+ const query = ctx.db.query("epistemicNodes").withIndex(
1322
1452
  "by_topic_type",
1323
1453
  (q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
1324
1454
  );
1325
- const nodes = await query3.order("desc").take(scanLimit);
1455
+ const nodes = (await query.order("desc").take(scanLimit)).flatMap((row) => {
1456
+ const node = readBeliefNodeView(row);
1457
+ return node ? [node] : [];
1458
+ });
1326
1459
  let filtered = nodes.filter(
1327
1460
  (node) => canAudienceClassAccess(
1328
1461
  viewerClass,
1329
- resolveAudienceClass(node.audienceLabel, "internal")
1462
+ resolveAudienceClass(readOptionalString2(node.audienceLabel), "internal")
1330
1463
  )
1331
1464
  );
1332
1465
  if (args.status) {
@@ -1360,11 +1493,16 @@ var internalGetById = internalQuery({
1360
1493
  },
1361
1494
  returns: permissiveReturn,
1362
1495
  handler: async (ctx, args) => {
1363
- const node = await ctx.db.get(args.beliefId);
1364
- if (!node || node.nodeType !== "belief") {
1496
+ const nodeId = ctx.db.normalizeId?.("epistemicNodes", args.beliefId);
1497
+ if (!nodeId) {
1498
+ return null;
1499
+ }
1500
+ const node = await ctx.db.get(nodeId);
1501
+ const beliefNode = readBeliefNodeView(node);
1502
+ if (!beliefNode) {
1365
1503
  return null;
1366
1504
  }
1367
- return flattenBeliefNode(node);
1505
+ return flattenBeliefNode(beliefNode);
1368
1506
  }
1369
1507
  });
1370
1508
  var internalCreate = internalMutation({
@@ -1407,171 +1545,235 @@ var internalCreate = internalMutation({
1407
1545
  )
1408
1546
  },
1409
1547
  returns: permissiveReturn,
1410
- handler: async (ctx, args) => {
1411
- const now = Date.now();
1412
- const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
1413
- const topicRef = readTopicNodeRef(args);
1414
- if (!topicRef) {
1415
- throw new Error(
1416
- "Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes."
1417
- );
1418
- }
1419
- const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
1420
- const scope = scopeFromTopicAnchor(topicNode);
1421
- assertWorkspaceScopedEpistemicNodeScope({
1422
- scope,
1423
- nodeType: "belief",
1424
- mutationName: "epistemicBeliefs.internalCreate"
1425
- });
1426
- assertTenantPackWorkspaceMutationAllowed({
1427
- runtime: resolveRuntimePackMutationContext(args),
1428
- target: {
1429
- tenantId: scope.tenantId,
1430
- workspaceId: scope.workspaceId,
1431
- nodeType: "belief",
1432
- epistemicLayer: "L3"
1433
- },
1434
- mutationName: "epistemicBeliefs.internalCreate"
1435
- });
1436
- const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
1437
- category: "belief_type",
1438
- value: args.beliefType,
1439
- tenantId: scope.tenantId,
1440
- context: "epistemicBeliefs.internalCreate"
1441
- });
1442
- const globalId = generateGlobalId();
1443
- const contentHash = generateContentHash(args.formulation);
1444
- const requestedConfidence = args.confidence;
1445
- const seedOpinion = {
1446
- opinion_b: 0,
1447
- opinion_d: 0,
1448
- opinion_u: 1,
1449
- opinion_a: baseRate
1450
- };
1451
- const nodeId = await insertEpistemicNode(ctx, {
1548
+ handler: async (ctx, args) => await createInternalBelief(ctx, args)
1549
+ });
1550
+ async function createInternalBelief(ctx, args) {
1551
+ const now = Date.now();
1552
+ const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
1553
+ const topicNode = await resolveInternalCreateTopicAnchor(ctx, args);
1554
+ const anchoredScope = scopeFromTopicAnchor(topicNode);
1555
+ const scope = {
1556
+ ...anchoredScope,
1557
+ topicId: anchoredScope.topicId
1558
+ };
1559
+ assertInternalCreateScope(args, scope);
1560
+ const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
1561
+ category: "belief_type",
1562
+ value: args.beliefType,
1563
+ tenantId: scope.tenantId,
1564
+ context: "epistemicBeliefs.internalCreate"
1565
+ });
1566
+ const seedOpinion = buildSeedOpinion(baseRate);
1567
+ const globalId = generateGlobalId();
1568
+ const nodeId = await insertEpistemicNode(
1569
+ ctx,
1570
+ buildInternalBeliefNode({
1571
+ args,
1452
1572
  globalId,
1453
- topicId: scope.topicId,
1454
- projectId: scope.projectId,
1573
+ normalizedBeliefType,
1574
+ now,
1575
+ scope,
1576
+ seedOpinion
1577
+ })
1578
+ );
1579
+ await insertInternalBeliefConfidence(ctx, {
1580
+ args,
1581
+ baseRate,
1582
+ nodeId,
1583
+ now,
1584
+ seedOpinion
1585
+ });
1586
+ await createRequiredBeliefTopicEdge(ctx, {
1587
+ beliefGlobalId: globalId,
1588
+ topicNode,
1589
+ createdBy: args.userId
1590
+ });
1591
+ await scheduleInternalBeliefSideEffects(ctx, {
1592
+ args,
1593
+ baseRate,
1594
+ nodeId,
1595
+ now,
1596
+ scope,
1597
+ seedOpinion
1598
+ });
1599
+ return { nodeId };
1600
+ }
1601
+ async function resolveInternalCreateTopicAnchor(ctx, args) {
1602
+ const topicRef = readTopicNodeRef(args);
1603
+ if (!topicRef) {
1604
+ throw new Error(
1605
+ "Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes."
1606
+ );
1607
+ }
1608
+ return await resolveRequiredTopicAnchor(ctx, topicRef);
1609
+ }
1610
+ function assertInternalCreateScope(args, scope) {
1611
+ assertWorkspaceScopedEpistemicNodeScope({
1612
+ scope,
1613
+ nodeType: "belief",
1614
+ mutationName: "epistemicBeliefs.internalCreate"
1615
+ });
1616
+ assertTenantPackWorkspaceMutationAllowed({
1617
+ runtime: resolveRuntimePackMutationContext(args),
1618
+ target: {
1455
1619
  tenantId: scope.tenantId,
1456
1620
  workspaceId: scope.workspaceId,
1457
1621
  nodeType: "belief",
1458
- canonicalText: args.formulation,
1459
- contentHash,
1460
- status: "active",
1461
- epistemicLayer: "L3",
1462
- // L3: Traversal Anchors
1463
- sourceType: args.userId.startsWith("agent:") ? "ai_generated" : "human",
1464
- ...normalizedBeliefType ? { beliefType: normalizedBeliefType } : {},
1465
- createdAt: now,
1466
- updatedAt: now,
1467
- createdBy: args.userId,
1468
- ...seedOpinion,
1469
- tupleContradicted: false,
1470
- metadata: {
1471
- ...requestedConfidence ? { confidence: requestedConfidence } : {},
1472
- tupleContradicted: false,
1473
- rationale: args.rationale || "",
1474
- topic: args.topic || args.pillar || "",
1475
- pillar: args.pillar || args.topic || "",
1476
- category: args.category || "",
1477
- subcategory: args.subcategory || "",
1478
- categoryIcon: args.categoryIcon || "",
1479
- sprintId: args.sprintId,
1480
- sourceBeliefIds: args.sourceBeliefIds || [],
1481
- criticality: args.criticality || "unanalyzed",
1482
- ...normalizedBeliefType ? { beliefType: normalizedBeliefType } : {},
1483
- supportingEvidenceIds: [],
1484
- contradictingEvidenceIds: [],
1485
- testingQuestionIds: [],
1486
- linkedInsightIds: [],
1487
- // Merge caller-provided metadata (e.g. codeAnchors for coding intelligence)
1488
- ...args.extraMetadata && typeof args.extraMetadata === "object" ? args.extraMetadata : {}
1489
- }
1490
- });
1491
- await ctx.db.insert(
1492
- "beliefConfidence",
1493
- buildBeliefConfidenceRow({
1494
- beliefId: nodeId,
1495
- belief: seedOpinion.opinion_b,
1496
- disbelief: seedOpinion.opinion_d,
1497
- uncertainty: seedOpinion.opinion_u,
1498
- baseRate,
1499
- trigger: "initial",
1500
- rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
1501
- assessedBy: args.userId,
1502
- assessedAt: now,
1503
- slOperator: "prior_seed"
1504
- })
1505
- );
1506
- await createRequiredBeliefTopicEdge(ctx, {
1507
- beliefGlobalId: globalId,
1508
- topicNode,
1509
- createdBy: args.userId
1510
- });
1511
- await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1512
- nodeId,
1513
- operation: "upsert"
1514
- });
1515
- await ctx.db.insert("epistemicAudit", {
1516
- entityType: "belief",
1517
- entityId: nodeId,
1518
- changeType: "created",
1519
- changedAt: now,
1520
- changedBy: args.userId,
1521
- isAgent: false,
1522
- newState: {
1523
- formulation: args.formulation,
1524
- baseRate,
1525
- confidence: requestedConfidence,
1526
- opinion: {
1527
- b: seedOpinion.opinion_b,
1528
- d: seedOpinion.opinion_d,
1529
- u: seedOpinion.opinion_u,
1530
- a: seedOpinion.opinion_a
1531
- },
1532
- tupleContradicted: false,
1533
- source: "internal"
1622
+ epistemicLayer: "L3"
1623
+ },
1624
+ mutationName: "epistemicBeliefs.internalCreate"
1625
+ });
1626
+ }
1627
+ function buildSeedOpinion(baseRate) {
1628
+ return {
1629
+ opinion_b: 0,
1630
+ opinion_d: 0,
1631
+ opinion_u: 1,
1632
+ opinion_a: baseRate
1633
+ };
1634
+ }
1635
+ function buildInternalBeliefNode(args) {
1636
+ return {
1637
+ globalId: args.globalId,
1638
+ topicId: args.scope.topicId,
1639
+ projectId: args.scope.projectId,
1640
+ tenantId: args.scope.tenantId,
1641
+ workspaceId: args.scope.workspaceId,
1642
+ nodeType: "belief",
1643
+ canonicalText: args.args.formulation,
1644
+ contentHash: generateContentHash(args.args.formulation),
1645
+ status: "active",
1646
+ epistemicLayer: "L3",
1647
+ sourceType: args.args.userId.startsWith("agent:") ? "ai_generated" : "human",
1648
+ ...args.normalizedBeliefType ? { beliefType: args.normalizedBeliefType } : {},
1649
+ createdAt: args.now,
1650
+ updatedAt: args.now,
1651
+ createdBy: args.args.userId,
1652
+ ...args.seedOpinion,
1653
+ tupleContradicted: false,
1654
+ metadata: buildInternalBeliefMetadata(args.args, args.normalizedBeliefType)
1655
+ };
1656
+ }
1657
+ function buildInternalBeliefMetadata(args, normalizedBeliefType) {
1658
+ return {
1659
+ ...args.confidence ? { confidence: args.confidence } : {},
1660
+ tupleContradicted: false,
1661
+ rationale: args.rationale || "",
1662
+ topic: args.topic || args.pillar || "",
1663
+ pillar: args.pillar || args.topic || "",
1664
+ category: args.category || "",
1665
+ subcategory: args.subcategory || "",
1666
+ categoryIcon: args.categoryIcon || "",
1667
+ sprintId: args.sprintId,
1668
+ sourceBeliefIds: args.sourceBeliefIds || [],
1669
+ criticality: args.criticality || "unanalyzed",
1670
+ ...normalizedBeliefType ? { beliefType: normalizedBeliefType } : {},
1671
+ supportingEvidenceIds: [],
1672
+ contradictingEvidenceIds: [],
1673
+ testingQuestionIds: [],
1674
+ linkedInsightIds: [],
1675
+ ...isRecord2(args.extraMetadata) ? args.extraMetadata : {}
1676
+ };
1677
+ }
1678
+ function isRecord2(value) {
1679
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1680
+ }
1681
+ async function insertInternalBeliefConfidence(ctx, args) {
1682
+ await ctx.db.insert(
1683
+ "beliefConfidence",
1684
+ buildBeliefConfidenceRow({
1685
+ beliefId: args.nodeId,
1686
+ belief: args.seedOpinion.opinion_b,
1687
+ disbelief: args.seedOpinion.opinion_d,
1688
+ uncertainty: args.seedOpinion.opinion_u,
1689
+ baseRate: args.baseRate,
1690
+ trigger: "initial",
1691
+ rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
1692
+ assessedBy: args.args.userId,
1693
+ assessedAt: args.now,
1694
+ slOperator: "prior_seed"
1695
+ })
1696
+ );
1697
+ }
1698
+ async function scheduleInternalBeliefSideEffects(ctx, args) {
1699
+ await scheduleInternalNeo4jSync(ctx, args.nodeId);
1700
+ await insertInternalBeliefAudit(ctx, args);
1701
+ await scheduleInternalBeliefEmbedding(ctx, args);
1702
+ await scheduleInternalBeliefCategorization(ctx, args);
1703
+ await markBeliefGraphDirty(ctx, {
1704
+ projectId: args.scope.projectId,
1705
+ topicId: String(args.scope.topicId)
1706
+ });
1707
+ }
1708
+ async function scheduleInternalNeo4jSync(ctx, nodeId) {
1709
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1710
+ nodeId,
1711
+ operation: "upsert"
1712
+ });
1713
+ }
1714
+ async function insertInternalBeliefAudit(ctx, args) {
1715
+ await ctx.db.insert("epistemicAudit", {
1716
+ entityType: "belief",
1717
+ entityId: args.nodeId,
1718
+ changeType: "created",
1719
+ changedAt: args.now,
1720
+ changedBy: args.args.userId,
1721
+ isAgent: false,
1722
+ newState: {
1723
+ formulation: args.args.formulation,
1724
+ baseRate: args.baseRate,
1725
+ confidence: args.args.confidence,
1726
+ opinion: {
1727
+ b: args.seedOpinion.opinion_b,
1728
+ d: args.seedOpinion.opinion_d,
1729
+ u: args.seedOpinion.opinion_u,
1730
+ a: args.seedOpinion.opinion_a
1534
1731
  },
1535
- projectId: scope.projectId,
1536
- topicId: String(scope.topicId)
1537
- });
1538
- if (scope.projectId || scope.topicId) {
1539
- await ctx.scheduler.runAfter(
1540
- 0,
1541
- "embeddingActions:generateEpistemicNodeEmbedding",
1542
- {
1543
- nodeId,
1544
- projectId: scope.projectId,
1545
- topicId: scope.topicId ? String(scope.topicId) : void 0,
1546
- createdBy: args.userId,
1547
- nodeType: "belief",
1548
- text: args.rationale ? `${args.formulation}
1732
+ tupleContradicted: false,
1733
+ source: "internal"
1734
+ },
1735
+ projectId: args.scope.projectId,
1736
+ topicId: String(args.scope.topicId)
1737
+ });
1738
+ }
1739
+ async function scheduleInternalBeliefEmbedding(ctx, args) {
1740
+ if (!(args.scope.projectId || args.scope.topicId)) {
1741
+ return;
1742
+ }
1743
+ await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
1744
+ nodeId: args.nodeId,
1745
+ projectId: args.scope.projectId,
1746
+ topicId: args.scope.topicId ? String(args.scope.topicId) : void 0,
1747
+ createdBy: args.args.userId,
1748
+ nodeType: "belief",
1749
+ text: buildBeliefEmbeddingText(args.args),
1750
+ ...args.args.confidence ? { confidence: numericRequestedConfidence(args.args.confidence) } : {}
1751
+ });
1752
+ }
1753
+ function buildBeliefEmbeddingText(args) {
1754
+ return args.rationale ? `${args.formulation}
1549
1755
 
1550
- Rationale: ${args.rationale}` : args.formulation,
1551
- ...requestedConfidence ? {
1552
- confidence: requestedConfidence === "high" ? 0.8 : requestedConfidence === "low" ? 0.3 : 0.5
1553
- } : {}
1554
- }
1555
- );
1556
- }
1557
- if (normalizePillar(args.pillar || args.topic) === "other" && (scope.projectId || scope.topicId)) {
1558
- await ctx.scheduler.runAfter(
1559
- 2500,
1560
- "beliefCategorization:autoCategorizeBelief",
1561
- {
1562
- nodeId,
1563
- projectId: scope.projectId,
1564
- topicId: String(scope.topicId)
1565
- }
1566
- );
1567
- }
1568
- await markBeliefGraphDirty(ctx, {
1569
- projectId: scope.projectId,
1570
- topicId: String(scope.topicId)
1571
- });
1572
- return { nodeId };
1756
+ Rationale: ${args.rationale}` : args.formulation;
1757
+ }
1758
+ function numericRequestedConfidence(confidence) {
1759
+ if (confidence === "high") {
1760
+ return 0.8;
1573
1761
  }
1574
- });
1762
+ if (confidence === "low") {
1763
+ return 0.3;
1764
+ }
1765
+ return 0.5;
1766
+ }
1767
+ async function scheduleInternalBeliefCategorization(ctx, args) {
1768
+ if (normalizePillar(args.args.pillar || args.args.topic) !== "other" || !(args.scope.projectId || args.scope.topicId)) {
1769
+ return;
1770
+ }
1771
+ await ctx.scheduler.runAfter(2500, BELIEF_CATEGORIZATION_ACTION, {
1772
+ nodeId: args.nodeId,
1773
+ projectId: args.scope.projectId,
1774
+ topicId: String(args.scope.topicId)
1775
+ });
1776
+ }
1575
1777
 
1576
1778
  export { internalCreate, internalGetActive, internalGetById, internalGetByProject, internalGetByTopic };
1577
1779
  //# sourceMappingURL=epistemicBeliefs.internal.js.map