@lucern/graph-primitives 0.3.0-alpha.0 → 0.3.0-alpha.10

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 (141) hide show
  1. package/dist/{beliefDecay-Q_26RTc-.d.ts → beliefDecay-DZ6tkLYq.d.ts} +1 -1
  2. package/dist/beliefDecay.d.ts +1 -1
  3. package/dist/beliefDecay.js +188 -1144
  4. package/dist/beliefDecay.js.map +1 -1
  5. package/dist/{beliefEvidenceLinks-42FlR48t.d.ts → beliefEvidenceLinks-CWOXxxJg.d.ts} +1 -1
  6. package/dist/beliefEvidenceLinks.d.ts +1 -1
  7. package/dist/beliefEvidenceLinks.js +186 -871
  8. package/dist/beliefEvidenceLinks.js.map +1 -1
  9. package/dist/{beliefLifecycle-C-AehZgF.d.ts → beliefLifecycle-y8WLXqQj.d.ts} +1 -1
  10. package/dist/beliefLifecycle.d.ts +1 -1
  11. package/dist/confidencePropagationDispatch.d.ts +4 -4
  12. package/dist/confidencePropagationDispatch.js +31 -311
  13. package/dist/confidencePropagationDispatch.js.map +1 -1
  14. package/dist/{contradictions-Hdwl7zid.d.ts → contradictions-51VLsESq.d.ts} +1 -1
  15. package/dist/contradictions.d.ts +1 -1
  16. package/dist/contradictions.js +67 -800
  17. package/dist/contradictions.js.map +1 -1
  18. package/dist/debug.d.ts +4 -0
  19. package/dist/debug.js +34 -0
  20. package/dist/debug.js.map +1 -0
  21. package/dist/edges/contradicts.js +1 -122
  22. package/dist/edges/contradicts.js.map +1 -1
  23. package/dist/edges/dependsOn.js +14 -172
  24. package/dist/edges/dependsOn.js.map +1 -1
  25. package/dist/edges/elaborates.js +1 -49
  26. package/dist/edges/elaborates.js.map +1 -1
  27. package/dist/edges/index.js +15 -280
  28. package/dist/edges/index.js.map +1 -1
  29. package/dist/edges/informs.js +2 -65
  30. package/dist/edges/informs.js.map +1 -1
  31. package/dist/edges/propagationTypes.d.ts +2 -2
  32. package/dist/edges/propagationTypes.js.map +1 -1
  33. package/dist/edges/refutes.js +2 -65
  34. package/dist/edges/refutes.js.map +1 -1
  35. package/dist/edges/supports.js +1 -122
  36. package/dist/edges/supports.js.map +1 -1
  37. package/dist/edges/utils.d.ts +7 -7
  38. package/dist/edges/utils.js +2 -133
  39. package/dist/edges/utils.js.map +1 -1
  40. package/dist/embeddingTrigger.js +21 -1
  41. package/dist/embeddingTrigger.js.map +1 -1
  42. package/dist/entityBridge.js +3 -18
  43. package/dist/entityBridge.js.map +1 -1
  44. package/dist/{entityLifecycle-BkhRJ-XI.d.ts → entityLifecycle-CvgSK5FV.d.ts} +1 -1
  45. package/dist/entityLifecycle.d.ts +1 -1
  46. package/dist/entityLifecycle.js +193 -892
  47. package/dist/entityLifecycle.js.map +1 -1
  48. package/dist/{epistemicAnswers-DSP1slZ9.d.ts → epistemicAnswers-C5ib4z6_.d.ts} +1 -1
  49. package/dist/epistemicAnswers.d.ts +1 -1
  50. package/dist/epistemicAnswers.js +73 -810
  51. package/dist/epistemicAnswers.js.map +1 -1
  52. package/dist/{epistemicBeliefs-DtFVTp-k.d.ts → epistemicBeliefs-DzKjZAeC.d.ts} +3 -3
  53. package/dist/epistemicBeliefs.d.ts +2 -2
  54. package/dist/epistemicBeliefs.js +404 -1698
  55. package/dist/epistemicBeliefs.js.map +1 -1
  56. package/dist/epistemicContractHelpers.js +1 -318
  57. package/dist/epistemicContractHelpers.js.map +1 -1
  58. package/dist/epistemicContracts.d.ts +1 -1
  59. package/dist/epistemicContracts.js +417 -1980
  60. package/dist/epistemicContracts.js.map +1 -1
  61. package/dist/{epistemicEdges-DcA8ErUG.d.ts → epistemicEdges-CD5vxmlH.d.ts} +3 -3
  62. package/dist/epistemicEdges.d.ts +1 -1
  63. package/dist/epistemicEdges.js +248 -919
  64. package/dist/epistemicEdges.js.map +1 -1
  65. package/dist/{epistemicEvidence-Bo638XDP.d.ts → epistemicEvidence-xw6UUrwh.d.ts} +1 -1
  66. package/dist/epistemicEvidence.d.ts +1 -1
  67. package/dist/epistemicEvidence.js +229 -1087
  68. package/dist/epistemicEvidence.js.map +1 -1
  69. package/dist/{epistemicHelpers-Bd9xbaib.d.ts → epistemicHelpers-DevrYgPN.d.ts} +1 -1
  70. package/dist/epistemicHelpers.d.ts +1 -1
  71. package/dist/{epistemicLinking-CyeLOIzN.d.ts → epistemicLinking-CfE00tHJ.d.ts} +1 -1
  72. package/dist/epistemicLinking.d.ts +1 -1
  73. package/dist/epistemicLinking.js +3 -786
  74. package/dist/epistemicLinking.js.map +1 -1
  75. package/dist/{epistemicNodes-BpD6Koud.d.ts → epistemicNodes-NBrPW7fk.d.ts} +2 -2
  76. package/dist/epistemicNodes.d.ts +1 -1
  77. package/dist/epistemicNodes.js +172 -899
  78. package/dist/epistemicNodes.js.map +1 -1
  79. package/dist/{epistemicQuestions-CmEeY6zQ.d.ts → epistemicQuestions-B_nUclrH.d.ts} +1 -1
  80. package/dist/epistemicQuestions.d.ts +1 -1
  81. package/dist/epistemicQuestions.js +369 -1125
  82. package/dist/epistemicQuestions.js.map +1 -1
  83. package/dist/{epistemicSources-ZazxHOK1.d.ts → epistemicSources-dlKj58Jp.d.ts} +1 -1
  84. package/dist/epistemicSources.d.ts +1 -1
  85. package/dist/epistemicSources.js +86 -886
  86. package/dist/epistemicSources.js.map +1 -1
  87. package/dist/evaluators/index.js +417 -1980
  88. package/dist/evaluators/index.js.map +1 -1
  89. package/dist/evaluators/lintCheckerEvaluator.js.map +1 -1
  90. package/dist/evaluators/sentryCheckerEvaluator.js.map +1 -1
  91. package/dist/evaluators/shared.js +20 -1
  92. package/dist/evaluators/shared.js.map +1 -1
  93. package/dist/evaluators/testRunnerEvaluator.js +20 -1
  94. package/dist/evaluators/testRunnerEvaluator.js.map +1 -1
  95. package/dist/evaluators/tscCheckerEvaluator.js.map +1 -1
  96. package/dist/index.d.ts +20 -20
  97. package/dist/index.js +965 -3004
  98. package/dist/index.js.map +1 -1
  99. package/dist/{ontology-matching-Buhu23ss.d.ts → ontology-matching-C6rrz2VP.d.ts} +1 -1
  100. package/dist/ontology-matching.d.ts +1 -1
  101. package/dist/ontology-matching.js +1 -344
  102. package/dist/ontology-matching.js.map +1 -1
  103. package/dist/{ontologyApproval-Ba0Jjk1k.d.ts → ontologyApproval-CFYmqKmk.d.ts} +1 -1
  104. package/dist/ontologyApproval.d.ts +1 -1
  105. package/dist/ontologyApproval.js +1 -13
  106. package/dist/ontologyApproval.js.map +1 -1
  107. package/dist/ontologyDefinitions.js +6 -20
  108. package/dist/ontologyDefinitions.js.map +1 -1
  109. package/dist/ontologyHelpers.d.ts +1 -1
  110. package/dist/ontologyHelpers.js +4 -3
  111. package/dist/ontologyHelpers.js.map +1 -1
  112. package/dist/ontologyRegistry.js +2 -17
  113. package/dist/ontologyRegistry.js.map +1 -1
  114. package/dist/{projectionReconciliation-CxrXYGaB.d.ts → projectionReconciliation-jww2fBI0.d.ts} +1 -1
  115. package/dist/projectionReconciliation.d.ts +1 -1
  116. package/dist/projectionReconciliation.js +16 -37
  117. package/dist/projectionReconciliation.js.map +1 -1
  118. package/dist/{projectionStaleness-CAdpIsaW.d.ts → projectionStaleness-CmdbpjVK.d.ts} +1 -1
  119. package/dist/projectionStaleness.d.ts +1 -1
  120. package/dist/{questionEvidenceLinks-BdQD0TkM.d.ts → questionEvidenceLinks-DFlyPpAj.d.ts} +1 -1
  121. package/dist/questionEvidenceLinks.d.ts +1 -1
  122. package/dist/questionEvidenceLinks.js +199 -881
  123. package/dist/questionEvidenceLinks.js.map +1 -1
  124. package/dist/resolvers.js +86 -37
  125. package/dist/resolvers.js.map +1 -1
  126. package/dist/scopeResolverCompat.js +64 -7
  127. package/dist/scopeResolverCompat.js.map +1 -1
  128. package/dist/{text-matching-CMn2WnVD.d.ts → text-matching-DNg4M5Wd.d.ts} +1 -1
  129. package/dist/text-matching.d.ts +1 -1
  130. package/dist/text-matching.js +1 -244
  131. package/dist/text-matching.js.map +1 -1
  132. package/dist/topicProjectOverlay.js +56 -13
  133. package/dist/topicProjectOverlay.js.map +1 -1
  134. package/dist/topicScope.js +55 -6
  135. package/dist/topicScope.js.map +1 -1
  136. package/dist/workflowBridge.d.ts +27 -0
  137. package/dist/workflowBridge.js +352 -0
  138. package/dist/workflowBridge.js.map +1 -0
  139. package/dist/workspaceIsolation.js +56 -57
  140. package/dist/workspaceIsolation.js.map +1 -1
  141. package/package.json +6 -5
