@lucern/graph-primitives 1.0.29 → 1.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
  2. package/dist/beliefDecay.d.ts +1 -1
  3. package/dist/beliefDecay.js +448 -314
  4. package/dist/beliefDecay.js.map +1 -1
  5. package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
  6. package/dist/beliefEvidenceLinks.d.ts +1 -1
  7. package/dist/beliefEvidenceLinks.js +843 -624
  8. package/dist/beliefEvidenceLinks.js.map +1 -1
  9. package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
  10. package/dist/beliefEvidenceLinks.operational.js +91 -18
  11. package/dist/beliefEvidenceLinks.operational.js.map +1 -1
  12. package/dist/beliefLifecycle.js.map +1 -1
  13. package/dist/confidencePropagationDispatch.d.ts +28 -27
  14. package/dist/confidencePropagationDispatch.js +157 -99
  15. package/dist/confidencePropagationDispatch.js.map +1 -1
  16. package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
  17. package/dist/contradictions.d.ts +1 -1
  18. package/dist/contradictions.js +395 -225
  19. package/dist/contradictions.js.map +1 -1
  20. package/dist/convex.d.ts +65 -30
  21. package/dist/convex.js +7 -3
  22. package/dist/convex.js.map +1 -1
  23. package/dist/debug.js.map +1 -1
  24. package/dist/edgeValidation.js +293 -85
  25. package/dist/edgeValidation.js.map +1 -1
  26. package/dist/edges/contains.d.ts +1 -1
  27. package/dist/edges/contains.js.map +1 -1
  28. package/dist/edges/contradicts.d.ts +1 -1
  29. package/dist/edges/contradicts.js.map +1 -1
  30. package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
  31. package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
  32. package/dist/edges/depends-on.js.map +1 -0
  33. package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
  34. package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
  35. package/dist/edges/derived-from.js.map +1 -0
  36. package/dist/edges/elaborates.d.ts +1 -1
  37. package/dist/edges/elaborates.js.map +1 -1
  38. package/dist/edges/index.d.ts +7 -3
  39. package/dist/edges/index.js +7 -4
  40. package/dist/edges/index.js.map +1 -1
  41. package/dist/edges/informs.d.ts +1 -1
  42. package/dist/edges/informs.js.map +1 -1
  43. package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
  44. package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
  45. package/dist/edges/propagation-types.js.map +1 -0
  46. package/dist/edges/refutes.d.ts +1 -1
  47. package/dist/edges/refutes.js.map +1 -1
  48. package/dist/edges/supports.d.ts +1 -1
  49. package/dist/edges/supports.js.map +1 -1
  50. package/dist/edges/tests.d.ts +1 -1
  51. package/dist/edges/tests.js.map +1 -1
  52. package/dist/edges/utils.d.ts +1 -1
  53. package/dist/edges/utils.js.map +1 -1
  54. package/dist/embeddingTrigger.d.ts +14 -6
  55. package/dist/embeddingTrigger.js +11 -14
  56. package/dist/embeddingTrigger.js.map +1 -1
  57. package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
  58. package/dist/entityBridge.d.ts +1 -1
  59. package/dist/entityBridge.js +602 -225
  60. package/dist/entityBridge.js.map +1 -1
  61. package/dist/entityCanonicalMatch.d.ts +14 -12
  62. package/dist/entityCanonicalMatch.js.map +1 -1
  63. package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
  64. package/dist/entityLifecycle.d.ts +1 -1
  65. package/dist/entityLifecycle.js +854 -480
  66. package/dist/entityLifecycle.js.map +1 -1
  67. package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
  68. package/dist/entityValidation.d.ts +3 -1
  69. package/dist/entityValidation.js +60 -8
  70. package/dist/entityValidation.js.map +1 -1
  71. package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
  72. package/dist/epistemicAnswers.d.ts +1 -1
  73. package/dist/epistemicAnswers.js +587 -545
  74. package/dist/epistemicAnswers.js.map +1 -1
  75. package/dist/epistemicBeliefs.admin.d.ts +8 -8
  76. package/dist/epistemicBeliefs.admin.js +365 -166
  77. package/dist/epistemicBeliefs.admin.js.map +1 -1
  78. package/dist/epistemicBeliefs.backfills.d.ts +8 -8
  79. package/dist/epistemicBeliefs.backfills.js +655 -289
  80. package/dist/epistemicBeliefs.backfills.js.map +1 -1
  81. package/dist/epistemicBeliefs.confidence.d.ts +19 -15
  82. package/dist/epistemicBeliefs.confidence.js +633 -386
  83. package/dist/epistemicBeliefs.confidence.js.map +1 -1
  84. package/dist/epistemicBeliefs.core.d.ts +6 -6
  85. package/dist/epistemicBeliefs.core.js +717 -371
  86. package/dist/epistemicBeliefs.core.js.map +1 -1
  87. package/dist/epistemicBeliefs.d.ts +11 -9
  88. package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
  89. package/dist/epistemicBeliefs.forkEvidence.js +8 -8
  90. package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
  91. package/dist/epistemicBeliefs.helpers.d.ts +68 -49
  92. package/dist/epistemicBeliefs.helpers.js +358 -211
  93. package/dist/epistemicBeliefs.helpers.js.map +1 -1
  94. package/dist/epistemicBeliefs.internal.d.ts +5 -5
  95. package/dist/epistemicBeliefs.internal.js +1248 -1026
  96. package/dist/epistemicBeliefs.internal.js.map +1 -1
  97. package/dist/epistemicBeliefs.js +4942 -3590
  98. package/dist/epistemicBeliefs.js.map +1 -1
  99. package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
  100. package/dist/epistemicBeliefs.lifecycle.js +1138 -781
  101. package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
  102. package/dist/epistemicBeliefs.links.d.ts +7 -7
  103. package/dist/epistemicBeliefs.links.js +404 -267
  104. package/dist/epistemicBeliefs.links.js.map +1 -1
  105. package/dist/epistemicBeliefs.queries.d.ts +4 -4
  106. package/dist/epistemicBeliefs.queries.js +175 -20
  107. package/dist/epistemicBeliefs.queries.js.map +1 -1
  108. package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
  109. package/dist/epistemicBeliefs.topicAnchor.js +12 -5
  110. package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
  111. package/dist/epistemicContracts.d.ts +28 -3
  112. package/dist/epistemicContracts.evaluators.d.ts +2 -0
  113. package/dist/epistemicContracts.evaluators.js +1062 -576
  114. package/dist/epistemicContracts.evaluators.js.map +1 -1
  115. package/dist/epistemicContracts.handlers.d.ts +15 -32
  116. package/dist/epistemicContracts.handlers.js +1829 -1351
  117. package/dist/epistemicContracts.handlers.js.map +1 -1
  118. package/dist/epistemicContracts.js +1131 -636
  119. package/dist/epistemicContracts.js.map +1 -1
  120. package/dist/epistemicContracts.metrics.d.ts +2 -0
  121. package/dist/epistemicContracts.metrics.js +375 -158
  122. package/dist/epistemicContracts.metrics.js.map +1 -1
  123. package/dist/epistemicContracts.types.d.ts +87 -81
  124. package/dist/epistemicEdgeCreation.d.ts +2 -0
  125. package/dist/epistemicEdgeCreation.js +87 -16
  126. package/dist/epistemicEdgeCreation.js.map +1 -1
  127. package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
  128. package/dist/epistemicEdges.d.ts +6 -5
  129. package/dist/epistemicEdges.handlers.d.ts +3 -3
  130. package/dist/epistemicEdges.handlers.js +129 -24
  131. package/dist/epistemicEdges.handlers.js.map +1 -1
  132. package/dist/epistemicEdges.helpers.d.ts +6 -4
  133. package/dist/epistemicEdges.helpers.js +37 -2
  134. package/dist/epistemicEdges.helpers.js.map +1 -1
  135. package/dist/epistemicEdges.js +1966 -1202
  136. package/dist/epistemicEdges.js.map +1 -1
  137. package/dist/epistemicEdges.mutations.d.ts +7 -7
  138. package/dist/epistemicEdges.mutations.js +956 -579
  139. package/dist/epistemicEdges.mutations.js.map +1 -1
  140. package/dist/epistemicEdges.queries.d.ts +16 -16
  141. package/dist/epistemicEdges.queries.js +639 -367
  142. package/dist/epistemicEdges.queries.js.map +1 -1
  143. package/dist/epistemicEdges.types.d.ts +10 -8
  144. package/dist/epistemicEvidence.d.ts +4 -1
  145. package/dist/epistemicEvidence.js +933 -532
  146. package/dist/epistemicEvidence.js.map +1 -1
  147. package/dist/epistemicEvidenceHelpers.d.ts +26 -10
  148. package/dist/epistemicEvidenceHelpers.js +239 -200
  149. package/dist/epistemicEvidenceHelpers.js.map +1 -1
  150. package/dist/epistemicEvidenceMutations.d.ts +8 -8
  151. package/dist/epistemicEvidenceMutations.js +840 -692
  152. package/dist/epistemicEvidenceMutations.js.map +1 -1
  153. package/dist/epistemicEvidenceQueries.d.ts +8 -8
  154. package/dist/epistemicEvidenceQueries.js +514 -238
  155. package/dist/epistemicEvidenceQueries.js.map +1 -1
  156. package/dist/epistemicHelpers.d.ts +4 -2
  157. package/dist/epistemicHelpers.js +308 -134
  158. package/dist/epistemicHelpers.js.map +1 -1
  159. package/dist/epistemicInsert.d.ts +16 -4
  160. package/dist/epistemicInsert.js +6 -3
  161. package/dist/epistemicInsert.js.map +1 -1
  162. package/dist/epistemicLayerRules.d.ts +10 -8
  163. package/dist/epistemicLayerRules.js +1 -5
  164. package/dist/epistemicLayerRules.js.map +1 -1
  165. package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
  166. package/dist/epistemicLinking.d.ts +1 -1
  167. package/dist/epistemicLinking.js +177 -100
  168. package/dist/epistemicLinking.js.map +1 -1
  169. package/dist/epistemicNodeCreation.d.ts +2 -0
  170. package/dist/epistemicNodeCreation.js +203 -40
  171. package/dist/epistemicNodeCreation.js.map +1 -1
  172. package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
  173. package/dist/epistemicNodes.d.ts +3 -3
  174. package/dist/epistemicNodes.helpers.d.ts +24 -15
  175. package/dist/epistemicNodes.helpers.js.map +1 -1
  176. package/dist/epistemicNodes.internal.d.ts +6 -6
  177. package/dist/epistemicNodes.internal.js +389 -319
  178. package/dist/epistemicNodes.internal.js.map +1 -1
  179. package/dist/epistemicNodes.js +700 -504
  180. package/dist/epistemicNodes.js.map +1 -1
  181. package/dist/epistemicNodes.mutations.d.ts +6 -6
  182. package/dist/epistemicNodes.mutations.js +560 -463
  183. package/dist/epistemicNodes.mutations.js.map +1 -1
  184. package/dist/epistemicNodes.queries.d.ts +8 -8
  185. package/dist/epistemicNodes.queries.js +311 -314
  186. package/dist/epistemicNodes.queries.js.map +1 -1
  187. package/dist/epistemicNodes.validators.d.ts +2 -2
  188. package/dist/epistemicNodes.validators.js.map +1 -1
  189. package/dist/epistemicQuestions.conviction.d.ts +8 -8
  190. package/dist/epistemicQuestions.conviction.js +665 -484
  191. package/dist/epistemicQuestions.conviction.js.map +1 -1
  192. package/dist/epistemicQuestions.create.d.ts +4 -4
  193. package/dist/epistemicQuestions.create.js +640 -612
  194. package/dist/epistemicQuestions.create.js.map +1 -1
  195. package/dist/epistemicQuestions.d.ts +8 -5
  196. package/dist/epistemicQuestions.evidence.d.ts +2 -2
  197. package/dist/epistemicQuestions.evidence.js +475 -383
  198. package/dist/epistemicQuestions.evidence.js.map +1 -1
  199. package/dist/epistemicQuestions.helpers.d.ts +125 -24
  200. package/dist/epistemicQuestions.helpers.js +240 -209
  201. package/dist/epistemicQuestions.helpers.js.map +1 -1
  202. package/dist/epistemicQuestions.js +3474 -2823
  203. package/dist/epistemicQuestions.js.map +1 -1
  204. package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
  205. package/dist/epistemicQuestions.lifecycle.js +607 -546
  206. package/dist/epistemicQuestions.lifecycle.js.map +1 -1
  207. package/dist/epistemicQuestions.queries.d.ts +12 -7
  208. package/dist/epistemicQuestions.queries.js +305 -244
  209. package/dist/epistemicQuestions.queries.js.map +1 -1
  210. package/dist/epistemicQuestions.sprint.d.ts +2 -2
  211. package/dist/epistemicQuestions.sprint.js +600 -394
  212. package/dist/epistemicQuestions.sprint.js.map +1 -1
  213. package/dist/epistemicQuestions.tail.d.ts +6 -6
  214. package/dist/epistemicQuestions.tail.js +572 -433
  215. package/dist/epistemicQuestions.tail.js.map +1 -1
  216. package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
  217. package/dist/epistemicSources.d.ts +1 -1
  218. package/dist/epistemicSources.js +351 -311
  219. package/dist/epistemicSources.js.map +1 -1
  220. package/dist/evaluators/index.d.ts +8 -6
  221. package/dist/evaluators/index.js +399 -167
  222. package/dist/evaluators/index.js.map +1 -1
  223. package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
  224. package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
  225. package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
  226. package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
  227. package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
  228. package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
  229. package/dist/evaluators/shared.d.ts +2 -2
  230. package/dist/evaluators/shared.js +3 -1
  231. package/dist/evaluators/shared.js.map +1 -1
  232. package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
  233. package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
  234. package/dist/evaluators/test-runner-evaluator.js.map +1 -0
  235. package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
  236. package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
  237. package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
  238. package/dist/graphTypes.js +6 -2
  239. package/dist/graphTypes.js.map +1 -1
  240. package/dist/helpers.d.ts +2 -0
  241. package/dist/helpers.js +313 -93
  242. package/dist/helpers.js.map +1 -1
  243. package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
  244. package/dist/index.d.ts +86 -83
  245. package/dist/index.js +16914 -11760
  246. package/dist/index.js.map +1 -1
  247. package/dist/invariantEnforcement.d.ts +3 -3
  248. package/dist/invariantEnforcement.js.map +1 -1
  249. package/dist/logicalRoleInference.d.ts +2 -0
  250. package/dist/logicalRoleInference.js +1 -1
  251. package/dist/logicalRoleInference.js.map +1 -1
  252. package/dist/matcherFeedbackUtils.d.ts +2 -2
  253. package/dist/matcherFeedbackUtils.js.map +1 -1
  254. package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
  255. package/dist/ontology-matching.d.ts +1 -1
  256. package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
  257. package/dist/ontologyApproval.d.ts +1 -1
  258. package/dist/ontologyApproval.js +7 -1
  259. package/dist/ontologyApproval.js.map +1 -1
  260. package/dist/ontologyDefinitions.d.ts +14 -24
  261. package/dist/ontologyDefinitions.js +269 -34
  262. package/dist/ontologyDefinitions.js.map +1 -1
  263. package/dist/ontologyHelpers.d.ts +13 -13
  264. package/dist/ontologyHelpers.js.map +1 -1
  265. package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
  266. package/dist/ontologyRegistry.d.ts +1 -1
  267. package/dist/ontologyRegistry.js +34 -6
  268. package/dist/ontologyRegistry.js.map +1 -1
  269. package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
  270. package/dist/projectionReconciliation.d.ts +1 -1
  271. package/dist/projectionReconciliation.js +57 -10
  272. package/dist/projectionReconciliation.js.map +1 -1
  273. package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
  274. package/dist/projectionStaleness.d.ts +1 -1
  275. package/dist/projectionStaleness.js +8 -2
  276. package/dist/projectionStaleness.js.map +1 -1
  277. package/dist/proof-attestation.json +1 -1
  278. package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
  279. package/dist/questionEvidenceLinks.d.ts +1 -1
  280. package/dist/questionEvidenceLinks.js +564 -347
  281. package/dist/questionEvidenceLinks.js.map +1 -1
  282. package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
  283. package/dist/resolverTypes.d.ts +4 -2
  284. package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
  285. package/dist/resolvers.d.ts +5 -3
  286. package/dist/resolvers.js +121 -77
  287. package/dist/resolvers.js.map +1 -1
  288. package/dist/scopeResolverCompat.d.ts +10 -7
  289. package/dist/scopeResolverCompat.js +106 -123
  290. package/dist/scopeResolverCompat.js.map +1 -1
  291. package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
  292. package/dist/text-matching.d.ts +1 -1
  293. package/dist/topicOntologyResolver.d.ts +22 -21
  294. package/dist/topicOntologyResolver.js +54 -32
  295. package/dist/topicOntologyResolver.js.map +1 -1
  296. package/dist/topicProjectOverlay.d.ts +30 -20
  297. package/dist/topicProjectOverlay.js +120 -76
  298. package/dist/topicProjectOverlay.js.map +1 -1
  299. package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
  300. package/dist/topicScope.d.ts +3 -1
  301. package/dist/topicScope.js +104 -119
  302. package/dist/topicScope.js.map +1 -1
  303. package/dist/workflowBridge.d.ts +26 -15
  304. package/dist/workflowBridge.js +140 -144
  305. package/dist/workflowBridge.js.map +1 -1
  306. package/dist/workspaceIsolation.d.ts +14 -12
  307. package/dist/workspaceIsolation.js +108 -122
  308. package/dist/workspaceIsolation.js.map +1 -1
  309. package/package.json +4 -4
  310. package/dist/edges/dependsOn.js.map +0 -1
  311. package/dist/edges/derivedFrom.js.map +0 -1
  312. package/dist/edges/propagationTypes.js.map +0 -1
  313. package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
  314. package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
  315. package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
  316. package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
  317. package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
  318. package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
  319. package/dist/{epistemicQuestions-bwHd2FWE.d.ts → epistemicQuestions-Do1fhYm5.d.ts} +4 -4
