@lucern/graph-primitives 1.0.29 → 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 +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,10 +1,14 @@
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, queryGeneric, anyApi } from 'convex/server';
3
+ import { v } from 'convex/values';
4
+ import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
5
+ import { componentsGeneric, queryGeneric } from 'convex/server';
5
6
 
6
7
  // src/epistemicQuestions.sprint.ts
7
- var api = anyApi;
8
+ var unsafeApi = unsafeConvexAnyApi(
9
+ "graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
10
+ );
11
+ var api = unsafeApi;
8
12
  componentsGeneric();
9
13
  var query = queryGeneric;
10
14
 
@@ -72,13 +76,15 @@ function asMappedProjectId(topic) {
72
76
  if (!topic) {
73
77
  return;
74
78
  }
75
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
79
+ const directLegacyProjectId = normalizeScopeValue(
80
+ topic[LEGACY_SCOPE_FIELD]
81
+ );
76
82
  if (directLegacyProjectId) {
77
83
  return directLegacyProjectId;
78
84
  }
79
85
  const metadata = topic.metadata || {};
80
86
  const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
81
- return candidate ? candidate : void 0;
87
+ return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
82
88
  }
83
89
  function normalizeScopeValue(value) {
84
90
  if (typeof value !== "string") {
@@ -103,8 +109,9 @@ function pickPrimaryTopic(candidates) {
103
109
  })[0];
104
110
  }
105
111
  async function findTopicsByScopeAlias(ctx, scopeId) {
112
+ const query2 = ctx.db.query("topics");
106
113
  try {
107
- return await ctx.db.query("topics").withIndex(
114
+ return await query2.withIndex(
108
115
  "by_graph_scope_project",
109
116
  (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
110
117
  ).collect();
@@ -116,7 +123,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
116
123
  scopeId
117
124
  }
118
125
  );
119
- const topics = await ctx.db.query("topics").collect();
126
+ const topics = await query2.collect();
120
127
  return topics.filter((topic) => {
121
128
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
122
129
  const mappedProjectId = asMappedProjectId(topic);
@@ -172,152 +179,211 @@ async function resolveInheritedWorkspaceScope(ctx, topic) {
172
179
  let current = topic;
173
180
  for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
174
181
  current = await ctx.db.get(current.parentTopicId);
175
- if (!current) break;
182
+ if (!current) {
183
+ break;
184
+ }
176
185
  if (!tenantId) {
177
186
  tenantId = normalizeScopeValue(current.tenantId);
178
187
  }
179
188
  if (!workspaceId) {
180
189
  workspaceId = normalizeScopeValue(current.workspaceId);
181
190
  }
182
- if (tenantId && workspaceId) break;
191
+ if (tenantId && workspaceId) {
192
+ break;
193
+ }
183
194
  }
184
195
  return { tenantId, workspaceId };
185
196
  }
186
197
  async function resolveTopicProjectScope(ctx, args) {
187
198
  if (args.topicId) {
188
- let topic = null;
189
- try {
190
- topic = await ctx.db.get(
191
- args.topicId
192
- );
193
- } catch (error) {
194
- debugGraphPrimitiveFallback(
195
- "[topicScope] Failed to load topic by direct id",
196
- {
197
- error,
198
- topicId: args.topicId
199
- }
200
- );
201
- }
202
- if (!topic) {
203
- topic = await tryResolveHostTopicById(ctx, String(args.topicId));
204
- }
205
- if (!topic) {
206
- topic = pickPrimaryTopic(
207
- await findTopicsByScopeAlias(ctx, String(args.topicId))
208
- ) ?? null;
209
- }
210
- if (!topic) {
211
- const nodeScope = await resolveTopicNodeScopeOrNull(
212
- ctx,
213
- String(args.topicId)
214
- );
215
- if (nodeScope) {
216
- return nodeScope;
217
- }
218
- throw new Error(`Topic not found: ${String(args.topicId)}`);
219
- }
220
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
221
- const mapped = asMappedProjectId(topic);
222
- if (mapped) {
223
- return {
224
- topicId: topic._id,
225
- projectId: mapped,
226
- tenantId: inherited.tenantId,
227
- workspaceId: inherited.workspaceId,
228
- source: "topic"
229
- };
230
- }
231
- return {
232
- topicId: topic._id,
233
- tenantId: inherited.tenantId,
234
- workspaceId: inherited.workspaceId,
235
- source: "topic"
236
- };
199
+ return await resolveScopeFromTopicId(ctx, args.topicId);
237
200
  }
238
201
  if (args.projectId) {
239
- let directTopic = null;
240
- try {
241
- directTopic = await ctx.db.get(
242
- args.projectId
243
- );
244
- } catch (error) {
245
- debugGraphPrimitiveFallback(
246
- "[topicScope] Failed to load direct project topic",
247
- {
248
- error,
249
- projectId: args.projectId
250
- }
251
- );
252
- }
253
- if (directTopic) {
254
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
255
- const mapped = asMappedProjectId(directTopic);
256
- return {
257
- topicId: directTopic._id,
258
- projectId: mapped ?? args.projectId,
259
- tenantId: inherited.tenantId,
260
- workspaceId: inherited.workspaceId,
261
- source: "topic_inferred"
262
- };
263
- }
264
- directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
265
- if (directTopic) {
266
- const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
267
- const mapped = asMappedProjectId(directTopic);
268
- return {
269
- topicId: directTopic._id,
270
- projectId: mapped ?? args.projectId,
271
- tenantId: inherited.tenantId,
272
- workspaceId: inherited.workspaceId,
273
- source: "topic_inferred"
274
- };
275
- }
276
- const topics = await findTopicsByScopeAlias(ctx, args.projectId);
277
- const primary = pickPrimaryTopic(topics);
278
- if (primary) {
279
- const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
280
- return {
281
- topicId: primary._id,
282
- projectId: args.projectId,
283
- tenantId: inherited.tenantId,
284
- workspaceId: inherited.workspaceId,
285
- source: "project_mapped_topic"
286
- };
287
- }
288
- const nodeScope = await resolveTopicNodeScopeOrNull(
289
- ctx,
290
- String(args.projectId)
291
- );
292
- if (nodeScope) {
293
- return {
294
- ...nodeScope,
295
- projectId: nodeScope.projectId ?? String(args.projectId)
296
- };
297
- }
298
- throw new Error(
299
- `Legacy project scope ${String(args.projectId)} has no mapped topic.`
300
- );
202
+ return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
301
203
  }
302
204
  throw new Error(
303
205
  "Missing scope: provide topicId (preferred) or legacy projectId alias."
304
206
  );
305
207
  }
208
+ async function resolveScopeFromTopicId(ctx, topicId) {
209
+ const topic = await resolveTopicDocFromTopicId(ctx, topicId);
210
+ if (topic) {
211
+ return await buildTopicScope(ctx, topic, "topic");
212
+ }
213
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
214
+ if (nodeScope) {
215
+ return nodeScope;
216
+ }
217
+ throw new Error(`Topic not found: ${String(topicId)}`);
218
+ }
219
+ async function resolveTopicDocFromTopicId(ctx, topicId) {
220
+ const direct = await tryReadTopicDoc(ctx, topicId, {
221
+ failureLog: "[topicScope] Failed to load topic by direct id",
222
+ idLogKey: "topicId"
223
+ });
224
+ if (direct) {
225
+ return direct;
226
+ }
227
+ const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
228
+ if (hostTopic) {
229
+ return hostTopic;
230
+ }
231
+ return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
232
+ }
233
+ async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
234
+ const directTopic = await resolveDirectLegacyProjectTopic(
235
+ ctx,
236
+ legacyProjectId
237
+ );
238
+ if (directTopic) {
239
+ return await buildTopicScope(ctx, directTopic, "topic_inferred", {
240
+ fallbackProjectId: legacyProjectId
241
+ });
242
+ }
243
+ const primary = pickPrimaryTopic(
244
+ await findTopicsByScopeAlias(ctx, legacyProjectId)
245
+ );
246
+ if (primary) {
247
+ return await buildTopicScope(ctx, primary, "project_mapped_topic", {
248
+ fallbackProjectId: legacyProjectId
249
+ });
250
+ }
251
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
252
+ if (nodeScope) {
253
+ return {
254
+ ...nodeScope,
255
+ projectId: nodeScope.projectId ?? legacyProjectId
256
+ };
257
+ }
258
+ throw new Error(
259
+ `Legacy project scope ${legacyProjectId} has no mapped topic.`
260
+ );
261
+ }
262
+ async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
263
+ const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
264
+ failureLog: "[topicScope] Failed to load direct project topic",
265
+ idLogKey: "projectId"
266
+ });
267
+ return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
268
+ }
269
+ async function tryReadTopicDoc(ctx, id, log) {
270
+ try {
271
+ return await ctx.db.get(id);
272
+ } catch (error) {
273
+ debugGraphPrimitiveFallback(log.failureLog, {
274
+ error,
275
+ [log.idLogKey]: id
276
+ });
277
+ return null;
278
+ }
279
+ }
280
+ async function buildTopicScope(ctx, topic, source, options = {}) {
281
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
282
+ const mapped = asMappedProjectId(topic);
283
+ return {
284
+ topicId: topic._id,
285
+ ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
286
+ tenantId: inherited.tenantId,
287
+ workspaceId: inherited.workspaceId,
288
+ source
289
+ };
290
+ }
306
291
  ({
307
292
  projectId: v.optional(v.string()),
308
293
  topicId: v.optional(v.string())
309
294
  });