@@ -1,943 +1,32 @@
1
1
  import { v } from 'convex/values';
2
- import { componentsGeneric, mutationGeneric, anyApi, queryGeneric, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
2
+ import { requireProjectAccess, checkScopeAccess, checkProjectAccess } from '@lucern/access-control/access';
3
+ import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
4
+ import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
5
+ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
6
+ import { componentsGeneric, anyApi, mutationGeneric, queryGeneric, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
7
+ import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
3
8
 
4
9
  // src/epistemicEvidence.ts
5
10
  var api = anyApi;
6
11
  componentsGeneric();
7
-
8
- // ../access-control/src/topicProjectOverlay.ts
9
- var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
10
- function readNonEmptyString(value) {
11
- if (typeof value !== "string") {
12
- return;
13
- }
14
- const normalized = value.trim();
15
- return normalized.length > 0 ? normalized : void 0;
16
- }
17
- function readStringArray(value) {
18
- if (!Array.isArray(value)) {
19
- return [];
20
- }
21
- return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
22
- }
23
- function readMetadata(topic) {
24
- return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
25
- }
26
- function readLegacyProjectId(value) {
27
- if (!value) {
28
- return;
29
- }
30
- return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
31
- }
32
- function coerceVisibility(value) {
33
- return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
34
- }
35
- function coerceStatus(value) {
36
- return value === "active" || value === "archived" || value === "watching" ? value : void 0;
37
- }
38
- function mapProjectType(topic, metadata) {
39
- const explicit = readNonEmptyString(metadata.projectType);
40
- if (explicit) {
41
- return explicit;
42
- }
43
- if (topic.type === "theme") {
44
- return "thematic";
45
- }
46
- return readNonEmptyString(topic.type) || "general";
47
- }
48
- function isProjectLikeTopic(topic) {
49
- const metadata = readMetadata(topic);
50
- return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
51
- }
52
- async function resolveTopicDoc(ctx, scopeId) {
53
- if (ctx?.db && typeof ctx.db.get === "function") {
54
- try {
55
- const directTopic = await ctx.db.get(scopeId);
56
- if (directTopic) {
57
- return directTopic;
58
- }
59
- } catch {
60
- }
61
- }
62
- if (typeof ctx.runQuery !== "function") {
63
- return null;
64
- }
65
- try {
66
- const topic = await ctx.runQuery(api.topics.get, {
67
- id: String(scopeId)
68
- });
69
- if (topic?.name !== void 0 && topic?.type !== void 0) {
70
- return topic;
71
- }
72
- } catch {
73
- }
74
- try {
75
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
76
- projectId: String(scopeId)
77
- });
78
- if (topic?.name !== void 0 && topic?.type !== void 0) {
79
- return topic;
80
- }
81
- } catch {
82
- }
83
- return null;
84
- }
85
- function materializeTopicProjectOverlay(topic, idMode = "legacy") {
86
- const metadata = readMetadata(topic);
87
- const topicId = String(topic._id);
88
- const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
89
- const storageProjectId = legacyProjectId || topicId;
90
- const outwardId = idMode === "topic" ? topicId : storageProjectId;
91
- const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
92
- const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
93
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
94
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
95
- return {
96
- ...metadata,
97
- _id: outwardId,
98
- projectId: outwardId,
99
- topicId,
100
- storageProjectId,
101
- legacyProjectId,
102
- name: readNonEmptyString(topic.name) || "Untitled Theme",
103
- type: mapProjectType(topic, metadata),
104
- description: readNonEmptyString(topic.description),
105
- ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
106
- sharedWith: readStringArray(metadata.sharedWith),
107
- visibility,
108
- tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
109
- workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
110
- status,
111
- tags: readStringArray(metadata.tags),
112
- chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
113
- artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
114
- lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
115
- _creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
116
- createdAt,
117
- updatedAt
118
- };
119
- }
120
- async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
121
- const topic = await resolveTopicDoc(ctx, scopeId);
122
- if (!topic) {
123
- return null;
124
- }
125
- if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
126
- return null;
127
- }
128
- return materializeTopicProjectOverlay(topic, options.idMode);
129
- }
130
- async function listTopicProjectOverlays(ctx, options = {}) {
131
- let allTopics = [];
132
- if (ctx?.db?.query && typeof ctx.db.query === "function") {
133
- try {
134
- allTopics = await ctx.db.query("topics").collect();
135
- } catch {
136
- allTopics = [];
137
- }
138
- }
139
- if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
140
- allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
141
- }
142
- return allTopics.filter(
143
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
144
- ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
145
- }
146
-
147
- // ../access-control/src/projectGrantsBridge.ts
148
- var PROJECT_GRANT_STATUSES = ["active", "revoked", "expired"];
149
- function normalizeString(value) {
150
- if (typeof value !== "string") {
151
- return;
152
- }
153
- const trimmed = value.trim();
154
- return trimmed.length > 0 ? trimmed : void 0;
155
- }
156
- async function resolveGrantScopeIds(ctx, args) {
157
- const topicId = normalizeString(args.topicId);
158
- const projectId = normalizeString(args.projectId);
159
- for (const scopeId of [topicId, projectId]) {
160
- if (!scopeId) {
161
- continue;
162
- }
163
- try {
164
- const overlay = await resolveTopicProjectOverlay(ctx, scopeId, {
165
- idMode: "legacy",
166
- projectLikeOnly: false
167
- });
168
- if (overlay) {
169
- return {
170
- topicId: normalizeString(overlay.topicId) ?? topicId,
171
- projectId: normalizeString(overlay.projectId) ?? projectId ?? scopeId
172
- };
173
- }
174
- } catch {
175
- }
176
- }
177
- return { topicId, projectId };
178
- }
179
- async function normalizeProjectGrantRow(ctx, row) {
180
- const scope = await resolveGrantScopeIds(ctx, {
181
- topicId: row.topicId,
182
- projectId: row.projectId
183
- });
184
- return {
185
- ...row,
186
- ...scope.topicId ? { topicId: scope.topicId } : {},
187
- ...scope.projectId ?? scope.topicId ? { projectId: scope.projectId ?? scope.topicId } : {}
188
- };
189
- }
190
- async function normalizeProjectGrantRows(ctx, rows) {
191
- return await Promise.all(rows.map((row) => normalizeProjectGrantRow(ctx, row)));
192
- }
193
- async function listProjectGrantsByPrincipal(ctx, principalId) {
194
- const rows = await Promise.all(
195
- PROJECT_GRANT_STATUSES.map(
196
- (status) => ctx.db.query("projectGrants").withIndex(
197
- "by_principal_status",
198
- (q) => q.eq("principalId", principalId).eq("status", status)
199
- ).collect()
200
- )
201
- );
202
- return await normalizeProjectGrantRows(ctx, rows.flat());
203
- }
204
- async function listProjectGrantsByGroup(ctx, groupId) {
205
- const rows = await Promise.all(
206
- PROJECT_GRANT_STATUSES.map(
207
- (status) => ctx.db.query("projectGrants").withIndex(
208
- "by_group_status",
209
- (q) => q.eq("groupId", groupId).eq("status", status)
210
- ).collect()
211
- )
212
- );
213
- return await normalizeProjectGrantRows(ctx, rows.flat());
214
- }
215
- function buildScopeMatchers(inputScopeId, resolved) {
216
- return new Set(
217
- [inputScopeId, resolved.topicId, resolved.projectId].map((value) => normalizeString(value)).filter((value) => Boolean(value))
218
- );
219
- }
220
- function matchesResolvedScope(row, scopeIds) {
221
- const rowTopicId = normalizeString(row.topicId);
222
- const rowProjectId = normalizeString(row.projectId);
223
- return rowTopicId !== void 0 && scopeIds.has(rowTopicId) || rowProjectId !== void 0 && scopeIds.has(rowProjectId);
224
- }
225
- async function bridgeListProjectGrantsByTopicAndPrincipal(ctx, topicId, principalId) {
226
- const resolved = await resolveGrantScopeIds(ctx, { topicId });
227
- const scopeIds = buildScopeMatchers(topicId, resolved);
228
- const rows = await listProjectGrantsByPrincipal(ctx, principalId);
229
- return rows.filter((row) => matchesResolvedScope(row, scopeIds));
230
- }
231
- async function bridgeListProjectGrantsByTopicAndGroup(ctx, topicId, groupId) {
232
- const resolved = await resolveGrantScopeIds(ctx, { topicId });
233
- const scopeIds = buildScopeMatchers(topicId, resolved);
234
- const rows = await listProjectGrantsByGroup(ctx, groupId);
235
- return rows.filter((row) => matchesResolvedScope(row, scopeIds));
236
- }
237
- async function bridgeListProjectGrantsByPrincipalStatus(ctx, principalId, status) {
238
- const rows = await listProjectGrantsByPrincipal(ctx, principalId);
239
- return rows.filter((row) => row.status === status);
240
- }
241
- async function bridgeListProjectGrantsByGroupStatus(ctx, groupId, status) {
242
- const rows = await listProjectGrantsByGroup(ctx, groupId);
243
- return rows.filter((row) => row.status === status);
244
- }
245
- async function bridgeInsertProjectGrant(ctx, value) {
246
- const resolved = await resolveGrantScopeIds(ctx, value);
247
- return await ctx.db.insert("projectGrants", {
248
- ...value,
249
- ...resolved.topicId ? { topicId: resolved.topicId } : {},
250
- ...resolved.projectId ?? resolved.topicId ? { projectId: resolved.projectId ?? resolved.topicId } : {}
251
- });
252
- }
253
-
254
- // ../access-control/src/resolvers.ts
255
- async function findUserByClerkId(ctx, clerkId) {
256
- const normalizedClerkId = clerkId.trim();
257
- if (!normalizedClerkId) {
258
- return null;
259
- }
260
- if (typeof ctx.runQuery === "function") {
261
- try {
262
- const bridgedUser = await ctx.runQuery(api.users.getUserByClerkId, {
263
- clerkId: normalizedClerkId
264
- });
265
- if (bridgedUser) {
266
- return bridgedUser;
267
- }
268
- } catch {
269
- }
270
- }
271
- try {
272
- const users = await ctx.db.query("users").collect();
273
- return users.find((user) => String(user.clerkId ?? "") === normalizedClerkId) ?? null;
274
- } catch {
275
- return null;
276
- }
277
- }
278
- async function findUserByPrincipalId(ctx, principalId) {
279
- const normalizedPrincipalId = principalId.trim();
280
- if (!normalizedPrincipalId) {
281
- return null;
282
- }
283
- try {
284
- const users = await ctx.db.query("users").collect();
285
- return users.find(
286
- (user) => String(user.defaultPrincipalId ?? "") === normalizedPrincipalId
287
- ) ?? null;
288
- } catch {
289
- return null;
290
- }
291
- }
292
- async function findAgentByPrincipalId(ctx, principalId) {
293
- const normalizedPrincipalId = principalId.trim();
294
- if (!normalizedPrincipalId) {
295
- return null;
296
- }
297
- if (typeof ctx.runQuery === "function") {
298
- try {
299
- const bridgedAgent = await ctx.runQuery(
300
- api.agents.getAgentByPrincipalId,
301
- {
302
- principalId: normalizedPrincipalId
303
- }
304
- );
305
- if (bridgedAgent) {
306
- return bridgedAgent;
307
- }
308
- } catch {
309
- }
310
- }
311
- try {
312
- const agents = await ctx.db.query("agents").collect();
313
- return agents.find(
314
- (agent) => String(agent.principalId ?? "") === normalizedPrincipalId
315
- ) ?? null;
316
- } catch {
317
- return null;
318
- }
319
- }
320
- function defaultResolvers() {
321
- return {
322
- async getProject(ctx, topicId) {
323
- return await resolveTopicProjectOverlay(ctx, topicId, {
324
- idMode: "legacy",
325
- projectLikeOnly: false
326
- });
327
- },
328
- async listTopics(ctx) {
329
- return await listTopicProjectOverlays(ctx, { idMode: "legacy" });
330
- },
331
- async listTopicsByOwner(ctx, ownerId) {
332
- const topics = await listTopicProjectOverlays(ctx, { idMode: "legacy" });
333
- return topics.filter((topic) => topic.ownerId === ownerId);
334
- },
335
- async listTopicsByVisibility(ctx, visibility) {
336
- const topics = await listTopicProjectOverlays(ctx, { idMode: "legacy" });
337
- return topics.filter((topic) => topic.visibility === visibility);
338
- },
339
- async listProjectGrantsByProjectAndPrincipal(ctx, topicId, principalId) {
340
- return await bridgeListProjectGrantsByTopicAndPrincipal(
341
- ctx,
342
- topicId,
343
- principalId
344
- );
345
- },
346
- async listProjectGrantsByProjectAndGroup(ctx, topicId, groupId) {
347
- return await bridgeListProjectGrantsByTopicAndGroup(ctx, topicId, groupId);
348
- },
349
- async listProjectGrantsByPrincipalStatus(ctx, principalId, status) {
350
- return await bridgeListProjectGrantsByPrincipalStatus(
351
- ctx,
352
- principalId,
353
- status
354
- );
355
- },
356
- async listProjectGrantsByGroupStatus(ctx, groupId, status) {
357
- return await bridgeListProjectGrantsByGroupStatus(ctx, groupId, status);
358
- },
359
- async insertProjectGrant(ctx, value) {
360
- return await bridgeInsertProjectGrant(ctx, value);
361
- },
362
- async getAgentByPrincipalId(ctx, principalId) {
363
- return await findAgentByPrincipalId(ctx, principalId);
364
- },
365
- async getUserByClerkId(ctx, clerkId) {
366
- return await findUserByClerkId(ctx, clerkId);
367
- },
368
- async getUserByPrincipalId(ctx, principalId) {
369
- return await findUserByPrincipalId(ctx, principalId);
370
- }
371
- };
372
- }
373
- var resolverOverrides = {};
374
- function resolveAccessControlAppResolvers(_ctx) {
375
- return {
376
- ...defaultResolvers(),
377
- ...resolverOverrides
378
- };
379
- }
380
-
381
- // ../access-control/src/principalContext.ts
382
- function requireCanonicalResolvedUser(user, clerkId) {
383
- const resolved = user;
384
- if (!resolved) {
385
- throw new Error(
386
- `[AccessControl] Canonical user identity required for ${clerkId}. Sync users.upsertUser before user-bound access checks.`
387
- );
388
- }
389
- const { mcRole, defaultTenantId, defaultWorkspaceId, defaultPrincipalId } = resolved;
390
- if (mcRole !== "platform_admin" && mcRole !== "tenant_admin" && mcRole !== "workspace_admin" && mcRole !== "editor" && mcRole !== "viewer" && mcRole !== "auditor" && mcRole !== "service_agent") {
391
- throw new Error(
392
- `[AccessControl] Canonical MC role required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
393
- );
394
- }
395
- if (typeof defaultTenantId !== "string" || defaultTenantId.trim().length === 0) {
396
- throw new Error(
397
- `[AccessControl] Canonical home tenant required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
398
- );
399
- }
400
- if (typeof defaultWorkspaceId !== "string" || defaultWorkspaceId.trim().length === 0) {
401
- throw new Error(
402
- `[AccessControl] Canonical home workspace required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
403
- );
404
- }
405
- if (typeof defaultPrincipalId !== "string" || defaultPrincipalId.trim().length === 0) {
406
- throw new Error(
407
- `[AccessControl] Canonical federated principal required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
408
- );
409
- }
410
- return {
411
- mcRole,
412
- defaultTenantId: defaultTenantId.trim(),
413
- defaultWorkspaceId: defaultWorkspaceId.trim(),
414
- defaultPrincipalId: defaultPrincipalId.trim()
415
- };
416
- }
417
- function isPrincipalIdInput(value) {
418
- return value.startsWith("user:") || value.startsWith("group:") || value.startsWith("service:") || value.startsWith("agent:") || value.startsWith("external_viewer:");
419
- }
420
- async function resolveCanonicalUserRecord(ctx, actorId) {
421
- const normalizedActorId = actorId.trim();
422
- const clerkId = isPrincipalIdInput(normalizedActorId) && normalizedActorId.startsWith("user:") ? normalizedActorId.slice("user:".length) : normalizedActorId;
423
- const resolvers = resolveAccessControlAppResolvers();
424
- const resolvedByClerkId = await resolvers.getUserByClerkId(ctx, clerkId);
425
- if (resolvedByClerkId) {
426
- return {
427
- resolvedUser: resolvedByClerkId,
428
- clerkId,
429
- contextClerkId: clerkId
430
- };
431
- }
432
- const resolvedByPrincipalId = await resolvers.getUserByPrincipalId(
433
- ctx,
434
- normalizedActorId
435
- );
436
- return {
437
- resolvedUser: resolvedByPrincipalId ?? null,
438
- clerkId,
439
- contextClerkId: normalizedActorId.startsWith("user:") && clerkId.length > 0 ? clerkId : normalizedActorId
440
- };
441
- }
442
- function uniqRoles(roles) {
443
- const roleSet = /* @__PURE__ */ new Set();
444
- for (const role of roles) {
445
- if (role === "platform_admin" || role === "tenant_admin" || role === "workspace_admin" || role === "editor" || role === "viewer" || role === "auditor" || role === "service_agent") {
446
- roleSet.add(role);
447
- }
448
- }
449
- return [...roleSet];
450
- }
451
- function normalizeGroupIds(value) {
452
- if (!Array.isArray(value)) {
453
- return [];
454
- }
455
- return [...new Set(
456
- value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean)
457
- )];
458
- }
459
- function requireServiceAgentUser(user, actorId) {
460
- const canonicalUser = requireCanonicalResolvedUser(user, actorId);
461
- if (canonicalUser.mcRole !== "service_agent") {
462
- throw new Error(
463
- `[AccessControl] Canonical service_agent identity required for ${actorId}. Sync users.upsertUser before agent-bound access checks.`
464
- );
465
- }
466
- return canonicalUser;
467
- }
468
- function requireCanonicalResolvedAgent(agent, actorId) {
469
- const resolved = agent;
470
- if (!resolved) {
471
- throw new Error(
472
- `[AccessControl] Agent "${actorId}" not found in agents or users table.`
473
- );
474
- }
475
- if (typeof resolved.principalId !== "string" || resolved.principalId.trim().length === 0) {
476
- throw new Error(
477
- `[AccessControl] Canonical agent principalId required for ${actorId}.`
478
- );
479
- }
480
- if (typeof resolved.tenantId !== "string" || resolved.tenantId.trim().length === 0) {
481
- throw new Error(
482
- `[AccessControl] Canonical home tenant required for ${actorId}.`
483
- );
484
- }
485
- if (typeof resolved.workspaceId !== "string" || resolved.workspaceId.trim().length === 0) {
486
- throw new Error(
487
- `[AccessControl] Canonical home workspace required for ${actorId}.`
488
- );
489
- }
490
- return {
491
- principalId: resolved.principalId.trim(),
492
- tenantId: resolved.tenantId.trim(),
493
- workspaceId: resolved.workspaceId.trim(),
494
- roles: uniqRoles(Array.isArray(resolved.roles) ? resolved.roles : []) ?? ["service_agent"],
495
- groupIds: normalizeGroupIds(resolved.groupIds)
496
- };
497
- }
498
- async function resolvePrincipalContext(ctx, actorId) {
499
- if (actorId.startsWith("agent:")) {
500
- const resolvers = resolveAccessControlAppResolvers();
501
- const resolvedAgent = await resolvers.getAgentByPrincipalId(ctx, actorId);
502
- if (resolvedAgent) {
503
- const agent = requireCanonicalResolvedAgent(
504
- resolvedAgent,
505
- actorId
506
- );
507
- return {
508
- principalId: agent.principalId,
509
- principalType: "service",
510
- clerkId: actorId,
511
- tenantId: agent.tenantId,
512
- workspaceId: agent.workspaceId,
513
- roles: agent.roles.length > 0 ? agent.roles : ["service_agent"],
514
- groupIds: agent.groupIds,
515
- isPlatformAdmin: false,
516
- isTenantAdmin: false,
517
- isWorkspaceAdmin: false,
518
- isSystemFallback: false
519
- };
520
- }
521
- const resolvedUser2 = await resolvers.getUserByClerkId(
522
- ctx,
523
- actorId
524
- );
525
- if (!resolvedUser2) {
526
- throw new Error(
527
- `[AccessControl] Agent "${actorId}" not found in agents or users table.`
528
- );
529
- }
530
- const user2 = requireServiceAgentUser(
531
- resolvedUser2,
532
- actorId
533
- );
534
- console.warn(
535
- `[AccessControl] Deprecated legacy service-agent fallback for ${actorId}; migrate this principal into identity.agents.`
536
- );
537
- return {
538
- principalId: user2.defaultPrincipalId,
539
- principalType: "service",
540
- clerkId: actorId,
541
- tenantId: user2.defaultTenantId,
542
- workspaceId: user2.defaultWorkspaceId,
543
- roles: ["service_agent"],
544
- groupIds: normalizeGroupIds(resolvedUser2?.principalGroupIds),
545
- isPlatformAdmin: false,
546
- isTenantAdmin: false,
547
- isWorkspaceAdmin: false,
548
- isSystemFallback: false
549
- };
550
- }
551
- const {
552
- resolvedUser,
553
- contextClerkId
554
- } = await resolveCanonicalUserRecord(ctx, actorId);
555
- const user = requireCanonicalResolvedUser(
556
- resolvedUser,
557
- contextClerkId
558
- );
559
- if (!user.defaultPrincipalId) {
560
- throw new Error(
561
- `[AccessControl] Canonical federated principal required for ${contextClerkId}. Re-sync Master Control identity before user-bound access checks.`
562
- );
563
- }
564
- if (user.mcRole === "service_agent") {
565
- return {
566
- principalId: user.defaultPrincipalId,
567
- principalType: "service",
568
- clerkId: contextClerkId,
569
- tenantId: user.defaultTenantId,
570
- workspaceId: user.defaultWorkspaceId,
571
- roles: ["service_agent"],
572
- groupIds: normalizeGroupIds(resolvedUser?.principalGroupIds),
573
- isPlatformAdmin: false,
574
- isTenantAdmin: false,
575
- isWorkspaceAdmin: false,
576
- isSystemFallback: false
577
- };
578
- }
579
- const principalId = user.defaultPrincipalId;
580
- const effectiveRole = user.mcRole;
581
- const roles = effectiveRole === "platform_admin" ? ["platform_admin", "tenant_admin"] : effectiveRole === "tenant_admin" ? ["tenant_admin"] : [effectiveRole];
582
- const tenantId = user.defaultTenantId;
583
- const workspaceId = user.defaultWorkspaceId;
584
- const isPlatformAdmin = effectiveRole === "platform_admin";
585
- return {
586
- principalId,
587
- principalType: "user",
588
- clerkId: contextClerkId,
589
- tenantId,
590
- workspaceId,
591
- roles: uniqRoles(roles),
592
- groupIds: normalizeGroupIds(resolvedUser?.principalGroupIds),
593
- isPlatformAdmin,
594
- isTenantAdmin: isPlatformAdmin || effectiveRole === "tenant_admin",
595
- isWorkspaceAdmin: isPlatformAdmin || effectiveRole === "tenant_admin" || effectiveRole === "workspace_admin",
596
- isSystemFallback: false
597
- };
598
- }
599
-
600
- // ../access-control/src/access.ts
601
- function isTopicInPrincipalTenant(topic, principalTenantId) {
602
- if (!topic.tenantId) {
603
- return false;
604
- }
605
- if (!principalTenantId) {
606
- return false;
607
- }
608
- return String(topic.tenantId) === String(principalTenantId);
609
- }
610
- function isTopicInPrincipalWorkspace(topic, principalWorkspaceId) {
611
- if (!topic.workspaceId) {
612
- return false;
613
- }
614
- if (!principalWorkspaceId) {
615
- return false;
616
- }
617
- return String(topic.workspaceId) === String(principalWorkspaceId);
618
- }
619
- function isLegacyUnscopedTopic(topic) {
620
- return !topic.tenantId || !topic.workspaceId;
621
- }
622
- function isGrantScopeAlignedToTopic(topic, grant) {
623
- if (topic.tenantId && grant.tenantId && String(topic.tenantId) !== String(grant.tenantId)) {
624
- return false;
625
- }
626
- if (topic.workspaceId && grant.workspaceId && String(topic.workspaceId) !== String(grant.workspaceId)) {
627
- return false;
628
- }
629
- return true;
630
- }
631
- function isGrantSourceAllowedForVisibility(visibility, source) {
632
- if (source !== "external_share") {
633
- return true;
634
- }
635
- return visibility === "external" || visibility === "public";
636
- }
637
- function isGrantActive(grant) {
638
- if (grant.status !== "active") {
639
- return false;
640
- }
641
- if (grant.expiresAt !== void 0 && grant.expiresAt <= Date.now()) {
642
- return false;
643
- }
644
- return true;
645
- }
646
- async function hasPrincipalGrant(ctx, args) {
647
- const grants = await resolveAccessControlAppResolvers().listProjectGrantsByProjectAndPrincipal(
648
- ctx,
649
- args.topic._id,
650
- args.principalId
651
- );
652
- if (grants.some(
653
- (grant) => isGrantActive(grant) && isGrantScopeAlignedToTopic(args.topic, grant) && isGrantSourceAllowedForVisibility(
654
- args.topic.visibility,
655
- grant.source
656
- ) && (!args.principalIsExternal || args.topic.visibility === "public" || grant.source === "external_share")
657
- )) {
658
- return true;
659
- }
660
- return false;
661
- }
662
- async function hasGroupGrant(ctx, args) {
663
- if (args.groupIds.length === 0) {
664
- return false;
665
- }
666
- for (const groupId of args.groupIds) {
667
- const grants = await resolveAccessControlAppResolvers().listProjectGrantsByProjectAndGroup(ctx, args.topic._id, groupId);
668
- if (grants.some(
669
- (grant) => isGrantActive(grant) && isGrantScopeAlignedToTopic(args.topic, grant) && isGrantSourceAllowedForVisibility(
670
- args.topic.visibility,
671
- grant.source
672
- )
673
- )) {
674
- return true;
675
- }
676
- }
677
- return false;
678
- }
679
- function isExternalPrincipal(_ctx, _args) {
680
- return false;
681
- }
682
- async function evaluateTopicAccessDetailed(ctx, args) {
683
- if (args.legacyUserId) {
684
- return {
685
- hasAccess: true,
686
- isAdmin: false,
687
- isOwner: false,
688
- isShared: false,
689
- hasGrant: true,
690
- isFirmVisible: true,
691
- isExternalVisible: false,
692
- isPublicVisible: false,
693
- isTenantScopeMatch: true,
694
- isWorkspaceScopeMatch: true,
695
- isPrincipalExternal: false
696
- };
697
- }
698
- const topic = await resolveAccessControlAppResolvers().getProject(
699
- ctx,
700
- args.topicId
701
- );
702
- if (!topic) {
703
- return {
704
- hasAccess: false,
705
- isAdmin: false,
706
- isOwner: false,
707
- isShared: false,
708
- hasGrant: false,
709
- isFirmVisible: false,
710
- isExternalVisible: false,
711
- isPublicVisible: false,
712
- isTenantScopeMatch: false,
713
- isWorkspaceScopeMatch: false,
714
- isPrincipalExternal: false
715
- };
716
- }
717
- const { principalContext, legacyUserId } = args;
718
- const userIsAdmin = principalContext.isPlatformAdmin;
719
- const isOwner = topic.ownerId === legacyUserId;
720
- const isShared = (topic.sharedWith ?? []).includes(legacyUserId);
721
- const principalIsExternal = await isExternalPrincipal(ctx, {
722
- groupIds: principalContext.groupIds,
723
- topicTenantId: topic.tenantId,
724
- topicWorkspaceId: topic.workspaceId
725
- });
726
- const hasPrincipalGrantResult = await hasPrincipalGrant(ctx, {
727
- topic,
728
- principalId: principalContext.principalId,
729
- principalIsExternal
730
- });
731
- const hasGroupGrantResult = await hasGroupGrant(ctx, {
732
- topic,
733
- groupIds: principalContext.groupIds
734
- });
735
- const hasGrant = isShared || hasPrincipalGrantResult || hasGroupGrantResult;
736
- const legacyUnscoped = isLegacyUnscopedTopic(topic);
737
- const tenantScopeMatch = isTopicInPrincipalTenant(
738
- topic,
739
- principalContext.tenantId
740
- );
741
- const workspaceScopeMatch = isTopicInPrincipalWorkspace(
742
- topic,
743
- principalContext.workspaceId
744
- );
745
- const isPublicVisible = topic.visibility === "public";
746
- const isFirmVisible = topic.visibility === "firm" && !legacyUnscoped && tenantScopeMatch && workspaceScopeMatch && !principalIsExternal;
747
- const hasScopedGrant = hasGrant && (legacyUnscoped || tenantScopeMatch && workspaceScopeMatch);
748
- const isExternalVisible = topic.visibility === "external" && hasScopedGrant;
749
- const hasAccess = userIsAdmin || isOwner || hasScopedGrant || isPublicVisible || isFirmVisible;
750
- return {
751
- hasAccess,
752
- isAdmin: userIsAdmin,
753
- isOwner,
754
- isShared,
755
- hasGrant,
756
- isFirmVisible,
757
- isExternalVisible,
758
- isPublicVisible,
759
- isTenantScopeMatch: tenantScopeMatch,
760
- isWorkspaceScopeMatch: workspaceScopeMatch,
761
- isPrincipalExternal: principalIsExternal
762
- };
763
- }
764
- async function checkTopicAccessDetailed(ctx, topicId, userId) {
765
- const principalContext = await resolvePrincipalContext(ctx, userId);
766
- return evaluateTopicAccessDetailed(ctx, {
767
- topicId,
768
- legacyUserId: userId,
769
- principalContext
770
- });
771
- }
772
- async function checkTopicAccess(ctx, topicId, userId) {
773
- const result = await checkTopicAccessDetailed(ctx, topicId, userId);
774
- return result.hasAccess;
775
- }
776
- async function checkScopeAccess(ctx, scopeId, userId) {
777
- try {
778
- const topic = await ctx.db.get(scopeId);
779
- if (topic && topic.name !== void 0 && topic.type !== void 0) {
780
- return true;
781
- }
782
- } catch {
783
- }
784
- try {
785
- return await checkTopicAccess(ctx, scopeId, userId);
786
- } catch {
787
- return false;
788
- }
789
- }
790
- async function requireTopicAccess(ctx, topicId, userId) {
791
- const hasAccess = await checkTopicAccess(ctx, topicId, userId);
792
- if (!hasAccess) {
793
- throw new Error(
794
- "Access denied: You don't have permission to access this topic"
795
- );
796
- }
797
- }
798
- var checkProjectAccess = checkTopicAccess;
799
- var requireProjectAccess = requireTopicAccess;
800
-
801
- // ../access-control/src/audience.ts
802
- var AUDIENCE_CLASS_RANK = {
803
- public: 0,
804
- restricted_external: 1,
805
- internal: 2
806
- };
807
- function normalizeKey(key) {
808
- return (key ?? "").trim().toLowerCase().replace(/[^a-z0-9:_-]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
809
- }
810
- function normalizeAudienceKey(key) {
811
- return normalizeKey(key);
812
- }
813
- function classFromAudienceKey(audienceKey, fallback = "internal") {
814
- const key = normalizeKey(audienceKey);
815
- if (!key) {
816
- return fallback;
817
- }
818
- if (key === "internal") {
819
- return "internal";
820
- }
821
- if (key === "public") {
822
- return "public";
823
- }
824
- if (key === "lp" || key === "external" || key === "client" || key === "partner" || key === "portfolio" || key === "network" || key === "restricted_external") {
825
- return "restricted_external";
826
- }
827
- return fallback;
828
- }
829
- function canAudienceClassAccess(viewerClass, resourceClass) {
830
- return AUDIENCE_CLASS_RANK[viewerClass] >= AUDIENCE_CLASS_RANK[resourceClass];
831
- }
832
-
833
- // ../access-control/src/audienceRegistry.ts
834
- var DEFAULT_AUDIENCES = [
835
- {
836
- audienceKey: "internal",
837
- audienceLabel: "Internal",
838
- audienceClass: "internal"
839
- },
840
- {
841
- audienceKey: "lp",
842
- audienceLabel: "Limited Partners",
843
- audienceClass: "restricted_external"
844
- },
845
- {
846
- audienceKey: "public",
847
- audienceLabel: "Public",
848
- audienceClass: "public"
849
- }
850
- ];
851
- var AUDIENCE_CLASS_PRIORITY = {
852
- internal: 0,
853
- restricted_external: 1,
854
- public: 2
855
- };
856
- function normalizeRegistryRow(row) {
857
- return {
858
- audienceKey: normalizeAudienceKey(row.audienceKey),
859
- audienceLabel: row.audienceLabel,
860
- audienceClass: row.audienceClass,
861
- workspaceId: row.workspaceId
862
- };
863
- }
864
- function dedupeRegistryRows(rows) {
865
- const byKey = /* @__PURE__ */ new Map();
866
- for (const row of rows) {
867
- const key = normalizeAudienceKey(row.audienceKey);
868
- if (!key) {
869
- continue;
870
- }
871
- const existing = byKey.get(key);
872
- const isWorkspaceScoped = row.workspaceId !== void 0;
873
- const existingWorkspaceScoped = existing?.workspaceId !== void 0;
874
- if (!existing || isWorkspaceScoped && !existingWorkspaceScoped) {
875
- byKey.set(key, {
876
- ...row,
877
- audienceKey: key
878
- });
879
- }
880
- }
881
- const normalized = [...byKey.values()];
882
- normalized.sort((a, b) => {
883
- const classDelta = AUDIENCE_CLASS_PRIORITY[a.audienceClass] - AUDIENCE_CLASS_PRIORITY[b.audienceClass];
884
- if (classDelta !== 0) {
885
- return classDelta;
886
- }
887
- return a.audienceKey.localeCompare(b.audienceKey);
888
- });
889
- return normalized;
890
- }
891
- async function queryRegistryRows(ctx, args) {
892
- if (!args.tenantId) {
893
- return [...DEFAULT_AUDIENCES];
894
- }
895
- const rows = await ctx.db.query("platformAudiences").withIndex("by_tenantId", (q) => q.eq("tenantId", args.tenantId)).collect();
896
- const workspaceIdString = args.workspaceId ? String(args.workspaceId) : null;
897
- const tenantScoped = rows.filter((row) => row.status === "active");
898
- const applicable = tenantScoped.filter((row) => {
899
- if (!row.workspaceId) {
900
- return true;
901
- }
902
- if (!workspaceIdString) {
903
- return false;
904
- }
905
- return String(row.workspaceId) === workspaceIdString;
906
- });
907
- return dedupeRegistryRows([
908
- ...DEFAULT_AUDIENCES,
909
- ...applicable.map(
910
- (row) => normalizeRegistryRow({
911
- audienceKey: row.audienceKey,
912
- audienceLabel: row.audienceLabel,
913
- audienceClass: row.audienceClass,
914
- workspaceId: row.workspaceId
915
- })
916
- )
917
- ]);
918
- }
919
- async function listAudienceRegistryRows(ctx, args) {
920
- return queryRegistryRows(ctx, args);
921
- }
922
- var permissiveReturn = v.optional(v.any());
923
- var looseJsonObject = v.record(v.string(), v.any());
924
- var looseJsonArray = v.array(v.any());
925
- v.union(
926
- v.string(),
927
- v.number(),
928
- v.boolean(),
929
- v.null(),
930
- looseJsonObject,
931
- looseJsonArray
932
- );
933
- var api2 = anyApi;
934
- componentsGeneric();
935
12
  var internal = anyApi;
936
13
  var internalMutation = internalMutationGeneric;
937
14
  var internalQuery = internalQueryGeneric;
938
15
  var mutation = mutationGeneric;
939
16
  var query = queryGeneric;
940
17
 
18
+ // src/debug.ts
19
+ function isGraphPrimitiveDebugEnabled() {
20
+ const env = globalThis.process?.env;
21
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
22
+ }
23
+ function debugGraphPrimitiveFallback(message, context) {
24
+ if (!isGraphPrimitiveDebugEnabled()) {
25
+ return;
26
+ }
27
+ console.debug(message, context ?? {});
28
+ }
29
+
941
30
  // src/embeddingTrigger.ts
942
31
  async function scheduleEmbeddingGeneration(args) {
943
32
  try {
@@ -955,7 +44,15 @@ async function scheduleEmbeddingGeneration(args) {
955
44
  confidence: args.confidence
956
45
  }
957
46
  );
958
- } catch {
47
+ } catch (error) {
48
+ debugGraphPrimitiveFallback(
49
+ "[embeddingTrigger] Failed to schedule embedding generation",
50
+ {
51
+ error,
52
+ nodeId: String(args.nodeId),
53
+ nodeType: args.nodeType
54
+ }
55
+ );
959
56
  }
960
57
  }
