@lucern/graph-primitives 1.0.28 → 1.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
- package/dist/beliefDecay.d.ts +1 -1
- package/dist/beliefDecay.js +448 -314
- package/dist/beliefDecay.js.map +1 -1
- package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
- package/dist/beliefEvidenceLinks.d.ts +1 -1
- package/dist/beliefEvidenceLinks.js +843 -624
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
- package/dist/beliefEvidenceLinks.operational.js +91 -18
- package/dist/beliefEvidenceLinks.operational.js.map +1 -1
- package/dist/beliefLifecycle.js.map +1 -1
- package/dist/confidencePropagationDispatch.d.ts +28 -27
- package/dist/confidencePropagationDispatch.js +157 -99
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
- package/dist/contradictions.d.ts +1 -1
- package/dist/contradictions.js +398 -228
- package/dist/contradictions.js.map +1 -1
- package/dist/convex.d.ts +65 -30
- package/dist/convex.js +7 -3
- package/dist/convex.js.map +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/edgeValidation.js +293 -85
- package/dist/edgeValidation.js.map +1 -1
- package/dist/edges/contains.d.ts +1 -1
- package/dist/edges/contains.js.map +1 -1
- package/dist/edges/contradicts.d.ts +1 -1
- package/dist/edges/contradicts.js.map +1 -1
- package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
- package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
- package/dist/edges/depends-on.js.map +1 -0
- package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
- package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
- package/dist/edges/derived-from.js.map +1 -0
- package/dist/edges/elaborates.d.ts +1 -1
- package/dist/edges/elaborates.js.map +1 -1
- package/dist/edges/index.d.ts +7 -3
- package/dist/edges/index.js +7 -4
- package/dist/edges/index.js.map +1 -1
- package/dist/edges/informs.d.ts +1 -1
- package/dist/edges/informs.js.map +1 -1
- package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
- package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
- package/dist/edges/propagation-types.js.map +1 -0
- package/dist/edges/refutes.d.ts +1 -1
- package/dist/edges/refutes.js.map +1 -1
- package/dist/edges/supports.d.ts +1 -1
- package/dist/edges/supports.js.map +1 -1
- package/dist/edges/tests.d.ts +1 -1
- package/dist/edges/tests.js.map +1 -1
- package/dist/edges/utils.d.ts +1 -1
- package/dist/edges/utils.js.map +1 -1
- package/dist/embeddingTrigger.d.ts +14 -6
- package/dist/embeddingTrigger.js +11 -14
- package/dist/embeddingTrigger.js.map +1 -1
- package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
- package/dist/entityBridge.d.ts +1 -1
- package/dist/entityBridge.js +602 -225
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityCanonicalMatch.d.ts +14 -12
- package/dist/entityCanonicalMatch.js.map +1 -1
- package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
- package/dist/entityLifecycle.d.ts +1 -1
- package/dist/entityLifecycle.js +857 -515
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
- package/dist/entityValidation.d.ts +3 -1
- package/dist/entityValidation.js +60 -8
- package/dist/entityValidation.js.map +1 -1
- package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
- package/dist/epistemicAnswers.d.ts +1 -1
- package/dist/epistemicAnswers.js +587 -545
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.d.ts +8 -8
- package/dist/epistemicBeliefs.admin.js +366 -203
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.d.ts +8 -8
- package/dist/epistemicBeliefs.backfills.js +655 -308
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.d.ts +19 -14
- package/dist/epistemicBeliefs.confidence.js +634 -423
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.d.ts +6 -6
- package/dist/epistemicBeliefs.core.js +719 -411
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.d.ts +11 -8
- package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
- package/dist/epistemicBeliefs.forkEvidence.js +8 -28
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
- package/dist/epistemicBeliefs.helpers.d.ts +69 -74
- package/dist/epistemicBeliefs.helpers.js +359 -248
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.d.ts +5 -5
- package/dist/epistemicBeliefs.internal.js +1246 -1044
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +4922 -3608
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
- package/dist/epistemicBeliefs.lifecycle.js +1137 -818
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.d.ts +7 -7
- package/dist/epistemicBeliefs.links.js +408 -307
- package/dist/epistemicBeliefs.links.js.map +1 -1
- package/dist/epistemicBeliefs.queries.d.ts +4 -4
- package/dist/epistemicBeliefs.queries.js +175 -20
- package/dist/epistemicBeliefs.queries.js.map +1 -1
- package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
- package/dist/epistemicBeliefs.topicAnchor.js +12 -5
- package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
- package/dist/epistemicContracts.d.ts +28 -3
- package/dist/epistemicContracts.evaluators.d.ts +2 -0
- package/dist/epistemicContracts.evaluators.js +1063 -613
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.d.ts +15 -32
- package/dist/epistemicContracts.handlers.js +2086 -1644
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +1131 -672
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicContracts.metrics.d.ts +2 -0
- package/dist/epistemicContracts.metrics.js +375 -158
- package/dist/epistemicContracts.metrics.js.map +1 -1
- package/dist/epistemicContracts.types.d.ts +87 -81
- package/dist/epistemicEdgeCreation.d.ts +2 -0
- package/dist/epistemicEdgeCreation.js +87 -16
- package/dist/epistemicEdgeCreation.js.map +1 -1
- package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
- package/dist/epistemicEdges.d.ts +6 -5
- package/dist/epistemicEdges.handlers.d.ts +3 -3
- package/dist/epistemicEdges.handlers.js +129 -24
- package/dist/epistemicEdges.handlers.js.map +1 -1
- package/dist/epistemicEdges.helpers.d.ts +6 -4
- package/dist/epistemicEdges.helpers.js +37 -2
- package/dist/epistemicEdges.helpers.js.map +1 -1
- package/dist/epistemicEdges.js +1969 -1205
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.d.ts +7 -7
- package/dist/epistemicEdges.mutations.js +960 -583
- package/dist/epistemicEdges.mutations.js.map +1 -1
- package/dist/epistemicEdges.queries.d.ts +16 -16
- package/dist/epistemicEdges.queries.js +639 -367
- package/dist/epistemicEdges.queries.js.map +1 -1
- package/dist/epistemicEdges.types.d.ts +10 -8
- package/dist/epistemicEvidence.d.ts +4 -1
- package/dist/epistemicEvidence.js +937 -536
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.d.ts +26 -10
- package/dist/epistemicEvidenceHelpers.js +239 -200
- package/dist/epistemicEvidenceHelpers.js.map +1 -1
- package/dist/epistemicEvidenceMutations.d.ts +8 -8
- package/dist/epistemicEvidenceMutations.js +844 -696
- package/dist/epistemicEvidenceMutations.js.map +1 -1
- package/dist/epistemicEvidenceQueries.d.ts +8 -8
- package/dist/epistemicEvidenceQueries.js +514 -238
- package/dist/epistemicEvidenceQueries.js.map +1 -1
- package/dist/epistemicHelpers.d.ts +4 -2
- package/dist/epistemicHelpers.js +308 -134
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicInsert.d.ts +16 -4
- package/dist/epistemicInsert.js +6 -3
- package/dist/epistemicInsert.js.map +1 -1
- package/dist/epistemicLayerRules.d.ts +10 -8
- package/dist/epistemicLayerRules.js +1 -5
- package/dist/epistemicLayerRules.js.map +1 -1
- package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
- package/dist/epistemicLinking.d.ts +1 -1
- package/dist/epistemicLinking.js +177 -100
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodeCreation.d.ts +2 -0
- package/dist/epistemicNodeCreation.js +203 -40
- package/dist/epistemicNodeCreation.js.map +1 -1
- package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
- package/dist/epistemicNodes.d.ts +3 -3
- package/dist/epistemicNodes.helpers.d.ts +24 -15
- package/dist/epistemicNodes.helpers.js.map +1 -1
- package/dist/epistemicNodes.internal.d.ts +6 -6
- package/dist/epistemicNodes.internal.js +389 -319
- package/dist/epistemicNodes.internal.js.map +1 -1
- package/dist/epistemicNodes.js +704 -508
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.d.ts +6 -6
- package/dist/epistemicNodes.mutations.js +564 -467
- package/dist/epistemicNodes.mutations.js.map +1 -1
- package/dist/epistemicNodes.queries.d.ts +8 -8
- package/dist/epistemicNodes.queries.js +311 -314
- package/dist/epistemicNodes.queries.js.map +1 -1
- package/dist/epistemicNodes.validators.d.ts +2 -2
- package/dist/epistemicNodes.validators.js.map +1 -1
- package/dist/epistemicQuestions.conviction.d.ts +8 -8
- package/dist/epistemicQuestions.conviction.js +665 -484
- package/dist/epistemicQuestions.conviction.js.map +1 -1
- package/dist/epistemicQuestions.create.d.ts +4 -4
- package/dist/epistemicQuestions.create.js +640 -612
- package/dist/epistemicQuestions.create.js.map +1 -1
- package/dist/epistemicQuestions.d.ts +8 -5
- package/dist/epistemicQuestions.evidence.d.ts +2 -2
- package/dist/epistemicQuestions.evidence.js +475 -383
- package/dist/epistemicQuestions.evidence.js.map +1 -1
- package/dist/epistemicQuestions.helpers.d.ts +125 -24
- package/dist/epistemicQuestions.helpers.js +240 -209
- package/dist/epistemicQuestions.helpers.js.map +1 -1
- package/dist/epistemicQuestions.js +3474 -2823
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
- package/dist/epistemicQuestions.lifecycle.js +607 -546
- package/dist/epistemicQuestions.lifecycle.js.map +1 -1
- package/dist/epistemicQuestions.queries.d.ts +12 -7
- package/dist/epistemicQuestions.queries.js +305 -244
- package/dist/epistemicQuestions.queries.js.map +1 -1
- package/dist/epistemicQuestions.sprint.d.ts +2 -2
- package/dist/epistemicQuestions.sprint.js +600 -394
- package/dist/epistemicQuestions.sprint.js.map +1 -1
- package/dist/epistemicQuestions.tail.d.ts +6 -6
- package/dist/epistemicQuestions.tail.js +572 -433
- package/dist/epistemicQuestions.tail.js.map +1 -1
- package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
- package/dist/epistemicSources.d.ts +1 -1
- package/dist/epistemicSources.js +352 -312
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.d.ts +8 -6
- package/dist/evaluators/index.js +399 -167
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
- package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
- package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
- package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
- package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
- package/dist/evaluators/shared.d.ts +2 -2
- package/dist/evaluators/shared.js +3 -1
- package/dist/evaluators/shared.js.map +1 -1
- package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
- package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
- package/dist/evaluators/test-runner-evaluator.js.map +1 -0
- package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
- package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
- package/dist/graphTypes.js +6 -2
- package/dist/graphTypes.js.map +1 -1
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +313 -93
- package/dist/helpers.js.map +1 -1
- package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
- package/dist/index.d.ts +87 -83
- package/dist/index.js +15677 -10594
- package/dist/index.js.map +1 -1
- package/dist/invariantEnforcement.d.ts +3 -3
- package/dist/invariantEnforcement.js.map +1 -1
- package/dist/logicalRoleInference.d.ts +2 -0
- package/dist/logicalRoleInference.js +1 -1
- package/dist/logicalRoleInference.js.map +1 -1
- package/dist/matcherFeedbackUtils.d.ts +2 -2
- package/dist/matcherFeedbackUtils.js.map +1 -1
- package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
- package/dist/ontology-matching.d.ts +1 -1
- package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
- package/dist/ontologyApproval.d.ts +1 -1
- package/dist/ontologyApproval.js +7 -1
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.d.ts +14 -24
- package/dist/ontologyDefinitions.js +269 -34
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyHelpers.d.ts +13 -13
- package/dist/ontologyHelpers.js.map +1 -1
- package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
- package/dist/ontologyRegistry.d.ts +1 -1
- package/dist/ontologyRegistry.js +34 -6
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
- package/dist/projectionReconciliation.d.ts +1 -1
- package/dist/projectionReconciliation.js +57 -10
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
- package/dist/projectionStaleness.d.ts +1 -1
- package/dist/projectionStaleness.js +8 -2
- package/dist/projectionStaleness.js.map +1 -1
- package/dist/proof-attestation.json +1 -1
- package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
- package/dist/questionEvidenceLinks.d.ts +1 -1
- package/dist/questionEvidenceLinks.js +564 -347
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
- package/dist/resolverTypes.d.ts +4 -2
- package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
- package/dist/resolvers.d.ts +5 -3
- package/dist/resolvers.js +121 -77
- package/dist/resolvers.js.map +1 -1
- package/dist/scopeResolverCompat.d.ts +10 -7
- package/dist/scopeResolverCompat.js +106 -123
- package/dist/scopeResolverCompat.js.map +1 -1
- package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
- package/dist/text-matching.d.ts +1 -1
- package/dist/topicOntologyResolver.d.ts +22 -21
- package/dist/topicOntologyResolver.js +54 -32
- package/dist/topicOntologyResolver.js.map +1 -1
- package/dist/topicProjectOverlay.d.ts +30 -20
- package/dist/topicProjectOverlay.js +120 -76
- package/dist/topicProjectOverlay.js.map +1 -1
- package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
- package/dist/topicScope.d.ts +3 -1
- package/dist/topicScope.js +104 -119
- package/dist/topicScope.js.map +1 -1
- package/dist/workflowBridge.d.ts +26 -15
- package/dist/workflowBridge.js +140 -144
- package/dist/workflowBridge.js.map +1 -1
- package/dist/workspaceIsolation.d.ts +14 -12
- package/dist/workspaceIsolation.js +108 -122
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +4 -4
- package/dist/edges/dependsOn.js.map +0 -1
- package/dist/edges/derivedFrom.js.map +0 -1
- package/dist/edges/propagationTypes.js.map +0 -1
- package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
- package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
- package/dist/{epistemicQuestions-bwHd2FWE.d.ts → epistemicQuestions-Do1fhYm5.d.ts} +4 -4
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade,
|
|
1
|
+
import { requireScopeWriteAccess } from '@lucern/access-control/access';
|
|
2
|
+
import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, readOpinionFromRecord, hasProjectedOpinionChanged } from '@lucern/confidence';
|
|
3
3
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
4
|
-
import {
|
|
4
|
+
import { v } from 'convex/values';
|
|
5
5
|
import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
6
|
-
import {
|
|
6
|
+
import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
|
|
7
|
+
import { componentsGeneric, internalMutationGeneric } from 'convex/server';
|
|
7
8
|
import '@lucern/access-control/audience';
|
|
8
9
|
import '@lucern/access-control/auth';
|
|
10
|
+
import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
|
|
9
11
|
|
|
10
12
|
// src/epistemicBeliefs.confidence.ts
|
|
11
13
|
|
|
@@ -129,10 +131,6 @@ function promoteBeliefStatusAfterScoring(status, opts) {
|
|
|
129
131
|
}
|
|
130
132
|
return status;
|
|
131
133
|
}
|
|
132
|
-
var api = anyApi;
|
|
133
|
-
componentsGeneric();
|
|
134
|
-
var internal = anyApi;
|
|
135
|
-
var internalMutation = internalMutationGeneric;
|
|
136
134
|
|
|
137
135
|
// src/edges/contains.ts
|
|
138
136
|
var containsPropagationSpec = {
|
|
@@ -269,7 +267,7 @@ var dependsOnPropagationSpec = {
|
|
|
269
267
|
description: "Structural gating. Textbook conditional deduction when edge conditionals exist, otherwise damped dependency cascade through downstream chains."
|
|
270
268
|
};
|
|
271
269
|
|
|
272
|
-
// src/edges/
|
|
270
|
+
// src/edges/derived-from.ts
|
|
273
271
|
var derivedFromPropagationSpec = {
|
|
274
272
|
edgeType: "derived_from",
|
|
275
273
|
direction: "incoming",
|
|
@@ -322,7 +320,7 @@ var informsPropagationSpec = {
|
|
|
322
320
|
description: "Evidence-bearing influence. Informs can chain through the graph with light per-hop damping."
|
|
323
321
|
};
|
|
324
322
|
|
|
325
|
-
// src/edges/
|
|
323
|
+
// src/edges/propagation-types.ts
|
|
326
324
|
function isPropagationTraversalDirection(direction) {
|
|
327
325
|
return direction === "outgoing" || direction === "incoming";
|
|
328
326
|
}
|
|
@@ -395,6 +393,9 @@ var testsPropagationSpec = {
|
|
|
395
393
|
};
|
|
396
394
|
|
|
397
395
|
// src/edges/index.ts
|
|
396
|
+
var canContinueTransitively2 = canContinueTransitively;
|
|
397
|
+
var canTraverseHop2 = canTraverseHop;
|
|
398
|
+
var isPropagationTraversalDirection2 = isPropagationTraversalDirection;
|
|
398
399
|
var EDGE_PROPAGATION_SPECS = [
|
|
399
400
|
supportsPropagationSpec,
|
|
400
401
|
informsPropagationSpec,
|
|
@@ -411,11 +412,18 @@ function getEdgePropagationSpecs() {
|
|
|
411
412
|
return EDGE_PROPAGATION_SPECS;
|
|
412
413
|
}
|
|
413
414
|
function getTraversalDirections(direction) {
|
|
414
|
-
if (
|
|
415
|
+
if (isPropagationTraversalDirection2(direction)) {
|
|
415
416
|
return [direction];
|
|
416
417
|
}
|
|
417
418
|
return ["outgoing", "incoming"];
|
|
418
419
|
}
|
|
420
|
+
var unsafeApi = unsafeConvexAnyApi(
|
|
421
|
+
"graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
|
|
422
|
+
);
|
|
423
|
+
var api = unsafeApi;
|
|
424
|
+
componentsGeneric();
|
|
425
|
+
var internal = unsafeApi;
|
|
426
|
+
var internalMutation = internalMutationGeneric;
|
|
419
427
|
|
|
420
428
|
// src/debug.ts
|
|
421
429
|
function isGraphPrimitiveDebugEnabled() {
|
|
@@ -464,13 +472,15 @@ function asMappedProjectId(topic) {
|
|
|
464
472
|
if (!topic) {
|
|
465
473
|
return;
|
|
466
474
|
}
|
|
467
|
-
const directLegacyProjectId = normalizeScopeValue(
|
|
475
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
476
|
+
topic[LEGACY_SCOPE_FIELD]
|
|
477
|
+
);
|
|
468
478
|
if (directLegacyProjectId) {
|
|
469
479
|
return directLegacyProjectId;
|
|
470
480
|
}
|
|
471
481
|
const metadata = topic.metadata || {};
|
|
472
482
|
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
473
|
-
return candidate ? candidate : void 0;
|
|
483
|
+
return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
|
|
474
484
|
}
|
|
475
485
|
function normalizeScopeValue(value) {
|
|
476
486
|
if (typeof value !== "string") {
|
|
@@ -495,8 +505,9 @@ function pickPrimaryTopic(candidates) {
|
|
|
495
505
|
})[0];
|
|
496
506
|
}
|
|
497
507
|
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
508
|
+
const query = ctx.db.query("topics");
|
|
498
509
|
try {
|
|
499
|
-
return await
|
|
510
|
+
return await query.withIndex(
|
|
500
511
|
"by_graph_scope_project",
|
|
501
512
|
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
502
513
|
).collect();
|
|
@@ -508,7 +519,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
|
508
519
|
scopeId
|
|
509
520
|
}
|
|
510
521
|
);
|
|
511
|
-
const topics = await
|
|
522
|
+
const topics = await query.collect();
|
|
512
523
|
return topics.filter((topic) => {
|
|
513
524
|
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
514
525
|
const mappedProjectId = asMappedProjectId(topic);
|
|
@@ -564,137 +575,115 @@ async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
|
564
575
|
let current = topic;
|
|
565
576
|
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
566
577
|
current = await ctx.db.get(current.parentTopicId);
|
|
567
|
-
if (!current)
|
|
578
|
+
if (!current) {
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
568
581
|
if (!tenantId) {
|
|
569
582
|
tenantId = normalizeScopeValue(current.tenantId);
|
|
570
583
|
}
|
|
571
584
|
if (!workspaceId) {
|
|
572
585
|
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
573
586
|
}
|
|
574
|
-
if (tenantId && workspaceId)
|
|
587
|
+
if (tenantId && workspaceId) {
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
575
590
|
}
|
|
576
591
|
return { tenantId, workspaceId };
|
|
577
592
|
}
|
|
578
593
|
async function resolveTopicProjectScope(ctx, args) {
|
|
579
594
|
if (args.topicId) {
|
|
580
|
-
|
|
581
|
-
try {
|
|
582
|
-
topic = await ctx.db.get(
|
|
583
|
-
args.topicId
|
|
584
|
-
);
|
|
585
|
-
} catch (error) {
|
|
586
|
-
debugGraphPrimitiveFallback(
|
|
587
|
-
"[topicScope] Failed to load topic by direct id",
|
|
588
|
-
{
|
|
589
|
-
error,
|
|
590
|
-
topicId: args.topicId
|
|
591
|
-
}
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
if (!topic) {
|
|
595
|
-
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
596
|
-
}
|
|
597
|
-
if (!topic) {
|
|
598
|
-
topic = pickPrimaryTopic(
|
|
599
|
-
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
600
|
-
) ?? null;
|
|
601
|
-
}
|
|
602
|
-
if (!topic) {
|
|
603
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
604
|
-
ctx,
|
|
605
|
-
String(args.topicId)
|
|
606
|
-
);
|
|
607
|
-
if (nodeScope) {
|
|
608
|
-
return nodeScope;
|
|
609
|
-
}
|
|
610
|
-
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
611
|
-
}
|
|
612
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
613
|
-
const mapped = asMappedProjectId(topic);
|
|
614
|
-
if (mapped) {
|
|
615
|
-
return {
|
|
616
|
-
topicId: topic._id,
|
|
617
|
-
projectId: mapped,
|
|
618
|
-
tenantId: inherited.tenantId,
|
|
619
|
-
workspaceId: inherited.workspaceId,
|
|
620
|
-
source: "topic"
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
return {
|
|
624
|
-
topicId: topic._id,
|
|
625
|
-
tenantId: inherited.tenantId,
|
|
626
|
-
workspaceId: inherited.workspaceId,
|
|
627
|
-
source: "topic"
|
|
628
|
-
};
|
|
595
|
+
return await resolveScopeFromTopicId(ctx, args.topicId);
|
|
629
596
|
}
|
|
630
597
|
if (args.projectId) {
|
|
631
|
-
|
|
632
|
-
try {
|
|
633
|
-
directTopic = await ctx.db.get(
|
|
634
|
-
args.projectId
|
|
635
|
-
);
|
|
636
|
-
} catch (error) {
|
|
637
|
-
debugGraphPrimitiveFallback(
|
|
638
|
-
"[topicScope] Failed to load direct project topic",
|
|
639
|
-
{
|
|
640
|
-
error,
|
|
641
|
-
projectId: args.projectId
|
|
642
|
-
}
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
if (directTopic) {
|
|
646
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
647
|
-
const mapped = asMappedProjectId(directTopic);
|
|
648
|
-
return {
|
|
649
|
-
topicId: directTopic._id,
|
|
650
|
-
projectId: mapped ?? args.projectId,
|
|
651
|
-
tenantId: inherited.tenantId,
|
|
652
|
-
workspaceId: inherited.workspaceId,
|
|
653
|
-
source: "topic_inferred"
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
657
|
-
if (directTopic) {
|
|
658
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
659
|
-
const mapped = asMappedProjectId(directTopic);
|
|
660
|
-
return {
|
|
661
|
-
topicId: directTopic._id,
|
|
662
|
-
projectId: mapped ?? args.projectId,
|
|
663
|
-
tenantId: inherited.tenantId,
|
|
664
|
-
workspaceId: inherited.workspaceId,
|
|
665
|
-
source: "topic_inferred"
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
669
|
-
const primary = pickPrimaryTopic(topics);
|
|
670
|
-
if (primary) {
|
|
671
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
672
|
-
return {
|
|
673
|
-
topicId: primary._id,
|
|
674
|
-
projectId: args.projectId,
|
|
675
|
-
tenantId: inherited.tenantId,
|
|
676
|
-
workspaceId: inherited.workspaceId,
|
|
677
|
-
source: "project_mapped_topic"
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
681
|
-
ctx,
|
|
682
|
-
String(args.projectId)
|
|
683
|
-
);
|
|
684
|
-
if (nodeScope) {
|
|
685
|
-
return {
|
|
686
|
-
...nodeScope,
|
|
687
|
-
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
throw new Error(
|
|
691
|
-
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
692
|
-
);
|
|
598
|
+
return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
|
|
693
599
|
}
|
|
694
600
|
throw new Error(
|
|
695
601
|
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
696
602
|
);
|
|
697
603
|
}
|
|
604
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
605
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
606
|
+
if (topic) {
|
|
607
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
608
|
+
}
|
|
609
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
|
|
610
|
+
if (nodeScope) {
|
|
611
|
+
return nodeScope;
|
|
612
|
+
}
|
|
613
|
+
throw new Error(`Topic not found: ${String(topicId)}`);
|
|
614
|
+
}
|
|
615
|
+
async function resolveTopicDocFromTopicId(ctx, topicId) {
|
|
616
|
+
const direct = await tryReadTopicDoc(ctx, topicId, {
|
|
617
|
+
failureLog: "[topicScope] Failed to load topic by direct id",
|
|
618
|
+
idLogKey: "topicId"
|
|
619
|
+
});
|
|
620
|
+
if (direct) {
|
|
621
|
+
return direct;
|
|
622
|
+
}
|
|
623
|
+
const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
|
|
624
|
+
if (hostTopic) {
|
|
625
|
+
return hostTopic;
|
|
626
|
+
}
|
|
627
|
+
return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
|
|
628
|
+
}
|
|
629
|
+
async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
|
|
630
|
+
const directTopic = await resolveDirectLegacyProjectTopic(
|
|
631
|
+
ctx,
|
|
632
|
+
legacyProjectId
|
|
633
|
+
);
|
|
634
|
+
if (directTopic) {
|
|
635
|
+
return await buildTopicScope(ctx, directTopic, "topic_inferred", {
|
|
636
|
+
fallbackProjectId: legacyProjectId
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
const primary = pickPrimaryTopic(
|
|
640
|
+
await findTopicsByScopeAlias(ctx, legacyProjectId)
|
|
641
|
+
);
|
|
642
|
+
if (primary) {
|
|
643
|
+
return await buildTopicScope(ctx, primary, "project_mapped_topic", {
|
|
644
|
+
fallbackProjectId: legacyProjectId
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
|
|
648
|
+
if (nodeScope) {
|
|
649
|
+
return {
|
|
650
|
+
...nodeScope,
|
|
651
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
throw new Error(
|
|
655
|
+
`Legacy project scope ${legacyProjectId} has no mapped topic.`
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
|
|
659
|
+
const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
|
|
660
|
+
failureLog: "[topicScope] Failed to load direct project topic",
|
|
661
|
+
idLogKey: "projectId"
|
|
662
|
+
});
|
|
663
|
+
return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
|
|
664
|
+
}
|
|
665
|
+
async function tryReadTopicDoc(ctx, id, log) {
|
|
666
|
+
try {
|
|
667
|
+
return await ctx.db.get(id);
|
|
668
|
+
} catch (error) {
|
|
669
|
+
debugGraphPrimitiveFallback(log.failureLog, {
|
|
670
|
+
error,
|
|
671
|
+
[log.idLogKey]: id
|
|
672
|
+
});
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
async function buildTopicScope(ctx, topic, source, options = {}) {
|
|
677
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
678
|
+
const mapped = asMappedProjectId(topic);
|
|
679
|
+
return {
|
|
680
|
+
topicId: topic._id,
|
|
681
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
682
|
+
tenantId: inherited.tenantId,
|
|
683
|
+
workspaceId: inherited.workspaceId,
|
|
684
|
+
source
|
|
685
|
+
};
|
|
686
|
+
}
|
|
698
687
|
({
|
|
699
688
|
projectId: v.optional(v.string()),
|
|
700
689
|
topicId: v.optional(v.string())
|
|
@@ -764,9 +753,10 @@ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
|
764
753
|
if (resolved.tenantId || resolved.workspaceId) {
|
|
765
754
|
return resolved;
|
|
766
755
|
}
|
|
767
|
-
|
|
756
|
+
const topicId = normalizeScopeValue2(node.topicId);
|
|
757
|
+
if (topicId) {
|
|
768
758
|
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
769
|
-
topicId
|
|
759
|
+
topicId
|
|
770
760
|
});
|
|
771
761
|
return {
|
|
772
762
|
...resolved,
|
|
@@ -788,9 +778,8 @@ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
|
788
778
|
}
|
|
789
779
|
|
|
790
780
|
// src/confidencePropagationDispatch.ts
|
|
791
|
-
function
|
|
792
|
-
|
|
793
|
-
return targetNodeId ?? void 0;
|
|
781
|
+
function nodeIdToCacheKey(nodeId) {
|
|
782
|
+
return String(nodeId);
|
|
794
783
|
}
|
|
795
784
|
function readNodeOpinion(node) {
|
|
796
785
|
const metadata = node.metadata ?? {};
|
|
@@ -806,138 +795,174 @@ function readNodeOpinion(node) {
|
|
|
806
795
|
return mkOpinion(0, 0, 1, 0.5);
|
|
807
796
|
}
|
|
808
797
|
}
|
|
798
|
+
function resolveTraversalTargetNodeId(edge, direction) {
|
|
799
|
+
const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
|
|
800
|
+
return targetNodeId ?? void 0;
|
|
801
|
+
}
|
|
802
|
+
function buildInitialState(sourceNodeId, sourceOpinion) {
|
|
803
|
+
return {
|
|
804
|
+
nodeId: sourceNodeId,
|
|
805
|
+
opinion: sourceOpinion,
|
|
806
|
+
hop: 0,
|
|
807
|
+
visitedNodeIds: /* @__PURE__ */ new Set([nodeIdToCacheKey(sourceNodeId)])
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
function extendVisited(currentVisited, targetNodeId) {
|
|
811
|
+
return /* @__PURE__ */ new Set([...currentVisited, nodeIdToCacheKey(targetNodeId)]);
|
|
812
|
+
}
|
|
813
|
+
function makeTransitiveState(current, targetNodeId, projectedOpinion, nextHop) {
|
|
814
|
+
return {
|
|
815
|
+
nodeId: targetNodeId,
|
|
816
|
+
opinion: projectedOpinion,
|
|
817
|
+
hop: nextHop,
|
|
818
|
+
visitedNodeIds: extendVisited(current.visitedNodeIds, targetNodeId)
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
function makeDispatchRecord(targetNodeId, spec, direction, edge, projectedOpinion, nextHop, result, existingDispatch) {
|
|
822
|
+
return {
|
|
823
|
+
targetNodeId,
|
|
824
|
+
edgeType: spec.edgeType,
|
|
825
|
+
traversedDirection: direction,
|
|
826
|
+
weight: edge.weight ?? 1,
|
|
827
|
+
opinion: projectedOpinion,
|
|
828
|
+
operator: result.operator,
|
|
829
|
+
rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
|
|
830
|
+
hop: nextHop
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
async function loadCachedNode(scope, nodeId) {
|
|
834
|
+
const cacheKey = nodeIdToCacheKey(nodeId);
|
|
835
|
+
if (!scope.nodeCache.has(cacheKey)) {
|
|
836
|
+
scope.nodeCache.set(cacheKey, await scope.args.getNode(nodeId));
|
|
837
|
+
}
|
|
838
|
+
return scope.nodeCache.get(cacheKey) ?? null;
|
|
839
|
+
}
|
|
840
|
+
async function collectTargetDispatch(state, nextHop, spec, direction, edge, queue, scope) {
|
|
841
|
+
const sourceScope = scope.args.sourceScope;
|
|
842
|
+
if (sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, sourceScope)) {
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
|
|
846
|
+
if (!targetNodeId) {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
const targetNodeIdKey = nodeIdToCacheKey(targetNodeId);
|
|
850
|
+
if (state.visitedNodeIds.has(targetNodeIdKey)) {
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
const targetNode = await loadCachedNode(scope, targetNodeId);
|
|
854
|
+
if (targetNode?.nodeType !== "belief") {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
if (sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, sourceScope)) {
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
const targetOpinion = scope.opinionCache.get(targetNodeIdKey) ?? readNodeOpinion(targetNode);
|
|
861
|
+
const result = spec.operator(state.opinion, targetOpinion, edge, {
|
|
862
|
+
hop: nextHop,
|
|
863
|
+
sourceNodeId: state.nodeId,
|
|
864
|
+
targetNodeId,
|
|
865
|
+
traversedDirection: direction,
|
|
866
|
+
spec
|
|
867
|
+
});
|
|
868
|
+
if (!(result && hasProjectedOpinionChanged(targetOpinion, result.opinion))) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const projectedOpinion = mkOpinion(
|
|
872
|
+
result.opinion.b,
|
|
873
|
+
result.opinion.d,
|
|
874
|
+
result.opinion.u,
|
|
875
|
+
result.opinion.a
|
|
876
|
+
);
|
|
877
|
+
scope.opinionCache.set(targetNodeIdKey, projectedOpinion);
|
|
878
|
+
const existingDispatch = scope.dispatchesByTargetId.get(targetNodeIdKey);
|
|
879
|
+
scope.dispatchesByTargetId.set(
|
|
880
|
+
targetNodeIdKey,
|
|
881
|
+
makeDispatchRecord(
|
|
882
|
+
targetNodeId,
|
|
883
|
+
spec,
|
|
884
|
+
direction,
|
|
885
|
+
edge,
|
|
886
|
+
projectedOpinion,
|
|
887
|
+
nextHop,
|
|
888
|
+
result,
|
|
889
|
+
existingDispatch
|
|
890
|
+
)
|
|
891
|
+
);
|
|
892
|
+
if (canContinueTransitively2(spec, nextHop)) {
|
|
893
|
+
queue.push(
|
|
894
|
+
makeTransitiveState(state, targetNodeId, projectedOpinion, nextHop)
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
async function processTraversalSpec(state, nextHop, spec, queue, scope) {
|
|
899
|
+
const sourceNodeId = state.nodeId;
|
|
900
|
+
for (const direction of getTraversalDirections(spec.direction)) {
|
|
901
|
+
const edges = await scope.args.queryEdges({
|
|
902
|
+
nodeId: sourceNodeId,
|
|
903
|
+
spec,
|
|
904
|
+
direction,
|
|
905
|
+
hop: nextHop
|
|
906
|
+
});
|
|
907
|
+
for (const edge of edges) {
|
|
908
|
+
await collectTargetDispatch(
|
|
909
|
+
state,
|
|
910
|
+
nextHop,
|
|
911
|
+
spec,
|
|
912
|
+
direction,
|
|
913
|
+
edge,
|
|
914
|
+
queue,
|
|
915
|
+
scope
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
async function processQueuedState(state, queue, scope) {
|
|
921
|
+
const nextHop = state.hop + 1;
|
|
922
|
+
for (const spec of scope.traversalSpecs) {
|
|
923
|
+
if (!canTraverseHop2(spec, nextHop)) {
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
await processTraversalSpec(state, nextHop, spec, queue, scope);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
function sortDispatches(dispatches) {
|
|
930
|
+
return Array.from(dispatches).sort((left, right) => {
|
|
931
|
+
if (left.hop !== right.hop) {
|
|
932
|
+
return left.hop - right.hop;
|
|
933
|
+
}
|
|
934
|
+
return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
|
|
935
|
+
});
|
|
936
|
+
}
|
|
809
937
|
async function collectConfidencePropagationDispatches(args) {
|
|
810
938
|
const dispatchesByTargetId = /* @__PURE__ */ new Map();
|
|
811
939
|
const opinionCache = /* @__PURE__ */ new Map();
|
|
812
940
|
const nodeCache = /* @__PURE__ */ new Map();
|
|
813
941
|
const traversalSpecs = args.traversalSpecs ?? getEdgePropagationSpecs();
|
|
942
|
+
const scope = {
|
|
943
|
+
args,
|
|
944
|
+
dispatchesByTargetId,
|
|
945
|
+
opinionCache,
|
|
946
|
+
nodeCache,
|
|
947
|
+
traversalSpecs
|
|
948
|
+
};
|
|
814
949
|
const queue = [
|
|
815
|
-
|
|
816
|
-
nodeId: args.sourceNodeId,
|
|
817
|
-
opinion: args.sourceOpinion,
|
|
818
|
-
hop: 0,
|
|
819
|
-
visitedNodeIds: /* @__PURE__ */ new Set([String(args.sourceNodeId)])
|
|
820
|
-
}
|
|
950
|
+
buildInitialState(args.sourceNodeId, args.sourceOpinion)
|
|
821
951
|
];
|
|
822
|
-
const loadNode = async (nodeId) => {
|
|
823
|
-
const cacheKey = String(nodeId);
|
|
824
|
-
if (!nodeCache.has(cacheKey)) {
|
|
825
|
-
nodeCache.set(cacheKey, await args.getNode(nodeId));
|
|
826
|
-
}
|
|
827
|
-
return nodeCache.get(cacheKey) ?? null;
|
|
828
|
-
};
|
|
829
952
|
while (queue.length > 0) {
|
|
830
953
|
const state = queue.shift();
|
|
831
954
|
if (!state) {
|
|
832
955
|
continue;
|
|
833
956
|
}
|
|
834
|
-
|
|
835
|
-
const nextHop = state.hop + 1;
|
|
836
|
-
if (!canTraverseHop(spec, nextHop)) {
|
|
837
|
-
continue;
|
|
838
|
-
}
|
|
839
|
-
for (const direction of getTraversalDirections(spec.direction)) {
|
|
840
|
-
const edges = await args.queryEdges({
|
|
841
|
-
nodeId: state.nodeId,
|
|
842
|
-
spec,
|
|
843
|
-
direction,
|
|
844
|
-
hop: nextHop
|
|
845
|
-
});
|
|
846
|
-
for (const edge of edges) {
|
|
847
|
-
if (args.sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, args.sourceScope)) {
|
|
848
|
-
continue;
|
|
849
|
-
}
|
|
850
|
-
const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
|
|
851
|
-
if (!targetNodeId) {
|
|
852
|
-
continue;
|
|
853
|
-
}
|
|
854
|
-
if (state.visitedNodeIds.has(String(targetNodeId))) {
|
|
855
|
-
continue;
|
|
856
|
-
}
|
|
857
|
-
const targetNode = await loadNode(targetNodeId);
|
|
858
|
-
if (!targetNode || targetNode.nodeType !== "belief") {
|
|
859
|
-
continue;
|
|
860
|
-
}
|
|
861
|
-
if (args.sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, args.sourceScope)) {
|
|
862
|
-
continue;
|
|
863
|
-
}
|
|
864
|
-
const cacheKey = String(targetNodeId);
|
|
865
|
-
const targetOpinion = opinionCache.get(cacheKey) ?? readNodeOpinion(targetNode);
|
|
866
|
-
const result = spec.operator(state.opinion, targetOpinion, edge, {
|
|
867
|
-
hop: nextHop,
|
|
868
|
-
sourceNodeId: state.nodeId,
|
|
869
|
-
targetNodeId,
|
|
870
|
-
traversedDirection: direction,
|
|
871
|
-
spec
|
|
872
|
-
});
|
|
873
|
-
if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
|
|
874
|
-
continue;
|
|
875
|
-
}
|
|
876
|
-
const projectedOpinion = mkOpinion(
|
|
877
|
-
result.opinion.b,
|
|
878
|
-
result.opinion.d,
|
|
879
|
-
result.opinion.u,
|
|
880
|
-
result.opinion.a
|
|
881
|
-
);
|
|
882
|
-
opinionCache.set(cacheKey, projectedOpinion);
|
|
883
|
-
const existingDispatch = dispatchesByTargetId.get(cacheKey);
|
|
884
|
-
dispatchesByTargetId.set(cacheKey, {
|
|
885
|
-
targetNodeId,
|
|
886
|
-
edgeType: spec.edgeType,
|
|
887
|
-
traversedDirection: direction,
|
|
888
|
-
weight: edge.weight ?? 1,
|
|
889
|
-
opinion: projectedOpinion,
|
|
890
|
-
operator: result.operator,
|
|
891
|
-
rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
|
|
892
|
-
hop: nextHop
|
|
893
|
-
});
|
|
894
|
-
if (canContinueTransitively(spec, nextHop)) {
|
|
895
|
-
queue.push({
|
|
896
|
-
nodeId: targetNodeId,
|
|
897
|
-
opinion: projectedOpinion,
|
|
898
|
-
hop: nextHop,
|
|
899
|
-
visitedNodeIds: /* @__PURE__ */ new Set([
|
|
900
|
-
...state.visitedNodeIds,
|
|
901
|
-
String(targetNodeId)
|
|
902
|
-
])
|
|
903
|
-
});
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
957
|
+
await processQueuedState(state, queue, scope);
|
|
908
958
|
}
|
|
909
|
-
return
|
|
910
|
-
if (left.hop !== right.hop) {
|
|
911
|
-
return left.hop - right.hop;
|
|
912
|
-
}
|
|
913
|
-
return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
|
|
914
|
-
});
|
|
959
|
+
return sortDispatches(dispatchesByTargetId.values());
|
|
915
960
|
}
|
|
916
961
|
v.id("epistemicNodes");
|
|
917
962
|
var DEFAULT_CONFIDENCE_POLICY = {
|
|
918
963
|
scoringMode: "after_worktree",
|
|
919
964
|
tupleContradiction: normalizeTupleContradictionPolicy()
|
|
920
965
|
};
|
|
921
|
-
function throwStructuredMutationError(args) {
|
|
922
|
-
const data = {
|
|
923
|
-
structuredMutationError: true,
|
|
924
|
-
message: args.message,
|
|
925
|
-
status: args.status,
|
|
926
|
-
code: args.code,
|
|
927
|
-
invariantCode: args.invariantCode,
|
|
928
|
-
suggestion: args.suggestion,
|
|
929
|
-
details: args.details
|
|
930
|
-
};
|
|
931
|
-
const error = new ConvexError(
|
|
932
|
-
data
|
|
933
|
-
);
|
|
934
|
-
error.status = args.status;
|
|
935
|
-
error.code = args.code;
|
|
936
|
-
error.invariantCode = args.invariantCode;
|
|
937
|
-
error.suggestion = args.suggestion;
|
|
938
|
-
error.details = args.details;
|
|
939
|
-
throw error;
|
|
940
|
-
}
|
|
941
966
|
function buildBeliefConfidenceRow(args) {
|
|
942
967
|
return {
|
|
943
968
|
beliefId: args.beliefId,
|
|
@@ -1012,7 +1037,10 @@ function resolveBeliefStatus(node, metadata) {
|
|
|
1012
1037
|
});
|
|
1013
1038
|
}
|
|
1014
1039
|
async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
|
|
1015
|
-
const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
|
|
1040
|
+
const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
|
|
1041
|
+
"by_belief",
|
|
1042
|
+
(q) => q.eq("beliefId", beliefNodeId)
|
|
1043
|
+
).collect();
|
|
1016
1044
|
for (const membership of clusterMembership) {
|
|
1017
1045
|
const worktree = await ctx.db.get(membership.worktreeId);
|
|
1018
1046
|
if (worktree?.status === "completed" || worktree?.status === "merged") {
|
|
@@ -1023,7 +1051,10 @@ async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
|
|
|
1023
1051
|
}
|
|
1024
1052
|
async function getActiveConfidencePolicy(ctx) {
|
|
1025
1053
|
try {
|
|
1026
|
-
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
1054
|
+
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
1055
|
+
"by_active",
|
|
1056
|
+
(q) => q.eq("isActive", true)
|
|
1057
|
+
).first();
|
|
1027
1058
|
return {
|
|
1028
1059
|
scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
|
|
1029
1060
|
tupleContradiction: normalizeTupleContradictionPolicy(
|
|
@@ -1040,28 +1071,191 @@ async function getActiveConfidencePolicy(ctx) {
|
|
|
1040
1071
|
return DEFAULT_CONFIDENCE_POLICY;
|
|
1041
1072
|
}
|
|
1042
1073
|
}
|
|
1043
|
-
async function requireProjectWriteAccess(ctx, projectId, userId) {
|
|
1044
|
-
const hasAccess = await checkProjectAccess(
|
|
1045
|
-
ctx,
|
|
1046
|
-
projectId,
|
|
1047
|
-
userId
|
|
1048
|
-
);
|
|
1049
|
-
if (!hasAccess) {
|
|
1050
|
-
throwStructuredMutationError({
|
|
1051
|
-
message: `Project write access denied for topic ${projectId}.`,
|
|
1052
|
-
status: 403,
|
|
1053
|
-
code: "PROJECT_ACCESS_DENIED",
|
|
1054
|
-
invariantCode: "policy.scope_required",
|
|
1055
|
-
suggestion: "The acting principal lacks project-write access to this topic. Request a topic grant (or, if the principal created this topic, run the creator-grant backfill) and retry.",
|
|
1056
|
-
details: { topicId: projectId, principalId: userId }
|
|
1057
|
-
});
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
1074
|
|
|
1061
1075
|
// src/epistemicBeliefs.confidence.ts
|
|
1076
|
+
function isRecord(value) {
|
|
1077
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1078
|
+
}
|
|
1079
|
+
function readConvexId(value) {
|
|
1080
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1081
|
+
}
|
|
1082
|
+
function readOptionalBoolean(value) {
|
|
1083
|
+
return typeof value === "boolean" ? value : void 0;
|
|
1084
|
+
}
|
|
1085
|
+
function readOptionalNumber(value) {
|
|
1086
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1087
|
+
}
|
|
1088
|
+
function readOptionalString(value) {
|
|
1089
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1090
|
+
}
|
|
1091
|
+
function readRecord(value) {
|
|
1092
|
+
return isRecord(value) ? value : void 0;
|
|
1093
|
+
}
|
|
1094
|
+
function readConfidenceBeliefNode(value) {
|
|
1095
|
+
if (!isRecord(value)) {
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
const id = readConvexId(value._id);
|
|
1099
|
+
const nodeType = readOptionalString(value.nodeType);
|
|
1100
|
+
const projectId = readOptionalString(value.projectId);
|
|
1101
|
+
if (!(id && nodeType === "belief" && projectId)) {
|
|
1102
|
+
return null;
|
|
1103
|
+
}
|
|
1104
|
+
const node = {
|
|
1105
|
+
_id: id,
|
|
1106
|
+
nodeType,
|
|
1107
|
+
projectId
|
|
1108
|
+
};
|
|
1109
|
+
const confidence = readOptionalNumber(value.confidence);
|
|
1110
|
+
const epistemicLayer = readOptionalString(value.epistemicLayer);
|
|
1111
|
+
const globalId = readOptionalString(value.globalId);
|
|
1112
|
+
const metadata = readRecord(value.metadata);
|
|
1113
|
+
const opinionA = readOptionalNumber(value.opinion_a);
|
|
1114
|
+
const opinionB = readOptionalNumber(value.opinion_b);
|
|
1115
|
+
const opinionD = readOptionalNumber(value.opinion_d);
|
|
1116
|
+
const opinionU = readOptionalNumber(value.opinion_u);
|
|
1117
|
+
const predictionMeta = readRecord(value.predictionMeta);
|
|
1118
|
+
const publicationStatus = readOptionalString(value.publicationStatus);
|
|
1119
|
+
const status = readOptionalString(value.status);
|
|
1120
|
+
const tenantId = readOptionalString(value.tenantId);
|
|
1121
|
+
const topicId = readOptionalString(value.topicId);
|
|
1122
|
+
const tupleContradicted = readOptionalBoolean(value.tupleContradicted);
|
|
1123
|
+
const workspaceId = readOptionalString(value.workspaceId);
|
|
1124
|
+
if (confidence !== void 0) {
|
|
1125
|
+
node.confidence = confidence;
|
|
1126
|
+
}
|
|
1127
|
+
if (epistemicLayer !== void 0) {
|
|
1128
|
+
node.epistemicLayer = epistemicLayer;
|
|
1129
|
+
}
|
|
1130
|
+
if (globalId !== void 0) {
|
|
1131
|
+
node.globalId = globalId;
|
|
1132
|
+
}
|
|
1133
|
+
if (metadata !== void 0) {
|
|
1134
|
+
node.metadata = metadata;
|
|
1135
|
+
}
|
|
1136
|
+
if (opinionA !== void 0) {
|
|
1137
|
+
node.opinion_a = opinionA;
|
|
1138
|
+
}
|
|
1139
|
+
if (opinionB !== void 0) {
|
|
1140
|
+
node.opinion_b = opinionB;
|
|
1141
|
+
}
|
|
1142
|
+
if (opinionD !== void 0) {
|
|
1143
|
+
node.opinion_d = opinionD;
|
|
1144
|
+
}
|
|
1145
|
+
if (opinionU !== void 0) {
|
|
1146
|
+
node.opinion_u = opinionU;
|
|
1147
|
+
}
|
|
1148
|
+
if (predictionMeta !== void 0) {
|
|
1149
|
+
node.predictionMeta = predictionMeta;
|
|
1150
|
+
}
|
|
1151
|
+
if (publicationStatus !== void 0) {
|
|
1152
|
+
node.publicationStatus = publicationStatus;
|
|
1153
|
+
}
|
|
1154
|
+
if (status !== void 0) {
|
|
1155
|
+
node.status = status;
|
|
1156
|
+
}
|
|
1157
|
+
if (tenantId !== void 0) {
|
|
1158
|
+
node.tenantId = tenantId;
|
|
1159
|
+
}
|
|
1160
|
+
if (topicId !== void 0) {
|
|
1161
|
+
node.topicId = topicId;
|
|
1162
|
+
}
|
|
1163
|
+
if (tupleContradicted !== void 0) {
|
|
1164
|
+
node.tupleContradicted = tupleContradicted;
|
|
1165
|
+
}
|
|
1166
|
+
if (workspaceId !== void 0) {
|
|
1167
|
+
node.workspaceId = workspaceId;
|
|
1168
|
+
}
|
|
1169
|
+
return node;
|
|
1170
|
+
}
|
|
1171
|
+
function readPropagationEdge(value) {
|
|
1172
|
+
if (!isRecord(value)) {
|
|
1173
|
+
return null;
|
|
1174
|
+
}
|
|
1175
|
+
const edgeType = readOptionalString(value.edgeType);
|
|
1176
|
+
if (!edgeType) {
|
|
1177
|
+
return null;
|
|
1178
|
+
}
|
|
1179
|
+
const edge = { edgeType };
|
|
1180
|
+
const fromNodeId = readConvexId(value.fromNodeId);
|
|
1181
|
+
const tenantId = readOptionalString(value.tenantId);
|
|
1182
|
+
const toNodeId = readConvexId(value.toNodeId);
|
|
1183
|
+
const weight = readOptionalNumber(value.weight);
|
|
1184
|
+
const workspaceId = readOptionalString(value.workspaceId);
|
|
1185
|
+
if (fromNodeId !== void 0) {
|
|
1186
|
+
edge.fromNodeId = fromNodeId;
|
|
1187
|
+
}
|
|
1188
|
+
if (tenantId !== void 0) {
|
|
1189
|
+
edge.tenantId = tenantId;
|
|
1190
|
+
}
|
|
1191
|
+
if (toNodeId !== void 0) {
|
|
1192
|
+
edge.toNodeId = toNodeId;
|
|
1193
|
+
}
|
|
1194
|
+
if (weight !== void 0) {
|
|
1195
|
+
edge.weight = weight;
|
|
1196
|
+
}
|
|
1197
|
+
if (workspaceId !== void 0) {
|
|
1198
|
+
edge.workspaceId = workspaceId;
|
|
1199
|
+
}
|
|
1200
|
+
return edge;
|
|
1201
|
+
}
|
|
1202
|
+
function readRowList(values, reader) {
|
|
1203
|
+
return values.flatMap((value) => {
|
|
1204
|
+
const row = reader(value);
|
|
1205
|
+
return row ? [row] : [];
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1062
1208
|
async function applyBeliefConfidenceChange(ctx, args) {
|
|
1063
1209
|
const now = Date.now();
|
|
1064
|
-
const node = await ctx
|
|
1210
|
+
const node = await requireConfidenceBeliefNode(ctx, args);
|
|
1211
|
+
const state = await buildConfidenceChangeState(ctx, node, args);
|
|
1212
|
+
await assertConfidenceScoringPolicySatisfied(ctx, args, state);
|
|
1213
|
+
const tupleContradictionId = await createTupleContradictionIfNeeded(
|
|
1214
|
+
ctx,
|
|
1215
|
+
args,
|
|
1216
|
+
node,
|
|
1217
|
+
state
|
|
1218
|
+
);
|
|
1219
|
+
await patchBeliefConfidenceState(ctx, args, state);
|
|
1220
|
+
await scheduleFirstScoringThemeEdges(ctx, args, node, state);
|
|
1221
|
+
const beliefConfidenceId = await insertBeliefConfidenceRecord(
|
|
1222
|
+
ctx,
|
|
1223
|
+
args,
|
|
1224
|
+
state,
|
|
1225
|
+
tupleContradictionId,
|
|
1226
|
+
now
|
|
1227
|
+
);
|
|
1228
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1229
|
+
nodeId: args.nodeId,
|
|
1230
|
+
operation: "upsert"
|
|
1231
|
+
});
|
|
1232
|
+
await insertConfidenceAudit(
|
|
1233
|
+
ctx,
|
|
1234
|
+
args,
|
|
1235
|
+
node,
|
|
1236
|
+
state,
|
|
1237
|
+
tupleContradictionId,
|
|
1238
|
+
now
|
|
1239
|
+
);
|
|
1240
|
+
await insertTupleTransitionAuditIfNeeded(
|
|
1241
|
+
ctx,
|
|
1242
|
+
args,
|
|
1243
|
+
node,
|
|
1244
|
+
state,
|
|
1245
|
+
tupleContradictionId,
|
|
1246
|
+
now
|
|
1247
|
+
);
|
|
1248
|
+
await scheduleConfidenceFollowups(ctx, args, node, state);
|
|
1249
|
+
return {
|
|
1250
|
+
nodeId: args.nodeId,
|
|
1251
|
+
previousConfidence: state.previousConfidence,
|
|
1252
|
+
newConfidence: state.derivedConfidence,
|
|
1253
|
+
opinion: state.nextOpinion,
|
|
1254
|
+
beliefConfidenceId
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
async function requireConfidenceBeliefNode(ctx, args) {
|
|
1258
|
+
const node = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
|
|
1065
1259
|
if (!node) {
|
|
1066
1260
|
throwStructuredMutationError({
|
|
1067
1261
|
message: "Node not found.",
|
|
@@ -1072,59 +1266,28 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1072
1266
|
details: { nodeId: args.nodeId }
|
|
1073
1267
|
});
|
|
1074
1268
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
invariantCode: "entity.no_confidence",
|
|
1081
|
-
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
|
|
1082
|
-
details: { nodeId: args.nodeId, nodeType: node.nodeType }
|
|
1083
|
-
});
|
|
1084
|
-
}
|
|
1085
|
-
if (!node.projectId) {
|
|
1086
|
-
throwStructuredMutationError({
|
|
1087
|
-
message: "Belief has no project scope.",
|
|
1088
|
-
status: 400,
|
|
1089
|
-
code: "MISSING_SCOPE",
|
|
1090
|
-
invariantCode: "belief.project_required",
|
|
1091
|
-
suggestion: "Belief must have a projectId before SL scoring can be appended.",
|
|
1092
|
-
details: { nodeId: args.nodeId }
|
|
1093
|
-
});
|
|
1094
|
-
}
|
|
1095
|
-
await requireProjectWriteAccess(
|
|
1096
|
-
ctx,
|
|
1097
|
-
node.projectId,
|
|
1098
|
-
args.authenticatedUserId
|
|
1099
|
-
);
|
|
1100
|
-
const existingMetadata = node.metadata || {};
|
|
1269
|
+
await requireScopeWriteAccess(ctx, node.projectId, args.authenticatedUserId);
|
|
1270
|
+
return node;
|
|
1271
|
+
}
|
|
1272
|
+
async function buildConfidenceChangeState(ctx, node, args) {
|
|
1273
|
+
const existingMetadata = readNodeMetadata(node);
|
|
1101
1274
|
const currentBeliefStatus = resolveBeliefStatus(node, existingMetadata);
|
|
1102
1275
|
const confidencePolicy = await getActiveConfidencePolicy(ctx);
|
|
1103
|
-
if (confidencePolicy.scoringMode === "after_worktree" && isPreValidationBeliefStatus(currentBeliefStatus)) {
|
|
1104
|
-
const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
|
|
1105
|
-
ctx,
|
|
1106
|
-
args.nodeId
|
|
1107
|
-
);
|
|
1108
|
-
if (!hasCompletedWorktree) {
|
|
1109
|
-
throwStructuredMutationError({
|
|
1110
|
-
message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
|
|
1111
|
-
status: 409,
|
|
1112
|
-
code: "CONFLICT",
|
|
1113
|
-
invariantCode: "belief.confidence_append_only",
|
|
1114
|
-
suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
|
|
1115
|
-
details: { nodeId: args.nodeId }
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
1276
|
const previousConfidence = node.confidence || 0.5;
|
|
1120
1277
|
const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
|
|
1121
1278
|
const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1279
|
+
const nextOpinion = {
|
|
1280
|
+
b: args.belief,
|
|
1281
|
+
d: args.disbelief,
|
|
1282
|
+
u: args.uncertainty,
|
|
1283
|
+
a: args.baseRate ?? 0.5
|
|
1284
|
+
};
|
|
1285
|
+
const derivedConfidence = confidenceFromSL(
|
|
1286
|
+
nextOpinion.b,
|
|
1287
|
+
nextOpinion.d,
|
|
1288
|
+
nextOpinion.u,
|
|
1289
|
+
nextOpinion.a
|
|
1290
|
+
);
|
|
1128
1291
|
const isFirstScoring = typeof node.confidence !== "number" || !Number.isFinite(node.confidence);
|
|
1129
1292
|
const previousTupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(existingMetadata.tupleContradicted) ?? detectTupleContradiction(
|
|
1130
1293
|
previousOpinion,
|
|
@@ -1145,79 +1308,121 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1145
1308
|
predictionMeta,
|
|
1146
1309
|
metadata: existingMetadata
|
|
1147
1310
|
});
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1311
|
+
const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
|
|
1312
|
+
return {
|
|
1313
|
+
confidencePolicy,
|
|
1314
|
+
currentBeliefStatus,
|
|
1315
|
+
derivedConfidence,
|
|
1316
|
+
existingMetadata,
|
|
1317
|
+
isFirstScoring,
|
|
1318
|
+
newBeliefStatus,
|
|
1319
|
+
nextOpinion,
|
|
1320
|
+
previousConfidence,
|
|
1321
|
+
previousTupleContradicted,
|
|
1322
|
+
storedRationale,
|
|
1323
|
+
tupleContradictionDescription,
|
|
1324
|
+
tupleTransition
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
function readNodeMetadata(node) {
|
|
1328
|
+
return node.metadata ?? {};
|
|
1329
|
+
}
|
|
1330
|
+
async function assertConfidenceScoringPolicySatisfied(ctx, args, state) {
|
|
1331
|
+
if (state.confidencePolicy.scoringMode !== "after_worktree" || !isPreValidationBeliefStatus(state.currentBeliefStatus)) {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
|
|
1335
|
+
ctx,
|
|
1336
|
+
args.nodeId
|
|
1337
|
+
);
|
|
1338
|
+
if (hasCompletedWorktree) {
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
throwStructuredMutationError({
|
|
1342
|
+
message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
|
|
1343
|
+
status: 409,
|
|
1344
|
+
code: "CONFLICT",
|
|
1345
|
+
invariantCode: "belief.confidence_append_only",
|
|
1346
|
+
suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
|
|
1347
|
+
details: { nodeId: args.nodeId }
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
async function createTupleContradictionIfNeeded(ctx, args, node, state) {
|
|
1351
|
+
if (!state.tupleTransition.crossedIntoTupleContradiction) {
|
|
1352
|
+
return;
|
|
1166
1353
|
}
|
|
1354
|
+
return await ctx.runMutation("contradictions:create", {
|
|
1355
|
+
projectId: node.projectId,
|
|
1356
|
+
topicId: node.topicId,
|
|
1357
|
+
beliefId: args.nodeId,
|
|
1358
|
+
beliefBId: args.nodeId,
|
|
1359
|
+
supportingInsightIds: [],
|
|
1360
|
+
contradictingInsightIds: [],
|
|
1361
|
+
severity: deriveTupleContradictionSeverity(node),
|
|
1362
|
+
source: "tuple_space",
|
|
1363
|
+
detectionMethod: "agent",
|
|
1364
|
+
description: state.tupleContradictionDescription,
|
|
1365
|
+
createdBy: args.authenticatedUserId
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
async function patchBeliefConfidenceState(ctx, args, state) {
|
|
1167
1369
|
await ctx.db.patch(args.nodeId, {
|
|
1168
|
-
confidence: derivedConfidence,
|
|
1169
|
-
beliefStatus: newBeliefStatus,
|
|
1170
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1171
|
-
updatedAt: now,
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
opinion_a: slA,
|
|
1370
|
+
confidence: state.derivedConfidence,
|
|
1371
|
+
beliefStatus: state.newBeliefStatus,
|
|
1372
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1373
|
+
updatedAt: Date.now(),
|
|
1374
|
+
opinion_b: state.nextOpinion.b,
|
|
1375
|
+
opinion_d: state.nextOpinion.d,
|
|
1376
|
+
opinion_u: state.nextOpinion.u,
|
|
1377
|
+
opinion_a: state.nextOpinion.a,
|
|
1177
1378
|
metadata: {
|
|
1178
|
-
...existingMetadata,
|
|
1179
|
-
beliefStatus: newBeliefStatus,
|
|
1180
|
-
slBelief:
|
|
1181
|
-
slDisbelief:
|
|
1182
|
-
slUncertainty:
|
|
1183
|
-
slBaseRate:
|
|
1184
|
-
tupleContradicted: tupleTransition.tupleContradicted
|
|
1379
|
+
...state.existingMetadata,
|
|
1380
|
+
beliefStatus: state.newBeliefStatus,
|
|
1381
|
+
slBelief: state.nextOpinion.b,
|
|
1382
|
+
slDisbelief: state.nextOpinion.d,
|
|
1383
|
+
slUncertainty: state.nextOpinion.u,
|
|
1384
|
+
slBaseRate: state.nextOpinion.a,
|
|
1385
|
+
tupleContradicted: state.tupleTransition.tupleContradicted
|
|
1185
1386
|
}
|
|
1186
1387
|
});
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
edgeType: "relates_to_thesis",
|
|
1200
|
-
weight: derivedConfidence,
|
|
1201
|
-
createdBy: args.authenticatedUserId,
|
|
1202
|
-
topicId: String(node.projectId),
|
|
1203
|
-
fromNodeType: "belief",
|
|
1204
|
-
toNodeType: "theme",
|
|
1205
|
-
fromLayer: "L3",
|
|
1206
|
-
toLayer: "L3"
|
|
1207
|
-
});
|
|
1208
|
-
}
|
|
1388
|
+
}
|
|
1389
|
+
async function scheduleFirstScoringThemeEdges(ctx, args, node, state) {
|
|
1390
|
+
if (!state.isFirstScoring) {
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
1394
|
+
"by_topic",
|
|
1395
|
+
(q) => q.eq("topicId", node.topicId || node.projectId)
|
|
1396
|
+
).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
|
|
1397
|
+
for (const theme of themeNodes) {
|
|
1398
|
+
if (!(theme.globalId && node.globalId)) {
|
|
1399
|
+
continue;
|
|
1209
1400
|
}
|
|
1401
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
1402
|
+
globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
|
|
1403
|
+
fromGlobalId: node.globalId,
|
|
1404
|
+
toGlobalId: theme.globalId,
|
|
1405
|
+
edgeType: "relates_to_thesis",
|
|
1406
|
+
weight: state.derivedConfidence,
|
|
1407
|
+
createdBy: args.authenticatedUserId,
|
|
1408
|
+
topicId: String(node.projectId),
|
|
1409
|
+
fromNodeType: "belief",
|
|
1410
|
+
toNodeType: "theme",
|
|
1411
|
+
fromLayer: "L3",
|
|
1412
|
+
toLayer: "L3"
|
|
1413
|
+
});
|
|
1210
1414
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1415
|
+
}
|
|
1416
|
+
async function insertBeliefConfidenceRecord(ctx, args, state, tupleContradictionId, now) {
|
|
1417
|
+
return await ctx.db.insert("beliefConfidence", {
|
|
1213
1418
|
...buildBeliefConfidenceRow({
|
|
1214
1419
|
beliefId: args.nodeId,
|
|
1215
|
-
belief:
|
|
1216
|
-
disbelief:
|
|
1217
|
-
uncertainty:
|
|
1218
|
-
baseRate:
|
|
1420
|
+
belief: state.nextOpinion.b,
|
|
1421
|
+
disbelief: state.nextOpinion.d,
|
|
1422
|
+
uncertainty: state.nextOpinion.u,
|
|
1423
|
+
baseRate: state.nextOpinion.a,
|
|
1219
1424
|
trigger: args.trigger,
|
|
1220
|
-
rationale: storedRationale,
|
|
1425
|
+
rationale: state.storedRationale,
|
|
1221
1426
|
assessedBy: args.authenticatedUserId,
|
|
1222
1427
|
assessedAt: now,
|
|
1223
1428
|
slOperator: args.slOperator,
|
|
@@ -1226,25 +1431,23 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1226
1431
|
triggeringWorktreeId: args.triggeringWorktreeId
|
|
1227
1432
|
})
|
|
1228
1433
|
});
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
operation: "upsert"
|
|
1232
|
-
});
|
|
1434
|
+
}
|
|
1435
|
+
async function insertConfidenceAudit(ctx, args, node, state, tupleContradictionId, now) {
|
|
1233
1436
|
await ctx.db.insert("epistemicAudit", {
|
|
1234
1437
|
entityType: "belief",
|
|
1235
1438
|
entityId: args.nodeId,
|
|
1236
1439
|
changeType: "confidence_changed",
|
|
1237
1440
|
previousState: {
|
|
1238
|
-
confidence: previousConfidence,
|
|
1239
|
-
tupleContradicted: previousTupleContradicted
|
|
1441
|
+
confidence: state.previousConfidence,
|
|
1442
|
+
tupleContradicted: state.previousTupleContradicted
|
|
1240
1443
|
},
|
|
1241
1444
|
newState: {
|
|
1242
|
-
opinion: nextOpinion,
|
|
1243
|
-
confidence: derivedConfidence,
|
|
1445
|
+
opinion: state.nextOpinion,
|
|
1446
|
+
confidence: state.derivedConfidence,
|
|
1244
1447
|
trigger: args.trigger,
|
|
1245
|
-
rationale: storedRationale,
|
|
1246
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1247
|
-
tupleContradictionPolicy: tupleTransition.policy,
|
|
1448
|
+
rationale: state.storedRationale,
|
|
1449
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1450
|
+
tupleContradictionPolicy: state.tupleTransition.policy,
|
|
1248
1451
|
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1249
1452
|
},
|
|
1250
1453
|
changedBy: args.authenticatedUserId,
|
|
@@ -1253,28 +1456,39 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1253
1456
|
projectId: node.projectId,
|
|
1254
1457
|
topicId: node.topicId
|
|
1255
1458
|
});
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
changeType: "updated",
|
|
1261
|
-
previousState: { tupleContradicted: previousTupleContradicted },
|
|
1262
|
-
newState: {
|
|
1263
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1264
|
-
action: tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
|
|
1265
|
-
opinion: nextOpinion,
|
|
1266
|
-
tupleContradictionPolicy: tupleTransition.policy,
|
|
1267
|
-
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1268
|
-
},
|
|
1269
|
-
rationale: tupleTransition.crossedIntoTupleContradiction ? tupleContradictionDescription : `Tuple-space contradiction cleared: b=${nextOpinion.b.toFixed(2)}, d=${nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`,
|
|
1270
|
-
changedBy: args.authenticatedUserId,
|
|
1271
|
-
isAgent: false,
|
|
1272
|
-
changedAt: now,
|
|
1273
|
-
projectId: node.projectId,
|
|
1274
|
-
topicId: node.topicId
|
|
1275
|
-
});
|
|
1459
|
+
}
|
|
1460
|
+
async function insertTupleTransitionAuditIfNeeded(ctx, args, node, state, tupleContradictionId, now) {
|
|
1461
|
+
if (!(state.tupleTransition.crossedIntoTupleContradiction || state.tupleTransition.crossedOutOfTupleContradiction)) {
|
|
1462
|
+
return;
|
|
1276
1463
|
}
|
|
1277
|
-
|
|
1464
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1465
|
+
entityType: "belief",
|
|
1466
|
+
entityId: args.nodeId,
|
|
1467
|
+
changeType: "updated",
|
|
1468
|
+
previousState: { tupleContradicted: state.previousTupleContradicted },
|
|
1469
|
+
newState: {
|
|
1470
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1471
|
+
action: state.tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
|
|
1472
|
+
opinion: state.nextOpinion,
|
|
1473
|
+
tupleContradictionPolicy: state.tupleTransition.policy,
|
|
1474
|
+
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1475
|
+
},
|
|
1476
|
+
rationale: tupleAuditRationale(state),
|
|
1477
|
+
changedBy: args.authenticatedUserId,
|
|
1478
|
+
isAgent: false,
|
|
1479
|
+
changedAt: now,
|
|
1480
|
+
projectId: node.projectId,
|
|
1481
|
+
topicId: node.topicId
|
|
1482
|
+
});
|
|
1483
|
+
}
|
|
1484
|
+
function tupleAuditRationale(state) {
|
|
1485
|
+
if (state.tupleTransition.crossedIntoTupleContradiction) {
|
|
1486
|
+
return state.tupleContradictionDescription;
|
|
1487
|
+
}
|
|
1488
|
+
return `Tuple-space contradiction cleared: b=${state.nextOpinion.b.toFixed(2)}, d=${state.nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`;
|
|
1489
|
+
}
|
|
1490
|
+
async function scheduleConfidenceFollowups(ctx, args, node, state) {
|
|
1491
|
+
if (Math.abs(state.derivedConfidence - state.previousConfidence) >= 0.15) {
|
|
1278
1492
|
await ctx.scheduler.runAfter(
|
|
1279
1493
|
5e3,
|
|
1280
1494
|
internal.bi.contradictionSemanticDetector.scanAffectedBeliefs,
|
|
@@ -1291,13 +1505,6 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1291
1505
|
{ nodeId: args.nodeId }
|
|
1292
1506
|
);
|
|
1293
1507
|
}
|
|
1294
|
-
return {
|
|
1295
|
-
nodeId: args.nodeId,
|
|
1296
|
-
previousConfidence,
|
|
1297
|
-
newConfidence: derivedConfidence,
|
|
1298
|
-
opinion: { b: slB, d: slD, u: slU, a: slA },
|
|
1299
|
-
beliefConfidenceId
|
|
1300
|
-
};
|
|
1301
1508
|
}
|
|
1302
1509
|
function propagationPressureLabel(edgeType, weight) {
|
|
1303
1510
|
if (edgeType === "contradicts" || edgeType === "refutes") {
|
|
@@ -1325,7 +1532,7 @@ var propagateConfidenceChange = internalMutation({
|
|
|
1325
1532
|
args.opinion_u,
|
|
1326
1533
|
args.opinion_a
|
|
1327
1534
|
);
|
|
1328
|
-
const sourceNode = await ctx.db.get(args.nodeId);
|
|
1535
|
+
const sourceNode = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
|
|
1329
1536
|
const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
|
|
1330
1537
|
ctx,
|
|
1331
1538
|
sourceNode
|
|
@@ -1334,16 +1541,20 @@ var propagateConfidenceChange = internalMutation({
|
|
|
1334
1541
|
sourceNodeId: args.nodeId,
|
|
1335
1542
|
sourceOpinion,
|
|
1336
1543
|
sourceScope,
|
|
1337
|
-
queryEdges: async ({ nodeId, spec, direction }) =>
|
|
1338
|
-
|
|
1544
|
+
queryEdges: async ({ nodeId, spec, direction }) => readRowList(
|
|
1545
|
+
await ctx.db.query("epistemicEdges").withIndex(
|
|
1339
1546
|
direction === "outgoing" ? "by_from_type" : "by_to_type",
|
|
1340
1547
|
(q) => direction === "outgoing" ? q.eq("fromNodeId", nodeId).eq("edgeType", spec.edgeType) : q.eq("toNodeId", nodeId).eq("edgeType", spec.edgeType)
|
|
1341
|
-
).collect()
|
|
1342
|
-
|
|
1343
|
-
|
|
1548
|
+
).collect(),
|
|
1549
|
+
readPropagationEdge
|
|
1550
|
+
),
|
|
1551
|
+
getNode: async (nodeId) => readConfidenceBeliefNode(await ctx.db.get(nodeId))
|
|
1344
1552
|
});
|
|
1345
1553
|
for (const dispatch of dispatches) {
|
|
1346
|
-
const pressureLabel = propagationPressureLabel(
|
|
1554
|
+
const pressureLabel = propagationPressureLabel(
|
|
1555
|
+
dispatch.edgeType,
|
|
1556
|
+
dispatch.weight
|
|
1557
|
+
);
|
|
1347
1558
|
await applyBeliefConfidenceChange(ctx, {
|
|
1348
1559
|
nodeId: dispatch.targetNodeId,
|
|
1349
1560
|
belief: dispatch.opinion.b,
|