@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,9 +1,592 @@
|
|
|
1
|
-
import { v } from 'convex/values';
|
|
2
1
|
import { requireScopeWriteAccess } 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 } from 'convex/server';
|
|
5
6
|
|
|
6
7
|
// src/epistemicEdges.mutations.ts
|
|
8
|
+
var unsafeApi = unsafeConvexAnyApi(
|
|
9
|
+
"graph-primitives top-level module bundle lacks a committed Convex _generated/api surface"
|
|
10
|
+
);
|
|
11
|
+
var api = unsafeApi;
|
|
12
|
+
componentsGeneric();
|
|
13
|
+
var internal = unsafeApi;
|
|
14
|
+
var mutation = mutationGeneric;
|
|
15
|
+
|
|
16
|
+
// src/graphTypes.ts
|
|
17
|
+
var EDGE_TYPE_TO_REL = {
|
|
18
|
+
// === THE SIX CANONICAL EPISTEMIC EDGE TYPES ===
|
|
19
|
+
supports: "SUPPORTS",
|
|
20
|
+
// L3↔L3: belief bears on belief (weight -1 to +1)
|
|
21
|
+
informs: "INFORMS",
|
|
22
|
+
// L2→L3: evidence bears on belief
|
|
23
|
+
depends_on: "DEPENDS_ON",
|
|
24
|
+
// L3→L3, Q→Q: structural gate
|
|
25
|
+
derived_from: "DERIVED_FROM",
|
|
26
|
+
// Any→Any: provenance chain (fork, synthesis, extraction, answer)
|
|
27
|
+
contains: "CONTAINS",
|
|
28
|
+
// Any→Any: hierarchy, scoping, membership
|
|
29
|
+
tests: "TESTS",
|
|
30
|
+
// Q→L3: question interrogates belief
|
|
31
|
+
// === L4 DECISION EDGES (derived_from with derivationType=decision) ===
|
|
32
|
+
// Kept as separate Neo4j relationship types for backward compat with L4 queries.
|
|
33
|
+
// New code should use derived_from + metadata.
|
|
34
|
+
based_on_belief: "BASED_ON_BELIEF",
|
|
35
|
+
based_on_question: "BASED_ON_QUESTION",
|
|
36
|
+
blocked_by_contradiction: "BLOCKED_BY_CONTRADICTION",
|
|
37
|
+
informed_by_theme: "INFORMED_BY_THEME",
|
|
38
|
+
// === ONTOLOGICAL EDGES (tenant-extensible, managed by ontology system) ===
|
|
39
|
+
works_at: "WORKS_AT",
|
|
40
|
+
invested_in: "INVESTED_IN",
|
|
41
|
+
competes_with: "COMPETES_WITH",
|
|
42
|
+
participates_in: "PARTICIPATES_IN",
|
|
43
|
+
founded_by: "FOUNDED_BY",
|
|
44
|
+
evaluates: "EVALUATES",
|
|
45
|
+
performs: "PERFORMS",
|
|
46
|
+
function_in: "FUNCTION_IN",
|
|
47
|
+
impacts: "IMPACTS",
|
|
48
|
+
raised_from: "RAISED_FROM",
|
|
49
|
+
mentioned_in: "MENTIONED_IN",
|
|
50
|
+
perspective_on: "PERSPECTIVE_ON",
|
|
51
|
+
about_entity: "ABOUT_ENTITY",
|
|
52
|
+
entity_referenced_in: "ENTITY_REFERENCED_IN"
|
|
53
|
+
};
|
|
54
|
+
function getNodeLayer(nodeType) {
|
|
55
|
+
const L4_TYPES = ["decision"];
|
|
56
|
+
const L3_TYPES = ["belief", "question", "theme", "deal"];
|
|
57
|
+
const L2_TYPES = ["claim", "evidence", "synthesis", "answer"];
|
|
58
|
+
const L1_TYPES = ["atomic_fact", "excerpt", "source"];
|
|
59
|
+
const ONTOLOGICAL_TYPES = [
|
|
60
|
+
"company",
|
|
61
|
+
"person",
|
|
62
|
+
"investor",
|
|
63
|
+
"function",
|
|
64
|
+
"value_chain"
|
|
65
|
+
];
|
|
66
|
+
const ORGANIZATIONAL_TYPES = ["topic"];
|
|
67
|
+
if (L4_TYPES.includes(nodeType)) {
|
|
68
|
+
return "L4";
|
|
69
|
+
}
|
|
70
|
+
if (L3_TYPES.includes(nodeType)) {
|
|
71
|
+
return "L3";
|
|
72
|
+
}
|
|
73
|
+
if (L2_TYPES.includes(nodeType)) {
|
|
74
|
+
return "L2";
|
|
75
|
+
}
|
|
76
|
+
if (L1_TYPES.includes(nodeType)) {
|
|
77
|
+
return "L1";
|
|
78
|
+
}
|
|
79
|
+
if (ONTOLOGICAL_TYPES.includes(nodeType)) {
|
|
80
|
+
return "ontological";
|
|
81
|
+
}
|
|
82
|
+
if (ORGANIZATIONAL_TYPES.includes(nodeType)) {
|
|
83
|
+
return "organizational";
|
|
84
|
+
}
|
|
85
|
+
console.warn(`[GraphTypes] Unknown nodeType "${nodeType}", defaulting to L2`);
|
|
86
|
+
return "L2";
|
|
87
|
+
}
|
|
88
|
+
var CANONICAL_EPISTEMIC_TYPES = /* @__PURE__ */ new Set([
|
|
89
|
+
"supports",
|
|
90
|
+
"informs",
|
|
91
|
+
"depends_on",
|
|
92
|
+
"derived_from",
|
|
93
|
+
"contains",
|
|
94
|
+
"tests"
|
|
95
|
+
]);
|
|
96
|
+
function isDeprecatedEdgeType(edgeType) {
|
|
97
|
+
if (CANONICAL_EPISTEMIC_TYPES.has(edgeType)) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
if (edgeType in EDGE_TYPE_TO_REL) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/edgeValidation.ts
|
|
107
|
+
var VALID_LAYER_CONNECTIONS = {
|
|
108
|
+
ontological: /* @__PURE__ */ new Set(["ontological", "L1", "L2", "L3"]),
|
|
109
|
+
L1: /* @__PURE__ */ new Set(["L1", "L2"]),
|
|
110
|
+
L2: /* @__PURE__ */ new Set(["L1", "L2", "L3", "ontological"]),
|
|
111
|
+
L3: /* @__PURE__ */ new Set(["L2", "L3", "L4", "ontological", "organizational"]),
|
|
112
|
+
L4: /* @__PURE__ */ new Set(["L3", "L4"]),
|
|
113
|
+
organizational: /* @__PURE__ */ new Set(["organizational", "L3"])
|
|
114
|
+
};
|
|
115
|
+
function getLayerDepth(layer) {
|
|
116
|
+
switch (layer) {
|
|
117
|
+
case "L4":
|
|
118
|
+
return 4;
|
|
119
|
+
case "L3":
|
|
120
|
+
return 3;
|
|
121
|
+
case "L2":
|
|
122
|
+
return 2;
|
|
123
|
+
case "L1":
|
|
124
|
+
return 1;
|
|
125
|
+
case "ontological":
|
|
126
|
+
return 0;
|
|
127
|
+
default:
|
|
128
|
+
return -1;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function isValidLayerConnection(fromLayer, toLayer) {
|
|
132
|
+
if (!VALID_LAYER_CONNECTIONS[fromLayer].has(toLayer)) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
if (fromLayer === "ontological" || toLayer === "ontological") {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
if (fromLayer === "organizational" || toLayer === "organizational") {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
const fromDepth = getLayerDepth(fromLayer);
|
|
142
|
+
const toDepth = getLayerDepth(toLayer);
|
|
143
|
+
if (Math.abs(fromDepth - toDepth) > 1) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
var EDGE_LAYER_RULES = {
|
|
149
|
+
// === 6 Canonical Epistemic Types ===
|
|
150
|
+
supports: {
|
|
151
|
+
from: ["L3"],
|
|
152
|
+
to: ["L3"],
|
|
153
|
+
description: "Belief bears on Belief (weight: +1 supports, -1 contradicts)"
|
|
154
|
+
},
|
|
155
|
+
informs: {
|
|
156
|
+
from: ["L2"],
|
|
157
|
+
to: ["L3"],
|
|
158
|
+
description: "Evidence -> Belief (L2 -> L3)"
|
|
159
|
+
},
|
|
160
|
+
depends_on: {
|
|
161
|
+
from: ["L3"],
|
|
162
|
+
to: ["L3"],
|
|
163
|
+
description: "Belief B requires Belief A (structural gate)"
|
|
164
|
+
},
|
|
165
|
+
derived_from: {
|
|
166
|
+
from: ["L2", "L3", "L4"],
|
|
167
|
+
to: ["L1", "L2", "L3"],
|
|
168
|
+
description: "A was produced from B (provenance chain)"
|
|
169
|
+
},
|
|
170
|
+
contains: {
|
|
171
|
+
from: ["L3", "L4", "ontological"],
|
|
172
|
+
to: ["L2", "L3", "ontological"],
|
|
173
|
+
description: "A scopes/aggregates B (hierarchy)"
|
|
174
|
+
},
|
|
175
|
+
tests: {
|
|
176
|
+
from: ["L3"],
|
|
177
|
+
to: ["L3"],
|
|
178
|
+
description: "Question -> Belief (L3 -> L3)"
|
|
179
|
+
},
|
|
180
|
+
// === Structural / Lifecycle ===
|
|
181
|
+
supersedes: {
|
|
182
|
+
from: ["L3"],
|
|
183
|
+
to: ["L3"],
|
|
184
|
+
description: "NewNode -> OldNode (fork lineage)"
|
|
185
|
+
},
|
|
186
|
+
responds_to: {
|
|
187
|
+
from: ["L2", "L3"],
|
|
188
|
+
to: ["L3"],
|
|
189
|
+
description: "Answer -> Question (L2/L3 -> L3)"
|
|
190
|
+
},
|
|
191
|
+
belongs_to: {
|
|
192
|
+
from: ["L2", "L3", "ontological"],
|
|
193
|
+
to: ["L3"],
|
|
194
|
+
description: "Membership (migrating to contains)"
|
|
195
|
+
},
|
|
196
|
+
relates_to_thesis: {
|
|
197
|
+
from: ["L3"],
|
|
198
|
+
to: ["L3"],
|
|
199
|
+
description: "Belief -> Theme (L3 -> L3)"
|
|
200
|
+
},
|
|
201
|
+
// === Ontological (entity-entity or entity-epistemic bridge) ===
|
|
202
|
+
works_at: {
|
|
203
|
+
from: ["ontological"],
|
|
204
|
+
to: ["ontological"],
|
|
205
|
+
description: "Person -> Company"
|
|
206
|
+
},
|
|
207
|
+
invested_in: {
|
|
208
|
+
from: ["ontological"],
|
|
209
|
+
to: ["ontological"],
|
|
210
|
+
description: "Investor -> Company"
|
|
211
|
+
},
|
|
212
|
+
competes_with: {
|
|
213
|
+
from: ["ontological"],
|
|
214
|
+
to: ["ontological"],
|
|
215
|
+
description: "Company -> Company"
|
|
216
|
+
},
|
|
217
|
+
participates_in: {
|
|
218
|
+
from: ["ontological"],
|
|
219
|
+
to: ["ontological"],
|
|
220
|
+
description: "Company -> ValueChain"
|
|
221
|
+
},
|
|
222
|
+
founded_by: {
|
|
223
|
+
from: ["ontological"],
|
|
224
|
+
to: ["ontological"],
|
|
225
|
+
description: "Company -> Person"
|
|
226
|
+
},
|
|
227
|
+
evaluates: {
|
|
228
|
+
from: ["ontological"],
|
|
229
|
+
to: ["ontological"],
|
|
230
|
+
description: "Deal -> Company"
|
|
231
|
+
},
|
|
232
|
+
performs: {
|
|
233
|
+
from: ["ontological"],
|
|
234
|
+
to: ["ontological"],
|
|
235
|
+
description: "Company -> Function"
|
|
236
|
+
},
|
|
237
|
+
function_in: {
|
|
238
|
+
from: ["ontological"],
|
|
239
|
+
to: ["ontological"],
|
|
240
|
+
description: "Function -> ValueChain"
|
|
241
|
+
},
|
|
242
|
+
impacts: {
|
|
243
|
+
from: ["ontological", "L3"],
|
|
244
|
+
to: ["ontological"],
|
|
245
|
+
description: "Theme/Entity -> ValueChain"
|
|
246
|
+
},
|
|
247
|
+
raised_from: {
|
|
248
|
+
from: ["ontological"],
|
|
249
|
+
to: ["ontological"],
|
|
250
|
+
description: "Company -> Investor"
|
|
251
|
+
},
|
|
252
|
+
mentioned_in: {
|
|
253
|
+
from: ["ontological"],
|
|
254
|
+
to: ["L1", "L2"],
|
|
255
|
+
description: "Entity -> Source/Evidence"
|
|
256
|
+
},
|
|
257
|
+
perspective_on: {
|
|
258
|
+
from: ["ontological"],
|
|
259
|
+
to: ["L3"],
|
|
260
|
+
description: "Person -> Belief/Theme"
|
|
261
|
+
},
|
|
262
|
+
plays_theme: {
|
|
263
|
+
from: ["ontological"],
|
|
264
|
+
to: ["L3"],
|
|
265
|
+
description: "Deal -> Theme"
|
|
266
|
+
},
|
|
267
|
+
// C2-RR.4 — storage migration alias + the remaining 55 reachable edge types.
|
|
268
|
+
// Mirrors the kernel rule table
|
|
269
|
+
// (packages/reasoning-kernel/src/adapters/lib/edgeValidation.ts) so this
|
|
270
|
+
// graph-primitives write path admits the same public edge vocabulary. See the
|
|
271
|
+
// kernel file for the per-group rationale.
|
|
272
|
+
extracted_from: {
|
|
273
|
+
from: ["L2", "L3", "L4"],
|
|
274
|
+
to: ["L1", "L2", "L3"],
|
|
275
|
+
description: "Legacy storage migration alias for derived_from; public writes use derived_from"
|
|
276
|
+
},
|
|
277
|
+
qualifies: {
|
|
278
|
+
from: ["L2", "L3"],
|
|
279
|
+
to: ["L3"],
|
|
280
|
+
description: "Evidence/Belief qualifies a Belief"
|
|
281
|
+
},
|
|
282
|
+
contradicts: {
|
|
283
|
+
from: ["L2", "L3"],
|
|
284
|
+
to: ["L3"],
|
|
285
|
+
description: "Evidence/Belief contradicts a Belief"
|
|
286
|
+
},
|
|
287
|
+
reinforces: {
|
|
288
|
+
from: ["L2", "L3"],
|
|
289
|
+
to: ["L3"],
|
|
290
|
+
description: "Evidence/Belief reinforces a Belief"
|
|
291
|
+
},
|
|
292
|
+
corroborates: {
|
|
293
|
+
from: ["L2", "L3"],
|
|
294
|
+
to: ["L3"],
|
|
295
|
+
description: "Independent evidence/belief corroborates a Belief"
|
|
296
|
+
},
|
|
297
|
+
strengthened_by: {
|
|
298
|
+
from: ["L3"],
|
|
299
|
+
to: ["L2", "L3"],
|
|
300
|
+
description: "Belief is strengthened by Evidence/Belief"
|
|
301
|
+
},
|
|
302
|
+
weakened_by: {
|
|
303
|
+
from: ["L3"],
|
|
304
|
+
to: ["L2", "L3"],
|
|
305
|
+
description: "Belief is weakened by Evidence/Belief"
|
|
306
|
+
},
|
|
307
|
+
validated_by: {
|
|
308
|
+
from: ["L3"],
|
|
309
|
+
to: ["L2", "L3"],
|
|
310
|
+
description: "Belief is validated by Evidence/Belief"
|
|
311
|
+
},
|
|
312
|
+
falsified_by: {
|
|
313
|
+
from: ["L3"],
|
|
314
|
+
to: ["L2", "L3"],
|
|
315
|
+
description: "Belief is falsified by Evidence/Belief"
|
|
316
|
+
},
|
|
317
|
+
amplifies: {
|
|
318
|
+
from: ["L3"],
|
|
319
|
+
to: ["L3"],
|
|
320
|
+
description: "Belief amplifies another Belief"
|
|
321
|
+
},
|
|
322
|
+
precondition_for: {
|
|
323
|
+
from: ["L3"],
|
|
324
|
+
to: ["L3"],
|
|
325
|
+
description: "Belief is a precondition for another Belief"
|
|
326
|
+
},
|
|
327
|
+
prerequisite_for: {
|
|
328
|
+
from: ["L3"],
|
|
329
|
+
to: ["L3"],
|
|
330
|
+
description: "Belief is a prerequisite for another Belief"
|
|
331
|
+
},
|
|
332
|
+
required_for: {
|
|
333
|
+
from: ["L3"],
|
|
334
|
+
to: ["L3"],
|
|
335
|
+
description: "Belief is required for another Belief"
|
|
336
|
+
},
|
|
337
|
+
in_tension_with: {
|
|
338
|
+
from: ["L3"],
|
|
339
|
+
to: ["L3"],
|
|
340
|
+
description: "Belief is in tension with another Belief"
|
|
341
|
+
},
|
|
342
|
+
mutually_exclusive: {
|
|
343
|
+
from: ["L3"],
|
|
344
|
+
to: ["L3"],
|
|
345
|
+
description: "Beliefs cannot both hold"
|
|
346
|
+
},
|
|
347
|
+
exclusive_with: {
|
|
348
|
+
from: ["L3"],
|
|
349
|
+
to: ["L3"],
|
|
350
|
+
description: "Belief is exclusive with another Belief"
|
|
351
|
+
},
|
|
352
|
+
alternative_to: {
|
|
353
|
+
from: ["L3"],
|
|
354
|
+
to: ["L3"],
|
|
355
|
+
description: "Belief is an alternative to another Belief"
|
|
356
|
+
},
|
|
357
|
+
subsumes: {
|
|
358
|
+
from: ["L3"],
|
|
359
|
+
to: ["L3"],
|
|
360
|
+
description: "Belief subsumes a narrower Belief"
|
|
361
|
+
},
|
|
362
|
+
extends: {
|
|
363
|
+
from: ["L3"],
|
|
364
|
+
to: ["L3"],
|
|
365
|
+
description: "Belief extends another Belief"
|
|
366
|
+
},
|
|
367
|
+
refines: {
|
|
368
|
+
from: ["L3"],
|
|
369
|
+
to: ["L3"],
|
|
370
|
+
description: "Belief refines another Belief"
|
|
371
|
+
},
|
|
372
|
+
implements: {
|
|
373
|
+
from: ["L3"],
|
|
374
|
+
to: ["L3"],
|
|
375
|
+
description: "Belief implements an abstract Belief"
|
|
376
|
+
},
|
|
377
|
+
violates: {
|
|
378
|
+
from: ["L3"],
|
|
379
|
+
to: ["L3"],
|
|
380
|
+
description: "Belief violates a constraint Belief"
|
|
381
|
+
},
|
|
382
|
+
assumes: {
|
|
383
|
+
from: ["L3"],
|
|
384
|
+
to: ["L3"],
|
|
385
|
+
description: "Belief assumes another Belief"
|
|
386
|
+
},
|
|
387
|
+
would_predict: {
|
|
388
|
+
from: ["L3"],
|
|
389
|
+
to: ["L3"],
|
|
390
|
+
description: "Belief would predict another Belief"
|
|
391
|
+
},
|
|
392
|
+
analogous_to: {
|
|
393
|
+
from: ["L3"],
|
|
394
|
+
to: ["L3"],
|
|
395
|
+
description: "Belief is analogous to another Belief"
|
|
396
|
+
},
|
|
397
|
+
independent_of: {
|
|
398
|
+
from: ["L3"],
|
|
399
|
+
to: ["L3"],
|
|
400
|
+
description: "Belief is independent of another Belief"
|
|
401
|
+
},
|
|
402
|
+
correlates_with: {
|
|
403
|
+
from: ["L3"],
|
|
404
|
+
to: ["L3"],
|
|
405
|
+
description: "Belief correlates with another Belief"
|
|
406
|
+
},
|
|
407
|
+
co_changes_with: {
|
|
408
|
+
from: ["L3"],
|
|
409
|
+
to: ["L3"],
|
|
410
|
+
description: "Belief co-changes with another Belief"
|
|
411
|
+
},
|
|
412
|
+
counterfactual_of: {
|
|
413
|
+
from: ["L3"],
|
|
414
|
+
to: ["L3"],
|
|
415
|
+
description: "Belief is a counterfactual of another Belief"
|
|
416
|
+
},
|
|
417
|
+
parallel_to: {
|
|
418
|
+
from: ["L3"],
|
|
419
|
+
to: ["L3"],
|
|
420
|
+
description: "Belief runs parallel to another Belief"
|
|
421
|
+
},
|
|
422
|
+
cascade_from: {
|
|
423
|
+
from: ["L3"],
|
|
424
|
+
to: ["L3"],
|
|
425
|
+
description: "Cascade from an upstream Belief"
|
|
426
|
+
},
|
|
427
|
+
cascade_to: {
|
|
428
|
+
from: ["L3"],
|
|
429
|
+
to: ["L3"],
|
|
430
|
+
description: "Cascade to a downstream Belief"
|
|
431
|
+
},
|
|
432
|
+
collapses_if: {
|
|
433
|
+
from: ["L3"],
|
|
434
|
+
to: ["L3"],
|
|
435
|
+
description: "Belief collapses if another fails"
|
|
436
|
+
},
|
|
437
|
+
branches_from: {
|
|
438
|
+
from: ["L3"],
|
|
439
|
+
to: ["L3"],
|
|
440
|
+
description: "Belief branches from an ancestor Belief"
|
|
441
|
+
},
|
|
442
|
+
same_as: {
|
|
443
|
+
from: ["L2", "L3", "ontological"],
|
|
444
|
+
to: ["L2", "L3", "ontological"],
|
|
445
|
+
description: "Two nodes are the same entity"
|
|
446
|
+
},
|
|
447
|
+
answers: {
|
|
448
|
+
from: ["L2", "L3"],
|
|
449
|
+
to: ["L3"],
|
|
450
|
+
description: "Answer/Belief answers a Question"
|
|
451
|
+
},
|
|
452
|
+
partially_answers: {
|
|
453
|
+
from: ["L2", "L3"],
|
|
454
|
+
to: ["L3"],
|
|
455
|
+
description: "Answer/Belief partially answers a Question"
|
|
456
|
+
},
|
|
457
|
+
explores: {
|
|
458
|
+
from: ["L3"],
|
|
459
|
+
to: ["L3"],
|
|
460
|
+
description: "Question explores a Belief/Theme"
|
|
461
|
+
},
|
|
462
|
+
informed_by_theme: {
|
|
463
|
+
from: ["L3"],
|
|
464
|
+
to: ["L3"],
|
|
465
|
+
description: "Belief is informed by a Theme"
|
|
466
|
+
},
|
|
467
|
+
same_theme_as: {
|
|
468
|
+
from: ["L3"],
|
|
469
|
+
to: ["L3"],
|
|
470
|
+
description: "Two Beliefs share a Theme"
|
|
471
|
+
},
|
|
472
|
+
based_on: {
|
|
473
|
+
from: ["L4"],
|
|
474
|
+
to: ["L3"],
|
|
475
|
+
description: "Decision is based on a Belief/Question"
|
|
476
|
+
},
|
|
477
|
+
based_on_belief: {
|
|
478
|
+
from: ["L4"],
|
|
479
|
+
to: ["L3"],
|
|
480
|
+
description: "Decision is based on a Belief"
|
|
481
|
+
},
|
|
482
|
+
based_on_question: {
|
|
483
|
+
from: ["L4"],
|
|
484
|
+
to: ["L3"],
|
|
485
|
+
description: "Decision is based on a Question"
|
|
486
|
+
},
|
|
487
|
+
blocked_by_contradiction: {
|
|
488
|
+
from: ["L4"],
|
|
489
|
+
to: ["L3"],
|
|
490
|
+
description: "Decision is blocked by a Contradiction"
|
|
491
|
+
},
|
|
492
|
+
parent_of: {
|
|
493
|
+
from: ["L3", "L4", "ontological", "organizational"],
|
|
494
|
+
to: ["L2", "L3", "ontological", "organizational"],
|
|
495
|
+
description: "A is the parent of B"
|
|
496
|
+
},
|
|
497
|
+
child_of: {
|
|
498
|
+
from: ["L2", "L3", "ontological", "organizational"],
|
|
499
|
+
to: ["L3", "L4", "ontological", "organizational"],
|
|
500
|
+
description: "A is the child of B"
|
|
501
|
+
},
|
|
502
|
+
scoped_by: {
|
|
503
|
+
from: ["L2", "L3"],
|
|
504
|
+
to: ["L3", "organizational"],
|
|
505
|
+
description: "Object is scoped by a Topic/Theme"
|
|
506
|
+
},
|
|
507
|
+
cites: {
|
|
508
|
+
from: ["L2", "L3"],
|
|
509
|
+
to: ["L1", "L2"],
|
|
510
|
+
description: "Evidence/Belief cites a Source/Excerpt"
|
|
511
|
+
},
|
|
512
|
+
summarizes: {
|
|
513
|
+
from: ["L2", "L3"],
|
|
514
|
+
to: ["L1", "L2"],
|
|
515
|
+
description: "Synthesis/Evidence summarizes a Source/Evidence"
|
|
516
|
+
},
|
|
517
|
+
same_source_as: {
|
|
518
|
+
from: ["L1", "L2"],
|
|
519
|
+
to: ["L1", "L2"],
|
|
520
|
+
description: "Two nodes derive from the same Source"
|
|
521
|
+
},
|
|
522
|
+
migrating_from: {
|
|
523
|
+
from: ["L2", "L3", "L4"],
|
|
524
|
+
to: ["L1", "L2", "L3"],
|
|
525
|
+
description: "Migration lineage: from an ancestor"
|
|
526
|
+
},
|
|
527
|
+
migrating_to: {
|
|
528
|
+
from: ["L1", "L2", "L3"],
|
|
529
|
+
to: ["L2", "L3", "L4"],
|
|
530
|
+
description: "Migration lineage: to a successor"
|
|
531
|
+
},
|
|
532
|
+
about_entity: {
|
|
533
|
+
from: ["L2", "L3"],
|
|
534
|
+
to: ["ontological"],
|
|
535
|
+
description: "Belief/Evidence is about an Entity"
|
|
536
|
+
},
|
|
537
|
+
entity_referenced_in: {
|
|
538
|
+
from: ["ontological"],
|
|
539
|
+
to: ["L1", "L2"],
|
|
540
|
+
description: "Entity is referenced in a Source/Evidence"
|
|
541
|
+
},
|
|
542
|
+
related_to: {
|
|
543
|
+
from: ["L2", "L3", "ontological", "organizational"],
|
|
544
|
+
to: ["L2", "L3", "ontological", "organizational"],
|
|
545
|
+
description: "Lateral adjacency; no confidence pressure"
|
|
546
|
+
},
|
|
547
|
+
blocks: {
|
|
548
|
+
from: ["L3", "L4"],
|
|
549
|
+
to: ["L3", "L4"],
|
|
550
|
+
description: "A blocks B (structural gate)"
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
function validateEdgeLayers(edgeType, fromLayer, toLayer) {
|
|
554
|
+
const rules = EDGE_LAYER_RULES[edgeType];
|
|
555
|
+
if (!rules) {
|
|
556
|
+
console.warn(
|
|
557
|
+
`[EdgeValidation] Unknown edge type: ${edgeType}, allowing by default`
|
|
558
|
+
);
|
|
559
|
+
return { valid: true };
|
|
560
|
+
}
|
|
561
|
+
if (edgeType === "supersedes") {
|
|
562
|
+
if (fromLayer !== toLayer) {
|
|
563
|
+
return {
|
|
564
|
+
valid: false,
|
|
565
|
+
reason: `${edgeType} edges must be between nodes of the same layer. Got ${fromLayer} -> ${toLayer}`
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
return { valid: true };
|
|
569
|
+
}
|
|
570
|
+
if (!rules.from.includes(fromLayer)) {
|
|
571
|
+
return {
|
|
572
|
+
valid: false,
|
|
573
|
+
reason: `Edge type '${edgeType}' does not allow source layer ${fromLayer}. Allowed: ${rules.from.join(", ")}`
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
if (!rules.to.includes(toLayer)) {
|
|
577
|
+
return {
|
|
578
|
+
valid: false,
|
|
579
|
+
reason: `Edge type '${edgeType}' does not allow target layer ${toLayer}. Allowed: ${rules.to.join(", ")}`
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
if (!isValidLayerConnection(fromLayer, toLayer)) {
|
|
583
|
+
return {
|
|
584
|
+
valid: false,
|
|
585
|
+
reason: `Layer transition ${fromLayer} -> ${toLayer} is not permitted`
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
return { valid: true };
|
|
589
|
+
}
|
|
7
590
|
v.union(
|
|
8
591
|
v.literal("L4"),
|
|
9
592
|
v.literal("L3"),
|
|
@@ -107,96 +690,6 @@ function buildEdgeNotFoundResult() {
|
|
|
107
690
|
return result;
|
|
108
691
|
}
|
|
109
692
|
|
|
110
|
-
// src/graphTypes.ts
|
|
111
|
-
var EDGE_TYPE_TO_REL = {
|
|
112
|
-
// === THE SIX CANONICAL EPISTEMIC EDGE TYPES ===
|
|
113
|
-
supports: "SUPPORTS",
|
|
114
|
-
// L3↔L3: belief bears on belief (weight -1 to +1)
|
|
115
|
-
informs: "INFORMS",
|
|
116
|
-
// L2→L3: evidence bears on belief
|
|
117
|
-
depends_on: "DEPENDS_ON",
|
|
118
|
-
// L3→L3, Q→Q: structural gate
|
|
119
|
-
derived_from: "DERIVED_FROM",
|
|
120
|
-
// Any→Any: provenance chain (fork, synthesis, extraction, answer)
|
|
121
|
-
contains: "CONTAINS",
|
|
122
|
-
// Any→Any: hierarchy, scoping, membership
|
|
123
|
-
tests: "TESTS",
|
|
124
|
-
// Q→L3: question interrogates belief
|
|
125
|
-
// === L4 DECISION EDGES (derived_from with derivationType=decision) ===
|
|
126
|
-
// Kept as separate Neo4j relationship types for backward compat with L4 queries.
|
|
127
|
-
// New code should use derived_from + metadata.
|
|
128
|
-
based_on_belief: "BASED_ON_BELIEF",
|
|
129
|
-
based_on_question: "BASED_ON_QUESTION",
|
|
130
|
-
blocked_by_contradiction: "BLOCKED_BY_CONTRADICTION",
|
|
131
|
-
informed_by_theme: "INFORMED_BY_THEME",
|
|
132
|
-
// === ONTOLOGICAL EDGES (tenant-extensible, managed by ontology system) ===
|
|
133
|
-
works_at: "WORKS_AT",
|
|
134
|
-
invested_in: "INVESTED_IN",
|
|
135
|
-
competes_with: "COMPETES_WITH",
|
|
136
|
-
participates_in: "PARTICIPATES_IN",
|
|
137
|
-
founded_by: "FOUNDED_BY",
|
|
138
|
-
evaluates: "EVALUATES",
|
|
139
|
-
performs: "PERFORMS",
|
|
140
|
-
function_in: "FUNCTION_IN",
|
|
141
|
-
impacts: "IMPACTS",
|
|
142
|
-
raised_from: "RAISED_FROM",
|
|
143
|
-
mentioned_in: "MENTIONED_IN",
|
|
144
|
-
perspective_on: "PERSPECTIVE_ON",
|
|
145
|
-
about_entity: "ABOUT_ENTITY",
|
|
146
|
-
entity_referenced_in: "ENTITY_REFERENCED_IN"
|
|
147
|
-
};
|
|
148
|
-
function getNodeLayer(nodeType) {
|
|
149
|
-
const L4_TYPES = ["decision"];
|
|
150
|
-
const L3_TYPES = ["belief", "question", "theme", "deal"];
|
|
151
|
-
const L2_TYPES = ["claim", "evidence", "synthesis", "answer"];
|
|
152
|
-
const L1_TYPES = ["atomic_fact", "excerpt", "source"];
|
|
153
|
-
const ONTOLOGICAL_TYPES = [
|
|
154
|
-
"company",
|
|
155
|
-
"person",
|
|
156
|
-
"investor",
|
|
157
|
-
"function",
|
|
158
|
-
"value_chain"
|
|
159
|
-
];
|
|
160
|
-
const ORGANIZATIONAL_TYPES = ["topic"];
|
|
161
|
-
if (L4_TYPES.includes(nodeType)) {
|
|
162
|
-
return "L4";
|
|
163
|
-
}
|
|
164
|
-
if (L3_TYPES.includes(nodeType)) {
|
|
165
|
-
return "L3";
|
|
166
|
-
}
|
|
167
|
-
if (L2_TYPES.includes(nodeType)) {
|
|
168
|
-
return "L2";
|
|
169
|
-
}
|
|
170
|
-
if (L1_TYPES.includes(nodeType)) {
|
|
171
|
-
return "L1";
|
|
172
|
-
}
|
|
173
|
-
if (ONTOLOGICAL_TYPES.includes(nodeType)) {
|
|
174
|
-
return "ontological";
|
|
175
|
-
}
|
|
176
|
-
if (ORGANIZATIONAL_TYPES.includes(nodeType)) {
|
|
177
|
-
return "organizational";
|
|
178
|
-
}
|
|
179
|
-
console.warn(`[GraphTypes] Unknown nodeType "${nodeType}", defaulting to L2`);
|
|
180
|
-
return "L2";
|
|
181
|
-
}
|
|
182
|
-
var CANONICAL_EPISTEMIC_TYPES = /* @__PURE__ */ new Set([
|
|
183
|
-
"supports",
|
|
184
|
-
"informs",
|
|
185
|
-
"depends_on",
|
|
186
|
-
"derived_from",
|
|
187
|
-
"contains",
|
|
188
|
-
"tests"
|
|
189
|
-
]);
|
|
190
|
-
function isDeprecatedEdgeType(edgeType) {
|
|
191
|
-
if (CANONICAL_EPISTEMIC_TYPES.has(edgeType)) return false;
|
|
192
|
-
if (edgeType in EDGE_TYPE_TO_REL) return false;
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
var api = anyApi;
|
|
196
|
-
componentsGeneric();
|
|
197
|
-
var internal = anyApi;
|
|
198
|
-
var mutation = mutationGeneric;
|
|
199
|
-
|
|
200
693
|
// src/debug.ts
|
|
201
694
|
function isGraphPrimitiveDebugEnabled() {
|
|
202
695
|
const env = globalThis.process?.env;
|
|
@@ -227,6 +720,10 @@ function readStringArray(value) {
|
|
|
227
720
|
function readMetadata(topic) {
|
|
228
721
|
return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
|
|
229
722
|
}
|
|
723
|
+
function omitMetadataKey(metadata, key) {
|
|
724
|
+
const { [key]: _omitted, ...rest } = metadata;
|
|
725
|
+
return rest;
|
|
726
|
+
}
|
|
230
727
|
function readLegacyProjectId(value) {
|
|
231
728
|
if (!value) {
|
|
232
729
|
return;
|
|
@@ -307,9 +804,12 @@ async function resolveTopicDoc(ctx, scopeId) {
|
|
|
307
804
|
);
|
|
308
805
|
}
|
|
309
806
|
try {
|
|
310
|
-
const topic = await ctx.runQuery(
|
|
311
|
-
|
|
312
|
-
|
|
807
|
+
const topic = await ctx.runQuery(
|
|
808
|
+
api.topics.getByLegacyScopeId,
|
|
809
|
+
{
|
|
810
|
+
projectId: String(scopeId)
|
|
811
|
+
}
|
|
812
|
+
);
|
|
313
813
|
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
314
814
|
return topic;
|
|
315
815
|
}
|
|
@@ -329,8 +829,18 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
|
329
829
|
const outwardId = idMode === "topic" ? topicId : storageProjectId;
|
|
330
830
|
const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
|
|
331
831
|
const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
|
|
332
|
-
|
|
333
|
-
|
|
832
|
+
let createdAt = 0;
|
|
833
|
+
if (typeof topic.createdAt === "number") {
|
|
834
|
+
createdAt = topic.createdAt;
|
|
835
|
+
} else if (typeof topic._creationTime === "number") {
|
|
836
|
+
createdAt = topic._creationTime;
|
|
837
|
+
}
|
|
838
|
+
let updatedAt = createdAt;
|
|
839
|
+
if (typeof topic.updatedAt === "number") {
|
|
840
|
+
updatedAt = topic.updatedAt;
|
|
841
|
+
} else if (typeof metadata.updatedAt === "number") {
|
|
842
|
+
updatedAt = metadata.updatedAt;
|
|
843
|
+
}
|
|
334
844
|
return {
|
|
335
845
|
...metadata,
|
|
336
846
|
_id: outwardId,
|
|
@@ -399,90 +909,113 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
|
399
909
|
if (!topic) {
|
|
400
910
|
return null;
|
|
401
911
|
}
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
912
|
+
const plan = buildTopicProjectOverlayPatchPlan(topic, value);
|
|
913
|
+
await applyTopicProjectOverlayPatch(ctx, topic, plan);
|
|
914
|
+
return materializeTopicProjectOverlay({
|
|
915
|
+
...topic,
|
|
916
|
+
...plan.patch,
|
|
917
|
+
metadata: plan.nextMetadata
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
function buildTopicProjectOverlayPatchPlan(topic, value) {
|
|
921
|
+
const plan = {
|
|
922
|
+
nextMetadata: { ...readMetadata(topic) },
|
|
923
|
+
patch: {},
|
|
924
|
+
topicUpdateArgs: {
|
|
925
|
+
id: String(topic._id)
|
|
926
|
+
}
|
|
406
927
|
};
|
|
407
928
|
for (const [key, rawValue] of Object.entries(value)) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
929
|
+
applyTopicProjectOverlayPatchEntry(plan, key, rawValue);
|
|
930
|
+
}
|
|
931
|
+
plan.patch.updatedAt = Date.now();
|
|
932
|
+
plan.patch.metadata = plan.nextMetadata;
|
|
933
|
+
plan.topicUpdateArgs.metadata = plan.nextMetadata;
|
|
934
|
+
return plan;
|
|
935
|
+
}
|
|
936
|
+
function applyTopicProjectOverlayPatchEntry(plan, key, rawValue) {
|
|
937
|
+
switch (key) {
|
|
938
|
+
case "_id":
|
|
939
|
+
case "projectId":
|
|
940
|
+
case "topicId":
|
|
941
|
+
case "legacyProjectId":
|
|
942
|
+
case "storageProjectId":
|
|
943
|
+
case "updatedAt":
|
|
944
|
+
case "createdAt":
|
|
945
|
+
return;
|
|
946
|
+
case "name":
|
|
947
|
+
case "description":
|
|
948
|
+
plan.patch[key] = rawValue;
|
|
949
|
+
plan.topicUpdateArgs[key] = rawValue;
|
|
950
|
+
return;
|
|
951
|
+
case "tenantId":
|
|
952
|
+
case "workspaceId":
|
|
953
|
+
case "ownerId":
|
|
954
|
+
throw new Error(
|
|
955
|
+
`patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
|
|
956
|
+
);
|
|
957
|
+
case "status":
|
|
958
|
+
applyTopicStatusPatch(plan, rawValue);
|
|
959
|
+
return;
|
|
960
|
+
case "visibility":
|
|
961
|
+
applyTopicVisibilityPatch(plan, rawValue);
|
|
962
|
+
return;
|
|
963
|
+
case "type":
|
|
964
|
+
applyTopicProjectTypePatch(plan, rawValue);
|
|
965
|
+
return;
|
|
966
|
+
default:
|
|
967
|
+
applyTopicMetadataPatch(plan, key, rawValue);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
function applyTopicStatusPatch(plan, rawValue) {
|
|
971
|
+
const status = coerceStatus(rawValue);
|
|
972
|
+
if (status) {
|
|
973
|
+
plan.patch.status = status;
|
|
974
|
+
plan.topicUpdateArgs.status = status;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
function applyTopicVisibilityPatch(plan, rawValue) {
|
|
978
|
+
const visibility = coerceVisibility(rawValue);
|
|
979
|
+
if (visibility) {
|
|
980
|
+
plan.patch.visibility = visibility;
|
|
981
|
+
plan.topicUpdateArgs.visibility = visibility;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function applyTopicProjectTypePatch(plan, rawValue) {
|
|
985
|
+
const projectType = readNonEmptyString(rawValue);
|
|
986
|
+
if (projectType) {
|
|
987
|
+
plan.nextMetadata.projectType = projectType;
|
|
988
|
+
return;
|
|
461
989
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
990
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, "projectType");
|
|
991
|
+
}
|
|
992
|
+
function applyTopicMetadataPatch(plan, key, rawValue) {
|
|
993
|
+
if (rawValue === void 0) {
|
|
994
|
+
plan.nextMetadata = omitMetadataKey(plan.nextMetadata, key);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
plan.nextMetadata[key] = rawValue;
|
|
998
|
+
}
|
|
999
|
+
async function applyTopicProjectOverlayPatch(ctx, topic, plan) {
|
|
465
1000
|
if (typeof ctx.runMutation === "function") {
|
|
466
1001
|
try {
|
|
467
|
-
await ctx.runMutation(api.topics.update, topicUpdateArgs);
|
|
1002
|
+
await ctx.runMutation(api.topics.update, plan.topicUpdateArgs);
|
|
468
1003
|
} catch (error) {
|
|
469
|
-
if (!
|
|
1004
|
+
if (!canPatchTopicViaLocalDb(ctx, error)) {
|
|
470
1005
|
throw error;
|
|
471
1006
|
}
|
|
472
|
-
await ctx.db.patch(
|
|
1007
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
473
1008
|
}
|
|
474
1009
|
} else if (ctx?.db && typeof ctx.db.patch === "function") {
|
|
475
|
-
await ctx.db.patch(
|
|
1010
|
+
await ctx.db.patch(topic._id, plan.patch);
|
|
476
1011
|
} else {
|
|
477
1012
|
throw new Error(
|
|
478
1013
|
"Cannot patch topic without component adapter (ctx.runMutation unavailable)"
|
|
479
1014
|
);
|
|
480
1015
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
metadata: nextMetadata
|
|
485
|
-
});
|
|
1016
|
+
}
|
|
1017
|
+
function canPatchTopicViaLocalDb(ctx, error) {
|
|
1018
|
+
return isMissingLucernChildComponentError(error) && Boolean(ctx?.db) && typeof ctx.db?.patch === "function";
|
|
486
1019
|
}
|
|
487
1020
|
|
|
488
1021
|
// src/resolvers.ts
|
|
@@ -510,7 +1043,7 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
|
|
|
510
1043
|
try {
|
|
511
1044
|
await patchTopicProjectOverlay(ctx, projectId, value);
|
|
512
1045
|
} catch (error) {
|
|
513
|
-
if (!isAdvisoryTopicPatch(value)
|
|
1046
|
+
if (!(isAdvisoryTopicPatch(value) && isMissingLucernChildComponentError2(error))) {
|
|
514
1047
|
throw error;
|
|
515
1048
|
}
|
|
516
1049
|
console.warn(
|
|
@@ -577,13 +1110,15 @@ function asMappedProjectId(topic) {
|
|
|
577
1110
|
if (!topic) {
|
|
578
1111
|
return;
|
|
579
1112
|
}
|
|
580
|
-
const directLegacyProjectId = normalizeScopeValue(
|
|
1113
|
+
const directLegacyProjectId = normalizeScopeValue(
|
|
1114
|
+
topic[LEGACY_SCOPE_FIELD2]
|
|
1115
|
+
);
|
|
581
1116
|
if (directLegacyProjectId) {
|
|
582
1117
|
return directLegacyProjectId;
|
|
583
1118
|
}
|
|
584
1119
|
const metadata = topic.metadata || {};
|
|
585
1120
|
const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
586
|
-
return candidate ? candidate : void 0;
|
|
1121
|
+
return typeof candidate === "string" ? normalizeScopeValue(candidate) : void 0;
|
|
587
1122
|
}
|
|
588
1123
|
function normalizeScopeValue(value) {
|
|
589
1124
|
if (typeof value !== "string") {
|
|
@@ -608,8 +1143,9 @@ function pickPrimaryTopic(candidates) {
|
|
|
608
1143
|
})[0];
|
|
609
1144
|
}
|
|
610
1145
|
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
1146
|
+
const query = ctx.db.query("topics");
|
|
611
1147
|
try {
|
|
612
|
-
return await
|
|
1148
|
+
return await query.withIndex(
|
|
613
1149
|
"by_graph_scope_project",
|
|
614
1150
|
(q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
|
|
615
1151
|
).collect();
|
|
@@ -621,7 +1157,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
|
621
1157
|
scopeId
|
|
622
1158
|
}
|
|
623
1159
|
);
|
|
624
|
-
const topics = await
|
|
1160
|
+
const topics = await query.collect();
|
|
625
1161
|
return topics.filter((topic) => {
|
|
626
1162
|
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
627
1163
|
const mappedProjectId = asMappedProjectId(topic);
|
|
@@ -677,424 +1213,253 @@ async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
|
677
1213
|
let current = topic;
|
|
678
1214
|
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
679
1215
|
current = await ctx.db.get(current.parentTopicId);
|
|
680
|
-
if (!current)
|
|
1216
|
+
if (!current) {
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
681
1219
|
if (!tenantId) {
|
|
682
1220
|
tenantId = normalizeScopeValue(current.tenantId);
|
|
683
1221
|
}
|
|
684
1222
|
if (!workspaceId) {
|
|
685
1223
|
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
686
1224
|
}
|
|
687
|
-
if (tenantId && workspaceId)
|
|
1225
|
+
if (tenantId && workspaceId) {
|
|
1226
|
+
break;
|
|
1227
|
+
}
|
|
688
1228
|
}
|
|
689
1229
|
return { tenantId, workspaceId };
|
|
690
1230
|
}
|
|
691
1231
|
async function resolveTopicProjectScope(ctx, args) {
|
|
692
1232
|
if (args.topicId) {
|
|
693
|
-
|
|
694
|
-
try {
|
|
695
|
-
topic = await ctx.db.get(
|
|
696
|
-
args.topicId
|
|
697
|
-
);
|
|
698
|
-
} catch (error) {
|
|
699
|
-
debugGraphPrimitiveFallback(
|
|
700
|
-
"[topicScope] Failed to load topic by direct id",
|
|
701
|
-
{
|
|
702
|
-
error,
|
|
703
|
-
topicId: args.topicId
|
|
704
|
-
}
|
|
705
|
-
);
|
|
706
|
-
}
|
|
707
|
-
if (!topic) {
|
|
708
|
-
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
709
|
-
}
|
|
710
|
-
if (!topic) {
|
|
711
|
-
topic = pickPrimaryTopic(
|
|
712
|
-
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
713
|
-
) ?? null;
|
|
714
|
-
}
|
|
715
|
-
if (!topic) {
|
|
716
|
-
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
717
|
-
ctx,
|
|
718
|
-
String(args.topicId)
|
|
719
|
-
);
|
|
720
|
-
if (nodeScope) {
|
|
721
|
-
return nodeScope;
|
|
722
|
-
}
|
|
723
|
-
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
724
|
-
}
|
|
725
|
-
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
726
|
-
const mapped = asMappedProjectId(topic);
|
|
727
|
-
if (mapped) {
|
|
728
|
-
return {
|
|
729
|
-
topicId: topic._id,
|
|
730
|
-
projectId: mapped,
|
|
731
|
-
tenantId: inherited.tenantId,
|
|
732
|
-
workspaceId: inherited.workspaceId,
|
|
733
|
-
source: "topic"
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
return {
|
|
737
|
-
topicId: topic._id,
|
|
738
|
-
tenantId: inherited.tenantId,
|
|
739
|
-
workspaceId: inherited.workspaceId,
|
|
740
|
-
source: "topic"
|
|
741
|
-
};
|
|
1233
|
+
return await resolveScopeFromTopicId(ctx, args.topicId);
|
|
742
1234
|
}
|
|
743
1235
|
if (args.projectId) {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
...nodeScope,
|
|
800
|
-
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
throw new Error(
|
|
804
|
-
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
805
|
-
);
|
|
1236
|
+
return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
|
|
1237
|
+
}
|
|
1238
|
+
throw new Error(
|
|
1239
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
async function resolveScopeFromTopicId(ctx, topicId) {
|
|
1243
|
+
const topic = await resolveTopicDocFromTopicId(ctx, topicId);
|
|
1244
|
+
if (topic) {
|
|
1245
|
+
return await buildTopicScope(ctx, topic, "topic");
|
|
1246
|
+
}
|
|
1247
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
|
|
1248
|
+
if (nodeScope) {
|
|
1249
|
+
return nodeScope;
|
|
1250
|
+
}
|
|
1251
|
+
throw new Error(`Topic not found: ${String(topicId)}`);
|
|
1252
|
+
}
|
|
1253
|
+
async function resolveTopicDocFromTopicId(ctx, topicId) {
|
|
1254
|
+
const direct = await tryReadTopicDoc(ctx, topicId, {
|
|
1255
|
+
failureLog: "[topicScope] Failed to load topic by direct id",
|
|
1256
|
+
idLogKey: "topicId"
|
|
1257
|
+
});
|
|
1258
|
+
if (direct) {
|
|
1259
|
+
return direct;
|
|
1260
|
+
}
|
|
1261
|
+
const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
|
|
1262
|
+
if (hostTopic) {
|
|
1263
|
+
return hostTopic;
|
|
1264
|
+
}
|
|
1265
|
+
return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
|
|
1266
|
+
}
|
|
1267
|
+
async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
|
|
1268
|
+
const directTopic = await resolveDirectLegacyProjectTopic(
|
|
1269
|
+
ctx,
|
|
1270
|
+
legacyProjectId
|
|
1271
|
+
);
|
|
1272
|
+
if (directTopic) {
|
|
1273
|
+
return await buildTopicScope(ctx, directTopic, "topic_inferred", {
|
|
1274
|
+
fallbackProjectId: legacyProjectId
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
const primary = pickPrimaryTopic(
|
|
1278
|
+
await findTopicsByScopeAlias(ctx, legacyProjectId)
|
|
1279
|
+
);
|
|
1280
|
+
if (primary) {
|
|
1281
|
+
return await buildTopicScope(ctx, primary, "project_mapped_topic", {
|
|
1282
|
+
fallbackProjectId: legacyProjectId
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
|
|
1286
|
+
if (nodeScope) {
|
|
1287
|
+
return {
|
|
1288
|
+
...nodeScope,
|
|
1289
|
+
projectId: nodeScope.projectId ?? legacyProjectId
|
|
1290
|
+
};
|
|
806
1291
|
}
|
|
807
1292
|
throw new Error(
|
|
808
|
-
|
|
1293
|
+
`Legacy project scope ${legacyProjectId} has no mapped topic.`
|
|
809
1294
|
);
|
|
810
1295
|
}
|
|
1296
|
+
async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
|
|
1297
|
+
const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
|
|
1298
|
+
failureLog: "[topicScope] Failed to load direct project topic",
|
|
1299
|
+
idLogKey: "projectId"
|
|
1300
|
+
});
|
|
1301
|
+
return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
|
|
1302
|
+
}
|
|
1303
|
+
async function tryReadTopicDoc(ctx, id, log) {
|
|
1304
|
+
try {
|
|
1305
|
+
return await ctx.db.get(id);
|
|
1306
|
+
} catch (error) {
|
|
1307
|
+
debugGraphPrimitiveFallback(log.failureLog, {
|
|
1308
|
+
error,
|
|
1309
|
+
[log.idLogKey]: id
|
|
1310
|
+
});
|
|
1311
|
+
return null;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
async function buildTopicScope(ctx, topic, source, options = {}) {
|
|
1315
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
1316
|
+
const mapped = asMappedProjectId(topic);
|
|
1317
|
+
return {
|
|
1318
|
+
topicId: topic._id,
|
|
1319
|
+
...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
|
|
1320
|
+
tenantId: inherited.tenantId,
|
|
1321
|
+
workspaceId: inherited.workspaceId,
|
|
1322
|
+
source
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
811
1325
|
var optionalScopeArgs = {
|
|
812
1326
|
projectId: v.optional(v.string()),
|
|
813
1327
|
topicId: v.optional(v.string())
|
|
814
1328
|
};
|
|
815
1329
|
|
|
816
|
-
// src/
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
case "ontological":
|
|
828
|
-
return 0;
|
|
829
|
-
default:
|
|
830
|
-
return -1;
|
|
831
|
-
}
|
|
1330
|
+
// src/epistemicEdges.mutations.ts
|
|
1331
|
+
var EPISTEMIC_LAYERS = /* @__PURE__ */ new Set([
|
|
1332
|
+
"L4",
|
|
1333
|
+
"L3",
|
|
1334
|
+
"L2",
|
|
1335
|
+
"L1",
|
|
1336
|
+
"ontological",
|
|
1337
|
+
"organizational"
|
|
1338
|
+
]);
|
|
1339
|
+
function readOptionalString(value) {
|
|
1340
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
832
1341
|
}
|
|
833
|
-
function
|
|
834
|
-
|
|
835
|
-
|
|
1342
|
+
function readOptionalNumber(value) {
|
|
1343
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1344
|
+
}
|
|
1345
|
+
function readConvexId(value) {
|
|
1346
|
+
const normalized = readOptionalString(value);
|
|
1347
|
+
return normalized;
|
|
1348
|
+
}
|
|
1349
|
+
function readRecord(value) {
|
|
1350
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1351
|
+
}
|
|
1352
|
+
function readEpistemicLayer(value) {
|
|
1353
|
+
const layer = readOptionalString(value);
|
|
1354
|
+
return layer && EPISTEMIC_LAYERS.has(layer) ? layer : void 0;
|
|
1355
|
+
}
|
|
1356
|
+
function readEdgeNodeRow(value) {
|
|
1357
|
+
const record = readRecord(value);
|
|
1358
|
+
if (!record) {
|
|
1359
|
+
return null;
|
|
836
1360
|
}
|
|
837
|
-
|
|
838
|
-
|
|
1361
|
+
const id = readConvexId(record._id);
|
|
1362
|
+
const globalId = readOptionalString(record.globalId);
|
|
1363
|
+
const nodeType = readOptionalString(record.nodeType);
|
|
1364
|
+
if (!(id && globalId && nodeType)) {
|
|
1365
|
+
return null;
|
|
839
1366
|
}
|
|
840
|
-
|
|
841
|
-
|
|
1367
|
+
const node = { _id: id, globalId, nodeType };
|
|
1368
|
+
const epistemicLayer = readEpistemicLayer(record.epistemicLayer);
|
|
1369
|
+
if (epistemicLayer !== void 0) {
|
|
1370
|
+
node.epistemicLayer = epistemicLayer;
|
|
842
1371
|
}
|
|
843
|
-
|
|
844
|
-
|
|
1372
|
+
const projectId = readOptionalString(record.projectId);
|
|
1373
|
+
if (projectId !== void 0) {
|
|
1374
|
+
node.projectId = projectId;
|
|
845
1375
|
}
|
|
846
|
-
|
|
847
|
-
|
|
1376
|
+
return node;
|
|
1377
|
+
}
|
|
1378
|
+
function requireEdgeNodeRow(value, context) {
|
|
1379
|
+
const node = readEdgeNodeRow(value);
|
|
1380
|
+
if (!node) {
|
|
1381
|
+
throw new Error(`${context} requires a canonical epistemic node row.`);
|
|
848
1382
|
}
|
|
849
|
-
|
|
850
|
-
|
|
1383
|
+
return node;
|
|
1384
|
+
}
|
|
1385
|
+
function readEdgeRow(value) {
|
|
1386
|
+
const record = readRecord(value);
|
|
1387
|
+
if (!record) {
|
|
1388
|
+
return null;
|
|
851
1389
|
}
|
|
852
|
-
|
|
853
|
-
|
|
1390
|
+
const id = readConvexId(record._id);
|
|
1391
|
+
const globalId = readOptionalString(record.globalId);
|
|
1392
|
+
const edgeType = readOptionalString(record.edgeType);
|
|
1393
|
+
if (!(id && globalId && edgeType)) {
|
|
1394
|
+
return null;
|
|
854
1395
|
}
|
|
855
|
-
|
|
856
|
-
|
|
1396
|
+
const edge = { _id: id, globalId, edgeType };
|
|
1397
|
+
const createdBy = readOptionalString(record.createdBy);
|
|
1398
|
+
if (createdBy !== void 0) {
|
|
1399
|
+
edge.createdBy = createdBy;
|
|
857
1400
|
}
|
|
858
|
-
|
|
859
|
-
|
|
1401
|
+
const fromNodeId = readOptionalString(record.fromNodeId);
|
|
1402
|
+
if (fromNodeId !== void 0) {
|
|
1403
|
+
edge.fromNodeId = fromNodeId;
|
|
860
1404
|
}
|
|
861
|
-
|
|
862
|
-
|
|
1405
|
+
const projectId = readOptionalString(record.projectId);
|
|
1406
|
+
if (projectId !== void 0) {
|
|
1407
|
+
edge.projectId = projectId;
|
|
863
1408
|
}
|
|
864
|
-
|
|
865
|
-
|
|
1409
|
+
const toNodeId = readOptionalString(record.toNodeId);
|
|
1410
|
+
if (toNodeId !== void 0) {
|
|
1411
|
+
edge.toNodeId = toNodeId;
|
|
866
1412
|
}
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
return false;
|
|
1413
|
+
const confidence = readOptionalNumber(record.confidence);
|
|
1414
|
+
if (confidence !== void 0) {
|
|
1415
|
+
edge.confidence = confidence;
|
|
871
1416
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
// === 6 Canonical Epistemic Types ===
|
|
876
|
-
supports: {
|
|
877
|
-
from: ["L3"],
|
|
878
|
-
to: ["L3"],
|
|
879
|
-
description: "Belief bears on Belief (weight: +1 supports, -1 contradicts)"
|
|
880
|
-
},
|
|
881
|
-
informs: {
|
|
882
|
-
from: ["L2"],
|
|
883
|
-
to: ["L3"],
|
|
884
|
-
description: "Evidence -> Belief (L2 -> L3)"
|
|
885
|
-
},
|
|
886
|
-
depends_on: {
|
|
887
|
-
from: ["L3"],
|
|
888
|
-
to: ["L3"],
|
|
889
|
-
description: "Belief B requires Belief A (structural gate)"
|
|
890
|
-
},
|
|
891
|
-
derived_from: {
|
|
892
|
-
from: ["L2", "L3", "L4"],
|
|
893
|
-
to: ["L1", "L2", "L3"],
|
|
894
|
-
description: "A was produced from B (provenance chain)"
|
|
895
|
-
},
|
|
896
|
-
contains: {
|
|
897
|
-
from: ["L3", "L4", "ontological"],
|
|
898
|
-
to: ["L2", "L3", "ontological"],
|
|
899
|
-
description: "A scopes/aggregates B (hierarchy)"
|
|
900
|
-
},
|
|
901
|
-
tests: {
|
|
902
|
-
from: ["L3"],
|
|
903
|
-
to: ["L3"],
|
|
904
|
-
description: "Question -> Belief (L3 -> L3)"
|
|
905
|
-
},
|
|
906
|
-
// === Structural / Lifecycle ===
|
|
907
|
-
supersedes: {
|
|
908
|
-
from: ["L3"],
|
|
909
|
-
to: ["L3"],
|
|
910
|
-
description: "NewNode -> OldNode (fork lineage)"
|
|
911
|
-
},
|
|
912
|
-
responds_to: {
|
|
913
|
-
from: ["L2", "L3"],
|
|
914
|
-
to: ["L3"],
|
|
915
|
-
description: "Answer -> Question (L2/L3 -> L3)"
|
|
916
|
-
},
|
|
917
|
-
belongs_to: {
|
|
918
|
-
from: ["L2", "L3", "ontological"],
|
|
919
|
-
to: ["L3"],
|
|
920
|
-
description: "Membership (migrating to contains)"
|
|
921
|
-
},
|
|
922
|
-
relates_to_thesis: {
|
|
923
|
-
from: ["L3"],
|
|
924
|
-
to: ["L3"],
|
|
925
|
-
description: "Belief -> Theme (L3 -> L3)"
|
|
926
|
-
},
|
|
927
|
-
// === Ontological (entity-entity or entity-epistemic bridge) ===
|
|
928
|
-
works_at: {
|
|
929
|
-
from: ["ontological"],
|
|
930
|
-
to: ["ontological"],
|
|
931
|
-
description: "Person -> Company"
|
|
932
|
-
},
|
|
933
|
-
invested_in: {
|
|
934
|
-
from: ["ontological"],
|
|
935
|
-
to: ["ontological"],
|
|
936
|
-
description: "Investor -> Company"
|
|
937
|
-
},
|
|
938
|
-
competes_with: {
|
|
939
|
-
from: ["ontological"],
|
|
940
|
-
to: ["ontological"],
|
|
941
|
-
description: "Company -> Company"
|
|
942
|
-
},
|
|
943
|
-
participates_in: {
|
|
944
|
-
from: ["ontological"],
|
|
945
|
-
to: ["ontological"],
|
|
946
|
-
description: "Company -> ValueChain"
|
|
947
|
-
},
|
|
948
|
-
founded_by: {
|
|
949
|
-
from: ["ontological"],
|
|
950
|
-
to: ["ontological"],
|
|
951
|
-
description: "Company -> Person"
|
|
952
|
-
},
|
|
953
|
-
evaluates: {
|
|
954
|
-
from: ["ontological"],
|
|
955
|
-
to: ["ontological"],
|
|
956
|
-
description: "Deal -> Company"
|
|
957
|
-
},
|
|
958
|
-
performs: {
|
|
959
|
-
from: ["ontological"],
|
|
960
|
-
to: ["ontological"],
|
|
961
|
-
description: "Company -> Function"
|
|
962
|
-
},
|
|
963
|
-
function_in: {
|
|
964
|
-
from: ["ontological"],
|
|
965
|
-
to: ["ontological"],
|
|
966
|
-
description: "Function -> ValueChain"
|
|
967
|
-
},
|
|
968
|
-
impacts: {
|
|
969
|
-
from: ["ontological", "L3"],
|
|
970
|
-
to: ["ontological"],
|
|
971
|
-
description: "Theme/Entity -> ValueChain"
|
|
972
|
-
},
|
|
973
|
-
raised_from: {
|
|
974
|
-
from: ["ontological"],
|
|
975
|
-
to: ["ontological"],
|
|
976
|
-
description: "Company -> Investor"
|
|
977
|
-
},
|
|
978
|
-
mentioned_in: {
|
|
979
|
-
from: ["ontological"],
|
|
980
|
-
to: ["L1", "L2"],
|
|
981
|
-
description: "Entity -> Source/Evidence"
|
|
982
|
-
},
|
|
983
|
-
perspective_on: {
|
|
984
|
-
from: ["ontological"],
|
|
985
|
-
to: ["L3"],
|
|
986
|
-
description: "Person -> Belief/Theme"
|
|
987
|
-
},
|
|
988
|
-
plays_theme: {
|
|
989
|
-
from: ["ontological"],
|
|
990
|
-
to: ["L3"],
|
|
991
|
-
description: "Deal -> Theme"
|
|
992
|
-
},
|
|
993
|
-
// C2-RR.4 — storage migration alias + the remaining 55 reachable edge types.
|
|
994
|
-
// Mirrors the kernel rule table
|
|
995
|
-
// (packages/reasoning-kernel/src/adapters/lib/edgeValidation.ts) so this
|
|
996
|
-
// graph-primitives write path admits the same public edge vocabulary. See the
|
|
997
|
-
// kernel file for the per-group rationale.
|
|
998
|
-
extracted_from: {
|
|
999
|
-
from: ["L2", "L3", "L4"],
|
|
1000
|
-
to: ["L1", "L2", "L3"],
|
|
1001
|
-
description: "Legacy storage migration alias for derived_from; public writes use derived_from"
|
|
1002
|
-
},
|
|
1003
|
-
qualifies: { from: ["L2", "L3"], to: ["L3"], description: "Evidence/Belief qualifies a Belief" },
|
|
1004
|
-
contradicts: { from: ["L2", "L3"], to: ["L3"], description: "Evidence/Belief contradicts a Belief" },
|
|
1005
|
-
reinforces: { from: ["L2", "L3"], to: ["L3"], description: "Evidence/Belief reinforces a Belief" },
|
|
1006
|
-
corroborates: { from: ["L2", "L3"], to: ["L3"], description: "Independent evidence/belief corroborates a Belief" },
|
|
1007
|
-
strengthened_by: { from: ["L3"], to: ["L2", "L3"], description: "Belief is strengthened by Evidence/Belief" },
|
|
1008
|
-
weakened_by: { from: ["L3"], to: ["L2", "L3"], description: "Belief is weakened by Evidence/Belief" },
|
|
1009
|
-
validated_by: { from: ["L3"], to: ["L2", "L3"], description: "Belief is validated by Evidence/Belief" },
|
|
1010
|
-
falsified_by: { from: ["L3"], to: ["L2", "L3"], description: "Belief is falsified by Evidence/Belief" },
|
|
1011
|
-
amplifies: { from: ["L3"], to: ["L3"], description: "Belief amplifies another Belief" },
|
|
1012
|
-
precondition_for: { from: ["L3"], to: ["L3"], description: "Belief is a precondition for another Belief" },
|
|
1013
|
-
prerequisite_for: { from: ["L3"], to: ["L3"], description: "Belief is a prerequisite for another Belief" },
|
|
1014
|
-
required_for: { from: ["L3"], to: ["L3"], description: "Belief is required for another Belief" },
|
|
1015
|
-
in_tension_with: { from: ["L3"], to: ["L3"], description: "Belief is in tension with another Belief" },
|
|
1016
|
-
mutually_exclusive: { from: ["L3"], to: ["L3"], description: "Beliefs cannot both hold" },
|
|
1017
|
-
exclusive_with: { from: ["L3"], to: ["L3"], description: "Belief is exclusive with another Belief" },
|
|
1018
|
-
alternative_to: { from: ["L3"], to: ["L3"], description: "Belief is an alternative to another Belief" },
|
|
1019
|
-
subsumes: { from: ["L3"], to: ["L3"], description: "Belief subsumes a narrower Belief" },
|
|
1020
|
-
extends: { from: ["L3"], to: ["L3"], description: "Belief extends another Belief" },
|
|
1021
|
-
refines: { from: ["L3"], to: ["L3"], description: "Belief refines another Belief" },
|
|
1022
|
-
implements: { from: ["L3"], to: ["L3"], description: "Belief implements an abstract Belief" },
|
|
1023
|
-
violates: { from: ["L3"], to: ["L3"], description: "Belief violates a constraint Belief" },
|
|
1024
|
-
assumes: { from: ["L3"], to: ["L3"], description: "Belief assumes another Belief" },
|
|
1025
|
-
would_predict: { from: ["L3"], to: ["L3"], description: "Belief would predict another Belief" },
|
|
1026
|
-
analogous_to: { from: ["L3"], to: ["L3"], description: "Belief is analogous to another Belief" },
|
|
1027
|
-
independent_of: { from: ["L3"], to: ["L3"], description: "Belief is independent of another Belief" },
|
|
1028
|
-
correlates_with: { from: ["L3"], to: ["L3"], description: "Belief correlates with another Belief" },
|
|
1029
|
-
co_changes_with: { from: ["L3"], to: ["L3"], description: "Belief co-changes with another Belief" },
|
|
1030
|
-
counterfactual_of: { from: ["L3"], to: ["L3"], description: "Belief is a counterfactual of another Belief" },
|
|
1031
|
-
parallel_to: { from: ["L3"], to: ["L3"], description: "Belief runs parallel to another Belief" },
|
|
1032
|
-
cascade_from: { from: ["L3"], to: ["L3"], description: "Cascade from an upstream Belief" },
|
|
1033
|
-
cascade_to: { from: ["L3"], to: ["L3"], description: "Cascade to a downstream Belief" },
|
|
1034
|
-
collapses_if: { from: ["L3"], to: ["L3"], description: "Belief collapses if another fails" },
|
|
1035
|
-
branches_from: { from: ["L3"], to: ["L3"], description: "Belief branches from an ancestor Belief" },
|
|
1036
|
-
same_as: { from: ["L2", "L3", "ontological"], to: ["L2", "L3", "ontological"], description: "Two nodes are the same entity" },
|
|
1037
|
-
answers: { from: ["L2", "L3"], to: ["L3"], description: "Answer/Belief answers a Question" },
|
|
1038
|
-
partially_answers: { from: ["L2", "L3"], to: ["L3"], description: "Answer/Belief partially answers a Question" },
|
|
1039
|
-
explores: { from: ["L3"], to: ["L3"], description: "Question explores a Belief/Theme" },
|
|
1040
|
-
informed_by_theme: { from: ["L3"], to: ["L3"], description: "Belief is informed by a Theme" },
|
|
1041
|
-
same_theme_as: { from: ["L3"], to: ["L3"], description: "Two Beliefs share a Theme" },
|
|
1042
|
-
based_on: { from: ["L4"], to: ["L3"], description: "Decision is based on a Belief/Question" },
|
|
1043
|
-
based_on_belief: { from: ["L4"], to: ["L3"], description: "Decision is based on a Belief" },
|
|
1044
|
-
based_on_question: { from: ["L4"], to: ["L3"], description: "Decision is based on a Question" },
|
|
1045
|
-
blocked_by_contradiction: { from: ["L4"], to: ["L3"], description: "Decision is blocked by a Contradiction" },
|
|
1046
|
-
parent_of: { from: ["L3", "L4", "ontological", "organizational"], to: ["L2", "L3", "ontological", "organizational"], description: "A is the parent of B" },
|
|
1047
|
-
child_of: { from: ["L2", "L3", "ontological", "organizational"], to: ["L3", "L4", "ontological", "organizational"], description: "A is the child of B" },
|
|
1048
|
-
scoped_by: { from: ["L2", "L3"], to: ["L3", "organizational"], description: "Object is scoped by a Topic/Theme" },
|
|
1049
|
-
cites: { from: ["L2", "L3"], to: ["L1", "L2"], description: "Evidence/Belief cites a Source/Excerpt" },
|
|
1050
|
-
summarizes: { from: ["L2", "L3"], to: ["L1", "L2"], description: "Synthesis/Evidence summarizes a Source/Evidence" },
|
|
1051
|
-
same_source_as: { from: ["L1", "L2"], to: ["L1", "L2"], description: "Two nodes derive from the same Source" },
|
|
1052
|
-
migrating_from: { from: ["L2", "L3", "L4"], to: ["L1", "L2", "L3"], description: "Migration lineage: from an ancestor" },
|
|
1053
|
-
migrating_to: { from: ["L1", "L2", "L3"], to: ["L2", "L3", "L4"], description: "Migration lineage: to a successor" },
|
|
1054
|
-
about_entity: { from: ["L2", "L3"], to: ["ontological"], description: "Belief/Evidence is about an Entity" },
|
|
1055
|
-
entity_referenced_in: { from: ["ontological"], to: ["L1", "L2"], description: "Entity is referenced in a Source/Evidence" },
|
|
1056
|
-
related_to: { from: ["L2", "L3", "ontological", "organizational"], to: ["L2", "L3", "ontological", "organizational"], description: "Lateral adjacency; no confidence pressure" },
|
|
1057
|
-
blocks: { from: ["L3", "L4"], to: ["L3", "L4"], description: "A blocks B (structural gate)" }
|
|
1058
|
-
};
|
|
1059
|
-
function validateEdgeLayers(edgeType, fromLayer, toLayer) {
|
|
1060
|
-
const rules = EDGE_LAYER_RULES[edgeType];
|
|
1061
|
-
if (!rules) {
|
|
1062
|
-
console.warn(
|
|
1063
|
-
`[EdgeValidation] Unknown edge type: ${edgeType}, allowing by default`
|
|
1064
|
-
);
|
|
1065
|
-
return { valid: true };
|
|
1417
|
+
const weight = readOptionalNumber(record.weight);
|
|
1418
|
+
if (weight !== void 0) {
|
|
1419
|
+
edge.weight = weight;
|
|
1066
1420
|
}
|
|
1067
|
-
if (
|
|
1068
|
-
|
|
1069
|
-
return {
|
|
1070
|
-
valid: false,
|
|
1071
|
-
reason: `${edgeType} edges must be between nodes of the same layer. Got ${fromLayer} -> ${toLayer}`
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
1074
|
-
return { valid: true };
|
|
1421
|
+
if ("context" in record) {
|
|
1422
|
+
edge.context = record.context;
|
|
1075
1423
|
}
|
|
1076
|
-
if (
|
|
1077
|
-
|
|
1078
|
-
valid: false,
|
|
1079
|
-
reason: `Edge type '${edgeType}' does not allow source layer ${fromLayer}. Allowed: ${rules.from.join(", ")}`
|
|
1080
|
-
};
|
|
1424
|
+
if ("description" in record) {
|
|
1425
|
+
edge.description = record.description;
|
|
1081
1426
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1427
|
+
return edge;
|
|
1428
|
+
}
|
|
1429
|
+
function readEdgeRows(values) {
|
|
1430
|
+
return values.flatMap((value) => {
|
|
1431
|
+
const edge = readEdgeRow(value);
|
|
1432
|
+
return edge ? [edge] : [];
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
function nodeEndpointRefs(nodeId, node) {
|
|
1436
|
+
const refs = /* @__PURE__ */ new Set([String(nodeId)]);
|
|
1437
|
+
if (node?.globalId) {
|
|
1438
|
+
refs.add(node.globalId);
|
|
1087
1439
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1440
|
+
return [...refs];
|
|
1441
|
+
}
|
|
1442
|
+
async function collectEdgesBetween(ctx, fromRefs, toRefs) {
|
|
1443
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1444
|
+
const edges = [];
|
|
1445
|
+
for (const fromRef of fromRefs) {
|
|
1446
|
+
for (const toRef of toRefs) {
|
|
1447
|
+
const rows = await ctx.db.query("epistemicEdges").withIndex(
|
|
1448
|
+
"by_from_to",
|
|
1449
|
+
(q) => q.eq("fromNodeId", fromRef).eq("toNodeId", toRef)
|
|
1450
|
+
).collect();
|
|
1451
|
+
for (const edge of readEdgeRows(rows)) {
|
|
1452
|
+
const key = String(edge._id);
|
|
1453
|
+
if (seen.has(key)) {
|
|
1454
|
+
continue;
|
|
1455
|
+
}
|
|
1456
|
+
seen.add(key);
|
|
1457
|
+
edges.push(edge);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1093
1460
|
}
|
|
1094
|
-
return
|
|
1461
|
+
return edges;
|
|
1095
1462
|
}
|
|
1096
|
-
|
|
1097
|
-
// src/epistemicEdges.mutations.ts
|
|
1098
1463
|
var create = mutation({
|
|
1099
1464
|
args: {
|
|
1100
1465
|
globalId: v.string(),
|
|
@@ -1111,11 +1476,14 @@ var create = mutation({
|
|
|
1111
1476
|
},
|
|
1112
1477
|
returns: permissiveReturn,
|
|
1113
1478
|
handler: async (ctx, args) => {
|
|
1114
|
-
const fromNode =
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1479
|
+
const fromNode = requireEdgeNodeRow(
|
|
1480
|
+
await ctx.db.get(args.fromNodeId),
|
|
1481
|
+
"Create edge source"
|
|
1482
|
+
);
|
|
1483
|
+
const toNode = requireEdgeNodeRow(
|
|
1484
|
+
await ctx.db.get(args.toNodeId),
|
|
1485
|
+
"Create edge target"
|
|
1486
|
+
);
|
|
1119
1487
|
const resolvedScope = args.topicId || args.projectId ? await resolveTopicProjectScope(ctx, {
|
|
1120
1488
|
topicId: args.topicId,
|
|
1121
1489
|
projectId: args.projectId
|
|
@@ -1124,8 +1492,8 @@ var create = mutation({
|
|
|
1124
1492
|
if (resolvedProjectId) {
|
|
1125
1493
|
await requireScopeWriteAccess(ctx, resolvedProjectId, args.createdBy);
|
|
1126
1494
|
}
|
|
1127
|
-
const fromLayer = fromNode.epistemicLayer
|
|
1128
|
-
const toLayer = toNode.epistemicLayer
|
|
1495
|
+
const fromLayer = fromNode.epistemicLayer ?? getNodeLayer(fromNode.nodeType);
|
|
1496
|
+
const toLayer = toNode.epistemicLayer ?? getNodeLayer(toNode.nodeType);
|
|
1129
1497
|
if (!args.skipLayerValidation) {
|
|
1130
1498
|
const validation = validateEdgeLayers(args.edgeType, fromLayer, toLayer);
|
|
1131
1499
|
if (!validation.valid) {
|
|
@@ -1139,10 +1507,11 @@ var create = mutation({
|
|
|
1139
1507
|
`FORBIDDEN: Edge type '${args.edgeType}' has been removed from StackOS schema.`
|
|
1140
1508
|
);
|
|
1141
1509
|
}
|
|
1142
|
-
const existing = await
|
|
1143
|
-
|
|
1144
|
-
(
|
|
1145
|
-
|
|
1510
|
+
const existing = await collectEdgesBetween(
|
|
1511
|
+
ctx,
|
|
1512
|
+
nodeEndpointRefs(args.fromNodeId, fromNode),
|
|
1513
|
+
nodeEndpointRefs(args.toNodeId, toNode)
|
|
1514
|
+
);
|
|
1146
1515
|
const duplicateEdge = existing.find((e) => e.edgeType === args.edgeType);
|
|
1147
1516
|
if (duplicateEdge) {
|
|
1148
1517
|
return { edgeId: duplicateEdge._id, isDuplicate: true };
|
|
@@ -1219,7 +1588,7 @@ var update = mutation({
|
|
|
1219
1588
|
returns: permissiveReturn,
|
|
1220
1589
|
handler: async (ctx, args) => {
|
|
1221
1590
|
const { edgeId, userId, ...updates } = args;
|
|
1222
|
-
const edge = await ctx.db.get(edgeId);
|
|
1591
|
+
const edge = readEdgeRow(await ctx.db.get(edgeId));
|
|
1223
1592
|
if (!edge) {
|
|
1224
1593
|
throw new Error("Edge not found");
|
|
1225
1594
|
}
|
|
@@ -1260,7 +1629,7 @@ var remove = mutation({
|
|
|
1260
1629
|
},
|
|
1261
1630
|
returns: permissiveReturn,
|
|
1262
1631
|
handler: async (ctx, args) => {
|
|
1263
|
-
const edge = await ctx.db.get(args.edgeId);
|
|
1632
|
+
const edge = readEdgeRow(await ctx.db.get(args.edgeId));
|
|
1264
1633
|
if (!edge) {
|
|
1265
1634
|
return buildEdgeNotFoundResult();
|
|
1266
1635
|
}
|
|
@@ -1306,10 +1675,13 @@ var removeBetween = mutation({
|
|
|
1306
1675
|
},
|
|
1307
1676
|
returns: permissiveReturn,
|
|
1308
1677
|
handler: async (ctx, args) => {
|
|
1309
|
-
const
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1678
|
+
const fromNode = readEdgeNodeRow(await ctx.db.get(args.fromNodeId));
|
|
1679
|
+
const toNode = readEdgeNodeRow(await ctx.db.get(args.toNodeId));
|
|
1680
|
+
const edges = await collectEdgesBetween(
|
|
1681
|
+
ctx,
|
|
1682
|
+
nodeEndpointRefs(args.fromNodeId, fromNode),
|
|
1683
|
+
nodeEndpointRefs(args.toNodeId, toNode)
|
|
1684
|
+
);
|
|
1313
1685
|
let deleted = 0;
|
|
1314
1686
|
for (const edge of edges) {
|
|
1315
1687
|
if (!args.edgeType || edge.edgeType === args.edgeType) {
|
|
@@ -1346,19 +1718,23 @@ var batchCreate = mutation({
|
|
|
1346
1718
|
const results = [];
|
|
1347
1719
|
const errors = [];
|
|
1348
1720
|
for (const edge of args.edges) {
|
|
1349
|
-
const fromNode = await ctx.db.get(edge.fromNodeId);
|
|
1350
|
-
const toNode = await ctx.db.get(edge.toNodeId);
|
|
1351
|
-
if (!fromNode
|
|
1721
|
+
const fromNode = readEdgeNodeRow(await ctx.db.get(edge.fromNodeId));
|
|
1722
|
+
const toNode = readEdgeNodeRow(await ctx.db.get(edge.toNodeId));
|
|
1723
|
+
if (!(fromNode && toNode)) {
|
|
1352
1724
|
errors.push({
|
|
1353
1725
|
globalId: edge.globalId,
|
|
1354
1726
|
error: "One or both nodes not found"
|
|
1355
1727
|
});
|
|
1356
1728
|
continue;
|
|
1357
1729
|
}
|
|
1358
|
-
const fromLayer = fromNode.epistemicLayer
|
|
1359
|
-
const toLayer = toNode.epistemicLayer
|
|
1730
|
+
const fromLayer = fromNode.epistemicLayer ?? getNodeLayer(fromNode.nodeType);
|
|
1731
|
+
const toLayer = toNode.epistemicLayer ?? getNodeLayer(toNode.nodeType);
|
|
1360
1732
|
if (!args.skipLayerValidation) {
|
|
1361
|
-
const validation = validateEdgeLayers(
|
|
1733
|
+
const validation = validateEdgeLayers(
|
|
1734
|
+
edge.edgeType,
|
|
1735
|
+
fromLayer,
|
|
1736
|
+
toLayer
|
|
1737
|
+
);
|
|
1362
1738
|
if (!validation.valid) {
|
|
1363
1739
|
errors.push({
|
|
1364
1740
|
globalId: edge.globalId,
|
|
@@ -1393,9 +1769,7 @@ var batchCreate = mutation({
|
|
|
1393
1769
|
results.push({ globalId: edge.globalId, edgeGlobalId: edge.globalId });
|
|
1394
1770
|
}
|
|
1395
1771
|
const projectIds = new Set(
|
|
1396
|
-
args.edges.flatMap(
|
|
1397
|
-
(edge) => typeof edge.projectId === "string" ? [edge.projectId] : []
|
|
1398
|
-
)
|
|
1772
|
+
args.edges.flatMap((edge) => edge.projectId ? [edge.projectId] : [])
|
|
1399
1773
|
);
|
|
1400
1774
|
for (const pid of projectIds) {
|
|
1401
1775
|
if (pid) {
|
|
@@ -1416,8 +1790,11 @@ var cleanupDeprecatedEdges = mutation({
|
|
|
1416
1790
|
handler: async (ctx, args) => {
|
|
1417
1791
|
const DEPRECATED_TYPES = ["contradicts"];
|
|
1418
1792
|
const scopeId = args.topicId || args.projectId;
|
|
1419
|
-
const allEdges = scopeId ? await ctx.db.query("epistemicEdges").withIndex(
|
|
1420
|
-
|
|
1793
|
+
const allEdges = scopeId ? await ctx.db.query("epistemicEdges").withIndex(
|
|
1794
|
+
"by_topic",
|
|
1795
|
+
(q) => q.eq("topicId", scopeId)
|
|
1796
|
+
).collect() : [];
|
|
1797
|
+
const deprecatedEdges = readEdgeRows(allEdges).filter(
|
|
1421
1798
|
(edge) => DEPRECATED_TYPES.includes(edge.edgeType)
|
|
1422
1799
|
);
|
|
1423
1800
|
if (args.dryRun) {
|
|
@@ -1460,15 +1837,15 @@ var deleteEdges = mutation({
|
|
|
1460
1837
|
const deleted = [];
|
|
1461
1838
|
const notFound = [];
|
|
1462
1839
|
for (const edgeId of args.edgeIds) {
|
|
1463
|
-
const edge = await ctx.db.get(edgeId);
|
|
1840
|
+
const edge = readEdgeRow(await ctx.db.get(edgeId));
|
|
1464
1841
|
if (edge) {
|
|
1465
1842
|
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.deleteEdge, {
|
|
1466
1843
|
globalId: edge.globalId
|
|
1467
1844
|
});
|
|
1468
1845
|
await ctx.db.delete(edgeId);
|
|
1469
|
-
deleted.push(edgeId);
|
|
1846
|
+
deleted.push(String(edgeId));
|
|
1470
1847
|
} else {
|
|
1471
|
-
notFound.push(edgeId);
|
|
1848
|
+
notFound.push(String(edgeId));
|
|
1472
1849
|
}
|
|
1473
1850
|
}
|
|
1474
1851
|
return {
|