961
58
 
@@ -972,96 +69,125 @@ function generateGlobalId() {
972
69
  }
973
70
 
974
71
  // src/topicProjectOverlay.ts
975
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
976
- function readNonEmptyString2(value) {
72
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
73
+ function readNonEmptyString(value) {
977
74
  if (typeof value !== "string") {
978
75
  return;
979
76
  }
980
77
  const normalized = value.trim();
981
78
  return normalized.length > 0 ? normalized : void 0;
982
79
  }
983
- function readStringArray2(value) {
80
+ function readStringArray(value) {
984
81
  if (!Array.isArray(value)) {
985
82
  return [];
986
83
  }
987
- return value.map((entry) => readNonEmptyString2(entry)).filter((entry) => Boolean(entry));
84
+ return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
988
85
  }
989
- function readMetadata2(topic) {
86
+ function readMetadata(topic) {
990
87
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
991
88
  }
992
- function readLegacyProjectId2(value) {
89
+ function readLegacyProjectId(value) {
993
90
  if (!value) {
994
91
  return;
995
92
  }
996
- return readNonEmptyString2(value[LEGACY_SCOPE_FIELD2]);
93
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
997
94
  }
998
- function coerceVisibility2(value) {
95
+ function coerceVisibility(value) {
999
96
  return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
1000
97
  }
1001
- function coerceStatus2(value) {
98
+ function coerceStatus(value) {
1002
99
  return value === "active" || value === "archived" || value === "watching" ? value : void 0;
1003
100
  }
1004
- function mapProjectType2(topic, metadata) {
1005
- const explicit = readNonEmptyString2(metadata.projectType);
101
+ function mapProjectType(topic, metadata) {
102
+ const explicit = readNonEmptyString(metadata.projectType);
1006
103
  if (explicit) {
1007
104
  return explicit;
1008
105
  }
1009
106
  if (topic.type === "theme") {
1010
107
  return "thematic";
1011
108
  }
1012
- return readNonEmptyString2(topic.type) || "general";
109
+ return readNonEmptyString(topic.type) || "general";
1013
110
  }
1014
- function isProjectLikeTopic2(topic) {
1015
- const metadata = readMetadata2(topic);
1016
- return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId2(topic) !== void 0 || readNonEmptyString2(metadata.projectType) !== void 0;
111
+ function isProjectLikeTopic(topic) {
112
+ const metadata = readMetadata(topic);
113
+ return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
1017
114
  }
1018
115
  function isMissingLucernChildComponentError(error) {
1019
- const message = error instanceof Error ? error.message : String(error);
116
+ const message = getErrorMessage(error);
1020
117
  return message.includes(
1021
118
  'Child component ComponentName(Identifier("lucern")) not found'
1022
119
  ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
1023
120
  }
1024
- async function resolveTopicDoc2(ctx, scopeId) {
121
+ function getErrorMessage(error) {
122
+ if (error instanceof Error) {
123
+ return error.message;
124
+ }
125
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
126
+ return error.message;
127
+ }
128
+ return "unknown error";
129
+ }
130
+ async function resolveTopicDoc(ctx, scopeId) {
1025
131
  if (ctx?.db && typeof ctx.db.get === "function") {
1026
132
  try {
1027
- const directTopic = await ctx.db.get(scopeId);
133
+ const directTopic = await ctx.db.get(
134
+ scopeId
135
+ );
1028
136
  if (directTopic) {
1029
137
  return directTopic;
1030
138
  }
1031
- } catch {
139
+ } catch (error) {
140
+ debugGraphPrimitiveFallback(
141
+ "[topicProjectOverlay] Failed to resolve topic by direct ID",
142
+ {
143
+ error,
144
+ scopeId
145
+ }
146
+ );
1032
147
  }
1033
148
  }
1034
149
  if (typeof ctx.runQuery !== "function") {
1035
150
  return null;
1036
151
  }
1037
152
  try {
1038
- const topic = await ctx.runQuery(api2.topics.get, {
153
+ const topic = await ctx.runQuery(api.topics.get, {
1039
154
  id: String(scopeId)
1040
155
  });
1041
156
  if (topic?.name !== void 0 && topic?.type !== void 0) {
1042
157
  return topic;
1043
158
  }
1044
- } catch {
159
+ } catch (error) {
160
+ debugGraphPrimitiveFallback(
161
+ "[topicProjectOverlay] Failed to resolve topic by ID query",
162
+ {
163
+ error,
164
+ scopeId
165
+ }
166
+ );
1045
167
  }
1046
168
  try {
1047
- const topic = await ctx.runQuery(api2.topics.getByLegacyScopeId, {
169
+ const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
1048
170
  projectId: String(scopeId)
1049
171
  });
1050
172
  if (topic?.name !== void 0 && topic?.type !== void 0) {
1051
173
  return topic;
1052
174
  }
1053
- } catch {
175
+ } catch (error) {
176
+ debugGraphPrimitiveFallback(
177
+ "[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
178
+ { error, scopeId }
179
+ );
1054
180
  }
1055
181
  return null;
1056
182
  }
1057
- function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1058
- const metadata = readMetadata2(topic);
183
+ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
184
+ const metadata = readMetadata(topic);
1059
185
  const topicId = String(topic._id);
1060
- const legacyProjectId = readLegacyProjectId2(topic) || readLegacyProjectId2(metadata) || readNonEmptyString2(metadata.legacyProjectId);
186
+ const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
1061
187
  const storageProjectId = legacyProjectId || topicId;
1062
188
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
1063
- const visibility = coerceVisibility2(topic.visibility) || coerceVisibility2(metadata.visibility) || "private";
1064
- const status = coerceStatus2(topic.status) || coerceStatus2(metadata.status) || "active";
189
+ const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
190
+ const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
1065
191
  const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
1066
192
  const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
1067
193
  return {
@@ -1071,16 +197,16 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1071
197
  topicId,
1072
198
  storageProjectId,
1073
199
  legacyProjectId,
1074
- name: readNonEmptyString2(topic.name) || "Untitled Theme",
1075
- type: mapProjectType2(topic, metadata),
1076
- description: readNonEmptyString2(topic.description),
1077
- ownerId: readNonEmptyString2(metadata.ownerId) || readNonEmptyString2(topic.createdBy) || "system",
1078
- sharedWith: readStringArray2(metadata.sharedWith),
200
+ name: readNonEmptyString(topic.name) || "Untitled Theme",
201
+ type: mapProjectType(topic, metadata),
202
+ description: readNonEmptyString(topic.description),
203
+ ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
204
+ sharedWith: readStringArray(metadata.sharedWith),
1079
205
  visibility,
1080
- tenantId: readNonEmptyString2(topic.tenantId) || readNonEmptyString2(metadata.tenantId),
1081
- workspaceId: readNonEmptyString2(topic.workspaceId) || readNonEmptyString2(metadata.workspaceId),
206
+ tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
207
+ workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
1082
208
  status,
1083
- tags: readStringArray2(metadata.tags),
209
+ tags: readStringArray(metadata.tags),
1084
210
  chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
1085
211
  artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
1086
212
  lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
@@ -1089,38 +215,42 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1089
215
  updatedAt
1090
216
  };
1091
217
  }
1092
- async function resolveTopicProjectOverlay2(ctx, scopeId, options = {}) {
1093
- const topic = await resolveTopicDoc2(ctx, scopeId);
218
+ async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
219
+ const topic = await resolveTopicDoc(ctx, scopeId);
1094
220
  if (!topic) {
1095
221
  return null;
1096
222
  }
1097
- if (options.projectLikeOnly !== false && !isProjectLikeTopic2(topic)) {
223
+ if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
1098
224
  return null;
1099
225
  }
1100
- return materializeTopicProjectOverlay2(topic, options.idMode);
226
+ return materializeTopicProjectOverlay(topic, options.idMode);
1101
227
  }
1102
- async function listTopicProjectOverlays2(ctx, options = {}) {
228
+ async function listTopicProjectOverlays(ctx, options = {}) {
1103
229
  let allTopics = [];
1104
230
  if (ctx?.db?.query && typeof ctx.db.query === "function") {
1105
231
  try {
1106
232
  allTopics = await ctx.db.query("topics").collect();
1107
- } catch {
233
+ } catch (error) {
234
+ debugGraphPrimitiveFallback(
235
+ "[topicProjectOverlay] Failed to read topics table; falling back to API",
236
+ { error }
237
+ );
1108
238
  allTopics = [];
1109
239
  }
1110
240
  }
1111
241
  if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
1112
- allTopics = (await ctx.runQuery(api2.topics.list, {}) ?? []) || [];
242
+ allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
1113
243
  }
1114
244
  return allTopics.filter(
1115
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic2(topic)
1116
- ).map((topic) => materializeTopicProjectOverlay2(topic, options.idMode));
245
+ (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
246
+ ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
1117
247
  }
1118
248
  async function patchTopicProjectOverlay(ctx, scopeId, value) {
1119
- const topic = await resolveTopicDoc2(ctx, scopeId);
249
+ const topic = await resolveTopicDoc(ctx, scopeId);
1120
250
  if (!topic) {
1121
251
  return null;
1122
252
  }
1123
- const nextMetadata = { ...readMetadata2(topic) };
253
+ const nextMetadata = { ...readMetadata(topic) };
1124
254
  const patch = {};
1125
255
  const topicUpdateArgs = {
1126
256
  id: String(topic._id)
@@ -1145,7 +275,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1145
275
  `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
1146
276
  );
1147
277
  case "status": {
1148
- const status = coerceStatus2(rawValue);
278
+ const status = coerceStatus(rawValue);
1149
279
  if (status) {
1150
280
  patch.status = status;
1151
281
  topicUpdateArgs.status = status;
@@ -1153,7 +283,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1153
283
  break;
1154
284
  }
1155
285
  case "visibility": {
1156
- const visibility = coerceVisibility2(rawValue);
286
+ const visibility = coerceVisibility(rawValue);
1157
287
  if (visibility) {
1158
288
  patch.visibility = visibility;
1159
289
  topicUpdateArgs.visibility = visibility;
@@ -1161,7 +291,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1161
291
  break;
1162
292
  }
1163
293
  case "type": {
1164
- const projectType = readNonEmptyString2(rawValue);
294
+ const projectType = readNonEmptyString(rawValue);
1165
295
  if (projectType) {
1166
296
  nextMetadata.projectType = projectType;
1167
297
  } else {
@@ -1185,7 +315,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1185
315
  topicUpdateArgs.metadata = nextMetadata;
1186
316
  if (typeof ctx.runMutation === "function") {
1187
317
  try {
1188
- await ctx.runMutation(api2.topics.update, topicUpdateArgs);
318
+ await ctx.runMutation(api.topics.update, topicUpdateArgs);
1189
319
  } catch (error) {
1190
320
  if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
1191
321
  throw error;
@@ -1199,19 +329,28 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1199
329
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
1200
330
  );
1201
331
  }
1202
- return materializeTopicProjectOverlay2(
1203
- {
1204
- ...topic,
1205
- ...patch,
1206
- metadata: nextMetadata
1207
- }
1208
- );
332
+ return materializeTopicProjectOverlay({
333
+ ...topic,
334
+ ...patch,
335
+ metadata: nextMetadata
336
+ });
1209
337
  }
1210
338
 
1211
339
  // src/resolvers.ts
1212
340
  function isMissingLucernChildComponentError2(error) {
1213
- const message = error instanceof Error ? error.message : String(error);
1214
- return message.includes('Child component ComponentName(Identifier("lucern")) not found') || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
341
+ const message = getErrorMessage2(error);
342
+ return message.includes(
343
+ 'Child component ComponentName(Identifier("lucern")) not found'
344
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
345
+ }
346
+ function getErrorMessage2(error) {
347
+ if (error instanceof Error) {
348
+ return error.message;
349
+ }
350
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
351
+ return error.message;
352
+ }
353
+ return "unknown error";
1215
354
  }
1216
355
  function isAdvisoryTopicPatch(value) {
1217
356
  const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
@@ -1225,52 +364,47 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
1225
364
  if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
1226
365
  throw error;
1227
366
  }
1228
- console.warn("[lucern graph-primitives] Non-fatal advisory topic patch failure", {
1229
- projectId,
1230
- keys: Object.keys(value),
1231
- error: error instanceof Error ? error.message : error
1232
- });
367
+ console.warn(
368
+ "[lucern graph-primitives] Non-fatal advisory topic patch failure",
369
+ {
370
+ projectId,
371
+ keys: Object.keys(value),
372
+ error: getErrorMessage2(error)
373
+ }
374
+ );
1233
375
  }
1234
376
  }
1235
- function defaultResolvers2() {
377
+ function defaultResolvers() {
1236
378
  return {
1237
- async getProject(ctx, projectId) {
1238
- return await resolveTopicProjectOverlay2(ctx, projectId, {
1239
- idMode: "legacy",
1240
- projectLikeOnly: false
1241
- });
1242
- },
1243
- async patchProject(ctx, projectId, value) {
1244
- await patchProjectWithTolerance(ctx, projectId, value);
1245
- },
1246
- async listTopics(ctx) {
1247
- return await listTopicProjectOverlays2(ctx, {
1248
- idMode: "legacy"
1249
- });
1250
- },
1251
- async getFinalArtifact(ctx, artifactId) {
1252
- return await ctx.db.get(artifactId);
1253
- }
379
+ getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
380
+ idMode: "legacy",
381
+ projectLikeOnly: false
382
+ }),
383
+ patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
384
+ listTopics: (ctx) => listTopicProjectOverlays(ctx, {
385
+ idMode: "legacy"
386
+ }),
387
+ getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
1254
388
  };
1255
389
  }
1256
- var resolverOverrides2 = {};
390
+ var resolverOverrides = {};
1257
391
  function resolveGraphPrimitivesAppResolvers(_ctx) {
1258
392
  return {
1259
- ...defaultResolvers2(),
1260
- ...resolverOverrides2
393
+ ...defaultResolvers(),
394
+ ...resolverOverrides
1261
395
  };
1262
396
  }
1263
- var LEGACY_SCOPE_FIELD3 = "graphScopeProjectId";
397
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
1264
398
  function asMappedProjectId(topic) {
1265
399
  if (!topic) {
1266
400
  return;
1267
401
  }
1268
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD3]);
402
+ const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD2]);
1269
403
  if (directLegacyProjectId) {
1270
404
  return directLegacyProjectId;
1271
405
  }
1272
406
  const metadata = topic.metadata || {};
1273
- const candidate = metadata[LEGACY_SCOPE_FIELD3] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
407
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
1274
408
  return candidate ? candidate : void 0;
1275
409
  }
1276
410
  function normalizeScopeValue(value) {
@@ -1299,9 +433,16 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
1299
433
  try {
1300
434
  return await ctx.db.query("topics").withIndex(
1301
435
  "by_graph_scope_project",
1302
- (q) => q.eq(LEGACY_SCOPE_FIELD3, scopeId)
436
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
1303
437
  ).collect();
1304
- } catch {
438
+ } catch (error) {
439
+ debugGraphPrimitiveFallback(
440
+ "[topicScope] Failed to resolve scope alias via index",
441
+ {
442
+ error,
443
+ scopeId
444
+ }
445
+ );
1305
446
  const topics = await ctx.db.query("topics").collect();
1306
447
  return topics.filter((topic) => {
1307
448
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
@@ -1315,10 +456,17 @@ async function tryResolveHostTopicById(ctx, topicId) {
1315
456
  return null;
1316
457
  }
1317
458
  try {
1318
- return await ctx.runQuery(api2.topics.get, {
459
+ return await ctx.runQuery(api.topics.get, {
1319
460
  id: topicId
1320
461
  }) ?? null;
1321
- } catch {
462
+ } catch (error) {
463
+ debugGraphPrimitiveFallback(
464
+ "[topicScope] Failed to resolve topic by host query",
465
+ {
466
+ error,
467
+ topicId
468
+ }
469
+ );
1322
470
  return null;
1323
471
  }
1324
472
  }
@@ -1327,10 +475,17 @@ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
1327
475
  return null;
1328
476
  }
1329
477
  try {
1330
- return await ctx.runQuery(api2.topics.getByLegacyScopeId, {
478
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
1331
479
  projectId: legacyScopeId
1332
480
  }) ?? null;
1333
- } catch {
481
+ } catch (error) {
482
+ debugGraphPrimitiveFallback(
483
+ "[topicScope] Failed to resolve topic by legacy scope",
484
+ {
485
+ error,
486
+ legacyScopeId
487
+ }
488
+ );
1334
489
  return null;
1335
490
  }
1336
491
  }
@@ -1359,8 +514,17 @@ async function resolveTopicProjectScope(ctx, args) {
1359
514
  if (args.topicId) {
1360
515
  let topic = null;
1361
516
  try {
1362
- topic = await ctx.db.get(args.topicId);
1363
- } catch {
517
+ topic = await ctx.db.get(
518
+ args.topicId
519
+ );
520
+ } catch (error) {
521
+ debugGraphPrimitiveFallback(
522
+ "[topicScope] Failed to load topic by direct id",
523
+ {
524
+ error,
525
+ topicId: args.topicId
526
+ }
527
+ );
1364
528
  }
1365
529
  if (!topic) {
1366
530
  topic = await tryResolveHostTopicById(ctx, String(args.topicId));
@@ -1397,7 +561,14 @@ async function resolveTopicProjectScope(ctx, args) {
1397
561
  directTopic = await ctx.db.get(
1398
562
  args.projectId
1399
563
  );
1400
- } catch {
564
+ } catch (error) {
565
+ debugGraphPrimitiveFallback(
566
+ "[topicScope] Failed to load direct project topic",
567
+ {
568
+ error,
569
+ projectId: args.projectId
570
+ }
571
+ );
1401
572
  }
1402
573
  if (directTopic) {
1403
574
  const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
@@ -1446,61 +617,6 @@ var optionalScopeArgs = {
1446
617
  projectId: v.optional(v.string()),
1447
618
  topicId: v.optional(v.string())
1448
619
  };
1449
-
1450
- // ../../packages/contracts/src/schema-helpers/spine/tables/epistemicNodes.ts
1451
- var NODE_TYPES = [
1452
- "decision",
1453
- "belief",
1454
- "question",
1455
- "theme",
1456
- "deal",
1457
- "topic",
1458
- "claim",
1459
- "evidence",
1460
- "synthesis",
1461
- "answer",
1462
- "atomic_fact",
1463
- "excerpt",
1464
- "source",
1465
- "company",
1466
- "person",
1467
- "investor",
1468
- "function",
1469
- "value_chain"
1470
- ];
1471
- function isNodeType(value) {
1472
- return NODE_TYPES.includes(value);
1473
- }
1474
- function getLayerForNodeType(type) {
1475
- switch (type) {
1476
- case "decision":
1477
- return "L4";
1478
- case "belief":
1479
- case "question":
1480
- case "theme":
1481
- case "deal":
1482
- return "L3";
1483
- case "claim":
1484
- case "evidence":
1485
- case "synthesis":
1486
- case "answer":
1487
- return "L2";
1488
- case "atomic_fact":
1489
- case "excerpt":
1490
- case "source":
1491
- return "L1";
1492
- case "topic":
1493
- return "organizational";
1494
- case "company":
1495
- case "person":
1496
- case "investor":
1497
- case "function":
1498
- case "value_chain":
1499
- return "ontological";
1500
- }
1501
- }
1502
-
1503
- // src/workspaceIsolation.ts
1504
620
  function normalizeScopeValue2(value) {
1505
621
  if (typeof value !== "string") {
1506
622
  return;
@@ -1703,7 +819,15 @@ async function resolveEvidenceScopeOrNull(ctx, args) {
1703
819
  projectId: args.projectId ?? void 0,
1704
820
  topicId: args.topicId ?? void 0
1705
821
  });
1706
- } catch {
822
+ } catch (error) {
823
+ debugGraphPrimitiveFallback(
824
+ "[epistemicEvidence] Failed to resolve evidence scope",
825
+ {
826
+ error,
827
+ projectId: args.projectId,
828
+ topicId: args.topicId
829
+ }
830
+ );
1707
831
  return null;
1708
832
  }
1709
833
  }
@@ -1767,6 +891,7 @@ var create = mutation({
1767
891
  sourceUrl: v.optional(v.string()),
1768
892
  sourceQuestionId: v.optional(v.string()),
1769
893
  userId: v.string(),
894
+ rationale: v.string(),
1770
895
  // Classification fields (from AI tools)
1771
896
  methodology: v.optional(v.string()),
1772
897
  informationAsymmetry: v.optional(v.string()),
@@ -1824,6 +949,7 @@ var create = mutation({
1824
949
  externalSourceType: args.externalSourceType,
1825
950
  sourceUrl: args.sourceUrl,
1826
951
  sourceQuestionId: args.sourceQuestionId,
952
+ rationale: args.rationale,
1827
953
  linkedBeliefNodeId: args.linkedBeliefNodeId,
1828
954
  evidenceRelation: args.evidenceRelation,
1829
955
  confidence: args.confidence,
@@ -1877,6 +1003,7 @@ var create = mutation({
1877
1003
  changedBy: args.userId,
1878
1004
  isAgent: false,
1879
1005
  projectId: scope.projectId,
1006
+ rationale: args.rationale,
1880
1007
  newState: {
1881
1008
  text: args.text.slice(0, 200),
1882
1009
  kind,
@@ -2076,7 +1203,15 @@ var getByProject = query({
2076
1203
  projectId: args.projectId,
2077
1204
  topicId: args.topicId
2078
1205
  });
2079
- } catch {
1206
+ } catch (error) {
1207
+ debugGraphPrimitiveFallback(
1208
+ "[epistemicEvidence] Failed to resolve getByProject scope",
1209
+ {
1210
+ error,
1211
+ projectId: args.projectId,
1212
+ topicId: args.topicId
1213
+ }
1214
+ );
2080
1215
  return [];
2081
1216
  }
2082
1217
  if (args.userId) {
@@ -2111,7 +1246,9 @@ var getByTopic = query({
2111
1246
  handler: async (ctx, args) => {
2112
1247
  const pageSize = clampEvidenceLimit(args.limit);
2113
1248
  const scanLimit = Math.min(pageSize * 3, MAX_EVIDENCE_PAGE_SIZE);
2114
- const scope = await resolveTopicProjectScope(ctx, { topicId: args.topicId });
1249
+ const scope = await resolveTopicProjectScope(ctx, {
1250
+ topicId: args.topicId
1251
+ });
2115
1252
  const topicNodes = await ctx.db.query("epistemicNodes").withIndex(
2116
1253
  "by_topic_type",
2117
1254
  (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
@@ -2221,7 +1358,9 @@ var internalGetByTopic = internalQuery({
2221
1358
  const pageSize = clampEvidenceLimit(args.limit, 500);
2222
1359
  const scanLimit = Math.min(pageSize * 3, MAX_EVIDENCE_PAGE_SIZE);
2223
1360
  const audienceMode = args.audienceMode ?? "internal";
2224
- const scope = await resolveTopicProjectScope(ctx, { topicId: args.topicId });
1361
+ const scope = await resolveTopicProjectScope(ctx, {
1362
+ topicId: args.topicId
1363
+ });
2225
1364
  const registryRows = await listAudienceRegistryRows(ctx, {
2226
1365
  tenantId: scope.tenantId,
2227
1366
  workspaceId: scope.workspaceId
@@ -2283,6 +1422,7 @@ var internalCreate = internalMutation({
2283
1422
  sourceUrl: v.optional(v.string()),
2284
1423
  sourceQuestionId: v.optional(v.string()),
2285
1424
  userId: v.string(),
1425
+ rationale: v.string(),
2286
1426
  linkedBeliefNodeId: v.optional(v.id("epistemicNodes")),
2287
1427
  evidenceRelation: v.optional(v.string()),
2288
1428
  confidence: v.optional(v.number()),
@@ -2346,6 +1486,7 @@ var internalCreate = internalMutation({
2346
1486
  externalSourceType: args.externalSourceType,
2347
1487
  sourceUrl: args.sourceUrl,
2348
1488
  sourceQuestionId: args.sourceQuestionId,
1489
+ rationale: args.rationale,
2349
1490
  linkedBeliefNodeId: args.linkedBeliefNodeId,
2350
1491
  evidenceRelation: args.evidenceRelation,
2351
1492
  confidence: args.confidence,
@@ -2360,6 +1501,7 @@ var internalCreate = internalMutation({
2360
1501
  changedBy: args.userId,
2361
1502
  isAgent: false,
2362
1503
  projectId: scope.projectId,
1504
+ rationale: args.rationale,
2363
1505
  newState: {
2364
1506
  text: args.text.slice(0, 200),
2365
1507
  kind,