@lucern/graph-primitives 1.0.29 → 1.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{beliefDecay-DZ6tkLYq.d.ts → beliefDecay-BmkEk5OJ.d.ts} +3 -3
- package/dist/beliefDecay.d.ts +1 -1
- package/dist/beliefDecay.js +448 -314
- package/dist/beliefDecay.js.map +1 -1
- package/dist/{beliefEvidenceLinks-CWOXxxJg.d.ts → beliefEvidenceLinks-BzfjON_6.d.ts} +13 -13
- package/dist/beliefEvidenceLinks.d.ts +1 -1
- package/dist/beliefEvidenceLinks.js +843 -624
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/beliefEvidenceLinks.operational.d.ts +7 -5
- package/dist/beliefEvidenceLinks.operational.js +91 -18
- package/dist/beliefEvidenceLinks.operational.js.map +1 -1
- package/dist/beliefLifecycle.js.map +1 -1
- package/dist/confidencePropagationDispatch.d.ts +28 -27
- package/dist/confidencePropagationDispatch.js +157 -99
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/{contradictions-51VLsESq.d.ts → contradictions-BATPuZTL.d.ts} +10 -10
- package/dist/contradictions.d.ts +1 -1
- package/dist/contradictions.js +395 -225
- package/dist/contradictions.js.map +1 -1
- package/dist/convex.d.ts +65 -30
- package/dist/convex.js +7 -3
- package/dist/convex.js.map +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/edgeValidation.js +293 -85
- package/dist/edgeValidation.js.map +1 -1
- package/dist/edges/contains.d.ts +1 -1
- package/dist/edges/contains.js.map +1 -1
- package/dist/edges/contradicts.d.ts +1 -1
- package/dist/edges/contradicts.js.map +1 -1
- package/dist/edges/{dependsOn.d.ts → depends-on.d.ts} +1 -1
- package/dist/edges/{dependsOn.js → depends-on.js} +4 -4
- package/dist/edges/depends-on.js.map +1 -0
- package/dist/edges/{derivedFrom.d.ts → derived-from.d.ts} +1 -1
- package/dist/edges/{derivedFrom.js → derived-from.js} +3 -3
- package/dist/edges/derived-from.js.map +1 -0
- package/dist/edges/elaborates.d.ts +1 -1
- package/dist/edges/elaborates.js.map +1 -1
- package/dist/edges/index.d.ts +7 -3
- package/dist/edges/index.js +7 -4
- package/dist/edges/index.js.map +1 -1
- package/dist/edges/informs.d.ts +1 -1
- package/dist/edges/informs.js.map +1 -1
- package/dist/edges/{propagationTypes.d.ts → propagation-types.d.ts} +14 -14
- package/dist/edges/{propagationTypes.js → propagation-types.js} +3 -3
- package/dist/edges/propagation-types.js.map +1 -0
- package/dist/edges/refutes.d.ts +1 -1
- package/dist/edges/refutes.js.map +1 -1
- package/dist/edges/supports.d.ts +1 -1
- package/dist/edges/supports.js.map +1 -1
- package/dist/edges/tests.d.ts +1 -1
- package/dist/edges/tests.js.map +1 -1
- package/dist/edges/utils.d.ts +1 -1
- package/dist/edges/utils.js.map +1 -1
- package/dist/embeddingTrigger.d.ts +14 -6
- package/dist/embeddingTrigger.js +11 -14
- package/dist/embeddingTrigger.js.map +1 -1
- package/dist/{entityBridge-DMaKooYn.d.ts → entityBridge-BhVDM3pc.d.ts} +5 -5
- package/dist/entityBridge.d.ts +1 -1
- package/dist/entityBridge.js +602 -225
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityCanonicalMatch.d.ts +14 -12
- package/dist/entityCanonicalMatch.js.map +1 -1
- package/dist/{entityLifecycle-CvgSK5FV.d.ts → entityLifecycle-BsfCz9pS.d.ts} +5 -9
- package/dist/entityLifecycle.d.ts +1 -1
- package/dist/entityLifecycle.js +854 -480
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/{entityValidation-KLZ_Xl2D.d.ts → entityValidation-B1yNEHJx.d.ts} +7 -6
- package/dist/entityValidation.d.ts +3 -1
- package/dist/entityValidation.js +60 -8
- package/dist/entityValidation.js.map +1 -1
- package/dist/{epistemicAnswers-C5ib4z6_.d.ts → epistemicAnswers-f47YMu9U.d.ts} +6 -6
- package/dist/epistemicAnswers.d.ts +1 -1
- package/dist/epistemicAnswers.js +587 -545
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.d.ts +8 -8
- package/dist/epistemicBeliefs.admin.js +365 -166
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.d.ts +8 -8
- package/dist/epistemicBeliefs.backfills.js +655 -289
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.d.ts +19 -15
- package/dist/epistemicBeliefs.confidence.js +633 -386
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.d.ts +6 -6
- package/dist/epistemicBeliefs.core.js +717 -371
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.d.ts +11 -9
- package/dist/epistemicBeliefs.forkEvidence.d.ts +2 -0
- package/dist/epistemicBeliefs.forkEvidence.js +8 -8
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
- package/dist/epistemicBeliefs.helpers.d.ts +68 -49
- package/dist/epistemicBeliefs.helpers.js +358 -211
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.d.ts +5 -5
- package/dist/epistemicBeliefs.internal.js +1248 -1026
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +4942 -3590
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +5 -5
- package/dist/epistemicBeliefs.lifecycle.js +1138 -781
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.d.ts +7 -7
- package/dist/epistemicBeliefs.links.js +404 -267
- package/dist/epistemicBeliefs.links.js.map +1 -1
- package/dist/epistemicBeliefs.queries.d.ts +4 -4
- package/dist/epistemicBeliefs.queries.js +175 -20
- package/dist/epistemicBeliefs.queries.js.map +1 -1
- package/dist/epistemicBeliefs.topicAnchor.d.ts +6 -4
- package/dist/epistemicBeliefs.topicAnchor.js +12 -5
- package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
- package/dist/epistemicContracts.d.ts +28 -3
- package/dist/epistemicContracts.evaluators.d.ts +2 -0
- package/dist/epistemicContracts.evaluators.js +1062 -576
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.d.ts +15 -32
- package/dist/epistemicContracts.handlers.js +1829 -1351
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +1131 -636
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicContracts.metrics.d.ts +2 -0
- package/dist/epistemicContracts.metrics.js +375 -158
- package/dist/epistemicContracts.metrics.js.map +1 -1
- package/dist/epistemicContracts.types.d.ts +87 -81
- package/dist/epistemicEdgeCreation.d.ts +2 -0
- package/dist/epistemicEdgeCreation.js +87 -16
- package/dist/epistemicEdgeCreation.js.map +1 -1
- package/dist/{epistemicEdges-BF-cn4i3.d.ts → epistemicEdges-BGBh0QSP.d.ts} +4 -7
- package/dist/epistemicEdges.d.ts +6 -5
- package/dist/epistemicEdges.handlers.d.ts +3 -3
- package/dist/epistemicEdges.handlers.js +129 -24
- package/dist/epistemicEdges.handlers.js.map +1 -1
- package/dist/epistemicEdges.helpers.d.ts +6 -4
- package/dist/epistemicEdges.helpers.js +37 -2
- package/dist/epistemicEdges.helpers.js.map +1 -1
- package/dist/epistemicEdges.js +1966 -1202
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.d.ts +7 -7
- package/dist/epistemicEdges.mutations.js +956 -579
- package/dist/epistemicEdges.mutations.js.map +1 -1
- package/dist/epistemicEdges.queries.d.ts +16 -16
- package/dist/epistemicEdges.queries.js +639 -367
- package/dist/epistemicEdges.queries.js.map +1 -1
- package/dist/epistemicEdges.types.d.ts +10 -8
- package/dist/epistemicEvidence.d.ts +4 -1
- package/dist/epistemicEvidence.js +933 -532
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.d.ts +26 -10
- package/dist/epistemicEvidenceHelpers.js +239 -200
- package/dist/epistemicEvidenceHelpers.js.map +1 -1
- package/dist/epistemicEvidenceMutations.d.ts +8 -8
- package/dist/epistemicEvidenceMutations.js +840 -692
- package/dist/epistemicEvidenceMutations.js.map +1 -1
- package/dist/epistemicEvidenceQueries.d.ts +8 -8
- package/dist/epistemicEvidenceQueries.js +514 -238
- package/dist/epistemicEvidenceQueries.js.map +1 -1
- package/dist/epistemicHelpers.d.ts +4 -2
- package/dist/epistemicHelpers.js +308 -134
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicInsert.d.ts +16 -4
- package/dist/epistemicInsert.js +6 -3
- package/dist/epistemicInsert.js.map +1 -1
- package/dist/epistemicLayerRules.d.ts +10 -8
- package/dist/epistemicLayerRules.js +1 -5
- package/dist/epistemicLayerRules.js.map +1 -1
- package/dist/{epistemicLinking-CfE00tHJ.d.ts → epistemicLinking-CsCDv2cN.d.ts} +3 -3
- package/dist/epistemicLinking.d.ts +1 -1
- package/dist/epistemicLinking.js +177 -100
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodeCreation.d.ts +2 -0
- package/dist/epistemicNodeCreation.js +203 -40
- package/dist/epistemicNodeCreation.js.map +1 -1
- package/dist/{epistemicNodes-BCQxpYx_.d.ts → epistemicNodes-CokAgBHg.d.ts} +3 -3
- package/dist/epistemicNodes.d.ts +3 -3
- package/dist/epistemicNodes.helpers.d.ts +24 -15
- package/dist/epistemicNodes.helpers.js.map +1 -1
- package/dist/epistemicNodes.internal.d.ts +6 -6
- package/dist/epistemicNodes.internal.js +389 -319
- package/dist/epistemicNodes.internal.js.map +1 -1
- package/dist/epistemicNodes.js +700 -504
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.d.ts +6 -6
- package/dist/epistemicNodes.mutations.js +560 -463
- package/dist/epistemicNodes.mutations.js.map +1 -1
- package/dist/epistemicNodes.queries.d.ts +8 -8
- package/dist/epistemicNodes.queries.js +311 -314
- package/dist/epistemicNodes.queries.js.map +1 -1
- package/dist/epistemicNodes.validators.d.ts +2 -2
- package/dist/epistemicNodes.validators.js.map +1 -1
- package/dist/epistemicQuestions.conviction.d.ts +8 -8
- package/dist/epistemicQuestions.conviction.js +665 -484
- package/dist/epistemicQuestions.conviction.js.map +1 -1
- package/dist/epistemicQuestions.create.d.ts +4 -4
- package/dist/epistemicQuestions.create.js +640 -612
- package/dist/epistemicQuestions.create.js.map +1 -1
- package/dist/epistemicQuestions.d.ts +8 -5
- package/dist/epistemicQuestions.evidence.d.ts +2 -2
- package/dist/epistemicQuestions.evidence.js +475 -383
- package/dist/epistemicQuestions.evidence.js.map +1 -1
- package/dist/epistemicQuestions.helpers.d.ts +125 -24
- package/dist/epistemicQuestions.helpers.js +240 -209
- package/dist/epistemicQuestions.helpers.js.map +1 -1
- package/dist/epistemicQuestions.js +3474 -2823
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.d.ts +2 -2
- package/dist/epistemicQuestions.lifecycle.js +607 -546
- package/dist/epistemicQuestions.lifecycle.js.map +1 -1
- package/dist/epistemicQuestions.queries.d.ts +12 -7
- package/dist/epistemicQuestions.queries.js +305 -244
- package/dist/epistemicQuestions.queries.js.map +1 -1
- package/dist/epistemicQuestions.sprint.d.ts +2 -2
- package/dist/epistemicQuestions.sprint.js +600 -394
- package/dist/epistemicQuestions.sprint.js.map +1 -1
- package/dist/epistemicQuestions.tail.d.ts +6 -6
- package/dist/epistemicQuestions.tail.js +572 -433
- package/dist/epistemicQuestions.tail.js.map +1 -1
- package/dist/{epistemicSources-dlKj58Jp.d.ts → epistemicSources-DQtaEkWs.d.ts} +4 -4
- package/dist/epistemicSources.d.ts +1 -1
- package/dist/epistemicSources.js +351 -311
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.d.ts +8 -6
- package/dist/evaluators/index.js +399 -167
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/lint-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{lintCheckerEvaluator.js → lint-checker-evaluator.js} +10 -5
- package/dist/evaluators/lint-checker-evaluator.js.map +1 -0
- package/dist/evaluators/{sentryCheckerEvaluator.d.ts → sentry-checker-evaluator.d.ts} +7 -2
- package/dist/evaluators/{sentryCheckerEvaluator.js → sentry-checker-evaluator.js} +3 -3
- package/dist/evaluators/sentry-checker-evaluator.js.map +1 -0
- package/dist/evaluators/shared.d.ts +2 -2
- package/dist/evaluators/shared.js +3 -1
- package/dist/evaluators/shared.js.map +1 -1
- package/dist/evaluators/{testRunnerEvaluator.d.ts → test-runner-evaluator.d.ts} +6 -1
- package/dist/evaluators/{testRunnerEvaluator.js → test-runner-evaluator.js} +6 -4
- package/dist/evaluators/test-runner-evaluator.js.map +1 -0
- package/dist/evaluators/tsc-checker-evaluator.d.ts +16 -0
- package/dist/evaluators/{tscCheckerEvaluator.js → tsc-checker-evaluator.js} +10 -5
- package/dist/evaluators/tsc-checker-evaluator.js.map +1 -0
- package/dist/graphTypes.js +6 -2
- package/dist/graphTypes.js.map +1 -1
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +313 -93
- package/dist/helpers.js.map +1 -1
- package/dist/{index-C-Kyd7hD.d.ts → index-DZxyC9Pb.d.ts} +7 -6
- package/dist/index.d.ts +86 -83
- package/dist/index.js +16914 -11760
- package/dist/index.js.map +1 -1
- package/dist/invariantEnforcement.d.ts +3 -3
- package/dist/invariantEnforcement.js.map +1 -1
- package/dist/logicalRoleInference.d.ts +2 -0
- package/dist/logicalRoleInference.js +1 -1
- package/dist/logicalRoleInference.js.map +1 -1
- package/dist/matcherFeedbackUtils.d.ts +2 -2
- package/dist/matcherFeedbackUtils.js.map +1 -1
- package/dist/{ontology-matching-C6rrz2VP.d.ts → ontology-matching-C-mYFrir.d.ts} +16 -16
- package/dist/ontology-matching.d.ts +1 -1
- package/dist/{ontologyApproval-CFYmqKmk.d.ts → ontologyApproval-BVt0feJi.d.ts} +10 -10
- package/dist/ontologyApproval.d.ts +1 -1
- package/dist/ontologyApproval.js +7 -1
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.d.ts +14 -24
- package/dist/ontologyDefinitions.js +269 -34
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyHelpers.d.ts +13 -13
- package/dist/ontologyHelpers.js.map +1 -1
- package/dist/{ontologyRegistry-B67rPJ16.d.ts → ontologyRegistry-CljS-ENv.d.ts} +2 -2
- package/dist/ontologyRegistry.d.ts +1 -1
- package/dist/ontologyRegistry.js +34 -6
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/{projectionReconciliation-jww2fBI0.d.ts → projectionReconciliation-DnrSgHSQ.d.ts} +4 -4
- package/dist/projectionReconciliation.d.ts +1 -1
- package/dist/projectionReconciliation.js +57 -10
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/{projectionStaleness-CmdbpjVK.d.ts → projectionStaleness-C8ImQ2zP.d.ts} +17 -17
- package/dist/projectionStaleness.d.ts +1 -1
- package/dist/projectionStaleness.js +8 -2
- package/dist/projectionStaleness.js.map +1 -1
- package/dist/proof-attestation.json +1 -1
- package/dist/{questionEvidenceLinks-DFlyPpAj.d.ts → questionEvidenceLinks-_nPRa-LY.d.ts} +10 -10
- package/dist/questionEvidenceLinks.d.ts +1 -1
- package/dist/questionEvidenceLinks.js +564 -347
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/{resolverTypes-CC8Ea2E2.d.ts → resolverTypes-BOXPxLET.d.ts} +8 -7
- package/dist/resolverTypes.d.ts +4 -2
- package/dist/{resolvers-Br1a6eLV.d.ts → resolvers-B1TIBmRO.d.ts} +3 -1
- package/dist/resolvers.d.ts +5 -3
- package/dist/resolvers.js +121 -77
- package/dist/resolvers.js.map +1 -1
- package/dist/scopeResolverCompat.d.ts +10 -7
- package/dist/scopeResolverCompat.js +106 -123
- package/dist/scopeResolverCompat.js.map +1 -1
- package/dist/{text-matching-DNg4M5Wd.d.ts → text-matching-DzFooju6.d.ts} +7 -7
- package/dist/text-matching.d.ts +1 -1
- package/dist/topicOntologyResolver.d.ts +22 -21
- package/dist/topicOntologyResolver.js +54 -32
- package/dist/topicOntologyResolver.js.map +1 -1
- package/dist/topicProjectOverlay.d.ts +30 -20
- package/dist/topicProjectOverlay.js +120 -76
- package/dist/topicProjectOverlay.js.map +1 -1
- package/dist/{topicScope-7zhyeGl7.d.ts → topicScope-DJVa0mLa.d.ts} +22 -7
- package/dist/topicScope.d.ts +3 -1
- package/dist/topicScope.js +104 -119
- package/dist/topicScope.js.map +1 -1
- package/dist/workflowBridge.d.ts +26 -15
- package/dist/workflowBridge.js +140 -144
- package/dist/workflowBridge.js.map +1 -1
- package/dist/workspaceIsolation.d.ts +14 -12
- package/dist/workspaceIsolation.js +108 -122
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +4 -4
- package/dist/edges/dependsOn.js.map +0 -1
- package/dist/edges/derivedFrom.js.map +0 -1
- package/dist/edges/propagationTypes.js.map +0 -1
- package/dist/evaluators/lintCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/lintCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/sentryCheckerEvaluator.js.map +0 -1
- package/dist/evaluators/testRunnerEvaluator.js.map +0 -1
- package/dist/evaluators/tscCheckerEvaluator.d.ts +0 -11
- package/dist/evaluators/tscCheckerEvaluator.js.map +0 -1
- package/dist/{epistemicQuestions-bwHd2FWE.d.ts → epistemicQuestions-Do1fhYm5.d.ts} +4 -4
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { v } from 'convex/values';
|
|
2
1
|
import { checkProjectAccess, checkScopeAccess } from '@lucern/access-control/access';
|
|
3
2
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
4
|
-
import {
|
|
3
|
+
import { v } from 'convex/values';
|
|
4
|
+
import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
|
|
5
|
+
import { componentsGeneric, mutationGeneric, internalMutationGeneric } from 'convex/server';
|
|
6
|
+
import '@lucern/contracts';
|
|
5
7
|
import { generateGlobalId, assertUuidV7Identity } from '@lucern/contracts/ids';
|
|
6
8
|
import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
7
|
-
import '@lucern/contracts';
|
|
8
9
|
|
|
9
10
|
// src/epistemicQuestions.create.ts
|
|
10
|
-
var
|
|
11
|
+
var unsafeApi = unsafeConvexAnyApi(
|
|
12
|
+
"graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
|
|
13
|
+
);
|
|
14
|
+
var api = unsafeApi;
|
|
11
15
|
componentsGeneric();
|
|
12
|
-
var internal =
|
|
16
|
+
var internal = unsafeApi;
|
|
13
17
|
var internalMutation = internalMutationGeneric;
|
|
14
18
|
var mutation = mutationGeneric;
|
|
15
19
|
|
|
@@ -26,22 +30,19 @@ function debugGraphPrimitiveFallback(message, context) {
|
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
// src/embeddingTrigger.ts
|
|
33
|
+
var embeddingActionRef = "embeddingActions:generateEpistemicNodeEmbedding";
|
|
29
34
|
async function scheduleEmbeddingGeneration(args) {
|
|
30
35
|
try {
|
|
31
|
-
await args.ctx.scheduler.runAfter(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
hasAnswer: args.hasAnswer,
|
|
42
|
-
confidence: args.confidence
|
|
43
|
-
}
|
|
44
|
-
);
|
|
36
|
+
await args.ctx.scheduler.runAfter(0, embeddingActionRef, {
|
|
37
|
+
nodeId: args.nodeId,
|
|
38
|
+
projectId: args.projectId ? String(args.projectId) : void 0,
|
|
39
|
+
topicId: args.topicId ? String(args.topicId) : void 0,
|
|
40
|
+
createdBy: args.createdBy,
|
|
41
|
+
nodeType: args.nodeType,
|
|
42
|
+
text: args.text.slice(0, 2e4),
|
|
43
|
+
hasAnswer: args.hasAnswer,
|
|
44
|
+
confidence: args.confidence
|
|
45
|
+
});
|
|
45
46
|
} catch (error) {
|
|
46
47
|
debugGraphPrimitiveFallback(
|
|
47
48
|
"[embeddingTrigger] Failed to schedule embedding generation",
|
|
@@ -53,348 +54,13 @@ async function scheduleEmbeddingGeneration(args) {
|
|
|
53
54
|
);
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
let node = null;
|
|
62
|
-
try {
|
|
63
|
-
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
64
|
-
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
65
|
-
node = byGlobalId;
|
|
66
|
-
}
|
|
67
|
-
} catch (error) {
|
|
68
|
-
debugGraphPrimitiveFallback(
|
|
69
|
-
"[topicScope] topic-node scope lookup by globalId failed",
|
|
70
|
-
{ error, ref }
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
if (!node) {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
77
|
-
if (!scopeKey) {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
return {
|
|
81
|
-
topicId: scopeKey,
|
|
82
|
-
projectId: asMappedProjectId(node),
|
|
83
|
-
source: "topic_node"
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function asMappedProjectId(topic) {
|
|
87
|
-
if (!topic) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
91
|
-
if (directLegacyProjectId) {
|
|
92
|
-
return directLegacyProjectId;
|
|
93
|
-
}
|
|
94
|
-
const metadata = topic.metadata || {};
|
|
95
|
-
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
96
|
-
return candidate ? candidate : void 0;
|
|
97
|
-
}
|
|
98
|
-
function normalizeScopeValue(value) {
|
|
99
|
-
if (typeof value !== "string") {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const normalized = value.trim();
|
|
103
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
104
|
-
}
|
|
105
|
-
function pickPrimaryTopic(candidates) {
|
|
106
|
-
return [...candidates].sort((a, b) => {
|
|
107
|
-
const depthA = a.depth ?? 9999;
|
|
108
|
-
const depthB = b.depth ?? 9999;
|
|
109
|
-
if (depthA !== depthB) {
|
|
110
|
-
return depthA - depthB;
|
|
111
|
-
}
|
|
112
|
-
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
113
|
-
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
114
|
-
if (createdA !== createdB) {
|
|
115
|
-
return createdA - createdB;
|
|
116
|
-
}
|
|
117
|
-
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
118
|
-
})[0];
|
|
119
|
-
}
|
|
120
|
-
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
121
|
-
try {
|
|
122
|
-
return await ctx.db.query("topics").withIndex(
|
|
123
|
-
"by_graph_scope_project",
|
|
124
|
-
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
125
|
-
).collect();
|
|
126
|
-
} catch (error) {
|
|
127
|
-
debugGraphPrimitiveFallback(
|
|
128
|
-
"[topicScope] Failed to resolve scope alias via index",
|
|
129
|
-
{
|
|
130
|
-
error,
|
|
131
|
-
scopeId
|
|
132
|
-
}
|
|
133
|
-
);
|
|
134
|
-
const topics = await ctx.db.query("topics").collect();
|
|
135
|
-
return topics.filter((topic) => {
|
|
136
|
-
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
137
|
-
const mappedProjectId = asMappedProjectId(topic);
|
|
138
|
-
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
async function tryResolveHostTopicById(ctx, topicId) {
|
|
143
|
-
if (typeof ctx.runQuery !== "function") {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
try {
|
|
147
|
-
return await ctx.runQuery(api.topics.get, {
|
|
148
|
-
id: topicId
|
|
149
|
-
}) ?? null;
|
|
150
|
-
} catch (error) {
|
|
151
|
-
debugGraphPrimitiveFallback(
|
|
152
|
-
"[topicScope] Failed to resolve topic by host query",
|
|
153
|
-
{
|
|
154
|
-
error,
|
|
155
|
-
topicId
|
|
156
|
-
}
|
|
157
|
-
);
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
162
|
-
if (typeof ctx.runQuery !== "function") {
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
try {
|
|
166
|
-
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
167
|
-
projectId: legacyScopeId
|
|
168
|
-
}) ?? null;
|
|
169
|
-
} catch (error) {
|
|
170
|
-
debugGraphPrimitiveFallback(
|
|
171
|
-
"[topicScope] Failed to resolve topic by legacy scope",
|
|
172
|
-
{
|
|
173
|
-
error,
|
|
174
|
-
legacyScopeId
|
|
175
|
-
}
|
|
176
|
-
);
|
|
177
|
-
return null;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
181
|
-
const MAX_DEPTH = 10;
|
|
182
|
-
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
183
|
-
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
184
|
-
if (tenantId && workspaceId) {
|
|
185
|
-
return { tenantId, workspaceId };
|
|
186
|
-
}
|
|
187
|
-
let current = topic;
|
|
188
|
-
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
189
|
-
current = await ctx.db.get(current.parentTopicId);
|
|
190
|
-
if (!current) break;
|
|
191
|
-
if (!tenantId) {
|
|
192
|
-
tenantId = normalizeScopeValue(current.tenantId);
|
|
193
|
-
}
|
|
194
|
-
if (!workspaceId) {
|
|
195
|
-
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
196
|
-
}
|
|
197
|
-
if (tenantId && workspaceId) break;
|
|
198
|
-
}
|
|
199
|
-
return { tenantId, workspaceId };
|
|
200
|
-
}
|
|
201
|
-
async function resolveTopicProjectScope(ctx, args) {
|
|
202
|
-
if (args.topicId) {
|
|
203
|
-
let topic = null;
|
|
204
|
-
try {
|
|
205
|
-
topic = await ctx.db.get(
|
|
206
|
-
args.topicId
|
|
207
|
-
);
|
|
208
|
-
} catch (error) {
|
|
209
|
-
debugGraphPrimitiveFallback(
|
|
210
|
-
"[topicScope] Failed to load topic by direct id",
|
|
211
|
-
{
|
|
212
|
-
error,
|
|
213
|
-
topicId: args.topicId
|
|
214
|
-
}
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
if (!topic) {
|
|
218
|
-
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
219
|
-
}
|
|
220
|
-
if (!topic) {
|
|
221
|
-
topic = pickPrimaryTopic(
|
|
222
|
-
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
223
|
-
) ?? null;
|
|
224
|
-
}
|
|
225
|
-
if (!topic) {
|
|
226
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
227
|
-
ctx,
|
|
228
|
-
String(args.topicId)
|
|
229
|
-
);
|
|
230
|
-
if (nodeScope) {
|
|
231
|
-
return nodeScope;
|
|
232
|
-
}
|
|
233
|
-
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
234
|
-
}
|
|
235
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
236
|
-
const mapped = asMappedProjectId(topic);
|
|
237
|
-
if (mapped) {
|
|
238
|
-
return {
|
|
239
|
-
topicId: topic._id,
|
|
240
|
-
projectId: mapped,
|
|
241
|
-
tenantId: inherited.tenantId,
|
|
242
|
-
workspaceId: inherited.workspaceId,
|
|
243
|
-
source: "topic"
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
return {
|
|
247
|
-
topicId: topic._id,
|
|
248
|
-
tenantId: inherited.tenantId,
|
|
249
|
-
workspaceId: inherited.workspaceId,
|
|
250
|
-
source: "topic"
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
if (args.projectId) {
|
|
254
|
-
let directTopic = null;
|
|
255
|
-
try {
|
|
256
|
-
directTopic = await ctx.db.get(
|
|
257
|
-
args.projectId
|
|
258
|
-
);
|
|
259
|
-
} catch (error) {
|
|
260
|
-
debugGraphPrimitiveFallback(
|
|
261
|
-
"[topicScope] Failed to load direct project topic",
|
|
262
|
-
{
|
|
263
|
-
error,
|
|
264
|
-
projectId: args.projectId
|
|
265
|
-
}
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
if (directTopic) {
|
|
269
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
270
|
-
const mapped = asMappedProjectId(directTopic);
|
|
271
|
-
return {
|
|
272
|
-
topicId: directTopic._id,
|
|
273
|
-
projectId: mapped ?? args.projectId,
|
|
274
|
-
tenantId: inherited.tenantId,
|
|
275
|
-
workspaceId: inherited.workspaceId,
|
|
276
|
-
source: "topic_inferred"
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
280
|
-
if (directTopic) {
|
|
281
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
282
|
-
const mapped = asMappedProjectId(directTopic);
|
|
283
|
-
return {
|
|
284
|
-
topicId: directTopic._id,
|
|
285
|
-
projectId: mapped ?? args.projectId,
|
|
286
|
-
tenantId: inherited.tenantId,
|
|
287
|
-
workspaceId: inherited.workspaceId,
|
|
288
|
-
source: "topic_inferred"
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
292
|
-
const primary = pickPrimaryTopic(topics);
|
|
293
|
-
if (primary) {
|
|
294
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
295
|
-
return {
|
|
296
|
-
topicId: primary._id,
|
|
297
|
-
projectId: args.projectId,
|
|
298
|
-
tenantId: inherited.tenantId,
|
|
299
|
-
workspaceId: inherited.workspaceId,
|
|
300
|
-
source: "project_mapped_topic"
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
304
|
-
ctx,
|
|
305
|
-
String(args.projectId)
|
|
306
|
-
);
|
|
307
|
-
if (nodeScope) {
|
|
308
|
-
return {
|
|
309
|
-
...nodeScope,
|
|
310
|
-
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
throw new Error(
|
|
314
|
-
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
throw new Error(
|
|
318
|
-
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
var optionalScopeArgs = {
|
|
322
|
-
projectId: v.optional(v.string()),
|
|
323
|
-
topicId: v.optional(v.string())
|
|
324
|
-
};
|
|
325
|
-
function normalizeScopeValue2(value) {
|
|
326
|
-
if (typeof value !== "string") {
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
const normalized = value.trim();
|
|
330
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
331
|
-
}
|
|
332
|
-
function throwWorkspaceIsolationError(args) {
|
|
333
|
-
const error = new Error(args.message);
|
|
334
|
-
error.status = 409;
|
|
335
|
-
error.code = "INVARIANT_VIOLATION";
|
|
336
|
-
error.invariantCode = args.invariantCode;
|
|
337
|
-
error.suggestion = args.suggestion;
|
|
338
|
-
error.details = args.details;
|
|
339
|
-
throw error;
|
|
340
|
-
}
|
|
341
|
-
function assertWorkspaceScopedEpistemicNodeScope(args) {
|
|
342
|
-
const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
|
|
343
|
-
if (layer === "ontological") {
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
|
|
347
|
-
if (workspaceId) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
throwWorkspaceIsolationError({
|
|
351
|
-
message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
|
|
352
|
-
invariantCode: "workspace.scope_required_for_epistemic_nodes",
|
|
353
|
-
suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
|
|
354
|
-
details: {
|
|
355
|
-
mutationName: args.mutationName,
|
|
356
|
-
nodeType: args.nodeType,
|
|
357
|
-
topicId: args.scope.topicId,
|
|
358
|
-
projectId: args.scope.projectId
|
|
359
|
-
}
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
function resolveRuntimePackMutationContext(args) {
|
|
363
|
-
if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
return {
|
|
367
|
-
toolName: args.runtimeToolName,
|
|
368
|
-
packKey: args.runtimePackKey,
|
|
369
|
-
packInstallScope: args.runtimePackInstallScope
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
function assertTenantPackWorkspaceMutationAllowed(args) {
|
|
373
|
-
if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
|
|
377
|
-
const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
|
|
378
|
-
if (!targetWorkspaceId || targetLayer === "ontological") {
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
throwWorkspaceIsolationError({
|
|
382
|
-
message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
|
|
383
|
-
invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
|
|
384
|
-
suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
|
|
385
|
-
details: {
|
|
386
|
-
mutationName: args.mutationName,
|
|
387
|
-
toolName: args.runtime.toolName,
|
|
388
|
-
packKey: args.runtime.packKey,
|
|
389
|
-
targetWorkspaceId,
|
|
390
|
-
targetNodeType: args.target.nodeType,
|
|
391
|
-
targetLayer
|
|
392
|
-
}
|
|
393
|
-
});
|
|
57
|
+
function insertEpistemicNode(ctx, doc) {
|
|
58
|
+
assertUuidV7Identity("epistemicNodes", doc.globalId);
|
|
59
|
+
return ctx.db.insert("epistemicNodes", doc);
|
|
394
60
|
}
|
|
395
61
|
|
|
396
62
|
// src/topicProjectOverlay.ts
|
|
397
|
-
var
|
|
63
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
398
64
|
function readNonEmptyString(value) {
|
|
399
65
|
if (typeof value !== "string") {
|
|
400
66
|
return;
|
|
@@ -411,11 +77,15 @@ function readStringArray(value) {
|
|
|
411
77
|
function readMetadata(topic) {
|
|
412
78
|
return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
|
|
413
79
|
}
|
|
80
|
+
function omitMetadataKey(metadata, key) {
|
|
81
|
+
const { [key]: _omitted, ...rest } = metadata;
|
|
82
|
+
return rest;
|
|
83
|
+
}
|
|
414
84
|
function readLegacyProjectId(value) {
|
|
415
85
|
if (!value) {
|
|
416
86
|
return;
|
|
417
87
|
}
|
|
418
|
-
return readNonEmptyString(value[
|
|
88
|
+
return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
|
|
419
89
|
}
|
|
420
90
|
function coerceVisibility(value) {
|
|
421
91
|
return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
|
|
@@ -491,9 +161,12 @@ async function resolveTopicDoc(ctx, scopeId) {
|
|
|
491
161
|
);
|
|
492
162
|
}
|
|
493
163
|
try {
|
|
494
|
-
const topic = await ctx.runQuery(
|
|
495
|
-
|
|
496
|
-
|
|
164
|
+
const topic = await ctx.runQuery(
|
|
165
|
+
api.topics.getByLegacyScopeId,
|
|
166
|
+
{
|
|
167
|
+
projectId: String(scopeId)
|
|
168
|
+
}
|
|
169
|
+
);
|
|
497
170
|
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
498
171
|
return topic;
|
|
499
172
|
}
|
|
@@ -513,8 +186,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
|
513
186
|
const outwardId = idMode === "topic" ? topicId : storageProjectId;
|
|
514
187
|
const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
|
|
515
188
|
const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
|
|
516
|
-
|
|
517
|
-
|
|
189
|
+
let createdAt = 0;
|
|
190
|
+
if (typeof topic.createdAt === "number") {
|
|
191
|
+
createdAt = topic.createdAt;
|
|
192
|
+
} else if (typeof topic._creationTime === "number") {
|
|
193
|
+
createdAt = topic._creationTime;
|
|
194
|
+
}
|
|
195
|
+
let updatedAt = createdAt;
|
|
196
|
+
if (typeof topic.updatedAt === "number") {
|
|
197
|
+
updatedAt = topic.updatedAt;
|
|
198
|
+
} else if (typeof metadata.updatedAt === "number") {
|
|
199
|
+
updatedAt = metadata.updatedAt;
|
|
200
|
+
}
|
|
518
201
|
return {
|
|
519
202
|
...metadata,
|
|
520
203
|
_id: outwardId,
|
|
@@ -574,167 +257,445 @@ async function listTopicProjectOverlays(ctx, options = {}) {
|
|
|
574
257
|
if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
|
|
575
258
|
allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
|
|
576
259
|
}
|
|
577
|
-
return allTopics.filter(
|
|
578
|
-
(topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
|
|
579
|
-
).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
|
|
260
|
+
return allTopics.filter(
|
|
261
|
+
(topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
|
|
262
|
+
).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
|
|
263
|
+
}
|
|
264
|
+
async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
265
|
+
const topic = await resolveTopicDoc(ctx, scopeId);
|
|
266
|
+
if (!topic) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
const plan = buildTopicProjectOverlayPatchPlan(topic, value);
|
|
270
|
+
await applyTopicProjectOverlayPatch(ctx, topic, plan);
|
|
271
|
+
return materializeTopicProjectOverlay({
|
|
272
|
+
...topic,
|
|
273
|
+
...plan.patch,
|
|
274
|
+
metadata: plan.nextMetadata
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function buildTopicProjectOverlayPatchPlan(topic, value) {
|
|
278
|
+
const plan = {
|
|
279
|
+
nextMetadata: { ...readMetadata(topic) },
|
|
280
|
+
patch: {},
|
|
281
|
+
topicUpdateArgs: {
|
|
282
|
+
id: String(topic._id)
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
for (const [key, rawValue] of Object.entries(value)) {
|
|
286
|
+
applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
|
|
287
|
+
}
|
|
288
|
+
plan.patch.updatedAt = Date.now();
|
|
289
|
+
plan.patch.metadata = plan.nextMetadata;
|
|
290
|
+
plan.topicUpdateArgs.metadata = plan.nextMetadata;
|
|
291
|
+
return plan;
|
|
292
|
+
}
|
|
293
|
+
function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
|
|
294
|
+
switch (key) {
|
|
295
|
+
case "_id":
|
|
296
|
+
case "projectId":
|
|
297
|
+
case "topicId":
|
|
298
|
+
case "legacyProjectId":
|
|
299
|
+
case "storageProjectId":
|
|
300
|
+
case "updatedAt":
|
|
301
|
+
case "createdAt":
|
|
302
|
+
return;
|
|
303
|
+
case "name":
|
|
304
|
+
case "description":
|
|
305
|
+
plan.patch[key] = rawValue;
|
|
306
|
+
plan.topicUpdateArgs[key] = rawValue;
|
|
307
|
+
return;
|
|
308
|
+
case "tenantId":
|
|
309
|
+
case "workspaceId":
|
|
310
|
+
case "ownerId":
|
|
311
|
+
throw new Error(
|
|
312
|
+
`patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
|
|
313
|
+
);
|
|
314
|
+
case "status":
|
|
315
|
+
applyTopicStatusPatch(plan, rawValue);
|
|
316
|
+
return;
|
|
317
|
+
case "visibility":
|
|
318
|
+
applyTopicVisibilityPatch(plan, rawValue);
|
|
319
|
+
return;
|
|
320
|
+
case "type":
|
|
321
|
+
applyTopicProjectTypePatch(plan, rawValue);
|
|
322
|
+
return;
|
|
323
|
+
default:
|
|
324
|
+
applyTopicMetadataPatch(plan, key, rawValue);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function applyTopicStatusPatch(plan, rawValue) {
|
|
328
|
+
const status = coerceStatus(rawValue);
|
|
329
|
+
if (status) {
|
|
330
|
+
plan.patch.status = status;
|
|
331
|
+
plan.topicUpdateArgs.status = status;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function applyTopicVisibilityPatch(plan, rawValue) {
|
|
335
|
+
const visibility = coerceVisibility(rawValue);
|
|
336
|
+
if (visibility) {
|
|
337
|
+
plan.patch.visibility = visibility;
|
|
338
|
+
plan.topicUpdateArgs.visibility = visibility;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function applyTopicProjectTypePatch(plan, rawValue) {
|
|
342
|
+
const projectType = readNonEmptyString(rawValue);
|
|
343
|
+
if (projectType) {
|
|
344
|
+
plan.nextMetadata.projectType = projectType;
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
|
|
348
|
+
}
|
|
349
|
+
function applyTopicMetadataPatch(plan, key, rawValue) {
|
|
350
|
+
if (rawValue === void 0) {
|
|
351
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
plan.nextMetadata[key] = rawValue;
|
|
355
|
+
}
|
|
356
|
+
async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
|
|
357
|
+
if (typeof ctx.runMutation === "function") {
|
|
358
|
+
try {
|
|
359
|
+
await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (!canPatchTopicViaLocalDb(ctx, error)) {
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
365
|
+
}
|
|
366
|
+
} else if (ctx?.db && typeof ctx.db.patch === "function") {
|
|
367
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
368
|
+
} else {
|
|
369
|
+
throw new Error(
|
|
370
|
+
"Cannot patch topic without component adapter (ctx.runMutation unavailable)"
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
function canPatchTopicViaLocalDb(ctx, error) {
|
|
375
|
+
return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/resolvers.ts
|
|
379
|
+
function isMissingLucernChildComponentError2(error) {
|
|
380
|
+
const message = getErrorMessage2(error);
|
|
381
|
+
return message.includes(
|
|
382
|
+
'Child component ComponentName(Identifier("lucern")) not found'
|
|
383
|
+
) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
|
|
384
|
+
}
|
|
385
|
+
function getErrorMessage2(error) {
|
|
386
|
+
if (error instanceof Error) {
|
|
387
|
+
return error.message;
|
|
388
|
+
}
|
|
389
|
+
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
|
|
390
|
+
return error.message;
|
|
391
|
+
}
|
|
392
|
+
return "unknown error";
|
|
393
|
+
}
|
|
394
|
+
function isAdvisoryTopicPatch(value) {
|
|
395
|
+
const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
|
|
396
|
+
const keys = Object.keys(value);
|
|
397
|
+
return keys.length > 0 && keys.every((key) => advisoryKeys.has(key));
|
|
398
|
+
}
|
|
399
|
+
async function patchProjectWithTolerance(ctx, projectId, value) {
|
|
400
|
+
try {
|
|
401
|
+
await patchTopicProjectOverlay(ctx, projectId, value);
|
|
402
|
+
} catch (error) {
|
|
403
|
+
if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
|
|
404
|
+
throw error;
|
|
405
|
+
}
|
|
406
|
+
console.warn(
|
|
407
|
+
"[lucern graph-primitives] Non-fatal advisory topic patch failure",
|
|
408
|
+
{
|
|
409
|
+
projectId,
|
|
410
|
+
keys: Object.keys(value),
|
|
411
|
+
error: getErrorMessage2(error)
|
|
412
|
+
}
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
function defaultResolvers() {
|
|
417
|
+
return {
|
|
418
|
+
getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
|
|
419
|
+
idMode: "legacy",
|
|
420
|
+
projectLikeOnly: false
|
|
421
|
+
}),
|
|
422
|
+
patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
|
|
423
|
+
listTopics: (ctx) => listTopicProjectOverlays(ctx, {
|
|
424
|
+
idMode: "legacy"
|
|
425
|
+
}),
|
|
426
|
+
getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
var resolverOverrides = {};
|
|
430
|
+
function resolveGraphPrimitivesAppResolvers(_ctx) {
|
|
431
|
+
return {
|
|
432
|
+
...defaultResolvers(),
|
|
433
|
+
...resolverOverrides
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
|
|
437
|
+
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
438
|
+
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
let node = null;
|
|
442
|
+
try {
|
|
443
|
+
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
444
|
+
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
445
|
+
node = byGlobalId;
|
|
446
|
+
}
|
|
447
|
+
} catch (error) {
|
|
448
|
+
debugGraphPrimitiveFallback(
|
|
449
|
+
"[topicScope] topic-node scope lookup by globalId failed",
|
|
450
|
+
{ error, ref }
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
if (!node) {
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
457
|
+
if (!scopeKey) {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
topicId: scopeKey,
|
|
462
|
+
projectId: asMappedProjectId(node),
|
|
463
|
+
source: "topic_node"
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function asMappedProjectId(topic) {
|
|
467
|
+
if (!topic) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
471
|
+
topic[LEGACY_SCOPE_FIELD2]
|
|
472
|
+
);
|
|
473
|
+
if (directLegacyProjectId) {
|
|
474
|
+
return directLegacyProjectId;
|
|
475
|
+
}
|
|
476
|
+
const metadata = topic.metadata || {};
|
|
477
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
478
|
+
return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
|
|
479
|
+
}
|
|
480
|
+
function normalizeScopeValue(value) {
|
|
481
|
+
if (typeof value !== "string") {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const normalized = value.trim();
|
|
485
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
486
|
+
}
|
|
487
|
+
function pickPrimaryTopic(candidates) {
|
|
488
|
+
return [...candidates].sort((a, b) => {
|
|
489
|
+
const depthA = a.depth ?? 9999;
|
|
490
|
+
const depthB = b.depth ?? 9999;
|
|
491
|
+
if (depthA !== depthB) {
|
|
492
|
+
return depthA - depthB;
|
|
493
|
+
}
|
|
494
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
495
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
496
|
+
if (createdA !== createdB) {
|
|
497
|
+
return createdA - createdB;
|
|
498
|
+
}
|
|
499
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
500
|
+
})[0];
|
|
501
|
+
}
|
|
502
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
503
|
+
const query2 = ctx.db.query("topics");
|
|
504
|
+
try {
|
|
505
|
+
return await query2.withIndex(
|
|
506
|
+
"by_graph_scope_project",
|
|
507
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
|
|
508
|
+
).collect();
|
|
509
|
+
} catch (error) {
|
|
510
|
+
debugGraphPrimitiveFallback(
|
|
511
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
512
|
+
{
|
|
513
|
+
error,
|
|
514
|
+
scopeId
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
const topics = await query2.collect();
|
|
518
|
+
return topics.filter((topic) => {
|
|
519
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
520
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
521
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
526
|
+
if (typeof ctx.runQuery !== "function") {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
return await ctx.runQuery(api.topics.get, {
|
|
531
|
+
id: topicId
|
|
532
|
+
}) ?? null;
|
|
533
|
+
} catch (error) {
|
|
534
|
+
debugGraphPrimitiveFallback(
|
|
535
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
536
|
+
{
|
|
537
|
+
error,
|
|
538
|
+
topicId
|
|
539
|
+
}
|
|
540
|
+
);
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
545
|
+
if (typeof ctx.runQuery !== "function") {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
try {
|
|
549
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
550
|
+
projectId: legacyScopeId
|
|
551
|
+
}) ?? null;
|
|
552
|
+
} catch (error) {
|
|
553
|
+
debugGraphPrimitiveFallback(
|
|
554
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
555
|
+
{
|
|
556
|
+
error,
|
|
557
|
+
legacyScopeId
|
|
558
|
+
}
|
|
559
|
+
);
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
564
|
+
const MAX_DEPTH = 10;
|
|
565
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
566
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
567
|
+
if (tenantId && workspaceId) {
|
|
568
|
+
return { tenantId, workspaceId };
|
|
569
|
+
}
|
|
570
|
+
let current = topic;
|
|
571
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
572
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
573
|
+
if (!current) {
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
if (!tenantId) {
|
|
577
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
578
|
+
}
|
|
579
|
+
if (!workspaceId) {
|
|
580
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
581
|
+
}
|
|
582
|
+
if (tenantId && workspaceId) {
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return { tenantId, workspaceId };
|
|
587
|
+
}
|
|
588
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
589
|
+
if (args.topicId) {
|
|
590
|
+
return await resolveScopeFromTopicId(ctx, args.topicId);
|
|
591
|
+
}
|
|
592
|
+
if (args.projectId) {
|
|
593
|
+
return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
|
|
594
|
+
}
|
|
595
|
+
throw new Error(
|
|
596
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
597
|
+
);
|
|
580
598
|
}
|
|
581
|
-
async function
|
|
582
|
-
const topic = await
|
|
583
|
-
if (
|
|
584
|
-
return
|
|
585
|
-
}
|
|
586
|
-
const nextMetadata = { ...readMetadata(topic) };
|
|
587
|
-
const patch = {};
|
|
588
|
-
const topicUpdateArgs = {
|
|
589
|
-
id: String(topic._id)
|
|
590
|
-
};
|
|
591
|
-
for (const [key, rawValue] of Object.entries(value)) {
|
|
592
|
-
switch (key) {
|
|
593
|
-
case "_id":
|
|
594
|
-
case "projectId":
|
|
595
|
-
case "topicId":
|
|
596
|
-
case "legacyProjectId":
|
|
597
|
-
case "storageProjectId":
|
|
598
|
-
break;
|
|
599
|
-
case "name":
|
|
600
|
-
case "description":
|
|
601
|
-
patch[key] = rawValue;
|
|
602
|
-
topicUpdateArgs[key] = rawValue;
|
|
603
|
-
break;
|
|
604
|
-
case "tenantId":
|
|
605
|
-
case "workspaceId":
|
|
606
|
-
case "ownerId":
|
|
607
|
-
throw new Error(
|
|
608
|
-
`patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
|
|
609
|
-
);
|
|
610
|
-
case "status": {
|
|
611
|
-
const status = coerceStatus(rawValue);
|
|
612
|
-
if (status) {
|
|
613
|
-
patch.status = status;
|
|
614
|
-
topicUpdateArgs.status = status;
|
|
615
|
-
}
|
|
616
|
-
break;
|
|
617
|
-
}
|
|
618
|
-
case "visibility": {
|
|
619
|
-
const visibility = coerceVisibility(rawValue);
|
|
620
|
-
if (visibility) {
|
|
621
|
-
patch.visibility = visibility;
|
|
622
|
-
topicUpdateArgs.visibility = visibility;
|
|
623
|
-
}
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
case "type": {
|
|
627
|
-
const projectType = readNonEmptyString(rawValue);
|
|
628
|
-
if (projectType) {
|
|
629
|
-
nextMetadata.projectType = projectType;
|
|
630
|
-
} else {
|
|
631
|
-
delete nextMetadata.projectType;
|
|
632
|
-
}
|
|
633
|
-
break;
|
|
634
|
-
}
|
|
635
|
-
case "updatedAt":
|
|
636
|
-
case "createdAt":
|
|
637
|
-
break;
|
|
638
|
-
default:
|
|
639
|
-
if (rawValue === void 0) {
|
|
640
|
-
delete nextMetadata[key];
|
|
641
|
-
} else {
|
|
642
|
-
nextMetadata[key] = rawValue;
|
|
643
|
-
}
|
|
644
|
-
}
|
|
599
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
600
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
601
|
+
if (topic) {
|
|
602
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
645
603
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
if (typeof ctx.runMutation === "function") {
|
|
650
|
-
try {
|
|
651
|
-
await ctx.runMutation(api.topics.update, topicUpdateArgs);
|
|
652
|
-
} catch (error) {
|
|
653
|
-
if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
|
|
654
|
-
throw error;
|
|
655
|
-
}
|
|
656
|
-
await ctx.db.patch(String(topic._id), patch);
|
|
657
|
-
}
|
|
658
|
-
} else if (ctx?.db && typeof ctx.db.patch === "function") {
|
|
659
|
-
await ctx.db.patch(String(topic._id), patch);
|
|
660
|
-
} else {
|
|
661
|
-
throw new Error(
|
|
662
|
-
"Cannot patch topic without component adapter (ctx.runMutation unavailable)"
|
|
663
|
-
);
|
|
604
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
|
|
605
|
+
if (nodeScope) {
|
|
606
|
+
return nodeScope;
|
|
664
607
|
}
|
|
665
|
-
|
|
666
|
-
...topic,
|
|
667
|
-
...patch,
|
|
668
|
-
metadata: nextMetadata
|
|
669
|
-
});
|
|
608
|
+
throw new Error(`Topic not found: ${String(topicId)}`);
|
|
670
609
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
610
|
+
async function resolveTopicDocFromTopicId(ctx, topicId) {
|
|
611
|
+
const direct = await tryReadTopicDoc(ctx, topicId, {
|
|
612
|
+
failureLog: "[topicScope] Failed to load topic by direct id",
|
|
613
|
+
idLogKey: "topicId"
|
|
614
|
+
});
|
|
615
|
+
if (direct) {
|
|
616
|
+
return direct;
|
|
617
|
+
}
|
|
618
|
+
const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
|
|
619
|
+
if (hostTopic) {
|
|
620
|
+
return hostTopic;
|
|
621
|
+
}
|
|
622
|
+
return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
|
|
678
623
|
}
|
|
679
|
-
function
|
|
680
|
-
|
|
681
|
-
|
|
624
|
+
async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
|
|
625
|
+
const directTopic = await resolveDirectLegacyProjectTopic(
|
|
626
|
+
ctx,
|
|
627
|
+
legacyProjectId
|
|
628
|
+
);
|
|
629
|
+
if (directTopic) {
|
|
630
|
+
return await buildTopicScope(ctx, directTopic, "topic_inferred", {
|
|
631
|
+
fallbackProjectId: legacyProjectId
|
|
632
|
+
});
|
|
682
633
|
}
|
|
683
|
-
|
|
684
|
-
|
|
634
|
+
const primary = pickPrimaryTopic(
|
|
635
|
+
await findTopicsByScopeAlias(ctx, legacyProjectId)
|
|
636
|
+
);
|
|
637
|
+
if (primary) {
|
|
638
|
+
return await buildTopicScope(ctx, primary, "project_mapped_topic", {
|
|
639
|
+
fallbackProjectId: legacyProjectId
|
|
640
|
+
});
|
|
685
641
|
}
|
|
686
|
-
|
|
642
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
|
|
643
|
+
if (nodeScope) {
|
|
644
|
+
return {
|
|
645
|
+
...nodeScope,
|
|
646
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
throw new Error(
|
|
650
|
+
`Legacy project scope ${legacyProjectId} has no mapped topic.`
|
|
651
|
+
);
|
|
687
652
|
}
|
|
688
|
-
function
|
|
689
|
-
const
|
|
690
|
-
|
|
691
|
-
|
|
653
|
+
async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
|
|
654
|
+
const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
|
|
655
|
+
failureLog: "[topicScope] Failed to load direct project topic",
|
|
656
|
+
idLogKey: "projectId"
|
|
657
|
+
});
|
|
658
|
+
return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
|
|
692
659
|
}
|
|
693
|
-
async function
|
|
660
|
+
async function tryReadTopicDoc(ctx, id, log) {
|
|
694
661
|
try {
|
|
695
|
-
await
|
|
662
|
+
return await ctx.db.get(id);
|
|
696
663
|
} catch (error) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
{
|
|
703
|
-
projectId,
|
|
704
|
-
keys: Object.keys(value),
|
|
705
|
-
error: getErrorMessage2(error)
|
|
706
|
-
}
|
|
707
|
-
);
|
|
664
|
+
debugGraphPrimitiveFallback(log.failureLog, {
|
|
665
|
+
error,
|
|
666
|
+
[log.idLogKey]: id
|
|
667
|
+
});
|
|
668
|
+
return null;
|
|
708
669
|
}
|
|
709
670
|
}
|
|
710
|
-
function
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
idMode: "legacy",
|
|
714
|
-
projectLikeOnly: false
|
|
715
|
-
}),
|
|
716
|
-
patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
|
|
717
|
-
listTopics: (ctx) => listTopicProjectOverlays(ctx, {
|
|
718
|
-
idMode: "legacy"
|
|
719
|
-
}),
|
|
720
|
-
getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
var resolverOverrides = {};
|
|
724
|
-
function resolveGraphPrimitivesAppResolvers(_ctx) {
|
|
671
|
+
async function buildTopicScope(ctx, topic, source, options = {}) {
|
|
672
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
673
|
+
const mapped = asMappedProjectId(topic);
|
|
725
674
|
return {
|
|
726
|
-
|
|
727
|
-
...
|
|
675
|
+
topicId: topic._id,
|
|
676
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
677
|
+
tenantId: inherited.tenantId,
|
|
678
|
+
workspaceId: inherited.workspaceId,
|
|
679
|
+
source
|
|
728
680
|
};
|
|
729
681
|
}
|
|
682
|
+
var optionalScopeArgs = {
|
|
683
|
+
projectId: v.optional(v.string()),
|
|
684
|
+
topicId: v.optional(v.string())
|
|
685
|
+
};
|
|
730
686
|
|
|
731
687
|
// src/epistemicQuestions.helpers.ts
|
|
732
688
|
function generateContentHash(text) {
|
|
733
689
|
const content = `question:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
|
|
734
690
|
let hash = 5381;
|
|
691
|
+
const maxSigned32Bit = 2147483647;
|
|
692
|
+
const uint32Size = 4294967296;
|
|
735
693
|
for (let i = 0; i < content.length; i++) {
|
|
736
|
-
hash = (hash
|
|
737
|
-
hash
|
|
694
|
+
hash = Math.imul(hash, 33) + content.charCodeAt(i);
|
|
695
|
+
hash %= uint32Size;
|
|
696
|
+
if (hash > maxSigned32Bit) {
|
|
697
|
+
hash -= uint32Size;
|
|
698
|
+
}
|
|
738
699
|
}
|
|
739
700
|
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
740
701
|
}
|
|
@@ -742,9 +703,10 @@ function buildTestsEdgeGlobalId(fromGlobalId, toGlobalId) {
|
|
|
742
703
|
return `edge-${fromGlobalId}-tests-${toGlobalId}`;
|
|
743
704
|
}
|
|
744
705
|
async function markProjectGraphDirty(ctx, projectId, topicId) {
|
|
706
|
+
const markCacheStaleByTopic = internal.graphAnalysisCache.markCacheStaleByTopic;
|
|
745
707
|
const normalizedProjectId = typeof projectId === "string" && projectId.trim().length > 0 ? projectId : void 0;
|
|
746
708
|
const normalizedTopicId = typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
|
|
747
|
-
if (!normalizedProjectId
|
|
709
|
+
if (!(normalizedProjectId || normalizedTopicId)) {
|
|
748
710
|
return;
|
|
749
711
|
}
|
|
750
712
|
if (normalizedProjectId) {
|
|
@@ -757,17 +719,17 @@ async function markProjectGraphDirty(ctx, projectId, topicId) {
|
|
|
757
719
|
);
|
|
758
720
|
}
|
|
759
721
|
if (normalizedTopicId) {
|
|
760
|
-
await ctx.scheduler.runAfter(
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
722
|
+
await ctx.scheduler.runAfter(0, markCacheStaleByTopic, {
|
|
723
|
+
topicId: normalizedTopicId
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
const resolvedProjectId = normalizedTopicId ?? normalizedProjectId;
|
|
727
|
+
if (!resolvedProjectId) {
|
|
728
|
+
return;
|
|
767
729
|
}
|
|
768
730
|
await resolveGraphPrimitivesAppResolvers().patchProject(
|
|
769
731
|
ctx,
|
|
770
|
-
|
|
732
|
+
resolvedProjectId,
|
|
771
733
|
{
|
|
772
734
|
lastActivityAt: Date.now()
|
|
773
735
|
}
|
|
@@ -803,12 +765,126 @@ function buildLinkedWorktreeMetadata(linkedWorktreeId) {
|
|
|
803
765
|
linkedWorktreeId
|
|
804
766
|
} : {};
|
|
805
767
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
768
|
+
function normalizeScopeValue2(value) {
|
|
769
|
+
if (typeof value !== "string") {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
const normalized = value.trim();
|
|
773
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
774
|
+
}
|
|
775
|
+
function throwWorkspaceIsolationError(args) {
|
|
776
|
+
const error = new Error(args.message);
|
|
777
|
+
error.status = 409;
|
|
778
|
+
error.code = "INVARIANT_VIOLATION";
|
|
779
|
+
error.invariantCode = args.invariantCode;
|
|
780
|
+
error.suggestion = args.suggestion;
|
|
781
|
+
error.details = args.details;
|
|
782
|
+
throw error;
|
|
783
|
+
}
|
|
784
|
+
function assertWorkspaceScopedEpistemicNodeScope(args) {
|
|
785
|
+
const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
|
|
786
|
+
if (layer === "ontological") {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
|
|
790
|
+
if (workspaceId) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
throwWorkspaceIsolationError({
|
|
794
|
+
message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
|
|
795
|
+
invariantCode: "workspace.scope_required_for_epistemic_nodes",
|
|
796
|
+
suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
|
|
797
|
+
details: {
|
|
798
|
+
mutationName: args.mutationName,
|
|
799
|
+
nodeType: args.nodeType,
|
|
800
|
+
topicId: args.scope.topicId,
|
|
801
|
+
projectId: args.scope.projectId
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
function resolveRuntimePackMutationContext(args) {
|
|
806
|
+
if (!(args.runtimeToolName || args.runtimePackKey || args.runtimePackInstallScope)) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
return {
|
|
810
|
+
toolName: args.runtimeToolName,
|
|
811
|
+
packKey: args.runtimePackKey,
|
|
812
|
+
packInstallScope: args.runtimePackInstallScope
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
function assertTenantPackWorkspaceMutationAllowed(args) {
|
|
816
|
+
if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
|
|
820
|
+
const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
|
|
821
|
+
if (!targetWorkspaceId || targetLayer === "ontological") {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
throwWorkspaceIsolationError({
|
|
825
|
+
message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
|
|
826
|
+
invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
|
|
827
|
+
suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
|
|
828
|
+
details: {
|
|
829
|
+
mutationName: args.mutationName,
|
|
830
|
+
toolName: args.runtime.toolName,
|
|
831
|
+
packKey: args.runtime.packKey,
|
|
832
|
+
targetWorkspaceId,
|
|
833
|
+
targetNodeType: args.target.nodeType,
|
|
834
|
+
targetLayer
|
|
835
|
+
}
|
|
836
|
+
});
|
|
809
837
|
}
|
|
810
838
|
|
|
811
839
|
// src/epistemicQuestions.create.ts
|
|
840
|
+
var EMBEDDING_GENERATION_ACTION = "embeddingActions:generateEpistemicNodeEmbedding";
|
|
841
|
+
function readOptionalString(value) {
|
|
842
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
843
|
+
}
|
|
844
|
+
function readConvexId(value) {
|
|
845
|
+
const normalized = readOptionalString(value);
|
|
846
|
+
return normalized ? normalized : null;
|
|
847
|
+
}
|
|
848
|
+
function readRecord(value) {
|
|
849
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
850
|
+
}
|
|
851
|
+
function readBeliefNodeRow(value) {
|
|
852
|
+
const record = readRecord(value);
|
|
853
|
+
if (!record) {
|
|
854
|
+
return null;
|
|
855
|
+
}
|
|
856
|
+
const id = readConvexId(record._id);
|
|
857
|
+
const globalId = readOptionalString(record.globalId);
|
|
858
|
+
return id && globalId ? { _id: id, globalId } : null;
|
|
859
|
+
}
|
|
860
|
+
async function scheduleTestsEdgeToBelief(ctx, args) {
|
|
861
|
+
const beliefNode = readBeliefNodeRow(await ctx.db.get(args.beliefNodeId));
|
|
862
|
+
if (!beliefNode) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
await ctx.scheduler.runAfter(100, internal.neo4jSync.syncNodeToNeo4j, {
|
|
866
|
+
nodeId: beliefNode._id,
|
|
867
|
+
operation: "upsert"
|
|
868
|
+
});
|
|
869
|
+
const edgeGlobalId = buildTestsEdgeGlobalId(
|
|
870
|
+
args.questionGlobalId,
|
|
871
|
+
beliefNode.globalId
|
|
872
|
+
);
|
|
873
|
+
await ctx.scheduler.runAfter(250, internal.neo4jEdgeAPI.createEdge, {
|
|
874
|
+
globalId: edgeGlobalId,
|
|
875
|
+
fromGlobalId: args.questionGlobalId,
|
|
876
|
+
toGlobalId: beliefNode.globalId,
|
|
877
|
+
edgeType: "tests",
|
|
878
|
+
weight: 1,
|
|
879
|
+
context: args.testType || "tests",
|
|
880
|
+
createdBy: args.createdBy,
|
|
881
|
+
topicId: args.topicId,
|
|
882
|
+
fromNodeType: "question",
|
|
883
|
+
toNodeType: "belief",
|
|
884
|
+
fromLayer: "L3",
|
|
885
|
+
toLayer: "L3"
|
|
886
|
+
});
|
|
887
|
+
}
|
|
812
888
|
var create = mutation({
|
|
813
889
|
args: {
|
|
814
890
|
...optionalScopeArgs,
|
|
@@ -929,31 +1005,13 @@ var create = mutation({
|
|
|
929
1005
|
text: args.question
|
|
930
1006
|
});
|
|
931
1007
|
if (args.linkedBeliefNodeId) {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
beliefNode.globalId,
|
|
940
|
-
globalId
|
|
941
|
-
);
|
|
942
|
-
await ctx.scheduler.runAfter(250, internal.neo4jEdgeAPI.createEdge, {
|
|
943
|
-
globalId: edgeGlobalId,
|
|
944
|
-
fromGlobalId: beliefNode.globalId,
|
|
945
|
-
toGlobalId: globalId,
|
|
946
|
-
edgeType: "tests",
|
|
947
|
-
weight: 1,
|
|
948
|
-
context: args.testType || "tests",
|
|
949
|
-
createdBy: args.userId,
|
|
950
|
-
topicId: scope.projectId ? String(scope.projectId) : void 0,
|
|
951
|
-
fromNodeType: "belief",
|
|
952
|
-
toNodeType: "question",
|
|
953
|
-
fromLayer: "L3",
|
|
954
|
-
toLayer: "L3"
|
|
955
|
-
});
|
|
956
|
-
}
|
|
1008
|
+
await scheduleTestsEdgeToBelief(ctx, {
|
|
1009
|
+
beliefNodeId: args.linkedBeliefNodeId,
|
|
1010
|
+
createdBy: args.userId,
|
|
1011
|
+
questionGlobalId: globalId,
|
|
1012
|
+
testType: args.testType,
|
|
1013
|
+
topicId: normalizeQuestionTopicId(scope.topicId) ?? scope.projectId
|
|
1014
|
+
});
|
|
957
1015
|
}
|
|
958
1016
|
await ctx.db.insert("epistemicAudit", {
|
|
959
1017
|
entityType: "question",
|
|
@@ -970,19 +1028,15 @@ var create = mutation({
|
|
|
970
1028
|
}
|
|
971
1029
|
});
|
|
972
1030
|
if (scope.projectId || scope.topicId) {
|
|
973
|
-
await ctx.scheduler.runAfter(
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
text: args.question,
|
|
983
|
-
hasAnswer: false
|
|
984
|
-
}
|
|
985
|
-
);
|
|
1031
|
+
await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
|
|
1032
|
+
nodeId,
|
|
1033
|
+
projectId: scope.projectId,
|
|
1034
|
+
topicId: scope.topicId ? String(scope.topicId) : void 0,
|
|
1035
|
+
createdBy: args.userId,
|
|
1036
|
+
nodeType: "question",
|
|
1037
|
+
text: args.question,
|
|
1038
|
+
hasAnswer: false
|
|
1039
|
+
});
|
|
986
1040
|
}
|
|
987
1041
|
if (scope.projectId || scope.topicId) {
|
|
988
1042
|
await ctx.scheduler.runAfter(
|
|
@@ -1097,22 +1151,13 @@ var createBatch = mutation({
|
|
|
1097
1151
|
operation: "upsert"
|
|
1098
1152
|
});
|
|
1099
1153
|
if (q.linkedBeliefNodeId) {
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
weight: 1,
|
|
1108
|
-
createdBy: args.userId,
|
|
1109
|
-
topicId: scope.projectId,
|
|
1110
|
-
fromNodeType: "belief",
|
|
1111
|
-
toNodeType: "question",
|
|
1112
|
-
fromLayer: "L3",
|
|
1113
|
-
toLayer: "L3"
|
|
1114
|
-
});
|
|
1115
|
-
}
|
|
1154
|
+
await scheduleTestsEdgeToBelief(ctx, {
|
|
1155
|
+
beliefNodeId: q.linkedBeliefNodeId,
|
|
1156
|
+
createdBy: args.userId,
|
|
1157
|
+
questionGlobalId: globalId,
|
|
1158
|
+
testType: q.testType,
|
|
1159
|
+
topicId: normalizeQuestionTopicId(scope.topicId) ?? scope.projectId
|
|
1160
|
+
});
|
|
1116
1161
|
}
|
|
1117
1162
|
}
|
|
1118
1163
|
await markProjectGraphDirty(
|
|
@@ -1193,37 +1238,24 @@ var internalCreate = internalMutation({
|
|
|
1193
1238
|
operation: "upsert"
|
|
1194
1239
|
});
|
|
1195
1240
|
if (args.linkedBeliefNodeId) {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
weight: 1,
|
|
1204
|
-
createdBy: args.userId,
|
|
1205
|
-
topicId: scope.projectId ? String(scope.projectId) : void 0,
|
|
1206
|
-
fromNodeType: "belief",
|
|
1207
|
-
toNodeType: "question",
|
|
1208
|
-
fromLayer: "L3",
|
|
1209
|
-
toLayer: "L3"
|
|
1210
|
-
});
|
|
1211
|
-
}
|
|
1241
|
+
await scheduleTestsEdgeToBelief(ctx, {
|
|
1242
|
+
beliefNodeId: args.linkedBeliefNodeId,
|
|
1243
|
+
createdBy: args.userId,
|
|
1244
|
+
questionGlobalId: globalId,
|
|
1245
|
+
testType: args.testType,
|
|
1246
|
+
topicId: normalizeQuestionTopicId(scope.topicId) ?? scope.projectId
|
|
1247
|
+
});
|
|
1212
1248
|
}
|
|
1213
1249
|
if (scope.projectId || scope.topicId) {
|
|
1214
|
-
await ctx.scheduler.runAfter(
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
text: args.question,
|
|
1224
|
-
hasAnswer: false
|
|
1225
|
-
}
|
|
1226
|
-
);
|
|
1250
|
+
await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
|
|
1251
|
+
nodeId,
|
|
1252
|
+
projectId: scope.projectId,
|
|
1253
|
+
topicId: scope.topicId ? String(scope.topicId) : void 0,
|
|
1254
|
+
createdBy: args.userId,
|
|
1255
|
+
nodeType: "question",
|
|
1256
|
+
text: args.question,
|
|
1257
|
+
hasAnswer: false
|
|
1258
|
+
});
|
|
1227
1259
|
}
|
|
1228
1260
|
await markProjectGraphDirty(
|
|
1229
1261
|
ctx,
|
|
@@ -1266,7 +1298,7 @@ var addQuestion = mutation({
|
|
|
1266
1298
|
const globalId = generateGlobalId();
|
|
1267
1299
|
const contentHash = generateContentHash(args.question);
|
|
1268
1300
|
const category = normalizeCategory(args.category);
|
|
1269
|
-
const additionalMetadata = args.metadata
|
|
1301
|
+
const additionalMetadata = readRecord(args.metadata) ?? {};
|
|
1270
1302
|
const nodeId = await insertEpistemicNode(ctx, {
|
|
1271
1303
|
globalId,
|
|
1272
1304
|
topicId: scope.topicId,
|
|
@@ -1321,19 +1353,15 @@ var addQuestion = mutation({
|
|
|
1321
1353
|
nodeId,
|
|
1322
1354
|
operation: "upsert"
|
|
1323
1355
|
});
|
|
1324
|
-
await ctx.scheduler.runAfter(
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
text: args.question,
|
|
1334
|
-
hasAnswer: false
|
|
1335
|
-
}
|
|
1336
|
-
);
|
|
1356
|
+
await ctx.scheduler.runAfter(0, EMBEDDING_GENERATION_ACTION, {
|
|
1357
|
+
nodeId,
|
|
1358
|
+
projectId: scope.projectId,
|
|
1359
|
+
topicId: normalizeQuestionTopicId(scope.topicId),
|
|
1360
|
+
createdBy: args.userId,
|
|
1361
|
+
nodeType: "question",
|
|
1362
|
+
text: args.question,
|
|
1363
|
+
hasAnswer: false
|
|
1364
|
+
});
|
|
1337
1365
|
await markProjectGraphDirty(
|
|
1338
1366
|
ctx,
|
|
1339
1367
|
scope.projectId,
|