@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,13 +1,17 @@
1
- import { v } from 'convex/values';
2
1
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
3
- import { componentsGeneric, anyApi, internalMutationGeneric } from 'convex/server';
4
- import { generateGlobalId, assertUuidV7Identity } from '@lucern/contracts/ids';
2
+ import { v } from 'convex/values';
3
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
4
+ import { componentsGeneric, internalMutationGeneric } from 'convex/server';
5
5
  import '@lucern/contracts';
6
+ import { generateGlobalId, assertUuidV7Identity } from '@lucern/contracts/ids';
6
7
 
7
8
  // src/epistemicQuestions.evidence.ts
8
- var api = anyApi;
9
+ var unsafeApi = unsafeConvexAnyApi(
10
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
11
+ );
12
+ var api = unsafeApi;
9
13
  componentsGeneric();
10
- var internal = anyApi;
14
+ var internal = unsafeApi;
11
15
  var internalMutation = internalMutationGeneric;
12
16
 
13
17
  // src/debug.ts
@@ -40,278 +44,13 @@ function debugGraphPrimitiveFallback(message, context) {
40
44
  }
41
45
  console.debug(message, context ?? {});
42
46
  }
43
- var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
44
- async function resolveTopicNodeScopeOrNull(ctx, ref) {
45
- if (!ctx?.db || typeof ctx.db.query !== "function") {
46
- return null;
47
- }
48
- let node = null;
49
- try {
50
- const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
51
- if (byGlobalId && byGlobalId.nodeType === "topic") {
52
- node = byGlobalId;
53
- }
54
- } catch (error) {
55
- debugGraphPrimitiveFallback(
56
- "[topicScope] topic-node scope lookup by globalId failed",
57
- { error, ref }
58
- );
59
- }
60
- if (!node) {
61
- return null;
62
- }
63
- const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
64
- if (!scopeKey) {
65
- return null;
66
- }
67
- return {
68
- topicId: scopeKey,
69
- projectId: asMappedProjectId(node),
70
- source: "topic_node"
71
- };
72
- }
73
- function asMappedProjectId(topic) {
74
- if (!topic) {
75
- return;
76
- }
77
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
78
- if (directLegacyProjectId) {
79
- return directLegacyProjectId;
80
- }
81
- const metadata = topic.metadata || {};
82
- const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
83
- return candidate ? candidate : void 0;
84
- }
85
- function normalizeScopeValue(value) {
86
- if (typeof value !== "string") {
87
- return;
88
- }
89
- const normalized = value.trim();
90
- return normalized.length > 0 ? normalized : void 0;
91
- }
92
- function pickPrimaryTopic(candidates) {
93
- return [...candidates].sort((a, b) => {
94
- const depthA = a.depth ?? 9999;
95
- const depthB = b.depth ?? 9999;
96
- if (depthA !== depthB) {
97
- return depthA - depthB;
98
- }
99
- const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
100
- const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
101
- if (createdA !== createdB) {
102
- return createdA - createdB;
103
- }
104
- return String(a.name || "").localeCompare(String(b.name || ""));
105
- })[0];
106
- }
107
- async function findTopicsByScopeAlias(ctx, scopeId) {
108
- try {
109
- return await ctx.db.query("topics").withIndex(
110
- "by_graph_scope_project",
111
- (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
112
- ).collect();
113
- } catch (error) {
114
- debugGraphPrimitiveFallback(
115
- "[topicScope] Failed to resolve scope alias via index",
116
- {
117
- error,
118
- scopeId
119
- }
120
- );
121
- const topics = await ctx.db.query("topics").collect();
122
- return topics.filter((topic) => {
123
- const normalizedGlobalId = normalizeScopeValue(topic.globalId);
124
- const mappedProjectId = asMappedProjectId(topic);
125
- return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
126
- });
127
- }
128
- }
129
- async function tryResolveHostTopicById(ctx, topicId) {
130
- if (typeof ctx.runQuery !== "function") {
131
- return null;
132
- }
133
- try {
134
- return await ctx.runQuery(api.topics.get, {
135
- id: topicId
136
- }) ?? null;
137
- } catch (error) {
138
- debugGraphPrimitiveFallback(
139
- "[topicScope] Failed to resolve topic by host query",
140
- {
141
- error,
142
- topicId
143
- }
144
- );
145
- return null;
146
- }
147
- }
148
- async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
149
- if (typeof ctx.runQuery !== "function") {
150
- return null;
151
- }
152
- try {
153
- return await ctx.runQuery(api.topics.getByLegacyScopeId, {
154
- projectId: legacyScopeId
155
- }) ?? null;
156
- } catch (error) {
157
- debugGraphPrimitiveFallback(
158
- "[topicScope] Failed to resolve topic by legacy scope",
159
- {
160
- error,
161
- legacyScopeId
162
- }
163
- );
164
- return null;
165
- }
166
- }
167
- async function resolveInheritedWorkspaceScope(ctx, topic) {
168
- const MAX_DEPTH = 10;
169
- let tenantId = normalizeScopeValue(topic.tenantId);
170
- let workspaceId = normalizeScopeValue(topic.workspaceId);
171
- if (tenantId && workspaceId) {
172
- return { tenantId, workspaceId };
173
- }
174
- let current = topic;
175
- for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
176
- current = await ctx.db.get(current.parentTopicId);
177
- if (!current) break;
178
- if (!tenantId) {
179
- tenantId = normalizeScopeValue(current.tenantId);
180
- }
181
- if (!workspaceId) {
182
- workspaceId = normalizeScopeValue(current.workspaceId);
183
- }
184
- if (tenantId && workspaceId) break;
185
- }
186
- return { tenantId, workspaceId };
187
- }
188
- async function resolveTopicProjectScope(ctx, args) {
189
- if (args.topicId) {
190
- let topic = null;
191
- try {
192
- topic = await ctx.db.get(
193
- args.topicId
194
- );
195
- } catch (error) {
196
- debugGraphPrimitiveFallback(
197
- "[topicScope] Failed to load topic by direct id",
198
- {
199
- error,
200
- topicId: args.topicId
201
- }
202
- );
203
- }
204
- if (!topic) {
205
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
206
- }
207
- if (!topic) {
208
- topic = pickPrimaryTopic(
209
- await findTopicsByScopeAlias(ctx, String(args.topicId))
210
- ) ?? null;
211
- }
212
- if (!topic) {
213
- const nodeScope = await resolveTopicNodeScopeOrNull(
214
- ctx,
215
- String(args.topicId)
216
- );
217
- if (nodeScope) {
218
- return nodeScope;
219
- }
220
- throw new Error(`Topic not found: ${String(args.topicId)}`);
221
- }
222
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
223
- const mapped = asMappedProjectId(topic);
224
- if (mapped) {
225
- return {
226
- topicId: topic._id,
227
- projectId: mapped,
228
- tenantId: inherited.tenantId,
229
- workspaceId: inherited.workspaceId,
230
- source: "topic"
231
- };
232
- }
233
- return {
234
- topicId: topic._id,
235
- tenantId: inherited.tenantId,
236
- workspaceId: inherited.workspaceId,
237
- source: "topic"
238
- };
239
- }
240
- if (args.projectId) {
241
- let directTopic = null;
242
- try {
243
- directTopic = await ctx.db.get(
244
- args.projectId
245
- );
246
- } catch (error) {
247
- debugGraphPrimitiveFallback(
248
- "[topicScope] Failed to load direct project topic",
249
- {
250
- error,
251
- projectId: args.projectId
252
- }
253
- );
254
- }
255
- if (directTopic) {
256
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
257
- const mapped = asMappedProjectId(directTopic);
258
- return {
259
- topicId: directTopic._id,
260
- projectId: mapped ?? args.projectId,
261
- tenantId: inherited.tenantId,
262
- workspaceId: inherited.workspaceId,
263
- source: "topic_inferred"
264
- };
265
- }
266
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
267
- if (directTopic) {
268
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
269
- const mapped = asMappedProjectId(directTopic);
270
- return {
271
- topicId: directTopic._id,
272
- projectId: mapped ?? args.projectId,
273
- tenantId: inherited.tenantId,
274
- workspaceId: inherited.workspaceId,
275
- source: "topic_inferred"
276
- };
277
- }
278
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
279
- const primary = pickPrimaryTopic(topics);
280
- if (primary) {
281
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
282
- return {
283
- topicId: primary._id,
284
- projectId: args.projectId,
285
- tenantId: inherited.tenantId,
286
- workspaceId: inherited.workspaceId,
287
- source: "project_mapped_topic"
288
- };
289
- }
290
- const nodeScope = await resolveTopicNodeScopeOrNull(
291
- ctx,
292
- String(args.projectId)
293
- );
294
- if (nodeScope) {
295
- return {
296
- ...nodeScope,
297
- projectId: nodeScope.projectId ?? String(args.projectId)
298
- };
299
- }
300
- throw new Error(
301
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
302
- );
303
- }
304
- throw new Error(
305
- "Missing scope: provide topicId (preferred) or legacy projectId alias."
306
- );
47
+ function insertEpistemicNode(ctx, doc) {
48
+ assertUuidV7Identity("epistemicNodes", doc.globalId);
49
+ return ctx.db.insert("epistemicNodes", doc);
307
50
  }
308
- var optionalScopeArgs = {
309
- projectId: v.optional(v.string()),
310
- topicId: v.optional(v.string())
311
- };
312
51
 
313
52
  // src/topicProjectOverlay.ts
314
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
53
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
315
54
  function readNonEmptyString(value) {
316
55
  if (typeof value !== "string") {
317
56
  return;
@@ -328,11 +67,15 @@ function readStringArray(value) {
328
67
  function readMetadata(topic) {
329
68
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
330
69
  }
70
+ function omitMetadataKey(metadata, key) {
71
+ const { [key]: _omitted, ...rest } = metadata;
72
+ return rest;
73
+ }
331
74
  function readLegacyProjectId(value) {
332
75
  if (!value) {
333
76
  return;
334
77
  }
335
- return readNonEmptyString(value[LEGACY_SCOPE_FIELD2]);
78
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
336
79
  }
337
80
  function coerceVisibility(value) {
338
81
  return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
@@ -408,9 +151,12 @@ async function resolveTopicDoc(ctx, scopeId) {
408
151
  );
409
152
  }
410
153
  try {
411
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
412
- projectId: String(scopeId)
413
- });
154
+ const topic = await ctx.runQuery(
155
+ api.topics.getByLegacyScopeId,
156
+ {
157
+ projectId: String(scopeId)
158
+ }
159
+ );
414
160
  if (topic?.name !== void 0 && topic?.type !== void 0) {
415
161
  return topic;
416
162
  }
@@ -430,8 +176,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
430
176
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
431
177
  const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
432
178
  const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
433
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
434
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
179
+ let createdAt = 0;
180
+ if (typeof topic.createdAt === "number") {
181
+ createdAt = topic.createdAt;
182
+ } else if (typeof topic._creationTime === "number") {
183
+ createdAt = topic._creationTime;
184
+ }
185
+ let updatedAt = createdAt;
186
+ if (typeof topic.updatedAt === "number") {
187
+ updatedAt = topic.updatedAt;
188
+ } else if (typeof metadata.updatedAt === "number") {
189
+ updatedAt = metadata.updatedAt;
190
+ }
435
191
  return {
436
192
  ...metadata,
437
193
  _id: outwardId,
@@ -500,90 +256,113 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
500
256
  if (!topic) {
501
257
  return null;
502
258
  }
503
- const nextMetadata = { ...readMetadata(topic) };
504
- const patch = {};
505
- const topicUpdateArgs = {
506
- id: String(topic._id)
259
+ const plan = buildTopicProjectOverlayPatchPlan(topic, value);
260
+ await applyTopicProjectOverlayPatch(ctx, topic, plan);
261
+ return materializeTopicProjectOverlay({
262
+ ...topic,
263
+ ...plan.patch,
264
+ metadata: plan.nextMetadata
265
+ });
266
+ }
267
+ function buildTopicProjectOverlayPatchPlan(topic, value) {
268
+ const plan = {
269
+ nextMetadata: { ...readMetadata(topic) },
270
+ patch: {},
271
+ topicUpdateArgs: {
272
+ id: String(topic._id)
273
+ }
507
274
  };
508
275
  for (const [key, rawValue] of Object.entries(value)) {
509
- switch (key) {
510
- case "_id":
511
- case "projectId":
512
- case "topicId":
513
- case "legacyProjectId":
514
- case "storageProjectId":
515
- break;
516
- case "name":
517
- case "description":
518
- patch[key] = rawValue;
519
- topicUpdateArgs[key] = rawValue;
520
- break;
521
- case "tenantId":
522
- case "workspaceId":
523
- case "ownerId":
524
- throw new Error(
525
- `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
526
- );
527
- case "status": {
528
- const status = coerceStatus(rawValue);
529
- if (status) {
530
- patch.status = status;
531
- topicUpdateArgs.status = status;
532
- }
533
- break;
534
- }
535
- case "visibility": {
536
- const visibility = coerceVisibility(rawValue);
537
- if (visibility) {
538
- patch.visibility = visibility;
539
- topicUpdateArgs.visibility = visibility;
540
- }
541
- break;
542
- }
543
- case "type": {
544
- const projectType = readNonEmptyString(rawValue);
545
- if (projectType) {
546
- nextMetadata.projectType = projectType;
547
- } else {
548
- delete nextMetadata.projectType;
549
- }
550
- break;
551
- }
552
- case "updatedAt":
553
- case "createdAt":
554
- break;
555
- default:
556
- if (rawValue === void 0) {
557
- delete nextMetadata[key];
558
- } else {
559
- nextMetadata[key] = rawValue;
560
- }
561
- }
276
+ applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
277
+ }
278
+ plan.patch.updatedAt = Date.now();
279
+ plan.patch.metadata = plan.nextMetadata;
280
+ plan.topicUpdateArgs.metadata = plan.nextMetadata;
281
+ return plan;
282
+ }
283
+ function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
284
+ switch (key) {
285
+ case "_id":
286
+ case "projectId":
287
+ case "topicId":
288
+ case "legacyProjectId":
289
+ case "storageProjectId":
290
+ case "updatedAt":
291
+ case "createdAt":
292
+ return;
293
+ case "name":
294
+ case "description":
295
+ plan.patch[key] = rawValue;
296
+ plan.topicUpdateArgs[key] = rawValue;
297
+ return;
298
+ case "tenantId":
299
+ case "workspaceId":
300
+ case "ownerId":
301
+ throw new Error(
302
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
303
+ );
304
+ case "status":
305
+ applyTopicStatusPatch(plan, rawValue);
306
+ return;
307
+ case "visibility":
308
+ applyTopicVisibilityPatch(plan, rawValue);
309
+ return;
310
+ case "type":
311
+ applyTopicProjectTypePatch(plan, rawValue);
312
+ return;
313
+ default:
314
+ applyTopicMetadataPatch(plan, key, rawValue);
562
315
  }
563
- patch.updatedAt = Date.now();
564
- patch.metadata = nextMetadata;
565
- topicUpdateArgs.metadata = nextMetadata;
316
+ }
317
+ function applyTopicStatusPatch(plan, rawValue) {
318
+ const status = coerceStatus(rawValue);
319
+ if (status) {
320
+ plan.patch.status = status;
321
+ plan.topicUpdateArgs.status = status;
322
+ }
323
+ }
324
+ function applyTopicVisibilityPatch(plan, rawValue) {
325
+ const visibility = coerceVisibility(rawValue);
326
+ if (visibility) {
327
+ plan.patch.visibility = visibility;
328
+ plan.topicUpdateArgs.visibility = visibility;
329
+ }
330
+ }
331
+ function applyTopicProjectTypePatch(plan, rawValue) {
332
+ const projectType = readNonEmptyString(rawValue);
333
+ if (projectType) {
334
+ plan.nextMetadata.projectType = projectType;
335
+ return;
336
+ }
337
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
338
+ }
339
+ function applyTopicMetadataPatch(plan, key, rawValue) {
340
+ if (rawValue === void 0) {
341
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
342
+ return;
343
+ }
344
+ plan.nextMetadata[key] = rawValue;
345
+ }
346
+ async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
566
347
  if (typeof ctx.runMutation === "function") {
567
348
  try {
568
- await ctx.runMutation(api.topics.update, topicUpdateArgs);
349
+ await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
569
350
  } catch (error) {
570
- if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
351
+ if (!canPatchTopicViaLocalDb(ctx, error)) {
571
352
  throw error;
572
353
  }
573
- await ctx.db.patch(String(topic._id), patch);
354
+ await ctx.db.patch(topic._id, plan.patch);
574
355
  }
575
356
  } else if (ctx?.db && typeof ctx.db.patch === "function") {
576
- await ctx.db.patch(String(topic._id), patch);
357
+ await ctx.db.patch(topic._id, plan.patch);
577
358
  } else {
578
359
  throw new Error(
579
360
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
580
361
  );
581
362
  }
582
- return materializeTopicProjectOverlay({
583
- ...topic,
584
- ...patch,
585
- metadata: nextMetadata
586
- });
363
+ }
364
+ function canPatchTopicViaLocalDb(ctx, error) {
365
+ return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
587
366
  }
588
367
 
589
368
  // src/resolvers.ts
@@ -611,7 +390,7 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
611
390
  try {
612
391
  await patchTopicProjectOverlay(ctx, projectId, value);
613
392
  } catch (error) {
614
- if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
393
+ if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
615
394
  throw error;
616
395
  }
617
396
  console.warn(
@@ -644,12 +423,263 @@ function resolveGraphPrimitivesAppResolvers(_ctx) {
644
423
  ...resolverOverrides
645
424
  };
646
425
  }
426
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
427
+ async function resolveTopicNodeScopeOrNull(ctx, ref) {
428
+ if (!ctx?.db || typeof ctx.db.query !== "function") {
429
+ return null;
430
+ }
431
+ let node = null;
432
+ try {
433
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
434
+ if (byGlobalId && byGlobalId.nodeType === "topic") {
435
+ node = byGlobalId;
436
+ }
437
+ } catch (error) {
438
+ debugGraphPrimitiveFallback(
439
+ "[topicScope] topic-node scope lookup by globalId failed",
440
+ { error, ref }
441
+ );
442
+ }
443
+ if (!node) {
444
+ return null;
445
+ }
446
+ const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
447
+ if (!scopeKey) {
448
+ return null;
449
+ }
450
+ return {
451
+ topicId: scopeKey,
452
+ projectId: asMappedProjectId(node),
453
+ source: "topic_node"
454
+ };
455
+ }
456
+ function asMappedProjectId(topic) {
457
+ if (!topic) {
458
+ return;
459
+ }
460
+ const directLegacyProjectId = normalizeScopeValue(
461
+ topic[LEGACY_SCOPE_FIELD2]
462
+ );
463
+ if (directLegacyProjectId) {
464
+ return directLegacyProjectId;
465
+ }
466
+ const metadata = topic.metadata || {};
467
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
468
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
469
+ }
470
+ function normalizeScopeValue(value) {
471
+ if (typeof value !== "string") {
472
+ return;
473
+ }
474
+ const normalized = value.trim();
475
+ return normalized.length > 0 ? normalized : void 0;
476
+ }
477
+ function pickPrimaryTopic(candidates) {
478
+ return [...candidates].sort((a, b) => {
479
+ const depthA = a.depth ?? 9999;
480
+ const depthB = b.depth ?? 9999;
481
+ if (depthA !== depthB) {
482
+ return depthA - depthB;
483
+ }
484
+ const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
485
+ const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
486
+ if (createdA !== createdB) {
487
+ return createdA - createdB;
488
+ }
489
+ return String(a.name || "").localeCompare(String(b.name || ""));
490
+ })[0];
491
+ }
492
+ async function findTopicsByScopeAlias(ctx, scopeId) {
493
+ const query2 = ctx.db.query("topics");
494
+ try {
495
+ return await query2.withIndex(
496
+ "by_graph_scope_project",
497
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
498
+ ).collect();
499
+ } catch (error) {
500
+ debugGraphPrimitiveFallback(
501
+ "[topicScope] Failed to resolve scope alias via index",
502
+ {
503
+ error,
504
+ scopeId
505
+ }
506
+ );
507
+ const topics = await query2.collect();
508
+ return topics.filter((topic) => {
509
+ const normalizedGlobalId = normalizeScopeValue(topic.globalId);
510
+ const mappedProjectId = asMappedProjectId(topic);
511
+ return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
512
+ });
513
+ }
514
+ }
515
+ async function tryResolveHostTopicById(ctx, topicId) {
516
+ if (typeof ctx.runQuery !== "function") {
517
+ return null;
518
+ }
519
+ try {
520
+ return await ctx.runQuery(api.topics.get, {
521
+ id: topicId
522
+ }) ?? null;
523
+ } catch (error) {
524
+ debugGraphPrimitiveFallback(
525
+ "[topicScope] Failed to resolve topic by host query",
526
+ {
527
+ error,
528
+ topicId
529
+ }
530
+ );
531
+ return null;
532
+ }
533
+ }
534
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
535
+ if (typeof ctx.runQuery !== "function") {
536
+ return null;
537
+ }
538
+ try {
539
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
540
+ projectId: legacyScopeId
541
+ }) ?? null;
542
+ } catch (error) {
543
+ debugGraphPrimitiveFallback(
544
+ "[topicScope] Failed to resolve topic by legacy scope",
545
+ {
546
+ error,
547
+ legacyScopeId
548
+ }
549
+ );
550
+ return null;
551
+ }
552
+ }
553
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
554
+ const MAX_DEPTH = 10;
555
+ let tenantId = normalizeScopeValue(topic.tenantId);
556
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
557
+ if (tenantId && workspaceId) {
558
+ return { tenantId, workspaceId };
559
+ }
560
+ let current = topic;
561
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
562
+ current = await ctx.db.get(current.parentTopicId);
563
+ if (!current) {
564
+ break;
565
+ }
566
+ if (!tenantId) {
567
+ tenantId = normalizeScopeValue(current.tenantId);
568
+ }
569
+ if (!workspaceId) {
570
+ workspaceId = normalizeScopeValue(current.workspaceId);
571
+ }
572
+ if (tenantId && workspaceId) {
573
+ break;
574
+ }
575
+ }
576
+ return { tenantId, workspaceId };
577
+ }
578
+ async function resolveTopicProjectScope(ctx, args) {
579
+ if (args.topicId) {
580
+ return await resolveScopeFromTopicId(ctx, args.topicId);
581
+ }
582
+ if (args.projectId) {
583
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
584
+ }
585
+ throw new Error(
586
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
587
+ );
588
+ }
589
+ async function resolveScopeFromTopicId(ctx, topicId) {
590
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
591
+ if (topic) {
592
+ return await buildTopicScope(ctx, topic, "topic");
593
+ }
594
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
595
+ if (nodeScope) {
596
+ return nodeScope;
597
+ }
598
+ throw new Error(`Topic not found: ${String(topicId)}`);
599
+ }
600
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
601
+ const direct = await tryReadTopicDoc(ctx, topicId, {
602
+ failureLog: "[topicScope] Failed to load topic by direct id",
603
+ idLogKey: "topicId"
604
+ });
605
+ if (direct) {
606
+ return direct;
607
+ }
608
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
609
+ if (hostTopic) {
610
+ return hostTopic;
611
+ }
612
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
613
+ }
614
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
615
+ const directTopic = await resolveDirectLegacyProjectTopic(
616
+ ctx,
617
+ legacyProjectId
618
+ );
619
+ if (directTopic) {
620
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
621
+ fallbackProjectId: legacyProjectId
622
+ });
623
+ }
624
+ const primary = pickPrimaryTopic(
625
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
626
+ );
627
+ if (primary) {
628
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
629
+ fallbackProjectId: legacyProjectId
630
+ });
631
+ }
632
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
633
+ if (nodeScope) {
634
+ return {
635
+ ...nodeScope,
636
+ projectId: nodeScope.projectId ?? legacyProjectId
637
+ };
638
+ }
639
+ throw new Error(
640
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
641
+ );
642
+ }
643
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
644
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
645
+ failureLog: "[topicScope] Failed to load direct project topic",
646
+ idLogKey: "projectId"
647
+ });
648
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
649
+ }
650
+ async function tryReadTopicDoc(ctx, id, log) {
651
+ try {
652
+ return await ctx.db.get(id);
653
+ } catch (error) {
654
+ debugGraphPrimitiveFallback(log.failureLog, {
655
+ error,
656
+ [log.idLogKey]: id
657
+ });
658
+ return null;
659
+ }
660
+ }
661
+ async function buildTopicScope(ctx, topic, source, options = {}) {
662
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
663
+ const mapped = asMappedProjectId(topic);
664
+ return {
665
+ topicId: topic._id,
666
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
667
+ tenantId: inherited.tenantId,
668
+ workspaceId: inherited.workspaceId,
669
+ source
670
+ };
671
+ }
672
+ var optionalScopeArgs = {
673
+ projectId: v.optional(v.string()),
674
+ topicId: v.optional(v.string())
675
+ };
647
676
 
648
677
  // src/epistemicQuestions.helpers.ts
649
678
  async function markProjectGraphDirty(ctx, projectId, topicId) {
679
+ const markCacheStaleByTopic = internal.graphAnalysisCache.markCacheStaleByTopic;
650
680
  const normalizedProjectId = typeof projectId === "string" && projectId.trim().length > 0 ? projectId : void 0;
651
681
  const normalizedTopicId = typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
652
- if (!normalizedProjectId && !normalizedTopicId) {
682
+ if (!(normalizedProjectId || normalizedTopicId)) {
653
683
  return;
654
684
  }
655
685
  if (normalizedProjectId) {
@@ -662,17 +692,17 @@ async function markProjectGraphDirty(ctx, projectId, topicId) {
662
692
  );
663
693
  }
664
694
  if (normalizedTopicId) {
665
- await ctx.scheduler.runAfter(
666
- 0,
667
- internal.graphAnalysisCache.markCacheStaleByTopic,
668
- {
669
- topicId: normalizedTopicId
670
- }
671
- );
695
+ await ctx.scheduler.runAfter(0, markCacheStaleByTopic, {
696
+ topicId: normalizedTopicId
697
+ });
698
+ }
699
+ const resolvedProjectId = normalizedTopicId ?? normalizedProjectId;
700
+ if (!resolvedProjectId) {
701
+ return;
672
702
  }
673
703
  await resolveGraphPrimitivesAppResolvers().patchProject(
674
704
  ctx,
675
- normalizedTopicId ?? normalizedProjectId,
705
+ resolvedProjectId,
676
706
  {
677
707
  lastActivityAt: Date.now()
678
708
  }
@@ -695,7 +725,7 @@ function normalizeQuestionTopicId(topicId) {
695
725
  return typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
696
726
  }
697
727
  async function resolveQuestionScopeOrNull(ctx, args) {
698
- if (!args.projectId && !args.topicId) {
728
+ if (!(args.projectId || args.topicId)) {
699
729
  return null;
700
730
  }
701
731
  try {
@@ -730,12 +760,62 @@ async function getQuestionNodesForScope(ctx, scope, args) {
730
760
  function questionMatchesScope(node, scope) {
731
761
  return scope.topicId !== void 0 && node.topicId === scope.topicId || scope.projectId !== void 0 && node.projectId === scope.projectId;
732
762
  }
733
- async function insertEpistemicNode(ctx, doc) {
734
- assertUuidV7Identity("epistemicNodes", doc.globalId);
735
- return ctx.db.insert("epistemicNodes", doc);
736
- }
737
763
 
738
764
  // src/epistemicQuestions.evidence.ts
765
+ function readOptionalString(value) {
766
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
767
+ }
768
+ function readConvexId(value) {
769
+ const normalized = readOptionalString(value);
770
+ return normalized ? normalized : null;
771
+ }
772
+ function readRecord(value) {
773
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
774
+ }
775
+ function readStringArray2(value) {
776
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : [];
777
+ }
778
+ function readFiniteNumber(value) {
779
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
780
+ }
781
+ function readQuestionEvidenceNodeRow(value) {
782
+ const record = readRecord(value);
783
+ if (!record) {
784
+ return null;
785
+ }
786
+ const id = readConvexId(record._id);
787
+ const nodeType = readOptionalString(record.nodeType);
788
+ if (!(id && nodeType)) {
789
+ return null;
790
+ }
791
+ const row = {
792
+ _id: id,
793
+ metadata: readRecord(record.metadata) ?? {},
794
+ nodeType
795
+ };
796
+ const canonicalText = readOptionalString(record.canonicalText);
797
+ if (canonicalText !== void 0) {
798
+ row.canonicalText = canonicalText;
799
+ }
800
+ const globalId = readOptionalString(record.globalId);
801
+ if (globalId !== void 0) {
802
+ row.globalId = globalId;
803
+ }
804
+ return row;
805
+ }
806
+ function readBeliefNodeRow(value) {
807
+ const record = readRecord(value);
808
+ if (!record) {
809
+ return null;
810
+ }
811
+ const id = readConvexId(record._id);
812
+ const globalId = readOptionalString(record.globalId);
813
+ const nodeType = readOptionalString(record.nodeType);
814
+ return id && globalId && nodeType ? { _id: id, globalId, nodeType } : null;
815
+ }
816
+ function resolveCanonicalEdgeTopicId(args) {
817
+ return normalizeQuestionTopicId(args.topicId) ?? args.projectId;
818
+ }
739
819
  var createEvidenceFromScoredQuestion = internalMutation({
740
820
  args: {
741
821
  questionNodeId: v.id("epistemicNodes"),
@@ -751,14 +831,25 @@ var createEvidenceFromScoredQuestion = internalMutation({
751
831
  returns: permissiveReturn,
752
832
  handler: async (ctx, args) => {
753
833
  const now = Date.now();
754
- const questionNode = await ctx.db.get(args.questionNodeId);
834
+ const questionNode = readQuestionEvidenceNodeRow(
835
+ await ctx.db.get(args.questionNodeId)
836
+ );
755
837
  if (!questionNode) {
756
838
  return;
757
839
  }
758
- const qMeta = questionNode.metadata || {};
840
+ if (questionNode.nodeType !== "question") {
841
+ return;
842
+ }
843
+ if (!questionNode.globalId) {
844
+ throw new Error(
845
+ "Question node missing globalId; cannot create canonical evidence provenance edge"
846
+ );
847
+ }
848
+ const qMeta = questionNode.metadata;
759
849
  if (qMeta.evidenceNodeId) {
760
850
  return;
761
851
  }
852
+ const edgeTopicId = resolveCanonicalEdgeTopicId(args);
762
853
  const evidenceText = `Q: ${args.questionText}
763
854
 
764
855
  A: ${args.answerText}`;
@@ -805,7 +896,8 @@ A: ${args.answerText}`;
805
896
  const weight = args.conviction >= 0.5 ? args.conviction : -(1 - args.conviction);
806
897
  async function resolveBeliefNode(bId) {
807
898
  try {
808
- const node = await ctx.db.get(bId);
899
+ const beliefNodeId = readConvexId(bId);
900
+ const node = beliefNodeId ? readBeliefNodeRow(await ctx.db.get(beliefNodeId)) : null;
809
901
  if (node?.nodeType === "belief") {
810
902
  return node;
811
903
  }
@@ -836,7 +928,7 @@ A: ${args.answerText}`;
836
928
  confidence: Math.abs(weight),
837
929
  context: `origin=sprint_question_scoring | relation=${weight >= 0 ? "supports" : "contradicts"} | sourceQuestionId=${String(args.questionNodeId)}`,
838
930
  createdBy: args.userId,
839
- topicId: args.projectId ? String(args.projectId) : void 0,
931
+ topicId: edgeTopicId,
840
932
  fromNodeType: "evidence",
841
933
  toNodeType: "belief",
842
934
  fromLayer: "L2",
@@ -853,7 +945,7 @@ A: ${args.answerText}`;
853
945
  confidence: 1,
854
946
  context: `origin=sprint_question_scoring | sourceQuestionId=${String(args.questionNodeId)}`,
855
947
  createdBy: args.userId,
856
- topicId: args.projectId ? String(args.projectId) : void 0,
948
+ topicId: edgeTopicId,
857
949
  fromNodeType: "evidence",
858
950
  toNodeType: "question",
859
951
  fromLayer: "L2",
@@ -904,23 +996,23 @@ var backfillScoredQuestionEvidence = internalMutation({
904
996
  candidates: []
905
997
  };
906
998
  }
907
- const allQuestions = await getQuestionNodesForScope(ctx, scope);
999
+ const allQuestions = (await getQuestionNodesForScope(ctx, scope)).map(readQuestionEvidenceNodeRow).filter((node) => node !== null);
908
1000
  const candidates = allQuestions.filter((n) => {
909
- const meta = n.metadata || {};
910
- return meta.convictionStage === "scored" && meta.answer && !meta.evidenceNodeId && (meta.linkedBeliefId || meta.beliefId);
1001
+ const meta = n.metadata;
1002
+ return meta.convictionStage === "scored" && readOptionalString(meta.answer) && !meta.evidenceNodeId && (readOptionalString(meta.linkedBeliefId) || readOptionalString(meta.beliefId));
911
1003
  });
912
1004
  if (dryRun) {
913
1005
  return {
914
1006
  dryRun: true,
915
1007
  candidateCount: candidates.length,
916
1008
  candidates: candidates.map((n) => {
917
- const meta = n.metadata || {};
1009
+ const meta = n.metadata;
918
1010
  return {
919
1011
  questionId: n._id,
920
1012
  questionText: n.canonicalText?.slice(0, 80),
921
- beliefId: meta.linkedBeliefId || meta.beliefId,
922
- conviction: meta.conviction,
923
- hasAnswer: !!meta.answer
1013
+ beliefId: readOptionalString(meta.linkedBeliefId) ?? readOptionalString(meta.beliefId),
1014
+ conviction: readFiniteNumber(meta.conviction),
1015
+ hasAnswer: readOptionalString(meta.answer) !== void 0
924
1016
  };
925
1017
  })
926
1018
  };
@@ -928,11 +1020,11 @@ var backfillScoredQuestionEvidence = internalMutation({
928
1020
  let created = 0;
929
1021
  let skipped = 0;
930
1022
  for (const questionNode of candidates) {
931
- const meta = questionNode.metadata || {};
932
- const beliefId = meta.linkedBeliefId ?? meta.beliefId;
933
- const answerText = meta.answer;
934
- const conviction = meta.conviction ?? 0.5;
935
- if (!beliefId || !answerText) {
1023
+ const meta = questionNode.metadata;
1024
+ const beliefId = readOptionalString(meta.linkedBeliefId) ?? readOptionalString(meta.beliefId);
1025
+ const answerText = readOptionalString(meta.answer);
1026
+ const conviction = readFiniteNumber(meta.conviction) ?? 0.5;
1027
+ if (!(beliefId && answerText)) {
936
1028
  skipped++;
937
1029
  continue;
938
1030
  }
@@ -945,9 +1037,9 @@ var backfillScoredQuestionEvidence = internalMutation({
945
1037
  questionText: questionNode.canonicalText || "",
946
1038
  answerText,
947
1039
  beliefId,
948
- relatedBeliefIds: meta.relatedBeliefIds || [],
1040
+ relatedBeliefIds: readStringArray2(meta.relatedBeliefIds),
949
1041
  conviction,
950
- rationale: meta.convictionRationale || "",
1042
+ rationale: readOptionalString(meta.convictionRationale) ?? "",
951
1043
  projectId: scope.projectId,
952
1044
  topicId: normalizeQuestionTopicId(scope.topicId),
953
1045
  userId: args.userId