@lucern/graph-primitives 1.0.16 → 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
@@ -15,18 +15,32 @@ import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistr
15
15
  var BELIEF_STATUS_VALUES = [
16
16
  "assumption",
17
17
  "hypothesis",
18
- "belief",
19
- "fact"
20
- ];
21
- var RESOLVED_PREDICTION_OUTCOMES = [
22
- "confirmed",
23
- "disconfirmed",
24
- "partial",
25
- "expired"
18
+ "active",
19
+ "superseded",
20
+ "resolved_true",
21
+ "resolved_false"
26
22
  ];
27
23
  function isBeliefLifecycleStatus(value) {
28
24
  return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
29
25
  }
26
+ function normalizeLegacyBeliefStatus(value) {
27
+ if (isBeliefLifecycleStatus(value)) {
28
+ return value;
29
+ }
30
+ if (value === "belief" || value === "established" || value === "emerging") {
31
+ return "active";
32
+ }
33
+ if (value === "fact" || value === "confirmed") {
34
+ return "resolved_true";
35
+ }
36
+ if (value === "disconfirmed" || value === "expired") {
37
+ return "resolved_false";
38
+ }
39
+ if (value === "deprecated") {
40
+ return "superseded";
41
+ }
42
+ return null;
43
+ }
30
44
  function normalizeBeliefConfidence(confidence) {
31
45
  if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
32
46
  return null;
@@ -46,47 +60,61 @@ function isResolvedByConfidence(confidence) {
46
60
  }
47
61
  return normalized <= 0 || normalized >= 1;
48
62
  }
