@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,761 @@
|
|
|
1
|
+
import { v } from 'convex/values';
|
|
2
|
+
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
3
|
+
import { componentsGeneric, anyApi, mutationGeneric, queryGeneric } from 'convex/server';
|
|
4
|
+
import { normalizeTupleContradictionPolicy } from '@lucern/confidence';
|
|
5
|
+
import { checkProjectAccess } from '@lucern/access-control/access';
|
|
6
|
+
import '@lucern/access-control/audience';
|
|
7
|
+
import { getCurrentUserId } from '@lucern/access-control/auth';
|
|
8
|
+
|
|
9
|
+
// src/epistemicBeliefs.links.ts
|
|
10
|
+
var api = anyApi;
|
|
11
|
+
componentsGeneric();
|
|
12
|
+
var internal = anyApi;
|
|
13
|
+
var mutation = mutationGeneric;
|
|
14
|
+
var query = queryGeneric;
|
|
15
|
+
|
|
16
|
+
// src/globalId.ts
|
|
17
|
+
function generateGlobalId() {
|
|
18
|
+
const bytes = new Uint8Array(16);
|
|
19
|
+
crypto.getRandomValues(bytes);
|
|
20
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
21
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
22
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join(
|
|
23
|
+
""
|
|
24
|
+
);
|
|
25
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/logicalRoleInference.ts
|
|
29
|
+
var PILLAR_IMPORTANCE = {
|
|
30
|
+
market: 1,
|
|
31
|
+
competition: 2,
|
|
32
|
+
product: 3,
|
|
33
|
+
team: 4,
|
|
34
|
+
financials: 5,
|
|
35
|
+
timing: 6,
|
|
36
|
+
other: 10
|
|
37
|
+
};
|
|
38
|
+
async function computeLogicalRole(ctx, evidenceId, beliefId) {
|
|
39
|
+
const belief = await ctx.db.get(beliefId);
|
|
40
|
+
if (!belief || belief.nodeType !== "belief") {
|
|
41
|
+
return "contributory";
|
|
42
|
+
}
|
|
43
|
+
const beliefMetadata = belief.metadata;
|
|
44
|
+
const pillar = beliefMetadata?.pillar || "other";
|
|
45
|
+
const pillarRank = PILLAR_IMPORTANCE[pillar] ?? 10;
|
|
46
|
+
const isSynthesized = await checkIfSynthesizedHypothesis(ctx, beliefId);
|
|
47
|
+
const testingQuestions = await getTestingQuestionsForBelief(ctx, beliefId);
|
|
48
|
+
const answeredQuestions = await getQuestionsAnsweredByEvidence(
|
|
49
|
+
ctx,
|
|
50
|
+
evidenceId
|
|
51
|
+
);
|
|
52
|
+
const directlyTests = testingQuestions.filter(
|
|
53
|
+
(questionId) => answeredQuestions.includes(questionId)
|
|
54
|
+
);
|
|
55
|
+
if (directlyTests.length === 0) {
|
|
56
|
+
return "contributory";
|
|
57
|
+
}
|
|
58
|
+
if (isSynthesized && pillarRank <= 2) {
|
|
59
|
+
return directlyTests.length > 1 ? "necessary_sufficient" : "necessary";
|
|
60
|
+
}
|
|
61
|
+
if (isSynthesized) {
|
|
62
|
+
return "necessary";
|
|
63
|
+
}
|
|
64
|
+
return directlyTests.length > 1 ? "necessary" : "contributory";
|
|
65
|
+
}
|
|
66
|
+
async function checkIfSynthesizedHypothesis(ctx, beliefId) {
|
|
67
|
+
const belief = await ctx.db.get(beliefId);
|
|
68
|
+
if (!belief) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
const metadata = belief.metadata;
|
|
72
|
+
return metadata?.isSynthesized === true || metadata?.beliefStatus === "hypothesis";
|
|
73
|
+
}
|
|
74
|
+
async function getTestingQuestionsForBelief(ctx, beliefId) {
|
|
75
|
+
const testEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
76
|
+
"by_to_type",
|
|
77
|
+
(q) => q.eq("toNodeId", beliefId).eq("edgeType", "tests")
|
|
78
|
+
).collect();
|
|
79
|
+
return testEdges.map((edge) => edge.fromNodeId).filter((id) => id !== void 0);
|
|
80
|
+
}
|
|
81
|
+
async function getQuestionsAnsweredByEvidence(ctx, evidenceId) {
|
|
82
|
+
const answerEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
83
|
+
"by_from_type",
|
|
84
|
+
(q) => q.eq("fromNodeId", evidenceId).eq("edgeType", "derived_from")
|
|
85
|
+
).collect();
|
|
86
|
+
return answerEdges.map((edge) => edge.toNodeId).filter((id) => id !== void 0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/debug.ts
|
|
90
|
+
function isGraphPrimitiveDebugEnabled() {
|
|
91
|
+
const env = globalThis.process?.env;
|
|
92
|
+
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
93
|
+
}
|
|
94
|
+
function debugGraphPrimitiveFallback(message, context) {
|
|
95
|
+
if (!isGraphPrimitiveDebugEnabled()) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
console.debug(message, context ?? {});
|
|
99
|
+
}
|
|
100
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
101
|
+
function asMappedProjectId(topic) {
|
|
102
|
+
if (!topic) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
106
|
+
if (directLegacyProjectId) {
|
|
107
|
+
return directLegacyProjectId;
|
|
108
|
+
}
|
|
109
|
+
const metadata = topic.metadata || {};
|
|
110
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
111
|
+
return candidate ? candidate : void 0;
|
|
112
|
+
}
|
|
113
|
+
function normalizeScopeValue(value) {
|
|
114
|
+
if (typeof value !== "string") {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const normalized = value.trim();
|
|
118
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
119
|
+
}
|
|
120
|
+
function pickPrimaryTopic(candidates) {
|
|
121
|
+
return [...candidates].sort((a, b) => {
|
|
122
|
+
const depthA = a.depth ?? 9999;
|
|
123
|
+
const depthB = b.depth ?? 9999;
|
|
124
|
+
if (depthA !== depthB) {
|
|
125
|
+
return depthA - depthB;
|
|
126
|
+
}
|
|
127
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
128
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
129
|
+
if (createdA !== createdB) {
|
|
130
|
+
return createdA - createdB;
|
|
131
|
+
}
|
|
132
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
133
|
+
})[0];
|
|
134
|
+
}
|
|
135
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
136
|
+
try {
|
|
137
|
+
return await ctx.db.query("topics").withIndex(
|
|
138
|
+
"by_graph_scope_project",
|
|
139
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
140
|
+
).collect();
|
|
141
|
+
} catch (error) {
|
|
142
|
+
debugGraphPrimitiveFallback(
|
|
143
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
144
|
+
{
|
|
145
|
+
error,
|
|
146
|
+
scopeId
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
const topics = await ctx.db.query("topics").collect();
|
|
150
|
+
return topics.filter((topic) => {
|
|
151
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
152
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
153
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
158
|
+
if (typeof ctx.runQuery !== "function") {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
return await ctx.runQuery(api.topics.get, {
|
|
163
|
+
id: topicId
|
|
164
|
+
}) ?? null;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
debugGraphPrimitiveFallback(
|
|
167
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
168
|
+
{
|
|
169
|
+
error,
|
|
170
|
+
topicId
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
177
|
+
if (typeof ctx.runQuery !== "function") {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
182
|
+
projectId: legacyScopeId
|
|
183
|
+
}) ?? null;
|
|
184
|
+
} catch (error) {
|
|
185
|
+
debugGraphPrimitiveFallback(
|
|
186
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
187
|
+
{
|
|
188
|
+
error,
|
|
189
|
+
legacyScopeId
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
196
|
+
const MAX_DEPTH = 10;
|
|
197
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
198
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
199
|
+
if (tenantId && workspaceId) {
|
|
200
|
+
return { tenantId, workspaceId };
|
|
201
|
+
}
|
|
202
|
+
let current = topic;
|
|
203
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
204
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
205
|
+
if (!current) break;
|
|
206
|
+
if (!tenantId) {
|
|
207
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
208
|
+
}
|
|
209
|
+
if (!workspaceId) {
|
|
210
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
211
|
+
}
|
|
212
|
+
if (tenantId && workspaceId) break;
|
|
213
|
+
}
|
|
214
|
+
return { tenantId, workspaceId };
|
|
215
|
+
}
|
|
216
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
217
|
+
if (args.topicId) {
|
|
218
|
+
let topic = null;
|
|
219
|
+
try {
|
|
220
|
+
topic = await ctx.db.get(
|
|
221
|
+
args.topicId
|
|
222
|
+
);
|
|
223
|
+
} catch (error) {
|
|
224
|
+
debugGraphPrimitiveFallback(
|
|
225
|
+
"[topicScope] Failed to load topic by direct id",
|
|
226
|
+
{
|
|
227
|
+
error,
|
|
228
|
+
topicId: args.topicId
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
if (!topic) {
|
|
233
|
+
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
234
|
+
}
|
|
235
|
+
if (!topic) {
|
|
236
|
+
topic = pickPrimaryTopic(
|
|
237
|
+
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
238
|
+
) ?? null;
|
|
239
|
+
}
|
|
240
|
+
if (!topic) {
|
|
241
|
+
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
242
|
+
}
|
|
243
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
244
|
+
const mapped = asMappedProjectId(topic);
|
|
245
|
+
if (mapped) {
|
|
246
|
+
return {
|
|
247
|
+
topicId: topic._id,
|
|
248
|
+
projectId: mapped,
|
|
249
|
+
tenantId: inherited.tenantId,
|
|
250
|
+
workspaceId: inherited.workspaceId,
|
|
251
|
+
source: "topic"
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
topicId: topic._id,
|
|
256
|
+
tenantId: inherited.tenantId,
|
|
257
|
+
workspaceId: inherited.workspaceId,
|
|
258
|
+
source: "topic"
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
if (args.projectId) {
|
|
262
|
+
let directTopic = null;
|
|
263
|
+
try {
|
|
264
|
+
directTopic = await ctx.db.get(
|
|
265
|
+
args.projectId
|
|
266
|
+
);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
debugGraphPrimitiveFallback(
|
|
269
|
+
"[topicScope] Failed to load direct project topic",
|
|
270
|
+
{
|
|
271
|
+
error,
|
|
272
|
+
projectId: args.projectId
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
if (directTopic) {
|
|
277
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
278
|
+
const mapped = asMappedProjectId(directTopic);
|
|
279
|
+
return {
|
|
280
|
+
topicId: directTopic._id,
|
|
281
|
+
projectId: mapped ?? args.projectId,
|
|
282
|
+
tenantId: inherited.tenantId,
|
|
283
|
+
workspaceId: inherited.workspaceId,
|
|
284
|
+
source: "topic_inferred"
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
288
|
+
if (directTopic) {
|
|
289
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
290
|
+
const mapped = asMappedProjectId(directTopic);
|
|
291
|
+
return {
|
|
292
|
+
topicId: directTopic._id,
|
|
293
|
+
projectId: mapped ?? args.projectId,
|
|
294
|
+
tenantId: inherited.tenantId,
|
|
295
|
+
workspaceId: inherited.workspaceId,
|
|
296
|
+
source: "topic_inferred"
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
300
|
+
const primary = pickPrimaryTopic(topics);
|
|
301
|
+
if (primary) {
|
|
302
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
303
|
+
return {
|
|
304
|
+
topicId: primary._id,
|
|
305
|
+
projectId: args.projectId,
|
|
306
|
+
tenantId: inherited.tenantId,
|
|
307
|
+
workspaceId: inherited.workspaceId,
|
|
308
|
+
source: "project_mapped_topic"
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
throw new Error(
|
|
312
|
+
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
throw new Error(
|
|
316
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
var optionalScopeArgs = {
|
|
320
|
+
projectId: v.optional(v.string()),
|
|
321
|
+
topicId: v.optional(v.string())
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// src/epistemicBeliefs.helpers.ts
|
|
325
|
+
var insightIdUnion = v.id("epistemicNodes");
|
|
326
|
+
var optionalBeliefScopeArgs = optionalScopeArgs;
|
|
327
|
+
({
|
|
328
|
+
tupleContradiction: normalizeTupleContradictionPolicy()
|
|
329
|
+
});
|
|
330
|
+
function throwStructuredMutationError(args) {
|
|
331
|
+
const error = new Error(args.message);
|
|
332
|
+
error.status = args.status;
|
|
333
|
+
error.code = args.code;
|
|
334
|
+
error.invariantCode = args.invariantCode;
|
|
335
|
+
error.suggestion = args.suggestion;
|
|
336
|
+
error.details = args.details;
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
function buildBeliefStatusSuccessResult() {
|
|
340
|
+
return { success: true };
|
|
341
|
+
}
|
|
342
|
+
function buildBeliefEvidenceNotFoundResult() {
|
|
343
|
+
const result = {};
|
|
344
|
+
result.success = false;
|
|
345
|
+
result.message = "Evidence node not found";
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
async function resolveBeliefScopeOrNull(ctx, args) {
|
|
349
|
+
if (!args.projectId && !args.topicId) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
try {
|
|
353
|
+
return await resolveTopicProjectScope(ctx, {
|
|
354
|
+
projectId: args.projectId ?? void 0,
|
|
355
|
+
topicId: args.topicId ?? void 0
|
|
356
|
+
});
|
|
357
|
+
} catch (error) {
|
|
358
|
+
debugGraphPrimitiveFallback(
|
|
359
|
+
"[epistemicBeliefs] Failed to resolve belief scope",
|
|
360
|
+
{
|
|
361
|
+
error,
|
|
362
|
+
projectId: args.projectId,
|
|
363
|
+
topicId: args.topicId
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
async function requireAuthenticatedUserId(ctx) {
|
|
370
|
+
const userId = await getCurrentUserId(
|
|
371
|
+
ctx
|
|
372
|
+
);
|
|
373
|
+
if (!userId) {
|
|
374
|
+
throwStructuredMutationError({
|
|
375
|
+
message: "Authentication required.",
|
|
376
|
+
status: 401,
|
|
377
|
+
code: "AUTHENTICATION_REQUIRED",
|
|
378
|
+
invariantCode: "auth.required",
|
|
379
|
+
suggestion: "Provide a valid bearer token before invoking belief mutations."
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
return userId;
|
|
383
|
+
}
|
|
384
|
+
async function requireProjectWriteAccess(ctx, projectId, userId) {
|
|
385
|
+
const hasAccess = await checkProjectAccess(
|
|
386
|
+
ctx,
|
|
387
|
+
projectId,
|
|
388
|
+
userId
|
|
389
|
+
);
|
|
390
|
+
if (!hasAccess) {
|
|
391
|
+
throwStructuredMutationError({
|
|
392
|
+
message: "Project access required.",
|
|
393
|
+
status: 403,
|
|
394
|
+
code: "FORBIDDEN",
|
|
395
|
+
invariantCode: "policy.scope_required",
|
|
396
|
+
suggestion: "Request write access for the project and retry.",
|
|
397
|
+
details: { projectId, userId }
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/epistemicBeliefs.links.ts
|
|
403
|
+
var updatePillar = mutation({
|
|
404
|
+
args: {
|
|
405
|
+
nodeId: v.id("epistemicNodes"),
|
|
406
|
+
pillar: v.union(
|
|
407
|
+
v.literal("market"),
|
|
408
|
+
v.literal("competition"),
|
|
409
|
+
v.literal("product"),
|
|
410
|
+
v.literal("team"),
|
|
411
|
+
v.literal("financials"),
|
|
412
|
+
v.literal("regulatory"),
|
|
413
|
+
v.literal("timing"),
|
|
414
|
+
v.literal("customer"),
|
|
415
|
+
v.literal("technology"),
|
|
416
|
+
v.literal("distribution"),
|
|
417
|
+
v.literal("deal"),
|
|
418
|
+
v.literal("risks"),
|
|
419
|
+
v.literal("other")
|
|
420
|
+
),
|
|
421
|
+
userId: v.string()
|
|
422
|
+
},
|
|
423
|
+
returns: permissiveReturn,
|
|
424
|
+
handler: async (ctx, args) => {
|
|
425
|
+
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
426
|
+
const now = Date.now();
|
|
427
|
+
const existingNode = await ctx.db.get(args.nodeId);
|
|
428
|
+
if (!existingNode || existingNode.nodeType !== "belief") {
|
|
429
|
+
throw new Error("Belief not found");
|
|
430
|
+
}
|
|
431
|
+
if (!existingNode.projectId) {
|
|
432
|
+
throw new Error("Belief has no project scope");
|
|
433
|
+
}
|
|
434
|
+
await requireProjectWriteAccess(
|
|
435
|
+
ctx,
|
|
436
|
+
existingNode.projectId,
|
|
437
|
+
authenticatedUserId
|
|
438
|
+
);
|
|
439
|
+
let previousPillar = null;
|
|
440
|
+
const metadata = existingNode.metadata || {};
|
|
441
|
+
previousPillar = metadata.pillar;
|
|
442
|
+
await ctx.db.patch(args.nodeId, {
|
|
443
|
+
metadata: {
|
|
444
|
+
...metadata,
|
|
445
|
+
pillar: args.pillar,
|
|
446
|
+
topic: args.pillar
|
|
447
|
+
},
|
|
448
|
+
updatedAt: now
|
|
449
|
+
});
|
|
450
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
451
|
+
nodeId: args.nodeId,
|
|
452
|
+
operation: "upsert"
|
|
453
|
+
});
|
|
454
|
+
await ctx.db.insert("epistemicAudit", {
|
|
455
|
+
entityType: "belief",
|
|
456
|
+
entityId: args.nodeId,
|
|
457
|
+
changeType: "pillar_changed",
|
|
458
|
+
projectId: existingNode.projectId,
|
|
459
|
+
changedBy: authenticatedUserId,
|
|
460
|
+
changedAt: now,
|
|
461
|
+
isAgent: false,
|
|
462
|
+
previousState: { pillar: previousPillar },
|
|
463
|
+
newState: { pillar: args.pillar }
|
|
464
|
+
});
|
|
465
|
+
return {
|
|
466
|
+
nodeId: args.nodeId,
|
|
467
|
+
previousPillar,
|
|
468
|
+
newPillar: args.pillar
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
var getCountByStatus = query({
|
|
473
|
+
args: {
|
|
474
|
+
...optionalBeliefScopeArgs
|
|
475
|
+
},
|
|
476
|
+
returns: permissiveReturn,
|
|
477
|
+
handler: async (ctx, args) => {
|
|
478
|
+
const scope = await resolveBeliefScopeOrNull(ctx, args);
|
|
479
|
+
if (!scope) {
|
|
480
|
+
return { active: 0, superseded: 0, archived: 0, total: 0 };
|
|
481
|
+
}
|
|
482
|
+
const nodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
483
|
+
"by_topic_type",
|
|
484
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
485
|
+
).collect();
|
|
486
|
+
const counts = {
|
|
487
|
+
active: 0,
|
|
488
|
+
superseded: 0,
|
|
489
|
+
archived: 0,
|
|
490
|
+
total: nodes.length
|
|
491
|
+
};
|
|
492
|
+
for (const node of nodes) {
|
|
493
|
+
if (node.status === "active") {
|
|
494
|
+
counts.active++;
|
|
495
|
+
} else if (node.status === "superseded") {
|
|
496
|
+
counts.superseded++;
|
|
497
|
+
} else if (node.status === "archived") {
|
|
498
|
+
counts.archived++;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return counts;
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
var linkBeliefs = mutation({
|
|
505
|
+
args: {
|
|
506
|
+
fromNodeId: v.id("epistemicNodes"),
|
|
507
|
+
toNodeId: v.id("epistemicNodes"),
|
|
508
|
+
edgeType: v.union(
|
|
509
|
+
// Basic belief relationships
|
|
510
|
+
v.literal("supersedes"),
|
|
511
|
+
v.literal("depends_on"),
|
|
512
|
+
v.literal("supports"),
|
|
513
|
+
v.literal("contains"),
|
|
514
|
+
v.literal("informs"),
|
|
515
|
+
v.literal("derived_from"),
|
|
516
|
+
v.literal("tests")
|
|
517
|
+
),
|
|
518
|
+
weight: v.optional(v.number()),
|
|
519
|
+
// -1 to 1
|
|
520
|
+
context: v.optional(v.string()),
|
|
521
|
+
userId: v.string()
|
|
522
|
+
},
|
|
523
|
+
returns: permissiveReturn,
|
|
524
|
+
handler: async (ctx, args) => {
|
|
525
|
+
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
526
|
+
const fromNode = await ctx.db.get(args.fromNodeId);
|
|
527
|
+
const toNode = await ctx.db.get(args.toNodeId);
|
|
528
|
+
if (!fromNode || !toNode) {
|
|
529
|
+
throw new Error("One or both belief nodes not found");
|
|
530
|
+
}
|
|
531
|
+
if (fromNode.nodeType !== "belief" || toNode.nodeType !== "belief") {
|
|
532
|
+
throw new Error("Both nodes must be beliefs");
|
|
533
|
+
}
|
|
534
|
+
if (fromNode.projectId !== toNode.projectId) {
|
|
535
|
+
throw new Error("Cannot link beliefs across different projects");
|
|
536
|
+
}
|
|
537
|
+
if (!fromNode.projectId) {
|
|
538
|
+
throw new Error("Belief has no project scope");
|
|
539
|
+
}
|
|
540
|
+
await requireProjectWriteAccess(
|
|
541
|
+
ctx,
|
|
542
|
+
fromNode.projectId,
|
|
543
|
+
authenticatedUserId
|
|
544
|
+
);
|
|
545
|
+
const now = Date.now();
|
|
546
|
+
const edgeGlobalId = generateGlobalId();
|
|
547
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
548
|
+
globalId: edgeGlobalId,
|
|
549
|
+
fromGlobalId: fromNode.globalId,
|
|
550
|
+
toGlobalId: toNode.globalId,
|
|
551
|
+
edgeType: args.edgeType,
|
|
552
|
+
weight: args.weight ?? 1,
|
|
553
|
+
context: args.context,
|
|
554
|
+
createdBy: authenticatedUserId,
|
|
555
|
+
topicId: fromNode.projectId ? String(fromNode.projectId) : void 0,
|
|
556
|
+
fromNodeType: "belief",
|
|
557
|
+
toNodeType: "belief"
|
|
558
|
+
});
|
|
559
|
+
await ctx.db.insert("epistemicAudit", {
|
|
560
|
+
entityType: "edge",
|
|
561
|
+
entityId: edgeGlobalId,
|
|
562
|
+
changeType: "created",
|
|
563
|
+
previousState: null,
|
|
564
|
+
newState: {
|
|
565
|
+
fromNodeId: args.fromNodeId,
|
|
566
|
+
toNodeId: args.toNodeId,
|
|
567
|
+
edgeType: args.edgeType
|
|
568
|
+
},
|
|
569
|
+
changedBy: authenticatedUserId,
|
|
570
|
+
isAgent: false,
|
|
571
|
+
changedAt: now,
|
|
572
|
+
projectId: fromNode.projectId
|
|
573
|
+
});
|
|
574
|
+
return { edgeGlobalId, created: true };
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
var linkEvidence = mutation({
|
|
578
|
+
args: {
|
|
579
|
+
beliefNodeId: v.id("epistemicNodes"),
|
|
580
|
+
insightId: insightIdUnion,
|
|
581
|
+
type: v.union(v.literal("supporting"), v.literal("contradicting")),
|
|
582
|
+
rationale: v.optional(v.string()),
|
|
583
|
+
userId: v.string()
|
|
584
|
+
},
|
|
585
|
+
returns: permissiveReturn,
|
|
586
|
+
handler: async (ctx, args) => {
|
|
587
|
+
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
588
|
+
const belief = await ctx.db.get(args.beliefNodeId);
|
|
589
|
+
if (!belief || belief.nodeType !== "belief") {
|
|
590
|
+
throw new Error("Belief not found");
|
|
591
|
+
}
|
|
592
|
+
if (!belief.projectId) {
|
|
593
|
+
throw new Error("Belief has no project scope");
|
|
594
|
+
}
|
|
595
|
+
await requireProjectWriteAccess(ctx, belief.projectId, authenticatedUserId);
|
|
596
|
+
const insight = await ctx.db.get(args.insightId);
|
|
597
|
+
if (!insight || insight.nodeType !== "evidence") {
|
|
598
|
+
throw new Error("Insight not found");
|
|
599
|
+
}
|
|
600
|
+
if ("projectId" in insight && insight.projectId && insight.projectId !== belief.projectId) {
|
|
601
|
+
throw new Error("Insight belongs to a different project");
|
|
602
|
+
}
|
|
603
|
+
const evidenceNodeId = insight._id;
|
|
604
|
+
const evidenceGlobalId = insight.globalId;
|
|
605
|
+
const edgeType = "informs";
|
|
606
|
+
const weight = args.type === "supporting" ? 1 : -1;
|
|
607
|
+
const logicalRole = evidenceNodeId ? await computeLogicalRole(ctx, evidenceNodeId, args.beliefNodeId) : "contributory";
|
|
608
|
+
const edgeGlobalId = generateGlobalId();
|
|
609
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
610
|
+
globalId: edgeGlobalId,
|
|
611
|
+
fromGlobalId: evidenceGlobalId,
|
|
612
|
+
toGlobalId: belief.globalId,
|
|
613
|
+
edgeType,
|
|
614
|
+
weight,
|
|
615
|
+
context: args.rationale || `${args.type} evidence`,
|
|
616
|
+
createdBy: authenticatedUserId,
|
|
617
|
+
topicId: belief.projectId ? String(belief.projectId) : void 0,
|
|
618
|
+
fromNodeType: "evidence",
|
|
619
|
+
toNodeType: "belief",
|
|
620
|
+
fromLayer: "L2",
|
|
621
|
+
toLayer: "L3",
|
|
622
|
+
// Classification fields
|
|
623
|
+
logicalRole,
|
|
624
|
+
temporalClass: "structural"
|
|
625
|
+
// Default - most evidence is long-lived
|
|
626
|
+
});
|
|
627
|
+
return { edgeGlobalId, evidenceNodeId, created: true };
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
var unlinkEvidence = mutation({
|
|
631
|
+
args: {
|
|
632
|
+
beliefNodeId: v.id("epistemicNodes"),
|
|
633
|
+
insightId: v.id("epistemicNodes"),
|
|
634
|
+
userId: v.string()
|
|
635
|
+
},
|
|
636
|
+
returns: permissiveReturn,
|
|
637
|
+
handler: async (ctx, args) => {
|
|
638
|
+
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
639
|
+
const now = Date.now();
|
|
640
|
+
const evidenceNode = await ctx.db.get(args.insightId);
|
|
641
|
+
if (!evidenceNode || evidenceNode.nodeType !== "evidence") {
|
|
642
|
+
return buildBeliefEvidenceNotFoundResult();
|
|
643
|
+
}
|
|
644
|
+
if (!evidenceNode.projectId) {
|
|
645
|
+
throw new Error("Evidence has no project scope");
|
|
646
|
+
}
|
|
647
|
+
await requireProjectWriteAccess(
|
|
648
|
+
ctx,
|
|
649
|
+
evidenceNode.projectId,
|
|
650
|
+
authenticatedUserId
|
|
651
|
+
);
|
|
652
|
+
const beliefNode = await ctx.db.get(args.beliefNodeId);
|
|
653
|
+
if (!beliefNode || beliefNode.nodeType !== "belief") {
|
|
654
|
+
throw new Error("Belief not found");
|
|
655
|
+
}
|
|
656
|
+
if (beliefNode.projectId !== evidenceNode.projectId) {
|
|
657
|
+
throw new Error("Belief and evidence belong to different projects");
|
|
658
|
+
}
|
|
659
|
+
const edge = await ctx.db.query("epistemicEdges").withIndex(
|
|
660
|
+
"by_from_to",
|
|
661
|
+
(q) => q.eq("fromNodeId", evidenceNode._id).eq("toNodeId", args.beliefNodeId)
|
|
662
|
+
).first();
|
|
663
|
+
if (edge) {
|
|
664
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.deleteEdge, {
|
|
665
|
+
globalId: edge.globalId
|
|
666
|
+
});
|
|
667
|
+
await ctx.db.delete(edge._id);
|
|
668
|
+
await ctx.db.insert("epistemicAudit", {
|
|
669
|
+
entityType: "edge",
|
|
670
|
+
entityId: edge.globalId,
|
|
671
|
+
changeType: "edge_removed",
|
|
672
|
+
changedAt: now,
|
|
673
|
+
changedBy: authenticatedUserId,
|
|
674
|
+
isAgent: false,
|
|
675
|
+
previousState: {
|
|
676
|
+
fromNodeId: evidenceNode._id,
|
|
677
|
+
toNodeId: args.beliefNodeId
|
|
678
|
+
},
|
|
679
|
+
newState: null,
|
|
680
|
+
projectId: evidenceNode.projectId
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
return buildBeliefStatusSuccessResult();
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
var getWithEvidence = query({
|
|
687
|
+
args: {
|
|
688
|
+
nodeId: v.id("epistemicNodes")
|
|
689
|
+
},
|
|
690
|
+
returns: permissiveReturn,
|
|
691
|
+
handler: async (ctx, args) => {
|
|
692
|
+
const belief = await ctx.db.get(args.nodeId);
|
|
693
|
+
if (!belief || belief.nodeType !== "belief") {
|
|
694
|
+
return null;
|
|
695
|
+
}
|
|
696
|
+
const incomingEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
697
|
+
"by_to_type",
|
|
698
|
+
(q) => q.eq("toNodeId", args.nodeId).eq("edgeType", "informs")
|
|
699
|
+
).collect();
|
|
700
|
+
const evidenceNodeIds = incomingEdges.filter((e) => e.fromNodeType === "evidence").map((e) => e.fromNodeId);
|
|
701
|
+
const evidenceNodes = await Promise.all(
|
|
702
|
+
evidenceNodeIds.map((id) => ctx.db.get(id))
|
|
703
|
+
);
|
|
704
|
+
const supporting = [];
|
|
705
|
+
const contradicting = [];
|
|
706
|
+
for (let i = 0; i < evidenceNodes.length; i++) {
|
|
707
|
+
const node = evidenceNodes[i];
|
|
708
|
+
const edge = incomingEdges[i];
|
|
709
|
+
if (node) {
|
|
710
|
+
if ((edge.weight || 0) >= 0) {
|
|
711
|
+
supporting.push(node);
|
|
712
|
+
} else {
|
|
713
|
+
contradicting.push(node);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return {
|
|
718
|
+
belief,
|
|
719
|
+
evidence: {
|
|
720
|
+
supporting,
|
|
721
|
+
contradicting,
|
|
722
|
+
total: supporting.length + contradicting.length
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
var getRelationships = query({
|
|
728
|
+
args: {
|
|
729
|
+
nodeId: v.id("epistemicNodes"),
|
|
730
|
+
direction: v.optional(
|
|
731
|
+
v.union(v.literal("in"), v.literal("out"), v.literal("both"))
|
|
732
|
+
)
|
|
733
|
+
},
|
|
734
|
+
returns: permissiveReturn,
|
|
735
|
+
handler: async (ctx, args) => {
|
|
736
|
+
const direction = args.direction || "both";
|
|
737
|
+
const results = {
|
|
738
|
+
incoming: [],
|
|
739
|
+
outgoing: []
|
|
740
|
+
};
|
|
741
|
+
if (direction === "in" || direction === "both") {
|
|
742
|
+
const inEdges = await ctx.db.query("epistemicEdges").filter((q) => q.eq(q.field("toNodeId"), args.nodeId)).collect();
|
|
743
|
+
for (const edge of inEdges) {
|
|
744
|
+
const sourceNode = await ctx.db.get(edge.fromNodeId);
|
|
745
|
+
results.incoming.push({ edge, node: sourceNode });
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
if (direction === "out" || direction === "both") {
|
|
749
|
+
const outEdges = await ctx.db.query("epistemicEdges").filter((q) => q.eq(q.field("fromNodeId"), args.nodeId)).collect();
|
|
750
|
+
for (const edge of outEdges) {
|
|
751
|
+
const targetNode = edge.toNodeId ? await ctx.db.get(edge.toNodeId) : null;
|
|
752
|
+
results.outgoing.push({ edge, node: targetNode });
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
return results;
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
export { getCountByStatus, getRelationships, getWithEvidence, linkBeliefs, linkEvidence, unlinkEvidence, updatePillar };
|
|
760
|
+
//# sourceMappingURL=epistemicBeliefs.links.js.map
|
|
761
|
+
//# sourceMappingURL=epistemicBeliefs.links.js.map
|