@lucern/graph-primitives 1.0.22 → 1.0.24

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 (136) hide show
  1. package/dist/beliefDecay.js +49 -0
  2. package/dist/beliefDecay.js.map +1 -1
  3. package/dist/beliefEvidenceLinks.js +99 -5
  4. package/dist/beliefEvidenceLinks.js.map +1 -1
  5. package/dist/beliefEvidenceLinks.operational.js +50 -5
  6. package/dist/beliefEvidenceLinks.operational.js.map +1 -1
  7. package/dist/contradictions.js +46 -0
  8. package/dist/contradictions.js.map +1 -1
  9. package/dist/edgeValidation.js +66 -1
  10. package/dist/edgeValidation.js.map +1 -1
  11. package/dist/entityBridge.js +66 -1
  12. package/dist/entityBridge.js.map +1 -1
  13. package/dist/entityCanonicalMatch.d.ts +40 -0
  14. package/dist/entityCanonicalMatch.js +33 -0
  15. package/dist/entityCanonicalMatch.js.map +1 -0
  16. package/dist/entityLifecycle.js +149 -39
  17. package/dist/entityLifecycle.js.map +1 -1
  18. package/dist/epistemicAnswers.js +64 -11
  19. package/dist/epistemicAnswers.js.map +1 -1
  20. package/dist/epistemicBeliefs.admin.js +63 -6
  21. package/dist/epistemicBeliefs.admin.js.map +1 -1
  22. package/dist/epistemicBeliefs.backfills.js +59 -2
  23. package/dist/epistemicBeliefs.backfills.js.map +1 -1
  24. package/dist/epistemicBeliefs.confidence.d.ts +1 -1
  25. package/dist/epistemicBeliefs.confidence.js +70 -12
  26. package/dist/epistemicBeliefs.confidence.js.map +1 -1
  27. package/dist/epistemicBeliefs.core.js +120 -17
  28. package/dist/epistemicBeliefs.core.js.map +1 -1
  29. package/dist/epistemicBeliefs.d.ts +1 -1
  30. package/dist/epistemicBeliefs.forkEvidence.js +13 -2
  31. package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
  32. package/dist/epistemicBeliefs.helpers.d.ts +18 -3
  33. package/dist/epistemicBeliefs.helpers.js +66 -6
  34. package/dist/epistemicBeliefs.helpers.js.map +1 -1
  35. package/dist/epistemicBeliefs.internal.js +115 -12
  36. package/dist/epistemicBeliefs.internal.js.map +1 -1
  37. package/dist/epistemicBeliefs.js +132 -28
  38. package/dist/epistemicBeliefs.js.map +1 -1
  39. package/dist/epistemicBeliefs.lifecycle.js +70 -12
  40. package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
  41. package/dist/epistemicBeliefs.links.js +111 -10
  42. package/dist/epistemicBeliefs.links.js.map +1 -1
  43. package/dist/epistemicBeliefs.topicAnchor.js +48 -8
  44. package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
  45. package/dist/epistemicContracts.evaluators.js +70 -12
  46. package/dist/epistemicContracts.evaluators.js.map +1 -1
  47. package/dist/epistemicContracts.handlers.js +71 -16
  48. package/dist/epistemicContracts.handlers.js.map +1 -1
  49. package/dist/epistemicContracts.js +71 -16
  50. package/dist/epistemicContracts.js.map +1 -1
  51. package/dist/epistemicEdges.d.ts +1 -1
  52. package/dist/epistemicEdges.handlers.js +57 -3
  53. package/dist/epistemicEdges.handlers.js.map +1 -1
  54. package/dist/epistemicEdges.helpers.d.ts +2 -2
  55. package/dist/epistemicEdges.js +174 -4
  56. package/dist/epistemicEdges.js.map +1 -1
  57. package/dist/epistemicEdges.mutations.js +115 -1
  58. package/dist/epistemicEdges.mutations.js.map +1 -1
  59. package/dist/epistemicEdges.queries.js +46 -0
  60. package/dist/epistemicEdges.queries.js.map +1 -1
  61. package/dist/epistemicEdges.types.d.ts +1 -1
  62. package/dist/epistemicEvidence.d.ts +1 -1
  63. package/dist/epistemicEvidence.js +180 -14
  64. package/dist/epistemicEvidence.js.map +1 -1
  65. package/dist/epistemicEvidenceHelpers.d.ts +1 -1
  66. package/dist/epistemicEvidenceHelpers.js +49 -0
  67. package/dist/epistemicEvidenceHelpers.js.map +1 -1
  68. package/dist/epistemicEvidenceMutations.js +180 -14
  69. package/dist/epistemicEvidenceMutations.js.map +1 -1
  70. package/dist/epistemicEvidenceQueries.js +49 -0
  71. package/dist/epistemicEvidenceQueries.js.map +1 -1
  72. package/dist/epistemicHelpers.js +11 -6
  73. package/dist/epistemicHelpers.js.map +1 -1
  74. package/dist/epistemicInsert.d.ts +8 -0
  75. package/dist/epistemicInsert.js +54 -0
  76. package/dist/epistemicInsert.js.map +1 -0
  77. package/dist/epistemicNodeCreation.js +11 -6
  78. package/dist/epistemicNodeCreation.js.map +1 -1
  79. package/dist/epistemicNodes.helpers.d.ts +1 -1
  80. package/dist/epistemicNodes.internal.js +53 -1
  81. package/dist/epistemicNodes.internal.js.map +1 -1
  82. package/dist/epistemicNodes.js +56 -4
  83. package/dist/epistemicNodes.js.map +1 -1
  84. package/dist/epistemicNodes.mutations.js +55 -3
  85. package/dist/epistemicNodes.mutations.js.map +1 -1
  86. package/dist/epistemicNodes.queries.js +46 -0
  87. package/dist/epistemicNodes.queries.js.map +1 -1
  88. package/dist/epistemicNodes.validators.d.ts +1 -1
  89. package/dist/epistemicQuestions.conviction.js +49 -0
  90. package/dist/epistemicQuestions.conviction.js.map +1 -1
  91. package/dist/epistemicQuestions.create.js +61 -7
  92. package/dist/epistemicQuestions.create.js.map +1 -1
  93. package/dist/epistemicQuestions.d.ts +1 -1
  94. package/dist/epistemicQuestions.evidence.js +56 -2
  95. package/dist/epistemicQuestions.evidence.js.map +1 -1
  96. package/dist/epistemicQuestions.helpers.d.ts +1 -1
  97. package/dist/epistemicQuestions.helpers.js +49 -0
  98. package/dist/epistemicQuestions.helpers.js.map +1 -1
  99. package/dist/epistemicQuestions.js +63 -9
  100. package/dist/epistemicQuestions.js.map +1 -1
  101. package/dist/epistemicQuestions.lifecycle.js +49 -0
  102. package/dist/epistemicQuestions.lifecycle.js.map +1 -1
  103. package/dist/epistemicQuestions.queries.js +49 -0
  104. package/dist/epistemicQuestions.queries.js.map +1 -1
  105. package/dist/epistemicQuestions.sprint.js +46 -0
  106. package/dist/epistemicQuestions.sprint.js.map +1 -1
  107. package/dist/epistemicQuestions.tail.js +56 -2
  108. package/dist/epistemicQuestions.tail.js.map +1 -1
  109. package/dist/epistemicSources.js +53 -2
  110. package/dist/epistemicSources.js.map +1 -1
  111. package/dist/helpers.js +66 -1
  112. package/dist/helpers.js.map +1 -1
  113. package/dist/index.d.ts +1 -1
  114. package/dist/index.js +379 -115
  115. package/dist/index.js.map +1 -1
  116. package/dist/proof-attestation.json +1 -1
  117. package/dist/questionEvidenceLinks.js +49 -0
  118. package/dist/questionEvidenceLinks.js.map +1 -1
  119. package/dist/resolvers.js +3 -0
  120. package/dist/resolvers.js.map +1 -1
  121. package/dist/scopeResolverCompat.d.ts +1 -1
  122. package/dist/scopeResolverCompat.js +46 -0
  123. package/dist/scopeResolverCompat.js.map +1 -1
  124. package/dist/topicProjectOverlay.d.ts +4 -0
  125. package/dist/topicProjectOverlay.js +3 -0
  126. package/dist/topicProjectOverlay.js.map +1 -1
  127. package/dist/{topicScope-By_zp4tt.d.ts → topicScope-7zhyeGl7.d.ts} +1 -1
  128. package/dist/topicScope.d.ts +1 -1
  129. package/dist/topicScope.js +46 -0
  130. package/dist/topicScope.js.map +1 -1
  131. package/dist/workflowBridge.js +46 -0
  132. package/dist/workflowBridge.js.map +1 -1
  133. package/dist/workspaceIsolation.d.ts +1 -1
  134. package/dist/workspaceIsolation.js +46 -0
  135. package/dist/workspaceIsolation.js.map +1 -1
  136. package/package.json +4 -4
