@lucern/graph-primitives 1.0.18 → 1.0.20

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.
@@ -7,7 +7,7 @@ import { componentsGeneric, anyApi, internalMutationGeneric, mutationGeneric, qu
7
7
  import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
8
8
  import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
9
9
  import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
10
- import { generateGlobalId } from '@lucern/contracts/ids';
10
+ import { generateGlobalId, generateUuidV7 } from '@lucern/contracts/ids';
11
11
  import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
12
12
 
13
13
  // src/epistemicBeliefs.helpers.ts
@@ -2081,9 +2081,16 @@ function scopeFromTopicAnchor(topicNode) {
2081
2081
  }
2082
2082
  async function createRequiredBeliefTopicEdge(ctx, args) {
2083
2083
  const topicGlobalId = args.topicNode.globalId;
2084
- const edgeGlobalId = `edge:${args.beliefGlobalId}:${topicGlobalId}:scoped_by`;
2085
2084
  const now = Date.now();
2086
- const existing = await ctx.db.query("epistemicEdges").withIndex("by_globalId", (q) => q.eq("globalId", edgeGlobalId)).first();
2085
+ const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
2086
+ "by_from_to",
2087
+ (q) => q.eq("fromNodeId", String(args.beliefNodeId)).eq(
2088
+ "toNodeId",
2089
+ String(args.topicNode._id)
2090
+ )
2091
+ ).collect();
2092
+ const existing = existingEdges.find((edge) => edge.edgeType === "belongs_to");
2093
+ const edgeGlobalId = cleanString(existing?.globalId) ?? generateUuidV7();
2087
2094
  if (!existing) {
2088
2095
  await ctx.db.insert("epistemicEdges", {
2089
2096
  globalId: edgeGlobalId,
@@ -2091,13 +2098,18 @@ async function createRequiredBeliefTopicEdge(ctx, args) {
2091
2098
  toNodeId: String(args.topicNode._id),
2092
2099
  sourceGlobalId: args.beliefGlobalId,
2093
2100
  targetGlobalId: topicGlobalId,
2094
- edgeType: "scoped_by",
2101
+ edgeType: "belongs_to",
2095
2102
  weight: 1,
2096
2103
  confidence: 1,
2097
2104
  context: "Belief creation topic anchor invariant.",
2098
2105
  reasoningMethod: "implicit",
2099
2106
  derivationType: "topic_scope_invariant",
2100
- metadata: { invariant: "belief.topic_edge_required" },
2107
+ metadata: {
2108
+ invariant: "belief.topic_edge_required",
2109
+ edgeUuid: edgeGlobalId,
2110
+ fromUuid: args.beliefGlobalId,
2111
+ toUuid: topicGlobalId
2112
+ },
2101
2113
  createdBy: args.createdBy,
2102
2114
  createdAt: now,
2103
2115
  updatedAt: now,
@@ -2115,7 +2127,7 @@ async function createRequiredBeliefTopicEdge(ctx, args) {
2115
2127
  globalId: edgeGlobalId,
2116
2128
  fromGlobalId: args.beliefGlobalId,
2117
2129
  toGlobalId: topicGlobalId,
2118
- edgeType: "scoped_by",
2130
+ edgeType: "belongs_to",
2119
2131
  weight: 1,
2120
2132
  confidence: 1,
2121
2133
  context: "Belief creation topic anchor invariant.",
@@ -2126,7 +2138,12 @@ async function createRequiredBeliefTopicEdge(ctx, args) {
2126
2138
  toNodeType: "topic",
2127
2139
  fromLayer: "L3",
2128
2140
  toLayer: args.topicNode.epistemicLayer ?? "ontological",
2129
- metadata: { invariant: "belief.topic_edge_required" }
2141
+ metadata: {
2142
+ invariant: "belief.topic_edge_required",
2143
+ edgeUuid: edgeGlobalId,
2144
+ fromUuid: args.beliefGlobalId,
2145
+ toUuid: topicGlobalId
2146
+ }
2130
2147
  });
2131
2148
  }
2132
2149
 
@@ -3663,6 +3680,39 @@ var getWithEvidence = query({
3663
3680
  };
3664
3681
  }
3665
3682
  });
3683
+ async function collectRelationshipNodeRefs(ctx, nodeId) {
3684
+ const refs = /* @__PURE__ */ new Set([String(nodeId)]);
3685
+ const node = await ctx.db.get(nodeId);
3686
+ const globalId = typeof node?.globalId === "string" ? node.globalId.trim() : "";
3687
+ if (globalId.length > 0) {
3688
+ refs.add(globalId);
3689
+ }
3690
+ return [...refs];
3691
+ }
3692
+ function endpointMatches(q, fields, refs) {
3693
+ return q.or(
3694
+ ...fields.flatMap(
3695
+ (field) => refs.map((ref) => q.eq(q.field(field), ref))
3696
+ )
3697
+ );
3698
+ }
3699
+ async function resolveRelationshipEndpoint(ctx, endpointId, globalEndpointId) {
3700
+ const candidates = [endpointId, globalEndpointId].map((value) => typeof value === "string" ? value.trim() : "").filter((value, index, values) => value.length > 0 && values.indexOf(value) === index);
3701
+ for (const candidate of candidates) {
3702
+ try {
3703
+ const direct = await ctx.db.get(candidate);
3704
+ if (direct) {
3705
+ return direct;
3706
+ }
3707
+ } catch {
3708
+ }
3709
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
3710
+ if (byGlobalId) {
3711
+ return byGlobalId;
3712
+ }
3713
+ }
3714
+ return null;
3715
+ }
3666
3716
  var getRelationships = query({
3667
3717
  args: {
3668
3718
  nodeId: v.id("epistemicNodes"),
@@ -3677,17 +3727,38 @@ var getRelationships = query({
3677
3727
  incoming: [],
3678
3728
  outgoing: []
3679
3729
  };
3730
+ const nodeRefs = await collectRelationshipNodeRefs(ctx, args.nodeId);
3680
3731
  if (direction === "in" || direction === "both") {
3681
- const inEdges = await ctx.db.query("epistemicEdges").filter((q) => q.eq(q.field("toNodeId"), args.nodeId)).collect();
3732
+ const inEdges = await ctx.db.query("epistemicEdges").filter(
3733
+ (q) => endpointMatches(
3734
+ q,
3735
+ ["toNodeId", "targetGlobalId", "toGlobalId", "toUuid"],
3736
+ nodeRefs
3737
+ )
3738
+ ).collect();
3682
3739
  for (const edge of inEdges) {
3683
- const sourceNode = await ctx.db.get(edge.fromNodeId);
3740
+ const sourceNode = await resolveRelationshipEndpoint(
3741
+ ctx,
3742
+ edge.fromNodeId,
3743
+ edge.sourceGlobalId ?? edge.fromGlobalId ?? edge.fromUuid
3744
+ );
3684
3745
  results.incoming.push({ edge, node: sourceNode });
3685
3746
  }
3686
3747
  }
3687
3748
  if (direction === "out" || direction === "both") {
3688
- const outEdges = await ctx.db.query("epistemicEdges").filter((q) => q.eq(q.field("fromNodeId"), args.nodeId)).collect();
3749
+ const outEdges = await ctx.db.query("epistemicEdges").filter(
3750
+ (q) => endpointMatches(
3751
+ q,
3752
+ ["fromNodeId", "sourceGlobalId", "fromGlobalId", "fromUuid"],
3753
+ nodeRefs
3754
+ )
3755
+ ).collect();
3689
3756
  for (const edge of outEdges) {
3690
- const targetNode = edge.toNodeId ? await ctx.db.get(edge.toNodeId) : null;
3757
+ const targetNode = await resolveRelationshipEndpoint(
3758
+ ctx,
3759
+ edge.toNodeId,
3760
+ edge.targetGlobalId ?? edge.toGlobalId ?? edge.toUuid
3761
+ );
3691
3762
  results.outgoing.push({ edge, node: targetNode });
3692
3763
  }
3693
3764
  }