@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,11 +1,12 @@
1
- import { v } from 'convex/values';
1
+ import { v, ConvexError } from 'convex/values';
2
2
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
3
3
  import { componentsGeneric, anyApi, mutationGeneric, queryGeneric } from 'convex/server';
4
- import { generateGlobalId } from '@lucern/contracts/ids';
4
+ import { generateGlobalId, assertUuidV7Identity, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
5
5
  import { normalizeTupleContradictionPolicy } from '@lucern/confidence';
6
6
  import { checkProjectAccess } from '@lucern/access-control/access';
7
7
  import '@lucern/access-control/audience';
8
8
  import { getCurrentUserId } from '@lucern/access-control/auth';
9
+ import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
9
10
 
10
11
  // src/epistemicBeliefs.links.ts
11
12
  var api = anyApi;
@@ -87,6 +88,35 @@ function debugGraphPrimitiveFallback(message, context) {
87
88
  console.debug(message, context ?? {});
88
89
  }
89
90
  var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
91
+ async function resolveTopicNodeScopeOrNull(ctx, ref) {
92
+ if (!ctx?.db || typeof ctx.db.query !== "function") {
93
+ return null;
94
+ }
95
+ let node = null;
96
+ try {
97
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
98
+ if (byGlobalId && byGlobalId.nodeType === "topic") {
99
+ node = byGlobalId;
100
+ }
101
+ } catch (error) {
102
+ debugGraphPrimitiveFallback(
103
+ "[topicScope] topic-node scope lookup by globalId failed",
104
+ { error, ref }
105
+ );
106
+ }
107
+ if (!node) {
108
+ return null;
109
+ }
110
+ const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
111
+ if (!scopeKey) {
112
+ return null;
113
+ }
114
+ return {
115
+ topicId: scopeKey,
116
+ projectId: asMappedProjectId(node),
117
+ source: "topic_node"
118
+ };
119
+ }
90
120
  function asMappedProjectId(topic) {
91
121
  if (!topic) {
92
122
  return;
@@ -227,6 +257,13 @@ async function resolveTopicProjectScope(ctx, args) {
227
257
  ) ?? null;
228
258
  }
229
259
  if (!topic) {
260
+ const nodeScope = await resolveTopicNodeScopeOrNull(
261
+ ctx,
262
+ String(args.topicId)
263
+ );
264
+ if (nodeScope) {
265
+ return nodeScope;
266
+ }
230
267
  throw new Error(`Topic not found: ${String(args.topicId)}`);
231
268
  }
232
269
  const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
@@ -297,6 +334,16 @@ async function resolveTopicProjectScope(ctx, args) {
297
334
  source: "project_mapped_topic"
298
335
  };
299
336
  }
337
+ const nodeScope = await resolveTopicNodeScopeOrNull(
338
+ ctx,
339
+ String(args.projectId)
340
+ );
341
+ if (nodeScope) {
342
+ return {
343
+ ...nodeScope,
344
+ projectId: nodeScope.projectId ?? String(args.projectId)
345
+ };
346
+ }
300
347
  throw new Error(
301
348
  `Legacy project scope ${String(args.projectId)} has no mapped topic.`
302
349
  );
@@ -317,7 +364,18 @@ var optionalBeliefScopeArgs = optionalScopeArgs;
317
364
  tupleContradiction: normalizeTupleContradictionPolicy()
318
365
  });
319
366
  function throwStructuredMutationError(args) {
320
- const error = new Error(args.message);
367
+ const data = {
368
+ structuredMutationError: true,
369
+ message: args.message,
370
+ status: args.status,
371
+ code: args.code,
372
+ invariantCode: args.invariantCode,
373
+ suggestion: args.suggestion,
374
+ details: args.details
375
+ };
376
+ const error = new ConvexError(
377
+ data
378
+ );
321
379
  error.status = args.status;
322
380
  error.code = args.code;
323
381
  error.invariantCode = args.invariantCode;
@@ -378,15 +436,57 @@ async function requireProjectWriteAccess(ctx, projectId, userId) {
378
436
  );
379
437
  if (!hasAccess) {
380
438
  throwStructuredMutationError({
381
- message: "Project access required.",
439
+ message: `Project write access denied for topic ${projectId}.`,
382
440
  status: 403,
383
- code: "FORBIDDEN",
441
+ code: "PROJECT_ACCESS_DENIED",
384
442
  invariantCode: "policy.scope_required",
385
- suggestion: "Request write access for the project and retry.",
386
- details: { projectId, userId }
443
+ suggestion: "The acting principal lacks project-write access to this topic. Request a topic grant (or, if the principal created this topic, run the creator-grant backfill) and retry.",
444
+ details: { topicId: projectId, principalId: userId }
387
445
  });
388
446
  }
389
447
  }
448
+ async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
449
+ assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
450
+ const node = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", endpoint)).first();
451
+ if (!node) {
452
+ throw new Error(
453
+ `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
454
+ );
455
+ }
456
+ }
457
+ async function insertEpistemicEdge(ctx, doc) {
458
+ assertUuidV7Identity("epistemicEdges", doc.globalId);
459
+ assertStorageEdgeVocabulary(doc.edgeType);
460
+ if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
461
+ throw new Error(
462
+ "edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
463
+ );
464
+ }
465
+ if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
466
+ throw new Error(
467
+ "edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
468
+ );
469
+ }
470
+ await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
471
+ await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
472
+ if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
473
+ assertEdgePolicyAllowed(
474
+ edgePolicyManifest,
475
+ doc.edgeType,
476
+ {
477
+ kind: "epistemic_node",
478
+ nodeId: doc.fromNodeId,
479
+ nodeType: doc.fromNodeType
480
+ },
481
+ {
482
+ kind: "epistemic_node",
483
+ nodeId: doc.toNodeId,
484
+ nodeType: doc.toNodeType
485
+ }
486
+ );
487
+ }
488
+ return ctx.db.insert("epistemicEdges", doc);
489
+ }
390
490
 
391
491
  // src/epistemicBeliefs.links.ts
392
492
  function assertSignedImpactScore(value, context) {
@@ -609,10 +709,11 @@ var linkEvidence = mutation({
609
709
  const edgeType = "informs";
610
710
  const logicalRole = evidenceNodeId ? await computeLogicalRole(ctx, evidenceNodeId, args.beliefNodeId) : "contributory";
611
711
  const edgeGlobalId = generateGlobalId();
612
- await ctx.db.insert("epistemicEdges", {
712
+ await insertEpistemicEdge(ctx, {
613
713
  globalId: edgeGlobalId,
614
- fromNodeId: evidenceNodeId,
615
- toNodeId: args.beliefNodeId,
714
+ // C2-RR.4 Defect E — canonical UUIDv7 endpoints, not Convex doc ids.
715
+ fromNodeId: evidenceGlobalId,
716
+ toNodeId: belief.globalId,
616
717
  sourceGlobalId: evidenceGlobalId,
617
718
  targetGlobalId: belief.globalId,
618
719
  edgeType,