49
- function hasResolvedPredictionOutcome(predictionMeta) {
63
+ function getPredictionMetaFromMetadata(metadata) {
64
+ return metadata?.predictionMeta;
65
+ }
66
+ function resolvedPredictionStatus(predictionMeta) {
50
67
  if (!predictionMeta || typeof predictionMeta !== "object") {
51
- return false;
68
+ return null;
52
69
  }
53
70
  const outcome = predictionMeta.outcome;
54
- return typeof outcome === "string" && RESOLVED_PREDICTION_OUTCOMES.includes(outcome);
55
- }
56
- function getPredictionMetaFromMetadata(metadata) {
57
- return metadata?.predictionMeta;
71
+ if (outcome === "confirmed") {
72
+ return "resolved_true";
73
+ }
74
+ if (outcome === "disconfirmed" || outcome === "expired") {
75
+ return "resolved_false";
76
+ }
77
+ return null;
58
78
  }
59
- function shouldTreatBeliefAsFact(opts) {
79
+ function shouldTreatBeliefAsResolved(opts) {
60
80
  if (isResolvedByConfidence(opts.confidence)) {
61
- return true;
81
+ const normalized = normalizeBeliefConfidence(opts.confidence);
82
+ return normalized === 0 ? "resolved_false" : "resolved_true";
62
83
  }
63
- if (hasResolvedPredictionOutcome(opts.predictionMeta)) {
64
- return true;
84
+ const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
85
+ if (directPredictionStatus) {
86
+ return directPredictionStatus;
65
87
  }
66
- if (hasResolvedPredictionOutcome(getPredictionMetaFromMetadata(opts.metadata))) {
67
- return true;
88
+ const metadataPredictionStatus = resolvedPredictionStatus(
89
+ getPredictionMetaFromMetadata(opts.metadata)
90
+ );
91
+ if (metadataPredictionStatus) {
92
+ return metadataPredictionStatus;
68
93
  }
69
- return false;
94
+ return null;
70
95
  }
71
96
  function resolveBeliefLifecycleStatus(opts) {
72
- if (shouldTreatBeliefAsFact(opts)) {
73
- return "fact";
97
+ const resolvedStatus = shouldTreatBeliefAsResolved(opts);
98
+ if (resolvedStatus) {
99
+ return resolvedStatus;
74
100
  }
75
101
  const direct = opts.beliefStatus;
76
- if (isBeliefLifecycleStatus(direct)) {
102
+ const normalizedDirect = normalizeLegacyBeliefStatus(direct);
103
+ if (normalizedDirect) {
77
104
  const normalized = normalizeBeliefConfidence(opts.confidence);
78
- if (normalized !== null && isPreValidationBeliefStatus(direct)) {
79
- return "belief";
105
+ if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
106
+ return "active";
80
107
  }
81
- return direct;
108
+ return normalizedDirect;
82
109
  }
83
110
  const metaStatus = opts.metadata?.beliefStatus;
84
- if (isBeliefLifecycleStatus(metaStatus)) {
111
+ const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
112
+ if (normalizedMetaStatus) {
85
113
  const normalized = normalizeBeliefConfidence(opts.confidence);
86
- if (normalized !== null && isPreValidationBeliefStatus(metaStatus)) {
87
- return "belief";
114
+ if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
115
+ return "active";
88
116
  }
89
- return metaStatus;
117
+ return normalizedMetaStatus;
90
118
  }
91
119
  return "assumption";
92
120
  }
@@ -94,13 +122,14 @@ function isPreValidationBeliefStatus(status) {
94
122
  return status === "assumption" || status === "hypothesis";
95
123
  }
96
124
  function promoteBeliefStatusAfterScoring(status, opts) {
97
- if (shouldTreatBeliefAsFact({ ...opts })) {
98
- return "fact";
125
+ const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
126
+ if (resolvedStatus) {
127
+ return resolvedStatus;
99
128
  }
100
129
  if (isPreValidationBeliefStatus(status)) {
101
- return "belief";
130
+ return "active";
102
131
  }
103
- return status === "fact" ? "fact" : "belief";
132
+ return status;
104
133
  }
105
134
  var api = anyApi;
106
135
  componentsGeneric();
@@ -870,7 +899,7 @@ function buildBeliefConfidenceRow(args) {
870
899
  disbelief: args.disbelief,
871
900
  uncertainty: args.uncertainty,
872
901
  baseRate: args.baseRate,
873
- slOperator: args.slOperator ?? "manual_assessment",
902
+ slOperator: args.slOperator ?? "prior_seed",
874
903
  trigger: args.trigger,
875
904
  ...args.rationale ? { rationale: args.rationale } : {},
876
905
  assessedBy: args.assessedBy,
@@ -1609,17 +1638,17 @@ async function applyBeliefConfidenceChange(ctx, args) {
1609
1638
  status: 404,
1610
1639
  code: "NOT_FOUND",
1611
1640
  invariantCode: "belief.exists",
1612
- suggestion: "Verify nodeId points to an existing node before modulating confidence.",
1641
+ suggestion: "Verify nodeId points to an existing node before appending SL scoring.",
1613
1642
  details: { nodeId: args.nodeId }
1614
1643
  });
1615
1644
  }
1616
1645
  if (node.nodeType !== "belief") {
1617
1646
  throwStructuredMutationError({
1618
- message: `modulateConfidence only applies to belief nodes. Received nodeType "${node.nodeType}". Entity nodes (company, person, investor, etc.) do not have confidence \u2014 use entityLifecycle.updateEntityAttributes for mutable entity data.`,
1647
+ message: `appendSlScoring only applies to belief nodes. Received nodeType "${node.nodeType}". Entity nodes (company, person, investor, etc.) do not have confidence \u2014 use entityLifecycle.updateEntityAttributes for mutable entity data.`,
1619
1648
  status: 400,
1620
1649
  code: "INVALID_ARGUMENT",
1621
1650
  invariantCode: "entity.no_confidence",
1622
- suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. modulateConfidence is for belief nodes only.",
1651
+ suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
1623
1652
  details: { nodeId: args.nodeId, nodeType: node.nodeType }
1624
1653
  });
1625
1654
  }
@@ -1629,7 +1658,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
1629
1658
  status: 400,
1630
1659
  code: "MISSING_SCOPE",
1631
1660
  invariantCode: "belief.project_required",
1632
- suggestion: "Belief must have a projectId to modulate confidence.",
1661
+ suggestion: "Belief must have a projectId before SL scoring can be appended.",
1633
1662
  details: { nodeId: args.nodeId }
1634
1663
  });
1635
1664
  }
@@ -1652,7 +1681,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
1652
1681
  status: 409,
1653
1682
  code: "CONFLICT",
1654
1683
  invariantCode: "belief.confidence_append_only",
1655
- suggestion: "Complete a worktree linked to this belief before recording confidence modulation.",
1684
+ suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
1656
1685
  details: { nodeId: args.nodeId }
1657
1686
  });
1658
1687
  }
@@ -1907,6 +1936,199 @@ var propagateConfidenceChange = internalMutation({
1907
1936
  }
1908
1937
  });
1909
1938
 
