@lucern/graph-primitives 1.0.29 → 1.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
- package/dist/beliefDecay.d.ts +1 -1
- package/dist/beliefDecay.js +448 -314
- package/dist/beliefDecay.js.map +1 -1
- package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
- package/dist/beliefEvidenceLinks.d.ts +1 -1
- package/dist/beliefEvidenceLinks.js +843 -624
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
- package/dist/beliefEvidenceLinks.operational.js +91 -18
- package/dist/beliefEvidenceLinks.operational.js.map +1 -1
- package/dist/beliefLifecycle.js.map +1 -1
- package/dist/confidencePropagationDispatch.d.ts +28 -27
- package/dist/confidencePropagationDispatch.js +157 -99
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
- package/dist/contradictions.d.ts +1 -1
- package/dist/contradictions.js +395 -225
- package/dist/contradictions.js.map +1 -1
- package/dist/convex.d.ts +65 -30
- package/dist/convex.js +7 -3
- package/dist/convex.js.map +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/edgeValidation.js +293 -85
- package/dist/edgeValidation.js.map +1 -1
- package/dist/edges/contains.d.ts +1 -1
- package/dist/edges/contains.js.map +1 -1
- package/dist/edges/contradicts.d.ts +1 -1
- package/dist/edges/contradicts.js.map +1 -1
- package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
- package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
- package/dist/edges/depends-on.js.map +1 -0
- package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
- package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
- package/dist/edges/derived-from.js.map +1 -0
- package/dist/edges/elaborates.d.ts +1 -1
- package/dist/edges/elaborates.js.map +1 -1
- package/dist/edges/index.d.ts +7 -3
- package/dist/edges/index.js +7 -4
- package/dist/edges/index.js.map +1 -1
- package/dist/edges/informs.d.ts +1 -1
- package/dist/edges/informs.js.map +1 -1
- package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
- package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
- package/dist/edges/propagation-types.js.map +1 -0
- package/dist/edges/refutes.d.ts +1 -1
- package/dist/edges/refutes.js.map +1 -1
- package/dist/edges/supports.d.ts +1 -1
- package/dist/edges/supports.js.map +1 -1
- package/dist/edges/tests.d.ts +1 -1
- package/dist/edges/tests.js.map +1 -1
- package/dist/edges/utils.d.ts +1 -1
- package/dist/edges/utils.js.map +1 -1
- package/dist/embeddingTrigger.d.ts +14 -6
- package/dist/embeddingTrigger.js +11 -14
- package/dist/embeddingTrigger.js.map +1 -1
- package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
- package/dist/entityBridge.d.ts +1 -1
- package/dist/entityBridge.js +602 -225
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityCanonicalMatch.d.ts +14 -12
- package/dist/entityCanonicalMatch.js.map +1 -1
- package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
- package/dist/entityLifecycle.d.ts +1 -1
- package/dist/entityLifecycle.js +854 -480
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
- package/dist/entityValidation.d.ts +3 -1
- package/dist/entityValidation.js +60 -8
- package/dist/entityValidation.js.map +1 -1
- package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
- package/dist/epistemicAnswers.d.ts +1 -1
- package/dist/epistemicAnswers.js +587 -545
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.d.ts +8 -8
- package/dist/epistemicBeliefs.admin.js +365 -166
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.d.ts +8 -8
- package/dist/epistemicBeliefs.backfills.js +655 -289
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.d.ts +19 -15
- package/dist/epistemicBeliefs.confidence.js +633 -386
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.d.ts +6 -6
- package/dist/epistemicBeliefs.core.js +717 -371
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.d.ts +11 -9
- package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
- package/dist/epistemicBeliefs.forkEvidence.js +8 -8
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
- package/dist/epistemicBeliefs.helpers.d.ts +68 -49
- package/dist/epistemicBeliefs.helpers.js +358 -211
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.d.ts +5 -5
- package/dist/epistemicBeliefs.internal.js +1248 -1026
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +4942 -3590
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
- package/dist/epistemicBeliefs.lifecycle.js +1138 -781
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.d.ts +7 -7
- package/dist/epistemicBeliefs.links.js +404 -267
- package/dist/epistemicBeliefs.links.js.map +1 -1
- package/dist/epistemicBeliefs.queries.d.ts +4 -4
- package/dist/epistemicBeliefs.queries.js +175 -20
- package/dist/epistemicBeliefs.queries.js.map +1 -1
- package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
- package/dist/epistemicBeliefs.topicAnchor.js +12 -5
- package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
- package/dist/epistemicContracts.d.ts +28 -3
- package/dist/epistemicContracts.evaluators.d.ts +2 -0
- package/dist/epistemicContracts.evaluators.js +1062 -576
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.d.ts +15 -32
- package/dist/epistemicContracts.handlers.js +1829 -1351
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +1131 -636
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicContracts.metrics.d.ts +2 -0
- package/dist/epistemicContracts.metrics.js +375 -158
- package/dist/epistemicContracts.metrics.js.map +1 -1
- package/dist/epistemicContracts.types.d.ts +87 -81
- package/dist/epistemicEdgeCreation.d.ts +2 -0
- package/dist/epistemicEdgeCreation.js +87 -16
- package/dist/epistemicEdgeCreation.js.map +1 -1
- package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
- package/dist/epistemicEdges.d.ts +6 -5
- package/dist/epistemicEdges.handlers.d.ts +3 -3
- package/dist/epistemicEdges.handlers.js +129 -24
- package/dist/epistemicEdges.handlers.js.map +1 -1
- package/dist/epistemicEdges.helpers.d.ts +6 -4
- package/dist/epistemicEdges.helpers.js +37 -2
- package/dist/epistemicEdges.helpers.js.map +1 -1
- package/dist/epistemicEdges.js +1966 -1202
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.d.ts +7 -7
- package/dist/epistemicEdges.mutations.js +956 -579
- package/dist/epistemicEdges.mutations.js.map +1 -1
- package/dist/epistemicEdges.queries.d.ts +16 -16
- package/dist/epistemicEdges.queries.js +639 -367
- package/dist/epistemicEdges.queries.js.map +1 -1
- package/dist/epistemicEdges.types.d.ts +10 -8
- package/dist/epistemicEvidence.d.ts +4 -1
- package/dist/epistemicEvidence.js +933 -532
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.d.ts +26 -10
- package/dist/epistemicEvidenceHelpers.js +239 -200
- package/dist/epistemicEvidenceHelpers.js.map +1 -1
- package/dist/epistemicEvidenceMutations.d.ts +8 -8
- package/dist/epistemicEvidenceMutations.js +840 -692
- package/dist/epistemicEvidenceMutations.js.map +1 -1
- package/dist/epistemicEvidenceQueries.d.ts +8 -8
- package/dist/epistemicEvidenceQueries.js +514 -238
- package/dist/epistemicEvidenceQueries.js.map +1 -1
- package/dist/epistemicHelpers.d.ts +4 -2
- package/dist/epistemicHelpers.js +308 -134
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicInsert.d.ts +16 -4
- package/dist/epistemicInsert.js +6 -3
- package/dist/epistemicInsert.js.map +1 -1
- package/dist/epistemicLayerRules.d.ts +10 -8
- package/dist/epistemicLayerRules.js +1 -5
- package/dist/epistemicLayerRules.js.map +1 -1
- package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
- package/dist/epistemicLinking.d.ts +1 -1
- package/dist/epistemicLinking.js +177 -100
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodeCreation.d.ts +2 -0
- package/dist/epistemicNodeCreation.js +203 -40
- package/dist/epistemicNodeCreation.js.map +1 -1
- package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
- package/dist/epistemicNodes.d.ts +3 -3
- package/dist/epistemicNodes.helpers.d.ts +24 -15
- package/dist/epistemicNodes.helpers.js.map +1 -1
- package/dist/epistemicNodes.internal.d.ts +6 -6
- package/dist/epistemicNodes.internal.js +389 -319
- package/dist/epistemicNodes.internal.js.map +1 -1
- package/dist/epistemicNodes.js +700 -504
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.d.ts +6 -6
- package/dist/epistemicNodes.mutations.js +560 -463
- package/dist/epistemicNodes.mutations.js.map +1 -1
- package/dist/epistemicNodes.queries.d.ts +8 -8
- package/dist/epistemicNodes.queries.js +311 -314
- package/dist/epistemicNodes.queries.js.map +1 -1
- package/dist/epistemicNodes.validators.d.ts +2 -2
- package/dist/epistemicNodes.validators.js.map +1 -1
- package/dist/epistemicQuestions.conviction.d.ts +8 -8
- package/dist/epistemicQuestions.conviction.js +665 -484
- package/dist/epistemicQuestions.conviction.js.map +1 -1
- package/dist/epistemicQuestions.create.d.ts +4 -4
- package/dist/epistemicQuestions.create.js +640 -612
- package/dist/epistemicQuestions.create.js.map +1 -1
- package/dist/epistemicQuestions.d.ts +8 -5
- package/dist/epistemicQuestions.evidence.d.ts +2 -2
- package/dist/epistemicQuestions.evidence.js +475 -383
- package/dist/epistemicQuestions.evidence.js.map +1 -1
- package/dist/epistemicQuestions.helpers.d.ts +125 -24
- package/dist/epistemicQuestions.helpers.js +240 -209
- package/dist/epistemicQuestions.helpers.js.map +1 -1
- package/dist/epistemicQuestions.js +3474 -2823
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
- package/dist/epistemicQuestions.lifecycle.js +607 -546
- package/dist/epistemicQuestions.lifecycle.js.map +1 -1
- package/dist/epistemicQuestions.queries.d.ts +12 -7
- package/dist/epistemicQuestions.queries.js +305 -244
- package/dist/epistemicQuestions.queries.js.map +1 -1
- package/dist/epistemicQuestions.sprint.d.ts +2 -2
- package/dist/epistemicQuestions.sprint.js +600 -394
- package/dist/epistemicQuestions.sprint.js.map +1 -1
- package/dist/epistemicQuestions.tail.d.ts +6 -6
- package/dist/epistemicQuestions.tail.js +572 -433
- package/dist/epistemicQuestions.tail.js.map +1 -1
- package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
- package/dist/epistemicSources.d.ts +1 -1
- package/dist/epistemicSources.js +351 -311
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.d.ts +8 -6
- package/dist/evaluators/index.js +399 -167
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
- package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
- package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
- package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
- package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
- package/dist/evaluators/shared.d.ts +2 -2
- package/dist/evaluators/shared.js +3 -1
- package/dist/evaluators/shared.js.map +1 -1
- package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
- package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
- package/dist/evaluators/test-runner-evaluator.js.map +1 -0
- package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
- package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
- package/dist/graphTypes.js +6 -2
- package/dist/graphTypes.js.map +1 -1
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +313 -93
- package/dist/helpers.js.map +1 -1
- package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
- package/dist/index.d.ts +86 -83
- package/dist/index.js +16914 -11760
- package/dist/index.js.map +1 -1
- package/dist/invariantEnforcement.d.ts +3 -3
- package/dist/invariantEnforcement.js.map +1 -1
- package/dist/logicalRoleInference.d.ts +2 -0
- package/dist/logicalRoleInference.js +1 -1
- package/dist/logicalRoleInference.js.map +1 -1
- package/dist/matcherFeedbackUtils.d.ts +2 -2
- package/dist/matcherFeedbackUtils.js.map +1 -1
- package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
- package/dist/ontology-matching.d.ts +1 -1
- package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
- package/dist/ontologyApproval.d.ts +1 -1
- package/dist/ontologyApproval.js +7 -1
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.d.ts +14 -24
- package/dist/ontologyDefinitions.js +269 -34
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyHelpers.d.ts +13 -13
- package/dist/ontologyHelpers.js.map +1 -1
- package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
- package/dist/ontologyRegistry.d.ts +1 -1
- package/dist/ontologyRegistry.js +34 -6
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
- package/dist/projectionReconciliation.d.ts +1 -1
- package/dist/projectionReconciliation.js +57 -10
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
- package/dist/projectionStaleness.d.ts +1 -1
- package/dist/projectionStaleness.js +8 -2
- package/dist/projectionStaleness.js.map +1 -1
- package/dist/proof-attestation.json +1 -1
- package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
- package/dist/questionEvidenceLinks.d.ts +1 -1
- package/dist/questionEvidenceLinks.js +564 -347
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
- package/dist/resolverTypes.d.ts +4 -2
- package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
- package/dist/resolvers.d.ts +5 -3
- package/dist/resolvers.js +121 -77
- package/dist/resolvers.js.map +1 -1
- package/dist/scopeResolverCompat.d.ts +10 -7
- package/dist/scopeResolverCompat.js +106 -123
- package/dist/scopeResolverCompat.js.map +1 -1
- package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
- package/dist/text-matching.d.ts +1 -1
- package/dist/topicOntologyResolver.d.ts +22 -21
- package/dist/topicOntologyResolver.js +54 -32
- package/dist/topicOntologyResolver.js.map +1 -1
- package/dist/topicProjectOverlay.d.ts +30 -20
- package/dist/topicProjectOverlay.js +120 -76
- package/dist/topicProjectOverlay.js.map +1 -1
- package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
- package/dist/topicScope.d.ts +3 -1
- package/dist/topicScope.js +104 -119
- package/dist/topicScope.js.map +1 -1
- package/dist/workflowBridge.d.ts +26 -15
- package/dist/workflowBridge.js +140 -144
- package/dist/workflowBridge.js.map +1 -1
- package/dist/workspaceIsolation.d.ts +14 -12
- package/dist/workspaceIsolation.js +108 -122
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +4 -4
- package/dist/edges/dependsOn.js.map +0 -1
- package/dist/edges/derivedFrom.js.map +0 -1
- package/dist/edges/propagationTypes.js.map +0 -1
- package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
- package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
- 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 {
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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)
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
404
|
-
sprintId: sprint
|
|
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.
|
|
411
|
-
function
|
|
412
|
-
const
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
504
|
+
beliefNodeIds.delete("");
|
|
505
|
+
return Array.from(beliefNodeIds);
|
|
423
506
|
}
|
|
424
|
-
function
|
|
425
|
-
|
|
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
|
|
428
|
-
|
|
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
|
-
|
|
431
|
-
|
|
432
|
-
|
|
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
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
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
|
|
471
|
-
|
|
700
|
+
function toRecord(value) {
|
|
701
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
702
|
+
return value;
|
|
703
|
+
}
|
|
704
|
+
return {};
|
|
472
705
|
}
|
|
473
|
-
function
|
|
474
|
-
|
|
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
|
|
478
|
-
const
|
|
479
|
-
return
|
|
480
|
-
|
|
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)
|
|
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
|
|
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
|
|
515
|
-
(id) => String(id)
|
|
516
|
-
)
|
|
859
|
+
toStringList(synthesisState.synthesizedBeliefIds)
|
|
517
860
|
);
|
|
518
861
|
const rawBeliefIds = new Set(
|
|
519
|
-
(synthesisState
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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)
|
|
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
|
|
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
|
|
659
|
-
|
|
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
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
)
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
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
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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) => {
|