@lucern/graph-primitives 1.0.0 → 1.0.1
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/README.md +13 -12
- package/dist/beliefDecay.js +24 -17
- package/dist/beliefDecay.js.map +1 -1
- package/dist/beliefEvidenceLinks.js +32 -8
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/contradictions.js +32 -9
- package/dist/contradictions.js.map +1 -1
- package/dist/convex.d.ts +55 -12
- package/dist/convex.js.map +1 -1
- package/dist/edgeValidation.d.ts +25 -2
- package/dist/edges/index.d.ts +9 -2
- package/dist/edges/index.js.map +1 -1
- package/dist/edges/propagationTypes.d.ts +2 -3
- package/dist/edges/propagationTypes.js.map +1 -1
- package/dist/entityBridge.js +10 -3
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityLifecycle.js +15 -3
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.d.ts +36 -0
- package/dist/epistemicBeliefs.admin.js +745 -0
- package/dist/epistemicBeliefs.admin.js.map +1 -0
- package/dist/epistemicBeliefs.backfills.d.ts +62 -0
- package/dist/epistemicBeliefs.backfills.js +1004 -0
- package/dist/epistemicBeliefs.backfills.js.map +1 -0
- package/dist/epistemicBeliefs.confidence.d.ts +45 -0
- package/dist/epistemicBeliefs.confidence.js +1285 -0
- package/dist/epistemicBeliefs.confidence.js.map +1 -0
- package/dist/epistemicBeliefs.core.d.ts +35 -0
- package/dist/epistemicBeliefs.core.js +1508 -0
- package/dist/epistemicBeliefs.core.js.map +1 -0
- package/dist/epistemicBeliefs.d.ts +12 -3
- package/dist/epistemicBeliefs.helpers.d.ts +168 -0
- package/dist/epistemicBeliefs.helpers.js +1060 -0
- package/dist/epistemicBeliefs.helpers.js.map +1 -0
- package/dist/epistemicBeliefs.internal.d.ts +30 -0
- package/dist/epistemicBeliefs.internal.js +1329 -0
- package/dist/epistemicBeliefs.internal.js.map +1 -0
- package/dist/epistemicBeliefs.js +1196 -1184
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +19 -0
- package/dist/epistemicBeliefs.lifecycle.js +1608 -0
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -0
- package/dist/epistemicBeliefs.links.d.ts +30 -0
- package/dist/epistemicBeliefs.links.js +761 -0
- package/dist/epistemicBeliefs.links.js.map +1 -0
- package/dist/epistemicBeliefs.queries.d.ts +16 -0
- package/dist/epistemicBeliefs.queries.js +90 -0
- package/dist/epistemicBeliefs.queries.js.map +1 -0
- package/dist/epistemicContractHelpers.d.ts +1 -1
- package/dist/epistemicContractHelpers.js +1 -1
- package/dist/epistemicContracts.d.ts +5 -76
- package/dist/epistemicContracts.evaluators.d.ts +36 -0
- package/dist/epistemicContracts.evaluators.js +2506 -0
- package/dist/epistemicContracts.evaluators.js.map +1 -0
- package/dist/epistemicContracts.handlers.d.ts +40 -0
- package/dist/epistemicContracts.handlers.js +3029 -0
- package/dist/epistemicContracts.handlers.js.map +1 -0
- package/dist/epistemicContracts.js +2006 -5281
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicContracts.metrics.d.ts +26 -0
- package/dist/epistemicContracts.metrics.js +427 -0
- package/dist/epistemicContracts.metrics.js.map +1 -0
- package/dist/epistemicContracts.types.d.ts +159 -0
- package/dist/epistemicContracts.types.js +3 -0
- package/dist/epistemicContracts.types.js.map +1 -0
- package/dist/epistemicEdgeCreation.d.ts +73 -0
- package/dist/epistemicEdgeCreation.js +450 -0
- package/dist/epistemicEdgeCreation.js.map +1 -0
- package/dist/epistemicEdges-BF-cn4i3.d.ts +43 -0
- package/dist/epistemicEdges.d.ts +8 -1
- package/dist/epistemicEdges.handlers.d.ts +20 -0
- package/dist/epistemicEdges.handlers.js +289 -0
- package/dist/epistemicEdges.handlers.js.map +1 -0
- package/dist/epistemicEdges.helpers.d.ts +27 -0
- package/dist/epistemicEdges.helpers.js +162 -0
- package/dist/epistemicEdges.helpers.js.map +1 -0
- package/dist/epistemicEdges.js +797 -875
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.d.ts +39 -0
- package/dist/epistemicEdges.mutations.js +1365 -0
- package/dist/epistemicEdges.mutations.js.map +1 -0
- package/dist/epistemicEdges.queries.d.ts +95 -0
- package/dist/epistemicEdges.queries.js +851 -0
- package/dist/epistemicEdges.queries.js.map +1 -0
- package/dist/epistemicEdges.types.d.ts +32 -0
- package/dist/epistemicEdges.types.js +3 -0
- package/dist/epistemicEdges.types.js.map +1 -0
- package/dist/epistemicEvidence-DvfchNt7.d.ts +46 -0
- package/dist/epistemicEvidence.d.ts +5 -2
- package/dist/epistemicEvidence.js +801 -807
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.d.ts +71 -0
- package/dist/epistemicEvidenceHelpers.js +769 -0
- package/dist/epistemicEvidenceHelpers.js.map +1 -0
- package/dist/epistemicEvidenceMutations.d.ts +10 -0
- package/dist/epistemicEvidenceMutations.js +1421 -0
- package/dist/epistemicEvidenceMutations.js.map +1 -0
- package/dist/epistemicEvidenceQueries.d.ts +10 -0
- package/dist/epistemicEvidenceQueries.js +1049 -0
- package/dist/epistemicEvidenceQueries.js.map +1 -0
- package/dist/epistemicHelpers.d.ts +4 -2
- package/dist/epistemicHelpers.js +132 -127
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicLayerRules.d.ts +138 -0
- package/dist/epistemicLayerRules.js +481 -0
- package/dist/epistemicLayerRules.js.map +1 -0
- package/dist/epistemicLinking.js +1 -1
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodeCreation.d.ts +101 -0
- package/dist/epistemicNodeCreation.js +709 -0
- package/dist/epistemicNodeCreation.js.map +1 -0
- package/dist/epistemicNodes-BCQxpYx_.d.ts +54 -0
- package/dist/epistemicNodes.d.ts +5 -1
- package/dist/epistemicNodes.helpers.d.ts +51 -0
- package/dist/epistemicNodes.helpers.js +73 -0
- package/dist/epistemicNodes.helpers.js.map +1 -0
- package/dist/epistemicNodes.internal.d.ts +34 -0
- package/dist/epistemicNodes.internal.js +658 -0
- package/dist/epistemicNodes.internal.js.map +1 -0
- package/dist/epistemicNodes.js +698 -693
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.d.ts +34 -0
- package/dist/epistemicNodes.mutations.js +1153 -0
- package/dist/epistemicNodes.mutations.js.map +1 -0
- package/dist/epistemicNodes.queries.d.ts +36 -0
- package/dist/epistemicNodes.queries.js +619 -0
- package/dist/epistemicNodes.queries.js.map +1 -0
- package/dist/epistemicNodes.validators.d.ts +23 -0
- package/dist/epistemicNodes.validators.js +105 -0
- package/dist/epistemicNodes.validators.js.map +1 -0
- package/dist/epistemicQuestions-bwHd2FWE.d.ts +68 -0
- package/dist/epistemicQuestions.conviction.d.ts +52 -0
- package/dist/epistemicQuestions.conviction.js +1389 -0
- package/dist/epistemicQuestions.conviction.js.map +1 -0
- package/dist/epistemicQuestions.create.d.ts +29 -0
- package/dist/epistemicQuestions.create.js +1300 -0
- package/dist/epistemicQuestions.create.js.map +1 -0
- package/dist/epistemicQuestions.d.ts +10 -2
- package/dist/epistemicQuestions.evidence.d.ts +22 -0
- package/dist/epistemicQuestions.evidence.js +929 -0
- package/dist/epistemicQuestions.evidence.js.map +1 -0
- package/dist/epistemicQuestions.helpers.d.ts +69 -0
- package/dist/epistemicQuestions.helpers.js +824 -0
- package/dist/epistemicQuestions.helpers.js.map +1 -0
- package/dist/epistemicQuestions.js +2435 -2430
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.d.ts +24 -0
- package/dist/epistemicQuestions.lifecycle.js +838 -0
- package/dist/epistemicQuestions.lifecycle.js.map +1 -0
- package/dist/epistemicQuestions.queries.d.ts +41 -0
- package/dist/epistemicQuestions.queries.js +1013 -0
- package/dist/epistemicQuestions.queries.js.map +1 -0
- package/dist/epistemicQuestions.sprint.d.ts +22 -0
- package/dist/epistemicQuestions.sprint.js +757 -0
- package/dist/epistemicQuestions.sprint.js.map +1 -0
- package/dist/epistemicQuestions.tail.d.ts +42 -0
- package/dist/epistemicQuestions.tail.js +1345 -0
- package/dist/epistemicQuestions.tail.js.map +1 -0
- package/dist/epistemicSources.js +6 -2
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.d.ts +2 -2
- package/dist/evaluators/index.js +45 -5320
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/lintCheckerEvaluator.d.ts +1 -1
- package/dist/evaluators/sentryCheckerEvaluator.d.ts +1 -1
- package/dist/evaluators/testRunnerEvaluator.d.ts +1 -1
- package/dist/evaluators/tscCheckerEvaluator.d.ts +1 -1
- package/dist/{graphTypes-CpgIuCdo.d.ts → graphTypes-B8VaIjnl.d.ts} +1 -1
- package/dist/graphTypes.d.ts +1 -1
- package/dist/{helpers-BYHIk5vU.d.ts → helpers-DNYfg6mo.d.ts} +2 -3
- package/dist/helpers.d.ts +2 -2
- package/dist/helpers.js.map +1 -1
- package/dist/{index-Dq-7R-gi.d.ts → index-C-Kyd7hD.d.ts} +1 -1
- package/dist/index.d.ts +160 -14
- package/dist/index.js +12291 -13001
- package/dist/index.js.map +1 -1
- package/dist/logicalRoleInference.js.map +1 -1
- package/dist/ontologyApproval.js +1 -1
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.js +25 -7
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/questionEvidenceLinks.js +28 -7
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/resolvers.js.map +1 -1
- package/dist/scopeResolverCompat.js.map +1 -1
- package/dist/topicProjectOverlay.js.map +1 -1
- package/dist/topicScope.js.map +1 -1
- package/dist/workflowBridge.js.map +1 -1
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +4 -5
- package/dist/edgeValidation-CeI0wc0r.d.ts +0 -35
- package/dist/epistemicBeliefs-DzKjZAeC.d.ts +0 -377
- package/dist/epistemicEdges-CvlKnEyy.d.ts +0 -191
- package/dist/epistemicEvidence-xw6UUrwh.d.ts +0 -128
- package/dist/epistemicHelpers-DevrYgPN.d.ts +0 -329
- package/dist/epistemicNodes-DjSUfvyD.d.ts +0 -167
- package/dist/epistemicQuestions-B_nUclrH.d.ts +0 -214
- package/dist/index-Dct1T70K.d.ts +0 -25
|
@@ -0,0 +1,851 @@
|
|
|
1
|
+
import { v } from 'convex/values';
|
|
2
|
+
import { checkScopeAccess } from '@lucern/access-control/access';
|
|
3
|
+
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
4
|
+
import { componentsGeneric, queryGeneric, anyApi } from 'convex/server';
|
|
5
|
+
|
|
6
|
+
// src/epistemicEdges.queries.ts
|
|
7
|
+
|
|
8
|
+
// src/debug.ts
|
|
9
|
+
function isGraphPrimitiveDebugEnabled() {
|
|
10
|
+
const env = globalThis.process?.env;
|
|
11
|
+
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
12
|
+
}
|
|
13
|
+
function debugGraphPrimitiveFallback(message, context) {
|
|
14
|
+
if (!isGraphPrimitiveDebugEnabled()) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
console.debug(message, context ?? {});
|
|
18
|
+
}
|
|
19
|
+
var api = anyApi;
|
|
20
|
+
componentsGeneric();
|
|
21
|
+
var query = queryGeneric;
|
|
22
|
+
v.union(
|
|
23
|
+
v.literal("L4"),
|
|
24
|
+
v.literal("L3"),
|
|
25
|
+
v.literal("L2"),
|
|
26
|
+
v.literal("L1"),
|
|
27
|
+
v.literal("ontological"),
|
|
28
|
+
v.literal("organizational")
|
|
29
|
+
);
|
|
30
|
+
v.object({
|
|
31
|
+
b: v.number(),
|
|
32
|
+
d: v.number(),
|
|
33
|
+
u: v.number(),
|
|
34
|
+
a: v.number()
|
|
35
|
+
});
|
|
36
|
+
var edgeTypeValidator = v.union(
|
|
37
|
+
// --- L4 Decision Edges (Phase 2A) ---
|
|
38
|
+
v.literal("based_on_belief"),
|
|
39
|
+
v.literal("based_on_question"),
|
|
40
|
+
v.literal("blocked_by_contradiction"),
|
|
41
|
+
v.literal("informed_by_theme"),
|
|
42
|
+
// --- Evidence Flow (L2 → L3, L2 → L1) ---
|
|
43
|
+
v.literal("derived_from"),
|
|
44
|
+
v.literal("responds_to"),
|
|
45
|
+
v.literal("informs"),
|
|
46
|
+
v.literal("tests"),
|
|
47
|
+
v.literal("explores"),
|
|
48
|
+
v.literal("qualifies"),
|
|
49
|
+
// --- Synthesis (L2 → L2, L2 → L1) ---
|
|
50
|
+
// "based_on" removed — use "derived_from" instead
|
|
51
|
+
// --- Theme Relationships (L3 → L3) ---
|
|
52
|
+
v.literal("relates_to_thesis"),
|
|
53
|
+
v.literal("belongs_to"),
|
|
54
|
+
v.literal("plays_theme"),
|
|
55
|
+
v.literal("scoped_by"),
|
|
56
|
+
// --- Deal/Company ---
|
|
57
|
+
v.literal("evaluates"),
|
|
58
|
+
// --- People (ontological → ontological, ontological → L3) ---
|
|
59
|
+
v.literal("perspective_on"),
|
|
60
|
+
v.literal("works_at"),
|
|
61
|
+
v.literal("mentioned_in"),
|
|
62
|
+
v.literal("founded_by"),
|
|
63
|
+
// --- Value Chain (ontological → ontological) ---
|
|
64
|
+
v.literal("participates_in"),
|
|
65
|
+
v.literal("performs"),
|
|
66
|
+
v.literal("function_in"),
|
|
67
|
+
v.literal("impacts"),
|
|
68
|
+
// --- Investment (ontological → ontological) ---
|
|
69
|
+
v.literal("invested_in"),
|
|
70
|
+
v.literal("raised_from"),
|
|
71
|
+
// --- Lifecycle (same layer only) ---
|
|
72
|
+
v.literal("supersedes"),
|
|
73
|
+
v.literal("same_as"),
|
|
74
|
+
// --- Same-Type Relationships: Belief ↔ Belief (L3 → L3) ---
|
|
75
|
+
v.literal("depends_on"),
|
|
76
|
+
v.literal("supports"),
|
|
77
|
+
v.literal("contains"),
|
|
78
|
+
// --- Belief Cluster Mapping (L3 → L3) ---
|
|
79
|
+
v.literal("counterfactual_of"),
|
|
80
|
+
v.literal("cascade_to"),
|
|
81
|
+
v.literal("cascade_from"),
|
|
82
|
+
v.literal("mutually_exclusive"),
|
|
83
|
+
v.literal("correlates_with"),
|
|
84
|
+
v.literal("amplifies"),
|
|
85
|
+
v.literal("precondition_for"),
|
|
86
|
+
v.literal("in_tension_with"),
|
|
87
|
+
// --- Belief ↔ Belief: Epistemic Impact (Confidence Propagation) ---
|
|
88
|
+
v.literal("falsified_by"),
|
|
89
|
+
v.literal("exclusive_with"),
|
|
90
|
+
v.literal("contradicts"),
|
|
91
|
+
v.literal("collapses_if"),
|
|
92
|
+
v.literal("strengthened_by"),
|
|
93
|
+
v.literal("weakened_by"),
|
|
94
|
+
v.literal("alternative_to"),
|
|
95
|
+
v.literal("subsumes"),
|
|
96
|
+
v.literal("validated_by"),
|
|
97
|
+
v.literal("required_for"),
|
|
98
|
+
v.literal("blocks"),
|
|
99
|
+
// --- Same-Type Relationships: Question ↔ Question (L3 → L3) ---
|
|
100
|
+
v.literal("prerequisite_for"),
|
|
101
|
+
v.literal("parallel_to"),
|
|
102
|
+
// --- Same-Type Relationships: Evidence ↔ Evidence (L2 → L2) ---
|
|
103
|
+
v.literal("corroborates"),
|
|
104
|
+
v.literal("extends"),
|
|
105
|
+
v.literal("same_source_as"),
|
|
106
|
+
v.literal("same_theme_as"),
|
|
107
|
+
// --- NEW: Deep Epistemic Analysis Edges (Phase: Schema Upgrade) ---
|
|
108
|
+
v.literal("assumes"),
|
|
109
|
+
v.literal("would_predict"),
|
|
110
|
+
v.literal("analogous_to"),
|
|
111
|
+
v.literal("independent_of"),
|
|
112
|
+
// --- Entity↔Belief Bridge (OE-B) ---
|
|
113
|
+
v.literal("competes_with")
|
|
114
|
+
);
|
|
115
|
+
function edgeMatchesWorkspaceReasoningScope(edge, scope) {
|
|
116
|
+
return scope.topicId !== void 0 && edge.topicId === scope.topicId || scope.projectId !== void 0 && edge.projectId === scope.projectId;
|
|
117
|
+
}
|
|
118
|
+
async function collectScopedEdges(ctx, scope, scanLimit) {
|
|
119
|
+
const queries = [];
|
|
120
|
+
if (scope.topicId) {
|
|
121
|
+
queries.push(
|
|
122
|
+
ctx.db.query("epistemicEdges").withIndex(
|
|
123
|
+
"by_topic",
|
|
124
|
+
(q) => q.eq("topicId", scope.topicId)
|
|
125
|
+
).order("desc").take(scanLimit)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
if (scope.projectId) {
|
|
129
|
+
queries.push(
|
|
130
|
+
ctx.db.query("epistemicEdges").withIndex(
|
|
131
|
+
"by_topic",
|
|
132
|
+
(q) => q.eq("topicId", scope.projectId)
|
|
133
|
+
).order("desc").take(scanLimit)
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
const seen = /* @__PURE__ */ new Set();
|
|
137
|
+
const deduped = [];
|
|
138
|
+
const flattened = (await Promise.all(queries)).flat();
|
|
139
|
+
for (const edge of flattened) {
|
|
140
|
+
const key = String(edge._id);
|
|
141
|
+
if (seen.has(key)) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
seen.add(key);
|
|
145
|
+
deduped.push(edge);
|
|
146
|
+
}
|
|
147
|
+
return deduped;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/graphTypes.ts
|
|
151
|
+
function getNodeLayer(nodeType) {
|
|
152
|
+
const L4_TYPES = ["decision"];
|
|
153
|
+
const L3_TYPES = ["belief", "question", "theme", "deal"];
|
|
154
|
+
const L2_TYPES = ["claim", "evidence", "synthesis", "answer"];
|
|
155
|
+
const L1_TYPES = ["atomic_fact", "excerpt", "source"];
|
|
156
|
+
const ONTOLOGICAL_TYPES = [
|
|
157
|
+
"company",
|
|
158
|
+
"person",
|
|
159
|
+
"investor",
|
|
160
|
+
"function",
|
|
161
|
+
"value_chain"
|
|
162
|
+
];
|
|
163
|
+
const ORGANIZATIONAL_TYPES = ["topic"];
|
|
164
|
+
if (L4_TYPES.includes(nodeType)) {
|
|
165
|
+
return "L4";
|
|
166
|
+
}
|
|
167
|
+
if (L3_TYPES.includes(nodeType)) {
|
|
168
|
+
return "L3";
|
|
169
|
+
}
|
|
170
|
+
if (L2_TYPES.includes(nodeType)) {
|
|
171
|
+
return "L2";
|
|
172
|
+
}
|
|
173
|
+
if (L1_TYPES.includes(nodeType)) {
|
|
174
|
+
return "L1";
|
|
175
|
+
}
|
|
176
|
+
if (ONTOLOGICAL_TYPES.includes(nodeType)) {
|
|
177
|
+
return "ontological";
|
|
178
|
+
}
|
|
179
|
+
if (ORGANIZATIONAL_TYPES.includes(nodeType)) {
|
|
180
|
+
return "organizational";
|
|
181
|
+
}
|
|
182
|
+
console.warn(`[GraphTypes] Unknown nodeType "${nodeType}", defaulting to L2`);
|
|
183
|
+
return "L2";
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/edgeValidation.ts
|
|
187
|
+
function getLayerDepth(layer) {
|
|
188
|
+
switch (layer) {
|
|
189
|
+
case "L4":
|
|
190
|
+
return 4;
|
|
191
|
+
case "L3":
|
|
192
|
+
return 3;
|
|
193
|
+
case "L2":
|
|
194
|
+
return 2;
|
|
195
|
+
case "L1":
|
|
196
|
+
return 1;
|
|
197
|
+
case "ontological":
|
|
198
|
+
return 0;
|
|
199
|
+
default:
|
|
200
|
+
return -1;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function shouldContinueTraversal(currentLayer, targetLayer, options) {
|
|
204
|
+
const currentDepth = getLayerDepth(currentLayer);
|
|
205
|
+
const targetDepth = getLayerDepth(targetLayer);
|
|
206
|
+
if (options.minLayer !== void 0 && targetDepth < options.minLayer) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
if (options.maxLayer !== void 0 && targetDepth > options.maxLayer) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
switch (options.mode) {
|
|
213
|
+
case "anchor_down":
|
|
214
|
+
return targetDepth <= currentDepth;
|
|
215
|
+
case "anchor_up":
|
|
216
|
+
return targetDepth >= currentDepth;
|
|
217
|
+
case "same_layer":
|
|
218
|
+
return targetDepth === currentDepth;
|
|
219
|
+
case "decision_trace":
|
|
220
|
+
return currentDepth === 4 ? targetDepth === 3 : targetDepth === currentDepth;
|
|
221
|
+
default:
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function getDefaultMinLayer(mode) {
|
|
226
|
+
switch (mode) {
|
|
227
|
+
case "anchor_down":
|
|
228
|
+
return 1;
|
|
229
|
+
case "anchor_up":
|
|
230
|
+
return 2;
|
|
231
|
+
case "same_layer":
|
|
232
|
+
return 1;
|
|
233
|
+
case "decision_trace":
|
|
234
|
+
return 3;
|
|
235
|
+
default:
|
|
236
|
+
return 1;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
240
|
+
function asMappedProjectId(topic) {
|
|
241
|
+
if (!topic) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
245
|
+
if (directLegacyProjectId) {
|
|
246
|
+
return directLegacyProjectId;
|
|
247
|
+
}
|
|
248
|
+
const metadata = topic.metadata || {};
|
|
249
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
250
|
+
return candidate ? candidate : void 0;
|
|
251
|
+
}
|
|
252
|
+
function normalizeScopeValue(value) {
|
|
253
|
+
if (typeof value !== "string") {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const normalized = value.trim();
|
|
257
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
258
|
+
}
|
|
259
|
+
function pickPrimaryTopic(candidates) {
|
|
260
|
+
return [...candidates].sort((a, b) => {
|
|
261
|
+
const depthA = a.depth ?? 9999;
|
|
262
|
+
const depthB = b.depth ?? 9999;
|
|
263
|
+
if (depthA !== depthB) {
|
|
264
|
+
return depthA - depthB;
|
|
265
|
+
}
|
|
266
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
267
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
268
|
+
if (createdA !== createdB) {
|
|
269
|
+
return createdA - createdB;
|
|
270
|
+
}
|
|
271
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
272
|
+
})[0];
|
|
273
|
+
}
|
|
274
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
275
|
+
try {
|
|
276
|
+
return await ctx.db.query("topics").withIndex(
|
|
277
|
+
"by_graph_scope_project",
|
|
278
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
279
|
+
).collect();
|
|
280
|
+
} catch (error) {
|
|
281
|
+
debugGraphPrimitiveFallback(
|
|
282
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
283
|
+
{
|
|
284
|
+
error,
|
|
285
|
+
scopeId
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
const topics = await ctx.db.query("topics").collect();
|
|
289
|
+
return topics.filter((topic) => {
|
|
290
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
291
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
292
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
297
|
+
if (typeof ctx.runQuery !== "function") {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
try {
|
|
301
|
+
return await ctx.runQuery(api.topics.get, {
|
|
302
|
+
id: topicId
|
|
303
|
+
}) ?? null;
|
|
304
|
+
} catch (error) {
|
|
305
|
+
debugGraphPrimitiveFallback(
|
|
306
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
307
|
+
{
|
|
308
|
+
error,
|
|
309
|
+
topicId
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
316
|
+
if (typeof ctx.runQuery !== "function") {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
321
|
+
projectId: legacyScopeId
|
|
322
|
+
}) ?? null;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
debugGraphPrimitiveFallback(
|
|
325
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
326
|
+
{
|
|
327
|
+
error,
|
|
328
|
+
legacyScopeId
|
|
329
|
+
}
|
|
330
|
+
);
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
335
|
+
const MAX_DEPTH = 10;
|
|
336
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
337
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
338
|
+
if (tenantId && workspaceId) {
|
|
339
|
+
return { tenantId, workspaceId };
|
|
340
|
+
}
|
|
341
|
+
let current = topic;
|
|
342
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
343
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
344
|
+
if (!current) break;
|
|
345
|
+
if (!tenantId) {
|
|
346
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
347
|
+
}
|
|
348
|
+
if (!workspaceId) {
|
|
349
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
350
|
+
}
|
|
351
|
+
if (tenantId && workspaceId) break;
|
|
352
|
+
}
|
|
353
|
+
return { tenantId, workspaceId };
|
|
354
|
+
}
|
|
355
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
356
|
+
if (args.topicId) {
|
|
357
|
+
let topic = null;
|
|
358
|
+
try {
|
|
359
|
+
topic = await ctx.db.get(
|
|
360
|
+
args.topicId
|
|
361
|
+
);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
debugGraphPrimitiveFallback(
|
|
364
|
+
"[topicScope] Failed to load topic by direct id",
|
|
365
|
+
{
|
|
366
|
+
error,
|
|
367
|
+
topicId: args.topicId
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
if (!topic) {
|
|
372
|
+
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
373
|
+
}
|
|
374
|
+
if (!topic) {
|
|
375
|
+
topic = pickPrimaryTopic(
|
|
376
|
+
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
377
|
+
) ?? null;
|
|
378
|
+
}
|
|
379
|
+
if (!topic) {
|
|
380
|
+
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
381
|
+
}
|
|
382
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
383
|
+
const mapped = asMappedProjectId(topic);
|
|
384
|
+
if (mapped) {
|
|
385
|
+
return {
|
|
386
|
+
topicId: topic._id,
|
|
387
|
+
projectId: mapped,
|
|
388
|
+
tenantId: inherited.tenantId,
|
|
389
|
+
workspaceId: inherited.workspaceId,
|
|
390
|
+
source: "topic"
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
topicId: topic._id,
|
|
395
|
+
tenantId: inherited.tenantId,
|
|
396
|
+
workspaceId: inherited.workspaceId,
|
|
397
|
+
source: "topic"
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
if (args.projectId) {
|
|
401
|
+
let directTopic = null;
|
|
402
|
+
try {
|
|
403
|
+
directTopic = await ctx.db.get(
|
|
404
|
+
args.projectId
|
|
405
|
+
);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
debugGraphPrimitiveFallback(
|
|
408
|
+
"[topicScope] Failed to load direct project topic",
|
|
409
|
+
{
|
|
410
|
+
error,
|
|
411
|
+
projectId: args.projectId
|
|
412
|
+
}
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
if (directTopic) {
|
|
416
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
417
|
+
const mapped = asMappedProjectId(directTopic);
|
|
418
|
+
return {
|
|
419
|
+
topicId: directTopic._id,
|
|
420
|
+
projectId: mapped ?? args.projectId,
|
|
421
|
+
tenantId: inherited.tenantId,
|
|
422
|
+
workspaceId: inherited.workspaceId,
|
|
423
|
+
source: "topic_inferred"
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
427
|
+
if (directTopic) {
|
|
428
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
429
|
+
const mapped = asMappedProjectId(directTopic);
|
|
430
|
+
return {
|
|
431
|
+
topicId: directTopic._id,
|
|
432
|
+
projectId: mapped ?? args.projectId,
|
|
433
|
+
tenantId: inherited.tenantId,
|
|
434
|
+
workspaceId: inherited.workspaceId,
|
|
435
|
+
source: "topic_inferred"
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
439
|
+
const primary = pickPrimaryTopic(topics);
|
|
440
|
+
if (primary) {
|
|
441
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
442
|
+
return {
|
|
443
|
+
topicId: primary._id,
|
|
444
|
+
projectId: args.projectId,
|
|
445
|
+
tenantId: inherited.tenantId,
|
|
446
|
+
workspaceId: inherited.workspaceId,
|
|
447
|
+
source: "project_mapped_topic"
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
throw new Error(
|
|
451
|
+
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
throw new Error(
|
|
455
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
var optionalScopeArgs = {
|
|
459
|
+
projectId: v.optional(v.string()),
|
|
460
|
+
topicId: v.optional(v.string())
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
// src/epistemicEdges.queries.ts
|
|
464
|
+
var get = query({
|
|
465
|
+
args: { edgeId: v.id("epistemicEdges") },
|
|
466
|
+
returns: permissiveReturn,
|
|
467
|
+
handler: async (ctx, args) => {
|
|
468
|
+
return await ctx.db.get(args.edgeId);
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
var getByGlobalId = query({
|
|
472
|
+
args: { globalId: v.string() },
|
|
473
|
+
returns: permissiveReturn,
|
|
474
|
+
handler: async (ctx, args) => {
|
|
475
|
+
return await ctx.db.query("epistemicEdges").withIndex("by_globalId", (q) => q.eq("globalId", args.globalId)).first();
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
var getFromNode = query({
|
|
479
|
+
args: {
|
|
480
|
+
fromNodeId: v.id("epistemicNodes"),
|
|
481
|
+
edgeType: v.optional(edgeTypeValidator)
|
|
482
|
+
},
|
|
483
|
+
returns: permissiveReturn,
|
|
484
|
+
handler: async (ctx, args) => {
|
|
485
|
+
const { edgeType } = args;
|
|
486
|
+
if (edgeType) {
|
|
487
|
+
return await ctx.db.query("epistemicEdges").withIndex(
|
|
488
|
+
"by_from_type",
|
|
489
|
+
(q) => q.eq("fromNodeId", args.fromNodeId).eq("edgeType", edgeType)
|
|
490
|
+
).collect();
|
|
491
|
+
}
|
|
492
|
+
return await ctx.db.query("epistemicEdges").withIndex("by_from", (q) => q.eq("fromNodeId", args.fromNodeId)).collect();
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
var getToNode = query({
|
|
496
|
+
args: {
|
|
497
|
+
toNodeId: v.id("epistemicNodes"),
|
|
498
|
+
edgeType: v.optional(edgeTypeValidator)
|
|
499
|
+
},
|
|
500
|
+
returns: permissiveReturn,
|
|
501
|
+
handler: async (ctx, args) => {
|
|
502
|
+
const { edgeType } = args;
|
|
503
|
+
if (edgeType) {
|
|
504
|
+
return await ctx.db.query("epistemicEdges").withIndex(
|
|
505
|
+
"by_to_type",
|
|
506
|
+
(q) => q.eq("toNodeId", args.toNodeId).eq("edgeType", edgeType)
|
|
507
|
+
).collect();
|
|
508
|
+
}
|
|
509
|
+
return await ctx.db.query("epistemicEdges").withIndex("by_to", (q) => q.eq("toNodeId", args.toNodeId)).collect();
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
var getBySourceNode = query({
|
|
513
|
+
args: {
|
|
514
|
+
sourceNodeId: v.string(),
|
|
515
|
+
edgeType: v.optional(v.string())
|
|
516
|
+
},
|
|
517
|
+
returns: permissiveReturn,
|
|
518
|
+
handler: async (ctx, args) => {
|
|
519
|
+
const isConvexId = args.sourceNodeId.length === 32 || args.sourceNodeId.includes("epistemicNodes");
|
|
520
|
+
if (isConvexId) {
|
|
521
|
+
const query2 = args.edgeType ? ctx.db.query("epistemicEdges").withIndex(
|
|
522
|
+
"by_from_type",
|
|
523
|
+
(q) => q.eq("fromNodeId", args.sourceNodeId).eq("edgeType", args.edgeType)
|
|
524
|
+
) : ctx.db.query("epistemicEdges").withIndex(
|
|
525
|
+
"by_from",
|
|
526
|
+
(q) => q.eq("fromNodeId", args.sourceNodeId)
|
|
527
|
+
);
|
|
528
|
+
return await query2.collect();
|
|
529
|
+
}
|
|
530
|
+
const byGlobalId = await ctx.db.query("epistemicEdges").withIndex(
|
|
531
|
+
"by_source_global_id",
|
|
532
|
+
(q) => q.eq("sourceGlobalId", args.sourceNodeId)
|
|
533
|
+
).collect();
|
|
534
|
+
if (args.edgeType) {
|
|
535
|
+
return byGlobalId.filter((edge) => edge.edgeType === args.edgeType);
|
|
536
|
+
}
|
|
537
|
+
return byGlobalId;
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
var getByTargetNode = query({
|
|
541
|
+
args: {
|
|
542
|
+
targetNodeId: v.string(),
|
|
543
|
+
edgeType: v.optional(v.string())
|
|
544
|
+
},
|
|
545
|
+
returns: permissiveReturn,
|
|
546
|
+
handler: async (ctx, args) => {
|
|
547
|
+
const isConvexId = args.targetNodeId.length === 32 || args.targetNodeId.includes("epistemicNodes");
|
|
548
|
+
if (isConvexId) {
|
|
549
|
+
const query2 = args.edgeType ? ctx.db.query("epistemicEdges").withIndex(
|
|
550
|
+
"by_to_type",
|
|
551
|
+
(q) => q.eq("toNodeId", args.targetNodeId).eq("edgeType", args.edgeType)
|
|
552
|
+
) : ctx.db.query("epistemicEdges").withIndex(
|
|
553
|
+
"by_to",
|
|
554
|
+
(q) => q.eq("toNodeId", args.targetNodeId)
|
|
555
|
+
);
|
|
556
|
+
return await query2.collect();
|
|
557
|
+
}
|
|
558
|
+
const byGlobalId = await ctx.db.query("epistemicEdges").withIndex(
|
|
559
|
+
"by_target_global_id",
|
|
560
|
+
(q) => q.eq("targetGlobalId", args.targetNodeId)
|
|
561
|
+
).collect();
|
|
562
|
+
if (args.edgeType) {
|
|
563
|
+
return byGlobalId.filter((edge) => edge.edgeType === args.edgeType);
|
|
564
|
+
}
|
|
565
|
+
return byGlobalId;
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
var getBetween = query({
|
|
569
|
+
args: {
|
|
570
|
+
fromNodeId: v.id("epistemicNodes"),
|
|
571
|
+
toNodeId: v.id("epistemicNodes"),
|
|
572
|
+
edgeType: v.optional(edgeTypeValidator)
|
|
573
|
+
},
|
|
574
|
+
returns: permissiveReturn,
|
|
575
|
+
handler: async (ctx, args) => {
|
|
576
|
+
const edges = await ctx.db.query("epistemicEdges").withIndex(
|
|
577
|
+
"by_from_to",
|
|
578
|
+
(q) => q.eq("fromNodeId", args.fromNodeId).eq("toNodeId", args.toNodeId)
|
|
579
|
+
).collect();
|
|
580
|
+
if (args.edgeType) {
|
|
581
|
+
return edges.filter((e) => e.edgeType === args.edgeType);
|
|
582
|
+
}
|
|
583
|
+
return edges;
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
var getByNodes = query({
|
|
587
|
+
args: {
|
|
588
|
+
fromNodeId: v.id("epistemicNodes"),
|
|
589
|
+
toNodeId: v.id("epistemicNodes")
|
|
590
|
+
},
|
|
591
|
+
returns: permissiveReturn,
|
|
592
|
+
handler: async (ctx, args) => {
|
|
593
|
+
return await ctx.db.query("epistemicEdges").withIndex(
|
|
594
|
+
"by_from_to",
|
|
595
|
+
(q) => q.eq("fromNodeId", args.fromNodeId).eq("toNodeId", args.toNodeId)
|
|
596
|
+
).first();
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
var getByProjectAndType = query({
|
|
600
|
+
args: {
|
|
601
|
+
...optionalScopeArgs,
|
|
602
|
+
edgeType: edgeTypeValidator
|
|
603
|
+
},
|
|
604
|
+
returns: permissiveReturn,
|
|
605
|
+
handler: async (ctx, args) => {
|
|
606
|
+
if (!args.projectId && !args.topicId) {
|
|
607
|
+
return [];
|
|
608
|
+
}
|
|
609
|
+
let scope;
|
|
610
|
+
try {
|
|
611
|
+
scope = await resolveTopicProjectScope(ctx, {
|
|
612
|
+
projectId: args.projectId,
|
|
613
|
+
topicId: args.topicId
|
|
614
|
+
});
|
|
615
|
+
} catch (error) {
|
|
616
|
+
debugGraphPrimitiveFallback(
|
|
617
|
+
"[epistemicEdges] Failed to resolve getAll scope",
|
|
618
|
+
{
|
|
619
|
+
error,
|
|
620
|
+
projectId: args.projectId,
|
|
621
|
+
topicId: args.topicId
|
|
622
|
+
}
|
|
623
|
+
);
|
|
624
|
+
return [];
|
|
625
|
+
}
|
|
626
|
+
const projectEdges = await collectScopedEdges(ctx, scope, 5e3);
|
|
627
|
+
return projectEdges.filter(
|
|
628
|
+
(e) => e.edgeType === args.edgeType && edgeMatchesWorkspaceReasoningScope(e, scope)
|
|
629
|
+
).slice(0, 5e3);
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
var getByProject = query({
|
|
633
|
+
args: {
|
|
634
|
+
...optionalScopeArgs,
|
|
635
|
+
userId: v.optional(v.string()),
|
|
636
|
+
limit: v.optional(v.number())
|
|
637
|
+
},
|
|
638
|
+
returns: permissiveReturn,
|
|
639
|
+
handler: async (ctx, args) => {
|
|
640
|
+
if (!args.projectId && !args.topicId) {
|
|
641
|
+
return [];
|
|
642
|
+
}
|
|
643
|
+
let scope;
|
|
644
|
+
try {
|
|
645
|
+
scope = await resolveTopicProjectScope(ctx, {
|
|
646
|
+
projectId: args.projectId,
|
|
647
|
+
topicId: args.topicId
|
|
648
|
+
});
|
|
649
|
+
} catch (error) {
|
|
650
|
+
debugGraphPrimitiveFallback(
|
|
651
|
+
"[epistemicEdges] Failed to resolve getByProject scope",
|
|
652
|
+
{
|
|
653
|
+
error,
|
|
654
|
+
projectId: args.projectId,
|
|
655
|
+
topicId: args.topicId
|
|
656
|
+
}
|
|
657
|
+
);
|
|
658
|
+
return [];
|
|
659
|
+
}
|
|
660
|
+
if (args.userId) {
|
|
661
|
+
const hasAccess = await checkScopeAccess(
|
|
662
|
+
ctx,
|
|
663
|
+
String(scope.topicId ?? scope.projectId),
|
|
664
|
+
args.userId
|
|
665
|
+
);
|
|
666
|
+
if (!hasAccess) {
|
|
667
|
+
return [];
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
const pageSize = Math.max(1, Math.min(Math.floor(args.limit ?? 500), 2e3));
|
|
671
|
+
const edges = await collectScopedEdges(
|
|
672
|
+
ctx,
|
|
673
|
+
scope,
|
|
674
|
+
Math.min(pageSize * 3, 6e3)
|
|
675
|
+
);
|
|
676
|
+
return edges.filter((edge) => edgeMatchesWorkspaceReasoningScope(edge, scope)).slice(0, pageSize);
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
var listAll = query({
|
|
680
|
+
args: {
|
|
681
|
+
limit: v.optional(v.number())
|
|
682
|
+
},
|
|
683
|
+
returns: permissiveReturn,
|
|
684
|
+
handler: async (ctx, args) => {
|
|
685
|
+
const pageSize = Math.max(
|
|
686
|
+
1,
|
|
687
|
+
Math.min(Math.floor(args.limit ?? 5e3), 1e4)
|
|
688
|
+
);
|
|
689
|
+
return await ctx.db.query("epistemicEdges").order("desc").take(pageSize);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
var findContradictions = query({
|
|
693
|
+
args: {
|
|
694
|
+
nodeId: v.id("epistemicNodes")
|
|
695
|
+
},
|
|
696
|
+
returns: permissiveReturn,
|
|
697
|
+
handler: async (ctx, args) => {
|
|
698
|
+
const edges = await ctx.db.query("epistemicEdges").withIndex(
|
|
699
|
+
"by_to_type",
|
|
700
|
+
(q) => q.eq("toNodeId", args.nodeId).eq("edgeType", "informs")
|
|
701
|
+
).collect();
|
|
702
|
+
return edges.filter((e) => (e.weight ?? 0) < 0);
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
var findSupport = query({
|
|
706
|
+
args: {
|
|
707
|
+
nodeId: v.id("epistemicNodes")
|
|
708
|
+
},
|
|
709
|
+
returns: permissiveReturn,
|
|
710
|
+
handler: async (ctx, args) => {
|
|
711
|
+
const edges = await ctx.db.query("epistemicEdges").withIndex(
|
|
712
|
+
"by_to_type",
|
|
713
|
+
(q) => q.eq("toNodeId", args.nodeId).eq("edgeType", "informs")
|
|
714
|
+
).collect();
|
|
715
|
+
return edges.filter((e) => (e.weight ?? 0) >= 0);
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
var getLineage = query({
|
|
719
|
+
args: {
|
|
720
|
+
nodeId: v.id("epistemicNodes"),
|
|
721
|
+
maxDepth: v.optional(v.number()),
|
|
722
|
+
// Phase 2D: Layer-aware traversal options
|
|
723
|
+
minLayer: v.optional(v.number()),
|
|
724
|
+
// 1=L1, 2=L2, 3=L3, 4=L4
|
|
725
|
+
maxLayer: v.optional(v.number()),
|
|
726
|
+
mode: v.optional(
|
|
727
|
+
v.union(
|
|
728
|
+
v.literal("anchor_down"),
|
|
729
|
+
v.literal("anchor_up"),
|
|
730
|
+
v.literal("same_layer"),
|
|
731
|
+
v.literal("decision_trace")
|
|
732
|
+
)
|
|
733
|
+
)
|
|
734
|
+
},
|
|
735
|
+
returns: permissiveReturn,
|
|
736
|
+
handler: async (ctx, args) => {
|
|
737
|
+
const maxDepth = args.maxDepth ?? 10;
|
|
738
|
+
const mode = args.mode ?? "anchor_down";
|
|
739
|
+
const minLayer = args.minLayer ?? getDefaultMinLayer(mode);
|
|
740
|
+
const maxLayer = args.maxLayer ?? 4;
|
|
741
|
+
const lineage = [];
|
|
742
|
+
const visited = /* @__PURE__ */ new Set();
|
|
743
|
+
const startNode = await ctx.db.get(args.nodeId);
|
|
744
|
+
if (!startNode) {
|
|
745
|
+
return lineage;
|
|
746
|
+
}
|
|
747
|
+
const startLayer = startNode.epistemicLayer || getNodeLayer(startNode.nodeType);
|
|
748
|
+
const queue = [{ nodeId: args.nodeId, depth: 0, currentLayer: startLayer }];
|
|
749
|
+
while (queue.length > 0) {
|
|
750
|
+
const current = queue.shift();
|
|
751
|
+
if (!current || current.depth >= maxDepth) {
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
const nodeIdStr = current.nodeId.toString();
|
|
755
|
+
if (visited.has(nodeIdStr)) {
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
visited.add(nodeIdStr);
|
|
759
|
+
const edges = await ctx.db.query("epistemicEdges").withIndex("by_from", (q) => q.eq("fromNodeId", current.nodeId)).collect();
|
|
760
|
+
const lineageEdges = edges.filter((e) => e.edgeType === "derived_from");
|
|
761
|
+
for (const edge of lineageEdges) {
|
|
762
|
+
if (!edge.toNodeId) {
|
|
763
|
+
continue;
|
|
764
|
+
}
|
|
765
|
+
const targetNode = await ctx.db.get(edge.toNodeId);
|
|
766
|
+
if (!targetNode || visited.has(edge.toNodeId.toString())) {
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
const targetLayer = edge.toLayer || targetNode.epistemicLayer || getNodeLayer(targetNode.nodeType);
|
|
770
|
+
const shouldContinue = shouldContinueTraversal(
|
|
771
|
+
current.currentLayer,
|
|
772
|
+
targetLayer,
|
|
773
|
+
{ mode, minLayer, maxLayer }
|
|
774
|
+
);
|
|
775
|
+
if (!shouldContinue) {
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
lineage.push({
|
|
779
|
+
node: targetNode,
|
|
780
|
+
depth: current.depth + 1,
|
|
781
|
+
edgeType: edge.edgeType,
|
|
782
|
+
layer: targetLayer
|
|
783
|
+
});
|
|
784
|
+
queue.push({
|
|
785
|
+
nodeId: edge.toNodeId,
|
|
786
|
+
depth: current.depth + 1,
|
|
787
|
+
currentLayer: targetLayer
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
return lineage;
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
var getEvidenceForBelief = query({
|
|
795
|
+
args: {
|
|
796
|
+
beliefNodeId: v.id("epistemicNodes")
|
|
797
|
+
},
|
|
798
|
+
returns: permissiveReturn,
|
|
799
|
+
handler: async (ctx, args) => {
|
|
800
|
+
const informsEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
801
|
+
"by_to_type",
|
|
802
|
+
(q) => q.eq("toNodeId", args.beliefNodeId).eq("edgeType", "informs")
|
|
803
|
+
).collect();
|
|
804
|
+
const supportEdges = informsEdges.filter((e) => (e.weight ?? 0) >= 0);
|
|
805
|
+
const contradictEdges = informsEdges.filter((e) => (e.weight ?? 0) < 0);
|
|
806
|
+
const supportingEvidence = await Promise.all(
|
|
807
|
+
supportEdges.map(async (edge) => ({
|
|
808
|
+
edge,
|
|
809
|
+
node: await ctx.db.get(edge.fromNodeId)
|
|
810
|
+
}))
|
|
811
|
+
);
|
|
812
|
+
const contradictingEvidence = await Promise.all(
|
|
813
|
+
contradictEdges.map(async (edge) => ({
|
|
814
|
+
edge,
|
|
815
|
+
node: await ctx.db.get(edge.fromNodeId)
|
|
816
|
+
}))
|
|
817
|
+
);
|
|
818
|
+
const filteredSupporting = supportingEvidence.filter((e) => e.node !== null);
|
|
819
|
+
const filteredContradicting = contradictingEvidence.filter(
|
|
820
|
+
(e) => e.node !== null
|
|
821
|
+
);
|
|
822
|
+
return {
|
|
823
|
+
supporting: filteredSupporting,
|
|
824
|
+
contradicting: filteredContradicting,
|
|
825
|
+
supportCount: filteredSupporting.length,
|
|
826
|
+
contradictCount: filteredContradicting.length
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
var getClusterEdges = query({
|
|
831
|
+
args: {
|
|
832
|
+
beliefIds: v.array(v.string())
|
|
833
|
+
},
|
|
834
|
+
returns: permissiveReturn,
|
|
835
|
+
handler: async (ctx, args) => {
|
|
836
|
+
if (args.beliefIds.length === 0) {
|
|
837
|
+
return [];
|
|
838
|
+
}
|
|
839
|
+
const beliefIdSet = new Set(args.beliefIds);
|
|
840
|
+
const allEdges = await ctx.db.query("epistemicEdges").collect();
|
|
841
|
+
return allEdges.filter((edge) => {
|
|
842
|
+
const fromInCluster = beliefIdSet.has(String(edge.fromNodeId)) || edge.sourceGlobalId && beliefIdSet.has(edge.sourceGlobalId);
|
|
843
|
+
const toInCluster = beliefIdSet.has(String(edge.toNodeId)) || edge.targetGlobalId && beliefIdSet.has(edge.targetGlobalId);
|
|
844
|
+
return fromInCluster && toInCluster;
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
export { findContradictions, findSupport, get, getBetween, getByGlobalId, getByNodes, getByProject, getByProjectAndType, getBySourceNode, getByTargetNode, getClusterEdges, getEvidenceForBelief, getFromNode, getLineage, getToNode, listAll };
|
|
850
|
+
//# sourceMappingURL=epistemicEdges.queries.js.map
|
|
851
|
+
//# sourceMappingURL=epistemicEdges.queries.js.map
|