@lucern/graph-primitives 1.0.28 → 1.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +398 -228
- 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 +857 -515
- 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 +366 -203
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.d.ts +8 -8
- package/dist/epistemicBeliefs.backfills.js +655 -308
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.d.ts +19 -14
- package/dist/epistemicBeliefs.confidence.js +634 -423
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.d.ts +6 -6
- package/dist/epistemicBeliefs.core.js +719 -411
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.d.ts +11 -8
- package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
- package/dist/epistemicBeliefs.forkEvidence.js +8 -28
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
- package/dist/epistemicBeliefs.helpers.d.ts +69 -74
- package/dist/epistemicBeliefs.helpers.js +359 -248
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.d.ts +5 -5
- package/dist/epistemicBeliefs.internal.js +1246 -1044
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +4922 -3608
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
- package/dist/epistemicBeliefs.lifecycle.js +1137 -818
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.d.ts +7 -7
- package/dist/epistemicBeliefs.links.js +408 -307
- 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 +1063 -613
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.d.ts +15 -32
- package/dist/epistemicContracts.handlers.js +2086 -1644
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +1131 -672
- 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 +1969 -1205
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.d.ts +7 -7
- package/dist/epistemicEdges.mutations.js +960 -583
- 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 +937 -536
- 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 +844 -696
- 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 +704 -508
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.d.ts +6 -6
- package/dist/epistemicNodes.mutations.js +564 -467
- 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 +352 -312
- 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 +87 -83
- package/dist/index.js +15677 -10594
- 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,14 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { checkScopeAccess, checkProjectAccess } from '@lucern/access-control/access';
|
|
1
|
+
import { requireScopeWriteAccess, checkScopeAccess } from '@lucern/access-control/access';
|
|
3
2
|
import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
|
|
4
3
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { v } from 'convex/values';
|
|
5
|
+
import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
|
|
6
|
+
import { componentsGeneric, mutationGeneric, queryGeneric } from 'convex/server';
|
|
7
7
|
import '@lucern/access-control/audience';
|
|
8
8
|
import { getCurrentUserId } from '@lucern/access-control/auth';
|
|
9
|
+
import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
|
|
10
|
+
import { normalizeTupleContradictionPolicy, createInheritedContractRecord, confidenceFromSL } from '@lucern/confidence';
|
|
9
11
|
import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
10
|
-
import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
|
|
11
12
|
import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
|
|
13
|
+
import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
|
|
12
14
|
|
|
13
15
|
// src/epistemicBeliefs.core.ts
|
|
14
16
|
|
|
@@ -122,9 +124,12 @@ function resolveBeliefLifecycleStatus(opts) {
|
|
|
122
124
|
function isPreValidationBeliefStatus(status) {
|
|
123
125
|
return status === "assumption" || status === "hypothesis";
|
|
124
126
|
}
|
|
125
|
-
var
|
|
127
|
+
var unsafeApi = unsafeConvexAnyApi(
|
|
128
|
+
"graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
|
|
129
|
+
);
|
|
130
|
+
var api = unsafeApi;
|
|
126
131
|
componentsGeneric();
|
|
127
|
-
var internal =
|
|
132
|
+
var internal = unsafeApi;
|
|
128
133
|
var mutation = mutationGeneric;
|
|
129
134
|
var query = queryGeneric;
|
|
130
135
|
|
|
@@ -140,6 +145,32 @@ function debugGraphPrimitiveFallback(message, context) {
|
|
|
140
145
|
console.debug(message, context ?? {});
|
|
141
146
|
}
|
|
142
147
|
|
|
148
|
+
// src/embeddingTrigger.ts
|
|
149
|
+
var embeddingActionRef = "embeddingActions:generateEpistemicNodeEmbedding";
|
|
150
|
+
async function scheduleEmbeddingGeneration(args) {
|
|
151
|
+
try {
|
|
152
|
+
await args.ctx.scheduler.runAfter(0, embeddingActionRef, {
|
|
153
|
+
nodeId: args.nodeId,
|
|
154
|
+
projectId: args.projectId ? String(args.projectId) : void 0,
|
|
155
|
+
topicId: args.topicId ? String(args.topicId) : void 0,
|
|
156
|
+
createdBy: args.createdBy,
|
|
157
|
+
nodeType: args.nodeType,
|
|
158
|
+
text: args.text.slice(0, 2e4),
|
|
159
|
+
hasAnswer: args.hasAnswer,
|
|
160
|
+
confidence: args.confidence
|
|
161
|
+
});
|
|
162
|
+
} catch (error) {
|
|
163
|
+
debugGraphPrimitiveFallback(
|
|
164
|
+
"[embeddingTrigger] Failed to schedule embedding generation",
|
|
165
|
+
{
|
|
166
|
+
error,
|
|
167
|
+
nodeId: String(args.nodeId),
|
|
168
|
+
nodeType: args.nodeType
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
143
174
|
// src/topicProjectOverlay.ts
|
|
144
175
|
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
145
176
|
function readNonEmptyString(value) {
|
|
@@ -158,6 +189,10 @@ function readStringArray(value) {
|
|
|
158
189
|
function readMetadata(topic) {
|
|
159
190
|
return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
|
|
160
191
|
}
|
|
192
|
+
function omitMetadataKey(metadata, key) {
|
|
193
|
+
const { [key]: _omitted, ...rest } = metadata;
|
|
194
|
+
return rest;
|
|
195
|
+
}
|
|
161
196
|
function readLegacyProjectId(value) {
|
|
162
197
|
if (!value) {
|
|
163
198
|
return;
|
|
@@ -238,9 +273,12 @@ async function resolveTopicDoc(ctx, scopeId) {
|
|
|
238
273
|
);
|
|
239
274
|
}
|
|
240
275
|
try {
|
|
241
|
-
const topic = await ctx.runQuery(
|
|
242
|
-
|
|
243
|
-
|
|
276
|
+
const topic = await ctx.runQuery(
|
|
277
|
+
api.topics.getByLegacyScopeId,
|
|
278
|
+
{
|
|
279
|
+
projectId: String(scopeId)
|
|
280
|
+
}
|
|
281
|
+
);
|
|
244
282
|
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
245
283
|
return topic;
|
|
246
284
|
}
|
|
@@ -260,8 +298,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
|
260
298
|
const outwardId = idMode === "topic" ? topicId : storageProjectId;
|
|
261
299
|
const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
|
|
262
300
|
const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
|
|
263
|
-
|
|
264
|
-
|
|
301
|
+
let createdAt = 0;
|
|
302
|
+
if (typeof topic.createdAt === "number") {
|
|
303
|
+
createdAt = topic.createdAt;
|
|
304
|
+
} else if (typeof topic._creationTime === "number") {
|
|
305
|
+
createdAt = topic._creationTime;
|
|
306
|
+
}
|
|
307
|
+
let updatedAt = createdAt;
|
|
308
|
+
if (typeof topic.updatedAt === "number") {
|
|
309
|
+
updatedAt = topic.updatedAt;
|
|
310
|
+
} else if (typeof metadata.updatedAt === "number") {
|
|
311
|
+
updatedAt = metadata.updatedAt;
|
|
312
|
+
}
|
|
265
313
|
return {
|
|
266
314
|
...metadata,
|
|
267
315
|
_id: outwardId,
|
|
@@ -330,90 +378,113 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
|
330
378
|
if (!topic) {
|
|
331
379
|
return null;
|
|
332
380
|
}
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
381
|
+
const plan = buildTopicProjectOverlayPatchPlan(topic, value);
|
|
382
|
+
await applyTopicProjectOverlayPatch(ctx, topic, plan);
|
|
383
|
+
return materializeTopicProjectOverlay({
|
|
384
|
+
...topic,
|
|
385
|
+
...plan.patch,
|
|
386
|
+
metadata: plan.nextMetadata
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
function buildTopicProjectOverlayPatchPlan(topic, value) {
|
|
390
|
+
const plan = {
|
|
391
|
+
nextMetadata: { ...readMetadata(topic) },
|
|
392
|
+
patch: {},
|
|
393
|
+
topicUpdateArgs: {
|
|
394
|
+
id: String(topic._id)
|
|
395
|
+
}
|
|
337
396
|
};
|
|
338
397
|
for (const [key, rawValue] of Object.entries(value)) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
398
|
+
applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
|
|
399
|
+
}
|
|
400
|
+
plan.patch.updatedAt = Date.now();
|
|
401
|
+
plan.patch.metadata = plan.nextMetadata;
|
|
402
|
+
plan.topicUpdateArgs.metadata = plan.nextMetadata;
|
|
403
|
+
return plan;
|
|
404
|
+
}
|
|
405
|
+
function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
|
|
406
|
+
switch (key) {
|
|
407
|
+
case "_id":
|
|
408
|
+
case "projectId":
|
|
409
|
+
case "topicId":
|
|
410
|
+
case "legacyProjectId":
|
|
411
|
+
case "storageProjectId":
|
|
412
|
+
case "updatedAt":
|
|
413
|
+
case "createdAt":
|
|
414
|
+
return;
|
|
415
|
+
case "name":
|
|
416
|
+
case "description":
|
|
417
|
+
plan.patch[key] = rawValue;
|
|
418
|
+
plan.topicUpdateArgs[key] = rawValue;
|
|
419
|
+
return;
|
|
420
|
+
case "tenantId":
|
|
421
|
+
case "workspaceId":
|
|
422
|
+
case "ownerId":
|
|
423
|
+
throw new Error(
|
|
424
|
+
`patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
|
|
425
|
+
);
|
|
426
|
+
case "status":
|
|
427
|
+
applyTopicStatusPatch(plan, rawValue);
|
|
428
|
+
return;
|
|
429
|
+
case "visibility":
|
|
430
|
+
applyTopicVisibilityPatch(plan, rawValue);
|
|
431
|
+
return;
|
|
432
|
+
case "type":
|
|
433
|
+
applyTopicProjectTypePatch(plan, rawValue);
|
|
434
|
+
return;
|
|
435
|
+
default:
|
|
436
|
+
applyTopicMetadataPatch(plan, key, rawValue);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function applyTopicStatusPatch(plan, rawValue) {
|
|
440
|
+
const status = coerceStatus(rawValue);
|
|
441
|
+
if (status) {
|
|
442
|
+
plan.patch.status = status;
|
|
443
|
+
plan.topicUpdateArgs.status = status;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function applyTopicVisibilityPatch(plan, rawValue) {
|
|
447
|
+
const visibility = coerceVisibility(rawValue);
|
|
448
|
+
if (visibility) {
|
|
449
|
+
plan.patch.visibility = visibility;
|
|
450
|
+
plan.topicUpdateArgs.visibility = visibility;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
function applyTopicProjectTypePatch(plan, rawValue) {
|
|
454
|
+
const projectType = readNonEmptyString(rawValue);
|
|
455
|
+
if (projectType) {
|
|
456
|
+
plan.nextMetadata.projectType = projectType;
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
|
|
460
|
+
}
|
|
461
|
+
function applyTopicMetadataPatch(plan, key, rawValue) {
|
|
462
|
+
if (rawValue === void 0) {
|
|
463
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
|
|
464
|
+
return;
|
|
392
465
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
466
|
+
plan.nextMetadata[key] = rawValue;
|
|
467
|
+
}
|
|
468
|
+
async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
|
|
396
469
|
if (typeof ctx.runMutation === "function") {
|
|
397
470
|
try {
|
|
398
|
-
await ctx.runMutation(api.topics.update, topicUpdateArgs);
|
|
471
|
+
await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
|
|
399
472
|
} catch (error) {
|
|
400
|
-
if (!
|
|
473
|
+
if (!canPatchTopicViaLocalDb(ctx, error)) {
|
|
401
474
|
throw error;
|
|
402
475
|
}
|
|
403
|
-
await ctx.db.patch(
|
|
476
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
404
477
|
}
|
|
405
478
|
} else if (ctx?.db && typeof ctx.db.patch === "function") {
|
|
406
|
-
await ctx.db.patch(
|
|
479
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
407
480
|
} else {
|
|
408
481
|
throw new Error(
|
|
409
482
|
"Cannot patch topic without component adapter (ctx.runMutation unavailable)"
|
|
410
483
|
);
|
|
411
484
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
metadata: nextMetadata
|
|
416
|
-
});
|
|
485
|
+
}
|
|
486
|
+
function canPatchTopicViaLocalDb(ctx, error) {
|
|
487
|
+
return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
|
|
417
488
|
}
|
|
418
489
|
|
|
419
490
|
// src/resolvers.ts
|
|
@@ -441,7 +512,7 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
|
|
|
441
512
|
try {
|
|
442
513
|
await patchTopicProjectOverlay(ctx, projectId, value);
|
|
443
514
|
} catch (error) {
|
|
444
|
-
if (!isAdvisoryTopicPatch(value)
|
|
515
|
+
if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
|
|
445
516
|
throw error;
|
|
446
517
|
}
|
|
447
518
|
console.warn(
|
|
@@ -508,13 +579,15 @@ function asMappedProjectId(topic) {
|
|
|
508
579
|
if (!topic) {
|
|
509
580
|
return;
|
|
510
581
|
}
|
|
511
|
-
const directLegacyProjectId = normalizeScopeValue(
|
|
582
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
583
|
+
topic[LEGACY_SCOPE_FIELD2]
|
|
584
|
+
);
|
|
512
585
|
if (directLegacyProjectId) {
|
|
513
586
|
return directLegacyProjectId;
|
|
514
587
|
}
|
|
515
588
|
const metadata = topic.metadata || {};
|
|
516
589
|
const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
517
|
-
return candidate ? candidate : void 0;
|
|
590
|
+
return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
|
|
518
591
|
}
|
|
519
592
|
function normalizeScopeValue(value) {
|
|
520
593
|
if (typeof value !== "string") {
|
|
@@ -539,8 +612,9 @@ function pickPrimaryTopic(candidates) {
|
|
|
539
612
|
})[0];
|
|
540
613
|
}
|
|
541
614
|
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
615
|
+
const query2 = ctx.db.query("topics");
|
|
542
616
|
try {
|
|
543
|
-
return await
|
|
617
|
+
return await query2.withIndex(
|
|
544
618
|
"by_graph_scope_project",
|
|
545
619
|
(q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
|
|
546
620
|
).collect();
|
|
@@ -552,7 +626,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
|
552
626
|
scopeId
|
|
553
627
|
}
|
|
554
628
|
);
|
|
555
|
-
const topics = await
|
|
629
|
+
const topics = await query2.collect();
|
|
556
630
|
return topics.filter((topic) => {
|
|
557
631
|
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
558
632
|
const mappedProjectId = asMappedProjectId(topic);
|
|
@@ -608,137 +682,115 @@ async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
|
608
682
|
let current = topic;
|
|
609
683
|
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
610
684
|
current = await ctx.db.get(current.parentTopicId);
|
|
611
|
-
if (!current)
|
|
685
|
+
if (!current) {
|
|
686
|
+
break;
|
|
687
|
+
}
|
|
612
688
|
if (!tenantId) {
|
|
613
689
|
tenantId = normalizeScopeValue(current.tenantId);
|
|
614
690
|
}
|
|
615
691
|
if (!workspaceId) {
|
|
616
692
|
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
617
693
|
}
|
|
618
|
-
if (tenantId && workspaceId)
|
|
694
|
+
if (tenantId && workspaceId) {
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
619
697
|
}
|
|
620
698
|
return { tenantId, workspaceId };
|
|
621
699
|
}
|
|
622
700
|
async function resolveTopicProjectScope(ctx, args) {
|
|
623
701
|
if (args.topicId) {
|
|
624
|
-
|
|
625
|
-
try {
|
|
626
|
-
topic = await ctx.db.get(
|
|
627
|
-
args.topicId
|
|
628
|
-
);
|
|
629
|
-
} catch (error) {
|
|
630
|
-
debugGraphPrimitiveFallback(
|
|
631
|
-
"[topicScope] Failed to load topic by direct id",
|
|
632
|
-
{
|
|
633
|
-
error,
|
|
634
|
-
topicId: args.topicId
|
|
635
|
-
}
|
|
636
|
-
);
|
|
637
|
-
}
|
|
638
|
-
if (!topic) {
|
|
639
|
-
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
640
|
-
}
|
|
641
|
-
if (!topic) {
|
|
642
|
-
topic = pickPrimaryTopic(
|
|
643
|
-
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
644
|
-
) ?? null;
|
|
645
|
-
}
|
|
646
|
-
if (!topic) {
|
|
647
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
648
|
-
ctx,
|
|
649
|
-
String(args.topicId)
|
|
650
|
-
);
|
|
651
|
-
if (nodeScope) {
|
|
652
|
-
return nodeScope;
|
|
653
|
-
}
|
|
654
|
-
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
655
|
-
}
|
|
656
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
657
|
-
const mapped = asMappedProjectId(topic);
|
|
658
|
-
if (mapped) {
|
|
659
|
-
return {
|
|
660
|
-
topicId: topic._id,
|
|
661
|
-
projectId: mapped,
|
|
662
|
-
tenantId: inherited.tenantId,
|
|
663
|
-
workspaceId: inherited.workspaceId,
|
|
664
|
-
source: "topic"
|
|
665
|
-
};
|
|
666
|
-
}
|
|
667
|
-
return {
|
|
668
|
-
topicId: topic._id,
|
|
669
|
-
tenantId: inherited.tenantId,
|
|
670
|
-
workspaceId: inherited.workspaceId,
|
|
671
|
-
source: "topic"
|
|
672
|
-
};
|
|
702
|
+
return await resolveScopeFromTopicId(ctx, args.topicId);
|
|
673
703
|
}
|
|
674
704
|
if (args.projectId) {
|
|
675
|
-
|
|
676
|
-
try {
|
|
677
|
-
directTopic = await ctx.db.get(
|
|
678
|
-
args.projectId
|
|
679
|
-
);
|
|
680
|
-
} catch (error) {
|
|
681
|
-
debugGraphPrimitiveFallback(
|
|
682
|
-
"[topicScope] Failed to load direct project topic",
|
|
683
|
-
{
|
|
684
|
-
error,
|
|
685
|
-
projectId: args.projectId
|
|
686
|
-
}
|
|
687
|
-
);
|
|
688
|
-
}
|
|
689
|
-
if (directTopic) {
|
|
690
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
691
|
-
const mapped = asMappedProjectId(directTopic);
|
|
692
|
-
return {
|
|
693
|
-
topicId: directTopic._id,
|
|
694
|
-
projectId: mapped ?? args.projectId,
|
|
695
|
-
tenantId: inherited.tenantId,
|
|
696
|
-
workspaceId: inherited.workspaceId,
|
|
697
|
-
source: "topic_inferred"
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
701
|
-
if (directTopic) {
|
|
702
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
703
|
-
const mapped = asMappedProjectId(directTopic);
|
|
704
|
-
return {
|
|
705
|
-
topicId: directTopic._id,
|
|
706
|
-
projectId: mapped ?? args.projectId,
|
|
707
|
-
tenantId: inherited.tenantId,
|
|
708
|
-
workspaceId: inherited.workspaceId,
|
|
709
|
-
source: "topic_inferred"
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
713
|
-
const primary = pickPrimaryTopic(topics);
|
|
714
|
-
if (primary) {
|
|
715
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
716
|
-
return {
|
|
717
|
-
topicId: primary._id,
|
|
718
|
-
projectId: args.projectId,
|
|
719
|
-
tenantId: inherited.tenantId,
|
|
720
|
-
workspaceId: inherited.workspaceId,
|
|
721
|
-
source: "project_mapped_topic"
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
725
|
-
ctx,
|
|
726
|
-
String(args.projectId)
|
|
727
|
-
);
|
|
728
|
-
if (nodeScope) {
|
|
729
|
-
return {
|
|
730
|
-
...nodeScope,
|
|
731
|
-
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
throw new Error(
|
|
735
|
-
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
736
|
-
);
|
|
705
|
+
return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
|
|
737
706
|
}
|
|
738
707
|
throw new Error(
|
|
739
708
|
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
740
709
|
);
|
|
741
710
|
}
|
|
711
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
712
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
713
|
+
if (topic) {
|
|
714
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
715
|
+
}
|
|
716
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
|
|
717
|
+
if (nodeScope) {
|
|
718
|
+
return nodeScope;
|
|
719
|
+
}
|
|
720
|
+
throw new Error(`Topic not found: ${String(topicId)}`);
|
|
721
|
+
}
|
|
722
|
+
async function resolveTopicDocFromTopicId(ctx, topicId) {
|
|
723
|
+
const direct = await tryReadTopicDoc(ctx, topicId, {
|
|
724
|
+
failureLog: "[topicScope] Failed to load topic by direct id",
|
|
725
|
+
idLogKey: "topicId"
|
|
726
|
+
});
|
|
727
|
+
if (direct) {
|
|
728
|
+
return direct;
|
|
729
|
+
}
|
|
730
|
+
const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
|
|
731
|
+
if (hostTopic) {
|
|
732
|
+
return hostTopic;
|
|
733
|
+
}
|
|
734
|
+
return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
|
|
735
|
+
}
|
|
736
|
+
async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
|
|
737
|
+
const directTopic = await resolveDirectLegacyProjectTopic(
|
|
738
|
+
ctx,
|
|
739
|
+
legacyProjectId
|
|
740
|
+
);
|
|
741
|
+
if (directTopic) {
|
|
742
|
+
return await buildTopicScope(ctx, directTopic, "topic_inferred", {
|
|
743
|
+
fallbackProjectId: legacyProjectId
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
const primary = pickPrimaryTopic(
|
|
747
|
+
await findTopicsByScopeAlias(ctx, legacyProjectId)
|
|
748
|
+
);
|
|
749
|
+
if (primary) {
|
|
750
|
+
return await buildTopicScope(ctx, primary, "project_mapped_topic", {
|
|
751
|
+
fallbackProjectId: legacyProjectId
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
|
|
755
|
+
if (nodeScope) {
|
|
756
|
+
return {
|
|
757
|
+
...nodeScope,
|
|
758
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
throw new Error(
|
|
762
|
+
`Legacy project scope ${legacyProjectId} has no mapped topic.`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
|
|
766
|
+
const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
|
|
767
|
+
failureLog: "[topicScope] Failed to load direct project topic",
|
|
768
|
+
idLogKey: "projectId"
|
|
769
|
+
});
|
|
770
|
+
return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
|
|
771
|
+
}
|
|
772
|
+
async function tryReadTopicDoc(ctx, id, log) {
|
|
773
|
+
try {
|
|
774
|
+
return await ctx.db.get(id);
|
|
775
|
+
} catch (error) {
|
|
776
|
+
debugGraphPrimitiveFallback(log.failureLog, {
|
|
777
|
+
error,
|
|
778
|
+
[log.idLogKey]: id
|
|
779
|
+
});
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
async function buildTopicScope(ctx, topic, source, options = {}) {
|
|
784
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
785
|
+
const mapped = asMappedProjectId(topic);
|
|
786
|
+
return {
|
|
787
|
+
topicId: topic._id,
|
|
788
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
789
|
+
tenantId: inherited.tenantId,
|
|
790
|
+
workspaceId: inherited.workspaceId,
|
|
791
|
+
source
|
|
792
|
+
};
|
|
793
|
+
}
|
|
742
794
|
var optionalScopeArgs = {
|
|
743
795
|
projectId: v.optional(v.string()),
|
|
744
796
|
topicId: v.optional(v.string())
|
|
@@ -803,8 +855,6 @@ function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
|
803
855
|
}
|
|
804
856
|
return scopeWorkspaceId === nodeWorkspaceId;
|
|
805
857
|
}
|
|
806
|
-
|
|
807
|
-
// src/epistemicBeliefs.helpers.ts
|
|
808
858
|
v.id("epistemicNodes");
|
|
809
859
|
var DEFAULT_PROJECT_BELIEF_LIMIT = 250;
|
|
810
860
|
var MAX_PROJECT_BELIEF_LIMIT = 1e3;
|
|
@@ -813,26 +863,6 @@ var DEFAULT_CONFIDENCE_POLICY = {
|
|
|
813
863
|
scoringMode: "after_worktree",
|
|
814
864
|
tupleContradiction: normalizeTupleContradictionPolicy()
|
|
815
865
|
};
|
|
816
|
-
function throwStructuredMutationError(args) {
|
|
817
|
-
const data = {
|
|
818
|
-
structuredMutationError: true,
|
|
819
|
-
message: args.message,
|
|
820
|
-
status: args.status,
|
|
821
|
-
code: args.code,
|
|
822
|
-
invariantCode: args.invariantCode,
|
|
823
|
-
suggestion: args.suggestion,
|
|
824
|
-
details: args.details
|
|
825
|
-
};
|
|
826
|
-
const error = new ConvexError(
|
|
827
|
-
data
|
|
828
|
-
);
|
|
829
|
-
error.status = args.status;
|
|
830
|
-
error.code = args.code;
|
|
831
|
-
error.invariantCode = args.invariantCode;
|
|
832
|
-
error.suggestion = args.suggestion;
|
|
833
|
-
error.details = args.details;
|
|
834
|
-
throw error;
|
|
835
|
-
}
|
|
836
866
|
function assertBaseRateInRange(baseRate, field = "baseRate") {
|
|
837
867
|
if (baseRate < 0 || baseRate > 1) {
|
|
838
868
|
throwStructuredMutationError({
|
|
@@ -916,7 +946,7 @@ function normalizePillar(pillar) {
|
|
|
916
946
|
async function markBeliefGraphDirty(ctx, scope) {
|
|
917
947
|
const projectId = typeof scope.projectId === "string" && scope.projectId.trim().length > 0 ? scope.projectId : void 0;
|
|
918
948
|
const topicId = typeof scope.topicId === "string" && scope.topicId.trim().length > 0 ? scope.topicId : void 0;
|
|
919
|
-
if (!projectId
|
|
949
|
+
if (!(projectId || topicId)) {
|
|
920
950
|
return;
|
|
921
951
|
}
|
|
922
952
|
if (projectId) {
|
|
@@ -933,9 +963,15 @@ async function markBeliefGraphDirty(ctx, scope) {
|
|
|
933
963
|
{ topicId }
|
|
934
964
|
);
|
|
935
965
|
}
|
|
966
|
+
const activityScopeId = topicId ?? projectId;
|
|
967
|
+
if (!activityScopeId) {
|
|
968
|
+
throw new Error(
|
|
969
|
+
"Expected belief graph dirty scope to include a topic or project id."
|
|
970
|
+
);
|
|
971
|
+
}
|
|
936
972
|
await resolveGraphPrimitivesAppResolvers().patchProject(
|
|
937
973
|
ctx,
|
|
938
|
-
|
|
974
|
+
activityScopeId,
|
|
939
975
|
{
|
|
940
976
|
lastActivityAt: Date.now()
|
|
941
977
|
}
|
|
@@ -943,7 +979,10 @@ async function markBeliefGraphDirty(ctx, scope) {
|
|
|
943
979
|
}
|
|
944
980
|
async function getActiveConfidencePolicy(ctx) {
|
|
945
981
|
try {
|
|
946
|
-
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
982
|
+
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
983
|
+
"by_active",
|
|
984
|
+
(q) => q.eq("isActive", true)
|
|
985
|
+
).first();
|
|
947
986
|
return {
|
|
948
987
|
scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
|
|
949
988
|
tupleContradiction: normalizeTupleContradictionPolicy(
|
|
@@ -975,23 +1014,6 @@ async function requireAuthenticatedUserId(ctx) {
|
|
|
975
1014
|
}
|
|
976
1015
|
return userId;
|
|
977
1016
|
}
|
|
978
|
-
async function requireProjectWriteAccess(ctx, projectId, userId) {
|
|
979
|
-
const hasAccess = await checkProjectAccess(
|
|
980
|
-
ctx,
|
|
981
|
-
projectId,
|
|
982
|
-
userId
|
|
983
|
-
);
|
|
984
|
-
if (!hasAccess) {
|
|
985
|
-
throwStructuredMutationError({
|
|
986
|
-
message: `Project write access denied for topic ${projectId}.`,
|
|
987
|
-
status: 403,
|
|
988
|
-
code: "PROJECT_ACCESS_DENIED",
|
|
989
|
-
invariantCode: "policy.scope_required",
|
|
990
|
-
suggestion: "The acting principal lacks project-write access to this topic. Request a topic grant (or, if the principal created this topic, run the creator-grant backfill) and retry.",
|
|
991
|
-
details: { topicId: projectId, principalId: userId }
|
|
992
|
-
});
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
1017
|
|
|
996
1018
|
// src/epistemicBeliefs.forkEvidence.ts
|
|
997
1019
|
function normalizeForkTriggerRelation(value) {
|
|
@@ -1005,7 +1027,7 @@ function normalizeForkTriggerRelation(value) {
|
|
|
1005
1027
|
}
|
|
1006
1028
|
async function resolveForkTriggerEvidence(ctx, args) {
|
|
1007
1029
|
const evidence = await ctx.db.get(args.triggeringEvidenceId);
|
|
1008
|
-
if (
|
|
1030
|
+
if (evidence?.nodeType !== "evidence") {
|
|
1009
1031
|
throwStructuredMutationError({
|
|
1010
1032
|
message: "Fork requires an existing evidence node.",
|
|
1011
1033
|
status: 400,
|
|
@@ -1044,16 +1066,16 @@ async function resolveForkTriggerEvidence(ctx, args) {
|
|
|
1044
1066
|
].filter(Boolean)
|
|
1045
1067
|
);
|
|
1046
1068
|
let relation = null;
|
|
1047
|
-
const linkedBeliefNodeId = String(
|
|
1048
|
-
evidenceMetadata.linkedBeliefNodeId ?? ""
|
|
1049
|
-
);
|
|
1069
|
+
const linkedBeliefNodeId = String(evidenceMetadata.linkedBeliefNodeId ?? "");
|
|
1050
1070
|
if (linkedBeliefNodeId && parentRefs.has(linkedBeliefNodeId)) {
|
|
1051
1071
|
relation = normalizeForkTriggerRelation(evidenceMetadata.evidenceRelation);
|
|
1052
1072
|
}
|
|
1053
1073
|
if (!relation) {
|
|
1054
1074
|
for (const parentRef of parentRefs) {
|
|
1055
1075
|
const links = await ctx.db.query("beliefEvidenceLinks").withIndex("by_beliefId", (q) => q.eq("beliefId", parentRef)).collect();
|
|
1056
|
-
const matched = links.find(
|
|
1076
|
+
const matched = links.find(
|
|
1077
|
+
(link) => evidenceRefs.has(String(link.insightId))
|
|
1078
|
+
);
|
|
1057
1079
|
if (matched) {
|
|
1058
1080
|
relation = normalizeForkTriggerRelation(matched.relation);
|
|
1059
1081
|
break;
|
|
@@ -1089,13 +1111,16 @@ async function resolveForkTriggerEvidence(ctx, args) {
|
|
|
1089
1111
|
}
|
|
1090
1112
|
return { evidenceNodeId: args.triggeringEvidenceId, relation };
|
|
1091
1113
|
}
|
|
1092
|
-
|
|
1114
|
+
function insertEpistemicNode(ctx, doc) {
|
|
1093
1115
|
assertUuidV7Identity("epistemicNodes", doc.globalId);
|
|
1094
1116
|
return ctx.db.insert("epistemicNodes", doc);
|
|
1095
1117
|
}
|
|
1096
1118
|
async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
|
|
1097
1119
|
assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
|
|
1098
|
-
const node = await ctx.db.query("epistemicNodes").withIndex(
|
|
1120
|
+
const node = await ctx.db.query("epistemicNodes").withIndex(
|
|
1121
|
+
"by_globalId",
|
|
1122
|
+
(q) => q.eq("globalId", endpoint)
|
|
1123
|
+
).first();
|
|
1099
1124
|
if (!node) {
|
|
1100
1125
|
throw new Error(
|
|
1101
1126
|
`edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
|
|
@@ -1161,7 +1186,7 @@ async function resolveRequiredTopicAnchor(ctx, topicRef) {
|
|
|
1161
1186
|
if (direct?.nodeType === "topic" && cleanString(direct.globalId)) {
|
|
1162
1187
|
return direct;
|
|
1163
1188
|
}
|
|
1164
|
-
} catch
|
|
1189
|
+
} catch {
|
|
1165
1190
|
}
|
|
1166
1191
|
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
|
|
1167
1192
|
if (byGlobalId?.nodeType === "topic" && cleanString(byGlobalId.globalId)) {
|
|
@@ -1246,36 +1271,279 @@ async function createRequiredBeliefTopicEdge(ctx, args) {
|
|
|
1246
1271
|
});
|
|
1247
1272
|
}
|
|
1248
1273
|
|
|
1249
|
-
// src/
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1274
|
+
// src/epistemicBeliefs.core.ts
|
|
1275
|
+
var CONTRACT_CONDITION_TYPES = /* @__PURE__ */ new Set(["assertion", "temporal", "evidential", "threshold", "composite"]);
|
|
1276
|
+
var CONTRACT_DIRECTIONS = /* @__PURE__ */ new Set([
|
|
1277
|
+
"confirms",
|
|
1278
|
+
"falsifies"
|
|
1279
|
+
]);
|
|
1280
|
+
var CONTRACT_LINEAGE_SOURCES = /* @__PURE__ */ new Set(["declared", "inherited"]);
|
|
1281
|
+
var CONTRACT_SCHEDULES = /* @__PURE__ */ new Set([
|
|
1282
|
+
"on_demand",
|
|
1283
|
+
"on_evidence",
|
|
1284
|
+
"periodic",
|
|
1285
|
+
"event_driven"
|
|
1286
|
+
]);
|
|
1287
|
+
var CONTRACT_STATUSES = /* @__PURE__ */ new Set([
|
|
1288
|
+
"active",
|
|
1289
|
+
"satisfied",
|
|
1290
|
+
"violated",
|
|
1291
|
+
"expired",
|
|
1292
|
+
"suspended",
|
|
1293
|
+
"archived"
|
|
1294
|
+
]);
|
|
1295
|
+
function isRecord(value) {
|
|
1296
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1297
|
+
}
|
|
1298
|
+
function readConvexId(value) {
|
|
1299
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1300
|
+
}
|
|
1301
|
+
function readOptionalBoolean(value) {
|
|
1302
|
+
return typeof value === "boolean" ? value : void 0;
|
|
1303
|
+
}
|
|
1304
|
+
function readOptionalNumber(value) {
|
|
1305
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1306
|
+
}
|
|
1307
|
+
function readOptionalString(value) {
|
|
1308
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1309
|
+
}
|
|
1310
|
+
function readRecord(value) {
|
|
1311
|
+
return isRecord(value) ? value : void 0;
|
|
1312
|
+
}
|
|
1313
|
+
function readStringList(value) {
|
|
1314
|
+
if (!Array.isArray(value)) {
|
|
1315
|
+
return;
|
|
1275
1316
|
}
|
|
1317
|
+
const strings = value.filter(
|
|
1318
|
+
(item) => typeof item === "string" && item.length > 0
|
|
1319
|
+
);
|
|
1320
|
+
return strings.length === value.length ? strings : void 0;
|
|
1321
|
+
}
|
|
1322
|
+
function readEnumValue(value, allowed) {
|
|
1323
|
+
return typeof value === "string" && allowed.has(value) ? value : void 0;
|
|
1324
|
+
}
|
|
1325
|
+
function readContractCondition(value) {
|
|
1326
|
+
const record = readRecord(value);
|
|
1327
|
+
const evaluator = readOptionalString(record?.evaluator);
|
|
1328
|
+
const expression = readOptionalString(record?.expression);
|
|
1329
|
+
if (!(record && evaluator && expression)) {
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
return {
|
|
1333
|
+
evaluator,
|
|
1334
|
+
expression,
|
|
1335
|
+
evaluatorConfig: record.evaluatorConfig
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
function readContractModulation(value) {
|
|
1339
|
+
const record = readRecord(value);
|
|
1340
|
+
const onConfirmed = readRecord(record?.onConfirmed);
|
|
1341
|
+
const onDisconfirmed = readRecord(record?.onDisconfirmed);
|
|
1342
|
+
const confirmedDelta = readOptionalNumber(onConfirmed?.delta);
|
|
1343
|
+
const disconfirmedDelta = readOptionalNumber(onDisconfirmed?.delta);
|
|
1344
|
+
if (!(record && onConfirmed && onDisconfirmed)) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
if (confirmedDelta === void 0 || disconfirmedDelta === void 0) {
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
const modulation = {
|
|
1351
|
+
onConfirmed: { delta: confirmedDelta },
|
|
1352
|
+
onDisconfirmed: { delta: disconfirmedDelta }
|
|
1353
|
+
};
|
|
1354
|
+
const confirmedCeiling = readOptionalNumber(onConfirmed.ceiling);
|
|
1355
|
+
if (confirmedCeiling !== void 0) {
|
|
1356
|
+
modulation.onConfirmed.ceiling = confirmedCeiling;
|
|
1357
|
+
}
|
|
1358
|
+
const disconfirmedFloor = readOptionalNumber(onDisconfirmed.floor);
|
|
1359
|
+
if (disconfirmedFloor !== void 0) {
|
|
1360
|
+
modulation.onDisconfirmed.floor = disconfirmedFloor;
|
|
1361
|
+
}
|
|
1362
|
+
const onExpired = readRecord(record.onExpired);
|
|
1363
|
+
const expiredDelta = readOptionalNumber(onExpired?.delta);
|
|
1364
|
+
if (expiredDelta !== void 0) {
|
|
1365
|
+
modulation.onExpired = { delta: expiredDelta };
|
|
1366
|
+
}
|
|
1367
|
+
const onPartial = readRecord(record.onPartial);
|
|
1368
|
+
const partialDelta = readOptionalNumber(onPartial?.delta);
|
|
1369
|
+
const partialThreshold = readOptionalNumber(onPartial?.threshold);
|
|
1370
|
+
if (partialDelta !== void 0 && partialThreshold !== void 0) {
|
|
1371
|
+
modulation.onPartial = {
|
|
1372
|
+
delta: partialDelta,
|
|
1373
|
+
threshold: partialThreshold
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
return modulation;
|
|
1377
|
+
}
|
|
1378
|
+
function readBeliefNodeDoc(value) {
|
|
1379
|
+
if (!isRecord(value)) {
|
|
1380
|
+
return null;
|
|
1381
|
+
}
|
|
1382
|
+
const id = readConvexId(value._id);
|
|
1383
|
+
const nodeType = readOptionalString(value.nodeType);
|
|
1384
|
+
const projectId = readOptionalString(value.projectId);
|
|
1385
|
+
if (!(id && nodeType === "belief" && projectId)) {
|
|
1386
|
+
return null;
|
|
1387
|
+
}
|
|
1388
|
+
const node = { _id: id, nodeType, projectId };
|
|
1389
|
+
const canonicalText = readOptionalString(value.canonicalText);
|
|
1390
|
+
const confidence = readOptionalNumber(value.confidence);
|
|
1391
|
+
const content = readOptionalString(value.content);
|
|
1392
|
+
const epistemicLayer = readOptionalString(value.epistemicLayer);
|
|
1393
|
+
const globalId = readOptionalString(value.globalId);
|
|
1394
|
+
const metadata = readRecord(value.metadata);
|
|
1395
|
+
const predictionMeta = readRecord(value.predictionMeta);
|
|
1396
|
+
const sourceType = readOptionalString(value.sourceType);
|
|
1397
|
+
const status = readOptionalString(value.status);
|
|
1398
|
+
const tenantId = readOptionalString(value.tenantId);
|
|
1399
|
+
const title = readOptionalString(value.title);
|
|
1400
|
+
const topicId = readConvexId(value.topicId);
|
|
1401
|
+
const tupleContradicted = readOptionalBoolean(value.tupleContradicted);
|
|
1402
|
+
const workspaceId = readOptionalString(value.workspaceId);
|
|
1403
|
+
if (canonicalText !== void 0) {
|
|
1404
|
+
node.canonicalText = canonicalText;
|
|
1405
|
+
}
|
|
1406
|
+
if (confidence !== void 0) {
|
|
1407
|
+
node.confidence = confidence;
|
|
1408
|
+
}
|
|
1409
|
+
if (content !== void 0) {
|
|
1410
|
+
node.content = content;
|
|
1411
|
+
}
|
|
1412
|
+
if (epistemicLayer !== void 0) {
|
|
1413
|
+
node.epistemicLayer = epistemicLayer;
|
|
1414
|
+
}
|
|
1415
|
+
if (globalId !== void 0) {
|
|
1416
|
+
node.globalId = globalId;
|
|
1417
|
+
}
|
|
1418
|
+
if (metadata !== void 0) {
|
|
1419
|
+
node.metadata = metadata;
|
|
1420
|
+
}
|
|
1421
|
+
if (predictionMeta !== void 0) {
|
|
1422
|
+
node.predictionMeta = predictionMeta;
|
|
1423
|
+
}
|
|
1424
|
+
if (sourceType !== void 0) {
|
|
1425
|
+
node.sourceType = sourceType;
|
|
1426
|
+
}
|
|
1427
|
+
if (status !== void 0) {
|
|
1428
|
+
node.status = status;
|
|
1429
|
+
}
|
|
1430
|
+
if (tenantId !== void 0) {
|
|
1431
|
+
node.tenantId = tenantId;
|
|
1432
|
+
}
|
|
1433
|
+
if (title !== void 0) {
|
|
1434
|
+
node.title = title;
|
|
1435
|
+
}
|
|
1436
|
+
if (topicId !== void 0) {
|
|
1437
|
+
node.topicId = topicId;
|
|
1438
|
+
}
|
|
1439
|
+
if (tupleContradicted !== void 0) {
|
|
1440
|
+
node.tupleContradicted = tupleContradicted;
|
|
1441
|
+
}
|
|
1442
|
+
if (workspaceId !== void 0) {
|
|
1443
|
+
node.workspaceId = workspaceId;
|
|
1444
|
+
}
|
|
1445
|
+
return node;
|
|
1446
|
+
}
|
|
1447
|
+
function readContractRow(value) {
|
|
1448
|
+
if (!isRecord(value)) {
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
const beliefNodeId = readConvexId(value.beliefNodeId);
|
|
1452
|
+
const condition = readContractCondition(value.condition);
|
|
1453
|
+
const conditionType = readEnumValue(
|
|
1454
|
+
value.conditionType,
|
|
1455
|
+
CONTRACT_CONDITION_TYPES
|
|
1456
|
+
);
|
|
1457
|
+
const contractId = readOptionalString(value.contractId);
|
|
1458
|
+
const createdAt = readOptionalNumber(value.createdAt);
|
|
1459
|
+
const createdBy = readOptionalString(value.createdBy);
|
|
1460
|
+
const direction = readEnumValue(value.direction, CONTRACT_DIRECTIONS);
|
|
1461
|
+
const evaluationSchedule = readEnumValue(
|
|
1462
|
+
value.evaluationSchedule,
|
|
1463
|
+
CONTRACT_SCHEDULES
|
|
1464
|
+
);
|
|
1465
|
+
const lineageSource = readEnumValue(
|
|
1466
|
+
value.lineageSource,
|
|
1467
|
+
CONTRACT_LINEAGE_SOURCES
|
|
1468
|
+
);
|
|
1469
|
+
const modulation = readContractModulation(value.modulation);
|
|
1470
|
+
const status = readEnumValue(value.status, CONTRACT_STATUSES);
|
|
1471
|
+
const title = readOptionalString(value.title);
|
|
1472
|
+
const updatedAt = readOptionalNumber(value.updatedAt);
|
|
1473
|
+
if (!(beliefNodeId && condition && conditionType && contractId && createdAt !== void 0 && createdBy && direction && evaluationSchedule && lineageSource && modulation && status && title && updatedAt !== void 0)) {
|
|
1474
|
+
return null;
|
|
1475
|
+
}
|
|
1476
|
+
const row = {
|
|
1477
|
+
beliefNodeId,
|
|
1478
|
+
condition,
|
|
1479
|
+
conditionType,
|
|
1480
|
+
contractId,
|
|
1481
|
+
createdAt,
|
|
1482
|
+
createdBy,
|
|
1483
|
+
direction,
|
|
1484
|
+
evaluationSchedule,
|
|
1485
|
+
lineageSource,
|
|
1486
|
+
modulation,
|
|
1487
|
+
status,
|
|
1488
|
+
title,
|
|
1489
|
+
updatedAt
|
|
1490
|
+
};
|
|
1491
|
+
const compositeOf = readStringList(value.compositeOf);
|
|
1492
|
+
if (compositeOf !== void 0) {
|
|
1493
|
+
row.compositeOf = compositeOf;
|
|
1494
|
+
}
|
|
1495
|
+
const compositeOperator = readOptionalString(value.compositeOperator);
|
|
1496
|
+
if (compositeOperator === "all" || compositeOperator === "any" || compositeOperator === "majority") {
|
|
1497
|
+
row.compositeOperator = compositeOperator;
|
|
1498
|
+
}
|
|
1499
|
+
const deadline = readOptionalNumber(value.deadline);
|
|
1500
|
+
if (deadline !== void 0) {
|
|
1501
|
+
row.deadline = deadline;
|
|
1502
|
+
}
|
|
1503
|
+
const description = readOptionalString(value.description);
|
|
1504
|
+
if (description !== void 0) {
|
|
1505
|
+
row.description = description;
|
|
1506
|
+
}
|
|
1507
|
+
const evaluationCount = readOptionalNumber(value.evaluationCount);
|
|
1508
|
+
if (evaluationCount !== void 0) {
|
|
1509
|
+
row.evaluationCount = evaluationCount;
|
|
1510
|
+
}
|
|
1511
|
+
const inheritedAt = readOptionalNumber(value.inheritedAt);
|
|
1512
|
+
if (inheritedAt !== void 0) {
|
|
1513
|
+
row.inheritedAt = inheritedAt;
|
|
1514
|
+
}
|
|
1515
|
+
const inheritedFromBeliefNodeId = readConvexId(
|
|
1516
|
+
value.inheritedFromBeliefNodeId
|
|
1517
|
+
);
|
|
1518
|
+
if (inheritedFromBeliefNodeId !== void 0) {
|
|
1519
|
+
row.inheritedFromBeliefNodeId = inheritedFromBeliefNodeId;
|
|
1520
|
+
}
|
|
1521
|
+
const inheritedFromContractId = readOptionalString(
|
|
1522
|
+
value.inheritedFromContractId
|
|
1523
|
+
);
|
|
1524
|
+
if (inheritedFromContractId !== void 0) {
|
|
1525
|
+
row.inheritedFromContractId = inheritedFromContractId;
|
|
1526
|
+
}
|
|
1527
|
+
const lastEvaluatedAt = readOptionalNumber(value.lastEvaluatedAt);
|
|
1528
|
+
if (lastEvaluatedAt !== void 0) {
|
|
1529
|
+
row.lastEvaluatedAt = lastEvaluatedAt;
|
|
1530
|
+
}
|
|
1531
|
+
const periodicIntervalMs = readOptionalNumber(value.periodicIntervalMs);
|
|
1532
|
+
if (periodicIntervalMs !== void 0) {
|
|
1533
|
+
row.periodicIntervalMs = periodicIntervalMs;
|
|
1534
|
+
}
|
|
1535
|
+
const topicId = readConvexId(value.topicId) ?? readOptionalString(value.topicId);
|
|
1536
|
+
if (topicId !== void 0) {
|
|
1537
|
+
row.topicId = topicId;
|
|
1538
|
+
}
|
|
1539
|
+
return row;
|
|
1540
|
+
}
|
|
1541
|
+
function readRowList(values, reader) {
|
|
1542
|
+
return values.flatMap((value) => {
|
|
1543
|
+
const row = reader(value);
|
|
1544
|
+
return row ? [row] : [];
|
|
1545
|
+
});
|
|
1276
1546
|
}
|
|
1277
|
-
|
|
1278
|
-
// src/epistemicBeliefs.core.ts
|
|
1279
1547
|
var create = mutation({
|
|
1280
1548
|
args: {
|
|
1281
1549
|
...optionalBeliefScopeArgs,
|
|
@@ -1325,41 +1593,7 @@ var create = mutation({
|
|
|
1325
1593
|
returns: permissiveReturn,
|
|
1326
1594
|
handler: async (ctx, args) => {
|
|
1327
1595
|
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
1328
|
-
const
|
|
1329
|
-
if (!topicRef) {
|
|
1330
|
-
throwStructuredMutationError({
|
|
1331
|
-
message: "Belief creation requires an explicit topic epistemic node.",
|
|
1332
|
-
status: 400,
|
|
1333
|
-
code: "INVALID_ARGUMENT",
|
|
1334
|
-
invariantCode: "belief.topic_node_required",
|
|
1335
|
-
suggestion: "Pass topicGlobalId or topicNodeId for a topic in epistemicNodes before creating a belief.",
|
|
1336
|
-
details: {
|
|
1337
|
-
topicId: args.topicId,
|
|
1338
|
-
topicNodeId: args.topicNodeId,
|
|
1339
|
-
topicGlobalId: args.topicGlobalId
|
|
1340
|
-
}
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
|
|
1344
|
-
const scope = scopeFromTopicAnchor(topicNode);
|
|
1345
|
-
assertWorkspaceScopedEpistemicNodeScope({
|
|
1346
|
-
scope,
|
|
1347
|
-
nodeType: "belief",
|
|
1348
|
-
mutationName: "epistemicBeliefs.create"
|
|
1349
|
-
});
|
|
1350
|
-
const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
|
|
1351
|
-
category: "belief_type",
|
|
1352
|
-
value: args.beliefType,
|
|
1353
|
-
tenantId: scope.tenantId,
|
|
1354
|
-
context: "epistemicBeliefs.create"
|
|
1355
|
-
});
|
|
1356
|
-
if (scope.projectId) {
|
|
1357
|
-
await requireProjectWriteAccess(
|
|
1358
|
-
ctx,
|
|
1359
|
-
scope.projectId,
|
|
1360
|
-
authenticatedUserId
|
|
1361
|
-
);
|
|
1362
|
-
}
|
|
1596
|
+
const { normalizedBeliefType, scope, topicNode } = await resolveCreateBeliefAdmission(ctx, args, authenticatedUserId);
|
|
1363
1597
|
const now = Date.now();
|
|
1364
1598
|
const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
|
|
1365
1599
|
const initialBeliefStatus = args.worktreeId ? "hypothesis" : "assumption";
|
|
@@ -1371,7 +1605,7 @@ var create = mutation({
|
|
|
1371
1605
|
opinion_a: baseRate
|
|
1372
1606
|
};
|
|
1373
1607
|
const pillar = normalizePillar(args.pillar);
|
|
1374
|
-
const additionalMeta = args.metadata
|
|
1608
|
+
const additionalMeta = readRecord(args.metadata) ?? {};
|
|
1375
1609
|
const beliefGlobalId = generateGlobalId();
|
|
1376
1610
|
const nodeId = await insertEpistemicNode(ctx, {
|
|
1377
1611
|
globalId: beliefGlobalId,
|
|
@@ -1533,6 +1767,44 @@ Rationale: ${args.rationale}` : args.formulation
|
|
|
1533
1767
|
return { nodeId };
|
|
1534
1768
|
}
|
|
1535
1769
|
});
|
|
1770
|
+
async function resolveCreateBeliefAdmission(ctx, args, authenticatedUserId) {
|
|
1771
|
+
const topicRef = readTopicNodeRef(args);
|
|
1772
|
+
if (!topicRef) {
|
|
1773
|
+
throwStructuredMutationError({
|
|
1774
|
+
message: "Belief creation requires an explicit topic epistemic node.",
|
|
1775
|
+
status: 400,
|
|
1776
|
+
code: "INVALID_ARGUMENT",
|
|
1777
|
+
invariantCode: "belief.topic_node_required",
|
|
1778
|
+
suggestion: "Pass topicGlobalId or topicNodeId for a topic in epistemicNodes before creating a belief.",
|
|
1779
|
+
details: {
|
|
1780
|
+
topicId: args.topicId,
|
|
1781
|
+
topicNodeId: args.topicNodeId,
|
|
1782
|
+
topicGlobalId: args.topicGlobalId
|
|
1783
|
+
}
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
|
|
1787
|
+
const anchoredScope = scopeFromTopicAnchor(topicNode);
|
|
1788
|
+
const scope = {
|
|
1789
|
+
...anchoredScope,
|
|
1790
|
+
topicId: anchoredScope.topicId
|
|
1791
|
+
};
|
|
1792
|
+
assertWorkspaceScopedEpistemicNodeScope({
|
|
1793
|
+
scope,
|
|
1794
|
+
nodeType: "belief",
|
|
1795
|
+
mutationName: "epistemicBeliefs.create"
|
|
1796
|
+
});
|
|
1797
|
+
const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
|
|
1798
|
+
category: "belief_type",
|
|
1799
|
+
value: args.beliefType,
|
|
1800
|
+
tenantId: scope.tenantId,
|
|
1801
|
+
context: "epistemicBeliefs.create"
|
|
1802
|
+
});
|
|
1803
|
+
if (scope.projectId) {
|
|
1804
|
+
await requireScopeWriteAccess(ctx, scope.projectId, authenticatedUserId);
|
|
1805
|
+
}
|
|
1806
|
+
return { normalizedBeliefType, scope, topicNode };
|
|
1807
|
+
}
|
|
1536
1808
|
var getById = query({
|
|
1537
1809
|
args: {
|
|
1538
1810
|
nodeId: v.optional(v.id("epistemicNodes")),
|
|
@@ -1544,8 +1816,8 @@ var getById = query({
|
|
|
1544
1816
|
if (!id) {
|
|
1545
1817
|
return null;
|
|
1546
1818
|
}
|
|
1547
|
-
const node = await ctx.db.get(id);
|
|
1548
|
-
if (!node
|
|
1819
|
+
const node = readBeliefNodeDoc(await ctx.db.get(id));
|
|
1820
|
+
if (!node) {
|
|
1549
1821
|
return null;
|
|
1550
1822
|
}
|
|
1551
1823
|
return node;
|
|
@@ -1563,48 +1835,8 @@ var refineBelief = mutation({
|
|
|
1563
1835
|
handler: async (ctx, args) => {
|
|
1564
1836
|
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
1565
1837
|
const now = Date.now();
|
|
1566
|
-
const node = await ctx
|
|
1567
|
-
|
|
1568
|
-
throwStructuredMutationError({
|
|
1569
|
-
message: "Belief not found.",
|
|
1570
|
-
status: 404,
|
|
1571
|
-
code: "NOT_FOUND",
|
|
1572
|
-
invariantCode: "belief.exists",
|
|
1573
|
-
suggestion: "Verify nodeId points to an existing belief before refining.",
|
|
1574
|
-
details: { nodeId: args.nodeId }
|
|
1575
|
-
});
|
|
1576
|
-
}
|
|
1577
|
-
if (node.nodeType !== "belief") {
|
|
1578
|
-
throwStructuredMutationError({
|
|
1579
|
-
message: `refineBelief only applies to belief nodes. Received nodeType "${node.nodeType}".`,
|
|
1580
|
-
status: 400,
|
|
1581
|
-
code: "INVALID_ARGUMENT",
|
|
1582
|
-
invariantCode: "entity.no_refine",
|
|
1583
|
-
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations.",
|
|
1584
|
-
details: { nodeId: args.nodeId, nodeType: node.nodeType }
|
|
1585
|
-
});
|
|
1586
|
-
}
|
|
1587
|
-
if (!node.projectId) {
|
|
1588
|
-
throwStructuredMutationError({
|
|
1589
|
-
message: "Belief has no project scope.",
|
|
1590
|
-
status: 400,
|
|
1591
|
-
code: "MISSING_SCOPE",
|
|
1592
|
-
invariantCode: "belief.project_required",
|
|
1593
|
-
suggestion: "Belief must have a projectId to refine.",
|
|
1594
|
-
details: { nodeId: args.nodeId }
|
|
1595
|
-
});
|
|
1596
|
-
}
|
|
1597
|
-
await requireProjectWriteAccess(ctx, node.projectId, authenticatedUserId);
|
|
1598
|
-
if (typeof node.confidence === "number" && Number.isFinite(node.confidence)) {
|
|
1599
|
-
throwStructuredMutationError({
|
|
1600
|
-
message: "Scored beliefs are immutable. Use forkBelief to evolve a scored belief.",
|
|
1601
|
-
status: 409,
|
|
1602
|
-
code: "CONFLICT",
|
|
1603
|
-
invariantCode: "belief.versioning.scored_immutable",
|
|
1604
|
-
suggestion: "Use forkBelief() to create a new version instead of refining in place.",
|
|
1605
|
-
details: { nodeId: args.nodeId, confidence: node.confidence }
|
|
1606
|
-
});
|
|
1607
|
-
}
|
|
1838
|
+
const node = await requireRefinableBelief(ctx, args.nodeId);
|
|
1839
|
+
await requireScopeWriteAccess(ctx, node.projectId, authenticatedUserId);
|
|
1608
1840
|
const nextText = typeof args.canonicalText === "string" && args.canonicalText.trim().length > 0 ? args.canonicalText.trim() : void 0;
|
|
1609
1841
|
const nextTitle = typeof args.title === "string" && args.title.trim().length > 0 ? args.title.trim() : void 0;
|
|
1610
1842
|
const patch = { updatedAt: now };
|
|
@@ -1665,6 +1897,110 @@ Rationale: ${args.rationale}` : nextText
|
|
|
1665
1897
|
return { nodeId: args.nodeId };
|
|
1666
1898
|
}
|
|
1667
1899
|
});
|
|
1900
|
+
async function requireRefinableBelief(ctx, nodeId) {
|
|
1901
|
+
const node = await ctx.db.get(nodeId);
|
|
1902
|
+
if (!node) {
|
|
1903
|
+
throwStructuredMutationError({
|
|
1904
|
+
message: "Belief not found.",
|
|
1905
|
+
status: 404,
|
|
1906
|
+
code: "NOT_FOUND",
|
|
1907
|
+
invariantCode: "belief.exists",
|
|
1908
|
+
suggestion: "Verify nodeId points to an existing belief before refining.",
|
|
1909
|
+
details: { nodeId }
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
const nodeType = isRecord(node) ? readOptionalString(node.nodeType) : void 0;
|
|
1913
|
+
if (nodeType !== "belief") {
|
|
1914
|
+
throwStructuredMutationError({
|
|
1915
|
+
message: `refineBelief only applies to belief nodes. Received nodeType "${nodeType}".`,
|
|
1916
|
+
status: 400,
|
|
1917
|
+
code: "INVALID_ARGUMENT",
|
|
1918
|
+
invariantCode: "entity.no_refine",
|
|
1919
|
+
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations.",
|
|
1920
|
+
details: { nodeId, nodeType }
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
const projectId = isRecord(node) ? readOptionalString(node.projectId) : void 0;
|
|
1924
|
+
if (!projectId) {
|
|
1925
|
+
throwStructuredMutationError({
|
|
1926
|
+
message: "Belief has no project scope.",
|
|
1927
|
+
status: 400,
|
|
1928
|
+
code: "MISSING_SCOPE",
|
|
1929
|
+
invariantCode: "belief.project_required",
|
|
1930
|
+
suggestion: "Belief must have a projectId to refine.",
|
|
1931
|
+
details: { nodeId }
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
const confidence = isRecord(node) ? readOptionalNumber(node.confidence) : void 0;
|
|
1935
|
+
if (confidence !== void 0) {
|
|
1936
|
+
throwStructuredMutationError({
|
|
1937
|
+
message: "Scored beliefs are immutable. Use forkBelief to evolve a scored belief.",
|
|
1938
|
+
status: 409,
|
|
1939
|
+
code: "CONFLICT",
|
|
1940
|
+
invariantCode: "belief.versioning.scored_immutable",
|
|
1941
|
+
suggestion: "Use forkBelief() to create a new version instead of refining in place.",
|
|
1942
|
+
details: { nodeId, confidence }
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1945
|
+
const beliefNode = readBeliefNodeDoc(node);
|
|
1946
|
+
if (!beliefNode) {
|
|
1947
|
+
throwStructuredMutationError({
|
|
1948
|
+
message: "Belief row is missing required typed fields.",
|
|
1949
|
+
status: 400,
|
|
1950
|
+
code: "MISSING_SCOPE",
|
|
1951
|
+
invariantCode: "belief.typed_row_required",
|
|
1952
|
+
suggestion: "Backfill belief project/topic/global scope before refining.",
|
|
1953
|
+
details: { nodeId }
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
return beliefNode;
|
|
1957
|
+
}
|
|
1958
|
+
async function requireForkParentAdmission(ctx, args, authenticatedUserId) {
|
|
1959
|
+
const parentRaw = await ctx.db.get(args.parentNodeId);
|
|
1960
|
+
if (!parentRaw) {
|
|
1961
|
+
throwStructuredMutationError({
|
|
1962
|
+
message: "Parent node not found.",
|
|
1963
|
+
status: 404,
|
|
1964
|
+
code: "NOT_FOUND",
|
|
1965
|
+
invariantCode: "belief.exists",
|
|
1966
|
+
suggestion: "Verify parentNodeId points to an existing node before forking.",
|
|
1967
|
+
details: { parentNodeId: args.parentNodeId }
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
const parent = readBeliefNodeDoc(parentRaw);
|
|
1971
|
+
const parentNodeType = isRecord(parentRaw) ? readOptionalString(parentRaw.nodeType) : void 0;
|
|
1972
|
+
if (!parent) {
|
|
1973
|
+
throwStructuredMutationError({
|
|
1974
|
+
message: `forkBelief only applies to fully scoped belief nodes. Received nodeType "${parentNodeType}". Entity nodes (company, person, investor, etc.) are mutable \u2014 use entityLifecycle.updateEntityAttributes instead of forking.`,
|
|
1975
|
+
status: 400,
|
|
1976
|
+
code: "INVALID_ARGUMENT",
|
|
1977
|
+
invariantCode: "entity.no_fork",
|
|
1978
|
+
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. forkBelief is for belief nodes only, and parent beliefs must carry project scope.",
|
|
1979
|
+
details: {
|
|
1980
|
+
parentNodeId: args.parentNodeId,
|
|
1981
|
+
nodeType: parentNodeType
|
|
1982
|
+
}
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
const parentGlobalId = parent.globalId;
|
|
1986
|
+
if (!parentGlobalId) {
|
|
1987
|
+
throwStructuredMutationError({
|
|
1988
|
+
message: "Parent belief has no globalId for lineage edge creation.",
|
|
1989
|
+
status: 400,
|
|
1990
|
+
code: "INVALID_ARGUMENT",
|
|
1991
|
+
invariantCode: "belief.global_id_required",
|
|
1992
|
+
suggestion: "Backfill parent belief globalId before forking so Neo4j lineage edges can use canonical endpoints.",
|
|
1993
|
+
details: { parentNodeId: args.parentNodeId }
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
await requireScopeWriteAccess(ctx, parent.projectId, authenticatedUserId);
|
|
1997
|
+
return {
|
|
1998
|
+
metadata: parent.metadata,
|
|
1999
|
+
parent,
|
|
2000
|
+
parentGlobalId,
|
|
2001
|
+
parentRaw
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
1668
2004
|
var getByProject = query({
|
|
1669
2005
|
args: {
|
|
1670
2006
|
...optionalBeliefScopeArgs,
|
|
@@ -1680,7 +2016,7 @@ var getByProject = query({
|
|
|
1680
2016
|
},
|
|
1681
2017
|
returns: permissiveReturn,
|
|
1682
2018
|
handler: async (ctx, args) => {
|
|
1683
|
-
if (!args.projectId
|
|
2019
|
+
if (!(args.projectId || args.topicId)) {
|
|
1684
2020
|
return [];
|
|
1685
2021
|
}
|
|
1686
2022
|
const pageSize = clampBeliefLimit(args.limit);
|
|
@@ -1712,11 +2048,14 @@ var getByProject = query({
|
|
|
1712
2048
|
return [];
|
|
1713
2049
|
}
|
|
1714
2050
|
}
|
|
1715
|
-
const
|
|
2051
|
+
const query2 = ctx.db.query("epistemicNodes").withIndex(
|
|
1716
2052
|
"by_topic_type",
|
|
1717
2053
|
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
1718
2054
|
);
|
|
1719
|
-
const nodes =
|
|
2055
|
+
const nodes = readRowList(
|
|
2056
|
+
await query2.order("desc").take(scanLimit),
|
|
2057
|
+
readBeliefNodeDoc
|
|
2058
|
+
);
|
|
1720
2059
|
const scopedNodes = nodes.filter(
|
|
1721
2060
|
(node) => nodeMatchesWorkspaceReasoningScope(node, scope)
|
|
1722
2061
|
);
|
|
@@ -1746,11 +2085,14 @@ var getByTopic = query({
|
|
|
1746
2085
|
const scope = await resolveTopicProjectScope(ctx, {
|
|
1747
2086
|
topicId: args.topicId
|
|
1748
2087
|
});
|
|
1749
|
-
const
|
|
2088
|
+
const query2 = ctx.db.query("epistemicNodes").withIndex(
|
|
1750
2089
|
"by_topic_type",
|
|
1751
2090
|
(q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
|
|
1752
2091
|
);
|
|
1753
|
-
const nodes =
|
|
2092
|
+
const nodes = readRowList(
|
|
2093
|
+
await query2.order("desc").take(scanLimit),
|
|
2094
|
+
readBeliefNodeDoc
|
|
2095
|
+
);
|
|
1754
2096
|
const scopedNodes = nodes.filter(
|
|
1755
2097
|
(node) => nodeMatchesWorkspaceReasoningScope(node, {
|
|
1756
2098
|
tenantId: scope.tenantId,
|
|
@@ -1783,44 +2125,12 @@ var forkBelief = mutation({
|
|
|
1783
2125
|
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
1784
2126
|
const now = Date.now();
|
|
1785
2127
|
await getActiveConfidencePolicy(ctx);
|
|
1786
|
-
const parent = await ctx
|
|
1787
|
-
if (!parent) {
|
|
1788
|
-
throwStructuredMutationError({
|
|
1789
|
-
message: "Parent node not found.",
|
|
1790
|
-
status: 404,
|
|
1791
|
-
code: "NOT_FOUND",
|
|
1792
|
-
invariantCode: "belief.exists",
|
|
1793
|
-
suggestion: "Verify parentNodeId points to an existing node before forking.",
|
|
1794
|
-
details: { parentNodeId: args.parentNodeId }
|
|
1795
|
-
});
|
|
1796
|
-
}
|
|
1797
|
-
if (parent.nodeType !== "belief") {
|
|
1798
|
-
throwStructuredMutationError({
|
|
1799
|
-
message: `forkBelief only applies to belief nodes. Received nodeType "${parent.nodeType}". Entity nodes (company, person, investor, etc.) are mutable \u2014 use entityLifecycle.updateEntityAttributes instead of forking.`,
|
|
1800
|
-
status: 400,
|
|
1801
|
-
code: "INVALID_ARGUMENT",
|
|
1802
|
-
invariantCode: "entity.no_fork",
|
|
1803
|
-
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. forkBelief is for belief nodes only.",
|
|
1804
|
-
details: { parentNodeId: args.parentNodeId, nodeType: parent.nodeType }
|
|
1805
|
-
});
|
|
1806
|
-
}
|
|
1807
|
-
if (!parent.projectId) {
|
|
1808
|
-
throwStructuredMutationError({
|
|
1809
|
-
message: "Parent belief has no project scope.",
|
|
1810
|
-
status: 400,
|
|
1811
|
-
code: "MISSING_SCOPE",
|
|
1812
|
-
invariantCode: "belief.project_required",
|
|
1813
|
-
suggestion: "Belief must have a projectId to fork.",
|
|
1814
|
-
details: { parentNodeId: args.parentNodeId }
|
|
1815
|
-
});
|
|
1816
|
-
}
|
|
1817
|
-
await requireProjectWriteAccess(ctx, parent.projectId, authenticatedUserId);
|
|
1818
|
-
const metadata = parent.metadata;
|
|
2128
|
+
const { metadata, parent, parentGlobalId, parentRaw } = await requireForkParentAdmission(ctx, args, authenticatedUserId);
|
|
1819
2129
|
const forkBeliefStatus = "hypothesis";
|
|
1820
2130
|
const forkMode = args.forkMode ?? "supersede";
|
|
1821
2131
|
const triggerEvidence = await resolveForkTriggerEvidence(ctx, {
|
|
1822
2132
|
parentNodeId: args.parentNodeId,
|
|
1823
|
-
parent,
|
|
2133
|
+
parent: parentRaw,
|
|
1824
2134
|
triggeringEvidenceId: args.triggeringEvidenceId,
|
|
1825
2135
|
forkMode
|
|
1826
2136
|
});
|
|
@@ -1867,7 +2177,7 @@ var forkBelief = mutation({
|
|
|
1867
2177
|
tupleContradicted: false
|
|
1868
2178
|
},
|
|
1869
2179
|
beliefStatus: forkBeliefStatus,
|
|
1870
|
-
sourceType: parent.sourceType,
|
|
2180
|
+
sourceType: parent.sourceType ?? "human",
|
|
1871
2181
|
confidence: void 0,
|
|
1872
2182
|
tupleContradicted: false,
|
|
1873
2183
|
verificationStatus: "unverified",
|
|
@@ -1899,23 +2209,21 @@ var forkBelief = mutation({
|
|
|
1899
2209
|
operation: "upsert"
|
|
1900
2210
|
});
|
|
1901
2211
|
}
|
|
1902
|
-
const inheritedContracts =
|
|
1903
|
-
"by_belief",
|
|
1904
|
-
|
|
1905
|
-
)
|
|
2212
|
+
const inheritedContracts = readRowList(
|
|
2213
|
+
await ctx.db.query("epistemicContracts").withIndex("by_belief", (q) => q.eq("beliefNodeId", args.parentNodeId)).collect(),
|
|
2214
|
+
readContractRow
|
|
2215
|
+
);
|
|
1906
2216
|
for (const contract of inheritedContracts) {
|
|
1907
2217
|
if (contract.status === "archived") {
|
|
1908
2218
|
continue;
|
|
1909
2219
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
})
|
|
1918
|
-
);
|
|
2220
|
+
const inheritedContract = createInheritedContractRecord(contract, {
|
|
2221
|
+
beliefNodeId: newNodeId,
|
|
2222
|
+
topicId: parent.topicId,
|
|
2223
|
+
createdBy: authenticatedUserId,
|
|
2224
|
+
now
|
|
2225
|
+
});
|
|
2226
|
+
await ctx.db.insert("epistemicContracts", { ...inheritedContract });
|
|
1919
2227
|
}
|
|
1920
2228
|
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1921
2229
|
nodeId: newNodeId,
|
|
@@ -1924,7 +2232,7 @@ var forkBelief = mutation({
|
|
|
1924
2232
|
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
1925
2233
|
globalId: generateGlobalId(),
|
|
1926
2234
|
fromGlobalId: newBeliefGlobalId,
|
|
1927
|
-
toGlobalId:
|
|
2235
|
+
toGlobalId: parentGlobalId,
|
|
1928
2236
|
edgeType: forkMode === "supersede" ? "supersedes" : "derived_from",
|
|
1929
2237
|
context: `Fork reason: ${args.forkReason}; triggering evidence: ${triggerEvidence.evidenceNodeId}`,
|
|
1930
2238
|
createdBy: authenticatedUserId,
|