@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,1608 @@
1
+ import { v } from 'convex/values';
2
+ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
3
+ import { componentsGeneric, anyApi, internalMutationGeneric, mutationGeneric } from 'convex/server';
4
+ import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
5
+ import { normalizeTupleContradictionPolicy, mkOpinion, conditionalDeduction, project, dampedDependencyCascade, hasProjectedOpinionChanged, confidenceFromSL, detectTupleContradiction, evaluateTupleContradictionTransition, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, readOpinionFromRecord } from '@lucern/confidence';
6
+ import { checkProjectAccess } from '@lucern/access-control/access';
7
+ import '@lucern/access-control/audience';
8
+ import { getCurrentUserId } from '@lucern/access-control/auth';
9
+
10
+ // src/epistemicBeliefs.lifecycle.ts
11
+ var api = anyApi;
12
+ componentsGeneric();
13
+ var internal = anyApi;
14
+ var internalMutation = internalMutationGeneric;
15
+ var mutation = mutationGeneric;
16
+
17
+ // src/debug.ts
18
+ function isGraphPrimitiveDebugEnabled() {
19
+ const env = globalThis.process?.env;
20
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
21
+ }
22
+ function debugGraphPrimitiveFallback(message, context) {
23
+ if (!isGraphPrimitiveDebugEnabled()) {
24
+ return;
25
+ }
26
+ console.debug(message, context ?? {});
27
+ }
28
+
29
+ // src/topicScope.ts
30
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
31
+ function asMappedProjectId(topic) {
32
+ if (!topic) {
33
+ return;
34
+ }
35
+ const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
36
+ if (directLegacyProjectId) {
37
+ return directLegacyProjectId;
38
+ }
39
+ const metadata = topic.metadata || {};
40
+ const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
41
+ return candidate ? candidate : void 0;
42
+ }
43
+ function normalizeScopeValue(value) {
44
+ if (typeof value !== "string") {
45
+ return;
46
+ }
47
+ const normalized = value.trim();
48
+ return normalized.length > 0 ? normalized : void 0;
49
+ }
50
+ function pickPrimaryTopic(candidates) {
51
+ return [...candidates].sort((a, b) => {
52
+ const depthA = a.depth ?? 9999;
53
+ const depthB = b.depth ?? 9999;
54
+ if (depthA !== depthB) {
55
+ return depthA - depthB;
56
+ }
57
+ const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
58
+ const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
59
+ if (createdA !== createdB) {
60
+ return createdA - createdB;
61
+ }
62
+ return String(a.name || "").localeCompare(String(b.name || ""));
63
+ })[0];
64
+ }
65
+ async function findTopicsByScopeAlias(ctx, scopeId) {
66
+ try {
67
+ return await ctx.db.query("topics").withIndex(
68
+ "by_graph_scope_project",
69
+ (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
70
+ ).collect();
71
+ } catch (error) {
72
+ debugGraphPrimitiveFallback(
73
+ "[topicScope] Failed to resolve scope alias via index",
74
+ {
75
+ error,
76
+ scopeId
77
+ }
78
+ );
79
+ const topics = await ctx.db.query("topics").collect();
80
+ return topics.filter((topic) => {
81
+ const normalizedGlobalId = normalizeScopeValue(topic.globalId);
82
+ const mappedProjectId = asMappedProjectId(topic);
83
+ return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
84
+ });
85
+ }
86
+ }
87
+ async function tryResolveHostTopicById(ctx, topicId) {
88
+ if (typeof ctx.runQuery !== "function") {
89
+ return null;
90
+ }
91
+ try {
92
+ return await ctx.runQuery(api.topics.get, {
93
+ id: topicId
94
+ }) ?? null;
95
+ } catch (error) {
96
+ debugGraphPrimitiveFallback(
97
+ "[topicScope] Failed to resolve topic by host query",
98
+ {
99
+ error,
100
+ topicId
101
+ }
102
+ );
103
+ return null;
104
+ }
105
+ }
106
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
107
+ if (typeof ctx.runQuery !== "function") {
108
+ return null;
109
+ }
110
+ try {
111
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
112
+ projectId: legacyScopeId
113
+ }) ?? null;
114
+ } catch (error) {
115
+ debugGraphPrimitiveFallback(
116
+ "[topicScope] Failed to resolve topic by legacy scope",
117
+ {
118
+ error,
119
+ legacyScopeId
120
+ }
121
+ );
122
+ return null;
123
+ }
124
+ }
125
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
126
+ const MAX_DEPTH = 10;
127
+ let tenantId = normalizeScopeValue(topic.tenantId);
128
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
129
+ if (tenantId && workspaceId) {
130
+ return { tenantId, workspaceId };
131
+ }
132
+ let current = topic;
133
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
134
+ current = await ctx.db.get(current.parentTopicId);
135
+ if (!current) break;
136
+ if (!tenantId) {
137
+ tenantId = normalizeScopeValue(current.tenantId);
138
+ }
139
+ if (!workspaceId) {
140
+ workspaceId = normalizeScopeValue(current.workspaceId);
141
+ }
142
+ if (tenantId && workspaceId) break;
143
+ }
144
+ return { tenantId, workspaceId };
145
+ }
146
+ async function resolveTopicProjectScope(ctx, args) {
147
+ if (args.topicId) {
148
+ let topic = null;
149
+ try {
150
+ topic = await ctx.db.get(
151
+ args.topicId
152
+ );
153
+ } catch (error) {
154
+ debugGraphPrimitiveFallback(
155
+ "[topicScope] Failed to load topic by direct id",
156
+ {
157
+ error,
158
+ topicId: args.topicId
159
+ }
160
+ );
161
+ }
162
+ if (!topic) {
163
+ topic = await tryResolveHostTopicById(ctx, String(args.topicId));
164
+ }
165
+ if (!topic) {
166
+ topic = pickPrimaryTopic(
167
+ await findTopicsByScopeAlias(ctx, String(args.topicId))
168
+ ) ?? null;
169
+ }
170
+ if (!topic) {
171
+ throw new Error(`Topic not found: ${String(args.topicId)}`);
172
+ }
173
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
174
+ const mapped = asMappedProjectId(topic);
175
+ if (mapped) {
176
+ return {
177
+ topicId: topic._id,
178
+ projectId: mapped,
179
+ tenantId: inherited.tenantId,
180
+ workspaceId: inherited.workspaceId,
181
+ source: "topic"
182
+ };
183
+ }
184
+ return {
185
+ topicId: topic._id,
186
+ tenantId: inherited.tenantId,
187
+ workspaceId: inherited.workspaceId,
188
+ source: "topic"
189
+ };
190
+ }
191
+ if (args.projectId) {
192
+ let directTopic = null;
193
+ try {
194
+ directTopic = await ctx.db.get(
195
+ args.projectId
196
+ );
197
+ } catch (error) {
198
+ debugGraphPrimitiveFallback(
199
+ "[topicScope] Failed to load direct project topic",
200
+ {
201
+ error,
202
+ projectId: args.projectId
203
+ }
204
+ );
205
+ }
206
+ if (directTopic) {
207
+ const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
208
+ const mapped = asMappedProjectId(directTopic);
209
+ return {
210
+ topicId: directTopic._id,
211
+ projectId: mapped ?? args.projectId,
212
+ tenantId: inherited.tenantId,
213
+ workspaceId: inherited.workspaceId,
214
+ source: "topic_inferred"
215
+ };
216
+ }
217
+ directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
218
+ if (directTopic) {
219
+ const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
220
+ const mapped = asMappedProjectId(directTopic);
221
+ return {
222
+ topicId: directTopic._id,
223
+ projectId: mapped ?? args.projectId,
224
+ tenantId: inherited.tenantId,
225
+ workspaceId: inherited.workspaceId,
226
+ source: "topic_inferred"
227
+ };
228
+ }
229
+ const topics = await findTopicsByScopeAlias(ctx, args.projectId);
230
+ const primary = pickPrimaryTopic(topics);
231
+ if (primary) {
232
+ const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
233
+ return {
234
+ topicId: primary._id,
235
+ projectId: args.projectId,
236
+ tenantId: inherited.tenantId,
237
+ workspaceId: inherited.workspaceId,
238
+ source: "project_mapped_topic"
239
+ };
240
+ }
241
+ throw new Error(
242
+ `Legacy project scope ${String(args.projectId)} has no mapped topic.`
243
+ );
244
+ }
245
+ throw new Error(
246
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
247
+ );
248
+ }
249
+ ({
250
+ projectId: v.optional(v.string()),
251
+ topicId: v.optional(v.string())
252
+ });
253
+
254
+ // src/workspaceIsolation.ts
255
+ function normalizeScopeValue2(value) {
256
+ if (typeof value !== "string") {
257
+ return;
258
+ }
259
+ const normalized = value.trim();
260
+ return normalized.length > 0 ? normalized : void 0;
261
+ }
262
+ function throwWorkspaceIsolationError(args) {
263
+ const error = new Error(args.message);
264
+ error.status = 409;
265
+ error.code = "INVARIANT_VIOLATION";
266
+ error.invariantCode = args.invariantCode;
267
+ error.suggestion = args.suggestion;
268
+ error.details = args.details;
269
+ throw error;
270
+ }
271
+ function nodeMatchesWorkspaceReasoningScope(node, scope) {
272
+ if (!node) {
273
+ return false;
274
+ }
275
+ const scopeTenantId = normalizeScopeValue2(scope.tenantId);
276
+ const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
277
+ const nodeTenantId = normalizeScopeValue2(node.tenantId);
278
+ const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
279
+ const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
280
+ if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
281
+ return false;
282
+ }
283
+ if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
284
+ return true;
285
+ }
286
+ if (!scopeWorkspaceId && node.publicationStatus === "published") {
287
+ return true;
288
+ }
289
+ if (!scopeWorkspaceId) {
290
+ return nodeWorkspaceId === void 0;
291
+ }
292
+ return scopeWorkspaceId === nodeWorkspaceId;
293
+ }
294
+ function edgeMatchesWorkspaceReasoningScope(edge, scope) {
295
+ if (!edge) {
296
+ return false;
297
+ }
298
+ const scopeTenantId = normalizeScopeValue2(scope.tenantId);
299
+ const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
300
+ const edgeTenantId = normalizeScopeValue2(edge.tenantId);
301
+ const edgeWorkspaceId = normalizeScopeValue2(edge.workspaceId);
302
+ if (scopeTenantId && edgeTenantId && scopeTenantId !== edgeTenantId) {
303
+ return false;
304
+ }
305
+ if (!scopeWorkspaceId) {
306
+ return edgeWorkspaceId === void 0;
307
+ }
308
+ return scopeWorkspaceId === edgeWorkspaceId;
309
+ }
310
+ async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
311
+ const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
312
+ const resolved = {
313
+ tenantId: normalizeScopeValue2(node?.tenantId),
314
+ workspaceId: normalizeScopeValue2(node?.workspaceId),
315
+ epistemicLayer,
316
+ nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
317
+ };
318
+ if (!node) {
319
+ return resolved;
320
+ }
321
+ if (resolved.epistemicLayer === "ontological") {
322
+ return resolved;
323
+ }
324
+ if (resolved.tenantId || resolved.workspaceId) {
325
+ return resolved;
326
+ }
327
+ if (node.topicId) {
328
+ const topicScope = await resolveTopicProjectScope(ctx, {
329
+ topicId: node.topicId
330
+ });
331
+ return {
332
+ ...resolved,
333
+ tenantId: topicScope.tenantId,
334
+ workspaceId: topicScope.workspaceId
335
+ };
336
+ }
337
+ if (node.projectId) {
338
+ const topicScope = await resolveTopicProjectScope(ctx, {
339
+ projectId: String(node.projectId)
340
+ });
341
+ return {
342
+ ...resolved,
343
+ tenantId: topicScope.tenantId,
344
+ workspaceId: topicScope.workspaceId
345
+ };
346
+ }
347
+ return resolved;
348
+ }
349
+ function resolveRuntimePackMutationContext(args) {
350
+ if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
351
+ return;
352
+ }
353
+ return {
354
+ toolName: args.runtimeToolName,
355
+ packKey: args.runtimePackKey,
356
+ packInstallScope: args.runtimePackInstallScope
357
+ };
358
+ }
359
+ function assertTenantPackWorkspaceMutationAllowed(args) {
360
+ if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
361
+ return;
362
+ }
363
+ const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
364
+ const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
365
+ if (!targetWorkspaceId || targetLayer === "ontological") {
366
+ return;
367
+ }
368
+ throwWorkspaceIsolationError({
369
+ message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
370
+ invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
371
+ suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
372
+ details: {
373
+ mutationName: args.mutationName,
374
+ toolName: args.runtime.toolName,
375
+ packKey: args.runtime.packKey,
376
+ targetWorkspaceId,
377
+ targetNodeType: args.target.nodeType,
378
+ targetLayer
379
+ }
380
+ });
381
+ }
382
+
383
+ // src/beliefLifecycle.ts
384
+ var BELIEF_STATUS_VALUES = [
385
+ "assumption",
386
+ "hypothesis",
387
+ "belief",
388
+ "fact"
389
+ ];
390
+ var RESOLVED_PREDICTION_OUTCOMES = [
391
+ "confirmed",
392
+ "disconfirmed",
393
+ "partial",
394
+ "expired"
395
+ ];
396
+ function isBeliefLifecycleStatus(value) {
397
+ return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
398
+ }
399
+ function normalizeBeliefConfidence(confidence) {
400
+ if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
401
+ return null;
402
+ }
403
+ if (confidence >= 0 && confidence <= 1) {
404
+ return confidence;
405
+ }
406
+ if (confidence > 1 && confidence <= 100) {
407
+ return confidence / 100;
408
+ }
409
+ return null;
410
+ }
411
+ function isResolvedByConfidence(confidence) {
412
+ const normalized = normalizeBeliefConfidence(confidence);
413
+ if (normalized === null) {
414
+ return false;
415
+ }
416
+ return normalized <= 0 || normalized >= 1;
417
+ }
418
+ function hasResolvedPredictionOutcome(predictionMeta) {
419
+ if (!predictionMeta || typeof predictionMeta !== "object") {
420
+ return false;
421
+ }
422
+ const outcome = predictionMeta.outcome;
423
+ return typeof outcome === "string" && RESOLVED_PREDICTION_OUTCOMES.includes(outcome);
424
+ }
425
+ function getPredictionMetaFromMetadata(metadata) {
426
+ return metadata?.predictionMeta;
427
+ }
428
+ function shouldTreatBeliefAsFact(opts) {
429
+ if (isResolvedByConfidence(opts.confidence)) {
430
+ return true;
431
+ }
432
+ if (hasResolvedPredictionOutcome(opts.predictionMeta)) {
433
+ return true;
434
+ }
435
+ if (hasResolvedPredictionOutcome(getPredictionMetaFromMetadata(opts.metadata))) {
436
+ return true;
437
+ }
438
+ return false;
439
+ }
440
+ function resolveBeliefLifecycleStatus(opts) {
441
+ if (shouldTreatBeliefAsFact(opts)) {
442
+ return "fact";
443
+ }
444
+ const direct = opts.beliefStatus;
445
+ if (isBeliefLifecycleStatus(direct)) {
446
+ const normalized = normalizeBeliefConfidence(opts.confidence);
447
+ if (normalized !== null && isPreValidationBeliefStatus(direct)) {
448
+ return "belief";
449
+ }
450
+ return direct;
451
+ }
452
+ const metaStatus = opts.metadata?.beliefStatus;
453
+ if (isBeliefLifecycleStatus(metaStatus)) {
454
+ const normalized = normalizeBeliefConfidence(opts.confidence);
455
+ if (normalized !== null && isPreValidationBeliefStatus(metaStatus)) {
456
+ return "belief";
457
+ }
458
+ return metaStatus;
459
+ }
460
+ return "assumption";
461
+ }
462
+ function isPreValidationBeliefStatus(status) {
463
+ return status === "assumption" || status === "hypothesis";
464
+ }
465
+ function promoteBeliefStatusAfterScoring(status, opts) {
466
+ if (shouldTreatBeliefAsFact({ ...opts })) {
467
+ return "fact";
468
+ }
469
+ if (isPreValidationBeliefStatus(status)) {
470
+ return "belief";
471
+ }
472
+ return status === "fact" ? "fact" : "belief";
473
+ }
474
+
475
+ // src/edges/contains.ts
476
+ var containsPropagationSpec = {
477
+ edgeType: "contains",
478
+ direction: "outgoing",
479
+ transitivity: "none",
480
+ damping: 1,
481
+ maxHops: 1,
482
+ operator: () => null,
483
+ description: "Structural containment only. Traversed for explicit semantics, but it never propagates opinions."
484
+ };
485
+ function readEdgeMetadata(edge) {
486
+ return {
487
+ constraint: edge.constraint ?? void 0,
488
+ normalization: edge.normalization ?? void 0,
489
+ propagation: edge.propagation ?? void 0,
490
+ conditionalA: edge.conditionalA ?? void 0,
491
+ conditionalNotA: edge.conditionalNotA ?? void 0
492
+ };
493
+ }
494
+ function applyPerHopDamping(sourceOpinion, damping) {
495
+ if (damping >= 1) {
496
+ return sourceOpinion;
497
+ }
498
+ return trustDiscount(sourceOpinion, Math.max(0, damping));
499
+ }
500
+ function annotateRationale(result, spec, hop) {
501
+ return {
502
+ ...result,
503
+ rationale: `hop=${hop} edge=${spec.edgeType} damping=${spec.damping.toFixed(
504
+ 2
505
+ )} :: ${result.rationale}`
506
+ };
507
+ }
508
+ function propagatePositiveSupport(sourceOpinion, targetOpinion, edgeWeight) {
509
+ const discounted = trustDiscount(sourceOpinion, Math.abs(edgeWeight));
510
+ return {
511
+ opinion: cumulativeFusion(targetOpinion, discounted),
512
+ operator: "cumulative_fusion",
513
+ rationale: `Supporting evidence (weight=${edgeWeight.toFixed(
514
+ 2
515
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
516
+ };
517
+ }
518
+ function propagatePositiveInform(sourceOpinion, targetOpinion, edgeWeight) {
519
+ const discounted = trustDiscount(sourceOpinion, Math.abs(edgeWeight));
520
+ return {
521
+ opinion: cumulativeFusion(targetOpinion, discounted),
522
+ operator: "cumulative_fusion",
523
+ rationale: `Supporting evidence (weight=${edgeWeight.toFixed(2)})`
524
+ };
525
+ }
526
+ function propagateNegativeSupportWithMetadata(sourceOpinion, targetOpinion, edgeWeight, edge) {
527
+ return applyNegativeSupport(
528
+ sourceOpinion,
529
+ targetOpinion,
530
+ edgeWeight,
531
+ readEdgeMetadata(edge)
532
+ );
533
+ }
534
+ var propagateNegativeInform = applyNegativeEvidence;
535
+
536
+ // src/edges/contradicts.ts
537
+ var contradictsPropagationSpec = {
538
+ edgeType: "contradicts",
539
+ direction: "bidirectional",
540
+ transitivity: "none",
541
+ damping: 0.85,
542
+ maxHops: 1,
543
+ operator: (sourceOpinion, targetOpinion, edge, context) => {
544
+ const dampedSource = applyPerHopDamping(
545
+ sourceOpinion,
546
+ context.spec.damping
547
+ );
548
+ const negativeWeight = -Math.abs(edge.weight ?? 1);
549
+ const result = propagateNegativeSupportWithMetadata(
550
+ dampedSource,
551
+ targetOpinion,
552
+ negativeWeight,
553
+ edge
554
+ );
555
+ return annotateRationale(result, context.spec, context.hop);
556
+ },
557
+ description: "Legacy contradiction edges move negative pressure in either direction, but never beyond one hop."
558
+ };
559
+ var dependsOnPropagationSpec = {
560
+ edgeType: "depends_on",
561
+ direction: "incoming",
562
+ transitivity: "damped",
563
+ damping: 0.8,
564
+ maxHops: "unbounded",
565
+ operator: (sourceOpinion, targetOpinion, edge, context) => {
566
+ const dampedSource = applyPerHopDamping(
567
+ sourceOpinion,
568
+ context.spec.damping
569
+ );
570
+ const metadata = readEdgeMetadata(edge);
571
+ if (metadata.conditionalA && metadata.conditionalNotA) {
572
+ const deducedOpinion = conditionalDeduction(
573
+ dampedSource,
574
+ mkOpinion(
575
+ metadata.conditionalA.b,
576
+ metadata.conditionalA.d,
577
+ metadata.conditionalA.u,
578
+ metadata.conditionalA.a
579
+ ),
580
+ mkOpinion(
581
+ metadata.conditionalNotA.b,
582
+ metadata.conditionalNotA.d,
583
+ metadata.conditionalNotA.u,
584
+ metadata.conditionalNotA.a
585
+ ),
586
+ targetOpinion.a
587
+ );
588
+ return annotateRationale(
589
+ {
590
+ opinion: deducedOpinion,
591
+ operator: "conditional_deduction",
592
+ rationale: `Conditional deduction: prerequisite at ${project(
593
+ dampedSource
594
+ ).toFixed(2)}`
595
+ },
596
+ context.spec,
597
+ context.hop
598
+ );
599
+ }
600
+ const result = dampedDependencyCascade(
601
+ dampedSource,
602
+ targetOpinion,
603
+ metadata.propagation ?? "continuous"
604
+ );
605
+ return annotateRationale(result, context.spec, context.hop);
606
+ },
607
+ description: "Structural gating. Textbook conditional deduction when edge conditionals exist, otherwise damped dependency cascade through downstream chains."
608
+ };
609
+
610
+ // src/edges/derivedFrom.ts
611
+ var derivedFromPropagationSpec = {
612
+ edgeType: "derived_from",
613
+ direction: "incoming",
614
+ transitivity: "none",
615
+ damping: 1,
616
+ maxHops: 1,
617
+ operator: () => null,
618
+ description: "Provenance only. The traversal surface stays explicit, but confidence does not move across derived_from edges."
619
+ };
620
+
621
+ // src/edges/elaborates.ts
622
+ var elaboratesPropagationSpec = {
623
+ edgeType: "elaborates",
624
+ direction: "outgoing",
625
+ transitivity: "damped",
626
+ damping: 0.7,
627
+ maxHops: 2,
628
+ operator: (sourceOpinion, targetOpinion, edge, context) => {
629
+ const dampedSource = applyPerHopDamping(
630
+ sourceOpinion,
631
+ context.spec.damping
632
+ );
633
+ const contextualWeight = Math.min(Math.abs(edge.weight ?? 0.35), 0.35);
634
+ const result = propagatePositiveInform(
635
+ dampedSource,
636
+ targetOpinion,
637
+ contextualWeight
638
+ );
639
+ return annotateRationale(result, context.spec, context.hop);
640
+ },
641
+ description: "Context-rich supporting detail. Elaborates carries a small positive effect with short, damped chaining."
642
+ };
643
+
644
+ // src/edges/informs.ts
645
+ var informsPropagationSpec = {
646
+ edgeType: "informs",
647
+ direction: "outgoing",
648
+ transitivity: "full",
649
+ damping: 0.92,
650
+ maxHops: "unbounded",
651
+ operator: (sourceOpinion, targetOpinion, edge, context) => {
652
+ const dampedSource = applyPerHopDamping(
653
+ sourceOpinion,
654
+ context.spec.damping
655
+ );
656
+ const weight = edge.weight ?? 1;
657
+ const result = weight < 0 ? propagateNegativeInform(dampedSource, targetOpinion, weight) : propagatePositiveInform(dampedSource, targetOpinion, weight);
658
+ return annotateRationale(result, context.spec, context.hop);
659
+ },
660
+ description: "Evidence-bearing influence. Informs can chain through the graph with light per-hop damping."
661
+ };
662
+
663
+ // src/edges/propagationTypes.ts
664
+ function isPropagationTraversalDirection(direction) {
665
+ return direction === "outgoing" || direction === "incoming";
666
+ }
667
+ function canTraverseHop(spec, nextHop) {
668
+ return spec.maxHops === "unbounded" || nextHop <= spec.maxHops;
669
+ }
670
+ function canContinueTransitively(spec, currentHop) {
671
+ if (spec.transitivity === "none") {
672
+ return false;
673
+ }
674
+ return spec.maxHops === "unbounded" || currentHop < spec.maxHops;
675
+ }
676
+
677
+ // src/edges/refutes.ts
678
+ var refutesPropagationSpec = {
679
+ edgeType: "refutes",
680
+ direction: "outgoing",
681
+ transitivity: "none",
682
+ damping: 0.9,
683
+ maxHops: 1,
684
+ operator: (sourceOpinion, targetOpinion, edge, context) => {
685
+ const dampedSource = applyPerHopDamping(
686
+ sourceOpinion,
687
+ context.spec.damping
688
+ );
689
+ const negativeWeight = -Math.abs(edge.weight ?? 1);
690
+ const result = propagateNegativeInform(
691
+ dampedSource,
692
+ targetOpinion,
693
+ negativeWeight
694
+ );
695
+ return annotateRationale(result, context.spec, context.hop);
696
+ },
697
+ description: "Explicit negative evidence semantics. Refutes is treated as strong one-hop counter-evidence."
698
+ };
699
+
700
+ // src/edges/supports.ts
701
+ var supportsPropagationSpec = {
702
+ edgeType: "supports",
703
+ direction: "outgoing",
704
+ transitivity: "full",
705
+ damping: 0.85,
706
+ maxHops: "unbounded",
707
+ operator: (sourceOpinion, targetOpinion, edge, context) => {
708
+ const dampedSource = applyPerHopDamping(
709
+ sourceOpinion,
710
+ context.spec.damping
711
+ );
712
+ const weight = edge.weight ?? 1;
713
+ const result = weight < 0 ? propagateNegativeSupportWithMetadata(
714
+ dampedSource,
715
+ targetOpinion,
716
+ weight,
717
+ edge
718
+ ) : propagatePositiveSupport(dampedSource, targetOpinion, weight);
719
+ return annotateRationale(result, context.spec, context.hop);
720
+ },
721
+ description: "Belief-to-belief influence. Supports chains transitively with moderate per-hop damping."
722
+ };
723
+
724
+ // src/edges/tests.ts
725
+ var testsPropagationSpec = {
726
+ edgeType: "tests",
727
+ direction: "outgoing",
728
+ transitivity: "none",
729
+ damping: 1,
730
+ maxHops: 1,
731
+ operator: () => null,
732
+ description: "Interrogation linkage only. Tests edges do not directly move confidence."
733
+ };
734
+
735
+ // src/edges/index.ts
736
+ var EDGE_PROPAGATION_SPECS = [
737
+ supportsPropagationSpec,
738
+ informsPropagationSpec,
739
+ dependsOnPropagationSpec,
740
+ derivedFromPropagationSpec,
741
+ containsPropagationSpec,
742
+ testsPropagationSpec,
743
+ contradictsPropagationSpec,
744
+ refutesPropagationSpec,
745
+ elaboratesPropagationSpec
746
+ ];
747
+ new Map(EDGE_PROPAGATION_SPECS.map((spec) => [spec.edgeType, spec]));
748
+ function getEdgePropagationSpecs() {
749
+ return EDGE_PROPAGATION_SPECS;
750
+ }
751
+ function getTraversalDirections(direction) {
752
+ if (isPropagationTraversalDirection(direction)) {
753
+ return [direction];
754
+ }
755
+ return ["outgoing", "incoming"];
756
+ }
757
+
758
+ // src/confidencePropagationDispatch.ts
759
+ function resolveTraversalTargetNodeId(edge, direction) {
760
+ const targetNodeId = direction === "outgoing" ? edge.toNodeId : edge.fromNodeId;
761
+ return targetNodeId ?? void 0;
762
+ }
763
+ function readNodeOpinion(node) {
764
+ const metadata = node.metadata ?? {};
765
+ try {
766
+ return readOpinionFromRecord({
767
+ ...metadata,
768
+ opinion_b: node.opinion_b,
769
+ opinion_d: node.opinion_d,
770
+ opinion_u: node.opinion_u,
771
+ opinion_a: node.opinion_a
772
+ });
773
+ } catch {
774
+ return mkOpinion(0, 0, 1, 0.5);
775
+ }
776
+ }
777
+ async function collectConfidencePropagationDispatches(args) {
778
+ const dispatchesByTargetId = /* @__PURE__ */ new Map();
779
+ const opinionCache = /* @__PURE__ */ new Map();
780
+ const nodeCache = /* @__PURE__ */ new Map();
781
+ const traversalSpecs = args.traversalSpecs ?? getEdgePropagationSpecs();
782
+ const queue = [
783
+ {
784
+ nodeId: args.sourceNodeId,
785
+ opinion: args.sourceOpinion,
786
+ hop: 0,
787
+ visitedNodeIds: /* @__PURE__ */ new Set([String(args.sourceNodeId)])
788
+ }
789
+ ];
790
+ const loadNode = async (nodeId) => {
791
+ const cacheKey = String(nodeId);
792
+ if (!nodeCache.has(cacheKey)) {
793
+ nodeCache.set(cacheKey, await args.getNode(nodeId));
794
+ }
795
+ return nodeCache.get(cacheKey) ?? null;
796
+ };
797
+ while (queue.length > 0) {
798
+ const state = queue.shift();
799
+ if (!state) {
800
+ continue;
801
+ }
802
+ for (const spec of traversalSpecs) {
803
+ const nextHop = state.hop + 1;
804
+ if (!canTraverseHop(spec, nextHop)) {
805
+ continue;
806
+ }
807
+ for (const direction of getTraversalDirections(spec.direction)) {
808
+ const edges = await args.queryEdges({
809
+ nodeId: state.nodeId,
810
+ spec,
811
+ direction,
812
+ hop: nextHop
813
+ });
814
+ for (const edge of edges) {
815
+ if (args.sourceScope && !edgeMatchesWorkspaceReasoningScope(edge, args.sourceScope)) {
816
+ continue;
817
+ }
818
+ const targetNodeId = resolveTraversalTargetNodeId(edge, direction);
819
+ if (!targetNodeId) {
820
+ continue;
821
+ }
822
+ if (state.visitedNodeIds.has(String(targetNodeId))) {
823
+ continue;
824
+ }
825
+ const targetNode = await loadNode(targetNodeId);
826
+ if (!targetNode || targetNode.nodeType !== "belief") {
827
+ continue;
828
+ }
829
+ if (args.sourceScope && !nodeMatchesWorkspaceReasoningScope(targetNode, args.sourceScope)) {
830
+ continue;
831
+ }
832
+ const cacheKey = String(targetNodeId);
833
+ const targetOpinion = opinionCache.get(cacheKey) ?? readNodeOpinion(targetNode);
834
+ const result = spec.operator(state.opinion, targetOpinion, edge, {
835
+ hop: nextHop,
836
+ sourceNodeId: state.nodeId,
837
+ targetNodeId,
838
+ traversedDirection: direction,
839
+ spec
840
+ });
841
+ if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
842
+ continue;
843
+ }
844
+ const projectedOpinion = mkOpinion(
845
+ result.opinion.b,
846
+ result.opinion.d,
847
+ result.opinion.u,
848
+ result.opinion.a
849
+ );
850
+ opinionCache.set(cacheKey, projectedOpinion);
851
+ const existingDispatch = dispatchesByTargetId.get(cacheKey);
852
+ dispatchesByTargetId.set(cacheKey, {
853
+ targetNodeId,
854
+ edgeType: spec.edgeType,
855
+ traversedDirection: direction,
856
+ weight: edge.weight ?? 1,
857
+ opinion: projectedOpinion,
858
+ operator: result.operator,
859
+ rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
860
+ hop: nextHop
861
+ });
862
+ if (canContinueTransitively(spec, nextHop)) {
863
+ queue.push({
864
+ nodeId: targetNodeId,
865
+ opinion: projectedOpinion,
866
+ hop: nextHop,
867
+ visitedNodeIds: /* @__PURE__ */ new Set([
868
+ ...state.visitedNodeIds,
869
+ String(targetNodeId)
870
+ ])
871
+ });
872
+ }
873
+ }
874
+ }
875
+ }
876
+ }
877
+ return Array.from(dispatchesByTargetId.values()).sort((left, right) => {
878
+ if (left.hop !== right.hop) {
879
+ return left.hop - right.hop;
880
+ }
881
+ return String(left.targetNodeId).localeCompare(String(right.targetNodeId));
882
+ });
883
+ }
884
+ v.id("epistemicNodes");
885
+ var DEFAULT_CONFIDENCE_POLICY = {
886
+ scoringMode: "after_worktree",
887
+ tupleContradiction: normalizeTupleContradictionPolicy()
888
+ };
889
+ function throwStructuredMutationError(args) {
890
+ const error = new Error(args.message);
891
+ error.status = args.status;
892
+ error.code = args.code;
893
+ error.invariantCode = args.invariantCode;
894
+ error.suggestion = args.suggestion;
895
+ error.details = args.details;
896
+ throw error;
897
+ }
898
+ function buildBeliefConfidenceRow(args) {
899
+ return {
900
+ beliefId: args.beliefId,
901
+ confidence: confidenceFromSL(
902
+ args.belief,
903
+ args.disbelief,
904
+ args.uncertainty,
905
+ args.baseRate
906
+ ),
907
+ belief: args.belief,
908
+ disbelief: args.disbelief,
909
+ uncertainty: args.uncertainty,
910
+ baseRate: args.baseRate,
911
+ slOperator: args.slOperator ?? "manual_assessment",
912
+ trigger: args.trigger,
913
+ ...args.rationale ? { rationale: args.rationale } : {},
914
+ assessedBy: args.assessedBy,
915
+ assessedAt: args.assessedAt,
916
+ ...args.triggeringEvidenceId ? {
917
+ triggeringEvidenceId: args.triggeringEvidenceId,
918
+ triggeringEvidenceIds: [String(args.triggeringEvidenceId)]
919
+ } : {},
920
+ ...args.triggeringContradictionId ? {
921
+ triggeringContradictionId: args.triggeringContradictionId
922
+ } : {},
923
+ ...args.triggeringWorktreeId ? { triggeringWorktreeId: args.triggeringWorktreeId } : {}
924
+ };
925
+ }
926
+ function readTupleContradictedFlag(value) {
927
+ return typeof value === "boolean" ? value : void 0;
928
+ }
929
+ function readBeliefOpinionSnapshot(node, metadata) {
930
+ try {
931
+ return readOpinionFromRecord({
932
+ ...metadata,
933
+ opinion_b: node.opinion_b,
934
+ opinion_d: node.opinion_d,
935
+ opinion_u: node.opinion_u,
936
+ opinion_a: node.opinion_a
937
+ });
938
+ } catch (error) {
939
+ debugGraphPrimitiveFallback(
940
+ "[epistemicBeliefs] Failed to read belief opinion snapshot",
941
+ {
942
+ error,
943
+ beliefId: node._id
944
+ }
945
+ );
946
+ return mkOpinion(0, 0, 1, 0.5);
947
+ }
948
+ }
949
+ function deriveTupleContradictionSeverity(node) {
950
+ const metadata = node.metadata || {};
951
+ const criticality = typeof metadata.criticality === "string" ? metadata.criticality : void 0;
952
+ if (criticality === "blocking") {
953
+ return "critical";
954
+ }
955
+ if (criticality === "supporting") {
956
+ return "minor";
957
+ }
958
+ return "significant";
959
+ }
960
+ function formatTupleContradictionDescription(args) {
961
+ return `Tuple-space contradiction detected: b=${args.opinion.b.toFixed(2)} > ${args.policy.beliefThreshold.toFixed(2)} and d=${args.opinion.d.toFixed(2)} > ${args.policy.disbeliefThreshold.toFixed(2)}.`;
962
+ }
963
+ function resolveBeliefStatus(node, metadata) {
964
+ return resolveBeliefLifecycleStatus({
965
+ beliefStatus: node.beliefStatus,
966
+ confidence: node.confidence,
967
+ predictionMeta: node.predictionMeta,
968
+ metadata
969
+ });
970
+ }
971
+ async function hasCompletedWorktreeForBelief(ctx, beliefNodeId) {
972
+ const clusterMembership = await ctx.db.query("worktreeBeliefCluster").withIndex("by_belief", (q) => q.eq("beliefId", beliefNodeId)).collect();
973
+ for (const membership of clusterMembership) {
974
+ const worktree = await ctx.db.get(membership.worktreeId);
975
+ if (worktree?.status === "completed" || worktree?.status === "merged") {
976
+ return true;
977
+ }
978
+ }
979
+ return false;
980
+ }
981
+ async function getActiveConfidencePolicy(ctx) {
982
+ try {
983
+ const activeConfig = await ctx.db.query("logicSprintScoring").withIndex("by_active", (q) => q.eq("isActive", true)).first();
984
+ return {
985
+ scoringMode: activeConfig?.confidencePolicy === "always" ? "always" : DEFAULT_CONFIDENCE_POLICY.scoringMode,
986
+ tupleContradiction: normalizeTupleContradictionPolicy(
987
+ activeConfig?.tupleContradictionPolicy
988
+ )
989
+ };
990
+ } catch (error) {
991
+ debugGraphPrimitiveFallback(
992
+ "[epistemicBeliefs] Failed to load active confidence policy",
993
+ {
994
+ error
995
+ }
996
+ );
997
+ return DEFAULT_CONFIDENCE_POLICY;
998
+ }
999
+ }
1000
+ async function requireAuthenticatedUserId(ctx) {
1001
+ const userId = await getCurrentUserId(
1002
+ ctx
1003
+ );
1004
+ if (!userId) {
1005
+ throwStructuredMutationError({
1006
+ message: "Authentication required.",
1007
+ status: 401,
1008
+ code: "AUTHENTICATION_REQUIRED",
1009
+ invariantCode: "auth.required",
1010
+ suggestion: "Provide a valid bearer token before invoking belief mutations."
1011
+ });
1012
+ }
1013
+ return userId;
1014
+ }
1015
+ async function requireProjectWriteAccess(ctx, projectId, userId) {
1016
+ const hasAccess = await checkProjectAccess(
1017
+ ctx,
1018
+ projectId,
1019
+ userId
1020
+ );
1021
+ if (!hasAccess) {
1022
+ throwStructuredMutationError({
1023
+ message: "Project access required.",
1024
+ status: 403,
1025
+ code: "FORBIDDEN",
1026
+ invariantCode: "policy.scope_required",
1027
+ suggestion: "Request write access for the project and retry.",
1028
+ details: { projectId, userId }
1029
+ });
1030
+ }
1031
+ }
1032
+
1033
+ // src/epistemicBeliefs.confidence.ts
1034
+ async function applyBeliefConfidenceChange(ctx, args) {
1035
+ const now = Date.now();
1036
+ const node = await ctx.db.get(args.nodeId);
1037
+ if (!node) {
1038
+ throwStructuredMutationError({
1039
+ message: "Node not found.",
1040
+ status: 404,
1041
+ code: "NOT_FOUND",
1042
+ invariantCode: "belief.exists",
1043
+ suggestion: "Verify nodeId points to an existing node before modulating confidence.",
1044
+ details: { nodeId: args.nodeId }
1045
+ });
1046
+ }
1047
+ if (node.nodeType !== "belief") {
1048
+ throwStructuredMutationError({
1049
+ message: `modulateConfidence only applies to belief nodes. Received nodeType "${node.nodeType}". Entity nodes (company, person, investor, etc.) do not have confidence \u2014 use entityLifecycle.updateEntityAttributes for mutable entity data.`,
1050
+ status: 400,
1051
+ code: "INVALID_ARGUMENT",
1052
+ invariantCode: "entity.no_confidence",
1053
+ suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. modulateConfidence is for belief nodes only.",
1054
+ details: { nodeId: args.nodeId, nodeType: node.nodeType }
1055
+ });
1056
+ }
1057
+ if (!node.projectId) {
1058
+ throwStructuredMutationError({
1059
+ message: "Belief has no project scope.",
1060
+ status: 400,
1061
+ code: "MISSING_SCOPE",
1062
+ invariantCode: "belief.project_required",
1063
+ suggestion: "Belief must have a projectId to modulate confidence.",
1064
+ details: { nodeId: args.nodeId }
1065
+ });
1066
+ }
1067
+ await requireProjectWriteAccess(
1068
+ ctx,
1069
+ node.projectId,
1070
+ args.authenticatedUserId
1071
+ );
1072
+ const existingMetadata = node.metadata || {};
1073
+ const currentBeliefStatus = resolveBeliefStatus(node, existingMetadata);
1074
+ const confidencePolicy = await getActiveConfidencePolicy(ctx);
1075
+ if (confidencePolicy.scoringMode === "after_worktree" && isPreValidationBeliefStatus(currentBeliefStatus)) {
1076
+ const hasCompletedWorktree = await hasCompletedWorktreeForBelief(
1077
+ ctx,
1078
+ args.nodeId
1079
+ );
1080
+ if (!hasCompletedWorktree) {
1081
+ throwStructuredMutationError({
1082
+ message: "Cannot score belief before worktree completion. Complete a worktree that tests this belief first.",
1083
+ status: 409,
1084
+ code: "CONFLICT",
1085
+ invariantCode: "belief.confidence_append_only",
1086
+ suggestion: "Complete a worktree linked to this belief before recording confidence modulation.",
1087
+ details: { nodeId: args.nodeId }
1088
+ });
1089
+ }
1090
+ }
1091
+ const previousConfidence = node.confidence || 0.5;
1092
+ const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
1093
+ const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
1094
+ const slB = args.belief;
1095
+ const slD = args.disbelief;
1096
+ const slU = args.uncertainty;
1097
+ const slA = args.baseRate ?? 0.5;
1098
+ const nextOpinion = { b: slB, d: slD, u: slU, a: slA };
1099
+ const derivedConfidence = confidenceFromSL(slB, slD, slU, slA);
1100
+ const isFirstScoring = typeof node.confidence !== "number" || !Number.isFinite(node.confidence);
1101
+ const previousTupleContradicted = readTupleContradictedFlag(node.tupleContradicted) ?? readTupleContradictedFlag(existingMetadata.tupleContradicted) ?? detectTupleContradiction(
1102
+ previousOpinion,
1103
+ confidencePolicy.tupleContradiction.beliefThreshold,
1104
+ confidencePolicy.tupleContradiction.disbeliefThreshold
1105
+ );
1106
+ const tupleTransition = evaluateTupleContradictionTransition({
1107
+ previousTupleContradicted,
1108
+ opinion: nextOpinion,
1109
+ policy: confidencePolicy.tupleContradiction
1110
+ });
1111
+ const tupleContradictionDescription = formatTupleContradictionDescription({
1112
+ opinion: nextOpinion,
1113
+ policy: tupleTransition.policy
1114
+ });
1115
+ const newBeliefStatus = promoteBeliefStatusAfterScoring(currentBeliefStatus, {
1116
+ confidence: derivedConfidence,
1117
+ predictionMeta,
1118
+ metadata: existingMetadata
1119
+ });
1120
+ let tupleContradictionId;
1121
+ if (tupleTransition.crossedIntoTupleContradiction) {
1122
+ tupleContradictionId = await ctx.runMutation(
1123
+ "contradictions:create",
1124
+ {
1125
+ projectId: node.projectId,
1126
+ topicId: node.topicId,
1127
+ beliefId: args.nodeId,
1128
+ beliefBId: args.nodeId,
1129
+ supportingInsightIds: [],
1130
+ contradictingInsightIds: [],
1131
+ severity: deriveTupleContradictionSeverity(node),
1132
+ source: "tuple_space",
1133
+ detectionMethod: "agent",
1134
+ description: tupleContradictionDescription,
1135
+ createdBy: args.authenticatedUserId
1136
+ }
1137
+ );
1138
+ }
1139
+ await ctx.db.patch(args.nodeId, {
1140
+ confidence: derivedConfidence,
1141
+ beliefStatus: newBeliefStatus,
1142
+ tupleContradicted: tupleTransition.tupleContradicted,
1143
+ updatedAt: now,
1144
+ // Store SL opinion fields at node level for fast access
1145
+ opinion_b: slB,
1146
+ opinion_d: slD,
1147
+ opinion_u: slU,
1148
+ opinion_a: slA,
1149
+ metadata: {
1150
+ ...existingMetadata,
1151
+ beliefStatus: newBeliefStatus,
1152
+ slBelief: slB,
1153
+ slDisbelief: slD,
1154
+ slUncertainty: slU,
1155
+ slBaseRate: slA,
1156
+ tupleContradicted: tupleTransition.tupleContradicted
1157
+ }
1158
+ });
1159
+ if (isFirstScoring) {
1160
+ const nodeTopicId = node.topicId;
1161
+ const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
1162
+ "by_topic",
1163
+ (q) => q.eq("topicId", nodeTopicId || node.projectId)
1164
+ ).filter((q) => q.eq(q.field("nodeType"), "theme")).collect();
1165
+ for (const theme of themeNodes) {
1166
+ if (theme.globalId && node.globalId) {
1167
+ await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
1168
+ globalId: `edge-${node.globalId}-relates_to_thesis-${theme.globalId}`,
1169
+ fromGlobalId: node.globalId,
1170
+ toGlobalId: theme.globalId,
1171
+ edgeType: "relates_to_thesis",
1172
+ weight: derivedConfidence,
1173
+ createdBy: args.authenticatedUserId,
1174
+ topicId: String(node.projectId),
1175
+ fromNodeType: "belief",
1176
+ toNodeType: "theme",
1177
+ fromLayer: "L3",
1178
+ toLayer: "L3"
1179
+ });
1180
+ }
1181
+ }
1182
+ }
1183
+ const storedRationale = args.rationale ?? `Confidence changed from ${previousConfidence.toFixed(2)} (nodeId: ${args.nodeId})`;
1184
+ const beliefConfidenceId = await ctx.db.insert("beliefConfidence", {
1185
+ ...buildBeliefConfidenceRow({
1186
+ beliefId: args.nodeId,
1187
+ belief: slB,
1188
+ disbelief: slD,
1189
+ uncertainty: slU,
1190
+ baseRate: slA,
1191
+ trigger: args.trigger,
1192
+ rationale: storedRationale,
1193
+ assessedBy: args.authenticatedUserId,
1194
+ assessedAt: now,
1195
+ slOperator: args.slOperator,
1196
+ triggeringEvidenceId: args.triggeringEvidenceId,
1197
+ triggeringContradictionId: tupleContradictionId,
1198
+ triggeringWorktreeId: args.triggeringWorktreeId
1199
+ })
1200
+ });
1201
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1202
+ nodeId: args.nodeId,
1203
+ operation: "upsert"
1204
+ });
1205
+ await ctx.db.insert("epistemicAudit", {
1206
+ entityType: "belief",
1207
+ entityId: args.nodeId,
1208
+ changeType: "confidence_changed",
1209
+ previousState: {
1210
+ confidence: previousConfidence,
1211
+ tupleContradicted: previousTupleContradicted
1212
+ },
1213
+ newState: {
1214
+ opinion: nextOpinion,
1215
+ confidence: derivedConfidence,
1216
+ trigger: args.trigger,
1217
+ rationale: storedRationale,
1218
+ tupleContradicted: tupleTransition.tupleContradicted,
1219
+ tupleContradictionPolicy: tupleTransition.policy,
1220
+ ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1221
+ },
1222
+ changedBy: args.authenticatedUserId,
1223
+ isAgent: false,
1224
+ changedAt: now,
1225
+ projectId: node.projectId,
1226
+ topicId: node.topicId
1227
+ });
1228
+ if (tupleTransition.crossedIntoTupleContradiction || tupleTransition.crossedOutOfTupleContradiction) {
1229
+ await ctx.db.insert("epistemicAudit", {
1230
+ entityType: "belief",
1231
+ entityId: args.nodeId,
1232
+ changeType: "updated",
1233
+ previousState: { tupleContradicted: previousTupleContradicted },
1234
+ newState: {
1235
+ tupleContradicted: tupleTransition.tupleContradicted,
1236
+ action: tupleTransition.crossedIntoTupleContradiction ? "tuple_contradiction_detected" : "tuple_contradiction_cleared",
1237
+ opinion: nextOpinion,
1238
+ tupleContradictionPolicy: tupleTransition.policy,
1239
+ ...tupleContradictionId ? { tupleContradictionId: String(tupleContradictionId) } : {}
1240
+ },
1241
+ rationale: tupleTransition.crossedIntoTupleContradiction ? tupleContradictionDescription : `Tuple-space contradiction cleared: b=${nextOpinion.b.toFixed(2)}, d=${nextOpinion.d.toFixed(2)} no longer exceed the configured policy thresholds.`,
1242
+ changedBy: args.authenticatedUserId,
1243
+ isAgent: false,
1244
+ changedAt: now,
1245
+ projectId: node.projectId,
1246
+ topicId: node.topicId
1247
+ });
1248
+ }
1249
+ if (Math.abs(derivedConfidence - previousConfidence) >= 0.15) {
1250
+ await ctx.scheduler.runAfter(
1251
+ 5e3,
1252
+ internal.bi.contradictionSemanticDetector.scanAffectedBeliefs,
1253
+ {
1254
+ beliefId: args.nodeId,
1255
+ projectId: node.projectId
1256
+ }
1257
+ );
1258
+ }
1259
+ if (node.workspaceId && node.tenantId) {
1260
+ await ctx.scheduler.runAfter(
1261
+ 0,
1262
+ internal.publication.evaluateNodePublication,
1263
+ { nodeId: args.nodeId }
1264
+ );
1265
+ }
1266
+ return {
1267
+ nodeId: args.nodeId,
1268
+ previousConfidence,
1269
+ newConfidence: derivedConfidence,
1270
+ opinion: { b: slB, d: slD, u: slU, a: slA },
1271
+ beliefConfidenceId
1272
+ };
1273
+ }
1274
+ function propagationTriggerForEdge(edgeType, weight) {
1275
+ if (edgeType === "contradicts" || edgeType === "refutes") {
1276
+ return "contradiction_detected";
1277
+ }
1278
+ if ((edgeType === "supports" || edgeType === "informs") && weight < 0) {
1279
+ return "contradiction_detected";
1280
+ }
1281
+ return "evidence_added";
1282
+ }
1283
+ internalMutation({
1284
+ args: {
1285
+ nodeId: v.id("epistemicNodes"),
1286
+ opinion_b: v.number(),
1287
+ opinion_d: v.number(),
1288
+ opinion_u: v.number(),
1289
+ opinion_a: v.number(),
1290
+ userId: v.string()
1291
+ },
1292
+ returns: permissiveReturn,
1293
+ handler: async (ctx, args) => {
1294
+ const sourceOpinion = mkOpinion(
1295
+ args.opinion_b,
1296
+ args.opinion_d,
1297
+ args.opinion_u,
1298
+ args.opinion_a
1299
+ );
1300
+ const sourceNode = await ctx.db.get(args.nodeId);
1301
+ const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
1302
+ ctx,
1303
+ sourceNode
1304
+ );
1305
+ const dispatches = await collectConfidencePropagationDispatches({
1306
+ sourceNodeId: args.nodeId,
1307
+ sourceOpinion,
1308
+ sourceScope,
1309
+ queryEdges: async ({ nodeId, spec, direction }) => {
1310
+ return await ctx.db.query("epistemicEdges").withIndex(
1311
+ direction === "outgoing" ? "by_from_type" : "by_to_type",
1312
+ (q) => direction === "outgoing" ? q.eq("fromNodeId", nodeId).eq("edgeType", spec.edgeType) : q.eq("toNodeId", nodeId).eq("edgeType", spec.edgeType)
1313
+ ).collect();
1314
+ },
1315
+ getNode: async (nodeId) => await ctx.db.get(nodeId)
1316
+ });
1317
+ for (const dispatch of dispatches) {
1318
+ await applyBeliefConfidenceChange(ctx, {
1319
+ nodeId: dispatch.targetNodeId,
1320
+ belief: dispatch.opinion.b,
1321
+ disbelief: dispatch.opinion.d,
1322
+ uncertainty: dispatch.opinion.u,
1323
+ baseRate: dispatch.opinion.a,
1324
+ trigger: propagationTriggerForEdge(dispatch.edgeType, dispatch.weight),
1325
+ rationale: `SL propagation via ${dispatch.edgeType} edge: ${dispatch.rationale}`,
1326
+ authenticatedUserId: args.userId,
1327
+ slOperator: dispatch.operator
1328
+ });
1329
+ }
1330
+ return {
1331
+ propagated: dispatches.map((dispatch) => ({
1332
+ targetNodeId: String(dispatch.targetNodeId),
1333
+ edgeType: dispatch.edgeType,
1334
+ operator: dispatch.operator
1335
+ })),
1336
+ count: dispatches.length
1337
+ };
1338
+ }
1339
+ });
1340
+
1341
+ // src/epistemicBeliefs.lifecycle.ts
1342
+ var modulateConfidence = mutation({
1343
+ args: {
1344
+ nodeId: v.id("epistemicNodes"),
1345
+ // SL opinion — the ONLY confidence input (EK-7)
1346
+ belief: v.number(),
1347
+ // b: evidence FOR [0,1]
1348
+ disbelief: v.number(),
1349
+ // d: evidence AGAINST [0,1]
1350
+ uncertainty: v.number(),
1351
+ // u: lack of evidence [0,1]
1352
+ baseRate: v.number(),
1353
+ // a: prior probability [0,1]
1354
+ trigger: v.union(
1355
+ v.literal("evidence_added"),
1356
+ v.literal("evidence_removed"),
1357
+ v.literal("contradiction_detected"),
1358
+ v.literal("contradiction_resolved"),
1359
+ v.literal("manual"),
1360
+ v.literal("decay"),
1361
+ v.literal("agent_assessment"),
1362
+ v.literal("worktree_outcome"),
1363
+ v.literal("worktree_completed"),
1364
+ // SL-specific triggers
1365
+ v.literal("fusion"),
1366
+ v.literal("discount"),
1367
+ v.literal("deduction"),
1368
+ v.literal("backfill_synthetic")
1369
+ ),
1370
+ rationale: v.optional(v.string()),
1371
+ userId: v.string(),
1372
+ // SL operator provenance (optional — defaults to manual_assessment)
1373
+ slOperator: v.optional(
1374
+ v.union(
1375
+ v.literal("cumulative_fusion"),
1376
+ v.literal("averaging_fusion"),
1377
+ v.literal("trust_discount"),
1378
+ v.literal("conditional_deduction"),
1379
+ v.literal("dependency_cascade"),
1380
+ v.literal("negation"),
1381
+ v.literal("constraint_fusion"),
1382
+ v.literal("manual_assessment")
1383
+ )
1384
+ ),
1385
+ triggeringEvidenceId: v.optional(v.id("epistemicNodes")),
1386
+ triggeringWorktreeId: v.optional(v.string())
1387
+ },
1388
+ returns: permissiveReturn,
1389
+ handler: async (ctx, args) => {
1390
+ const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1391
+ const result = await applyBeliefConfidenceChange(ctx, {
1392
+ nodeId: args.nodeId,
1393
+ belief: args.belief,
1394
+ disbelief: args.disbelief,
1395
+ uncertainty: args.uncertainty,
1396
+ baseRate: args.baseRate,
1397
+ trigger: args.trigger,
1398
+ rationale: args.rationale,
1399
+ authenticatedUserId,
1400
+ slOperator: args.slOperator,
1401
+ triggeringEvidenceId: args.triggeringEvidenceId,
1402
+ triggeringWorktreeId: args.triggeringWorktreeId
1403
+ });
1404
+ if (Math.abs(result.newConfidence - result.previousConfidence) >= 0.01) {
1405
+ await ctx.scheduler.runAfter(
1406
+ 0,
1407
+ internal.epistemicBeliefs.propagateConfidenceChange,
1408
+ {
1409
+ nodeId: args.nodeId,
1410
+ opinion_b: args.belief,
1411
+ opinion_d: args.disbelief,
1412
+ opinion_u: args.uncertainty,
1413
+ opinion_a: args.baseRate ?? 0.5,
1414
+ userId: authenticatedUserId
1415
+ }
1416
+ );
1417
+ }
1418
+ return {
1419
+ nodeId: result.nodeId,
1420
+ previousConfidence: result.previousConfidence,
1421
+ newConfidence: result.newConfidence,
1422
+ opinion: result.opinion
1423
+ };
1424
+ }
1425
+ });
1426
+ var updateStatus = mutation({
1427
+ args: {
1428
+ nodeId: v.id("epistemicNodes"),
1429
+ status: v.union(
1430
+ v.literal("active"),
1431
+ v.literal("superseded"),
1432
+ v.literal("archived")
1433
+ ),
1434
+ reason: v.optional(v.string()),
1435
+ userId: v.string()
1436
+ },
1437
+ returns: permissiveReturn,
1438
+ handler: async (ctx, args) => {
1439
+ const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1440
+ const now = Date.now();
1441
+ const node = await ctx.db.get(args.nodeId);
1442
+ if (!node || node.nodeType !== "belief") {
1443
+ throw new Error("Belief not found");
1444
+ }
1445
+ if (!node.projectId) {
1446
+ throw new Error("Belief has no project scope");
1447
+ }
1448
+ await requireProjectWriteAccess(ctx, node.projectId, authenticatedUserId);
1449
+ const previousStatus = node.status;
1450
+ const metadata = node.metadata || {};
1451
+ await ctx.db.patch(args.nodeId, {
1452
+ status: args.status,
1453
+ updatedAt: now,
1454
+ metadata: {
1455
+ ...metadata,
1456
+ status: args.status
1457
+ }
1458
+ });
1459
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1460
+ nodeId: args.nodeId,
1461
+ operation: "upsert"
1462
+ });
1463
+ await ctx.db.insert("epistemicAudit", {
1464
+ entityType: "belief",
1465
+ entityId: args.nodeId,
1466
+ changeType: "status_changed",
1467
+ previousState: { status: previousStatus },
1468
+ newState: { status: args.status, reason: args.reason },
1469
+ changedBy: authenticatedUserId,
1470
+ isAgent: false,
1471
+ changedAt: now,
1472
+ projectId: node.projectId
1473
+ });
1474
+ return { nodeId: args.nodeId, previousStatus, newStatus: args.status };
1475
+ }
1476
+ });
1477
+ var archive = mutation({
1478
+ args: {
1479
+ nodeId: v.id("epistemicNodes"),
1480
+ reason: v.optional(v.string()),
1481
+ userId: v.string()
1482
+ },
1483
+ returns: permissiveReturn,
1484
+ handler: async (ctx, args) => {
1485
+ const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1486
+ const node = await ctx.db.get(args.nodeId);
1487
+ if (!node || node.nodeType !== "belief") {
1488
+ throw new Error("Belief not found");
1489
+ }
1490
+ if (!node.projectId) {
1491
+ throw new Error("Belief has no project scope");
1492
+ }
1493
+ await requireProjectWriteAccess(ctx, node.projectId, authenticatedUserId);
1494
+ return await ctx.runMutation(
1495
+ // Use updateStatus internally
1496
+ internal.epistemicBeliefs.updateStatusInternal,
1497
+ {
1498
+ nodeId: args.nodeId,
1499
+ status: "archived",
1500
+ reason: args.reason,
1501
+ userId: authenticatedUserId
1502
+ }
1503
+ );
1504
+ }
1505
+ });
1506
+ var updateRationale = mutation({
1507
+ args: {
1508
+ nodeId: v.id("epistemicNodes"),
1509
+ rationale: v.optional(v.string()),
1510
+ userId: v.string()
1511
+ },
1512
+ returns: permissiveReturn,
1513
+ handler: async (ctx, args) => {
1514
+ const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1515
+ const now = Date.now();
1516
+ const node = await ctx.db.get(args.nodeId);
1517
+ if (!node || node.nodeType !== "belief") {
1518
+ throw new Error("Belief not found");
1519
+ }
1520
+ if (!node.projectId) {
1521
+ throw new Error("Belief has no project scope");
1522
+ }
1523
+ await requireProjectWriteAccess(ctx, node.projectId, authenticatedUserId);
1524
+ const metadata = node.metadata || {};
1525
+ const previousRationale = typeof metadata.rationale === "string" ? metadata.rationale : void 0;
1526
+ const nextRationale = args.rationale?.trim();
1527
+ await ctx.db.patch(args.nodeId, {
1528
+ metadata: {
1529
+ ...metadata,
1530
+ rationale: nextRationale && nextRationale.length > 0 ? nextRationale : void 0
1531
+ },
1532
+ updatedAt: now
1533
+ });
1534
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
1535
+ nodeId: args.nodeId,
1536
+ operation: "upsert"
1537
+ });
1538
+ await ctx.db.insert("epistemicAudit", {
1539
+ entityType: "belief",
1540
+ entityId: args.nodeId,
1541
+ changeType: "updated",
1542
+ previousState: { rationale: previousRationale },
1543
+ newState: {
1544
+ rationale: nextRationale && nextRationale.length > 0 ? nextRationale : void 0
1545
+ },
1546
+ changedBy: authenticatedUserId,
1547
+ isAgent: false,
1548
+ changedAt: now,
1549
+ projectId: node.projectId
1550
+ });
1551
+ return {
1552
+ nodeId: args.nodeId,
1553
+ previousRationale,
1554
+ newRationale: nextRationale
1555
+ };
1556
+ }
1557
+ });
1558
+ var updateStatusInternal = internalMutation({
1559
+ args: {
1560
+ nodeId: v.id("epistemicNodes"),
1561
+ status: v.union(
1562
+ v.literal("active"),
1563
+ v.literal("superseded"),
1564
+ v.literal("archived")
1565
+ ),
1566
+ reason: v.optional(v.string()),
1567
+ userId: v.string(),
1568
+ runtimeToolName: v.optional(v.string()),
1569
+ runtimePackKey: v.optional(v.string()),
1570
+ runtimePackInstallScope: v.optional(
1571
+ v.union(v.literal("tenant"), v.literal("workspace"))
1572
+ )
1573
+ },
1574
+ returns: permissiveReturn,
1575
+ handler: async (ctx, args) => {
1576
+ const now = Date.now();
1577
+ const node = await ctx.db.get(args.nodeId);
1578
+ if (!node || node.nodeType !== "belief") {
1579
+ throw new Error("Belief not found");
1580
+ }
1581
+ assertTenantPackWorkspaceMutationAllowed({
1582
+ runtime: resolveRuntimePackMutationContext(args),
1583
+ target: await resolveNodeScopeForWorkspaceIsolation(ctx, node),
1584
+ mutationName: "epistemicBeliefs.updateStatusInternal"
1585
+ });
1586
+ const previousStatus = node.status;
1587
+ await ctx.db.patch(args.nodeId, {
1588
+ status: args.status,
1589
+ updatedAt: now
1590
+ });
1591
+ await ctx.db.insert("epistemicAudit", {
1592
+ entityType: "belief",
1593
+ entityId: args.nodeId,
1594
+ changeType: "status_changed",
1595
+ previousState: { status: previousStatus },
1596
+ newState: { status: args.status, reason: args.reason },
1597
+ changedBy: args.userId,
1598
+ isAgent: false,
1599
+ changedAt: now,
1600
+ projectId: node.projectId
1601
+ });
1602
+ return { nodeId: args.nodeId, previousStatus, newStatus: args.status };
1603
+ }
1604
+ });
1605
+
1606
+ export { archive, modulateConfidence, updateRationale, updateStatus, updateStatusInternal };
1607
+ //# sourceMappingURL=epistemicBeliefs.lifecycle.js.map
1608
+ //# sourceMappingURL=epistemicBeliefs.lifecycle.js.map