@@ -1,10 +1,11 @@
1
- import { v } from 'convex/values';
1
+ import { v, ConvexError } from 'convex/values';
2
2
  import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
3
3
  import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
4
4
  import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
5
5
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
6
6
  import { componentsGeneric, anyApi, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
7
- import { generateGlobalId, generateUuidV7 } from '@lucern/contracts/ids';
7
+ import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
8
+ import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
8
9
  import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
9
10
  import { normalizeTupleContradictionPolicy, confidenceFromSL } from '@lucern/confidence';
10
11
  import '@lucern/access-control/access';
@@ -31,6 +32,35 @@ function debugGraphPrimitiveFallback(message, context) {
31
32
 
32
33
  // src/topicScope.ts
33
34
  var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
35
+ async function resolveTopicNodeScopeOrNull(ctx, ref) {
36
+ if (!ctx?.db || typeof ctx.db.query !== "function") {
37
+ return null;
38
+ }
39
+ let node = null;
40
+ try {
41
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
42
+ if (byGlobalId && byGlobalId.nodeType === "topic") {
43
+ node = byGlobalId;
44
+ }
45
+ } catch (error) {
46
+ debugGraphPrimitiveFallback(
47
+ "[topicScope] topic-node scope lookup by globalId failed",
48
+ { error, ref }
49
+ );
50
+ }
51
+ if (!node) {
52
+ return null;
53
+ }
54
+ const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
55
+ if (!scopeKey) {
56
+ return null;
57
+ }
58
+ return {
59
+ topicId: scopeKey,
60
+ projectId: asMappedProjectId(node),
61
+ source: "topic_node"
62
+ };
63
+ }
34
64
  function asMappedProjectId(topic) {
35
65
  if (!topic) {
36
66
  return;
@@ -171,6 +201,13 @@ async function resolveTopicProjectScope(ctx, args) {
171
201
  ) ?? null;
172
202
  }
173
203
  if (!topic) {
204
+ const nodeScope = await resolveTopicNodeScopeOrNull(
205
+ ctx,
206
+ String(args.topicId)
207
+ );
208
+ if (nodeScope) {
209
+ return nodeScope;
210
+ }
174
211
  throw new Error(`Topic not found: ${String(args.topicId)}`);
175
212
  }
176
213
  const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
@@ -241,6 +278,16 @@ async function resolveTopicProjectScope(ctx, args) {
241
278
  source: "project_mapped_topic"
242
279
  };
243
280
  }
281
+ const nodeScope = await resolveTopicNodeScopeOrNull(
282
+ ctx,
283
+ String(args.projectId)
284
+ );
285
+ if (nodeScope) {
286
+ return {
287
+ ...nodeScope,
288
+ projectId: nodeScope.projectId ?? String(args.projectId)
289
+ };
290
+ }
244
291
  throw new Error(
245
292
  `Legacy project scope ${String(args.projectId)} has no mapped topic.`
246
293
  );
@@ -253,6 +300,52 @@ var optionalScopeArgs = {
253
300
  projectId: v.optional(v.string()),
254
301
  topicId: v.optional(v.string())
255
302
  };
303
+ async function insertEpistemicNode(ctx, doc) {
304
+ assertUuidV7Identity("epistemicNodes", doc.globalId);
305
+ return ctx.db.insert("epistemicNodes", doc);
306
+ }
307
+ async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
308
+ assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
309
+ const node = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", endpoint)).first();
310
+ if (!node) {
311
+ throw new Error(
312
+ `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
313
+ );
314
+ }
315
+ }
316
+ async function insertEpistemicEdge(ctx, doc) {
317
+ assertUuidV7Identity("epistemicEdges", doc.globalId);
318
+ assertStorageEdgeVocabulary(doc.edgeType);
319
+ if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
320
+ throw new Error(
321
+ "edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
322
+ );
323
+ }
324
+ if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
325
+ throw new Error(
326
+ "edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
327
+ );
328
+ }
329
+ await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
330
+ await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
331
+ if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
332
+ assertEdgePolicyAllowed(
333
+ edgePolicyManifest,
334
+ doc.edgeType,
335
+ {
336
+ kind: "epistemic_node",
337
+ nodeId: doc.fromNodeId,
338
+ nodeType: doc.fromNodeType
339
+ },
340
+ {
341
+ kind: "epistemic_node",
342
+ nodeId: doc.toNodeId,
343
+ nodeType: doc.toNodeType
344
+ }
345
+ );
346
+ }
347
+ return ctx.db.insert("epistemicEdges", doc);
348
+ }
256
349
 
257
350
  // src/epistemicBeliefs.topicAnchor.ts
258
351
  function cleanString(value) {
@@ -304,18 +397,15 @@ async function createRequiredBeliefTopicEdge(ctx, args) {
304
397
  const now = Date.now();
305
398
  const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
306
399
  "by_from_to",
307
- (q) => q.eq("fromNodeId", String(args.beliefNodeId)).eq(
308
- "toNodeId",
309
- String(args.topicNode._id)
310
- )
400
+ (q) => q.eq("fromNodeId", args.beliefGlobalId).eq("toNodeId", topicGlobalId)
311
401
  ).collect();
312
402
  const existing = existingEdges.find((edge) => edge.edgeType === "belongs_to");
313
403
  const edgeGlobalId = cleanString(existing?.globalId) ?? generateUuidV7();
314
404
  if (!existing) {
315
- await ctx.db.insert("epistemicEdges", {
405
+ await insertEpistemicEdge(ctx, {
316
406
  globalId: edgeGlobalId,
317
- fromNodeId: String(args.beliefNodeId),
318
- toNodeId: String(args.topicNode._id),
407
+ fromNodeId: args.beliefGlobalId,
408
+ toNodeId: topicGlobalId,
319
409
  sourceGlobalId: args.beliefGlobalId,
320
410
  targetGlobalId: topicGlobalId,
321
411
  edgeType: "belongs_to",
@@ -704,6 +794,9 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
704
794
  type: mapProjectType(topic, metadata),
705
795
  description: readNonEmptyString(topic.description),
706
796
  ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
797
+ // FR.7 creator-grant: surface the principal-shaped owner field (column-first,
798
+ // metadata fallback for legacy rows that recorded it in metadata).
799
+ ownerPrincipalId: readNonEmptyString(topic.ownerPrincipalId) || readNonEmptyString(metadata.ownerPrincipalId),
707
800
  sharedWith: readStringArray(metadata.sharedWith),
708
801
  visibility,
709
802
  tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
@@ -907,7 +1000,18 @@ var optionalBeliefScopeArgs = optionalScopeArgs;
907
1000
  tupleContradiction: normalizeTupleContradictionPolicy()
908
1001
  });
909
1002
  function throwStructuredMutationError(args) {
910
- const error = new Error(args.message);
1003
+ const data = {
1004
+ structuredMutationError: true,
1005
+ message: args.message,
1006
+ status: args.status,
1007
+ code: args.code,
1008
+ invariantCode: args.invariantCode,
1009
+ suggestion: args.suggestion,
1010
+ details: args.details
1011
+ };
1012
+ const error = new ConvexError(
1013
+ data
1014
+ );
911
1015
  error.status = args.status;
912
1016
  error.code = args.code;
913
1017
  error.invariantCode = args.invariantCode;
@@ -1339,7 +1443,7 @@ var internalCreate = internalMutation({
1339
1443
  opinion_u: 1,
1340
1444
  opinion_a: baseRate
1341
1445
  };
1342
- const nodeId = await ctx.db.insert("epistemicNodes", {
1446
+ const nodeId = await insertEpistemicNode(ctx, {
1343
1447
  globalId,
1344
1448
  topicId: scope.topicId,
1345
1449
  projectId: scope.projectId,
@@ -1395,7 +1499,6 @@ var internalCreate = internalMutation({
1395
1499
  })
1396
1500
  );
1397
1501
  await createRequiredBeliefTopicEdge(ctx, {
1398
- beliefNodeId: nodeId,
1399
1502
  beliefGlobalId: globalId,
1400
1503
  topicNode,
1401
1504
  createdBy: args.userId