@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,1105 +1,640 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { checkProjectAccess } from '@lucern/access-control/access';
|
|
1
|
+
import { checkProjectAccess, requireScopeWriteAccess } from '@lucern/access-control/access';
|
|
3
2
|
import { getCurrentUserId } from '@lucern/access-control/auth';
|
|
4
3
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
5
|
-
import {
|
|
4
|
+
import { v } from 'convex/values';
|
|
5
|
+
import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
|
|
6
|
+
import { componentsGeneric, internalMutationGeneric, queryGeneric, mutationGeneric } from 'convex/server';
|
|
7
|
+
import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, deriveContractModulationPlan, deriveContractStatus, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, readOpinionFromRecord, parseEvidentialEvaluatorConfig, compareMetricValue, resolveComparisonResult, buildEvidentialRationale, parseMetricCheckerConfig, getEvaluatorInputRecord, pickFiniteNumber, buildComparisonRationale, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, parseMarketIndexComparatorConfig, hasProjectedOpinionChanged, createInheritedContractRecord } from '@lucern/confidence';
|
|
6
8
|
import '@lucern/access-control/audience';
|
|
7
|
-
import {
|
|
9
|
+
import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
|
|
8
10
|
import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
9
11
|
import { generateGlobalId } from '@lucern/contracts/ids';
|
|
10
12
|
|
|
11
13
|
// src/epistemicContracts.handlers.ts
|
|
14
|
+
var unsafeApi = unsafeConvexAnyApi(
|
|
15
|
+
"graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
|
|
16
|
+
);
|
|
17
|
+
var api = unsafeApi;
|
|
18
|
+
componentsGeneric();
|
|
19
|
+
var internal = unsafeApi;
|
|
20
|
+
var internalMutation = internalMutationGeneric;
|
|
21
|
+
var mutation = mutationGeneric;
|
|
22
|
+
var query = queryGeneric;
|
|
12
23
|
|
|
13
|
-
// src/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
]);
|
|
22
|
-
function classifyContradictionStatus(status) {
|
|
23
|
-
if (typeof status !== "string") {
|
|
24
|
-
return "active";
|
|
24
|
+
// src/debug.ts
|
|
25
|
+
function isGraphPrimitiveDebugEnabled() {
|
|
26
|
+
const env = globalThis.process?.env;
|
|
27
|
+
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
28
|
+
}
|
|
29
|
+
function debugGraphPrimitiveFallback(message, context) {
|
|
30
|
+
if (!isGraphPrimitiveDebugEnabled()) {
|
|
31
|
+
return;
|
|
25
32
|
}
|
|
26
|
-
|
|
33
|
+
console.debug(message, context ?? {});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/beliefLifecycle.ts
|
|
37
|
+
var BELIEF_STATUS_VALUES = [
|
|
38
|
+
"assumption",
|
|
39
|
+
"hypothesis",
|
|
40
|
+
"active",
|
|
41
|
+
"superseded",
|
|
42
|
+
"resolved_true",
|
|
43
|
+
"resolved_false"
|
|
44
|
+
];
|
|
45
|
+
function isBeliefLifecycleStatus(value) {
|
|
46
|
+
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
47
|
+
}
|
|
48
|
+
function normalizeLegacyBeliefStatus(value) {
|
|
49
|
+
if (isBeliefLifecycleStatus(value)) {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
if (value === "belief" || value === "established" || value === "emerging") {
|
|
27
53
|
return "active";
|
|
28
54
|
}
|
|
29
|
-
if (
|
|
30
|
-
return "
|
|
55
|
+
if (value === "fact" || value === "confirmed") {
|
|
56
|
+
return "resolved_true";
|
|
31
57
|
}
|
|
32
|
-
|
|
58
|
+
if (value === "disconfirmed" || value === "expired") {
|
|
59
|
+
return "resolved_false";
|
|
60
|
+
}
|
|
61
|
+
if (value === "deprecated") {
|
|
62
|
+
return "superseded";
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
33
65
|
}
|
|
34
|
-
function
|
|
35
|
-
if (typeof
|
|
36
|
-
return
|
|
66
|
+
function normalizeBeliefConfidence(confidence) {
|
|
67
|
+
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
68
|
+
return null;
|
|
37
69
|
}
|
|
38
|
-
if (
|
|
39
|
-
return
|
|
70
|
+
if (confidence >= 0 && confidence <= 1) {
|
|
71
|
+
return confidence;
|
|
40
72
|
}
|
|
41
|
-
if (
|
|
42
|
-
return
|
|
73
|
+
if (confidence > 1 && confidence <= 100) {
|
|
74
|
+
return confidence / 100;
|
|
43
75
|
}
|
|
44
76
|
return null;
|
|
45
77
|
}
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
).collect();
|
|
51
|
-
if (edges.length === 0) {
|
|
52
|
-
return [];
|
|
78
|
+
function isResolvedByConfidence(confidence) {
|
|
79
|
+
const normalized = normalizeBeliefConfidence(confidence);
|
|
80
|
+
if (normalized === null) {
|
|
81
|
+
return false;
|
|
53
82
|
}
|
|
54
|
-
|
|
55
|
-
return edges.flatMap((edge, index) => {
|
|
56
|
-
const node = nodes[index];
|
|
57
|
-
if (!node || node.nodeType !== "evidence" || node.status === "archived") {
|
|
58
|
-
return [];
|
|
59
|
-
}
|
|
60
|
-
return [{ edge, node }];
|
|
61
|
-
});
|
|
83
|
+
return normalized <= 0 || normalized >= 1;
|
|
62
84
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
85
|
+
function getPredictionMetaFromMetadata(metadata) {
|
|
86
|
+
return metadata?.predictionMeta;
|
|
87
|
+
}
|
|
88
|
+
function resolvedPredictionStatus(predictionMeta) {
|
|
89
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
90
|
+
return null;
|
|
68
91
|
}
|
|
69
|
-
|
|
92
|
+
const outcome = predictionMeta.outcome;
|
|
93
|
+
if (outcome === "confirmed") {
|
|
94
|
+
return "resolved_true";
|
|
95
|
+
}
|
|
96
|
+
if (outcome === "disconfirmed" || outcome === "expired") {
|
|
97
|
+
return "resolved_false";
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
70
100
|
}
|
|
71
|
-
|
|
72
|
-
|
|
101
|
+
function shouldTreatBeliefAsResolved(opts) {
|
|
102
|
+
if (isResolvedByConfidence(opts.confidence)) {
|
|
103
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
104
|
+
return normalized === 0 ? "resolved_false" : "resolved_true";
|
|
105
|
+
}
|
|
106
|
+
const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
|
|
107
|
+
if (directPredictionStatus) {
|
|
108
|
+
return directPredictionStatus;
|
|
109
|
+
}
|
|
110
|
+
const metadataPredictionStatus = resolvedPredictionStatus(
|
|
111
|
+
getPredictionMetaFromMetadata(opts.metadata)
|
|
112
|
+
);
|
|
113
|
+
if (metadataPredictionStatus) {
|
|
114
|
+
return metadataPredictionStatus;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
73
117
|
}
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
118
|
+
function resolveBeliefLifecycleStatus(opts) {
|
|
119
|
+
const resolvedStatus = shouldTreatBeliefAsResolved(opts);
|
|
120
|
+
if (resolvedStatus) {
|
|
121
|
+
return resolvedStatus;
|
|
122
|
+
}
|
|
123
|
+
const direct = opts.beliefStatus;
|
|
124
|
+
const normalizedDirect = normalizeLegacyBeliefStatus(direct);
|
|
125
|
+
if (normalizedDirect) {
|
|
126
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
127
|
+
if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
|
|
128
|
+
return "active";
|
|
129
|
+
}
|
|
130
|
+
return normalizedDirect;
|
|
131
|
+
}
|
|
132
|
+
const metaStatus = opts.metadata?.beliefStatus;
|
|
133
|
+
const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
|
|
134
|
+
if (normalizedMetaStatus) {
|
|
135
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
136
|
+
if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
|
|
137
|
+
return "active";
|
|
138
|
+
}
|
|
139
|
+
return normalizedMetaStatus;
|
|
140
|
+
}
|
|
141
|
+
return "assumption";
|
|
85
142
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return contradictions.reduce(
|
|
89
|
-
(counts, contradiction) => {
|
|
90
|
-
const status = contradiction.resolutionStatus ?? contradiction.status ?? "unresolved";
|
|
91
|
-
if (classifyContradictionStatus(status) === "active") {
|
|
92
|
-
counts.activeCount += 1;
|
|
93
|
-
} else {
|
|
94
|
-
counts.resolvedCount += 1;
|
|
95
|
-
}
|
|
96
|
-
return counts;
|
|
97
|
-
},
|
|
98
|
-
{ activeCount: 0, resolvedCount: 0 }
|
|
99
|
-
);
|
|
143
|
+
function isPreValidationBeliefStatus(status) {
|
|
144
|
+
return status === "assumption" || status === "hypothesis";
|
|
100
145
|
}
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
104
|
-
return
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
146
|
+
function promoteBeliefStatusAfterScoring(status, opts) {
|
|
147
|
+
const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
|
|
148
|
+
if (resolvedStatus) {
|
|
149
|
+
return resolvedStatus;
|
|
150
|
+
}
|
|
151
|
+
if (isPreValidationBeliefStatus(status)) {
|
|
152
|
+
return "active";
|
|
153
|
+
}
|
|
154
|
+
return status;
|
|
155
|
+
}
|
|
156
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
157
|
+
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
158
|
+
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
let node = null;
|
|
162
|
+
try {
|
|
163
|
+
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
164
|
+
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
165
|
+
node = byGlobalId;
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
debugGraphPrimitiveFallback(
|
|
169
|
+
"[topicScope] topic-node scope lookup by globalId failed",
|
|
170
|
+
{ error, ref }
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
if (!node) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
177
|
+
if (!scopeKey) {
|
|
178
|
+
return null;
|
|
111
179
|
}
|
|
112
|
-
const newestEdgeAt = Math.max(...timestamps);
|
|
113
|
-
const oldestEdgeAt = Math.min(...timestamps);
|
|
114
180
|
return {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
oldestEdgeAt,
|
|
119
|
-
edgeCount: timestamps.length
|
|
181
|
+
topicId: scopeKey,
|
|
182
|
+
projectId: asMappedProjectId(node),
|
|
183
|
+
source: "topic_node"
|
|
120
184
|
};
|
|
121
185
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
(edge) => DEPENDENT_EDGE_TYPES.has(edge.edgeType)
|
|
126
|
-
);
|
|
127
|
-
if (dependencyEdges.length === 0) {
|
|
128
|
-
return 0;
|
|
186
|
+
function asMappedProjectId(topic) {
|
|
187
|
+
if (!topic) {
|
|
188
|
+
return;
|
|
129
189
|
}
|
|
130
|
-
const
|
|
131
|
-
|
|
190
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
191
|
+
topic[LEGACY_SCOPE_FIELD]
|
|
132
192
|
);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (node && node.nodeType === "belief" && node.status !== "archived" && node.status !== "deleted") {
|
|
136
|
-
uniqueBeliefIds.add(String(node._id));
|
|
137
|
-
}
|
|
193
|
+
if (directLegacyProjectId) {
|
|
194
|
+
return directLegacyProjectId;
|
|
138
195
|
}
|
|
139
|
-
|
|
196
|
+
const metadata = topic.metadata || {};
|
|
197
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
198
|
+
return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
|
|
140
199
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return
|
|
154
|
-
metric: args.metric,
|
|
155
|
-
value: counts.activeCount,
|
|
156
|
-
data: counts
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
case "edge_freshness": {
|
|
160
|
-
const freshness = await computeEvidenceFreshness(
|
|
161
|
-
args.ctx,
|
|
162
|
-
args.beliefNodeId,
|
|
163
|
-
args.now
|
|
164
|
-
);
|
|
165
|
-
return {
|
|
166
|
-
metric: args.metric,
|
|
167
|
-
value: freshness.newestAgeMs,
|
|
168
|
-
data: freshness
|
|
169
|
-
};
|
|
200
|
+
function normalizeScopeValue(value) {
|
|
201
|
+
if (typeof value !== "string") {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const normalized = value.trim();
|
|
205
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
206
|
+
}
|
|
207
|
+
function pickPrimaryTopic(candidates) {
|
|
208
|
+
return [...candidates].sort((a, b) => {
|
|
209
|
+
const depthA = a.depth ?? 9999;
|
|
210
|
+
const depthB = b.depth ?? 9999;
|
|
211
|
+
if (depthA !== depthB) {
|
|
212
|
+
return depthA - depthB;
|
|
170
213
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
value: count,
|
|
176
|
-
data: { dependentCount: count }
|
|
177
|
-
};
|
|
214
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
215
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
216
|
+
if (createdA !== createdB) {
|
|
217
|
+
return createdA - createdB;
|
|
178
218
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
219
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
220
|
+
})[0];
|
|
221
|
+
}
|
|
222
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
223
|
+
const query2 = ctx.db.query("topics");
|
|
224
|
+
try {
|
|
225
|
+
return await query2.withIndex(
|
|
226
|
+
"by_graph_scope_project",
|
|
227
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
228
|
+
).collect();
|
|
229
|
+
} catch (error) {
|
|
230
|
+
debugGraphPrimitiveFallback(
|
|
231
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
232
|
+
{
|
|
233
|
+
error,
|
|
234
|
+
scopeId
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
const topics = await query2.collect();
|
|
238
|
+
return topics.filter((topic) => {
|
|
239
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
240
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
241
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
242
|
+
});
|
|
185
243
|
}
|
|
186
244
|
}
|
|
187
|
-
async function
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
data: {
|
|
206
|
-
...snapshot.data,
|
|
207
|
-
metric: config.metric,
|
|
208
|
-
observedValue: snapshot.value,
|
|
209
|
-
operator: config.operator,
|
|
210
|
-
threshold: config.threshold,
|
|
211
|
-
action: config.action ?? "append_sl_scoring",
|
|
212
|
-
actionParams: config.actionParams
|
|
213
|
-
}
|
|
214
|
-
};
|
|
245
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
246
|
+
if (typeof ctx.runQuery !== "function") {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
return await ctx.runQuery(api.topics.get, {
|
|
251
|
+
id: topicId
|
|
252
|
+
}) ?? null;
|
|
253
|
+
} catch (error) {
|
|
254
|
+
debugGraphPrimitiveFallback(
|
|
255
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
256
|
+
{
|
|
257
|
+
error,
|
|
258
|
+
topicId
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
215
263
|
}
|
|
216
|
-
async function
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
data: {
|
|
231
|
-
metric,
|
|
232
|
-
observedValue: null,
|
|
233
|
-
operator: config.operator,
|
|
234
|
-
threshold: config.threshold,
|
|
235
|
-
unit: config.unit
|
|
264
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
265
|
+
if (typeof ctx.runQuery !== "function") {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
270
|
+
projectId: legacyScopeId
|
|
271
|
+
}) ?? null;
|
|
272
|
+
} catch (error) {
|
|
273
|
+
debugGraphPrimitiveFallback(
|
|
274
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
275
|
+
{
|
|
276
|
+
error,
|
|
277
|
+
legacyScopeId
|
|
236
278
|
}
|
|
237
|
-
|
|
279
|
+
);
|
|
280
|
+
return null;
|
|
238
281
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
comparisonSatisfied,
|
|
253
|
-
result,
|
|
254
|
-
unit: config.unit
|
|
255
|
-
}),
|
|
256
|
-
data: {
|
|
257
|
-
metric,
|
|
258
|
-
observedValue,
|
|
259
|
-
operator: config.operator,
|
|
260
|
-
threshold: config.threshold,
|
|
261
|
-
unit: config.unit
|
|
282
|
+
}
|
|
283
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
284
|
+
const MAX_DEPTH = 10;
|
|
285
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
286
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
287
|
+
if (tenantId && workspaceId) {
|
|
288
|
+
return { tenantId, workspaceId };
|
|
289
|
+
}
|
|
290
|
+
let current = topic;
|
|
291
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
292
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
293
|
+
if (!current) {
|
|
294
|
+
break;
|
|
262
295
|
}
|
|
263
|
-
|
|
296
|
+
if (!tenantId) {
|
|
297
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
298
|
+
}
|
|
299
|
+
if (!workspaceId) {
|
|
300
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
301
|
+
}
|
|
302
|
+
if (tenantId && workspaceId) {
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return { tenantId, workspaceId };
|
|
264
307
|
}
|
|
265
|
-
async function
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
ctx
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
});
|
|
275
|
-
const comparisonSatisfied = compareMetricValue(
|
|
276
|
-
config.operator,
|
|
277
|
-
snapshot.count,
|
|
278
|
-
config.threshold
|
|
308
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
309
|
+
if (args.topicId) {
|
|
310
|
+
return await resolveScopeFromTopicId(ctx, args.topicId);
|
|
311
|
+
}
|
|
312
|
+
if (args.projectId) {
|
|
313
|
+
return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
|
|
314
|
+
}
|
|
315
|
+
throw new Error(
|
|
316
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
279
317
|
);
|
|
280
|
-
const result = resolveComparisonResult(args.contract.direction, comparisonSatisfied);
|
|
281
|
-
return {
|
|
282
|
-
result,
|
|
283
|
-
rationale: buildComparisonRationale({
|
|
284
|
-
label: `reference checks tagged "${tag}"`,
|
|
285
|
-
observedValue: snapshot.count,
|
|
286
|
-
operator: config.operator,
|
|
287
|
-
threshold: config.threshold,
|
|
288
|
-
comparisonSatisfied,
|
|
289
|
-
result
|
|
290
|
-
}),
|
|
291
|
-
data: {
|
|
292
|
-
tag,
|
|
293
|
-
observedValue: snapshot.count,
|
|
294
|
-
referenceCheckCount: snapshot.count,
|
|
295
|
-
matchedEvidenceIds: snapshot.matchedEvidenceIds,
|
|
296
|
-
operator: config.operator,
|
|
297
|
-
threshold: config.threshold,
|
|
298
|
-
caseSensitive: config.caseSensitive ?? false
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
318
|
}
|
|
302
|
-
async function
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
);
|
|
319
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
320
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
321
|
+
if (topic) {
|
|
322
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
307
323
|
}
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
deadline: args.contract.deadline,
|
|
326
|
-
completed: true,
|
|
327
|
-
completedAt,
|
|
328
|
-
missedDeadline: true,
|
|
329
|
-
overdueByMs: completedAt - args.contract.deadline
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
const result = args.contract.direction === "falsifies" ? "disconfirmed" : "confirmed";
|
|
334
|
-
return {
|
|
335
|
-
result,
|
|
336
|
-
rationale: `${label} completed before deadline ${args.contract.deadline}.`,
|
|
337
|
-
data: {
|
|
338
|
-
label,
|
|
339
|
-
deadline: args.contract.deadline,
|
|
340
|
-
completed: true,
|
|
341
|
-
completedAt: completedAt ?? null,
|
|
342
|
-
missedDeadline: false
|
|
343
|
-
}
|
|
344
|
-
};
|
|
324
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
|
|
325
|
+
if (nodeScope) {
|
|
326
|
+
return nodeScope;
|
|
327
|
+
}
|
|
328
|
+
throw new Error(`Topic not found: ${String(topicId)}`);
|
|
329
|
+
}
|
|
330
|
+
async function resolveTopicDocFromTopicId(ctx, topicId) {
|
|
331
|
+
const direct = await tryReadTopicDoc(ctx, topicId, {
|
|
332
|
+
failureLog: "[topicScope] Failed to load topic by direct id",
|
|
333
|
+
idLogKey: "topicId"
|
|
334
|
+
});
|
|
335
|
+
if (direct) {
|
|
336
|
+
return direct;
|
|
337
|
+
}
|
|
338
|
+
const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
|
|
339
|
+
if (hostTopic) {
|
|
340
|
+
return hostTopic;
|
|
345
341
|
}
|
|
346
|
-
|
|
342
|
+
return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
|
|
343
|
+
}
|
|
344
|
+
async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
|
|
345
|
+
const directTopic = await resolveDirectLegacyProjectTopic(
|
|
346
|
+
ctx,
|
|
347
|
+
legacyProjectId
|
|
348
|
+
);
|
|
349
|
+
if (directTopic) {
|
|
350
|
+
return await buildTopicScope(ctx, directTopic, "topic_inferred", {
|
|
351
|
+
fallbackProjectId: legacyProjectId
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
const primary = pickPrimaryTopic(
|
|
355
|
+
await findTopicsByScopeAlias(ctx, legacyProjectId)
|
|
356
|
+
);
|
|
357
|
+
if (primary) {
|
|
358
|
+
return await buildTopicScope(ctx, primary, "project_mapped_topic", {
|
|
359
|
+
fallbackProjectId: legacyProjectId
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
|
|
363
|
+
if (nodeScope) {
|
|
347
364
|
return {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
data: {
|
|
351
|
-
label,
|
|
352
|
-
deadline: args.contract.deadline,
|
|
353
|
-
completed: false,
|
|
354
|
-
overdueByMs: args.now - args.contract.deadline
|
|
355
|
-
}
|
|
365
|
+
...nodeScope,
|
|
366
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
356
367
|
};
|
|
357
368
|
}
|
|
369
|
+
throw new Error(
|
|
370
|
+
`Legacy project scope ${legacyProjectId} has no mapped topic.`
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
|
|
374
|
+
const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
|
|
375
|
+
failureLog: "[topicScope] Failed to load direct project topic",
|
|
376
|
+
idLogKey: "projectId"
|
|
377
|
+
});
|
|
378
|
+
return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
|
|
379
|
+
}
|
|
380
|
+
async function tryReadTopicDoc(ctx, id, log) {
|
|
381
|
+
try {
|
|
382
|
+
return await ctx.db.get(id);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
debugGraphPrimitiveFallback(log.failureLog, {
|
|
385
|
+
error,
|
|
386
|
+
[log.idLogKey]: id
|
|
387
|
+
});
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async function buildTopicScope(ctx, topic, source, options = {}) {
|
|
392
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
393
|
+
const mapped = asMappedProjectId(topic);
|
|
358
394
|
return {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
completed: false,
|
|
365
|
-
timeRemainingMs: args.contract.deadline - args.now
|
|
366
|
-
}
|
|
395
|
+
topicId: topic._id,
|
|
396
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
397
|
+
tenantId: inherited.tenantId,
|
|
398
|
+
workspaceId: inherited.workspaceId,
|
|
399
|
+
source
|
|
367
400
|
};
|
|
368
401
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if (subjectValue === null || benchmarkValue === null) {
|
|
377
|
-
return {
|
|
378
|
-
result: "inconclusive",
|
|
379
|
-
rationale: "market_index_comparator is awaiting both subject and benchmark values.",
|
|
380
|
-
data: {
|
|
381
|
-
subject,
|
|
382
|
-
subjectValue,
|
|
383
|
-
benchmark,
|
|
384
|
-
benchmarkValue,
|
|
385
|
-
operator: config.operator,
|
|
386
|
-
threshold: config.threshold
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
if (benchmarkValue === 0) {
|
|
391
|
-
throw new Error(
|
|
392
|
-
"market_index_comparator cannot compare against a zero benchmark value."
|
|
393
|
-
);
|
|
402
|
+
({
|
|
403
|
+
projectId: v.optional(v.string()),
|
|
404
|
+
topicId: v.optional(v.string())
|
|
405
|
+
});
|
|
406
|
+
function normalizeScopeValue2(value) {
|
|
407
|
+
if (typeof value !== "string") {
|
|
408
|
+
return;
|
|
394
409
|
}
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
config.operator,
|
|
398
|
-
differentialPercent,
|
|
399
|
-
config.threshold
|
|
400
|
-
);
|
|
401
|
-
const result = resolveComparisonResult(args.contract.direction, comparisonSatisfied);
|
|
402
|
-
return {
|
|
403
|
-
result,
|
|
404
|
-
rationale: buildComparisonRationale({
|
|
405
|
-
label: `${subject ?? "subject"} vs ${benchmark ?? "benchmark"} differential`,
|
|
406
|
-
observedValue: differentialPercent,
|
|
407
|
-
operator: config.operator,
|
|
408
|
-
threshold: config.threshold,
|
|
409
|
-
comparisonSatisfied,
|
|
410
|
-
result,
|
|
411
|
-
unit: "%"
|
|
412
|
-
}),
|
|
413
|
-
data: {
|
|
414
|
-
subject,
|
|
415
|
-
subjectValue,
|
|
416
|
-
benchmark,
|
|
417
|
-
benchmarkValue,
|
|
418
|
-
differentialPercent,
|
|
419
|
-
operator: config.operator,
|
|
420
|
-
threshold: config.threshold
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
var METRIC_COMPARATOR_EVALUATOR_NAMES = {
|
|
425
|
-
evidentialAliases: /* @__PURE__ */ new Set(["evidential", "built_in_evidential", "builtin_evidential"]),
|
|
426
|
-
metricChecker: "metric_checker",
|
|
427
|
-
referenceCheckCounter: "reference_check_counter",
|
|
428
|
-
temporalDeadline: "temporal_deadline",
|
|
429
|
-
marketIndexComparator: "market_index_comparator"
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
// src/beliefLifecycle.ts
|
|
433
|
-
var BELIEF_STATUS_VALUES = [
|
|
434
|
-
"assumption",
|
|
435
|
-
"hypothesis",
|
|
436
|
-
"active",
|
|
437
|
-
"superseded",
|
|
438
|
-
"resolved_true",
|
|
439
|
-
"resolved_false"
|
|
440
|
-
];
|
|
441
|
-
function isBeliefLifecycleStatus(value) {
|
|
442
|
-
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
410
|
+
const normalized = value.trim();
|
|
411
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
443
412
|
}
|
|
444
|
-
function
|
|
445
|
-
if (
|
|
446
|
-
return
|
|
447
|
-
}
|
|
448
|
-
if (value === "belief" || value === "established" || value === "emerging") {
|
|
449
|
-
return "active";
|
|
450
|
-
}
|
|
451
|
-
if (value === "fact" || value === "confirmed") {
|
|
452
|
-
return "resolved_true";
|
|
453
|
-
}
|
|
454
|
-
if (value === "disconfirmed" || value === "expired") {
|
|
455
|
-
return "resolved_false";
|
|
413
|
+
function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
414
|
+
if (!node) {
|
|
415
|
+
return false;
|
|
456
416
|
}
|
|
457
|
-
|
|
458
|
-
|
|
417
|
+
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
418
|
+
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
419
|
+
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
420
|
+
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
421
|
+
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
422
|
+
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
423
|
+
return false;
|
|
459
424
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
function normalizeBeliefConfidence(confidence) {
|
|
463
|
-
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
464
|
-
return null;
|
|
425
|
+
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
426
|
+
return true;
|
|
465
427
|
}
|
|
466
|
-
if (
|
|
467
|
-
return
|
|
428
|
+
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
429
|
+
return true;
|
|
468
430
|
}
|
|
469
|
-
if (
|
|
470
|
-
return
|
|
431
|
+
if (!scopeWorkspaceId) {
|
|
432
|
+
return nodeWorkspaceId === void 0;
|
|
471
433
|
}
|
|
472
|
-
return
|
|
434
|
+
return scopeWorkspaceId === nodeWorkspaceId;
|
|
473
435
|
}
|
|
474
|
-
function
|
|
475
|
-
|
|
476
|
-
if (normalized === null) {
|
|
436
|
+
function edgeMatchesWorkspaceReasoningScope(edge, scope) {
|
|
437
|
+
if (!edge) {
|
|
477
438
|
return false;
|
|
478
439
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
486
|
-
return null;
|
|
487
|
-
}
|
|
488
|
-
const outcome = predictionMeta.outcome;
|
|
489
|
-
if (outcome === "confirmed") {
|
|
490
|
-
return "resolved_true";
|
|
440
|
+
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
441
|
+
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
442
|
+
const edgeTenantId = normalizeScopeValue2(edge.tenantId);
|
|
443
|
+
const edgeWorkspaceId = normalizeScopeValue2(edge.workspaceId);
|
|
444
|
+
if (scopeTenantId && edgeTenantId && scopeTenantId !== edgeTenantId) {
|
|
445
|
+
return false;
|
|
491
446
|
}
|
|
492
|
-
if (
|
|
493
|
-
return
|
|
447
|
+
if (!scopeWorkspaceId) {
|
|
448
|
+
return edgeWorkspaceId === void 0;
|
|
494
449
|
}
|
|
495
|
-
return
|
|
450
|
+
return scopeWorkspaceId === edgeWorkspaceId;
|
|
496
451
|
}
|
|
497
|
-
function
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
452
|
+
async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
453
|
+
const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
454
|
+
const resolved = {
|
|
455
|
+
tenantId: normalizeScopeValue2(node?.tenantId),
|
|
456
|
+
workspaceId: normalizeScopeValue2(node?.workspaceId),
|
|
457
|
+
epistemicLayer,
|
|
458
|
+
nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
|
|
459
|
+
};
|
|
460
|
+
if (!node) {
|
|
461
|
+
return resolved;
|
|
505
462
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
);
|
|
509
|
-
if (metadataPredictionStatus) {
|
|
510
|
-
return metadataPredictionStatus;
|
|
463
|
+
if (resolved.epistemicLayer === "ontological") {
|
|
464
|
+
return resolved;
|
|
511
465
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
function resolveBeliefLifecycleStatus(opts) {
|
|
515
|
-
const resolvedStatus = shouldTreatBeliefAsResolved(opts);
|
|
516
|
-
if (resolvedStatus) {
|
|
517
|
-
return resolvedStatus;
|
|
466
|
+
if (resolved.tenantId || resolved.workspaceId) {
|
|
467
|
+
return resolved;
|
|
518
468
|
}
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
469
|
+
const topicId = normalizeScopeValue2(node.topicId);
|
|
470
|
+
if (topicId) {
|
|
471
|
+
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
472
|
+
topicId
|
|
473
|
+
});
|
|
474
|
+
return {
|
|
475
|
+
...resolved,
|
|
476
|
+
tenantId: topicScope.tenantId,
|
|
477
|
+
workspaceId: topicScope.workspaceId
|
|
478
|
+
};
|
|
527
479
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
480
|
+
if (node.projectId) {
|
|
481
|
+
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
482
|
+
projectId: String(node.projectId)
|
|
483
|
+
});
|
|
484
|
+
return {
|
|
485
|
+
...resolved,
|
|
486
|
+
tenantId: topicScope.tenantId,
|
|
487
|
+
workspaceId: topicScope.workspaceId
|
|
488
|
+
};
|
|
536
489
|
}
|
|
537
|
-
return
|
|
490
|
+
return resolved;
|
|
538
491
|
}
|
|
539
|
-
|
|
540
|
-
|
|
492
|
+
v.id("epistemicNodes");
|
|
493
|
+
var DEFAULT_CONFIDENCE_POLICY = {
|
|
494
|
+
scoringMode: "after_worktree",
|
|
495
|
+
tupleContradiction: normalizeTupleContradictionPolicy()
|
|
496
|
+
};
|
|
497
|
+
function buildBeliefConfidenceRow(args) {
|
|
498
|
+
return {
|
|
499
|
+
beliefId: args.beliefId,
|
|
500
|
+
confidence: confidenceFromSL(
|
|
501
|
+
args.belief,
|
|
502
|
+
args.disbelief,
|
|
503
|
+
args.uncertainty,
|
|
504
|
+
args.baseRate
|
|
505
|
+
),
|
|
506
|
+
belief: args.belief,
|
|
507
|
+
disbelief: args.disbelief,
|
|
508
|
+
uncertainty: args.uncertainty,
|
|
509
|
+
baseRate: args.baseRate,
|
|
510
|
+
slOperator: args.slOperator ?? "prior_seed",
|
|
511
|
+
trigger: args.trigger,
|
|
512
|
+
...args.rationale ? { rationale: args.rationale } : {},
|
|
513
|
+
assessedBy: args.assessedBy,
|
|
514
|
+
assessedAt: args.assessedAt,
|
|
515
|
+
...args.triggeringEvidenceId ? {
|
|
516
|
+
triggeringEvidenceId: args.triggeringEvidenceId,
|
|
517
|
+
triggeringEvidenceIds: [String(args.triggeringEvidenceId)]
|
|
518
|
+
} : {},
|
|
519
|
+
...args.triggeringContradictionId ? {
|
|
520
|
+
triggeringContradictionId: args.triggeringContradictionId
|
|
521
|
+
} : {},
|
|
522
|
+
...args.triggeringWorktreeId ? { triggeringWorktreeId: args.triggeringWorktreeId } : {}
|
|
523
|
+
};
|
|
541
524
|
}
|
|
542
|
-
function
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
525
|
+
function readTupleContradictedFlag(value) {
|
|
526
|
+
return typeof value === "boolean" ? value : void 0;
|
|
527
|
+
}
|
|
528
|
+
function readBeliefOpinionSnapshot(node, metadata) {
|
|
529
|
+
try {
|
|
530
|
+
return readOpinionFromRecord({
|
|
531
|
+
...metadata,
|
|
532
|
+
opinion_b: node.opinion_b,
|
|
533
|
+
opinion_d: node.opinion_d,
|
|
534
|
+
opinion_u: node.opinion_u,
|
|
535
|
+
opinion_a: node.opinion_a
|
|
536
|
+
});
|
|
537
|
+
} catch (error) {
|
|
538
|
+
debugGraphPrimitiveFallback(
|
|
539
|
+
"[epistemicBeliefs] Failed to read belief opinion snapshot",
|
|
540
|
+
{
|
|
541
|
+
error,
|
|
542
|
+
beliefId: node._id
|
|
543
|
+
}
|
|
544
|
+
);
|
|
545
|
+
return mkOpinion(0, 0, 1, 0.5);
|
|
549
546
|
}
|
|
550
|
-
return status;
|
|
551
547
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
var query = queryGeneric;
|
|
558
|
-
|
|
559
|
-
// src/debug.ts
|
|
560
|
-
function isGraphPrimitiveDebugEnabled() {
|
|
561
|
-
const env = globalThis.process?.env;
|
|
562
|
-
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
563
|
-
}
|
|
564
|
-
function debugGraphPrimitiveFallback(message, context) {
|
|
565
|
-
if (!isGraphPrimitiveDebugEnabled()) {
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
console.debug(message, context ?? {});
|
|
569
|
-
}
|
|
570
|
-
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
571
|
-
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
572
|
-
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
573
|
-
return null;
|
|
574
|
-
}
|
|
575
|
-
let node = null;
|
|
576
|
-
try {
|
|
577
|
-
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
578
|
-
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
579
|
-
node = byGlobalId;
|
|
580
|
-
}
|
|
581
|
-
} catch (error) {
|
|
582
|
-
debugGraphPrimitiveFallback(
|
|
583
|
-
"[topicScope] topic-node scope lookup by globalId failed",
|
|
584
|
-
{ error, ref }
|
|
585
|
-
);
|
|
586
|
-
}
|
|
587
|
-
if (!node) {
|
|
588
|
-
return null;
|
|
548
|
+
function deriveTupleContradictionSeverity(node) {
|
|
549
|
+
const metadata = node.metadata || {};
|
|
550
|
+
const criticality = typeof metadata.criticality === "string" ? metadata.criticality : void 0;
|
|
551
|
+
if (criticality === "blocking") {
|
|
552
|
+
return "critical";
|
|
589
553
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
return null;
|
|
554
|
+
if (criticality === "supporting") {
|
|
555
|
+
return "minor";
|
|
593
556
|
}
|
|
594
|
-
return
|
|
595
|
-
topicId: scopeKey,
|
|
596
|
-
projectId: asMappedProjectId(node),
|
|
597
|
-
source: "topic_node"
|
|
598
|
-
};
|
|
557
|
+
return "significant";
|
|
599
558
|
}
|
|
600
|
-
function
|
|
601
|
-
|
|
602
|
-
return;
|
|
603
|
-
}
|
|
604
|
-
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
605
|
-
if (directLegacyProjectId) {
|
|
606
|
-
return directLegacyProjectId;
|
|
607
|
-
}
|
|
608
|
-
const metadata = topic.metadata || {};
|
|
609
|
-
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
610
|
-
return candidate ? candidate : void 0;
|
|
559
|
+
function formatTupleContradictionDescription(args) {
|
|
560
|
+
return `Tuple-space contradiction detected: b=${args.opinion.b.toFixed(2)} > ${args.policy.beliefThreshold.toFixed(2)} and d=${args.opinion.d.toFixed(2)} > ${args.policy.disbeliefThreshold.toFixed(2)}.`;
|
|
611
561
|
}
|
|
612
|
-
function
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
562
|
+
function resolveBeliefStatus(node, metadata) {
|
|
563
|
+
return resolveBeliefLifecycleStatus({
|
|
564
|
+
beliefStatus: node.beliefStatus,
|
|
565
|
+
confidence: node.confidence,
|
|
566
|
+
predictionMeta: node.predictionMeta,
|
|
567
|
+
metadata
|
|
568
|
+
});
|
|
618
569
|
}
|
|
619
|
-
function
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
if (createdA !== createdB) {
|
|
629
|
-
return createdA - createdB;
|
|
570
|
+
async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
|
|
571
|
+
const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
|
|
572
|
+
"by_belief",
|
|
573
|
+
(q) => q.eq("beliefId", beliefNodeId)
|
|
574
|
+
).collect();
|
|
575
|
+
for (const membership of clusterMembership) {
|
|
576
|
+
const worktree = await ctx.db.get(membership.worktreeId);
|
|
577
|
+
if (worktree?.status === "completed" || worktree?.status === "merged") {
|
|
578
|
+
return true;
|
|
630
579
|
}
|
|
631
|
-
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
632
|
-
})[0];
|
|
633
|
-
}
|
|
634
|
-
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
635
|
-
try {
|
|
636
|
-
return await ctx.db.query("topics").withIndex(
|
|
637
|
-
"by_graph_scope_project",
|
|
638
|
-
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
639
|
-
).collect();
|
|
640
|
-
} catch (error) {
|
|
641
|
-
debugGraphPrimitiveFallback(
|
|
642
|
-
"[topicScope] Failed to resolve scope alias via index",
|
|
643
|
-
{
|
|
644
|
-
error,
|
|
645
|
-
scopeId
|
|
646
|
-
}
|
|
647
|
-
);
|
|
648
|
-
const topics = await ctx.db.query("topics").collect();
|
|
649
|
-
return topics.filter((topic) => {
|
|
650
|
-
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
651
|
-
const mappedProjectId = asMappedProjectId(topic);
|
|
652
|
-
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
653
|
-
});
|
|
654
580
|
}
|
|
581
|
+
return false;
|
|
655
582
|
}
|
|
656
|
-
async function
|
|
657
|
-
if (typeof ctx.runQuery !== "function") {
|
|
658
|
-
return null;
|
|
659
|
-
}
|
|
583
|
+
async function getActiveConfidencePolicy(ctx) {
|
|
660
584
|
try {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
585
|
+
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
586
|
+
"by_active",
|
|
587
|
+
(q) => q.eq("isActive", true)
|
|
588
|
+
).first();
|
|
589
|
+
return {
|
|
590
|
+
scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
|
|
591
|
+
tupleContradiction: normalizeTupleContradictionPolicy(
|
|
592
|
+
activeConfig?.tupleContradictionPolicy
|
|
593
|
+
)
|
|
594
|
+
};
|
|
664
595
|
} catch (error) {
|
|
665
596
|
debugGraphPrimitiveFallback(
|
|
666
|
-
"[
|
|
597
|
+
"[epistemicBeliefs] Failed to load active confidence policy",
|
|
667
598
|
{
|
|
668
|
-
error
|
|
669
|
-
topicId
|
|
599
|
+
error
|
|
670
600
|
}
|
|
671
601
|
);
|
|
672
|
-
return
|
|
602
|
+
return DEFAULT_CONFIDENCE_POLICY;
|
|
673
603
|
}
|
|
674
604
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
605
|
+
|
|
606
|
+
// src/edges/contains.ts
|
|
607
|
+
var containsPropagationSpec = {
|
|
608
|
+
edgeType: "contains",
|
|
609
|
+
direction: "outgoing",
|
|
610
|
+
transitivity: "none",
|
|
611
|
+
damping: 1,
|
|
612
|
+
maxHops: 1,
|
|
613
|
+
operator: () => null,
|
|
614
|
+
description: "Structural containment only. Traversed for explicit semantics, but it never propagates opinions."
|
|
615
|
+
};
|
|
616
|
+
function readEdgeMetadata(edge) {
|
|
617
|
+
return {
|
|
618
|
+
constraint: edge.constraint ?? void 0,
|
|
619
|
+
normalization: edge.normalization ?? void 0,
|
|
620
|
+
propagation: edge.propagation ?? void 0,
|
|
621
|
+
conditionalA: edge.conditionalA ?? void 0,
|
|
622
|
+
conditionalNotA: edge.conditionalNotA ?? void 0
|
|
623
|
+
};
|
|
693
624
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
698
|
-
if (tenantId && workspaceId) {
|
|
699
|
-
return { tenantId, workspaceId };
|
|
700
|
-
}
|
|
701
|
-
let current = topic;
|
|
702
|
-
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
703
|
-
current = await ctx.db.get(current.parentTopicId);
|
|
704
|
-
if (!current) break;
|
|
705
|
-
if (!tenantId) {
|
|
706
|
-
tenantId = normalizeScopeValue(current.tenantId);
|
|
707
|
-
}
|
|
708
|
-
if (!workspaceId) {
|
|
709
|
-
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
710
|
-
}
|
|
711
|
-
if (tenantId && workspaceId) break;
|
|
625
|
+
function applyPerHopDamping(sourceOpinion, damping) {
|
|
626
|
+
if (damping >= 1) {
|
|
627
|
+
return sourceOpinion;
|
|
712
628
|
}
|
|
713
|
-
return
|
|
629
|
+
return trustDiscount(sourceOpinion, Math.max(0, damping));
|
|
714
630
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
} catch (error) {
|
|
723
|
-
debugGraphPrimitiveFallback(
|
|
724
|
-
"[topicScope] Failed to load topic by direct id",
|
|
725
|
-
{
|
|
726
|
-
error,
|
|
727
|
-
topicId: args.topicId
|
|
728
|
-
}
|
|
729
|
-
);
|
|
730
|
-
}
|
|
731
|
-
if (!topic) {
|
|
732
|
-
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
733
|
-
}
|
|
734
|
-
if (!topic) {
|
|
735
|
-
topic = pickPrimaryTopic(
|
|
736
|
-
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
737
|
-
) ?? null;
|
|
738
|
-
}
|
|
739
|
-
if (!topic) {
|
|
740
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
741
|
-
ctx,
|
|
742
|
-
String(args.topicId)
|
|
743
|
-
);
|
|
744
|
-
if (nodeScope) {
|
|
745
|
-
return nodeScope;
|
|
746
|
-
}
|
|
747
|
-
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
748
|
-
}
|
|
749
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
750
|
-
const mapped = asMappedProjectId(topic);
|
|
751
|
-
if (mapped) {
|
|
752
|
-
return {
|
|
753
|
-
topicId: topic._id,
|
|
754
|
-
projectId: mapped,
|
|
755
|
-
tenantId: inherited.tenantId,
|
|
756
|
-
workspaceId: inherited.workspaceId,
|
|
757
|
-
source: "topic"
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
return {
|
|
761
|
-
topicId: topic._id,
|
|
762
|
-
tenantId: inherited.tenantId,
|
|
763
|
-
workspaceId: inherited.workspaceId,
|
|
764
|
-
source: "topic"
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
if (args.projectId) {
|
|
768
|
-
let directTopic = null;
|
|
769
|
-
try {
|
|
770
|
-
directTopic = await ctx.db.get(
|
|
771
|
-
args.projectId
|
|
772
|
-
);
|
|
773
|
-
} catch (error) {
|
|
774
|
-
debugGraphPrimitiveFallback(
|
|
775
|
-
"[topicScope] Failed to load direct project topic",
|
|
776
|
-
{
|
|
777
|
-
error,
|
|
778
|
-
projectId: args.projectId
|
|
779
|
-
}
|
|
780
|
-
);
|
|
781
|
-
}
|
|
782
|
-
if (directTopic) {
|
|
783
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
784
|
-
const mapped = asMappedProjectId(directTopic);
|
|
785
|
-
return {
|
|
786
|
-
topicId: directTopic._id,
|
|
787
|
-
projectId: mapped ?? args.projectId,
|
|
788
|
-
tenantId: inherited.tenantId,
|
|
789
|
-
workspaceId: inherited.workspaceId,
|
|
790
|
-
source: "topic_inferred"
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
794
|
-
if (directTopic) {
|
|
795
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
796
|
-
const mapped = asMappedProjectId(directTopic);
|
|
797
|
-
return {
|
|
798
|
-
topicId: directTopic._id,
|
|
799
|
-
projectId: mapped ?? args.projectId,
|
|
800
|
-
tenantId: inherited.tenantId,
|
|
801
|
-
workspaceId: inherited.workspaceId,
|
|
802
|
-
source: "topic_inferred"
|
|
803
|
-
};
|
|
804
|
-
}
|
|
805
|
-
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
806
|
-
const primary = pickPrimaryTopic(topics);
|
|
807
|
-
if (primary) {
|
|
808
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
809
|
-
return {
|
|
810
|
-
topicId: primary._id,
|
|
811
|
-
projectId: args.projectId,
|
|
812
|
-
tenantId: inherited.tenantId,
|
|
813
|
-
workspaceId: inherited.workspaceId,
|
|
814
|
-
source: "project_mapped_topic"
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
818
|
-
ctx,
|
|
819
|
-
String(args.projectId)
|
|
820
|
-
);
|
|
821
|
-
if (nodeScope) {
|
|
822
|
-
return {
|
|
823
|
-
...nodeScope,
|
|
824
|
-
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
825
|
-
};
|
|
826
|
-
}
|
|
827
|
-
throw new Error(
|
|
828
|
-
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
829
|
-
);
|
|
830
|
-
}
|
|
831
|
-
throw new Error(
|
|
832
|
-
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
833
|
-
);
|
|
834
|
-
}
|
|
835
|
-
({
|
|
836
|
-
projectId: v.optional(v.string()),
|
|
837
|
-
topicId: v.optional(v.string())
|
|
838
|
-
});
|
|
839
|
-
function normalizeScopeValue2(value) {
|
|
840
|
-
if (typeof value !== "string") {
|
|
841
|
-
return;
|
|
842
|
-
}
|
|
843
|
-
const normalized = value.trim();
|
|
844
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
845
|
-
}
|
|
846
|
-
function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
847
|
-
if (!node) {
|
|
848
|
-
return false;
|
|
849
|
-
}
|
|
850
|
-
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
851
|
-
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
852
|
-
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
853
|
-
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
854
|
-
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
855
|
-
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
856
|
-
return false;
|
|
857
|
-
}
|
|
858
|
-
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
859
|
-
return true;
|
|
860
|
-
}
|
|
861
|
-
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
862
|
-
return true;
|
|
863
|
-
}
|
|
864
|
-
if (!scopeWorkspaceId) {
|
|
865
|
-
return nodeWorkspaceId === void 0;
|
|
866
|
-
}
|
|
867
|
-
return scopeWorkspaceId === nodeWorkspaceId;
|
|
868
|
-
}
|
|
869
|
-
function edgeMatchesWorkspaceReasoningScope(edge, scope) {
|
|
870
|
-
if (!edge) {
|
|
871
|
-
return false;
|
|
872
|
-
}
|
|
873
|
-
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
874
|
-
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
875
|
-
const edgeTenantId = normalizeScopeValue2(edge.tenantId);
|
|
876
|
-
const edgeWorkspaceId = normalizeScopeValue2(edge.workspaceId);
|
|
877
|
-
if (scopeTenantId && edgeTenantId && scopeTenantId !== edgeTenantId) {
|
|
878
|
-
return false;
|
|
879
|
-
}
|
|
880
|
-
if (!scopeWorkspaceId) {
|
|
881
|
-
return edgeWorkspaceId === void 0;
|
|
882
|
-
}
|
|
883
|
-
return scopeWorkspaceId === edgeWorkspaceId;
|
|
884
|
-
}
|
|
885
|
-
async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
886
|
-
const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
887
|
-
const resolved = {
|
|
888
|
-
tenantId: normalizeScopeValue2(node?.tenantId),
|
|
889
|
-
workspaceId: normalizeScopeValue2(node?.workspaceId),
|
|
890
|
-
epistemicLayer,
|
|
891
|
-
nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
|
|
892
|
-
};
|
|
893
|
-
if (!node) {
|
|
894
|
-
return resolved;
|
|
895
|
-
}
|
|
896
|
-
if (resolved.epistemicLayer === "ontological") {
|
|
897
|
-
return resolved;
|
|
898
|
-
}
|
|
899
|
-
if (resolved.tenantId || resolved.workspaceId) {
|
|
900
|
-
return resolved;
|
|
901
|
-
}
|
|
902
|
-
if (node.topicId) {
|
|
903
|
-
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
904
|
-
topicId: node.topicId
|
|
905
|
-
});
|
|
906
|
-
return {
|
|
907
|
-
...resolved,
|
|
908
|
-
tenantId: topicScope.tenantId,
|
|
909
|
-
workspaceId: topicScope.workspaceId
|
|
910
|
-
};
|
|
911
|
-
}
|
|
912
|
-
if (node.projectId) {
|
|
913
|
-
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
914
|
-
projectId: String(node.projectId)
|
|
915
|
-
});
|
|
916
|
-
return {
|
|
917
|
-
...resolved,
|
|
918
|
-
tenantId: topicScope.tenantId,
|
|
919
|
-
workspaceId: topicScope.workspaceId
|
|
920
|
-
};
|
|
921
|
-
}
|
|
922
|
-
return resolved;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
// src/epistemicBeliefs.helpers.ts
|
|
926
|
-
v.id("epistemicNodes");
|
|
927
|
-
var DEFAULT_CONFIDENCE_POLICY = {
|
|
928
|
-
scoringMode: "after_worktree",
|
|
929
|
-
tupleContradiction: normalizeTupleContradictionPolicy()
|
|
930
|
-
};
|
|
931
|
-
function throwStructuredMutationError(args) {
|
|
932
|
-
const data = {
|
|
933
|
-
structuredMutationError: true,
|
|
934
|
-
message: args.message,
|
|
935
|
-
status: args.status,
|
|
936
|
-
code: args.code,
|
|
937
|
-
invariantCode: args.invariantCode,
|
|
938
|
-
suggestion: args.suggestion,
|
|
939
|
-
details: args.details
|
|
940
|
-
};
|
|
941
|
-
const error = new ConvexError(
|
|
942
|
-
data
|
|
943
|
-
);
|
|
944
|
-
error.status = args.status;
|
|
945
|
-
error.code = args.code;
|
|
946
|
-
error.invariantCode = args.invariantCode;
|
|
947
|
-
error.suggestion = args.suggestion;
|
|
948
|
-
error.details = args.details;
|
|
949
|
-
throw error;
|
|
950
|
-
}
|
|
951
|
-
function buildBeliefConfidenceRow(args) {
|
|
952
|
-
return {
|
|
953
|
-
beliefId: args.beliefId,
|
|
954
|
-
confidence: confidenceFromSL(
|
|
955
|
-
args.belief,
|
|
956
|
-
args.disbelief,
|
|
957
|
-
args.uncertainty,
|
|
958
|
-
args.baseRate
|
|
959
|
-
),
|
|
960
|
-
belief: args.belief,
|
|
961
|
-
disbelief: args.disbelief,
|
|
962
|
-
uncertainty: args.uncertainty,
|
|
963
|
-
baseRate: args.baseRate,
|
|
964
|
-
slOperator: args.slOperator ?? "prior_seed",
|
|
965
|
-
trigger: args.trigger,
|
|
966
|
-
...args.rationale ? { rationale: args.rationale } : {},
|
|
967
|
-
assessedBy: args.assessedBy,
|
|
968
|
-
assessedAt: args.assessedAt,
|
|
969
|
-
...args.triggeringEvidenceId ? {
|
|
970
|
-
triggeringEvidenceId: args.triggeringEvidenceId,
|
|
971
|
-
triggeringEvidenceIds: [String(args.triggeringEvidenceId)]
|
|
972
|
-
} : {},
|
|
973
|
-
...args.triggeringContradictionId ? {
|
|
974
|
-
triggeringContradictionId: args.triggeringContradictionId
|
|
975
|
-
} : {},
|
|
976
|
-
...args.triggeringWorktreeId ? { triggeringWorktreeId: args.triggeringWorktreeId } : {}
|
|
977
|
-
};
|
|
978
|
-
}
|
|
979
|
-
function readTupleContradictedFlag(value) {
|
|
980
|
-
return typeof value === "boolean" ? value : void 0;
|
|
981
|
-
}
|
|
982
|
-
function readBeliefOpinionSnapshot(node, metadata) {
|
|
983
|
-
try {
|
|
984
|
-
return readOpinionFromRecord({
|
|
985
|
-
...metadata,
|
|
986
|
-
opinion_b: node.opinion_b,
|
|
987
|
-
opinion_d: node.opinion_d,
|
|
988
|
-
opinion_u: node.opinion_u,
|
|
989
|
-
opinion_a: node.opinion_a
|
|
990
|
-
});
|
|
991
|
-
} catch (error) {
|
|
992
|
-
debugGraphPrimitiveFallback(
|
|
993
|
-
"[epistemicBeliefs] Failed to read belief opinion snapshot",
|
|
994
|
-
{
|
|
995
|
-
error,
|
|
996
|
-
beliefId: node._id
|
|
997
|
-
}
|
|
998
|
-
);
|
|
999
|
-
return mkOpinion(0, 0, 1, 0.5);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
function deriveTupleContradictionSeverity(node) {
|
|
1003
|
-
const metadata = node.metadata || {};
|
|
1004
|
-
const criticality = typeof metadata.criticality === "string" ? metadata.criticality : void 0;
|
|
1005
|
-
if (criticality === "blocking") {
|
|
1006
|
-
return "critical";
|
|
1007
|
-
}
|
|
1008
|
-
if (criticality === "supporting") {
|
|
1009
|
-
return "minor";
|
|
1010
|
-
}
|
|
1011
|
-
return "significant";
|
|
1012
|
-
}
|
|
1013
|
-
function formatTupleContradictionDescription(args) {
|
|
1014
|
-
return `Tuple-space contradiction detected: b=${args.opinion.b.toFixed(2)} > ${args.policy.beliefThreshold.toFixed(2)} and d=${args.opinion.d.toFixed(2)} > ${args.policy.disbeliefThreshold.toFixed(2)}.`;
|
|
1015
|
-
}
|
|
1016
|
-
function resolveBeliefStatus(node, metadata) {
|
|
1017
|
-
return resolveBeliefLifecycleStatus({
|
|
1018
|
-
beliefStatus: node.beliefStatus,
|
|
1019
|
-
confidence: node.confidence,
|
|
1020
|
-
predictionMeta: node.predictionMeta,
|
|
1021
|
-
metadata
|
|
1022
|
-
});
|
|
1023
|
-
}
|
|
1024
|
-
async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
|
|
1025
|
-
const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex("by_belief", (q) => q.eq("beliefId", beliefNodeId)).collect();
|
|
1026
|
-
for (const membership of clusterMembership) {
|
|
1027
|
-
const worktree = await ctx.db.get(membership.worktreeId);
|
|
1028
|
-
if (worktree?.status === "completed" || worktree?.status === "merged") {
|
|
1029
|
-
return true;
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
return false;
|
|
1033
|
-
}
|
|
1034
|
-
async function getActiveConfidencePolicy(ctx) {
|
|
1035
|
-
try {
|
|
1036
|
-
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex("by_active", (q) => q.eq("isActive", true)).first();
|
|
1037
|
-
return {
|
|
1038
|
-
scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
|
|
1039
|
-
tupleContradiction: normalizeTupleContradictionPolicy(
|
|
1040
|
-
activeConfig?.tupleContradictionPolicy
|
|
1041
|
-
)
|
|
1042
|
-
};
|
|
1043
|
-
} catch (error) {
|
|
1044
|
-
debugGraphPrimitiveFallback(
|
|
1045
|
-
"[epistemicBeliefs] Failed to load active confidence policy",
|
|
1046
|
-
{
|
|
1047
|
-
error
|
|
1048
|
-
}
|
|
1049
|
-
);
|
|
1050
|
-
return DEFAULT_CONFIDENCE_POLICY;
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
async function requireProjectWriteAccess(ctx, projectId, userId) {
|
|
1054
|
-
const hasAccess = await checkProjectAccess(
|
|
1055
|
-
ctx,
|
|
1056
|
-
projectId,
|
|
1057
|
-
userId
|
|
1058
|
-
);
|
|
1059
|
-
if (!hasAccess) {
|
|
1060
|
-
throwStructuredMutationError({
|
|
1061
|
-
message: `Project write access denied for topic ${projectId}.`,
|
|
1062
|
-
status: 403,
|
|
1063
|
-
code: "PROJECT_ACCESS_DENIED",
|
|
1064
|
-
invariantCode: "policy.scope_required",
|
|
1065
|
-
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.",
|
|
1066
|
-
details: { topicId: projectId, principalId: userId }
|
|
1067
|
-
});
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
// src/edges/contains.ts
|
|
1072
|
-
var containsPropagationSpec = {
|
|
1073
|
-
edgeType: "contains",
|
|
1074
|
-
direction: "outgoing",
|
|
1075
|
-
transitivity: "none",
|
|
1076
|
-
damping: 1,
|
|
1077
|
-
maxHops: 1,
|
|
1078
|
-
operator: () => null,
|
|
1079
|
-
description: "Structural containment only. Traversed for explicit semantics, but it never propagates opinions."
|
|
1080
|
-
};
|
|
1081
|
-
function readEdgeMetadata(edge) {
|
|
1082
|
-
return {
|
|
1083
|
-
constraint: edge.constraint ?? void 0,
|
|
1084
|
-
normalization: edge.normalization ?? void 0,
|
|
1085
|
-
propagation: edge.propagation ?? void 0,
|
|
1086
|
-
conditionalA: edge.conditionalA ?? void 0,
|
|
1087
|
-
conditionalNotA: edge.conditionalNotA ?? void 0
|
|
1088
|
-
};
|
|
1089
|
-
}
|
|
1090
|
-
function applyPerHopDamping(sourceOpinion, damping) {
|
|
1091
|
-
if (damping >= 1) {
|
|
1092
|
-
return sourceOpinion;
|
|
1093
|
-
}
|
|
1094
|
-
return trustDiscount(sourceOpinion, Math.max(0, damping));
|
|
1095
|
-
}
|
|
1096
|
-
function annotateRationale(result, spec, hop) {
|
|
1097
|
-
return {
|
|
1098
|
-
...result,
|
|
1099
|
-
rationale: `hop=${hop} edge=${spec.edgeType} damping=${spec.damping.toFixed(
|
|
1100
|
-
2
|
|
1101
|
-
)} :: ${result.rationale}`
|
|
1102
|
-
};
|
|
631
|
+
function annotateRationale(result, spec, hop) {
|
|
632
|
+
return {
|
|
633
|
+
...result,
|
|
634
|
+
rationale: `hop=${hop} edge=${spec.edgeType} damping=${spec.damping.toFixed(
|
|
635
|
+
2
|
|
636
|
+
)} :: ${result.rationale}`
|
|
637
|
+
};
|
|
1103
638
|
}
|
|
1104
639
|
function propagatePositiveSupport(sourceOpinion, targetOpinion, edgeWeight) {
|
|
1105
640
|
const discounted = trustDiscount(sourceOpinion, Math.abs(edgeWeight));
|
|
@@ -1203,7 +738,7 @@ var dependsOnPropagationSpec = {
|
|
|
1203
738
|
description: "Structural gating. Textbook conditional deduction when edge conditionals exist, otherwise damped dependency cascade through downstream chains."
|
|
1204
739
|
};
|
|
1205
740
|
|
|
1206
|
-
// src/edges/
|
|
741
|
+
// src/edges/derived-from.ts
|
|
1207
742
|
var derivedFromPropagationSpec = {
|
|
1208
743
|
edgeType: "derived_from",
|
|
1209
744
|
direction: "incoming",
|
|
@@ -1256,7 +791,7 @@ var informsPropagationSpec = {
|
|
|
1256
791
|
description: "Evidence-bearing influence. Informs can chain through the graph with light per-hop damping."
|
|
1257
792
|
};
|
|
1258
793
|
|
|
1259
|
-
// src/edges/
|
|
794
|
+
// src/edges/propagation-types.ts
|
|
1260
795
|
function isPropagationTraversalDirection(direction) {
|
|
1261
796
|
return direction === "outgoing" || direction === "incoming";
|
|
1262
797
|
}
|
|
@@ -1329,6 +864,9 @@ var testsPropagationSpec = {
|
|
|
1329
864
|
};
|
|
1330
865
|
|
|
1331
866
|
// src/edges/index.ts
|
|
867
|
+
var canContinueTransitively2 = canContinueTransitively;
|
|
868
|
+
var canTraverseHop2 = canTraverseHop;
|
|
869
|
+
var isPropagationTraversalDirection2 = isPropagationTraversalDirection;
|
|
1332
870
|
var EDGE_PROPAGATION_SPECS = [
|
|
1333
871
|
supportsPropagationSpec,
|
|
1334
872
|
informsPropagationSpec,
|
|
@@ -1345,16 +883,15 @@ function getEdgePropagationSpecs() {
|
|
|
1345
883
|
return EDGE_PROPAGATION_SPECS;
|
|
1346
884
|
}
|
|
1347
885
|
function getTraversalDirections(direction) {
|
|
1348
|
-
if (
|
|
886
|
+
if (isPropagationTraversalDirection2(direction)) {
|
|
1349
887
|
return [direction];
|
|
1350
888
|
}
|
|
1351
889
|
return ["outgoing", "incoming"];
|
|
1352
890
|
}
|
|
1353
891
|
|
|
1354
892
|
// src/confidencePropagationDispatch.ts
|
|
1355
|
-
function
|
|
1356
|
-
|
|
1357
|
-
return targetNodeId ?? void 0;
|
|
893
|
+
function nodeIdToCacheKey(nodeId) {
|
|
894
|
+
return String(nodeId);
|
|
1358
895
|
}
|
|
1359
896
|
function readNodeOpinion(node) {
|
|
1360
897
|
const metadata = node.metadata ?? {};
|
|
@@ -1370,118 +907,354 @@ function readNodeOpinion(node) {
|
|
|
1370
907
|
return mkOpinion(0, 0, 1, 0.5);
|
|
1371
908
|
}
|
|
1372
909
|
}
|
|
1373
|
-
|
|
1374
|
-
const
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
visitedNodeIds: /* @__PURE__ */ new Set([String(args.sourceNodeId)])
|
|
1384
|
-
}
|
|
1385
|
-
];
|
|
1386
|
-
const loadNode = async (nodeId) => {
|
|
1387
|
-
const cacheKey = String(nodeId);
|
|
1388
|
-
if (!nodeCache.has(cacheKey)) {
|
|
1389
|
-
nodeCache.set(cacheKey, await args.getNode(nodeId));
|
|
1390
|
-
}
|
|
1391
|
-
return nodeCache.get(cacheKey) ?? null;
|
|
910
|
+
function resolveTraversalTargetNodeId(edge, direction) {
|
|
911
|
+
const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
|
|
912
|
+
return targetNodeId ?? void 0;
|
|
913
|
+
}
|
|
914
|
+
function buildInitialState(sourceNodeId, sourceOpinion) {
|
|
915
|
+
return {
|
|
916
|
+
nodeId: sourceNodeId,
|
|
917
|
+
opinion: sourceOpinion,
|
|
918
|
+
hop: 0,
|
|
919
|
+
visitedNodeIds: /* @__PURE__ */ new Set([nodeIdToCacheKey(sourceNodeId)])
|
|
1392
920
|
};
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
921
|
+
}
|
|
922
|
+
function extendVisited(currentVisited, targetNodeId) {
|
|
923
|
+
return /* @__PURE__ */ new Set([...currentVisited, nodeIdToCacheKey(targetNodeId)]);
|
|
924
|
+
}
|
|
925
|
+
function makeTransitiveState(current, targetNodeId, projectedOpinion, nextHop) {
|
|
926
|
+
return {
|
|
927
|
+
nodeId: targetNodeId,
|
|
928
|
+
opinion: projectedOpinion,
|
|
929
|
+
hop: nextHop,
|
|
930
|
+
visitedNodeIds: extendVisited(current.visitedNodeIds, targetNodeId)
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
function makeDispatchRecord(targetNodeId, spec, direction, edge, projectedOpinion, nextHop, result, existingDispatch) {
|
|
934
|
+
return {
|
|
935
|
+
targetNodeId,
|
|
936
|
+
edgeType: spec.edgeType,
|
|
937
|
+
traversedDirection: direction,
|
|
938
|
+
weight: edge.weight ?? 1,
|
|
939
|
+
opinion: projectedOpinion,
|
|
940
|
+
operator: result.operator,
|
|
941
|
+
rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
|
|
942
|
+
hop: nextHop
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
async function loadCachedNode(scope, nodeId) {
|
|
946
|
+
const cacheKey = nodeIdToCacheKey(nodeId);
|
|
947
|
+
if (!scope.nodeCache.has(cacheKey)) {
|
|
948
|
+
scope.nodeCache.set(cacheKey, await scope.args.getNode(nodeId));
|
|
949
|
+
}
|
|
950
|
+
return scope.nodeCache.get(cacheKey) ?? null;
|
|
951
|
+
}
|
|
952
|
+
async function collectTargetDispatch(state, nextHop, spec, direction, edge, queue, scope) {
|
|
953
|
+
const sourceScope = scope.args.sourceScope;
|
|
954
|
+
if (sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, sourceScope)) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
|
|
958
|
+
if (!targetNodeId) {
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
const targetNodeIdKey = nodeIdToCacheKey(targetNodeId);
|
|
962
|
+
if (state.visitedNodeIds.has(targetNodeIdKey)) {
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
const targetNode = await loadCachedNode(scope, targetNodeId);
|
|
966
|
+
if (targetNode?.nodeType !== "belief") {
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
if (sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, sourceScope)) {
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
const targetOpinion = scope.opinionCache.get(targetNodeIdKey) ?? readNodeOpinion(targetNode);
|
|
973
|
+
const result = spec.operator(state.opinion, targetOpinion, edge, {
|
|
974
|
+
hop: nextHop,
|
|
975
|
+
sourceNodeId: state.nodeId,
|
|
976
|
+
targetNodeId,
|
|
977
|
+
traversedDirection: direction,
|
|
978
|
+
spec
|
|
979
|
+
});
|
|
980
|
+
if (!(result && hasProjectedOpinionChanged(targetOpinion, result.opinion))) {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
const projectedOpinion = mkOpinion(
|
|
984
|
+
result.opinion.b,
|
|
985
|
+
result.opinion.d,
|
|
986
|
+
result.opinion.u,
|
|
987
|
+
result.opinion.a
|
|
988
|
+
);
|
|
989
|
+
scope.opinionCache.set(targetNodeIdKey, projectedOpinion);
|
|
990
|
+
const existingDispatch = scope.dispatchesByTargetId.get(targetNodeIdKey);
|
|
991
|
+
scope.dispatchesByTargetId.set(
|
|
992
|
+
targetNodeIdKey,
|
|
993
|
+
makeDispatchRecord(
|
|
994
|
+
targetNodeId,
|
|
995
|
+
spec,
|
|
996
|
+
direction,
|
|
997
|
+
edge,
|
|
998
|
+
projectedOpinion,
|
|
999
|
+
nextHop,
|
|
1000
|
+
result,
|
|
1001
|
+
existingDispatch
|
|
1002
|
+
)
|
|
1003
|
+
);
|
|
1004
|
+
if (canContinueTransitively2(spec, nextHop)) {
|
|
1005
|
+
queue.push(
|
|
1006
|
+
makeTransitiveState(state, targetNodeId, projectedOpinion, nextHop)
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
async function processTraversalSpec(state, nextHop, spec, queue, scope) {
|
|
1011
|
+
const sourceNodeId = state.nodeId;
|
|
1012
|
+
for (const direction of getTraversalDirections(spec.direction)) {
|
|
1013
|
+
const edges = await scope.args.queryEdges({
|
|
1014
|
+
nodeId: sourceNodeId,
|
|
1015
|
+
spec,
|
|
1016
|
+
direction,
|
|
1017
|
+
hop: nextHop
|
|
1018
|
+
});
|
|
1019
|
+
for (const edge of edges) {
|
|
1020
|
+
await collectTargetDispatch(
|
|
1021
|
+
state,
|
|
1022
|
+
nextHop,
|
|
1023
|
+
spec,
|
|
1024
|
+
direction,
|
|
1025
|
+
edge,
|
|
1026
|
+
queue,
|
|
1027
|
+
scope
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
async function processQueuedState(state, queue, scope) {
|
|
1033
|
+
const nextHop = state.hop + 1;
|
|
1034
|
+
for (const spec of scope.traversalSpecs) {
|
|
1035
|
+
if (!canTraverseHop2(spec, nextHop)) {
|
|
1036
|
+
continue;
|
|
1471
1037
|
}
|
|
1038
|
+
await processTraversalSpec(state, nextHop, spec, queue, scope);
|
|
1472
1039
|
}
|
|
1473
|
-
|
|
1040
|
+
}
|
|
1041
|
+
function sortDispatches(dispatches) {
|
|
1042
|
+
return Array.from(dispatches).sort((left, right) => {
|
|
1474
1043
|
if (left.hop !== right.hop) {
|
|
1475
1044
|
return left.hop - right.hop;
|
|
1476
1045
|
}
|
|
1477
1046
|
return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
|
|
1478
1047
|
});
|
|
1479
1048
|
}
|
|
1049
|
+
async function collectConfidencePropagationDispatches(args) {
|
|
1050
|
+
const dispatchesByTargetId = /* @__PURE__ */ new Map();
|
|
1051
|
+
const opinionCache = /* @__PURE__ */ new Map();
|
|
1052
|
+
const nodeCache = /* @__PURE__ */ new Map();
|
|
1053
|
+
const traversalSpecs = args.traversalSpecs ?? getEdgePropagationSpecs();
|
|
1054
|
+
const scope = {
|
|
1055
|
+
args,
|
|
1056
|
+
dispatchesByTargetId,
|
|
1057
|
+
opinionCache,
|
|
1058
|
+
nodeCache,
|
|
1059
|
+
traversalSpecs
|
|
1060
|
+
};
|
|
1061
|
+
const queue = [
|
|
1062
|
+
buildInitialState(args.sourceNodeId, args.sourceOpinion)
|
|
1063
|
+
];
|
|
1064
|
+
while (queue.length > 0) {
|
|
1065
|
+
const state = queue.shift();
|
|
1066
|
+
if (!state) {
|
|
1067
|
+
continue;
|
|
1068
|
+
}
|
|
1069
|
+
await processQueuedState(state, queue, scope);
|
|
1070
|
+
}
|
|
1071
|
+
return sortDispatches(dispatchesByTargetId.values());
|
|
1072
|
+
}
|
|
1480
1073
|
|
|
1481
1074
|
// src/epistemicBeliefs.confidence.ts
|
|
1075
|
+
function isRecord(value) {
|
|
1076
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1077
|
+
}
|
|
1078
|
+
function readConvexId(value) {
|
|
1079
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1080
|
+
}
|
|
1081
|
+
function readOptionalBoolean(value) {
|
|
1082
|
+
return typeof value === "boolean" ? value : void 0;
|
|
1083
|
+
}
|
|
1084
|
+
function readOptionalNumber(value) {
|
|
1085
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1086
|
+
}
|
|
1087
|
+
function readOptionalString(value) {
|
|
1088
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1089
|
+
}
|
|
1090
|
+
function readRecord(value) {
|
|
1091
|
+
return isRecord(value) ? value : void 0;
|
|
1092
|
+
}
|
|
1093
|
+
function readConfidenceBeliefNode(value) {
|
|
1094
|
+
if (!isRecord(value)) {
|
|
1095
|
+
return null;
|
|
1096
|
+
}
|
|
1097
|
+
const id = readConvexId(value._id);
|
|
1098
|
+
const nodeType = readOptionalString(value.nodeType);
|
|
1099
|
+
const projectId = readOptionalString(value.projectId);
|
|
1100
|
+
if (!(id && nodeType === "belief" && projectId)) {
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
const node = {
|
|
1104
|
+
_id: id,
|
|
1105
|
+
nodeType,
|
|
1106
|
+
projectId
|
|
1107
|
+
};
|
|
1108
|
+
const confidence = readOptionalNumber(value.confidence);
|
|
1109
|
+
const epistemicLayer = readOptionalString(value.epistemicLayer);
|
|
1110
|
+
const globalId = readOptionalString(value.globalId);
|
|
1111
|
+
const metadata = readRecord(value.metadata);
|
|
1112
|
+
const opinionA = readOptionalNumber(value.opinion_a);
|
|
1113
|
+
const opinionB = readOptionalNumber(value.opinion_b);
|
|
1114
|
+
const opinionD = readOptionalNumber(value.opinion_d);
|
|
1115
|
+
const opinionU = readOptionalNumber(value.opinion_u);
|
|
1116
|
+
const predictionMeta = readRecord(value.predictionMeta);
|
|
1117
|
+
const publicationStatus = readOptionalString(value.publicationStatus);
|
|
1118
|
+
const status = readOptionalString(value.status);
|
|
1119
|
+
const tenantId = readOptionalString(value.tenantId);
|
|
1120
|
+
const topicId = readOptionalString(value.topicId);
|
|
1121
|
+
const tupleContradicted = readOptionalBoolean(value.tupleContradicted);
|
|
1122
|
+
const workspaceId = readOptionalString(value.workspaceId);
|
|
1123
|
+
if (confidence !== void 0) {
|
|
1124
|
+
node.confidence = confidence;
|
|
1125
|
+
}
|
|
1126
|
+
if (epistemicLayer !== void 0) {
|
|
1127
|
+
node.epistemicLayer = epistemicLayer;
|
|
1128
|
+
}
|
|
1129
|
+
if (globalId !== void 0) {
|
|
1130
|
+
node.globalId = globalId;
|
|
1131
|
+
}
|
|
1132
|
+
if (metadata !== void 0) {
|
|
1133
|
+
node.metadata = metadata;
|
|
1134
|
+
}
|
|
1135
|
+
if (opinionA !== void 0) {
|
|
1136
|
+
node.opinion_a = opinionA;
|
|
1137
|
+
}
|
|
1138
|
+
if (opinionB !== void 0) {
|
|
1139
|
+
node.opinion_b = opinionB;
|
|
1140
|
+
}
|
|
1141
|
+
if (opinionD !== void 0) {
|
|
1142
|
+
node.opinion_d = opinionD;
|
|
1143
|
+
}
|
|
1144
|
+
if (opinionU !== void 0) {
|
|
1145
|
+
node.opinion_u = opinionU;
|
|
1146
|
+
}
|
|
1147
|
+
if (predictionMeta !== void 0) {
|
|
1148
|
+
node.predictionMeta = predictionMeta;
|
|
1149
|
+
}
|
|
1150
|
+
if (publicationStatus !== void 0) {
|
|
1151
|
+
node.publicationStatus = publicationStatus;
|
|
1152
|
+
}
|
|
1153
|
+
if (status !== void 0) {
|
|
1154
|
+
node.status = status;
|
|
1155
|
+
}
|
|
1156
|
+
if (tenantId !== void 0) {
|
|
1157
|
+
node.tenantId = tenantId;
|
|
1158
|
+
}
|
|
1159
|
+
if (topicId !== void 0) {
|
|
1160
|
+
node.topicId = topicId;
|
|
1161
|
+
}
|
|
1162
|
+
if (tupleContradicted !== void 0) {
|
|
1163
|
+
node.tupleContradicted = tupleContradicted;
|
|
1164
|
+
}
|
|
1165
|
+
if (workspaceId !== void 0) {
|
|
1166
|
+
node.workspaceId = workspaceId;
|
|
1167
|
+
}
|
|
1168
|
+
return node;
|
|
1169
|
+
}
|
|
1170
|
+
function readPropagationEdge(value) {
|
|
1171
|
+
if (!isRecord(value)) {
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
const edgeType = readOptionalString(value.edgeType);
|
|
1175
|
+
if (!edgeType) {
|
|
1176
|
+
return null;
|
|
1177
|
+
}
|
|
1178
|
+
const edge = { edgeType };
|
|
1179
|
+
const fromNodeId = readConvexId(value.fromNodeId);
|
|
1180
|
+
const tenantId = readOptionalString(value.tenantId);
|
|
1181
|
+
const toNodeId = readConvexId(value.toNodeId);
|
|
1182
|
+
const weight = readOptionalNumber(value.weight);
|
|
1183
|
+
const workspaceId = readOptionalString(value.workspaceId);
|
|
1184
|
+
if (fromNodeId !== void 0) {
|
|
1185
|
+
edge.fromNodeId = fromNodeId;
|
|
1186
|
+
}
|
|
1187
|
+
if (tenantId !== void 0) {
|
|
1188
|
+
edge.tenantId = tenantId;
|
|
1189
|
+
}
|
|
1190
|
+
if (toNodeId !== void 0) {
|
|
1191
|
+
edge.toNodeId = toNodeId;
|
|
1192
|
+
}
|
|
1193
|
+
if (weight !== void 0) {
|
|
1194
|
+
edge.weight = weight;
|
|
1195
|
+
}
|
|
1196
|
+
if (workspaceId !== void 0) {
|
|
1197
|
+
edge.workspaceId = workspaceId;
|
|
1198
|
+
}
|
|
1199
|
+
return edge;
|
|
1200
|
+
}
|
|
1201
|
+
function readRowList(values, reader) {
|
|
1202
|
+
return values.flatMap((value) => {
|
|
1203
|
+
const row = reader(value);
|
|
1204
|
+
return row ? [row] : [];
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1482
1207
|
async function applyBeliefConfidenceChange(ctx, args) {
|
|
1483
1208
|
const now = Date.now();
|
|
1484
|
-
const node = await ctx
|
|
1209
|
+
const node = await requireConfidenceBeliefNode(ctx, args);
|
|
1210
|
+
const state = await buildConfidenceChangeState(ctx, node, args);
|
|
1211
|
+
await assertConfidenceScoringPolicySatisfied(ctx, args, state);
|
|
1212
|
+
const tupleContradictionId = await createTupleContradictionIfNeeded(
|
|
1213
|
+
ctx,
|
|
1214
|
+
args,
|
|
1215
|
+
node,
|
|
1216
|
+
state
|
|
1217
|
+
);
|
|
1218
|
+
await patchBeliefConfidenceState(ctx, args, state);
|
|
1219
|
+
await scheduleFirstScoringThemeEdges(ctx, args, node, state);
|
|
1220
|
+
const beliefConfidenceId = await insertBeliefConfidenceRecord(
|
|
1221
|
+
ctx,
|
|
1222
|
+
args,
|
|
1223
|
+
state,
|
|
1224
|
+
tupleContradictionId,
|
|
1225
|
+
now
|
|
1226
|
+
);
|
|
1227
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1228
|
+
nodeId: args.nodeId,
|
|
1229
|
+
operation: "upsert"
|
|
1230
|
+
});
|
|
1231
|
+
await insertConfidenceAudit(
|
|
1232
|
+
ctx,
|
|
1233
|
+
args,
|
|
1234
|
+
node,
|
|
1235
|
+
state,
|
|
1236
|
+
tupleContradictionId,
|
|
1237
|
+
now
|
|
1238
|
+
);
|
|
1239
|
+
await insertTupleTransitionAuditIfNeeded(
|
|
1240
|
+
ctx,
|
|
1241
|
+
args,
|
|
1242
|
+
node,
|
|
1243
|
+
state,
|
|
1244
|
+
tupleContradictionId,
|
|
1245
|
+
now
|
|
1246
|
+
);
|
|
1247
|
+
await scheduleConfidenceFollowups(ctx, args, node, state);
|
|
1248
|
+
return {
|
|
1249
|
+
nodeId: args.nodeId,
|
|
1250
|
+
previousConfidence: state.previousConfidence,
|
|
1251
|
+
newConfidence: state.derivedConfidence,
|
|
1252
|
+
opinion: state.nextOpinion,
|
|
1253
|
+
beliefConfidenceId
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
async function requireConfidenceBeliefNode(ctx, args) {
|
|
1257
|
+
const node = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
|
|
1485
1258
|
if (!node) {
|
|
1486
1259
|
throwStructuredMutationError({
|
|
1487
1260
|
message: "Node not found.",
|
|
@@ -1492,59 +1265,28 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1492
1265
|
details: { nodeId: args.nodeId }
|
|
1493
1266
|
});
|
|
1494
1267
|
}
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
invariantCode: "entity.no_confidence",
|
|
1501
|
-
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
|
|
1502
|
-
details: { nodeId: args.nodeId, nodeType: node.nodeType }
|
|
1503
|
-
});
|
|
1504
|
-
}
|
|
1505
|
-
if (!node.projectId) {
|
|
1506
|
-
throwStructuredMutationError({
|
|
1507
|
-
message: "Belief has no project scope.",
|
|
1508
|
-
status: 400,
|
|
1509
|
-
code: "MISSING_SCOPE",
|
|
1510
|
-
invariantCode: "belief.project_required",
|
|
1511
|
-
suggestion: "Belief must have a projectId before SL scoring can be appended.",
|
|
1512
|
-
details: { nodeId: args.nodeId }
|
|
1513
|
-
});
|
|
1514
|
-
}
|
|
1515
|
-
await requireProjectWriteAccess(
|
|
1516
|
-
ctx,
|
|
1517
|
-
node.projectId,
|
|
1518
|
-
args.authenticatedUserId
|
|
1519
|
-
);
|
|
1520
|
-
const existingMetadata = node.metadata || {};
|
|
1268
|
+
await requireScopeWriteAccess(ctx, node.projectId, args.authenticatedUserId);
|
|
1269
|
+
return node;
|
|
1270
|
+
}
|
|
1271
|
+
async function buildConfidenceChangeState(ctx, node, args) {
|
|
1272
|
+
const existingMetadata = readNodeMetadata(node);
|
|
1521
1273
|
const currentBeliefStatus = resolveBeliefStatus(node, existingMetadata);
|
|
1522
1274
|
const confidencePolicy = await getActiveConfidencePolicy(ctx);
|
|
1523
|
-
if (confidencePolicy.scoringMode === "after_worktree" && isPreValidationBeliefStatus(currentBeliefStatus)) {
|
|
1524
|
-
const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
|
|
1525
|
-
ctx,
|
|
1526
|
-
args.nodeId
|
|
1527
|
-
);
|
|
1528
|
-
if (!hasCompletedWorktree) {
|
|
1529
|
-
throwStructuredMutationError({
|
|
1530
|
-
message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
|
|
1531
|
-
status: 409,
|
|
1532
|
-
code: "CONFLICT",
|
|
1533
|
-
invariantCode: "belief.confidence_append_only",
|
|
1534
|
-
suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
|
|
1535
|
-
details: { nodeId: args.nodeId }
|
|
1536
|
-
});
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
1275
|
const previousConfidence = node.confidence || 0.5;
|
|
1540
1276
|
const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
|
|
1541
1277
|
const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
|
|
1542
|
-
const
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1278
|
+
const nextOpinion = {
|
|
1279
|
+
b: args.belief,
|
|
1280
|
+
d: args.disbelief,
|
|
1281
|
+
u: args.uncertainty,
|
|
1282
|
+
a: args.baseRate ?? 0.5
|
|
1283
|
+
};
|
|
1284
|
+
const derivedConfidence = confidenceFromSL(
|
|
1285
|
+
nextOpinion.b,
|
|
1286
|
+
nextOpinion.d,
|
|
1287
|
+
nextOpinion.u,
|
|
1288
|
+
nextOpinion.a
|
|
1289
|
+
);
|
|
1548
1290
|
const isFirstScoring = typeof node.confidence !== "number" || !Number.isFinite(node.confidence);
|
|
1549
1291
|
const previousTupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(existingMetadata.tupleContradicted) ?? detectTupleContradiction(
|
|
1550
1292
|
previousOpinion,
|
|
@@ -1565,79 +1307,121 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1565
1307
|
predictionMeta,
|
|
1566
1308
|
metadata: existingMetadata
|
|
1567
1309
|
});
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1310
|
+
const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
|
|
1311
|
+
return {
|
|
1312
|
+
confidencePolicy,
|
|
1313
|
+
currentBeliefStatus,
|
|
1314
|
+
derivedConfidence,
|
|
1315
|
+
existingMetadata,
|
|
1316
|
+
isFirstScoring,
|
|
1317
|
+
newBeliefStatus,
|
|
1318
|
+
nextOpinion,
|
|
1319
|
+
previousConfidence,
|
|
1320
|
+
previousTupleContradicted,
|
|
1321
|
+
storedRationale,
|
|
1322
|
+
tupleContradictionDescription,
|
|
1323
|
+
tupleTransition
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
function readNodeMetadata(node) {
|
|
1327
|
+
return node.metadata ?? {};
|
|
1328
|
+
}
|
|
1329
|
+
async function assertConfidenceScoringPolicySatisfied(ctx, args, state) {
|
|
1330
|
+
if (state.confidencePolicy.scoringMode !== "after_worktree" || !isPreValidationBeliefStatus(state.currentBeliefStatus)) {
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
|
|
1334
|
+
ctx,
|
|
1335
|
+
args.nodeId
|
|
1336
|
+
);
|
|
1337
|
+
if (hasCompletedWorktree) {
|
|
1338
|
+
return;
|
|
1586
1339
|
}
|
|
1340
|
+
throwStructuredMutationError({
|
|
1341
|
+
message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
|
|
1342
|
+
status: 409,
|
|
1343
|
+
code: "CONFLICT",
|
|
1344
|
+
invariantCode: "belief.confidence_append_only",
|
|
1345
|
+
suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
|
|
1346
|
+
details: { nodeId: args.nodeId }
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
async function createTupleContradictionIfNeeded(ctx, args, node, state) {
|
|
1350
|
+
if (!state.tupleTransition.crossedIntoTupleContradiction) {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
return await ctx.runMutation("contradictions:create", {
|
|
1354
|
+
projectId: node.projectId,
|
|
1355
|
+
topicId: node.topicId,
|
|
1356
|
+
beliefId: args.nodeId,
|
|
1357
|
+
beliefBId: args.nodeId,
|
|
1358
|
+
supportingInsightIds: [],
|
|
1359
|
+
contradictingInsightIds: [],
|
|
1360
|
+
severity: deriveTupleContradictionSeverity(node),
|
|
1361
|
+
source: "tuple_space",
|
|
1362
|
+
detectionMethod: "agent",
|
|
1363
|
+
description: state.tupleContradictionDescription,
|
|
1364
|
+
createdBy: args.authenticatedUserId
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
async function patchBeliefConfidenceState(ctx, args, state) {
|
|
1587
1368
|
await ctx.db.patch(args.nodeId, {
|
|
1588
|
-
confidence: derivedConfidence,
|
|
1589
|
-
beliefStatus: newBeliefStatus,
|
|
1590
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1591
|
-
updatedAt: now,
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
opinion_a: slA,
|
|
1369
|
+
confidence: state.derivedConfidence,
|
|
1370
|
+
beliefStatus: state.newBeliefStatus,
|
|
1371
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1372
|
+
updatedAt: Date.now(),
|
|
1373
|
+
opinion_b: state.nextOpinion.b,
|
|
1374
|
+
opinion_d: state.nextOpinion.d,
|
|
1375
|
+
opinion_u: state.nextOpinion.u,
|
|
1376
|
+
opinion_a: state.nextOpinion.a,
|
|
1597
1377
|
metadata: {
|
|
1598
|
-
...existingMetadata,
|
|
1599
|
-
beliefStatus: newBeliefStatus,
|
|
1600
|
-
slBelief:
|
|
1601
|
-
slDisbelief:
|
|
1602
|
-
slUncertainty:
|
|
1603
|
-
slBaseRate:
|
|
1604
|
-
tupleContradicted: tupleTransition.tupleContradicted
|
|
1378
|
+
...state.existingMetadata,
|
|
1379
|
+
beliefStatus: state.newBeliefStatus,
|
|
1380
|
+
slBelief: state.nextOpinion.b,
|
|
1381
|
+
slDisbelief: state.nextOpinion.d,
|
|
1382
|
+
slUncertainty: state.nextOpinion.u,
|
|
1383
|
+
slBaseRate: state.nextOpinion.a,
|
|
1384
|
+
tupleContradicted: state.tupleTransition.tupleContradicted
|
|
1605
1385
|
}
|
|
1606
1386
|
});
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
edgeType: "relates_to_thesis",
|
|
1620
|
-
weight: derivedConfidence,
|
|
1621
|
-
createdBy: args.authenticatedUserId,
|
|
1622
|
-
topicId: String(node.projectId),
|
|
1623
|
-
fromNodeType: "belief",
|
|
1624
|
-
toNodeType: "theme",
|
|
1625
|
-
fromLayer: "L3",
|
|
1626
|
-
toLayer: "L3"
|
|
1627
|
-
});
|
|
1628
|
-
}
|
|
1387
|
+
}
|
|
1388
|
+
async function scheduleFirstScoringThemeEdges(ctx, args, node, state) {
|
|
1389
|
+
if (!state.isFirstScoring) {
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
1393
|
+
"by_topic",
|
|
1394
|
+
(q) => q.eq("topicId", node.topicId || node.projectId)
|
|
1395
|
+
).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
|
|
1396
|
+
for (const theme of themeNodes) {
|
|
1397
|
+
if (!(theme.globalId && node.globalId)) {
|
|
1398
|
+
continue;
|
|
1629
1399
|
}
|
|
1400
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
1401
|
+
globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
|
|
1402
|
+
fromGlobalId: node.globalId,
|
|
1403
|
+
toGlobalId: theme.globalId,
|
|
1404
|
+
edgeType: "relates_to_thesis",
|
|
1405
|
+
weight: state.derivedConfidence,
|
|
1406
|
+
createdBy: args.authenticatedUserId,
|
|
1407
|
+
topicId: String(node.projectId),
|
|
1408
|
+
fromNodeType: "belief",
|
|
1409
|
+
toNodeType: "theme",
|
|
1410
|
+
fromLayer: "L3",
|
|
1411
|
+
toLayer: "L3"
|
|
1412
|
+
});
|
|
1630
1413
|
}
|
|
1631
|
-
|
|
1632
|
-
|
|
1414
|
+
}
|
|
1415
|
+
async function insertBeliefConfidenceRecord(ctx, args, state, tupleContradictionId, now) {
|
|
1416
|
+
return await ctx.db.insert("beliefConfidence", {
|
|
1633
1417
|
...buildBeliefConfidenceRow({
|
|
1634
1418
|
beliefId: args.nodeId,
|
|
1635
|
-
belief:
|
|
1636
|
-
disbelief:
|
|
1637
|
-
uncertainty:
|
|
1638
|
-
baseRate:
|
|
1419
|
+
belief: state.nextOpinion.b,
|
|
1420
|
+
disbelief: state.nextOpinion.d,
|
|
1421
|
+
uncertainty: state.nextOpinion.u,
|
|
1422
|
+
baseRate: state.nextOpinion.a,
|
|
1639
1423
|
trigger: args.trigger,
|
|
1640
|
-
rationale: storedRationale,
|
|
1424
|
+
rationale: state.storedRationale,
|
|
1641
1425
|
assessedBy: args.authenticatedUserId,
|
|
1642
1426
|
assessedAt: now,
|
|
1643
1427
|
slOperator: args.slOperator,
|
|
@@ -1646,25 +1430,23 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1646
1430
|
triggeringWorktreeId: args.triggeringWorktreeId
|
|
1647
1431
|
})
|
|
1648
1432
|
});
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
operation: "upsert"
|
|
1652
|
-
});
|
|
1433
|
+
}
|
|
1434
|
+
async function insertConfidenceAudit(ctx, args, node, state, tupleContradictionId, now) {
|
|
1653
1435
|
await ctx.db.insert("epistemicAudit", {
|
|
1654
1436
|
entityType: "belief",
|
|
1655
1437
|
entityId: args.nodeId,
|
|
1656
1438
|
changeType: "confidence_changed",
|
|
1657
1439
|
previousState: {
|
|
1658
|
-
confidence: previousConfidence,
|
|
1659
|
-
tupleContradicted: previousTupleContradicted
|
|
1440
|
+
confidence: state.previousConfidence,
|
|
1441
|
+
tupleContradicted: state.previousTupleContradicted
|
|
1660
1442
|
},
|
|
1661
1443
|
newState: {
|
|
1662
|
-
opinion: nextOpinion,
|
|
1663
|
-
confidence: derivedConfidence,
|
|
1444
|
+
opinion: state.nextOpinion,
|
|
1445
|
+
confidence: state.derivedConfidence,
|
|
1664
1446
|
trigger: args.trigger,
|
|
1665
|
-
rationale: storedRationale,
|
|
1666
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1667
|
-
tupleContradictionPolicy: tupleTransition.policy,
|
|
1447
|
+
rationale: state.storedRationale,
|
|
1448
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1449
|
+
tupleContradictionPolicy: state.tupleTransition.policy,
|
|
1668
1450
|
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1669
1451
|
},
|
|
1670
1452
|
changedBy: args.authenticatedUserId,
|
|
@@ -1673,28 +1455,39 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1673
1455
|
projectId: node.projectId,
|
|
1674
1456
|
topicId: node.topicId
|
|
1675
1457
|
});
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1458
|
+
}
|
|
1459
|
+
async function insertTupleTransitionAuditIfNeeded(ctx, args, node, state, tupleContradictionId, now) {
|
|
1460
|
+
if (!(state.tupleTransition.crossedIntoTupleContradiction || state.tupleTransition.crossedOutOfTupleContradiction)) {
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1464
|
+
entityType: "belief",
|
|
1465
|
+
entityId: args.nodeId,
|
|
1466
|
+
changeType: "updated",
|
|
1467
|
+
previousState: { tupleContradicted: state.previousTupleContradicted },
|
|
1468
|
+
newState: {
|
|
1469
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1470
|
+
action: state.tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
|
|
1471
|
+
opinion: state.nextOpinion,
|
|
1472
|
+
tupleContradictionPolicy: state.tupleTransition.policy,
|
|
1473
|
+
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1474
|
+
},
|
|
1475
|
+
rationale: tupleAuditRationale(state),
|
|
1476
|
+
changedBy: args.authenticatedUserId,
|
|
1477
|
+
isAgent: false,
|
|
1478
|
+
changedAt: now,
|
|
1479
|
+
projectId: node.projectId,
|
|
1480
|
+
topicId: node.topicId
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
function tupleAuditRationale(state) {
|
|
1484
|
+
if (state.tupleTransition.crossedIntoTupleContradiction) {
|
|
1485
|
+
return state.tupleContradictionDescription;
|
|
1696
1486
|
}
|
|
1697
|
-
|
|
1487
|
+
return `Tuple-space contradiction cleared: b=${state.nextOpinion.b.toFixed(2)}, d=${state.nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`;
|
|
1488
|
+
}
|
|
1489
|
+
async function scheduleConfidenceFollowups(ctx, args, node, state) {
|
|
1490
|
+
if (Math.abs(state.derivedConfidence - state.previousConfidence) >= 0.15) {
|
|
1698
1491
|
await ctx.scheduler.runAfter(
|
|
1699
1492
|
5e3,
|
|
1700
1493
|
internal.bi.contradictionSemanticDetector.scanAffectedBeliefs,
|
|
@@ -1711,13 +1504,6 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1711
1504
|
{ nodeId: args.nodeId }
|
|
1712
1505
|
);
|
|
1713
1506
|
}
|
|
1714
|
-
return {
|
|
1715
|
-
nodeId: args.nodeId,
|
|
1716
|
-
previousConfidence,
|
|
1717
|
-
newConfidence: derivedConfidence,
|
|
1718
|
-
opinion: { b: slB, d: slD, u: slU, a: slA },
|
|
1719
|
-
beliefConfidenceId
|
|
1720
|
-
};
|
|
1721
1507
|
}
|
|
1722
1508
|
function propagationPressureLabel(edgeType, weight) {
|
|
1723
1509
|
if (edgeType === "contradicts" || edgeType === "refutes") {
|
|
@@ -1745,7 +1531,7 @@ internalMutation({
|
|
|
1745
1531
|
args.opinion_u,
|
|
1746
1532
|
args.opinion_a
|
|
1747
1533
|
);
|
|
1748
|
-
const sourceNode = await ctx.db.get(args.nodeId);
|
|
1534
|
+
const sourceNode = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
|
|
1749
1535
|
const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
|
|
1750
1536
|
ctx,
|
|
1751
1537
|
sourceNode
|
|
@@ -1754,16 +1540,20 @@ internalMutation({
|
|
|
1754
1540
|
sourceNodeId: args.nodeId,
|
|
1755
1541
|
sourceOpinion,
|
|
1756
1542
|
sourceScope,
|
|
1757
|
-
queryEdges: async ({ nodeId, spec, direction }) =>
|
|
1758
|
-
|
|
1543
|
+
queryEdges: async ({ nodeId, spec, direction }) => readRowList(
|
|
1544
|
+
await ctx.db.query("epistemicEdges").withIndex(
|
|
1759
1545
|
direction === "outgoing" ? "by_from_type" : "by_to_type",
|
|
1760
1546
|
(q) => direction === "outgoing" ? q.eq("fromNodeId", nodeId).eq("edgeType", spec.edgeType) : q.eq("toNodeId", nodeId).eq("edgeType", spec.edgeType)
|
|
1761
|
-
).collect()
|
|
1762
|
-
|
|
1763
|
-
|
|
1547
|
+
).collect(),
|
|
1548
|
+
readPropagationEdge
|
|
1549
|
+
),
|
|
1550
|
+
getNode: async (nodeId) => readConfidenceBeliefNode(await ctx.db.get(nodeId))
|
|
1764
1551
|
});
|
|
1765
1552
|
for (const dispatch of dispatches) {
|
|
1766
|
-
const pressureLabel = propagationPressureLabel(
|
|
1553
|
+
const pressureLabel = propagationPressureLabel(
|
|
1554
|
+
dispatch.edgeType,
|
|
1555
|
+
dispatch.weight
|
|
1556
|
+
);
|
|
1767
1557
|
await applyBeliefConfidenceChange(ctx, {
|
|
1768
1558
|
nodeId: dispatch.targetNodeId,
|
|
1769
1559
|
belief: dispatch.opinion.b,
|
|
@@ -1787,253 +1577,645 @@ internalMutation({
|
|
|
1787
1577
|
}
|
|
1788
1578
|
});
|
|
1789
1579
|
|
|
1790
|
-
// src/epistemicContracts.
|
|
1791
|
-
var
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
var
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
if (evaluatorRegistry.has(name)) {
|
|
1801
|
-
continue;
|
|
1802
|
-
}
|
|
1803
|
-
evaluatorRegistry.set(name, {
|
|
1804
|
-
name,
|
|
1805
|
-
evaluate: evaluateBuiltInEvidentialContract
|
|
1806
|
-
});
|
|
1580
|
+
// src/epistemicContracts.metrics.ts
|
|
1581
|
+
var ACTIVE_CONTRADICTION_STATUSES = /* @__PURE__ */ new Set([
|
|
1582
|
+
"unresolved",
|
|
1583
|
+
"investigating",
|
|
1584
|
+
"accepted_as_permanent"
|
|
1585
|
+
]);
|
|
1586
|
+
var DEPENDENT_EDGE_TYPES = /* @__PURE__ */ new Set(["depends_on"]);
|
|
1587
|
+
function classifyContradictionStatus(status) {
|
|
1588
|
+
if (typeof status !== "string") {
|
|
1589
|
+
return "active";
|
|
1807
1590
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
continue;
|
|
1811
|
-
}
|
|
1812
|
-
evaluatorRegistry.set(evaluator.name, evaluator);
|
|
1591
|
+
if (ACTIVE_CONTRADICTION_STATUSES.has(status)) {
|
|
1592
|
+
return "active";
|
|
1813
1593
|
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
[BUILT_IN_REFERENCE_CHECK_COUNTER2, evaluateReferenceCheckCounterContract],
|
|
1817
|
-
[BUILT_IN_TEMPORAL_DEADLINE2, evaluateTemporalDeadlineContract],
|
|
1818
|
-
[BUILT_IN_MARKET_INDEX_COMPARATOR2, evaluateMarketIndexComparatorContract]
|
|
1819
|
-
];
|
|
1820
|
-
for (const [name, evaluate] of researchEvaluators) {
|
|
1821
|
-
if (evaluatorRegistry.has(name)) {
|
|
1822
|
-
continue;
|
|
1823
|
-
}
|
|
1824
|
-
evaluatorRegistry.set(name, { name, evaluate });
|
|
1594
|
+
if (status === "resolved_support" || status === "resolved_contra" || status === "belief_forked") {
|
|
1595
|
+
return "resolved";
|
|
1825
1596
|
}
|
|
1597
|
+
return "resolved";
|
|
1826
1598
|
}
|
|
1827
|
-
function
|
|
1828
|
-
|
|
1829
|
-
|
|
1599
|
+
function isRecord2(value) {
|
|
1600
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1601
|
+
}
|
|
1602
|
+
function readOptionalNumber2(value) {
|
|
1603
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1604
|
+
}
|
|
1605
|
+
function readOptionalString2(value) {
|
|
1606
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1607
|
+
}
|
|
1608
|
+
function readConvexId2(value) {
|
|
1609
|
+
const normalized = readOptionalString2(value);
|
|
1610
|
+
return normalized;
|
|
1611
|
+
}
|
|
1612
|
+
function readMetricNodeDoc(value) {
|
|
1613
|
+
if (!isRecord2(value)) {
|
|
1614
|
+
return null;
|
|
1830
1615
|
}
|
|
1831
|
-
|
|
1832
|
-
|
|
1616
|
+
const id = readConvexId2(value._id);
|
|
1617
|
+
const nodeType = readOptionalString2(value.nodeType);
|
|
1618
|
+
if (!(id && nodeType)) {
|
|
1619
|
+
return null;
|
|
1833
1620
|
}
|
|
1834
|
-
|
|
1835
|
-
|
|
1621
|
+
const node = { _id: id, nodeType };
|
|
1622
|
+
const globalId = readOptionalString2(value.globalId);
|
|
1623
|
+
if (globalId !== void 0) {
|
|
1624
|
+
node.globalId = globalId;
|
|
1836
1625
|
}
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
function resolveSchedulesForTrigger(trigger) {
|
|
1840
|
-
if (trigger === "evidence_added") {
|
|
1841
|
-
return /* @__PURE__ */ new Set(["on_evidence", "event_driven"]);
|
|
1626
|
+
if ("metadata" in value) {
|
|
1627
|
+
node.metadata = value.metadata;
|
|
1842
1628
|
}
|
|
1843
|
-
|
|
1844
|
-
|
|
1629
|
+
const status = readOptionalString2(value.status);
|
|
1630
|
+
if (status !== void 0) {
|
|
1631
|
+
node.status = status;
|
|
1845
1632
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1633
|
+
return node;
|
|
1634
|
+
}
|
|
1635
|
+
function readIncomingEdgeRow(value) {
|
|
1636
|
+
if (!isRecord2(value)) {
|
|
1637
|
+
return null;
|
|
1848
1638
|
}
|
|
1849
|
-
|
|
1639
|
+
const fromNodeId = readOptionalString2(value.fromNodeId);
|
|
1640
|
+
if (!fromNodeId) {
|
|
1641
|
+
return null;
|
|
1642
|
+
}
|
|
1643
|
+
const edge = { fromNodeId };
|
|
1644
|
+
const id = readConvexId2(value._id);
|
|
1645
|
+
if (id !== void 0) {
|
|
1646
|
+
edge._id = id;
|
|
1647
|
+
}
|
|
1648
|
+
const edgeType = readOptionalString2(value.edgeType);
|
|
1649
|
+
if (edgeType !== void 0) {
|
|
1650
|
+
edge.edgeType = edgeType;
|
|
1651
|
+
}
|
|
1652
|
+
const fromGlobalId = readOptionalString2(value.fromGlobalId);
|
|
1653
|
+
if (fromGlobalId !== void 0) {
|
|
1654
|
+
edge.fromGlobalId = fromGlobalId;
|
|
1655
|
+
}
|
|
1656
|
+
const fromUuid = readOptionalString2(value.fromUuid);
|
|
1657
|
+
if (fromUuid !== void 0) {
|
|
1658
|
+
edge.fromUuid = fromUuid;
|
|
1659
|
+
}
|
|
1660
|
+
const sourceGlobalId = readOptionalString2(value.sourceGlobalId);
|
|
1661
|
+
if (sourceGlobalId !== void 0) {
|
|
1662
|
+
edge.sourceGlobalId = sourceGlobalId;
|
|
1663
|
+
}
|
|
1664
|
+
const targetGlobalId = readOptionalString2(value.targetGlobalId);
|
|
1665
|
+
if (targetGlobalId !== void 0) {
|
|
1666
|
+
edge.targetGlobalId = targetGlobalId;
|
|
1667
|
+
}
|
|
1668
|
+
const toGlobalId = readOptionalString2(value.toGlobalId);
|
|
1669
|
+
if (toGlobalId !== void 0) {
|
|
1670
|
+
edge.toGlobalId = toGlobalId;
|
|
1671
|
+
}
|
|
1672
|
+
const toNodeId = readOptionalString2(value.toNodeId);
|
|
1673
|
+
if (toNodeId !== void 0) {
|
|
1674
|
+
edge.toNodeId = toNodeId;
|
|
1675
|
+
}
|
|
1676
|
+
const toUuid = readOptionalString2(value.toUuid);
|
|
1677
|
+
if (toUuid !== void 0) {
|
|
1678
|
+
edge.toUuid = toUuid;
|
|
1679
|
+
}
|
|
1680
|
+
const weight = readOptionalNumber2(value.weight);
|
|
1681
|
+
if (weight !== void 0) {
|
|
1682
|
+
edge.weight = weight;
|
|
1683
|
+
}
|
|
1684
|
+
for (const timestampField of ["_creationTime", "createdAt", "updatedAt"]) {
|
|
1685
|
+
const timestamp = readOptionalNumber2(value[timestampField]);
|
|
1686
|
+
if (timestamp !== void 0) {
|
|
1687
|
+
edge[timestampField] = timestamp;
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
return edge;
|
|
1850
1691
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
if (
|
|
1692
|
+
function getEdgeTimestamp(edge) {
|
|
1693
|
+
if (typeof edge.updatedAt === "number") {
|
|
1694
|
+
return edge.updatedAt;
|
|
1695
|
+
}
|
|
1696
|
+
if (typeof edge.createdAt === "number") {
|
|
1697
|
+
return edge.createdAt;
|
|
1698
|
+
}
|
|
1699
|
+
if (typeof edge._creationTime === "number") {
|
|
1700
|
+
return edge._creationTime;
|
|
1701
|
+
}
|
|
1702
|
+
return null;
|
|
1703
|
+
}
|
|
1704
|
+
async function collectNodeEndpointRefs(ctx, nodeId) {
|
|
1705
|
+
const refs = /* @__PURE__ */ new Set([String(nodeId)]);
|
|
1706
|
+
const node = readMetricNodeDoc(await ctx.db.get(nodeId));
|
|
1707
|
+
if (node?.globalId) {
|
|
1708
|
+
refs.add(node.globalId);
|
|
1709
|
+
}
|
|
1710
|
+
return [...refs];
|
|
1711
|
+
}
|
|
1712
|
+
async function collectIncomingEdgeRows(ctx, nodeId, edgeType) {
|
|
1713
|
+
const refs = await collectNodeEndpointRefs(ctx, nodeId);
|
|
1714
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1715
|
+
const edges = [];
|
|
1716
|
+
for (const ref of refs) {
|
|
1717
|
+
const rows = edgeType === void 0 ? await ctx.db.query("epistemicEdges").withIndex("by_to", (q) => q.eq("toNodeId", ref)).collect() : await ctx.db.query("epistemicEdges").withIndex(
|
|
1718
|
+
"by_to_type",
|
|
1719
|
+
(q) => q.eq("toNodeId", ref).eq("edgeType", edgeType)
|
|
1720
|
+
).collect();
|
|
1721
|
+
for (const row of rows) {
|
|
1722
|
+
const edge = readIncomingEdgeRow(row);
|
|
1723
|
+
if (!edge) {
|
|
1724
|
+
continue;
|
|
1725
|
+
}
|
|
1726
|
+
if (edgeType !== void 0 && edge.edgeType !== edgeType) {
|
|
1727
|
+
continue;
|
|
1728
|
+
}
|
|
1729
|
+
const key = edge._id === void 0 ? `${edge.fromNodeId}->${edge.toNodeId ?? ref}:${edge.edgeType ?? ""}` : String(edge._id);
|
|
1730
|
+
if (seen.has(key)) {
|
|
1731
|
+
continue;
|
|
1732
|
+
}
|
|
1733
|
+
seen.add(key);
|
|
1734
|
+
edges.push(edge);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
return edges;
|
|
1738
|
+
}
|
|
1739
|
+
function sourceEndpointRefs(edge) {
|
|
1740
|
+
return [
|
|
1741
|
+
edge.fromNodeId,
|
|
1742
|
+
edge.sourceGlobalId,
|
|
1743
|
+
edge.fromGlobalId,
|
|
1744
|
+
edge.fromUuid
|
|
1745
|
+
].filter((value) => value !== void 0);
|
|
1746
|
+
}
|
|
1747
|
+
async function resolveEndpointNode(ctx, refs) {
|
|
1748
|
+
const candidates = refs.map((value) => value.trim()).filter(
|
|
1749
|
+
(value, index, values) => value.length > 0 && values.indexOf(value) === index
|
|
1750
|
+
);
|
|
1751
|
+
for (const candidate of candidates) {
|
|
1856
1752
|
try {
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
};
|
|
1753
|
+
const direct = readMetricNodeDoc(
|
|
1754
|
+
await ctx.db.get(candidate)
|
|
1755
|
+
);
|
|
1756
|
+
if (direct) {
|
|
1757
|
+
return direct;
|
|
1758
|
+
}
|
|
1759
|
+
} catch {
|
|
1760
|
+
}
|
|
1761
|
+
const byGlobalId = readMetricNodeDoc(
|
|
1762
|
+
await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first()
|
|
1763
|
+
);
|
|
1764
|
+
if (byGlobalId) {
|
|
1765
|
+
return byGlobalId;
|
|
1871
1766
|
}
|
|
1872
|
-
} else {
|
|
1873
|
-
evaluation = {
|
|
1874
|
-
result: "error",
|
|
1875
|
-
rationale: `No epistemic evaluator registered for "${args.contract.condition.evaluator}".`
|
|
1876
|
-
};
|
|
1877
1767
|
}
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
});
|
|
1885
|
-
let beliefConfidenceId;
|
|
1886
|
-
let confidenceAfter = confidenceBefore;
|
|
1887
|
-
if (modulationPlan) {
|
|
1888
|
-
const contractB = Math.max(0, Math.min(1, modulationPlan.confidenceAfter));
|
|
1889
|
-
const modulationResult = await applyBeliefConfidenceChange(args.ctx, {
|
|
1890
|
-
nodeId: args.contract.beliefNodeId,
|
|
1891
|
-
belief: contractB,
|
|
1892
|
-
disbelief: 1 - contractB,
|
|
1893
|
-
uncertainty: 0,
|
|
1894
|
-
baseRate: 0.5,
|
|
1895
|
-
trigger: modulationPlan.trigger,
|
|
1896
|
-
rationale: `Epistemic contract "${args.contract.title}" ${evaluation.result}: ${evaluation.rationale}`,
|
|
1897
|
-
authenticatedUserId: args.authenticatedUserId
|
|
1898
|
-
});
|
|
1899
|
-
beliefConfidenceId = modulationResult.beliefConfidenceId;
|
|
1900
|
-
confidenceAfter = typeof modulationResult.newConfidence === "number" ? modulationResult.newConfidence : modulationPlan.confidenceAfter;
|
|
1768
|
+
return null;
|
|
1769
|
+
}
|
|
1770
|
+
async function getEvidenceLinks(ctx, beliefNodeId) {
|
|
1771
|
+
const edges = await collectIncomingEdgeRows(ctx, beliefNodeId, "informs");
|
|
1772
|
+
if (edges.length === 0) {
|
|
1773
|
+
return [];
|
|
1901
1774
|
}
|
|
1902
|
-
const
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
evaluator: args.contract.condition.evaluator,
|
|
1908
|
-
trigger: args.trigger,
|
|
1909
|
-
resultData: evaluation.data,
|
|
1910
|
-
modulationApplied: Boolean(modulationPlan),
|
|
1911
|
-
confidenceDelta: modulationPlan?.confidenceDelta,
|
|
1912
|
-
confidenceBefore: modulationPlan?.confidenceBefore,
|
|
1913
|
-
confidenceAfter: modulationPlan ? confidenceAfter : void 0,
|
|
1914
|
-
beliefConfidenceId,
|
|
1915
|
-
modulationRationale: evaluation.rationale,
|
|
1916
|
-
topicId: args.contract.topicId
|
|
1917
|
-
});
|
|
1918
|
-
const nextStatus = deriveContractStatus(evaluation.result, args.contract.status);
|
|
1919
|
-
await args.ctx.db.patch(
|
|
1920
|
-
args.contract._id,
|
|
1921
|
-
{
|
|
1922
|
-
status: nextStatus,
|
|
1923
|
-
lastEvaluatedAt: args.now,
|
|
1924
|
-
evaluationCount: (args.contract.evaluationCount ?? 0) + 1,
|
|
1925
|
-
updatedAt: args.now
|
|
1775
|
+
const links = [];
|
|
1776
|
+
for (const edge of edges) {
|
|
1777
|
+
const node = await resolveEndpointNode(ctx, sourceEndpointRefs(edge));
|
|
1778
|
+
if (node?.nodeType !== "evidence" || node.status === "archived") {
|
|
1779
|
+
continue;
|
|
1926
1780
|
}
|
|
1781
|
+
links.push({ edge, node });
|
|
1782
|
+
}
|
|
1783
|
+
return links;
|
|
1784
|
+
}
|
|
1785
|
+
function getEvidenceTags(node) {
|
|
1786
|
+
const metadata = node.metadata && typeof node.metadata === "object" ? node.metadata : null;
|
|
1787
|
+
const tags = metadata?.tags;
|
|
1788
|
+
if (!Array.isArray(tags)) {
|
|
1789
|
+
return [];
|
|
1790
|
+
}
|
|
1791
|
+
return tags.filter((tag) => typeof tag === "string");
|
|
1792
|
+
}
|
|
1793
|
+
async function computeEvidenceCountMetric(ctx, beliefNodeId) {
|
|
1794
|
+
return (await getEvidenceLinks(ctx, beliefNodeId)).length;
|
|
1795
|
+
}
|
|
1796
|
+
async function computeTaggedEvidenceCount(args) {
|
|
1797
|
+
const expectedTag = args.caseSensitive ? args.tag : args.tag.toLowerCase();
|
|
1798
|
+
const matchedEvidenceIds = (await getEvidenceLinks(args.ctx, args.beliefNodeId)).filter(
|
|
1799
|
+
({ node }) => getEvidenceTags(node).some(
|
|
1800
|
+
(tag) => (args.caseSensitive ? tag : tag.toLowerCase()) === expectedTag
|
|
1801
|
+
)
|
|
1802
|
+
).map(({ node }) => String(node._id));
|
|
1803
|
+
return {
|
|
1804
|
+
count: matchedEvidenceIds.length,
|
|
1805
|
+
matchedEvidenceIds
|
|
1806
|
+
};
|
|
1807
|
+
}
|
|
1808
|
+
async function computeContradictionCounts(ctx, beliefNodeId) {
|
|
1809
|
+
const contradictionDb = ctx.db;
|
|
1810
|
+
const contradictions = await contradictionDb.query("contradictions").withIndex("by_beliefId", (q) => q.eq("beliefId", beliefNodeId)).collect();
|
|
1811
|
+
return contradictions.reduce(
|
|
1812
|
+
(counts, contradiction) => {
|
|
1813
|
+
const status = contradiction.resolutionStatus ?? contradiction.status ?? "unresolved";
|
|
1814
|
+
if (classifyContradictionStatus(status) === "active") {
|
|
1815
|
+
counts.activeCount += 1;
|
|
1816
|
+
} else {
|
|
1817
|
+
counts.resolvedCount += 1;
|
|
1818
|
+
}
|
|
1819
|
+
return counts;
|
|
1820
|
+
},
|
|
1821
|
+
{ activeCount: 0, resolvedCount: 0 }
|
|
1927
1822
|
);
|
|
1823
|
+
}
|
|
1824
|
+
async function computeEvidenceFreshness(ctx, beliefNodeId, now = Date.now()) {
|
|
1825
|
+
const timestamps = (await getEvidenceLinks(ctx, beliefNodeId)).map(({ edge }) => getEdgeTimestamp(edge)).filter((value) => value !== null);
|
|
1826
|
+
if (timestamps.length === 0) {
|
|
1827
|
+
return {
|
|
1828
|
+
newestAgeMs: null,
|
|
1829
|
+
oldestAgeMs: null,
|
|
1830
|
+
newestEdgeAt: null,
|
|
1831
|
+
oldestEdgeAt: null,
|
|
1832
|
+
edgeCount: 0
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
const newestEdgeAt = Math.max(...timestamps);
|
|
1836
|
+
const oldestEdgeAt = Math.min(...timestamps);
|
|
1928
1837
|
return {
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
rationale: evaluation.rationale,
|
|
1935
|
-
data: evaluation.data,
|
|
1936
|
-
currentConfidence: confidenceAfter
|
|
1838
|
+
newestAgeMs: Math.max(0, now - newestEdgeAt),
|
|
1839
|
+
oldestAgeMs: Math.max(0, now - oldestEdgeAt),
|
|
1840
|
+
newestEdgeAt,
|
|
1841
|
+
oldestEdgeAt,
|
|
1842
|
+
edgeCount: timestamps.length
|
|
1937
1843
|
};
|
|
1938
1844
|
}
|
|
1939
|
-
async function
|
|
1940
|
-
const
|
|
1941
|
-
const
|
|
1845
|
+
async function computeDependentBeliefCount(ctx, beliefNodeId) {
|
|
1846
|
+
const incomingEdges = await collectIncomingEdgeRows(ctx, beliefNodeId);
|
|
1847
|
+
const dependencyEdges = incomingEdges.filter(
|
|
1848
|
+
(edge) => edge.edgeType ? DEPENDENT_EDGE_TYPES.has(edge.edgeType) : false
|
|
1849
|
+
);
|
|
1850
|
+
if (dependencyEdges.length === 0) {
|
|
1851
|
+
return 0;
|
|
1852
|
+
}
|
|
1853
|
+
const uniqueBeliefIds = /* @__PURE__ */ new Set();
|
|
1854
|
+
for (const edge of dependencyEdges) {
|
|
1855
|
+
const node = await resolveEndpointNode(ctx, sourceEndpointRefs(edge));
|
|
1856
|
+
if (node && node.nodeType === "belief" && node.status !== "archived" && node.status !== "deleted") {
|
|
1857
|
+
uniqueBeliefIds.add(String(node._id));
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
return uniqueBeliefIds.size;
|
|
1861
|
+
}
|
|
1862
|
+
async function snapshotEvidentialMetric(args) {
|
|
1863
|
+
switch (args.metric) {
|
|
1864
|
+
case "evidence_count": {
|
|
1865
|
+
const count = await computeEvidenceCountMetric(
|
|
1866
|
+
args.ctx,
|
|
1867
|
+
args.beliefNodeId
|
|
1868
|
+
);
|
|
1869
|
+
return {
|
|
1870
|
+
metric: args.metric,
|
|
1871
|
+
value: count,
|
|
1872
|
+
data: { evidenceCount: count }
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1875
|
+
case "contradiction_status": {
|
|
1876
|
+
const counts = await computeContradictionCounts(
|
|
1877
|
+
args.ctx,
|
|
1878
|
+
args.beliefNodeId
|
|
1879
|
+
);
|
|
1880
|
+
return {
|
|
1881
|
+
metric: args.metric,
|
|
1882
|
+
value: counts.activeCount,
|
|
1883
|
+
data: counts
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
case "edge_freshness": {
|
|
1887
|
+
const freshness = await computeEvidenceFreshness(
|
|
1888
|
+
args.ctx,
|
|
1889
|
+
args.beliefNodeId,
|
|
1890
|
+
args.now
|
|
1891
|
+
);
|
|
1892
|
+
return {
|
|
1893
|
+
metric: args.metric,
|
|
1894
|
+
value: freshness.newestAgeMs,
|
|
1895
|
+
data: freshness
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
case "dependent_count": {
|
|
1899
|
+
const count = await computeDependentBeliefCount(
|
|
1900
|
+
args.ctx,
|
|
1901
|
+
args.beliefNodeId
|
|
1902
|
+
);
|
|
1903
|
+
return {
|
|
1904
|
+
metric: args.metric,
|
|
1905
|
+
value: count,
|
|
1906
|
+
data: { dependentCount: count }
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
default:
|
|
1910
|
+
return {
|
|
1911
|
+
metric: args.metric,
|
|
1912
|
+
value: null,
|
|
1913
|
+
data: {}
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
async function evaluateBuiltInEvidentialContract(args) {
|
|
1918
|
+
const config = parseEvidentialEvaluatorConfig(
|
|
1919
|
+
args.contract.condition.evaluatorConfig
|
|
1920
|
+
);
|
|
1921
|
+
const snapshot = await snapshotEvidentialMetric({
|
|
1942
1922
|
ctx: args.ctx,
|
|
1943
1923
|
beliefNodeId: args.belief._id,
|
|
1944
|
-
|
|
1945
|
-
|
|
1924
|
+
metric: config.metric,
|
|
1925
|
+
now: args.now
|
|
1946
1926
|
});
|
|
1947
|
-
const
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
MAX_CONTRACT_EVALUATION_BATCH_SIZE
|
|
1952
|
-
)
|
|
1927
|
+
const comparisonSatisfied = snapshot.value !== null && compareMetricValue(config.operator, snapshot.value, config.threshold);
|
|
1928
|
+
const result = resolveComparisonResult(
|
|
1929
|
+
args.contract.direction,
|
|
1930
|
+
comparisonSatisfied
|
|
1953
1931
|
);
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
}
|
|
1978
|
-
if (overflowContracts.length > 0) {
|
|
1979
|
-
await args.ctx.scheduler.runAfter(
|
|
1980
|
-
0,
|
|
1981
|
-
"epistemicContracts.processContractEvaluationOverflow",
|
|
1982
|
-
{
|
|
1983
|
-
beliefNodeId: args.belief._id,
|
|
1984
|
-
trigger: normalizeTrigger(args.trigger),
|
|
1985
|
-
contractIds: overflowContracts.map((contract) => contract.contractId),
|
|
1986
|
-
inputData: args.inputData,
|
|
1987
|
-
authenticatedUserId: args.authenticatedUserId,
|
|
1988
|
-
maxBatchSize: batchLimit
|
|
1989
|
-
}
|
|
1932
|
+
return {
|
|
1933
|
+
result,
|
|
1934
|
+
rationale: buildEvidentialRationale({
|
|
1935
|
+
config,
|
|
1936
|
+
snapshot,
|
|
1937
|
+
comparisonSatisfied,
|
|
1938
|
+
result
|
|
1939
|
+
}),
|
|
1940
|
+
data: {
|
|
1941
|
+
...snapshot.data,
|
|
1942
|
+
metric: config.metric,
|
|
1943
|
+
observedValue: snapshot.value,
|
|
1944
|
+
operator: config.operator,
|
|
1945
|
+
threshold: config.threshold,
|
|
1946
|
+
action: config.action ?? "append_sl_scoring",
|
|
1947
|
+
actionParams: config.actionParams
|
|
1948
|
+
}
|
|
1949
|
+
};
|
|
1950
|
+
}
|
|
1951
|
+
function evaluateMetricCheckerContract(args) {
|
|
1952
|
+
return Promise.resolve().then(() => {
|
|
1953
|
+
const config = parseMetricCheckerConfig(
|
|
1954
|
+
args.contract.condition.evaluatorConfig
|
|
1990
1955
|
);
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1956
|
+
const input = getEvaluatorInputRecord(args.inputData, "metricData");
|
|
1957
|
+
const metric = typeof input.metric === "string" && input.metric.length > 0 ? input.metric : config.metric;
|
|
1958
|
+
const observedValue = pickFiniteNumber(input, [
|
|
1959
|
+
"observedValue",
|
|
1960
|
+
"currentValue",
|
|
1961
|
+
"metricValue",
|
|
1962
|
+
"value"
|
|
1963
|
+
]) ?? config.observedValue ?? config.currentValue ?? config.metricValue ?? null;
|
|
1964
|
+
if (observedValue === null) {
|
|
1965
|
+
return {
|
|
1966
|
+
result: "inconclusive",
|
|
1967
|
+
rationale: `metric_checker is awaiting data for ${metric ?? args.contract.condition.expression}.`,
|
|
1968
|
+
data: {
|
|
1969
|
+
metric,
|
|
1970
|
+
observedValue: null,
|
|
1971
|
+
operator: config.operator,
|
|
1972
|
+
threshold: config.threshold,
|
|
1973
|
+
unit: config.unit
|
|
1974
|
+
}
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
const comparisonSatisfied = compareMetricValue(
|
|
1978
|
+
config.operator,
|
|
1979
|
+
observedValue,
|
|
1980
|
+
config.threshold
|
|
1981
|
+
);
|
|
1982
|
+
const result = resolveComparisonResult(
|
|
1983
|
+
args.contract.direction,
|
|
1984
|
+
comparisonSatisfied
|
|
1985
|
+
);
|
|
1986
|
+
return {
|
|
1987
|
+
result,
|
|
1988
|
+
rationale: buildComparisonRationale({
|
|
1989
|
+
label: metric ?? "metric",
|
|
1990
|
+
observedValue,
|
|
1991
|
+
operator: config.operator,
|
|
1992
|
+
threshold: config.threshold,
|
|
1993
|
+
comparisonSatisfied,
|
|
1994
|
+
result,
|
|
1995
|
+
unit: config.unit
|
|
1996
|
+
}),
|
|
1997
|
+
data: {
|
|
1998
|
+
metric,
|
|
1999
|
+
observedValue,
|
|
2000
|
+
operator: config.operator,
|
|
2001
|
+
threshold: config.threshold,
|
|
2002
|
+
unit: config.unit
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
async function evaluateReferenceCheckCounterContract(args) {
|
|
2008
|
+
const config = parseReferenceCheckCounterConfig(
|
|
2009
|
+
args.contract.condition.evaluatorConfig
|
|
2010
|
+
);
|
|
2011
|
+
const input = getEvaluatorInputRecord(args.inputData, "referenceCheckData");
|
|
2012
|
+
const tag = typeof input.tag === "string" && input.tag.trim().length > 0 ? input.tag.trim() : config.tag;
|
|
2013
|
+
const snapshot = await computeTaggedEvidenceCount({
|
|
2014
|
+
ctx: args.ctx,
|
|
2015
|
+
beliefNodeId: args.belief._id,
|
|
2016
|
+
tag,
|
|
2017
|
+
caseSensitive: config.caseSensitive
|
|
1999
2018
|
});
|
|
2019
|
+
const comparisonSatisfied = compareMetricValue(
|
|
2020
|
+
config.operator,
|
|
2021
|
+
snapshot.count,
|
|
2022
|
+
config.threshold
|
|
2023
|
+
);
|
|
2024
|
+
const result = resolveComparisonResult(
|
|
2025
|
+
args.contract.direction,
|
|
2026
|
+
comparisonSatisfied
|
|
2027
|
+
);
|
|
2000
2028
|
return {
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2029
|
+
result,
|
|
2030
|
+
rationale: buildComparisonRationale({
|
|
2031
|
+
label: `reference checks tagged "${tag}"`,
|
|
2032
|
+
observedValue: snapshot.count,
|
|
2033
|
+
operator: config.operator,
|
|
2034
|
+
threshold: config.threshold,
|
|
2035
|
+
comparisonSatisfied,
|
|
2036
|
+
result
|
|
2037
|
+
}),
|
|
2038
|
+
data: {
|
|
2039
|
+
tag,
|
|
2040
|
+
observedValue: snapshot.count,
|
|
2041
|
+
referenceCheckCount: snapshot.count,
|
|
2042
|
+
matchedEvidenceIds: snapshot.matchedEvidenceIds,
|
|
2043
|
+
operator: config.operator,
|
|
2044
|
+
threshold: config.threshold,
|
|
2045
|
+
caseSensitive: config.caseSensitive ?? false
|
|
2046
|
+
}
|
|
2009
2047
|
};
|
|
2010
2048
|
}
|
|
2011
|
-
|
|
2012
|
-
|
|
2049
|
+
function resolveCompletedTemporalDeadlineResult(args) {
|
|
2050
|
+
const { completedAt, context, deadline, label } = args;
|
|
2051
|
+
if (completedAt !== void 0 && completedAt > deadline) {
|
|
2052
|
+
return {
|
|
2053
|
+
result: "expired",
|
|
2054
|
+
rationale: `${label} completed at ${completedAt}, after deadline ${deadline}.`,
|
|
2055
|
+
data: {
|
|
2056
|
+
label,
|
|
2057
|
+
deadline,
|
|
2058
|
+
completed: true,
|
|
2059
|
+
completedAt,
|
|
2060
|
+
missedDeadline: true,
|
|
2061
|
+
overdueByMs: completedAt - deadline
|
|
2062
|
+
}
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
2065
|
+
const result = context.contract.direction === "falsifies" ? "disconfirmed" : "confirmed";
|
|
2066
|
+
return {
|
|
2067
|
+
result,
|
|
2068
|
+
rationale: `${label} completed before deadline ${deadline}.`,
|
|
2069
|
+
data: {
|
|
2070
|
+
label,
|
|
2071
|
+
deadline,
|
|
2072
|
+
completed: true,
|
|
2073
|
+
completedAt: completedAt ?? null,
|
|
2074
|
+
missedDeadline: false
|
|
2075
|
+
}
|
|
2076
|
+
};
|
|
2013
2077
|
}
|
|
2014
|
-
|
|
2015
|
-
const
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2078
|
+
function resolveOpenTemporalDeadlineResult(args) {
|
|
2079
|
+
const { context, deadline, label } = args;
|
|
2080
|
+
if (context.now > deadline) {
|
|
2081
|
+
return {
|
|
2082
|
+
result: "expired",
|
|
2083
|
+
rationale: `${label} missed deadline ${deadline}; temporal contract expired.`,
|
|
2084
|
+
data: {
|
|
2085
|
+
label,
|
|
2086
|
+
deadline,
|
|
2087
|
+
completed: false,
|
|
2088
|
+
overdueByMs: context.now - deadline
|
|
2089
|
+
}
|
|
2090
|
+
};
|
|
2091
|
+
}
|
|
2092
|
+
return {
|
|
2093
|
+
result: "inconclusive",
|
|
2094
|
+
rationale: `${label} is still before deadline ${deadline}; awaiting outcome.`,
|
|
2095
|
+
data: {
|
|
2096
|
+
label,
|
|
2097
|
+
deadline,
|
|
2098
|
+
completed: false,
|
|
2099
|
+
timeRemainingMs: deadline - context.now
|
|
2022
2100
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2101
|
+
};
|
|
2102
|
+
}
|
|
2103
|
+
function evaluateTemporalDeadlineContract(args) {
|
|
2104
|
+
return Promise.resolve().then(() => {
|
|
2105
|
+
if (typeof args.contract.deadline !== "number" || !Number.isFinite(args.contract.deadline)) {
|
|
2106
|
+
throw new Error(
|
|
2107
|
+
"temporal_deadline requires contract.deadline to be set to a finite timestamp."
|
|
2108
|
+
);
|
|
2025
2109
|
}
|
|
2026
|
-
|
|
2027
|
-
|
|
2110
|
+
const deadline = args.contract.deadline;
|
|
2111
|
+
const config = parseTemporalDeadlineConfig(
|
|
2112
|
+
args.contract.condition.evaluatorConfig
|
|
2113
|
+
);
|
|
2114
|
+
const input = getEvaluatorInputRecord(args.inputData, "temporalData");
|
|
2115
|
+
const label = (typeof input.label === "string" && input.label.length > 0 ? input.label : config.label) ?? args.contract.title ?? args.contract.condition.expression;
|
|
2116
|
+
const completedAt = pickFiniteNumber(input, [
|
|
2117
|
+
"completedAt",
|
|
2118
|
+
"observedAt",
|
|
2119
|
+
"satisfiedAt",
|
|
2120
|
+
"achievedAt"
|
|
2121
|
+
]) ?? config.completedAt ?? config.observedAt ?? config.satisfiedAt ?? config.achievedAt;
|
|
2122
|
+
const completed = input.completed === true || config.completed === true || completedAt !== void 0;
|
|
2123
|
+
if (completed) {
|
|
2124
|
+
return resolveCompletedTemporalDeadlineResult({
|
|
2125
|
+
completedAt,
|
|
2126
|
+
context: args,
|
|
2127
|
+
deadline,
|
|
2128
|
+
label
|
|
2129
|
+
});
|
|
2028
2130
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2131
|
+
return resolveOpenTemporalDeadlineResult({
|
|
2132
|
+
context: args,
|
|
2133
|
+
deadline,
|
|
2134
|
+
label
|
|
2135
|
+
});
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
function evaluateMarketIndexComparatorContract(args) {
|
|
2139
|
+
return Promise.resolve().then(() => {
|
|
2140
|
+
const config = parseMarketIndexComparatorConfig(
|
|
2141
|
+
args.contract.condition.evaluatorConfig
|
|
2142
|
+
);
|
|
2143
|
+
const input = getEvaluatorInputRecord(args.inputData, "marketIndexData");
|
|
2144
|
+
const subject = typeof input.subject === "string" && input.subject.length > 0 ? input.subject : config.subject;
|
|
2145
|
+
const benchmark = typeof input.benchmark === "string" && input.benchmark.length > 0 ? input.benchmark : config.benchmark;
|
|
2146
|
+
const subjectValue = pickFiniteNumber(input, ["subjectValue", "primaryValue", "leftValue"]) ?? config.subjectValue ?? config.primaryValue ?? null;
|
|
2147
|
+
const benchmarkValue = pickFiniteNumber(input, [
|
|
2148
|
+
"benchmarkValue",
|
|
2149
|
+
"comparisonValue",
|
|
2150
|
+
"rightValue"
|
|
2151
|
+
]) ?? config.benchmarkValue ?? config.comparisonValue ?? null;
|
|
2152
|
+
if (subjectValue === null || benchmarkValue === null) {
|
|
2153
|
+
return {
|
|
2154
|
+
result: "inconclusive",
|
|
2155
|
+
rationale: "market_index_comparator is awaiting both subject and benchmark values.",
|
|
2156
|
+
data: {
|
|
2157
|
+
subject,
|
|
2158
|
+
subjectValue,
|
|
2159
|
+
benchmark,
|
|
2160
|
+
benchmarkValue,
|
|
2161
|
+
operator: config.operator,
|
|
2162
|
+
threshold: config.threshold
|
|
2163
|
+
}
|
|
2164
|
+
};
|
|
2031
2165
|
}
|
|
2032
|
-
|
|
2166
|
+
if (benchmarkValue === 0) {
|
|
2167
|
+
throw new Error(
|
|
2168
|
+
"market_index_comparator cannot compare against a zero benchmark value."
|
|
2169
|
+
);
|
|
2170
|
+
}
|
|
2171
|
+
const differentialPercent = (subjectValue - benchmarkValue) / Math.abs(benchmarkValue) * 100;
|
|
2172
|
+
const comparisonSatisfied = compareMetricValue(
|
|
2173
|
+
config.operator,
|
|
2174
|
+
differentialPercent,
|
|
2175
|
+
config.threshold
|
|
2176
|
+
);
|
|
2177
|
+
const result = resolveComparisonResult(
|
|
2178
|
+
args.contract.direction,
|
|
2179
|
+
comparisonSatisfied
|
|
2180
|
+
);
|
|
2181
|
+
return {
|
|
2182
|
+
result,
|
|
2183
|
+
rationale: buildComparisonRationale({
|
|
2184
|
+
label: `${subject ?? "subject"} vs ${benchmark ?? "benchmark"} differential`,
|
|
2185
|
+
observedValue: differentialPercent,
|
|
2186
|
+
operator: config.operator,
|
|
2187
|
+
threshold: config.threshold,
|
|
2188
|
+
comparisonSatisfied,
|
|
2189
|
+
result,
|
|
2190
|
+
unit: "%"
|
|
2191
|
+
}),
|
|
2192
|
+
data: {
|
|
2193
|
+
subject,
|
|
2194
|
+
subjectValue,
|
|
2195
|
+
benchmark,
|
|
2196
|
+
benchmarkValue,
|
|
2197
|
+
differentialPercent,
|
|
2198
|
+
operator: config.operator,
|
|
2199
|
+
threshold: config.threshold
|
|
2200
|
+
}
|
|
2201
|
+
};
|
|
2033
2202
|
});
|
|
2034
2203
|
}
|
|
2204
|
+
var METRIC_COMPARATOR_EVALUATOR_NAMES = {
|
|
2205
|
+
evidentialAliases: /* @__PURE__ */ new Set([
|
|
2206
|
+
"evidential",
|
|
2207
|
+
"built_in_evidential",
|
|
2208
|
+
"builtin_evidential"
|
|
2209
|
+
]),
|
|
2210
|
+
metricChecker: "metric_checker",
|
|
2211
|
+
referenceCheckCounter: "reference_check_counter",
|
|
2212
|
+
temporalDeadline: "temporal_deadline",
|
|
2213
|
+
marketIndexComparator: "market_index_comparator"
|
|
2214
|
+
};
|
|
2035
2215
|
|
|
2036
2216
|
// src/evaluators/shared.ts
|
|
2217
|
+
var WINDOWS_PATH_SEPARATORS = /\\/g;
|
|
2218
|
+
var LEADING_DOT_SLASH = /^\.\//;
|
|
2037
2219
|
function asArray(value) {
|
|
2038
2220
|
return Array.isArray(value) ? value : [];
|
|
2039
2221
|
}
|
|
@@ -2075,7 +2257,7 @@ function extractTextCandidates(value) {
|
|
|
2075
2257
|
return Array.from(new Set(candidates));
|
|
2076
2258
|
}
|
|
2077
2259
|
function normalizeFilePath(value) {
|
|
2078
|
-
return value.replace(
|
|
2260
|
+
return value.replace(WINDOWS_PATH_SEPARATORS, "/").replace(LEADING_DOT_SLASH, "");
|
|
2079
2261
|
}
|
|
2080
2262
|
function normalizeToolResultEnvelope(value) {
|
|
2081
2263
|
const record = asRecord(value);
|
|
@@ -2129,7 +2311,7 @@ function somePatternMatches(filePath, patterns) {
|
|
|
2129
2311
|
return patterns.some((pattern) => patternMatchesPath(filePath, pattern));
|
|
2130
2312
|
}
|
|
2131
2313
|
|
|
2132
|
-
// src/evaluators/
|
|
2314
|
+
// src/evaluators/lint-checker-evaluator.ts
|
|
2133
2315
|
function parseConfig(condition) {
|
|
2134
2316
|
const record = asRecord(condition.evaluatorConfig);
|
|
2135
2317
|
if (!record) {
|
|
@@ -2201,7 +2383,10 @@ var lintCheckerEvaluator = {
|
|
|
2201
2383
|
}
|
|
2202
2384
|
const envelope = normalizeToolResultEnvelope(args.resultData);
|
|
2203
2385
|
const exitCode = asNumber(envelope.exitCode);
|
|
2204
|
-
const matchedDiagnostics = getMatchedDiagnostics(
|
|
2386
|
+
const matchedDiagnostics = getMatchedDiagnostics(
|
|
2387
|
+
args.contract,
|
|
2388
|
+
args.resultData
|
|
2389
|
+
);
|
|
2205
2390
|
if (matchedDiagnostics.length === 0 && exitCode !== 0 && exitCode !== null) {
|
|
2206
2391
|
return {
|
|
2207
2392
|
result: "inconclusive",
|
|
@@ -2227,7 +2412,7 @@ var lintCheckerEvaluator = {
|
|
|
2227
2412
|
}
|
|
2228
2413
|
};
|
|
2229
2414
|
|
|
2230
|
-
// src/evaluators/
|
|
2415
|
+
// src/evaluators/sentry-checker-evaluator.ts
|
|
2231
2416
|
function parseConfig2(condition) {
|
|
2232
2417
|
const record = asRecord(condition.evaluatorConfig);
|
|
2233
2418
|
if (!record) {
|
|
@@ -2312,7 +2497,7 @@ var sentryCheckerEvaluator = {
|
|
|
2312
2497
|
}
|
|
2313
2498
|
};
|
|
2314
2499
|
|
|
2315
|
-
// src/evaluators/
|
|
2500
|
+
// src/evaluators/test-runner-evaluator.ts
|
|
2316
2501
|
function parseConfig3(condition) {
|
|
2317
2502
|
const record = asRecord(condition.evaluatorConfig);
|
|
2318
2503
|
if (!record) {
|
|
@@ -2458,7 +2643,7 @@ var testRunnerEvaluator = {
|
|
|
2458
2643
|
}
|
|
2459
2644
|
};
|
|
2460
2645
|
|
|
2461
|
-
// src/evaluators/
|
|
2646
|
+
// src/evaluators/tsc-checker-evaluator.ts
|
|
2462
2647
|
function parseConfig4(condition) {
|
|
2463
2648
|
const record = asRecord(condition.evaluatorConfig);
|
|
2464
2649
|
if (!record) {
|
|
@@ -2470,118 +2655,383 @@ function parseConfig4(condition) {
|
|
|
2470
2655
|
if (filePatterns.length === 0) {
|
|
2471
2656
|
throw new Error("tsc_checker requires at least one file pattern.");
|
|
2472
2657
|
}
|
|
2473
|
-
return { filePatterns };
|
|
2658
|
+
return { filePatterns };
|
|
2659
|
+
}
|
|
2660
|
+
function parseStructuredDiagnostics(resultData) {
|
|
2661
|
+
const envelope = normalizeToolResultEnvelope(resultData);
|
|
2662
|
+
const record = asRecord(envelope.report) ?? asRecord(envelope.data) ?? asRecord(resultData);
|
|
2663
|
+
if (!record) {
|
|
2664
|
+
return [];
|
|
2665
|
+
}
|
|
2666
|
+
return asArray(record.diagnostics).flatMap((entry) => {
|
|
2667
|
+
const diagnostic = asRecord(entry);
|
|
2668
|
+
if (!diagnostic) {
|
|
2669
|
+
return [];
|
|
2670
|
+
}
|
|
2671
|
+
const filePath = asString(diagnostic.filePath) ?? asString(diagnostic.file) ?? asString(asRecord(diagnostic.location)?.filePath) ?? asString(asRecord(asRecord(diagnostic.location)?.path)?.file);
|
|
2672
|
+
const message = asString(diagnostic.message) ?? "TypeScript error";
|
|
2673
|
+
return [
|
|
2674
|
+
{
|
|
2675
|
+
code: asString(diagnostic.code) ?? void 0,
|
|
2676
|
+
filePath: filePath ? normalizeFilePath(filePath) : null,
|
|
2677
|
+
message
|
|
2678
|
+
}
|
|
2679
|
+
];
|
|
2680
|
+
});
|
|
2681
|
+
}
|
|
2682
|
+
function parseTextDiagnostics(resultData) {
|
|
2683
|
+
const diagnostics = [];
|
|
2684
|
+
const patterns = [
|
|
2685
|
+
/^(.+?)\((\d+),(\d+)\): error TS(\d+): (.+)$/gm,
|
|
2686
|
+
/^(.+?):(\d+):(\d+) - error TS(\d+): (.+)$/gm
|
|
2687
|
+
];
|
|
2688
|
+
for (const text of extractTextCandidates(resultData)) {
|
|
2689
|
+
for (const pattern of patterns) {
|
|
2690
|
+
for (const match of text.matchAll(pattern)) {
|
|
2691
|
+
diagnostics.push({
|
|
2692
|
+
code: match[4],
|
|
2693
|
+
filePath: normalizeFilePath(match[1] ?? ""),
|
|
2694
|
+
message: match[5] ?? "TypeScript error"
|
|
2695
|
+
});
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
return diagnostics;
|
|
2700
|
+
}
|
|
2701
|
+
function parseDiagnostics2(resultData) {
|
|
2702
|
+
const structured = parseStructuredDiagnostics(resultData);
|
|
2703
|
+
return structured.length > 0 ? structured : parseTextDiagnostics(resultData);
|
|
2704
|
+
}
|
|
2705
|
+
function getMatchedDiagnostics2(contract, resultData) {
|
|
2706
|
+
const config = parseConfig4(contract.condition);
|
|
2707
|
+
return parseDiagnostics2(resultData).filter(
|
|
2708
|
+
(diagnostic) => somePatternMatches(diagnostic.filePath, config.filePatterns)
|
|
2709
|
+
);
|
|
2710
|
+
}
|
|
2711
|
+
var tscCheckerEvaluator = {
|
|
2712
|
+
name: "tsc_checker",
|
|
2713
|
+
matches({ contract, resultData }) {
|
|
2714
|
+
const envelope = normalizeToolResultEnvelope(resultData);
|
|
2715
|
+
const exitCode = asNumber(envelope.exitCode);
|
|
2716
|
+
if (exitCode === 0) {
|
|
2717
|
+
return true;
|
|
2718
|
+
}
|
|
2719
|
+
return getMatchedDiagnostics2(contract, resultData).length > 0;
|
|
2720
|
+
},
|
|
2721
|
+
evaluate(args) {
|
|
2722
|
+
const config = parseConfig4(args.contract.condition);
|
|
2723
|
+
if (!args.resultData) {
|
|
2724
|
+
return {
|
|
2725
|
+
result: "error",
|
|
2726
|
+
rationale: "tsc_checker requires TypeScript diagnostic resultData."
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
const envelope = normalizeToolResultEnvelope(args.resultData);
|
|
2730
|
+
const exitCode = asNumber(envelope.exitCode);
|
|
2731
|
+
const matchedDiagnostics = getMatchedDiagnostics2(
|
|
2732
|
+
args.contract,
|
|
2733
|
+
args.resultData
|
|
2734
|
+
);
|
|
2735
|
+
if (matchedDiagnostics.length === 0 && exitCode !== 0 && exitCode !== null) {
|
|
2736
|
+
return {
|
|
2737
|
+
result: "inconclusive",
|
|
2738
|
+
rationale: "TypeScript reported errors, but none matched the configured file patterns."
|
|
2739
|
+
};
|
|
2740
|
+
}
|
|
2741
|
+
const conditionSatisfied = exitCode === 0 || exitCode !== null && matchedDiagnostics.length === 0;
|
|
2742
|
+
return {
|
|
2743
|
+
result: deriveDirectionalResult(
|
|
2744
|
+
args.contract.direction,
|
|
2745
|
+
conditionSatisfied
|
|
2746
|
+
),
|
|
2747
|
+
rationale: conditionSatisfied ? `TypeScript reported no matching diagnostics for ${config.filePatterns.join(", ")}.` : `TypeScript found ${matchedDiagnostics.length} matching diagnostic(s): ${matchedDiagnostics.map(
|
|
2748
|
+
(diagnostic) => diagnostic.filePath ? `${diagnostic.filePath}${diagnostic.code ? ` (TS${diagnostic.code})` : ""}` : diagnostic.message
|
|
2749
|
+
).join(", ")}.`,
|
|
2750
|
+
data: {
|
|
2751
|
+
exitCode,
|
|
2752
|
+
filePatterns: config.filePatterns,
|
|
2753
|
+
matchedDiagnostics
|
|
2754
|
+
}
|
|
2755
|
+
};
|
|
2756
|
+
}
|
|
2757
|
+
};
|
|
2758
|
+
|
|
2759
|
+
// src/evaluators/index.ts
|
|
2760
|
+
var ENGINEERING_EPISTEMIC_EVALUATORS = [
|
|
2761
|
+
testRunnerEvaluator,
|
|
2762
|
+
tscCheckerEvaluator,
|
|
2763
|
+
lintCheckerEvaluator,
|
|
2764
|
+
sentryCheckerEvaluator
|
|
2765
|
+
];
|
|
2766
|
+
var ENGINEERING_EVALUATOR_NAMES = new Set(
|
|
2767
|
+
ENGINEERING_EPISTEMIC_EVALUATORS.map((evaluator) => evaluator.name)
|
|
2768
|
+
);
|
|
2769
|
+
function getEngineeringEpistemicEvaluator(name) {
|
|
2770
|
+
return ENGINEERING_EPISTEMIC_EVALUATORS.find(
|
|
2771
|
+
(evaluator) => evaluator.name === name
|
|
2772
|
+
);
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2775
|
+
// src/epistemicContracts.evaluators.ts
|
|
2776
|
+
var evaluatorRegistry = /* @__PURE__ */ new Map();
|
|
2777
|
+
var BUILT_IN_EVIDENTIAL_ALIASES2 = METRIC_COMPARATOR_EVALUATOR_NAMES.evidentialAliases;
|
|
2778
|
+
var BUILT_IN_METRIC_CHECKER2 = METRIC_COMPARATOR_EVALUATOR_NAMES.metricChecker;
|
|
2779
|
+
var BUILT_IN_REFERENCE_CHECK_COUNTER2 = METRIC_COMPARATOR_EVALUATOR_NAMES.referenceCheckCounter;
|
|
2780
|
+
var BUILT_IN_TEMPORAL_DEADLINE2 = METRIC_COMPARATOR_EVALUATOR_NAMES.temporalDeadline;
|
|
2781
|
+
var BUILT_IN_MARKET_INDEX_COMPARATOR2 = METRIC_COMPARATOR_EVALUATOR_NAMES.marketIndexComparator;
|
|
2782
|
+
var MAX_CONTRACT_EVALUATION_BATCH_SIZE = 50;
|
|
2783
|
+
function confidenceSeed(args) {
|
|
2784
|
+
if (typeof args.currentConfidence === "number") {
|
|
2785
|
+
return args.currentConfidence;
|
|
2786
|
+
}
|
|
2787
|
+
if (typeof args.beliefConfidence === "number") {
|
|
2788
|
+
return args.beliefConfidence;
|
|
2789
|
+
}
|
|
2790
|
+
return 0.5;
|
|
2791
|
+
}
|
|
2792
|
+
function contractDocId(contract) {
|
|
2793
|
+
return contract._id;
|
|
2794
|
+
}
|
|
2795
|
+
function ensureBuiltInEvaluators() {
|
|
2796
|
+
for (const name of BUILT_IN_EVIDENTIAL_ALIASES2) {
|
|
2797
|
+
if (evaluatorRegistry.has(name)) {
|
|
2798
|
+
continue;
|
|
2799
|
+
}
|
|
2800
|
+
evaluatorRegistry.set(name, {
|
|
2801
|
+
name,
|
|
2802
|
+
evaluate: evaluateBuiltInEvidentialContract
|
|
2803
|
+
});
|
|
2804
|
+
}
|
|
2805
|
+
for (const evaluator of ENGINEERING_EPISTEMIC_EVALUATORS) {
|
|
2806
|
+
if (evaluatorRegistry.has(evaluator.name)) {
|
|
2807
|
+
continue;
|
|
2808
|
+
}
|
|
2809
|
+
evaluatorRegistry.set(evaluator.name, evaluator);
|
|
2810
|
+
}
|
|
2811
|
+
const researchEvaluators = [
|
|
2812
|
+
[BUILT_IN_METRIC_CHECKER2, evaluateMetricCheckerContract],
|
|
2813
|
+
[BUILT_IN_REFERENCE_CHECK_COUNTER2, evaluateReferenceCheckCounterContract],
|
|
2814
|
+
[BUILT_IN_TEMPORAL_DEADLINE2, evaluateTemporalDeadlineContract],
|
|
2815
|
+
[BUILT_IN_MARKET_INDEX_COMPARATOR2, evaluateMarketIndexComparatorContract]
|
|
2816
|
+
];
|
|
2817
|
+
for (const [name, evaluate] of researchEvaluators) {
|
|
2818
|
+
if (evaluatorRegistry.has(name)) {
|
|
2819
|
+
continue;
|
|
2820
|
+
}
|
|
2821
|
+
evaluatorRegistry.set(name, { name, evaluate });
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
function normalizeTrigger(trigger) {
|
|
2825
|
+
if (trigger === "evidence_added") {
|
|
2826
|
+
return "evidence_added";
|
|
2827
|
+
}
|
|
2828
|
+
if (trigger === "periodic") {
|
|
2829
|
+
return "periodic";
|
|
2830
|
+
}
|
|
2831
|
+
if (trigger === "manual") {
|
|
2832
|
+
return "manual";
|
|
2833
|
+
}
|
|
2834
|
+
return "event_driven";
|
|
2835
|
+
}
|
|
2836
|
+
function resolveSchedulesForTrigger(trigger) {
|
|
2837
|
+
if (trigger === "evidence_added") {
|
|
2838
|
+
return /* @__PURE__ */ new Set(["on_evidence", "event_driven"]);
|
|
2839
|
+
}
|
|
2840
|
+
if (trigger === "periodic") {
|
|
2841
|
+
return /* @__PURE__ */ new Set(["periodic"]);
|
|
2842
|
+
}
|
|
2843
|
+
if (trigger === "manual") {
|
|
2844
|
+
return /* @__PURE__ */ new Set(["on_demand", "event_driven"]);
|
|
2845
|
+
}
|
|
2846
|
+
return /* @__PURE__ */ new Set(["event_driven"]);
|
|
2847
|
+
}
|
|
2848
|
+
async function executeContractEvaluation(args) {
|
|
2849
|
+
ensureBuiltInEvaluators();
|
|
2850
|
+
const evaluator = evaluatorRegistry.get(args.contract.condition.evaluator);
|
|
2851
|
+
let evaluation;
|
|
2852
|
+
if (evaluator) {
|
|
2853
|
+
try {
|
|
2854
|
+
evaluation = await evaluator.evaluate({
|
|
2855
|
+
belief: args.belief,
|
|
2856
|
+
contract: args.contract,
|
|
2857
|
+
ctx: args.ctx,
|
|
2858
|
+
now: args.now,
|
|
2859
|
+
resultData: args.resultData,
|
|
2860
|
+
trigger: args.trigger,
|
|
2861
|
+
inputData: args.inputData
|
|
2862
|
+
});
|
|
2863
|
+
} catch (error) {
|
|
2864
|
+
evaluation = {
|
|
2865
|
+
result: "error",
|
|
2866
|
+
rationale: error instanceof Error ? error.message : "Unknown evaluator error."
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
} else {
|
|
2870
|
+
evaluation = {
|
|
2871
|
+
result: "error",
|
|
2872
|
+
rationale: `No epistemic evaluator registered for "${args.contract.condition.evaluator}".`
|
|
2873
|
+
};
|
|
2874
|
+
}
|
|
2875
|
+
const confidenceBefore = confidenceSeed({
|
|
2876
|
+
beliefConfidence: args.belief.confidence,
|
|
2877
|
+
currentConfidence: args.currentConfidence
|
|
2878
|
+
});
|
|
2879
|
+
const modulationPlan = deriveContractModulationPlan({
|
|
2880
|
+
currentConfidence: confidenceBefore,
|
|
2881
|
+
modulation: args.contract.modulation,
|
|
2882
|
+
result: evaluation.result,
|
|
2883
|
+
resultConfidence: evaluation.confidence
|
|
2884
|
+
});
|
|
2885
|
+
let beliefConfidenceId;
|
|
2886
|
+
let confidenceAfter = confidenceBefore;
|
|
2887
|
+
if (modulationPlan) {
|
|
2888
|
+
const contractB = Math.max(0, Math.min(1, modulationPlan.confidenceAfter));
|
|
2889
|
+
const modulationResult = await applyBeliefConfidenceChange(args.ctx, {
|
|
2890
|
+
nodeId: args.contract.beliefNodeId,
|
|
2891
|
+
belief: contractB,
|
|
2892
|
+
disbelief: 1 - contractB,
|
|
2893
|
+
uncertainty: 0,
|
|
2894
|
+
baseRate: 0.5,
|
|
2895
|
+
trigger: modulationPlan.trigger,
|
|
2896
|
+
rationale: `Epistemic contract "${args.contract.title}" ${evaluation.result}: ${evaluation.rationale}`,
|
|
2897
|
+
authenticatedUserId: args.authenticatedUserId
|
|
2898
|
+
});
|
|
2899
|
+
beliefConfidenceId = modulationResult.beliefConfidenceId;
|
|
2900
|
+
confidenceAfter = typeof modulationResult.newConfidence === "number" ? modulationResult.newConfidence : modulationPlan.confidenceAfter;
|
|
2901
|
+
}
|
|
2902
|
+
const evaluationId = await args.ctx.db.insert("contractEvaluations", {
|
|
2903
|
+
contractId: args.contract.contractId,
|
|
2904
|
+
beliefNodeId: args.contract.beliefNodeId,
|
|
2905
|
+
result: evaluation.result,
|
|
2906
|
+
evaluatedAt: args.now,
|
|
2907
|
+
evaluator: args.contract.condition.evaluator,
|
|
2908
|
+
trigger: args.trigger,
|
|
2909
|
+
resultData: evaluation.data,
|
|
2910
|
+
modulationApplied: Boolean(modulationPlan),
|
|
2911
|
+
confidenceDelta: modulationPlan?.confidenceDelta,
|
|
2912
|
+
confidenceBefore: modulationPlan?.confidenceBefore,
|
|
2913
|
+
confidenceAfter: modulationPlan ? confidenceAfter : void 0,
|
|
2914
|
+
beliefConfidenceId,
|
|
2915
|
+
modulationRationale: evaluation.rationale,
|
|
2916
|
+
topicId: args.contract.topicId
|
|
2917
|
+
});
|
|
2918
|
+
const nextStatus = deriveContractStatus(
|
|
2919
|
+
evaluation.result,
|
|
2920
|
+
args.contract.status
|
|
2921
|
+
);
|
|
2922
|
+
await args.ctx.db.patch(contractDocId(args.contract), {
|
|
2923
|
+
status: nextStatus,
|
|
2924
|
+
lastEvaluatedAt: args.now,
|
|
2925
|
+
evaluationCount: (args.contract.evaluationCount ?? 0) + 1,
|
|
2926
|
+
updatedAt: args.now
|
|
2927
|
+
});
|
|
2928
|
+
return {
|
|
2929
|
+
evaluationId,
|
|
2930
|
+
result: evaluation.result,
|
|
2931
|
+
status: nextStatus,
|
|
2932
|
+
confidenceBefore,
|
|
2933
|
+
confidenceAfter,
|
|
2934
|
+
rationale: evaluation.rationale,
|
|
2935
|
+
data: evaluation.data,
|
|
2936
|
+
currentConfidence: confidenceAfter
|
|
2937
|
+
};
|
|
2474
2938
|
}
|
|
2475
|
-
function
|
|
2476
|
-
const
|
|
2477
|
-
const
|
|
2478
|
-
|
|
2479
|
-
|
|
2939
|
+
async function evaluateContractsForTriggerBatch(args) {
|
|
2940
|
+
const startedAt = Date.now();
|
|
2941
|
+
const contracts = await loadContractsForTrigger({
|
|
2942
|
+
ctx: args.ctx,
|
|
2943
|
+
beliefNodeId: args.belief._id,
|
|
2944
|
+
trigger: normalizeTrigger(args.trigger),
|
|
2945
|
+
contractIds: args.contractIds
|
|
2946
|
+
});
|
|
2947
|
+
const batchLimit = Math.max(
|
|
2948
|
+
1,
|
|
2949
|
+
Math.min(
|
|
2950
|
+
args.maxBatchSize ?? MAX_CONTRACT_EVALUATION_BATCH_SIZE,
|
|
2951
|
+
MAX_CONTRACT_EVALUATION_BATCH_SIZE
|
|
2952
|
+
)
|
|
2953
|
+
);
|
|
2954
|
+
const currentBatch = contracts.slice(0, batchLimit);
|
|
2955
|
+
const overflowContracts = contracts.slice(batchLimit);
|
|
2956
|
+
let runningConfidence = typeof args.belief.confidence === "number" ? args.belief.confidence : 0.5;
|
|
2957
|
+
const results = [];
|
|
2958
|
+
for (const contract of currentBatch) {
|
|
2959
|
+
const evaluation = await executeContractEvaluation({
|
|
2960
|
+
ctx: args.ctx,
|
|
2961
|
+
belief: args.belief,
|
|
2962
|
+
contract,
|
|
2963
|
+
now: Date.now(),
|
|
2964
|
+
trigger: normalizeTrigger(args.trigger),
|
|
2965
|
+
inputData: args.inputData,
|
|
2966
|
+
authenticatedUserId: args.authenticatedUserId,
|
|
2967
|
+
currentConfidence: runningConfidence
|
|
2968
|
+
});
|
|
2969
|
+
runningConfidence = evaluation.currentConfidence;
|
|
2970
|
+
args.belief.confidence = runningConfidence;
|
|
2971
|
+
results.push({
|
|
2972
|
+
contractId: contract.contractId,
|
|
2973
|
+
result: evaluation.result,
|
|
2974
|
+
status: evaluation.status,
|
|
2975
|
+
confidenceAfter: evaluation.confidenceAfter
|
|
2976
|
+
});
|
|
2480
2977
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
}
|
|
2486
|
-
const filePath = asString(diagnostic.filePath) ?? asString(diagnostic.file) ?? asString(asRecord(diagnostic.location)?.filePath) ?? asString(asRecord(asRecord(diagnostic.location)?.path)?.file);
|
|
2487
|
-
const message = asString(diagnostic.message) ?? "TypeScript error";
|
|
2488
|
-
return [
|
|
2978
|
+
if (overflowContracts.length > 0) {
|
|
2979
|
+
await args.ctx.scheduler.runAfter(
|
|
2980
|
+
0,
|
|
2981
|
+
"epistemicContracts.processContractEvaluationOverflow",
|
|
2489
2982
|
{
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
}
|
|
2497
|
-
function parseTextDiagnostics(resultData) {
|
|
2498
|
-
const diagnostics = [];
|
|
2499
|
-
const patterns = [
|
|
2500
|
-
/^(.+?)\((\d+),(\d+)\): error TS(\d+): (.+)$/gm,
|
|
2501
|
-
/^(.+?):(\d+):(\d+) - error TS(\d+): (.+)$/gm
|
|
2502
|
-
];
|
|
2503
|
-
for (const text of extractTextCandidates(resultData)) {
|
|
2504
|
-
for (const pattern of patterns) {
|
|
2505
|
-
for (const match of text.matchAll(pattern)) {
|
|
2506
|
-
diagnostics.push({
|
|
2507
|
-
code: match[4],
|
|
2508
|
-
filePath: normalizeFilePath(match[1] ?? ""),
|
|
2509
|
-
message: match[5] ?? "TypeScript error"
|
|
2510
|
-
});
|
|
2983
|
+
beliefNodeId: args.belief._id,
|
|
2984
|
+
trigger: normalizeTrigger(args.trigger),
|
|
2985
|
+
contractIds: overflowContracts.map((contract) => contract.contractId),
|
|
2986
|
+
inputData: args.inputData,
|
|
2987
|
+
authenticatedUserId: args.authenticatedUserId,
|
|
2988
|
+
maxBatchSize: batchLimit
|
|
2511
2989
|
}
|
|
2512
|
-
|
|
2990
|
+
);
|
|
2513
2991
|
}
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2992
|
+
const executionTimeMs = Date.now() - startedAt;
|
|
2993
|
+
console.info("[epistemicContracts] processed contract evaluation batch", {
|
|
2994
|
+
beliefNodeId: String(args.belief._id),
|
|
2995
|
+
trigger: normalizeTrigger(args.trigger),
|
|
2996
|
+
batchSize: currentBatch.length,
|
|
2997
|
+
overflowCount: overflowContracts.length,
|
|
2998
|
+
executionTimeMs
|
|
2999
|
+
});
|
|
3000
|
+
return {
|
|
3001
|
+
totalContracts: contracts.length,
|
|
3002
|
+
processedCount: currentBatch.length,
|
|
3003
|
+
overflowCount: overflowContracts.length,
|
|
3004
|
+
scheduledOverflow: overflowContracts.length > 0,
|
|
3005
|
+
batchSize: currentBatch.length,
|
|
3006
|
+
executionTimeMs,
|
|
3007
|
+
trigger: normalizeTrigger(args.trigger),
|
|
3008
|
+
results
|
|
3009
|
+
};
|
|
2519
3010
|
}
|
|
2520
|
-
function
|
|
2521
|
-
const
|
|
2522
|
-
return
|
|
2523
|
-
(diagnostic) => somePatternMatches(diagnostic.filePath, config.filePatterns)
|
|
2524
|
-
);
|
|
3011
|
+
async function loadContractsForBelief(args) {
|
|
3012
|
+
const rows = await args.ctx.db.query("epistemicContracts").withIndex("by_belief", (q) => q.eq("beliefNodeId", args.beliefNodeId)).collect();
|
|
3013
|
+
return rows;
|
|
2525
3014
|
}
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
3015
|
+
async function loadContractsForTrigger(args) {
|
|
3016
|
+
const contracts = await loadContractsForBelief(args);
|
|
3017
|
+
ensureBuiltInEvaluators();
|
|
3018
|
+
const allowedSchedules = resolveSchedulesForTrigger(args.trigger);
|
|
3019
|
+
const contractIdFilter = args.contractIds && args.contractIds.length > 0 ? new Set(args.contractIds) : null;
|
|
3020
|
+
return contracts.filter((contract) => {
|
|
3021
|
+
if (contract.status === "archived") {
|
|
3022
|
+
return false;
|
|
2533
3023
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
evaluate(args) {
|
|
2537
|
-
const config = parseConfig4(args.contract.condition);
|
|
2538
|
-
if (!args.resultData) {
|
|
2539
|
-
return {
|
|
2540
|
-
result: "error",
|
|
2541
|
-
rationale: "tsc_checker requires TypeScript diagnostic resultData."
|
|
2542
|
-
};
|
|
3024
|
+
if (contract.conditionType === "composite") {
|
|
3025
|
+
return false;
|
|
2543
3026
|
}
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
const matchedDiagnostics = getMatchedDiagnostics2(args.contract, args.resultData);
|
|
2547
|
-
if (matchedDiagnostics.length === 0 && exitCode !== 0 && exitCode !== null) {
|
|
2548
|
-
return {
|
|
2549
|
-
result: "inconclusive",
|
|
2550
|
-
rationale: "TypeScript reported errors, but none matched the configured file patterns."
|
|
2551
|
-
};
|
|
3027
|
+
if (!evaluatorRegistry.has(contract.condition.evaluator)) {
|
|
3028
|
+
return false;
|
|
2552
3029
|
}
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
),
|
|
2559
|
-
rationale: conditionSatisfied ? `TypeScript reported no matching diagnostics for ${config.filePatterns.join(", ")}.` : `TypeScript found ${matchedDiagnostics.length} matching diagnostic(s): ${matchedDiagnostics.map(
|
|
2560
|
-
(diagnostic) => diagnostic.filePath ? `${diagnostic.filePath}${diagnostic.code ? ` (TS${diagnostic.code})` : ""}` : diagnostic.message
|
|
2561
|
-
).join(", ")}.`,
|
|
2562
|
-
data: {
|
|
2563
|
-
exitCode,
|
|
2564
|
-
filePatterns: config.filePatterns,
|
|
2565
|
-
matchedDiagnostics
|
|
2566
|
-
}
|
|
2567
|
-
};
|
|
2568
|
-
}
|
|
2569
|
-
};
|
|
2570
|
-
|
|
2571
|
-
// src/evaluators/index.ts
|
|
2572
|
-
var ENGINEERING_EPISTEMIC_EVALUATORS = [
|
|
2573
|
-
testRunnerEvaluator,
|
|
2574
|
-
tscCheckerEvaluator,
|
|
2575
|
-
lintCheckerEvaluator,
|
|
2576
|
-
sentryCheckerEvaluator
|
|
2577
|
-
];
|
|
2578
|
-
var ENGINEERING_EVALUATOR_NAMES = new Set(
|
|
2579
|
-
ENGINEERING_EPISTEMIC_EVALUATORS.map((evaluator) => evaluator.name)
|
|
2580
|
-
);
|
|
2581
|
-
function getEngineeringEpistemicEvaluator(name) {
|
|
2582
|
-
return ENGINEERING_EPISTEMIC_EVALUATORS.find(
|
|
2583
|
-
(evaluator) => evaluator.name === name
|
|
2584
|
-
);
|
|
3030
|
+
if (contractIdFilter) {
|
|
3031
|
+
return contractIdFilter.has(contract.contractId);
|
|
3032
|
+
}
|
|
3033
|
+
return allowedSchedules.has(contract.evaluationSchedule);
|
|
3034
|
+
});
|
|
2585
3035
|
}
|
|
2586
3036
|
|
|
2587
3037
|
// src/epistemicContracts.handlers.ts
|
|
@@ -2597,6 +3047,24 @@ function resolveSchedulesForTrigger2(trigger) {
|
|
|
2597
3047
|
}
|
|
2598
3048
|
return /* @__PURE__ */ new Set(["event_driven"]);
|
|
2599
3049
|
}
|
|
3050
|
+
function contractTables(ctx) {
|
|
3051
|
+
return ctx.db;
|
|
3052
|
+
}
|
|
3053
|
+
function assertBeliefNode(value, message = "Belief not found.") {
|
|
3054
|
+
if (!value || typeof value !== "object" || value.nodeType !== "belief") {
|
|
3055
|
+
throw new Error(message);
|
|
3056
|
+
}
|
|
3057
|
+
return value;
|
|
3058
|
+
}
|
|
3059
|
+
function normalizeEngineeringTrigger(trigger) {
|
|
3060
|
+
if (trigger === "manual") {
|
|
3061
|
+
return "manual";
|
|
3062
|
+
}
|
|
3063
|
+
if (trigger === "evidence_added") {
|
|
3064
|
+
return "evidence_added";
|
|
3065
|
+
}
|
|
3066
|
+
return trigger;
|
|
3067
|
+
}
|
|
2600
3068
|
async function requireAuth(ctx) {
|
|
2601
3069
|
const userId = await getCurrentUserId(ctx);
|
|
2602
3070
|
if (!userId) {
|
|
@@ -2632,17 +3100,21 @@ async function requireTopicReadAccess(ctx, beliefs, userId) {
|
|
|
2632
3100
|
projectIds.add(belief.projectId);
|
|
2633
3101
|
}
|
|
2634
3102
|
for (const projectId of projectIds) {
|
|
2635
|
-
const hasAccess = await checkProjectAccess(
|
|
3103
|
+
const hasAccess = await checkProjectAccess(
|
|
3104
|
+
ctx,
|
|
3105
|
+
projectId,
|
|
3106
|
+
userId
|
|
3107
|
+
);
|
|
2636
3108
|
if (!hasAccess) {
|
|
2637
3109
|
throw new Error("Project access required.");
|
|
2638
3110
|
}
|
|
2639
3111
|
}
|
|
2640
3112
|
}
|
|
2641
3113
|
async function getContractByContractId(ctx, contractId) {
|
|
2642
|
-
return await ctx.
|
|
3114
|
+
return await contractTables(ctx).query("epistemicContracts").withIndex("by_contractId", (q) => q.eq("contractId", contractId)).first();
|
|
2643
3115
|
}
|
|
2644
3116
|
async function getLatestEvaluation(ctx, contractId) {
|
|
2645
|
-
const evaluations = await ctx.
|
|
3117
|
+
const evaluations = await contractTables(ctx).query("contractEvaluations").withIndex("by_contract_time", (q) => q.eq("contractId", contractId)).order("desc").take(1);
|
|
2646
3118
|
return evaluations[0] ?? null;
|
|
2647
3119
|
}
|
|
2648
3120
|
var evaluateEvidenceCount = query({
|
|
@@ -2652,10 +3124,7 @@ var evaluateEvidenceCount = query({
|
|
|
2652
3124
|
returns: permissiveReturn,
|
|
2653
3125
|
handler: async (ctx, args) => {
|
|
2654
3126
|
const userId = await requireAuth(ctx);
|
|
2655
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2656
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2657
|
-
throw new Error("Belief not found.");
|
|
2658
|
-
}
|
|
3127
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2659
3128
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2660
3129
|
return await computeEvidenceCountMetric(ctx, args.beliefNodeId);
|
|
2661
3130
|
}
|
|
@@ -2667,10 +3136,7 @@ var evaluateContradictionStatus = query({
|
|
|
2667
3136
|
returns: permissiveReturn,
|
|
2668
3137
|
handler: async (ctx, args) => {
|
|
2669
3138
|
const userId = await requireAuth(ctx);
|
|
2670
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2671
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2672
|
-
throw new Error("Belief not found.");
|
|
2673
|
-
}
|
|
3139
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2674
3140
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2675
3141
|
return await computeContradictionCounts(ctx, args.beliefNodeId);
|
|
2676
3142
|
}
|
|
@@ -2682,10 +3148,7 @@ var evaluateEdgeFreshness = query({
|
|
|
2682
3148
|
returns: permissiveReturn,
|
|
2683
3149
|
handler: async (ctx, args) => {
|
|
2684
3150
|
const userId = await requireAuth(ctx);
|
|
2685
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2686
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2687
|
-
throw new Error("Belief not found.");
|
|
2688
|
-
}
|
|
3151
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2689
3152
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2690
3153
|
return await computeEvidenceFreshness(ctx, args.beliefNodeId);
|
|
2691
3154
|
}
|
|
@@ -2697,10 +3160,7 @@ var evaluateDependentBeliefCount = query({
|
|
|
2697
3160
|
returns: permissiveReturn,
|
|
2698
3161
|
handler: async (ctx, args) => {
|
|
2699
3162
|
const userId = await requireAuth(ctx);
|
|
2700
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2701
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2702
|
-
throw new Error("Belief not found.");
|
|
2703
|
-
}
|
|
3163
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2704
3164
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2705
3165
|
return await computeDependentBeliefCount(ctx, args.beliefNodeId);
|
|
2706
3166
|
}
|
|
@@ -2764,10 +3224,7 @@ var createEpistemicContract = mutation({
|
|
|
2764
3224
|
ctx,
|
|
2765
3225
|
args.authenticatedUserId
|
|
2766
3226
|
);
|
|
2767
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2768
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2769
|
-
throw new Error("Belief not found.");
|
|
2770
|
-
}
|
|
3227
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2771
3228
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2772
3229
|
const now = Date.now();
|
|
2773
3230
|
const contractId = generateGlobalId();
|
|
@@ -2822,10 +3279,10 @@ var evaluateContract = mutation({
|
|
|
2822
3279
|
if (contract.status === "archived") {
|
|
2823
3280
|
throw new Error("Archived contracts cannot be evaluated.");
|
|
2824
3281
|
}
|
|
2825
|
-
const belief =
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
3282
|
+
const belief = assertBeliefNode(
|
|
3283
|
+
await ctx.db.get(contract.beliefNodeId),
|
|
3284
|
+
"Belief not found for contract."
|
|
3285
|
+
);
|
|
2829
3286
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2830
3287
|
const evaluation = await executeContractEvaluation({
|
|
2831
3288
|
ctx,
|
|
@@ -2863,14 +3320,11 @@ var evaluateEngineeringContracts = mutation({
|
|
|
2863
3320
|
ctx,
|
|
2864
3321
|
args.authenticatedUserId
|
|
2865
3322
|
);
|
|
2866
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2867
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2868
|
-
throw new Error("Belief not found.");
|
|
2869
|
-
}
|
|
3323
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2870
3324
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2871
3325
|
const trigger = args.trigger ?? "event_driven";
|
|
2872
3326
|
const allowedSchedules = resolveSchedulesForTrigger2(
|
|
2873
|
-
trigger
|
|
3327
|
+
normalizeEngineeringTrigger(trigger)
|
|
2874
3328
|
);
|
|
2875
3329
|
const payloadByEvaluator = /* @__PURE__ */ new Map([
|
|
2876
3330
|
["test_runner", args.testOutput],
|
|
@@ -2949,10 +3403,7 @@ var evaluateContractsForTrigger = mutation({
|
|
|
2949
3403
|
ctx,
|
|
2950
3404
|
args.authenticatedUserId
|
|
2951
3405
|
);
|
|
2952
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2953
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2954
|
-
throw new Error("Belief not found.");
|
|
2955
|
-
}
|
|
3406
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2956
3407
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2957
3408
|
return await evaluateContractsForTriggerBatch({
|
|
2958
3409
|
ctx,
|
|
@@ -2975,10 +3426,7 @@ var processContractEvaluationOverflow = internalMutation({
|
|
|
2975
3426
|
},
|
|
2976
3427
|
returns: permissiveReturn,
|
|
2977
3428
|
handler: async (ctx, args) => {
|
|
2978
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2979
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2980
|
-
throw new Error("Belief not found.");
|
|
2981
|
-
}
|
|
3429
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2982
3430
|
return await evaluateContractsForTriggerBatch({
|
|
2983
3431
|
ctx,
|
|
2984
3432
|
belief,
|
|
@@ -3017,15 +3465,9 @@ var getContractStatus = query({
|
|
|
3017
3465
|
const contract = await getContractByContractId(ctx, args.contractId);
|
|
3018
3466
|
contracts = contract ? [contract] : [];
|
|
3019
3467
|
} else if (args.beliefNodeId) {
|
|
3020
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
3021
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
3022
|
-
throw new Error("Belief not found.");
|
|
3023
|
-
}
|
|
3468
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
3024
3469
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
3025
|
-
contracts = await ctx.
|
|
3026
|
-
"by_belief",
|
|
3027
|
-
(q) => q.eq("beliefNodeId", args.beliefNodeId)
|
|
3028
|
-
).collect();
|
|
3470
|
+
contracts = await contractTables(ctx).query("epistemicContracts").withIndex("by_belief", (q) => q.eq("beliefNodeId", args.beliefNodeId)).collect();
|
|
3029
3471
|
}
|
|
3030
3472
|
if (contracts.length > 0) {
|
|
3031
3473
|
const contractBeliefDocs = await Promise.all(
|
|
@@ -3033,15 +3475,14 @@ var getContractStatus = query({
|
|
|
3033
3475
|
);
|
|
3034
3476
|
const contractBeliefs = [];
|
|
3035
3477
|
for (const belief of contractBeliefDocs) {
|
|
3036
|
-
|
|
3037
|
-
throw new Error("Belief not found.");
|
|
3038
|
-
}
|
|
3039
|
-
contractBeliefs.push(belief);
|
|
3478
|
+
contractBeliefs.push(assertBeliefNode(belief));
|
|
3040
3479
|
}
|
|
3041
3480
|
await requireTopicReadAccess(ctx, contractBeliefs, userId);
|
|
3042
3481
|
}
|
|
3043
3482
|
if (args.status) {
|
|
3044
|
-
contracts = contracts.filter(
|
|
3483
|
+
contracts = contracts.filter(
|
|
3484
|
+
(contract) => contract.status === args.status
|
|
3485
|
+
);
|
|
3045
3486
|
}
|
|
3046
3487
|
const rows = await Promise.all(
|
|
3047
3488
|
contracts.map(async (contract) => ({
|
|
@@ -3060,21 +3501,22 @@ var getContractCoverage = query({
|
|
|
3060
3501
|
},
|
|
3061
3502
|
returns: permissiveReturn,
|
|
3062
3503
|
handler: async (ctx, args) => {
|
|
3063
|
-
const contracts = await ctx.
|
|
3504
|
+
const contracts = await contractTables(ctx).query("epistemicContracts").withIndex("by_topic", (q) => q.eq("topicId", args.topicId)).collect();
|
|
3064
3505
|
const userId = await resolveAuthenticatedUserId(
|
|
3065
3506
|
ctx,
|
|
3066
3507
|
args.authenticatedUserId
|
|
3067
3508
|
);
|
|
3068
|
-
const
|
|
3509
|
+
const beliefRows = await ctx.db.query("epistemicNodes").withIndex(
|
|
3069
3510
|
"by_topic_type",
|
|
3070
3511
|
(q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
|
|
3071
3512
|
).collect();
|
|
3513
|
+
const beliefs = beliefRows.map((belief) => assertBeliefNode(belief));
|
|
3072
3514
|
await requireTopicReadAccess(ctx, beliefs, userId);
|
|
3073
3515
|
const recentEvaluationLimit = Math.max(
|
|
3074
3516
|
0,
|
|
3075
3517
|
Math.min(args.recentEvaluationLimit ?? 5, 25)
|
|
3076
3518
|
);
|
|
3077
|
-
const recentEvaluations = recentEvaluationLimit === 0 ? [] : await ctx.
|
|
3519
|
+
const recentEvaluations = recentEvaluationLimit === 0 ? [] : await contractTables(ctx).query("contractEvaluations").withIndex("by_topic_time", (q) => q.eq("topicId", args.topicId)).order("desc").take(recentEvaluationLimit);
|
|
3078
3520
|
const contractBeliefIds = new Set(
|
|
3079
3521
|
contracts.filter((contract) => contract.status !== "archived").map((contract) => String(contract.beliefNodeId))
|
|
3080
3522
|
);
|