@lucern/graph-primitives 1.0.28 → 1.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
- package/dist/beliefDecay.d.ts +1 -1
- package/dist/beliefDecay.js +448 -314
- package/dist/beliefDecay.js.map +1 -1
- package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
- package/dist/beliefEvidenceLinks.d.ts +1 -1
- package/dist/beliefEvidenceLinks.js +843 -624
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
- package/dist/beliefEvidenceLinks.operational.js +91 -18
- package/dist/beliefEvidenceLinks.operational.js.map +1 -1
- package/dist/beliefLifecycle.js.map +1 -1
- package/dist/confidencePropagationDispatch.d.ts +28 -27
- package/dist/confidencePropagationDispatch.js +157 -99
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
- package/dist/contradictions.d.ts +1 -1
- package/dist/contradictions.js +398 -228
- package/dist/contradictions.js.map +1 -1
- package/dist/convex.d.ts +65 -30
- package/dist/convex.js +7 -3
- package/dist/convex.js.map +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/edgeValidation.js +293 -85
- package/dist/edgeValidation.js.map +1 -1
- package/dist/edges/contains.d.ts +1 -1
- package/dist/edges/contains.js.map +1 -1
- package/dist/edges/contradicts.d.ts +1 -1
- package/dist/edges/contradicts.js.map +1 -1
- package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
- package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
- package/dist/edges/depends-on.js.map +1 -0
- package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
- package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
- package/dist/edges/derived-from.js.map +1 -0
- package/dist/edges/elaborates.d.ts +1 -1
- package/dist/edges/elaborates.js.map +1 -1
- package/dist/edges/index.d.ts +7 -3
- package/dist/edges/index.js +7 -4
- package/dist/edges/index.js.map +1 -1
- package/dist/edges/informs.d.ts +1 -1
- package/dist/edges/informs.js.map +1 -1
- package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
- package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
- package/dist/edges/propagation-types.js.map +1 -0
- package/dist/edges/refutes.d.ts +1 -1
- package/dist/edges/refutes.js.map +1 -1
- package/dist/edges/supports.d.ts +1 -1
- package/dist/edges/supports.js.map +1 -1
- package/dist/edges/tests.d.ts +1 -1
- package/dist/edges/tests.js.map +1 -1
- package/dist/edges/utils.d.ts +1 -1
- package/dist/edges/utils.js.map +1 -1
- package/dist/embeddingTrigger.d.ts +14 -6
- package/dist/embeddingTrigger.js +11 -14
- package/dist/embeddingTrigger.js.map +1 -1
- package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
- package/dist/entityBridge.d.ts +1 -1
- package/dist/entityBridge.js +602 -225
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityCanonicalMatch.d.ts +14 -12
- package/dist/entityCanonicalMatch.js.map +1 -1
- package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
- package/dist/entityLifecycle.d.ts +1 -1
- package/dist/entityLifecycle.js +857 -515
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
- package/dist/entityValidation.d.ts +3 -1
- package/dist/entityValidation.js +60 -8
- package/dist/entityValidation.js.map +1 -1
- package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
- package/dist/epistemicAnswers.d.ts +1 -1
- package/dist/epistemicAnswers.js +587 -545
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.d.ts +8 -8
- package/dist/epistemicBeliefs.admin.js +366 -203
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.d.ts +8 -8
- package/dist/epistemicBeliefs.backfills.js +655 -308
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.d.ts +19 -14
- package/dist/epistemicBeliefs.confidence.js +634 -423
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.d.ts +6 -6
- package/dist/epistemicBeliefs.core.js +719 -411
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.d.ts +11 -8
- package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
- package/dist/epistemicBeliefs.forkEvidence.js +8 -28
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
- package/dist/epistemicBeliefs.helpers.d.ts +69 -74
- package/dist/epistemicBeliefs.helpers.js +359 -248
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.d.ts +5 -5
- package/dist/epistemicBeliefs.internal.js +1246 -1044
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +4922 -3608
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
- package/dist/epistemicBeliefs.lifecycle.js +1137 -818
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.d.ts +7 -7
- package/dist/epistemicBeliefs.links.js +408 -307
- package/dist/epistemicBeliefs.links.js.map +1 -1
- package/dist/epistemicBeliefs.queries.d.ts +4 -4
- package/dist/epistemicBeliefs.queries.js +175 -20
- package/dist/epistemicBeliefs.queries.js.map +1 -1
- package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
- package/dist/epistemicBeliefs.topicAnchor.js +12 -5
- package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
- package/dist/epistemicContracts.d.ts +28 -3
- package/dist/epistemicContracts.evaluators.d.ts +2 -0
- package/dist/epistemicContracts.evaluators.js +1063 -613
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.d.ts +15 -32
- package/dist/epistemicContracts.handlers.js +2086 -1644
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +1131 -672
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicContracts.metrics.d.ts +2 -0
- package/dist/epistemicContracts.metrics.js +375 -158
- package/dist/epistemicContracts.metrics.js.map +1 -1
- package/dist/epistemicContracts.types.d.ts +87 -81
- package/dist/epistemicEdgeCreation.d.ts +2 -0
- package/dist/epistemicEdgeCreation.js +87 -16
- package/dist/epistemicEdgeCreation.js.map +1 -1
- package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
- package/dist/epistemicEdges.d.ts +6 -5
- package/dist/epistemicEdges.handlers.d.ts +3 -3
- package/dist/epistemicEdges.handlers.js +129 -24
- package/dist/epistemicEdges.handlers.js.map +1 -1
- package/dist/epistemicEdges.helpers.d.ts +6 -4
- package/dist/epistemicEdges.helpers.js +37 -2
- package/dist/epistemicEdges.helpers.js.map +1 -1
- package/dist/epistemicEdges.js +1969 -1205
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.d.ts +7 -7
- package/dist/epistemicEdges.mutations.js +960 -583
- package/dist/epistemicEdges.mutations.js.map +1 -1
- package/dist/epistemicEdges.queries.d.ts +16 -16
- package/dist/epistemicEdges.queries.js +639 -367
- package/dist/epistemicEdges.queries.js.map +1 -1
- package/dist/epistemicEdges.types.d.ts +10 -8
- package/dist/epistemicEvidence.d.ts +4 -1
- package/dist/epistemicEvidence.js +937 -536
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.d.ts +26 -10
- package/dist/epistemicEvidenceHelpers.js +239 -200
- package/dist/epistemicEvidenceHelpers.js.map +1 -1
- package/dist/epistemicEvidenceMutations.d.ts +8 -8
- package/dist/epistemicEvidenceMutations.js +844 -696
- package/dist/epistemicEvidenceMutations.js.map +1 -1
- package/dist/epistemicEvidenceQueries.d.ts +8 -8
- package/dist/epistemicEvidenceQueries.js +514 -238
- package/dist/epistemicEvidenceQueries.js.map +1 -1
- package/dist/epistemicHelpers.d.ts +4 -2
- package/dist/epistemicHelpers.js +308 -134
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicInsert.d.ts +16 -4
- package/dist/epistemicInsert.js +6 -3
- package/dist/epistemicInsert.js.map +1 -1
- package/dist/epistemicLayerRules.d.ts +10 -8
- package/dist/epistemicLayerRules.js +1 -5
- package/dist/epistemicLayerRules.js.map +1 -1
- package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
- package/dist/epistemicLinking.d.ts +1 -1
- package/dist/epistemicLinking.js +177 -100
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodeCreation.d.ts +2 -0
- package/dist/epistemicNodeCreation.js +203 -40
- package/dist/epistemicNodeCreation.js.map +1 -1
- package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
- package/dist/epistemicNodes.d.ts +3 -3
- package/dist/epistemicNodes.helpers.d.ts +24 -15
- package/dist/epistemicNodes.helpers.js.map +1 -1
- package/dist/epistemicNodes.internal.d.ts +6 -6
- package/dist/epistemicNodes.internal.js +389 -319
- package/dist/epistemicNodes.internal.js.map +1 -1
- package/dist/epistemicNodes.js +704 -508
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.d.ts +6 -6
- package/dist/epistemicNodes.mutations.js +564 -467
- package/dist/epistemicNodes.mutations.js.map +1 -1
- package/dist/epistemicNodes.queries.d.ts +8 -8
- package/dist/epistemicNodes.queries.js +311 -314
- package/dist/epistemicNodes.queries.js.map +1 -1
- package/dist/epistemicNodes.validators.d.ts +2 -2
- package/dist/epistemicNodes.validators.js.map +1 -1
- package/dist/epistemicQuestions.conviction.d.ts +8 -8
- package/dist/epistemicQuestions.conviction.js +665 -484
- package/dist/epistemicQuestions.conviction.js.map +1 -1
- package/dist/epistemicQuestions.create.d.ts +4 -4
- package/dist/epistemicQuestions.create.js +640 -612
- package/dist/epistemicQuestions.create.js.map +1 -1
- package/dist/epistemicQuestions.d.ts +8 -5
- package/dist/epistemicQuestions.evidence.d.ts +2 -2
- package/dist/epistemicQuestions.evidence.js +475 -383
- package/dist/epistemicQuestions.evidence.js.map +1 -1
- package/dist/epistemicQuestions.helpers.d.ts +125 -24
- package/dist/epistemicQuestions.helpers.js +240 -209
- package/dist/epistemicQuestions.helpers.js.map +1 -1
- package/dist/epistemicQuestions.js +3474 -2823
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
- package/dist/epistemicQuestions.lifecycle.js +607 -546
- package/dist/epistemicQuestions.lifecycle.js.map +1 -1
- package/dist/epistemicQuestions.queries.d.ts +12 -7
- package/dist/epistemicQuestions.queries.js +305 -244
- package/dist/epistemicQuestions.queries.js.map +1 -1
- package/dist/epistemicQuestions.sprint.d.ts +2 -2
- package/dist/epistemicQuestions.sprint.js +600 -394
- package/dist/epistemicQuestions.sprint.js.map +1 -1
- package/dist/epistemicQuestions.tail.d.ts +6 -6
- package/dist/epistemicQuestions.tail.js +572 -433
- package/dist/epistemicQuestions.tail.js.map +1 -1
- package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
- package/dist/epistemicSources.d.ts +1 -1
- package/dist/epistemicSources.js +352 -312
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.d.ts +8 -6
- package/dist/evaluators/index.js +399 -167
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
- package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
- package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
- package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
- package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
- package/dist/evaluators/shared.d.ts +2 -2
- package/dist/evaluators/shared.js +3 -1
- package/dist/evaluators/shared.js.map +1 -1
- package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
- package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
- package/dist/evaluators/test-runner-evaluator.js.map +1 -0
- package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
- package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
- package/dist/graphTypes.js +6 -2
- package/dist/graphTypes.js.map +1 -1
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +313 -93
- package/dist/helpers.js.map +1 -1
- package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
- package/dist/index.d.ts +87 -83
- package/dist/index.js +15677 -10594
- package/dist/index.js.map +1 -1
- package/dist/invariantEnforcement.d.ts +3 -3
- package/dist/invariantEnforcement.js.map +1 -1
- package/dist/logicalRoleInference.d.ts +2 -0
- package/dist/logicalRoleInference.js +1 -1
- package/dist/logicalRoleInference.js.map +1 -1
- package/dist/matcherFeedbackUtils.d.ts +2 -2
- package/dist/matcherFeedbackUtils.js.map +1 -1
- package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
- package/dist/ontology-matching.d.ts +1 -1
- package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
- package/dist/ontologyApproval.d.ts +1 -1
- package/dist/ontologyApproval.js +7 -1
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.d.ts +14 -24
- package/dist/ontologyDefinitions.js +269 -34
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyHelpers.d.ts +13 -13
- package/dist/ontologyHelpers.js.map +1 -1
- package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
- package/dist/ontologyRegistry.d.ts +1 -1
- package/dist/ontologyRegistry.js +34 -6
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
- package/dist/projectionReconciliation.d.ts +1 -1
- package/dist/projectionReconciliation.js +57 -10
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
- package/dist/projectionStaleness.d.ts +1 -1
- package/dist/projectionStaleness.js +8 -2
- package/dist/projectionStaleness.js.map +1 -1
- package/dist/proof-attestation.json +1 -1
- package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
- package/dist/questionEvidenceLinks.d.ts +1 -1
- package/dist/questionEvidenceLinks.js +564 -347
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
- package/dist/resolverTypes.d.ts +4 -2
- package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
- package/dist/resolvers.d.ts +5 -3
- package/dist/resolvers.js +121 -77
- package/dist/resolvers.js.map +1 -1
- package/dist/scopeResolverCompat.d.ts +10 -7
- package/dist/scopeResolverCompat.js +106 -123
- package/dist/scopeResolverCompat.js.map +1 -1
- package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
- package/dist/text-matching.d.ts +1 -1
- package/dist/topicOntologyResolver.d.ts +22 -21
- package/dist/topicOntologyResolver.js +54 -32
- package/dist/topicOntologyResolver.js.map +1 -1
- package/dist/topicProjectOverlay.d.ts +30 -20
- package/dist/topicProjectOverlay.js +120 -76
- package/dist/topicProjectOverlay.js.map +1 -1
- package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
- package/dist/topicScope.d.ts +3 -1
- package/dist/topicScope.js +104 -119
- package/dist/topicScope.js.map +1 -1
- package/dist/workflowBridge.d.ts +26 -15
- package/dist/workflowBridge.js +140 -144
- package/dist/workflowBridge.js.map +1 -1
- package/dist/workspaceIsolation.d.ts +14 -12
- package/dist/workspaceIsolation.js +108 -122
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +4 -4
- package/dist/edges/dependsOn.js.map +0 -1
- package/dist/edges/derivedFrom.js.map +0 -1
- package/dist/edges/propagationTypes.js.map +0 -1
- package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
- package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
- package/dist/{epistemicQuestions-bwHd2FWE.d.ts → epistemicQuestions-Do1fhYm5.d.ts} +4 -4
|
@@ -1,23 +1,138 @@
|
|
|
1
|
-
import { v, ConvexError } from 'convex/values';
|
|
2
1
|
import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
|
|
3
2
|
import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
|
|
4
3
|
import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
|
|
5
4
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
10
|
-
import { normalizeTupleContradictionPolicy, confidenceFromSL } from '@lucern/confidence';
|
|
11
|
-
import '@lucern/access-control/access';
|
|
5
|
+
import { v } from 'convex/values';
|
|
6
|
+
import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
|
|
7
|
+
import { componentsGeneric, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
|
|
12
8
|
import '@lucern/access-control/auth';
|
|
9
|
+
import { throwStructuredMutationError } from '@lucern/access-control/structuredMutationError';
|
|
10
|
+
import { normalizeTupleContradictionPolicy, confidenceFromSL } from '@lucern/confidence';
|
|
11
|
+
import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
12
|
+
import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
|
|
13
|
+
import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
|
|
13
14
|
|
|
14
15
|
// src/epistemicBeliefs.internal.ts
|
|
15
|
-
var
|
|
16
|
+
var unsafeApi = unsafeConvexAnyApi(
|
|
17
|
+
"graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
|
|
18
|
+
);
|
|
19
|
+
var api = unsafeApi;
|
|
16
20
|
componentsGeneric();
|
|
17
|
-
var internal =
|
|
21
|
+
var internal = unsafeApi;
|
|
18
22
|
var internalMutation = internalMutationGeneric;
|
|
19
23
|
var internalQuery = internalQueryGeneric;
|
|
20
24
|
|
|
25
|
+
// src/beliefLifecycle.ts
|
|
26
|
+
var BELIEF_STATUS_VALUES = [
|
|
27
|
+
"assumption",
|
|
28
|
+
"hypothesis",
|
|
29
|
+
"active",
|
|
30
|
+
"superseded",
|
|
31
|
+
"resolved_true",
|
|
32
|
+
"resolved_false"
|
|
33
|
+
];
|
|
34
|
+
function isBeliefLifecycleStatus(value) {
|
|
35
|
+
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
36
|
+
}
|
|
37
|
+
function normalizeLegacyBeliefStatus(value) {
|
|
38
|
+
if (isBeliefLifecycleStatus(value)) {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
if (value === "belief" || value === "established" || value === "emerging") {
|
|
42
|
+
return "active";
|
|
43
|
+
}
|
|
44
|
+
if (value === "fact" || value === "confirmed") {
|
|
45
|
+
return "resolved_true";
|
|
46
|
+
}
|
|
47
|
+
if (value === "disconfirmed" || value === "expired") {
|
|
48
|
+
return "resolved_false";
|
|
49
|
+
}
|
|
50
|
+
if (value === "deprecated") {
|
|
51
|
+
return "superseded";
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
function normalizeBeliefConfidence(confidence) {
|
|
56
|
+
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
if (confidence >= 0 && confidence <= 1) {
|
|
60
|
+
return confidence;
|
|
61
|
+
}
|
|
62
|
+
if (confidence > 1 && confidence <= 100) {
|
|
63
|
+
return confidence / 100;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function isResolvedByConfidence(confidence) {
|
|
68
|
+
const normalized = normalizeBeliefConfidence(confidence);
|
|
69
|
+
if (normalized === null) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return normalized <= 0 || normalized >= 1;
|
|
73
|
+
}
|
|
74
|
+
function getPredictionMetaFromMetadata(metadata) {
|
|
75
|
+
return metadata?.predictionMeta;
|
|
76
|
+
}
|
|
77
|
+
function resolvedPredictionStatus(predictionMeta) {
|
|
78
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const outcome = predictionMeta.outcome;
|
|
82
|
+
if (outcome === "confirmed") {
|
|
83
|
+
return "resolved_true";
|
|
84
|
+
}
|
|
85
|
+
if (outcome === "disconfirmed" || outcome === "expired") {
|
|
86
|
+
return "resolved_false";
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
function shouldTreatBeliefAsResolved(opts) {
|
|
91
|
+
if (isResolvedByConfidence(opts.confidence)) {
|
|
92
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
93
|
+
return normalized === 0 ? "resolved_false" : "resolved_true";
|
|
94
|
+
}
|
|
95
|
+
const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
|
|
96
|
+
if (directPredictionStatus) {
|
|
97
|
+
return directPredictionStatus;
|
|
98
|
+
}
|
|
99
|
+
const metadataPredictionStatus = resolvedPredictionStatus(
|
|
100
|
+
getPredictionMetaFromMetadata(opts.metadata)
|
|
101
|
+
);
|
|
102
|
+
if (metadataPredictionStatus) {
|
|
103
|
+
return metadataPredictionStatus;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function resolveBeliefLifecycleStatus(opts) {
|
|
108
|
+
const resolvedStatus = shouldTreatBeliefAsResolved(opts);
|
|
109
|
+
if (resolvedStatus) {
|
|
110
|
+
return resolvedStatus;
|
|
111
|
+
}
|
|
112
|
+
const direct = opts.beliefStatus;
|
|
113
|
+
const normalizedDirect = normalizeLegacyBeliefStatus(direct);
|
|
114
|
+
if (normalizedDirect) {
|
|
115
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
116
|
+
if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
|
|
117
|
+
return "active";
|
|
118
|
+
}
|
|
119
|
+
return normalizedDirect;
|
|
120
|
+
}
|
|
121
|
+
const metaStatus = opts.metadata?.beliefStatus;
|
|
122
|
+
const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
|
|
123
|
+
if (normalizedMetaStatus) {
|
|
124
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
125
|
+
if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
|
|
126
|
+
return "active";
|
|
127
|
+
}
|
|
128
|
+
return normalizedMetaStatus;
|
|
129
|
+
}
|
|
130
|
+
return "assumption";
|
|
131
|
+
}
|
|
132
|
+
function isPreValidationBeliefStatus(status) {
|
|
133
|
+
return status === "assumption" || status === "hypothesis";
|
|
134
|
+
}
|
|
135
|
+
|
|
21
136
|
// src/debug.ts
|
|
22
137
|
function isGraphPrimitiveDebugEnabled() {
|
|
23
138
|
const env = globalThis.process?.env;
|
|
@@ -30,973 +145,723 @@ function debugGraphPrimitiveFallback(message, context) {
|
|
|
30
145
|
console.debug(message, context ?? {});
|
|
31
146
|
}
|
|
32
147
|
|
|
33
|
-
// src/
|
|
148
|
+
// src/topicProjectOverlay.ts
|
|
34
149
|
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
35
|
-
|
|
36
|
-
if (
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
let node = null;
|
|
40
|
-
try {
|
|
41
|
-
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
42
|
-
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
43
|
-
node = byGlobalId;
|
|
44
|
-
}
|
|
45
|
-
} catch (error) {
|
|
46
|
-
debugGraphPrimitiveFallback(
|
|
47
|
-
"[topicScope] topic-node scope lookup by globalId failed",
|
|
48
|
-
{ error, ref }
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
if (!node) {
|
|
52
|
-
return null;
|
|
150
|
+
function readNonEmptyString(value) {
|
|
151
|
+
if (typeof value !== "string") {
|
|
152
|
+
return;
|
|
53
153
|
}
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
154
|
+
const normalized = value.trim();
|
|
155
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
156
|
+
}
|
|
157
|
+
function readStringArray(value) {
|
|
158
|
+
if (!Array.isArray(value)) {
|
|
159
|
+
return [];
|
|
57
160
|
}
|
|
58
|
-
return
|
|
59
|
-
topicId: scopeKey,
|
|
60
|
-
projectId: asMappedProjectId(node),
|
|
61
|
-
source: "topic_node"
|
|
62
|
-
};
|
|
161
|
+
return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
|
|
63
162
|
}
|
|
64
|
-
function
|
|
65
|
-
|
|
163
|
+
function readMetadata(topic) {
|
|
164
|
+
return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
|
|
165
|
+
}
|
|
166
|
+
function omitMetadataKey(metadata, key) {
|
|
167
|
+
const { [key]: _omitted, ...rest } = metadata;
|
|
168
|
+
return rest;
|
|
169
|
+
}
|
|
170
|
+
function readLegacyProjectId(value) {
|
|
171
|
+
if (!value) {
|
|
66
172
|
return;
|
|
67
173
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
174
|
+
return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
|
|
175
|
+
}
|
|
176
|
+
function coerceVisibility(value) {
|
|
177
|
+
return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
|
|
178
|
+
}
|
|
179
|
+
function coerceStatus(value) {
|
|
180
|
+
return value === "active" || value === "archived" || value === "watching" ? value : void 0;
|
|
181
|
+
}
|
|
182
|
+
function mapProjectType(topic, metadata) {
|
|
183
|
+
const explicit = readNonEmptyString(metadata.projectType);
|
|
184
|
+
if (explicit) {
|
|
185
|
+
return explicit;
|
|
71
186
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
187
|
+
if (topic.type === "theme") {
|
|
188
|
+
return "thematic";
|
|
189
|
+
}
|
|
190
|
+
return readNonEmptyString(topic.type) || "general";
|
|
75
191
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
192
|
+
function isProjectLikeTopic(topic) {
|
|
193
|
+
const metadata = readMetadata(topic);
|
|
194
|
+
return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
|
|
195
|
+
}
|
|
196
|
+
function isMissingLucernChildComponentError(error) {
|
|
197
|
+
const message = getErrorMessage(error);
|
|
198
|
+
return message.includes(
|
|
199
|
+
'Child component ComponentName(Identifier("lucern")) not found'
|
|
200
|
+
) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
|
|
201
|
+
}
|
|
202
|
+
function getErrorMessage(error) {
|
|
203
|
+
if (error instanceof Error) {
|
|
204
|
+
return error.message;
|
|
79
205
|
}
|
|
80
|
-
|
|
81
|
-
|
|
206
|
+
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
|
|
207
|
+
return error.message;
|
|
208
|
+
}
|
|
209
|
+
return "unknown error";
|
|
82
210
|
}
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
211
|
+
async function resolveTopicDoc(ctx, scopeId) {
|
|
212
|
+
if (ctx?.db && typeof ctx.db.get === "function") {
|
|
213
|
+
try {
|
|
214
|
+
const directTopic = await ctx.db.get(
|
|
215
|
+
scopeId
|
|
216
|
+
);
|
|
217
|
+
if (directTopic) {
|
|
218
|
+
return directTopic;
|
|
219
|
+
}
|
|
220
|
+
} catch (error) {
|
|
221
|
+
debugGraphPrimitiveFallback(
|
|
222
|
+
"[topicProjectOverlay] Failed to resolve topic by direct ID",
|
|
223
|
+
{
|
|
224
|
+
error,
|
|
225
|
+
scopeId
|
|
226
|
+
}
|
|
227
|
+
);
|
|
94
228
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
229
|
+
}
|
|
230
|
+
if (typeof ctx.runQuery !== "function") {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
99
233
|
try {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
234
|
+
const topic = await ctx.runQuery(api.topics.get, {
|
|
235
|
+
id: String(scopeId)
|
|
236
|
+
});
|
|
237
|
+
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
238
|
+
return topic;
|
|
239
|
+
}
|
|
104
240
|
} catch (error) {
|
|
105
241
|
debugGraphPrimitiveFallback(
|
|
106
|
-
"[
|
|
242
|
+
"[topicProjectOverlay] Failed to resolve topic by ID query",
|
|
107
243
|
{
|
|
108
244
|
error,
|
|
109
245
|
scopeId
|
|
110
246
|
}
|
|
111
247
|
);
|
|
112
|
-
const topics = await ctx.db.query("topics").collect();
|
|
113
|
-
return topics.filter((topic) => {
|
|
114
|
-
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
115
|
-
const mappedProjectId = asMappedProjectId(topic);
|
|
116
|
-
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async function tryResolveHostTopicById(ctx, topicId) {
|
|
121
|
-
if (typeof ctx.runQuery !== "function") {
|
|
122
|
-
return null;
|
|
123
248
|
}
|
|
124
249
|
try {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}) ?? null;
|
|
128
|
-
} catch (error) {
|
|
129
|
-
debugGraphPrimitiveFallback(
|
|
130
|
-
"[topicScope] Failed to resolve topic by host query",
|
|
250
|
+
const topic = await ctx.runQuery(
|
|
251
|
+
api.topics.getByLegacyScopeId,
|
|
131
252
|
{
|
|
132
|
-
|
|
133
|
-
topicId
|
|
253
|
+
projectId: String(scopeId)
|
|
134
254
|
}
|
|
135
255
|
);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
140
|
-
if (typeof ctx.runQuery !== "function") {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
145
|
-
projectId: legacyScopeId
|
|
146
|
-
}) ?? null;
|
|
256
|
+
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
257
|
+
return topic;
|
|
258
|
+
}
|
|
147
259
|
} catch (error) {
|
|
148
260
|
debugGraphPrimitiveFallback(
|
|
149
|
-
"[
|
|
150
|
-
{
|
|
151
|
-
error,
|
|
152
|
-
legacyScopeId
|
|
153
|
-
}
|
|
261
|
+
"[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
|
|
262
|
+
{ error, scopeId }
|
|
154
263
|
);
|
|
155
|
-
return null;
|
|
156
264
|
}
|
|
265
|
+
return null;
|
|
157
266
|
}
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
267
|
+
function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
268
|
+
const metadata = readMetadata(topic);
|
|
269
|
+
const topicId = String(topic._id);
|
|
270
|
+
const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
|
|
271
|
+
const storageProjectId = legacyProjectId || topicId;
|
|
272
|
+
const outwardId = idMode === "topic" ? topicId : storageProjectId;
|
|
273
|
+
const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
|
|
274
|
+
const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
|
|
275
|
+
let createdAt = 0;
|
|
276
|
+
if (typeof topic.createdAt === "number") {
|
|
277
|
+
createdAt = topic.createdAt;
|
|
278
|
+
} else if (typeof topic._creationTime === "number") {
|
|
279
|
+
createdAt = topic._creationTime;
|
|
280
|
+
}
|
|
281
|
+
let updatedAt = createdAt;
|
|
282
|
+
if (typeof topic.updatedAt === "number") {
|
|
283
|
+
updatedAt = topic.updatedAt;
|
|
284
|
+
} else if (typeof metadata.updatedAt === "number") {
|
|
285
|
+
updatedAt = metadata.updatedAt;
|
|
164
286
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
287
|
+
return {
|
|
288
|
+
...metadata,
|
|
289
|
+
_id: outwardId,
|
|
290
|
+
projectId: outwardId,
|
|
291
|
+
topicId,
|
|
292
|
+
storageProjectId,
|
|
293
|
+
legacyProjectId,
|
|
294
|
+
name: readNonEmptyString(topic.name) || "Untitled Theme",
|
|
295
|
+
type: mapProjectType(topic, metadata),
|
|
296
|
+
description: readNonEmptyString(topic.description),
|
|
297
|
+
ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
|
|
298
|
+
// FR.7 creator-grant: surface the principal-shaped owner field (column-first,
|
|
299
|
+
// metadata fallback for legacy rows that recorded it in metadata).
|
|
300
|
+
ownerPrincipalId: readNonEmptyString(topic.ownerPrincipalId) || readNonEmptyString(metadata.ownerPrincipalId),
|
|
301
|
+
// RR.1 carrier: preserve the nested metadata carrier so the kernel's
|
|
302
|
+
// `checkProjectAccessDetailed` metadata-PRIMARY read
|
|
303
|
+
// (`project.metadata?.ownerPrincipalId`) resolves the grant. The `...metadata`
|
|
304
|
+
// spread above only flattens keys; it does not leave a nested `metadata`.
|
|
305
|
+
metadata,
|
|
306
|
+
sharedWith: readStringArray(metadata.sharedWith),
|
|
307
|
+
visibility,
|
|
308
|
+
tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
|
|
309
|
+
workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
|
|
310
|
+
status,
|
|
311
|
+
tags: readStringArray(metadata.tags),
|
|
312
|
+
chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
|
|
313
|
+
artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
|
|
314
|
+
lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
|
|
315
|
+
_creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
|
|
316
|
+
createdAt,
|
|
317
|
+
updatedAt
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
|
|
321
|
+
const topic = await resolveTopicDoc(ctx, scopeId);
|
|
322
|
+
if (!topic) {
|
|
323
|
+
return null;
|
|
176
324
|
}
|
|
177
|
-
|
|
325
|
+
if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
return materializeTopicProjectOverlay(topic, options.idMode);
|
|
178
329
|
}
|
|
179
|
-
async function
|
|
180
|
-
|
|
181
|
-
|
|
330
|
+
async function listTopicProjectOverlays(ctx, options = {}) {
|
|
331
|
+
let allTopics = [];
|
|
332
|
+
if (ctx?.db?.query && typeof ctx.db.query === "function") {
|
|
182
333
|
try {
|
|
183
|
-
|
|
184
|
-
args.topicId
|
|
185
|
-
);
|
|
334
|
+
allTopics = await ctx.db.query("topics").collect();
|
|
186
335
|
} catch (error) {
|
|
187
336
|
debugGraphPrimitiveFallback(
|
|
188
|
-
"[
|
|
189
|
-
{
|
|
190
|
-
error,
|
|
191
|
-
topicId: args.topicId
|
|
192
|
-
}
|
|
337
|
+
"[topicProjectOverlay] Failed to read topics table; falling back to API",
|
|
338
|
+
{ error }
|
|
193
339
|
);
|
|
340
|
+
allTopics = [];
|
|
194
341
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
342
|
+
}
|
|
343
|
+
if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
|
|
344
|
+
allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
|
|
345
|
+
}
|
|
346
|
+
return allTopics.filter(
|
|
347
|
+
(topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
|
|
348
|
+
).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
|
|
349
|
+
}
|
|
350
|
+
async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
351
|
+
const topic = await resolveTopicDoc(ctx, scopeId);
|
|
352
|
+
if (!topic) {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
const plan = buildTopicProjectOverlayPatchPlan(topic, value);
|
|
356
|
+
await applyTopicProjectOverlayPatch(ctx, topic, plan);
|
|
357
|
+
return materializeTopicProjectOverlay({
|
|
358
|
+
...topic,
|
|
359
|
+
...plan.patch,
|
|
360
|
+
metadata: plan.nextMetadata
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
function buildTopicProjectOverlayPatchPlan(topic, value) {
|
|
364
|
+
const plan = {
|
|
365
|
+
nextMetadata: { ...readMetadata(topic) },
|
|
366
|
+
patch: {},
|
|
367
|
+
topicUpdateArgs: {
|
|
368
|
+
id: String(topic._id)
|
|
202
369
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
370
|
+
};
|
|
371
|
+
for (const [key, rawValue] of Object.entries(value)) {
|
|
372
|
+
applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
|
|
373
|
+
}
|
|
374
|
+
plan.patch.updatedAt = Date.now();
|
|
375
|
+
plan.patch.metadata = plan.nextMetadata;
|
|
376
|
+
plan.topicUpdateArgs.metadata = plan.nextMetadata;
|
|
377
|
+
return plan;
|
|
378
|
+
}
|
|
379
|
+
function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
|
|
380
|
+
switch (key) {
|
|
381
|
+
case "_id":
|
|
382
|
+
case "projectId":
|
|
383
|
+
case "topicId":
|
|
384
|
+
case "legacyProjectId":
|
|
385
|
+
case "storageProjectId":
|
|
386
|
+
case "updatedAt":
|
|
387
|
+
case "createdAt":
|
|
388
|
+
return;
|
|
389
|
+
case "name":
|
|
390
|
+
case "description":
|
|
391
|
+
plan.patch[key] = rawValue;
|
|
392
|
+
plan.topicUpdateArgs[key] = rawValue;
|
|
393
|
+
return;
|
|
394
|
+
case "tenantId":
|
|
395
|
+
case "workspaceId":
|
|
396
|
+
case "ownerId":
|
|
397
|
+
throw new Error(
|
|
398
|
+
`patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
|
|
207
399
|
);
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
400
|
+
case "status":
|
|
401
|
+
applyTopicStatusPatch(plan, rawValue);
|
|
402
|
+
return;
|
|
403
|
+
case "visibility":
|
|
404
|
+
applyTopicVisibilityPatch(plan, rawValue);
|
|
405
|
+
return;
|
|
406
|
+
case "type":
|
|
407
|
+
applyTopicProjectTypePatch(plan, rawValue);
|
|
408
|
+
return;
|
|
409
|
+
default:
|
|
410
|
+
applyTopicMetadataPatch(plan, key, rawValue);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function applyTopicStatusPatch(plan, rawValue) {
|
|
414
|
+
const status = coerceStatus(rawValue);
|
|
415
|
+
if (status) {
|
|
416
|
+
plan.patch.status = status;
|
|
417
|
+
plan.topicUpdateArgs.status = status;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function applyTopicVisibilityPatch(plan, rawValue) {
|
|
421
|
+
const visibility = coerceVisibility(rawValue);
|
|
422
|
+
if (visibility) {
|
|
423
|
+
plan.patch.visibility = visibility;
|
|
424
|
+
plan.topicUpdateArgs.visibility = visibility;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function applyTopicProjectTypePatch(plan, rawValue) {
|
|
428
|
+
const projectType = readNonEmptyString(rawValue);
|
|
429
|
+
if (projectType) {
|
|
430
|
+
plan.nextMetadata.projectType = projectType;
|
|
431
|
+
return;
|
|
230
432
|
}
|
|
231
|
-
|
|
232
|
-
|
|
433
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
|
|
434
|
+
}
|
|
435
|
+
function applyTopicMetadataPatch(plan, key, rawValue) {
|
|
436
|
+
if (rawValue === void 0) {
|
|
437
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
plan.nextMetadata[key] = rawValue;
|
|
441
|
+
}
|
|
442
|
+
async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
|
|
443
|
+
if (typeof ctx.runMutation === "function") {
|
|
233
444
|
try {
|
|
234
|
-
|
|
235
|
-
args.projectId
|
|
236
|
-
);
|
|
445
|
+
await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
|
|
237
446
|
} catch (error) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
projectId: args.projectId
|
|
243
|
-
}
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
if (directTopic) {
|
|
247
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
248
|
-
const mapped = asMappedProjectId(directTopic);
|
|
249
|
-
return {
|
|
250
|
-
topicId: directTopic._id,
|
|
251
|
-
projectId: mapped ?? args.projectId,
|
|
252
|
-
tenantId: inherited.tenantId,
|
|
253
|
-
workspaceId: inherited.workspaceId,
|
|
254
|
-
source: "topic_inferred"
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
258
|
-
if (directTopic) {
|
|
259
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
260
|
-
const mapped = asMappedProjectId(directTopic);
|
|
261
|
-
return {
|
|
262
|
-
topicId: directTopic._id,
|
|
263
|
-
projectId: mapped ?? args.projectId,
|
|
264
|
-
tenantId: inherited.tenantId,
|
|
265
|
-
workspaceId: inherited.workspaceId,
|
|
266
|
-
source: "topic_inferred"
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
270
|
-
const primary = pickPrimaryTopic(topics);
|
|
271
|
-
if (primary) {
|
|
272
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
273
|
-
return {
|
|
274
|
-
topicId: primary._id,
|
|
275
|
-
projectId: args.projectId,
|
|
276
|
-
tenantId: inherited.tenantId,
|
|
277
|
-
workspaceId: inherited.workspaceId,
|
|
278
|
-
source: "project_mapped_topic"
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
282
|
-
ctx,
|
|
283
|
-
String(args.projectId)
|
|
284
|
-
);
|
|
285
|
-
if (nodeScope) {
|
|
286
|
-
return {
|
|
287
|
-
...nodeScope,
|
|
288
|
-
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
289
|
-
};
|
|
447
|
+
if (!canPatchTopicViaLocalDb(ctx, error)) {
|
|
448
|
+
throw error;
|
|
449
|
+
}
|
|
450
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
290
451
|
}
|
|
452
|
+
} else if (ctx?.db && typeof ctx.db.patch === "function") {
|
|
453
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
454
|
+
} else {
|
|
291
455
|
throw new Error(
|
|
292
|
-
|
|
456
|
+
"Cannot patch topic without component adapter (ctx.runMutation unavailable)"
|
|
293
457
|
);
|
|
294
458
|
}
|
|
295
|
-
throw new Error(
|
|
296
|
-
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
297
|
-
);
|
|
298
459
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
topicId: v.optional(v.string())
|
|
302
|
-
};
|
|
303
|
-
async function insertEpistemicNode(ctx, doc) {
|
|
304
|
-
assertUuidV7Identity("epistemicNodes", doc.globalId);
|
|
305
|
-
return ctx.db.insert("epistemicNodes", doc);
|
|
460
|
+
function canPatchTopicViaLocalDb(ctx, error) {
|
|
461
|
+
return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
|
|
306
462
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
463
|
+
|
|
464
|
+
// src/resolvers.ts
|
|
465
|
+
function isMissingLucernChildComponentError2(error) {
|
|
466
|
+
const message = getErrorMessage2(error);
|
|
467
|
+
return message.includes(
|
|
468
|
+
'Child component ComponentName(Identifier("lucern")) not found'
|
|
469
|
+
) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
|
|
315
470
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
|
|
320
|
-
throw new Error(
|
|
321
|
-
"edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
|
|
322
|
-
);
|
|
471
|
+
function getErrorMessage2(error) {
|
|
472
|
+
if (error instanceof Error) {
|
|
473
|
+
return error.message;
|
|
323
474
|
}
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
"edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
|
|
327
|
-
);
|
|
475
|
+
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
|
|
476
|
+
return error.message;
|
|
328
477
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
478
|
+
return "unknown error";
|
|
479
|
+
}
|
|
480
|
+
function isAdvisoryTopicPatch(value) {
|
|
481
|
+
const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
|
|
482
|
+
const keys = Object.keys(value);
|
|
483
|
+
return keys.length > 0 && keys.every((key) => advisoryKeys.has(key));
|
|
484
|
+
}
|
|
485
|
+
async function patchProjectWithTolerance(ctx, projectId, value) {
|
|
486
|
+
try {
|
|
487
|
+
await patchTopicProjectOverlay(ctx, projectId, value);
|
|
488
|
+
} catch (error) {
|
|
489
|
+
if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
492
|
+
console.warn(
|
|
493
|
+
"[lucern graph-primitives] Non-fatal advisory topic patch failure",
|
|
340
494
|
{
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
495
|
+
projectId,
|
|
496
|
+
keys: Object.keys(value),
|
|
497
|
+
error: getErrorMessage2(error)
|
|
344
498
|
}
|
|
345
499
|
);
|
|
346
500
|
}
|
|
347
|
-
return ctx.db.insert("epistemicEdges", doc);
|
|
348
501
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
502
|
+
function defaultResolvers() {
|
|
503
|
+
return {
|
|
504
|
+
getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
|
|
505
|
+
idMode: "legacy",
|
|
506
|
+
projectLikeOnly: false
|
|
507
|
+
}),
|
|
508
|
+
patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
|
|
509
|
+
listTopics: (ctx) => listTopicProjectOverlays(ctx, {
|
|
510
|
+
idMode: "legacy"
|
|
511
|
+
}),
|
|
512
|
+
getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
|
|
513
|
+
};
|
|
353
514
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
if (!normalized) {
|
|
357
|
-
return [];
|
|
358
|
-
}
|
|
359
|
-
const candidates = [normalized];
|
|
360
|
-
if (normalized.startsWith("top_")) {
|
|
361
|
-
candidates.push(normalized.slice(4));
|
|
362
|
-
}
|
|
363
|
-
return [...new Set(candidates)];
|
|
364
|
-
}
|
|
365
|
-
function readTopicNodeRef(args) {
|
|
366
|
-
return cleanString(args.topicGlobalId) ?? cleanString(args.topicNodeId) ?? cleanString(args.topicId);
|
|
367
|
-
}
|
|
368
|
-
async function resolveRequiredTopicAnchor(ctx, topicRef) {
|
|
369
|
-
for (const candidate of topicNodeCandidates(topicRef)) {
|
|
370
|
-
try {
|
|
371
|
-
const direct = await ctx.db.get(candidate);
|
|
372
|
-
if (direct?.nodeType === "topic" && cleanString(direct.globalId)) {
|
|
373
|
-
return direct;
|
|
374
|
-
}
|
|
375
|
-
} catch (_) {
|
|
376
|
-
}
|
|
377
|
-
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
|
|
378
|
-
if (byGlobalId?.nodeType === "topic" && cleanString(byGlobalId.globalId)) {
|
|
379
|
-
return byGlobalId;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
throw new Error(
|
|
383
|
-
"Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes. Legacy topics-table IDs are not valid belief anchors."
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
function scopeFromTopicAnchor(topicNode) {
|
|
515
|
+
var resolverOverrides = {};
|
|
516
|
+
function resolveGraphPrimitivesAppResolvers(_ctx) {
|
|
387
517
|
return {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
tenantId: cleanString(topicNode.tenantId),
|
|
391
|
-
workspaceId: cleanString(topicNode.workspaceId),
|
|
392
|
-
source: "topic"
|
|
518
|
+
...defaultResolvers(),
|
|
519
|
+
...resolverOverrides
|
|
393
520
|
};
|
|
394
521
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
"by_from_to",
|
|
400
|
-
(q) => q.eq("fromNodeId", args.beliefGlobalId).eq("toNodeId", topicGlobalId)
|
|
401
|
-
).collect();
|
|
402
|
-
const existing = existingEdges.find((edge) => edge.edgeType === "belongs_to");
|
|
403
|
-
const edgeGlobalId = cleanString(existing?.globalId) ?? generateUuidV7();
|
|
404
|
-
if (!existing) {
|
|
405
|
-
await insertEpistemicEdge(ctx, {
|
|
406
|
-
globalId: edgeGlobalId,
|
|
407
|
-
fromNodeId: args.beliefGlobalId,
|
|
408
|
-
toNodeId: topicGlobalId,
|
|
409
|
-
sourceGlobalId: args.beliefGlobalId,
|
|
410
|
-
targetGlobalId: topicGlobalId,
|
|
411
|
-
edgeType: "belongs_to",
|
|
412
|
-
weight: 1,
|
|
413
|
-
confidence: 1,
|
|
414
|
-
context: "Belief creation topic anchor invariant.",
|
|
415
|
-
reasoningMethod: "implicit",
|
|
416
|
-
derivationType: "topic_scope_invariant",
|
|
417
|
-
metadata: {
|
|
418
|
-
invariant: "belief.topic_edge_required",
|
|
419
|
-
edgeUuid: edgeGlobalId,
|
|
420
|
-
fromUuid: args.beliefGlobalId,
|
|
421
|
-
toUuid: topicGlobalId
|
|
422
|
-
},
|
|
423
|
-
createdBy: args.createdBy,
|
|
424
|
-
createdAt: now,
|
|
425
|
-
updatedAt: now,
|
|
426
|
-
projectId: cleanString(args.topicNode.projectId),
|
|
427
|
-
topicId: topicGlobalId,
|
|
428
|
-
tenantId: cleanString(args.topicNode.tenantId),
|
|
429
|
-
workspaceId: cleanString(args.topicNode.workspaceId),
|
|
430
|
-
fromNodeType: "belief",
|
|
431
|
-
toNodeType: "topic",
|
|
432
|
-
fromLayer: "L3",
|
|
433
|
-
toLayer: args.topicNode.epistemicLayer ?? "ontological"
|
|
434
|
-
});
|
|
522
|
+
var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
|
|
523
|
+
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
524
|
+
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
525
|
+
return null;
|
|
435
526
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
weight: 1,
|
|
442
|
-
confidence: 1,
|
|
443
|
-
context: "Belief creation topic anchor invariant.",
|
|
444
|
-
projectId: cleanString(args.topicNode.projectId),
|
|
445
|
-
topicId: topicGlobalId,
|
|
446
|
-
createdBy: args.createdBy,
|
|
447
|
-
fromNodeType: "belief",
|
|
448
|
-
toNodeType: "topic",
|
|
449
|
-
fromLayer: "L3",
|
|
450
|
-
toLayer: args.topicNode.epistemicLayer ?? "ontological",
|
|
451
|
-
metadata: {
|
|
452
|
-
invariant: "belief.topic_edge_required",
|
|
453
|
-
edgeUuid: edgeGlobalId,
|
|
454
|
-
fromUuid: args.beliefGlobalId,
|
|
455
|
-
toUuid: topicGlobalId
|
|
527
|
+
let node = null;
|
|
528
|
+
try {
|
|
529
|
+
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
530
|
+
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
531
|
+
node = byGlobalId;
|
|
456
532
|
}
|
|
457
|
-
})
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
}
|
|
463
|
-
const normalized = value.trim();
|
|
464
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
465
|
-
}
|
|
466
|
-
function throwWorkspaceIsolationError(args) {
|
|
467
|
-
const error = new Error(args.message);
|
|
468
|
-
error.status = 409;
|
|
469
|
-
error.code = "INVARIANT_VIOLATION";
|
|
470
|
-
error.invariantCode = args.invariantCode;
|
|
471
|
-
error.suggestion = args.suggestion;
|
|
472
|
-
error.details = args.details;
|
|
473
|
-
throw error;
|
|
474
|
-
}
|
|
475
|
-
function assertWorkspaceScopedEpistemicNodeScope(args) {
|
|
476
|
-
const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
|
|
477
|
-
if (layer === "ontological") {
|
|
478
|
-
return;
|
|
479
|
-
}
|
|
480
|
-
const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
|
|
481
|
-
if (workspaceId) {
|
|
482
|
-
return;
|
|
533
|
+
} catch (error) {
|
|
534
|
+
debugGraphPrimitiveFallback(
|
|
535
|
+
"[topicScope] topic-node scope lookup by globalId failed",
|
|
536
|
+
{ error, ref }
|
|
537
|
+
);
|
|
483
538
|
}
|
|
484
|
-
throwWorkspaceIsolationError({
|
|
485
|
-
message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
|
|
486
|
-
invariantCode: "workspace.scope_required_for_epistemic_nodes",
|
|
487
|
-
suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
|
|
488
|
-
details: {
|
|
489
|
-
mutationName: args.mutationName,
|
|
490
|
-
nodeType: args.nodeType,
|
|
491
|
-
topicId: args.scope.topicId,
|
|
492
|
-
projectId: args.scope.projectId
|
|
493
|
-
}
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
497
539
|
if (!node) {
|
|
498
|
-
return
|
|
499
|
-
}
|
|
500
|
-
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
501
|
-
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
502
|
-
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
503
|
-
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
504
|
-
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
505
|
-
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
506
|
-
return false;
|
|
507
|
-
}
|
|
508
|
-
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
509
|
-
return true;
|
|
510
|
-
}
|
|
511
|
-
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
512
|
-
return true;
|
|
513
|
-
}
|
|
514
|
-
if (!scopeWorkspaceId) {
|
|
515
|
-
return nodeWorkspaceId === void 0;
|
|
540
|
+
return null;
|
|
516
541
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
|
|
521
|
-
return;
|
|
542
|
+
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
543
|
+
if (!scopeKey) {
|
|
544
|
+
return null;
|
|
522
545
|
}
|
|
523
546
|
return {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
547
|
+
topicId: scopeKey,
|
|
548
|
+
projectId: asMappedProjectId(node),
|
|
549
|
+
source: "topic_node"
|
|
527
550
|
};
|
|
528
551
|
}
|
|
529
|
-
function
|
|
530
|
-
if (!
|
|
531
|
-
return;
|
|
532
|
-
}
|
|
533
|
-
const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
|
|
534
|
-
const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
|
|
535
|
-
if (!targetWorkspaceId || targetLayer === "ontological") {
|
|
552
|
+
function asMappedProjectId(topic) {
|
|
553
|
+
if (!topic) {
|
|
536
554
|
return;
|
|
537
555
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
|
|
541
|
-
suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
|
|
542
|
-
details: {
|
|
543
|
-
mutationName: args.mutationName,
|
|
544
|
-
toolName: args.runtime.toolName,
|
|
545
|
-
packKey: args.runtime.packKey,
|
|
546
|
-
targetWorkspaceId,
|
|
547
|
-
targetNodeType: args.target.nodeType,
|
|
548
|
-
targetLayer
|
|
549
|
-
}
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// src/beliefLifecycle.ts
|
|
554
|
-
var BELIEF_STATUS_VALUES = [
|
|
555
|
-
"assumption",
|
|
556
|
-
"hypothesis",
|
|
557
|
-
"active",
|
|
558
|
-
"superseded",
|
|
559
|
-
"resolved_true",
|
|
560
|
-
"resolved_false"
|
|
561
|
-
];
|
|
562
|
-
function isBeliefLifecycleStatus(value) {
|
|
563
|
-
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
564
|
-
}
|
|
565
|
-
function normalizeLegacyBeliefStatus(value) {
|
|
566
|
-
if (isBeliefLifecycleStatus(value)) {
|
|
567
|
-
return value;
|
|
568
|
-
}
|
|
569
|
-
if (value === "belief" || value === "established" || value === "emerging") {
|
|
570
|
-
return "active";
|
|
571
|
-
}
|
|
572
|
-
if (value === "fact" || value === "confirmed") {
|
|
573
|
-
return "resolved_true";
|
|
574
|
-
}
|
|
575
|
-
if (value === "disconfirmed" || value === "expired") {
|
|
576
|
-
return "resolved_false";
|
|
577
|
-
}
|
|
578
|
-
if (value === "deprecated") {
|
|
579
|
-
return "superseded";
|
|
580
|
-
}
|
|
581
|
-
return null;
|
|
582
|
-
}
|
|
583
|
-
function normalizeBeliefConfidence(confidence) {
|
|
584
|
-
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
585
|
-
return null;
|
|
586
|
-
}
|
|
587
|
-
if (confidence >= 0 && confidence <= 1) {
|
|
588
|
-
return confidence;
|
|
589
|
-
}
|
|
590
|
-
if (confidence > 1 && confidence <= 100) {
|
|
591
|
-
return confidence / 100;
|
|
592
|
-
}
|
|
593
|
-
return null;
|
|
594
|
-
}
|
|
595
|
-
function isResolvedByConfidence(confidence) {
|
|
596
|
-
const normalized = normalizeBeliefConfidence(confidence);
|
|
597
|
-
if (normalized === null) {
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
return normalized <= 0 || normalized >= 1;
|
|
601
|
-
}
|
|
602
|
-
function getPredictionMetaFromMetadata(metadata) {
|
|
603
|
-
return metadata?.predictionMeta;
|
|
604
|
-
}
|
|
605
|
-
function resolvedPredictionStatus(predictionMeta) {
|
|
606
|
-
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
607
|
-
return null;
|
|
608
|
-
}
|
|
609
|
-
const outcome = predictionMeta.outcome;
|
|
610
|
-
if (outcome === "confirmed") {
|
|
611
|
-
return "resolved_true";
|
|
612
|
-
}
|
|
613
|
-
if (outcome === "disconfirmed" || outcome === "expired") {
|
|
614
|
-
return "resolved_false";
|
|
615
|
-
}
|
|
616
|
-
return null;
|
|
617
|
-
}
|
|
618
|
-
function shouldTreatBeliefAsResolved(opts) {
|
|
619
|
-
if (isResolvedByConfidence(opts.confidence)) {
|
|
620
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
621
|
-
return normalized === 0 ? "resolved_false" : "resolved_true";
|
|
622
|
-
}
|
|
623
|
-
const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
|
|
624
|
-
if (directPredictionStatus) {
|
|
625
|
-
return directPredictionStatus;
|
|
626
|
-
}
|
|
627
|
-
const metadataPredictionStatus = resolvedPredictionStatus(
|
|
628
|
-
getPredictionMetaFromMetadata(opts.metadata)
|
|
556
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
557
|
+
topic[LEGACY_SCOPE_FIELD2]
|
|
629
558
|
);
|
|
630
|
-
if (
|
|
631
|
-
return
|
|
632
|
-
}
|
|
633
|
-
return null;
|
|
634
|
-
}
|
|
635
|
-
function resolveBeliefLifecycleStatus(opts) {
|
|
636
|
-
const resolvedStatus = shouldTreatBeliefAsResolved(opts);
|
|
637
|
-
if (resolvedStatus) {
|
|
638
|
-
return resolvedStatus;
|
|
639
|
-
}
|
|
640
|
-
const direct = opts.beliefStatus;
|
|
641
|
-
const normalizedDirect = normalizeLegacyBeliefStatus(direct);
|
|
642
|
-
if (normalizedDirect) {
|
|
643
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
644
|
-
if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
|
|
645
|
-
return "active";
|
|
646
|
-
}
|
|
647
|
-
return normalizedDirect;
|
|
648
|
-
}
|
|
649
|
-
const metaStatus = opts.metadata?.beliefStatus;
|
|
650
|
-
const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
|
|
651
|
-
if (normalizedMetaStatus) {
|
|
652
|
-
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
653
|
-
if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
|
|
654
|
-
return "active";
|
|
655
|
-
}
|
|
656
|
-
return normalizedMetaStatus;
|
|
559
|
+
if (directLegacyProjectId) {
|
|
560
|
+
return directLegacyProjectId;
|
|
657
561
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
return status === "assumption" || status === "hypothesis";
|
|
562
|
+
const metadata = topic.metadata || {};
|
|
563
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
564
|
+
return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
|
|
662
565
|
}
|
|
663
|
-
|
|
664
|
-
// src/topicProjectOverlay.ts
|
|
665
|
-
var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
|
|
666
|
-
function readNonEmptyString(value) {
|
|
566
|
+
function normalizeScopeValue(value) {
|
|
667
567
|
if (typeof value !== "string") {
|
|
668
568
|
return;
|
|
669
569
|
}
|
|
670
570
|
const normalized = value.trim();
|
|
671
571
|
return normalized.length > 0 ? normalized : void 0;
|
|
672
572
|
}
|
|
673
|
-
function
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
function readMetadata(topic) {
|
|
680
|
-
return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
|
|
681
|
-
}
|
|
682
|
-
function readLegacyProjectId(value) {
|
|
683
|
-
if (!value) {
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
return readNonEmptyString(value[LEGACY_SCOPE_FIELD2]);
|
|
687
|
-
}
|
|
688
|
-
function coerceVisibility(value) {
|
|
689
|
-
return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
|
|
690
|
-
}
|
|
691
|
-
function coerceStatus(value) {
|
|
692
|
-
return value === "active" || value === "archived" || value === "watching" ? value : void 0;
|
|
693
|
-
}
|
|
694
|
-
function mapProjectType(topic, metadata) {
|
|
695
|
-
const explicit = readNonEmptyString(metadata.projectType);
|
|
696
|
-
if (explicit) {
|
|
697
|
-
return explicit;
|
|
698
|
-
}
|
|
699
|
-
if (topic.type === "theme") {
|
|
700
|
-
return "thematic";
|
|
701
|
-
}
|
|
702
|
-
return readNonEmptyString(topic.type) || "general";
|
|
703
|
-
}
|
|
704
|
-
function isProjectLikeTopic(topic) {
|
|
705
|
-
const metadata = readMetadata(topic);
|
|
706
|
-
return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
|
|
707
|
-
}
|
|
708
|
-
function isMissingLucernChildComponentError(error) {
|
|
709
|
-
const message = getErrorMessage(error);
|
|
710
|
-
return message.includes(
|
|
711
|
-
'Child component ComponentName(Identifier("lucern")) not found'
|
|
712
|
-
) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
|
|
713
|
-
}
|
|
714
|
-
function getErrorMessage(error) {
|
|
715
|
-
if (error instanceof Error) {
|
|
716
|
-
return error.message;
|
|
717
|
-
}
|
|
718
|
-
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
|
|
719
|
-
return error.message;
|
|
720
|
-
}
|
|
721
|
-
return "unknown error";
|
|
722
|
-
}
|
|
723
|
-
async function resolveTopicDoc(ctx, scopeId) {
|
|
724
|
-
if (ctx?.db && typeof ctx.db.get === "function") {
|
|
725
|
-
try {
|
|
726
|
-
const directTopic = await ctx.db.get(
|
|
727
|
-
scopeId
|
|
728
|
-
);
|
|
729
|
-
if (directTopic) {
|
|
730
|
-
return directTopic;
|
|
731
|
-
}
|
|
732
|
-
} catch (error) {
|
|
733
|
-
debugGraphPrimitiveFallback(
|
|
734
|
-
"[topicProjectOverlay] Failed to resolve topic by direct ID",
|
|
735
|
-
{
|
|
736
|
-
error,
|
|
737
|
-
scopeId
|
|
738
|
-
}
|
|
739
|
-
);
|
|
573
|
+
function pickPrimaryTopic(candidates) {
|
|
574
|
+
return [...candidates].sort((a, b) => {
|
|
575
|
+
const depthA = a.depth ?? 9999;
|
|
576
|
+
const depthB = b.depth ?? 9999;
|
|
577
|
+
if (depthA !== depthB) {
|
|
578
|
+
return depthA - depthB;
|
|
740
579
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
try {
|
|
746
|
-
const topic = await ctx.runQuery(api.topics.get, {
|
|
747
|
-
id: String(scopeId)
|
|
748
|
-
});
|
|
749
|
-
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
750
|
-
return topic;
|
|
580
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
581
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
582
|
+
if (createdA !== createdB) {
|
|
583
|
+
return createdA - createdB;
|
|
751
584
|
}
|
|
585
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
586
|
+
})[0];
|
|
587
|
+
}
|
|
588
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
589
|
+
const query = ctx.db.query("topics");
|
|
590
|
+
try {
|
|
591
|
+
return await query.withIndex(
|
|
592
|
+
"by_graph_scope_project",
|
|
593
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
|
|
594
|
+
).collect();
|
|
752
595
|
} catch (error) {
|
|
753
596
|
debugGraphPrimitiveFallback(
|
|
754
|
-
"[
|
|
597
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
755
598
|
{
|
|
756
599
|
error,
|
|
757
600
|
scopeId
|
|
758
601
|
}
|
|
759
602
|
);
|
|
603
|
+
const topics = await query.collect();
|
|
604
|
+
return topics.filter((topic) => {
|
|
605
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
606
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
607
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
612
|
+
if (typeof ctx.runQuery !== "function") {
|
|
613
|
+
return null;
|
|
760
614
|
}
|
|
761
615
|
try {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
});
|
|
765
|
-
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
766
|
-
return topic;
|
|
767
|
-
}
|
|
616
|
+
return await ctx.runQuery(api.topics.get, {
|
|
617
|
+
id: topicId
|
|
618
|
+
}) ?? null;
|
|
768
619
|
} catch (error) {
|
|
769
620
|
debugGraphPrimitiveFallback(
|
|
770
|
-
"[
|
|
771
|
-
{
|
|
621
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
622
|
+
{
|
|
623
|
+
error,
|
|
624
|
+
topicId
|
|
625
|
+
}
|
|
772
626
|
);
|
|
627
|
+
return null;
|
|
773
628
|
}
|
|
774
|
-
return null;
|
|
775
|
-
}
|
|
776
|
-
function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
777
|
-
const metadata = readMetadata(topic);
|
|
778
|
-
const topicId = String(topic._id);
|
|
779
|
-
const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
|
|
780
|
-
const storageProjectId = legacyProjectId || topicId;
|
|
781
|
-
const outwardId = idMode === "topic" ? topicId : storageProjectId;
|
|
782
|
-
const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
|
|
783
|
-
const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
|
|
784
|
-
const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
|
|
785
|
-
const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
|
|
786
|
-
return {
|
|
787
|
-
...metadata,
|
|
788
|
-
_id: outwardId,
|
|
789
|
-
projectId: outwardId,
|
|
790
|
-
topicId,
|
|
791
|
-
storageProjectId,
|
|
792
|
-
legacyProjectId,
|
|
793
|
-
name: readNonEmptyString(topic.name) || "Untitled Theme",
|
|
794
|
-
type: mapProjectType(topic, metadata),
|
|
795
|
-
description: readNonEmptyString(topic.description),
|
|
796
|
-
ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
|
|
797
|
-
// FR.7 creator-grant: surface the principal-shaped owner field (column-first,
|
|
798
|
-
// metadata fallback for legacy rows that recorded it in metadata).
|
|
799
|
-
ownerPrincipalId: readNonEmptyString(topic.ownerPrincipalId) || readNonEmptyString(metadata.ownerPrincipalId),
|
|
800
|
-
// RR.1 carrier: preserve the nested metadata carrier so the kernel's
|
|
801
|
-
// `checkProjectAccessDetailed` metadata-PRIMARY read
|
|
802
|
-
// (`project.metadata?.ownerPrincipalId`) resolves the grant. The `...metadata`
|
|
803
|
-
// spread above only flattens keys; it does not leave a nested `metadata`.
|
|
804
|
-
metadata,
|
|
805
|
-
sharedWith: readStringArray(metadata.sharedWith),
|
|
806
|
-
visibility,
|
|
807
|
-
tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
|
|
808
|
-
workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
|
|
809
|
-
status,
|
|
810
|
-
tags: readStringArray(metadata.tags),
|
|
811
|
-
chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
|
|
812
|
-
artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
|
|
813
|
-
lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
|
|
814
|
-
_creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
|
|
815
|
-
createdAt,
|
|
816
|
-
updatedAt
|
|
817
|
-
};
|
|
818
629
|
}
|
|
819
|
-
async function
|
|
820
|
-
|
|
821
|
-
if (!topic) {
|
|
630
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
631
|
+
if (typeof ctx.runQuery !== "function") {
|
|
822
632
|
return null;
|
|
823
633
|
}
|
|
824
|
-
|
|
634
|
+
try {
|
|
635
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
636
|
+
projectId: legacyScopeId
|
|
637
|
+
}) ?? null;
|
|
638
|
+
} catch (error) {
|
|
639
|
+
debugGraphPrimitiveFallback(
|
|
640
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
641
|
+
{
|
|
642
|
+
error,
|
|
643
|
+
legacyScopeId
|
|
644
|
+
}
|
|
645
|
+
);
|
|
825
646
|
return null;
|
|
826
647
|
}
|
|
827
|
-
return materializeTopicProjectOverlay(topic, options.idMode);
|
|
828
648
|
}
|
|
829
|
-
async function
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
debugGraphPrimitiveFallback(
|
|
836
|
-
"[topicProjectOverlay] Failed to read topics table; falling back to API",
|
|
837
|
-
{ error }
|
|
838
|
-
);
|
|
839
|
-
allTopics = [];
|
|
840
|
-
}
|
|
649
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
650
|
+
const MAX_DEPTH = 10;
|
|
651
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
652
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
653
|
+
if (tenantId && workspaceId) {
|
|
654
|
+
return { tenantId, workspaceId };
|
|
841
655
|
}
|
|
842
|
-
|
|
843
|
-
|
|
656
|
+
let current = topic;
|
|
657
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
658
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
659
|
+
if (!current) {
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
if (!tenantId) {
|
|
663
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
664
|
+
}
|
|
665
|
+
if (!workspaceId) {
|
|
666
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
667
|
+
}
|
|
668
|
+
if (tenantId && workspaceId) {
|
|
669
|
+
break;
|
|
670
|
+
}
|
|
844
671
|
}
|
|
845
|
-
return
|
|
846
|
-
(topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
|
|
847
|
-
).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
|
|
672
|
+
return { tenantId, workspaceId };
|
|
848
673
|
}
|
|
849
|
-
async function
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
return null;
|
|
674
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
675
|
+
if (args.topicId) {
|
|
676
|
+
return await resolveScopeFromTopicId(ctx, args.topicId);
|
|
853
677
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
const topicUpdateArgs = {
|
|
857
|
-
id: String(topic._id)
|
|
858
|
-
};
|
|
859
|
-
for (const [key, rawValue] of Object.entries(value)) {
|
|
860
|
-
switch (key) {
|
|
861
|
-
case "_id":
|
|
862
|
-
case "projectId":
|
|
863
|
-
case "topicId":
|
|
864
|
-
case "legacyProjectId":
|
|
865
|
-
case "storageProjectId":
|
|
866
|
-
break;
|
|
867
|
-
case "name":
|
|
868
|
-
case "description":
|
|
869
|
-
patch[key] = rawValue;
|
|
870
|
-
topicUpdateArgs[key] = rawValue;
|
|
871
|
-
break;
|
|
872
|
-
case "tenantId":
|
|
873
|
-
case "workspaceId":
|
|
874
|
-
case "ownerId":
|
|
875
|
-
throw new Error(
|
|
876
|
-
`patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
|
|
877
|
-
);
|
|
878
|
-
case "status": {
|
|
879
|
-
const status = coerceStatus(rawValue);
|
|
880
|
-
if (status) {
|
|
881
|
-
patch.status = status;
|
|
882
|
-
topicUpdateArgs.status = status;
|
|
883
|
-
}
|
|
884
|
-
break;
|
|
885
|
-
}
|
|
886
|
-
case "visibility": {
|
|
887
|
-
const visibility = coerceVisibility(rawValue);
|
|
888
|
-
if (visibility) {
|
|
889
|
-
patch.visibility = visibility;
|
|
890
|
-
topicUpdateArgs.visibility = visibility;
|
|
891
|
-
}
|
|
892
|
-
break;
|
|
893
|
-
}
|
|
894
|
-
case "type": {
|
|
895
|
-
const projectType = readNonEmptyString(rawValue);
|
|
896
|
-
if (projectType) {
|
|
897
|
-
nextMetadata.projectType = projectType;
|
|
898
|
-
} else {
|
|
899
|
-
delete nextMetadata.projectType;
|
|
900
|
-
}
|
|
901
|
-
break;
|
|
902
|
-
}
|
|
903
|
-
case "updatedAt":
|
|
904
|
-
case "createdAt":
|
|
905
|
-
break;
|
|
906
|
-
default:
|
|
907
|
-
if (rawValue === void 0) {
|
|
908
|
-
delete nextMetadata[key];
|
|
909
|
-
} else {
|
|
910
|
-
nextMetadata[key] = rawValue;
|
|
911
|
-
}
|
|
912
|
-
}
|
|
678
|
+
if (args.projectId) {
|
|
679
|
+
return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
|
|
913
680
|
}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
throw error;
|
|
923
|
-
}
|
|
924
|
-
await ctx.db.patch(String(topic._id), patch);
|
|
925
|
-
}
|
|
926
|
-
} else if (ctx?.db && typeof ctx.db.patch === "function") {
|
|
927
|
-
await ctx.db.patch(String(topic._id), patch);
|
|
928
|
-
} else {
|
|
929
|
-
throw new Error(
|
|
930
|
-
"Cannot patch topic without component adapter (ctx.runMutation unavailable)"
|
|
931
|
-
);
|
|
681
|
+
throw new Error(
|
|
682
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
686
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
687
|
+
if (topic) {
|
|
688
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
932
689
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
});
|
|
690
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
|
|
691
|
+
if (nodeScope) {
|
|
692
|
+
return nodeScope;
|
|
693
|
+
}
|
|
694
|
+
throw new Error(`Topic not found: ${String(topicId)}`);
|
|
938
695
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
696
|
+
async function resolveTopicDocFromTopicId(ctx, topicId) {
|
|
697
|
+
const direct = await tryReadTopicDoc(ctx, topicId, {
|
|
698
|
+
failureLog: "[topicScope] Failed to load topic by direct id",
|
|
699
|
+
idLogKey: "topicId"
|
|
700
|
+
});
|
|
701
|
+
if (direct) {
|
|
702
|
+
return direct;
|
|
703
|
+
}
|
|
704
|
+
const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
|
|
705
|
+
if (hostTopic) {
|
|
706
|
+
return hostTopic;
|
|
707
|
+
}
|
|
708
|
+
return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
|
|
946
709
|
}
|
|
947
|
-
function
|
|
948
|
-
|
|
949
|
-
|
|
710
|
+
async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
|
|
711
|
+
const directTopic = await resolveDirectLegacyProjectTopic(
|
|
712
|
+
ctx,
|
|
713
|
+
legacyProjectId
|
|
714
|
+
);
|
|
715
|
+
if (directTopic) {
|
|
716
|
+
return await buildTopicScope(ctx, directTopic, "topic_inferred", {
|
|
717
|
+
fallbackProjectId: legacyProjectId
|
|
718
|
+
});
|
|
950
719
|
}
|
|
951
|
-
|
|
952
|
-
|
|
720
|
+
const primary = pickPrimaryTopic(
|
|
721
|
+
await findTopicsByScopeAlias(ctx, legacyProjectId)
|
|
722
|
+
);
|
|
723
|
+
if (primary) {
|
|
724
|
+
return await buildTopicScope(ctx, primary, "project_mapped_topic", {
|
|
725
|
+
fallbackProjectId: legacyProjectId
|
|
726
|
+
});
|
|
953
727
|
}
|
|
954
|
-
|
|
728
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
|
|
729
|
+
if (nodeScope) {
|
|
730
|
+
return {
|
|
731
|
+
...nodeScope,
|
|
732
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
throw new Error(
|
|
736
|
+
`Legacy project scope ${legacyProjectId} has no mapped topic.`
|
|
737
|
+
);
|
|
955
738
|
}
|
|
956
|
-
function
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
739
|
+
async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
|
|
740
|
+
const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
|
|
741
|
+
failureLog: "[topicScope] Failed to load direct project topic",
|
|
742
|
+
idLogKey: "projectId"
|
|
743
|
+
});
|
|
744
|
+
return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
|
|
960
745
|
}
|
|
961
|
-
async function
|
|
746
|
+
async function tryReadTopicDoc(ctx, id, log) {
|
|
962
747
|
try {
|
|
963
|
-
await
|
|
748
|
+
return await ctx.db.get(id);
|
|
964
749
|
} catch (error) {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
{
|
|
971
|
-
projectId,
|
|
972
|
-
keys: Object.keys(value),
|
|
973
|
-
error: getErrorMessage2(error)
|
|
974
|
-
}
|
|
975
|
-
);
|
|
750
|
+
debugGraphPrimitiveFallback(log.failureLog, {
|
|
751
|
+
error,
|
|
752
|
+
[log.idLogKey]: id
|
|
753
|
+
});
|
|
754
|
+
return null;
|
|
976
755
|
}
|
|
977
756
|
}
|
|
978
|
-
function
|
|
757
|
+
async function buildTopicScope(ctx, topic, source, options = {}) {
|
|
758
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
759
|
+
const mapped = asMappedProjectId(topic);
|
|
979
760
|
return {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
listTopics: (ctx) => listTopicProjectOverlays(ctx, {
|
|
986
|
-
idMode: "legacy"
|
|
987
|
-
}),
|
|
988
|
-
getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
|
|
761
|
+
topicId: topic._id,
|
|
762
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
763
|
+
tenantId: inherited.tenantId,
|
|
764
|
+
workspaceId: inherited.workspaceId,
|
|
765
|
+
source
|
|
989
766
|
};
|
|
990
767
|
}
|
|
991
|
-
var
|
|
992
|
-
|
|
768
|
+
var optionalScopeArgs = {
|
|
769
|
+
projectId: v.optional(v.string()),
|
|
770
|
+
topicId: v.optional(v.string())
|
|
771
|
+
};
|
|
772
|
+
function normalizeScopeValue2(value) {
|
|
773
|
+
if (typeof value !== "string") {
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
const normalized = value.trim();
|
|
777
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
778
|
+
}
|
|
779
|
+
function throwWorkspaceIsolationError(args) {
|
|
780
|
+
const error = new Error(args.message);
|
|
781
|
+
error.status = 409;
|
|
782
|
+
error.code = "INVARIANT_VIOLATION";
|
|
783
|
+
error.invariantCode = args.invariantCode;
|
|
784
|
+
error.suggestion = args.suggestion;
|
|
785
|
+
error.details = args.details;
|
|
786
|
+
throw error;
|
|
787
|
+
}
|
|
788
|
+
function assertWorkspaceScopedEpistemicNodeScope(args) {
|
|
789
|
+
const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
|
|
790
|
+
if (layer === "ontological") {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
|
|
794
|
+
if (workspaceId) {
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
throwWorkspaceIsolationError({
|
|
798
|
+
message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
|
|
799
|
+
invariantCode: "workspace.scope_required_for_epistemic_nodes",
|
|
800
|
+
suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
|
|
801
|
+
details: {
|
|
802
|
+
mutationName: args.mutationName,
|
|
803
|
+
nodeType: args.nodeType,
|
|
804
|
+
topicId: args.scope.topicId,
|
|
805
|
+
projectId: args.scope.projectId
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
810
|
+
if (!node) {
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
814
|
+
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
815
|
+
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
816
|
+
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
817
|
+
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
818
|
+
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
822
|
+
return true;
|
|
823
|
+
}
|
|
824
|
+
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
825
|
+
return true;
|
|
826
|
+
}
|
|
827
|
+
if (!scopeWorkspaceId) {
|
|
828
|
+
return nodeWorkspaceId === void 0;
|
|
829
|
+
}
|
|
830
|
+
return scopeWorkspaceId === nodeWorkspaceId;
|
|
831
|
+
}
|
|
832
|
+
function resolveRuntimePackMutationContext(args) {
|
|
833
|
+
if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
993
836
|
return {
|
|
994
|
-
|
|
995
|
-
|
|
837
|
+
toolName: args.runtimeToolName,
|
|
838
|
+
packKey: args.runtimePackKey,
|
|
839
|
+
packInstallScope: args.runtimePackInstallScope
|
|
996
840
|
};
|
|
997
841
|
}
|
|
998
|
-
|
|
999
|
-
|
|
842
|
+
function assertTenantPackWorkspaceMutationAllowed(args) {
|
|
843
|
+
if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
|
|
847
|
+
const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
|
|
848
|
+
if (!targetWorkspaceId || targetLayer === "ontological") {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
throwWorkspaceIsolationError({
|
|
852
|
+
message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
|
|
853
|
+
invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
|
|
854
|
+
suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
|
|
855
|
+
details: {
|
|
856
|
+
mutationName: args.mutationName,
|
|
857
|
+
toolName: args.runtime.toolName,
|
|
858
|
+
packKey: args.runtime.packKey,
|
|
859
|
+
targetWorkspaceId,
|
|
860
|
+
targetNodeType: args.target.nodeType,
|
|
861
|
+
targetLayer
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
}
|
|
1000
865
|
v.id("epistemicNodes");
|
|
1001
866
|
var DEFAULT_PROJECT_BELIEF_LIMIT = 250;
|
|
1002
867
|
var MAX_PROJECT_BELIEF_LIMIT = 1e3;
|
|
@@ -1004,25 +869,119 @@ var optionalBeliefScopeArgs = optionalScopeArgs;
|
|
|
1004
869
|
({
|
|
1005
870
|
tupleContradiction: normalizeTupleContradictionPolicy()
|
|
1006
871
|
});
|
|
1007
|
-
function
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
872
|
+
function readFiniteNumber(value) {
|
|
873
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
874
|
+
}
|
|
875
|
+
function isRecord(value) {
|
|
876
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
877
|
+
}
|
|
878
|
+
function readOptionalString(value) {
|
|
879
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
880
|
+
}
|
|
881
|
+
function readStringArray2(value) {
|
|
882
|
+
if (!Array.isArray(value)) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
const strings = value.filter(
|
|
886
|
+
(item) => typeof item === "string" && item.length > 0
|
|
887
|
+
);
|
|
888
|
+
return strings.length === value.length ? strings : void 0;
|
|
889
|
+
}
|
|
890
|
+
function readRecord(value) {
|
|
891
|
+
return isRecord(value) ? value : void 0;
|
|
892
|
+
}
|
|
893
|
+
function readBeliefNodeView(value) {
|
|
894
|
+
if (!isRecord(value)) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
const id = readOptionalString(value._id);
|
|
898
|
+
const nodeType = readOptionalString(value.nodeType);
|
|
899
|
+
if (!(id && nodeType === "belief")) {
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
const node = {
|
|
903
|
+
_id: id,
|
|
904
|
+
nodeType
|
|
1016
905
|
};
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
906
|
+
const creationTime = readFiniteNumber(value._creationTime);
|
|
907
|
+
if (creationTime !== void 0) {
|
|
908
|
+
node._creationTime = creationTime;
|
|
909
|
+
}
|
|
910
|
+
const metadata = readRecord(value.metadata);
|
|
911
|
+
if (metadata !== void 0) {
|
|
912
|
+
node.metadata = metadata;
|
|
913
|
+
}
|
|
914
|
+
const opinionA = readFiniteNumber(value.opinion_a);
|
|
915
|
+
if (opinionA !== void 0) {
|
|
916
|
+
node.opinion_a = opinionA;
|
|
917
|
+
}
|
|
918
|
+
const opinionB = readFiniteNumber(value.opinion_b);
|
|
919
|
+
if (opinionB !== void 0) {
|
|
920
|
+
node.opinion_b = opinionB;
|
|
921
|
+
}
|
|
922
|
+
const opinionD = readFiniteNumber(value.opinion_d);
|
|
923
|
+
if (opinionD !== void 0) {
|
|
924
|
+
node.opinion_d = opinionD;
|
|
925
|
+
}
|
|
926
|
+
const opinionU = readFiniteNumber(value.opinion_u);
|
|
927
|
+
if (opinionU !== void 0) {
|
|
928
|
+
node.opinion_u = opinionU;
|
|
929
|
+
}
|
|
930
|
+
const tupleContradicted = typeof value.tupleContradicted === "boolean" ? value.tupleContradicted : void 0;
|
|
931
|
+
if (tupleContradicted !== void 0) {
|
|
932
|
+
node.tupleContradicted = tupleContradicted;
|
|
933
|
+
}
|
|
934
|
+
const stringFields = {
|
|
935
|
+
anonymizationClass: value.anonymizationClass,
|
|
936
|
+
audienceLabel: value.audienceLabel,
|
|
937
|
+
canonicalText: value.canonicalText,
|
|
938
|
+
createdBy: value.createdBy,
|
|
939
|
+
epistemicLayer: value.epistemicLayer,
|
|
940
|
+
exportClass: value.exportClass,
|
|
941
|
+
globalId: value.globalId,
|
|
942
|
+
projectId: value.projectId,
|
|
943
|
+
publicationStatus: value.publicationStatus,
|
|
944
|
+
sensitivityTier: value.sensitivityTier,
|
|
945
|
+
status: value.status,
|
|
946
|
+
tenantId: value.tenantId,
|
|
947
|
+
topicId: value.topicId,
|
|
948
|
+
userId: value.userId,
|
|
949
|
+
workspaceId: value.workspaceId
|
|
950
|
+
};
|
|
951
|
+
for (const [field, fieldValue] of Object.entries(stringFields)) {
|
|
952
|
+
const normalized = readOptionalString(fieldValue);
|
|
953
|
+
if (normalized !== void 0) {
|
|
954
|
+
node[field] = normalized;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
const createdAt = readFiniteNumber(value.createdAt);
|
|
958
|
+
if (createdAt !== void 0) {
|
|
959
|
+
node.createdAt = createdAt;
|
|
960
|
+
}
|
|
961
|
+
const updatedAt = readFiniteNumber(value.updatedAt);
|
|
962
|
+
if (updatedAt !== void 0) {
|
|
963
|
+
node.updatedAt = updatedAt;
|
|
964
|
+
}
|
|
965
|
+
if (value.beliefStatus !== void 0) {
|
|
966
|
+
node.beliefStatus = value.beliefStatus;
|
|
967
|
+
}
|
|
968
|
+
if (value.confidence !== void 0) {
|
|
969
|
+
node.confidence = value.confidence;
|
|
970
|
+
}
|
|
971
|
+
if (value.predictionMeta !== void 0) {
|
|
972
|
+
node.predictionMeta = value.predictionMeta;
|
|
973
|
+
}
|
|
974
|
+
const policyTags = readStringArray2(value.policyTags);
|
|
975
|
+
if (policyTags !== void 0) {
|
|
976
|
+
node.policyTags = policyTags;
|
|
977
|
+
}
|
|
978
|
+
return node;
|
|
979
|
+
}
|
|
980
|
+
function readBeliefNodeViews(values) {
|
|
981
|
+
return values.flatMap((value) => {
|
|
982
|
+
const node = readBeliefNodeView(value);
|
|
983
|
+
return node ? [node] : [];
|
|
984
|
+
});
|
|
1026
985
|
}
|
|
1027
986
|
function assertBaseRateInRange(baseRate, field = "baseRate") {
|
|
1028
987
|
if (baseRate < 0 || baseRate > 1) {
|
|
@@ -1118,7 +1077,7 @@ function normalizePillar(pillar) {
|
|
|
1118
1077
|
async function markBeliefGraphDirty(ctx, scope) {
|
|
1119
1078
|
const projectId = typeof scope.projectId === "string" && scope.projectId.trim().length > 0 ? scope.projectId : void 0;
|
|
1120
1079
|
const topicId = typeof scope.topicId === "string" && scope.topicId.trim().length > 0 ? scope.topicId : void 0;
|
|
1121
|
-
if (!projectId
|
|
1080
|
+
if (!(projectId || topicId)) {
|
|
1122
1081
|
return;
|
|
1123
1082
|
}
|
|
1124
1083
|
if (projectId) {
|
|
@@ -1135,16 +1094,22 @@ async function markBeliefGraphDirty(ctx, scope) {
|
|
|
1135
1094
|
{ topicId }
|
|
1136
1095
|
);
|
|
1137
1096
|
}
|
|
1097
|
+
const activityScopeId = topicId ?? projectId;
|
|
1098
|
+
if (!activityScopeId) {
|
|
1099
|
+
throw new Error(
|
|
1100
|
+
"Expected belief graph dirty scope to include a topic or project id."
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1138
1103
|
await resolveGraphPrimitivesAppResolvers().patchProject(
|
|
1139
1104
|
ctx,
|
|
1140
|
-
|
|
1105
|
+
activityScopeId,
|
|
1141
1106
|
{
|
|
1142
1107
|
lastActivityAt: Date.now()
|
|
1143
1108
|
}
|
|
1144
1109
|
);
|
|
1145
1110
|
}
|
|
1146
1111
|
async function resolveBeliefScopeOrNull(ctx, args) {
|
|
1147
|
-
if (!args.projectId
|
|
1112
|
+
if (!(args.projectId || args.topicId)) {
|
|
1148
1113
|
return null;
|
|
1149
1114
|
}
|
|
1150
1115
|
try {
|
|
@@ -1169,14 +1134,17 @@ async function getBeliefNodesForScope(ctx, scope, args) {
|
|
|
1169
1134
|
"by_topic_type",
|
|
1170
1135
|
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
1171
1136
|
);
|
|
1172
|
-
const
|
|
1137
|
+
const rows = typeof args?.scanLimit === "number" ? await baseQuery.order("desc").take(args.scanLimit) : await baseQuery.collect();
|
|
1138
|
+
const nodes = readBeliefNodeViews(rows);
|
|
1173
1139
|
const scopedNodes = nodes.filter(
|
|
1174
1140
|
(node) => nodeMatchesWorkspaceReasoningScope(node, scope)
|
|
1175
1141
|
);
|
|
1176
1142
|
if (!args?.status) {
|
|
1177
1143
|
return scopedNodes;
|
|
1178
1144
|
}
|
|
1179
|
-
return scopedNodes.filter(
|
|
1145
|
+
return scopedNodes.filter(
|
|
1146
|
+
(node) => node.status === args.status
|
|
1147
|
+
);
|
|
1180
1148
|
}
|
|
1181
1149
|
function createBeliefAudienceResolver(registryRows) {
|
|
1182
1150
|
const audienceClassByKey = new Map(
|
|
@@ -1196,9 +1164,7 @@ function createBeliefAudienceResolver(registryRows) {
|
|
|
1196
1164
|
function flattenBeliefNode(node) {
|
|
1197
1165
|
const meta = node.metadata || {};
|
|
1198
1166
|
const worktreeId = resolveBeliefWorktreeId(meta);
|
|
1199
|
-
const tupleContradicted = readTupleContradictedFlag(
|
|
1200
|
-
node.tupleContradicted
|
|
1201
|
-
) ?? readTupleContradictedFlag(meta.tupleContradicted) ?? false;
|
|
1167
|
+
const tupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(meta.tupleContradicted) ?? false;
|
|
1202
1168
|
return {
|
|
1203
1169
|
_id: node._id,
|
|
1204
1170
|
_epistemicNodeId: node._id,
|
|
@@ -1243,8 +1209,172 @@ function resolveBeliefStatus(node, metadata) {
|
|
|
1243
1209
|
metadata
|
|
1244
1210
|
});
|
|
1245
1211
|
}
|
|
1212
|
+
function insertEpistemicNode(ctx, doc) {
|
|
1213
|
+
assertUuidV7Identity("epistemicNodes", doc.globalId);
|
|
1214
|
+
return ctx.db.insert("epistemicNodes", doc);
|
|
1215
|
+
}
|
|
1216
|
+
async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
|
|
1217
|
+
assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
|
|
1218
|
+
const node = await ctx.db.query("epistemicNodes").withIndex(
|
|
1219
|
+
"by_globalId",
|
|
1220
|
+
(q) => q.eq("globalId", endpoint)
|
|
1221
|
+
).first();
|
|
1222
|
+
if (!node) {
|
|
1223
|
+
throw new Error(
|
|
1224
|
+
`edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
|
|
1225
|
+
);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
async function insertEpistemicEdge(ctx, doc) {
|
|
1229
|
+
assertUuidV7Identity("epistemicEdges", doc.globalId);
|
|
1230
|
+
assertStorageEdgeVocabulary(doc.edgeType);
|
|
1231
|
+
if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
|
|
1232
|
+
throw new Error(
|
|
1233
|
+
"edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
|
|
1237
|
+
throw new Error(
|
|
1238
|
+
"edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
|
|
1242
|
+
await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
|
|
1243
|
+
if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
|
|
1244
|
+
assertEdgePolicyAllowed(
|
|
1245
|
+
edgePolicyManifest,
|
|
1246
|
+
doc.edgeType,
|
|
1247
|
+
{
|
|
1248
|
+
kind: "epistemic_node",
|
|
1249
|
+
nodeId: doc.fromNodeId,
|
|
1250
|
+
nodeType: doc.fromNodeType
|
|
1251
|
+
},
|
|
1252
|
+
{
|
|
1253
|
+
kind: "epistemic_node",
|
|
1254
|
+
nodeId: doc.toNodeId,
|
|
1255
|
+
nodeType: doc.toNodeType
|
|
1256
|
+
}
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
return ctx.db.insert("epistemicEdges", doc);
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// src/epistemicBeliefs.topicAnchor.ts
|
|
1263
|
+
function cleanString(value) {
|
|
1264
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
1265
|
+
}
|
|
1266
|
+
function topicNodeCandidates(topicRef) {
|
|
1267
|
+
const normalized = topicRef.trim();
|
|
1268
|
+
if (!normalized) {
|
|
1269
|
+
return [];
|
|
1270
|
+
}
|
|
1271
|
+
const candidates = [normalized];
|
|
1272
|
+
if (normalized.startsWith("top_")) {
|
|
1273
|
+
candidates.push(normalized.slice(4));
|
|
1274
|
+
}
|
|
1275
|
+
return [...new Set(candidates)];
|
|
1276
|
+
}
|
|
1277
|
+
function readTopicNodeRef(args) {
|
|
1278
|
+
return cleanString(args.topicGlobalId) ?? cleanString(args.topicNodeId) ?? cleanString(args.topicId);
|
|
1279
|
+
}
|
|
1280
|
+
async function resolveRequiredTopicAnchor(ctx, topicRef) {
|
|
1281
|
+
for (const candidate of topicNodeCandidates(topicRef)) {
|
|
1282
|
+
try {
|
|
1283
|
+
const direct = await ctx.db.get(candidate);
|
|
1284
|
+
if (direct?.nodeType === "topic" && cleanString(direct.globalId)) {
|
|
1285
|
+
return direct;
|
|
1286
|
+
}
|
|
1287
|
+
} catch {
|
|
1288
|
+
}
|
|
1289
|
+
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
|
|
1290
|
+
if (byGlobalId?.nodeType === "topic" && cleanString(byGlobalId.globalId)) {
|
|
1291
|
+
return byGlobalId;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
throw new Error(
|
|
1295
|
+
"Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes. Legacy topics-table IDs are not valid belief anchors."
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
1298
|
+
function scopeFromTopicAnchor(topicNode) {
|
|
1299
|
+
return {
|
|
1300
|
+
topicId: topicNode.globalId,
|
|
1301
|
+
projectId: cleanString(topicNode.projectId),
|
|
1302
|
+
tenantId: cleanString(topicNode.tenantId),
|
|
1303
|
+
workspaceId: cleanString(topicNode.workspaceId),
|
|
1304
|
+
source: "topic"
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
async function createRequiredBeliefTopicEdge(ctx, args) {
|
|
1308
|
+
const topicGlobalId = args.topicNode.globalId;
|
|
1309
|
+
const now = Date.now();
|
|
1310
|
+
const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
1311
|
+
"by_from_to",
|
|
1312
|
+
(q) => q.eq("fromNodeId", args.beliefGlobalId).eq("toNodeId", topicGlobalId)
|
|
1313
|
+
).collect();
|
|
1314
|
+
const existing = existingEdges.find((edge) => edge.edgeType === "belongs_to");
|
|
1315
|
+
const edgeGlobalId = cleanString(existing?.globalId) ?? generateUuidV7();
|
|
1316
|
+
if (!existing) {
|
|
1317
|
+
await insertEpistemicEdge(ctx, {
|
|
1318
|
+
globalId: edgeGlobalId,
|
|
1319
|
+
fromNodeId: args.beliefGlobalId,
|
|
1320
|
+
toNodeId: topicGlobalId,
|
|
1321
|
+
sourceGlobalId: args.beliefGlobalId,
|
|
1322
|
+
targetGlobalId: topicGlobalId,
|
|
1323
|
+
edgeType: "belongs_to",
|
|
1324
|
+
weight: 1,
|
|
1325
|
+
confidence: 1,
|
|
1326
|
+
context: "Belief creation topic anchor invariant.",
|
|
1327
|
+
reasoningMethod: "implicit",
|
|
1328
|
+
derivationType: "topic_scope_invariant",
|
|
1329
|
+
metadata: {
|
|
1330
|
+
invariant: "belief.topic_edge_required",
|
|
1331
|
+
edgeUuid: edgeGlobalId,
|
|
1332
|
+
fromUuid: args.beliefGlobalId,
|
|
1333
|
+
toUuid: topicGlobalId
|
|
1334
|
+
},
|
|
1335
|
+
createdBy: args.createdBy,
|
|
1336
|
+
createdAt: now,
|
|
1337
|
+
updatedAt: now,
|
|
1338
|
+
projectId: cleanString(args.topicNode.projectId),
|
|
1339
|
+
topicId: topicGlobalId,
|
|
1340
|
+
tenantId: cleanString(args.topicNode.tenantId),
|
|
1341
|
+
workspaceId: cleanString(args.topicNode.workspaceId),
|
|
1342
|
+
fromNodeType: "belief",
|
|
1343
|
+
toNodeType: "topic",
|
|
1344
|
+
fromLayer: "L3",
|
|
1345
|
+
toLayer: args.topicNode.epistemicLayer ?? "ontological"
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
1349
|
+
globalId: edgeGlobalId,
|
|
1350
|
+
fromGlobalId: args.beliefGlobalId,
|
|
1351
|
+
toGlobalId: topicGlobalId,
|
|
1352
|
+
edgeType: "belongs_to",
|
|
1353
|
+
weight: 1,
|
|
1354
|
+
confidence: 1,
|
|
1355
|
+
context: "Belief creation topic anchor invariant.",
|
|
1356
|
+
projectId: cleanString(args.topicNode.projectId),
|
|
1357
|
+
topicId: topicGlobalId,
|
|
1358
|
+
createdBy: args.createdBy,
|
|
1359
|
+
fromNodeType: "belief",
|
|
1360
|
+
toNodeType: "topic",
|
|
1361
|
+
fromLayer: "L3",
|
|
1362
|
+
toLayer: args.topicNode.epistemicLayer ?? "ontological",
|
|
1363
|
+
metadata: {
|
|
1364
|
+
invariant: "belief.topic_edge_required",
|
|
1365
|
+
edgeUuid: edgeGlobalId,
|
|
1366
|
+
fromUuid: args.beliefGlobalId,
|
|
1367
|
+
toUuid: topicGlobalId
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1246
1371
|
|
|
1247
1372
|
// src/epistemicBeliefs.internal.ts
|
|
1373
|
+
var BELIEF_CATEGORIZATION_ACTION = "beliefCategorization:autoCategorizeBelief";
|
|
1374
|
+
var EMBEDDING_GENERATION_ACTION = "embeddingActions:generateEpistemicNodeEmbedding";
|
|
1375
|
+
function readOptionalString2(value) {
|
|
1376
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1377
|
+
}
|
|
1248
1378
|
var internalGetByProject = internalQuery({
|
|
1249
1379
|
args: {
|
|
1250
1380
|
...optionalBeliefScopeArgs,
|
|
@@ -1279,7 +1409,7 @@ var internalGetByProject = internalQuery({
|
|
|
1279
1409
|
let filtered = nodes.filter(
|
|
1280
1410
|
(node) => canAudienceClassAccess(
|
|
1281
1411
|
viewerClass,
|
|
1282
|
-
resolveAudienceClass(node.audienceLabel, "internal")
|
|
1412
|
+
resolveAudienceClass(readOptionalString2(node.audienceLabel), "internal")
|
|
1283
1413
|
)
|
|
1284
1414
|
);
|
|
1285
1415
|
if (args.status) {
|
|
@@ -1318,15 +1448,18 @@ var internalGetByTopic = internalQuery({
|
|
|
1318
1448
|
});
|
|
1319
1449
|
const resolveAudienceClass = createBeliefAudienceResolver(registryRows);
|
|
1320
1450
|
const viewerClass = resolveAudienceClass(audienceMode, "public");
|
|
1321
|
-
const
|
|
1451
|
+
const query = ctx.db.query("epistemicNodes").withIndex(
|
|
1322
1452
|
"by_topic_type",
|
|
1323
1453
|
(q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
|
|
1324
1454
|
);
|
|
1325
|
-
const nodes = await
|
|
1455
|
+
const nodes = (await query.order("desc").take(scanLimit)).flatMap((row) => {
|
|
1456
|
+
const node = readBeliefNodeView(row);
|
|
1457
|
+
return node ? [node] : [];
|
|
1458
|
+
});
|
|
1326
1459
|
let filtered = nodes.filter(
|
|
1327
1460
|
(node) => canAudienceClassAccess(
|
|
1328
1461
|
viewerClass,
|
|
1329
|
-
resolveAudienceClass(node.audienceLabel, "internal")
|
|
1462
|
+
resolveAudienceClass(readOptionalString2(node.audienceLabel), "internal")
|
|
1330
1463
|
)
|
|
1331
1464
|
);
|
|
1332
1465
|
if (args.status) {
|
|
@@ -1360,11 +1493,16 @@ var internalGetById = internalQuery({
|
|
|
1360
1493
|
},
|
|
1361
1494
|
returns: permissiveReturn,
|
|
1362
1495
|
handler: async (ctx, args) => {
|
|
1363
|
-
const
|
|
1364
|
-
if (!
|
|
1496
|
+
const nodeId = ctx.db.normalizeId?.("epistemicNodes", args.beliefId);
|
|
1497
|
+
if (!nodeId) {
|
|
1498
|
+
return null;
|
|
1499
|
+
}
|
|
1500
|
+
const node = await ctx.db.get(nodeId);
|
|
1501
|
+
const beliefNode = readBeliefNodeView(node);
|
|
1502
|
+
if (!beliefNode) {
|
|
1365
1503
|
return null;
|
|
1366
1504
|
}
|
|
1367
|
-
return flattenBeliefNode(
|
|
1505
|
+
return flattenBeliefNode(beliefNode);
|
|
1368
1506
|
}
|
|
1369
1507
|
});
|
|
1370
1508
|
var internalCreate = internalMutation({
|
|
@@ -1407,171 +1545,235 @@ var internalCreate = internalMutation({
|
|
|
1407
1545
|
)
|
|
1408
1546
|
},
|
|
1409
1547
|
returns: permissiveReturn,
|
|
1410
|
-
handler: async (ctx, args) =>
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
mutationName: "epistemicBeliefs.internalCreate"
|
|
1435
|
-
});
|
|
1436
|
-
const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
|
|
1437
|
-
category: "belief_type",
|
|
1438
|
-
value: args.beliefType,
|
|
1439
|
-
tenantId: scope.tenantId,
|
|
1440
|
-
context: "epistemicBeliefs.internalCreate"
|
|
1441
|
-
});
|
|
1442
|
-
const globalId = generateGlobalId();
|
|
1443
|
-
const contentHash = generateContentHash(args.formulation);
|
|
1444
|
-
const requestedConfidence = args.confidence;
|
|
1445
|
-
const seedOpinion = {
|
|
1446
|
-
opinion_b: 0,
|
|
1447
|
-
opinion_d: 0,
|
|
1448
|
-
opinion_u: 1,
|
|
1449
|
-
opinion_a: baseRate
|
|
1450
|
-
};
|
|
1451
|
-
const nodeId = await insertEpistemicNode(ctx, {
|
|
1548
|
+
handler: async (ctx, args) => await createInternalBelief(ctx, args)
|
|
1549
|
+
});
|
|
1550
|
+
async function createInternalBelief(ctx, args) {
|
|
1551
|
+
const now = Date.now();
|
|
1552
|
+
const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
|
|
1553
|
+
const topicNode = await resolveInternalCreateTopicAnchor(ctx, args);
|
|
1554
|
+
const anchoredScope = scopeFromTopicAnchor(topicNode);
|
|
1555
|
+
const scope = {
|
|
1556
|
+
...anchoredScope,
|
|
1557
|
+
topicId: anchoredScope.topicId
|
|
1558
|
+
};
|
|
1559
|
+
assertInternalCreateScope(args, scope);
|
|
1560
|
+
const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
|
|
1561
|
+
category: "belief_type",
|
|
1562
|
+
value: args.beliefType,
|
|
1563
|
+
tenantId: scope.tenantId,
|
|
1564
|
+
context: "epistemicBeliefs.internalCreate"
|
|
1565
|
+
});
|
|
1566
|
+
const seedOpinion = buildSeedOpinion(baseRate);
|
|
1567
|
+
const globalId = generateGlobalId();
|
|
1568
|
+
const nodeId = await insertEpistemicNode(
|
|
1569
|
+
ctx,
|
|
1570
|
+
buildInternalBeliefNode({
|
|
1571
|
+
args,
|
|
1452
1572
|
globalId,
|
|
1453
|
-
|
|
1454
|
-
|
|
1573
|
+
normalizedBeliefType,
|
|
1574
|
+
now,
|
|
1575
|
+
scope,
|
|
1576
|
+
seedOpinion
|
|
1577
|
+
})
|
|
1578
|
+
);
|
|
1579
|
+
await insertInternalBeliefConfidence(ctx, {
|
|
1580
|
+
args,
|
|
1581
|
+
baseRate,
|
|
1582
|
+
nodeId,
|
|
1583
|
+
now,
|
|
1584
|
+
seedOpinion
|
|
1585
|
+
});
|
|
1586
|
+
await createRequiredBeliefTopicEdge(ctx, {
|
|
1587
|
+
beliefGlobalId: globalId,
|
|
1588
|
+
topicNode,
|
|
1589
|
+
createdBy: args.userId
|
|
1590
|
+
});
|
|
1591
|
+
await scheduleInternalBeliefSideEffects(ctx, {
|
|
1592
|
+
args,
|
|
1593
|
+
baseRate,
|
|
1594
|
+
nodeId,
|
|
1595
|
+
now,
|
|
1596
|
+
scope,
|
|
1597
|
+
seedOpinion
|
|
1598
|
+
});
|
|
1599
|
+
return { nodeId };
|
|
1600
|
+
}
|
|
1601
|
+
async function resolveInternalCreateTopicAnchor(ctx, args) {
|
|
1602
|
+
const topicRef = readTopicNodeRef(args);
|
|
1603
|
+
if (!topicRef) {
|
|
1604
|
+
throw new Error(
|
|
1605
|
+
"Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes."
|
|
1606
|
+
);
|
|
1607
|
+
}
|
|
1608
|
+
return await resolveRequiredTopicAnchor(ctx, topicRef);
|
|
1609
|
+
}
|
|
1610
|
+
function assertInternalCreateScope(args, scope) {
|
|
1611
|
+
assertWorkspaceScopedEpistemicNodeScope({
|
|
1612
|
+
scope,
|
|
1613
|
+
nodeType: "belief",
|
|
1614
|
+
mutationName: "epistemicBeliefs.internalCreate"
|
|
1615
|
+
});
|
|
1616
|
+
assertTenantPackWorkspaceMutationAllowed({
|
|
1617
|
+
runtime: resolveRuntimePackMutationContext(args),
|
|
1618
|
+
target: {
|
|
1455
1619
|
tenantId: scope.tenantId,
|
|
1456
1620
|
workspaceId: scope.workspaceId,
|
|
1457
1621
|
nodeType: "belief",
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1622
|
+
epistemicLayer: "L3"
|
|
1623
|
+
},
|
|
1624
|
+
mutationName: "epistemicBeliefs.internalCreate"
|
|
1625
|
+
});
|
|
1626
|
+
}
|
|
1627
|
+
function buildSeedOpinion(baseRate) {
|
|
1628
|
+
return {
|
|
1629
|
+
opinion_b: 0,
|
|
1630
|
+
opinion_d: 0,
|
|
1631
|
+
opinion_u: 1,
|
|
1632
|
+
opinion_a: baseRate
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
function buildInternalBeliefNode(args) {
|
|
1636
|
+
return {
|
|
1637
|
+
globalId: args.globalId,
|
|
1638
|
+
topicId: args.scope.topicId,
|
|
1639
|
+
projectId: args.scope.projectId,
|
|
1640
|
+
tenantId: args.scope.tenantId,
|
|
1641
|
+
workspaceId: args.scope.workspaceId,
|
|
1642
|
+
nodeType: "belief",
|
|
1643
|
+
canonicalText: args.args.formulation,
|
|
1644
|
+
contentHash: generateContentHash(args.args.formulation),
|
|
1645
|
+
status: "active",
|
|
1646
|
+
epistemicLayer: "L3",
|
|
1647
|
+
sourceType: args.args.userId.startsWith("agent:") ? "ai_generated" : "human",
|
|
1648
|
+
...args.normalizedBeliefType ? { beliefType: args.normalizedBeliefType } : {},
|
|
1649
|
+
createdAt: args.now,
|
|
1650
|
+
updatedAt: args.now,
|
|
1651
|
+
createdBy: args.args.userId,
|
|
1652
|
+
...args.seedOpinion,
|
|
1653
|
+
tupleContradicted: false,
|
|
1654
|
+
metadata: buildInternalBeliefMetadata(args.args, args.normalizedBeliefType)
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
function buildInternalBeliefMetadata(args, normalizedBeliefType) {
|
|
1658
|
+
return {
|
|
1659
|
+
...args.confidence ? { confidence: args.confidence } : {},
|
|
1660
|
+
tupleContradicted: false,
|
|
1661
|
+
rationale: args.rationale || "",
|
|
1662
|
+
topic: args.topic || args.pillar || "",
|
|
1663
|
+
pillar: args.pillar || args.topic || "",
|
|
1664
|
+
category: args.category || "",
|
|
1665
|
+
subcategory: args.subcategory || "",
|
|
1666
|
+
categoryIcon: args.categoryIcon || "",
|
|
1667
|
+
sprintId: args.sprintId,
|
|
1668
|
+
sourceBeliefIds: args.sourceBeliefIds || [],
|
|
1669
|
+
criticality: args.criticality || "unanalyzed",
|
|
1670
|
+
...normalizedBeliefType ? { beliefType: normalizedBeliefType } : {},
|
|
1671
|
+
supportingEvidenceIds: [],
|
|
1672
|
+
contradictingEvidenceIds: [],
|
|
1673
|
+
testingQuestionIds: [],
|
|
1674
|
+
linkedInsightIds: [],
|
|
1675
|
+
...isRecord2(args.extraMetadata) ? args.extraMetadata : {}
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
function isRecord2(value) {
|
|
1679
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1680
|
+
}
|
|
1681
|
+
async function insertInternalBeliefConfidence(ctx, args) {
|
|
1682
|
+
await ctx.db.insert(
|
|
1683
|
+
"beliefConfidence",
|
|
1684
|
+
buildBeliefConfidenceRow({
|
|
1685
|
+
beliefId: args.nodeId,
|
|
1686
|
+
belief: args.seedOpinion.opinion_b,
|
|
1687
|
+
disbelief: args.seedOpinion.opinion_d,
|
|
1688
|
+
uncertainty: args.seedOpinion.opinion_u,
|
|
1689
|
+
baseRate: args.baseRate,
|
|
1690
|
+
trigger: "initial",
|
|
1691
|
+
rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
|
|
1692
|
+
assessedBy: args.args.userId,
|
|
1693
|
+
assessedAt: args.now,
|
|
1694
|
+
slOperator: "prior_seed"
|
|
1695
|
+
})
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
async function scheduleInternalBeliefSideEffects(ctx, args) {
|
|
1699
|
+
await scheduleInternalNeo4jSync(ctx, args.nodeId);
|
|
1700
|
+
await insertInternalBeliefAudit(ctx, args);
|
|
1701
|
+
await scheduleInternalBeliefEmbedding(ctx, args);
|
|
1702
|
+
await scheduleInternalBeliefCategorization(ctx, args);
|
|
1703
|
+
await markBeliefGraphDirty(ctx, {
|
|
1704
|
+
projectId: args.scope.projectId,
|
|
1705
|
+
topicId: String(args.scope.topicId)
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
async function scheduleInternalNeo4jSync(ctx, nodeId) {
|
|
1709
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1710
|
+
nodeId,
|
|
1711
|
+
operation: "upsert"
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1714
|
+
async function insertInternalBeliefAudit(ctx, args) {
|
|
1715
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1716
|
+
entityType: "belief",
|
|
1717
|
+
entityId: args.nodeId,
|
|
1718
|
+
changeType: "created",
|
|
1719
|
+
changedAt: args.now,
|
|
1720
|
+
changedBy: args.args.userId,
|
|
1721
|
+
isAgent: false,
|
|
1722
|
+
newState: {
|
|
1723
|
+
formulation: args.args.formulation,
|
|
1724
|
+
baseRate: args.baseRate,
|
|
1725
|
+
confidence: args.args.confidence,
|
|
1726
|
+
opinion: {
|
|
1727
|
+
b: args.seedOpinion.opinion_b,
|
|
1728
|
+
d: args.seedOpinion.opinion_d,
|
|
1729
|
+
u: args.seedOpinion.opinion_u,
|
|
1730
|
+
a: args.seedOpinion.opinion_a
|
|
1534
1731
|
},
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1732
|
+
tupleContradicted: false,
|
|
1733
|
+
source: "internal"
|
|
1734
|
+
},
|
|
1735
|
+
projectId: args.scope.projectId,
|
|
1736
|
+
topicId: String(args.scope.topicId)
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
async function scheduleInternalBeliefEmbedding(ctx, args) {
|
|
1740
|
+
if (!(args.scope.projectId || args.scope.topicId)) {
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
|
|
1744
|
+
nodeId: args.nodeId,
|
|
1745
|
+
projectId: args.scope.projectId,
|
|
1746
|
+
topicId: args.scope.topicId ? String(args.scope.topicId) : void 0,
|
|
1747
|
+
createdBy: args.args.userId,
|
|
1748
|
+
nodeType: "belief",
|
|
1749
|
+
text: buildBeliefEmbeddingText(args.args),
|
|
1750
|
+
...args.args.confidence ? { confidence: numericRequestedConfidence(args.args.confidence) } : {}
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
function buildBeliefEmbeddingText(args) {
|
|
1754
|
+
return args.rationale ? `${args.formulation}
|
|
1549
1755
|
|
|
1550
|
-
Rationale: ${args.rationale}` : args.formulation
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
);
|
|
1556
|
-
}
|
|
1557
|
-
if (normalizePillar(args.pillar || args.topic) === "other" && (scope.projectId || scope.topicId)) {
|
|
1558
|
-
await ctx.scheduler.runAfter(
|
|
1559
|
-
2500,
|
|
1560
|
-
"beliefCategorization:autoCategorizeBelief",
|
|
1561
|
-
{
|
|
1562
|
-
nodeId,
|
|
1563
|
-
projectId: scope.projectId,
|
|
1564
|
-
topicId: String(scope.topicId)
|
|
1565
|
-
}
|
|
1566
|
-
);
|
|
1567
|
-
}
|
|
1568
|
-
await markBeliefGraphDirty(ctx, {
|
|
1569
|
-
projectId: scope.projectId,
|
|
1570
|
-
topicId: String(scope.topicId)
|
|
1571
|
-
});
|
|
1572
|
-
return { nodeId };
|
|
1756
|
+
Rationale: ${args.rationale}` : args.formulation;
|
|
1757
|
+
}
|
|
1758
|
+
function numericRequestedConfidence(confidence) {
|
|
1759
|
+
if (confidence === "high") {
|
|
1760
|
+
return 0.8;
|
|
1573
1761
|
}
|
|
1574
|
-
|
|
1762
|
+
if (confidence === "low") {
|
|
1763
|
+
return 0.3;
|
|
1764
|
+
}
|
|
1765
|
+
return 0.5;
|
|
1766
|
+
}
|
|
1767
|
+
async function scheduleInternalBeliefCategorization(ctx, args) {
|
|
1768
|
+
if (normalizePillar(args.args.pillar || args.args.topic) !== "other" || !(args.scope.projectId || args.scope.topicId)) {
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
await ctx.scheduler.runAfter(2500, BELIEF_CATEGORIZATION_ACTION, {
|
|
1772
|
+
nodeId: args.nodeId,
|
|
1773
|
+
projectId: args.scope.projectId,
|
|
1774
|
+
topicId: String(args.scope.topicId)
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1575
1777
|
|
|
1576
1778
|
export { internalCreate, internalGetActive, internalGetById, internalGetByProject, internalGetByTopic };
|
|
1577
1779
|
//# sourceMappingURL=epistemicBeliefs.internal.js.map
|