1939
+ // src/epistemicBeliefs.forkEvidence.ts
1940
+ function normalizeForkTriggerRelation(value) {
1941
+ if (value === "supports" || value === "supporting") {
1942
+ return "supports";
1943
+ }
1944
+ if (value === "contradicts" || value === "contradicting") {
1945
+ return "contradicts";
1946
+ }
1947
+ return null;
1948
+ }
1949
+ async function resolveForkTriggerEvidence(ctx, args) {
1950
+ const evidence = await ctx.db.get(args.triggeringEvidenceId);
1951
+ if (!evidence || evidence.nodeType !== "evidence") {
1952
+ throwStructuredMutationError({
1953
+ message: "Fork requires an existing evidence node.",
1954
+ status: 400,
1955
+ code: "INVALID_ARGUMENT",
1956
+ invariantCode: "belief.fork_requires_evidence",
1957
+ suggestion: "Create or link evidence first, then fork with triggeringEvidenceId.",
1958
+ details: { triggeringEvidenceId: args.triggeringEvidenceId }
1959
+ });
1960
+ }
1961
+ if (evidence.topicId && evidence.topicId !== args.parent.topicId) {
1962
+ throwStructuredMutationError({
1963
+ message: "Fork evidence belongs to a different topic scope.",
1964
+ status: 400,
1965
+ code: "INVALID_ARGUMENT",
1966
+ invariantCode: "belief.fork_evidence_scope",
1967
+ suggestion: "Use evidence from the same topic/workspace scope as the parent belief.",
1968
+ details: {
1969
+ parentNodeId: args.parentNodeId,
1970
+ triggeringEvidenceId: args.triggeringEvidenceId
1971
+ }
1972
+ });
1973
+ }
1974
+ const evidenceMetadata = evidence.metadata && typeof evidence.metadata === "object" ? evidence.metadata : {};
1975
+ const parentRefs = new Set(
1976
+ [
1977
+ String(args.parentNodeId),
1978
+ String(args.parent.globalId ?? ""),
1979
+ String(args.parent._id)
1980
+ ].filter(Boolean)
1981
+ );
1982
+ const evidenceRefs = new Set(
1983
+ [
1984
+ String(args.triggeringEvidenceId),
1985
+ String(evidence.globalId ?? ""),
1986
+ String(evidence._id)
1987
+ ].filter(Boolean)
1988
+ );
1989
+ let relation = null;
1990
+ const linkedBeliefNodeId = String(
1991
+ evidenceMetadata.linkedBeliefNodeId ?? ""
1992
+ );
1993
+ if (linkedBeliefNodeId && parentRefs.has(linkedBeliefNodeId)) {
1994
+ relation = normalizeForkTriggerRelation(evidenceMetadata.evidenceRelation);
1995
+ }
1996
+ if (!relation) {
1997
+ for (const parentRef of parentRefs) {
1998
+ const links = await ctx.db.query("beliefEvidenceLinks").withIndex("by_beliefId", (q) => q.eq("beliefId", parentRef)).collect();
1999
+ const matched = links.find((link) => evidenceRefs.has(String(link.insightId)));
2000
+ if (matched) {
2001
+ relation = normalizeForkTriggerRelation(matched.relation);
2002
+ break;
2003
+ }
2004
+ }
2005
+ }
2006
+ if (!relation) {
2007
+ throwStructuredMutationError({
2008
+ message: "Fork evidence must already be attached to the parent belief through an SL evidence relation.",
2009
+ status: 409,
2010
+ code: "CONFLICT",
2011
+ invariantCode: "belief.fork_requires_attached_evidence",
2012
+ suggestion: "Attach the evidence to the parent belief as supports or contradicts before forking.",
2013
+ details: {
2014
+ parentNodeId: args.parentNodeId,
2015
+ triggeringEvidenceId: args.triggeringEvidenceId
2016
+ }
2017
+ });
2018
+ }
2019
+ if (args.forkMode === "supersede" && relation !== "contradicts") {
2020
+ throwStructuredMutationError({
2021
+ message: "Superseding fork requires contradicting evidence against the parent belief.",
2022
+ status: 409,
2023
+ code: "CONFLICT",
2024
+ invariantCode: "belief.supersede_requires_contradiction",
2025
+ suggestion: "Use forkMode='branch' for a non-replacing fork, or attach contradicting evidence before superseding.",
2026
+ details: {
2027
+ parentNodeId: args.parentNodeId,
2028
+ triggeringEvidenceId: args.triggeringEvidenceId,
2029
+ relation
2030
+ }
2031
+ });
2032
+ }
2033
+ return { evidenceNodeId: args.triggeringEvidenceId, relation };
2034
+ }
2035
+
2036
+ // src/epistemicBeliefs.topicAnchor.ts
2037
+ function cleanString(value) {
2038
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
2039
+ }
2040
+ function topicNodeCandidates(topicRef) {
2041
+ const normalized = topicRef.trim();
2042
+ if (!normalized) {
2043
+ return [];
2044
+ }
2045
+ const candidates = [normalized];
2046
+ if (normalized.startsWith("top_")) {
2047
+ candidates.push(normalized.slice(4));
2048
+ }
2049
+ return [...new Set(candidates)];
2050
+ }
2051
+ function readTopicNodeRef(args) {
2052
+ return cleanString(args.topicGlobalId) ?? cleanString(args.topicNodeId) ?? cleanString(args.topicId);
2053
+ }
2054
+ async function resolveRequiredTopicAnchor(ctx, topicRef) {
2055
+ for (const candidate of topicNodeCandidates(topicRef)) {
2056
+ try {
2057
+ const direct = await ctx.db.get(candidate);
2058
+ if (direct?.nodeType === "topic" && cleanString(direct.globalId)) {
2059
+ return direct;
2060
+ }
2061
+ } catch (_) {
2062
+ }
2063
+ const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
2064
+ if (byGlobalId?.nodeType === "topic" && cleanString(byGlobalId.globalId)) {
2065
+ return byGlobalId;
2066
+ }
2067
+ }
2068
+ throw new Error(
2069
+ "Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes. Legacy topics-table IDs are not valid belief anchors."
2070
+ );
2071
+ }
2072
+ function scopeFromTopicAnchor(topicNode) {
2073
+ return {
2074
+ topicId: topicNode.globalId,
2075
+ projectId: cleanString(topicNode.projectId),
2076
+ tenantId: cleanString(topicNode.tenantId),
2077
+ workspaceId: cleanString(topicNode.workspaceId),
2078
+ source: "topic"
2079
+ };
2080
+ }
2081
+ async function createRequiredBeliefTopicEdge(ctx, args) {
2082
+ const topicGlobalId = args.topicNode.globalId;
2083
+ const edgeGlobalId = `edge:${args.beliefGlobalId}:${topicGlobalId}:scoped_by`;
2084
+ const now = Date.now();
2085
+ const existing = await ctx.db.query("epistemicEdges").withIndex("by_globalId", (q) => q.eq("globalId", edgeGlobalId)).first();
2086
+ if (!existing) {
2087
+ await ctx.db.insert("epistemicEdges", {
2088
+ globalId: edgeGlobalId,
2089
+ fromNodeId: String(args.beliefNodeId),
2090
+ toNodeId: String(args.topicNode._id),
2091
+ sourceGlobalId: args.beliefGlobalId,
2092
+ targetGlobalId: topicGlobalId,
2093
+ edgeType: "scoped_by",
2094
+ weight: 1,
2095
+ confidence: 1,
2096
+ context: "Belief creation topic anchor invariant.",
2097
+ reasoningMethod: "implicit",
2098
+ derivationType: "topic_scope_invariant",
2099
+ metadata: { invariant: "belief.topic_edge_required" },
2100
+ createdBy: args.createdBy,
2101
+ createdAt: now,
2102
+ updatedAt: now,
2103
+ projectId: cleanString(args.topicNode.projectId),
2104
+ topicId: topicGlobalId,
2105
+ tenantId: cleanString(args.topicNode.tenantId),
2106
+ workspaceId: cleanString(args.topicNode.workspaceId),
2107
+ fromNodeType: "belief",
2108
+ toNodeType: "topic",
2109
+ fromLayer: "L3",
2110
+ toLayer: args.topicNode.epistemicLayer ?? "ontological"
2111
+ });
2112
+ }
2113
+ await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
2114
+ globalId: edgeGlobalId,
2115
+ fromGlobalId: args.beliefGlobalId,
2116
+ toGlobalId: topicGlobalId,
2117
+ edgeType: "scoped_by",
2118
+ weight: 1,
2119
+ confidence: 1,
2120
+ context: "Belief creation topic anchor invariant.",
2121
+ projectId: cleanString(args.topicNode.projectId),
2122
+ topicId: topicGlobalId,
2123
+ createdBy: args.createdBy,
2124
+ fromNodeType: "belief",
2125
+ toNodeType: "topic",
2126
+ fromLayer: "L3",
2127
+ toLayer: args.topicNode.epistemicLayer ?? "ontological",
2128
+ metadata: { invariant: "belief.topic_edge_required" }
2129
+ });
2130
+ }
2131
+
1910
2132
  // src/embeddingTrigger.ts
