@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.
- 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,386 +1,327 @@
|
|
|
1
|
-
import { v } from 'convex/values';
|
|
2
|
-
import { componentsGeneric, anyApi, mutationGeneric, queryGeneric } from 'convex/server';
|
|
3
1
|
import { checkProjectAccess } from '@lucern/access-control/access';
|
|
4
2
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
5
|
-
import {
|
|
3
|
+
import { v } from 'convex/values';
|
|
4
|
+
import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
|
|
5
|
+
import { componentsGeneric, mutationGeneric, queryGeneric } from 'convex/server';
|
|
6
6
|
import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
|
|
7
|
+
import { generateGlobalId, assertUuidV7Identity, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
|
|
7
8
|
|
|
8
9
|
// src/beliefEvidenceLinks.ts
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
var unsafeApi = unsafeConvexAnyApi(
|
|
11
|
+
"graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
|
|
12
|
+
);
|
|
13
|
+
var api = unsafeApi;
|
|
14
|
+
componentsGeneric();
|
|
15
|
+
var internal = unsafeApi;
|
|
16
|
+
var mutation = mutationGeneric;
|
|
17
|
+
var query = queryGeneric;
|
|
18
|
+
async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
|
|
19
|
+
assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
|
|
20
|
+
const node = await ctx.db.query("epistemicNodes").withIndex(
|
|
21
|
+
"by_globalId",
|
|
22
|
+
(q) => q.eq("globalId", endpoint)
|
|
23
|
+
).first();
|
|
24
|
+
if (!node) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
|
|
27
|
+
);
|
|
20
28
|
}
|
|
21
|
-
return requested;
|
|
22
|
-
}
|
|
23
|
-
function resolveReviewedLinkStatus(requested) {
|
|
24
|
-
return requested;
|
|
25
29
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
async function insertEpistemicEdge(ctx, doc) {
|
|
31
|
+
assertUuidV7Identity("epistemicEdges", doc.globalId);
|
|
32
|
+
assertStorageEdgeVocabulary(doc.edgeType);
|
|
33
|
+
if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
|
|
34
|
+
throw new Error(
|
|
35
|
+
"edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
|
|
36
|
+
);
|
|
32
37
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
38
|
+
if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
|
|
41
|
+
);
|
|
35
42
|
}
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
|
|
44
|
+
await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
|
|
45
|
+
if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
|
|
46
|
+
assertEdgePolicyAllowed(
|
|
47
|
+
edgePolicyManifest,
|
|
48
|
+
doc.edgeType,
|
|
49
|
+
{
|
|
50
|
+
kind: "epistemic_node",
|
|
51
|
+
nodeId: doc.fromNodeId,
|
|
52
|
+
nodeType: doc.fromNodeType
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
kind: "epistemic_node",
|
|
56
|
+
nodeId: doc.toNodeId,
|
|
57
|
+
nodeType: doc.toNodeType
|
|
58
|
+
}
|
|
59
|
+
);
|
|
38
60
|
}
|
|
39
|
-
return "
|
|
61
|
+
return ctx.db.insert("epistemicEdges", doc);
|
|
40
62
|
}
|
|
41
|
-
var api = anyApi;
|
|
42
|
-
componentsGeneric();
|
|
43
|
-
var internal = anyApi;
|
|
44
|
-
var mutation = mutationGeneric;
|
|
45
|
-
var query = queryGeneric;
|
|
46
63
|
|
|
47
|
-
// src/
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
64
|
+
// src/beliefEvidenceLinks.operational.ts
|
|
65
|
+
function isRecord(value) {
|
|
66
|
+
return typeof value === "object" && value !== null;
|
|
51
67
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
console.debug(message, context ?? {});
|
|
68
|
+
function readConvexId(value) {
|
|
69
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
57
70
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
61
|
-
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
62
|
-
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
71
|
+
function readEpistemicEdgeDoc(value) {
|
|
72
|
+
if (!isRecord(value)) {
|
|
63
73
|
return null;
|
|
64
74
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
68
|
-
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
69
|
-
node = byGlobalId;
|
|
70
|
-
}
|
|
71
|
-
} catch (error) {
|
|
72
|
-
debugGraphPrimitiveFallback(
|
|
73
|
-
"[topicScope] topic-node scope lookup by globalId failed",
|
|
74
|
-
{ error, ref }
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
if (!node) {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
81
|
-
if (!scopeKey) {
|
|
75
|
+
const id = readConvexId(value._id);
|
|
76
|
+
if (!id || typeof value.edgeType !== "string" || typeof value.globalId !== "string") {
|
|
82
77
|
return null;
|
|
83
78
|
}
|
|
84
79
|
return {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
_id: id,
|
|
81
|
+
edgeType: value.edgeType,
|
|
82
|
+
globalId: value.globalId
|
|
88
83
|
};
|
|
89
84
|
}
|
|
90
|
-
function
|
|
91
|
-
if (!
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
95
|
-
if (directLegacyProjectId) {
|
|
96
|
-
return directLegacyProjectId;
|
|
97
|
-
}
|
|
98
|
-
const metadata = topic.metadata || {};
|
|
99
|
-
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
100
|
-
return candidate ? candidate : void 0;
|
|
101
|
-
}
|
|
102
|
-
function normalizeScopeValue(value) {
|
|
103
|
-
if (typeof value !== "string") {
|
|
104
|
-
return;
|
|
85
|
+
function readInsightIdArray(value) {
|
|
86
|
+
if (!Array.isArray(value)) {
|
|
87
|
+
return [];
|
|
105
88
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return [...candidates].sort((a, b) => {
|
|
111
|
-
const depthA = a.depth ?? 9999;
|
|
112
|
-
const depthB = b.depth ?? 9999;
|
|
113
|
-
if (depthA !== depthB) {
|
|
114
|
-
return depthA - depthB;
|
|
115
|
-
}
|
|
116
|
-
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
117
|
-
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
118
|
-
if (createdA !== createdB) {
|
|
119
|
-
return createdA - createdB;
|
|
120
|
-
}
|
|
121
|
-
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
122
|
-
})[0];
|
|
89
|
+
return value.flatMap((entry) => {
|
|
90
|
+
const id = readConvexId(entry);
|
|
91
|
+
return id ? [id] : [];
|
|
92
|
+
});
|
|
123
93
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
} catch (error) {
|
|
131
|
-
debugGraphPrimitiveFallback(
|
|
132
|
-
"[topicScope] Failed to resolve scope alias via index",
|
|
133
|
-
{
|
|
134
|
-
error,
|
|
135
|
-
scopeId
|
|
136
|
-
}
|
|
137
|
-
);
|
|
138
|
-
const topics = await ctx.db.query("topics").collect();
|
|
139
|
-
return topics.filter((topic) => {
|
|
140
|
-
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
141
|
-
const mappedProjectId = asMappedProjectId(topic);
|
|
142
|
-
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
143
|
-
});
|
|
94
|
+
function readInsightIdCollections(value) {
|
|
95
|
+
if (!isRecord(value)) {
|
|
96
|
+
return {
|
|
97
|
+
contradictingInsightIds: [],
|
|
98
|
+
supportingInsightIds: []
|
|
99
|
+
};
|
|
144
100
|
}
|
|
101
|
+
return {
|
|
102
|
+
contradictingInsightIds: readInsightIdArray(value.contradictingInsightIds),
|
|
103
|
+
supportingInsightIds: readInsightIdArray(value.supportingInsightIds)
|
|
104
|
+
};
|
|
145
105
|
}
|
|
146
|
-
|
|
147
|
-
if (
|
|
106
|
+
function readSpineNodeDoc(value) {
|
|
107
|
+
if (!isRecord(value)) {
|
|
148
108
|
return null;
|
|
149
109
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
id: topicId
|
|
153
|
-
}) ?? null;
|
|
154
|
-
} catch (error) {
|
|
155
|
-
debugGraphPrimitiveFallback(
|
|
156
|
-
"[topicScope] Failed to resolve topic by host query",
|
|
157
|
-
{
|
|
158
|
-
error,
|
|
159
|
-
topicId
|
|
160
|
-
}
|
|
161
|
-
);
|
|
110
|
+
const id = readConvexId(value._id);
|
|
111
|
+
if (!id || typeof value.globalId !== "string" || typeof value.nodeType !== "string") {
|
|
162
112
|
return null;
|
|
163
113
|
}
|
|
114
|
+
return {
|
|
115
|
+
_id: id,
|
|
116
|
+
globalId: value.globalId,
|
|
117
|
+
nodeType: value.nodeType
|
|
118
|
+
};
|
|
164
119
|
}
|
|
165
|
-
async function
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
"[topicScope] Failed to resolve topic by legacy scope",
|
|
176
|
-
{
|
|
177
|
-
error,
|
|
178
|
-
legacyScopeId
|
|
179
|
-
}
|
|
120
|
+
async function insertOperationalEpistemicEdge(ctx, doc) {
|
|
121
|
+
await insertEpistemicEdge(
|
|
122
|
+
ctx,
|
|
123
|
+
doc
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
function assertEvidenceImpact(args) {
|
|
127
|
+
if (!Number.isFinite(args.weight) || args.weight === 0 || args.weight < -1 || args.weight > 1) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
"Belief evidence links require explicit nonzero weight in [-1, 1]"
|
|
180
130
|
);
|
|
181
|
-
return null;
|
|
182
131
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const MAX_DEPTH = 10;
|
|
186
|
-
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
187
|
-
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
188
|
-
if (tenantId && workspaceId) {
|
|
189
|
-
return { tenantId, workspaceId };
|
|
132
|
+
if (args.relation === "supports" && args.weight < 0) {
|
|
133
|
+
throw new Error("Supporting evidence links require positive weight");
|
|
190
134
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
current = await ctx.db.get(current.parentTopicId);
|
|
194
|
-
if (!current) break;
|
|
195
|
-
if (!tenantId) {
|
|
196
|
-
tenantId = normalizeScopeValue(current.tenantId);
|
|
197
|
-
}
|
|
198
|
-
if (!workspaceId) {
|
|
199
|
-
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
200
|
-
}
|
|
201
|
-
if (tenantId && workspaceId) break;
|
|
135
|
+
if (args.relation === "contradicts" && args.weight > 0) {
|
|
136
|
+
throw new Error("Contradicting evidence links require negative weight");
|
|
202
137
|
}
|
|
203
|
-
return { tenantId, workspaceId };
|
|
204
138
|
}
|
|
205
|
-
async function
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
139
|
+
async function applyOperationalLinkEffects(ctx, args) {
|
|
140
|
+
assertEvidenceImpact({ relation: args.relation, weight: args.weight });
|
|
141
|
+
const confidence = Math.abs(args.weight);
|
|
142
|
+
const currentSupporting = args.beliefNode.supportingInsightIds ?? [];
|
|
143
|
+
const currentContradicting = args.beliefNode.contradictingInsightIds ?? [];
|
|
144
|
+
if (args.relation === "supports" && !currentSupporting.includes(args.insightId)) {
|
|
145
|
+
await ctx.db.patch(args.beliefId, {
|
|
146
|
+
supportingInsightIds: [...currentSupporting, args.insightId],
|
|
147
|
+
contradictingInsightIds: currentContradicting.filter(
|
|
148
|
+
(id) => id !== args.insightId
|
|
149
|
+
)
|
|
150
|
+
});
|
|
151
|
+
} else if (args.relation === "contradicts" && !currentContradicting.includes(args.insightId)) {
|
|
152
|
+
await ctx.db.patch(args.beliefId, {
|
|
153
|
+
contradictingInsightIds: [...currentContradicting, args.insightId],
|
|
154
|
+
supportingInsightIds: currentSupporting.filter(
|
|
155
|
+
(id) => id !== args.insightId
|
|
156
|
+
)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const beliefSpineNode = readSpineNodeDoc(await ctx.db.get(args.beliefId));
|
|
161
|
+
const evidenceSpineNode = readSpineNodeDoc(
|
|
162
|
+
await ctx.db.get(args.insightId)
|
|
163
|
+
);
|
|
164
|
+
if (beliefSpineNode?.nodeType === "belief" && evidenceSpineNode?.nodeType === "evidence") {
|
|
165
|
+
const existingEdges = (await ctx.db.query("epistemicEdges").withIndex(
|
|
166
|
+
"by_from_to",
|
|
167
|
+
(q) => q.eq("fromNodeId", evidenceSpineNode.globalId).eq("toNodeId", beliefSpineNode.globalId)
|
|
168
|
+
).collect()).map(readEpistemicEdgeDoc).filter((edge) => edge !== null);
|
|
169
|
+
for (const edge of existingEdges) {
|
|
170
|
+
if (edge.edgeType === "informs") {
|
|
171
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.deleteEdge, {
|
|
172
|
+
globalId: edge.globalId
|
|
173
|
+
});
|
|
174
|
+
await ctx.db.delete(edge._id);
|
|
218
175
|
}
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
if (!topic) {
|
|
222
|
-
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
223
|
-
}
|
|
224
|
-
if (!topic) {
|
|
225
|
-
topic = pickPrimaryTopic(
|
|
226
|
-
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
227
|
-
) ?? null;
|
|
228
|
-
}
|
|
229
|
-
if (!topic) {
|
|
230
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
231
|
-
ctx,
|
|
232
|
-
String(args.topicId)
|
|
233
|
-
);
|
|
234
|
-
if (nodeScope) {
|
|
235
|
-
return nodeScope;
|
|
236
176
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
177
|
+
const globalId = generateGlobalId();
|
|
178
|
+
const context = args.rationale || `Linked as ${args.relation}`;
|
|
179
|
+
await insertOperationalEpistemicEdge(ctx, {
|
|
180
|
+
globalId,
|
|
181
|
+
// C2-RR.4 Defect E — canonical UUIDv7 endpoints, not Convex doc ids.
|
|
182
|
+
fromNodeId: evidenceSpineNode.globalId,
|
|
183
|
+
toNodeId: beliefSpineNode.globalId,
|
|
184
|
+
sourceGlobalId: evidenceSpineNode.globalId,
|
|
185
|
+
targetGlobalId: beliefSpineNode.globalId,
|
|
186
|
+
edgeType: "informs",
|
|
187
|
+
weight: args.weight,
|
|
188
|
+
confidence,
|
|
189
|
+
context,
|
|
190
|
+
reasoningMethod: "testimonial",
|
|
191
|
+
derivationType: "evidence_sl_scoring",
|
|
192
|
+
metadata: {
|
|
193
|
+
relation: args.relation,
|
|
194
|
+
confidence,
|
|
195
|
+
impactScore: args.weight,
|
|
196
|
+
invariant: "evidence.belief_impact_required"
|
|
197
|
+
},
|
|
198
|
+
createdBy: args.createdBy,
|
|
199
|
+
createdAt: Date.now(),
|
|
200
|
+
updatedAt: Date.now(),
|
|
201
|
+
projectId: args.beliefNode.projectId,
|
|
202
|
+
topicId: args.beliefNode.topicId ? String(args.beliefNode.topicId) : void 0,
|
|
203
|
+
fromNodeType: "evidence",
|
|
204
|
+
toNodeType: "belief",
|
|
205
|
+
fromLayer: "L2",
|
|
206
|
+
toLayer: "L3"
|
|
207
|
+
});
|
|
208
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
209
|
+
globalId,
|
|
210
|
+
fromGlobalId: evidenceSpineNode.globalId,
|
|
211
|
+
toGlobalId: beliefSpineNode.globalId,
|
|
212
|
+
edgeType: "informs",
|
|
213
|
+
weight: args.weight,
|
|
214
|
+
confidence,
|
|
215
|
+
context,
|
|
216
|
+
projectId: args.beliefNode.projectId ? String(args.beliefNode.projectId) : void 0,
|
|
217
|
+
createdBy: args.createdBy,
|
|
218
|
+
fromNodeType: "evidence",
|
|
219
|
+
toNodeType: "belief",
|
|
220
|
+
fromLayer: "L2",
|
|
221
|
+
toLayer: "L3"
|
|
222
|
+
});
|
|
249
223
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
tenantId: inherited.tenantId,
|
|
253
|
-
workspaceId: inherited.workspaceId,
|
|
254
|
-
source: "topic"
|
|
255
|
-
};
|
|
224
|
+
} catch (e) {
|
|
225
|
+
console.error("[EpistemicSpine] Failed to create informs edge:", e);
|
|
256
226
|
}
|
|
257
|
-
if (args.projectId) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
284
|
-
if (directTopic) {
|
|
285
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
286
|
-
const mapped = asMappedProjectId(directTopic);
|
|
287
|
-
return {
|
|
288
|
-
topicId: directTopic._id,
|
|
289
|
-
projectId: mapped ?? args.projectId,
|
|
290
|
-
tenantId: inherited.tenantId,
|
|
291
|
-
workspaceId: inherited.workspaceId,
|
|
292
|
-
source: "topic_inferred"
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
296
|
-
const primary = pickPrimaryTopic(topics);
|
|
297
|
-
if (primary) {
|
|
298
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
299
|
-
return {
|
|
300
|
-
topicId: primary._id,
|
|
301
|
-
projectId: args.projectId,
|
|
302
|
-
tenantId: inherited.tenantId,
|
|
303
|
-
workspaceId: inherited.workspaceId,
|
|
304
|
-
source: "project_mapped_topic"
|
|
305
|
-
};
|
|
227
|
+
if (args.beliefNode.projectId) {
|
|
228
|
+
await ctx.scheduler.runAfter(0, "verificationActions:deepVerifyEvidence", {
|
|
229
|
+
insightId: args.insightId,
|
|
230
|
+
targetType: "belief",
|
|
231
|
+
targetId: args.beliefId,
|
|
232
|
+
projectId: args.beliefNode.projectId,
|
|
233
|
+
userId: args.createdBy
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async function removeOperationalLinkEffects(ctx, args) {
|
|
238
|
+
const belief = await ctx.db.get(args.beliefId);
|
|
239
|
+
if (belief) {
|
|
240
|
+
const { contradictingInsightIds, supportingInsightIds } = readInsightIdCollections(belief);
|
|
241
|
+
if (args.relation === "supports") {
|
|
242
|
+
await ctx.db.patch(args.beliefId, {
|
|
243
|
+
supportingInsightIds: supportingInsightIds.filter(
|
|
244
|
+
(id) => id !== args.insightId
|
|
245
|
+
)
|
|
246
|
+
});
|
|
247
|
+
} else {
|
|
248
|
+
await ctx.db.patch(args.beliefId, {
|
|
249
|
+
contradictingInsightIds: contradictingInsightIds.filter(
|
|
250
|
+
(id) => id !== args.insightId
|
|
251
|
+
)
|
|
252
|
+
});
|
|
306
253
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const beliefSpineNode = readSpineNodeDoc(await ctx.db.get(args.beliefId));
|
|
257
|
+
const evidenceSpineNode = readSpineNodeDoc(
|
|
258
|
+
await ctx.db.get(args.insightId)
|
|
310
259
|
);
|
|
311
|
-
if (
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
260
|
+
if (beliefSpineNode?.nodeType === "belief" && evidenceSpineNode?.nodeType === "evidence") {
|
|
261
|
+
const edges = (await ctx.db.query("epistemicEdges").withIndex(
|
|
262
|
+
"by_from_to",
|
|
263
|
+
(q) => q.eq("fromNodeId", evidenceSpineNode._id).eq("toNodeId", beliefSpineNode._id)
|
|
264
|
+
).collect()).map(readEpistemicEdgeDoc).filter((edge) => edge !== null);
|
|
265
|
+
for (const edge of edges) {
|
|
266
|
+
if (edge.edgeType === "informs") {
|
|
267
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.deleteEdge, {
|
|
268
|
+
globalId: edge.globalId
|
|
269
|
+
});
|
|
270
|
+
await ctx.db.delete(edge._id);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
316
273
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
);
|
|
274
|
+
} catch (e) {
|
|
275
|
+
console.error("[EpistemicSpine] Failed to remove informs edge:", e);
|
|
320
276
|
}
|
|
321
|
-
throw new Error(
|
|
322
|
-
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
323
|
-
);
|
|
324
277
|
}
|
|
325
|
-
var optionalScopeArgs = {
|
|
326
|
-
projectId: v.optional(v.string()),
|
|
327
|
-
topicId: v.optional(v.string())
|
|
328
|
-
};
|
|
329
278
|
|
|
330
|
-
// src/
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
279
|
+
// src/matcherFeedbackUtils.ts
|
|
280
|
+
function isOperationalLinkStatus(status) {
|
|
281
|
+
return status !== "suggested" && status !== "dismissed";
|
|
282
|
+
}
|
|
283
|
+
function mergeLinkSuggestionStatus(existing, requested) {
|
|
284
|
+
if (requested === void 0 || requested === null) {
|
|
285
|
+
return existing ?? void 0;
|
|
335
286
|
}
|
|
336
|
-
|
|
337
|
-
|
|
287
|
+
if (existing && isOperationalLinkStatus(existing) && !isOperationalLinkStatus(requested)) {
|
|
288
|
+
return existing;
|
|
289
|
+
}
|
|
290
|
+
return requested;
|
|
338
291
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
292
|
+
function resolveReviewedLinkStatus(requested) {
|
|
293
|
+
return requested;
|
|
294
|
+
}
|
|
295
|
+
function deriveMatcherReviewStatus(input) {
|
|
296
|
+
if (input.explicitReviewStatus) {
|
|
297
|
+
return input.explicitReviewStatus;
|
|
344
298
|
}
|
|
345
|
-
|
|
346
|
-
return
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
{
|
|
354
|
-
error,
|
|
355
|
-
topicId,
|
|
356
|
-
projectId
|
|
357
|
-
}
|
|
358
|
-
);
|
|
359
|
-
return null;
|
|
299
|
+
if (input.autoAccepted) {
|
|
300
|
+
return "auto_accepted";
|
|
301
|
+
}
|
|
302
|
+
if (input.linkStatus === "suggested") {
|
|
303
|
+
return "pending";
|
|
304
|
+
}
|
|
305
|
+
if (input.linkStatus === "dismissed") {
|
|
306
|
+
return "rejected";
|
|
360
307
|
}
|
|
308
|
+
return "accepted";
|
|
361
309
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
...resolved.source ? { source: resolved.source } : {}
|
|
372
|
-
};
|
|
310
|
+
|
|
311
|
+
// src/debug.ts
|
|
312
|
+
function isGraphPrimitiveDebugEnabled() {
|
|
313
|
+
const env = globalThis.process?.env;
|
|
314
|
+
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
315
|
+
}
|
|
316
|
+
function debugGraphPrimitiveFallback(message, context) {
|
|
317
|
+
if (!isGraphPrimitiveDebugEnabled()) {
|
|
318
|
+
return;
|
|
373
319
|
}
|
|
374
|
-
|
|
375
|
-
const projectId = normalizeScopeValue2(args.projectId);
|
|
376
|
-
return {
|
|
377
|
-
...topicId ? { topicId } : {},
|
|
378
|
-
...projectId ? { projectId } : {}
|
|
379
|
-
};
|
|
320
|
+
console.debug(message, context ?? {});
|
|
380
321
|
}
|
|
381
322
|
|
|
382
323
|
// src/topicProjectOverlay.ts
|
|
383
|
-
var
|
|
324
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
384
325
|
function readNonEmptyString(value) {
|
|
385
326
|
if (typeof value !== "string") {
|
|
386
327
|
return;
|
|
@@ -397,11 +338,15 @@ function readStringArray(value) {
|
|
|
397
338
|
function readMetadata(topic) {
|
|
398
339
|
return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
|
|
399
340
|
}
|
|
341
|
+
function omitMetadataKey(metadata, key) {
|
|
342
|
+
const { [key]: _omitted, ...rest } = metadata;
|
|
343
|
+
return rest;
|
|
344
|
+
}
|
|
400
345
|
function readLegacyProjectId(value) {
|
|
401
346
|
if (!value) {
|
|
402
347
|
return;
|
|
403
348
|
}
|
|
404
|
-
return readNonEmptyString(value[
|
|
349
|
+
return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
|
|
405
350
|
}
|
|
406
351
|
function coerceVisibility(value) {
|
|
407
352
|
return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
|
|
@@ -477,9 +422,12 @@ async function resolveTopicDoc(ctx, scopeId) {
|
|
|
477
422
|
);
|
|
478
423
|
}
|
|
479
424
|
try {
|
|
480
|
-
const topic = await ctx.runQuery(
|
|
481
|
-
|
|
482
|
-
|
|
425
|
+
const topic = await ctx.runQuery(
|
|
426
|
+
api.topics.getByLegacyScopeId,
|
|
427
|
+
{
|
|
428
|
+
projectId: String(scopeId)
|
|
429
|
+
}
|
|
430
|
+
);
|
|
483
431
|
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
484
432
|
return topic;
|
|
485
433
|
}
|
|
@@ -499,8 +447,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
|
499
447
|
const outwardId = idMode === "topic" ? topicId : storageProjectId;
|
|
500
448
|
const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
|
|
501
449
|
const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
|
|
502
|
-
|
|
503
|
-
|
|
450
|
+
let createdAt = 0;
|
|
451
|
+
if (typeof topic.createdAt === "number") {
|
|
452
|
+
createdAt = topic.createdAt;
|
|
453
|
+
} else if (typeof topic._creationTime === "number") {
|
|
454
|
+
createdAt = topic._creationTime;
|
|
455
|
+
}
|
|
456
|
+
let updatedAt = createdAt;
|
|
457
|
+
if (typeof topic.updatedAt === "number") {
|
|
458
|
+
updatedAt = topic.updatedAt;
|
|
459
|
+
} else if (typeof metadata.updatedAt === "number") {
|
|
460
|
+
updatedAt = metadata.updatedAt;
|
|
461
|
+
}
|
|
504
462
|
return {
|
|
505
463
|
...metadata,
|
|
506
464
|
_id: outwardId,
|
|
@@ -569,90 +527,113 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
|
569
527
|
if (!topic) {
|
|
570
528
|
return null;
|
|
571
529
|
}
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
530
|
+
const plan = buildTopicProjectOverlayPatchPlan(topic, value);
|
|
531
|
+
await applyTopicProjectOverlayPatch(ctx, topic, plan);
|
|
532
|
+
return materializeTopicProjectOverlay({
|
|
533
|
+
...topic,
|
|
534
|
+
...plan.patch,
|
|
535
|
+
metadata: plan.nextMetadata
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
function buildTopicProjectOverlayPatchPlan(topic, value) {
|
|
539
|
+
const plan = {
|
|
540
|
+
nextMetadata: { ...readMetadata(topic) },
|
|
541
|
+
patch: {},
|
|
542
|
+
topicUpdateArgs: {
|
|
543
|
+
id: String(topic._id)
|
|
544
|
+
}
|
|
576
545
|
};
|
|
577
546
|
for (const [key, rawValue] of Object.entries(value)) {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
547
|
+
applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
|
|
548
|
+
}
|
|
549
|
+
plan.patch.updatedAt = Date.now();
|
|
550
|
+
plan.patch.metadata = plan.nextMetadata;
|
|
551
|
+
plan.topicUpdateArgs.metadata = plan.nextMetadata;
|
|
552
|
+
return plan;
|
|
553
|
+
}
|
|
554
|
+
function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
|
|
555
|
+
switch (key) {
|
|
556
|
+
case "_id":
|
|
557
|
+
case "projectId":
|
|
558
|
+
case "topicId":
|
|
559
|
+
case "legacyProjectId":
|
|
560
|
+
case "storageProjectId":
|
|
561
|
+
case "updatedAt":
|
|
562
|
+
case "createdAt":
|
|
563
|
+
return;
|
|
564
|
+
case "name":
|
|
565
|
+
case "description":
|
|
566
|
+
plan.patch[key] = rawValue;
|
|
567
|
+
plan.topicUpdateArgs[key] = rawValue;
|
|
568
|
+
return;
|
|
569
|
+
case "tenantId":
|
|
570
|
+
case "workspaceId":
|
|
571
|
+
case "ownerId":
|
|
572
|
+
throw new Error(
|
|
573
|
+
`patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
|
|
574
|
+
);
|
|
575
|
+
case "status":
|
|
576
|
+
applyTopicStatusPatch(plan, rawValue);
|
|
577
|
+
return;
|
|
578
|
+
case "visibility":
|
|
579
|
+
applyTopicVisibilityPatch(plan, rawValue);
|
|
580
|
+
return;
|
|
581
|
+
case "type":
|
|
582
|
+
applyTopicProjectTypePatch(plan, rawValue);
|
|
583
|
+
return;
|
|
584
|
+
default:
|
|
585
|
+
applyTopicMetadataPatch(plan, key, rawValue);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
function applyTopicStatusPatch(plan, rawValue) {
|
|
589
|
+
const status = coerceStatus(rawValue);
|
|
590
|
+
if (status) {
|
|
591
|
+
plan.patch.status = status;
|
|
592
|
+
plan.topicUpdateArgs.status = status;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
function applyTopicVisibilityPatch(plan, rawValue) {
|
|
596
|
+
const visibility = coerceVisibility(rawValue);
|
|
597
|
+
if (visibility) {
|
|
598
|
+
plan.patch.visibility = visibility;
|
|
599
|
+
plan.topicUpdateArgs.visibility = visibility;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
function applyTopicProjectTypePatch(plan, rawValue) {
|
|
603
|
+
const projectType = readNonEmptyString(rawValue);
|
|
604
|
+
if (projectType) {
|
|
605
|
+
plan.nextMetadata.projectType = projectType;
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
|
|
609
|
+
}
|
|
610
|
+
function applyTopicMetadataPatch(plan, key, rawValue) {
|
|
611
|
+
if (rawValue === void 0) {
|
|
612
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
|
|
613
|
+
return;
|
|
631
614
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
615
|
+
plan.nextMetadata[key] = rawValue;
|
|
616
|
+
}
|
|
617
|
+
async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
|
|
635
618
|
if (typeof ctx.runMutation === "function") {
|
|
636
619
|
try {
|
|
637
|
-
await ctx.runMutation(api.topics.update, topicUpdateArgs);
|
|
620
|
+
await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
|
|
638
621
|
} catch (error) {
|
|
639
|
-
if (!
|
|
622
|
+
if (!canPatchTopicViaLocalDb(ctx, error)) {
|
|
640
623
|
throw error;
|
|
641
624
|
}
|
|
642
|
-
await ctx.db.patch(
|
|
625
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
643
626
|
}
|
|
644
627
|
} else if (ctx?.db && typeof ctx.db.patch === "function") {
|
|
645
|
-
await ctx.db.patch(
|
|
628
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
646
629
|
} else {
|
|
647
630
|
throw new Error(
|
|
648
631
|
"Cannot patch topic without component adapter (ctx.runMutation unavailable)"
|
|
649
632
|
);
|
|
650
633
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
metadata: nextMetadata
|
|
655
|
-
});
|
|
634
|
+
}
|
|
635
|
+
function canPatchTopicViaLocalDb(ctx, error) {
|
|
636
|
+
return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
|
|
656
637
|
}
|
|
657
638
|
|
|
658
639
|
// src/resolvers.ts
|
|
@@ -680,7 +661,7 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
|
|
|
680
661
|
try {
|
|
681
662
|
await patchTopicProjectOverlay(ctx, projectId, value);
|
|
682
663
|
} catch (error) {
|
|
683
|
-
if (!isAdvisoryTopicPatch(value)
|
|
664
|
+
if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
|
|
684
665
|
throw error;
|
|
685
666
|
}
|
|
686
667
|
console.warn(
|
|
@@ -713,196 +694,307 @@ function resolveGraphPrimitivesAppResolvers(_ctx) {
|
|
|
713
694
|
...resolverOverrides
|
|
714
695
|
};
|
|
715
696
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
697
|
+
var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
|
|
698
|
+
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
699
|
+
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
let node = null;
|
|
703
|
+
try {
|
|
704
|
+
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
705
|
+
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
706
|
+
node = byGlobalId;
|
|
707
|
+
}
|
|
708
|
+
} catch (error) {
|
|
709
|
+
debugGraphPrimitiveFallback(
|
|
710
|
+
"[topicScope] topic-node scope lookup by globalId failed",
|
|
711
|
+
{ error, ref }
|
|
722
712
|
);
|
|
723
713
|
}
|
|
714
|
+
if (!node) {
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
718
|
+
if (!scopeKey) {
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
return {
|
|
722
|
+
topicId: scopeKey,
|
|
723
|
+
projectId: asMappedProjectId(node),
|
|
724
|
+
source: "topic_node"
|
|
725
|
+
};
|
|
724
726
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
|
|
729
|
-
throw new Error(
|
|
730
|
-
"edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
|
|
731
|
-
);
|
|
727
|
+
function asMappedProjectId(topic) {
|
|
728
|
+
if (!topic) {
|
|
729
|
+
return;
|
|
732
730
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
731
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
732
|
+
topic[LEGACY_SCOPE_FIELD2]
|
|
733
|
+
);
|
|
734
|
+
if (directLegacyProjectId) {
|
|
735
|
+
return directLegacyProjectId;
|
|
736
|
+
}
|
|
737
|
+
const metadata = topic.metadata || {};
|
|
738
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
739
|
+
return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
|
|
740
|
+
}
|
|
741
|
+
function normalizeScopeValue(value) {
|
|
742
|
+
if (typeof value !== "string") {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
const normalized = value.trim();
|
|
746
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
747
|
+
}
|
|
748
|
+
function pickPrimaryTopic(candidates) {
|
|
749
|
+
return [...candidates].sort((a, b) => {
|
|
750
|
+
const depthA = a.depth ?? 9999;
|
|
751
|
+
const depthB = b.depth ?? 9999;
|
|
752
|
+
if (depthA !== depthB) {
|
|
753
|
+
return depthA - depthB;
|
|
754
|
+
}
|
|
755
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
756
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
757
|
+
if (createdA !== createdB) {
|
|
758
|
+
return createdA - createdB;
|
|
759
|
+
}
|
|
760
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
761
|
+
})[0];
|
|
762
|
+
}
|
|
763
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
764
|
+
const query2 = ctx.db.query("topics");
|
|
765
|
+
try {
|
|
766
|
+
return await query2.withIndex(
|
|
767
|
+
"by_graph_scope_project",
|
|
768
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
|
|
769
|
+
).collect();
|
|
770
|
+
} catch (error) {
|
|
771
|
+
debugGraphPrimitiveFallback(
|
|
772
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
773
|
+
{
|
|
774
|
+
error,
|
|
775
|
+
scopeId
|
|
776
|
+
}
|
|
736
777
|
);
|
|
778
|
+
const topics = await query2.collect();
|
|
779
|
+
return topics.filter((topic) => {
|
|
780
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
781
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
782
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
783
|
+
});
|
|
737
784
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
if (
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
785
|
+
}
|
|
786
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
787
|
+
if (typeof ctx.runQuery !== "function") {
|
|
788
|
+
return null;
|
|
789
|
+
}
|
|
790
|
+
try {
|
|
791
|
+
return await ctx.runQuery(api.topics.get, {
|
|
792
|
+
id: topicId
|
|
793
|
+
}) ?? null;
|
|
794
|
+
} catch (error) {
|
|
795
|
+
debugGraphPrimitiveFallback(
|
|
796
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
744
797
|
{
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
798
|
+
error,
|
|
799
|
+
topicId
|
|
800
|
+
}
|
|
801
|
+
);
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
806
|
+
if (typeof ctx.runQuery !== "function") {
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
try {
|
|
810
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
811
|
+
projectId: legacyScopeId
|
|
812
|
+
}) ?? null;
|
|
813
|
+
} catch (error) {
|
|
814
|
+
debugGraphPrimitiveFallback(
|
|
815
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
749
816
|
{
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
nodeType: doc.toNodeType
|
|
817
|
+
error,
|
|
818
|
+
legacyScopeId
|
|
753
819
|
}
|
|
754
820
|
);
|
|
821
|
+
return null;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
825
|
+
const MAX_DEPTH = 10;
|
|
826
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
827
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
828
|
+
if (tenantId && workspaceId) {
|
|
829
|
+
return { tenantId, workspaceId };
|
|
830
|
+
}
|
|
831
|
+
let current = topic;
|
|
832
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
833
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
834
|
+
if (!current) {
|
|
835
|
+
break;
|
|
836
|
+
}
|
|
837
|
+
if (!tenantId) {
|
|
838
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
839
|
+
}
|
|
840
|
+
if (!workspaceId) {
|
|
841
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
842
|
+
}
|
|
843
|
+
if (tenantId && workspaceId) {
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
755
846
|
}
|
|
756
|
-
return
|
|
847
|
+
return { tenantId, workspaceId };
|
|
757
848
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
if (!Number.isFinite(args.weight) || args.weight === 0 || args.weight < -1 || args.weight > 1) {
|
|
762
|
-
throw new Error("Belief evidence links require explicit nonzero weight in [-1, 1]");
|
|
849
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
850
|
+
if (args.topicId) {
|
|
851
|
+
return await resolveScopeFromTopicId(ctx, args.topicId);
|
|
763
852
|
}
|
|
764
|
-
if (args.
|
|
765
|
-
|
|
853
|
+
if (args.projectId) {
|
|
854
|
+
return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
|
|
766
855
|
}
|
|
767
|
-
|
|
768
|
-
|
|
856
|
+
throw new Error(
|
|
857
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
861
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
862
|
+
if (topic) {
|
|
863
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
769
864
|
}
|
|
865
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
|
|
866
|
+
if (nodeScope) {
|
|
867
|
+
return nodeScope;
|
|
868
|
+
}
|
|
869
|
+
throw new Error(`Topic not found: ${String(topicId)}`);
|
|
770
870
|
}
|
|
771
|
-
async function
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
if (
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
871
|
+
async function resolveTopicDocFromTopicId(ctx, topicId) {
|
|
872
|
+
const direct = await tryReadTopicDoc(ctx, topicId, {
|
|
873
|
+
failureLog: "[topicScope] Failed to load topic by direct id",
|
|
874
|
+
idLogKey: "topicId"
|
|
875
|
+
});
|
|
876
|
+
if (direct) {
|
|
877
|
+
return direct;
|
|
878
|
+
}
|
|
879
|
+
const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
|
|
880
|
+
if (hostTopic) {
|
|
881
|
+
return hostTopic;
|
|
882
|
+
}
|
|
883
|
+
return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
|
|
884
|
+
}
|
|
885
|
+
async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
|
|
886
|
+
const directTopic = await resolveDirectLegacyProjectTopic(
|
|
887
|
+
ctx,
|
|
888
|
+
legacyProjectId
|
|
889
|
+
);
|
|
890
|
+
if (directTopic) {
|
|
891
|
+
return await buildTopicScope(ctx, directTopic, "topic_inferred", {
|
|
892
|
+
fallbackProjectId: legacyProjectId
|
|
782
893
|
});
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
894
|
+
}
|
|
895
|
+
const primary = pickPrimaryTopic(
|
|
896
|
+
await findTopicsByScopeAlias(ctx, legacyProjectId)
|
|
897
|
+
);
|
|
898
|
+
if (primary) {
|
|
899
|
+
return await buildTopicScope(ctx, primary, "project_mapped_topic", {
|
|
900
|
+
fallbackProjectId: legacyProjectId
|
|
789
901
|
});
|
|
790
902
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
(q) => q.eq("fromNodeId", evidenceSpineNode.globalId).eq("toNodeId", beliefSpineNode.globalId)
|
|
798
|
-
).collect();
|
|
799
|
-
for (const edge of existingEdges) {
|
|
800
|
-
if (edge.edgeType === "informs") {
|
|
801
|
-
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.deleteEdge, {
|
|
802
|
-
globalId: edge.globalId
|
|
803
|
-
});
|
|
804
|
-
await ctx.db.delete(edge._id);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
const globalId = generateGlobalId();
|
|
808
|
-
const context = args.rationale || `Linked as ${args.relation}`;
|
|
809
|
-
await insertEpistemicEdge(ctx, {
|
|
810
|
-
globalId,
|
|
811
|
-
// C2-RR.4 Defect E — canonical UUIDv7 endpoints, not Convex doc ids.
|
|
812
|
-
fromNodeId: evidenceSpineNode.globalId,
|
|
813
|
-
toNodeId: beliefSpineNode.globalId,
|
|
814
|
-
sourceGlobalId: evidenceSpineNode.globalId,
|
|
815
|
-
targetGlobalId: beliefSpineNode.globalId,
|
|
816
|
-
edgeType: "informs",
|
|
817
|
-
weight: args.weight,
|
|
818
|
-
confidence,
|
|
819
|
-
context,
|
|
820
|
-
reasoningMethod: "testimonial",
|
|
821
|
-
derivationType: "evidence_sl_scoring",
|
|
822
|
-
metadata: {
|
|
823
|
-
relation: args.relation,
|
|
824
|
-
confidence,
|
|
825
|
-
impactScore: args.weight,
|
|
826
|
-
invariant: "evidence.belief_impact_required"
|
|
827
|
-
},
|
|
828
|
-
createdBy: args.createdBy,
|
|
829
|
-
createdAt: Date.now(),
|
|
830
|
-
updatedAt: Date.now(),
|
|
831
|
-
projectId: args.beliefNode.projectId,
|
|
832
|
-
topicId: args.beliefNode.topicId ? String(args.beliefNode.topicId) : void 0,
|
|
833
|
-
fromNodeType: "evidence",
|
|
834
|
-
toNodeType: "belief",
|
|
835
|
-
fromLayer: "L2",
|
|
836
|
-
toLayer: "L3"
|
|
837
|
-
});
|
|
838
|
-
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
839
|
-
globalId,
|
|
840
|
-
fromGlobalId: evidenceSpineNode.globalId,
|
|
841
|
-
toGlobalId: beliefSpineNode.globalId,
|
|
842
|
-
edgeType: "informs",
|
|
843
|
-
weight: args.weight,
|
|
844
|
-
confidence,
|
|
845
|
-
context,
|
|
846
|
-
projectId: args.beliefNode.projectId ? String(args.beliefNode.projectId) : void 0,
|
|
847
|
-
createdBy: args.createdBy,
|
|
848
|
-
fromNodeType: "evidence",
|
|
849
|
-
toNodeType: "belief",
|
|
850
|
-
fromLayer: "L2",
|
|
851
|
-
toLayer: "L3"
|
|
852
|
-
});
|
|
853
|
-
}
|
|
854
|
-
} catch (e) {
|
|
855
|
-
console.error("[EpistemicSpine] Failed to create informs edge:", e);
|
|
903
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
|
|
904
|
+
if (nodeScope) {
|
|
905
|
+
return {
|
|
906
|
+
...nodeScope,
|
|
907
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
908
|
+
};
|
|
856
909
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
910
|
+
throw new Error(
|
|
911
|
+
`Legacy project scope ${legacyProjectId} has no mapped topic.`
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
|
|
915
|
+
const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
|
|
916
|
+
failureLog: "[topicScope] Failed to load direct project topic",
|
|
917
|
+
idLogKey: "projectId"
|
|
918
|
+
});
|
|
919
|
+
return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
|
|
920
|
+
}
|
|
921
|
+
async function tryReadTopicDoc(ctx, id, log) {
|
|
922
|
+
try {
|
|
923
|
+
return await ctx.db.get(id);
|
|
924
|
+
} catch (error) {
|
|
925
|
+
debugGraphPrimitiveFallback(log.failureLog, {
|
|
926
|
+
error,
|
|
927
|
+
[log.idLogKey]: id
|
|
864
928
|
});
|
|
929
|
+
return null;
|
|
865
930
|
}
|
|
866
931
|
}
|
|
867
|
-
async function
|
|
868
|
-
const
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
932
|
+
async function buildTopicScope(ctx, topic, source, options = {}) {
|
|
933
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
934
|
+
const mapped = asMappedProjectId(topic);
|
|
935
|
+
return {
|
|
936
|
+
topicId: topic._id,
|
|
937
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
938
|
+
tenantId: inherited.tenantId,
|
|
939
|
+
workspaceId: inherited.workspaceId,
|
|
940
|
+
source
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
var optionalScopeArgs = {
|
|
944
|
+
projectId: v.optional(v.string()),
|
|
945
|
+
topicId: v.optional(v.string())
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
// src/scopeResolverCompat.ts
|
|
949
|
+
var scopeArgs = optionalScopeArgs;
|
|
950
|
+
function normalizeScopeValue2(value) {
|
|
951
|
+
if (typeof value !== "string") {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
const normalized = value.trim();
|
|
955
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
956
|
+
}
|
|
957
|
+
async function resolveScope(ctx, args) {
|
|
958
|
+
const topicId = normalizeScopeValue2(args.topicId);
|
|
959
|
+
const projectId = normalizeScopeValue2(args.projectId);
|
|
960
|
+
if (!(topicId || projectId)) {
|
|
961
|
+
return null;
|
|
885
962
|
}
|
|
886
963
|
try {
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
});
|
|
899
|
-
await ctx.db.delete(edge._id);
|
|
900
|
-
}
|
|
964
|
+
return await resolveTopicProjectScope(ctx, {
|
|
965
|
+
topicId,
|
|
966
|
+
projectId
|
|
967
|
+
});
|
|
968
|
+
} catch (error) {
|
|
969
|
+
debugGraphPrimitiveFallback(
|
|
970
|
+
"[scopeResolverCompat] Failed to resolve scope",
|
|
971
|
+
{
|
|
972
|
+
error,
|
|
973
|
+
topicId,
|
|
974
|
+
projectId
|
|
901
975
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
976
|
+
);
|
|
977
|
+
return null;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
async function resolveScopeSoft(ctx, args) {
|
|
981
|
+
const resolved = await resolveScope(ctx, args);
|
|
982
|
+
if (resolved) {
|
|
983
|
+
const topicId2 = normalizeScopeValue2(resolved.topicId);
|
|
984
|
+
return {
|
|
985
|
+
...topicId2 ? { topicId: topicId2 } : {},
|
|
986
|
+
...resolved.projectId ? { projectId: resolved.projectId } : {},
|
|
987
|
+
...resolved.tenantId ? { tenantId: resolved.tenantId } : {},
|
|
988
|
+
...resolved.workspaceId ? { workspaceId: resolved.workspaceId } : {},
|
|
989
|
+
...resolved.source ? { source: resolved.source } : {}
|
|
990
|
+
};
|
|
905
991
|
}
|
|
992
|
+
const topicId = normalizeScopeValue2(args.topicId);
|
|
993
|
+
const projectId = normalizeScopeValue2(args.projectId);
|
|
994
|
+
return {
|
|
995
|
+
...topicId ? { topicId } : {},
|
|
996
|
+
...projectId ? { projectId } : {}
|
|
997
|
+
};
|
|
906
998
|
}
|
|
907
999
|
|
|
908
1000
|
// src/beliefEvidenceLinks.ts
|
|
@@ -931,6 +1023,101 @@ var matcherMetadataValidator = v.object({
|
|
|
931
1023
|
signalSnapshot: v.optional(v.any()),
|
|
932
1024
|
outcomeMetadata: v.optional(v.any())
|
|
933
1025
|
});
|
|
1026
|
+
function isRecord2(value) {
|
|
1027
|
+
return typeof value === "object" && value !== null;
|
|
1028
|
+
}
|
|
1029
|
+
function readConvexId2(value) {
|
|
1030
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
1031
|
+
}
|
|
1032
|
+
function readOptionalNumber(value) {
|
|
1033
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1034
|
+
}
|
|
1035
|
+
function readOptionalString(value) {
|
|
1036
|
+
return typeof value === "string" ? value : void 0;
|
|
1037
|
+
}
|
|
1038
|
+
function readLinkSuggestionStatus(value) {
|
|
1039
|
+
return value === "suggested" || value === "approved" || value === "dismissed" ? value : void 0;
|
|
1040
|
+
}
|
|
1041
|
+
function readRelation(value) {
|
|
1042
|
+
return value === "supports" || value === "contradicts" ? value : null;
|
|
1043
|
+
}
|
|
1044
|
+
function readNodeIdArray(value) {
|
|
1045
|
+
if (!Array.isArray(value)) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
return value.flatMap((entry) => {
|
|
1049
|
+
const id = readConvexId2(entry);
|
|
1050
|
+
return id ? [id] : [];
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
function readEpistemicNode(value) {
|
|
1054
|
+
if (!isRecord2(value)) {
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
1057
|
+
const id = readConvexId2(value._id);
|
|
1058
|
+
if (!id) {
|
|
1059
|
+
return null;
|
|
1060
|
+
}
|
|
1061
|
+
const confidence = readOptionalNumber(value.confidence) ?? readOptionalString(value.confidence);
|
|
1062
|
+
return {
|
|
1063
|
+
_id: id,
|
|
1064
|
+
belief: readOptionalString(value.belief),
|
|
1065
|
+
canonicalText: readOptionalString(value.canonicalText),
|
|
1066
|
+
confidence,
|
|
1067
|
+
contradictingInsightIds: readNodeIdArray(value.contradictingInsightIds),
|
|
1068
|
+
globalId: readOptionalString(value.globalId),
|
|
1069
|
+
nodeType: readOptionalString(value.nodeType),
|
|
1070
|
+
projectId: readOptionalString(value.projectId),
|
|
1071
|
+
status: readOptionalString(value.status),
|
|
1072
|
+
supportingInsightIds: readNodeIdArray(value.supportingInsightIds),
|
|
1073
|
+
topicId: readOptionalString(value.topicId)
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
function readBeliefEvidenceLink(value) {
|
|
1077
|
+
if (!isRecord2(value)) {
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
const id = readConvexId2(value._id);
|
|
1081
|
+
const beliefId = readConvexId2(value.beliefId);
|
|
1082
|
+
const insightId = readConvexId2(value.insightId);
|
|
1083
|
+
const relation = readRelation(value.relation);
|
|
1084
|
+
const createdBy = readOptionalString(value.createdBy);
|
|
1085
|
+
if (!(id && beliefId && insightId && relation && createdBy)) {
|
|
1086
|
+
return null;
|
|
1087
|
+
}
|
|
1088
|
+
return {
|
|
1089
|
+
_id: id,
|
|
1090
|
+
beliefId,
|
|
1091
|
+
confidence: readOptionalNumber(value.confidence),
|
|
1092
|
+
createdAt: readOptionalNumber(value.createdAt),
|
|
1093
|
+
createdBy,
|
|
1094
|
+
insightId,
|
|
1095
|
+
rationale: readOptionalString(value.rationale),
|
|
1096
|
+
relation,
|
|
1097
|
+
status: readLinkSuggestionStatus(value.status)
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
function readProjectBeliefSummary(value) {
|
|
1101
|
+
if (!isRecord2(value)) {
|
|
1102
|
+
return null;
|
|
1103
|
+
}
|
|
1104
|
+
const id = readConvexId2(value._id);
|
|
1105
|
+
if (!id || typeof value.belief !== "string" || typeof value.confidence !== "string" || typeof value.status !== "string") {
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
return {
|
|
1109
|
+
_id: id,
|
|
1110
|
+
belief: value.belief,
|
|
1111
|
+
confidence: value.confidence,
|
|
1112
|
+
status: value.status
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
function readRowList(values, reader) {
|
|
1116
|
+
return values.flatMap((value) => {
|
|
1117
|
+
const row = reader(value);
|
|
1118
|
+
return row ? [row] : [];
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
934
1121
|
async function markProjectGraphDirty(ctx, projectId) {
|
|
935
1122
|
if (!projectId) {
|
|
936
1123
|
return;
|
|
@@ -988,16 +1175,18 @@ var create = mutation({
|
|
|
988
1175
|
handler: async (ctx, args) => {
|
|
989
1176
|
const resolvedBeliefId = args.beliefId;
|
|
990
1177
|
const resolvedInsightId = args.insightId;
|
|
991
|
-
const beliefNode = await ctx.db.get(resolvedBeliefId);
|
|
1178
|
+
const beliefNode = readEpistemicNode(await ctx.db.get(resolvedBeliefId));
|
|
992
1179
|
if (!beliefNode) {
|
|
993
1180
|
throw new Error("Belief node not found");
|
|
994
1181
|
}
|
|
995
|
-
const insightNode = await ctx.db.get(resolvedInsightId);
|
|
1182
|
+
const insightNode = readEpistemicNode(await ctx.db.get(resolvedInsightId));
|
|
996
1183
|
if (!insightNode) {
|
|
997
1184
|
throw new Error("Evidence node not found");
|
|
998
1185
|
}
|
|
999
1186
|
if (!Number.isFinite(args.weight) || args.weight === 0 || args.weight < -1 || args.weight > 1) {
|
|
1000
|
-
throw new Error(
|
|
1187
|
+
throw new Error(
|
|
1188
|
+
"Belief evidence links require explicit nonzero weight in [-1, 1]"
|
|
1189
|
+
);
|
|
1001
1190
|
}
|
|
1002
1191
|
if (args.relation === "supports" && args.weight < 0) {
|
|
1003
1192
|
throw new Error("Supporting evidence links require positive weight");
|
|
@@ -1016,10 +1205,13 @@ var create = mutation({
|
|
|
1016
1205
|
throw new Error("No permission to link evidence to this belief");
|
|
1017
1206
|
}
|
|
1018
1207
|
}
|
|
1019
|
-
const existingLinks =
|
|
1020
|
-
"
|
|
1021
|
-
|
|
1022
|
-
|
|
1208
|
+
const existingLinks = readRowList(
|
|
1209
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1210
|
+
"by_beliefId",
|
|
1211
|
+
(q) => q.eq("beliefId", args.beliefId)
|
|
1212
|
+
).collect(),
|
|
1213
|
+
readBeliefEvidenceLink
|
|
1214
|
+
);
|
|
1023
1215
|
const duplicate = existingLinks.find(
|
|
1024
1216
|
(link) => link.insightId === args.insightId
|
|
1025
1217
|
);
|
|
@@ -1099,14 +1291,14 @@ var remove = mutation({
|
|
|
1099
1291
|
},
|
|
1100
1292
|
returns: permissiveReturn,
|
|
1101
1293
|
handler: async (ctx, args) => {
|
|
1102
|
-
const link = await ctx.db.get(args.linkId);
|
|
1294
|
+
const link = readBeliefEvidenceLink(await ctx.db.get(args.linkId));
|
|
1103
1295
|
if (!link) {
|
|
1104
1296
|
throw new Error("Link not found");
|
|
1105
1297
|
}
|
|
1106
1298
|
if (link.createdBy !== args.userId) {
|
|
1107
1299
|
throw new Error("Only the creator can remove this link");
|
|
1108
1300
|
}
|
|
1109
|
-
const belief = await ctx.db.get(link.beliefId);
|
|
1301
|
+
const belief = readEpistemicNode(await ctx.db.get(link.beliefId));
|
|
1110
1302
|
if (isOperationalLinkStatus(link.status)) {
|
|
1111
1303
|
await removeOperationalLinkEffects(ctx, {
|
|
1112
1304
|
beliefId: link.beliefId,
|
|
@@ -1127,11 +1319,11 @@ var update = mutation({
|
|
|
1127
1319
|
},
|
|
1128
1320
|
returns: permissiveReturn,
|
|
1129
1321
|
handler: async (ctx, args) => {
|
|
1130
|
-
const link = await ctx.db.get(args.linkId);
|
|
1322
|
+
const link = readBeliefEvidenceLink(await ctx.db.get(args.linkId));
|
|
1131
1323
|
if (!link) {
|
|
1132
1324
|
throw new Error("Link not found");
|
|
1133
1325
|
}
|
|
1134
|
-
const belief = await ctx.db.get(link.beliefId);
|
|
1326
|
+
const belief = readEpistemicNode(await ctx.db.get(link.beliefId));
|
|
1135
1327
|
if (!belief) {
|
|
1136
1328
|
throw new Error("Belief not found");
|
|
1137
1329
|
}
|
|
@@ -1167,11 +1359,11 @@ var reviewSuggestion = mutation({
|
|
|
1167
1359
|
},
|
|
1168
1360
|
returns: permissiveReturn,
|
|
1169
1361
|
handler: async (ctx, args) => {
|
|
1170
|
-
const link = await ctx.db.get(args.linkId);
|
|
1362
|
+
const link = readBeliefEvidenceLink(await ctx.db.get(args.linkId));
|
|
1171
1363
|
if (!link) {
|
|
1172
1364
|
throw new Error("Link not found");
|
|
1173
1365
|
}
|
|
1174
|
-
const belief = await ctx.db.get(link.beliefId);
|
|
1366
|
+
const belief = readEpistemicNode(await ctx.db.get(link.beliefId));
|
|
1175
1367
|
if (!belief) {
|
|
1176
1368
|
throw new Error("Belief not found");
|
|
1177
1369
|
}
|
|
@@ -1225,10 +1417,13 @@ var getByBelief = query({
|
|
|
1225
1417
|
},
|
|
1226
1418
|
returns: permissiveReturn,
|
|
1227
1419
|
handler: async (ctx, args) => {
|
|
1228
|
-
const links =
|
|
1229
|
-
"
|
|
1230
|
-
|
|
1231
|
-
|
|
1420
|
+
const links = readRowList(
|
|
1421
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1422
|
+
"by_beliefId",
|
|
1423
|
+
(q) => q.eq("beliefId", args.beliefId)
|
|
1424
|
+
).collect(),
|
|
1425
|
+
readBeliefEvidenceLink
|
|
1426
|
+
);
|
|
1232
1427
|
return links.filter(
|
|
1233
1428
|
(link) => isOperationalLinkStatus(link.status)
|
|
1234
1429
|
);
|
|
@@ -1240,10 +1435,13 @@ var getPendingSuggestions = query({
|
|
|
1240
1435
|
},
|
|
1241
1436
|
returns: permissiveReturn,
|
|
1242
1437
|
handler: async (ctx, args) => {
|
|
1243
|
-
const links =
|
|
1244
|
-
"
|
|
1245
|
-
|
|
1246
|
-
|
|
1438
|
+
const links = readRowList(
|
|
1439
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1440
|
+
"by_beliefId",
|
|
1441
|
+
(q) => q.eq("beliefId", args.beliefId)
|
|
1442
|
+
).collect(),
|
|
1443
|
+
readBeliefEvidenceLink
|
|
1444
|
+
);
|
|
1247
1445
|
return links.filter((link) => link.status === "suggested");
|
|
1248
1446
|
}
|
|
1249
1447
|
});
|
|
@@ -1253,10 +1451,13 @@ var getSupportingLinks = query({
|
|
|
1253
1451
|
},
|
|
1254
1452
|
returns: permissiveReturn,
|
|
1255
1453
|
handler: async (ctx, args) => {
|
|
1256
|
-
const links =
|
|
1257
|
-
"
|
|
1258
|
-
|
|
1259
|
-
|
|
1454
|
+
const links = readRowList(
|
|
1455
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1456
|
+
"by_relation",
|
|
1457
|
+
(q) => q.eq("beliefId", args.beliefId).eq("relation", "supports")
|
|
1458
|
+
).collect(),
|
|
1459
|
+
readBeliefEvidenceLink
|
|
1460
|
+
);
|
|
1260
1461
|
return links.filter(
|
|
1261
1462
|
(link) => isOperationalLinkStatus(link.status)
|
|
1262
1463
|
);
|
|
@@ -1268,10 +1469,13 @@ var getContradictingLinks = query({
|
|
|
1268
1469
|
},
|
|
1269
1470
|
returns: permissiveReturn,
|
|
1270
1471
|
handler: async (ctx, args) => {
|
|
1271
|
-
const links =
|
|
1272
|
-
"
|
|
1273
|
-
|
|
1274
|
-
|
|
1472
|
+
const links = readRowList(
|
|
1473
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1474
|
+
"by_relation",
|
|
1475
|
+
(q) => q.eq("beliefId", args.beliefId).eq("relation", "contradicts")
|
|
1476
|
+
).collect(),
|
|
1477
|
+
readBeliefEvidenceLink
|
|
1478
|
+
);
|
|
1275
1479
|
return links.filter(
|
|
1276
1480
|
(link) => isOperationalLinkStatus(link.status)
|
|
1277
1481
|
);
|
|
@@ -1283,10 +1487,13 @@ var getByInsight = query({
|
|
|
1283
1487
|
},
|
|
1284
1488
|
returns: permissiveReturn,
|
|
1285
1489
|
handler: async (ctx, args) => {
|
|
1286
|
-
const links =
|
|
1287
|
-
"
|
|
1288
|
-
|
|
1289
|
-
|
|
1490
|
+
const links = readRowList(
|
|
1491
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1492
|
+
"by_insightId",
|
|
1493
|
+
(q) => q.eq("insightId", args.insightId)
|
|
1494
|
+
).collect(),
|
|
1495
|
+
readBeliefEvidenceLink
|
|
1496
|
+
);
|
|
1290
1497
|
return links.filter(
|
|
1291
1498
|
(link) => isOperationalLinkStatus(link.status)
|
|
1292
1499
|
);
|
|
@@ -1298,10 +1505,13 @@ var getCounts = query({
|
|
|
1298
1505
|
},
|
|
1299
1506
|
returns: permissiveReturn,
|
|
1300
1507
|
handler: async (ctx, args) => {
|
|
1301
|
-
const links =
|
|
1302
|
-
"
|
|
1303
|
-
|
|
1304
|
-
|
|
1508
|
+
const links = readRowList(
|
|
1509
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1510
|
+
"by_beliefId",
|
|
1511
|
+
(q) => q.eq("beliefId", args.beliefId)
|
|
1512
|
+
).collect(),
|
|
1513
|
+
readBeliefEvidenceLink
|
|
1514
|
+
);
|
|
1305
1515
|
const activeLinks = links.filter(
|
|
1306
1516
|
(link) => isOperationalLinkStatus(link.status)
|
|
1307
1517
|
);
|
|
@@ -1326,7 +1536,7 @@ var getEvidenceWithDetails = query({
|
|
|
1326
1536
|
},
|
|
1327
1537
|
returns: permissiveReturn,
|
|
1328
1538
|
handler: async (ctx, args) => {
|
|
1329
|
-
const belief = await ctx.db.get(args.beliefId);
|
|
1539
|
+
const belief = readEpistemicNode(await ctx.db.get(args.beliefId));
|
|
1330
1540
|
if (!belief) {
|
|
1331
1541
|
return null;
|
|
1332
1542
|
}
|
|
@@ -1340,17 +1550,20 @@ var getEvidenceWithDetails = query({
|
|
|
1340
1550
|
return null;
|
|
1341
1551
|
}
|
|
1342
1552
|
}
|
|
1343
|
-
const links =
|
|
1344
|
-
"
|
|
1345
|
-
|
|
1346
|
-
|
|
1553
|
+
const links = readRowList(
|
|
1554
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1555
|
+
"by_beliefId",
|
|
1556
|
+
(q) => q.eq("beliefId", args.beliefId)
|
|
1557
|
+
).collect(),
|
|
1558
|
+
readBeliefEvidenceLink
|
|
1559
|
+
);
|
|
1347
1560
|
const linksWithDetails = await Promise.all(
|
|
1348
1561
|
links.filter(
|
|
1349
1562
|
(link) => isOperationalLinkStatus(
|
|
1350
1563
|
link.status
|
|
1351
1564
|
)
|
|
1352
1565
|
).map(async (link) => {
|
|
1353
|
-
const insight = await ctx.db.get(link.insightId);
|
|
1566
|
+
const insight = readEpistemicNode(await ctx.db.get(link.insightId));
|
|
1354
1567
|
return {
|
|
1355
1568
|
...link,
|
|
1356
1569
|
insight
|
|
@@ -1392,20 +1605,23 @@ var getByProject = query({
|
|
|
1392
1605
|
return { links: [], beliefDetails: {} };
|
|
1393
1606
|
}
|
|
1394
1607
|
const pageSize = Math.max(1, Math.min(Math.floor(args.limit ?? 300), 1e3));
|
|
1395
|
-
const beliefs =
|
|
1396
|
-
internal.epistemicBeliefs.internalGetByProject,
|
|
1397
|
-
{
|
|
1608
|
+
const beliefs = readRowList(
|
|
1609
|
+
await ctx.runQuery(internal.epistemicBeliefs.internalGetByProject, {
|
|
1398
1610
|
projectId,
|
|
1399
1611
|
limit: pageSize
|
|
1400
|
-
}
|
|
1612
|
+
}),
|
|
1613
|
+
readProjectBeliefSummary
|
|
1401
1614
|
);
|
|
1402
1615
|
const beliefIds = beliefs.map((b) => b._id);
|
|
1403
1616
|
const allLinks = await Promise.all(
|
|
1404
1617
|
beliefIds.map(async (beliefId) => {
|
|
1405
|
-
const links =
|
|
1406
|
-
"
|
|
1407
|
-
|
|
1408
|
-
|
|
1618
|
+
const links = readRowList(
|
|
1619
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1620
|
+
"by_beliefId",
|
|
1621
|
+
(q) => q.eq("beliefId", beliefId)
|
|
1622
|
+
).take(200),
|
|
1623
|
+
readBeliefEvidenceLink
|
|
1624
|
+
);
|
|
1409
1625
|
return links;
|
|
1410
1626
|
})
|
|
1411
1627
|
);
|
|
@@ -1431,13 +1647,16 @@ var getLinkedBeliefsForInsight = query({
|
|
|
1431
1647
|
},
|
|
1432
1648
|
returns: permissiveReturn,
|
|
1433
1649
|
handler: async (ctx, args) => {
|
|
1434
|
-
const links =
|
|
1435
|
-
"
|
|
1436
|
-
|
|
1437
|
-
|
|
1650
|
+
const links = readRowList(
|
|
1651
|
+
await ctx.db.query("beliefEvidenceLinks").withIndex(
|
|
1652
|
+
"by_insightId",
|
|
1653
|
+
(q) => q.eq("insightId", args.insightId)
|
|
1654
|
+
).collect(),
|
|
1655
|
+
readBeliefEvidenceLink
|
|
1656
|
+
);
|
|
1438
1657
|
const linkedBeliefs = await Promise.all(
|
|
1439
1658
|
links.map(async (link) => {
|
|
1440
|
-
const belief = await ctx.db.get(link.beliefId);
|
|
1659
|
+
const belief = readEpistemicNode(await ctx.db.get(link.beliefId));
|
|
1441
1660
|
return {
|
|
1442
1661
|
linkId: link._id,
|
|
1443
1662
|
beliefId: link.beliefId,
|