310
295
 
296
+ // src/epistemicQuestions.helpers.ts
297
+ function dedupeQuestionNodes(nodes) {
298
+ const seen = /* @__PURE__ */ new Set();
299
+ const deduped = [];
300
+ for (const node of nodes) {
301
+ const id = String(node._id);
302
+ if (seen.has(id)) {
303
+ continue;
304
+ }
305
+ seen.add(id);
306
+ deduped.push(node);
307
+ }
308
+ return deduped;
309
+ }
310
+ function normalizeQuestionTopicId(topicId) {
311
+ return typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
312
+ }
313
+ function resolveQuestionScopeId(scope) {
314
+ return normalizeQuestionTopicId(scope.topicId) ?? scope.projectId ?? void 0;
315
+ }
316
+ async function resolveQuestionScopeOrNull(ctx, args) {
317
+ if (!(args.projectId || args.topicId)) {
318
+ return null;
319
+ }
320
+ try {
321
+ return await resolveTopicProjectScope(ctx, {
322
+ projectId: args.projectId ?? void 0,
323
+ topicId: args.topicId ?? void 0
324
+ });
325
+ } catch (error) {
326
+ debugGraphPrimitiveFallback(
327
+ "[epistemicQuestions] Failed to resolve question scope",
328
+ {
329
+ error: formatGraphPrimitiveError(error),
330
+ projectId: args.projectId,
331
+ topicId: args.topicId
332
+ }
333
+ );
334
+ return null;
335
+ }
336
+ }
337
+ async function getQuestionNodesForScope(ctx, scope, args) {
338
+ const fetchNodes = (query2) => query2.collect();
339
+ const topicNodes = await fetchNodes(
340
+ ctx.db.query("epistemicNodes").withIndex(
341
+ "by_topic_type",
342
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
343
+ )
344
+ );
345
+ return dedupeQuestionNodes(topicNodes).filter(
346
+ (node) => questionMatchesScope(node, scope)
347
+ );
348
+ }
349
+ async function getQuestionEdgesForScope(ctx, scope) {
350
+ const query2 = ctx.db.query("epistemicEdges").withIndex(
351
+ "by_topic",
352
+ (q) => q.eq("topicId", scope.topicId || scope.projectId)
353
+ );
354
+ return await query2.collect();
355
+ }
356
+ function questionMatchesScope(node, scope) {
357
+ return scope.topicId !== void 0 && node.topicId === scope.topicId || scope.projectId !== void 0 && node.projectId === scope.projectId;
358
+ }
359
+ function resolveLinkedWorktreeId(meta) {
360
+ const linkedWorktreeId = meta.linkedWorktreeId;
361
+ return typeof linkedWorktreeId === "string" && linkedWorktreeId.trim() ? linkedWorktreeId : null;
362
+ }
363
+ function questionMatchesWorkflowLink(meta, workflow) {
364
+ const linkedWorktreeId = resolveLinkedWorktreeId(meta);
365
+ return Boolean(
366
+ linkedWorktreeId && (linkedWorktreeId === workflow.worktreeId || linkedWorktreeId === workflow.sprintId)
367
+ );
368
+ }
369
+
311
370
  // src/workflowBridge.ts