@@ -1,23 +1,138 @@
1
- import { v } 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';
5
+ import { v } from 'convex/values';
6
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
7
+ import { componentsGeneric, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
8
+ import '@lucern/access-control/auth';
10
9
  import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
11
10
  import { normalizeTupleContradictionPolicy, confidenceFromSL } from '@lucern/confidence';
12
- import '@lucern/access-control/auth';
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,980 +145,844 @@ 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") {
552
+ function asMappedProjectId(topic) {
553
+ if (!topic) {
531
554
  return;
532
555
  }
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") {
536
- return;
556
+ const directLegacyProjectId = normalizeScopeValue(
557
+ topic[LEGACY_SCOPE_FIELD2]
558
+ );
559
+ if (directLegacyProjectId) {
560
+ return directLegacyProjectId;
537
561
  }
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);
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;
564
565
  }
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";
566
+ function normalizeScopeValue(value) {
567
+ if (typeof value !== "string") {
568
+ return;
580
569
  }
581
- return null;
570
+ const normalized = value.trim();
571
+ return normalized.length > 0 ? normalized : void 0;
582
572
  }
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;
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;
579
+ }
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;
584
+ }
585
+ return String(a.name || "").localeCompare(String(b.name || ""));
586
+ })[0];
594
587
  }
595
- function isResolvedByConfidence(confidence) {
596
- const normalized = normalizeBeliefConfidence(confidence);
597
- if (normalized === null) {
598
- return false;
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();
595
+ } catch (error) {
596
+ debugGraphPrimitiveFallback(
597
+ "[topicScope] Failed to resolve scope alias via index",
598
+ {
599
+ error,
600
+ scopeId
601
+ }
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
+ });
599
609
  }
