@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,551 +1,143 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { requireScopeWriteAccess } from '@lucern/access-control/access';
|
|
2
2
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
3
|
-
import {
|
|
3
|
+
import { v } from 'convex/values';
|
|
4
|
+
import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
|
|
5
|
+
import { componentsGeneric, internalMutationGeneric, mutationGeneric } from 'convex/server';
|
|
6
|
+
import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, readOpinionFromRecord, hasProjectedOpinionChanged } from '@lucern/confidence';
|
|
4
7
|
import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
5
|
-
import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, hasProjectedOpinionChanged, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, readOpinionFromRecord } from '@lucern/confidence';
|
|
6
|
-
import { requireScopeWriteAccess } from '@lucern/access-control/access';
|
|
7
|
-
import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
|
|
8
8
|
import '@lucern/access-control/audience';
|
|
9
9
|
import { getCurrentUserId } from '@lucern/access-control/auth';
|
|
10
|
+
import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
|
|
10
11
|
|
|
11
12
|
// src/epistemicBeliefs.lifecycle.ts
|
|
12
|
-
var
|
|
13
|
+
var unsafeApi = unsafeConvexAnyApi(
|
|
14
|
+
"graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
|
|
15
|
+
);
|
|
16
|
+
var api = unsafeApi;
|
|
13
17
|
componentsGeneric();
|
|
14
|
-
var internal =
|
|
18
|
+
var internal = unsafeApi;
|
|
15
19
|
var internalMutation = internalMutationGeneric;
|
|
16
20
|
var mutation = mutationGeneric;
|
|
17
21
|
|
|
18
|
-
// src/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
// src/beliefLifecycle.ts
|
|
23
|
+
var BELIEF_STATUS_VALUES = [
|
|
24
|
+
"assumption",
|
|
25
|
+
"hypothesis",
|
|
26
|
+
"active",
|
|
27
|
+
"superseded",
|
|
28
|
+
"resolved_true",
|
|
29
|
+
"resolved_false"
|
|
30
|
+
];
|
|
31
|
+
function isBeliefLifecycleStatus(value) {
|
|
32
|
+
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
22
33
|
}
|
|
23
|
-
function
|
|
24
|
-
if (
|
|
25
|
-
return;
|
|
34
|
+
function normalizeLegacyBeliefStatus(value) {
|
|
35
|
+
if (isBeliefLifecycleStatus(value)) {
|
|
36
|
+
return value;
|
|
26
37
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// src/topicScope.ts
|
|
31
|
-
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
32
|
-
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
33
|
-
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
34
|
-
return null;
|
|
38
|
+
if (value === "belief" || value === "established" || value === "emerging") {
|
|
39
|
+
return "active";
|
|
35
40
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
39
|
-
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
40
|
-
node = byGlobalId;
|
|
41
|
-
}
|
|
42
|
-
} catch (error) {
|
|
43
|
-
debugGraphPrimitiveFallback(
|
|
44
|
-
"[topicScope] topic-node scope lookup by globalId failed",
|
|
45
|
-
{ error, ref }
|
|
46
|
-
);
|
|
41
|
+
if (value === "fact" || value === "confirmed") {
|
|
42
|
+
return "resolved_true";
|
|
47
43
|
}
|
|
48
|
-
if (
|
|
49
|
-
return
|
|
44
|
+
if (value === "disconfirmed" || value === "expired") {
|
|
45
|
+
return "resolved_false";
|
|
50
46
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return null;
|
|
47
|
+
if (value === "deprecated") {
|
|
48
|
+
return "superseded";
|
|
54
49
|
}
|
|
55
|
-
return
|
|
56
|
-
topicId: scopeKey,
|
|
57
|
-
projectId: asMappedProjectId(node),
|
|
58
|
-
source: "topic_node"
|
|
59
|
-
};
|
|
50
|
+
return null;
|
|
60
51
|
}
|
|
61
|
-
function
|
|
62
|
-
if (!
|
|
63
|
-
return;
|
|
52
|
+
function normalizeBeliefConfidence(confidence) {
|
|
53
|
+
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
54
|
+
return null;
|
|
64
55
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return directLegacyProjectId;
|
|
56
|
+
if (confidence >= 0 && confidence <= 1) {
|
|
57
|
+
return confidence;
|
|
68
58
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return candidate ? candidate : void 0;
|
|
72
|
-
}
|
|
73
|
-
function normalizeScopeValue(value) {
|
|
74
|
-
if (typeof value !== "string") {
|
|
75
|
-
return;
|
|
59
|
+
if (confidence > 1 && confidence <= 100) {
|
|
60
|
+
return confidence / 100;
|
|
76
61
|
}
|
|
77
|
-
|
|
78
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
79
|
-
}
|
|
80
|
-
function pickPrimaryTopic(candidates) {
|
|
81
|
-
return [...candidates].sort((a, b) => {
|
|
82
|
-
const depthA = a.depth ?? 9999;
|
|
83
|
-
const depthB = b.depth ?? 9999;
|
|
84
|
-
if (depthA !== depthB) {
|
|
85
|
-
return depthA - depthB;
|
|
86
|
-
}
|
|
87
|
-
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
88
|
-
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
89
|
-
if (createdA !== createdB) {
|
|
90
|
-
return createdA - createdB;
|
|
91
|
-
}
|
|
92
|
-
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
93
|
-
})[0];
|
|
62
|
+
return null;
|
|
94
63
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
100
|
-
).collect();
|
|
101
|
-
} catch (error) {
|
|
102
|
-
debugGraphPrimitiveFallback(
|
|
103
|
-
"[topicScope] Failed to resolve scope alias via index",
|
|
104
|
-
{
|
|
105
|
-
error,
|
|
106
|
-
scopeId
|
|
107
|
-
}
|
|
108
|
-
);
|
|
109
|
-
const topics = await ctx.db.query("topics").collect();
|
|
110
|
-
return topics.filter((topic) => {
|
|
111
|
-
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
112
|
-
const mappedProjectId = asMappedProjectId(topic);
|
|
113
|
-
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
114
|
-
});
|
|
64
|
+
function isResolvedByConfidence(confidence) {
|
|
65
|
+
const normalized = normalizeBeliefConfidence(confidence);
|
|
66
|
+
if (normalized === null) {
|
|
67
|
+
return false;
|
|
115
68
|
}
|
|
69
|
+
return normalized <= 0 || normalized >= 1;
|
|
116
70
|
}
|
|
117
|
-
|
|
118
|
-
|
|
71
|
+
function getPredictionMetaFromMetadata(metadata) {
|
|
72
|
+
return metadata?.predictionMeta;
|
|
73
|
+
}
|
|
74
|
+
function resolvedPredictionStatus(predictionMeta) {
|
|
75
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
119
76
|
return null;
|
|
120
77
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
"[topicScope] Failed to resolve topic by host query",
|
|
128
|
-
{
|
|
129
|
-
error,
|
|
130
|
-
topicId
|
|
131
|
-
}
|
|
132
|
-
);
|
|
133
|
-
return null;
|
|
78
|
+
const outcome = predictionMeta.outcome;
|
|
79
|
+
if (outcome === "confirmed") {
|
|
80
|
+
return "resolved_true";
|
|
81
|
+
}
|
|
82
|
+
if (outcome === "disconfirmed" || outcome === "expired") {
|
|
83
|
+
return "resolved_false";
|
|
134
84
|
}
|
|
85
|
+
return null;
|
|
135
86
|
}
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
|
|
87
|
+
function shouldTreatBeliefAsResolved(opts) {
|
|
88
|
+
if (isResolvedByConfidence(opts.confidence)) {
|
|
89
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
90
|
+
return normalized === 0 ? "resolved_false" : "resolved_true";
|
|
139
91
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
legacyScopeId
|
|
150
|
-
}
|
|
151
|
-
);
|
|
152
|
-
return null;
|
|
92
|
+
const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
|
|
93
|
+
if (directPredictionStatus) {
|
|
94
|
+
return directPredictionStatus;
|
|
95
|
+
}
|
|
96
|
+
const metadataPredictionStatus = resolvedPredictionStatus(
|
|
97
|
+
getPredictionMetaFromMetadata(opts.metadata)
|
|
98
|
+
);
|
|
99
|
+
if (metadataPredictionStatus) {
|
|
100
|
+
return metadataPredictionStatus;
|
|
153
101
|
}
|
|
102
|
+
return null;
|
|
154
103
|
}
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (tenantId && workspaceId) {
|
|
160
|
-
return { tenantId, workspaceId };
|
|
104
|
+
function resolveBeliefLifecycleStatus(opts) {
|
|
105
|
+
const resolvedStatus = shouldTreatBeliefAsResolved(opts);
|
|
106
|
+
if (resolvedStatus) {
|
|
107
|
+
return resolvedStatus;
|
|
161
108
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (
|
|
167
|
-
|
|
109
|
+
const direct = opts.beliefStatus;
|
|
110
|
+
const normalizedDirect = normalizeLegacyBeliefStatus(direct);
|
|
111
|
+
if (normalizedDirect) {
|
|
112
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
113
|
+
if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
|
|
114
|
+
return "active";
|
|
168
115
|
}
|
|
169
|
-
|
|
170
|
-
|
|
116
|
+
return normalizedDirect;
|
|
117
|
+
}
|
|
118
|
+
const metaStatus = opts.metadata?.beliefStatus;
|
|
119
|
+
const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
|
|
120
|
+
if (normalizedMetaStatus) {
|
|
121
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
122
|
+
if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
|
|
123
|
+
return "active";
|
|
171
124
|
}
|
|
172
|
-
|
|
125
|
+
return normalizedMetaStatus;
|
|
173
126
|
}
|
|
174
|
-
return
|
|
127
|
+
return "assumption";
|
|
175
128
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
} catch (error) {
|
|
184
|
-
debugGraphPrimitiveFallback(
|
|
185
|
-
"[topicScope] Failed to load topic by direct id",
|
|
186
|
-
{
|
|
187
|
-
error,
|
|
188
|
-
topicId: args.topicId
|
|
189
|
-
}
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
if (!topic) {
|
|
193
|
-
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
194
|
-
}
|
|
195
|
-
if (!topic) {
|
|
196
|
-
topic = pickPrimaryTopic(
|
|
197
|
-
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
198
|
-
) ?? null;
|
|
199
|
-
}
|
|
200
|
-
if (!topic) {
|
|
201
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
202
|
-
ctx,
|
|
203
|
-
String(args.topicId)
|
|
204
|
-
);
|
|
205
|
-
if (nodeScope) {
|
|
206
|
-
return nodeScope;
|
|
207
|
-
}
|
|
208
|
-
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
209
|
-
}
|
|
210
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
211
|
-
const mapped = asMappedProjectId(topic);
|
|
212
|
-
if (mapped) {
|
|
213
|
-
return {
|
|
214
|
-
topicId: topic._id,
|
|
215
|
-
projectId: mapped,
|
|
216
|
-
tenantId: inherited.tenantId,
|
|
217
|
-
workspaceId: inherited.workspaceId,
|
|
218
|
-
source: "topic"
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
return {
|
|
222
|
-
topicId: topic._id,
|
|
223
|
-
tenantId: inherited.tenantId,
|
|
224
|
-
workspaceId: inherited.workspaceId,
|
|
225
|
-
source: "topic"
|
|
226
|
-
};
|
|
129
|
+
function isPreValidationBeliefStatus(status) {
|
|
130
|
+
return status === "assumption" || status === "hypothesis";
|
|
131
|
+
}
|
|
132
|
+
function promoteBeliefStatusAfterScoring(status, opts) {
|
|
133
|
+
const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
|
|
134
|
+
if (resolvedStatus) {
|
|
135
|
+
return resolvedStatus;
|
|
227
136
|
}
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
try {
|
|
231
|
-
directTopic = await ctx.db.get(
|
|
232
|
-
args.projectId
|
|
233
|
-
);
|
|
234
|
-
} catch (error) {
|
|
235
|
-
debugGraphPrimitiveFallback(
|
|
236
|
-
"[topicScope] Failed to load direct project topic",
|
|
237
|
-
{
|
|
238
|
-
error,
|
|
239
|
-
projectId: args.projectId
|
|
240
|
-
}
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
if (directTopic) {
|
|
244
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
245
|
-
const mapped = asMappedProjectId(directTopic);
|
|
246
|
-
return {
|
|
247
|
-
topicId: directTopic._id,
|
|
248
|
-
projectId: mapped ?? args.projectId,
|
|
249
|
-
tenantId: inherited.tenantId,
|
|
250
|
-
workspaceId: inherited.workspaceId,
|
|
251
|
-
source: "topic_inferred"
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
255
|
-
if (directTopic) {
|
|
256
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
257
|
-
const mapped = asMappedProjectId(directTopic);
|
|
258
|
-
return {
|
|
259
|
-
topicId: directTopic._id,
|
|
260
|
-
projectId: mapped ?? args.projectId,
|
|
261
|
-
tenantId: inherited.tenantId,
|
|
262
|
-
workspaceId: inherited.workspaceId,
|
|
263
|
-
source: "topic_inferred"
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
267
|
-
const primary = pickPrimaryTopic(topics);
|
|
268
|
-
if (primary) {
|
|
269
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
270
|
-
return {
|
|
271
|
-
topicId: primary._id,
|
|
272
|
-
projectId: args.projectId,
|
|
273
|
-
tenantId: inherited.tenantId,
|
|
274
|
-
workspaceId: inherited.workspaceId,
|
|
275
|
-
source: "project_mapped_topic"
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
279
|
-
ctx,
|
|
280
|
-
String(args.projectId)
|
|
281
|
-
);
|
|
282
|
-
if (nodeScope) {
|
|
283
|
-
return {
|
|
284
|
-
...nodeScope,
|
|
285
|
-
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
throw new Error(
|
|
289
|
-
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
290
|
-
);
|
|
137
|
+
if (isPreValidationBeliefStatus(status)) {
|
|
138
|
+
return "active";
|
|
291
139
|
}
|
|
292
|
-
|
|
293
|
-
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
({
|
|
297
|
-
projectId: v.optional(v.string()),
|
|
298
|
-
topicId: v.optional(v.string())
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// src/workspaceIsolation.ts
|
|
302
|
-
function normalizeScopeValue2(value) {
|
|
303
|
-
if (typeof value !== "string") {
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
const normalized = value.trim();
|
|
307
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
308
|
-
}
|
|
309
|
-
function throwWorkspaceIsolationError(args) {
|
|
310
|
-
const error = new Error(args.message);
|
|
311
|
-
error.status = 409;
|
|
312
|
-
error.code = "INVARIANT_VIOLATION";
|
|
313
|
-
error.invariantCode = args.invariantCode;
|
|
314
|
-
error.suggestion = args.suggestion;
|
|
315
|
-
error.details = args.details;
|
|
316
|
-
throw error;
|
|
317
|
-
}
|
|
318
|
-
function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
319
|
-
if (!node) {
|
|
320
|
-
return false;
|
|
321
|
-
}
|
|
322
|
-
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
323
|
-
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
324
|
-
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
325
|
-
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
326
|
-
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
327
|
-
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
328
|
-
return false;
|
|
329
|
-
}
|
|
330
|
-
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
331
|
-
return true;
|
|
332
|
-
}
|
|
333
|
-
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
334
|
-
return true;
|
|
335
|
-
}
|
|
336
|
-
if (!scopeWorkspaceId) {
|
|
337
|
-
return nodeWorkspaceId === void 0;
|
|
338
|
-
}
|
|
339
|
-
return scopeWorkspaceId === nodeWorkspaceId;
|
|
340
|
-
}
|
|
341
|
-
function edgeMatchesWorkspaceReasoningScope(edge, scope) {
|
|
342
|
-
if (!edge) {
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
346
|
-
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
347
|
-
const edgeTenantId = normalizeScopeValue2(edge.tenantId);
|
|
348
|
-
const edgeWorkspaceId = normalizeScopeValue2(edge.workspaceId);
|
|
349
|
-
if (scopeTenantId && edgeTenantId && scopeTenantId !== edgeTenantId) {
|
|
350
|
-
return false;
|
|
351
|
-
}
|
|
352
|
-
if (!scopeWorkspaceId) {
|
|
353
|
-
return edgeWorkspaceId === void 0;
|
|
354
|
-
}
|
|
355
|
-
return scopeWorkspaceId === edgeWorkspaceId;
|
|
356
|
-
}
|
|
357
|
-
async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
358
|
-
const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
359
|
-
const resolved = {
|
|
360
|
-
tenantId: normalizeScopeValue2(node?.tenantId),
|
|
361
|
-
workspaceId: normalizeScopeValue2(node?.workspaceId),
|
|
362
|
-
epistemicLayer,
|
|
363
|
-
nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
|
|
364
|
-
};
|
|
365
|
-
if (!node) {
|
|
366
|
-
return resolved;
|
|
367
|
-
}
|
|
368
|
-
if (resolved.epistemicLayer === "ontological") {
|
|
369
|
-
return resolved;
|
|
370
|
-
}
|
|
371
|
-
if (resolved.tenantId || resolved.workspaceId) {
|
|
372
|
-
return resolved;
|
|
373
|
-
}
|
|
374
|
-
if (node.topicId) {
|
|
375
|
-
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
376
|
-
topicId: node.topicId
|
|
377
|
-
});
|
|
378
|
-
return {
|
|
379
|
-
...resolved,
|
|
380
|
-
tenantId: topicScope.tenantId,
|
|
381
|
-
workspaceId: topicScope.workspaceId
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
if (node.projectId) {
|
|
385
|
-
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
386
|
-
projectId: String(node.projectId)
|
|
387
|
-
});
|
|
388
|
-
return {
|
|
389
|
-
...resolved,
|
|
390
|
-
tenantId: topicScope.tenantId,
|
|
391
|
-
workspaceId: topicScope.workspaceId
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
return resolved;
|
|
395
|
-
}
|
|
396
|
-
function resolveRuntimePackMutationContext(args) {
|
|
397
|
-
if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
return {
|
|
401
|
-
toolName: args.runtimeToolName,
|
|
402
|
-
packKey: args.runtimePackKey,
|
|
403
|
-
packInstallScope: args.runtimePackInstallScope
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
function assertTenantPackWorkspaceMutationAllowed(args) {
|
|
407
|
-
if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
|
|
411
|
-
const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
|
|
412
|
-
if (!targetWorkspaceId || targetLayer === "ontological") {
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
throwWorkspaceIsolationError({
|
|
416
|
-
message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
|
|
417
|
-
invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
|
|
418
|
-
suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
|
|
419
|
-
details: {
|
|
420
|
-
mutationName: args.mutationName,
|
|
421
|
-
toolName: args.runtime.toolName,
|
|
422
|
-
packKey: args.runtime.packKey,
|
|
423
|
-
targetWorkspaceId,
|
|
424
|
-
targetNodeType: args.target.nodeType,
|
|
425
|
-
targetLayer
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// src/beliefLifecycle.ts
|
|
431
|
-
var BELIEF_STATUS_VALUES = [
|
|
432
|
-
"assumption",
|
|
433
|
-
"hypothesis",
|
|
434
|
-
"active",
|
|
435
|
-
"superseded",
|
|
436
|
-
"resolved_true",
|
|
437
|
-
"resolved_false"
|
|
438
|
-
];
|
|
439
|
-
function isBeliefLifecycleStatus(value) {
|
|
440
|
-
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
441
|
-
}
|
|
442
|
-
function normalizeLegacyBeliefStatus(value) {
|
|
443
|
-
if (isBeliefLifecycleStatus(value)) {
|
|
444
|
-
return value;
|
|
445
|
-
}
|
|
446
|
-
if (value === "belief" || value === "established" || value === "emerging") {
|
|
447
|
-
return "active";
|
|
448
|
-
}
|
|
449
|
-
if (value === "fact" || value === "confirmed") {
|
|
450
|
-
return "resolved_true";
|
|
451
|
-
}
|
|
452
|
-
if (value === "disconfirmed" || value === "expired") {
|
|
453
|
-
return "resolved_false";
|
|
454
|
-
}
|
|
455
|
-
if (value === "deprecated") {
|
|
456
|
-
return "superseded";
|
|
457
|
-
}
|
|
458
|
-
return null;
|
|
459
|
-
}
|
|
460
|
-
function normalizeBeliefConfidence(confidence) {
|
|
461
|
-
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
462
|
-
return null;
|
|
463
|
-
}
|
|
464
|
-
if (confidence >= 0 && confidence <= 1) {
|
|
465
|
-
return confidence;
|
|
466
|
-
}
|
|
467
|
-
if (confidence > 1 && confidence <= 100) {
|
|
468
|
-
return confidence / 100;
|
|
469
|
-
}
|
|
470
|
-
return null;
|
|
471
|
-
}
|
|
472
|
-
function isResolvedByConfidence(confidence) {
|
|
473
|
-
const normalized = normalizeBeliefConfidence(confidence);
|
|
474
|
-
if (normalized === null) {
|
|
475
|
-
return false;
|
|
476
|
-
}
|
|
477
|
-
return normalized <= 0 || normalized >= 1;
|
|
478
|
-
}
|
|
479
|
-
function getPredictionMetaFromMetadata(metadata) {
|
|
480
|
-
return metadata?.predictionMeta;
|
|
481
|
-
}
|
|
482
|
-
function resolvedPredictionStatus(predictionMeta) {
|
|
483
|
-
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
484
|
-
return null;
|
|
485
|
-
}
|
|
486
|
-
const outcome = predictionMeta.outcome;
|
|
487
|
-
if (outcome === "confirmed") {
|
|
488
|
-
return "resolved_true";
|
|
489
|
-
}
|
|
490
|
-
if (outcome === "disconfirmed" || outcome === "expired") {
|
|
491
|
-
return "resolved_false";
|
|
492
|
-
}
|
|
493
|
-
return null;
|
|
494
|
-
}
|
|
495
|
-
function shouldTreatBeliefAsResolved(opts) {
|
|
496
|
-
if (isResolvedByConfidence(opts.confidence)) {
|
|
497
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
498
|
-
return normalized === 0 ? "resolved_false" : "resolved_true";
|
|
499
|
-
}
|
|
500
|
-
const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
|
|
501
|
-
if (directPredictionStatus) {
|
|
502
|
-
return directPredictionStatus;
|
|
503
|
-
}
|
|
504
|
-
const metadataPredictionStatus = resolvedPredictionStatus(
|
|
505
|
-
getPredictionMetaFromMetadata(opts.metadata)
|
|
506
|
-
);
|
|
507
|
-
if (metadataPredictionStatus) {
|
|
508
|
-
return metadataPredictionStatus;
|
|
509
|
-
}
|
|
510
|
-
return null;
|
|
511
|
-
}
|
|
512
|
-
function resolveBeliefLifecycleStatus(opts) {
|
|
513
|
-
const resolvedStatus = shouldTreatBeliefAsResolved(opts);
|
|
514
|
-
if (resolvedStatus) {
|
|
515
|
-
return resolvedStatus;
|
|
516
|
-
}
|
|
517
|
-
const direct = opts.beliefStatus;
|
|
518
|
-
const normalizedDirect = normalizeLegacyBeliefStatus(direct);
|
|
519
|
-
if (normalizedDirect) {
|
|
520
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
521
|
-
if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
|
|
522
|
-
return "active";
|
|
523
|
-
}
|
|
524
|
-
return normalizedDirect;
|
|
525
|
-
}
|
|
526
|
-
const metaStatus = opts.metadata?.beliefStatus;
|
|
527
|
-
const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
|
|
528
|
-
if (normalizedMetaStatus) {
|
|
529
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
530
|
-
if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
|
|
531
|
-
return "active";
|
|
532
|
-
}
|
|
533
|
-
return normalizedMetaStatus;
|
|
534
|
-
}
|
|
535
|
-
return "assumption";
|
|
536
|
-
}
|
|
537
|
-
function isPreValidationBeliefStatus(status) {
|
|
538
|
-
return status === "assumption" || status === "hypothesis";
|
|
539
|
-
}
|
|
540
|
-
function promoteBeliefStatusAfterScoring(status, opts) {
|
|
541
|
-
const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
|
|
542
|
-
if (resolvedStatus) {
|
|
543
|
-
return resolvedStatus;
|
|
544
|
-
}
|
|
545
|
-
if (isPreValidationBeliefStatus(status)) {
|
|
546
|
-
return "active";
|
|
547
|
-
}
|
|
548
|
-
return status;
|
|
140
|
+
return status;
|
|
549
141
|
}
|
|
550
142
|
|
|
551
143
|
// src/edges/contains.ts
|
|
@@ -683,7 +275,7 @@ var dependsOnPropagationSpec = {
|
|
|
683
275
|
description: "Structural gating. Textbook conditional deduction when edge conditionals exist, otherwise damped dependency cascade through downstream chains."
|
|
684
276
|
};
|
|
685
277
|
|
|
686
|
-
// src/edges/
|
|
278
|
+
// src/edges/derived-from.ts
|
|
687
279
|
var derivedFromPropagationSpec = {
|
|
688
280
|
edgeType: "derived_from",
|
|
689
281
|
direction: "incoming",
|
|
@@ -736,7 +328,7 @@ var informsPropagationSpec = {
|
|
|
736
328
|
description: "Evidence-bearing influence. Informs can chain through the graph with light per-hop damping."
|
|
737
329
|
};
|
|
738
330
|
|
|
739
|
-
// src/edges/
|
|
331
|
+
// src/edges/propagation-types.ts
|
|
740
332
|
function isPropagationTraversalDirection(direction) {
|
|
741
333
|
return direction === "outgoing" || direction === "incoming";
|
|
742
334
|
}
|
|
@@ -809,6 +401,9 @@ var testsPropagationSpec = {
|
|
|
809
401
|
};
|
|
810
402
|
|
|
811
403
|
// src/edges/index.ts
|
|
404
|
+
var canContinueTransitively2 = canContinueTransitively;
|
|
405
|
+
var canTraverseHop2 = canTraverseHop;
|
|
406
|
+
var isPropagationTraversalDirection2 = isPropagationTraversalDirection;
|
|
812
407
|
var EDGE_PROPAGATION_SPECS = [
|
|
813
408
|
supportsPropagationSpec,
|
|
814
409
|
informsPropagationSpec,
|
|
@@ -825,16 +420,409 @@ function getEdgePropagationSpecs() {
|
|
|
825
420
|
return EDGE_PROPAGATION_SPECS;
|
|
826
421
|
}
|
|
827
422
|
function getTraversalDirections(direction) {
|
|
828
|
-
if (
|
|
423
|
+
if (isPropagationTraversalDirection2(direction)) {
|
|
829
424
|
return [direction];
|
|
830
425
|
}
|
|
831
|
-
return ["outgoing", "incoming"];
|
|
426
|
+
return ["outgoing", "incoming"];
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/debug.ts
|
|
430
|
+
function isGraphPrimitiveDebugEnabled() {
|
|
431
|
+
const env = globalThis.process?.env;
|
|
432
|
+
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
433
|
+
}
|
|
434
|
+
function debugGraphPrimitiveFallback(message, context) {
|
|
435
|
+
if (!isGraphPrimitiveDebugEnabled()) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
console.debug(message, context ?? {});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// src/topicScope.ts
|
|
442
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
443
|
+
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
444
|
+
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
let node = null;
|
|
448
|
+
try {
|
|
449
|
+
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
450
|
+
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
451
|
+
node = byGlobalId;
|
|
452
|
+
}
|
|
453
|
+
} catch (error) {
|
|
454
|
+
debugGraphPrimitiveFallback(
|
|
455
|
+
"[topicScope] topic-node scope lookup by globalId failed",
|
|
456
|
+
{ error, ref }
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
if (!node) {
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
463
|
+
if (!scopeKey) {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
topicId: scopeKey,
|
|
468
|
+
projectId: asMappedProjectId(node),
|
|
469
|
+
source: "topic_node"
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
function asMappedProjectId(topic) {
|
|
473
|
+
if (!topic) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
477
|
+
topic[LEGACY_SCOPE_FIELD]
|
|
478
|
+
);
|
|
479
|
+
if (directLegacyProjectId) {
|
|
480
|
+
return directLegacyProjectId;
|
|
481
|
+
}
|
|
482
|
+
const metadata = topic.metadata || {};
|
|
483
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
484
|
+
return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
|
|
485
|
+
}
|
|
486
|
+
function normalizeScopeValue(value) {
|
|
487
|
+
if (typeof value !== "string") {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const normalized = value.trim();
|
|
491
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
492
|
+
}
|
|
493
|
+
function pickPrimaryTopic(candidates) {
|
|
494
|
+
return [...candidates].sort((a, b) => {
|
|
495
|
+
const depthA = a.depth ?? 9999;
|
|
496
|
+
const depthB = b.depth ?? 9999;
|
|
497
|
+
if (depthA !== depthB) {
|
|
498
|
+
return depthA - depthB;
|
|
499
|
+
}
|
|
500
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
501
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
502
|
+
if (createdA !== createdB) {
|
|
503
|
+
return createdA - createdB;
|
|
504
|
+
}
|
|
505
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
506
|
+
})[0];
|
|
507
|
+
}
|
|
508
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
509
|
+
const query = ctx.db.query("topics");
|
|
510
|
+
try {
|
|
511
|
+
return await query.withIndex(
|
|
512
|
+
"by_graph_scope_project",
|
|
513
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
514
|
+
).collect();
|
|
515
|
+
} catch (error) {
|
|
516
|
+
debugGraphPrimitiveFallback(
|
|
517
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
518
|
+
{
|
|
519
|
+
error,
|
|
520
|
+
scopeId
|
|
521
|
+
}
|
|
522
|
+
);
|
|
523
|
+
const topics = await query.collect();
|
|
524
|
+
return topics.filter((topic) => {
|
|
525
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
526
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
527
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
532
|
+
if (typeof ctx.runQuery !== "function") {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
return await ctx.runQuery(api.topics.get, {
|
|
537
|
+
id: topicId
|
|
538
|
+
}) ?? null;
|
|
539
|
+
} catch (error) {
|
|
540
|
+
debugGraphPrimitiveFallback(
|
|
541
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
542
|
+
{
|
|
543
|
+
error,
|
|
544
|
+
topicId
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
551
|
+
if (typeof ctx.runQuery !== "function") {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
try {
|
|
555
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
556
|
+
projectId: legacyScopeId
|
|
557
|
+
}) ?? null;
|
|
558
|
+
} catch (error) {
|
|
559
|
+
debugGraphPrimitiveFallback(
|
|
560
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
561
|
+
{
|
|
562
|
+
error,
|
|
563
|
+
legacyScopeId
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
570
|
+
const MAX_DEPTH = 10;
|
|
571
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
572
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
573
|
+
if (tenantId && workspaceId) {
|
|
574
|
+
return { tenantId, workspaceId };
|
|
575
|
+
}
|
|
576
|
+
let current = topic;
|
|
577
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
578
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
579
|
+
if (!current) {
|
|
580
|
+
break;
|
|
581
|
+
}
|
|
582
|
+
if (!tenantId) {
|
|
583
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
584
|
+
}
|
|
585
|
+
if (!workspaceId) {
|
|
586
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
587
|
+
}
|
|
588
|
+
if (tenantId && workspaceId) {
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return { tenantId, workspaceId };
|
|
593
|
+
}
|
|
594
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
595
|
+
if (args.topicId) {
|
|
596
|
+
return await resolveScopeFromTopicId(ctx, args.topicId);
|
|
597
|
+
}
|
|
598
|
+
if (args.projectId) {
|
|
599
|
+
return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
|
|
600
|
+
}
|
|
601
|
+
throw new Error(
|
|
602
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
606
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
607
|
+
if (topic) {
|
|
608
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
609
|
+
}
|
|
610
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
|
|
611
|
+
if (nodeScope) {
|
|
612
|
+
return nodeScope;
|
|
613
|
+
}
|
|
614
|
+
throw new Error(`Topic not found: ${String(topicId)}`);
|
|
615
|
+
}
|
|
616
|
+
async function resolveTopicDocFromTopicId(ctx, topicId) {
|
|
617
|
+
const direct = await tryReadTopicDoc(ctx, topicId, {
|
|
618
|
+
failureLog: "[topicScope] Failed to load topic by direct id",
|
|
619
|
+
idLogKey: "topicId"
|
|
620
|
+
});
|
|
621
|
+
if (direct) {
|
|
622
|
+
return direct;
|
|
623
|
+
}
|
|
624
|
+
const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
|
|
625
|
+
if (hostTopic) {
|
|
626
|
+
return hostTopic;
|
|
627
|
+
}
|
|
628
|
+
return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
|
|
629
|
+
}
|
|
630
|
+
async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
|
|
631
|
+
const directTopic = await resolveDirectLegacyProjectTopic(
|
|
632
|
+
ctx,
|
|
633
|
+
legacyProjectId
|
|
634
|
+
);
|
|
635
|
+
if (directTopic) {
|
|
636
|
+
return await buildTopicScope(ctx, directTopic, "topic_inferred", {
|
|
637
|
+
fallbackProjectId: legacyProjectId
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
const primary = pickPrimaryTopic(
|
|
641
|
+
await findTopicsByScopeAlias(ctx, legacyProjectId)
|
|
642
|
+
);
|
|
643
|
+
if (primary) {
|
|
644
|
+
return await buildTopicScope(ctx, primary, "project_mapped_topic", {
|
|
645
|
+
fallbackProjectId: legacyProjectId
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
|
|
649
|
+
if (nodeScope) {
|
|
650
|
+
return {
|
|
651
|
+
...nodeScope,
|
|
652
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
throw new Error(
|
|
656
|
+
`Legacy project scope ${legacyProjectId} has no mapped topic.`
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
|
|
660
|
+
const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
|
|
661
|
+
failureLog: "[topicScope] Failed to load direct project topic",
|
|
662
|
+
idLogKey: "projectId"
|
|
663
|
+
});
|
|
664
|
+
return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
|
|
665
|
+
}
|
|
666
|
+
async function tryReadTopicDoc(ctx, id, log) {
|
|
667
|
+
try {
|
|
668
|
+
return await ctx.db.get(id);
|
|
669
|
+
} catch (error) {
|
|
670
|
+
debugGraphPrimitiveFallback(log.failureLog, {
|
|
671
|
+
error,
|
|
672
|
+
[log.idLogKey]: id
|
|
673
|
+
});
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
async function buildTopicScope(ctx, topic, source, options = {}) {
|
|
678
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
679
|
+
const mapped = asMappedProjectId(topic);
|
|
680
|
+
return {
|
|
681
|
+
topicId: topic._id,
|
|
682
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
683
|
+
tenantId: inherited.tenantId,
|
|
684
|
+
workspaceId: inherited.workspaceId,
|
|
685
|
+
source
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
({
|
|
689
|
+
projectId: v.optional(v.string()),
|
|
690
|
+
topicId: v.optional(v.string())
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
// src/workspaceIsolation.ts
|
|
694
|
+
function normalizeScopeValue2(value) {
|
|
695
|
+
if (typeof value !== "string") {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
const normalized = value.trim();
|
|
699
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
700
|
+
}
|
|
701
|
+
function throwWorkspaceIsolationError(args) {
|
|
702
|
+
const error = new Error(args.message);
|
|
703
|
+
error.status = 409;
|
|
704
|
+
error.code = "INVARIANT_VIOLATION";
|
|
705
|
+
error.invariantCode = args.invariantCode;
|
|
706
|
+
error.suggestion = args.suggestion;
|
|
707
|
+
error.details = args.details;
|
|
708
|
+
throw error;
|
|
709
|
+
}
|
|
710
|
+
function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
711
|
+
if (!node) {
|
|
712
|
+
return false;
|
|
713
|
+
}
|
|
714
|
+
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
715
|
+
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
716
|
+
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
717
|
+
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
718
|
+
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
719
|
+
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
723
|
+
return true;
|
|
724
|
+
}
|
|
725
|
+
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
726
|
+
return true;
|
|
727
|
+
}
|
|
728
|
+
if (!scopeWorkspaceId) {
|
|
729
|
+
return nodeWorkspaceId === void 0;
|
|
730
|
+
}
|
|
731
|
+
return scopeWorkspaceId === nodeWorkspaceId;
|
|
732
|
+
}
|
|
733
|
+
function edgeMatchesWorkspaceReasoningScope(edge, scope) {
|
|
734
|
+
if (!edge) {
|
|
735
|
+
return false;
|
|
736
|
+
}
|
|
737
|
+
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
738
|
+
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
739
|
+
const edgeTenantId = normalizeScopeValue2(edge.tenantId);
|
|
740
|
+
const edgeWorkspaceId = normalizeScopeValue2(edge.workspaceId);
|
|
741
|
+
if (scopeTenantId && edgeTenantId && scopeTenantId !== edgeTenantId) {
|
|
742
|
+
return false;
|
|
743
|
+
}
|
|
744
|
+
if (!scopeWorkspaceId) {
|
|
745
|
+
return edgeWorkspaceId === void 0;
|
|
746
|
+
}
|
|
747
|
+
return scopeWorkspaceId === edgeWorkspaceId;
|
|
748
|
+
}
|
|
749
|
+
async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
750
|
+
const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
751
|
+
const resolved = {
|
|
752
|
+
tenantId: normalizeScopeValue2(node?.tenantId),
|
|
753
|
+
workspaceId: normalizeScopeValue2(node?.workspaceId),
|
|
754
|
+
epistemicLayer,
|
|
755
|
+
nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
|
|
756
|
+
};
|
|
757
|
+
if (!node) {
|
|
758
|
+
return resolved;
|
|
759
|
+
}
|
|
760
|
+
if (resolved.epistemicLayer === "ontological") {
|
|
761
|
+
return resolved;
|
|
762
|
+
}
|
|
763
|
+
if (resolved.tenantId || resolved.workspaceId) {
|
|
764
|
+
return resolved;
|
|
765
|
+
}
|
|
766
|
+
const topicId = normalizeScopeValue2(node.topicId);
|
|
767
|
+
if (topicId) {
|
|
768
|
+
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
769
|
+
topicId
|
|
770
|
+
});
|
|
771
|
+
return {
|
|
772
|
+
...resolved,
|
|
773
|
+
tenantId: topicScope.tenantId,
|
|
774
|
+
workspaceId: topicScope.workspaceId
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
if (node.projectId) {
|
|
778
|
+
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
779
|
+
projectId: String(node.projectId)
|
|
780
|
+
});
|
|
781
|
+
return {
|
|
782
|
+
...resolved,
|
|
783
|
+
tenantId: topicScope.tenantId,
|
|
784
|
+
workspaceId: topicScope.workspaceId
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
return resolved;
|
|
788
|
+
}
|
|
789
|
+
function resolveRuntimePackMutationContext(args) {
|
|
790
|
+
if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
return {
|
|
794
|
+
toolName: args.runtimeToolName,
|
|
795
|
+
packKey: args.runtimePackKey,
|
|
796
|
+
packInstallScope: args.runtimePackInstallScope
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
function assertTenantPackWorkspaceMutationAllowed(args) {
|
|
800
|
+
if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
|
|
804
|
+
const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
|
|
805
|
+
if (!targetWorkspaceId || targetLayer === "ontological") {
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
throwWorkspaceIsolationError({
|
|
809
|
+
message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
|
|
810
|
+
invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
|
|
811
|
+
suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
|
|
812
|
+
details: {
|
|
813
|
+
mutationName: args.mutationName,
|
|
814
|
+
toolName: args.runtime.toolName,
|
|
815
|
+
packKey: args.runtime.packKey,
|
|
816
|
+
targetWorkspaceId,
|
|
817
|
+
targetNodeType: args.target.nodeType,
|
|
818
|
+
targetLayer
|
|
819
|
+
}
|
|
820
|
+
});
|
|
832
821
|
}
|
|
833
822
|
|
|
834
823
|
// src/confidencePropagationDispatch.ts
|
|
835
|
-
function
|
|
836
|
-
|
|
837
|
-
return targetNodeId ?? void 0;
|
|
824
|
+
function nodeIdToCacheKey(nodeId) {
|
|
825
|
+
return String(nodeId);
|
|
838
826
|
}
|
|
839
827
|
function readNodeOpinion(node) {
|
|
840
828
|
const metadata = node.metadata ?? {};
|
|
@@ -850,118 +838,282 @@ function readNodeOpinion(node) {
|
|
|
850
838
|
return mkOpinion(0, 0, 1, 0.5);
|
|
851
839
|
}
|
|
852
840
|
}
|
|
841
|
+
function resolveTraversalTargetNodeId(edge, direction) {
|
|
842
|
+
const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
|
|
843
|
+
return targetNodeId ?? void 0;
|
|
844
|
+
}
|
|
845
|
+
function buildInitialState(sourceNodeId, sourceOpinion) {
|
|
846
|
+
return {
|
|
847
|
+
nodeId: sourceNodeId,
|
|
848
|
+
opinion: sourceOpinion,
|
|
849
|
+
hop: 0,
|
|
850
|
+
visitedNodeIds: /* @__PURE__ */ new Set([nodeIdToCacheKey(sourceNodeId)])
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
function extendVisited(currentVisited, targetNodeId) {
|
|
854
|
+
return /* @__PURE__ */ new Set([...currentVisited, nodeIdToCacheKey(targetNodeId)]);
|
|
855
|
+
}
|
|
856
|
+
function makeTransitiveState(current, targetNodeId, projectedOpinion, nextHop) {
|
|
857
|
+
return {
|
|
858
|
+
nodeId: targetNodeId,
|
|
859
|
+
opinion: projectedOpinion,
|
|
860
|
+
hop: nextHop,
|
|
861
|
+
visitedNodeIds: extendVisited(current.visitedNodeIds, targetNodeId)
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
function makeDispatchRecord(targetNodeId, spec, direction, edge, projectedOpinion, nextHop, result, existingDispatch) {
|
|
865
|
+
return {
|
|
866
|
+
targetNodeId,
|
|
867
|
+
edgeType: spec.edgeType,
|
|
868
|
+
traversedDirection: direction,
|
|
869
|
+
weight: edge.weight ?? 1,
|
|
870
|
+
opinion: projectedOpinion,
|
|
871
|
+
operator: result.operator,
|
|
872
|
+
rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
|
|
873
|
+
hop: nextHop
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
async function loadCachedNode(scope, nodeId) {
|
|
877
|
+
const cacheKey = nodeIdToCacheKey(nodeId);
|
|
878
|
+
if (!scope.nodeCache.has(cacheKey)) {
|
|
879
|
+
scope.nodeCache.set(cacheKey, await scope.args.getNode(nodeId));
|
|
880
|
+
}
|
|
881
|
+
return scope.nodeCache.get(cacheKey) ?? null;
|
|
882
|
+
}
|
|
883
|
+
async function collectTargetDispatch(state, nextHop, spec, direction, edge, queue, scope) {
|
|
884
|
+
const sourceScope = scope.args.sourceScope;
|
|
885
|
+
if (sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, sourceScope)) {
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
|
|
889
|
+
if (!targetNodeId) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
const targetNodeIdKey = nodeIdToCacheKey(targetNodeId);
|
|
893
|
+
if (state.visitedNodeIds.has(targetNodeIdKey)) {
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
const targetNode = await loadCachedNode(scope, targetNodeId);
|
|
897
|
+
if (targetNode?.nodeType !== "belief") {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
if (sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, sourceScope)) {
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
const targetOpinion = scope.opinionCache.get(targetNodeIdKey) ?? readNodeOpinion(targetNode);
|
|
904
|
+
const result = spec.operator(state.opinion, targetOpinion, edge, {
|
|
905
|
+
hop: nextHop,
|
|
906
|
+
sourceNodeId: state.nodeId,
|
|
907
|
+
targetNodeId,
|
|
908
|
+
traversedDirection: direction,
|
|
909
|
+
spec
|
|
910
|
+
});
|
|
911
|
+
if (!(result && hasProjectedOpinionChanged(targetOpinion, result.opinion))) {
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
const projectedOpinion = mkOpinion(
|
|
915
|
+
result.opinion.b,
|
|
916
|
+
result.opinion.d,
|
|
917
|
+
result.opinion.u,
|
|
918
|
+
result.opinion.a
|
|
919
|
+
);
|
|
920
|
+
scope.opinionCache.set(targetNodeIdKey, projectedOpinion);
|
|
921
|
+
const existingDispatch = scope.dispatchesByTargetId.get(targetNodeIdKey);
|
|
922
|
+
scope.dispatchesByTargetId.set(
|
|
923
|
+
targetNodeIdKey,
|
|
924
|
+
makeDispatchRecord(
|
|
925
|
+
targetNodeId,
|
|
926
|
+
spec,
|
|
927
|
+
direction,
|
|
928
|
+
edge,
|
|
929
|
+
projectedOpinion,
|
|
930
|
+
nextHop,
|
|
931
|
+
result,
|
|
932
|
+
existingDispatch
|
|
933
|
+
)
|
|
934
|
+
);
|
|
935
|
+
if (canContinueTransitively2(spec, nextHop)) {
|
|
936
|
+
queue.push(
|
|
937
|
+
makeTransitiveState(state, targetNodeId, projectedOpinion, nextHop)
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
async function processTraversalSpec(state, nextHop, spec, queue, scope) {
|
|
942
|
+
const sourceNodeId = state.nodeId;
|
|
943
|
+
for (const direction of getTraversalDirections(spec.direction)) {
|
|
944
|
+
const edges = await scope.args.queryEdges({
|
|
945
|
+
nodeId: sourceNodeId,
|
|
946
|
+
spec,
|
|
947
|
+
direction,
|
|
948
|
+
hop: nextHop
|
|
949
|
+
});
|
|
950
|
+
for (const edge of edges) {
|
|
951
|
+
await collectTargetDispatch(
|
|
952
|
+
state,
|
|
953
|
+
nextHop,
|
|
954
|
+
spec,
|
|
955
|
+
direction,
|
|
956
|
+
edge,
|
|
957
|
+
queue,
|
|
958
|
+
scope
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
async function processQueuedState(state, queue, scope) {
|
|
964
|
+
const nextHop = state.hop + 1;
|
|
965
|
+
for (const spec of scope.traversalSpecs) {
|
|
966
|
+
if (!canTraverseHop2(spec, nextHop)) {
|
|
967
|
+
continue;
|
|
968
|
+
}
|
|
969
|
+
await processTraversalSpec(state, nextHop, spec, queue, scope);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
function sortDispatches(dispatches) {
|
|
973
|
+
return Array.from(dispatches).sort((left, right) => {
|
|
974
|
+
if (left.hop !== right.hop) {
|
|
975
|
+
return left.hop - right.hop;
|
|
976
|
+
}
|
|
977
|
+
return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
|
|
978
|
+
});
|
|
979
|
+
}
|
|
853
980
|
async function collectConfidencePropagationDispatches(args) {
|
|
854
981
|
const dispatchesByTargetId = /* @__PURE__ */ new Map();
|
|
855
982
|
const opinionCache = /* @__PURE__ */ new Map();
|
|
856
983
|
const nodeCache = /* @__PURE__ */ new Map();
|
|
857
984
|
const traversalSpecs = args.traversalSpecs ?? getEdgePropagationSpecs();
|
|
985
|
+
const scope = {
|
|
986
|
+
args,
|
|
987
|
+
dispatchesByTargetId,
|
|
988
|
+
opinionCache,
|
|
989
|
+
nodeCache,
|
|
990
|
+
traversalSpecs
|
|
991
|
+
};
|
|
858
992
|
const queue = [
|
|
859
|
-
|
|
860
|
-
nodeId: args.sourceNodeId,
|
|
861
|
-
opinion: args.sourceOpinion,
|
|
862
|
-
hop: 0,
|
|
863
|
-
visitedNodeIds: /* @__PURE__ */ new Set([String(args.sourceNodeId)])
|
|
864
|
-
}
|
|
993
|
+
buildInitialState(args.sourceNodeId, args.sourceOpinion)
|
|
865
994
|
];
|
|
866
|
-
const loadNode = async (nodeId) => {
|
|
867
|
-
const cacheKey = String(nodeId);
|
|
868
|
-
if (!nodeCache.has(cacheKey)) {
|
|
869
|
-
nodeCache.set(cacheKey, await args.getNode(nodeId));
|
|
870
|
-
}
|
|
871
|
-
return nodeCache.get(cacheKey) ?? null;
|
|
872
|
-
};
|
|
873
995
|
while (queue.length > 0) {
|
|
874
996
|
const state = queue.shift();
|
|
875
997
|
if (!state) {
|
|
876
998
|
continue;
|
|
877
999
|
}
|
|
878
|
-
|
|
879
|
-
const nextHop = state.hop + 1;
|
|
880
|
-
if (!canTraverseHop(spec, nextHop)) {
|
|
881
|
-
continue;
|
|
882
|
-
}
|
|
883
|
-
for (const direction of getTraversalDirections(spec.direction)) {
|
|
884
|
-
const edges = await args.queryEdges({
|
|
885
|
-
nodeId: state.nodeId,
|
|
886
|
-
spec,
|
|
887
|
-
direction,
|
|
888
|
-
hop: nextHop
|
|
889
|
-
});
|
|
890
|
-
for (const edge of edges) {
|
|
891
|
-
if (args.sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, args.sourceScope)) {
|
|
892
|
-
continue;
|
|
893
|
-
}
|
|
894
|
-
const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
|
|
895
|
-
if (!targetNodeId) {
|
|
896
|
-
continue;
|
|
897
|
-
}
|
|
898
|
-
if (state.visitedNodeIds.has(String(targetNodeId))) {
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
const targetNode = await loadNode(targetNodeId);
|
|
902
|
-
if (!targetNode || targetNode.nodeType !== "belief") {
|
|
903
|
-
continue;
|
|
904
|
-
}
|
|
905
|
-
if (args.sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, args.sourceScope)) {
|
|
906
|
-
continue;
|
|
907
|
-
}
|
|
908
|
-
const cacheKey = String(targetNodeId);
|
|
909
|
-
const targetOpinion = opinionCache.get(cacheKey) ?? readNodeOpinion(targetNode);
|
|
910
|
-
const result = spec.operator(state.opinion, targetOpinion, edge, {
|
|
911
|
-
hop: nextHop,
|
|
912
|
-
sourceNodeId: state.nodeId,
|
|
913
|
-
targetNodeId,
|
|
914
|
-
traversedDirection: direction,
|
|
915
|
-
spec
|
|
916
|
-
});
|
|
917
|
-
if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
|
|
918
|
-
continue;
|
|
919
|
-
}
|
|
920
|
-
const projectedOpinion = mkOpinion(
|
|
921
|
-
result.opinion.b,
|
|
922
|
-
result.opinion.d,
|
|
923
|
-
result.opinion.u,
|
|
924
|
-
result.opinion.a
|
|
925
|
-
);
|
|
926
|
-
opinionCache.set(cacheKey, projectedOpinion);
|
|
927
|
-
const existingDispatch = dispatchesByTargetId.get(cacheKey);
|
|
928
|
-
dispatchesByTargetId.set(cacheKey, {
|
|
929
|
-
targetNodeId,
|
|
930
|
-
edgeType: spec.edgeType,
|
|
931
|
-
traversedDirection: direction,
|
|
932
|
-
weight: edge.weight ?? 1,
|
|
933
|
-
opinion: projectedOpinion,
|
|
934
|
-
operator: result.operator,
|
|
935
|
-
rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
|
|
936
|
-
hop: nextHop
|
|
937
|
-
});
|
|
938
|
-
if (canContinueTransitively(spec, nextHop)) {
|
|
939
|
-
queue.push({
|
|
940
|
-
nodeId: targetNodeId,
|
|
941
|
-
opinion: projectedOpinion,
|
|
942
|
-
hop: nextHop,
|
|
943
|
-
visitedNodeIds: /* @__PURE__ */ new Set([
|
|
944
|
-
...state.visitedNodeIds,
|
|
945
|
-
String(targetNodeId)
|
|
946
|
-
])
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
}
|
|
1000
|
+
await processQueuedState(state, queue, scope);
|
|
952
1001
|
}
|
|
953
|
-
return
|
|
954
|
-
if (left.hop !== right.hop) {
|
|
955
|
-
return left.hop - right.hop;
|
|
956
|
-
}
|
|
957
|
-
return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
|
|
958
|
-
});
|
|
1002
|
+
return sortDispatches(dispatchesByTargetId.values());
|
|
959
1003
|
}
|
|
960
1004
|
v.id("epistemicNodes");
|
|
961
1005
|
var DEFAULT_CONFIDENCE_POLICY = {
|
|
962
1006
|
scoringMode: "after_worktree",
|
|
963
1007
|
tupleContradiction: normalizeTupleContradictionPolicy()
|
|
964
1008
|
};
|
|
1009
|
+
function readFiniteNumber(value) {
|
|
1010
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1011
|
+
}
|
|
1012
|
+
function isRecord(value) {
|
|
1013
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1014
|
+
}
|
|
1015
|
+
function readOptionalString(value) {
|
|
1016
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1017
|
+
}
|
|
1018
|
+
function readStringArray(value) {
|
|
1019
|
+
if (!Array.isArray(value)) {
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
const strings = value.filter(
|
|
1023
|
+
(item) => typeof item === "string" && item.length > 0
|
|
1024
|
+
);
|
|
1025
|
+
return strings.length === value.length ? strings : void 0;
|
|
1026
|
+
}
|
|
1027
|
+
function readRecord(value) {
|
|
1028
|
+
return isRecord(value) ? value : void 0;
|
|
1029
|
+
}
|
|
1030
|
+
function readBeliefNodeView(value) {
|
|
1031
|
+
if (!isRecord(value)) {
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
1034
|
+
const id = readOptionalString(value._id);
|
|
1035
|
+
const nodeType = readOptionalString(value.nodeType);
|
|
1036
|
+
if (!(id && nodeType === "belief")) {
|
|
1037
|
+
return null;
|
|
1038
|
+
}
|
|
1039
|
+
const node = {
|
|
1040
|
+
_id: id,
|
|
1041
|
+
nodeType
|
|
1042
|
+
};
|
|
1043
|
+
const creationTime = readFiniteNumber(value._creationTime);
|
|
1044
|
+
if (creationTime !== void 0) {
|
|
1045
|
+
node._creationTime = creationTime;
|
|
1046
|
+
}
|
|
1047
|
+
const metadata = readRecord(value.metadata);
|
|
1048
|
+
if (metadata !== void 0) {
|
|
1049
|
+
node.metadata = metadata;
|
|
1050
|
+
}
|
|
1051
|
+
const opinionA = readFiniteNumber(value.opinion_a);
|
|
1052
|
+
if (opinionA !== void 0) {
|
|
1053
|
+
node.opinion_a = opinionA;
|
|
1054
|
+
}
|
|
1055
|
+
const opinionB = readFiniteNumber(value.opinion_b);
|
|
1056
|
+
if (opinionB !== void 0) {
|
|
1057
|
+
node.opinion_b = opinionB;
|
|
1058
|
+
}
|
|
1059
|
+
const opinionD = readFiniteNumber(value.opinion_d);
|
|
1060
|
+
if (opinionD !== void 0) {
|
|
1061
|
+
node.opinion_d = opinionD;
|
|
1062
|
+
}
|
|
1063
|
+
const opinionU = readFiniteNumber(value.opinion_u);
|
|
1064
|
+
if (opinionU !== void 0) {
|
|
1065
|
+
node.opinion_u = opinionU;
|
|
1066
|
+
}
|
|
1067
|
+
const tupleContradicted = typeof value.tupleContradicted === "boolean" ? value.tupleContradicted : void 0;
|
|
1068
|
+
if (tupleContradicted !== void 0) {
|
|
1069
|
+
node.tupleContradicted = tupleContradicted;
|
|
1070
|
+
}
|
|
1071
|
+
const stringFields = {
|
|
1072
|
+
anonymizationClass: value.anonymizationClass,
|
|
1073
|
+
audienceLabel: value.audienceLabel,
|
|
1074
|
+
canonicalText: value.canonicalText,
|
|
1075
|
+
createdBy: value.createdBy,
|
|
1076
|
+
epistemicLayer: value.epistemicLayer,
|
|
1077
|
+
exportClass: value.exportClass,
|
|
1078
|
+
globalId: value.globalId,
|
|
1079
|
+
projectId: value.projectId,
|
|
1080
|
+
publicationStatus: value.publicationStatus,
|
|
1081
|
+
sensitivityTier: value.sensitivityTier,
|
|
1082
|
+
status: value.status,
|
|
1083
|
+
tenantId: value.tenantId,
|
|
1084
|
+
topicId: value.topicId,
|
|
1085
|
+
userId: value.userId,
|
|
1086
|
+
workspaceId: value.workspaceId
|
|
1087
|
+
};
|
|
1088
|
+
for (const [field, fieldValue] of Object.entries(stringFields)) {
|
|
1089
|
+
const normalized = readOptionalString(fieldValue);
|
|
1090
|
+
if (normalized !== void 0) {
|
|
1091
|
+
node[field] = normalized;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
const createdAt = readFiniteNumber(value.createdAt);
|
|
1095
|
+
if (createdAt !== void 0) {
|
|
1096
|
+
node.createdAt = createdAt;
|
|
1097
|
+
}
|
|
1098
|
+
const updatedAt = readFiniteNumber(value.updatedAt);
|
|
1099
|
+
if (updatedAt !== void 0) {
|
|
1100
|
+
node.updatedAt = updatedAt;
|
|
1101
|
+
}
|
|
1102
|
+
if (value.beliefStatus !== void 0) {
|
|
1103
|
+
node.beliefStatus = value.beliefStatus;
|
|
1104
|
+
}
|
|
1105
|
+
if (value.confidence !== void 0) {
|
|
1106
|
+
node.confidence = value.confidence;
|
|
1107
|
+
}
|
|
1108
|
+
if (value.predictionMeta !== void 0) {
|
|
1109
|
+
node.predictionMeta = value.predictionMeta;
|
|
1110
|
+
}
|
|
1111
|
+
const policyTags = readStringArray(value.policyTags);
|
|
1112
|
+
if (policyTags !== void 0) {
|
|
1113
|
+
node.policyTags = policyTags;
|
|
1114
|
+
}
|
|
1115
|
+
return node;
|
|
1116
|
+
}
|
|
965
1117
|
function buildBeliefConfidenceRow(args) {
|
|
966
1118
|
return {
|
|
967
1119
|
beliefId: args.beliefId,
|
|
@@ -1036,7 +1188,10 @@ function resolveBeliefStatus(node, metadata) {
|
|
|
1036
1188
|
});
|
|
1037
1189
|
}
|
|
1038
1190
|
async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
|
|
1039
|
-
const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
|
|
1191
|
+
const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
|
|
1192
|
+
"by_belief",
|
|
1193
|
+
(q) => q.eq("beliefId", beliefNodeId)
|
|
1194
|
+
).collect();
|
|
1040
1195
|
for (const membership of clusterMembership) {
|
|
1041
1196
|
const worktree = await ctx.db.get(membership.worktreeId);
|
|
1042
1197
|
if (worktree?.status === "completed" || worktree?.status === "merged") {
|
|
@@ -1047,7 +1202,10 @@ async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
|
|
|
1047
1202
|
}
|
|
1048
1203
|
async function getActiveConfidencePolicy(ctx) {
|
|
1049
1204
|
try {
|
|
1050
|
-
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
1205
|
+
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
1206
|
+
"by_active",
|
|
1207
|
+
(q) => q.eq("isActive", true)
|
|
1208
|
+
).first();
|
|
1051
1209
|
return {
|
|
1052
1210
|
scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
|
|
1053
1211
|
tupleContradiction: normalizeTupleContradictionPolicy(
|
|
@@ -1081,9 +1239,189 @@ async function requireAuthenticatedUserId(ctx) {
|
|
|
1081
1239
|
}
|
|
1082
1240
|
|
|
1083
1241
|
// src/epistemicBeliefs.confidence.ts
|
|
1242
|
+
function isRecord2(value) {
|
|
1243
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1244
|
+
}
|
|
1245
|
+
function readConvexId(value) {
|
|
1246
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1247
|
+
}
|
|
1248
|
+
function readOptionalBoolean(value) {
|
|
1249
|
+
return typeof value === "boolean" ? value : void 0;
|
|
1250
|
+
}
|
|
1251
|
+
function readOptionalNumber(value) {
|
|
1252
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1253
|
+
}
|
|
1254
|
+
function readOptionalString2(value) {
|
|
1255
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1256
|
+
}
|
|
1257
|
+
function readRecord2(value) {
|
|
1258
|
+
return isRecord2(value) ? value : void 0;
|
|
1259
|
+
}
|
|
1260
|
+
function readConfidenceBeliefNode(value) {
|
|
1261
|
+
if (!isRecord2(value)) {
|
|
1262
|
+
return null;
|
|
1263
|
+
}
|
|
1264
|
+
const id = readConvexId(value._id);
|
|
1265
|
+
const nodeType = readOptionalString2(value.nodeType);
|
|
1266
|
+
const projectId = readOptionalString2(value.projectId);
|
|
1267
|
+
if (!(id && nodeType === "belief" && projectId)) {
|
|
1268
|
+
return null;
|
|
1269
|
+
}
|
|
1270
|
+
const node = {
|
|
1271
|
+
_id: id,
|
|
1272
|
+
nodeType,
|
|
1273
|
+
projectId
|
|
1274
|
+
};
|
|
1275
|
+
const confidence = readOptionalNumber(value.confidence);
|
|
1276
|
+
const epistemicLayer = readOptionalString2(value.epistemicLayer);
|
|
1277
|
+
const globalId = readOptionalString2(value.globalId);
|
|
1278
|
+
const metadata = readRecord2(value.metadata);
|
|
1279
|
+
const opinionA = readOptionalNumber(value.opinion_a);
|
|
1280
|
+
const opinionB = readOptionalNumber(value.opinion_b);
|
|
1281
|
+
const opinionD = readOptionalNumber(value.opinion_d);
|
|
1282
|
+
const opinionU = readOptionalNumber(value.opinion_u);
|
|
1283
|
+
const predictionMeta = readRecord2(value.predictionMeta);
|
|
1284
|
+
const publicationStatus = readOptionalString2(value.publicationStatus);
|
|
1285
|
+
const status = readOptionalString2(value.status);
|
|
1286
|
+
const tenantId = readOptionalString2(value.tenantId);
|
|
1287
|
+
const topicId = readOptionalString2(value.topicId);
|
|
1288
|
+
const tupleContradicted = readOptionalBoolean(value.tupleContradicted);
|
|
1289
|
+
const workspaceId = readOptionalString2(value.workspaceId);
|
|
1290
|
+
if (confidence !== void 0) {
|
|
1291
|
+
node.confidence = confidence;
|
|
1292
|
+
}
|
|
1293
|
+
if (epistemicLayer !== void 0) {
|
|
1294
|
+
node.epistemicLayer = epistemicLayer;
|
|
1295
|
+
}
|
|
1296
|
+
if (globalId !== void 0) {
|
|
1297
|
+
node.globalId = globalId;
|
|
1298
|
+
}
|
|
1299
|
+
if (metadata !== void 0) {
|
|
1300
|
+
node.metadata = metadata;
|
|
1301
|
+
}
|
|
1302
|
+
if (opinionA !== void 0) {
|
|
1303
|
+
node.opinion_a = opinionA;
|
|
1304
|
+
}
|
|
1305
|
+
if (opinionB !== void 0) {
|
|
1306
|
+
node.opinion_b = opinionB;
|
|
1307
|
+
}
|
|
1308
|
+
if (opinionD !== void 0) {
|
|
1309
|
+
node.opinion_d = opinionD;
|
|
1310
|
+
}
|
|
1311
|
+
if (opinionU !== void 0) {
|
|
1312
|
+
node.opinion_u = opinionU;
|
|
1313
|
+
}
|
|
1314
|
+
if (predictionMeta !== void 0) {
|
|
1315
|
+
node.predictionMeta = predictionMeta;
|
|
1316
|
+
}
|
|
1317
|
+
if (publicationStatus !== void 0) {
|
|
1318
|
+
node.publicationStatus = publicationStatus;
|
|
1319
|
+
}
|
|
1320
|
+
if (status !== void 0) {
|
|
1321
|
+
node.status = status;
|
|
1322
|
+
}
|
|
1323
|
+
if (tenantId !== void 0) {
|
|
1324
|
+
node.tenantId = tenantId;
|
|
1325
|
+
}
|
|
1326
|
+
if (topicId !== void 0) {
|
|
1327
|
+
node.topicId = topicId;
|
|
1328
|
+
}
|
|
1329
|
+
if (tupleContradicted !== void 0) {
|
|
1330
|
+
node.tupleContradicted = tupleContradicted;
|
|
1331
|
+
}
|
|
1332
|
+
if (workspaceId !== void 0) {
|
|
1333
|
+
node.workspaceId = workspaceId;
|
|
1334
|
+
}
|
|
1335
|
+
return node;
|
|
1336
|
+
}
|
|
1337
|
+
function readPropagationEdge(value) {
|
|
1338
|
+
if (!isRecord2(value)) {
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
const edgeType = readOptionalString2(value.edgeType);
|
|
1342
|
+
if (!edgeType) {
|
|
1343
|
+
return null;
|
|
1344
|
+
}
|
|
1345
|
+
const edge = { edgeType };
|
|
1346
|
+
const fromNodeId = readConvexId(value.fromNodeId);
|
|
1347
|
+
const tenantId = readOptionalString2(value.tenantId);
|
|
1348
|
+
const toNodeId = readConvexId(value.toNodeId);
|
|
1349
|
+
const weight = readOptionalNumber(value.weight);
|
|
1350
|
+
const workspaceId = readOptionalString2(value.workspaceId);
|
|
1351
|
+
if (fromNodeId !== void 0) {
|
|
1352
|
+
edge.fromNodeId = fromNodeId;
|
|
1353
|
+
}
|
|
1354
|
+
if (tenantId !== void 0) {
|
|
1355
|
+
edge.tenantId = tenantId;
|
|
1356
|
+
}
|
|
1357
|
+
if (toNodeId !== void 0) {
|
|
1358
|
+
edge.toNodeId = toNodeId;
|
|
1359
|
+
}
|
|
1360
|
+
if (weight !== void 0) {
|
|
1361
|
+
edge.weight = weight;
|
|
1362
|
+
}
|
|
1363
|
+
if (workspaceId !== void 0) {
|
|
1364
|
+
edge.workspaceId = workspaceId;
|
|
1365
|
+
}
|
|
1366
|
+
return edge;
|
|
1367
|
+
}
|
|
1368
|
+
function readRowList(values, reader) {
|
|
1369
|
+
return values.flatMap((value) => {
|
|
1370
|
+
const row = reader(value);
|
|
1371
|
+
return row ? [row] : [];
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1084
1374
|
async function applyBeliefConfidenceChange(ctx, args) {
|
|
1085
1375
|
const now = Date.now();
|
|
1086
|
-
const node = await ctx
|
|
1376
|
+
const node = await requireConfidenceBeliefNode(ctx, args);
|
|
1377
|
+
const state = await buildConfidenceChangeState(ctx, node, args);
|
|
1378
|
+
await assertConfidenceScoringPolicySatisfied(ctx, args, state);
|
|
1379
|
+
const tupleContradictionId = await createTupleContradictionIfNeeded(
|
|
1380
|
+
ctx,
|
|
1381
|
+
args,
|
|
1382
|
+
node,
|
|
1383
|
+
state
|
|
1384
|
+
);
|
|
1385
|
+
await patchBeliefConfidenceState(ctx, args, state);
|
|
1386
|
+
await scheduleFirstScoringThemeEdges(ctx, args, node, state);
|
|
1387
|
+
const beliefConfidenceId = await insertBeliefConfidenceRecord(
|
|
1388
|
+
ctx,
|
|
1389
|
+
args,
|
|
1390
|
+
state,
|
|
1391
|
+
tupleContradictionId,
|
|
1392
|
+
now
|
|
1393
|
+
);
|
|
1394
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1395
|
+
nodeId: args.nodeId,
|
|
1396
|
+
operation: "upsert"
|
|
1397
|
+
});
|
|
1398
|
+
await insertConfidenceAudit(
|
|
1399
|
+
ctx,
|
|
1400
|
+
args,
|
|
1401
|
+
node,
|
|
1402
|
+
state,
|
|
1403
|
+
tupleContradictionId,
|
|
1404
|
+
now
|
|
1405
|
+
);
|
|
1406
|
+
await insertTupleTransitionAuditIfNeeded(
|
|
1407
|
+
ctx,
|
|
1408
|
+
args,
|
|
1409
|
+
node,
|
|
1410
|
+
state,
|
|
1411
|
+
tupleContradictionId,
|
|
1412
|
+
now
|
|
1413
|
+
);
|
|
1414
|
+
await scheduleConfidenceFollowups(ctx, args, node, state);
|
|
1415
|
+
return {
|
|
1416
|
+
nodeId: args.nodeId,
|
|
1417
|
+
previousConfidence: state.previousConfidence,
|
|
1418
|
+
newConfidence: state.derivedConfidence,
|
|
1419
|
+
opinion: state.nextOpinion,
|
|
1420
|
+
beliefConfidenceId
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
async function requireConfidenceBeliefNode(ctx, args) {
|
|
1424
|
+
const node = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
|
|
1087
1425
|
if (!node) {
|
|
1088
1426
|
throwStructuredMutationError({
|
|
1089
1427
|
message: "Node not found.",
|
|
@@ -1094,59 +1432,28 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1094
1432
|
details: { nodeId: args.nodeId }
|
|
1095
1433
|
});
|
|
1096
1434
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
invariantCode: "entity.no_confidence",
|
|
1103
|
-
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
|
|
1104
|
-
details: { nodeId: args.nodeId, nodeType: node.nodeType }
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1107
|
-
if (!node.projectId) {
|
|
1108
|
-
throwStructuredMutationError({
|
|
1109
|
-
message: "Belief has no project scope.",
|
|
1110
|
-
status: 400,
|
|
1111
|
-
code: "MISSING_SCOPE",
|
|
1112
|
-
invariantCode: "belief.project_required",
|
|
1113
|
-
suggestion: "Belief must have a projectId before SL scoring can be appended.",
|
|
1114
|
-
details: { nodeId: args.nodeId }
|
|
1115
|
-
});
|
|
1116
|
-
}
|
|
1117
|
-
await requireScopeWriteAccess(
|
|
1118
|
-
ctx,
|
|
1119
|
-
node.projectId,
|
|
1120
|
-
args.authenticatedUserId
|
|
1121
|
-
);
|
|
1122
|
-
const existingMetadata = node.metadata || {};
|
|
1435
|
+
await requireScopeWriteAccess(ctx, node.projectId, args.authenticatedUserId);
|
|
1436
|
+
return node;
|
|
1437
|
+
}
|
|
1438
|
+
async function buildConfidenceChangeState(ctx, node, args) {
|
|
1439
|
+
const existingMetadata = readNodeMetadata(node);
|
|
1123
1440
|
const currentBeliefStatus = resolveBeliefStatus(node, existingMetadata);
|
|
1124
1441
|
const confidencePolicy = await getActiveConfidencePolicy(ctx);
|
|
1125
|
-
if (confidencePolicy.scoringMode === "after_worktree" && isPreValidationBeliefStatus(currentBeliefStatus)) {
|
|
1126
|
-
const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
|
|
1127
|
-
ctx,
|
|
1128
|
-
args.nodeId
|
|
1129
|
-
);
|
|
1130
|
-
if (!hasCompletedWorktree) {
|
|
1131
|
-
throwStructuredMutationError({
|
|
1132
|
-
message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
|
|
1133
|
-
status: 409,
|
|
1134
|
-
code: "CONFLICT",
|
|
1135
|
-
invariantCode: "belief.confidence_append_only",
|
|
1136
|
-
suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
|
|
1137
|
-
details: { nodeId: args.nodeId }
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
1442
|
const previousConfidence = node.confidence || 0.5;
|
|
1142
1443
|
const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
|
|
1143
1444
|
const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1445
|
+
const nextOpinion = {
|
|
1446
|
+
b: args.belief,
|
|
1447
|
+
d: args.disbelief,
|
|
1448
|
+
u: args.uncertainty,
|
|
1449
|
+
a: args.baseRate ?? 0.5
|
|
1450
|
+
};
|
|
1451
|
+
const derivedConfidence = confidenceFromSL(
|
|
1452
|
+
nextOpinion.b,
|
|
1453
|
+
nextOpinion.d,
|
|
1454
|
+
nextOpinion.u,
|
|
1455
|
+
nextOpinion.a
|
|
1456
|
+
);
|
|
1150
1457
|
const isFirstScoring = typeof node.confidence !== "number" || !Number.isFinite(node.confidence);
|
|
1151
1458
|
const previousTupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(existingMetadata.tupleContradicted) ?? detectTupleContradiction(
|
|
1152
1459
|
previousOpinion,
|
|
@@ -1167,79 +1474,121 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1167
1474
|
predictionMeta,
|
|
1168
1475
|
metadata: existingMetadata
|
|
1169
1476
|
});
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1477
|
+
const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
|
|
1478
|
+
return {
|
|
1479
|
+
confidencePolicy,
|
|
1480
|
+
currentBeliefStatus,
|
|
1481
|
+
derivedConfidence,
|
|
1482
|
+
existingMetadata,
|
|
1483
|
+
isFirstScoring,
|
|
1484
|
+
newBeliefStatus,
|
|
1485
|
+
nextOpinion,
|
|
1486
|
+
previousConfidence,
|
|
1487
|
+
previousTupleContradicted,
|
|
1488
|
+
storedRationale,
|
|
1489
|
+
tupleContradictionDescription,
|
|
1490
|
+
tupleTransition
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
function readNodeMetadata(node) {
|
|
1494
|
+
return node.metadata ?? {};
|
|
1495
|
+
}
|
|
1496
|
+
async function assertConfidenceScoringPolicySatisfied(ctx, args, state) {
|
|
1497
|
+
if (state.confidencePolicy.scoringMode !== "after_worktree" || !isPreValidationBeliefStatus(state.currentBeliefStatus)) {
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
|
|
1501
|
+
ctx,
|
|
1502
|
+
args.nodeId
|
|
1503
|
+
);
|
|
1504
|
+
if (hasCompletedWorktree) {
|
|
1505
|
+
return;
|
|
1188
1506
|
}
|
|
1507
|
+
throwStructuredMutationError({
|
|
1508
|
+
message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
|
|
1509
|
+
status: 409,
|
|
1510
|
+
code: "CONFLICT",
|
|
1511
|
+
invariantCode: "belief.confidence_append_only",
|
|
1512
|
+
suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
|
|
1513
|
+
details: { nodeId: args.nodeId }
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
async function createTupleContradictionIfNeeded(ctx, args, node, state) {
|
|
1517
|
+
if (!state.tupleTransition.crossedIntoTupleContradiction) {
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
return await ctx.runMutation("contradictions:create", {
|
|
1521
|
+
projectId: node.projectId,
|
|
1522
|
+
topicId: node.topicId,
|
|
1523
|
+
beliefId: args.nodeId,
|
|
1524
|
+
beliefBId: args.nodeId,
|
|
1525
|
+
supportingInsightIds: [],
|
|
1526
|
+
contradictingInsightIds: [],
|
|
1527
|
+
severity: deriveTupleContradictionSeverity(node),
|
|
1528
|
+
source: "tuple_space",
|
|
1529
|
+
detectionMethod: "agent",
|
|
1530
|
+
description: state.tupleContradictionDescription,
|
|
1531
|
+
createdBy: args.authenticatedUserId
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
async function patchBeliefConfidenceState(ctx, args, state) {
|
|
1189
1535
|
await ctx.db.patch(args.nodeId, {
|
|
1190
|
-
confidence: derivedConfidence,
|
|
1191
|
-
beliefStatus: newBeliefStatus,
|
|
1192
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1193
|
-
updatedAt: now,
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
opinion_a: slA,
|
|
1536
|
+
confidence: state.derivedConfidence,
|
|
1537
|
+
beliefStatus: state.newBeliefStatus,
|
|
1538
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1539
|
+
updatedAt: Date.now(),
|
|
1540
|
+
opinion_b: state.nextOpinion.b,
|
|
1541
|
+
opinion_d: state.nextOpinion.d,
|
|
1542
|
+
opinion_u: state.nextOpinion.u,
|
|
1543
|
+
opinion_a: state.nextOpinion.a,
|
|
1199
1544
|
metadata: {
|
|
1200
|
-
...existingMetadata,
|
|
1201
|
-
beliefStatus: newBeliefStatus,
|
|
1202
|
-
slBelief:
|
|
1203
|
-
slDisbelief:
|
|
1204
|
-
slUncertainty:
|
|
1205
|
-
slBaseRate:
|
|
1206
|
-
tupleContradicted: tupleTransition.tupleContradicted
|
|
1545
|
+
...state.existingMetadata,
|
|
1546
|
+
beliefStatus: state.newBeliefStatus,
|
|
1547
|
+
slBelief: state.nextOpinion.b,
|
|
1548
|
+
slDisbelief: state.nextOpinion.d,
|
|
1549
|
+
slUncertainty: state.nextOpinion.u,
|
|
1550
|
+
slBaseRate: state.nextOpinion.a,
|
|
1551
|
+
tupleContradicted: state.tupleTransition.tupleContradicted
|
|
1207
1552
|
}
|
|
1208
1553
|
});
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
edgeType: "relates_to_thesis",
|
|
1222
|
-
weight: derivedConfidence,
|
|
1223
|
-
createdBy: args.authenticatedUserId,
|
|
1224
|
-
topicId: String(node.projectId),
|
|
1225
|
-
fromNodeType: "belief",
|
|
1226
|
-
toNodeType: "theme",
|
|
1227
|
-
fromLayer: "L3",
|
|
1228
|
-
toLayer: "L3"
|
|
1229
|
-
});
|
|
1230
|
-
}
|
|
1554
|
+
}
|
|
1555
|
+
async function scheduleFirstScoringThemeEdges(ctx, args, node, state) {
|
|
1556
|
+
if (!state.isFirstScoring) {
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
1560
|
+
"by_topic",
|
|
1561
|
+
(q) => q.eq("topicId", node.topicId || node.projectId)
|
|
1562
|
+
).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
|
|
1563
|
+
for (const theme of themeNodes) {
|
|
1564
|
+
if (!(theme.globalId && node.globalId)) {
|
|
1565
|
+
continue;
|
|
1231
1566
|
}
|
|
1567
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
1568
|
+
globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
|
|
1569
|
+
fromGlobalId: node.globalId,
|
|
1570
|
+
toGlobalId: theme.globalId,
|
|
1571
|
+
edgeType: "relates_to_thesis",
|
|
1572
|
+
weight: state.derivedConfidence,
|
|
1573
|
+
createdBy: args.authenticatedUserId,
|
|
1574
|
+
topicId: String(node.projectId),
|
|
1575
|
+
fromNodeType: "belief",
|
|
1576
|
+
toNodeType: "theme",
|
|
1577
|
+
fromLayer: "L3",
|
|
1578
|
+
toLayer: "L3"
|
|
1579
|
+
});
|
|
1232
1580
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1581
|
+
}
|
|
1582
|
+
async function insertBeliefConfidenceRecord(ctx, args, state, tupleContradictionId, now) {
|
|
1583
|
+
return await ctx.db.insert("beliefConfidence", {
|
|
1235
1584
|
...buildBeliefConfidenceRow({
|
|
1236
1585
|
beliefId: args.nodeId,
|
|
1237
|
-
belief:
|
|
1238
|
-
disbelief:
|
|
1239
|
-
uncertainty:
|
|
1240
|
-
baseRate:
|
|
1586
|
+
belief: state.nextOpinion.b,
|
|
1587
|
+
disbelief: state.nextOpinion.d,
|
|
1588
|
+
uncertainty: state.nextOpinion.u,
|
|
1589
|
+
baseRate: state.nextOpinion.a,
|
|
1241
1590
|
trigger: args.trigger,
|
|
1242
|
-
rationale: storedRationale,
|
|
1591
|
+
rationale: state.storedRationale,
|
|
1243
1592
|
assessedBy: args.authenticatedUserId,
|
|
1244
1593
|
assessedAt: now,
|
|
1245
1594
|
slOperator: args.slOperator,
|
|
@@ -1248,25 +1597,23 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1248
1597
|
triggeringWorktreeId: args.triggeringWorktreeId
|
|
1249
1598
|
})
|
|
1250
1599
|
});
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
operation: "upsert"
|
|
1254
|
-
});
|
|
1600
|
+
}
|
|
1601
|
+
async function insertConfidenceAudit(ctx, args, node, state, tupleContradictionId, now) {
|
|
1255
1602
|
await ctx.db.insert("epistemicAudit", {
|
|
1256
1603
|
entityType: "belief",
|
|
1257
1604
|
entityId: args.nodeId,
|
|
1258
1605
|
changeType: "confidence_changed",
|
|
1259
1606
|
previousState: {
|
|
1260
|
-
confidence: previousConfidence,
|
|
1261
|
-
tupleContradicted: previousTupleContradicted
|
|
1607
|
+
confidence: state.previousConfidence,
|
|
1608
|
+
tupleContradicted: state.previousTupleContradicted
|
|
1262
1609
|
},
|
|
1263
1610
|
newState: {
|
|
1264
|
-
opinion: nextOpinion,
|
|
1265
|
-
confidence: derivedConfidence,
|
|
1611
|
+
opinion: state.nextOpinion,
|
|
1612
|
+
confidence: state.derivedConfidence,
|
|
1266
1613
|
trigger: args.trigger,
|
|
1267
|
-
rationale: storedRationale,
|
|
1268
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1269
|
-
tupleContradictionPolicy: tupleTransition.policy,
|
|
1614
|
+
rationale: state.storedRationale,
|
|
1615
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1616
|
+
tupleContradictionPolicy: state.tupleTransition.policy,
|
|
1270
1617
|
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1271
1618
|
},
|
|
1272
1619
|
changedBy: args.authenticatedUserId,
|
|
@@ -1275,28 +1622,39 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1275
1622
|
projectId: node.projectId,
|
|
1276
1623
|
topicId: node.topicId
|
|
1277
1624
|
});
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1625
|
+
}
|
|
1626
|
+
async function insertTupleTransitionAuditIfNeeded(ctx, args, node, state, tupleContradictionId, now) {
|
|
1627
|
+
if (!(state.tupleTransition.crossedIntoTupleContradiction || state.tupleTransition.crossedOutOfTupleContradiction)) {
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1631
|
+
entityType: "belief",
|
|
1632
|
+
entityId: args.nodeId,
|
|
1633
|
+
changeType: "updated",
|
|
1634
|
+
previousState: { tupleContradicted: state.previousTupleContradicted },
|
|
1635
|
+
newState: {
|
|
1636
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1637
|
+
action: state.tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
|
|
1638
|
+
opinion: state.nextOpinion,
|
|
1639
|
+
tupleContradictionPolicy: state.tupleTransition.policy,
|
|
1640
|
+
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1641
|
+
},
|
|
1642
|
+
rationale: tupleAuditRationale(state),
|
|
1643
|
+
changedBy: args.authenticatedUserId,
|
|
1644
|
+
isAgent: false,
|
|
1645
|
+
changedAt: now,
|
|
1646
|
+
projectId: node.projectId,
|
|
1647
|
+
topicId: node.topicId
|
|
1648
|
+
});
|
|
1649
|
+
}
|
|
1650
|
+
function tupleAuditRationale(state) {
|
|
1651
|
+
if (state.tupleTransition.crossedIntoTupleContradiction) {
|
|
1652
|
+
return state.tupleContradictionDescription;
|
|
1298
1653
|
}
|
|
1299
|
-
|
|
1654
|
+
return `Tuple-space contradiction cleared: b=${state.nextOpinion.b.toFixed(2)}, d=${state.nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`;
|
|
1655
|
+
}
|
|
1656
|
+
async function scheduleConfidenceFollowups(ctx, args, node, state) {
|
|
1657
|
+
if (Math.abs(state.derivedConfidence - state.previousConfidence) >= 0.15) {
|
|
1300
1658
|
await ctx.scheduler.runAfter(
|
|
1301
1659
|
5e3,
|
|
1302
1660
|
internal.bi.contradictionSemanticDetector.scanAffectedBeliefs,
|
|
@@ -1313,13 +1671,6 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1313
1671
|
{ nodeId: args.nodeId }
|
|
1314
1672
|
);
|
|
1315
1673
|
}
|
|
1316
|
-
return {
|
|
1317
|
-
nodeId: args.nodeId,
|
|
1318
|
-
previousConfidence,
|
|
1319
|
-
newConfidence: derivedConfidence,
|
|
1320
|
-
opinion: { b: slB, d: slD, u: slU, a: slA },
|
|
1321
|
-
beliefConfidenceId
|
|
1322
|
-
};
|
|
1323
1674
|
}
|
|
1324
1675
|
function propagationPressureLabel(edgeType, weight) {
|
|
1325
1676
|
if (edgeType === "contradicts" || edgeType === "refutes") {
|
|
@@ -1347,7 +1698,7 @@ internalMutation({
|
|
|
1347
1698
|
args.opinion_u,
|
|
1348
1699
|
args.opinion_a
|
|
1349
1700
|
);
|
|
1350
|
-
const sourceNode = await ctx.db.get(args.nodeId);
|
|
1701
|
+
const sourceNode = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
|
|
1351
1702
|
const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
|
|
1352
1703
|
ctx,
|
|
1353
1704
|
sourceNode
|
|
@@ -1356,16 +1707,20 @@ internalMutation({
|
|
|
1356
1707
|
sourceNodeId: args.nodeId,
|
|
1357
1708
|
sourceOpinion,
|
|
1358
1709
|
sourceScope,
|
|
1359
|
-
queryEdges: async ({ nodeId, spec, direction }) =>
|
|
1360
|
-
|
|
1710
|
+
queryEdges: async ({ nodeId, spec, direction }) => readRowList(
|
|
1711
|
+
await ctx.db.query("epistemicEdges").withIndex(
|
|
1361
1712
|
direction === "outgoing" ? "by_from_type" : "by_to_type",
|
|
1362
1713
|
(q) => direction === "outgoing" ? q.eq("fromNodeId", nodeId).eq("edgeType", spec.edgeType) : q.eq("toNodeId", nodeId).eq("edgeType", spec.edgeType)
|
|
1363
|
-
).collect()
|
|
1364
|
-
|
|
1365
|
-
|
|
1714
|
+
).collect(),
|
|
1715
|
+
readPropagationEdge
|
|
1716
|
+
),
|
|
1717
|
+
getNode: async (nodeId) => readConfidenceBeliefNode(await ctx.db.get(nodeId))
|
|
1366
1718
|
});
|
|
1367
1719
|
for (const dispatch of dispatches) {
|
|
1368
|
-
const pressureLabel = propagationPressureLabel(
|
|
1720
|
+
const pressureLabel = propagationPressureLabel(
|
|
1721
|
+
dispatch.edgeType,
|
|
1722
|
+
dispatch.weight
|
|
1723
|
+
);
|
|
1369
1724
|
await applyBeliefConfidenceChange(ctx, {
|
|
1370
1725
|
nodeId: dispatch.targetNodeId,
|
|
1371
1726
|
belief: dispatch.opinion.b,
|
|
@@ -1388,6 +1743,8 @@ internalMutation({
|
|
|
1388
1743
|
};
|
|
1389
1744
|
}
|
|
1390
1745
|
});
|
|
1746
|
+
|
|
1747
|
+
// src/epistemicBeliefs.lifecycle.ts
|
|
1391
1748
|
var appendSlScoring = mutation({
|
|
1392
1749
|
args: {
|
|
1393
1750
|
nodeId: v.id("epistemicNodes"),
|
|
@@ -1486,8 +1843,8 @@ var updateStatus = mutation({
|
|
|
1486
1843
|
handler: async (ctx, args) => {
|
|
1487
1844
|
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
1488
1845
|
const now = Date.now();
|
|
1489
|
-
const node = await ctx.db.get(args.nodeId);
|
|
1490
|
-
if (!node
|
|
1846
|
+
const node = readBeliefNodeView(await ctx.db.get(args.nodeId));
|
|
1847
|
+
if (!node) {
|
|
1491
1848
|
throw new Error("Belief not found");
|
|
1492
1849
|
}
|
|
1493
1850
|
if (!node.projectId) {
|
|
@@ -1495,7 +1852,7 @@ var updateStatus = mutation({
|
|
|
1495
1852
|
}
|
|
1496
1853
|
await requireScopeWriteAccess(ctx, node.projectId, authenticatedUserId);
|
|
1497
1854
|
const previousStatus = node.status;
|
|
1498
|
-
const metadata = node.metadata
|
|
1855
|
+
const metadata = node.metadata ?? {};
|
|
1499
1856
|
await ctx.db.patch(args.nodeId, {
|
|
1500
1857
|
status: args.status,
|
|
1501
1858
|
updatedAt: now,
|
|
@@ -1531,8 +1888,8 @@ var archive = mutation({
|
|
|
1531
1888
|
returns: permissiveReturn,
|
|
1532
1889
|
handler: async (ctx, args) => {
|
|
1533
1890
|
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
1534
|
-
const node = await ctx.db.get(args.nodeId);
|
|
1535
|
-
if (!node
|
|
1891
|
+
const node = readBeliefNodeView(await ctx.db.get(args.nodeId));
|
|
1892
|
+
if (!node) {
|
|
1536
1893
|
throw new Error("Belief not found");
|
|
1537
1894
|
}
|
|
1538
1895
|
if (!node.projectId) {
|
|
@@ -1561,15 +1918,15 @@ var updateRationale = mutation({
|
|
|
1561
1918
|
handler: async (ctx, args) => {
|
|
1562
1919
|
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
1563
1920
|
const now = Date.now();
|
|
1564
|
-
const node = await ctx.db.get(args.nodeId);
|
|
1565
|
-
if (!node
|
|
1921
|
+
const node = readBeliefNodeView(await ctx.db.get(args.nodeId));
|
|
1922
|
+
if (!node) {
|
|
1566
1923
|
throw new Error("Belief not found");
|
|
1567
1924
|
}
|
|
1568
1925
|
if (!node.projectId) {
|
|
1569
1926
|
throw new Error("Belief has no project scope");
|
|
1570
1927
|
}
|
|
1571
1928
|
await requireScopeWriteAccess(ctx, node.projectId, authenticatedUserId);
|
|
1572
|
-
const metadata = node.metadata
|
|
1929
|
+
const metadata = node.metadata ?? {};
|
|
1573
1930
|
const previousRationale = typeof metadata.rationale === "string" ? metadata.rationale : void 0;
|
|
1574
1931
|
const nextRationale = args.rationale?.trim();
|
|
1575
1932
|
await ctx.db.patch(args.nodeId, {
|
|
@@ -1622,8 +1979,8 @@ var updateStatusInternal = internalMutation({
|
|
|
1622
1979
|
returns: permissiveReturn,
|
|
1623
1980
|
handler: async (ctx, args) => {
|
|
1624
1981
|
const now = Date.now();
|
|
1625
|
-
const node = await ctx.db.get(args.nodeId);
|
|
1626
|
-
if (!node
|
|
1982
|
+
const node = readBeliefNodeView(await ctx.db.get(args.nodeId));
|
|
1983
|
+
if (!node) {
|
|
1627
1984
|
throw new Error("Belief not found");
|
|
1628
1985
|
}
|
|
1629
1986
|
assertTenantPackWorkspaceMutationAllowed({
|