@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,658 @@
|
|
|
1
|
+
import { v } from 'convex/values';
|
|
2
|
+
import { componentsGeneric, anyApi, internalMutationGeneric, internalQueryGeneric } from 'convex/server';
|
|
3
|
+
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
4
|
+
|
|
5
|
+
// src/epistemicNodes.internal.ts
|
|
6
|
+
var api = anyApi;
|
|
7
|
+
componentsGeneric();
|
|
8
|
+
var internal = anyApi;
|
|
9
|
+
var internalMutation = internalMutationGeneric;
|
|
10
|
+
var internalQuery = internalQueryGeneric;
|
|
11
|
+
|
|
12
|
+
// src/debug.ts
|
|
13
|
+
function isGraphPrimitiveDebugEnabled() {
|
|
14
|
+
const env = globalThis.process?.env;
|
|
15
|
+
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
16
|
+
}
|
|
17
|
+
function debugGraphPrimitiveFallback(message, context) {
|
|
18
|
+
if (!isGraphPrimitiveDebugEnabled()) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
console.debug(message, context ?? {});
|
|
22
|
+
}
|
|
23
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
24
|
+
function asMappedProjectId(topic) {
|
|
25
|
+
if (!topic) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
29
|
+
if (directLegacyProjectId) {
|
|
30
|
+
return directLegacyProjectId;
|
|
31
|
+
}
|
|
32
|
+
const metadata = topic.metadata || {};
|
|
33
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
34
|
+
return candidate ? candidate : void 0;
|
|
35
|
+
}
|
|
36
|
+
function normalizeScopeValue(value) {
|
|
37
|
+
if (typeof value !== "string") {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const normalized = value.trim();
|
|
41
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
42
|
+
}
|
|
43
|
+
function pickPrimaryTopic(candidates) {
|
|
44
|
+
return [...candidates].sort((a, b) => {
|
|
45
|
+
const depthA = a.depth ?? 9999;
|
|
46
|
+
const depthB = b.depth ?? 9999;
|
|
47
|
+
if (depthA !== depthB) {
|
|
48
|
+
return depthA - depthB;
|
|
49
|
+
}
|
|
50
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
51
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
52
|
+
if (createdA !== createdB) {
|
|
53
|
+
return createdA - createdB;
|
|
54
|
+
}
|
|
55
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
56
|
+
})[0];
|
|
57
|
+
}
|
|
58
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
59
|
+
try {
|
|
60
|
+
return await ctx.db.query("topics").withIndex(
|
|
61
|
+
"by_graph_scope_project",
|
|
62
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
63
|
+
).collect();
|
|
64
|
+
} catch (error) {
|
|
65
|
+
debugGraphPrimitiveFallback(
|
|
66
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
67
|
+
{
|
|
68
|
+
error,
|
|
69
|
+
scopeId
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
const topics = await ctx.db.query("topics").collect();
|
|
73
|
+
return topics.filter((topic) => {
|
|
74
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
75
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
76
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
81
|
+
if (typeof ctx.runQuery !== "function") {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
return await ctx.runQuery(api.topics.get, {
|
|
86
|
+
id: topicId
|
|
87
|
+
}) ?? null;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
debugGraphPrimitiveFallback(
|
|
90
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
91
|
+
{
|
|
92
|
+
error,
|
|
93
|
+
topicId
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
100
|
+
if (typeof ctx.runQuery !== "function") {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
105
|
+
projectId: legacyScopeId
|
|
106
|
+
}) ?? null;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
debugGraphPrimitiveFallback(
|
|
109
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
110
|
+
{
|
|
111
|
+
error,
|
|
112
|
+
legacyScopeId
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
119
|
+
const MAX_DEPTH = 10;
|
|
120
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
121
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
122
|
+
if (tenantId && workspaceId) {
|
|
123
|
+
return { tenantId, workspaceId };
|
|
124
|
+
}
|
|
125
|
+
let current = topic;
|
|
126
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
127
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
128
|
+
if (!current) break;
|
|
129
|
+
if (!tenantId) {
|
|
130
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
131
|
+
}
|
|
132
|
+
if (!workspaceId) {
|
|
133
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
134
|
+
}
|
|
135
|
+
if (tenantId && workspaceId) break;
|
|
136
|
+
}
|
|
137
|
+
return { tenantId, workspaceId };
|
|
138
|
+
}
|
|
139
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
140
|
+
if (args.topicId) {
|
|
141
|
+
let topic = null;
|
|
142
|
+
try {
|
|
143
|
+
topic = await ctx.db.get(
|
|
144
|
+
args.topicId
|
|
145
|
+
);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
debugGraphPrimitiveFallback(
|
|
148
|
+
"[topicScope] Failed to load topic by direct id",
|
|
149
|
+
{
|
|
150
|
+
error,
|
|
151
|
+
topicId: args.topicId
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
if (!topic) {
|
|
156
|
+
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
157
|
+
}
|
|
158
|
+
if (!topic) {
|
|
159
|
+
topic = pickPrimaryTopic(
|
|
160
|
+
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
161
|
+
) ?? null;
|
|
162
|
+
}
|
|
163
|
+
if (!topic) {
|
|
164
|
+
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
165
|
+
}
|
|
166
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
167
|
+
const mapped = asMappedProjectId(topic);
|
|
168
|
+
if (mapped) {
|
|
169
|
+
return {
|
|
170
|
+
topicId: topic._id,
|
|
171
|
+
projectId: mapped,
|
|
172
|
+
tenantId: inherited.tenantId,
|
|
173
|
+
workspaceId: inherited.workspaceId,
|
|
174
|
+
source: "topic"
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
topicId: topic._id,
|
|
179
|
+
tenantId: inherited.tenantId,
|
|
180
|
+
workspaceId: inherited.workspaceId,
|
|
181
|
+
source: "topic"
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (args.projectId) {
|
|
185
|
+
let directTopic = null;
|
|
186
|
+
try {
|
|
187
|
+
directTopic = await ctx.db.get(
|
|
188
|
+
args.projectId
|
|
189
|
+
);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
debugGraphPrimitiveFallback(
|
|
192
|
+
"[topicScope] Failed to load direct project topic",
|
|
193
|
+
{
|
|
194
|
+
error,
|
|
195
|
+
projectId: args.projectId
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
if (directTopic) {
|
|
200
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
201
|
+
const mapped = asMappedProjectId(directTopic);
|
|
202
|
+
return {
|
|
203
|
+
topicId: directTopic._id,
|
|
204
|
+
projectId: mapped ?? args.projectId,
|
|
205
|
+
tenantId: inherited.tenantId,
|
|
206
|
+
workspaceId: inherited.workspaceId,
|
|
207
|
+
source: "topic_inferred"
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
211
|
+
if (directTopic) {
|
|
212
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
213
|
+
const mapped = asMappedProjectId(directTopic);
|
|
214
|
+
return {
|
|
215
|
+
topicId: directTopic._id,
|
|
216
|
+
projectId: mapped ?? args.projectId,
|
|
217
|
+
tenantId: inherited.tenantId,
|
|
218
|
+
workspaceId: inherited.workspaceId,
|
|
219
|
+
source: "topic_inferred"
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
223
|
+
const primary = pickPrimaryTopic(topics);
|
|
224
|
+
if (primary) {
|
|
225
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
226
|
+
return {
|
|
227
|
+
topicId: primary._id,
|
|
228
|
+
projectId: args.projectId,
|
|
229
|
+
tenantId: inherited.tenantId,
|
|
230
|
+
workspaceId: inherited.workspaceId,
|
|
231
|
+
source: "project_mapped_topic"
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
throw new Error(
|
|
235
|
+
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
throw new Error(
|
|
239
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
var optionalScopeArgs = {
|
|
243
|
+
projectId: v.optional(v.string()),
|
|
244
|
+
topicId: v.optional(v.string())
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// src/graphTypes.ts
|
|
248
|
+
function getNodeLayer(nodeType) {
|
|
249
|
+
const L4_TYPES = ["decision"];
|
|
250
|
+
const L3_TYPES = ["belief", "question", "theme", "deal"];
|
|
251
|
+
const L2_TYPES = ["claim", "evidence", "synthesis", "answer"];
|
|
252
|
+
const L1_TYPES = ["atomic_fact", "excerpt", "source"];
|
|
253
|
+
const ONTOLOGICAL_TYPES = [
|
|
254
|
+
"company",
|
|
255
|
+
"person",
|
|
256
|
+
"investor",
|
|
257
|
+
"function",
|
|
258
|
+
"value_chain"
|
|
259
|
+
];
|
|
260
|
+
const ORGANIZATIONAL_TYPES = ["topic"];
|
|
261
|
+
if (L4_TYPES.includes(nodeType)) {
|
|
262
|
+
return "L4";
|
|
263
|
+
}
|
|
264
|
+
if (L3_TYPES.includes(nodeType)) {
|
|
265
|
+
return "L3";
|
|
266
|
+
}
|
|
267
|
+
if (L2_TYPES.includes(nodeType)) {
|
|
268
|
+
return "L2";
|
|
269
|
+
}
|
|
270
|
+
if (L1_TYPES.includes(nodeType)) {
|
|
271
|
+
return "L1";
|
|
272
|
+
}
|
|
273
|
+
if (ONTOLOGICAL_TYPES.includes(nodeType)) {
|
|
274
|
+
return "ontological";
|
|
275
|
+
}
|
|
276
|
+
if (ORGANIZATIONAL_TYPES.includes(nodeType)) {
|
|
277
|
+
return "organizational";
|
|
278
|
+
}
|
|
279
|
+
console.warn(`[GraphTypes] Unknown nodeType "${nodeType}", defaulting to L2`);
|
|
280
|
+
return "L2";
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/epistemicNodes.helpers.ts
|
|
284
|
+
function buildNodeStatusSuccessResult() {
|
|
285
|
+
return { success: true };
|
|
286
|
+
}
|
|
287
|
+
function buildNodeNotFoundResult() {
|
|
288
|
+
const result = {};
|
|
289
|
+
result.success = false;
|
|
290
|
+
result.error = "Node not found";
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
function buildNodeDeletedResult(deletedEdgeCount) {
|
|
294
|
+
return {
|
|
295
|
+
success: true,
|
|
296
|
+
deletedEdgeCount
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
v.union(
|
|
300
|
+
v.literal("L4"),
|
|
301
|
+
v.literal("L3"),
|
|
302
|
+
v.literal("L2"),
|
|
303
|
+
v.literal("L1"),
|
|
304
|
+
v.literal("ontological"),
|
|
305
|
+
v.literal("organizational")
|
|
306
|
+
);
|
|
307
|
+
v.union(v.literal("decision"));
|
|
308
|
+
v.union(
|
|
309
|
+
v.literal("belief"),
|
|
310
|
+
v.literal("question"),
|
|
311
|
+
v.literal("theme"),
|
|
312
|
+
v.literal("deal")
|
|
313
|
+
);
|
|
314
|
+
v.union(
|
|
315
|
+
v.literal("claim"),
|
|
316
|
+
v.literal("evidence"),
|
|
317
|
+
v.literal("synthesis")
|
|
318
|
+
);
|
|
319
|
+
v.union(
|
|
320
|
+
v.literal("atomic_fact"),
|
|
321
|
+
v.literal("excerpt"),
|
|
322
|
+
v.literal("source")
|
|
323
|
+
);
|
|
324
|
+
v.union(
|
|
325
|
+
// L4: Audit targets
|
|
326
|
+
v.literal("decision"),
|
|
327
|
+
// L3: Traversal anchors
|
|
328
|
+
v.literal("belief"),
|
|
329
|
+
v.literal("question"),
|
|
330
|
+
v.literal("theme"),
|
|
331
|
+
v.literal("deal"),
|
|
332
|
+
// L2: Compression boundary
|
|
333
|
+
v.literal("claim"),
|
|
334
|
+
v.literal("evidence"),
|
|
335
|
+
v.literal("synthesis"),
|
|
336
|
+
v.literal("answer"),
|
|
337
|
+
// L1: Terminal leaves
|
|
338
|
+
v.literal("atomic_fact"),
|
|
339
|
+
v.literal("excerpt"),
|
|
340
|
+
v.literal("source")
|
|
341
|
+
);
|
|
342
|
+
v.union(
|
|
343
|
+
v.literal("company"),
|
|
344
|
+
v.literal("person"),
|
|
345
|
+
v.literal("investor"),
|
|
346
|
+
v.literal("function"),
|
|
347
|
+
v.literal("value_chain")
|
|
348
|
+
);
|
|
349
|
+
v.union(v.literal("topic"));
|
|
350
|
+
var nodeTypeValidator = v.union(
|
|
351
|
+
// L4: Audit targets
|
|
352
|
+
v.literal("decision"),
|
|
353
|
+
// L3: Traversal anchors
|
|
354
|
+
v.literal("belief"),
|
|
355
|
+
v.literal("question"),
|
|
356
|
+
v.literal("theme"),
|
|
357
|
+
v.literal("deal"),
|
|
358
|
+
// L2: Compression boundary
|
|
359
|
+
v.literal("claim"),
|
|
360
|
+
v.literal("evidence"),
|
|
361
|
+
v.literal("synthesis"),
|
|
362
|
+
v.literal("answer"),
|
|
363
|
+
// L1: Terminal leaves
|
|
364
|
+
v.literal("atomic_fact"),
|
|
365
|
+
v.literal("excerpt"),
|
|
366
|
+
v.literal("source"),
|
|
367
|
+
// Ontological
|
|
368
|
+
v.literal("company"),
|
|
369
|
+
v.literal("person"),
|
|
370
|
+
v.literal("investor"),
|
|
371
|
+
v.literal("function"),
|
|
372
|
+
v.literal("value_chain"),
|
|
373
|
+
// Organizational
|
|
374
|
+
v.literal("topic")
|
|
375
|
+
);
|
|
376
|
+
var sourceTypeValidator = v.union(
|
|
377
|
+
v.literal("human"),
|
|
378
|
+
v.literal("ai_extracted"),
|
|
379
|
+
v.literal("ai_generated"),
|
|
380
|
+
v.literal("imported"),
|
|
381
|
+
v.literal("system")
|
|
382
|
+
// System-generated (migrations, classifiers)
|
|
383
|
+
);
|
|
384
|
+
v.union(
|
|
385
|
+
v.literal("active"),
|
|
386
|
+
v.literal("superseded"),
|
|
387
|
+
v.literal("archived"),
|
|
388
|
+
v.literal("deleted")
|
|
389
|
+
);
|
|
390
|
+
var verificationStatusValidator = v.union(
|
|
391
|
+
v.literal("unverified"),
|
|
392
|
+
v.literal("human_verified"),
|
|
393
|
+
v.literal("ai_verified"),
|
|
394
|
+
v.literal("contradicted"),
|
|
395
|
+
v.literal("outdated")
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
// src/invariantEnforcement.ts
|
|
399
|
+
function throwInvariantError(args) {
|
|
400
|
+
const error = new Error(args.message);
|
|
401
|
+
error.status = args.status ?? 409;
|
|
402
|
+
error.code = args.code ?? "INVARIANT_VIOLATION";
|
|
403
|
+
error.invariantCode = args.invariantCode;
|
|
404
|
+
error.suggestion = args.suggestion;
|
|
405
|
+
error.details = args.details;
|
|
406
|
+
throw error;
|
|
407
|
+
}
|
|
408
|
+
function isBeliefNode(node) {
|
|
409
|
+
return node?.nodeType === "belief";
|
|
410
|
+
}
|
|
411
|
+
function assertBeliefNodeHardDeleteAllowed(args) {
|
|
412
|
+
if (!isBeliefNode(args.node)) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (!args.allowBeliefHardDelete) {
|
|
416
|
+
throwInvariantError({
|
|
417
|
+
message: "Belief hard delete is forbidden by default. Beliefs must retain lineage and audit history.",
|
|
418
|
+
invariantCode: "belief.hard_delete_forbidden",
|
|
419
|
+
suggestion: "Use epistemicBeliefs.archive() or epistemicBeliefs.forkBelief() instead. Only migration repair flows may opt into hard delete explicitly.",
|
|
420
|
+
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
if (!args.reason.trim().toLowerCase().startsWith("migration:")) {
|
|
424
|
+
throwInvariantError({
|
|
425
|
+
message: "Belief hard delete bypasses require a migration-scoped rationale.",
|
|
426
|
+
invariantCode: "belief.hard_delete_forbidden",
|
|
427
|
+
suggestion: 'Retry with allowBeliefHardDelete: true and a reason starting with "migration:" only for one-off data repair flows.',
|
|
428
|
+
details: {
|
|
429
|
+
mutationName: args.mutationName,
|
|
430
|
+
nodeId: args.node._id,
|
|
431
|
+
reason: args.reason
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/epistemicNodes.internal.ts
|
|
438
|
+
var optionalNodeScopeArgs = optionalScopeArgs;
|
|
439
|
+
var createInternal = internalMutation({
|
|
440
|
+
args: {
|
|
441
|
+
...optionalNodeScopeArgs,
|
|
442
|
+
globalId: v.string(),
|
|
443
|
+
nodeType: nodeTypeValidator,
|
|
444
|
+
subtype: v.optional(v.string()),
|
|
445
|
+
canonicalText: v.string(),
|
|
446
|
+
contentHash: v.optional(v.string()),
|
|
447
|
+
// Optional - will be generated if not provided
|
|
448
|
+
content: v.optional(v.string()),
|
|
449
|
+
contentType: v.optional(v.string()),
|
|
450
|
+
title: v.optional(v.string()),
|
|
451
|
+
tags: v.optional(v.array(v.string())),
|
|
452
|
+
domain: v.optional(v.string()),
|
|
453
|
+
metadata: v.optional(v.any()),
|
|
454
|
+
externalIds: v.optional(
|
|
455
|
+
v.object({
|
|
456
|
+
crunchbase: v.optional(v.string()),
|
|
457
|
+
linkedin: v.optional(v.string()),
|
|
458
|
+
pitchbook: v.optional(v.string()),
|
|
459
|
+
twitter: v.optional(v.string()),
|
|
460
|
+
website: v.optional(v.string())
|
|
461
|
+
})
|
|
462
|
+
),
|
|
463
|
+
sourceType: v.optional(sourceTypeValidator),
|
|
464
|
+
aiProvider: v.optional(v.string()),
|
|
465
|
+
extractedFromNodeId: v.optional(v.id("epistemicNodes")),
|
|
466
|
+
confidence: v.optional(v.number()),
|
|
467
|
+
verificationStatus: v.optional(verificationStatusValidator),
|
|
468
|
+
createdBy: v.string(),
|
|
469
|
+
// Neo4j sync status tracking
|
|
470
|
+
syncStatus: v.optional(
|
|
471
|
+
v.union(
|
|
472
|
+
v.literal("synced"),
|
|
473
|
+
v.literal("pending_edges"),
|
|
474
|
+
v.literal("edge_creation_failed")
|
|
475
|
+
)
|
|
476
|
+
),
|
|
477
|
+
epistemicLayer: v.optional(v.string()),
|
|
478
|
+
status: v.optional(v.string())
|
|
479
|
+
},
|
|
480
|
+
returns: permissiveReturn,
|
|
481
|
+
handler: async (ctx, args) => {
|
|
482
|
+
const now = Date.now();
|
|
483
|
+
const resolvedScope = args.topicId || args.projectId ? await (async () => {
|
|
484
|
+
try {
|
|
485
|
+
return await resolveTopicProjectScope(ctx, {
|
|
486
|
+
topicId: args.topicId,
|
|
487
|
+
projectId: args.projectId
|
|
488
|
+
});
|
|
489
|
+
} catch (error) {
|
|
490
|
+
debugGraphPrimitiveFallback(
|
|
491
|
+
"[epistemicNodes] Failed to resolve create scope",
|
|
492
|
+
{
|
|
493
|
+
error,
|
|
494
|
+
topicId: args.topicId,
|
|
495
|
+
projectId: args.projectId
|
|
496
|
+
}
|
|
497
|
+
);
|
|
498
|
+
return void 0;
|
|
499
|
+
}
|
|
500
|
+
})() : void 0;
|
|
501
|
+
const contentHash = args.contentHash || `${args.nodeType}:${args.canonicalText}`.slice(0, 64);
|
|
502
|
+
const epistemicLayer = args.epistemicLayer || getNodeLayer(args.nodeType);
|
|
503
|
+
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
504
|
+
globalId: args.globalId,
|
|
505
|
+
nodeType: args.nodeType,
|
|
506
|
+
epistemicLayer,
|
|
507
|
+
subtype: args.subtype,
|
|
508
|
+
canonicalText: args.canonicalText,
|
|
509
|
+
contentHash,
|
|
510
|
+
content: args.content,
|
|
511
|
+
contentType: args.contentType,
|
|
512
|
+
title: args.title,
|
|
513
|
+
tags: args.tags,
|
|
514
|
+
domain: args.domain,
|
|
515
|
+
metadata: args.metadata,
|
|
516
|
+
externalIds: args.externalIds,
|
|
517
|
+
sourceType: args.sourceType ?? "human",
|
|
518
|
+
aiProvider: args.aiProvider,
|
|
519
|
+
extractedFromNodeId: args.extractedFromNodeId,
|
|
520
|
+
confidence: args.confidence,
|
|
521
|
+
verificationStatus: args.verificationStatus ?? "unverified",
|
|
522
|
+
status: args.status ?? "active",
|
|
523
|
+
topicId: resolvedScope?.topicId ?? args.topicId,
|
|
524
|
+
projectId: resolvedScope?.projectId ?? args.projectId,
|
|
525
|
+
createdBy: args.createdBy,
|
|
526
|
+
createdAt: now,
|
|
527
|
+
updatedAt: now,
|
|
528
|
+
// Neo4j sync status
|
|
529
|
+
syncStatus: args.syncStatus
|
|
530
|
+
});
|
|
531
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
532
|
+
nodeId,
|
|
533
|
+
operation: "upsert"
|
|
534
|
+
});
|
|
535
|
+
return nodeId;
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
var getInternal = internalQuery({
|
|
539
|
+
args: {
|
|
540
|
+
nodeId: v.id("epistemicNodes")
|
|
541
|
+
},
|
|
542
|
+
returns: permissiveReturn,
|
|
543
|
+
handler: async (ctx, args) => {
|
|
544
|
+
return await ctx.db.get(args.nodeId);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
var updateSyncStatus = internalMutation({
|
|
548
|
+
args: {
|
|
549
|
+
nodeId: v.id("epistemicNodes"),
|
|
550
|
+
syncStatus: v.union(
|
|
551
|
+
v.literal("synced"),
|
|
552
|
+
v.literal("pending_edges"),
|
|
553
|
+
v.literal("edge_creation_failed")
|
|
554
|
+
),
|
|
555
|
+
syncError: v.optional(v.string())
|
|
556
|
+
},
|
|
557
|
+
returns: permissiveReturn,
|
|
558
|
+
handler: async (ctx, args) => {
|
|
559
|
+
const updates = {
|
|
560
|
+
syncStatus: args.syncStatus,
|
|
561
|
+
updatedAt: Date.now()
|
|
562
|
+
};
|
|
563
|
+
if (args.syncError !== void 0) {
|
|
564
|
+
updates.syncError = args.syncError;
|
|
565
|
+
}
|
|
566
|
+
await ctx.db.patch(args.nodeId, updates);
|
|
567
|
+
return buildNodeStatusSuccessResult();
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
var backfillTopicId = internalMutation({
|
|
571
|
+
args: {
|
|
572
|
+
nodeIds: v.array(v.id("epistemicNodes")),
|
|
573
|
+
newTopicId: v.string()
|
|
574
|
+
},
|
|
575
|
+
returns: permissiveReturn,
|
|
576
|
+
handler: async (ctx, args) => {
|
|
577
|
+
let patched = 0;
|
|
578
|
+
for (const nodeId of args.nodeIds) {
|
|
579
|
+
const node = await ctx.db.get(nodeId);
|
|
580
|
+
if (!node) {
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
await ctx.db.patch(nodeId, {
|
|
584
|
+
topicId: args.newTopicId,
|
|
585
|
+
updatedAt: Date.now()
|
|
586
|
+
});
|
|
587
|
+
patched++;
|
|
588
|
+
}
|
|
589
|
+
return { patched, total: args.nodeIds.length };
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
var getNodesPendingEdgeSync = internalQuery({
|
|
593
|
+
args: {
|
|
594
|
+
limit: v.optional(v.number())
|
|
595
|
+
},
|
|
596
|
+
returns: permissiveReturn,
|
|
597
|
+
handler: async (ctx, args) => {
|
|
598
|
+
const limit = args.limit ?? 100;
|
|
599
|
+
return await ctx.db.query("epistemicNodes").withIndex(
|
|
600
|
+
"by_syncStatus",
|
|
601
|
+
(q) => q.eq("syncStatus", "edge_creation_failed")
|
|
602
|
+
).take(limit);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
var hardDelete = internalMutation({
|
|
606
|
+
args: {
|
|
607
|
+
nodeId: v.id("epistemicNodes"),
|
|
608
|
+
reason: v.string(),
|
|
609
|
+
// Required: document why this is being hard-deleted
|
|
610
|
+
allowBeliefHardDelete: v.optional(v.boolean())
|
|
611
|
+
},
|
|
612
|
+
returns: permissiveReturn,
|
|
613
|
+
handler: async (ctx, args) => {
|
|
614
|
+
const node = await ctx.db.get(args.nodeId);
|
|
615
|
+
if (!node) {
|
|
616
|
+
return buildNodeNotFoundResult();
|
|
617
|
+
}
|
|
618
|
+
assertBeliefNodeHardDeleteAllowed({
|
|
619
|
+
node,
|
|
620
|
+
allowBeliefHardDelete: args.allowBeliefHardDelete ?? false,
|
|
621
|
+
reason: args.reason,
|
|
622
|
+
mutationName: "epistemicNodes.hardDelete"
|
|
623
|
+
});
|
|
624
|
+
await ctx.db.insert("epistemicAudit", {
|
|
625
|
+
entityType: "node",
|
|
626
|
+
entityId: args.nodeId,
|
|
627
|
+
changeType: "deleted",
|
|
628
|
+
projectId: node.projectId,
|
|
629
|
+
changedBy: "system:hard_delete",
|
|
630
|
+
changedAt: Date.now(),
|
|
631
|
+
isAgent: false,
|
|
632
|
+
previousState: {
|
|
633
|
+
nodeType: node.nodeType,
|
|
634
|
+
title: node.title || node.canonicalText?.slice(0, 100),
|
|
635
|
+
status: node.status
|
|
636
|
+
},
|
|
637
|
+
rationale: args.reason
|
|
638
|
+
});
|
|
639
|
+
const fromEdges = await ctx.db.query("epistemicEdges").withIndex("by_from", (q) => q.eq("fromNodeId", args.nodeId)).collect();
|
|
640
|
+
const toEdges = await ctx.db.query("epistemicEdges").withIndex("by_to", (q) => q.eq("toNodeId", args.nodeId)).collect();
|
|
641
|
+
const uniqueEdges = /* @__PURE__ */ new Map();
|
|
642
|
+
for (const edge of [...fromEdges, ...toEdges]) {
|
|
643
|
+
uniqueEdges.set(edge.globalId, edge);
|
|
644
|
+
}
|
|
645
|
+
for (const edge of uniqueEdges.values()) {
|
|
646
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.deleteEdge, {
|
|
647
|
+
globalId: edge.globalId
|
|
648
|
+
});
|
|
649
|
+
await ctx.db.delete(edge._id);
|
|
650
|
+
}
|
|
651
|
+
await ctx.db.delete(args.nodeId);
|
|
652
|
+
return buildNodeDeletedResult(uniqueEdges.size);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
export { backfillTopicId, createInternal, getInternal, getNodesPendingEdgeSync, hardDelete, updateSyncStatus };
|
|
657
|
+
//# sourceMappingURL=epistemicNodes.internal.js.map
|
|
658
|
+
//# sourceMappingURL=epistemicNodes.internal.js.map
|