600
- return normalized <= 0 || normalized >= 1;
601
- }
602
- function getPredictionMetaFromMetadata(metadata) {
603
- return metadata?.predictionMeta;
604
610
  }
605
- function resolvedPredictionStatus(predictionMeta) {
606
- if (!predictionMeta || typeof predictionMeta !== "object") {
611
+ async function tryResolveHostTopicById(ctx, topicId) {
612
+ if (typeof ctx.runQuery !== "function") {
607
613
  return null;
608
614
  }
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
+ try {
616
+ return await ctx.runQuery(api.topics.get, {
617
+ id: topicId
618
+ }) ?? null;
619
+ } catch (error) {
620
+ debugGraphPrimitiveFallback(
621
+ "[topicScope] Failed to resolve topic by host query",
622
+ {
623
+ error,
624
+ topicId
625
+ }
626
+ );
627
+ return null;
615
628
  }
616
- return null;
617
629
  }
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;
630
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
631
+ if (typeof ctx.runQuery !== "function") {
632
+ return null;
626
633
  }
627
- const metadataPredictionStatus = resolvedPredictionStatus(
628
- getPredictionMetaFromMetadata(opts.metadata)
629
- );
630
- if (metadataPredictionStatus) {
631
- return metadataPredictionStatus;
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
+ );
646
+ return null;
632
647
  }
633
- return null;
634
648
  }
