@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,1508 @@
1
+ import { v } from 'convex/values';
2
+ import { checkScopeAccess, checkProjectAccess } from '@lucern/access-control/access';
3
+ import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
4
+ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
5
+ import { componentsGeneric, anyApi, mutationGeneric, queryGeneric } from 'convex/server';
6
+ import { normalizeTupleContradictionPolicy, createInheritedContractRecord, confidenceFromSL } from '@lucern/confidence';
7
+ import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
8
+ import '@lucern/access-control/audience';
9
+ import { getCurrentUserId } from '@lucern/access-control/auth';
10
+
11
+ // src/epistemicBeliefs.core.ts
12
+ var api = anyApi;
13
+ componentsGeneric();
14
+ var internal = anyApi;
15
+ var mutation = mutationGeneric;
16
+ var query = queryGeneric;
17
+
18
+ // src/debug.ts
19
+ function isGraphPrimitiveDebugEnabled() {
20
+ const env = globalThis.process?.env;
21
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
22
+ }
23
+ function debugGraphPrimitiveFallback(message, context) {
24
+ if (!isGraphPrimitiveDebugEnabled()) {
25
+ return;
26
+ }
27
+ console.debug(message, context ?? {});
28
+ }
29
+
30
+ // src/embeddingTrigger.ts
31
+ async function scheduleEmbeddingGeneration(args) {
32
+ try {
33
+ await args.ctx.scheduler.runAfter(
34
+ 0,
35
+ "embeddingActions:generateEpistemicNodeEmbedding",
36
+ {
37
+ nodeId: args.nodeId,
38
+ projectId: args.projectId ? String(args.projectId) : void 0,
39
+ topicId: args.topicId ? String(args.topicId) : void 0,
40
+ createdBy: args.createdBy,
41
+ nodeType: args.nodeType,
42
+ text: args.text.slice(0, 2e4),
43
+ hasAnswer: args.hasAnswer,
44
+ confidence: args.confidence
45
+ }
46
+ );
47
+ } catch (error) {
48
+ debugGraphPrimitiveFallback(
49
+ "[embeddingTrigger] Failed to schedule embedding generation",
50
+ {
51
+ error,
52
+ nodeId: String(args.nodeId),
53
+ nodeType: args.nodeType
54
+ }
55
+ );
56
+ }
57
+ }
58
+
59
+ // src/globalId.ts
60
+ function generateGlobalId() {
61
+ const bytes = new Uint8Array(16);
62
+ crypto.getRandomValues(bytes);
63
+ bytes[6] = bytes[6] & 15 | 64;
64
+ bytes[8] = bytes[8] & 63 | 128;
65
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join(
66
+ ""
67
+ );
68
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
69
+ }
70
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
71
+ function asMappedProjectId(topic) {
72
+ if (!topic) {
73
+ return;
74
+ }
75
+ const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
76
+ if (directLegacyProjectId) {
77
+ return directLegacyProjectId;
78
+ }
79
+ const metadata = topic.metadata || {};
80
+ const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
81
+ return candidate ? candidate : void 0;
82
+ }
83
+ function normalizeScopeValue(value) {
84
+ if (typeof value !== "string") {
85
+ return;
86
+ }
87
+ const normalized = value.trim();
88
+ return normalized.length > 0 ? normalized : void 0;
89
+ }
90
+ function pickPrimaryTopic(candidates) {
91
+ return [...candidates].sort((a, b) => {
92
+ const depthA = a.depth ?? 9999;
93
+ const depthB = b.depth ?? 9999;
94
+ if (depthA !== depthB) {
95
+ return depthA - depthB;
96
+ }
97
+ const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
98
+ const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
99
+ if (createdA !== createdB) {
100
+ return createdA - createdB;
101
+ }
102
+ return String(a.name || "").localeCompare(String(b.name || ""));
103
+ })[0];
104
+ }
105
+ async function findTopicsByScopeAlias(ctx, scopeId) {
106
+ try {
107
+ return await ctx.db.query("topics").withIndex(
108
+ "by_graph_scope_project",
109
+ (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
110
+ ).collect();
111
+ } catch (error) {
112
+ debugGraphPrimitiveFallback(
113
+ "[topicScope] Failed to resolve scope alias via index",
114
+ {
115
+ error,
116
+ scopeId
117
+ }
118
+ );
119
+ const topics = await ctx.db.query("topics").collect();
120
+ return topics.filter((topic) => {
121
+ const normalizedGlobalId = normalizeScopeValue(topic.globalId);
122
+ const mappedProjectId = asMappedProjectId(topic);
123
+ return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
124
+ });
125
+ }
126
+ }
127
+ async function tryResolveHostTopicById(ctx, topicId) {
128
+ if (typeof ctx.runQuery !== "function") {
129
+ return null;
130
+ }
131
+ try {
132
+ return await ctx.runQuery(api.topics.get, {
133
+ id: topicId
134
+ }) ?? null;
135
+ } catch (error) {
136
+ debugGraphPrimitiveFallback(
137
+ "[topicScope] Failed to resolve topic by host query",
138
+ {
139
+ error,
140
+ topicId
141
+ }
142
+ );
143
+ return null;
144
+ }
145
+ }
146
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
147
+ if (typeof ctx.runQuery !== "function") {
148
+ return null;
149
+ }
150
+ try {
151
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
152
+ projectId: legacyScopeId
153
+ }) ?? null;
154
+ } catch (error) {
155
+ debugGraphPrimitiveFallback(
156
+ "[topicScope] Failed to resolve topic by legacy scope",
157
+ {
158
+ error,
159
+ legacyScopeId
160
+ }
161
+ );
162
+ return null;
163
+ }
164
+ }
165
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
166
+ const MAX_DEPTH = 10;
167
+ let tenantId = normalizeScopeValue(topic.tenantId);
168
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
169
+ if (tenantId && workspaceId) {
170
+ return { tenantId, workspaceId };
171
+ }
172
+ let current = topic;
173
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
174
+ current = await ctx.db.get(current.parentTopicId);
175
+ if (!current) break;
176
+ if (!tenantId) {
177
+ tenantId = normalizeScopeValue(current.tenantId);
178
+ }
179
+ if (!workspaceId) {
180
+ workspaceId = normalizeScopeValue(current.workspaceId);
181
+ }
182
+ if (tenantId && workspaceId) break;
183
+ }
184
+ return { tenantId, workspaceId };
185
+ }
186
+ async function resolveTopicProjectScope(ctx, args) {
187
+ if (args.topicId) {
188
+ let topic = null;
189
+ try {
190
+ topic = await ctx.db.get(
191
+ args.topicId
192
+ );
193
+ } catch (error) {
194
+ debugGraphPrimitiveFallback(
195
+ "[topicScope] Failed to load topic by direct id",
196
+ {
197
+ error,
198
+ topicId: args.topicId
199
+ }
200
+ );
201
+ }
202
+ if (!topic) {
203
+ topic = await tryResolveHostTopicById(ctx, String(args.topicId));
204
+ }
205
+ if (!topic) {
206
+ topic = pickPrimaryTopic(
207
+ await findTopicsByScopeAlias(ctx, String(args.topicId))
208
+ ) ?? null;
209
+ }
210
+ if (!topic) {
211
+ throw new Error(`Topic not found: ${String(args.topicId)}`);
212
+ }
213
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
214
+ const mapped = asMappedProjectId(topic);
215
+ if (mapped) {
216
+ return {
217
+ topicId: topic._id,
218
+ projectId: mapped,
219
+ tenantId: inherited.tenantId,
220
+ workspaceId: inherited.workspaceId,
221
+ source: "topic"
222
+ };
223
+ }
224
+ return {
225
+ topicId: topic._id,
226
+ tenantId: inherited.tenantId,
227
+ workspaceId: inherited.workspaceId,
228
+ source: "topic"
229
+ };
230
+ }
231
+ if (args.projectId) {
232
+ let directTopic = null;
233
+ try {
234
+ directTopic = await ctx.db.get(
235
+ args.projectId
236
+ );
237
+ } catch (error) {
238
+ debugGraphPrimitiveFallback(
239
+ "[topicScope] Failed to load direct project topic",
240
+ {
241
+ error,
242
+ projectId: args.projectId
243
+ }
244
+ );
245
+ }
246
+ if (directTopic) {
247
+ const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
248
+ const mapped = asMappedProjectId(directTopic);
249
+ return {
250
+ topicId: directTopic._id,
251
+ projectId: mapped ?? args.projectId,
252
+ tenantId: inherited.tenantId,
253
+ workspaceId: inherited.workspaceId,
254
+ source: "topic_inferred"
255
+ };
256
+ }
257
+ directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
258
+ if (directTopic) {
259
+ const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
260
+ const mapped = asMappedProjectId(directTopic);
261
+ return {
262
+ topicId: directTopic._id,
263
+ projectId: mapped ?? args.projectId,
264
+ tenantId: inherited.tenantId,
265
+ workspaceId: inherited.workspaceId,
266
+ source: "topic_inferred"
267
+ };
268
+ }
269
+ const topics = await findTopicsByScopeAlias(ctx, args.projectId);
270
+ const primary = pickPrimaryTopic(topics);
271
+ if (primary) {
272
+ const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
273
+ return {
274
+ topicId: primary._id,
275
+ projectId: args.projectId,
276
+ tenantId: inherited.tenantId,
277
+ workspaceId: inherited.workspaceId,
278
+ source: "project_mapped_topic"
279
+ };
280
+ }
281
+ throw new Error(
282
+ `Legacy project scope ${String(args.projectId)} has no mapped topic.`
283
+ );
284
+ }
285
+ throw new Error(
286
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
287
+ );
288
+ }
289
+ var optionalScopeArgs = {
290
+ projectId: v.optional(v.string()),
291
+ topicId: v.optional(v.string())
292
+ };
293
+ function normalizeScopeValue2(value) {
294
+ if (typeof value !== "string") {
295
+ return;
296
+ }
297
+ const normalized = value.trim();
298
+ return normalized.length > 0 ? normalized : void 0;
299
+ }
300
+ function throwWorkspaceIsolationError(args) {
301
+ const error = new Error(args.message);
302
+ error.status = 409;
303
+ error.code = "INVARIANT_VIOLATION";
304
+ error.invariantCode = args.invariantCode;
305
+ error.suggestion = args.suggestion;
306
+ error.details = args.details;
307
+ throw error;
308
+ }
309
+ function assertWorkspaceScopedEpistemicNodeScope(args) {
310
+ const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
311
+ if (layer === "ontological") {
312
+ return;
313
+ }
314
+ const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
315
+ if (workspaceId) {
316
+ return;
317
+ }
318
+ throwWorkspaceIsolationError({
319
+ message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
320
+ invariantCode: "workspace.scope_required_for_epistemic_nodes",
321
+ suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
322
+ details: {
323
+ mutationName: args.mutationName,
324
+ nodeType: args.nodeType,
325
+ topicId: args.scope.topicId,
326
+ projectId: args.scope.projectId
327
+ }
328
+ });
329
+ }
330
+ function nodeMatchesWorkspaceReasoningScope(node, scope) {
331
+ if (!node) {
332
+ return false;
333
+ }
334
+ const scopeTenantId = normalizeScopeValue2(scope.tenantId);
335
+ const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
336
+ const nodeTenantId = normalizeScopeValue2(node.tenantId);
337
+ const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
338
+ const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
339
+ if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
340
+ return false;
341
+ }
342
+ if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
343
+ return true;
344
+ }
345
+ if (!scopeWorkspaceId && node.publicationStatus === "published") {
346
+ return true;
347
+ }
348
+ if (!scopeWorkspaceId) {
349
+ return nodeWorkspaceId === void 0;
350
+ }
351
+ return scopeWorkspaceId === nodeWorkspaceId;
352
+ }
353
+
354
+ // src/topicProjectOverlay.ts
355
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
356
+ function readNonEmptyString(value) {
357
+ if (typeof value !== "string") {
358
+ return;
359
+ }
360
+ const normalized = value.trim();
361
+ return normalized.length > 0 ? normalized : void 0;
362
+ }
363
+ function readStringArray(value) {
364
+ if (!Array.isArray(value)) {
365
+ return [];
366
+ }
367
+ return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
368
+ }
369
+ function readMetadata(topic) {
370
+ return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
371
+ }
372
+ function readLegacyProjectId(value) {
373
+ if (!value) {
374
+ return;
375
+ }
376
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD2]);
377
+ }
378
+ function coerceVisibility(value) {
379
+ return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
380
+ }
381
+ function coerceStatus(value) {
382
+ return value === "active" || value === "archived" || value === "watching" ? value : void 0;
383
+ }
384
+ function mapProjectType(topic, metadata) {
385
+ const explicit = readNonEmptyString(metadata.projectType);
386
+ if (explicit) {
387
+ return explicit;
388
+ }
389
+ if (topic.type === "theme") {
390
+ return "thematic";
391
+ }
392
+ return readNonEmptyString(topic.type) || "general";
393
+ }
394
+ function isProjectLikeTopic(topic) {
395
+ const metadata = readMetadata(topic);
396
+ return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
397
+ }
398
+ function isMissingLucernChildComponentError(error) {
399
+ const message = getErrorMessage(error);
400
+ return message.includes(
401
+ 'Child component ComponentName(Identifier("lucern")) not found'
402
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
403
+ }
404
+ function getErrorMessage(error) {
405
+ if (error instanceof Error) {
406
+ return error.message;
407
+ }
408
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
409
+ return error.message;
410
+ }
411
+ return "unknown error";
412
+ }
413
+ async function resolveTopicDoc(ctx, scopeId) {
414
+ if (ctx?.db && typeof ctx.db.get === "function") {
415
+ try {
416
+ const directTopic = await ctx.db.get(
417
+ scopeId
418
+ );
419
+ if (directTopic) {
420
+ return directTopic;
421
+ }
422
+ } catch (error) {
423
+ debugGraphPrimitiveFallback(
424
+ "[topicProjectOverlay] Failed to resolve topic by direct ID",
425
+ {
426
+ error,
427
+ scopeId
428
+ }
429
+ );
430
+ }
431
+ }
432
+ if (typeof ctx.runQuery !== "function") {
433
+ return null;
434
+ }
435
+ try {
436
+ const topic = await ctx.runQuery(api.topics.get, {
437
+ id: String(scopeId)
438
+ });
439
+ if (topic?.name !== void 0 && topic?.type !== void 0) {
440
+ return topic;
441
+ }
442
+ } catch (error) {
443
+ debugGraphPrimitiveFallback(
444
+ "[topicProjectOverlay] Failed to resolve topic by ID query",
445
+ {
446
+ error,
447
+ scopeId
448
+ }
449
+ );
450
+ }
451
+ try {
452
+ const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
453
+ projectId: String(scopeId)
454
+ });
455
+ if (topic?.name !== void 0 && topic?.type !== void 0) {
456
+ return topic;
457
+ }
458
+ } catch (error) {
459
+ debugGraphPrimitiveFallback(
460
+ "[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
461
+ { error, scopeId }
462
+ );
463
+ }
464
+ return null;
465
+ }
466
+ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
467
+ const metadata = readMetadata(topic);
468
+ const topicId = String(topic._id);
469
+ const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
470
+ const storageProjectId = legacyProjectId || topicId;
471
+ const outwardId = idMode === "topic" ? topicId : storageProjectId;
472
+ const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
473
+ const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
474
+ const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
475
+ const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
476
+ return {
477
+ ...metadata,
478
+ _id: outwardId,
479
+ projectId: outwardId,
480
+ topicId,
481
+ storageProjectId,
482
+ legacyProjectId,
483
+ name: readNonEmptyString(topic.name) || "Untitled Theme",
484
+ type: mapProjectType(topic, metadata),
485
+ description: readNonEmptyString(topic.description),
486
+ ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
487
+ sharedWith: readStringArray(metadata.sharedWith),
488
+ visibility,
489
+ tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
490
+ workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
491
+ status,
492
+ tags: readStringArray(metadata.tags),
493
+ chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
494
+ artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
495
+ lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
496
+ _creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
497
+ createdAt,
498
+ updatedAt
499
+ };
500
+ }
501
+ async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
502
+ const topic = await resolveTopicDoc(ctx, scopeId);
503
+ if (!topic) {
504
+ return null;
505
+ }
506
+ if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
507
+ return null;
508
+ }
509
+ return materializeTopicProjectOverlay(topic, options.idMode);
510
+ }
511
+ async function listTopicProjectOverlays(ctx, options = {}) {
512
+ let allTopics = [];
513
+ if (ctx?.db?.query && typeof ctx.db.query === "function") {
514
+ try {
515
+ allTopics = await ctx.db.query("topics").collect();
516
+ } catch (error) {
517
+ debugGraphPrimitiveFallback(
518
+ "[topicProjectOverlay] Failed to read topics table; falling back to API",
519
+ { error }
520
+ );
521
+ allTopics = [];
522
+ }
523
+ }
524
+ if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
525
+ allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
526
+ }
527
+ return allTopics.filter(
528
+ (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
529
+ ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
530
+ }
531
+ async function patchTopicProjectOverlay(ctx, scopeId, value) {
532
+ const topic = await resolveTopicDoc(ctx, scopeId);
533
+ if (!topic) {
534
+ return null;
535
+ }
536
+ const nextMetadata = { ...readMetadata(topic) };
537
+ const patch = {};
538
+ const topicUpdateArgs = {
539
+ id: String(topic._id)
540
+ };
541
+ for (const [key, rawValue] of Object.entries(value)) {
542
+ switch (key) {
543
+ case "_id":
544
+ case "projectId":
545
+ case "topicId":
546
+ case "legacyProjectId":
547
+ case "storageProjectId":
548
+ break;
549
+ case "name":
550
+ case "description":
551
+ patch[key] = rawValue;
552
+ topicUpdateArgs[key] = rawValue;
553
+ break;
554
+ case "tenantId":
555
+ case "workspaceId":
556
+ case "ownerId":
557
+ throw new Error(
558
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
559
+ );
560
+ case "status": {
561
+ const status = coerceStatus(rawValue);
562
+ if (status) {
563
+ patch.status = status;
564
+ topicUpdateArgs.status = status;
565
+ }
566
+ break;
567
+ }
568
+ case "visibility": {
569
+ const visibility = coerceVisibility(rawValue);
570
+ if (visibility) {
571
+ patch.visibility = visibility;
572
+ topicUpdateArgs.visibility = visibility;
573
+ }
574
+ break;
575
+ }
576
+ case "type": {
577
+ const projectType = readNonEmptyString(rawValue);
578
+ if (projectType) {
579
+ nextMetadata.projectType = projectType;
580
+ } else {
581
+ delete nextMetadata.projectType;
582
+ }
583
+ break;
584
+ }
585
+ case "updatedAt":
586
+ case "createdAt":
587
+ break;
588
+ default:
589
+ if (rawValue === void 0) {
590
+ delete nextMetadata[key];
591
+ } else {
592
+ nextMetadata[key] = rawValue;
593
+ }
594
+ }
595
+ }
596
+ patch.updatedAt = Date.now();
597
+ patch.metadata = nextMetadata;
598
+ topicUpdateArgs.metadata = nextMetadata;
599
+ if (typeof ctx.runMutation === "function") {
600
+ try {
601
+ await ctx.runMutation(api.topics.update, topicUpdateArgs);
602
+ } catch (error) {
603
+ if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
604
+ throw error;
605
+ }
606
+ await ctx.db.patch(String(topic._id), patch);
607
+ }
608
+ } else if (ctx?.db && typeof ctx.db.patch === "function") {
609
+ await ctx.db.patch(String(topic._id), patch);
610
+ } else {
611
+ throw new Error(
612
+ "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
613
+ );
614
+ }
615
+ return materializeTopicProjectOverlay({
616
+ ...topic,
617
+ ...patch,
618
+ metadata: nextMetadata
619
+ });
620
+ }
621
+
622
+ // src/resolvers.ts
623
+ function isMissingLucernChildComponentError2(error) {
624
+ const message = getErrorMessage2(error);
625
+ return message.includes(
626
+ 'Child component ComponentName(Identifier("lucern")) not found'
627
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
628
+ }
629
+ function getErrorMessage2(error) {
630
+ if (error instanceof Error) {
631
+ return error.message;
632
+ }
633
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
634
+ return error.message;
635
+ }
636
+ return "unknown error";
637
+ }
638
+ function isAdvisoryTopicPatch(value) {
639
+ const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
640
+ const keys = Object.keys(value);
641
+ return keys.length > 0 && keys.every((key) => advisoryKeys.has(key));
642
+ }
643
+ async function patchProjectWithTolerance(ctx, projectId, value) {
644
+ try {
645
+ await patchTopicProjectOverlay(ctx, projectId, value);
646
+ } catch (error) {
647
+ if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
648
+ throw error;
649
+ }
650
+ console.warn(
651
+ "[lucern graph-primitives] Non-fatal advisory topic patch failure",
652
+ {
653
+ projectId,
654
+ keys: Object.keys(value),
655
+ error: getErrorMessage2(error)
656
+ }
657
+ );
658
+ }
659
+ }
660
+ function defaultResolvers() {
661
+ return {
662
+ getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
663
+ idMode: "legacy",
664
+ projectLikeOnly: false
665
+ }),
666
+ patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
667
+ listTopics: (ctx) => listTopicProjectOverlays(ctx, {
668
+ idMode: "legacy"
669
+ }),
670
+ getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
671
+ };
672
+ }
673
+ var resolverOverrides = {};
674
+ function resolveGraphPrimitivesAppResolvers(_ctx) {
675
+ return {
676
+ ...defaultResolvers(),
677
+ ...resolverOverrides
678
+ };
679
+ }
680
+
681
+ // src/epistemicBeliefs.helpers.ts
682
+ v.id("epistemicNodes");
683
+ var DEFAULT_PROJECT_BELIEF_LIMIT = 250;
684
+ var MAX_PROJECT_BELIEF_LIMIT = 1e3;
685
+ var optionalBeliefScopeArgs = optionalScopeArgs;
686
+ var DEFAULT_CONFIDENCE_POLICY = {
687
+ scoringMode: "after_worktree",
688
+ tupleContradiction: normalizeTupleContradictionPolicy()
689
+ };
690
+ function throwStructuredMutationError(args) {
691
+ const error = new Error(args.message);
692
+ error.status = args.status;
693
+ error.code = args.code;
694
+ error.invariantCode = args.invariantCode;
695
+ error.suggestion = args.suggestion;
696
+ error.details = args.details;
697
+ throw error;
698
+ }
699
+ function assertBaseRateInRange(baseRate, field = "baseRate") {
700
+ if (baseRate < 0 || baseRate > 1) {
701
+ throwStructuredMutationError({
702
+ message: `${field} must be within [0, 1].`,
703
+ status: 400,
704
+ code: "INVALID_ARGUMENT",
705
+ invariantCode: "request.valid_shape",
706
+ suggestion: `Clamp ${field} into the inclusive [0, 1] interval.`,
707
+ details: { field, baseRate }
708
+ });
709
+ }
710
+ return baseRate;
711
+ }
712
+ function buildBeliefConfidenceRow(args) {
713
+ return {
714
+ beliefId: args.beliefId,
715
+ confidence: confidenceFromSL(
716
+ args.belief,
717
+ args.disbelief,
718
+ args.uncertainty,
719
+ args.baseRate
720
+ ),
721
+ belief: args.belief,
722
+ disbelief: args.disbelief,
723
+ uncertainty: args.uncertainty,
724
+ baseRate: args.baseRate,
725
+ slOperator: args.slOperator ?? "manual_assessment",
726
+ trigger: args.trigger,
727
+ ...args.rationale ? { rationale: args.rationale } : {},
728
+ assessedBy: args.assessedBy,
729
+ assessedAt: args.assessedAt,
730
+ ...args.triggeringEvidenceId ? {
731
+ triggeringEvidenceId: args.triggeringEvidenceId,
732
+ triggeringEvidenceIds: [String(args.triggeringEvidenceId)]
733
+ } : {},
734
+ ...args.triggeringContradictionId ? {
735
+ triggeringContradictionId: args.triggeringContradictionId
736
+ } : {},
737
+ ...args.triggeringWorktreeId ? { triggeringWorktreeId: args.triggeringWorktreeId } : {}
738
+ };
739
+ }
740
+ function clampBeliefLimit(limit, fallback = DEFAULT_PROJECT_BELIEF_LIMIT) {
741
+ if (!Number.isFinite(limit)) {
742
+ return fallback;
743
+ }
744
+ return Math.max(
745
+ 1,
746
+ Math.min(Math.floor(limit), MAX_PROJECT_BELIEF_LIMIT)
747
+ );
748
+ }
749
+ function generateContentHash(text) {
750
+ const content = `belief:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
751
+ let hash = 5381;
752
+ for (let i = 0; i < content.length; i++) {
753
+ hash = (hash << 5) + hash + content.charCodeAt(i);
754
+ hash &= hash;
755
+ }
756
+ return Math.abs(hash).toString(16).padStart(8, "0");
757
+ }
758
+ function normalizePillar(pillar) {
759
+ if (!pillar) {
760
+ return "other";
761
+ }
762
+ const lower = pillar.toLowerCase();
763
+ const validPillars = [
764
+ "market",
765
+ "competition",
766
+ "product",
767
+ "team",
768
+ "financials",
769
+ "regulatory",
770
+ "timing",
771
+ "customer",
772
+ "technology",
773
+ "distribution",
774
+ "deal",
775
+ "risks"
776
+ ];
777
+ return validPillars.find((p) => lower.includes(p)) || "other";
778
+ }
779
+ async function markBeliefGraphDirty(ctx, scope) {
780
+ const projectId = typeof scope.projectId === "string" && scope.projectId.trim().length > 0 ? scope.projectId : void 0;
781
+ const topicId = typeof scope.topicId === "string" && scope.topicId.trim().length > 0 ? scope.topicId : void 0;
782
+ if (!projectId && !topicId) {
783
+ return;
784
+ }
785
+ if (projectId) {
786
+ await ctx.scheduler.runAfter(
787
+ 0,
788
+ internal.graphAnalysisCache.markCacheStaleInternal,
789
+ { projectId }
790
+ );
791
+ }
792
+ if (topicId) {
793
+ await ctx.scheduler.runAfter(
794
+ 0,
795
+ internal.graphAnalysisCache.markCacheStaleByTopic,
796
+ { topicId }
797
+ );
798
+ }
799
+ await resolveGraphPrimitivesAppResolvers().patchProject(
800
+ ctx,
801
+ topicId ?? projectId,
802
+ {
803
+ lastActivityAt: Date.now()
804
+ }
805
+ );
806
+ }
807
+ async function getActiveConfidencePolicy(ctx) {
808
+ try {
809
+ const activeConfig = await ctx.db.query("logicSprintScoring").withIndex("by_active", (q) => q.eq("isActive", true)).first();
810
+ return {
811
+ scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
812
+ tupleContradiction: normalizeTupleContradictionPolicy(
813
+ activeConfig?.tupleContradictionPolicy
814
+ )
815
+ };
816
+ } catch (error) {
817
+ debugGraphPrimitiveFallback(
818
+ "[epistemicBeliefs] Failed to load active confidence policy",
819
+ {
820
+ error
821
+ }
822
+ );
823
+ return DEFAULT_CONFIDENCE_POLICY;
824
+ }
825
+ }
826
+ async function requireAuthenticatedUserId(ctx) {
827
+ const userId = await getCurrentUserId(
828
+ ctx
829
+ );
830
+ if (!userId) {
831
+ throwStructuredMutationError({
832
+ message: "Authentication required.",
833
+ status: 401,
834
+ code: "AUTHENTICATION_REQUIRED",
835
+ invariantCode: "auth.required",
836
+ suggestion: "Provide a valid bearer token before invoking belief mutations."
837
+ });
838
+ }
839
+ return userId;
840
+ }
841
+ async function requireProjectWriteAccess(ctx, projectId, userId) {
842
+ const hasAccess = await checkProjectAccess(
843
+ ctx,
844
+ projectId,
845
+ userId
846
+ );
847
+ if (!hasAccess) {
848
+ throwStructuredMutationError({
849
+ message: "Project access required.",
850
+ status: 403,
851
+ code: "FORBIDDEN",
852
+ invariantCode: "policy.scope_required",
853
+ suggestion: "Request write access for the project and retry.",
854
+ details: { projectId, userId }
855
+ });
856
+ }
857
+ }
858
+
859
+ // src/epistemicBeliefs.core.ts
860
+ var create = mutation({
861
+ args: {
862
+ ...optionalBeliefScopeArgs,
863
+ formulation: v.string(),
864
+ beliefType: v.optional(v.string()),
865
+ rationale: v.optional(v.string()),
866
+ confidence: v.optional(
867
+ v.union(
868
+ v.literal("untested"),
869
+ v.literal("high"),
870
+ v.literal("medium"),
871
+ v.literal("low")
872
+ )
873
+ ),
874
+ pillar: v.optional(v.string()),
875
+ worktreeId: v.optional(v.string()),
876
+ sourceType: v.optional(
877
+ v.union(
878
+ v.literal("human"),
879
+ v.literal("ai_extracted"),
880
+ v.literal("ai_generated")
881
+ )
882
+ ),
883
+ userId: v.string(),
884
+ // === CLASSIFICATION FIELDS ===
885
+ reversibility: v.optional(
886
+ v.union(
887
+ v.literal("irreversible"),
888
+ v.literal("hard_to_reverse"),
889
+ v.literal("reversible"),
890
+ v.literal("trivial")
891
+ )
892
+ ),
893
+ predictionMeta: v.optional(
894
+ v.object({
895
+ isPrediction: v.boolean(),
896
+ registeredAt: v.number(),
897
+ expectedBy: v.optional(v.number())
898
+ })
899
+ ),
900
+ baseRate: v.optional(v.number()),
901
+ metadata: v.optional(v.any())
902
+ // Additional metadata including isConditional
903
+ },
904
+ returns: permissiveReturn,
905
+ handler: async (ctx, args) => {
906
+ const authenticatedUserId = await requireAuthenticatedUserId(ctx);
907
+ const scope = await resolveTopicProjectScope(ctx, {
908
+ topicId: args.topicId,
909
+ projectId: args.projectId
910
+ });
911
+ assertWorkspaceScopedEpistemicNodeScope({
912
+ scope,
913
+ nodeType: "belief",
914
+ mutationName: "epistemicBeliefs.create"
915
+ });
916
+ const topic = await ctx.db.get(scope.topicId);
917
+ const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
918
+ category: "belief_type",
919
+ value: args.beliefType,
920
+ tenantId: topic?.tenantId,
921
+ context: "epistemicBeliefs.create"
922
+ });
923
+ if (scope.projectId) {
924
+ await requireProjectWriteAccess(
925
+ ctx,
926
+ scope.projectId,
927
+ authenticatedUserId
928
+ );
929
+ }
930
+ const now = Date.now();
931
+ const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
932
+ const initialBeliefStatus = args.worktreeId ? "hypothesis" : "assumption";
933
+ const initialEpistemicStatus = args.worktreeId ? "hypothesis" : "assumption";
934
+ const seedOpinion = {
935
+ opinion_b: 0,
936
+ opinion_d: 0,
937
+ opinion_u: 1,
938
+ opinion_a: baseRate
939
+ };
940
+ const pillar = normalizePillar(args.pillar);
941
+ const additionalMeta = args.metadata || {};
942
+ const beliefGlobalId = generateGlobalId();
943
+ const nodeId = await ctx.db.insert("epistemicNodes", {
944
+ globalId: beliefGlobalId,
945
+ nodeType: "belief",
946
+ epistemicLayer: "L3",
947
+ canonicalText: args.formulation,
948
+ contentHash: generateContentHash(args.formulation),
949
+ content: args.rationale,
950
+ title: args.formulation.slice(0, 100) + (args.formulation.length > 100 ? "..." : ""),
951
+ metadata: {
952
+ pillar,
953
+ // No confidenceLevel — only set after worktree completion via modulateConfidence()
954
+ status: "active",
955
+ worktreeId: args.worktreeId,
956
+ beliefStatus: initialBeliefStatus,
957
+ epistemicStatus: initialEpistemicStatus,
958
+ tupleContradicted: false,
959
+ ...normalizedBeliefType ? { beliefType: normalizedBeliefType } : {},
960
+ ...additionalMeta
961
+ // Includes isConditional if provided
962
+ },
963
+ beliefStatus: initialBeliefStatus,
964
+ ...seedOpinion,
965
+ tupleContradicted: false,
966
+ // Classification fields
967
+ reversibility: args.reversibility ?? "reversible",
968
+ predictionMeta: args.predictionMeta,
969
+ // Infer epistemicStatus based on context
970
+ epistemicStatus: initialEpistemicStatus,
971
+ sourceType: args.sourceType || "human",
972
+ ...normalizedBeliefType ? { beliefType: normalizedBeliefType } : {},
973
+ confidence: void 0,
974
+ // No scalar confidence until worktree completion
975
+ verificationStatus: "unverified",
976
+ status: "active",
977
+ topicId: scope.topicId,
978
+ projectId: scope.projectId,
979
+ tenantId: scope.tenantId,
980
+ workspaceId: scope.workspaceId,
981
+ createdBy: authenticatedUserId,
982
+ createdAt: now,
983
+ updatedAt: now
984
+ });
985
+ await ctx.db.insert(
986
+ "beliefConfidence",
987
+ buildBeliefConfidenceRow({
988
+ beliefId: nodeId,
989
+ belief: seedOpinion.opinion_b,
990
+ disbelief: seedOpinion.opinion_d,
991
+ uncertainty: seedOpinion.opinion_u,
992
+ baseRate,
993
+ trigger: "initial",
994
+ rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
995
+ assessedBy: authenticatedUserId,
996
+ assessedAt: now,
997
+ slOperator: "manual_assessment"
998
+ })
999
+ );
1000
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1001
+ nodeId,
1002
+ operation: "upsert"
1003
+ });
1004
+ await scheduleEmbeddingGeneration({
1005
+ ctx,
1006
+ nodeId,
1007
+ projectId: scope.projectId,
1008
+ topicId: scope.topicId,
1009
+ createdBy: authenticatedUserId,
1010
+ nodeType: "belief",
1011
+ text: args.formulation
1012
+ });
1013
+ await ctx.db.insert("epistemicAudit", {
1014
+ entityType: "belief",
1015
+ entityId: nodeId,
1016
+ changeType: "created",
1017
+ changedAt: now,
1018
+ changedBy: authenticatedUserId,
1019
+ isAgent: false,
1020
+ previousState: null,
1021
+ newState: {
1022
+ formulation: args.formulation,
1023
+ status: "active",
1024
+ baseRate: seedOpinion.opinion_a,
1025
+ tupleContradicted: false,
1026
+ opinion: {
1027
+ b: seedOpinion.opinion_b,
1028
+ d: seedOpinion.opinion_d,
1029
+ u: seedOpinion.opinion_u,
1030
+ a: seedOpinion.opinion_a
1031
+ }
1032
+ },
1033
+ projectId: scope.projectId,
1034
+ topicId: String(scope.topicId)
1035
+ });
1036
+ if (scope.projectId || scope.topicId) {
1037
+ await ctx.scheduler.runAfter(
1038
+ 0,
1039
+ "embeddingActions:generateEpistemicNodeEmbedding",
1040
+ {
1041
+ nodeId,
1042
+ projectId: scope.projectId,
1043
+ topicId: String(scope.topicId),
1044
+ createdBy: authenticatedUserId,
1045
+ nodeType: "belief",
1046
+ text: args.rationale ? `${args.formulation}
1047
+
1048
+ Rationale: ${args.rationale}` : args.formulation
1049
+ // Don't pass confidence — "untested" is a string, but the
1050
+ // embedding action expects v.optional(v.number()). New beliefs
1051
+ // have no numeric confidence until scoring.
1052
+ }
1053
+ );
1054
+ }
1055
+ if (scope.projectId || scope.topicId) {
1056
+ await ctx.scheduler.runAfter(
1057
+ 2e3,
1058
+ // 2 second delay
1059
+ internal.nodeClassification.scheduleClassification,
1060
+ {
1061
+ nodeId,
1062
+ nodeType: "belief",
1063
+ projectId: scope.projectId,
1064
+ topicId: String(scope.topicId)
1065
+ }
1066
+ );
1067
+ }
1068
+ if (pillar === "other" && (scope.projectId || scope.topicId)) {
1069
+ await ctx.scheduler.runAfter(
1070
+ 2500,
1071
+ "beliefCategorization:autoCategorizeBelief",
1072
+ {
1073
+ nodeId,
1074
+ projectId: scope.projectId,
1075
+ topicId: String(scope.topicId)
1076
+ }
1077
+ );
1078
+ }
1079
+ if (scope.projectId || scope.topicId) {
1080
+ await ctx.scheduler.runAfter(
1081
+ 3e3,
1082
+ // 3 second delay — after entity extraction
1083
+ internal.beliefTemporalClassifier.classifyBelief,
1084
+ {
1085
+ nodeId,
1086
+ projectId: scope.projectId,
1087
+ topicId: String(scope.topicId)
1088
+ }
1089
+ );
1090
+ }
1091
+ await markBeliefGraphDirty(ctx, {
1092
+ projectId: scope.projectId,
1093
+ topicId: String(scope.topicId)
1094
+ });
1095
+ return { nodeId };
1096
+ }
1097
+ });
1098
+ var getById = query({
1099
+ args: {
1100
+ nodeId: v.optional(v.id("epistemicNodes")),
1101
+ beliefId: v.optional(v.string())
1102
+ },
1103
+ returns: permissiveReturn,
1104
+ handler: async (ctx, args) => {
1105
+ const id = args.nodeId ?? args.beliefId;
1106
+ if (!id) {
1107
+ return null;
1108
+ }
1109
+ const node = await ctx.db.get(id);
1110
+ if (!node || node.nodeType !== "belief") {
1111
+ return null;
1112
+ }
1113
+ return node;
1114
+ }
1115
+ });
1116
+ var refineBelief = mutation({
1117
+ args: {
1118
+ nodeId: v.id("epistemicNodes"),
1119
+ canonicalText: v.optional(v.string()),
1120
+ title: v.optional(v.string()),
1121
+ rationale: v.optional(v.string()),
1122
+ userId: v.string()
1123
+ },
1124
+ returns: permissiveReturn,
1125
+ handler: async (ctx, args) => {
1126
+ const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1127
+ const now = Date.now();
1128
+ const node = await ctx.db.get(args.nodeId);
1129
+ if (!node) {
1130
+ throwStructuredMutationError({
1131
+ message: "Belief not found.",
1132
+ status: 404,
1133
+ code: "NOT_FOUND",
1134
+ invariantCode: "belief.exists",
1135
+ suggestion: "Verify nodeId points to an existing belief before refining.",
1136
+ details: { nodeId: args.nodeId }
1137
+ });
1138
+ }
1139
+ if (node.nodeType !== "belief") {
1140
+ throwStructuredMutationError({
1141
+ message: `refineBelief only applies to belief nodes. Received nodeType "${node.nodeType}".`,
1142
+ status: 400,
1143
+ code: "INVALID_ARGUMENT",
1144
+ invariantCode: "entity.no_refine",
1145
+ suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations.",
1146
+ details: { nodeId: args.nodeId, nodeType: node.nodeType }
1147
+ });
1148
+ }
1149
+ if (!node.projectId) {
1150
+ throwStructuredMutationError({
1151
+ message: "Belief has no project scope.",
1152
+ status: 400,
1153
+ code: "MISSING_SCOPE",
1154
+ invariantCode: "belief.project_required",
1155
+ suggestion: "Belief must have a projectId to refine.",
1156
+ details: { nodeId: args.nodeId }
1157
+ });
1158
+ }
1159
+ await requireProjectWriteAccess(ctx, node.projectId, authenticatedUserId);
1160
+ if (typeof node.confidence === "number" && Number.isFinite(node.confidence)) {
1161
+ throwStructuredMutationError({
1162
+ message: "Scored beliefs are immutable. Use forkBelief to evolve a scored belief.",
1163
+ status: 409,
1164
+ code: "CONFLICT",
1165
+ invariantCode: "belief.versioning.scored_immutable",
1166
+ suggestion: "Use forkBelief() to create a new version instead of refining in place.",
1167
+ details: { nodeId: args.nodeId, confidence: node.confidence }
1168
+ });
1169
+ }
1170
+ const nextText = typeof args.canonicalText === "string" && args.canonicalText.trim().length > 0 ? args.canonicalText.trim() : void 0;
1171
+ const nextTitle = typeof args.title === "string" && args.title.trim().length > 0 ? args.title.trim() : void 0;
1172
+ const patch = { updatedAt: now };
1173
+ if (nextText !== void 0) {
1174
+ patch.canonicalText = nextText;
1175
+ patch.title = nextTitle ?? nextText.slice(0, 100) + (nextText.length > 100 ? "..." : "");
1176
+ patch.contentHash = generateContentHash(nextText);
1177
+ } else if (nextTitle !== void 0) {
1178
+ patch.title = nextTitle;
1179
+ }
1180
+ if (args.rationale !== void 0) {
1181
+ patch.content = args.rationale;
1182
+ }
1183
+ await ctx.db.patch(args.nodeId, patch);
1184
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1185
+ nodeId: args.nodeId,
1186
+ operation: "upsert"
1187
+ });
1188
+ if (nextText !== void 0) {
1189
+ await scheduleEmbeddingGeneration({
1190
+ ctx,
1191
+ nodeId: args.nodeId,
1192
+ projectId: node.projectId,
1193
+ topicId: node.topicId,
1194
+ createdBy: authenticatedUserId,
1195
+ nodeType: "belief",
1196
+ text: args.rationale ? `${nextText}
1197
+
1198
+ Rationale: ${args.rationale}` : nextText
1199
+ });
1200
+ }
1201
+ await ctx.db.insert("epistemicAudit", {
1202
+ entityType: "belief",
1203
+ entityId: args.nodeId,
1204
+ changeType: "updated",
1205
+ changedAt: now,
1206
+ changedBy: authenticatedUserId,
1207
+ isAgent: false,
1208
+ previousState: {
1209
+ canonicalText: node.canonicalText,
1210
+ title: node.title,
1211
+ content: node.content
1212
+ },
1213
+ newState: {
1214
+ canonicalText: patch.canonicalText ?? node.canonicalText,
1215
+ title: patch.title ?? node.title,
1216
+ content: patch.content ?? node.content,
1217
+ action: "refined",
1218
+ rationale: args.rationale
1219
+ },
1220
+ projectId: node.projectId,
1221
+ topicId: node.topicId
1222
+ });
1223
+ await markBeliefGraphDirty(ctx, {
1224
+ projectId: node.projectId,
1225
+ topicId: node.topicId
1226
+ });
1227
+ return { nodeId: args.nodeId };
1228
+ }
1229
+ });
1230
+ var getByProject = query({
1231
+ args: {
1232
+ ...optionalBeliefScopeArgs,
1233
+ status: v.optional(
1234
+ v.union(
1235
+ v.literal("active"),
1236
+ v.literal("superseded"),
1237
+ v.literal("archived")
1238
+ )
1239
+ ),
1240
+ userId: v.optional(v.string()),
1241
+ limit: v.optional(v.number())
1242
+ },
1243
+ returns: permissiveReturn,
1244
+ handler: async (ctx, args) => {
1245
+ if (!args.projectId && !args.topicId) {
1246
+ return [];
1247
+ }
1248
+ const pageSize = clampBeliefLimit(args.limit);
1249
+ const scanLimit = Math.min(pageSize * 3, MAX_PROJECT_BELIEF_LIMIT);
1250
+ let scope;
1251
+ try {
1252
+ scope = await resolveTopicProjectScope(ctx, {
1253
+ projectId: args.projectId,
1254
+ topicId: args.topicId
1255
+ });
1256
+ } catch (error) {
1257
+ debugGraphPrimitiveFallback(
1258
+ "[epistemicBeliefs] Failed to resolve project scope",
1259
+ {
1260
+ error,
1261
+ projectId: args.projectId,
1262
+ topicId: args.topicId
1263
+ }
1264
+ );
1265
+ return [];
1266
+ }
1267
+ if (args.userId) {
1268
+ const scopeId = scope.topicId ? String(scope.topicId) : scope.projectId;
1269
+ if (!scopeId) {
1270
+ return [];
1271
+ }
1272
+ const hasAccess = await checkScopeAccess(ctx, scopeId, args.userId);
1273
+ if (!hasAccess) {
1274
+ return [];
1275
+ }
1276
+ }
1277
+ const query3 = ctx.db.query("epistemicNodes").withIndex(
1278
+ "by_topic_type",
1279
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
1280
+ );
1281
+ const nodes = await query3.order("desc").take(scanLimit);
1282
+ const scopedNodes = nodes.filter(
1283
+ (node) => nodeMatchesWorkspaceReasoningScope(node, scope)
1284
+ );
1285
+ if (args.status) {
1286
+ return scopedNodes.filter((n) => n.status === args.status).slice(0, pageSize);
1287
+ }
1288
+ return scopedNodes.filter((n) => n.status === "active").slice(0, pageSize);
1289
+ }
1290
+ });
1291
+ var getByTopic = query({
1292
+ args: {
1293
+ topicId: v.string(),
1294
+ status: v.optional(
1295
+ v.union(
1296
+ v.literal("active"),
1297
+ v.literal("superseded"),
1298
+ v.literal("archived")
1299
+ )
1300
+ ),
1301
+ userId: v.optional(v.string()),
1302
+ limit: v.optional(v.number())
1303
+ },
1304
+ returns: permissiveReturn,
1305
+ handler: async (ctx, args) => {
1306
+ const pageSize = clampBeliefLimit(args.limit);
1307
+ const scanLimit = Math.min(pageSize * 3, MAX_PROJECT_BELIEF_LIMIT);
1308
+ const scope = await resolveTopicProjectScope(ctx, {
1309
+ topicId: args.topicId
1310
+ });
1311
+ const query3 = ctx.db.query("epistemicNodes").withIndex(
1312
+ "by_topic_type",
1313
+ (q) => q.eq("topicId", args.topicId).eq("nodeType", "belief")
1314
+ );
1315
+ const nodes = await query3.order("desc").take(scanLimit);
1316
+ const scopedNodes = nodes.filter(
1317
+ (node) => nodeMatchesWorkspaceReasoningScope(node, {
1318
+ tenantId: scope.tenantId,
1319
+ workspaceId: scope.workspaceId
1320
+ })
1321
+ );
1322
+ if (args.status) {
1323
+ return scopedNodes.filter((n) => n.status === args.status).slice(0, pageSize);
1324
+ }
1325
+ return scopedNodes.filter((n) => n.status === "active").slice(0, pageSize);
1326
+ }
1327
+ });
1328
+ var forkBelief = mutation({
1329
+ args: {
1330
+ parentNodeId: v.id("epistemicNodes"),
1331
+ newFormulation: v.string(),
1332
+ forkReason: v.union(
1333
+ v.literal("refinement"),
1334
+ v.literal("contradiction_response"),
1335
+ v.literal("scope_change"),
1336
+ v.literal("confidence_collapse"),
1337
+ v.literal("manual")
1338
+ ),
1339
+ rationale: v.optional(v.string()),
1340
+ userId: v.string()
1341
+ },
1342
+ returns: permissiveReturn,
1343
+ handler: async (ctx, args) => {
1344
+ const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1345
+ const now = Date.now();
1346
+ await getActiveConfidencePolicy(ctx);
1347
+ const parent = await ctx.db.get(args.parentNodeId);
1348
+ if (!parent) {
1349
+ throwStructuredMutationError({
1350
+ message: "Parent node not found.",
1351
+ status: 404,
1352
+ code: "NOT_FOUND",
1353
+ invariantCode: "belief.exists",
1354
+ suggestion: "Verify parentNodeId points to an existing node before forking.",
1355
+ details: { parentNodeId: args.parentNodeId }
1356
+ });
1357
+ }
1358
+ if (parent.nodeType !== "belief") {
1359
+ throwStructuredMutationError({
1360
+ message: `forkBelief only applies to belief nodes. Received nodeType "${parent.nodeType}". Entity nodes (company, person, investor, etc.) are mutable \u2014 use entityLifecycle.updateEntityAttributes instead of forking.`,
1361
+ status: 400,
1362
+ code: "INVALID_ARGUMENT",
1363
+ invariantCode: "entity.no_fork",
1364
+ suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. forkBelief is for belief nodes only.",
1365
+ details: { parentNodeId: args.parentNodeId, nodeType: parent.nodeType }
1366
+ });
1367
+ }
1368
+ if (!parent.projectId) {
1369
+ throwStructuredMutationError({
1370
+ message: "Parent belief has no project scope.",
1371
+ status: 400,
1372
+ code: "MISSING_SCOPE",
1373
+ invariantCode: "belief.project_required",
1374
+ suggestion: "Belief must have a projectId to fork.",
1375
+ details: { parentNodeId: args.parentNodeId }
1376
+ });
1377
+ }
1378
+ await requireProjectWriteAccess(ctx, parent.projectId, authenticatedUserId);
1379
+ const metadata = parent.metadata;
1380
+ const forkBeliefStatus = "hypothesis";
1381
+ const newBeliefGlobalId = generateGlobalId();
1382
+ const newNodeId = await ctx.db.insert("epistemicNodes", {
1383
+ globalId: newBeliefGlobalId,
1384
+ nodeType: "belief",
1385
+ epistemicLayer: "L3",
1386
+ canonicalText: args.newFormulation,
1387
+ contentHash: generateContentHash(args.newFormulation),
1388
+ content: args.rationale || parent.content,
1389
+ title: args.newFormulation.slice(0, 100) + (args.newFormulation.length > 100 ? "..." : ""),
1390
+ metadata: {
1391
+ ...metadata,
1392
+ forkedFrom: args.parentNodeId,
1393
+ forkReason: args.forkReason,
1394
+ forkTimestamp: now,
1395
+ forkedBy: authenticatedUserId,
1396
+ status: "active",
1397
+ beliefStatus: forkBeliefStatus,
1398
+ tupleContradicted: false
1399
+ },
1400
+ beliefStatus: forkBeliefStatus,
1401
+ sourceType: parent.sourceType,
1402
+ confidence: void 0,
1403
+ tupleContradicted: false,
1404
+ verificationStatus: "unverified",
1405
+ status: "active",
1406
+ projectId: parent.projectId,
1407
+ topicId: parent.topicId,
1408
+ createdBy: authenticatedUserId,
1409
+ createdAt: now,
1410
+ updatedAt: now
1411
+ });
1412
+ const inheritedContracts = await ctx.db.query("epistemicContracts").withIndex(
1413
+ "by_belief",
1414
+ (q) => q.eq("beliefNodeId", args.parentNodeId)
1415
+ ).collect();
1416
+ for (const contract of inheritedContracts) {
1417
+ if (contract.status === "archived") {
1418
+ continue;
1419
+ }
1420
+ await ctx.db.insert(
1421
+ "epistemicContracts",
1422
+ createInheritedContractRecord(contract, {
1423
+ beliefNodeId: newNodeId,
1424
+ topicId: parent.topicId,
1425
+ createdBy: authenticatedUserId,
1426
+ now
1427
+ })
1428
+ );
1429
+ }
1430
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1431
+ nodeId: newNodeId,
1432
+ operation: "upsert"
1433
+ });
1434
+ await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
1435
+ globalId: generateGlobalId(),
1436
+ fromGlobalId: newBeliefGlobalId,
1437
+ toGlobalId: parent.globalId,
1438
+ edgeType: "supersedes",
1439
+ context: `Fork reason: ${args.forkReason}`,
1440
+ createdBy: authenticatedUserId,
1441
+ topicId: parent.projectId ? String(parent.projectId) : void 0,
1442
+ fromNodeType: "belief",
1443
+ toNodeType: "belief"
1444
+ });
1445
+ await scheduleEmbeddingGeneration({
1446
+ ctx,
1447
+ nodeId: newNodeId,
1448
+ projectId: parent.projectId,
1449
+ topicId: parent.topicId,
1450
+ createdBy: authenticatedUserId,
1451
+ nodeType: "belief",
1452
+ text: args.newFormulation
1453
+ });
1454
+ await ctx.db.insert("epistemicAudit", {
1455
+ entityType: "belief",
1456
+ entityId: newNodeId,
1457
+ changeType: "forked",
1458
+ changedAt: now,
1459
+ changedBy: authenticatedUserId,
1460
+ isAgent: false,
1461
+ previousState: {
1462
+ parentNodeId: args.parentNodeId,
1463
+ formulation: parent.canonicalText
1464
+ },
1465
+ newState: {
1466
+ formulation: args.newFormulation,
1467
+ forkReason: args.forkReason,
1468
+ tupleContradicted: false
1469
+ },
1470
+ projectId: parent.projectId,
1471
+ topicId: parent.topicId
1472
+ });
1473
+ if (parent.projectId || parent.topicId) {
1474
+ const inheritedPillar = normalizePillar(
1475
+ String(metadata?.pillar || metadata?.topic || "")
1476
+ );
1477
+ if (inheritedPillar === "other") {
1478
+ await ctx.scheduler.runAfter(
1479
+ 2500,
1480
+ "beliefCategorization:autoCategorizeBelief",
1481
+ {
1482
+ nodeId: newNodeId,
1483
+ projectId: parent.projectId,
1484
+ topicId: parent.topicId
1485
+ }
1486
+ );
1487
+ }
1488
+ await ctx.scheduler.runAfter(
1489
+ 3e3,
1490
+ internal.beliefTemporalClassifier.classifyBelief,
1491
+ {
1492
+ nodeId: newNodeId,
1493
+ projectId: parent.projectId,
1494
+ topicId: parent.topicId
1495
+ }
1496
+ );
1497
+ }
1498
+ await markBeliefGraphDirty(ctx, {
1499
+ projectId: parent.projectId,
1500
+ topicId: parent.topicId
1501
+ });
1502
+ return { newNodeId, parentNodeId: args.parentNodeId };
1503
+ }
1504
+ });
1505
+
1506
+ export { create, forkBelief, getById, getByProject, getByTopic, refineBelief };
1507
+ //# sourceMappingURL=epistemicBeliefs.core.js.map
1508
+ //# sourceMappingURL=epistemicBeliefs.core.js.map