@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,1049 @@
1
+ import { v } from 'convex/values';
2
+ import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
3
+ import { checkScopeAccess } from '@lucern/access-control/access';
4
+ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
5
+ import { componentsGeneric, queryGeneric, internalQueryGeneric, anyApi } from 'convex/server';
6
+ import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
7
+ import '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
8
+
9
+ // src/epistemicEvidenceQueries.ts
10
+ var api = anyApi;
11
+ componentsGeneric();
12
+ var internalQuery = internalQueryGeneric;
13
+ var query = queryGeneric;
14
+
15
+ // src/debug.ts
16
+ function isGraphPrimitiveDebugEnabled() {
17
+ const env = globalThis.process?.env;
18
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
19
+ }
20
+ function debugGraphPrimitiveFallback(message, context) {
21
+ if (!isGraphPrimitiveDebugEnabled()) {
22
+ return;
23
+ }
24
+ console.debug(message, context ?? {});
25
+ }
26
+
27
+ // src/topicProjectOverlay.ts
28
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
29
+ function readNonEmptyString(value) {
30
+ if (typeof value !== "string") {
31
+ return;
32
+ }
33
+ const normalized = value.trim();
34
+ return normalized.length > 0 ? normalized : void 0;
35
+ }
36
+ function readStringArray(value) {
37
+ if (!Array.isArray(value)) {
38
+ return [];
39
+ }
40
+ return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
41
+ }
42
+ function readMetadata(topic) {
43
+ return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
44
+ }
45
+ function readLegacyProjectId(value) {
46
+ if (!value) {
47
+ return;
48
+ }
49
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
50
+ }
51
+ function coerceVisibility(value) {
52
+ return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
53
+ }
54
+ function coerceStatus(value) {
55
+ return value === "active" || value === "archived" || value === "watching" ? value : void 0;
56
+ }
57
+ function mapProjectType(topic, metadata) {
58
+ const explicit = readNonEmptyString(metadata.projectType);
59
+ if (explicit) {
60
+ return explicit;
61
+ }
62
+ if (topic.type === "theme") {
63
+ return "thematic";
64
+ }
65
+ return readNonEmptyString(topic.type) || "general";
66
+ }
67
+ function isProjectLikeTopic(topic) {
68
+ const metadata = readMetadata(topic);
69
+ return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
70
+ }
71
+ function isMissingLucernChildComponentError(error) {
72
+ const message = getErrorMessage(error);
73
+ return message.includes(
74
+ 'Child component ComponentName(Identifier("lucern")) not found'
75
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
76
+ }
77
+ function getErrorMessage(error) {
78
+ if (error instanceof Error) {
79
+ return error.message;
80
+ }
81
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
82
+ return error.message;
83
+ }
84
+ return "unknown error";
85
+ }
86
+ async function resolveTopicDoc(ctx, scopeId) {
87
+ if (ctx?.db && typeof ctx.db.get === "function") {
88
+ try {
89
+ const directTopic = await ctx.db.get(
90
+ scopeId
91
+ );
92
+ if (directTopic) {
93
+ return directTopic;
94
+ }
95
+ } catch (error) {
96
+ debugGraphPrimitiveFallback(
97
+ "[topicProjectOverlay] Failed to resolve topic by direct ID",
98
+ {
99
+ error,
100
+ scopeId
101
+ }
102
+ );
103
+ }
104
+ }
105
+ if (typeof ctx.runQuery !== "function") {
106
+ return null;
107
+ }
108
+ try {
109
+ const topic = await ctx.runQuery(api.topics.get, {
110
+ id: String(scopeId)
111
+ });
112
+ if (topic?.name !== void 0 && topic?.type !== void 0) {
113
+ return topic;
114
+ }
115
+ } catch (error) {
116
+ debugGraphPrimitiveFallback(
117
+ "[topicProjectOverlay] Failed to resolve topic by ID query",
118
+ {
119
+ error,
120
+ scopeId
121
+ }
122
+ );
123
+ }
124
+ try {
125
+ const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
126
+ projectId: String(scopeId)
127
+ });
128
+ if (topic?.name !== void 0 && topic?.type !== void 0) {
129
+ return topic;
130
+ }
131
+ } catch (error) {
132
+ debugGraphPrimitiveFallback(
133
+ "[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
134
+ { error, scopeId }
135
+ );
136
+ }
137
+ return null;
138
+ }
139
+ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
140
+ const metadata = readMetadata(topic);
141
+ const topicId = String(topic._id);
142
+ const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
143
+ const storageProjectId = legacyProjectId || topicId;
144
+ const outwardId = idMode === "topic" ? topicId : storageProjectId;
145
+ const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
146
+ const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
147
+ const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
148
+ const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
149
+ return {
150
+ ...metadata,
151
+ _id: outwardId,
152
+ projectId: outwardId,
153
+ topicId,
154
+ storageProjectId,
155
+ legacyProjectId,
156
+ name: readNonEmptyString(topic.name) || "Untitled Theme",
157
+ type: mapProjectType(topic, metadata),
158
+ description: readNonEmptyString(topic.description),
159
+ ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
160
+ sharedWith: readStringArray(metadata.sharedWith),
161
+ visibility,
162
+ tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
163
+ workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
164
+ status,
165
+ tags: readStringArray(metadata.tags),
166
+ chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
167
+ artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
168
+ lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
169
+ _creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
170
+ createdAt,
171
+ updatedAt
172
+ };
173
+ }
174
+ async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
175
+ const topic = await resolveTopicDoc(ctx, scopeId);
176
+ if (!topic) {
177
+ return null;
178
+ }
179
+ if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
180
+ return null;
181
+ }
182
+ return materializeTopicProjectOverlay(topic, options.idMode);
183
+ }
184
+ async function listTopicProjectOverlays(ctx, options = {}) {
185
+ let allTopics = [];
186
+ if (ctx?.db?.query && typeof ctx.db.query === "function") {
187
+ try {
188
+ allTopics = await ctx.db.query("topics").collect();
189
+ } catch (error) {
190
+ debugGraphPrimitiveFallback(
191
+ "[topicProjectOverlay] Failed to read topics table; falling back to API",
192
+ { error }
193
+ );
194
+ allTopics = [];
195
+ }
196
+ }
197
+ if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
198
+ allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
199
+ }
200
+ return allTopics.filter(
201
+ (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
202
+ ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
203
+ }
204
+ async function patchTopicProjectOverlay(ctx, scopeId, value) {
205
+ const topic = await resolveTopicDoc(ctx, scopeId);
206
+ if (!topic) {
207
+ return null;
208
+ }
209
+ const nextMetadata = { ...readMetadata(topic) };
210
+ const patch = {};
211
+ const topicUpdateArgs = {
212
+ id: String(topic._id)
213
+ };
214
+ for (const [key, rawValue] of Object.entries(value)) {
215
+ switch (key) {
216
+ case "_id":
217
+ case "projectId":
218
+ case "topicId":
219
+ case "legacyProjectId":
220
+ case "storageProjectId":
221
+ break;
222
+ case "name":
223
+ case "description":
224
+ patch[key] = rawValue;
225
+ topicUpdateArgs[key] = rawValue;
226
+ break;
227
+ case "tenantId":
228
+ case "workspaceId":
229
+ case "ownerId":
230
+ throw new Error(
231
+ `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
232
+ );
233
+ case "status": {
234
+ const status = coerceStatus(rawValue);
235
+ if (status) {
236
+ patch.status = status;
237
+ topicUpdateArgs.status = status;
238
+ }
239
+ break;
240
+ }
241
+ case "visibility": {
242
+ const visibility = coerceVisibility(rawValue);
243
+ if (visibility) {
244
+ patch.visibility = visibility;
245
+ topicUpdateArgs.visibility = visibility;
246
+ }
247
+ break;
248
+ }
249
+ case "type": {
250
+ const projectType = readNonEmptyString(rawValue);
251
+ if (projectType) {
252
+ nextMetadata.projectType = projectType;
253
+ } else {
254
+ delete nextMetadata.projectType;
255
+ }
256
+ break;
257
+ }
258
+ case "updatedAt":
259
+ case "createdAt":
260
+ break;
261
+ default:
262
+ if (rawValue === void 0) {
263
+ delete nextMetadata[key];
264
+ } else {
265
+ nextMetadata[key] = rawValue;
266
+ }
267
+ }
268
+ }
269
+ patch.updatedAt = Date.now();
270
+ patch.metadata = nextMetadata;
271
+ topicUpdateArgs.metadata = nextMetadata;
272
+ if (typeof ctx.runMutation === "function") {
273
+ try {
274
+ await ctx.runMutation(api.topics.update, topicUpdateArgs);
275
+ } catch (error) {
276
+ if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
277
+ throw error;
278
+ }
279
+ await ctx.db.patch(String(topic._id), patch);
280
+ }
281
+ } else if (ctx?.db && typeof ctx.db.patch === "function") {
282
+ await ctx.db.patch(String(topic._id), patch);
283
+ } else {
284
+ throw new Error(
285
+ "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
286
+ );
287
+ }
288
+ return materializeTopicProjectOverlay({
289
+ ...topic,
290
+ ...patch,
291
+ metadata: nextMetadata
292
+ });
293
+ }
294
+
295
+ // src/resolvers.ts
296
+ function isMissingLucernChildComponentError2(error) {
297
+ const message = getErrorMessage2(error);
298
+ return message.includes(
299
+ 'Child component ComponentName(Identifier("lucern")) not found'
300
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
301
+ }
302
+ function getErrorMessage2(error) {
303
+ if (error instanceof Error) {
304
+ return error.message;
305
+ }
306
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
307
+ return error.message;
308
+ }
309
+ return "unknown error";
310
+ }
311
+ function isAdvisoryTopicPatch(value) {
312
+ const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
313
+ const keys = Object.keys(value);
314
+ return keys.length > 0 && keys.every((key) => advisoryKeys.has(key));
315
+ }
316
+ async function patchProjectWithTolerance(ctx, projectId, value) {
317
+ try {
318
+ await patchTopicProjectOverlay(ctx, projectId, value);
319
+ } catch (error) {
320
+ if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
321
+ throw error;
322
+ }
323
+ console.warn(
324
+ "[lucern graph-primitives] Non-fatal advisory topic patch failure",
325
+ {
326
+ projectId,
327
+ keys: Object.keys(value),
328
+ error: getErrorMessage2(error)
329
+ }
330
+ );
331
+ }
332
+ }
333
+ function defaultResolvers() {
334
+ return {
335
+ getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
336
+ idMode: "legacy",
337
+ projectLikeOnly: false
338
+ }),
339
+ patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
340
+ listTopics: (ctx) => listTopicProjectOverlays(ctx, {
341
+ idMode: "legacy"
342
+ }),
343
+ getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
344
+ };
345
+ }
346
+ var resolverOverrides = {};
347
+ function resolveGraphPrimitivesAppResolvers(_ctx) {
348
+ return {
349
+ ...defaultResolvers(),
350
+ ...resolverOverrides
351
+ };
352
+ }
353
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
354
+ function asMappedProjectId(topic) {
355
+ if (!topic) {
356
+ return;
357
+ }
358
+ const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD2]);
359
+ if (directLegacyProjectId) {
360
+ return directLegacyProjectId;
361
+ }
362
+ const metadata = topic.metadata || {};
363
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
364
+ return candidate ? candidate : void 0;
365
+ }
366
+ function normalizeScopeValue(value) {
367
+ if (typeof value !== "string") {
368
+ return;
369
+ }
370
+ const normalized = value.trim();
371
+ return normalized.length > 0 ? normalized : void 0;
372
+ }
373
+ function pickPrimaryTopic(candidates) {
374
+ return [...candidates].sort((a, b) => {
375
+ const depthA = a.depth ?? 9999;
376
+ const depthB = b.depth ?? 9999;
377
+ if (depthA !== depthB) {
378
+ return depthA - depthB;
379
+ }
380
+ const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
381
+ const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
382
+ if (createdA !== createdB) {
383
+ return createdA - createdB;
384
+ }
385
+ return String(a.name || "").localeCompare(String(b.name || ""));
386
+ })[0];
387
+ }
388
+ async function findTopicsByScopeAlias(ctx, scopeId) {
389
+ try {
390
+ return await ctx.db.query("topics").withIndex(
391
+ "by_graph_scope_project",
392
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
393
+ ).collect();
394
+ } catch (error) {
395
+ debugGraphPrimitiveFallback(
396
+ "[topicScope] Failed to resolve scope alias via index",
397
+ {
398
+ error,
399
+ scopeId
400
+ }
401
+ );
402
+ const topics = await ctx.db.query("topics").collect();
403
+ return topics.filter((topic) => {
404
+ const normalizedGlobalId = normalizeScopeValue(topic.globalId);
405
+ const mappedProjectId = asMappedProjectId(topic);
406
+ return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
407
+ });
408
+ }
409
+ }
410
+ async function tryResolveHostTopicById(ctx, topicId) {
411
+ if (typeof ctx.runQuery !== "function") {
412
+ return null;
413
+ }
414
+ try {
415
+ return await ctx.runQuery(api.topics.get, {
416
+ id: topicId
417
+ }) ?? null;
418
+ } catch (error) {
419
+ debugGraphPrimitiveFallback(
420
+ "[topicScope] Failed to resolve topic by host query",
421
+ {
422
+ error,
423
+ topicId
424
+ }
425
+ );
426
+ return null;
427
+ }
428
+ }
429
+ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
430
+ if (typeof ctx.runQuery !== "function") {
431
+ return null;
432
+ }
433
+ try {
434
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
435
+ projectId: legacyScopeId
436
+ }) ?? null;
437
+ } catch (error) {
438
+ debugGraphPrimitiveFallback(
439
+ "[topicScope] Failed to resolve topic by legacy scope",
440
+ {
441
+ error,
442
+ legacyScopeId
443
+ }
444
+ );
445
+ return null;
446
+ }
447
+ }
448
+ async function resolveInheritedWorkspaceScope(ctx, topic) {
449
+ const MAX_DEPTH = 10;
450
+ let tenantId = normalizeScopeValue(topic.tenantId);
451
+ let workspaceId = normalizeScopeValue(topic.workspaceId);
452
+ if (tenantId && workspaceId) {
453
+ return { tenantId, workspaceId };
454
+ }
455
+ let current = topic;
456
+ for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
457
+ current = await ctx.db.get(current.parentTopicId);
458
+ if (!current) break;
459
+ if (!tenantId) {
460
+ tenantId = normalizeScopeValue(current.tenantId);
461
+ }
462
+ if (!workspaceId) {
463
+ workspaceId = normalizeScopeValue(current.workspaceId);
464
+ }
465
+ if (tenantId && workspaceId) break;
466
+ }
467
+ return { tenantId, workspaceId };
468
+ }
469
+ async function resolveTopicProjectScope(ctx, args) {
470
+ if (args.topicId) {
471
+ let topic = null;
472
+ try {
473
+ topic = await ctx.db.get(
474
+ args.topicId
475
+ );
476
+ } catch (error) {
477
+ debugGraphPrimitiveFallback(
478
+ "[topicScope] Failed to load topic by direct id",
479
+ {
480
+ error,
481
+ topicId: args.topicId
482
+ }
483
+ );
484
+ }
485
+ if (!topic) {
486
+ topic = await tryResolveHostTopicById(ctx, String(args.topicId));
487
+ }
488
+ if (!topic) {
489
+ topic = pickPrimaryTopic(
490
+ await findTopicsByScopeAlias(ctx, String(args.topicId))
491
+ ) ?? null;
492
+ }
493
+ if (!topic) {
494
+ throw new Error(`Topic not found: ${String(args.topicId)}`);
495
+ }
496
+ const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
497
+ const mapped = asMappedProjectId(topic);
498
+ if (mapped) {
499
+ return {
500
+ topicId: topic._id,
501
+ projectId: mapped,
502
+ tenantId: inherited.tenantId,
503
+ workspaceId: inherited.workspaceId,
504
+ source: "topic"
505
+ };
506
+ }
507
+ return {
508
+ topicId: topic._id,
509
+ tenantId: inherited.tenantId,
510
+ workspaceId: inherited.workspaceId,
511
+ source: "topic"
512
+ };
513
+ }
514
+ if (args.projectId) {
515
+ let directTopic = null;
516
+ try {
517
+ directTopic = await ctx.db.get(
518
+ args.projectId
519
+ );
520
+ } catch (error) {
521
+ debugGraphPrimitiveFallback(
522
+ "[topicScope] Failed to load direct project topic",
523
+ {
524
+ error,
525
+ projectId: args.projectId
526
+ }
527
+ );
528
+ }
529
+ if (directTopic) {
530
+ const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
531
+ const mapped = asMappedProjectId(directTopic);
532
+ return {
533
+ topicId: directTopic._id,
534
+ projectId: mapped ?? args.projectId,
535
+ tenantId: inherited.tenantId,
536
+ workspaceId: inherited.workspaceId,
537
+ source: "topic_inferred"
538
+ };
539
+ }
540
+ directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
541
+ if (directTopic) {
542
+ const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
543
+ const mapped = asMappedProjectId(directTopic);
544
+ return {
545
+ topicId: directTopic._id,
546
+ projectId: mapped ?? args.projectId,
547
+ tenantId: inherited.tenantId,
548
+ workspaceId: inherited.workspaceId,
549
+ source: "topic_inferred"
550
+ };
551
+ }
552
+ const topics = await findTopicsByScopeAlias(ctx, args.projectId);
553
+ const primary = pickPrimaryTopic(topics);
554
+ if (primary) {
555
+ const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
556
+ return {
557
+ topicId: primary._id,
558
+ projectId: args.projectId,
559
+ tenantId: inherited.tenantId,
560
+ workspaceId: inherited.workspaceId,
561
+ source: "project_mapped_topic"
562
+ };
563
+ }
564
+ throw new Error(
565
+ `Legacy project scope ${String(args.projectId)} has no mapped topic.`
566
+ );
567
+ }
568
+ throw new Error(
569
+ "Missing scope: provide topicId (preferred) or legacy projectId alias."
570
+ );
571
+ }
572
+ var optionalScopeArgs = {
573
+ projectId: v.optional(v.string()),
574
+ topicId: v.optional(v.string())
575
+ };
576
+
577
+ // src/epistemicEvidenceHelpers.ts
578
+ var optionalEvidenceScopeArgs = optionalScopeArgs;
579
+ var DEFAULT_EVIDENCE_PAGE_SIZE = 250;
580
+ var MAX_EVIDENCE_PAGE_SIZE = 1e3;
581
+ var LEGACY_SPRINT_LINK_KEY = "linkedSprintId";
582
+ function clampEvidenceLimit(limit, fallback = DEFAULT_EVIDENCE_PAGE_SIZE) {
583
+ if (!Number.isFinite(limit)) {
584
+ return fallback;
585
+ }
586
+ return Math.max(
587
+ 1,
588
+ Math.min(Math.floor(limit), MAX_EVIDENCE_PAGE_SIZE)
589
+ );
590
+ }
591
+ function dedupeEvidenceNodes(nodes) {
592
+ const seen = /* @__PURE__ */ new Set();
593
+ const deduped = [];
594
+ for (const node of nodes) {
595
+ const id = String(node._id);
596
+ if (seen.has(id)) {
597
+ continue;
598
+ }
599
+ seen.add(id);
600
+ deduped.push(node);
601
+ }
602
+ return deduped;
603
+ }
604
+ function evidenceMatchesScope(node, scope) {
605
+ return scope.topicId !== void 0 && node.topicId === scope.topicId || scope.projectId !== void 0 && node.projectId === scope.projectId;
606
+ }
607
+ function resolveEvidenceLinkedWorktreeId(metadata) {
608
+ const worktreeId = metadata?.linkedWorktreeId;
609
+ if (typeof worktreeId === "string" && worktreeId.trim().length > 0) {
610
+ return worktreeId;
611
+ }
612
+ const sprintId = metadata?.[LEGACY_SPRINT_LINK_KEY];
613
+ return typeof sprintId === "string" && sprintId.trim().length > 0 ? sprintId : void 0;
614
+ }
615
+ async function resolveEvidenceScopeOrNull(ctx, args) {
616
+ if (!args.projectId && !args.topicId) {
617
+ return null;
618
+ }
619
+ try {
620
+ return await resolveTopicProjectScope(ctx, {
621
+ projectId: args.projectId ?? void 0,
622
+ topicId: args.topicId ?? void 0
623
+ });
624
+ } catch (error) {
625
+ debugGraphPrimitiveFallback(
626
+ "[epistemicEvidence] Failed to resolve evidence scope",
627
+ {
628
+ error,
629
+ projectId: args.projectId,
630
+ topicId: args.topicId
631
+ }
632
+ );
633
+ return null;
634
+ }
635
+ }
636
+ async function getEvidenceNodesForScope(ctx, scope, args) {
637
+ const scanLimit = typeof args?.scanLimit === "number" ? args.scanLimit : void 0;
638
+ const topicNodes = await (scanLimit ? ctx.db.query("epistemicNodes").withIndex(
639
+ "by_topic_type",
640
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
641
+ ).order("desc").take(scanLimit) : ctx.db.query("epistemicNodes").withIndex(
642
+ "by_topic_type",
643
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
644
+ ).order("desc").collect());
645
+ return dedupeEvidenceNodes(topicNodes).filter(
646
+ (node) => evidenceMatchesScope(node, scope)
647
+ );
648
+ }
649
+ function createEvidenceAudienceResolver(registryRows) {
650
+ const audienceClassByKey = new Map(
651
+ registryRows.map((row) => [
652
+ normalizeAudienceKey(row.audienceKey),
653
+ row.audienceClass
654
+ ])
655
+ );
656
+ return (audienceKey, fallback) => {
657
+ const key = normalizeAudienceKey(audienceKey);
658
+ if (!key) {
659
+ return fallback;
660
+ }
661
+ return audienceClassByKey.get(key) ?? classFromAudienceKey(key, fallback);
662
+ };
663
+ }
664
+ function flattenEvidenceNode(n) {
665
+ const meta = n.metadata || {};
666
+ const linkedWorktreeId = resolveEvidenceLinkedWorktreeId(meta);
667
+ return {
668
+ ...n,
669
+ text: n.canonicalText || "",
670
+ title: n.title || "",
671
+ kind: meta.kind || "observation",
672
+ tags: meta.tags || [],
673
+ sourceQuestionId: meta.sourceQuestionId || void 0,
674
+ linkedBeliefId: meta.linkedBeliefNodeId || meta.linkedBeliefId || void 0,
675
+ linkedWorktreeId,
676
+ [LEGACY_SPRINT_LINK_KEY]: meta[LEGACY_SPRINT_LINK_KEY] || void 0,
677
+ sprintIndex: meta.sprintIndex || void 0,
678
+ externalSourceUrl: meta.sourceUrl || void 0,
679
+ externalSourceType: meta.externalSourceType || void 0
680
+ };
681
+ }
682
+ function formatEvidenceNode(n) {
683
+ const metadata = n.metadata || {};
684
+ const linkedWorktreeId = resolveEvidenceLinkedWorktreeId(metadata);
685
+ return {
686
+ _id: n._id,
687
+ _epistemicNodeId: n._id,
688
+ _creationTime: n.createdAt,
689
+ projectId: n.projectId,
690
+ topicId: n.topicId,
691
+ text: n.canonicalText,
692
+ kind: metadata.kind || "observation",
693
+ tags: metadata.tags || [],
694
+ sourceType: n.sourceType,
695
+ externalSourceType: metadata.externalSourceType,
696
+ externalSourceUrl: metadata.sourceUrl,
697
+ sourceArtifactId: metadata.sourceArtifactId,
698
+ sourceQuestionId: metadata.sourceQuestionId,
699
+ linkedWorktreeId,
700
+ [LEGACY_SPRINT_LINK_KEY]: metadata[LEGACY_SPRINT_LINK_KEY] || void 0,
701
+ sourceAnchor: metadata.sourceAnchor,
702
+ aiProvider: metadata.aiProvider,
703
+ verificationStatus: metadata.verificationStatus,
704
+ status: n.status,
705
+ createdBy: n.createdBy,
706
+ createdAt: n.createdAt,
707
+ updatedAt: n.updatedAt
708
+ };
709
+ }
710
+ function normalizeScopeValue2(value) {
711
+ if (typeof value !== "string") {
712
+ return;
713
+ }
714
+ const normalized = value.trim();
715
+ return normalized.length > 0 ? normalized : void 0;
716
+ }
717
+ function nodeMatchesWorkspaceReasoningScope(node, scope) {
718
+ if (!node) {
719
+ return false;
720
+ }
721
+ const scopeTenantId = normalizeScopeValue2(scope.tenantId);
722
+ const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
723
+ const nodeTenantId = normalizeScopeValue2(node.tenantId);
724
+ const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
725
+ const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
726
+ if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
727
+ return false;
728
+ }
729
+ if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
730
+ return true;
731
+ }
732
+ if (!scopeWorkspaceId && node.publicationStatus === "published") {
733
+ return true;
734
+ }
735
+ if (!scopeWorkspaceId) {
736
+ return nodeWorkspaceId === void 0;
737
+ }
738
+ return scopeWorkspaceId === nodeWorkspaceId;
739
+ }
740
+
741
+ // src/epistemicEvidenceQueries.ts
742
+ var getById = query({
743
+ args: {
744
+ nodeId: v.optional(v.id("epistemicNodes")),
745
+ insightId: v.optional(v.string()),
746
+ evidenceId: v.optional(v.string())
747
+ },
748
+ returns: permissiveReturn,
749
+ handler: async (ctx, args) => {
750
+ const id = args.nodeId ?? args.insightId ?? args.evidenceId;
751
+ if (!id) {
752
+ return null;
753
+ }
754
+ const node = await ctx.db.get(id);
755
+ if (!node || node.nodeType !== "evidence") {
756
+ return null;
757
+ }
758
+ return node;
759
+ }
760
+ });
761
+ var getByProject = query({
762
+ args: {
763
+ ...optionalEvidenceScopeArgs,
764
+ status: v.optional(v.string()),
765
+ userId: v.optional(v.string()),
766
+ limit: v.optional(v.number())
767
+ },
768
+ returns: permissiveReturn,
769
+ handler: async (ctx, args) => {
770
+ if (!args.projectId && !args.topicId) {
771
+ return [];
772
+ }
773
+ const pageSize = clampEvidenceLimit(args.limit);
774
+ const scanLimit = Math.min(pageSize * 3, 1e3);
775
+ let scope;
776
+ try {
777
+ scope = await resolveTopicProjectScope(ctx, {
778
+ projectId: args.projectId,
779
+ topicId: args.topicId
780
+ });
781
+ } catch (error) {
782
+ debugGraphPrimitiveFallback(
783
+ "[epistemicEvidence] Failed to resolve getByProject scope",
784
+ {
785
+ error,
786
+ projectId: args.projectId,
787
+ topicId: args.topicId
788
+ }
789
+ );
790
+ return [];
791
+ }
792
+ if (args.userId) {
793
+ const scopeId = scope.topicId ? String(scope.topicId) : scope.projectId;
794
+ if (!scopeId) {
795
+ return [];
796
+ }
797
+ const hasAccess = await checkScopeAccess(ctx, scopeId, args.userId);
798
+ if (!hasAccess) {
799
+ return [];
800
+ }
801
+ }
802
+ const topicNodes = await ctx.db.query("epistemicNodes").withIndex(
803
+ "by_topic_type",
804
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
805
+ ).order("desc").take(scanLimit);
806
+ const scopedNodes = dedupeEvidenceNodes(topicNodes).filter(
807
+ (node) => evidenceMatchesScope(node, scope)
808
+ );
809
+ const filteredNodes = args.status ? scopedNodes.filter((node) => node.status === args.status) : scopedNodes;
810
+ return filteredNodes.map(flattenEvidenceNode).slice(0, pageSize);
811
+ }
812
+ });
813
+ var getByTopic = query({
814
+ args: {
815
+ topicId: v.string(),
816
+ status: v.optional(v.string()),
817
+ userId: v.optional(v.string()),
818
+ limit: v.optional(v.number())
819
+ },
820
+ returns: permissiveReturn,
821
+ handler: async (ctx, args) => {
822
+ const pageSize = clampEvidenceLimit(args.limit);
823
+ const scanLimit = Math.min(pageSize * 3, 1e3);
824
+ const scope = await resolveTopicProjectScope(ctx, {
825
+ topicId: args.topicId
826
+ });
827
+ const topicNodes = await ctx.db.query("epistemicNodes").withIndex(
828
+ "by_topic_type",
829
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
830
+ ).order("desc").take(scanLimit);
831
+ const scopedNodes = dedupeEvidenceNodes(topicNodes).filter(
832
+ (node) => evidenceMatchesScope(node, scope)
833
+ );
834
+ const filteredNodes = args.status ? scopedNodes.filter((node) => node.status === args.status) : scopedNodes;
835
+ return filteredNodes.map(flattenEvidenceNode).slice(0, pageSize);
836
+ }
837
+ });
838
+ var getForBelief = query({
839
+ args: {
840
+ beliefNodeId: v.id("epistemicNodes")
841
+ },
842
+ returns: permissiveReturn,
843
+ handler: async (ctx, args) => {
844
+ const edges = await ctx.db.query("epistemicEdges").withIndex(
845
+ "by_to_type",
846
+ (q) => q.eq("toNodeId", args.beliefNodeId).eq("edgeType", "informs")
847
+ ).collect();
848
+ const evidenceNodeIds = edges.map((e) => e.fromNodeId);
849
+ const evidenceNodes = await Promise.all(
850
+ evidenceNodeIds.map((id) => ctx.db.get(id))
851
+ );
852
+ return evidenceNodes.filter((e) => e !== null && e.nodeType === "evidence").map((e, i) => ({
853
+ ...e,
854
+ relation: (edges[i]?.weight ?? 0) >= 0 ? "supports" : "contradicts",
855
+ confidence: Math.abs(edges[i]?.weight ?? 0),
856
+ edgeId: edges[i]?._id
857
+ }));
858
+ }
859
+ });
860
+ var internalGetByProject = internalQuery({
861
+ args: {
862
+ ...optionalEvidenceScopeArgs,
863
+ status: v.optional(v.string()),
864
+ limit: v.optional(v.number()),
865
+ audienceMode: v.optional(v.string())
866
+ },
867
+ returns: permissiveReturn,
868
+ handler: async (ctx, args) => {
869
+ const pageSize = clampEvidenceLimit(args.limit, 500);
870
+ const scanLimit = Math.min(pageSize * 3, 1e3);
871
+ const scope = await resolveEvidenceScopeOrNull(ctx, args);
872
+ if (!scope) {
873
+ return [];
874
+ }
875
+ const audienceMode = args.audienceMode ?? "internal";
876
+ const project = await resolveGraphPrimitivesAppResolvers().getProject(
877
+ ctx,
878
+ scope.topicId ? String(scope.topicId) : scope.projectId
879
+ );
880
+ const registryRows = await listAudienceRegistryRows(ctx, {
881
+ tenantId: project?.tenantId,
882
+ workspaceId: project?.workspaceId
883
+ });
884
+ const resolveAudienceClass = createEvidenceAudienceResolver(registryRows);
885
+ const viewerClass = resolveAudienceClass(audienceMode, "public");
886
+ const nodes = await getEvidenceNodesForScope(ctx, scope, { scanLimit });
887
+ const workspaceScopedNodes = nodes.filter(
888
+ (node) => nodeMatchesWorkspaceReasoningScope(node, {
889
+ tenantId: project?.tenantId,
890
+ workspaceId: project?.workspaceId
891
+ })
892
+ );
893
+ return workspaceScopedNodes.filter(
894
+ (n) => canAudienceClassAccess(
895
+ viewerClass,
896
+ resolveAudienceClass(n.audienceLabel, "internal")
897
+ ) && (!args.status || n.status === args.status)
898
+ ).slice(0, pageSize).map((n) => {
899
+ const metadata = n.metadata || {};
900
+ return {
901
+ _id: n._id,
902
+ _creationTime: n.createdAt,
903
+ projectId: n.projectId,
904
+ topicId: n.topicId,
905
+ text: n.canonicalText,
906
+ kind: metadata.kind || "observation",
907
+ tags: metadata.tags || [],
908
+ sourceType: n.sourceType,
909
+ externalSourceType: metadata.externalSourceType,
910
+ sourceUrl: metadata.sourceUrl,
911
+ status: n.status,
912
+ createdBy: n.createdBy,
913
+ createdAt: n.createdAt,
914
+ updatedAt: n.updatedAt,
915
+ audienceLabel: n.audienceLabel,
916
+ policyTags: n.policyTags,
917
+ sensitivityTier: n.sensitivityTier,
918
+ exportClass: n.exportClass,
919
+ anonymizationClass: n.anonymizationClass
920
+ };
921
+ });
922
+ }
923
+ });
924
+ var internalGetByTopic = internalQuery({
925
+ args: {
926
+ topicId: v.string(),
927
+ status: v.optional(v.string()),
928
+ limit: v.optional(v.number()),
929
+ audienceMode: v.optional(v.string())
930
+ },
931
+ returns: permissiveReturn,
932
+ handler: async (ctx, args) => {
933
+ const pageSize = clampEvidenceLimit(args.limit, 500);
934
+ const scanLimit = Math.min(pageSize * 3, 1e3);
935
+ const audienceMode = args.audienceMode ?? "internal";
936
+ const scope = await resolveTopicProjectScope(ctx, {
937
+ topicId: args.topicId
938
+ });
939
+ const registryRows = await listAudienceRegistryRows(ctx, {
940
+ tenantId: scope.tenantId,
941
+ workspaceId: scope.workspaceId
942
+ });
943
+ const resolveAudienceClass = createEvidenceAudienceResolver(registryRows);
944
+ const viewerClass = resolveAudienceClass(audienceMode, "public");
945
+ const nodes = await ctx.db.query("epistemicNodes").withIndex(
946
+ "by_topic_type",
947
+ (q) => q.eq("topicId", args.topicId).eq("nodeType", "evidence")
948
+ ).order("desc").take(scanLimit);
949
+ const workspaceScopedNodes = nodes.filter(
950
+ (node) => nodeMatchesWorkspaceReasoningScope(node, {
951
+ tenantId: scope.tenantId,
952
+ workspaceId: scope.workspaceId
953
+ })
954
+ );
955
+ return workspaceScopedNodes.filter(
956
+ (n) => canAudienceClassAccess(
957
+ viewerClass,
958
+ resolveAudienceClass(n.audienceLabel, "internal")
959
+ ) && (!args.status || n.status === args.status)
960
+ ).slice(0, pageSize).map((n) => {
961
+ const metadata = n.metadata || {};
962
+ return {
963
+ _id: n._id,
964
+ _creationTime: n.createdAt,
965
+ projectId: n.projectId,
966
+ topicId: n.topicId,
967
+ text: n.canonicalText,
968
+ kind: metadata.kind || "observation",
969
+ tags: metadata.tags || [],
970
+ sourceType: n.sourceType,
971
+ externalSourceType: metadata.externalSourceType,
972
+ sourceUrl: metadata.sourceUrl,
973
+ status: n.status,
974
+ createdBy: n.createdBy,
975
+ createdAt: n.createdAt,
976
+ updatedAt: n.updatedAt,
977
+ audienceLabel: n.audienceLabel,
978
+ policyTags: n.policyTags,
979
+ sensitivityTier: n.sensitivityTier,
980
+ exportClass: n.exportClass,
981
+ anonymizationClass: n.anonymizationClass
982
+ };
983
+ });
984
+ }
985
+ });
986
+ var getByProjectSystem = query({
987
+ args: {
988
+ ...optionalEvidenceScopeArgs,
989
+ kind: v.optional(v.string()),
990
+ limit: v.optional(v.number())
991
+ },
992
+ returns: permissiveReturn,
993
+ handler: async (ctx, args) => {
994
+ const pageSize = clampEvidenceLimit(args.limit, 500);
995
+ const scanLimit = Math.min(pageSize * 3, 1e3);
996
+ const scope = await resolveEvidenceScopeOrNull(ctx, args);
997
+ if (!scope) {
998
+ return [];
999
+ }
1000
+ const nodes = await getEvidenceNodesForScope(ctx, scope, { scanLimit });
1001
+ const filtered = args.kind ? nodes.filter((n) => {
1002
+ const meta = n.metadata || {};
1003
+ return meta.kind === args.kind;
1004
+ }) : nodes;
1005
+ filtered.sort((a, b) => b.createdAt - a.createdAt);
1006
+ return filtered.slice(0, pageSize).map((n) => formatEvidenceNode(n));
1007
+ }
1008
+ });
1009
+ var getEvidenceBalance = query({
1010
+ args: {
1011
+ ...optionalEvidenceScopeArgs,
1012
+ userId: v.string()
1013
+ },
1014
+ returns: permissiveReturn,
1015
+ handler: async (ctx, args) => {
1016
+ const scope = await resolveTopicProjectScope(ctx, {
1017
+ topicId: args.topicId,
1018
+ projectId: args.projectId
1019
+ });
1020
+ const hasAccess = await checkScopeAccess(
1021
+ ctx,
1022
+ scope.topicId ? String(scope.topicId) : scope.projectId,
1023
+ args.userId
1024
+ );
1025
+ if (!hasAccess) {
1026
+ return { supporting: 0, challenging: 0, total: 0 };
1027
+ }
1028
+ const resolvedTopicId = scope.topicId || scope.projectId;
1029
+ const edges = resolvedTopicId ? await ctx.db.query("epistemicEdges").withIndex("by_topic", (q) => q.eq("topicId", resolvedTopicId)).collect() : [];
1030
+ const evidenceEdges = edges.filter(
1031
+ (e) => e.edgeType === "informs" && e.fromLayer === "L2" && e.toLayer === "L3"
1032
+ );
1033
+ let supporting = 0;
1034
+ let challenging = 0;
1035
+ for (const edge of evidenceEdges) {
1036
+ const weight = edge.weight ?? 0;
1037
+ if (weight > 0) {
1038
+ supporting++;
1039
+ } else if (weight < 0) {
1040
+ challenging++;
1041
+ }
1042
+ }
1043
+ return { supporting, challenging, total: evidenceEdges.length };
1044
+ }
1045
+ });
1046
+
1047
+ export { getById, getByProject, getByProjectSystem, getByTopic, getEvidenceBalance, getForBelief, internalGetByProject, internalGetByTopic };
1048
+ //# sourceMappingURL=epistemicEvidenceQueries.js.map
1049
+ //# sourceMappingURL=epistemicEvidenceQueries.js.map