635
- function resolveBeliefLifecycleStatus(opts) {
636
- const resolvedStatus = shouldTreatBeliefAsResolved(opts);
637
- if (resolvedStatus) {
638
- return resolvedStatus;
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 };
639
655
  }
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";
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;
646
661
  }
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";
662
+ if (!tenantId) {
663
+ tenantId = normalizeScopeValue(current.tenantId);
664
+ }
665
+ if (!workspaceId) {
666
+ workspaceId = normalizeScopeValue(current.workspaceId);
667
+ }
668
+ if (tenantId && workspaceId) {
669
+ break;
655
670
  }
656
- return normalizedMetaStatus;
657
- }
658
- return "assumption";
659
- }
660
- function isPreValidationBeliefStatus(status) {
661
- return status === "assumption" || status === "hypothesis";
662
- }
663
-
664
- // src/topicProjectOverlay.ts
665
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
666
- function readNonEmptyString(value) {
667
- if (typeof value !== "string") {
668
- return;
669
671
  }
670
- const normalized = value.trim();
671
- return normalized.length > 0 ? normalized : void 0;
672
+ return { tenantId, workspaceId };
672
673
  }
673
- function readStringArray(value) {
674
- if (!Array.isArray(value)) {
675
- return [];
674
+ async function resolveTopicProjectScope(ctx, args) {
675
+ if (args.topicId) {
676
+ return await resolveScopeFromTopicId(ctx, args.topicId);
676
677
  }
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;
678
+ if (args.projectId) {
679
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
685
680
  }
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;
681
+ throw new Error(
682
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
683
+ );
693
684
  }
694
- function mapProjectType(topic, metadata) {
695
- const explicit = readNonEmptyString(metadata.projectType);
696
- if (explicit) {
697
- return explicit;
685
+ async function resolveScopeFromTopicId(ctx, topicId) {
686
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
687
+ if (topic) {
688
+ return await buildTopicScope(ctx, topic, "topic");
698
689
  }
699
- if (topic.type === "theme") {
700
- return "thematic";
690
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
691
+ if (nodeScope) {
692
+ return nodeScope;
701
693
  }
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;
694
+ throw new Error(`Topic not found: ${String(topicId)}`);
707
695
  }
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;
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;
717
703
  }
718
- if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
719
- return error.message;
704
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
705
+ if (hostTopic) {
706
+ return hostTopic;
720
707
  }
721
- return "unknown error";
708
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
722
709
  }
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
- );
740
- }
741
- }
742
- if (typeof ctx.runQuery !== "function") {
743
- return null;
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
+ });
744
719
  }
