@lucern/graph-primitives 1.0.15 → 1.0.17

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 (65) hide show
  1. package/dist/beliefEvidenceLinks.js +144 -99
  2. package/dist/beliefEvidenceLinks.js.map +1 -1
  3. package/dist/beliefEvidenceLinks.operational.d.ts +29 -0
  4. package/dist/beliefEvidenceLinks.operational.js +157 -0
  5. package/dist/beliefEvidenceLinks.operational.js.map +1 -0
  6. package/dist/{beliefLifecycle-y8WLXqQj.d.ts → beliefLifecycle-CXwdDw5e.d.ts} +7 -4
  7. package/dist/beliefLifecycle.d.ts +1 -1
  8. package/dist/beliefLifecycle.js +75 -18
  9. package/dist/beliefLifecycle.js.map +1 -1
  10. package/dist/epistemicBeliefs.admin.js.map +1 -1
  11. package/dist/epistemicBeliefs.backfills.d.ts +1 -1
  12. package/dist/epistemicBeliefs.backfills.js +63 -35
  13. package/dist/epistemicBeliefs.backfills.js.map +1 -1
  14. package/dist/epistemicBeliefs.confidence.d.ts +1 -1
  15. package/dist/epistemicBeliefs.confidence.js +70 -41
  16. package/dist/epistemicBeliefs.confidence.js.map +1 -1
  17. package/dist/epistemicBeliefs.core.js +957 -566
  18. package/dist/epistemicBeliefs.core.js.map +1 -1
  19. package/dist/epistemicBeliefs.d.ts +2 -2
  20. package/dist/epistemicBeliefs.forkEvidence.d.ts +18 -0
  21. package/dist/epistemicBeliefs.forkEvidence.js +121 -0
  22. package/dist/epistemicBeliefs.forkEvidence.js.map +1 -0
  23. package/dist/epistemicBeliefs.helpers.d.ts +2 -2
  24. package/dist/epistemicBeliefs.helpers.js +60 -32
  25. package/dist/epistemicBeliefs.helpers.js.map +1 -1
  26. package/dist/epistemicBeliefs.internal.js +174 -39
  27. package/dist/epistemicBeliefs.internal.js.map +1 -1
  28. package/dist/epistemicBeliefs.js +436 -72
  29. package/dist/epistemicBeliefs.js.map +1 -1
  30. package/dist/epistemicBeliefs.lifecycle.d.ts +2 -2
  31. package/dist/epistemicBeliefs.lifecycle.js +75 -47
  32. package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
  33. package/dist/epistemicBeliefs.links.js +46 -1
  34. package/dist/epistemicBeliefs.links.js.map +1 -1
  35. package/dist/epistemicBeliefs.topicAnchor.d.ts +29 -0
  36. package/dist/epistemicBeliefs.topicAnchor.js +105 -0
  37. package/dist/epistemicBeliefs.topicAnchor.js.map +1 -0
  38. package/dist/epistemicContracts.evaluators.js +71 -42
  39. package/dist/epistemicContracts.evaluators.js.map +1 -1
  40. package/dist/epistemicContracts.handlers.js +71 -42
  41. package/dist/epistemicContracts.handlers.js.map +1 -1
  42. package/dist/epistemicContracts.js +71 -42
  43. package/dist/epistemicContracts.js.map +1 -1
  44. package/dist/epistemicContracts.metrics.js +1 -1
  45. package/dist/epistemicContracts.metrics.js.map +1 -1
  46. package/dist/epistemicContracts.types.d.ts +1 -1
  47. package/dist/epistemicEdges.helpers.d.ts +1 -1
  48. package/dist/epistemicEvidence.js +172 -81
  49. package/dist/epistemicEvidence.js.map +1 -1
  50. package/dist/epistemicEvidenceMutations.js +172 -81
  51. package/dist/epistemicEvidenceMutations.js.map +1 -1
  52. package/dist/epistemicNodes.internal.js.map +1 -1
  53. package/dist/epistemicNodes.js +2 -2
  54. package/dist/epistemicNodes.js.map +1 -1
  55. package/dist/epistemicNodes.mutations.js +2 -2
  56. package/dist/epistemicNodes.mutations.js.map +1 -1
  57. package/dist/evaluators/index.js +1 -1
  58. package/dist/evaluators/index.js.map +1 -1
  59. package/dist/index.d.ts +2 -2
  60. package/dist/index.js +767 -236
  61. package/dist/index.js.map +1 -1
  62. package/dist/invariantEnforcement.js +2 -2
  63. package/dist/invariantEnforcement.js.map +1 -1
  64. package/dist/proof-attestation.json +3 -3
  65. package/package.json +4 -4
