@lucern/graph-primitives 1.0.28 → 1.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
  2. package/dist/beliefDecay.d.ts +1 -1
  3. package/dist/beliefDecay.js +448 -314
  4. package/dist/beliefDecay.js.map +1 -1
  5. package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
  6. package/dist/beliefEvidenceLinks.d.ts +1 -1
  7. package/dist/beliefEvidenceLinks.js +843 -624
  8. package/dist/beliefEvidenceLinks.js.map +1 -1
  9. package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
  10. package/dist/beliefEvidenceLinks.operational.js +91 -18
  11. package/dist/beliefEvidenceLinks.operational.js.map +1 -1
  12. package/dist/beliefLifecycle.js.map +1 -1
  13. package/dist/confidencePropagationDispatch.d.ts +28 -27
  14. package/dist/confidencePropagationDispatch.js +157 -99
  15. package/dist/confidencePropagationDispatch.js.map +1 -1
  16. package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
  17. package/dist/contradictions.d.ts +1 -1
  18. package/dist/contradictions.js +398 -228
  19. package/dist/contradictions.js.map +1 -1
  20. package/dist/convex.d.ts +65 -30
  21. package/dist/convex.js +7 -3
  22. package/dist/convex.js.map +1 -1
  23. package/dist/debug.js.map +1 -1
  24. package/dist/edgeValidation.js +293 -85
  25. package/dist/edgeValidation.js.map +1 -1
  26. package/dist/edges/contains.d.ts +1 -1
  27. package/dist/edges/contains.js.map +1 -1
  28. package/dist/edges/contradicts.d.ts +1 -1
  29. package/dist/edges/contradicts.js.map +1 -1
  30. package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
  31. package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
  32. package/dist/edges/depends-on.js.map +1 -0
  33. package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
  34. package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
  35. package/dist/edges/derived-from.js.map +1 -0
  36. package/dist/edges/elaborates.d.ts +1 -1
  37. package/dist/edges/elaborates.js.map +1 -1
  38. package/dist/edges/index.d.ts +7 -3
  39. package/dist/edges/index.js +7 -4
  40. package/dist/edges/index.js.map +1 -1
  41. package/dist/edges/informs.d.ts +1 -1
  42. package/dist/edges/informs.js.map +1 -1
  43. package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
  44. package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
  45. package/dist/edges/propagation-types.js.map +1 -0
  46. package/dist/edges/refutes.d.ts +1 -1
  47. package/dist/edges/refutes.js.map +1 -1
  48. package/dist/edges/supports.d.ts +1 -1
  49. package/dist/edges/supports.js.map +1 -1
  50. package/dist/edges/tests.d.ts +1 -1
  51. package/dist/edges/tests.js.map +1 -1
  52. package/dist/edges/utils.d.ts +1 -1
  53. package/dist/edges/utils.js.map +1 -1
  54. package/dist/embeddingTrigger.d.ts +14 -6
  55. package/dist/embeddingTrigger.js +11 -14
  56. package/dist/embeddingTrigger.js.map +1 -1
  57. package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
  58. package/dist/entityBridge.d.ts +1 -1
  59. package/dist/entityBridge.js +602 -225
  60. package/dist/entityBridge.js.map +1 -1
  61. package/dist/entityCanonicalMatch.d.ts +14 -12
  62. package/dist/entityCanonicalMatch.js.map +1 -1
  63. package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
  64. package/dist/entityLifecycle.d.ts +1 -1
  65. package/dist/entityLifecycle.js +857 -515
  66. package/dist/entityLifecycle.js.map +1 -1
  67. package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
  68. package/dist/entityValidation.d.ts +3 -1
  69. package/dist/entityValidation.js +60 -8
  70. package/dist/entityValidation.js.map +1 -1
  71. package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
  72. package/dist/epistemicAnswers.d.ts +1 -1
  73. package/dist/epistemicAnswers.js +587 -545
  74. package/dist/epistemicAnswers.js.map +1 -1
  75. package/dist/epistemicBeliefs.admin.d.ts +8 -8
  76. package/dist/epistemicBeliefs.admin.js +366 -203
  77. package/dist/epistemicBeliefs.admin.js.map +1 -1
  78. package/dist/epistemicBeliefs.backfills.d.ts +8 -8
  79. package/dist/epistemicBeliefs.backfills.js +655 -308
  80. package/dist/epistemicBeliefs.backfills.js.map +1 -1
  81. package/dist/epistemicBeliefs.confidence.d.ts +19 -14
  82. package/dist/epistemicBeliefs.confidence.js +634 -423
  83. package/dist/epistemicBeliefs.confidence.js.map +1 -1
  84. package/dist/epistemicBeliefs.core.d.ts +6 -6
  85. package/dist/epistemicBeliefs.core.js +719 -411
  86. package/dist/epistemicBeliefs.core.js.map +1 -1
  87. package/dist/epistemicBeliefs.d.ts +11 -8
  88. package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
  89. package/dist/epistemicBeliefs.forkEvidence.js +8 -28
  90. package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
  91. package/dist/epistemicBeliefs.helpers.d.ts +69 -74
  92. package/dist/epistemicBeliefs.helpers.js +359 -248
  93. package/dist/epistemicBeliefs.helpers.js.map +1 -1
  94. package/dist/epistemicBeliefs.internal.d.ts +5 -5
  95. package/dist/epistemicBeliefs.internal.js +1246 -1044
  96. package/dist/epistemicBeliefs.internal.js.map +1 -1
  97. package/dist/epistemicBeliefs.js +4922 -3608
  98. package/dist/epistemicBeliefs.js.map +1 -1
  99. package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
  100. package/dist/epistemicBeliefs.lifecycle.js +1137 -818
  101. package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
  102. package/dist/epistemicBeliefs.links.d.ts +7 -7
  103. package/dist/epistemicBeliefs.links.js +408 -307
  104. package/dist/epistemicBeliefs.links.js.map +1 -1
  105. package/dist/epistemicBeliefs.queries.d.ts +4 -4
  106. package/dist/epistemicBeliefs.queries.js +175 -20
  107. package/dist/epistemicBeliefs.queries.js.map +1 -1
  108. package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
  109. package/dist/epistemicBeliefs.topicAnchor.js +12 -5
  110. package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
  111. package/dist/epistemicContracts.d.ts +28 -3
  112. package/dist/epistemicContracts.evaluators.d.ts +2 -0
  113. package/dist/epistemicContracts.evaluators.js +1063 -613
  114. package/dist/epistemicContracts.evaluators.js.map +1 -1
  115. package/dist/epistemicContracts.handlers.d.ts +15 -32
  116. package/dist/epistemicContracts.handlers.js +2086 -1644
  117. package/dist/epistemicContracts.handlers.js.map +1 -1
  118. package/dist/epistemicContracts.js +1131 -672
  119. package/dist/epistemicContracts.js.map +1 -1
  120. package/dist/epistemicContracts.metrics.d.ts +2 -0
  121. package/dist/epistemicContracts.metrics.js +375 -158
  122. package/dist/epistemicContracts.metrics.js.map +1 -1
  123. package/dist/epistemicContracts.types.d.ts +87 -81
  124. package/dist/epistemicEdgeCreation.d.ts +2 -0
  125. package/dist/epistemicEdgeCreation.js +87 -16
  126. package/dist/epistemicEdgeCreation.js.map +1 -1
  127. package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
  128. package/dist/epistemicEdges.d.ts +6 -5
  129. package/dist/epistemicEdges.handlers.d.ts +3 -3
  130. package/dist/epistemicEdges.handlers.js +129 -24
  131. package/dist/epistemicEdges.handlers.js.map +1 -1
  132. package/dist/epistemicEdges.helpers.d.ts +6 -4
  133. package/dist/epistemicEdges.helpers.js +37 -2
  134. package/dist/epistemicEdges.helpers.js.map +1 -1
  135. package/dist/epistemicEdges.js +1969 -1205
  136. package/dist/epistemicEdges.js.map +1 -1
  137. package/dist/epistemicEdges.mutations.d.ts +7 -7
  138. package/dist/epistemicEdges.mutations.js +960 -583
  139. package/dist/epistemicEdges.mutations.js.map +1 -1
  140. package/dist/epistemicEdges.queries.d.ts +16 -16
  141. package/dist/epistemicEdges.queries.js +639 -367
  142. package/dist/epistemicEdges.queries.js.map +1 -1
  143. package/dist/epistemicEdges.types.d.ts +10 -8
  144. package/dist/epistemicEvidence.d.ts +4 -1
  145. package/dist/epistemicEvidence.js +937 -536
  146. package/dist/epistemicEvidence.js.map +1 -1
  147. package/dist/epistemicEvidenceHelpers.d.ts +26 -10
  148. package/dist/epistemicEvidenceHelpers.js +239 -200
  149. package/dist/epistemicEvidenceHelpers.js.map +1 -1
  150. package/dist/epistemicEvidenceMutations.d.ts +8 -8
  151. package/dist/epistemicEvidenceMutations.js +844 -696
  152. package/dist/epistemicEvidenceMutations.js.map +1 -1
  153. package/dist/epistemicEvidenceQueries.d.ts +8 -8
  154. package/dist/epistemicEvidenceQueries.js +514 -238
  155. package/dist/epistemicEvidenceQueries.js.map +1 -1
  156. package/dist/epistemicHelpers.d.ts +4 -2
  157. package/dist/epistemicHelpers.js +308 -134
  158. package/dist/epistemicHelpers.js.map +1 -1
  159. package/dist/epistemicInsert.d.ts +16 -4
  160. package/dist/epistemicInsert.js +6 -3
  161. package/dist/epistemicInsert.js.map +1 -1
  162. package/dist/epistemicLayerRules.d.ts +10 -8
  163. package/dist/epistemicLayerRules.js +1 -5
  164. package/dist/epistemicLayerRules.js.map +1 -1
  165. package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
  166. package/dist/epistemicLinking.d.ts +1 -1
  167. package/dist/epistemicLinking.js +177 -100
  168. package/dist/epistemicLinking.js.map +1 -1
  169. package/dist/epistemicNodeCreation.d.ts +2 -0
  170. package/dist/epistemicNodeCreation.js +203 -40
  171. package/dist/epistemicNodeCreation.js.map +1 -1
  172. package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
  173. package/dist/epistemicNodes.d.ts +3 -3
  174. package/dist/epistemicNodes.helpers.d.ts +24 -15
  175. package/dist/epistemicNodes.helpers.js.map +1 -1
  176. package/dist/epistemicNodes.internal.d.ts +6 -6
  177. package/dist/epistemicNodes.internal.js +389 -319
  178. package/dist/epistemicNodes.internal.js.map +1 -1
  179. package/dist/epistemicNodes.js +704 -508
  180. package/dist/epistemicNodes.js.map +1 -1
  181. package/dist/epistemicNodes.mutations.d.ts +6 -6
  182. package/dist/epistemicNodes.mutations.js +564 -467
  183. package/dist/epistemicNodes.mutations.js.map +1 -1
  184. package/dist/epistemicNodes.queries.d.ts +8 -8
  185. package/dist/epistemicNodes.queries.js +311 -314
  186. package/dist/epistemicNodes.queries.js.map +1 -1
  187. package/dist/epistemicNodes.validators.d.ts +2 -2
  188. package/dist/epistemicNodes.validators.js.map +1 -1
  189. package/dist/epistemicQuestions.conviction.d.ts +8 -8
  190. package/dist/epistemicQuestions.conviction.js +665 -484
  191. package/dist/epistemicQuestions.conviction.js.map +1 -1
  192. package/dist/epistemicQuestions.create.d.ts +4 -4
  193. package/dist/epistemicQuestions.create.js +640 -612
  194. package/dist/epistemicQuestions.create.js.map +1 -1
  195. package/dist/epistemicQuestions.d.ts +8 -5
  196. package/dist/epistemicQuestions.evidence.d.ts +2 -2
  197. package/dist/epistemicQuestions.evidence.js +475 -383
  198. package/dist/epistemicQuestions.evidence.js.map +1 -1
  199. package/dist/epistemicQuestions.helpers.d.ts +125 -24
  200. package/dist/epistemicQuestions.helpers.js +240 -209
  201. package/dist/epistemicQuestions.helpers.js.map +1 -1
  202. package/dist/epistemicQuestions.js +3474 -2823
  203. package/dist/epistemicQuestions.js.map +1 -1
  204. package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
  205. package/dist/epistemicQuestions.lifecycle.js +607 -546
  206. package/dist/epistemicQuestions.lifecycle.js.map +1 -1
  207. package/dist/epistemicQuestions.queries.d.ts +12 -7
  208. package/dist/epistemicQuestions.queries.js +305 -244
  209. package/dist/epistemicQuestions.queries.js.map +1 -1
  210. package/dist/epistemicQuestions.sprint.d.ts +2 -2
  211. package/dist/epistemicQuestions.sprint.js +600 -394
  212. package/dist/epistemicQuestions.sprint.js.map +1 -1
  213. package/dist/epistemicQuestions.tail.d.ts +6 -6
  214. package/dist/epistemicQuestions.tail.js +572 -433
  215. package/dist/epistemicQuestions.tail.js.map +1 -1
  216. package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
  217. package/dist/epistemicSources.d.ts +1 -1
  218. package/dist/epistemicSources.js +352 -312
  219. package/dist/epistemicSources.js.map +1 -1
  220. package/dist/evaluators/index.d.ts +8 -6
  221. package/dist/evaluators/index.js +399 -167
  222. package/dist/evaluators/index.js.map +1 -1
  223. package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
  224. package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
  225. package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
  226. package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
  227. package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
  228. package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
  229. package/dist/evaluators/shared.d.ts +2 -2
  230. package/dist/evaluators/shared.js +3 -1
  231. package/dist/evaluators/shared.js.map +1 -1
  232. package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
  233. package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
  234. package/dist/evaluators/test-runner-evaluator.js.map +1 -0
  235. package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
  236. package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
  237. package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
  238. package/dist/graphTypes.js +6 -2
  239. package/dist/graphTypes.js.map +1 -1
  240. package/dist/helpers.d.ts +2 -0
  241. package/dist/helpers.js +313 -93
  242. package/dist/helpers.js.map +1 -1
  243. package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
  244. package/dist/index.d.ts +87 -83
  245. package/dist/index.js +15677 -10594
  246. package/dist/index.js.map +1 -1
  247. package/dist/invariantEnforcement.d.ts +3 -3
  248. package/dist/invariantEnforcement.js.map +1 -1
  249. package/dist/logicalRoleInference.d.ts +2 -0
  250. package/dist/logicalRoleInference.js +1 -1
  251. package/dist/logicalRoleInference.js.map +1 -1
  252. package/dist/matcherFeedbackUtils.d.ts +2 -2
  253. package/dist/matcherFeedbackUtils.js.map +1 -1
  254. package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
  255. package/dist/ontology-matching.d.ts +1 -1
  256. package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
  257. package/dist/ontologyApproval.d.ts +1 -1
  258. package/dist/ontologyApproval.js +7 -1
  259. package/dist/ontologyApproval.js.map +1 -1
  260. package/dist/ontologyDefinitions.d.ts +14 -24
  261. package/dist/ontologyDefinitions.js +269 -34
  262. package/dist/ontologyDefinitions.js.map +1 -1
  263. package/dist/ontologyHelpers.d.ts +13 -13
  264. package/dist/ontologyHelpers.js.map +1 -1
  265. package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
  266. package/dist/ontologyRegistry.d.ts +1 -1
  267. package/dist/ontologyRegistry.js +34 -6
  268. package/dist/ontologyRegistry.js.map +1 -1
  269. package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
  270. package/dist/projectionReconciliation.d.ts +1 -1
  271. package/dist/projectionReconciliation.js +57 -10
  272. package/dist/projectionReconciliation.js.map +1 -1
  273. package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
  274. package/dist/projectionStaleness.d.ts +1 -1
  275. package/dist/projectionStaleness.js +8 -2
  276. package/dist/projectionStaleness.js.map +1 -1
  277. package/dist/proof-attestation.json +1 -1
  278. package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
  279. package/dist/questionEvidenceLinks.d.ts +1 -1
  280. package/dist/questionEvidenceLinks.js +564 -347
  281. package/dist/questionEvidenceLinks.js.map +1 -1
  282. package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
  283. package/dist/resolverTypes.d.ts +4 -2
  284. package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
  285. package/dist/resolvers.d.ts +5 -3
  286. package/dist/resolvers.js +121 -77
  287. package/dist/resolvers.js.map +1 -1
  288. package/dist/scopeResolverCompat.d.ts +10 -7
  289. package/dist/scopeResolverCompat.js +106 -123
  290. package/dist/scopeResolverCompat.js.map +1 -1
  291. package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
  292. package/dist/text-matching.d.ts +1 -1
  293. package/dist/topicOntologyResolver.d.ts +22 -21
  294. package/dist/topicOntologyResolver.js +54 -32
  295. package/dist/topicOntologyResolver.js.map +1 -1
  296. package/dist/topicProjectOverlay.d.ts +30 -20
  297. package/dist/topicProjectOverlay.js +120 -76
  298. package/dist/topicProjectOverlay.js.map +1 -1
  299. package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
  300. package/dist/topicScope.d.ts +3 -1
  301. package/dist/topicScope.js +104 -119
  302. package/dist/topicScope.js.map +1 -1
  303. package/dist/workflowBridge.d.ts +26 -15
  304. package/dist/workflowBridge.js +140 -144
  305. package/dist/workflowBridge.js.map +1 -1
  306. package/dist/workspaceIsolation.d.ts +14 -12
  307. package/dist/workspaceIsolation.js +108 -122
  308. package/dist/workspaceIsolation.js.map +1 -1
  309. package/package.json +4 -4
  310. package/dist/edges/dependsOn.js.map +0 -1
  311. package/dist/edges/derivedFrom.js.map +0 -1
  312. package/dist/edges/propagationTypes.js.map +0 -1
  313. package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
  314. package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
  315. package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
  316. package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
  317. package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
  318. package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
  319. package/dist/{epistemicQuestions-bwHd2FWE.d.ts → epistemicQuestions-Do1fhYm5.d.ts} +4 -4
