@lucern/graph-primitives 1.0.29 → 1.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
- package/dist/beliefDecay.d.ts +1 -1
- package/dist/beliefDecay.js +448 -314
- package/dist/beliefDecay.js.map +1 -1
- package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
- package/dist/beliefEvidenceLinks.d.ts +1 -1
- package/dist/beliefEvidenceLinks.js +843 -624
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
- package/dist/beliefEvidenceLinks.operational.js +91 -18
- package/dist/beliefEvidenceLinks.operational.js.map +1 -1
- package/dist/beliefLifecycle.js.map +1 -1
- package/dist/confidencePropagationDispatch.d.ts +28 -27
- package/dist/confidencePropagationDispatch.js +157 -99
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
- package/dist/contradictions.d.ts +1 -1
- package/dist/contradictions.js +395 -225
- package/dist/contradictions.js.map +1 -1
- package/dist/convex.d.ts +65 -30
- package/dist/convex.js +7 -3
- package/dist/convex.js.map +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/edgeValidation.js +293 -85
- package/dist/edgeValidation.js.map +1 -1
- package/dist/edges/contains.d.ts +1 -1
- package/dist/edges/contains.js.map +1 -1
- package/dist/edges/contradicts.d.ts +1 -1
- package/dist/edges/contradicts.js.map +1 -1
- package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
- package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
- package/dist/edges/depends-on.js.map +1 -0
- package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
- package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
- package/dist/edges/derived-from.js.map +1 -0
- package/dist/edges/elaborates.d.ts +1 -1
- package/dist/edges/elaborates.js.map +1 -1
- package/dist/edges/index.d.ts +7 -3
- package/dist/edges/index.js +7 -4
- package/dist/edges/index.js.map +1 -1
- package/dist/edges/informs.d.ts +1 -1
- package/dist/edges/informs.js.map +1 -1
- package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
- package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
- package/dist/edges/propagation-types.js.map +1 -0
- package/dist/edges/refutes.d.ts +1 -1
- package/dist/edges/refutes.js.map +1 -1
- package/dist/edges/supports.d.ts +1 -1
- package/dist/edges/supports.js.map +1 -1
- package/dist/edges/tests.d.ts +1 -1
- package/dist/edges/tests.js.map +1 -1
- package/dist/edges/utils.d.ts +1 -1
- package/dist/edges/utils.js.map +1 -1
- package/dist/embeddingTrigger.d.ts +14 -6
- package/dist/embeddingTrigger.js +11 -14
- package/dist/embeddingTrigger.js.map +1 -1
- package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
- package/dist/entityBridge.d.ts +1 -1
- package/dist/entityBridge.js +602 -225
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityCanonicalMatch.d.ts +14 -12
- package/dist/entityCanonicalMatch.js.map +1 -1
- package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
- package/dist/entityLifecycle.d.ts +1 -1
- package/dist/entityLifecycle.js +854 -480
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
- package/dist/entityValidation.d.ts +3 -1
- package/dist/entityValidation.js +60 -8
- package/dist/entityValidation.js.map +1 -1
- package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
- package/dist/epistemicAnswers.d.ts +1 -1
- package/dist/epistemicAnswers.js +587 -545
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.d.ts +8 -8
- package/dist/epistemicBeliefs.admin.js +365 -166
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.d.ts +8 -8
- package/dist/epistemicBeliefs.backfills.js +655 -289
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.d.ts +19 -15
- package/dist/epistemicBeliefs.confidence.js +633 -386
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.d.ts +6 -6
- package/dist/epistemicBeliefs.core.js +717 -371
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.d.ts +11 -9
- package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
- package/dist/epistemicBeliefs.forkEvidence.js +8 -8
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
- package/dist/epistemicBeliefs.helpers.d.ts +68 -49
- package/dist/epistemicBeliefs.helpers.js +358 -211
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.d.ts +5 -5
- package/dist/epistemicBeliefs.internal.js +1248 -1026
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +4942 -3590
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
- package/dist/epistemicBeliefs.lifecycle.js +1138 -781
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.d.ts +7 -7
- package/dist/epistemicBeliefs.links.js +404 -267
- package/dist/epistemicBeliefs.links.js.map +1 -1
- package/dist/epistemicBeliefs.queries.d.ts +4 -4
- package/dist/epistemicBeliefs.queries.js +175 -20
- package/dist/epistemicBeliefs.queries.js.map +1 -1
- package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
- package/dist/epistemicBeliefs.topicAnchor.js +12 -5
- package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
- package/dist/epistemicContracts.d.ts +28 -3
- package/dist/epistemicContracts.evaluators.d.ts +2 -0
- package/dist/epistemicContracts.evaluators.js +1062 -576
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.d.ts +15 -32
- package/dist/epistemicContracts.handlers.js +1829 -1351
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +1131 -636
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicContracts.metrics.d.ts +2 -0
- package/dist/epistemicContracts.metrics.js +375 -158
- package/dist/epistemicContracts.metrics.js.map +1 -1
- package/dist/epistemicContracts.types.d.ts +87 -81
- package/dist/epistemicEdgeCreation.d.ts +2 -0
- package/dist/epistemicEdgeCreation.js +87 -16
- package/dist/epistemicEdgeCreation.js.map +1 -1
- package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
- package/dist/epistemicEdges.d.ts +6 -5
- package/dist/epistemicEdges.handlers.d.ts +3 -3
- package/dist/epistemicEdges.handlers.js +129 -24
- package/dist/epistemicEdges.handlers.js.map +1 -1
- package/dist/epistemicEdges.helpers.d.ts +6 -4
- package/dist/epistemicEdges.helpers.js +37 -2
- package/dist/epistemicEdges.helpers.js.map +1 -1
- package/dist/epistemicEdges.js +1966 -1202
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.d.ts +7 -7
- package/dist/epistemicEdges.mutations.js +956 -579
- package/dist/epistemicEdges.mutations.js.map +1 -1
- package/dist/epistemicEdges.queries.d.ts +16 -16
- package/dist/epistemicEdges.queries.js +639 -367
- package/dist/epistemicEdges.queries.js.map +1 -1
- package/dist/epistemicEdges.types.d.ts +10 -8
- package/dist/epistemicEvidence.d.ts +4 -1
- package/dist/epistemicEvidence.js +933 -532
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.d.ts +26 -10
- package/dist/epistemicEvidenceHelpers.js +239 -200
- package/dist/epistemicEvidenceHelpers.js.map +1 -1
- package/dist/epistemicEvidenceMutations.d.ts +8 -8
- package/dist/epistemicEvidenceMutations.js +840 -692
- package/dist/epistemicEvidenceMutations.js.map +1 -1
- package/dist/epistemicEvidenceQueries.d.ts +8 -8
- package/dist/epistemicEvidenceQueries.js +514 -238
- package/dist/epistemicEvidenceQueries.js.map +1 -1
- package/dist/epistemicHelpers.d.ts +4 -2
- package/dist/epistemicHelpers.js +308 -134
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicInsert.d.ts +16 -4
- package/dist/epistemicInsert.js +6 -3
- package/dist/epistemicInsert.js.map +1 -1
- package/dist/epistemicLayerRules.d.ts +10 -8
- package/dist/epistemicLayerRules.js +1 -5
- package/dist/epistemicLayerRules.js.map +1 -1
- package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
- package/dist/epistemicLinking.d.ts +1 -1
- package/dist/epistemicLinking.js +177 -100
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodeCreation.d.ts +2 -0
- package/dist/epistemicNodeCreation.js +203 -40
- package/dist/epistemicNodeCreation.js.map +1 -1
- package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
- package/dist/epistemicNodes.d.ts +3 -3
- package/dist/epistemicNodes.helpers.d.ts +24 -15
- package/dist/epistemicNodes.helpers.js.map +1 -1
- package/dist/epistemicNodes.internal.d.ts +6 -6
- package/dist/epistemicNodes.internal.js +389 -319
- package/dist/epistemicNodes.internal.js.map +1 -1
- package/dist/epistemicNodes.js +700 -504
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.d.ts +6 -6
- package/dist/epistemicNodes.mutations.js +560 -463
- package/dist/epistemicNodes.mutations.js.map +1 -1
- package/dist/epistemicNodes.queries.d.ts +8 -8
- package/dist/epistemicNodes.queries.js +311 -314
- package/dist/epistemicNodes.queries.js.map +1 -1
- package/dist/epistemicNodes.validators.d.ts +2 -2
- package/dist/epistemicNodes.validators.js.map +1 -1
- package/dist/epistemicQuestions.conviction.d.ts +8 -8
- package/dist/epistemicQuestions.conviction.js +665 -484
- package/dist/epistemicQuestions.conviction.js.map +1 -1
- package/dist/epistemicQuestions.create.d.ts +4 -4
- package/dist/epistemicQuestions.create.js +640 -612
- package/dist/epistemicQuestions.create.js.map +1 -1
- package/dist/epistemicQuestions.d.ts +8 -5
- package/dist/epistemicQuestions.evidence.d.ts +2 -2
- package/dist/epistemicQuestions.evidence.js +475 -383
- package/dist/epistemicQuestions.evidence.js.map +1 -1
- package/dist/epistemicQuestions.helpers.d.ts +125 -24
- package/dist/epistemicQuestions.helpers.js +240 -209
- package/dist/epistemicQuestions.helpers.js.map +1 -1
- package/dist/epistemicQuestions.js +3474 -2823
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
- package/dist/epistemicQuestions.lifecycle.js +607 -546
- package/dist/epistemicQuestions.lifecycle.js.map +1 -1
- package/dist/epistemicQuestions.queries.d.ts +12 -7
- package/dist/epistemicQuestions.queries.js +305 -244
- package/dist/epistemicQuestions.queries.js.map +1 -1
- package/dist/epistemicQuestions.sprint.d.ts +2 -2
- package/dist/epistemicQuestions.sprint.js +600 -394
- package/dist/epistemicQuestions.sprint.js.map +1 -1
- package/dist/epistemicQuestions.tail.d.ts +6 -6
- package/dist/epistemicQuestions.tail.js +572 -433
- package/dist/epistemicQuestions.tail.js.map +1 -1
- package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
- package/dist/epistemicSources.d.ts +1 -1
- package/dist/epistemicSources.js +351 -311
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.d.ts +8 -6
- package/dist/evaluators/index.js +399 -167
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
- package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
- package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
- package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
- package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
- package/dist/evaluators/shared.d.ts +2 -2
- package/dist/evaluators/shared.js +3 -1
- package/dist/evaluators/shared.js.map +1 -1
- package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
- package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
- package/dist/evaluators/test-runner-evaluator.js.map +1 -0
- package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
- package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
- package/dist/graphTypes.js +6 -2
- package/dist/graphTypes.js.map +1 -1
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +313 -93
- package/dist/helpers.js.map +1 -1
- package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
- package/dist/index.d.ts +86 -83
- package/dist/index.js +16914 -11760
- package/dist/index.js.map +1 -1
- package/dist/invariantEnforcement.d.ts +3 -3
- package/dist/invariantEnforcement.js.map +1 -1
- package/dist/logicalRoleInference.d.ts +2 -0
- package/dist/logicalRoleInference.js +1 -1
- package/dist/logicalRoleInference.js.map +1 -1
- package/dist/matcherFeedbackUtils.d.ts +2 -2
- package/dist/matcherFeedbackUtils.js.map +1 -1
- package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
- package/dist/ontology-matching.d.ts +1 -1
- package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
- package/dist/ontologyApproval.d.ts +1 -1
- package/dist/ontologyApproval.js +7 -1
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.d.ts +14 -24
- package/dist/ontologyDefinitions.js +269 -34
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyHelpers.d.ts +13 -13
- package/dist/ontologyHelpers.js.map +1 -1
- package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
- package/dist/ontologyRegistry.d.ts +1 -1
- package/dist/ontologyRegistry.js +34 -6
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
- package/dist/projectionReconciliation.d.ts +1 -1
- package/dist/projectionReconciliation.js +57 -10
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
- package/dist/projectionStaleness.d.ts +1 -1
- package/dist/projectionStaleness.js +8 -2
- package/dist/projectionStaleness.js.map +1 -1
- package/dist/proof-attestation.json +1 -1
- package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
- package/dist/questionEvidenceLinks.d.ts +1 -1
- package/dist/questionEvidenceLinks.js +564 -347
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
- package/dist/resolverTypes.d.ts +4 -2
- package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
- package/dist/resolvers.d.ts +5 -3
- package/dist/resolvers.js +121 -77
- package/dist/resolvers.js.map +1 -1
- package/dist/scopeResolverCompat.d.ts +10 -7
- package/dist/scopeResolverCompat.js +106 -123
- package/dist/scopeResolverCompat.js.map +1 -1
- package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
- package/dist/text-matching.d.ts +1 -1
- package/dist/topicOntologyResolver.d.ts +22 -21
- package/dist/topicOntologyResolver.js +54 -32
- package/dist/topicOntologyResolver.js.map +1 -1
- package/dist/topicProjectOverlay.d.ts +30 -20
- package/dist/topicProjectOverlay.js +120 -76
- package/dist/topicProjectOverlay.js.map +1 -1
- package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
- package/dist/topicScope.d.ts +3 -1
- package/dist/topicScope.js +104 -119
- package/dist/topicScope.js.map +1 -1
- package/dist/workflowBridge.d.ts +26 -15
- package/dist/workflowBridge.js +140 -144
- package/dist/workflowBridge.js.map +1 -1
- package/dist/workspaceIsolation.d.ts +14 -12
- package/dist/workspaceIsolation.js +108 -122
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +4 -4
- package/dist/edges/dependsOn.js.map +0 -1
- package/dist/edges/derivedFrom.js.map +0 -1
- package/dist/edges/propagationTypes.js.map +0 -1
- package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
- package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
- package/dist/{epistemicQuestions-bwHd2FWE.d.ts → epistemicQuestions-Do1fhYm5.d.ts} +4 -4
|
@@ -1,614 +1,201 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { requireScopeWriteAccess, 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 {
|
|
6
|
-
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';
|
|
7
8
|
import '@lucern/access-control/audience';
|
|
8
|
-
import {
|
|
9
|
+
import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
|
|
9
10
|
import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
10
11
|
import { generateGlobalId } from '@lucern/contracts/ids';
|
|
11
12
|
|
|
12
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;
|
|
13
23
|
|
|
14
|
-
// src/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
]);
|
|
23
|
-
function classifyContradictionStatus(status) {
|
|
24
|
-
if (typeof status !== "string") {
|
|
25
|
-
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;
|
|
26
32
|
}
|
|
27
|
-
|
|
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") {
|
|
28
53
|
return "active";
|
|
29
54
|
}
|
|
30
|
-
if (
|
|
31
|
-
return "
|
|
55
|
+
if (value === "fact" || value === "confirmed") {
|
|
56
|
+
return "resolved_true";
|
|
32
57
|
}
|
|
33
|
-
|
|
58
|
+
if (value === "disconfirmed" || value === "expired") {
|
|
59
|
+
return "resolved_false";
|
|
60
|
+
}
|
|
61
|
+
if (value === "deprecated") {
|
|
62
|
+
return "superseded";
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
34
65
|
}
|
|
35
|
-
function
|
|
36
|
-
if (typeof
|
|
37
|
-
return
|
|
66
|
+
function normalizeBeliefConfidence(confidence) {
|
|
67
|
+
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
68
|
+
return null;
|
|
38
69
|
}
|
|
39
|
-
if (
|
|
40
|
-
return
|
|
70
|
+
if (confidence >= 0 && confidence <= 1) {
|
|
71
|
+
return confidence;
|
|
41
72
|
}
|
|
42
|
-
if (
|
|
43
|
-
return
|
|
73
|
+
if (confidence > 1 && confidence <= 100) {
|
|
74
|
+
return confidence / 100;
|
|
44
75
|
}
|
|
45
76
|
return null;
|
|
46
77
|
}
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
).collect();
|
|
52
|
-
if (edges.length === 0) {
|
|
53
|
-
return [];
|
|
78
|
+
function isResolvedByConfidence(confidence) {
|
|
79
|
+
const normalized = normalizeBeliefConfidence(confidence);
|
|
80
|
+
if (normalized === null) {
|
|
81
|
+
return false;
|
|
54
82
|
}
|
|
55
|
-
|
|
56
|
-
return edges.flatMap((edge, index) => {
|
|
57
|
-
const node = nodes[index];
|
|
58
|
-
if (!node || node.nodeType !== "evidence" || node.status === "archived") {
|
|
59
|
-
return [];
|
|
60
|
-
}
|
|
61
|
-
return [{ edge, node }];
|
|
62
|
-
});
|
|
83
|
+
return normalized <= 0 || normalized >= 1;
|
|
63
84
|
}
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
85
|
+
function getPredictionMetaFromMetadata(metadata) {
|
|
86
|
+
return metadata?.predictionMeta;
|
|
87
|
+
}
|
|
88
|
+
function resolvedPredictionStatus(predictionMeta) {
|
|
89
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
90
|
+
return null;
|
|
69
91
|
}
|
|
70
|
-
|
|
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;
|
|
71
100
|
}
|
|
72
|
-
|
|
73
|
-
|
|
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;
|
|
74
117
|
}
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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";
|
|
86
142
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return contradictions.reduce(
|
|
90
|
-
(counts, contradiction) => {
|
|
91
|
-
const status = contradiction.resolutionStatus ?? contradiction.status ?? "unresolved";
|
|
92
|
-
if (classifyContradictionStatus(status) === "active") {
|
|
93
|
-
counts.activeCount += 1;
|
|
94
|
-
} else {
|
|
95
|
-
counts.resolvedCount += 1;
|
|
96
|
-
}
|
|
97
|
-
return counts;
|
|
98
|
-
},
|
|
99
|
-
{ activeCount: 0, resolvedCount: 0 }
|
|
100
|
-
);
|
|
143
|
+
function isPreValidationBeliefStatus(status) {
|
|
144
|
+
return status === "assumption" || status === "hypothesis";
|
|
101
145
|
}
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
if (
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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;
|
|
112
179
|
}
|
|
113
|
-
const newestEdgeAt = Math.max(...timestamps);
|
|
114
|
-
const oldestEdgeAt = Math.min(...timestamps);
|
|
115
180
|
return {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
oldestEdgeAt,
|
|
120
|
-
edgeCount: timestamps.length
|
|
181
|
+
topicId: scopeKey,
|
|
182
|
+
projectId: asMappedProjectId(node),
|
|
183
|
+
source: "topic_node"
|
|
121
184
|
};
|
|
122
185
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
(edge) => DEPENDENT_EDGE_TYPES.has(edge.edgeType)
|
|
127
|
-
);
|
|
128
|
-
if (dependencyEdges.length === 0) {
|
|
129
|
-
return 0;
|
|
186
|
+
function asMappedProjectId(topic) {
|
|
187
|
+
if (!topic) {
|
|
188
|
+
return;
|
|
130
189
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
190
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
191
|
+
topic[LEGACY_SCOPE_FIELD]
|
|
133
192
|
);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (node && node.nodeType === "belief" && node.status !== "archived" && node.status !== "deleted") {
|
|
137
|
-
uniqueBeliefIds.add(String(node._id));
|
|
138
|
-
}
|
|
193
|
+
if (directLegacyProjectId) {
|
|
194
|
+
return directLegacyProjectId;
|
|
139
195
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
switch (args.metric) {
|
|
144
|
-
case "evidence_count": {
|
|
145
|
-
const count = await computeEvidenceCountMetric(args.ctx, args.beliefNodeId);
|
|
146
|
-
return {
|
|
147
|
-
metric: args.metric,
|
|
148
|
-
value: count,
|
|
149
|
-
data: { evidenceCount: count }
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
case "contradiction_status": {
|
|
153
|
-
const counts = await computeContradictionCounts(args.ctx, args.beliefNodeId);
|
|
154
|
-
return {
|
|
155
|
-
metric: args.metric,
|
|
156
|
-
value: counts.activeCount,
|
|
157
|
-
data: counts
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
case "edge_freshness": {
|
|
161
|
-
const freshness = await computeEvidenceFreshness(
|
|
162
|
-
args.ctx,
|
|
163
|
-
args.beliefNodeId,
|
|
164
|
-
args.now
|
|
165
|
-
);
|
|
166
|
-
return {
|
|
167
|
-
metric: args.metric,
|
|
168
|
-
value: freshness.newestAgeMs,
|
|
169
|
-
data: freshness
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
case "dependent_count": {
|
|
173
|
-
const count = await computeDependentBeliefCount(args.ctx, args.beliefNodeId);
|
|
174
|
-
return {
|
|
175
|
-
metric: args.metric,
|
|
176
|
-
value: count,
|
|
177
|
-
data: { dependentCount: count }
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
default:
|
|
181
|
-
return {
|
|
182
|
-
metric: args.metric,
|
|
183
|
-
value: null,
|
|
184
|
-
data: {}
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
async function evaluateBuiltInEvidentialContract(args) {
|
|
189
|
-
const config = parseEvidentialEvaluatorConfig(args.contract.condition.evaluatorConfig);
|
|
190
|
-
const snapshot = await snapshotEvidentialMetric({
|
|
191
|
-
ctx: args.ctx,
|
|
192
|
-
beliefNodeId: args.belief._id,
|
|
193
|
-
metric: config.metric,
|
|
194
|
-
now: args.now
|
|
195
|
-
});
|
|
196
|
-
const comparisonSatisfied = snapshot.value !== null && compareMetricValue(config.operator, snapshot.value, config.threshold);
|
|
197
|
-
const result = args.contract.direction === "falsifies" ? comparisonSatisfied ? "disconfirmed" : "confirmed" : comparisonSatisfied ? "confirmed" : "disconfirmed";
|
|
198
|
-
return {
|
|
199
|
-
result,
|
|
200
|
-
rationale: buildEvidentialRationale({
|
|
201
|
-
config,
|
|
202
|
-
snapshot,
|
|
203
|
-
comparisonSatisfied,
|
|
204
|
-
result
|
|
205
|
-
}),
|
|
206
|
-
data: {
|
|
207
|
-
...snapshot.data,
|
|
208
|
-
metric: config.metric,
|
|
209
|
-
observedValue: snapshot.value,
|
|
210
|
-
operator: config.operator,
|
|
211
|
-
threshold: config.threshold,
|
|
212
|
-
action: config.action ?? "append_sl_scoring",
|
|
213
|
-
actionParams: config.actionParams
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
async function evaluateMetricCheckerContract(args) {
|
|
218
|
-
const config = parseMetricCheckerConfig(args.contract.condition.evaluatorConfig);
|
|
219
|
-
const input = getEvaluatorInputRecord(args.inputData, "metricData");
|
|
220
|
-
const metric = typeof input.metric === "string" && input.metric.length > 0 ? input.metric : config.metric;
|
|
221
|
-
const observedValue = pickFiniteNumber(input, [
|
|
222
|
-
"observedValue",
|
|
223
|
-
"currentValue",
|
|
224
|
-
"metricValue",
|
|
225
|
-
"value"
|
|
226
|
-
]) ?? config.observedValue ?? config.currentValue ?? config.metricValue ?? null;
|
|
227
|
-
if (observedValue === null) {
|
|
228
|
-
return {
|
|
229
|
-
result: "inconclusive",
|
|
230
|
-
rationale: `metric_checker is awaiting data for ${metric ?? args.contract.condition.expression}.`,
|
|
231
|
-
data: {
|
|
232
|
-
metric,
|
|
233
|
-
observedValue: null,
|
|
234
|
-
operator: config.operator,
|
|
235
|
-
threshold: config.threshold,
|
|
236
|
-
unit: config.unit
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
const comparisonSatisfied = compareMetricValue(
|
|
241
|
-
config.operator,
|
|
242
|
-
observedValue,
|
|
243
|
-
config.threshold
|
|
244
|
-
);
|
|
245
|
-
const result = resolveComparisonResult(args.contract.direction, comparisonSatisfied);
|
|
246
|
-
return {
|
|
247
|
-
result,
|
|
248
|
-
rationale: buildComparisonRationale({
|
|
249
|
-
label: metric ?? "metric",
|
|
250
|
-
observedValue,
|
|
251
|
-
operator: config.operator,
|
|
252
|
-
threshold: config.threshold,
|
|
253
|
-
comparisonSatisfied,
|
|
254
|
-
result,
|
|
255
|
-
unit: config.unit
|
|
256
|
-
}),
|
|
257
|
-
data: {
|
|
258
|
-
metric,
|
|
259
|
-
observedValue,
|
|
260
|
-
operator: config.operator,
|
|
261
|
-
threshold: config.threshold,
|
|
262
|
-
unit: config.unit
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
async function evaluateReferenceCheckCounterContract(args) {
|
|
267
|
-
const config = parseReferenceCheckCounterConfig(args.contract.condition.evaluatorConfig);
|
|
268
|
-
const input = getEvaluatorInputRecord(args.inputData, "referenceCheckData");
|
|
269
|
-
const tag = typeof input.tag === "string" && input.tag.trim().length > 0 ? input.tag.trim() : config.tag;
|
|
270
|
-
const snapshot = await computeTaggedEvidenceCount({
|
|
271
|
-
ctx: args.ctx,
|
|
272
|
-
beliefNodeId: args.belief._id,
|
|
273
|
-
tag,
|
|
274
|
-
caseSensitive: config.caseSensitive
|
|
275
|
-
});
|
|
276
|
-
const comparisonSatisfied = compareMetricValue(
|
|
277
|
-
config.operator,
|
|
278
|
-
snapshot.count,
|
|
279
|
-
config.threshold
|
|
280
|
-
);
|
|
281
|
-
const result = resolveComparisonResult(args.contract.direction, comparisonSatisfied);
|
|
282
|
-
return {
|
|
283
|
-
result,
|
|
284
|
-
rationale: buildComparisonRationale({
|
|
285
|
-
label: `reference checks tagged "${tag}"`,
|
|
286
|
-
observedValue: snapshot.count,
|
|
287
|
-
operator: config.operator,
|
|
288
|
-
threshold: config.threshold,
|
|
289
|
-
comparisonSatisfied,
|
|
290
|
-
result
|
|
291
|
-
}),
|
|
292
|
-
data: {
|
|
293
|
-
tag,
|
|
294
|
-
observedValue: snapshot.count,
|
|
295
|
-
referenceCheckCount: snapshot.count,
|
|
296
|
-
matchedEvidenceIds: snapshot.matchedEvidenceIds,
|
|
297
|
-
operator: config.operator,
|
|
298
|
-
threshold: config.threshold,
|
|
299
|
-
caseSensitive: config.caseSensitive ?? false
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
async function evaluateTemporalDeadlineContract(args) {
|
|
304
|
-
if (typeof args.contract.deadline !== "number" || !Number.isFinite(args.contract.deadline)) {
|
|
305
|
-
throw new Error(
|
|
306
|
-
"temporal_deadline requires contract.deadline to be set to a finite timestamp."
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
const config = parseTemporalDeadlineConfig(args.contract.condition.evaluatorConfig);
|
|
310
|
-
const input = getEvaluatorInputRecord(args.inputData, "temporalData");
|
|
311
|
-
const label = (typeof input.label === "string" && input.label.length > 0 ? input.label : config.label) ?? args.contract.title ?? args.contract.condition.expression;
|
|
312
|
-
const completedAt = pickFiniteNumber(input, [
|
|
313
|
-
"completedAt",
|
|
314
|
-
"observedAt",
|
|
315
|
-
"satisfiedAt",
|
|
316
|
-
"achievedAt"
|
|
317
|
-
]) ?? config.completedAt ?? config.observedAt ?? config.satisfiedAt ?? config.achievedAt;
|
|
318
|
-
const completed = input.completed === true || config.completed === true || completedAt !== void 0;
|
|
319
|
-
if (completed) {
|
|
320
|
-
if (completedAt !== void 0 && completedAt > args.contract.deadline) {
|
|
321
|
-
return {
|
|
322
|
-
result: "expired",
|
|
323
|
-
rationale: `${label} completed at ${completedAt}, after deadline ${args.contract.deadline}.`,
|
|
324
|
-
data: {
|
|
325
|
-
label,
|
|
326
|
-
deadline: args.contract.deadline,
|
|
327
|
-
completed: true,
|
|
328
|
-
completedAt,
|
|
329
|
-
missedDeadline: true,
|
|
330
|
-
overdueByMs: completedAt - args.contract.deadline
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
const result = args.contract.direction === "falsifies" ? "disconfirmed" : "confirmed";
|
|
335
|
-
return {
|
|
336
|
-
result,
|
|
337
|
-
rationale: `${label} completed before deadline ${args.contract.deadline}.`,
|
|
338
|
-
data: {
|
|
339
|
-
label,
|
|
340
|
-
deadline: args.contract.deadline,
|
|
341
|
-
completed: true,
|
|
342
|
-
completedAt: completedAt ?? null,
|
|
343
|
-
missedDeadline: false
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
if (args.now > args.contract.deadline) {
|
|
348
|
-
return {
|
|
349
|
-
result: "expired",
|
|
350
|
-
rationale: `${label} missed deadline ${args.contract.deadline}; temporal contract expired.`,
|
|
351
|
-
data: {
|
|
352
|
-
label,
|
|
353
|
-
deadline: args.contract.deadline,
|
|
354
|
-
completed: false,
|
|
355
|
-
overdueByMs: args.now - args.contract.deadline
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
return {
|
|
360
|
-
result: "inconclusive",
|
|
361
|
-
rationale: `${label} is still before deadline ${args.contract.deadline}; awaiting outcome.`,
|
|
362
|
-
data: {
|
|
363
|
-
label,
|
|
364
|
-
deadline: args.contract.deadline,
|
|
365
|
-
completed: false,
|
|
366
|
-
timeRemainingMs: args.contract.deadline - args.now
|
|
367
|
-
}
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
async function evaluateMarketIndexComparatorContract(args) {
|
|
371
|
-
const config = parseMarketIndexComparatorConfig(args.contract.condition.evaluatorConfig);
|
|
372
|
-
const input = getEvaluatorInputRecord(args.inputData, "marketIndexData");
|
|
373
|
-
const subject = typeof input.subject === "string" && input.subject.length > 0 ? input.subject : config.subject;
|
|
374
|
-
const benchmark = typeof input.benchmark === "string" && input.benchmark.length > 0 ? input.benchmark : config.benchmark;
|
|
375
|
-
const subjectValue = pickFiniteNumber(input, ["subjectValue", "primaryValue", "leftValue"]) ?? config.subjectValue ?? config.primaryValue ?? null;
|
|
376
|
-
const benchmarkValue = pickFiniteNumber(input, ["benchmarkValue", "comparisonValue", "rightValue"]) ?? config.benchmarkValue ?? config.comparisonValue ?? null;
|
|
377
|
-
if (subjectValue === null || benchmarkValue === null) {
|
|
378
|
-
return {
|
|
379
|
-
result: "inconclusive",
|
|
380
|
-
rationale: "market_index_comparator is awaiting both subject and benchmark values.",
|
|
381
|
-
data: {
|
|
382
|
-
subject,
|
|
383
|
-
subjectValue,
|
|
384
|
-
benchmark,
|
|
385
|
-
benchmarkValue,
|
|
386
|
-
operator: config.operator,
|
|
387
|
-
threshold: config.threshold
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
if (benchmarkValue === 0) {
|
|
392
|
-
throw new Error(
|
|
393
|
-
"market_index_comparator cannot compare against a zero benchmark value."
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
const differentialPercent = (subjectValue - benchmarkValue) / Math.abs(benchmarkValue) * 100;
|
|
397
|
-
const comparisonSatisfied = compareMetricValue(
|
|
398
|
-
config.operator,
|
|
399
|
-
differentialPercent,
|
|
400
|
-
config.threshold
|
|
401
|
-
);
|
|
402
|
-
const result = resolveComparisonResult(args.contract.direction, comparisonSatisfied);
|
|
403
|
-
return {
|
|
404
|
-
result,
|
|
405
|
-
rationale: buildComparisonRationale({
|
|
406
|
-
label: `${subject ?? "subject"} vs ${benchmark ?? "benchmark"} differential`,
|
|
407
|
-
observedValue: differentialPercent,
|
|
408
|
-
operator: config.operator,
|
|
409
|
-
threshold: config.threshold,
|
|
410
|
-
comparisonSatisfied,
|
|
411
|
-
result,
|
|
412
|
-
unit: "%"
|
|
413
|
-
}),
|
|
414
|
-
data: {
|
|
415
|
-
subject,
|
|
416
|
-
subjectValue,
|
|
417
|
-
benchmark,
|
|
418
|
-
benchmarkValue,
|
|
419
|
-
differentialPercent,
|
|
420
|
-
operator: config.operator,
|
|
421
|
-
threshold: config.threshold
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
var METRIC_COMPARATOR_EVALUATOR_NAMES = {
|
|
426
|
-
evidentialAliases: /* @__PURE__ */ new Set(["evidential", "built_in_evidential", "builtin_evidential"]),
|
|
427
|
-
metricChecker: "metric_checker",
|
|
428
|
-
referenceCheckCounter: "reference_check_counter",
|
|
429
|
-
temporalDeadline: "temporal_deadline",
|
|
430
|
-
marketIndexComparator: "market_index_comparator"
|
|
431
|
-
};
|
|
432
|
-
|
|
433
|
-
// src/beliefLifecycle.ts
|
|
434
|
-
var BELIEF_STATUS_VALUES = [
|
|
435
|
-
"assumption",
|
|
436
|
-
"hypothesis",
|
|
437
|
-
"active",
|
|
438
|
-
"superseded",
|
|
439
|
-
"resolved_true",
|
|
440
|
-
"resolved_false"
|
|
441
|
-
];
|
|
442
|
-
function isBeliefLifecycleStatus(value) {
|
|
443
|
-
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
444
|
-
}
|
|
445
|
-
function normalizeLegacyBeliefStatus(value) {
|
|
446
|
-
if (isBeliefLifecycleStatus(value)) {
|
|
447
|
-
return value;
|
|
448
|
-
}
|
|
449
|
-
if (value === "belief" || value === "established" || value === "emerging") {
|
|
450
|
-
return "active";
|
|
451
|
-
}
|
|
452
|
-
if (value === "fact" || value === "confirmed") {
|
|
453
|
-
return "resolved_true";
|
|
454
|
-
}
|
|
455
|
-
if (value === "disconfirmed" || value === "expired") {
|
|
456
|
-
return "resolved_false";
|
|
457
|
-
}
|
|
458
|
-
if (value === "deprecated") {
|
|
459
|
-
return "superseded";
|
|
460
|
-
}
|
|
461
|
-
return null;
|
|
462
|
-
}
|
|
463
|
-
function normalizeBeliefConfidence(confidence) {
|
|
464
|
-
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
465
|
-
return null;
|
|
466
|
-
}
|
|
467
|
-
if (confidence >= 0 && confidence <= 1) {
|
|
468
|
-
return confidence;
|
|
469
|
-
}
|
|
470
|
-
if (confidence > 1 && confidence <= 100) {
|
|
471
|
-
return confidence / 100;
|
|
472
|
-
}
|
|
473
|
-
return null;
|
|
474
|
-
}
|
|
475
|
-
function isResolvedByConfidence(confidence) {
|
|
476
|
-
const normalized = normalizeBeliefConfidence(confidence);
|
|
477
|
-
if (normalized === null) {
|
|
478
|
-
return false;
|
|
479
|
-
}
|
|
480
|
-
return normalized <= 0 || normalized >= 1;
|
|
481
|
-
}
|
|
482
|
-
function getPredictionMetaFromMetadata(metadata) {
|
|
483
|
-
return metadata?.predictionMeta;
|
|
484
|
-
}
|
|
485
|
-
function resolvedPredictionStatus(predictionMeta) {
|
|
486
|
-
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
487
|
-
return null;
|
|
488
|
-
}
|
|
489
|
-
const outcome = predictionMeta.outcome;
|
|
490
|
-
if (outcome === "confirmed") {
|
|
491
|
-
return "resolved_true";
|
|
492
|
-
}
|
|
493
|
-
if (outcome === "disconfirmed" || outcome === "expired") {
|
|
494
|
-
return "resolved_false";
|
|
495
|
-
}
|
|
496
|
-
return null;
|
|
497
|
-
}
|
|
498
|
-
function shouldTreatBeliefAsResolved(opts) {
|
|
499
|
-
if (isResolvedByConfidence(opts.confidence)) {
|
|
500
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
501
|
-
return normalized === 0 ? "resolved_false" : "resolved_true";
|
|
502
|
-
}
|
|
503
|
-
const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
|
|
504
|
-
if (directPredictionStatus) {
|
|
505
|
-
return directPredictionStatus;
|
|
506
|
-
}
|
|
507
|
-
const metadataPredictionStatus = resolvedPredictionStatus(
|
|
508
|
-
getPredictionMetaFromMetadata(opts.metadata)
|
|
509
|
-
);
|
|
510
|
-
if (metadataPredictionStatus) {
|
|
511
|
-
return metadataPredictionStatus;
|
|
512
|
-
}
|
|
513
|
-
return null;
|
|
514
|
-
}
|
|
515
|
-
function resolveBeliefLifecycleStatus(opts) {
|
|
516
|
-
const resolvedStatus = shouldTreatBeliefAsResolved(opts);
|
|
517
|
-
if (resolvedStatus) {
|
|
518
|
-
return resolvedStatus;
|
|
519
|
-
}
|
|
520
|
-
const direct = opts.beliefStatus;
|
|
521
|
-
const normalizedDirect = normalizeLegacyBeliefStatus(direct);
|
|
522
|
-
if (normalizedDirect) {
|
|
523
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
524
|
-
if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
|
|
525
|
-
return "active";
|
|
526
|
-
}
|
|
527
|
-
return normalizedDirect;
|
|
528
|
-
}
|
|
529
|
-
const metaStatus = opts.metadata?.beliefStatus;
|
|
530
|
-
const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
|
|
531
|
-
if (normalizedMetaStatus) {
|
|
532
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
533
|
-
if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
|
|
534
|
-
return "active";
|
|
535
|
-
}
|
|
536
|
-
return normalizedMetaStatus;
|
|
537
|
-
}
|
|
538
|
-
return "assumption";
|
|
539
|
-
}
|
|
540
|
-
function isPreValidationBeliefStatus(status) {
|
|
541
|
-
return status === "assumption" || status === "hypothesis";
|
|
542
|
-
}
|
|
543
|
-
function promoteBeliefStatusAfterScoring(status, opts) {
|
|
544
|
-
const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
|
|
545
|
-
if (resolvedStatus) {
|
|
546
|
-
return resolvedStatus;
|
|
547
|
-
}
|
|
548
|
-
if (isPreValidationBeliefStatus(status)) {
|
|
549
|
-
return "active";
|
|
550
|
-
}
|
|
551
|
-
return status;
|
|
552
|
-
}
|
|
553
|
-
var api = anyApi;
|
|
554
|
-
componentsGeneric();
|
|
555
|
-
var internal = anyApi;
|
|
556
|
-
var internalMutation = internalMutationGeneric;
|
|
557
|
-
var mutation = mutationGeneric;
|
|
558
|
-
var query = queryGeneric;
|
|
559
|
-
|
|
560
|
-
// src/debug.ts
|
|
561
|
-
function isGraphPrimitiveDebugEnabled() {
|
|
562
|
-
const env = globalThis.process?.env;
|
|
563
|
-
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
564
|
-
}
|
|
565
|
-
function debugGraphPrimitiveFallback(message, context) {
|
|
566
|
-
if (!isGraphPrimitiveDebugEnabled()) {
|
|
567
|
-
return;
|
|
568
|
-
}
|
|
569
|
-
console.debug(message, context ?? {});
|
|
570
|
-
}
|
|
571
|
-
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
572
|
-
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
573
|
-
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
574
|
-
return null;
|
|
575
|
-
}
|
|
576
|
-
let node = null;
|
|
577
|
-
try {
|
|
578
|
-
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
579
|
-
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
580
|
-
node = byGlobalId;
|
|
581
|
-
}
|
|
582
|
-
} catch (error) {
|
|
583
|
-
debugGraphPrimitiveFallback(
|
|
584
|
-
"[topicScope] topic-node scope lookup by globalId failed",
|
|
585
|
-
{ error, ref }
|
|
586
|
-
);
|
|
587
|
-
}
|
|
588
|
-
if (!node) {
|
|
589
|
-
return null;
|
|
590
|
-
}
|
|
591
|
-
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
592
|
-
if (!scopeKey) {
|
|
593
|
-
return null;
|
|
594
|
-
}
|
|
595
|
-
return {
|
|
596
|
-
topicId: scopeKey,
|
|
597
|
-
projectId: asMappedProjectId(node),
|
|
598
|
-
source: "topic_node"
|
|
599
|
-
};
|
|
600
|
-
}
|
|
601
|
-
function asMappedProjectId(topic) {
|
|
602
|
-
if (!topic) {
|
|
603
|
-
return;
|
|
604
|
-
}
|
|
605
|
-
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
606
|
-
if (directLegacyProjectId) {
|
|
607
|
-
return directLegacyProjectId;
|
|
608
|
-
}
|
|
609
|
-
const metadata = topic.metadata || {};
|
|
610
|
-
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
611
|
-
return candidate ? candidate : void 0;
|
|
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;
|
|
612
199
|
}
|
|
613
200
|
function normalizeScopeValue(value) {
|
|
614
201
|
if (typeof value !== "string") {
|
|
@@ -633,8 +220,9 @@ function pickPrimaryTopic(candidates) {
|
|
|
633
220
|
})[0];
|
|
634
221
|
}
|
|
635
222
|
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
223
|
+
const query2 = ctx.db.query("topics");
|
|
636
224
|
try {
|
|
637
|
-
return await
|
|
225
|
+
return await query2.withIndex(
|
|
638
226
|
"by_graph_scope_project",
|
|
639
227
|
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
640
228
|
).collect();
|
|
@@ -646,7 +234,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
|
646
234
|
scopeId
|
|
647
235
|
}
|
|
648
236
|
);
|
|
649
|
-
const topics = await
|
|
237
|
+
const topics = await query2.collect();
|
|
650
238
|
return topics.filter((topic) => {
|
|
651
239
|
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
652
240
|
const mappedProjectId = asMappedProjectId(topic);
|
|
@@ -691,148 +279,126 @@ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
|
691
279
|
);
|
|
692
280
|
return null;
|
|
693
281
|
}
|
|
694
|
-
}
|
|
695
|
-
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
696
|
-
const MAX_DEPTH = 10;
|
|
697
|
-
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
698
|
-
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
699
|
-
if (tenantId && workspaceId) {
|
|
700
|
-
return { tenantId, workspaceId };
|
|
701
|
-
}
|
|
702
|
-
let current = topic;
|
|
703
|
-
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
704
|
-
current = await ctx.db.get(current.parentTopicId);
|
|
705
|
-
if (!current)
|
|
706
|
-
|
|
707
|
-
tenantId = normalizeScopeValue(current.tenantId);
|
|
708
|
-
}
|
|
709
|
-
if (!workspaceId) {
|
|
710
|
-
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
711
|
-
}
|
|
712
|
-
if (tenantId && workspaceId) break;
|
|
713
|
-
}
|
|
714
|
-
return { tenantId, workspaceId };
|
|
715
|
-
}
|
|
716
|
-
async function resolveTopicProjectScope(ctx, args) {
|
|
717
|
-
if (args.topicId) {
|
|
718
|
-
let topic = null;
|
|
719
|
-
try {
|
|
720
|
-
topic = await ctx.db.get(
|
|
721
|
-
args.topicId
|
|
722
|
-
);
|
|
723
|
-
} catch (error) {
|
|
724
|
-
debugGraphPrimitiveFallback(
|
|
725
|
-
"[topicScope] Failed to load topic by direct id",
|
|
726
|
-
{
|
|
727
|
-
error,
|
|
728
|
-
topicId: args.topicId
|
|
729
|
-
}
|
|
730
|
-
);
|
|
731
|
-
}
|
|
732
|
-
if (!topic) {
|
|
733
|
-
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
734
|
-
}
|
|
735
|
-
if (!topic) {
|
|
736
|
-
topic = pickPrimaryTopic(
|
|
737
|
-
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
738
|
-
) ?? null;
|
|
739
|
-
}
|
|
740
|
-
if (!topic) {
|
|
741
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
742
|
-
ctx,
|
|
743
|
-
String(args.topicId)
|
|
744
|
-
);
|
|
745
|
-
if (nodeScope) {
|
|
746
|
-
return nodeScope;
|
|
747
|
-
}
|
|
748
|
-
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
749
|
-
}
|
|
750
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
751
|
-
const mapped = asMappedProjectId(topic);
|
|
752
|
-
if (mapped) {
|
|
753
|
-
return {
|
|
754
|
-
topicId: topic._id,
|
|
755
|
-
projectId: mapped,
|
|
756
|
-
tenantId: inherited.tenantId,
|
|
757
|
-
workspaceId: inherited.workspaceId,
|
|
758
|
-
source: "topic"
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
return {
|
|
762
|
-
topicId: topic._id,
|
|
763
|
-
tenantId: inherited.tenantId,
|
|
764
|
-
workspaceId: inherited.workspaceId,
|
|
765
|
-
source: "topic"
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
if (args.projectId) {
|
|
769
|
-
let directTopic = null;
|
|
770
|
-
try {
|
|
771
|
-
directTopic = await ctx.db.get(
|
|
772
|
-
args.projectId
|
|
773
|
-
);
|
|
774
|
-
} catch (error) {
|
|
775
|
-
debugGraphPrimitiveFallback(
|
|
776
|
-
"[topicScope] Failed to load direct project topic",
|
|
777
|
-
{
|
|
778
|
-
error,
|
|
779
|
-
projectId: args.projectId
|
|
780
|
-
}
|
|
781
|
-
);
|
|
782
|
-
}
|
|
783
|
-
if (directTopic) {
|
|
784
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
785
|
-
const mapped = asMappedProjectId(directTopic);
|
|
786
|
-
return {
|
|
787
|
-
topicId: directTopic._id,
|
|
788
|
-
projectId: mapped ?? args.projectId,
|
|
789
|
-
tenantId: inherited.tenantId,
|
|
790
|
-
workspaceId: inherited.workspaceId,
|
|
791
|
-
source: "topic_inferred"
|
|
792
|
-
};
|
|
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;
|
|
793
295
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
797
|
-
const mapped = asMappedProjectId(directTopic);
|
|
798
|
-
return {
|
|
799
|
-
topicId: directTopic._id,
|
|
800
|
-
projectId: mapped ?? args.projectId,
|
|
801
|
-
tenantId: inherited.tenantId,
|
|
802
|
-
workspaceId: inherited.workspaceId,
|
|
803
|
-
source: "topic_inferred"
|
|
804
|
-
};
|
|
296
|
+
if (!tenantId) {
|
|
297
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
805
298
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (primary) {
|
|
809
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
810
|
-
return {
|
|
811
|
-
topicId: primary._id,
|
|
812
|
-
projectId: args.projectId,
|
|
813
|
-
tenantId: inherited.tenantId,
|
|
814
|
-
workspaceId: inherited.workspaceId,
|
|
815
|
-
source: "project_mapped_topic"
|
|
816
|
-
};
|
|
299
|
+
if (!workspaceId) {
|
|
300
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
817
301
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
String(args.projectId)
|
|
821
|
-
);
|
|
822
|
-
if (nodeScope) {
|
|
823
|
-
return {
|
|
824
|
-
...nodeScope,
|
|
825
|
-
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
826
|
-
};
|
|
302
|
+
if (tenantId && workspaceId) {
|
|
303
|
+
break;
|
|
827
304
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
305
|
+
}
|
|
306
|
+
return { tenantId, workspaceId };
|
|
307
|
+
}
|
|
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);
|
|
831
314
|
}
|
|
832
315
|
throw new Error(
|
|
833
316
|
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
834
317
|
);
|
|
835
318
|
}
|
|
319
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
320
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
321
|
+
if (topic) {
|
|
322
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
323
|
+
}
|
|
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;
|
|
341
|
+
}
|
|
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) {
|
|
364
|
+
return {
|
|
365
|
+
...nodeScope,
|
|
366
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
367
|
+
};
|
|
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);
|
|
394
|
+
return {
|
|
395
|
+
topicId: topic._id,
|
|
396
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
397
|
+
tenantId: inherited.tenantId,
|
|
398
|
+
workspaceId: inherited.workspaceId,
|
|
399
|
+
source
|
|
400
|
+
};
|
|
401
|
+
}
|
|
836
402
|
({
|
|
837
403
|
projectId: v.optional(v.string()),
|
|
838
404
|
topicId: v.optional(v.string())
|
|
@@ -900,9 +466,10 @@ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
|
900
466
|
if (resolved.tenantId || resolved.workspaceId) {
|
|
901
467
|
return resolved;
|
|
902
468
|
}
|
|
903
|
-
|
|
469
|
+
const topicId = normalizeScopeValue2(node.topicId);
|
|
470
|
+
if (topicId) {
|
|
904
471
|
const topicScope = await resolveTopicProjectScope(ctx, {
|
|
905
|
-
topicId
|
|
472
|
+
topicId
|
|
906
473
|
});
|
|
907
474
|
return {
|
|
908
475
|
...resolved,
|
|
@@ -922,8 +489,6 @@ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
|
922
489
|
}
|
|
923
490
|
return resolved;
|
|
924
491
|
}
|
|
925
|
-
|
|
926
|
-
// src/epistemicBeliefs.helpers.ts
|
|
927
492
|
v.id("epistemicNodes");
|
|
928
493
|
var DEFAULT_CONFIDENCE_POLICY = {
|
|
929
494
|
scoringMode: "after_worktree",
|
|
@@ -1003,7 +568,10 @@ function resolveBeliefStatus(node, metadata) {
|
|
|
1003
568
|
});
|
|
1004
569
|
}
|
|
1005
570
|
async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
|
|
1006
|
-
const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
|
|
571
|
+
const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex(
|
|
572
|
+
"by_belief",
|
|
573
|
+
(q) => q.eq("beliefId", beliefNodeId)
|
|
574
|
+
).collect();
|
|
1007
575
|
for (const membership of clusterMembership) {
|
|
1008
576
|
const worktree = await ctx.db.get(membership.worktreeId);
|
|
1009
577
|
if (worktree?.status === "completed" || worktree?.status === "merged") {
|
|
@@ -1014,7 +582,10 @@ async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
|
|
|
1014
582
|
}
|
|
1015
583
|
async function getActiveConfidencePolicy(ctx) {
|
|
1016
584
|
try {
|
|
1017
|
-
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
585
|
+
const activeConfig = await ctx.db.query("logicSprintScoring").withIndex(
|
|
586
|
+
"by_active",
|
|
587
|
+
(q) => q.eq("isActive", true)
|
|
588
|
+
).first();
|
|
1018
589
|
return {
|
|
1019
590
|
scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
|
|
1020
591
|
tupleContradiction: normalizeTupleContradictionPolicy(
|
|
@@ -1167,7 +738,7 @@ var dependsOnPropagationSpec = {
|
|
|
1167
738
|
description: "Structural gating. Textbook conditional deduction when edge conditionals exist, otherwise damped dependency cascade through downstream chains."
|
|
1168
739
|
};
|
|
1169
740
|
|
|
1170
|
-
// src/edges/
|
|
741
|
+
// src/edges/derived-from.ts
|
|
1171
742
|
var derivedFromPropagationSpec = {
|
|
1172
743
|
edgeType: "derived_from",
|
|
1173
744
|
direction: "incoming",
|
|
@@ -1220,7 +791,7 @@ var informsPropagationSpec = {
|
|
|
1220
791
|
description: "Evidence-bearing influence. Informs can chain through the graph with light per-hop damping."
|
|
1221
792
|
};
|
|
1222
793
|
|
|
1223
|
-
// src/edges/
|
|
794
|
+
// src/edges/propagation-types.ts
|
|
1224
795
|
function isPropagationTraversalDirection(direction) {
|
|
1225
796
|
return direction === "outgoing" || direction === "incoming";
|
|
1226
797
|
}
|
|
@@ -1293,6 +864,9 @@ var testsPropagationSpec = {
|
|
|
1293
864
|
};
|
|
1294
865
|
|
|
1295
866
|
// src/edges/index.ts
|
|
867
|
+
var canContinueTransitively2 = canContinueTransitively;
|
|
868
|
+
var canTraverseHop2 = canTraverseHop;
|
|
869
|
+
var isPropagationTraversalDirection2 = isPropagationTraversalDirection;
|
|
1296
870
|
var EDGE_PROPAGATION_SPECS = [
|
|
1297
871
|
supportsPropagationSpec,
|
|
1298
872
|
informsPropagationSpec,
|
|
@@ -1309,16 +883,15 @@ function getEdgePropagationSpecs() {
|
|
|
1309
883
|
return EDGE_PROPAGATION_SPECS;
|
|
1310
884
|
}
|
|
1311
885
|
function getTraversalDirections(direction) {
|
|
1312
|
-
if (
|
|
886
|
+
if (isPropagationTraversalDirection2(direction)) {
|
|
1313
887
|
return [direction];
|
|
1314
888
|
}
|
|
1315
889
|
return ["outgoing", "incoming"];
|
|
1316
890
|
}
|
|
1317
891
|
|
|
1318
892
|
// src/confidencePropagationDispatch.ts
|
|
1319
|
-
function
|
|
1320
|
-
|
|
1321
|
-
return targetNodeId ?? void 0;
|
|
893
|
+
function nodeIdToCacheKey(nodeId) {
|
|
894
|
+
return String(nodeId);
|
|
1322
895
|
}
|
|
1323
896
|
function readNodeOpinion(node) {
|
|
1324
897
|
const metadata = node.metadata ?? {};
|
|
@@ -1334,118 +907,354 @@ function readNodeOpinion(node) {
|
|
|
1334
907
|
return mkOpinion(0, 0, 1, 0.5);
|
|
1335
908
|
}
|
|
1336
909
|
}
|
|
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)])
|
|
920
|
+
};
|
|
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;
|
|
1037
|
+
}
|
|
1038
|
+
await processTraversalSpec(state, nextHop, spec, queue, scope);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
function sortDispatches(dispatches) {
|
|
1042
|
+
return Array.from(dispatches).sort((left, right) => {
|
|
1043
|
+
if (left.hop !== right.hop) {
|
|
1044
|
+
return left.hop - right.hop;
|
|
1045
|
+
}
|
|
1046
|
+
return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1337
1049
|
async function collectConfidencePropagationDispatches(args) {
|
|
1338
1050
|
const dispatchesByTargetId = /* @__PURE__ */ new Map();
|
|
1339
1051
|
const opinionCache = /* @__PURE__ */ new Map();
|
|
1340
1052
|
const nodeCache = /* @__PURE__ */ new Map();
|
|
1341
1053
|
const traversalSpecs = args.traversalSpecs ?? getEdgePropagationSpecs();
|
|
1054
|
+
const scope = {
|
|
1055
|
+
args,
|
|
1056
|
+
dispatchesByTargetId,
|
|
1057
|
+
opinionCache,
|
|
1058
|
+
nodeCache,
|
|
1059
|
+
traversalSpecs
|
|
1060
|
+
};
|
|
1342
1061
|
const queue = [
|
|
1343
|
-
|
|
1344
|
-
nodeId: args.sourceNodeId,
|
|
1345
|
-
opinion: args.sourceOpinion,
|
|
1346
|
-
hop: 0,
|
|
1347
|
-
visitedNodeIds: /* @__PURE__ */ new Set([String(args.sourceNodeId)])
|
|
1348
|
-
}
|
|
1062
|
+
buildInitialState(args.sourceNodeId, args.sourceOpinion)
|
|
1349
1063
|
];
|
|
1350
|
-
const loadNode = async (nodeId) => {
|
|
1351
|
-
const cacheKey = String(nodeId);
|
|
1352
|
-
if (!nodeCache.has(cacheKey)) {
|
|
1353
|
-
nodeCache.set(cacheKey, await args.getNode(nodeId));
|
|
1354
|
-
}
|
|
1355
|
-
return nodeCache.get(cacheKey) ?? null;
|
|
1356
|
-
};
|
|
1357
1064
|
while (queue.length > 0) {
|
|
1358
1065
|
const state = queue.shift();
|
|
1359
1066
|
if (!state) {
|
|
1360
1067
|
continue;
|
|
1361
1068
|
}
|
|
1362
|
-
|
|
1363
|
-
const nextHop = state.hop + 1;
|
|
1364
|
-
if (!canTraverseHop(spec, nextHop)) {
|
|
1365
|
-
continue;
|
|
1366
|
-
}
|
|
1367
|
-
for (const direction of getTraversalDirections(spec.direction)) {
|
|
1368
|
-
const edges = await args.queryEdges({
|
|
1369
|
-
nodeId: state.nodeId,
|
|
1370
|
-
spec,
|
|
1371
|
-
direction,
|
|
1372
|
-
hop: nextHop
|
|
1373
|
-
});
|
|
1374
|
-
for (const edge of edges) {
|
|
1375
|
-
if (args.sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, args.sourceScope)) {
|
|
1376
|
-
continue;
|
|
1377
|
-
}
|
|
1378
|
-
const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
|
|
1379
|
-
if (!targetNodeId) {
|
|
1380
|
-
continue;
|
|
1381
|
-
}
|
|
1382
|
-
if (state.visitedNodeIds.has(String(targetNodeId))) {
|
|
1383
|
-
continue;
|
|
1384
|
-
}
|
|
1385
|
-
const targetNode = await loadNode(targetNodeId);
|
|
1386
|
-
if (!targetNode || targetNode.nodeType !== "belief") {
|
|
1387
|
-
continue;
|
|
1388
|
-
}
|
|
1389
|
-
if (args.sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, args.sourceScope)) {
|
|
1390
|
-
continue;
|
|
1391
|
-
}
|
|
1392
|
-
const cacheKey = String(targetNodeId);
|
|
1393
|
-
const targetOpinion = opinionCache.get(cacheKey) ?? readNodeOpinion(targetNode);
|
|
1394
|
-
const result = spec.operator(state.opinion, targetOpinion, edge, {
|
|
1395
|
-
hop: nextHop,
|
|
1396
|
-
sourceNodeId: state.nodeId,
|
|
1397
|
-
targetNodeId,
|
|
1398
|
-
traversedDirection: direction,
|
|
1399
|
-
spec
|
|
1400
|
-
});
|
|
1401
|
-
if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
|
|
1402
|
-
continue;
|
|
1403
|
-
}
|
|
1404
|
-
const projectedOpinion = mkOpinion(
|
|
1405
|
-
result.opinion.b,
|
|
1406
|
-
result.opinion.d,
|
|
1407
|
-
result.opinion.u,
|
|
1408
|
-
result.opinion.a
|
|
1409
|
-
);
|
|
1410
|
-
opinionCache.set(cacheKey, projectedOpinion);
|
|
1411
|
-
const existingDispatch = dispatchesByTargetId.get(cacheKey);
|
|
1412
|
-
dispatchesByTargetId.set(cacheKey, {
|
|
1413
|
-
targetNodeId,
|
|
1414
|
-
edgeType: spec.edgeType,
|
|
1415
|
-
traversedDirection: direction,
|
|
1416
|
-
weight: edge.weight ?? 1,
|
|
1417
|
-
opinion: projectedOpinion,
|
|
1418
|
-
operator: result.operator,
|
|
1419
|
-
rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
|
|
1420
|
-
hop: nextHop
|
|
1421
|
-
});
|
|
1422
|
-
if (canContinueTransitively(spec, nextHop)) {
|
|
1423
|
-
queue.push({
|
|
1424
|
-
nodeId: targetNodeId,
|
|
1425
|
-
opinion: projectedOpinion,
|
|
1426
|
-
hop: nextHop,
|
|
1427
|
-
visitedNodeIds: /* @__PURE__ */ new Set([
|
|
1428
|
-
...state.visitedNodeIds,
|
|
1429
|
-
String(targetNodeId)
|
|
1430
|
-
])
|
|
1431
|
-
});
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1069
|
+
await processQueuedState(state, queue, scope);
|
|
1436
1070
|
}
|
|
1437
|
-
return
|
|
1438
|
-
if (left.hop !== right.hop) {
|
|
1439
|
-
return left.hop - right.hop;
|
|
1440
|
-
}
|
|
1441
|
-
return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
|
|
1442
|
-
});
|
|
1071
|
+
return sortDispatches(dispatchesByTargetId.values());
|
|
1443
1072
|
}
|
|
1444
1073
|
|
|
1445
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
|
+
}
|
|
1446
1207
|
async function applyBeliefConfidenceChange(ctx, args) {
|
|
1447
1208
|
const now = Date.now();
|
|
1448
|
-
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));
|
|
1449
1258
|
if (!node) {
|
|
1450
1259
|
throwStructuredMutationError({
|
|
1451
1260
|
message: "Node not found.",
|
|
@@ -1456,59 +1265,28 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1456
1265
|
details: { nodeId: args.nodeId }
|
|
1457
1266
|
});
|
|
1458
1267
|
}
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
invariantCode: "entity.no_confidence",
|
|
1465
|
-
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
|
|
1466
|
-
details: { nodeId: args.nodeId, nodeType: node.nodeType }
|
|
1467
|
-
});
|
|
1468
|
-
}
|
|
1469
|
-
if (!node.projectId) {
|
|
1470
|
-
throwStructuredMutationError({
|
|
1471
|
-
message: "Belief has no project scope.",
|
|
1472
|
-
status: 400,
|
|
1473
|
-
code: "MISSING_SCOPE",
|
|
1474
|
-
invariantCode: "belief.project_required",
|
|
1475
|
-
suggestion: "Belief must have a projectId before SL scoring can be appended.",
|
|
1476
|
-
details: { nodeId: args.nodeId }
|
|
1477
|
-
});
|
|
1478
|
-
}
|
|
1479
|
-
await requireScopeWriteAccess(
|
|
1480
|
-
ctx,
|
|
1481
|
-
node.projectId,
|
|
1482
|
-
args.authenticatedUserId
|
|
1483
|
-
);
|
|
1484
|
-
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);
|
|
1485
1273
|
const currentBeliefStatus = resolveBeliefStatus(node, existingMetadata);
|
|
1486
1274
|
const confidencePolicy = await getActiveConfidencePolicy(ctx);
|
|
1487
|
-
if (confidencePolicy.scoringMode === "after_worktree" && isPreValidationBeliefStatus(currentBeliefStatus)) {
|
|
1488
|
-
const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
|
|
1489
|
-
ctx,
|
|
1490
|
-
args.nodeId
|
|
1491
|
-
);
|
|
1492
|
-
if (!hasCompletedWorktree) {
|
|
1493
|
-
throwStructuredMutationError({
|
|
1494
|
-
message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
|
|
1495
|
-
status: 409,
|
|
1496
|
-
code: "CONFLICT",
|
|
1497
|
-
invariantCode: "belief.confidence_append_only",
|
|
1498
|
-
suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
|
|
1499
|
-
details: { nodeId: args.nodeId }
|
|
1500
|
-
});
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1503
1275
|
const previousConfidence = node.confidence || 0.5;
|
|
1504
1276
|
const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
|
|
1505
1277
|
const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
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
|
+
);
|
|
1512
1290
|
const isFirstScoring = typeof node.confidence !== "number" || !Number.isFinite(node.confidence);
|
|
1513
1291
|
const previousTupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(existingMetadata.tupleContradicted) ?? detectTupleContradiction(
|
|
1514
1292
|
previousOpinion,
|
|
@@ -1529,79 +1307,121 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1529
1307
|
predictionMeta,
|
|
1530
1308
|
metadata: existingMetadata
|
|
1531
1309
|
});
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
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;
|
|
1550
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) {
|
|
1551
1368
|
await ctx.db.patch(args.nodeId, {
|
|
1552
|
-
confidence: derivedConfidence,
|
|
1553
|
-
beliefStatus: newBeliefStatus,
|
|
1554
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1555
|
-
updatedAt: now,
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
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,
|
|
1561
1377
|
metadata: {
|
|
1562
|
-
...existingMetadata,
|
|
1563
|
-
beliefStatus: newBeliefStatus,
|
|
1564
|
-
slBelief:
|
|
1565
|
-
slDisbelief:
|
|
1566
|
-
slUncertainty:
|
|
1567
|
-
slBaseRate:
|
|
1568
|
-
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
|
|
1569
1385
|
}
|
|
1570
1386
|
});
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
edgeType: "relates_to_thesis",
|
|
1584
|
-
weight: derivedConfidence,
|
|
1585
|
-
createdBy: args.authenticatedUserId,
|
|
1586
|
-
topicId: String(node.projectId),
|
|
1587
|
-
fromNodeType: "belief",
|
|
1588
|
-
toNodeType: "theme",
|
|
1589
|
-
fromLayer: "L3",
|
|
1590
|
-
toLayer: "L3"
|
|
1591
|
-
});
|
|
1592
|
-
}
|
|
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;
|
|
1593
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
|
+
});
|
|
1594
1413
|
}
|
|
1595
|
-
|
|
1596
|
-
|
|
1414
|
+
}
|
|
1415
|
+
async function insertBeliefConfidenceRecord(ctx, args, state, tupleContradictionId, now) {
|
|
1416
|
+
return await ctx.db.insert("beliefConfidence", {
|
|
1597
1417
|
...buildBeliefConfidenceRow({
|
|
1598
1418
|
beliefId: args.nodeId,
|
|
1599
|
-
belief:
|
|
1600
|
-
disbelief:
|
|
1601
|
-
uncertainty:
|
|
1602
|
-
baseRate:
|
|
1419
|
+
belief: state.nextOpinion.b,
|
|
1420
|
+
disbelief: state.nextOpinion.d,
|
|
1421
|
+
uncertainty: state.nextOpinion.u,
|
|
1422
|
+
baseRate: state.nextOpinion.a,
|
|
1603
1423
|
trigger: args.trigger,
|
|
1604
|
-
rationale: storedRationale,
|
|
1424
|
+
rationale: state.storedRationale,
|
|
1605
1425
|
assessedBy: args.authenticatedUserId,
|
|
1606
1426
|
assessedAt: now,
|
|
1607
1427
|
slOperator: args.slOperator,
|
|
@@ -1610,55 +1430,64 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1610
1430
|
triggeringWorktreeId: args.triggeringWorktreeId
|
|
1611
1431
|
})
|
|
1612
1432
|
});
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1433
|
+
}
|
|
1434
|
+
async function insertConfidenceAudit(ctx, args, node, state, tupleContradictionId, now) {
|
|
1435
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1436
|
+
entityType: "belief",
|
|
1437
|
+
entityId: args.nodeId,
|
|
1438
|
+
changeType: "confidence_changed",
|
|
1439
|
+
previousState: {
|
|
1440
|
+
confidence: state.previousConfidence,
|
|
1441
|
+
tupleContradicted: state.previousTupleContradicted
|
|
1442
|
+
},
|
|
1443
|
+
newState: {
|
|
1444
|
+
opinion: state.nextOpinion,
|
|
1445
|
+
confidence: state.derivedConfidence,
|
|
1446
|
+
trigger: args.trigger,
|
|
1447
|
+
rationale: state.storedRationale,
|
|
1448
|
+
tupleContradicted: state.tupleTransition.tupleContradicted,
|
|
1449
|
+
tupleContradictionPolicy: state.tupleTransition.policy,
|
|
1450
|
+
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1451
|
+
},
|
|
1452
|
+
changedBy: args.authenticatedUserId,
|
|
1453
|
+
isAgent: false,
|
|
1454
|
+
changedAt: now,
|
|
1455
|
+
projectId: node.projectId,
|
|
1456
|
+
topicId: node.topicId
|
|
1616
1457
|
});
|
|
1458
|
+
}
|
|
1459
|
+
async function insertTupleTransitionAuditIfNeeded(ctx, args, node, state, tupleContradictionId, now) {
|
|
1460
|
+
if (!(state.tupleTransition.crossedIntoTupleContradiction || state.tupleTransition.crossedOutOfTupleContradiction)) {
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1617
1463
|
await ctx.db.insert("epistemicAudit", {
|
|
1618
1464
|
entityType: "belief",
|
|
1619
1465
|
entityId: args.nodeId,
|
|
1620
|
-
changeType: "
|
|
1621
|
-
previousState: {
|
|
1622
|
-
confidence: previousConfidence,
|
|
1623
|
-
tupleContradicted: previousTupleContradicted
|
|
1624
|
-
},
|
|
1466
|
+
changeType: "updated",
|
|
1467
|
+
previousState: { tupleContradicted: state.previousTupleContradicted },
|
|
1625
1468
|
newState: {
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1631
|
-
tupleContradictionPolicy: tupleTransition.policy,
|
|
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,
|
|
1632
1473
|
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1633
1474
|
},
|
|
1475
|
+
rationale: tupleAuditRationale(state),
|
|
1634
1476
|
changedBy: args.authenticatedUserId,
|
|
1635
1477
|
isAgent: false,
|
|
1636
1478
|
changedAt: now,
|
|
1637
1479
|
projectId: node.projectId,
|
|
1638
1480
|
topicId: node.topicId
|
|
1639
1481
|
});
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
changeType: "updated",
|
|
1645
|
-
previousState: { tupleContradicted: previousTupleContradicted },
|
|
1646
|
-
newState: {
|
|
1647
|
-
tupleContradicted: tupleTransition.tupleContradicted,
|
|
1648
|
-
action: tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
|
|
1649
|
-
opinion: nextOpinion,
|
|
1650
|
-
tupleContradictionPolicy: tupleTransition.policy,
|
|
1651
|
-
...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
|
|
1652
|
-
},
|
|
1653
|
-
rationale: tupleTransition.crossedIntoTupleContradiction ? tupleContradictionDescription : `Tuple-space contradiction cleared: b=${nextOpinion.b.toFixed(2)}, d=${nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`,
|
|
1654
|
-
changedBy: args.authenticatedUserId,
|
|
1655
|
-
isAgent: false,
|
|
1656
|
-
changedAt: now,
|
|
1657
|
-
projectId: node.projectId,
|
|
1658
|
-
topicId: node.topicId
|
|
1659
|
-
});
|
|
1482
|
+
}
|
|
1483
|
+
function tupleAuditRationale(state) {
|
|
1484
|
+
if (state.tupleTransition.crossedIntoTupleContradiction) {
|
|
1485
|
+
return state.tupleContradictionDescription;
|
|
1660
1486
|
}
|
|
1661
|
-
|
|
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) {
|
|
1662
1491
|
await ctx.scheduler.runAfter(
|
|
1663
1492
|
5e3,
|
|
1664
1493
|
internal.bi.contradictionSemanticDetector.scanAffectedBeliefs,
|
|
@@ -1675,13 +1504,6 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
1675
1504
|
{ nodeId: args.nodeId }
|
|
1676
1505
|
);
|
|
1677
1506
|
}
|
|
1678
|
-
return {
|
|
1679
|
-
nodeId: args.nodeId,
|
|
1680
|
-
previousConfidence,
|
|
1681
|
-
newConfidence: derivedConfidence,
|
|
1682
|
-
opinion: { b: slB, d: slD, u: slU, a: slA },
|
|
1683
|
-
beliefConfidenceId
|
|
1684
|
-
};
|
|
1685
1507
|
}
|
|
1686
1508
|
function propagationPressureLabel(edgeType, weight) {
|
|
1687
1509
|
if (edgeType === "contradicts" || edgeType === "refutes") {
|
|
@@ -1709,7 +1531,7 @@ internalMutation({
|
|
|
1709
1531
|
args.opinion_u,
|
|
1710
1532
|
args.opinion_a
|
|
1711
1533
|
);
|
|
1712
|
-
const sourceNode = await ctx.db.get(args.nodeId);
|
|
1534
|
+
const sourceNode = readConfidenceBeliefNode(await ctx.db.get(args.nodeId));
|
|
1713
1535
|
const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
|
|
1714
1536
|
ctx,
|
|
1715
1537
|
sourceNode
|
|
@@ -1718,16 +1540,20 @@ internalMutation({
|
|
|
1718
1540
|
sourceNodeId: args.nodeId,
|
|
1719
1541
|
sourceOpinion,
|
|
1720
1542
|
sourceScope,
|
|
1721
|
-
queryEdges: async ({ nodeId, spec, direction }) =>
|
|
1722
|
-
|
|
1543
|
+
queryEdges: async ({ nodeId, spec, direction }) => readRowList(
|
|
1544
|
+
await ctx.db.query("epistemicEdges").withIndex(
|
|
1723
1545
|
direction === "outgoing" ? "by_from_type" : "by_to_type",
|
|
1724
1546
|
(q) => direction === "outgoing" ? q.eq("fromNodeId", nodeId).eq("edgeType", spec.edgeType) : q.eq("toNodeId", nodeId).eq("edgeType", spec.edgeType)
|
|
1725
|
-
).collect()
|
|
1726
|
-
|
|
1727
|
-
|
|
1547
|
+
).collect(),
|
|
1548
|
+
readPropagationEdge
|
|
1549
|
+
),
|
|
1550
|
+
getNode: async (nodeId) => readConfidenceBeliefNode(await ctx.db.get(nodeId))
|
|
1728
1551
|
});
|
|
1729
1552
|
for (const dispatch of dispatches) {
|
|
1730
|
-
const pressureLabel = propagationPressureLabel(
|
|
1553
|
+
const pressureLabel = propagationPressureLabel(
|
|
1554
|
+
dispatch.edgeType,
|
|
1555
|
+
dispatch.weight
|
|
1556
|
+
);
|
|
1731
1557
|
await applyBeliefConfidenceChange(ctx, {
|
|
1732
1558
|
nodeId: dispatch.targetNodeId,
|
|
1733
1559
|
belief: dispatch.opinion.b,
|
|
@@ -1751,253 +1577,645 @@ internalMutation({
|
|
|
1751
1577
|
}
|
|
1752
1578
|
});
|
|
1753
1579
|
|
|
1754
|
-
// src/epistemicContracts.
|
|
1755
|
-
var
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
var
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
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";
|
|
1590
|
+
}
|
|
1591
|
+
if (ACTIVE_CONTRADICTION_STATUSES.has(status)) {
|
|
1592
|
+
return "active";
|
|
1593
|
+
}
|
|
1594
|
+
if (status === "resolved_support" || status === "resolved_contra" || status === "belief_forked") {
|
|
1595
|
+
return "resolved";
|
|
1596
|
+
}
|
|
1597
|
+
return "resolved";
|
|
1598
|
+
}
|
|
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;
|
|
1615
|
+
}
|
|
1616
|
+
const id = readConvexId2(value._id);
|
|
1617
|
+
const nodeType = readOptionalString2(value.nodeType);
|
|
1618
|
+
if (!(id && nodeType)) {
|
|
1619
|
+
return null;
|
|
1620
|
+
}
|
|
1621
|
+
const node = { _id: id, nodeType };
|
|
1622
|
+
const globalId = readOptionalString2(value.globalId);
|
|
1623
|
+
if (globalId !== void 0) {
|
|
1624
|
+
node.globalId = globalId;
|
|
1625
|
+
}
|
|
1626
|
+
if ("metadata" in value) {
|
|
1627
|
+
node.metadata = value.metadata;
|
|
1628
|
+
}
|
|
1629
|
+
const status = readOptionalString2(value.status);
|
|
1630
|
+
if (status !== void 0) {
|
|
1631
|
+
node.status = status;
|
|
1632
|
+
}
|
|
1633
|
+
return node;
|
|
1634
|
+
}
|
|
1635
|
+
function readIncomingEdgeRow(value) {
|
|
1636
|
+
if (!isRecord2(value)) {
|
|
1637
|
+
return null;
|
|
1638
|
+
}
|
|
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;
|
|
1766
1688
|
}
|
|
1767
|
-
evaluatorRegistry.set(name, {
|
|
1768
|
-
name,
|
|
1769
|
-
evaluate: evaluateBuiltInEvidentialContract
|
|
1770
|
-
});
|
|
1771
1689
|
}
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1690
|
+
return edge;
|
|
1691
|
+
}
|
|
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);
|
|
1775
1735
|
}
|
|
1776
|
-
evaluatorRegistry.set(evaluator.name, evaluator);
|
|
1777
1736
|
}
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
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) {
|
|
1752
|
+
try {
|
|
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;
|
|
1787
1766
|
}
|
|
1788
|
-
evaluatorRegistry.set(name, { name, evaluate });
|
|
1789
1767
|
}
|
|
1768
|
+
return null;
|
|
1790
1769
|
}
|
|
1791
|
-
function
|
|
1792
|
-
|
|
1793
|
-
|
|
1770
|
+
async function getEvidenceLinks(ctx, beliefNodeId) {
|
|
1771
|
+
const edges = await collectIncomingEdgeRows(ctx, beliefNodeId, "informs");
|
|
1772
|
+
if (edges.length === 0) {
|
|
1773
|
+
return [];
|
|
1794
1774
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
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;
|
|
1780
|
+
}
|
|
1781
|
+
links.push({ edge, node });
|
|
1797
1782
|
}
|
|
1798
|
-
|
|
1799
|
-
|
|
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 [];
|
|
1800
1790
|
}
|
|
1801
|
-
return "
|
|
1791
|
+
return tags.filter((tag) => typeof tag === "string");
|
|
1802
1792
|
}
|
|
1803
|
-
function
|
|
1804
|
-
|
|
1805
|
-
|
|
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 }
|
|
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
|
+
};
|
|
1806
1834
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1835
|
+
const newestEdgeAt = Math.max(...timestamps);
|
|
1836
|
+
const oldestEdgeAt = Math.min(...timestamps);
|
|
1837
|
+
return {
|
|
1838
|
+
newestAgeMs: Math.max(0, now - newestEdgeAt),
|
|
1839
|
+
oldestAgeMs: Math.max(0, now - oldestEdgeAt),
|
|
1840
|
+
newestEdgeAt,
|
|
1841
|
+
oldestEdgeAt,
|
|
1842
|
+
edgeCount: timestamps.length
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
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;
|
|
1809
1852
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
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
|
+
}
|
|
1812
1859
|
}
|
|
1813
|
-
return
|
|
1860
|
+
return uniqueBeliefIds.size;
|
|
1814
1861
|
}
|
|
1815
|
-
async function
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
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
|
|
1834
1896
|
};
|
|
1835
1897
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
const modulationResult = await applyBeliefConfidenceChange(args.ctx, {
|
|
1854
|
-
nodeId: args.contract.beliefNodeId,
|
|
1855
|
-
belief: contractB,
|
|
1856
|
-
disbelief: 1 - contractB,
|
|
1857
|
-
uncertainty: 0,
|
|
1858
|
-
baseRate: 0.5,
|
|
1859
|
-
trigger: modulationPlan.trigger,
|
|
1860
|
-
rationale: `Epistemic contract "${args.contract.title}" ${evaluation.result}: ${evaluation.rationale}`,
|
|
1861
|
-
authenticatedUserId: args.authenticatedUserId
|
|
1862
|
-
});
|
|
1863
|
-
beliefConfidenceId = modulationResult.beliefConfidenceId;
|
|
1864
|
-
confidenceAfter = typeof modulationResult.newConfidence === "number" ? modulationResult.newConfidence : modulationPlan.confidenceAfter;
|
|
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
|
+
};
|
|
1865
1915
|
}
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
confidenceBefore: modulationPlan?.confidenceBefore,
|
|
1877
|
-
confidenceAfter: modulationPlan ? confidenceAfter : void 0,
|
|
1878
|
-
beliefConfidenceId,
|
|
1879
|
-
modulationRationale: evaluation.rationale,
|
|
1880
|
-
topicId: args.contract.topicId
|
|
1916
|
+
}
|
|
1917
|
+
async function evaluateBuiltInEvidentialContract(args) {
|
|
1918
|
+
const config = parseEvidentialEvaluatorConfig(
|
|
1919
|
+
args.contract.condition.evaluatorConfig
|
|
1920
|
+
);
|
|
1921
|
+
const snapshot = await snapshotEvidentialMetric({
|
|
1922
|
+
ctx: args.ctx,
|
|
1923
|
+
beliefNodeId: args.belief._id,
|
|
1924
|
+
metric: config.metric,
|
|
1925
|
+
now: args.now
|
|
1881
1926
|
});
|
|
1882
|
-
const
|
|
1883
|
-
|
|
1884
|
-
args.contract.
|
|
1885
|
-
|
|
1886
|
-
status: nextStatus,
|
|
1887
|
-
lastEvaluatedAt: args.now,
|
|
1888
|
-
evaluationCount: (args.contract.evaluationCount ?? 0) + 1,
|
|
1889
|
-
updatedAt: args.now
|
|
1890
|
-
}
|
|
1927
|
+
const comparisonSatisfied = snapshot.value !== null && compareMetricValue(config.operator, snapshot.value, config.threshold);
|
|
1928
|
+
const result = resolveComparisonResult(
|
|
1929
|
+
args.contract.direction,
|
|
1930
|
+
comparisonSatisfied
|
|
1891
1931
|
);
|
|
1892
1932
|
return {
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
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
|
+
}
|
|
1901
1949
|
};
|
|
1902
1950
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1951
|
+
function evaluateMetricCheckerContract(args) {
|
|
1952
|
+
return Promise.resolve().then(() => {
|
|
1953
|
+
const config = parseMetricCheckerConfig(
|
|
1954
|
+
args.contract.condition.evaluatorConfig
|
|
1955
|
+
);
|
|
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({
|
|
1906
2014
|
ctx: args.ctx,
|
|
1907
2015
|
beliefNodeId: args.belief._id,
|
|
1908
|
-
|
|
1909
|
-
|
|
2016
|
+
tag,
|
|
2017
|
+
caseSensitive: config.caseSensitive
|
|
1910
2018
|
});
|
|
1911
|
-
const
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
MAX_CONTRACT_EVALUATION_BATCH_SIZE
|
|
1916
|
-
)
|
|
2019
|
+
const comparisonSatisfied = compareMetricValue(
|
|
2020
|
+
config.operator,
|
|
2021
|
+
snapshot.count,
|
|
2022
|
+
config.threshold
|
|
1917
2023
|
);
|
|
1918
|
-
const
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
2024
|
+
const result = resolveComparisonResult(
|
|
2025
|
+
args.contract.direction,
|
|
2026
|
+
comparisonSatisfied
|
|
2027
|
+
);
|
|
2028
|
+
return {
|
|
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
|
+
}
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
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
|
|
1953
2062
|
}
|
|
1954
|
-
|
|
2063
|
+
};
|
|
1955
2064
|
}
|
|
1956
|
-
const
|
|
1957
|
-
console.info("[epistemicContracts] processed contract evaluation batch", {
|
|
1958
|
-
beliefNodeId: String(args.belief._id),
|
|
1959
|
-
trigger: normalizeTrigger(args.trigger),
|
|
1960
|
-
batchSize: currentBatch.length,
|
|
1961
|
-
overflowCount: overflowContracts.length,
|
|
1962
|
-
executionTimeMs
|
|
1963
|
-
});
|
|
2065
|
+
const result = context.contract.direction === "falsifies" ? "disconfirmed" : "confirmed";
|
|
1964
2066
|
return {
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
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
|
+
}
|
|
1973
2076
|
};
|
|
1974
2077
|
}
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
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
|
|
1986
2100
|
}
|
|
1987
|
-
|
|
1988
|
-
|
|
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
|
+
);
|
|
1989
2109
|
}
|
|
1990
|
-
|
|
1991
|
-
|
|
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
|
+
});
|
|
1992
2130
|
}
|
|
1993
|
-
|
|
1994
|
-
|
|
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
|
+
};
|
|
1995
2165
|
}
|
|
1996
|
-
|
|
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
|
+
};
|
|
1997
2202
|
});
|
|
1998
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
|
+
};
|
|
1999
2215
|
|
|
2000
2216
|
// src/evaluators/shared.ts
|
|
2217
|
+
var WINDOWS_PATH_SEPARATORS = /\\/g;
|
|
2218
|
+
var LEADING_DOT_SLASH = /^\.\//;
|
|
2001
2219
|
function asArray(value) {
|
|
2002
2220
|
return Array.isArray(value) ? value : [];
|
|
2003
2221
|
}
|
|
@@ -2039,7 +2257,7 @@ function extractTextCandidates(value) {
|
|
|
2039
2257
|
return Array.from(new Set(candidates));
|
|
2040
2258
|
}
|
|
2041
2259
|
function normalizeFilePath(value) {
|
|
2042
|
-
return value.replace(
|
|
2260
|
+
return value.replace(WINDOWS_PATH_SEPARATORS, "/").replace(LEADING_DOT_SLASH, "");
|
|
2043
2261
|
}
|
|
2044
2262
|
function normalizeToolResultEnvelope(value) {
|
|
2045
2263
|
const record = asRecord(value);
|
|
@@ -2093,7 +2311,7 @@ function somePatternMatches(filePath, patterns) {
|
|
|
2093
2311
|
return patterns.some((pattern) => patternMatchesPath(filePath, pattern));
|
|
2094
2312
|
}
|
|
2095
2313
|
|
|
2096
|
-
// src/evaluators/
|
|
2314
|
+
// src/evaluators/lint-checker-evaluator.ts
|
|
2097
2315
|
function parseConfig(condition) {
|
|
2098
2316
|
const record = asRecord(condition.evaluatorConfig);
|
|
2099
2317
|
if (!record) {
|
|
@@ -2165,7 +2383,10 @@ var lintCheckerEvaluator = {
|
|
|
2165
2383
|
}
|
|
2166
2384
|
const envelope = normalizeToolResultEnvelope(args.resultData);
|
|
2167
2385
|
const exitCode = asNumber(envelope.exitCode);
|
|
2168
|
-
const matchedDiagnostics = getMatchedDiagnostics(
|
|
2386
|
+
const matchedDiagnostics = getMatchedDiagnostics(
|
|
2387
|
+
args.contract,
|
|
2388
|
+
args.resultData
|
|
2389
|
+
);
|
|
2169
2390
|
if (matchedDiagnostics.length === 0 && exitCode !== 0 && exitCode !== null) {
|
|
2170
2391
|
return {
|
|
2171
2392
|
result: "inconclusive",
|
|
@@ -2191,7 +2412,7 @@ var lintCheckerEvaluator = {
|
|
|
2191
2412
|
}
|
|
2192
2413
|
};
|
|
2193
2414
|
|
|
2194
|
-
// src/evaluators/
|
|
2415
|
+
// src/evaluators/sentry-checker-evaluator.ts
|
|
2195
2416
|
function parseConfig2(condition) {
|
|
2196
2417
|
const record = asRecord(condition.evaluatorConfig);
|
|
2197
2418
|
if (!record) {
|
|
@@ -2276,7 +2497,7 @@ var sentryCheckerEvaluator = {
|
|
|
2276
2497
|
}
|
|
2277
2498
|
};
|
|
2278
2499
|
|
|
2279
|
-
// src/evaluators/
|
|
2500
|
+
// src/evaluators/test-runner-evaluator.ts
|
|
2280
2501
|
function parseConfig3(condition) {
|
|
2281
2502
|
const record = asRecord(condition.evaluatorConfig);
|
|
2282
2503
|
if (!record) {
|
|
@@ -2422,7 +2643,7 @@ var testRunnerEvaluator = {
|
|
|
2422
2643
|
}
|
|
2423
2644
|
};
|
|
2424
2645
|
|
|
2425
|
-
// src/evaluators/
|
|
2646
|
+
// src/evaluators/tsc-checker-evaluator.ts
|
|
2426
2647
|
function parseConfig4(condition) {
|
|
2427
2648
|
const record = asRecord(condition.evaluatorConfig);
|
|
2428
2649
|
if (!record) {
|
|
@@ -2434,118 +2655,383 @@ function parseConfig4(condition) {
|
|
|
2434
2655
|
if (filePatterns.length === 0) {
|
|
2435
2656
|
throw new Error("tsc_checker requires at least one file pattern.");
|
|
2436
2657
|
}
|
|
2437
|
-
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
|
+
};
|
|
2438
2938
|
}
|
|
2439
|
-
function
|
|
2440
|
-
const
|
|
2441
|
-
const
|
|
2442
|
-
|
|
2443
|
-
|
|
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
|
+
});
|
|
2444
2977
|
}
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
}
|
|
2450
|
-
const filePath = asString(diagnostic.filePath) ?? asString(diagnostic.file) ?? asString(asRecord(diagnostic.location)?.filePath) ?? asString(asRecord(asRecord(diagnostic.location)?.path)?.file);
|
|
2451
|
-
const message = asString(diagnostic.message) ?? "TypeScript error";
|
|
2452
|
-
return [
|
|
2978
|
+
if (overflowContracts.length > 0) {
|
|
2979
|
+
await args.ctx.scheduler.runAfter(
|
|
2980
|
+
0,
|
|
2981
|
+
"epistemicContracts.processContractEvaluationOverflow",
|
|
2453
2982
|
{
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
}
|
|
2461
|
-
function parseTextDiagnostics(resultData) {
|
|
2462
|
-
const diagnostics = [];
|
|
2463
|
-
const patterns = [
|
|
2464
|
-
/^(.+?)\((\d+),(\d+)\): error TS(\d+): (.+)$/gm,
|
|
2465
|
-
/^(.+?):(\d+):(\d+) - error TS(\d+): (.+)$/gm
|
|
2466
|
-
];
|
|
2467
|
-
for (const text of extractTextCandidates(resultData)) {
|
|
2468
|
-
for (const pattern of patterns) {
|
|
2469
|
-
for (const match of text.matchAll(pattern)) {
|
|
2470
|
-
diagnostics.push({
|
|
2471
|
-
code: match[4],
|
|
2472
|
-
filePath: normalizeFilePath(match[1] ?? ""),
|
|
2473
|
-
message: match[5] ?? "TypeScript error"
|
|
2474
|
-
});
|
|
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
|
|
2475
2989
|
}
|
|
2476
|
-
|
|
2990
|
+
);
|
|
2477
2991
|
}
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
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
|
+
};
|
|
2483
3010
|
}
|
|
2484
|
-
function
|
|
2485
|
-
const
|
|
2486
|
-
return
|
|
2487
|
-
(diagnostic) => somePatternMatches(diagnostic.filePath, config.filePatterns)
|
|
2488
|
-
);
|
|
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;
|
|
2489
3014
|
}
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
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;
|
|
2497
3023
|
}
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
evaluate(args) {
|
|
2501
|
-
const config = parseConfig4(args.contract.condition);
|
|
2502
|
-
if (!args.resultData) {
|
|
2503
|
-
return {
|
|
2504
|
-
result: "error",
|
|
2505
|
-
rationale: "tsc_checker requires TypeScript diagnostic resultData."
|
|
2506
|
-
};
|
|
3024
|
+
if (contract.conditionType === "composite") {
|
|
3025
|
+
return false;
|
|
2507
3026
|
}
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
const matchedDiagnostics = getMatchedDiagnostics2(args.contract, args.resultData);
|
|
2511
|
-
if (matchedDiagnostics.length === 0 && exitCode !== 0 && exitCode !== null) {
|
|
2512
|
-
return {
|
|
2513
|
-
result: "inconclusive",
|
|
2514
|
-
rationale: "TypeScript reported errors, but none matched the configured file patterns."
|
|
2515
|
-
};
|
|
3027
|
+
if (!evaluatorRegistry.has(contract.condition.evaluator)) {
|
|
3028
|
+
return false;
|
|
2516
3029
|
}
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
),
|
|
2523
|
-
rationale: conditionSatisfied ? `TypeScript reported no matching diagnostics for ${config.filePatterns.join(", ")}.` : `TypeScript found ${matchedDiagnostics.length} matching diagnostic(s): ${matchedDiagnostics.map(
|
|
2524
|
-
(diagnostic) => diagnostic.filePath ? `${diagnostic.filePath}${diagnostic.code ? ` (TS${diagnostic.code})` : ""}` : diagnostic.message
|
|
2525
|
-
).join(", ")}.`,
|
|
2526
|
-
data: {
|
|
2527
|
-
exitCode,
|
|
2528
|
-
filePatterns: config.filePatterns,
|
|
2529
|
-
matchedDiagnostics
|
|
2530
|
-
}
|
|
2531
|
-
};
|
|
2532
|
-
}
|
|
2533
|
-
};
|
|
2534
|
-
|
|
2535
|
-
// src/evaluators/index.ts
|
|
2536
|
-
var ENGINEERING_EPISTEMIC_EVALUATORS = [
|
|
2537
|
-
testRunnerEvaluator,
|
|
2538
|
-
tscCheckerEvaluator,
|
|
2539
|
-
lintCheckerEvaluator,
|
|
2540
|
-
sentryCheckerEvaluator
|
|
2541
|
-
];
|
|
2542
|
-
var ENGINEERING_EVALUATOR_NAMES = new Set(
|
|
2543
|
-
ENGINEERING_EPISTEMIC_EVALUATORS.map((evaluator) => evaluator.name)
|
|
2544
|
-
);
|
|
2545
|
-
function getEngineeringEpistemicEvaluator(name) {
|
|
2546
|
-
return ENGINEERING_EPISTEMIC_EVALUATORS.find(
|
|
2547
|
-
(evaluator) => evaluator.name === name
|
|
2548
|
-
);
|
|
3030
|
+
if (contractIdFilter) {
|
|
3031
|
+
return contractIdFilter.has(contract.contractId);
|
|
3032
|
+
}
|
|
3033
|
+
return allowedSchedules.has(contract.evaluationSchedule);
|
|
3034
|
+
});
|
|
2549
3035
|
}
|
|
2550
3036
|
|
|
2551
3037
|
// src/epistemicContracts.handlers.ts
|
|
@@ -2561,6 +3047,24 @@ function resolveSchedulesForTrigger2(trigger) {
|
|
|
2561
3047
|
}
|
|
2562
3048
|
return /* @__PURE__ */ new Set(["event_driven"]);
|
|
2563
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
|
+
}
|
|
2564
3068
|
async function requireAuth(ctx) {
|
|
2565
3069
|
const userId = await getCurrentUserId(ctx);
|
|
2566
3070
|
if (!userId) {
|
|
@@ -2596,17 +3100,21 @@ async function requireTopicReadAccess(ctx, beliefs, userId) {
|
|
|
2596
3100
|
projectIds.add(belief.projectId);
|
|
2597
3101
|
}
|
|
2598
3102
|
for (const projectId of projectIds) {
|
|
2599
|
-
const hasAccess = await checkProjectAccess(
|
|
3103
|
+
const hasAccess = await checkProjectAccess(
|
|
3104
|
+
ctx,
|
|
3105
|
+
projectId,
|
|
3106
|
+
userId
|
|
3107
|
+
);
|
|
2600
3108
|
if (!hasAccess) {
|
|
2601
3109
|
throw new Error("Project access required.");
|
|
2602
3110
|
}
|
|
2603
3111
|
}
|
|
2604
3112
|
}
|
|
2605
3113
|
async function getContractByContractId(ctx, contractId) {
|
|
2606
|
-
return await ctx.
|
|
3114
|
+
return await contractTables(ctx).query("epistemicContracts").withIndex("by_contractId", (q) => q.eq("contractId", contractId)).first();
|
|
2607
3115
|
}
|
|
2608
3116
|
async function getLatestEvaluation(ctx, contractId) {
|
|
2609
|
-
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);
|
|
2610
3118
|
return evaluations[0] ?? null;
|
|
2611
3119
|
}
|
|
2612
3120
|
var evaluateEvidenceCount = query({
|
|
@@ -2616,10 +3124,7 @@ var evaluateEvidenceCount = query({
|
|
|
2616
3124
|
returns: permissiveReturn,
|
|
2617
3125
|
handler: async (ctx, args) => {
|
|
2618
3126
|
const userId = await requireAuth(ctx);
|
|
2619
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2620
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2621
|
-
throw new Error("Belief not found.");
|
|
2622
|
-
}
|
|
3127
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2623
3128
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2624
3129
|
return await computeEvidenceCountMetric(ctx, args.beliefNodeId);
|
|
2625
3130
|
}
|
|
@@ -2631,10 +3136,7 @@ var evaluateContradictionStatus = query({
|
|
|
2631
3136
|
returns: permissiveReturn,
|
|
2632
3137
|
handler: async (ctx, args) => {
|
|
2633
3138
|
const userId = await requireAuth(ctx);
|
|
2634
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2635
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2636
|
-
throw new Error("Belief not found.");
|
|
2637
|
-
}
|
|
3139
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2638
3140
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2639
3141
|
return await computeContradictionCounts(ctx, args.beliefNodeId);
|
|
2640
3142
|
}
|
|
@@ -2646,10 +3148,7 @@ var evaluateEdgeFreshness = query({
|
|
|
2646
3148
|
returns: permissiveReturn,
|
|
2647
3149
|
handler: async (ctx, args) => {
|
|
2648
3150
|
const userId = await requireAuth(ctx);
|
|
2649
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2650
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2651
|
-
throw new Error("Belief not found.");
|
|
2652
|
-
}
|
|
3151
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2653
3152
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2654
3153
|
return await computeEvidenceFreshness(ctx, args.beliefNodeId);
|
|
2655
3154
|
}
|
|
@@ -2661,10 +3160,7 @@ var evaluateDependentBeliefCount = query({
|
|
|
2661
3160
|
returns: permissiveReturn,
|
|
2662
3161
|
handler: async (ctx, args) => {
|
|
2663
3162
|
const userId = await requireAuth(ctx);
|
|
2664
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2665
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2666
|
-
throw new Error("Belief not found.");
|
|
2667
|
-
}
|
|
3163
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2668
3164
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2669
3165
|
return await computeDependentBeliefCount(ctx, args.beliefNodeId);
|
|
2670
3166
|
}
|
|
@@ -2728,10 +3224,7 @@ var createEpistemicContract = mutation({
|
|
|
2728
3224
|
ctx,
|
|
2729
3225
|
args.authenticatedUserId
|
|
2730
3226
|
);
|
|
2731
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2732
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2733
|
-
throw new Error("Belief not found.");
|
|
2734
|
-
}
|
|
3227
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2735
3228
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2736
3229
|
const now = Date.now();
|
|
2737
3230
|
const contractId = generateGlobalId();
|
|
@@ -2786,10 +3279,10 @@ var evaluateContract = mutation({
|
|
|
2786
3279
|
if (contract.status === "archived") {
|
|
2787
3280
|
throw new Error("Archived contracts cannot be evaluated.");
|
|
2788
3281
|
}
|
|
2789
|
-
const belief =
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
3282
|
+
const belief = assertBeliefNode(
|
|
3283
|
+
await ctx.db.get(contract.beliefNodeId),
|
|
3284
|
+
"Belief not found for contract."
|
|
3285
|
+
);
|
|
2793
3286
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2794
3287
|
const evaluation = await executeContractEvaluation({
|
|
2795
3288
|
ctx,
|
|
@@ -2827,14 +3320,11 @@ var evaluateEngineeringContracts = mutation({
|
|
|
2827
3320
|
ctx,
|
|
2828
3321
|
args.authenticatedUserId
|
|
2829
3322
|
);
|
|
2830
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2831
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2832
|
-
throw new Error("Belief not found.");
|
|
2833
|
-
}
|
|
3323
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2834
3324
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2835
3325
|
const trigger = args.trigger ?? "event_driven";
|
|
2836
3326
|
const allowedSchedules = resolveSchedulesForTrigger2(
|
|
2837
|
-
trigger
|
|
3327
|
+
normalizeEngineeringTrigger(trigger)
|
|
2838
3328
|
);
|
|
2839
3329
|
const payloadByEvaluator = /* @__PURE__ */ new Map([
|
|
2840
3330
|
["test_runner", args.testOutput],
|
|
@@ -2913,10 +3403,7 @@ var evaluateContractsForTrigger = mutation({
|
|
|
2913
3403
|
ctx,
|
|
2914
3404
|
args.authenticatedUserId
|
|
2915
3405
|
);
|
|
2916
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2917
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2918
|
-
throw new Error("Belief not found.");
|
|
2919
|
-
}
|
|
3406
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2920
3407
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2921
3408
|
return await evaluateContractsForTriggerBatch({
|
|
2922
3409
|
ctx,
|
|
@@ -2939,10 +3426,7 @@ var processContractEvaluationOverflow = internalMutation({
|
|
|
2939
3426
|
},
|
|
2940
3427
|
returns: permissiveReturn,
|
|
2941
3428
|
handler: async (ctx, args) => {
|
|
2942
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2943
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2944
|
-
throw new Error("Belief not found.");
|
|
2945
|
-
}
|
|
3429
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2946
3430
|
return await evaluateContractsForTriggerBatch({
|
|
2947
3431
|
ctx,
|
|
2948
3432
|
belief,
|
|
@@ -2981,15 +3465,9 @@ var getContractStatus = query({
|
|
|
2981
3465
|
const contract = await getContractByContractId(ctx, args.contractId);
|
|
2982
3466
|
contracts = contract ? [contract] : [];
|
|
2983
3467
|
} else if (args.beliefNodeId) {
|
|
2984
|
-
const belief = await ctx.db.get(args.beliefNodeId);
|
|
2985
|
-
if (!belief || belief.nodeType !== "belief") {
|
|
2986
|
-
throw new Error("Belief not found.");
|
|
2987
|
-
}
|
|
3468
|
+
const belief = assertBeliefNode(await ctx.db.get(args.beliefNodeId));
|
|
2988
3469
|
await requireBeliefProjectAccess(ctx, belief, userId);
|
|
2989
|
-
contracts = await ctx.
|
|
2990
|
-
"by_belief",
|
|
2991
|
-
(q) => q.eq("beliefNodeId", args.beliefNodeId)
|
|
2992
|
-
).collect();
|
|
3470
|
+
contracts = await contractTables(ctx).query("epistemicContracts").withIndex("by_belief", (q) => q.eq("beliefNodeId", args.beliefNodeId)).collect();
|
|
2993
3471
|
}
|
|
2994
3472
|
if (contracts.length > 0) {
|
|
2995
3473
|
const contractBeliefDocs = await Promise.all(
|
|
@@ -2997,15 +3475,14 @@ var getContractStatus = query({
|
|
|
2997
3475
|
);
|
|
2998
3476
|
const contractBeliefs = [];
|
|
2999
3477
|
for (const belief of contractBeliefDocs) {
|
|
3000
|
-
|
|
3001
|
-
throw new Error("Belief not found.");
|
|
3002
|
-
}
|
|
3003
|
-
contractBeliefs.push(belief);
|
|
3478
|
+
contractBeliefs.push(assertBeliefNode(belief));
|
|
3004
3479
|
}
|
|
3005
3480
|
await requireTopicReadAccess(ctx, contractBeliefs, userId);
|
|
3006
3481
|
}
|
|
3007
3482
|
if (args.status) {
|
|
3008
|
-
contracts = contracts.filter(
|
|
3483
|
+
contracts = contracts.filter(
|
|
3484
|
+
(contract) => contract.status === args.status
|
|
3485
|
+
);
|
|
3009
3486
|
}
|
|
3010
3487
|
const rows = await Promise.all(
|
|
3011
3488
|
contracts.map(async (contract) => ({
|
|
@@ -3024,21 +3501,22 @@ var getContractCoverage = query({
|
|
|
3024
3501
|
},
|
|
3025
3502
|
returns: permissiveReturn,
|
|
3026
3503
|
handler: async (ctx, args) => {
|
|
3027
|
-
const contracts = await ctx.
|
|
3504
|
+
const contracts = await contractTables(ctx).query("epistemicContracts").withIndex("by_topic", (q) => q.eq("topicId", args.topicId)).collect();
|
|
3028
3505
|
const userId = await resolveAuthenticatedUserId(
|
|
3029
3506
|
ctx,
|
|
3030
3507
|
args.authenticatedUserId
|
|
3031
3508
|
);
|
|
3032
|
-
const
|
|
3509
|
+
const beliefRows = await ctx.db.query("epistemicNodes").withIndex(
|
|
3033
3510
|
"by_topic_type",
|
|
3034
3511
|
(q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
|
|
3035
3512
|
).collect();
|
|
3513
|
+
const beliefs = beliefRows.map((belief) => assertBeliefNode(belief));
|
|
3036
3514
|
await requireTopicReadAccess(ctx, beliefs, userId);
|
|
3037
3515
|
const recentEvaluationLimit = Math.max(
|
|
3038
3516
|
0,
|
|
3039
3517
|
Math.min(args.recentEvaluationLimit ?? 5, 25)
|
|
3040
3518
|
);
|
|
3041
|
-
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);
|
|
3042
3520
|
const contractBeliefIds = new Set(
|
|
3043
3521
|
contracts.filter((contract) => contract.status !== "archived").map((contract) => String(contract.beliefNodeId))
|
|
3044
3522
|
);
|