@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.
Files changed (202) hide show
  1. package/README.md +13 -12
  2. package/dist/beliefDecay.js +24 -17
  3. package/dist/beliefDecay.js.map +1 -1
  4. package/dist/beliefEvidenceLinks.js +32 -8
  5. package/dist/beliefEvidenceLinks.js.map +1 -1
  6. package/dist/confidencePropagationDispatch.js.map +1 -1
  7. package/dist/contradictions.js +32 -9
  8. package/dist/contradictions.js.map +1 -1
  9. package/dist/convex.d.ts +55 -12
  10. package/dist/convex.js.map +1 -1
  11. package/dist/edgeValidation.d.ts +25 -2
  12. package/dist/edges/index.d.ts +9 -2
  13. package/dist/edges/index.js.map +1 -1
  14. package/dist/edges/propagationTypes.d.ts +2 -3
  15. package/dist/edges/propagationTypes.js.map +1 -1
  16. package/dist/entityBridge.js +10 -3
  17. package/dist/entityBridge.js.map +1 -1
  18. package/dist/entityLifecycle.js +15 -3
  19. package/dist/entityLifecycle.js.map +1 -1
  20. package/dist/epistemicAnswers.js.map +1 -1
  21. package/dist/epistemicBeliefs.admin.d.ts +36 -0
  22. package/dist/epistemicBeliefs.admin.js +745 -0
  23. package/dist/epistemicBeliefs.admin.js.map +1 -0
  24. package/dist/epistemicBeliefs.backfills.d.ts +62 -0
  25. package/dist/epistemicBeliefs.backfills.js +1004 -0
  26. package/dist/epistemicBeliefs.backfills.js.map +1 -0
  27. package/dist/epistemicBeliefs.confidence.d.ts +45 -0
  28. package/dist/epistemicBeliefs.confidence.js +1285 -0
  29. package/dist/epistemicBeliefs.confidence.js.map +1 -0
  30. package/dist/epistemicBeliefs.core.d.ts +35 -0
  31. package/dist/epistemicBeliefs.core.js +1508 -0
  32. package/dist/epistemicBeliefs.core.js.map +1 -0
  33. package/dist/epistemicBeliefs.d.ts +12 -3
  34. package/dist/epistemicBeliefs.helpers.d.ts +168 -0
  35. package/dist/epistemicBeliefs.helpers.js +1060 -0
  36. package/dist/epistemicBeliefs.helpers.js.map +1 -0
  37. package/dist/epistemicBeliefs.internal.d.ts +30 -0
  38. package/dist/epistemicBeliefs.internal.js +1329 -0
  39. package/dist/epistemicBeliefs.internal.js.map +1 -0
  40. package/dist/epistemicBeliefs.js +1196 -1184
  41. package/dist/epistemicBeliefs.js.map +1 -1
  42. package/dist/epistemicBeliefs.lifecycle.d.ts +19 -0
  43. package/dist/epistemicBeliefs.lifecycle.js +1608 -0
  44. package/dist/epistemicBeliefs.lifecycle.js.map +1 -0
  45. package/dist/epistemicBeliefs.links.d.ts +30 -0
  46. package/dist/epistemicBeliefs.links.js +761 -0
  47. package/dist/epistemicBeliefs.links.js.map +1 -0
  48. package/dist/epistemicBeliefs.queries.d.ts +16 -0
  49. package/dist/epistemicBeliefs.queries.js +90 -0
  50. package/dist/epistemicBeliefs.queries.js.map +1 -0
  51. package/dist/epistemicContractHelpers.d.ts +1 -1
  52. package/dist/epistemicContractHelpers.js +1 -1
  53. package/dist/epistemicContracts.d.ts +5 -76
  54. package/dist/epistemicContracts.evaluators.d.ts +36 -0
  55. package/dist/epistemicContracts.evaluators.js +2506 -0
  56. package/dist/epistemicContracts.evaluators.js.map +1 -0
  57. package/dist/epistemicContracts.handlers.d.ts +40 -0
  58. package/dist/epistemicContracts.handlers.js +3029 -0
  59. package/dist/epistemicContracts.handlers.js.map +1 -0
  60. package/dist/epistemicContracts.js +2006 -5281
  61. package/dist/epistemicContracts.js.map +1 -1
  62. package/dist/epistemicContracts.metrics.d.ts +26 -0
  63. package/dist/epistemicContracts.metrics.js +427 -0
  64. package/dist/epistemicContracts.metrics.js.map +1 -0
  65. package/dist/epistemicContracts.types.d.ts +159 -0
  66. package/dist/epistemicContracts.types.js +3 -0
  67. package/dist/epistemicContracts.types.js.map +1 -0
  68. package/dist/epistemicEdgeCreation.d.ts +73 -0
  69. package/dist/epistemicEdgeCreation.js +450 -0
  70. package/dist/epistemicEdgeCreation.js.map +1 -0
  71. package/dist/epistemicEdges-BF-cn4i3.d.ts +43 -0
  72. package/dist/epistemicEdges.d.ts +8 -1
  73. package/dist/epistemicEdges.handlers.d.ts +20 -0
  74. package/dist/epistemicEdges.handlers.js +289 -0
  75. package/dist/epistemicEdges.handlers.js.map +1 -0
  76. package/dist/epistemicEdges.helpers.d.ts +27 -0
  77. package/dist/epistemicEdges.helpers.js +162 -0
  78. package/dist/epistemicEdges.helpers.js.map +1 -0
  79. package/dist/epistemicEdges.js +797 -875
  80. package/dist/epistemicEdges.js.map +1 -1
  81. package/dist/epistemicEdges.mutations.d.ts +39 -0
  82. package/dist/epistemicEdges.mutations.js +1365 -0
  83. package/dist/epistemicEdges.mutations.js.map +1 -0
  84. package/dist/epistemicEdges.queries.d.ts +95 -0
  85. package/dist/epistemicEdges.queries.js +851 -0
  86. package/dist/epistemicEdges.queries.js.map +1 -0
  87. package/dist/epistemicEdges.types.d.ts +32 -0
  88. package/dist/epistemicEdges.types.js +3 -0
  89. package/dist/epistemicEdges.types.js.map +1 -0
  90. package/dist/epistemicEvidence-DvfchNt7.d.ts +46 -0
  91. package/dist/epistemicEvidence.d.ts +5 -2
  92. package/dist/epistemicEvidence.js +801 -807
  93. package/dist/epistemicEvidence.js.map +1 -1
  94. package/dist/epistemicEvidenceHelpers.d.ts +71 -0
  95. package/dist/epistemicEvidenceHelpers.js +769 -0
  96. package/dist/epistemicEvidenceHelpers.js.map +1 -0
  97. package/dist/epistemicEvidenceMutations.d.ts +10 -0
  98. package/dist/epistemicEvidenceMutations.js +1421 -0
  99. package/dist/epistemicEvidenceMutations.js.map +1 -0
  100. package/dist/epistemicEvidenceQueries.d.ts +10 -0
  101. package/dist/epistemicEvidenceQueries.js +1049 -0
  102. package/dist/epistemicEvidenceQueries.js.map +1 -0
  103. package/dist/epistemicHelpers.d.ts +4 -2
  104. package/dist/epistemicHelpers.js +132 -127
  105. package/dist/epistemicHelpers.js.map +1 -1
  106. package/dist/epistemicLayerRules.d.ts +138 -0
  107. package/dist/epistemicLayerRules.js +481 -0
  108. package/dist/epistemicLayerRules.js.map +1 -0
  109. package/dist/epistemicLinking.js +1 -1
  110. package/dist/epistemicLinking.js.map +1 -1
  111. package/dist/epistemicNodeCreation.d.ts +101 -0
  112. package/dist/epistemicNodeCreation.js +709 -0
  113. package/dist/epistemicNodeCreation.js.map +1 -0
  114. package/dist/epistemicNodes-BCQxpYx_.d.ts +54 -0
  115. package/dist/epistemicNodes.d.ts +5 -1
  116. package/dist/epistemicNodes.helpers.d.ts +51 -0
  117. package/dist/epistemicNodes.helpers.js +73 -0
  118. package/dist/epistemicNodes.helpers.js.map +1 -0
  119. package/dist/epistemicNodes.internal.d.ts +34 -0
  120. package/dist/epistemicNodes.internal.js +658 -0
  121. package/dist/epistemicNodes.internal.js.map +1 -0
  122. package/dist/epistemicNodes.js +698 -693
  123. package/dist/epistemicNodes.js.map +1 -1
  124. package/dist/epistemicNodes.mutations.d.ts +34 -0
  125. package/dist/epistemicNodes.mutations.js +1153 -0
  126. package/dist/epistemicNodes.mutations.js.map +1 -0
  127. package/dist/epistemicNodes.queries.d.ts +36 -0
  128. package/dist/epistemicNodes.queries.js +619 -0
  129. package/dist/epistemicNodes.queries.js.map +1 -0
  130. package/dist/epistemicNodes.validators.d.ts +23 -0
  131. package/dist/epistemicNodes.validators.js +105 -0
  132. package/dist/epistemicNodes.validators.js.map +1 -0
  133. package/dist/epistemicQuestions-bwHd2FWE.d.ts +68 -0
  134. package/dist/epistemicQuestions.conviction.d.ts +52 -0
  135. package/dist/epistemicQuestions.conviction.js +1389 -0
  136. package/dist/epistemicQuestions.conviction.js.map +1 -0
  137. package/dist/epistemicQuestions.create.d.ts +29 -0
  138. package/dist/epistemicQuestions.create.js +1300 -0
  139. package/dist/epistemicQuestions.create.js.map +1 -0
  140. package/dist/epistemicQuestions.d.ts +10 -2
  141. package/dist/epistemicQuestions.evidence.d.ts +22 -0
  142. package/dist/epistemicQuestions.evidence.js +929 -0
  143. package/dist/epistemicQuestions.evidence.js.map +1 -0
  144. package/dist/epistemicQuestions.helpers.d.ts +69 -0
  145. package/dist/epistemicQuestions.helpers.js +824 -0
  146. package/dist/epistemicQuestions.helpers.js.map +1 -0
  147. package/dist/epistemicQuestions.js +2435 -2430
  148. package/dist/epistemicQuestions.js.map +1 -1
  149. package/dist/epistemicQuestions.lifecycle.d.ts +24 -0
  150. package/dist/epistemicQuestions.lifecycle.js +838 -0
  151. package/dist/epistemicQuestions.lifecycle.js.map +1 -0
  152. package/dist/epistemicQuestions.queries.d.ts +41 -0
  153. package/dist/epistemicQuestions.queries.js +1013 -0
  154. package/dist/epistemicQuestions.queries.js.map +1 -0
  155. package/dist/epistemicQuestions.sprint.d.ts +22 -0
  156. package/dist/epistemicQuestions.sprint.js +757 -0
  157. package/dist/epistemicQuestions.sprint.js.map +1 -0
  158. package/dist/epistemicQuestions.tail.d.ts +42 -0
  159. package/dist/epistemicQuestions.tail.js +1345 -0
  160. package/dist/epistemicQuestions.tail.js.map +1 -0
  161. package/dist/epistemicSources.js +6 -2
  162. package/dist/epistemicSources.js.map +1 -1
  163. package/dist/evaluators/index.d.ts +2 -2
  164. package/dist/evaluators/index.js +45 -5320
  165. package/dist/evaluators/index.js.map +1 -1
  166. package/dist/evaluators/lintCheckerEvaluator.d.ts +1 -1
  167. package/dist/evaluators/sentryCheckerEvaluator.d.ts +1 -1
  168. package/dist/evaluators/testRunnerEvaluator.d.ts +1 -1
  169. package/dist/evaluators/tscCheckerEvaluator.d.ts +1 -1
  170. package/dist/{graphTypes-CpgIuCdo.d.ts → graphTypes-B8VaIjnl.d.ts} +1 -1
  171. package/dist/graphTypes.d.ts +1 -1
  172. package/dist/{helpers-BYHIk5vU.d.ts → helpers-DNYfg6mo.d.ts} +2 -3
  173. package/dist/helpers.d.ts +2 -2
  174. package/dist/helpers.js.map +1 -1
  175. package/dist/{index-Dq-7R-gi.d.ts → index-C-Kyd7hD.d.ts} +1 -1
  176. package/dist/index.d.ts +160 -14
  177. package/dist/index.js +12291 -13001
  178. package/dist/index.js.map +1 -1
  179. package/dist/logicalRoleInference.js.map +1 -1
  180. package/dist/ontologyApproval.js +1 -1
  181. package/dist/ontologyApproval.js.map +1 -1
  182. package/dist/ontologyDefinitions.js +25 -7
  183. package/dist/ontologyDefinitions.js.map +1 -1
  184. package/dist/ontologyRegistry.js.map +1 -1
  185. package/dist/projectionReconciliation.js.map +1 -1
  186. package/dist/questionEvidenceLinks.js +28 -7
  187. package/dist/questionEvidenceLinks.js.map +1 -1
  188. package/dist/resolvers.js.map +1 -1
  189. package/dist/scopeResolverCompat.js.map +1 -1
  190. package/dist/topicProjectOverlay.js.map +1 -1
  191. package/dist/topicScope.js.map +1 -1
  192. package/dist/workflowBridge.js.map +1 -1
  193. package/dist/workspaceIsolation.js.map +1 -1
  194. package/package.json +4 -5
  195. package/dist/edgeValidation-CeI0wc0r.d.ts +0 -35
  196. package/dist/epistemicBeliefs-DzKjZAeC.d.ts +0 -377
  197. package/dist/epistemicEdges-CvlKnEyy.d.ts +0 -191
  198. package/dist/epistemicEvidence-xw6UUrwh.d.ts +0 -128
  199. package/dist/epistemicHelpers-DevrYgPN.d.ts +0 -329
  200. package/dist/epistemicNodes-DjSUfvyD.d.ts +0 -167
  201. package/dist/epistemicQuestions-B_nUclrH.d.ts +0 -214
  202. 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