@@ -1,15 +1,19 @@
1
- import { v } from 'convex/values';
2
1
  import { checkScopeAccess } from '@lucern/access-control/access';
3
2
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
4
- import { componentsGeneric, anyApi, queryGeneric, mutationGeneric } from 'convex/server';
3
+ import { v } from 'convex/values';
4
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
5
+ import { componentsGeneric, queryGeneric, mutationGeneric } from 'convex/server';
6
+ import '@lucern/contracts';
5
7
  import { generateGlobalId, assertUuidV7Identity } from '@lucern/contracts/ids';
6
8
  import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
7
- import '@lucern/contracts';
8
9
 
9
10
  // src/epistemicQuestions.tail.ts
10
- var api = anyApi;
11
+ var unsafeApi = unsafeConvexAnyApi(
12
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
13
+ );
14
+ var api = unsafeApi;
11
15
  componentsGeneric();
12
- var internal = anyApi;
16
+ var internal = unsafeApi;
13
17
  var mutation = mutationGeneric;
14
18
  var query = queryGeneric;
15
19
 
@@ -43,6 +47,10 @@ function debugGraphPrimitiveFallback(message, context) {
43
47
  }
44
48
  console.debug(message, context ?? {});
45
49
  }
50
+ function insertEpistemicNode(ctx, doc) {
51
+ assertUuidV7Identity("epistemicNodes", doc.globalId);
52
+ return ctx.db.insert("epistemicNodes", doc);
53
+ }
46
54
 