1911
2133
  async function scheduleEmbeddingGeneration(args) {
1912
2134
  try {
@@ -1952,6 +2174,8 @@ function generateGlobalId() {
1952
2174
  var create = mutation({
1953
2175
  args: {
1954
2176
  ...optionalBeliefScopeArgs,
2177
+ topicNodeId: v.optional(v.string()),
2178
+ topicGlobalId: v.optional(v.string()),
1955
2179
  formulation: v.string(),
1956
2180
  beliefType: v.optional(v.string()),
1957
2181
  rationale: v.optional(v.string()),
@@ -1996,20 +2220,32 @@ var create = mutation({
1996
2220
  returns: permissiveReturn,
1997
2221
  handler: async (ctx, args) => {
1998
2222
  const authenticatedUserId = await requireAuthenticatedUserId(ctx);
1999
- const scope = await resolveTopicProjectScope(ctx, {
2000
- topicId: args.topicId,
2001
- projectId: args.projectId
2002
- });
2223
+ const topicRef = readTopicNodeRef(args);
2224
+ if (!topicRef) {
2225
+ throwStructuredMutationError({
2226
+ message: "Belief creation requires an explicit topic epistemic node.",
2227
+ status: 400,
2228
+ code: "INVALID_ARGUMENT",
2229
+ invariantCode: "belief.topic_node_required",
2230
+ suggestion: "Pass topicGlobalId or topicNodeId for a topic in epistemicNodes before creating a belief.",
2231
+ details: {
2232
+ topicId: args.topicId,
2233
+ topicNodeId: args.topicNodeId,
2234
+ topicGlobalId: args.topicGlobalId
2235
+ }
2236
+ });
2237
+ }
2238
+ const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
2239
+ const scope = scopeFromTopicAnchor(topicNode);
2003
2240
  assertWorkspaceScopedEpistemicNodeScope({
2004
2241
  scope,
2005
2242
  nodeType: "belief",
2006
2243
  mutationName: "epistemicBeliefs.create"
2007
2244
  });
2008
- const topic = await ctx.db.get(scope.topicId);
2009
2245
  const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
2010
2246
  category: "belief_type",
2011
2247
  value: args.beliefType,
2012
- tenantId: topic?.tenantId,
2248
+ tenantId: scope.tenantId,
2013
2249
  context: "epistemicBeliefs.create"
2014
2250
  });
2015
2251
  if (scope.projectId) {
@@ -2042,7 +2278,7 @@ var create = mutation({
2042
2278
  title: args.formulation.slice(0, 100) + (args.formulation.length > 100 ? "..." : ""),
2043
2279
  metadata: {
2044
2280
  pillar,
2045
- // No confidenceLevel — only set after worktree completion via modulateConfidence()
2281
+ // No confidenceLevel — only set after evidence-backed SL scoring.
2046
2282
  status: "active",
2047
2283
  worktreeId: args.worktreeId,
2048
2284
  beliefStatus: initialBeliefStatus,
@@ -2086,9 +2322,15 @@ var create = mutation({
2086
2322
  rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
2087
2323
  assessedBy: authenticatedUserId,
2088
2324
  assessedAt: now,
2089
- slOperator: "manual_assessment"
2325
+ slOperator: "prior_seed"
2090
2326
  })
2091
2327
  );
2328
+ await createRequiredBeliefTopicEdge(ctx, {
2329
+ beliefNodeId: nodeId,
2330
+ beliefGlobalId,
2331
+ topicNode,
2332
+ createdBy: authenticatedUserId
2333
+ });
2092
2334
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
2093
2335
  nodeId,
2094
2336
  operation: "upsert"
@@ -2425,9 +2667,10 @@ var forkBelief = mutation({
2425
2667
  v.literal("refinement"),
2426
2668
  v.literal("contradiction_response"),
2427
2669
  v.literal("scope_change"),
2428
- v.literal("confidence_collapse"),
2429
- v.literal("manual")
2670
+ v.literal("confidence_collapse")
2430
2671
  ),
2672
+ forkMode: v.optional(v.union(v.literal("supersede"), v.literal("branch"))),
2673
+ triggeringEvidenceId: v.id("epistemicNodes"),
2431
2674
  rationale: v.optional(v.string()),
2432
2675
  userId: v.string()
2433
2676
  },
@@ -2470,6 +2713,33 @@ var forkBelief = mutation({
2470
2713
  await requireProjectWriteAccess(ctx, parent.projectId, authenticatedUserId);
2471
2714
  const metadata = parent.metadata;
2472
2715
  const forkBeliefStatus = "hypothesis";
2716
+ const forkMode = args.forkMode ?? "supersede";
2717
+ const triggerEvidence = await resolveForkTriggerEvidence(ctx, {
2718
+ parentNodeId: args.parentNodeId,
2719
+ parent,
2720
+ triggeringEvidenceId: args.triggeringEvidenceId,
2721
+ forkMode
2722
+ });
2723
+ const parentLifecycleStatus = resolveBeliefLifecycleStatus({
2724
+ beliefStatus: parent.beliefStatus,
2725
+ confidence: parent.confidence,
2726
+ predictionMeta: parent.predictionMeta,
2727
+ metadata
2728
+ });
2729
+ if (forkMode === "supersede" && parentLifecycleStatus !== "active") {
2730
+ throwStructuredMutationError({
2731
+ message: "Superseding fork requires an active parent belief. Attach evidence first so the lifecycle can promote deterministically.",
2732
+ status: 409,
2733
+ code: "CONFLICT",
2734
+ invariantCode: "belief.supersede_requires_active_parent",
2735
+ suggestion: "Attach the contradicting evidence to the parent belief, let the evidence path promote it to active, then supersede.",
2736
+ details: {
2737
+ parentNodeId: args.parentNodeId,
2738
+ parentLifecycleStatus,
2739
+ triggeringEvidenceId: args.triggeringEvidenceId
2740
+ }
2741
+ });
2742
+ }
2473
2743
  const newBeliefGlobalId = generateGlobalId();
2474
2744
  const newNodeId = await ctx.db.insert("epistemicNodes", {
2475
2745
  globalId: newBeliefGlobalId,
@@ -2483,6 +2753,9 @@ var forkBelief = mutation({
2483
2753
  ...metadata,
2484
2754
  forkedFrom: args.parentNodeId,
2485
2755
  forkReason: args.forkReason,
2756
+ forkMode,
2757
+ triggeringEvidenceId: args.triggeringEvidenceId,
2758
+ triggeringEvidenceRelation: triggerEvidence.relation,
2486
2759
  forkTimestamp: now,
2487
2760
  forkedBy: authenticatedUserId,
2488
2761
  status: "active",
@@ -2501,6 +2774,27 @@ var forkBelief = mutation({
2501
2774
  createdAt: now,
2502
2775
  updatedAt: now
2503
2776
  });
2777
+ if (forkMode === "supersede") {
2778
+ await ctx.db.patch(args.parentNodeId, {
2779
+ status: "superseded",
2780
+ beliefStatus: "superseded",
2781
+ epistemicStatus: "superseded",
2782
+ supersededBy: newNodeId,
2783
+ updatedAt: now,
2784
+ metadata: {
2785
+ ...metadata ?? {},
2786
+ status: "superseded",
2787
+ beliefStatus: "superseded",
2788
+ epistemicStatus: "superseded",
2789
+ supersededBy: String(newNodeId),
2790
+ supersededByEvidenceId: String(triggerEvidence.evidenceNodeId)
2791
+ }
2792
+ });
2793
+ await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
2794
+ nodeId: args.parentNodeId,
2795
+ operation: "upsert"
2796
+ });
2797
+ }
2504
2798
  const inheritedContracts = await ctx.db.query("epistemicContracts").withIndex(
2505
2799
  "by_belief",
2506
2800
  (q) => q.eq("beliefNodeId", args.parentNodeId)
@@ -2527,12 +2821,17 @@ var forkBelief = mutation({
2527
2821
  globalId: generateGlobalId(),
2528
2822
  fromGlobalId: newBeliefGlobalId,
2529
2823
  toGlobalId: parent.globalId,
2530
- edgeType: "supersedes",
2531
- context: `Fork reason: ${args.forkReason}`,
2824
+ edgeType: forkMode === "supersede" ? "supersedes" : "derived_from",
2825
+ context: `Fork reason: ${args.forkReason}; triggering evidence: ${triggerEvidence.evidenceNodeId}`,
2532
2826
  createdBy: authenticatedUserId,
2533
2827
  topicId: parent.projectId ? String(parent.projectId) : void 0,
2534
2828
  fromNodeType: "belief",
2535
- toNodeType: "belief"
2829
+ toNodeType: "belief",
2830
+ metadata: {
2831
+ forkMode,
2832
+ triggeringEvidenceId: String(triggerEvidence.evidenceNodeId),
2833
+ triggeringEvidenceRelation: triggerEvidence.relation
2834
+ }
2536
2835
  });
2537
2836
  await scheduleEmbeddingGeneration({
2538
2837
  ctx,
@@ -2557,6 +2856,9 @@ var forkBelief = mutation({
2557
2856
  newState: {
2558
2857
  formulation: args.newFormulation,
2559
2858
  forkReason: args.forkReason,
2859
+ forkMode,
2860
+ triggeringEvidenceId: String(triggerEvidence.evidenceNodeId),
2861
+ triggeringEvidenceRelation: triggerEvidence.relation,
2560
2862
  tupleContradicted: false
2561
2863
  },
2562
2864
  projectId: parent.projectId,
@@ -2591,10 +2893,17 @@ var forkBelief = mutation({
2591
2893
  projectId: parent.projectId,
2592
2894
  topicId: parent.topicId
2593
2895
  });
2594
- return { newNodeId, parentNodeId: args.parentNodeId };
2896
+ return {
2897
+ newNodeId,
2898
+ parentNodeId: args.parentNodeId,
2899
+ forkMode,
2900
+ forkReason: args.forkReason,
2901
+ triggeringEvidenceId: triggerEvidence.evidenceNodeId,
2902
+ triggeringEvidenceRelation: triggerEvidence.relation
2903
+ };
2595
2904
  }
2596
2905
  });
2597
- var modulateConfidence = mutation({
2906
+ var appendSlScoring = mutation({
2598
2907
  args: {
2599
2908
  nodeId: v.id("epistemicNodes"),
2600
2909
  // SL opinion — the ONLY confidence input (EK-7)
@@ -2611,8 +2920,6 @@ var modulateConfidence = mutation({
2611
2920
  v.literal("evidence_removed"),
2612
2921
  v.literal("contradiction_detected"),
2613
2922
  v.literal("contradiction_resolved"),
2614
- v.literal("manual"),
2615
- v.literal("decay"),
2616
2923
  v.literal("agent_assessment"),
2617
2924
  v.literal("worktree_outcome"),
2618
2925
  v.literal("worktree_completed"),
@@ -2624,7 +2931,7 @@ var modulateConfidence = mutation({
2624
2931
  ),
2625
2932
  rationale: v.optional(v.string()),
2626
2933
  userId: v.string(),
2627
- // SL operator provenance (optional — defaults to manual_assessment)
2934
+ // SL operator provenance (optional — defaults inside the SL scorer)
2628
2935
  slOperator: v.optional(
2629
2936
  v.union(
2630
2937
  v.literal("cumulative_fusion"),
@@ -2634,7 +2941,8 @@ var modulateConfidence = mutation({
2634
2941
  v.literal("dependency_cascade"),
2635
2942
  v.literal("negation"),
2636
2943
  v.literal("constraint_fusion"),
2637
- v.literal("manual_assessment")
2944
+ v.literal("no_op"),
2945
+ v.literal("prior_seed")
2638
2946
  )
2639
2947
  ),
2640
2948
  triggeringEvidenceId: v.optional(v.id("epistemicNodes")),
@@ -2997,6 +3305,12 @@ async function getQuestionsAnsweredByEvidence(ctx, evidenceId) {
2997
3305
  }
2998
3306
 
2999
3307
  // src/epistemicBeliefs.links.ts
3308
+ function assertSignedImpactScore(value, context) {
3309
+ if (typeof value !== "number" || !Number.isFinite(value) || value === 0 || value < -1 || value > 1) {
3310
+ throw new Error(`${context} requires explicit nonzero weight in [-1, 1]`);
3311
+ }
3312
+ return value;
3313
+ }
3000
3314
  var updatePillar = mutation({
3001
3315
  args: {
3002
3316
  nodeId: v.id("epistemicNodes"),
@@ -3176,6 +3490,7 @@ var linkEvidence = mutation({
3176
3490
  beliefNodeId: v.id("epistemicNodes"),
3177
3491
  insightId: insightIdUnion,
3178
3492
  type: v.union(v.literal("supporting"), v.literal("contradicting")),
3493
+ weight: v.number(),
3179
3494
  rationale: v.optional(v.string()),
3180
3495
  userId: v.string()
3181
3496
  },
@@ -3199,16 +3514,54 @@ var linkEvidence = mutation({
3199
3514
  }
3200
3515
  const evidenceNodeId = insight._id;
3201
3516
  const evidenceGlobalId = insight.globalId;
3517
+ const weight = assertSignedImpactScore(args.weight, "Evidence link");
3518
+ if (args.type === "supporting" && weight < 0) {
3519
+ throw new Error("Supporting evidence links require positive weight");
3520
+ }
3521
+ if (args.type === "contradicting" && weight > 0) {
3522
+ throw new Error("Contradicting evidence links require negative weight");
3523
+ }
3524
+ const confidence = Math.abs(weight);
3202
3525
  const edgeType = "informs";
3203
- const weight = args.type === "supporting" ? 1 : -1;
3204
3526
  const logicalRole = evidenceNodeId ? await computeLogicalRole(ctx, evidenceNodeId, args.beliefNodeId) : "contributory";
3205
3527
  const edgeGlobalId = generateGlobalId();
3528
+ await ctx.db.insert("epistemicEdges", {
3529
+ globalId: edgeGlobalId,
3530
+ fromNodeId: evidenceNodeId,
3531
+ toNodeId: args.beliefNodeId,
3532
+ sourceGlobalId: evidenceGlobalId,
3533
+ targetGlobalId: belief.globalId,
3534
+ edgeType,
3535
+ weight,
3536
+ confidence,
3537
+ context: args.rationale || `${args.type} evidence`,
3538
+ reasoningMethod: "testimonial",
3539
+ logicalRole,
3540
+ temporalClass: "structural",
3541
+ derivationType: "evidence_sl_scoring",
3542
+ metadata: {
3543
+ relation: args.type,
3544
+ confidence,
3545
+ impactScore: weight,
3546
+ invariant: "evidence.belief_impact_required"
3547
+ },
3548
+ createdBy: authenticatedUserId,
3549
+ createdAt: Date.now(),
3550
+ updatedAt: Date.now(),
3551
+ topicId: belief.topicId ? String(belief.topicId) : void 0,
3552
+ projectId: belief.projectId ? String(belief.projectId) : void 0,
3553
+ fromNodeType: "evidence",
3554
+ toNodeType: "belief",
3555
+ fromLayer: "L2",
3556
+ toLayer: "L3"
3557
+ });
3206
3558
  await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
3207
3559
  globalId: edgeGlobalId,
3208
3560
  fromGlobalId: evidenceGlobalId,
3209
3561
  toGlobalId: belief.globalId,
3210
3562
  edgeType,
3211
3563
  weight,
3564
+ confidence,
3212
3565
  context: args.rationale || `${args.type} evidence`,
3213
3566
  createdBy: authenticatedUserId,
3214
3567
  topicId: belief.projectId ? String(belief.projectId) : void 0,
@@ -3839,6 +4192,8 @@ var internalGetById = internalQuery({
3839
4192
  var internalCreate = internalMutation({
3840
4193
  args: {
3841
4194
  ...optionalBeliefScopeArgs,
4195
+ topicNodeId: v.optional(v.string()),
4196
+ topicGlobalId: v.optional(v.string()),
3842
4197
  formulation: v.string(),
3843
4198
  baseRate: v.optional(v.number()),
3844
4199
  confidence: v.optional(
@@ -3877,10 +4232,14 @@ var internalCreate = internalMutation({
3877
4232
  handler: async (ctx, args) => {
3878
4233
  const now = Date.now();
3879
4234
  const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
3880
- const scope = await resolveTopicProjectScope(ctx, {
3881
- topicId: args.topicId,
3882
- projectId: args.projectId
3883
- });
4235
+ const topicRef = readTopicNodeRef(args);
4236
+ if (!topicRef) {
4237
+ throw new Error(
4238
+ "Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes."
4239
+ );
4240
+ }
4241
+ const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
4242
+ const scope = scopeFromTopicAnchor(topicNode);
3884
4243
  assertWorkspaceScopedEpistemicNodeScope({
3885
4244
  scope,
3886
4245
  nodeType: "belief",
@@ -3896,11 +4255,10 @@ var internalCreate = internalMutation({
3896
4255
  },
3897
4256
  mutationName: "epistemicBeliefs.internalCreate"
3898
4257
  });
3899
- const topic = await ctx.db.get(scope.topicId);
3900
4258
  const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
3901
4259
  category: "belief_type",
3902
4260
  value: args.beliefType,
3903
- tenantId: topic?.tenantId,
4261
+ tenantId: scope.tenantId,
3904
4262
  context: "epistemicBeliefs.internalCreate"
3905
4263
  });
3906
4264
  const globalId = generateGlobalId();
@@ -3964,9 +4322,15 @@ var internalCreate = internalMutation({
3964
4322
  rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
3965
4323
  assessedBy: args.userId,
3966
4324
  assessedAt: now,
3967
- slOperator: "manual_assessment"
4325
+ slOperator: "prior_seed"
3968
4326
  })
3969
4327
  );
4328
+ await createRequiredBeliefTopicEdge(ctx, {
4329
+ beliefNodeId: nodeId,
4330
+ beliefGlobalId: globalId,
4331
+ topicNode,
4332
+ createdBy: args.userId
4333
+ });
3970
4334
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
3971
4335
  nodeId,
3972
4336
  operation: "upsert"
@@ -4140,7 +4504,7 @@ var backfillSyntheticOpinionHistory = internalMutation({
4140
4504
  rationale: "LK-6 backfill: synthesized t0 from node-level opinion fields (no prior beliefConfidence row found).",
4141
4505
  assessedAt: readFiniteNumber(node.createdAt) ?? readFiniteNumber(node.updatedAt) ?? Date.now(),
4142
4506
  assessedBy: "system:lk-6-backfill",
4143
- slOperator: "manual_assessment"
4507
+ slOperator: "prior_seed"
4144
4508
  })
4145
4509
  );
4146
4510
  beliefsWithHistory.add(String(node._id));
@@ -4246,7 +4610,7 @@ var backfillMandatoryPriors = internalMutation({
4246
4610
  rationale: "LKC-2 backfill: inserted missing initial vacuous opinion with neutral prior.",
4247
4611
  assessedAt: readFiniteNumber(node.createdAt) ?? readFiniteNumber(node.updatedAt) ?? Date.now(),
4248
4612
  assessedBy: "system:lkc-2-prior-backfill",
4249
- slOperator: "manual_assessment"
4613
+ slOperator: "prior_seed"
4250
4614
  })
4251
4615
  );
4252
4616
  insertedInitialRows++;
@@ -4354,7 +4718,7 @@ var backfillScoredBeliefEdges = internalMutation({
4354
4718
  const scoredBeliefs = allBeliefs.filter((belief) => {
4355
4719
  const metadata = belief.metadata || {};
4356
4720
  const lifecycle = resolveBeliefStatus(belief, metadata);
4357
- return lifecycle === "belief" || lifecycle === "fact";
4721
+ return lifecycle === "active" || lifecycle === "resolved_true";
4358
4722
  });
4359
4723
  const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
4360
4724
  "by_topic",
@@ -4540,6 +4904,6 @@ var reassignBeliefsTopic = mutation({
4540
4904
  }
4541
4905
  });
4542
4906
 
4543
- export { applyBeliefConfidenceChange, archive, backfillBeliefSprintIds, backfillMandatoryPriors, backfillScoredBeliefEdges, backfillSyntheticOpinionHistory, backfillTwoAxisConfidence, batchUpdateCriticality, create, deleteRelationship, flattenBeliefNode, forkBelief, getBeliefClusterPositions, getByCriticality, getById, getByIds, getByPillar, getByProject, getByProjectSystem, getByTopic, getByWorktree, getConfidenceHistory, getCountByStatus, getLineage, getRecentConfidenceChanges, getRelationships, getUnanalyzed, getWithEvidence, getWorktreeCluster, internalCreate, internalGetActive, internalGetById, internalGetByProject, internalGetByTopic, linkBeliefs, linkEvidence, modulateConfidence, propagateConfidenceChange, reassignBeliefsTopic, refineBelief, resolveBeliefWorktreeId, unlinkEvidence, updateCriticality, updatePillar, updateRationale, updateStatus, updateStatusInternal };
4907
+ export { appendSlScoring, applyBeliefConfidenceChange, archive, backfillBeliefSprintIds, backfillMandatoryPriors, backfillScoredBeliefEdges, backfillSyntheticOpinionHistory, backfillTwoAxisConfidence, batchUpdateCriticality, create, deleteRelationship, flattenBeliefNode, forkBelief, getBeliefClusterPositions, getByCriticality, getById, getByIds, getByPillar, getByProject, getByProjectSystem, getByTopic, getByWorktree, getConfidenceHistory, getCountByStatus, getLineage, getRecentConfidenceChanges, getRelationships, getUnanalyzed, getWithEvidence, getWorktreeCluster, internalCreate, internalGetActive, internalGetById, internalGetByProject, internalGetByTopic, linkBeliefs, linkEvidence, propagateConfidenceChange, reassignBeliefsTopic, refineBelief, resolveBeliefWorktreeId, unlinkEvidence, updateCriticality, updatePillar, updateRationale, updateStatus, updateStatusInternal };
4544
4908
  //# sourceMappingURL=epistemicBeliefs.js.map
4545
4909
  //# sourceMappingURL=epistemicBeliefs.js.map