312
371
  function isLegacySprintDoc(doc) {
313
372
  if (!doc || typeof doc !== "object") {
314
373
  return false;
315
374
  }
316
- if ("metadata" in doc && doc.metadata?.pairedSprintId) {
375
+ const metadata = typeof doc.metadata === "object" && doc.metadata !== null ? doc.metadata : void 0;
376
+ if (metadata?.pairedSprintId) {
317
377
  return false;
318
378
  }
319
379
  return "sprintScope" in doc || "targetPillar" in doc || "pillarThesis" in doc || "synthesisState" in doc || "projectId" in doc && !("worktreeScope" in doc);
320
380
  }
381
+ function isWorktreeDoc(doc) {
382
+ if (!doc || typeof doc !== "object") {
383
+ return false;
384
+ }
385
+ return "worktreeScope" in doc || "targetBranch" in doc || "campaign" in doc || "executionBand" in doc || "proofArtifacts" in doc;
386
+ }
321
387
  function getPairedSprintId(doc) {
322
388
  const pairedSprintId = doc?.metadata?.pairedSprintId;
323
389
  return typeof pairedSprintId === "string" && pairedSprintId.trim().length > 0 ? pairedSprintId : null;
@@ -348,7 +414,7 @@ async function findPairedWorktreeForSprint(ctx, sprint) {
348
414
  }
349
415
  const worktrees = await ctx.db.query("worktrees").withIndex("by_topicId", (q) => q.eq("topicId", topicId)).collect();
350
416
  return worktrees.find(
351
- (worktree) => String(worktree?.metadata?.pairedSprintId || "") === sprintId
417
+ (worktree) => isWorktreeDoc(worktree) && String(worktree.metadata?.pairedSprintId || "") === sprintId
352
418
  ) ?? null;
353
419
  }
354
420
  async function resolveWorkflowBridgeDoc(ctx, workflowId) {
@@ -372,116 +438,393 @@ async function resolveWorkflowBridgeDoc(ctx, workflowId) {
372
438
  return empty;
373
439
  }
374
440
  if (isLegacySprintDoc(doc)) {
375
- const worktree2 = await findPairedWorktreeForSprint(ctx, doc);
376
- return {
377
- ...empty,
378
- sprint: doc,
379
- worktree: worktree2,
380
- sprintId: typeof doc._id === "string" && doc._id.length > 0 ? doc._id : workflowId,
381
- worktreeId: worktree2 && typeof worktree2._id === "string" && worktree2._id.length > 0 ? worktree2._id : null,
382
- topicId: getStringField(worktree2, "topicId") ?? getStringField(doc, "topicId"),
383
- projectId: getStringField(doc, "projectId") ?? getStringField(worktree2, "projectId")
384
- };
441
+ return await resolveLegacySprintBridge(ctx, empty, doc, workflowId);
385
442
  }
443
+ return await resolveWorktreeBridge(ctx, empty, doc, workflowId);
444
+ }
445
+ async function resolveLegacySprintBridge(ctx, empty, sprint, workflowId) {
446
+ const worktree = await findPairedWorktreeForSprint(ctx, sprint);
447
+ return {
448
+ ...empty,
449
+ sprint,
450
+ worktree,
451
+ sprintId: getDocumentIdOrFallback(sprint, workflowId),
452
+ worktreeId: getDocumentIdOrFallback(worktree, null),
453
+ topicId: getStringField(worktree, "topicId") ?? getStringField(sprint, "topicId"),
454
+ projectId: getStringField(sprint, "projectId") ?? getStringField(worktree, "projectId")
455
+ };
456
+ }
457
+ async function resolveWorktreeBridge(ctx, empty, doc, workflowId) {
386
458
  const worktree = doc;
387
459
  const pairedSprintId = getPairedSprintId(worktree);
388
- let sprint = null;
389
- if (pairedSprintId) {
390
- try {
391
- const paired = await ctx.db.get(pairedSprintId);
392
- if (isLegacySprintDoc(paired)) {
393
- sprint = paired;
394
- }
395
- } catch {
396
- sprint = null;
397
- }
398
- }
460
+ const sprint = await readPairedSprint(ctx, pairedSprintId);
399
461
  return {
400
462
  ...empty,
401
463
  worktree,
402
464
  sprint,
403
- worktreeId: typeof worktree._id === "string" && worktree._id.length > 0 ? worktree._id : workflowId,
404
- sprintId: sprint && typeof sprint._id === "string" && sprint._id.length > 0 ? sprint._id : pairedSprintId,
465
+ worktreeId: getDocumentIdOrFallback(worktree, workflowId),
466
+ sprintId: getDocumentIdOrFallback(sprint, pairedSprintId),
405
467
  topicId: getStringField(worktree, "topicId") ?? getStringField(sprint, "topicId"),
406
468
  projectId: getStringField(sprint, "projectId") ?? getStringField(worktree, "projectId")
407
469
  };
408
470
  }
471
+ async function readPairedSprint(ctx, pairedSprintId) {
472
+ if (!pairedSprintId) {
473
+ return null;
474
+ }
475
+ try {
476
+ const paired = await ctx.db.get(pairedSprintId);
477
+ return isLegacySprintDoc(paired) ? paired : null;
478
+ } catch {
479
+ return null;
480
+ }
481
+ }
482
+ function getDocumentIdOrFallback(doc, fallback) {
483
+ return typeof doc?._id === "string" && doc._id.length > 0 ? doc._id : fallback;
484
+ }
409
485
 
410
- // src/epistemicQuestions.helpers.ts
411
- function dedupeQuestionNodes(nodes) {
412
- const seen = /* @__PURE__ */ new Set();
413
- const deduped = [];
414
- for (const node of nodes) {
415
- const id = String(node._id);
416
- if (seen.has(id)) {
417
- continue;
486
+ // src/epistemicQuestions.sprint.ts
487
+ function collectLinkedBeliefNodeIds(questionNodeId, edges, currentMeta) {
488
+ const questionId = String(questionNodeId);
489
+ const beliefNodeIds = /* @__PURE__ */ new Set();
490
+ const primaryBeliefId = readOptionalString(currentMeta.linkedBeliefNodeId);
491
+ if (primaryBeliefId) {
492
+ beliefNodeIds.add(primaryBeliefId);
493
+ }
494
+ for (const edge of edges) {
495
+ const fromNodeId = edge.fromNodeId ?? "";
496
+ const toNodeId = edge.toNodeId ?? "";
497
+ if (fromNodeId === questionId && toNodeId) {
498
+ beliefNodeIds.add(toNodeId);
499
+ }
500
+ if (toNodeId === questionId && fromNodeId) {
501
+ beliefNodeIds.add(fromNodeId);
418
502
  }
419
- seen.add(id);
420
- deduped.push(node);
421
503
  }
422
- return deduped;
504
+ beliefNodeIds.delete("");
505
+ return Array.from(beliefNodeIds);
423
506
  }
424
- function normalizeQuestionTopicId(topicId) {
425
- return typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
507
+ async function collectClusterLinkedBeliefs(ctx, linkedBeliefNodeIds, clusterBeliefIds, hypothesisIds, rawBeliefIds) {
508
+ const linkedBeliefs = await Promise.all(
509
+ linkedBeliefNodeIds.map(async (beliefNodeId) => {
510
+ const nodeId = readConvexId(beliefNodeId);
511
+ const node = nodeId ? readQuestionNodeRow(await ctx.db.get(nodeId)) : null;
512
+ if (node?.nodeType !== "belief") {
513
+ return null;
514
+ }
515
+ return {
516
+ beliefId: node._id,
517
+ beliefText: node.canonicalText ?? "",
518
+ isHypothesis: hypothesisIds.has(beliefNodeId),
519
+ isConditional: !(hypothesisIds.has(beliefNodeId) || rawBeliefIds.has(beliefNodeId)) && clusterBeliefIds.has(beliefNodeId),
520
+ isRaw: rawBeliefIds.has(beliefNodeId),
521
+ isPrimaryTarget: hypothesisIds.has(beliefNodeId)
522
+ };
523
+ })
524
+ );
525
+ return linkedBeliefs.filter(
526
+ (belief) => belief !== null
527
+ );
426
528
  }
427
- function resolveQuestionScopeId(scope) {
428
- return normalizeQuestionTopicId(scope.topicId) ?? scope.projectId ?? void 0;
529
+ async function enrichSprintClusterQuestion(ctx, question, edges, hypothesisIds, rawBeliefIds, clusterBeliefIds) {
530
+ const meta = question.metadata;
531
+ const linkedBeliefNodeIds = collectLinkedBeliefNodeIds(
532
+ question._id,
533
+ edges,
534
+ meta
535
+ );
536
+ const linkedBeliefs = await collectClusterLinkedBeliefs(
537
+ ctx,
538
+ linkedBeliefNodeIds,
539
+ clusterBeliefIds,
540
+ hypothesisIds,
541
+ rawBeliefIds
542
+ );
543
+ const questionText = question.canonicalText;
544
+ const payload = {
545
+ _id: question._id,
546
+ _creationTime: question._creationTime,
547
+ questionType: question.questionType ?? readOptionalString(meta.questionType) ?? "general",
548
+ category: readOptionalString(meta.category) ?? "other",
549
+ priority: readOptionalString(meta.priority) ?? "medium",
550
+ isKeyQuestion: typeof meta.isKeyQuestion === "boolean" ? meta.isKeyQuestion : false,
551
+ testType: readOptionalString(meta.testType) ?? "validates",
552
+ status: question.status ?? "active",
553
+ testLogic: readOptionalString(meta.testType) ?? "validates",
554
+ testRationale: readOptionalString(meta.rationale) ?? null,
555
+ beliefId: readOptionalString(meta.linkedBeliefNodeId) ?? null,
556
+ relatedBeliefIds: linkedBeliefNodeIds,
557
+ // Conviction stage fields — needed by UI to show/hide action buttons
558
+ convictionStage: readOptionalString(meta.convictionStage) ?? null,
559
+ answer: readOptionalString(meta.answer) ?? null,
560
+ conviction: readFiniteNumber(meta.conviction) ?? null,
561
+ linkedWorktreeId: resolveLinkedWorktreeId(meta),
562
+ linkedBeliefs,
563
+ metadata: question.metadata
564
+ };
565
+ if (question.projectId) {
566
+ payload.projectId = question.projectId;
567
+ }
568
+ if (question.topicId) {
569
+ payload.topicId = question.topicId;
570
+ }
571
+ if (questionText) {
572
+ payload.canonicalText = questionText;
573
+ payload.question = questionText;
574
+ }
575
+ return payload;
429
576
  }
430
- async function resolveQuestionScopeOrNull(ctx, args) {
431
- if (!args.projectId && !args.topicId) {
432
- return null;
577
+ function collectSprintBeliefIds(sprintSynthesis, workflow) {
578
+ return /* @__PURE__ */ new Set([
579
+ ...toStringList(sprintSynthesis.synthesizedBeliefIds),
580
+ ...(workflow.worktree?.targetBeliefIds || workflow.sprint?.targetBeliefIds || []).map(String)
581
+ ]);
582
+ }
583
+ function collectInConvictionQuestionBeliefIds(meta) {
584
+ const beliefIds = /* @__PURE__ */ new Set();
585
+ const relatedIds = toStringList(meta.relatedBeliefIds);
586
+ if (meta.linkedBeliefNodeId) {
587
+ beliefIds.add(String(meta.linkedBeliefNodeId));
433
588
  }
434
- try {
435
- return await resolveTopicProjectScope(ctx, {
436
- projectId: args.projectId ?? void 0,
437
- topicId: args.topicId ?? void 0
589
+ if (meta.linkedBeliefId) {
590
+ beliefIds.add(String(meta.linkedBeliefId));
591
+ }
592
+ if (meta.beliefId) {
593
+ beliefIds.add(String(meta.beliefId));
594
+ }
595
+ for (const beliefId of relatedIds) {
596
+ beliefIds.add(String(beliefId));
597
+ }
598
+ return Array.from(beliefIds);
599
+ }
600
+ async function collectQuestionEvidenceDetails(ctx, q) {
601
+ const evidenceLinks = await ctx.db.query("questionEvidenceLinks").withIndex("by_questionId", (qb) => qb.eq("questionId", q._id)).collect();
602
+ const evidenceDetails = [];
603
+ for (const rawLink of evidenceLinks) {
604
+ const link = readQuestionEvidenceLinkRow(rawLink);
605
+ if (!link) {
606
+ continue;
607
+ }
608
+ const insight = readQuestionNodeRow(await ctx.db.get(link.insightId));
609
+ evidenceDetails.push({
610
+ ...link,
611
+ insightText: getNodeText(insight),
612
+ insightSource: getInsightSource(insight)
438
613
  });
439
- } catch (error) {
440
- debugGraphPrimitiveFallback(
441
- "[epistemicQuestions] Failed to resolve question scope",
442
- {
443
- error: formatGraphPrimitiveError(error),
444
- projectId: args.projectId,
445
- topicId: args.topicId
446
- }
447
- );
448
- return null;
449
614
  }
615
+ return evidenceDetails;
450
616
  }
451
- async function getQuestionNodesForScope(ctx, scope, args) {
452
- const fetchNodes = (query2) => query2.collect();
453
- const topicNodes = await fetchNodes(
454
- ctx.db.query("epistemicNodes").withIndex(
455
- "by_topic_type",
456
- (q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
457
- )
458
- );
459
- return dedupeQuestionNodes(topicNodes).filter(
460
- (node) => questionMatchesScope(node, scope)
617
+ async function collectQuestionBeliefDetails(ctx, beliefIds) {
618
+ const beliefDetails = await Promise.all(
619
+ beliefIds.map(async (beliefId) => {
620
+ try {
621
+ const nodeId = readConvexId(beliefId);
622
+ const node = nodeId ? readQuestionNodeRow(await ctx.db.get(nodeId)) : null;
623
+ if (node && node.nodeType === "belief") {
624
+ return {
625
+ _id: node._id,
626
+ belief: node.canonicalText ?? "",
627
+ confidence: toRecord(node.metadata).confidence,
628
+ pillar: readStringValue(toRecord(node.metadata), "category"),
629
+ beliefType: node.status ?? "active",
630
+ dependsOnCount: 0,
631
+ cascadesToCount: 0,
632
+ exclusiveWithCount: 0
633
+ };
634
+ }
635
+ } catch (error) {
636
+ debugGraphPrimitiveFallback(
637
+ "[epistemicQuestions] Failed to hydrate linked belief",
638
+ {
639
+ error: formatGraphPrimitiveError(error),
640
+ beliefId
641
+ }
642
+ );
643
+ }
644
+ return null;
645
+ })
461
646
  );
647
+ return beliefDetails.filter(Boolean);
462
648
  }
463
- async function getQuestionEdgesForScope(ctx, scope) {
464
- const query2 = ctx.db.query("epistemicEdges").withIndex(
465
- "by_topic",
466
- (q) => q.eq("topicId", scope.topicId || scope.projectId)
467
- );
468
- return await query2.collect();
649
+ function buildInConvictionQuestionPayload(question, meta, evidenceWithDetails, testedBeliefs) {
650
+ const relatedBeliefIds = toStringList(meta.relatedBeliefIds);
651
+ const convictionStage = readOptionalString(meta.convictionStage) ?? "in_conviction";
652
+ const payload = {
653
+ _id: question._id,
654
+ _creationTime: question._creationTime,
655
+ category: readOptionalString(meta.category) ?? "other",
656
+ priority: readOptionalString(meta.priority) ?? "medium",
657
+ status: readOptionalString(meta.questionStatus) ?? question.status ?? "open",
658
+ questionType: question.questionType ?? readOptionalString(meta.questionType) ?? "general",
659
+ testType: readOptionalString(meta.testType),
660
+ importance: readFiniteNumber(meta.importance),
661
+ isKeyQuestion: typeof meta.isKeyQuestion === "boolean" ? meta.isKeyQuestion : false,
662
+ conviction: readFiniteNumber(meta.conviction),
663
+ convictionStage,
664
+ convictionRationale: readOptionalString(meta.convictionRationale),
665
+ convictionAdvancedAt: readFiniteNumber(meta.convictionAdvancedAt),
666
+ convictionAdvancedBy: readOptionalString(meta.convictionAdvancedBy),
667
+ convictionUpdatedAt: readFiniteNumber(meta.convictionUpdatedAt),
668
+ convictionUpdatedBy: readOptionalString(meta.convictionUpdatedBy),
669
+ answer: readOptionalString(meta.answer),
670
+ answerStatus: readOptionalString(meta.answerStatus),
671
+ answerCompleteness: readOptionalString(meta.answerCompleteness),
672
+ whatWeNeed: readOptionalString(meta.whatWeNeed),
673
+ linkedWorktreeId: resolveLinkedWorktreeId(meta) || void 0,
674
+ beliefId: readOptionalString(meta.linkedBeliefNodeId) ?? readOptionalString(meta.beliefId) ?? null,
675
+ linkedBeliefId: readOptionalString(meta.linkedBeliefNodeId) ?? readOptionalString(meta.linkedBeliefId),
676
+ relatedBeliefIds,
677
+ evidenceCount: evidenceWithDetails.length,
678
+ evidence: evidenceWithDetails,
679
+ testedBeliefs,
680
+ metadata: question.metadata
681
+ };
682
+ if (question.projectId) {
683
+ payload.projectId = question.projectId;
684
+ }
685
+ if (question.canonicalText) {
686
+ payload.question = question.canonicalText;
687
+ payload.canonicalText = question.canonicalText;
688
+ }
689
+ if (question.createdAt !== void 0) {
690
+ payload.createdAt = question.createdAt;
691
+ }
692
+ if (question.createdBy) {
693
+ payload.createdBy = question.createdBy;
694
+ }
695
+ if (question.updatedAt !== void 0) {
696
+ payload.updatedAt = question.updatedAt;
697
+ }
698
+ return payload;
469
699
  }
470
- function questionMatchesScope(node, scope) {
471
- return scope.topicId !== void 0 && node.topicId === scope.topicId || scope.projectId !== void 0 && node.projectId === scope.projectId;
700
+ function toRecord(value) {
701
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
702
+ return value;
703
+ }
704
+ return {};
472
705
  }
473
- function resolveLinkedWorktreeId(meta) {
474
- const linkedWorktreeId = meta.linkedWorktreeId;
475
- return typeof linkedWorktreeId === "string" && linkedWorktreeId.trim() ? linkedWorktreeId : null;
706
+ function readOptionalString(value) {
707
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
476
708
  }
477
- function questionMatchesWorkflowLink(meta, workflow) {
478
- const linkedWorktreeId = resolveLinkedWorktreeId(meta);
479
- return Boolean(
480
- linkedWorktreeId && (linkedWorktreeId === workflow.worktreeId || linkedWorktreeId === workflow.sprintId)
481
- );
709
+ function readConvexId(value) {
710
+ const normalized = readOptionalString(value);
711
+ return normalized ? normalized : null;
712
+ }
713
+ function readFiniteNumber(value) {
714
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
715
+ }
716
+ function readStringValue(source, key) {
717
+ const value = source[key];
718
+ return typeof value === "string" ? value : void 0;
719
+ }
720
+ function toStringList(value) {
721
+ if (!Array.isArray(value)) {
722
+ return [];
723
+ }
724
+ return value.map((entry) => readOptionalString(entry)).filter((entry) => entry !== void 0);
725
+ }
726
+ function readQuestionNodeRow(value) {
727
+ const record = toRecord(value);
728
+ const id = readConvexId(record._id);
729
+ const creationTime = readFiniteNumber(record._creationTime);
730
+ if (!(id && creationTime !== void 0)) {
731
+ return null;
732
+ }
733
+ const row = {
734
+ _id: id,
735
+ _creationTime: creationTime,
736
+ metadata: toRecord(record.metadata)
737
+ };
738
+ const optionalStrings = [
739
+ "canonicalText",
740
+ "content",
741
+ "createdBy",
742
+ "nodeType",
743
+ "projectId",
744
+ "questionType",
745
+ "sourceType",
746
+ "status",
747
+ "text",
748
+ "title",
749
+ "topicId"
750
+ ];
751
+ for (const key of optionalStrings) {
752
+ const value2 = readOptionalString(record[key]);
753
+ if (value2 !== void 0) {
754
+ row[key] = value2;
755
+ }
756
+ }
757
+ const createdAt = readFiniteNumber(record.createdAt);
758
+ if (createdAt !== void 0) {
759
+ row.createdAt = createdAt;
760
+ }
761
+ const updatedAt = readFiniteNumber(record.updatedAt);
762
+ if (updatedAt !== void 0) {
763
+ row.updatedAt = updatedAt;
764
+ }
765
+ return row;
766
+ }
767
+ function readQuestionEvidenceLinkRow(value) {
768
+ const record = toRecord(value);
769
+ const id = readConvexId(record._id);
770
+ const questionId = readConvexId(record.questionId);
771
+ const insightId = readConvexId(record.insightId);
772
+ const creationTime = readFiniteNumber(record._creationTime);
773
+ if (!(id && questionId && insightId && creationTime !== void 0)) {
774
+ return null;
775
+ }
776
+ return {
777
+ _id: id,
778
+ _creationTime: creationTime,
779
+ createdAt: readFiniteNumber(record.createdAt) ?? creationTime,
780
+ createdBy: readOptionalString(record.createdBy) ?? "unknown",
781
+ helpsAnswer: typeof record.helpsAnswer === "boolean" ? record.helpsAnswer : true,
782
+ insightId,
783
+ questionId,
784
+ rationale: readOptionalString(record.rationale) ?? "",
785
+ relevance: readFiniteNumber(record.relevance) ?? 0
786
+ };
787
+ }
788
+ function readEdgeRef(value) {
789
+ const record = toRecord(value);
790
+ const fromNodeId = readOptionalString(record.fromNodeId);
791
+ const toNodeId = readOptionalString(record.toNodeId);
792
+ if (!(fromNodeId || toNodeId)) {
793
+ return null;
794
+ }
795
+ return { fromNodeId, toNodeId };
796
+ }
797
+ function getNodeText(insight) {
798
+ if (!insight) {
799
+ return "";
800
+ }
801
+ const metadata = toRecord(insight.metadata);
802
+ const canonicalText = insight.canonicalText;
803
+ const legacyText = insight.text;
804
+ const contentText = insight.content;
805
+ const titleText = insight.title;
806
+ const snippetText = metadata.snippet;
807
+ if (typeof canonicalText === "string" && canonicalText.trim()) {
808
+ return canonicalText.trim();
809
+ }
810
+ if (typeof legacyText === "string" && legacyText.trim()) {
811
+ return legacyText.trim();
812
+ }
813
+ if (typeof contentText === "string" && contentText.trim()) {
814
+ return contentText.trim();
815
+ }
816
+ if (typeof titleText === "string" && titleText.trim()) {
817
+ return titleText.trim();
818
+ }
819
+ return typeof snippetText === "string" ? snippetText.trim() : "";
820
+ }
821
+ function getInsightSource(insight) {
822
+ if (!insight) {
823
+ return "unknown";
824
+ }
825
+ const sourceType = insight.sourceType;
826
+ return typeof sourceType === "string" && sourceType.trim().length > 0 ? sourceType : "unknown";
482
827
  }
483
-
484
- // src/epistemicQuestions.sprint.ts
485
828
  var getForSprintCluster = query({
486
829
  args: {
487
830
  sprintId: v.optional(v.string()),
@@ -491,7 +834,9 @@ var getForSprintCluster = query({
491
834
  returns: permissiveReturn,
492
835
  handler: async (ctx, args) => {
493
836
  const docId = args.sprintId || args.worktreeId;
494
- if (!docId) return [];
837
+ if (!docId) {
838
+ return [];
839
+ }
495
840
  const workflow = await resolveWorkflowBridgeDoc(ctx, docId);
496
841
  const scopeDoc = workflow.worktree ?? workflow.sprint;
497
842
  if (!scopeDoc) {
@@ -502,26 +847,22 @@ var getForSprintCluster = query({
502
847
  topicId: workflow.topicId
503
848
  });
504
849
  const scopeId = scope ? resolveQuestionScopeId(scope) : void 0;
505
- if (!scope || !scopeId) {
850
+ if (!(scope && scopeId)) {
506
851
  return [];
507
852
  }
508
853
  const hasAccess = await checkScopeAccess(ctx, scopeId, args.userId);
509
854
  if (!hasAccess) {
510
855
  return [];
511
856
  }
512
- const synthesisState = scopeDoc.synthesisState;
857
+ const synthesisState = toRecord(scopeDoc.synthesisState);
513
858
  const hypothesisIds = new Set(
514
- (synthesisState?.synthesizedBeliefIds || []).map(
515
- (id) => String(id)
516
- )
859
+ toStringList(synthesisState.synthesizedBeliefIds)
517
860
  );
518
861
  const rawBeliefIds = new Set(
519
- (synthesisState?.originalBeliefIds || []).map(
520
- (id) => String(id)
521
- )
862
+ toStringList(synthesisState.originalBeliefIds)
522
863
  );
523
864
  const clusterBeliefIds = new Set(hypothesisIds);
524
- const edges = await getQuestionEdgesForScope(ctx, scope);
865
+ const edges = (await getQuestionEdgesForScope(ctx, scope)).map(readEdgeRef).filter((edge) => edge !== null);
525
866
  for (const edge of edges) {
526
867
  const fromStr = String(edge.fromNodeId || "");
527
868
  const toStr = String(edge.toNodeId || "");
@@ -532,86 +873,37 @@ var getForSprintCluster = query({
532
873
  clusterBeliefIds.add(fromStr);
533
874
  }
534
875
  }
535
- const questionNodes = await getQuestionNodesForScope(ctx, scope);
536
- const sprintQuestionIds = new Set(
537
- (workflow.worktree?.targetQuestionIds || workflow.sprint?.targetQuestionIds || []).map((id) => String(id))
876
+ const questionNodes = (await getQuestionNodesForScope(ctx, scope)).map(readQuestionNodeRow).filter(
877
+ (question) => question?.nodeType === "question"
538
878
  );
879
+ const sprintQuestionIds = /* @__PURE__ */ new Set([
880
+ ...toStringList(workflow.worktree?.targetQuestionIds),
881
+ ...toStringList(workflow.sprint?.targetQuestionIds)
882
+ ]);
539
883
  const clusterQuestions = questionNodes.filter((q) => {
540
884
  if (sprintQuestionIds.has(String(q._id))) {
541
885
  return true;
542
886
  }
543
- const meta = q.metadata || {};
544
- const linkedId = String(meta.linkedBeliefNodeId || "");
887
+ const meta = q.metadata;
888
+ const linkedId = readOptionalString(meta.linkedBeliefNodeId);
545
889
  if (linkedId && clusterBeliefIds.has(linkedId)) {
546
890
  return true;
547
891
  }
548
892
  return edges.some(
549
- (e) => String(e.fromNodeId) === String(q._id) && clusterBeliefIds.has(String(e.toNodeId || "")) || String(e.toNodeId) === String(q._id) && clusterBeliefIds.has(String(e.fromNodeId || ""))
893
+ (e) => String(e.fromNodeId) === String(q._id) && clusterBeliefIds.has(e.toNodeId ?? "") || String(e.toNodeId) === String(q._id) && clusterBeliefIds.has(e.fromNodeId ?? "")
550
894
  );
551
895
  });
552
896
  const enrichedQuestions = await Promise.all(
553
- clusterQuestions.map(async (q) => {
554
- const meta = q.metadata || {};
555
- const linkedBeliefNodeIds = /* @__PURE__ */ new Set();
556
- const primaryBeliefId = String(meta.linkedBeliefNodeId || "");
557
- if (primaryBeliefId) {
558
- linkedBeliefNodeIds.add(primaryBeliefId);
559
- }
560
- for (const edge of edges) {
561
- if (String(edge.fromNodeId) === String(q._id)) {
562
- linkedBeliefNodeIds.add(String(edge.toNodeId || ""));
563
- }
564
- if (String(edge.toNodeId) === String(q._id)) {
565
- linkedBeliefNodeIds.add(String(edge.fromNodeId || ""));
566
- }
567
- }
568
- linkedBeliefNodeIds.delete("");
569
- const linkedBeliefs = (await Promise.all(
570
- Array.from(linkedBeliefNodeIds).map(async (nodeId) => {
571
- const node = await ctx.db.get(nodeId);
572
- if (!node || node.nodeType !== "belief") {
573
- return null;
574
- }
575
- const isHypothesis = hypothesisIds.has(nodeId);
576
- const isRaw = rawBeliefIds.has(nodeId);
577
- const isConditional = !isHypothesis && !isRaw && clusterBeliefIds.has(nodeId);
578
- return {
579
- beliefId: node._id,
580
- beliefText: node.canonicalText || "",
581
- isHypothesis,
582
- isConditional,
583
- isRaw,
584
- isPrimaryTarget: isHypothesis
585
- };
586
- })
587
- )).filter(Boolean);
588
- return {
589
- _id: q._id,
590
- _creationTime: q._creationTime,
591
- projectId: q.projectId,
592
- topicId: q.topicId,
593
- canonicalText: q.canonicalText,
594
- question: q.canonicalText,
595
- // legacy field name
596
- questionType: q.questionType || meta.questionType || "general",
597
- priority: meta.priority || "medium",
598
- isKeyQuestion: meta.isKeyQuestion || false,
599
- testType: meta.testType || "validates",
600
- category: meta.category || "other",
601
- status: q.status,
602
- linkedBeliefs,
603
- testLogic: meta.testType || "validates",
604
- testRationale: meta.rationale || null,
605
- beliefId: meta.linkedBeliefNodeId || null,
606
- relatedBeliefIds: Array.from(linkedBeliefNodeIds),
607
- // Conviction stage fields — needed by UI to show/hide action buttons
608
- convictionStage: meta.convictionStage || null,
609
- answer: meta.answer || null,
610
- conviction: meta.conviction ?? null,
611
- linkedWorktreeId: resolveLinkedWorktreeId(meta),
612
- metadata: q.metadata
613
- };
614
- })
897
+ clusterQuestions.map(
898
+ (q) => enrichSprintClusterQuestion(
899
+ ctx,
900
+ q,
901
+ edges,
902
+ hypothesisIds,
903
+ rawBeliefIds,
904
+ clusterBeliefIds
905
+ )
906
+ )
615
907
  );
616
908
  const seen = /* @__PURE__ */ new Set();
617
909
  return enrichedQuestions.filter((q) => {
@@ -632,7 +924,9 @@ var getInConviction = query({
632
924
  returns: permissiveReturn,
633
925
  handler: async (ctx, args) => {
634
926
  const docId = args.sprintId || args.worktreeId;
635
- if (!docId) return [];
927
+ if (!docId) {
928
+ return [];
929
+ }
636
930
  const workflow = await resolveWorkflowBridgeDoc(ctx, docId);
637
931
  const scopeDoc = workflow.worktree ?? workflow.sprint;
638
932
  if (!scopeDoc) {
@@ -643,26 +937,24 @@ var getInConviction = query({
643
937
  topicId: workflow.topicId
644
938
  });
645
939
  const scopeId = scope ? resolveQuestionScopeId(scope) : void 0;
646
- if (!scope || !scopeId) {
940
+ if (!(scope && scopeId)) {
647
941
  return [];
648
942
  }
649
943
  const hasAccess = await checkScopeAccess(ctx, scopeId, args.userId);
650
944
  if (!hasAccess) {
651
945
  return [];
652
946
  }
653
- const allQuestions = await getQuestionNodesForScope(ctx, scope);
947
+ const allQuestions = (await getQuestionNodesForScope(ctx, scope)).map(readQuestionNodeRow).filter(
948
+ (question) => question?.nodeType === "question"
949
+ );
654
950
  const convictionQuestions = allQuestions.filter((q) => {
655
- const meta = q.metadata || {};
951
+ const meta = q.metadata;
656
952
  return meta.convictionStage === "in_conviction" || meta.convictionStage === "scored";
657
953
  });
658
- const sprintBeliefIds = /* @__PURE__ */ new Set([
659
- ...(scopeDoc.synthesisState?.synthesizedBeliefIds || []).map(
660
- String
661
- ),
662
- ...(workflow.worktree?.targetBeliefIds || workflow.sprint?.targetBeliefIds || []).map(String)
663
- ]);
954
+ const sprintSynthesis = toRecord(scopeDoc.synthesisState);
955
+ const sprintBeliefIds = collectSprintBeliefIds(sprintSynthesis, workflow);
664
956
  const sprintQuestions = convictionQuestions.filter((q) => {
665
- const meta = q.metadata || {};
957
+ const meta = q.metadata;
666
958
  if (questionMatchesWorkflowLink(meta, workflow)) {
667
959
  return true;
668
960
  }
@@ -675,7 +967,7 @@ var getInConviction = query({
675
967
  if (meta.beliefId && sprintBeliefIds.has(String(meta.beliefId))) {
676
968
  return true;
677
969
  }
678
- const relatedIds = meta.relatedBeliefIds || [];
970
+ const relatedIds = toStringList(meta.relatedBeliefIds);
679
971
  if (relatedIds.some((id) => sprintBeliefIds.has(String(id)))) {
680
972
  return true;
681
973
  }
@@ -683,107 +975,21 @@ var getInConviction = query({
683
975
  });
684
976
  const questionsWithDetails = await Promise.all(
685
977
  sprintQuestions.map(async (q) => {
686
- const meta = q.metadata || {};
687
- const evidenceLinks = await ctx.db.query("questionEvidenceLinks").withIndex(
688
- "by_questionId",
689
- (qb) => qb.eq("questionId", q._id)
690
- ).collect();
691
- const evidenceWithDetails = await Promise.all(
692
- evidenceLinks.map(async (link) => {
693
- const insight = await ctx.db.get(link.insightId);
694
- const insightMeta = insight?.metadata || {};
695
- const canonicalText = insight?.canonicalText;
696
- const legacyText = insight?.text;
697
- const contentText = insight?.content;
698
- const titleText = insight?.title;
699
- const snippetText = insightMeta.snippet;
700
- return {
701
- ...link,
702
- insightText: typeof canonicalText === "string" && canonicalText.trim() || typeof legacyText === "string" && legacyText.trim() || typeof contentText === "string" && contentText.trim() || typeof titleText === "string" && titleText.trim() || typeof snippetText === "string" && snippetText.trim() || "",
703
- insightSource: insight?.sourceType || "unknown"
704
- };
705
- })
978
+ const meta = q.metadata;
979
+ const [evidenceWithDetails, beliefIds] = await Promise.all([
980
+ collectQuestionEvidenceDetails(ctx, q),
981
+ Promise.resolve(collectInConvictionQuestionBeliefIds(meta))
982
+ ]);
983
+ const beliefsWithDetails = await collectQuestionBeliefDetails(
984
+ ctx,
985
+ beliefIds
706
986
  );
707
- const beliefIds = [];
708
- const relatedIds = meta.relatedBeliefIds || [];
709
- if (meta.linkedBeliefNodeId) {
710
- beliefIds.push(String(meta.linkedBeliefNodeId));
711
- }
712
- if (meta.linkedBeliefId) {
713
- beliefIds.push(String(meta.linkedBeliefId));
714
- }
715
- if (meta.beliefId) {
716
- beliefIds.push(String(meta.beliefId));
717
- }
718
- for (const id of relatedIds) {
719
- if (!beliefIds.includes(String(id))) {
720
- beliefIds.push(String(id));
721
- }
722
- }
723
- const beliefsWithDetails = await Promise.all(
724
- beliefIds.map(async (beliefId) => {
725
- try {
726
- const node = await ctx.db.get(beliefId);
727
- if (node && node.nodeType === "belief") {
728
- return {
729
- _id: node._id,
730
- belief: node.canonicalText || "",
731
- confidence: node.metadata?.confidence,
732
- pillar: node.metadata?.category,
733
- beliefType: node.status,
734
- dependsOnCount: 0,
735
- cascadesToCount: 0,
736
- exclusiveWithCount: 0
737
- };
738
- }
739
- } catch (error) {
740
- debugGraphPrimitiveFallback(
741
- "[epistemicQuestions] Failed to hydrate linked belief",
742
- {
743
- error: formatGraphPrimitiveError(error),
744
- beliefId
745
- }
746
- );
747
- }
748
- return null;
749
- })
987
+ return buildInConvictionQuestionPayload(
988
+ q,
989
+ meta,
990
+ evidenceWithDetails,
991
+ beliefsWithDetails
750
992
  );
751
- return {
752
- _id: q._id,
753
- _creationTime: q._creationTime,
754
- projectId: q.projectId,
755
- question: q.canonicalText,
756
- canonicalText: q.canonicalText,
757
- category: meta.category || "other",
758
- priority: meta.priority || "medium",
759
- status: meta.questionStatus || q.status,
760
- questionType: q.questionType || meta.questionType || "general",
761
- testType: meta.testType || void 0,
762
- importance: meta.importance || void 0,
763
- isKeyQuestion: meta.isKeyQuestion || false,
764
- conviction: meta.conviction,
765
- convictionStage: meta.convictionStage,
766
- convictionRationale: meta.convictionRationale,
767
- convictionAdvancedAt: meta.convictionAdvancedAt,
768
- convictionAdvancedBy: meta.convictionAdvancedBy,
769
- convictionUpdatedAt: meta.convictionUpdatedAt,
770
- convictionUpdatedBy: meta.convictionUpdatedBy,
771
- answer: meta.answer,
772
- answerStatus: meta.answerStatus,
773
- answerCompleteness: meta.answerCompleteness,
774
- whatWeNeed: meta.whatWeNeed,
775
- linkedWorktreeId: resolveLinkedWorktreeId(meta) || void 0,
776
- beliefId: meta.linkedBeliefNodeId || meta.beliefId || null,
777
- linkedBeliefId: meta.linkedBeliefNodeId || meta.linkedBeliefId,
778
- relatedBeliefIds: relatedIds,
779
- evidenceCount: evidenceWithDetails.length,
780
- evidence: evidenceWithDetails,
781
- testedBeliefs: beliefsWithDetails.filter(Boolean),
782
- createdAt: q.createdAt,
783
- createdBy: q.createdBy,
784
- updatedAt: q.updatedAt,
785
- metadata: q.metadata
786
- };
787
993
  })
788
994
  );
789
995
  return questionsWithDetails.sort((a, b) => {