745
- try {
746
- const topic = await ctx.runQuery(api.topics.get, {
747
- id: String(scopeId)
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
748
726
  });
749
- if (topic?.name !== void 0 && topic?.type !== void 0) {
750
- return topic;
751
- }
752
- } catch (error) {
753
- debugGraphPrimitiveFallback(
754
- "[topicProjectOverlay] Failed to resolve topic by ID query",
755
- {
756
- error,
757
- scopeId
758
- }
759
- );
760
727
  }
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
+ );
738
+ }
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);
745
+ }
746
+ async function tryReadTopicDoc(ctx, id, log) {
761
747
  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
- }
748
+ return await ctx.db.get(id);
768
749
  } catch (error) {
769
- debugGraphPrimitiveFallback(
770
- "[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
771
- { error, scopeId }
772
- );
750
+ debugGraphPrimitiveFallback(log.failureLog, {
751
+ error,
752
+ [log.idLogKey]: id
753
+ });
754
+ return null;
773
755
  }
774
- return null;
775
756
  }
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;
757
+ async function buildTopicScope(ctx, topic, source, options = {}) {
758
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
759
+ const mapped = asMappedProjectId(topic);
786
760
  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
761
+ topicId: topic._id,
762
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
763
+ tenantId: inherited.tenantId,
764
+ workspaceId: inherited.workspaceId,
765
+ source
817
766
  };
818
767
  }
819
- async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
820
- const topic = await resolveTopicDoc(ctx, scopeId);
821
- if (!topic) {
822
- return null;
823
- }
824
- if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
825
- return null;
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;
826
775
  }
827
- return materializeTopicProjectOverlay(topic, options.idMode);
776
+ const normalized = value.trim();
777
+ return normalized.length > 0 ? normalized : void 0;
828
778
  }
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 = [];
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
840
806
  }
807
+ });
808
+ }
809
+ function nodeMatchesWorkspaceReasoningScope(node, scope) {
810
+ if (!node) {
811
+ return false;
841
812
  }
842
- if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
843
- allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
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;
844
820
  }
845
- return allTopics.filter(
846
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
847
- ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
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;
848
831
  }