47
55
  // src/topicProjectOverlay.ts
48
56
  var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
@@ -62,6 +70,10 @@ function readStringArray(value) {
62
70
  function readMetadata(topic) {
63
71
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
64
72
  }
73
+ function omitMetadataKey(metadata, key) {
74
+ const { [key]: _omitted, ...rest } = metadata;
75
+ return rest;
76
+ }
65
77
  function readLegacyProjectId(value) {
66
78
  if (!value) {
67
79
  return;
@@ -142,9 +154,12 @@ async function resolveTopicDoc(ctx, scopeId) {
142
154
  );
143
155
  }
144
156
  try {
145
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
146
- projectId: String(scopeId)
147
- });
157
+ const topic = await ctx.runQuery(
158
+ api.topics.getByLegacyScopeId,
159
+ {
160
+ projectId: String(scopeId)
161
+ }
162
+ );
148
163
  if (topic?.name !== void 0 && topic?.type !== void 0) {
149
164
  return topic;
150
165
  }
@@ -164,8 +179,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
164
179
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
165
180
  const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
166
181
  const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
167
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
168
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
182
+ let createdAt = 0;
183
+ if (typeof topic.createdAt === "number") {
184
+ createdAt = topic.createdAt;
185
+ } else if (typeof topic._creationTime === "number") {
186
+ createdAt = topic._creationTime;
187
+ }
188
+ let updatedAt = createdAt;
189
+ if (typeof topic.updatedAt === "number") {
190
+ updatedAt = topic.updatedAt;
191
+ } else if (typeof metadata.updatedAt === "number") {
192
+ updatedAt = metadata.updatedAt;
193
+ }
169
194
  return {
170
195
  ...metadata,
171
196
  _id: outwardId,
@@ -234,90 +259,113 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
234
259
  if (!topic) {
235
260
  return null;
236
261
  }
237
- const nextMetadata = { ...readMetadata(topic) };
238
- const patch = {};
239
- const topicUpdateArgs = {
240
- id: String(topic._id)
262
+ const plan = buildTopicProjectOverlayPatchPlan(topic, value);
263
+ await applyTopicProjectOverlayPatch(ctx, topic, plan);
264
+ return materializeTopicProjectOverlay({
265
+ ...topic,
266
+ ...plan.patch,
267
+ metadata: plan.nextMetadata
268
+ });
269
+ }
270
+ function buildTopicProjectOverlayPatchPlan(topic, value) {
271
+ const plan = {
272
+ nextMetadata: { ...readMetadata(topic) },
273
+ patch: {},
274
+ topicUpdateArgs: {
275
+ id: String(topic._id)
276
+ }
241
277
  };
242
278
  for (const [key, rawValue] of Object.entries(value)) {
243
- switch (key) {
244
- case "_id":
245
- case "projectId":
246
- case "topicId":
247
- case "legacyProjectId":
248
- case "storageProjectId":
249
- break;
250
- case "name":
251
- case "description":
252
- patch[key] = rawValue;
253
- topicUpdateArgs[key] = rawValue;
254
- break;
255
- case "tenantId":
256
- case "workspaceId":
257
- case "ownerId":
258
- throw new Error(
259
- `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
260
- );
261
- case "status": {
262
- const status = coerceStatus(rawValue);
263
- if (status) {
264
- patch.status = status;
265
- topicUpdateArgs.status = status;
266
- }
267
- break;
268
- }
269
- case "visibility": {
270
- const visibility = coerceVisibility(rawValue);
271
- if (visibility) {
272
- patch.visibility = visibility;
273
- topicUpdateArgs.visibility = visibility;
274
- }
275
- break;
276
- }
277
- case "type": {
278
- const projectType = readNonEmptyString(rawValue);
279
- if (projectType) {
280
- nextMetadata.projectType = projectType;
281
- } else {
282
- delete nextMetadata.projectType;
283
- }
284
- break;
285
- }
286
- case "updatedAt":
287
- case "createdAt":
288
- break;
289
- default:
290
- if (rawValue === void 0) {
291
- delete nextMetadata[key];
292
- } else {
293
- nextMetadata[key] = rawValue;
294
- }
295
- }
279
+ applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
280
+ }
281
+ plan.patch.updatedAt = Date.now();
282
+ plan.patch.metadata = plan.nextMetadata;
283
+ plan.topicUpdateArgs.metadata = plan.nextMetadata;
284
+ return plan;
285
+ }
286
+ function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
287
+ switch (key) {
288
+ case "_id":
289
+ case "projectId":
290
+ case "topicId":
291
+ case "legacyProjectId":
292
+ case "storageProjectId":
293
+ case "updatedAt":
294
+ case "createdAt":
295
+ return;
296
+ case "name":
297
+ case "description":
298
+ plan.patch[key] = rawValue;
299
+ plan.topicUpdateArgs[key] = rawValue;
300
+ return;
301
+ case "tenantId":
302
+ case "workspaceId":
303
+ case "ownerId":
304
+ throw new Error(
305
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
306
+ );
307
+ case "status":
308
+ applyTopicStatusPatch(plan, rawValue);
309
+ return;
310
+ case "visibility":
311
+ applyTopicVisibilityPatch(plan, rawValue);
312
+ return;
313
+ case "type":
314
+ applyTopicProjectTypePatch(plan, rawValue);
315
+ return;
316
+ default:
317
+ applyTopicMetadataPatch(plan, key, rawValue);
318
+ }
319
+ }
320
+ function applyTopicStatusPatch(plan, rawValue) {
321
+ const status = coerceStatus(rawValue);
322
+ if (status) {
323
+ plan.patch.status = status;
324
+ plan.topicUpdateArgs.status = status;
296
325
  }
297
- patch.updatedAt = Date.now();
298
- patch.metadata = nextMetadata;
299
- topicUpdateArgs.metadata = nextMetadata;
326
+ }
327
+ function applyTopicVisibilityPatch(plan, rawValue) {
328
+ const visibility = coerceVisibility(rawValue);
329
+ if (visibility) {
330
+ plan.patch.visibility = visibility;
331
+ plan.topicUpdateArgs.visibility = visibility;
332
+ }
333
+ }
334
+ function applyTopicProjectTypePatch(plan, rawValue) {
335
+ const projectType = readNonEmptyString(rawValue);
336
+ if (projectType) {
337
+ plan.nextMetadata.projectType = projectType;
338
+ return;
339
+ }
340
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
341
+ }
342
+ function applyTopicMetadataPatch(plan, key, rawValue) {
343
+ if (rawValue === void 0) {
344
+ plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
345
+ return;
346
+ }
347
+ plan.nextMetadata[key] = rawValue;
348
+ }
349
+ async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
300
350
  if (typeof ctx.runMutation === "function") {
301
351
  try {
302
- await ctx.runMutation(api.topics.update, topicUpdateArgs);
352
+ await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
303
353
  } catch (error) {
304
- if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
354
+ if (!canPatchTopicViaLocalDb(ctx, error)) {
305
355
  throw error;
306
356
  }
307
- await ctx.db.patch(String(topic._id), patch);
357
+ await ctx.db.patch(topic._id, plan.patch);
308
358
  }
309
359
  } else if (ctx?.db && typeof ctx.db.patch === "function") {
310
- await ctx.db.patch(String(topic._id), patch);
360
+ await ctx.db.patch(topic._id, plan.patch);
311
361
  } else {
312
362
  throw new Error(
313
363
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
314
364
  );
315
365
  }
316
- return materializeTopicProjectOverlay({
317
- ...topic,
318
- ...patch,
319
- metadata: nextMetadata
320
- });
366
+ }
367
+ function canPatchTopicViaLocalDb(ctx, error) {
368
+ return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
321
369
  }
322
370
 
323
371
  // src/resolvers.ts
@@ -345,7 +393,7 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
345
393
  try {
346
394
  await patchTopicProjectOverlay(ctx, projectId, value);
347
395
  } catch (error) {
348
- if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
396
+ if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
349
397
  throw error;
350
398
  }
351
399
  console.warn(
@@ -412,13 +460,15 @@ function asMappedProjectId(topic) {
412
460
  if (!topic) {
413
461
  return;
414
462
  }
415
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD2]);
463
+ const directLegacyProjectId = normalizeScopeValue(
464
+ topic[LEGACY_SCOPE_FIELD2]
465
+ );
416
466
  if (directLegacyProjectId) {
417
467
  return directLegacyProjectId;
418
468
  }
419
469
  const metadata = topic.metadata || {};
420
470
  const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
421
- return candidate ? candidate : void 0;
471
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
422
472
  }
423
473
  function normalizeScopeValue(value) {
424
474
  if (typeof value !== "string") {
@@ -443,8 +493,9 @@ function pickPrimaryTopic(candidates) {
443
493
  })[0];
444
494
  }
445
495
  async function findTopicsByScopeAlias(ctx, scopeId) {
496
+ const query2 = ctx.db.query("topics");
446
497
  try {
447
- return await ctx.db.query("topics").withIndex(
498
+ return await query2.withIndex(
448
499
  "by_graph_scope_project",
449
500
  (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
450
501
  ).collect();
@@ -456,7 +507,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
456
507
  scopeId
457
508
  }
458
509
  );
459
- const topics = await ctx.db.query("topics").collect();
510
+ const topics = await query2.collect();
460
511
  return topics.filter((topic) => {
461
512
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
462
513
  const mappedProjectId = asMappedProjectId(topic);
@@ -512,244 +563,140 @@ async function resolveInheritedWorkspaceScope(ctx, topic) {
512
563
  let current = topic;
513
564
  for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
514
565
  current = await ctx.db.get(current.parentTopicId);
515
- if (!current) break;
566
+ if (!current) {
567
+ break;
568
+ }
516
569
  if (!tenantId) {
517
570
  tenantId = normalizeScopeValue(current.tenantId);
518
571
  }
519
572
  if (!workspaceId) {
520
573
  workspaceId = normalizeScopeValue(current.workspaceId);
521
574
  }
522
- if (tenantId && workspaceId) break;
575
+ if (tenantId && workspaceId) {
576
+ break;
577
+ }
523
578
  }
524
579
  return { tenantId, workspaceId };
525
580
  }
526
581
  async function resolveTopicProjectScope(ctx, args) {
527
582
  if (args.topicId) {
528
- let topic = null;
529
- try {
530
- topic = await ctx.db.get(
531
- args.topicId
532
- );
533
- } catch (error) {
534
- debugGraphPrimitiveFallback(
535
- "[topicScope] Failed to load topic by direct id",
536
- {
537
- error,
538
- topicId: args.topicId
539
- }
540
- );
541
- }
542
- if (!topic) {
543
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
544
- }
545
- if (!topic) {
546
- topic = pickPrimaryTopic(
547
- await findTopicsByScopeAlias(ctx, String(args.topicId))
548
- ) ?? null;
549
- }
550
- if (!topic) {
551
- const nodeScope = await resolveTopicNodeScopeOrNull(
552
- ctx,
553
- String(args.topicId)
554
- );
555
- if (nodeScope) {
556
- return nodeScope;
557
- }
558
- throw new Error(`Topic not found: ${String(args.topicId)}`);
559
- }
560
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
561
- const mapped = asMappedProjectId(topic);
562
- if (mapped) {
563
- return {
564
- topicId: topic._id,
565
- projectId: mapped,
566
- tenantId: inherited.tenantId,
567
- workspaceId: inherited.workspaceId,
568
- source: "topic"
569
- };
570
- }
571
- return {
572
- topicId: topic._id,
573
- tenantId: inherited.tenantId,
574
- workspaceId: inherited.workspaceId,
575
- source: "topic"
576
- };
583
+ return await resolveScopeFromTopicId(ctx, args.topicId);
577
584
  }
578
585
  if (args.projectId) {
579
- let directTopic = null;
580
- try {
581
- directTopic = await ctx.db.get(
582
- args.projectId
583
- );
584
- } catch (error) {
585
- debugGraphPrimitiveFallback(
586
- "[topicScope] Failed to load direct project topic",
587
- {
588
- error,
589
- projectId: args.projectId
590
- }
591
- );
592
- }
593
- if (directTopic) {
594
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
595
- const mapped = asMappedProjectId(directTopic);
596
- return {
597
- topicId: directTopic._id,
598
- projectId: mapped ?? args.projectId,
599
- tenantId: inherited.tenantId,
600
- workspaceId: inherited.workspaceId,
601
- source: "topic_inferred"
602
- };
603
- }
604
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
605
- if (directTopic) {
606
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
607
- const mapped = asMappedProjectId(directTopic);
608
- return {
609
- topicId: directTopic._id,
610
- projectId: mapped ?? args.projectId,
611
- tenantId: inherited.tenantId,
612
- workspaceId: inherited.workspaceId,
613
- source: "topic_inferred"
614
- };
615
- }
616
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
617
- const primary = pickPrimaryTopic(topics);
618
- if (primary) {
619
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
620
- return {
621
- topicId: primary._id,
622
- projectId: args.projectId,
623
- tenantId: inherited.tenantId,
624
- workspaceId: inherited.workspaceId,
625
- source: "project_mapped_topic"
626
- };
627
- }
628
- const nodeScope = await resolveTopicNodeScopeOrNull(
629
- ctx,
630
- String(args.projectId)
631
- );
632
- if (nodeScope) {
633
- return {
634
- ...nodeScope,
635
- projectId: nodeScope.projectId ?? String(args.projectId)
636
- };
637
- }
638
- throw new Error(
639
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
640
- );
586
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
641
587
  }
642
588
  throw new Error(
643
589
  "Missing scope: provide topicId (preferred) or legacy projectId alias."
644
590
  );
645
591
  }
646
- var optionalScopeArgs = {
647
- projectId: v.optional(v.string()),
648
- topicId: v.optional(v.string())
649
- };
650
- function normalizeScopeValue2(value) {
651
- if (typeof value !== "string") {
652
- return;
592
+ async function resolveScopeFromTopicId(ctx, topicId) {
593
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
594
+ if (topic) {
595
+ return await buildTopicScope(ctx, topic, "topic");
653
596
  }
654
- const normalized = value.trim();
655
- return normalized.length > 0 ? normalized : void 0;
656
- }
657
- function throwWorkspaceIsolationError(args) {
658
- const error = new Error(args.message);
659
- error.status = 409;
660
- error.code = "INVARIANT_VIOLATION";
661
- error.invariantCode = args.invariantCode;
662
- error.suggestion = args.suggestion;
663
- error.details = args.details;
664
- throw error;
665
- }
666
- async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
667
- const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
668
- const resolved = {
669
- tenantId: normalizeScopeValue2(node?.tenantId),
670
- workspaceId: normalizeScopeValue2(node?.workspaceId),
671
- epistemicLayer,
672
- nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
673
- };
674
- if (!node) {
675
- return resolved;
597
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
598
+ if (nodeScope) {
599
+ return nodeScope;
676
600
  }
677
- if (resolved.epistemicLayer === "ontological") {
678
- return resolved;
601
+ throw new Error(`Topic not found: ${String(topicId)}`);
602
+ }
603
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
604
+ const direct = await tryReadTopicDoc(ctx, topicId, {
605
+ failureLog: "[topicScope] Failed to load topic by direct id",
606
+ idLogKey: "topicId"
607
+ });
608
+ if (direct) {
609
+ return direct;
679
610
  }
680
- if (resolved.tenantId || resolved.workspaceId) {
681
- return resolved;
611
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
612
+ if (hostTopic) {
613
+ return hostTopic;
682
614
  }
683
- if (node.topicId) {
684
- const topicScope = await resolveTopicProjectScope(ctx, {
685
- topicId: node.topicId
615
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
616
+ }
617
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
618
+ const directTopic = await resolveDirectLegacyProjectTopic(
619
+ ctx,
620
+ legacyProjectId
621
+ );
622
+ if (directTopic) {
623
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
624
+ fallbackProjectId: legacyProjectId
686
625
  });
687
- return {
688
- ...resolved,
689
- tenantId: topicScope.tenantId,
690
- workspaceId: topicScope.workspaceId
691
- };
692
626
  }
693
- if (node.projectId) {
694
- const topicScope = await resolveTopicProjectScope(ctx, {
695
- projectId: String(node.projectId)
627
+ const primary = pickPrimaryTopic(
628
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
629
+ );
630
+ if (primary) {
631
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
632
+ fallbackProjectId: legacyProjectId
696
633
  });
634
+ }
635
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
636
+ if (nodeScope) {
697
637
  return {
698
- ...resolved,
699
- tenantId: topicScope.tenantId,
700
- workspaceId: topicScope.workspaceId
638
+ ...nodeScope,
639
+ projectId: nodeScope.projectId ?? legacyProjectId
701
640
  };
702
641
  }
703
- return resolved;
642
+ throw new Error(
643
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
644
+ );
704
645
  }
705
- function resolveRuntimePackMutationContext(args) {
706
- if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
707
- return;
646
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
647
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
648
+ failureLog: "[topicScope] Failed to load direct project topic",
649
+ idLogKey: "projectId"
650
+ });
651
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
652
+ }
653
+ async function tryReadTopicDoc(ctx, id, log) {
654
+ try {
655
+ return await ctx.db.get(id);
656
+ } catch (error) {
657
+ debugGraphPrimitiveFallback(log.failureLog, {
658
+ error,
659
+ [log.idLogKey]: id
660
+ });
661
+ return null;
708
662
  }
663
+ }
664
+ async function buildTopicScope(ctx, topic, source, options = {}) {
665
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
666
+ const mapped = asMappedProjectId(topic);
709
667
  return {
710
- toolName: args.runtimeToolName,
711
- packKey: args.runtimePackKey,
712
- packInstallScope: args.runtimePackInstallScope
668
+ topicId: topic._id,
669
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
670
+ tenantId: inherited.tenantId,
671
+ workspaceId: inherited.workspaceId,
672
+ source
713
673
  };
714
674
  }
715
- function assertTenantPackWorkspaceMutationAllowed(args) {
716
- if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
717
- return;
718
- }
719
- const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
720
- const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
721
- if (!targetWorkspaceId || targetLayer === "ontological") {
722
- return;
723
- }
724
- throwWorkspaceIsolationError({
725
- message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
726
- invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
727
- suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
728
- details: {
729
- mutationName: args.mutationName,
730
- toolName: args.runtime.toolName,
731
- packKey: args.runtime.packKey,
732
- targetWorkspaceId,
733
- targetNodeType: args.target.nodeType,
734
- targetLayer
735
- }
736
- });
737
- }
675
+ var optionalScopeArgs = {
676
+ projectId: v.optional(v.string()),
677
+ topicId: v.optional(v.string())
678
+ };
738
679
 
739
680
  // src/epistemicQuestions.helpers.ts
740
681
  function generateContentHash(text) {
741
682
  const content = `question:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
742
683
  let hash = 5381;
684
+ const maxSigned32Bit = 2147483647;
685
+ const uint32Size = 4294967296;
743
686
  for (let i = 0; i < content.length; i++) {
744
- hash = (hash << 5) + hash + content.charCodeAt(i);
745
- hash &= hash;
687
+ hash = Math.imul(hash, 33) + content.charCodeAt(i);
688
+ hash %= uint32Size;
689
+ if (hash > maxSigned32Bit) {
690
+ hash -= uint32Size;
691
+ }
746
692
  }
747
693
  return Math.abs(hash).toString(16).padStart(8, "0");
748
694
  }
749
695
  async function markProjectGraphDirty(ctx, projectId, topicId) {
696
+ const markCacheStaleByTopic = internal.graphAnalysisCache.markCacheStaleByTopic;
750
697
  const normalizedProjectId = typeof projectId === "string" && projectId.trim().length > 0 ? projectId : void 0;
751
698
  const normalizedTopicId = typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
752
- if (!normalizedProjectId && !normalizedTopicId) {
699
+ if (!(normalizedProjectId || normalizedTopicId)) {
753
700
  return;
754
701
  }
755
702
  if (normalizedProjectId) {
@@ -762,17 +709,17 @@ async function markProjectGraphDirty(ctx, projectId, topicId) {
762
709
  );
763
710
  }
764
711
  if (normalizedTopicId) {
765
- await ctx.scheduler.runAfter(
766
- 0,
767
- internal.graphAnalysisCache.markCacheStaleByTopic,
768
- {
769
- topicId: normalizedTopicId
770
- }
771
- );
712
+ await ctx.scheduler.runAfter(0, markCacheStaleByTopic, {
713
+ topicId: normalizedTopicId
714
+ });
715
+ }
716
+ const resolvedProjectId = normalizedTopicId ?? normalizedProjectId;
717
+ if (!resolvedProjectId) {
718
+ return;
772
719
  }
773
720
  await resolveGraphPrimitivesAppResolvers().patchProject(
774
721
  ctx,
775
- normalizedTopicId ?? normalizedProjectId,
722
+ resolvedProjectId,
776
723
  {
777
724
  lastActivityAt: Date.now()
778
725
  }
@@ -798,7 +745,7 @@ function resolveQuestionScopeId(scope) {
798
745
  return normalizeQuestionTopicId(scope.topicId) ?? scope.projectId ?? void 0;
799
746
  }
800
747
  async function resolveQuestionScopeOrNull(ctx, args) {
801
- if (!args.projectId && !args.topicId) {
748
+ if (!(args.projectId || args.topicId)) {
802
749
  return null;
803
750
  }
804
751
  try {
@@ -854,7 +801,7 @@ function flattenQuestionNode(n) {
854
801
  linkedBeliefId: meta.linkedBeliefNodeId || null,
855
802
  testType: meta.testType || "validates",
856
803
  importance: meta.importance || 5,
857
- isKeyQuestion: meta.isKeyQuestion || false,
804
+ isKeyQuestion: Boolean(meta.isKeyQuestion),
858
805
  answer: meta.answer || null,
859
806
  convictionStage: meta.convictionStage || null,
860
807
  conviction: meta.conviction ?? null,
@@ -889,7 +836,7 @@ function getQuestionStatusCandidates(node) {
889
836
  );
890
837
  }
891
838
  function isActiveQuestionNode(node) {
892
- if (INACTIVE_NODE_STATUSES.has(node.status)) {
839
+ if (typeof node.status === "string" && INACTIVE_NODE_STATUSES.has(node.status)) {
893
840
  return false;
894
841
  }
895
842
  return !getQuestionStatusCandidates(node).some(
@@ -902,12 +849,288 @@ function matchesRequestedQuestionStatus(node, requestedStatus) {
902
849
  (status) => status.toLowerCase() === normalizedStatus
903
850
  );
904
851
  }
905
- async function insertEpistemicNode(ctx, doc) {
906
- assertUuidV7Identity("epistemicNodes", doc.globalId);
907
- return ctx.db.insert("epistemicNodes", doc);
852
+ function normalizeScopeValue2(value) {
853
+ if (typeof value !== "string") {
854
+ return;
855
+ }
856
+ const normalized = value.trim();
857
+ return normalized.length > 0 ? normalized : void 0;
858
+ }
859
+ function throwWorkspaceIsolationError(args) {
860
+ const error = new Error(args.message);
861
+ error.status = 409;
862
+ error.code = "INVARIANT_VIOLATION";
863
+ error.invariantCode = args.invariantCode;
864
+ error.suggestion = args.suggestion;
865
+ error.details = args.details;
866
+ throw error;
867
+ }
868
+ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
869
+ const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
870
+ const resolved = {
871
+ tenantId: normalizeScopeValue2(node?.tenantId),
872
+ workspaceId: normalizeScopeValue2(node?.workspaceId),
873
+ epistemicLayer,
874
+ nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
875
+ };
876
+ if (!node) {
877
+ return resolved;
878
+ }
879
+ if (resolved.epistemicLayer === "ontological") {
880
+ return resolved;
881
+ }
882
+ if (resolved.tenantId || resolved.workspaceId) {
883
+ return resolved;
884
+ }
885
+ const topicId = normalizeScopeValue2(node.topicId);
886
+ if (topicId) {
887
+ const topicScope = await resolveTopicProjectScope(ctx, {
888
+ topicId
889
+ });
890
+ return {
891
+ ...resolved,
892
+ tenantId: topicScope.tenantId,
893
+ workspaceId: topicScope.workspaceId
894
+ };
895
+ }
896
+ if (node.projectId) {
897
+ const topicScope = await resolveTopicProjectScope(ctx, {
898
+ projectId: String(node.projectId)
899
+ });
900
+ return {
901
+ ...resolved,
902
+ tenantId: topicScope.tenantId,
903
+ workspaceId: topicScope.workspaceId
904
+ };
905
+ }
906
+ return resolved;
907
+ }
908
+ function resolveRuntimePackMutationContext(args) {
909
+ if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
910
+ return;
911
+ }
912
+ return {
913
+ toolName: args.runtimeToolName,
914
+ packKey: args.runtimePackKey,
915
+ packInstallScope: args.runtimePackInstallScope
916
+ };
917
+ }
918
+ function assertTenantPackWorkspaceMutationAllowed(args) {
919
+ if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
920
+ return;
921
+ }
922
+ const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
923
+ const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
924
+ if (!targetWorkspaceId || targetLayer === "ontological") {
925
+ return;
926
+ }
927
+ throwWorkspaceIsolationError({
928
+ message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
929
+ invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
930
+ suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
931
+ details: {
932
+ mutationName: args.mutationName,
933
+ toolName: args.runtime.toolName,
934
+ packKey: args.runtime.packKey,
935
+ targetWorkspaceId,
936
+ targetNodeType: args.target.nodeType,
937
+ targetLayer
938
+ }
939
+ });
908
940
  }
909
941
 
910
942
  // src/epistemicQuestions.tail.ts
943
+ var QUESTION_PRIORITY_ORDER = {
944
+ high: 0,
945
+ low: 2,
946
+ medium: 1
947
+ };
948
+ function readQuestionType(question, metadata) {
949
+ if (typeof question.questionType === "string") {
950
+ return question.questionType;
951
+ }
952
+ if (typeof metadata.questionType === "string") {
953
+ return metadata.questionType;
954
+ }
955
+ return;
956
+ }
957
+ function toRecord(value) {
958
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
959
+ return value;
960
+ }
961
+ return {};
962
+ }
963
+ function readOptionalString(value) {
964
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
965
+ }
966
+ function readStringValue(source, key) {
967
+ return readOptionalString(source[key]);
968
+ }
969
+ function readConvexId(value) {
970
+ const normalized = readOptionalString(value);
971
+ return normalized ? normalized : null;
972
+ }
973
+ function readStringArray2(value) {
974
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
975
+ }
976
+ function isEpistemicNodeDoc(value) {
977
+ return readConvexId(toRecord(value)._id) !== null;
978
+ }
979
+ function isQuestionNodeDoc(value) {
980
+ return isEpistemicNodeDoc(value) && readStringValue(toRecord(value), "nodeType") === "question";
981
+ }
982
+ function isBeliefNodeDoc(value) {
983
+ return isEpistemicNodeDoc(value) && readStringValue(toRecord(value), "nodeType") === "belief";
984
+ }
985
+ function readFinalArtifactRow(value) {
986
+ const record = toRecord(value);
987
+ const id = readConvexId(record._id);
988
+ if (!id) {
989
+ return null;
990
+ }
991
+ const row = { _id: id };
992
+ const projectId = readOptionalString(record.projectId);
993
+ if (projectId !== void 0) {
994
+ row.projectId = projectId;
995
+ }
996
+ const topicId = readOptionalString(record.topicId);
997
+ if (topicId !== void 0) {
998
+ row.topicId = topicId;
999
+ }
1000
+ return row;
1001
+ }
1002
+ function readQuestionPriority(metadata) {
1003
+ const value = metadata.priority;
1004
+ return value === "high" || value === "medium" || value === "low" ? value : "medium";
1005
+ }
1006
+ function loadQuestionNodes(ctx, questionIds) {
1007
+ return Promise.all(
1008
+ questionIds.map(async (questionId) => {
1009
+ try {
1010
+ const nodeId = readConvexId(questionId);
1011
+ return nodeId ? await ctx.db.get(nodeId) : null;
1012
+ } catch (error) {
1013
+ debugGraphPrimitiveFallback(
1014
+ "[epistemicQuestions] Failed to load original question",
1015
+ {
1016
+ error: formatGraphPrimitiveError(error),
1017
+ questionId
1018
+ }
1019
+ );
1020
+ return null;
1021
+ }
1022
+ })
1023
+ );
1024
+ }
1025
+ function questionBelongsToScope(question, scope) {
1026
+ if (scope.topicId) {
1027
+ return String(question.topicId) === String(scope.topicId) || !question.topicId && scope.projectId !== void 0 && String(question.projectId) === String(scope.projectId);
1028
+ }
1029
+ return String(question.projectId) === String(scope.projectId);
1030
+ }
1031
+ function consolidatedQuestionNodes(questions, scope, expectedCount) {
1032
+ const validQuestions = questions.filter(
1033
+ (question) => isQuestionNodeDoc(question) && questionBelongsToScope(question, scope)
1034
+ );
1035
+ if (validQuestions.length !== expectedCount) {
1036
+ throw new Error(
1037
+ "Some questions not found or do not belong to this topic scope"
1038
+ );
1039
+ }
1040
+ return validQuestions;
1041
+ }
1042
+ function chooseConsolidatedPriority(explicitPriority, questions) {
1043
+ if (explicitPriority) {
1044
+ return explicitPriority;
1045
+ }
1046
+ let bestPriority = "medium";
1047
+ let bestScore = QUESTION_PRIORITY_ORDER.low;
1048
+ for (const question of questions) {
1049
+ const priority = readQuestionPriority(toRecord(question.metadata));
1050
+ const score = QUESTION_PRIORITY_ORDER[priority];
1051
+ if (score < bestScore) {
1052
+ bestPriority = priority;
1053
+ bestScore = score;
1054
+ }
1055
+ }
1056
+ return bestPriority;
1057
+ }
1058
+ function collectLinkedBeliefIds(questions, explicitBeliefIds) {
1059
+ const linkedBeliefSet = /* @__PURE__ */ new Set();
1060
+ if (explicitBeliefIds) {
1061
+ for (const beliefId of explicitBeliefIds) {
1062
+ linkedBeliefSet.add(String(beliefId));
1063
+ }
1064
+ return linkedBeliefSet;
1065
+ }
1066
+ for (const question of questions) {
1067
+ const metadata = toRecord(question.metadata);
1068
+ const linkedBeliefNodeId = metadata.linkedBeliefNodeId;
1069
+ const linkedBeliefId = metadata.linkedBeliefId;
1070
+ if (linkedBeliefNodeId) {
1071
+ linkedBeliefSet.add(String(linkedBeliefNodeId));
1072
+ }
1073
+ if (linkedBeliefId) {
1074
+ linkedBeliefSet.add(String(linkedBeliefId));
1075
+ }
1076
+ }
1077
+ return linkedBeliefSet;
1078
+ }
1079
+ async function readConsolidatedQuestionCategory(ctx, linkedBeliefSet) {
1080
+ const firstBeliefId = Array.from(linkedBeliefSet)[0];
1081
+ if (!firstBeliefId) {
1082
+ return "other";
1083
+ }
1084
+ try {
1085
+ const beliefId = readConvexId(firstBeliefId);
1086
+ const belief = beliefId ? await ctx.db.get(beliefId) : null;
1087
+ const metadata = toRecord(belief?.metadata);
1088
+ return readStringValue(metadata, "category") ?? readStringValue(metadata, "pillar") ?? "other";
1089
+ } catch (error) {
1090
+ debugGraphPrimitiveFallback(
1091
+ "[epistemicQuestions] Failed to read first linked belief metadata",
1092
+ {
1093
+ beliefId: firstBeliefId,
1094
+ error: formatGraphPrimitiveError(error)
1095
+ }
1096
+ );
1097
+ return "other";
1098
+ }
1099
+ }
1100
+ async function archiveConsolidatedQuestions(ctx, questionIds, newNodeId, now) {
1101
+ for (const questionId of questionIds) {
1102
+ try {
1103
+ const nodeId = readConvexId(questionId);
1104
+ if (!nodeId) {
1105
+ continue;
1106
+ }
1107
+ const node = await ctx.db.get(nodeId);
1108
+ if (!node) {
1109
+ continue;
1110
+ }
1111
+ const metadata = toRecord(node.metadata);
1112
+ await ctx.db.patch(nodeId, {
1113
+ metadata: {
1114
+ ...metadata,
1115
+ archivedAt: now,
1116
+ archivedReason: `Consolidated into question ${newNodeId}`,
1117
+ consolidatedIntoId: newNodeId,
1118
+ questionStatus: "archived"
1119
+ },
1120
+ status: "archived",
1121
+ updatedAt: now
1122
+ });
1123
+ } catch (error) {
1124
+ debugGraphPrimitiveFallback(
1125
+ "[epistemicQuestions] Failed to archive linked question",
1126
+ {
1127
+ error: formatGraphPrimitiveError(error),
1128
+ questionId
1129
+ }
1130
+ );
1131
+ }
1132
+ }
1133
+ }
911
1134
  var list = query({
912
1135
  args: {
913
1136
  ...optionalScopeArgs,
@@ -929,8 +1152,9 @@ var list = query({
929
1152
  return [];
930
1153
  }
931
1154
  const nodes = await getQuestionNodesForScope(ctx, scope);
932
- const filtered = args.status ? nodes.filter(
933
- (node) => matchesRequestedQuestionStatus(node, args.status)
1155
+ const requestedStatus = args.status;
1156
+ const filtered = requestedStatus ? nodes.filter(
1157
+ (node) => matchesRequestedQuestionStatus(node, requestedStatus)
934
1158
  ) : nodes.filter(isActiveQuestionNode);
935
1159
  return filtered.map(flattenInternalQuestionNode);
936
1160
  }
@@ -961,7 +1185,10 @@ var getByPillar = query({
961
1185
  (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
962
1186
  ).collect();
963
1187
  const beliefs = allBeliefNodes.filter((n) => {
964
- const meta = n.metadata || {};
1188
+ if (!isBeliefNodeDoc(n)) {
1189
+ return false;
1190
+ }
1191
+ const meta = toRecord(n.metadata);
965
1192
  return (meta.category === args.pillar || meta.topic === args.pillar || meta.pillar === args.pillar) && n.status !== "archived";
966
1193
  });
967
1194
  if (beliefs.length === 0) {
@@ -973,37 +1200,34 @@ var getByPillar = query({
973
1200
  );
974
1201
  const questionNodes = await getQuestionNodesForScope(ctx, scope);
975
1202
  const pillarQuestions = questionNodes.filter((q) => {
976
- const meta = q.metadata || {};
977
- const linkedId = String(
978
- meta.linkedBeliefNodeId || meta.linkedBeliefId || meta.beliefId || ""
979
- );
1203
+ const meta = toRecord(q.metadata);
1204
+ const linkedId = readOptionalString(meta.linkedBeliefNodeId) ?? readOptionalString(meta.linkedBeliefId) ?? readOptionalString(meta.beliefId);
980
1205
  if (linkedId && beliefIds.has(linkedId)) {
981
1206
  return true;
982
1207
  }
983
- const relatedIds = meta.relatedBeliefIds || [];
984
- return relatedIds.some((id) => beliefIds.has(String(id)));
1208
+ return readStringArray2(meta.relatedBeliefIds).some(
1209
+ (id) => beliefIds.has(id)
1210
+ );
985
1211
  });
986
1212
  const includeAnswered = args.includeAnswered ?? true;
987
1213
  const filteredQuestions = includeAnswered ? pillarQuestions : pillarQuestions.filter((q) => {
988
- const meta = q.metadata || {};
1214
+ const meta = toRecord(q.metadata);
989
1215
  return meta.questionStatus !== "answered";
990
1216
  });
991
1217
  const enrichedQuestions = filteredQuestions.map((q) => {
992
- const meta = q.metadata || {};
993
- const linkedId = String(
994
- meta.linkedBeliefNodeId || meta.linkedBeliefId || meta.beliefId || ""
995
- );
1218
+ const meta = toRecord(q.metadata);
1219
+ const linkedId = readOptionalString(meta.linkedBeliefNodeId) ?? readOptionalString(meta.linkedBeliefId) ?? readOptionalString(meta.beliefId);
996
1220
  return {
997
1221
  _id: q._id,
998
1222
  _creationTime: q._creationTime,
999
1223
  projectId: q.projectId,
1000
1224
  question: q.canonicalText,
1001
1225
  canonicalText: q.canonicalText,
1002
- category: meta.category || "other",
1003
- priority: meta.priority || "medium",
1004
- status: meta.questionStatus || q.status,
1005
- questionType: q.questionType || meta.questionType || "general",
1006
- beliefId: linkedId || void 0,
1226
+ category: readOptionalString(meta.category) ?? "other",
1227
+ priority: readQuestionPriority(meta),
1228
+ status: readOptionalString(meta.questionStatus) ?? q.status ?? "open",
1229
+ questionType: q.questionType ?? readOptionalString(meta.questionType) ?? "general",
1230
+ beliefId: linkedId,
1007
1231
  beliefText: linkedId ? beliefMap.get(linkedId) : void 0,
1008
1232
  createdAt: q.createdAt,
1009
1233
  createdBy: q.createdBy,
@@ -1021,15 +1245,15 @@ var getByPillar = query({
1021
1245
  if (aPriority !== bPriority) {
1022
1246
  return aPriority - bPriority;
1023
1247
  }
1024
- return (b.createdAt || 0) - (a.createdAt || 0);
1248
+ return (b.createdAt ?? 0) - (a.createdAt ?? 0);
1025
1249
  });
1026
1250
  return {
1027
1251
  questions: enrichedQuestions,
1028
1252
  beliefs: beliefs.map((b) => ({
1029
1253
  _id: b._id,
1030
1254
  belief: b.canonicalText,
1031
- pillar: b.metadata?.category || b.metadata?.pillar,
1032
- confidence: b.metadata?.confidence
1255
+ pillar: readStringValue(toRecord(b.metadata), "category") || readStringValue(toRecord(b.metadata), "pillar"),
1256
+ confidence: toRecord(b.metadata).confidence
1033
1257
  }))
1034
1258
  };
1035
1259
  }
@@ -1065,88 +1289,23 @@ var consolidate = mutation({
1065
1289
  if (args.questionIds.length < 2) {
1066
1290
  throw new Error("At least 2 questions required for consolidation");
1067
1291
  }
1068
- const originalQuestions = await Promise.all(
1069
- args.questionIds.map(async (qid) => {
1070
- try {
1071
- return await ctx.db.get(qid);
1072
- } catch (error) {
1073
- debugGraphPrimitiveFallback(
1074
- "[epistemicQuestions] Failed to load original question",
1075
- {
1076
- error: formatGraphPrimitiveError(error),
1077
- questionId: qid
1078
- }
1079
- );
1080
- return null;
1081
- }
1082
- })
1292
+ const validQuestions = consolidatedQuestionNodes(
1293
+ await loadQuestionNodes(ctx, args.questionIds),
1294
+ scope,
1295
+ args.questionIds.length
1296
+ );
1297
+ const bestPriority = chooseConsolidatedPriority(
1298
+ args.priority,
1299
+ validQuestions
1300
+ );
1301
+ const linkedBeliefSet = collectLinkedBeliefIds(
1302
+ validQuestions,
1303
+ args.linkedBeliefIds
1304
+ );
1305
+ const category = await readConsolidatedQuestionCategory(
1306
+ ctx,
1307
+ linkedBeliefSet
1083
1308
  );
1084
- const validQuestions = originalQuestions.filter((q) => {
1085
- if (!q || q.nodeType !== "question") {
1086
- return false;
1087
- }
1088
- if (scope.topicId) {
1089
- return String(q.topicId) === String(scope.topicId) || !q.topicId && scope.projectId !== void 0 && String(q.projectId) === String(scope.projectId);
1090
- }
1091
- return String(q.projectId) === String(scope.projectId);
1092
- });
1093
- if (validQuestions.length !== args.questionIds.length) {
1094
- throw new Error(
1095
- "Some questions not found or do not belong to this topic scope"
1096
- );
1097
- }
1098
- const priorityOrder = {
1099
- high: 0,
1100
- medium: 1,
1101
- low: 2
1102
- };
1103
- let bestPriority = args.priority;
1104
- if (!bestPriority) {
1105
- let bestScore = 2;
1106
- for (const q of validQuestions) {
1107
- const meta = q?.metadata || {};
1108
- const score = priorityOrder[meta.priority || "medium"] ?? 1;
1109
- if (score < bestScore) {
1110
- bestScore = score;
1111
- bestPriority = meta.priority || "medium";
1112
- }
1113
- }
1114
- }
1115
- const linkedBeliefSet = /* @__PURE__ */ new Set();
1116
- if (args.linkedBeliefIds) {
1117
- for (const bid of args.linkedBeliefIds) {
1118
- linkedBeliefSet.add(String(bid));
1119
- }
1120
- } else {
1121
- for (const q of validQuestions) {
1122
- const meta = q?.metadata || {};
1123
- if (meta.linkedBeliefNodeId) {
1124
- linkedBeliefSet.add(String(meta.linkedBeliefNodeId));
1125
- }
1126
- if (meta.linkedBeliefId) {
1127
- linkedBeliefSet.add(String(meta.linkedBeliefId));
1128
- }
1129
- }
1130
- }
1131
- let category = "other";
1132
- if (linkedBeliefSet.size > 0) {
1133
- const firstBeliefId = Array.from(linkedBeliefSet)[0];
1134
- try {
1135
- const belief = await ctx.db.get(firstBeliefId);
1136
- if (belief) {
1137
- const bMeta = belief.metadata || {};
1138
- category = bMeta.category || bMeta.pillar || "other";
1139
- }
1140
- } catch (error) {
1141
- debugGraphPrimitiveFallback(
1142
- "[epistemicQuestions] Failed to read first linked belief metadata",
1143
- {
1144
- error: formatGraphPrimitiveError(error),
1145
- beliefId: firstBeliefId
1146
- }
1147
- );
1148
- }
1149
- }
1150
1309
  const now = Date.now();
1151
1310
  const globalId = generateGlobalId();
1152
1311
  const contentHash = generateContentHash(args.consolidatedQuestion);
@@ -1165,7 +1324,7 @@ var consolidate = mutation({
1165
1324
  createdBy: args.consolidatedBy,
1166
1325
  metadata: {
1167
1326
  category,
1168
- priority: bestPriority || "medium",
1327
+ priority: bestPriority,
1169
1328
  source: "consolidated",
1170
1329
  questionStatus: "open",
1171
1330
  linkedBeliefNodeId: linkedBeliefSet.size > 0 ? Array.from(linkedBeliefSet)[0] : void 0,
@@ -1177,33 +1336,7 @@ var consolidate = mutation({
1177
1336
  }
1178
1337
  }
1179
1338
  });
1180
- for (const qid of args.questionIds) {
1181
- try {
1182
- const node = await ctx.db.get(qid);
1183
- if (node) {
1184
- const meta = node.metadata || {};
1185
- await ctx.db.patch(qid, {
1186
- status: "archived",
1187
- updatedAt: now,
1188
- metadata: {
1189
- ...meta,
1190
- questionStatus: "archived",
1191
- archivedAt: now,
1192
- archivedReason: `Consolidated into question ${newNodeId}`,
1193
- consolidatedIntoId: newNodeId
1194
- }
1195
- });
1196
- }
1197
- } catch (error) {
1198
- debugGraphPrimitiveFallback(
1199
- "[epistemicQuestions] Failed to archive linked question",
1200
- {
1201
- error: formatGraphPrimitiveError(error),
1202
- questionId: qid
1203
- }
1204
- );
1205
- }
1206
- }
1339
+ await archiveConsolidatedQuestions(ctx, args.questionIds, newNodeId, now);
1207
1340
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1208
1341
  nodeId: newNodeId,
1209
1342
  operation: "upsert"
@@ -1233,7 +1366,7 @@ var deleteQuestion = mutation({
1233
1366
  returns: permissiveReturn,
1234
1367
  handler: async (ctx, args) => {
1235
1368
  const node = await ctx.db.get(args.questionId);
1236
- if (!node || node.nodeType !== "question") {
1369
+ if (!isQuestionNodeDoc(node)) {
1237
1370
  throw new Error("Question not found");
1238
1371
  }
1239
1372
  assertTenantPackWorkspaceMutationAllowed({
@@ -1242,7 +1375,7 @@ var deleteQuestion = mutation({
1242
1375
  mutationName: "epistemicQuestions.deleteQuestion"
1243
1376
  });
1244
1377
  const now = Date.now();
1245
- const meta = node.metadata || {};
1378
+ const meta = toRecord(node.metadata);
1246
1379
  await ctx.db.patch(args.questionId, {
1247
1380
  status: "archived",
1248
1381
  updatedAt: now,
@@ -1283,16 +1416,22 @@ var markAnsweredWithArtifact = mutation({
1283
1416
  returns: permissiveReturn,
1284
1417
  handler: async (ctx, args) => {
1285
1418
  const node = await ctx.db.get(args.questionId);
1286
- if (!node || node.nodeType !== "question") {
1419
+ if (!isQuestionNodeDoc(node)) {
1287
1420
  throw new Error("Question not found");
1288
1421
  }
1289
- const artifact = await resolveGraphPrimitivesAppResolvers().getFinalArtifact(ctx, args.artifactId);
1422
+ const artifact = readFinalArtifactRow(
1423
+ await resolveGraphPrimitivesAppResolvers().getFinalArtifact(
1424
+ ctx,
1425
+ args.artifactId
1426
+ )
1427
+ );
1290
1428
  if (!artifact) {
1291
1429
  throw new Error("Artifact not found");
1292
1430
  }
1431
+ const nodeTopicId = normalizeQuestionTopicId(node.topicId);
1293
1432
  const scopeId = resolveQuestionScopeId({
1294
- projectId: node.projectId,
1295
- topicId: normalizeQuestionTopicId(node.topicId)
1433
+ ...node.projectId ? { projectId: node.projectId } : {},
1434
+ ...nodeTopicId ? { topicId: nodeTopicId } : {}
1296
1435
  });
1297
1436
  if (scopeId) {
1298
1437
  const hasAccess = await checkScopeAccess(ctx, scopeId, args.userId);
@@ -1301,7 +1440,7 @@ var markAnsweredWithArtifact = mutation({
1301
1440
  }
1302
1441
  }
1303
1442
  const now = Date.now();
1304
- const meta = node.metadata || {};
1443
+ const meta = toRecord(node.metadata);
1305
1444
  await ctx.db.patch(args.questionId, {
1306
1445
  updatedAt: now,
1307
1446
  metadata: {
@@ -1352,10 +1491,10 @@ var getQuestionClusterPositions = query({
1352
1491
  }
1353
1492
  };
1354
1493
  }
1355
- const questionNodes = await ctx.db.query("epistemicNodes").withIndex(
1494
+ const questionNodes = (await ctx.db.query("epistemicNodes").withIndex(
1356
1495
  "by_topic_type",
1357
1496
  (q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
1358
- ).collect();
1497
+ ).collect()).filter(isQuestionNodeDoc);
1359
1498
  const activeQuestionNodes = questionNodes.filter(isActiveQuestionNode);
1360
1499
  const positions = {};
1361
1500
  let clusterCount = 0;
@@ -1363,8 +1502,8 @@ var getQuestionClusterPositions = query({
1363
1502
  let baselineCount = 0;
1364
1503
  for (const question of activeQuestionNodes) {
1365
1504
  const id = question._id.toString();
1366
- const meta = question.metadata || {};
1367
- const questionType = typeof question.questionType === "string" ? question.questionType : typeof meta.questionType === "string" ? meta.questionType : void 0;
1505
+ const meta = toRecord(question.metadata);
1506
+ const questionType = readQuestionType(question, meta);
1368
1507
  if (questionType === "belief_test" || meta.testType) {
1369
1508
  positions[id] = "cluster";
1370
1509
  clusterCount++;