@@ -658,86 +658,31 @@ function resolveGraphPrimitivesAppResolvers(_ctx) {
658
658
  };
659
659
  }
660
660
 
661
- // src/beliefEvidenceLinks.ts
662
- var beliefIdUnion = v.id("epistemicNodes");
663
- var insightIdUnion = v.id("epistemicNodes");
664
- var suggestionStatusValidator = v.union(
665
- v.literal("suggested"),
666
- v.literal("approved"),
667
- v.literal("dismissed")
668
- );
669
- var matcherMetadataValidator = v.object({
670
- surface: v.string(),
671
- matcherFamily: v.optional(v.string()),
672
- matcherKey: v.optional(v.string()),
673
- matcherVersion: v.optional(v.string()),
674
- reviewStatus: v.optional(
675
- v.union(
676
- v.literal("pending"),
677
- v.literal("accepted"),
678
- v.literal("rejected"),
679
- v.literal("auto_accepted"),
680
- v.literal("superseded")
681
- )
682
- ),
683
- configSnapshot: v.optional(v.any()),
684
- signalSnapshot: v.optional(v.any()),
685
- outcomeMetadata: v.optional(v.any())
686
- });
687
- async function markProjectGraphDirty(ctx, projectId) {
688
- if (!projectId) {
689
- return;
661
+ // src/beliefEvidenceLinks.operational.ts
662
+ function assertEvidenceImpact(args) {
663
+ if (!Number.isFinite(args.weight) || args.weight === 0 || args.weight < -1 || args.weight > 1) {
664
+ throw new Error("Belief evidence links require explicit nonzero weight in [-1, 1]");
690
665
  }
691
- await ctx.scheduler.runAfter(
692
- 0,
693
- internal.graphAnalysisCache.markCacheStaleInternal,
694
- {
695
- projectId
696
- }
697
- );
698
- await resolveGraphPrimitivesAppResolvers().patchProject(ctx, projectId, {
699
- lastActivityAt: Date.now()
700
- });
701
- }
702
- async function recordMatcherDecision(ctx, args) {
703
- if (!args.matcherMetadata) {
704
- return;
666
+ if (args.relation === "supports" && args.weight < 0) {
667
+ throw new Error("Supporting evidence links require positive weight");
668
+ }
669
+ if (args.relation === "contradicts" && args.weight > 0) {
670
+ throw new Error("Contradicting evidence links require negative weight");
705
671
  }
706
- await ctx.runMutation("matcherFeedback:recordDecision", {
707
- projectId: args.beliefNode.projectId,
708
- topicId: args.beliefNode.topicId,
709
- surface: args.matcherMetadata.surface,
710
- matcherFamily: args.matcherMetadata.matcherFamily,
711
- matcherKey: args.matcherMetadata.matcherKey,
712
- matcherVersion: args.matcherMetadata.matcherVersion,
713
- sourceEntityId: String(args.insightId),
714
- targetEntityId: String(args.beliefId),
715
- suggestionTable: "beliefEvidenceLinks",
716
- suggestionId: args.linkId,
717
- reviewStatus: deriveMatcherReviewStatus({
718
- explicitReviewStatus: args.matcherMetadata.reviewStatus,
719
- linkStatus: args.linkStatus
720
- }),
721
- reviewedBy: args.reviewedBy,
722
- decisionReason: args.decisionReason,
723
- configSnapshot: args.matcherMetadata.configSnapshot,
724
- signalSnapshot: args.matcherMetadata.signalSnapshot,
725
- outcomeMetadata: args.matcherMetadata.outcomeMetadata
726
- });
727
672
  }
728
673
  async function applyOperationalLinkEffects(ctx, args) {
674
+ assertEvidenceImpact({ relation: args.relation, weight: args.weight });
675
+ const confidence = Math.abs(args.weight);
729
676
  const currentSupporting = args.beliefNode.supportingInsightIds ?? [];
730
677
  const currentContradicting = args.beliefNode.contradictingInsightIds ?? [];
731
- if (args.relation === "supports") {
732
- if (!currentSupporting.includes(args.insightId)) {
733
- await ctx.db.patch(args.beliefId, {
734
- supportingInsightIds: [...currentSupporting, args.insightId],
735
- contradictingInsightIds: currentContradicting.filter(
736
- (id) => id !== args.insightId
737
- )
738
- });
739
- }
740
- } else if (!currentContradicting.includes(args.insightId)) {
678
+ if (args.relation === "supports" && !currentSupporting.includes(args.insightId)) {
679
+ await ctx.db.patch(args.beliefId, {
680
+ supportingInsightIds: [...currentSupporting, args.insightId],
681
+ contradictingInsightIds: currentContradicting.filter(
682
+ (id) => id !== args.insightId
683
+ )
684
+ });
685
+ } else if (args.relation === "contradicts" && !currentContradicting.includes(args.insightId)) {
741
686
  await ctx.db.patch(args.beliefId, {
742
687
  contradictingInsightIds: [...currentContradicting, args.insightId],
743
688
  supportingInsightIds: currentSupporting.filter(
@@ -748,7 +693,7 @@ async function applyOperationalLinkEffects(ctx, args) {
748
693
  try {
749
694
  const beliefSpineNode = await ctx.db.get(args.beliefId);
750
695
  const evidenceSpineNode = await ctx.db.get(args.insightId);
751
- if (beliefSpineNode && beliefSpineNode.nodeType === "belief" && evidenceSpineNode && evidenceSpineNode.nodeType === "evidence") {
696
+ if (beliefSpineNode?.nodeType === "belief" && evidenceSpineNode?.nodeType === "evidence") {
752
697
  const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
753
698
  "by_from_to",
754
699
  (q) => q.eq("fromNodeId", evidenceSpineNode._id).eq("toNodeId", beliefSpineNode._id)
@@ -761,16 +706,44 @@ async function applyOperationalLinkEffects(ctx, args) {
761
706
  await ctx.db.delete(edge._id);
762
707
  }
763
708
  }
764
- const weight = args.relation === "supports" ? args.confidence ?? 0.7 : -(args.confidence ?? 0.7);
765
709
  const globalId = `edge-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
710
+ const context = args.rationale || `Linked as ${args.relation}`;
711
+ await ctx.db.insert("epistemicEdges", {
712
+ globalId,
713
+ fromNodeId: evidenceSpineNode._id,
714
+ toNodeId: beliefSpineNode._id,
715
+ sourceGlobalId: evidenceSpineNode.globalId,
716
+ targetGlobalId: beliefSpineNode.globalId,
717
+ edgeType: "informs",
718
+ weight: args.weight,
719
+ confidence,
720
+ context,
721
+ reasoningMethod: "testimonial",
722
+ derivationType: "evidence_sl_scoring",
723
+ metadata: {
724
+ relation: args.relation,
725
+ confidence,
726
+ impactScore: args.weight,
727
+ invariant: "evidence.belief_impact_required"
728
+ },
729
+ createdBy: args.createdBy,
730
+ createdAt: Date.now(),
731
+ updatedAt: Date.now(),
732
+ projectId: args.beliefNode.projectId,
733
+ topicId: args.beliefNode.topicId ? String(args.beliefNode.topicId) : void 0,
734
+ fromNodeType: "evidence",
735
+ toNodeType: "belief",
736
+ fromLayer: "L2",
737
+ toLayer: "L3"
738
+ });
766
739
  await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
767
740
  globalId,
768
741
  fromGlobalId: evidenceSpineNode.globalId,
769
742
  toGlobalId: beliefSpineNode.globalId,
770
743
  edgeType: "informs",
771
- weight,
772
- confidence: args.confidence,
773
- context: args.rationale || `Linked as ${args.relation}`,
744
+ weight: args.weight,
745
+ confidence,
746
+ context,
774
747
  projectId: args.beliefNode.projectId ? String(args.beliefNode.projectId) : void 0,
775
748
  createdBy: args.createdBy,
776
749
  fromNodeType: "evidence",
@@ -783,17 +756,13 @@ async function applyOperationalLinkEffects(ctx, args) {
783
756
  console.error("[EpistemicSpine] Failed to create informs edge:", e);
784
757
  }
785
758
  if (args.beliefNode.projectId) {
786
- await ctx.scheduler.runAfter(
787
- 0,
788
- "verificationActions:deepVerifyEvidence",
789
- {
790
- insightId: args.insightId,
791
- targetType: "belief",
792
- targetId: args.beliefId,
793
- projectId: args.beliefNode.projectId,
794
- userId: args.createdBy
795
- }
796
- );
759
+ await ctx.scheduler.runAfter(0, "verificationActions:deepVerifyEvidence", {
760
+ insightId: args.insightId,
761
+ targetType: "belief",
762
+ targetId: args.beliefId,
763
+ projectId: args.beliefNode.projectId,
764
+ userId: args.createdBy
765
+ });
797
766
  }
798
767
  }
799
768
  async function removeOperationalLinkEffects(ctx, args) {
@@ -818,7 +787,7 @@ async function removeOperationalLinkEffects(ctx, args) {
818
787
  try {
819
788
  const beliefSpineNode = await ctx.db.get(args.beliefId);
820
789
  const evidenceSpineNode = await ctx.db.get(args.insightId);
821
- if (beliefSpineNode && beliefSpineNode.nodeType === "belief" && evidenceSpineNode && evidenceSpineNode.nodeType === "evidence") {
790
+ if (beliefSpineNode?.nodeType === "belief" && evidenceSpineNode?.nodeType === "evidence") {
822
791
  const edges = await ctx.db.query("epistemicEdges").withIndex(
823
792
  "by_from_to",
824
793
  (q) => q.eq("fromNodeId", evidenceSpineNode._id).eq("toNodeId", beliefSpineNode._id)
@@ -836,11 +805,80 @@ async function removeOperationalLinkEffects(ctx, args) {
836
805
  console.error("[EpistemicSpine] Failed to remove informs edge:", e);
837
806
  }
838
807
  }
808
+
809
+ // src/beliefEvidenceLinks.ts
810
+ var beliefIdUnion = v.id("epistemicNodes");
811
+ var insightIdUnion = v.id("epistemicNodes");
812
+ var suggestionStatusValidator = v.union(
813
+ v.literal("suggested"),
814
+ v.literal("approved"),
815
+ v.literal("dismissed")
816
+ );
817
+ var matcherMetadataValidator = v.object({
818
+ surface: v.string(),
819
+ matcherFamily: v.optional(v.string()),
820
+ matcherKey: v.optional(v.string()),
821
+ matcherVersion: v.optional(v.string()),
822
+ reviewStatus: v.optional(
823
+ v.union(
824
+ v.literal("pending"),
825
+ v.literal("accepted"),
826
+ v.literal("rejected"),
827
+ v.literal("auto_accepted"),
828
+ v.literal("superseded")
829
+ )
830
+ ),
831
+ configSnapshot: v.optional(v.any()),
832
+ signalSnapshot: v.optional(v.any()),
833
+ outcomeMetadata: v.optional(v.any())
834
+ });
835
+ async function markProjectGraphDirty(ctx, projectId) {
836
+ if (!projectId) {
837
+ return;
838
+ }
839
+ await ctx.scheduler.runAfter(
840
+ 0,
841
+ internal.graphAnalysisCache.markCacheStaleInternal,
842
+ {
843
+ projectId
844
+ }
845
+ );
846
+ await resolveGraphPrimitivesAppResolvers().patchProject(ctx, projectId, {
847
+ lastActivityAt: Date.now()
848
+ });
849
+ }
850
+ async function recordMatcherDecision(ctx, args) {
851
+ if (!args.matcherMetadata) {
852
+ return;
853
+ }
854
+ await ctx.runMutation("matcherFeedback:recordDecision", {
855
+ projectId: args.beliefNode.projectId,
856
+ topicId: args.beliefNode.topicId,
857
+ surface: args.matcherMetadata.surface,
858
+ matcherFamily: args.matcherMetadata.matcherFamily,
859
+ matcherKey: args.matcherMetadata.matcherKey,
860
+ matcherVersion: args.matcherMetadata.matcherVersion,
861
+ sourceEntityId: String(args.insightId),
862
+ targetEntityId: String(args.beliefId),
863
+ suggestionTable: "beliefEvidenceLinks",
864
+ suggestionId: args.linkId,
865
+ reviewStatus: deriveMatcherReviewStatus({
866
+ explicitReviewStatus: args.matcherMetadata.reviewStatus,
867
+ linkStatus: args.linkStatus
868
+ }),
869
+ reviewedBy: args.reviewedBy,
870
+ decisionReason: args.decisionReason,
871
+ configSnapshot: args.matcherMetadata.configSnapshot,
872
+ signalSnapshot: args.matcherMetadata.signalSnapshot,
873
+ outcomeMetadata: args.matcherMetadata.outcomeMetadata
874
+ });
875
+ }
839
876
  var create = mutation({
840
877
  args: {
841
878
  beliefId: beliefIdUnion,
842
879
  insightId: insightIdUnion,
843
880
  relation: v.union(v.literal("supports"), v.literal("contradicts")),
881
+ weight: v.number(),
844
882
  confidence: v.optional(v.number()),
845
883
  rationale: v.optional(v.string()),
846
884
  status: v.optional(suggestionStatusValidator),
@@ -859,6 +897,16 @@ var create = mutation({
859
897
  if (!insightNode) {
860
898
  throw new Error("Evidence node not found");
861
899
  }
900
+ if (!Number.isFinite(args.weight) || args.weight === 0 || args.weight < -1 || args.weight > 1) {
901
+ throw new Error("Belief evidence links require explicit nonzero weight in [-1, 1]");
902
+ }
903
+ if (args.relation === "supports" && args.weight < 0) {
904
+ throw new Error("Supporting evidence links require positive weight");
905
+ }
906
+ if (args.relation === "contradicts" && args.weight > 0) {
907
+ throw new Error("Contradicting evidence links require negative weight");
908
+ }
909
+ const relationConfidence = Math.abs(args.weight);
862
910
  if (beliefNode.projectId) {
863
911
  const hasAccess = await checkProjectAccess(
864
912
  ctx,
@@ -883,7 +931,7 @@ var create = mutation({
883
931
  );
884
932
  await ctx.db.patch(duplicate._id, {
885
933
  relation: args.relation,
886
- confidence: args.confidence,
934
+ confidence: relationConfidence,
887
935
  rationale: args.rationale,
888
936
  status: nextStatus
889
937
  });
@@ -895,7 +943,7 @@ var create = mutation({
895
943
  beliefId: resolvedBeliefId,
896
944
  insightId: resolvedInsightId,
897
945
  relation: args.relation,
898
- confidence: args.confidence,
946
+ weight: args.weight,
899
947
  rationale: args.rationale,
900
948
  createdBy: args.createdBy
901
949
  });
@@ -911,15 +959,12 @@ var create = mutation({
911
959
  await markProjectGraphDirty(ctx, beliefNode.projectId);
912
960
  return duplicate._id;
913
961
  }
914
- if (args.confidence !== void 0 && (args.confidence < 0 || args.confidence > 1)) {
915
- throw new Error("Confidence must be between 0 and 1");
916
- }
917
962
  const now = Date.now();
918
963
  const linkId = await ctx.db.insert("beliefEvidenceLinks", {
919
964
  beliefId: args.beliefId,
920
965
  insightId: args.insightId,
921
966
  relation: args.relation,
922
- confidence: args.confidence,
967
+ confidence: relationConfidence,
923
968
  rationale: args.rationale,
924
969
  status: args.status,
925
970
  createdBy: args.createdBy,
@@ -939,7 +984,7 @@ var create = mutation({
939
984
  beliefId: resolvedBeliefId,
940
985
  insightId: resolvedInsightId,
941
986
  relation: args.relation,
942
- confidence: args.confidence,
987
+ weight: args.weight,
943
988
  rationale: args.rationale,
944
989
  createdBy: args.createdBy
945
990
  });
@@ -1047,7 +1092,7 @@ var reviewSuggestion = mutation({
1047
1092
  beliefId: link.beliefId,
1048
1093
  insightId: link.insightId,
1049
1094
  relation: link.relation,
1050
- confidence: link.confidence,
1095
+ weight: link.relation === "supports" ? Math.abs(link.confidence ?? 0) : -Math.abs(link.confidence ?? 0),
1051
1096
  rationale: link.rationale,
1052
1097
  createdBy: args.userId
1053
1098
  });