849
- async function patchTopicProjectOverlay(ctx, scopeId, value) {
850
- const topic = await resolveTopicDoc(ctx, scopeId);
851
- if (!topic) {
852
- return null;
832
+ function resolveRuntimePackMutationContext(args) {
833
+ if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
834
+ return;
853
835
  }
854
- const nextMetadata = { ...readMetadata(topic) };
855
- const patch = {};
856
- const topicUpdateArgs = {
857
- id: String(topic._id)
836
+ return {
837
+ toolName: args.runtimeToolName,
838
+ packKey: args.runtimePackKey,
839
+ packInstallScope: args.runtimePackInstallScope
858
840
  };
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
- }
841
+ }
842
+ function assertTenantPackWorkspaceMutationAllowed(args) {
843
+ if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
844
+ return;
913
845
  }
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
- );
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;
932
850
  }
933
- return materializeTopicProjectOverlay({
934
- ...topic,
935
- ...patch,
936
- metadata: nextMetadata
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
+ }
937
863
  });
938
864
  }
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");
865
+ v.id("epistemicNodes");
866
+ var DEFAULT_PROJECT_BELIEF_LIMIT = 250;
867
+ var MAX_PROJECT_BELIEF_LIMIT = 1e3;
868
+ var optionalBeliefScopeArgs = optionalScopeArgs;
869
+ ({
870
+ tupleContradiction: normalizeTupleContradictionPolicy()
871
+ });
872
+ function readFiniteNumber(value) {
873
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
946
874
  }
947
- function getErrorMessage2(error) {
948
- if (error instanceof Error) {
949
- return error.message;
950
- }
951
- if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
952
- return error.message;
953
- }
954
- return "unknown error";
875
+ function isRecord(value) {
876
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
955
877
  }
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));
878
+ function readOptionalString(value) {
879
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
960
880
  }
961
- async function patchProjectWithTolerance(ctx, projectId, value) {
962
- try {
963
- await patchTopicProjectOverlay(ctx, projectId, value);
964
- } 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
- );
881
+ function readStringArray2(value) {
882
+ if (!Array.isArray(value)) {
883
+ return;
976
884
  }
885
+ const strings = value.filter(
886
+ (item) => typeof item === "string" && item.length > 0
887
+ );
888
+ return strings.length === value.length ? strings : void 0;
977
889
  }
978
- function defaultResolvers() {
979
- 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)
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
989
905
  };
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;
990
979
  }
