@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,939 +1,51 @@
1
1
  import { v } from 'convex/values';
2
- import { componentsGeneric, mutationGeneric, anyApi, queryGeneric, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
2
+ import { checkProjectAccess, checkScopeAccess } from '@lucern/access-control/access';
3
+ import { normalizeAudienceKey, canAudienceClassAccess, classFromAudienceKey } from '@lucern/access-control/audience';
4
+ import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
5
+ import { getCurrentUserId } from '@lucern/access-control/auth';
6
+ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
7
+ import { componentsGeneric, anyApi, mutationGeneric, queryGeneric, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
8
+ import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
3
9
 
4
10
  // src/epistemicQuestions.ts
5
11
  var api = anyApi;
6
12
  componentsGeneric();
13
+ var internal = anyApi;
14
+ var internalMutation = internalMutationGeneric;
15
+ var internalQuery = internalQueryGeneric;
16
+ var mutation = mutationGeneric;
17
+ var query = queryGeneric;
7
18
 
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
- var checkProjectAccess = checkTopicAccess;
791
-
792
- // ../access-control/src/audience.ts
793
- var AUDIENCE_CLASS_RANK = {
794
- public: 0,
795
- restricted_external: 1,
796
- internal: 2
797
- };
798
- function normalizeKey(key) {
799
- return (key ?? "").trim().toLowerCase().replace(/[^a-z0-9:_-]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
19
+ // src/debug.ts
20
+ function isGraphPrimitiveDebugEnabled() {
21
+ const env = globalThis.process?.env;
22
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
800
23
  }
801
- function normalizeAudienceKey(key) {
802
- return normalizeKey(key);
803
- }
804
- function classFromAudienceKey(audienceKey, fallback = "internal") {
805
- const key = normalizeKey(audienceKey);
806
- if (!key) {
807
- return fallback;
24
+ function formatGraphPrimitiveError(error) {
25
+ if (error instanceof Error) {
26
+ return `${error.name}: ${error.message}`;
808
27
  }
809
- if (key === "internal") {
810
- return "internal";
28
+ if (typeof error === "string") {
29
+ return error;
811
30
  }
812
- if (key === "public") {
813
- return "public";
31
+ if (error === null) {
32
+ return "null";
814
33
  }
815
- if (key === "lp" || key === "external" || key === "client" || key === "partner" || key === "portfolio" || key === "network" || key === "restricted_external") {
816
- return "restricted_external";
817
- }
818
- return fallback;
819
- }
820
- function canAudienceClassAccess(viewerClass, resourceClass) {
821
- return AUDIENCE_CLASS_RANK[viewerClass] >= AUDIENCE_CLASS_RANK[resourceClass];
822
- }
823
-
824
- // ../access-control/src/audienceRegistry.ts
825
- var DEFAULT_AUDIENCES = [
826
- {
827
- audienceKey: "internal",
828
- audienceLabel: "Internal",
829
- audienceClass: "internal"
830
- },
831
- {
832
- audienceKey: "lp",
833
- audienceLabel: "Limited Partners",
834
- audienceClass: "restricted_external"
835
- },
836
- {
837
- audienceKey: "public",
838
- audienceLabel: "Public",
839
- audienceClass: "public"
34
+ if (error === void 0) {
35
+ return "undefined";
840
36
  }
841
- ];
842
- var AUDIENCE_CLASS_PRIORITY = {
843
- internal: 0,
844
- restricted_external: 1,
845
- public: 2
846
- };
847
- function normalizeRegistryRow(row) {
848
- return {
849
- audienceKey: normalizeAudienceKey(row.audienceKey),
850
- audienceLabel: row.audienceLabel,
851
- audienceClass: row.audienceClass,
852
- workspaceId: row.workspaceId
853
- };
854
- }
855
- function dedupeRegistryRows(rows) {
856
- const byKey = /* @__PURE__ */ new Map();
857
- for (const row of rows) {
858
- const key = normalizeAudienceKey(row.audienceKey);
859
- if (!key) {
860
- continue;
861
- }
862
- const existing = byKey.get(key);
863
- const isWorkspaceScoped = row.workspaceId !== void 0;
864
- const existingWorkspaceScoped = existing?.workspaceId !== void 0;
865
- if (!existing || isWorkspaceScoped && !existingWorkspaceScoped) {
866
- byKey.set(key, {
867
- ...row,
868
- audienceKey: key
869
- });
870
- }
37
+ try {
38
+ return JSON.stringify(error);
39
+ } catch {
40
+ return Object.prototype.toString.call(error);
871
41
  }
872
- const normalized = [...byKey.values()];
873
- normalized.sort((a, b) => {
874
- const classDelta = AUDIENCE_CLASS_PRIORITY[a.audienceClass] - AUDIENCE_CLASS_PRIORITY[b.audienceClass];
875
- if (classDelta !== 0) {
876
- return classDelta;
877
- }
878
- return a.audienceKey.localeCompare(b.audienceKey);
879
- });
880
- return normalized;
881
42
  }
882
- async function queryRegistryRows(ctx, args) {
883
- if (!args.tenantId) {
884
- return [...DEFAULT_AUDIENCES];
43
+ function debugGraphPrimitiveFallback(message, context) {
44
+ if (!isGraphPrimitiveDebugEnabled()) {
45
+ return;
885
46
  }
886
- const rows = await ctx.db.query("platformAudiences").withIndex("by_tenantId", (q) => q.eq("tenantId", args.tenantId)).collect();
887
- const workspaceIdString = args.workspaceId ? String(args.workspaceId) : null;
888
- const tenantScoped = rows.filter((row) => row.status === "active");
889
- const applicable = tenantScoped.filter((row) => {
890
- if (!row.workspaceId) {
891
- return true;
892
- }
893
- if (!workspaceIdString) {
894
- return false;
895
- }
896
- return String(row.workspaceId) === workspaceIdString;
897
- });
898
- return dedupeRegistryRows([
899
- ...DEFAULT_AUDIENCES,
900
- ...applicable.map(
901
- (row) => normalizeRegistryRow({
902
- audienceKey: row.audienceKey,
903
- audienceLabel: row.audienceLabel,
904
- audienceClass: row.audienceClass,
905
- workspaceId: row.workspaceId
906
- })
907
- )
908
- ]);
909
- }
910
- async function listAudienceRegistryRows(ctx, args) {
911
- return queryRegistryRows(ctx, args);
912
- }
913
-
914
- // ../access-control/src/auth.ts
915
- async function getCurrentUserId(ctx) {
916
- const identity = await ctx.auth.getUserIdentity();
917
- return identity?.subject ?? null;
47
+ console.debug(message, context ?? {});
918
48
  }
919
- var permissiveReturn = v.optional(v.any());
920
- var looseJsonObject = v.record(v.string(), v.any());
921
- var looseJsonArray = v.array(v.any());
922
- v.union(
923
- v.string(),
924
- v.number(),
925
- v.boolean(),
926
- v.null(),
927
- looseJsonObject,
928
- looseJsonArray
929
- );
930
- var api2 = anyApi;
931
- componentsGeneric();
932
- var internal = anyApi;
933
- var internalMutation = internalMutationGeneric;
934
- var internalQuery = internalQueryGeneric;
935
- var mutation = mutationGeneric;
936
- var query = queryGeneric;
937
49
 
938
50
  // src/embeddingTrigger.ts
939
51
  async function scheduleEmbeddingGeneration(args) {
@@ -952,7 +64,15 @@ async function scheduleEmbeddingGeneration(args) {
952
64
  confidence: args.confidence
953
65
  }
954
66
  );
955
- } catch {
67
+ } catch (error) {
68
+ debugGraphPrimitiveFallback(
69
+ "[embeddingTrigger] Failed to schedule embedding generation",
70
+ {
71
+ error,
72
+ nodeId: String(args.nodeId),
73
+ nodeType: args.nodeType
74
+ }
75
+ );
956
76
  }
957
77
  }
958
78
 
@@ -969,96 +89,125 @@ function generateGlobalId() {
969
89
  }
970
90
 
971
91
  // src/topicProjectOverlay.ts
972
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
973
- function readNonEmptyString2(value) {
92
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
93
+ function readNonEmptyString(value) {
974
94
  if (typeof value !== "string") {
975
95
  return;
976
96
  }
977
97
  const normalized = value.trim();
978
98
  return normalized.length > 0 ? normalized : void 0;
979
99
  }
980
- function readStringArray2(value) {
100
+ function readStringArray(value) {
981
101
  if (!Array.isArray(value)) {
982
102
  return [];
983
103
  }
984
- return value.map((entry) => readNonEmptyString2(entry)).filter((entry) => Boolean(entry));
104
+ return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
985
105
  }
986
- function readMetadata2(topic) {
106
+ function readMetadata(topic) {
987
107
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
988
108
  }
989
- function readLegacyProjectId2(value) {
109
+ function readLegacyProjectId(value) {
990
110
  if (!value) {
991
111
  return;
992
112
  }
993
- return readNonEmptyString2(value[LEGACY_SCOPE_FIELD2]);
113
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
994
114
  }
995
- function coerceVisibility2(value) {
115
+ function coerceVisibility(value) {
996
116
  return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
997
117
  }
998
- function coerceStatus2(value) {
118
+ function coerceStatus(value) {
999
119
  return value === "active" || value === "archived" || value === "watching" ? value : void 0;
1000
120
  }
1001
- function mapProjectType2(topic, metadata) {
1002
- const explicit = readNonEmptyString2(metadata.projectType);
121
+ function mapProjectType(topic, metadata) {
122
+ const explicit = readNonEmptyString(metadata.projectType);
1003
123
  if (explicit) {
1004
124
  return explicit;
1005
125
  }
1006
126
  if (topic.type === "theme") {
1007
127
  return "thematic";
1008
128
  }
1009
- return readNonEmptyString2(topic.type) || "general";
129
+ return readNonEmptyString(topic.type) || "general";
1010
130
  }
1011
- function isProjectLikeTopic2(topic) {
1012
- const metadata = readMetadata2(topic);
1013
- return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId2(topic) !== void 0 || readNonEmptyString2(metadata.projectType) !== void 0;
131
+ function isProjectLikeTopic(topic) {
132
+ const metadata = readMetadata(topic);
133
+ return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
1014
134
  }
1015
135
  function isMissingLucernChildComponentError(error) {
1016
- const message = error instanceof Error ? error.message : String(error);
136
+ const message = getErrorMessage(error);
1017
137
  return message.includes(
1018
138
  'Child component ComponentName(Identifier("lucern")) not found'
1019
139
  ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
1020
140
  }
1021
- async function resolveTopicDoc2(ctx, scopeId) {
141
+ function getErrorMessage(error) {
142
+ if (error instanceof Error) {
143
+ return error.message;
144
+ }
145
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
146
+ return error.message;
147
+ }
148
+ return "unknown error";
149
+ }
150
+ async function resolveTopicDoc(ctx, scopeId) {
1022
151
  if (ctx?.db && typeof ctx.db.get === "function") {
1023
152
  try {
1024
- const directTopic = await ctx.db.get(scopeId);
153
+ const directTopic = await ctx.db.get(
154
+ scopeId
155
+ );
1025
156
  if (directTopic) {
1026
157
  return directTopic;
1027
158
  }
1028
- } catch {
159
+ } catch (error) {
160
+ debugGraphPrimitiveFallback(
161
+ "[topicProjectOverlay] Failed to resolve topic by direct ID",
162
+ {
163
+ error,
164
+ scopeId
165
+ }
166
+ );
1029
167
  }
1030
168
  }
1031
169
  if (typeof ctx.runQuery !== "function") {
1032
170
  return null;
1033
171
  }
1034
172
  try {
1035
- const topic = await ctx.runQuery(api2.topics.get, {
173
+ const topic = await ctx.runQuery(api.topics.get, {
1036
174
  id: String(scopeId)
1037
175
  });
1038
176
  if (topic?.name !== void 0 && topic?.type !== void 0) {
1039
177
  return topic;
1040
178
  }
1041
- } catch {
179
+ } catch (error) {
180
+ debugGraphPrimitiveFallback(
181
+ "[topicProjectOverlay] Failed to resolve topic by ID query",
182
+ {
183
+ error,
184
+ scopeId
185
+ }
186
+ );
1042
187
  }
1043
188
  try {
1044
- const topic = await ctx.runQuery(api2.topics.getByLegacyScopeId, {
189
+ const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
1045
190
  projectId: String(scopeId)
1046
191
  });
1047
192
  if (topic?.name !== void 0 && topic?.type !== void 0) {
1048
193
  return topic;
1049
194
  }
1050
- } catch {
195
+ } catch (error) {
196
+ debugGraphPrimitiveFallback(
197
+ "[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
198
+ { error, scopeId }
199
+ );
1051
200
  }
1052
201
  return null;
1053
202
  }
1054
- function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1055
- const metadata = readMetadata2(topic);
203
+ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
204
+ const metadata = readMetadata(topic);
1056
205
  const topicId = String(topic._id);
1057
- const legacyProjectId = readLegacyProjectId2(topic) || readLegacyProjectId2(metadata) || readNonEmptyString2(metadata.legacyProjectId);
206
+ const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
1058
207
  const storageProjectId = legacyProjectId || topicId;
1059
208
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
1060
- const visibility = coerceVisibility2(topic.visibility) || coerceVisibility2(metadata.visibility) || "private";
1061
- const status = coerceStatus2(topic.status) || coerceStatus2(metadata.status) || "active";
209
+ const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
210
+ const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
1062
211
  const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
1063
212
  const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
1064
213
  return {
@@ -1068,16 +217,16 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1068
217
  topicId,
1069
218
  storageProjectId,
1070
219
  legacyProjectId,
1071
- name: readNonEmptyString2(topic.name) || "Untitled Theme",
1072
- type: mapProjectType2(topic, metadata),
1073
- description: readNonEmptyString2(topic.description),
1074
- ownerId: readNonEmptyString2(metadata.ownerId) || readNonEmptyString2(topic.createdBy) || "system",
1075
- sharedWith: readStringArray2(metadata.sharedWith),
220
+ name: readNonEmptyString(topic.name) || "Untitled Theme",
221
+ type: mapProjectType(topic, metadata),
222
+ description: readNonEmptyString(topic.description),
223
+ ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
224
+ sharedWith: readStringArray(metadata.sharedWith),
1076
225
  visibility,
1077
- tenantId: readNonEmptyString2(topic.tenantId) || readNonEmptyString2(metadata.tenantId),
1078
- workspaceId: readNonEmptyString2(topic.workspaceId) || readNonEmptyString2(metadata.workspaceId),
226
+ tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
227
+ workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
1079
228
  status,
1080
- tags: readStringArray2(metadata.tags),
229
+ tags: readStringArray(metadata.tags),
1081
230
  chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
1082
231
  artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
1083
232
  lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
@@ -1086,38 +235,42 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1086
235
  updatedAt
1087
236
  };
1088
237
  }
1089
- async function resolveTopicProjectOverlay2(ctx, scopeId, options = {}) {
1090
- const topic = await resolveTopicDoc2(ctx, scopeId);
238
+ async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
239
+ const topic = await resolveTopicDoc(ctx, scopeId);
1091
240
  if (!topic) {
1092
241
  return null;
1093
242
  }
1094
- if (options.projectLikeOnly !== false && !isProjectLikeTopic2(topic)) {
243
+ if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
1095
244
  return null;
1096
245
  }
1097
- return materializeTopicProjectOverlay2(topic, options.idMode);
246
+ return materializeTopicProjectOverlay(topic, options.idMode);
1098
247
  }
1099
- async function listTopicProjectOverlays2(ctx, options = {}) {
248
+ async function listTopicProjectOverlays(ctx, options = {}) {
1100
249
  let allTopics = [];
1101
250
  if (ctx?.db?.query && typeof ctx.db.query === "function") {
1102
251
  try {
1103
252
  allTopics = await ctx.db.query("topics").collect();
1104
- } catch {
253
+ } catch (error) {
254
+ debugGraphPrimitiveFallback(
255
+ "[topicProjectOverlay] Failed to read topics table; falling back to API",
256
+ { error }
257
+ );
1105
258
  allTopics = [];
1106
259
  }
1107
260
  }
1108
261
  if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
1109
- allTopics = (await ctx.runQuery(api2.topics.list, {}) ?? []) || [];
262
+ allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
1110
263
  }
1111
264
  return allTopics.filter(
1112
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic2(topic)
1113
- ).map((topic) => materializeTopicProjectOverlay2(topic, options.idMode));
265
+ (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
266
+ ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
1114
267
  }
1115
268
  async function patchTopicProjectOverlay(ctx, scopeId, value) {
1116
- const topic = await resolveTopicDoc2(ctx, scopeId);
269
+ const topic = await resolveTopicDoc(ctx, scopeId);
1117
270
  if (!topic) {
1118
271
  return null;
1119
272
  }
1120
- const nextMetadata = { ...readMetadata2(topic) };
273
+ const nextMetadata = { ...readMetadata(topic) };
1121
274
  const patch = {};
1122
275
  const topicUpdateArgs = {
1123
276
  id: String(topic._id)
@@ -1142,7 +295,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1142
295
  `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
1143
296
  );
1144
297
  case "status": {
1145
- const status = coerceStatus2(rawValue);
298
+ const status = coerceStatus(rawValue);
1146
299
  if (status) {
1147
300
  patch.status = status;
1148
301
  topicUpdateArgs.status = status;
@@ -1150,7 +303,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1150
303
  break;
1151
304
  }
1152
305
  case "visibility": {
1153
- const visibility = coerceVisibility2(rawValue);
306
+ const visibility = coerceVisibility(rawValue);
1154
307
  if (visibility) {
1155
308
  patch.visibility = visibility;
1156
309
  topicUpdateArgs.visibility = visibility;
@@ -1158,7 +311,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1158
311
  break;
1159
312
  }
1160
313
  case "type": {
1161
- const projectType = readNonEmptyString2(rawValue);
314
+ const projectType = readNonEmptyString(rawValue);
1162
315
  if (projectType) {
1163
316
  nextMetadata.projectType = projectType;
1164
317
  } else {
@@ -1182,7 +335,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1182
335
  topicUpdateArgs.metadata = nextMetadata;
1183
336
  if (typeof ctx.runMutation === "function") {
1184
337
  try {
1185
- await ctx.runMutation(api2.topics.update, topicUpdateArgs);
338
+ await ctx.runMutation(api.topics.update, topicUpdateArgs);
1186
339
  } catch (error) {
1187
340
  if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
1188
341
  throw error;
@@ -1196,19 +349,28 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1196
349
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
1197
350
  );
1198
351
  }
1199
- return materializeTopicProjectOverlay2(
1200
- {
1201
- ...topic,
1202
- ...patch,
1203
- metadata: nextMetadata
1204
- }
1205
- );
352
+ return materializeTopicProjectOverlay({
353
+ ...topic,
354
+ ...patch,
355
+ metadata: nextMetadata
356
+ });
1206
357
  }
1207
358
 
1208
359
  // src/resolvers.ts
1209
360
  function isMissingLucernChildComponentError2(error) {
1210
- const message = error instanceof Error ? error.message : String(error);
1211
- return message.includes('Child component ComponentName(Identifier("lucern")) not found') || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
361
+ const message = getErrorMessage2(error);
362
+ return message.includes(
363
+ 'Child component ComponentName(Identifier("lucern")) not found'
364
+ ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
365
+ }
366
+ function getErrorMessage2(error) {
367
+ if (error instanceof Error) {
368
+ return error.message;
369
+ }
370
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
371
+ return error.message;
372
+ }
373
+ return "unknown error";
1212
374
  }
1213
375
  function isAdvisoryTopicPatch(value) {
1214
376
  const advisoryKeys = /* @__PURE__ */ new Set(["lastActivityAt", "updatedAt"]);
@@ -1222,52 +384,47 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
1222
384
  if (!isAdvisoryTopicPatch(value) || !isMissingLucernChildComponentError2(error)) {
1223
385
  throw error;
1224
386
  }
1225
- console.warn("[lucern graph-primitives] Non-fatal advisory topic patch failure", {
1226
- projectId,
1227
- keys: Object.keys(value),
1228
- error: error instanceof Error ? error.message : error
1229
- });
387
+ console.warn(
388
+ "[lucern graph-primitives] Non-fatal advisory topic patch failure",
389
+ {
390
+ projectId,
391
+ keys: Object.keys(value),
392
+ error: getErrorMessage2(error)
393
+ }
394
+ );
1230
395
  }
1231
396
  }
1232
- function defaultResolvers2() {
397
+ function defaultResolvers() {
1233
398
  return {
1234
- async getProject(ctx, projectId) {
1235
- return await resolveTopicProjectOverlay2(ctx, projectId, {
1236
- idMode: "legacy",
1237
- projectLikeOnly: false
1238
- });
1239
- },
1240
- async patchProject(ctx, projectId, value) {
1241
- await patchProjectWithTolerance(ctx, projectId, value);
1242
- },
1243
- async listTopics(ctx) {
1244
- return await listTopicProjectOverlays2(ctx, {
1245
- idMode: "legacy"
1246
- });
1247
- },
1248
- async getFinalArtifact(ctx, artifactId) {
1249
- return await ctx.db.get(artifactId);
1250
- }
399
+ getProject: (ctx, projectId) => resolveTopicProjectOverlay(ctx, projectId, {
400
+ idMode: "legacy",
401
+ projectLikeOnly: false
402
+ }),
403
+ patchProject: (ctx, projectId, value) => patchProjectWithTolerance(ctx, projectId, value),
404
+ listTopics: (ctx) => listTopicProjectOverlays(ctx, {
405
+ idMode: "legacy"
406
+ }),
407
+ getFinalArtifact: (ctx, artifactId) => ctx.db.get(artifactId)
1251
408
  };
1252
409
  }
1253
- var resolverOverrides2 = {};
410
+ var resolverOverrides = {};
1254
411
  function resolveGraphPrimitivesAppResolvers(_ctx) {
1255
412
  return {
1256
- ...defaultResolvers2(),
1257
- ...resolverOverrides2
413
+ ...defaultResolvers(),
414
+ ...resolverOverrides
1258
415
  };
1259
416
  }
1260
- var LEGACY_SCOPE_FIELD3 = "graphScopeProjectId";
417
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
1261
418
  function asMappedProjectId(topic) {
1262
419
  if (!topic) {
1263
420
  return;
1264
421
  }
1265
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD3]);
422
+ const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD2]);
1266
423
  if (directLegacyProjectId) {
1267
424
  return directLegacyProjectId;
1268
425
  }
1269
426
  const metadata = topic.metadata || {};
1270
- const candidate = metadata[LEGACY_SCOPE_FIELD3] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
427
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
1271
428
  return candidate ? candidate : void 0;
1272
429
  }
1273
430
  function normalizeScopeValue(value) {
@@ -1296,9 +453,16 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
1296
453
  try {
1297
454
  return await ctx.db.query("topics").withIndex(
1298
455
  "by_graph_scope_project",
1299
- (q) => q.eq(LEGACY_SCOPE_FIELD3, scopeId)
456
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
1300
457
  ).collect();
1301
- } catch {
458
+ } catch (error) {
459
+ debugGraphPrimitiveFallback(
460
+ "[topicScope] Failed to resolve scope alias via index",
461
+ {
462
+ error,
463
+ scopeId
464
+ }
465
+ );
1302
466
  const topics = await ctx.db.query("topics").collect();
1303
467
  return topics.filter((topic) => {
1304
468
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
@@ -1312,10 +476,17 @@ async function tryResolveHostTopicById(ctx, topicId) {
1312
476
  return null;
1313
477
  }
1314
478
  try {
1315
- return await ctx.runQuery(api2.topics.get, {
479
+ return await ctx.runQuery(api.topics.get, {
1316
480
  id: topicId
1317
481
  }) ?? null;
1318
- } catch {
482
+ } catch (error) {
483
+ debugGraphPrimitiveFallback(
484
+ "[topicScope] Failed to resolve topic by host query",
485
+ {
486
+ error,
487
+ topicId
488
+ }
489
+ );
1319
490
  return null;
1320
491
  }
1321
492
  }
@@ -1324,10 +495,17 @@ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
1324
495
  return null;
1325
496
  }
1326
497
  try {
1327
- return await ctx.runQuery(api2.topics.getByLegacyScopeId, {
498
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
1328
499
  projectId: legacyScopeId
1329
500
  }) ?? null;
1330
- } catch {
501
+ } catch (error) {
502
+ debugGraphPrimitiveFallback(
503
+ "[topicScope] Failed to resolve topic by legacy scope",
504
+ {
505
+ error,
506
+ legacyScopeId
507
+ }
508
+ );
1331
509
  return null;
1332
510
  }
1333
511
  }
@@ -1356,8 +534,17 @@ async function resolveTopicProjectScope(ctx, args) {
1356
534
  if (args.topicId) {
1357
535
  let topic = null;
1358
536
  try {
1359
- topic = await ctx.db.get(args.topicId);
1360
- } catch {
537
+ topic = await ctx.db.get(
538
+ args.topicId
539
+ );
540
+ } catch (error) {
541
+ debugGraphPrimitiveFallback(
542
+ "[topicScope] Failed to load topic by direct id",
543
+ {
544
+ error,
545
+ topicId: args.topicId
546
+ }
547
+ );
1361
548
  }
1362
549
  if (!topic) {
1363
550
  topic = await tryResolveHostTopicById(ctx, String(args.topicId));
@@ -1394,7 +581,14 @@ async function resolveTopicProjectScope(ctx, args) {
1394
581
  directTopic = await ctx.db.get(
1395
582
  args.projectId
1396
583
  );
1397
- } catch {
584
+ } catch (error) {
585
+ debugGraphPrimitiveFallback(
586
+ "[topicScope] Failed to load direct project topic",
587
+ {
588
+ error,
589
+ projectId: args.projectId
590
+ }
591
+ );
1398
592
  }
1399
593
  if (directTopic) {
1400
594
  const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
@@ -1443,61 +637,6 @@ var optionalScopeArgs = {
1443
637
  projectId: v.optional(v.string()),
1444
638
  topicId: v.optional(v.string())
1445
639
  };
1446
-
1447
- // ../../packages/contracts/src/schema-helpers/spine/tables/epistemicNodes.ts
1448
- var NODE_TYPES = [
1449
- "decision",
1450
- "belief",
1451
- "question",
1452
- "theme",
1453
- "deal",
1454
- "topic",
1455
- "claim",
1456
- "evidence",
1457
- "synthesis",
1458
- "answer",
1459
- "atomic_fact",
1460
- "excerpt",
1461
- "source",
1462
- "company",
1463
- "person",
1464
- "investor",
1465
- "function",
1466
- "value_chain"
1467
- ];
1468
- function isNodeType(value) {
1469
- return NODE_TYPES.includes(value);
1470
- }
1471
- function getLayerForNodeType(type) {
1472
- switch (type) {
1473
- case "decision":
1474
- return "L4";
1475
- case "belief":
1476
- case "question":
1477
- case "theme":
1478
- case "deal":
1479
- return "L3";
1480
- case "claim":
1481
- case "evidence":
1482
- case "synthesis":
1483
- case "answer":
1484
- return "L2";
1485
- case "atomic_fact":
1486
- case "excerpt":
1487
- case "source":
1488
- return "L1";
1489
- case "topic":
1490
- return "organizational";
1491
- case "company":
1492
- case "person":
1493
- case "investor":
1494
- case "function":
1495
- case "value_chain":
1496
- return "ontological";
1497
- }
1498
- }
1499
-
1500
- // src/workspaceIsolation.ts
1501
640
  function normalizeScopeValue2(value) {
1502
641
  if (typeof value !== "string") {
1503
642
  return;
@@ -1631,38 +770,7 @@ function assertTenantPackWorkspaceMutationAllowed(args) {
1631
770
  });
1632
771
  }
1633
772
 
1634
- // ../worktrees/src/v1/engine/scopeBridge.ts
1635
- function normalizeString2(value) {
1636
- if (typeof value !== "string") {
1637
- return void 0;
1638
- }
1639
- const trimmed = value.trim();
1640
- return trimmed.length > 0 ? trimmed : void 0;
1641
- }
1642
- function requireScopeId(...ids) {
1643
- for (const id of ids) {
1644
- const normalized = normalizeString2(id);
1645
- if (normalized) {
1646
- return normalized;
1647
- }
1648
- }
1649
- throw new Error("No scope identifier provided (topicId or projectId required)");
1650
- }
1651
- async function resolveTopicProjectScope2(ctx, args) {
1652
- const resolved = await resolveTopicProjectScope(ctx, {
1653
- topicId: normalizeString2(args.topicId),
1654
- projectId: normalizeString2(args.projectId)
1655
- });
1656
- const topicId = normalizeString2(resolved.topicId);
1657
- const projectId = requireScopeId(
1658
- resolved.projectId,
1659
- args.projectId,
1660
- topicId
1661
- );
1662
- return { projectId, ...topicId ? { topicId } : {} };
1663
- }
1664
-
1665
- // ../worktrees/src/v1/engine/worktreeWorkflowBridge.ts
773
+ // src/workflowBridge.ts
1666
774
  function isLegacySprintDoc(doc) {
1667
775
  if (!doc || typeof doc !== "object") {
1668
776
  return false;
@@ -1688,7 +796,7 @@ async function findPairedWorktreeForSprint(ctx, sprint) {
1688
796
  let topicId = getStringField(sprint, "topicId");
1689
797
  if (!topicId) {
1690
798
  try {
1691
- const scope = await resolveTopicProjectScope2(ctx, {
799
+ const scope = await resolveTopicProjectScope(ctx, {
1692
800
  topicId: getStringField(sprint, "topicId"),
1693
801
  projectId: getStringField(sprint, "projectId")
1694
802
  });
@@ -1855,6 +963,12 @@ function normalizeQuestionTopicId(topicId) {
1855
963
  function resolveQuestionScopeId(scope) {
1856
964
  return normalizeQuestionTopicId(scope.topicId) ?? scope.projectId ?? void 0;
1857
965
  }
966
+ function logQuestionFallback(message, error, context) {
967
+ debugGraphPrimitiveFallback(message, {
968
+ error: formatGraphPrimitiveError(error),
969
+ ...context ?? {}
970
+ });
971
+ }
1858
972
  async function resolveQuestionScopeOrNull(ctx, args) {
1859
973
  if (!args.projectId && !args.topicId) {
1860
974
  return null;
@@ -1864,7 +978,15 @@ async function resolveQuestionScopeOrNull(ctx, args) {
1864
978
  projectId: args.projectId ?? void 0,
1865
979
  topicId: args.topicId ?? void 0
1866
980
  });
1867
- } catch {
981
+ } catch (error) {
982
+ debugGraphPrimitiveFallback(
983
+ "[epistemicQuestions] Failed to resolve question scope",
984
+ {
985
+ error: formatGraphPrimitiveError(error),
986
+ projectId: args.projectId,
987
+ topicId: args.topicId
988
+ }
989
+ );
1868
990
  return null;
1869
991
  }
1870
992
  }
@@ -2068,9 +1190,7 @@ var create = mutation({
2068
1190
  source: args.source || "ai_suggested",
2069
1191
  questionStatus: "open",
2070
1192
  linkedBeliefNodeId: args.linkedBeliefNodeId,
2071
- ...buildLinkedWorktreeMetadata(
2072
- args.linkedWorktreeId
2073
- ),
1193
+ ...buildLinkedWorktreeMetadata(args.linkedWorktreeId),
2074
1194
  testType: args.testType,
2075
1195
  importance: args.importance,
2076
1196
  epistemicUnlock: args.epistemicUnlock,
@@ -2481,7 +1601,9 @@ var getByTopic = query({
2481
1601
  handler: async (ctx, args) => {
2482
1602
  const pageSize = clampQuestionLimit(args.limit);
2483
1603
  const scanLimit = Math.min(pageSize * 3, MAX_QUESTION_PAGE_SIZE);
2484
- const scope = await resolveTopicProjectScope(ctx, { topicId: args.topicId });
1604
+ const scope = await resolveTopicProjectScope(ctx, {
1605
+ topicId: args.topicId
1606
+ });
2485
1607
  const scopedNodes = await getQuestionNodesForScope(ctx, scope, {
2486
1608
  scanLimit
2487
1609
  });
@@ -2505,7 +1627,7 @@ var getByCategory = query({
2505
1627
  const nodes = await getQuestionNodesForScope(ctx, scope);
2506
1628
  return nodes.filter((n) => {
2507
1629
  const metadata = n.metadata || {};
2508
- return questionMatchesScope(n, scope) && (isActiveQuestionNode(n) && metadata.category === normalizeCategory(args.category));
1630
+ return questionMatchesScope(n, scope) && isActiveQuestionNode(n) && metadata.category === normalizeCategory(args.category);
2509
1631
  });
2510
1632
  }
2511
1633
  });
@@ -2601,7 +1723,9 @@ var internalGetByTopic = internalQuery({
2601
1723
  const pageSize = clampQuestionLimit(args.limit, 500);
2602
1724
  const scanLimit = Math.min(pageSize * 3, MAX_QUESTION_PAGE_SIZE);
2603
1725
  const audienceMode = args.audienceMode ?? "internal";
2604
- const scope = await resolveTopicProjectScope(ctx, { topicId: args.topicId });
1726
+ const scope = await resolveTopicProjectScope(ctx, {
1727
+ topicId: args.topicId
1728
+ });
2605
1729
  const registryRows = await listAudienceRegistryRows(ctx, {
2606
1730
  tenantId: scope.tenantId,
2607
1731
  workspaceId: scope.workspaceId
@@ -2931,7 +2055,14 @@ A: ${args.answerText}`;
2931
2055
  if (node?.nodeType === "belief") {
2932
2056
  return node;
2933
2057
  }
2934
- } catch {
2058
+ } catch (error) {
2059
+ debugGraphPrimitiveFallback(
2060
+ "[epistemicQuestions] Failed to resolve belief node",
2061
+ {
2062
+ error: formatGraphPrimitiveError(error),
2063
+ beliefId: bId
2064
+ }
2065
+ );
2935
2066
  return null;
2936
2067
  }
2937
2068
  return null;
@@ -3337,7 +2468,14 @@ var getInConviction = query({
3337
2468
  exclusiveWithCount: 0
3338
2469
  };
3339
2470
  }
3340
- } catch {
2471
+ } catch (error) {
2472
+ debugGraphPrimitiveFallback(
2473
+ "[epistemicQuestions] Failed to hydrate linked belief",
2474
+ {
2475
+ error: formatGraphPrimitiveError(error),
2476
+ beliefId
2477
+ }
2478
+ );
3341
2479
  }
3342
2480
  return null;
3343
2481
  })
@@ -3435,6 +2573,14 @@ var advanceToConviction = mutation({
3435
2573
  triggeringAction: "question_advanced_to_conviction"
3436
2574
  });
3437
2575
  } catch (e) {
2576
+ logQuestionFallback(
2577
+ "[epistemicQuestions] Failed to log advanceToConviction audit",
2578
+ e,
2579
+ {
2580
+ questionId: args.questionId,
2581
+ projectId: node.projectId
2582
+ }
2583
+ );
3438
2584
  console.error("[EpistemicAudit] Failed to log advanceToConviction:", e);
3439
2585
  }
3440
2586
  await markProjectGraphDirty(ctx, node.projectId, node.topicId);
@@ -3561,6 +2707,14 @@ var finalizeConviction = mutation({
3561
2707
  triggeringAction: "question_conviction_finalized"
3562
2708
  });
3563
2709
  } catch (e) {
2710
+ logQuestionFallback(
2711
+ "[epistemicQuestions] Failed to log finalizeConviction audit",
2712
+ e,
2713
+ {
2714
+ questionId: args.questionId,
2715
+ projectId: node.projectId
2716
+ }
2717
+ );
3564
2718
  console.error("[EpistemicAudit] Failed to log finalizeConviction:", e);
3565
2719
  }
3566
2720
  if (node.projectId || node.topicId) {
@@ -3584,6 +2738,15 @@ var finalizeConviction = mutation({
3584
2738
  }
3585
2739
  );
3586
2740
  } catch (e) {
2741
+ logQuestionFallback(
2742
+ "[epistemicQuestions] Failed to schedule evidence creation from scored question",
2743
+ e,
2744
+ {
2745
+ questionId: args.questionId,
2746
+ beliefId,
2747
+ projectId: node.projectId
2748
+ }
2749
+ );
3587
2750
  console.error(
3588
2751
  "[finalizeConviction] Failed to schedule evidence creation:",
3589
2752
  e
@@ -3613,10 +2776,24 @@ var getByBeliefWithAccess = query({
3613
2776
  let beliefNode = null;
3614
2777
  try {
3615
2778
  beliefNode = await ctx.db.get(args.beliefId);
3616
- } catch {
2779
+ } catch (error) {
2780
+ debugGraphPrimitiveFallback(
2781
+ "[epistemicQuestions] Failed to resolve belief node directly",
2782
+ {
2783
+ error: formatGraphPrimitiveError(error),
2784
+ beliefId: args.beliefId
2785
+ }
2786
+ );
3617
2787
  try {
3618
2788
  beliefNode = await ctx.db.get(args.beliefId);
3619
- } catch {
2789
+ } catch (legacyError) {
2790
+ debugGraphPrimitiveFallback(
2791
+ "[epistemicQuestions] Failed to resolve legacy belief node",
2792
+ {
2793
+ error: formatGraphPrimitiveError(legacyError),
2794
+ beliefId: args.beliefId
2795
+ }
2796
+ );
3620
2797
  return [];
3621
2798
  }
3622
2799
  }
@@ -3760,10 +2937,24 @@ var linkToBelief = mutation({
3760
2937
  let beliefNode = null;
3761
2938
  try {
3762
2939
  beliefNode = await ctx.db.get(args.beliefId);
3763
- } catch {
2940
+ } catch (error) {
2941
+ debugGraphPrimitiveFallback(
2942
+ "[epistemicQuestions] Failed to resolve belief node directly",
2943
+ {
2944
+ error: formatGraphPrimitiveError(error),
2945
+ beliefId: args.beliefId
2946
+ }
2947
+ );
3764
2948
  try {
3765
2949
  beliefNode = await ctx.db.get(args.beliefId);
3766
- } catch {
2950
+ } catch (legacyError) {
2951
+ debugGraphPrimitiveFallback(
2952
+ "[epistemicQuestions] Failed to resolve legacy belief node",
2953
+ {
2954
+ error: formatGraphPrimitiveError(legacyError),
2955
+ beliefId: args.beliefId
2956
+ }
2957
+ );
3767
2958
  throw new Error("Belief not found");
3768
2959
  }
3769
2960
  }
@@ -3824,6 +3015,14 @@ var linkToBelief = mutation({
3824
3015
  });
3825
3016
  }
3826
3017
  } catch (e) {
3018
+ logQuestionFallback(
3019
+ "[epistemicQuestions] Failed to create tests edge",
3020
+ e,
3021
+ {
3022
+ questionId: args.questionId,
3023
+ beliefId: args.beliefId
3024
+ }
3025
+ );
3827
3026
  console.error("[linkToBelief] Failed to create tests edge:", e);
3828
3027
  }
3829
3028
  await markProjectGraphDirty(
@@ -3962,6 +3161,14 @@ var unlinkInsight = mutation({
3962
3161
  }
3963
3162
  }
3964
3163
  } catch (e) {
3164
+ logQuestionFallback(
3165
+ "[epistemicQuestions] Failed to remove questionEvidenceLink",
3166
+ e,
3167
+ {
3168
+ questionId: args.questionId,
3169
+ insightId: args.insightId
3170
+ }
3171
+ );
3965
3172
  console.error(
3966
3173
  "[unlinkInsight] Failed to remove questionEvidenceLink:",
3967
3174
  e
@@ -3984,6 +3191,14 @@ var unlinkInsight = mutation({
3984
3191
  }
3985
3192
  }
3986
3193
  } catch (e) {
3194
+ logQuestionFallback(
3195
+ "[epistemicQuestions] Failed to remove derived edge",
3196
+ e,
3197
+ {
3198
+ questionId: args.questionId,
3199
+ insightId: args.insightId
3200
+ }
3201
+ );
3987
3202
  console.error("[unlinkInsight] Failed to remove edge:", e);
3988
3203
  }
3989
3204
  await markProjectGraphDirty(
@@ -4154,7 +3369,14 @@ var consolidate = mutation({
4154
3369
  args.questionIds.map(async (qid) => {
4155
3370
  try {
4156
3371
  return await ctx.db.get(qid);
4157
- } catch {
3372
+ } catch (error) {
3373
+ debugGraphPrimitiveFallback(
3374
+ "[epistemicQuestions] Failed to load original question",
3375
+ {
3376
+ error: formatGraphPrimitiveError(error),
3377
+ questionId: qid
3378
+ }
3379
+ );
4158
3380
  return null;
4159
3381
  }
4160
3382
  })
@@ -4215,7 +3437,14 @@ var consolidate = mutation({
4215
3437
  const bMeta = belief.metadata || {};
4216
3438
  category = bMeta.category || bMeta.pillar || "other";
4217
3439
  }
4218
- } catch {
3440
+ } catch (error) {
3441
+ debugGraphPrimitiveFallback(
3442
+ "[epistemicQuestions] Failed to read first linked belief metadata",
3443
+ {
3444
+ error: formatGraphPrimitiveError(error),
3445
+ beliefId: firstBeliefId
3446
+ }
3447
+ );
4219
3448
  }
4220
3449
  }
4221
3450
  const now = Date.now();
@@ -4265,7 +3494,14 @@ var consolidate = mutation({
4265
3494
  }
4266
3495
  });
4267
3496
  }
4268
- } catch {
3497
+ } catch (error) {
3498
+ debugGraphPrimitiveFallback(
3499
+ "[epistemicQuestions] Failed to archive linked question",
3500
+ {
3501
+ error: formatGraphPrimitiveError(error),
3502
+ questionId: qid
3503
+ }
3504
+ );
4269
3505
  }
4270
3506
  }
4271
3507
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
@@ -4397,7 +3633,15 @@ var getQuestionClusterPositions = query({
4397
3633
  projectId: args.projectId,
4398
3634
  topicId: args.topicId
4399
3635
  });
4400
- } catch {
3636
+ } catch (error) {
3637
+ debugGraphPrimitiveFallback(
3638
+ "[epistemicQuestions] Failed to resolve question cluster scope",
3639
+ {
3640
+ error: formatGraphPrimitiveError(error),
3641
+ projectId: args.projectId,
3642
+ topicId: args.topicId
3643
+ }
3644
+ );
4401
3645
  return {
4402
3646
  positions: {},
4403
3647
  counts: {