991
- var resolverOverrides = {};
992
- function resolveGraphPrimitivesAppResolvers(_ctx) {
993
- return {
994
- ...defaultResolvers(),
995
- ...resolverOverrides
996
- };
980
+ function readBeliefNodeViews(values) {
981
+ return values.flatMap((value) => {
982
+ const node = readBeliefNodeView(value);
983
+ return node ? [node] : [];
984
+ });
997
985
  }
998
-
999
- // src/epistemicBeliefs.helpers.ts
1000
- v.id("epistemicNodes");
1001
- var DEFAULT_PROJECT_BELIEF_LIMIT = 250;
1002
- var MAX_PROJECT_BELIEF_LIMIT = 1e3;
1003
- var optionalBeliefScopeArgs = optionalScopeArgs;
1004
- ({
1005
- tupleContradiction: normalizeTupleContradictionPolicy()
1006
- });
1007
986
  function assertBaseRateInRange(baseRate, field = "baseRate") {
1008
987
  if (baseRate < 0 || baseRate > 1) {
1009
988
  throwStructuredMutationError({
@@ -1098,7 +1077,7 @@ function normalizePillar(pillar) {
1098
1077
  async function markBeliefGraphDirty(ctx, scope) {
1099
1078
  const projectId = typeof scope.projectId === "string" && scope.projectId.trim().length > 0 ? scope.projectId : void 0;
1100
1079
  const topicId = typeof scope.topicId === "string" && scope.topicId.trim().length > 0 ? scope.topicId : void 0;
1101
- if (!projectId && !topicId) {
1080
+ if (!(projectId || topicId)) {
1102
1081
  return;
1103
1082
  }
1104
1083
  if (projectId) {
@@ -1115,16 +1094,22 @@ async function markBeliefGraphDirty(ctx, scope) {
1115
1094
  { topicId }
1116
1095
  );
1117
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
+ }
1118
1103
  await resolveGraphPrimitivesAppResolvers().patchProject(
1119
1104
  ctx,
1120
- topicId ?? projectId,
1105
+ activityScopeId,
1121
1106
  {
1122
1107
  lastActivityAt: Date.now()
1123
1108
  }
1124
1109
  );
1125
1110
  }
1126
1111
  async function resolveBeliefScopeOrNull(ctx, args) {
1127
- if (!args.projectId && !args.topicId) {
1112
+ if (!(args.projectId || args.topicId)) {
1128
1113
  return null;
1129
1114
  }
1130
1115
  try {
@@ -1149,14 +1134,17 @@ async function getBeliefNodesForScope(ctx, scope, args) {
1149
1134
  "by_topic_type",
1150
1135
  (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
1151
1136
  );
1152
- 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);
1153
1139
  const scopedNodes = nodes.filter(
1154
1140
  (node) => nodeMatchesWorkspaceReasoningScope(node, scope)
1155
1141
  );
1156
1142
  if (!args?.status) {
1157
1143
  return scopedNodes;
1158
1144
  }
1159
- return scopedNodes.filter((node) => node.status === args.status);
1145
+ return scopedNodes.filter(
1146
+ (node) => node.status === args.status
1147
+ );
1160
1148
  }
1161
1149
  function createBeliefAudienceResolver(registryRows) {
1162
1150
  const audienceClassByKey = new Map(
@@ -1176,9 +1164,7 @@ function createBeliefAudienceResolver(registryRows) {
1176
1164
  function flattenBeliefNode(node) {
1177
1165
  const meta = node.metadata || {};
1178
1166
  const worktreeId = resolveBeliefWorktreeId(meta);
1179
- const tupleContradicted = readTupleContradictedFlag(
1180
- node.tupleContradicted
1181
- ) ?? readTupleContradictedFlag(meta.tupleContradicted) ?? false;
1167
+ const tupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(meta.tupleContradicted) ?? false;
1182
1168
  return {
1183
1169
  _id: node._id,
1184
1170
  _epistemicNodeId: node._id,
@@ -1223,8 +1209,172 @@ function resolveBeliefStatus(node, metadata) {
1223
1209
  metadata
1224
1210
  });
1225
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
+ }
1226
1371
 
1227
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
+ }
1228
1378
  var internalGetByProject = internalQuery({
1229
1379
  args: {
1230
1380
  ...optionalBeliefScopeArgs,
@@ -1259,7 +1409,7 @@ var internalGetByProject = internalQuery({
1259
1409
  let filtered = nodes.filter(
1260
1410
  (node) => canAudienceClassAccess(
1261
1411
  viewerClass,
1262
- resolveAudienceClass(node.audienceLabel, "internal")
1412
+ resolveAudienceClass(readOptionalString2(node.audienceLabel), "internal")
1263
1413
  )
1264
1414
  );
1265
1415
  if (args.status) {
@@ -1298,15 +1448,18 @@ var internalGetByTopic = internalQuery({
1298
1448
  });
1299
1449
  const resolveAudienceClass = createBeliefAudienceResolver(registryRows);
1300
1450
  const viewerClass = resolveAudienceClass(audienceMode, "public");
1301
- const query3 = ctx.db.query("epistemicNodes").withIndex(
1451
+ const query = ctx.db.query("epistemicNodes").withIndex(
1302
1452
  "by_topic_type",
1303
1453
  (q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
1304
1454
  );
1305
- 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
+ });
1306
1459
  let filtered = nodes.filter(
1307
1460
  (node) => canAudienceClassAccess(
1308
1461
  viewerClass,
1309
- resolveAudienceClass(node.audienceLabel, "internal")
1462
+ resolveAudienceClass(readOptionalString2(node.audienceLabel), "internal")
1310
1463
  )
1311
1464
  );
1312
1465
  if (args.status) {
@@ -1340,11 +1493,16 @@ var internalGetById = internalQuery({
1340
1493
  },
1341
1494
  returns: permissiveReturn,
1342
1495
  handler: async (ctx, args) => {
1343
- const node = await ctx.db.get(args.beliefId);
1344
- 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) {
1345
1503
  return null;
1346
1504
  }
1347
- return flattenBeliefNode(node);
1505
+ return flattenBeliefNode(beliefNode);
1348
1506
  }
1349
1507
  });
1350
1508
  var internalCreate = internalMutation({
@@ -1387,171 +1545,235 @@ var internalCreate = internalMutation({
1387
1545
  )
1388
1546
  },
1389
1547
  returns: permissiveReturn,
1390
- handler: async (ctx, args) => {
1391
- const now = Date.now();
1392
- const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
1393
- const topicRef = readTopicNodeRef(args);
1394
- if (!topicRef) {
1395
- throw new Error(
1396
- "Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes."
1397
- );
1398
- }
1399
- const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
1400
- const scope = scopeFromTopicAnchor(topicNode);
1401
- assertWorkspaceScopedEpistemicNodeScope({
1402
- scope,
1403
- nodeType: "belief",
1404
- mutationName: "epistemicBeliefs.internalCreate"
1405
- });
1406
- assertTenantPackWorkspaceMutationAllowed({
1407
- runtime: resolveRuntimePackMutationContext(args),
1408
- target: {
1409
- tenantId: scope.tenantId,
1410
- workspaceId: scope.workspaceId,
1411
- nodeType: "belief",
1412
- epistemicLayer: "L3"
1413
- },
1414
- mutationName: "epistemicBeliefs.internalCreate"
1415
- });
1416
- const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
1417
- category: "belief_type",
1418
- value: args.beliefType,
1419
- tenantId: scope.tenantId,
1420
- context: "epistemicBeliefs.internalCreate"
1421
- });
1422
- const globalId = generateGlobalId();
1423
- const contentHash = generateContentHash(args.formulation);
1424
- const requestedConfidence = args.confidence;
1425
- const seedOpinion = {
1426
- opinion_b: 0,
1427
- opinion_d: 0,
1428
- opinion_u: 1,
1429
- opinion_a: baseRate
1430
- };
1431
- 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,
1432
1572
  globalId,
1433
- topicId: scope.topicId,
1434
- 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: {
1435
1619
  tenantId: scope.tenantId,
1436
1620
  workspaceId: scope.workspaceId,
1437
1621
  nodeType: "belief",
1438
- canonicalText: args.formulation,
1439
- contentHash,
1440
- status: "active",
1441
- epistemicLayer: "L3",
1442
- // L3: Traversal Anchors
1443
- sourceType: args.userId.startsWith("agent:") ? "ai_generated" : "human",
1444
- ...normalizedBeliefType ? { beliefType: normalizedBeliefType } : {},
1445
- createdAt: now,
1446
- updatedAt: now,
1447
- createdBy: args.userId,
1448
- ...seedOpinion,
1449
- tupleContradicted: false,
1450
- metadata: {
1451
- ...requestedConfidence ? { confidence: requestedConfidence } : {},
1452
- tupleContradicted: false,
1453
- rationale: args.rationale || "",
1454
- topic: args.topic || args.pillar || "",
1455
- pillar: args.pillar || args.topic || "",
1456
- category: args.category || "",
1457
- subcategory: args.subcategory || "",
1458
- categoryIcon: args.categoryIcon || "",
1459
- sprintId: args.sprintId,
1460
- sourceBeliefIds: args.sourceBeliefIds || [],
1461
- criticality: args.criticality || "unanalyzed",
1462
- ...normalizedBeliefType ? { beliefType: normalizedBeliefType } : {},
1463
- supportingEvidenceIds: [],
1464
- contradictingEvidenceIds: [],
1465
- testingQuestionIds: [],
1466
- linkedInsightIds: [],
1467
- // Merge caller-provided metadata (e.g. codeAnchors for coding intelligence)
1468
- ...args.extraMetadata && typeof args.extraMetadata === "object" ? args.extraMetadata : {}
1469
- }
1470
- });
1471
- await ctx.db.insert(
1472
- "beliefConfidence",
1473
- buildBeliefConfidenceRow({
1474
- beliefId: nodeId,
1475
- belief: seedOpinion.opinion_b,
1476
- disbelief: seedOpinion.opinion_d,
1477
- uncertainty: seedOpinion.opinion_u,
1478
- baseRate,
1479
- trigger: "initial",
1480
- rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
1481
- assessedBy: args.userId,
1482
- assessedAt: now,
1483
- slOperator: "prior_seed"
1484
- })
1485
- );
1486
- await createRequiredBeliefTopicEdge(ctx, {
1487
- beliefGlobalId: globalId,
1488
- topicNode,
1489
- createdBy: args.userId
1490
- });
1491
- await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1492
- nodeId,
1493
- operation: "upsert"
1494
- });
1495
- await ctx.db.insert("epistemicAudit", {
1496
- entityType: "belief",
1497
- entityId: nodeId,
1498
- changeType: "created",
1499
- changedAt: now,
1500
- changedBy: args.userId,
1501
- isAgent: false,
1502
- newState: {
1503
- formulation: args.formulation,
1504
- baseRate,
1505
- confidence: requestedConfidence,
1506
- opinion: {
1507
- b: seedOpinion.opinion_b,
1508
- d: seedOpinion.opinion_d,
1509
- u: seedOpinion.opinion_u,
1510
- a: seedOpinion.opinion_a
1511
- },
1512
- tupleContradicted: false,
1513
- 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
1514
1731
  },
1515
- projectId: scope.projectId,
1516
- topicId: String(scope.topicId)
1517
- });
1518
- if (scope.projectId || scope.topicId) {
1519
- await ctx.scheduler.runAfter(
1520
- 0,
1521
- "embeddingActions:generateEpistemicNodeEmbedding",
1522
- {
1523
- nodeId,
1524
- projectId: scope.projectId,
1525
- topicId: scope.topicId ? String(scope.topicId) : void 0,
1526
- createdBy: args.userId,
1527
- nodeType: "belief",
1528
- 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}
1529
1755
 
1530
- Rationale: ${args.rationale}` : args.formulation,
1531
- ...requestedConfidence ? {
1532
- confidence: requestedConfidence === "high" ? 0.8 : requestedConfidence === "low" ? 0.3 : 0.5
1533
- } : {}
1534
- }
1535
- );
1536
- }
1537
- if (normalizePillar(args.pillar || args.topic) === "other" && (scope.projectId || scope.topicId)) {
1538
- await ctx.scheduler.runAfter(
1539
- 2500,
1540
- "beliefCategorization:autoCategorizeBelief",
1541
- {
1542
- nodeId,
1543
- projectId: scope.projectId,
1544
- topicId: String(scope.topicId)
1545
- }
1546
- );
1547
- }
1548
- await markBeliefGraphDirty(ctx, {
1549
- projectId: scope.projectId,
1550
- topicId: String(scope.topicId)
1551
- });
1552
- return { nodeId };
1756
+ Rationale: ${args.rationale}` : args.formulation;
1757
+ }
1758
+ function numericRequestedConfidence(confidence) {
1759
+ if (confidence === "high") {
1760
+ return 0.8;
1553
1761
  }
1554
- });
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
+ }
1555
1777
 
1556
1778
  export { internalCreate, internalGetActive, internalGetById, internalGetByProject, internalGetByTopic };
1557
1779
  //# sourceMappingURL=epistemicBeliefs.internal.js.map