@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.
- package/dist/beliefEvidenceLinks.js +144 -99
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/beliefEvidenceLinks.operational.d.ts +29 -0
- package/dist/beliefEvidenceLinks.operational.js +157 -0
- package/dist/beliefEvidenceLinks.operational.js.map +1 -0
- package/dist/{beliefLifecycle-y8WLXqQj.d.ts → beliefLifecycle-CXwdDw5e.d.ts} +7 -4
- package/dist/beliefLifecycle.d.ts +1 -1
- package/dist/beliefLifecycle.js +75 -18
- package/dist/beliefLifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.d.ts +1 -1
- package/dist/epistemicBeliefs.backfills.js +63 -35
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.d.ts +1 -1
- package/dist/epistemicBeliefs.confidence.js +70 -41
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.js +957 -566
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.d.ts +2 -2
- package/dist/epistemicBeliefs.forkEvidence.d.ts +18 -0
- package/dist/epistemicBeliefs.forkEvidence.js +121 -0
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -0
- package/dist/epistemicBeliefs.helpers.d.ts +2 -2
- package/dist/epistemicBeliefs.helpers.js +60 -32
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.js +174 -39
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +436 -72
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +2 -2
- package/dist/epistemicBeliefs.lifecycle.js +75 -47
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.js +46 -1
- package/dist/epistemicBeliefs.links.js.map +1 -1
- package/dist/epistemicBeliefs.topicAnchor.d.ts +29 -0
- package/dist/epistemicBeliefs.topicAnchor.js +105 -0
- package/dist/epistemicBeliefs.topicAnchor.js.map +1 -0
- package/dist/epistemicContracts.evaluators.js +71 -42
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.js +71 -42
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +71 -42
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicContracts.metrics.js +1 -1
- package/dist/epistemicContracts.metrics.js.map +1 -1
- package/dist/epistemicContracts.types.d.ts +1 -1
- package/dist/epistemicEdges.helpers.d.ts +1 -1
- package/dist/epistemicEvidence.js +172 -81
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceMutations.js +172 -81
- package/dist/epistemicEvidenceMutations.js.map +1 -1
- package/dist/epistemicNodes.internal.js.map +1 -1
- package/dist/epistemicNodes.js +2 -2
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.js +2 -2
- package/dist/epistemicNodes.mutations.js.map +1 -1
- package/dist/evaluators/index.js +1 -1
- package/dist/evaluators/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +767 -236
- package/dist/index.js.map +1 -1
- package/dist/invariantEnforcement.js +2 -2
- package/dist/invariantEnforcement.js.map +1 -1
- package/dist/proof-attestation.json +3 -3
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -689,6 +689,7 @@ __export(beliefLifecycle_exports, {
|
|
|
689
689
|
isPreValidationBeliefStatus: () => isPreValidationBeliefStatus,
|
|
690
690
|
isPropagationEligibleBeliefStatus: () => isPropagationEligibleBeliefStatus,
|
|
691
691
|
isResolvedByConfidence: () => isResolvedByConfidence,
|
|
692
|
+
promoteBeliefStatusAfterEvidence: () => promoteBeliefStatusAfterEvidence,
|
|
692
693
|
promoteBeliefStatusAfterScoring: () => promoteBeliefStatusAfterScoring,
|
|
693
694
|
resolveBeliefLifecycleStatus: () => resolveBeliefLifecycleStatus,
|
|
694
695
|
shouldTreatBeliefAsFact: () => shouldTreatBeliefAsFact
|
|
@@ -696,8 +697,10 @@ __export(beliefLifecycle_exports, {
|
|
|
696
697
|
var BELIEF_STATUS_VALUES = [
|
|
697
698
|
"assumption",
|
|
698
699
|
"hypothesis",
|
|
699
|
-
"
|
|
700
|
-
"
|
|
700
|
+
"active",
|
|
701
|
+
"superseded",
|
|
702
|
+
"resolved_true",
|
|
703
|
+
"resolved_false"
|
|
701
704
|
];
|
|
702
705
|
var RESOLVED_PREDICTION_OUTCOMES = [
|
|
703
706
|
"confirmed",
|
|
@@ -708,6 +711,24 @@ var RESOLVED_PREDICTION_OUTCOMES = [
|
|
|
708
711
|
function isBeliefLifecycleStatus(value) {
|
|
709
712
|
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
710
713
|
}
|
|
714
|
+
function normalizeLegacyBeliefStatus(value) {
|
|
715
|
+
if (isBeliefLifecycleStatus(value)) {
|
|
716
|
+
return value;
|
|
717
|
+
}
|
|
718
|
+
if (value === "belief" || value === "established" || value === "emerging") {
|
|
719
|
+
return "active";
|
|
720
|
+
}
|
|
721
|
+
if (value === "fact" || value === "confirmed") {
|
|
722
|
+
return "resolved_true";
|
|
723
|
+
}
|
|
724
|
+
if (value === "disconfirmed" || value === "expired") {
|
|
725
|
+
return "resolved_false";
|
|
726
|
+
}
|
|
727
|
+
if (value === "deprecated") {
|
|
728
|
+
return "superseded";
|
|
729
|
+
}
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
711
732
|
function normalizeBeliefConfidence(confidence) {
|
|
712
733
|
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
713
734
|
return null;
|
|
@@ -749,25 +770,58 @@ function shouldTreatBeliefAsFact(opts) {
|
|
|
749
770
|
}
|
|
750
771
|
return false;
|
|
751
772
|
}
|
|
773
|
+
function resolvedPredictionStatus(predictionMeta) {
|
|
774
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
const outcome = predictionMeta.outcome;
|
|
778
|
+
if (outcome === "confirmed") {
|
|
779
|
+
return "resolved_true";
|
|
780
|
+
}
|
|
781
|
+
if (outcome === "disconfirmed" || outcome === "expired") {
|
|
782
|
+
return "resolved_false";
|
|
783
|
+
}
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
function shouldTreatBeliefAsResolved(opts) {
|
|
787
|
+
if (isResolvedByConfidence(opts.confidence)) {
|
|
788
|
+
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
789
|
+
return normalized === 0 ? "resolved_false" : "resolved_true";
|
|
790
|
+
}
|
|
791
|
+
const directPredictionStatus = resolvedPredictionStatus(opts.predictionMeta);
|
|
792
|
+
if (directPredictionStatus) {
|
|
793
|
+
return directPredictionStatus;
|
|
794
|
+
}
|
|
795
|
+
const metadataPredictionStatus = resolvedPredictionStatus(
|
|
796
|
+
getPredictionMetaFromMetadata(opts.metadata)
|
|
797
|
+
);
|
|
798
|
+
if (metadataPredictionStatus) {
|
|
799
|
+
return metadataPredictionStatus;
|
|
800
|
+
}
|
|
801
|
+
return null;
|
|
802
|
+
}
|
|
752
803
|
function resolveBeliefLifecycleStatus(opts) {
|
|
753
|
-
|
|
754
|
-
|
|
804
|
+
const resolvedStatus = shouldTreatBeliefAsResolved(opts);
|
|
805
|
+
if (resolvedStatus) {
|
|
806
|
+
return resolvedStatus;
|
|
755
807
|
}
|
|
756
808
|
const direct = opts.beliefStatus;
|
|
757
|
-
|
|
809
|
+
const normalizedDirect = normalizeLegacyBeliefStatus(direct);
|
|
810
|
+
if (normalizedDirect) {
|
|
758
811
|
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
759
|
-
if (normalized !== null && isPreValidationBeliefStatus(
|
|
760
|
-
return "
|
|
812
|
+
if (normalized !== null && isPreValidationBeliefStatus(normalizedDirect)) {
|
|
813
|
+
return "active";
|
|
761
814
|
}
|
|
762
|
-
return
|
|
815
|
+
return normalizedDirect;
|
|
763
816
|
}
|
|
764
817
|
const metaStatus = opts.metadata?.beliefStatus;
|
|
765
|
-
|
|
818
|
+
const normalizedMetaStatus = normalizeLegacyBeliefStatus(metaStatus);
|
|
819
|
+
if (normalizedMetaStatus) {
|
|
766
820
|
const normalized = normalizeBeliefConfidence(opts.confidence);
|
|
767
|
-
if (normalized !== null && isPreValidationBeliefStatus(
|
|
768
|
-
return "
|
|
821
|
+
if (normalized !== null && isPreValidationBeliefStatus(normalizedMetaStatus)) {
|
|
822
|
+
return "active";
|
|
769
823
|
}
|
|
770
|
-
return
|
|
824
|
+
return normalizedMetaStatus;
|
|
771
825
|
}
|
|
772
826
|
return "assumption";
|
|
773
827
|
}
|
|
@@ -775,16 +829,20 @@ function isPreValidationBeliefStatus(status) {
|
|
|
775
829
|
return status === "assumption" || status === "hypothesis";
|
|
776
830
|
}
|
|
777
831
|
function isPropagationEligibleBeliefStatus(status) {
|
|
778
|
-
return status === "
|
|
832
|
+
return status === "active" || status === "resolved_true";
|
|
779
833
|
}
|
|
780
834
|
function promoteBeliefStatusAfterScoring(status, opts) {
|
|
781
|
-
|
|
782
|
-
|
|
835
|
+
const resolvedStatus = shouldTreatBeliefAsResolved({ ...opts });
|
|
836
|
+
if (resolvedStatus) {
|
|
837
|
+
return resolvedStatus;
|
|
783
838
|
}
|
|
784
839
|
if (isPreValidationBeliefStatus(status)) {
|
|
785
|
-
return "
|
|
840
|
+
return "active";
|
|
786
841
|
}
|
|
787
|
-
return status
|
|
842
|
+
return status;
|
|
843
|
+
}
|
|
844
|
+
function promoteBeliefStatusAfterEvidence(status) {
|
|
845
|
+
return isPreValidationBeliefStatus(status) ? "active" : status;
|
|
788
846
|
}
|
|
789
847
|
var api = anyApi;
|
|
790
848
|
componentsGeneric();
|
|
@@ -1607,7 +1665,7 @@ function buildBeliefConfidenceRow(args) {
|
|
|
1607
1665
|
disbelief: args.disbelief,
|
|
1608
1666
|
uncertainty: args.uncertainty,
|
|
1609
1667
|
baseRate: args.baseRate,
|
|
1610
|
-
slOperator: args.slOperator ?? "
|
|
1668
|
+
slOperator: args.slOperator ?? "prior_seed",
|
|
1611
1669
|
trigger: args.trigger,
|
|
1612
1670
|
...args.rationale ? { rationale: args.rationale } : {},
|
|
1613
1671
|
assessedBy: args.assessedBy,
|
|
@@ -2061,17 +2119,17 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
2061
2119
|
status: 404,
|
|
2062
2120
|
code: "NOT_FOUND",
|
|
2063
2121
|
invariantCode: "belief.exists",
|
|
2064
|
-
suggestion: "Verify nodeId points to an existing node before
|
|
2122
|
+
suggestion: "Verify nodeId points to an existing node before appending SL scoring.",
|
|
2065
2123
|
details: { nodeId: args.nodeId }
|
|
2066
2124
|
});
|
|
2067
2125
|
}
|
|
2068
2126
|
if (node.nodeType !== "belief") {
|
|
2069
2127
|
throwStructuredMutationError({
|
|
2070
|
-
message: `
|
|
2128
|
+
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.`,
|
|
2071
2129
|
status: 400,
|
|
2072
2130
|
code: "INVALID_ARGUMENT",
|
|
2073
2131
|
invariantCode: "entity.no_confidence",
|
|
2074
|
-
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations.
|
|
2132
|
+
suggestion: "Use entityLifecycle.updateEntityAttributes for entity mutations. appendSlScoring is for belief nodes only.",
|
|
2075
2133
|
details: { nodeId: args.nodeId, nodeType: node.nodeType }
|
|
2076
2134
|
});
|
|
2077
2135
|
}
|
|
@@ -2081,7 +2139,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
2081
2139
|
status: 400,
|
|
2082
2140
|
code: "MISSING_SCOPE",
|
|
2083
2141
|
invariantCode: "belief.project_required",
|
|
2084
|
-
suggestion: "Belief must have a projectId
|
|
2142
|
+
suggestion: "Belief must have a projectId before SL scoring can be appended.",
|
|
2085
2143
|
details: { nodeId: args.nodeId }
|
|
2086
2144
|
});
|
|
2087
2145
|
}
|
|
@@ -2104,7 +2162,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
2104
2162
|
status: 409,
|
|
2105
2163
|
code: "CONFLICT",
|
|
2106
2164
|
invariantCode: "belief.confidence_append_only",
|
|
2107
|
-
suggestion: "Complete a worktree linked to this belief before recording
|
|
2165
|
+
suggestion: "Complete a worktree linked to this belief before recording SL scoring.",
|
|
2108
2166
|
details: { nodeId: args.nodeId }
|
|
2109
2167
|
});
|
|
2110
2168
|
}
|
|
@@ -2359,6 +2417,199 @@ var propagateConfidenceChange = internalMutation({
|
|
|
2359
2417
|
}
|
|
2360
2418
|
});
|
|
2361
2419
|
|
|
2420
|
+
// src/epistemicBeliefs.forkEvidence.ts
|
|
2421
|
+
function normalizeForkTriggerRelation(value) {
|
|
2422
|
+
if (value === "supports" || value === "supporting") {
|
|
2423
|
+
return "supports";
|
|
2424
|
+
}
|
|
2425
|
+
if (value === "contradicts" || value === "contradicting") {
|
|
2426
|
+
return "contradicts";
|
|
2427
|
+
}
|
|
2428
|
+
return null;
|
|
2429
|
+
}
|
|
2430
|
+
async function resolveForkTriggerEvidence(ctx, args) {
|
|
2431
|
+
const evidence = await ctx.db.get(args.triggeringEvidenceId);
|
|
2432
|
+
if (!evidence || evidence.nodeType !== "evidence") {
|
|
2433
|
+
throwStructuredMutationError({
|
|
2434
|
+
message: "Fork requires an existing evidence node.",
|
|
2435
|
+
status: 400,
|
|
2436
|
+
code: "INVALID_ARGUMENT",
|
|
2437
|
+
invariantCode: "belief.fork_requires_evidence",
|
|
2438
|
+
suggestion: "Create or link evidence first, then fork with triggeringEvidenceId.",
|
|
2439
|
+
details: { triggeringEvidenceId: args.triggeringEvidenceId }
|
|
2440
|
+
});
|
|
2441
|
+
}
|
|
2442
|
+
if (evidence.topicId && evidence.topicId !== args.parent.topicId) {
|
|
2443
|
+
throwStructuredMutationError({
|
|
2444
|
+
message: "Fork evidence belongs to a different topic scope.",
|
|
2445
|
+
status: 400,
|
|
2446
|
+
code: "INVALID_ARGUMENT",
|
|
2447
|
+
invariantCode: "belief.fork_evidence_scope",
|
|
2448
|
+
suggestion: "Use evidence from the same topic/workspace scope as the parent belief.",
|
|
2449
|
+
details: {
|
|
2450
|
+
parentNodeId: args.parentNodeId,
|
|
2451
|
+
triggeringEvidenceId: args.triggeringEvidenceId
|
|
2452
|
+
}
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2455
|
+
const evidenceMetadata = evidence.metadata && typeof evidence.metadata === "object" ? evidence.metadata : {};
|
|
2456
|
+
const parentRefs = new Set(
|
|
2457
|
+
[
|
|
2458
|
+
String(args.parentNodeId),
|
|
2459
|
+
String(args.parent.globalId ?? ""),
|
|
2460
|
+
String(args.parent._id)
|
|
2461
|
+
].filter(Boolean)
|
|
2462
|
+
);
|
|
2463
|
+
const evidenceRefs = new Set(
|
|
2464
|
+
[
|
|
2465
|
+
String(args.triggeringEvidenceId),
|
|
2466
|
+
String(evidence.globalId ?? ""),
|
|
2467
|
+
String(evidence._id)
|
|
2468
|
+
].filter(Boolean)
|
|
2469
|
+
);
|
|
2470
|
+
let relation = null;
|
|
2471
|
+
const linkedBeliefNodeId = String(
|
|
2472
|
+
evidenceMetadata.linkedBeliefNodeId ?? ""
|
|
2473
|
+
);
|
|
2474
|
+
if (linkedBeliefNodeId && parentRefs.has(linkedBeliefNodeId)) {
|
|
2475
|
+
relation = normalizeForkTriggerRelation(evidenceMetadata.evidenceRelation);
|
|
2476
|
+
}
|
|
2477
|
+
if (!relation) {
|
|
2478
|
+
for (const parentRef of parentRefs) {
|
|
2479
|
+
const links = await ctx.db.query("beliefEvidenceLinks").withIndex("by_beliefId", (q) => q.eq("beliefId", parentRef)).collect();
|
|
2480
|
+
const matched = links.find((link) => evidenceRefs.has(String(link.insightId)));
|
|
2481
|
+
if (matched) {
|
|
2482
|
+
relation = normalizeForkTriggerRelation(matched.relation);
|
|
2483
|
+
break;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
if (!relation) {
|
|
2488
|
+
throwStructuredMutationError({
|
|
2489
|
+
message: "Fork evidence must already be attached to the parent belief through an SL evidence relation.",
|
|
2490
|
+
status: 409,
|
|
2491
|
+
code: "CONFLICT",
|
|
2492
|
+
invariantCode: "belief.fork_requires_attached_evidence",
|
|
2493
|
+
suggestion: "Attach the evidence to the parent belief as supports or contradicts before forking.",
|
|
2494
|
+
details: {
|
|
2495
|
+
parentNodeId: args.parentNodeId,
|
|
2496
|
+
triggeringEvidenceId: args.triggeringEvidenceId
|
|
2497
|
+
}
|
|
2498
|
+
});
|
|
2499
|
+
}
|
|
2500
|
+
if (args.forkMode === "supersede" && relation !== "contradicts") {
|
|
2501
|
+
throwStructuredMutationError({
|
|
2502
|
+
message: "Superseding fork requires contradicting evidence against the parent belief.",
|
|
2503
|
+
status: 409,
|
|
2504
|
+
code: "CONFLICT",
|
|
2505
|
+
invariantCode: "belief.supersede_requires_contradiction",
|
|
2506
|
+
suggestion: "Use forkMode='branch' for a non-replacing fork, or attach contradicting evidence before superseding.",
|
|
2507
|
+
details: {
|
|
2508
|
+
parentNodeId: args.parentNodeId,
|
|
2509
|
+
triggeringEvidenceId: args.triggeringEvidenceId,
|
|
2510
|
+
relation
|
|
2511
|
+
}
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
return { evidenceNodeId: args.triggeringEvidenceId, relation };
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
// src/epistemicBeliefs.topicAnchor.ts
|
|
2518
|
+
function cleanString(value) {
|
|
2519
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
2520
|
+
}
|
|
2521
|
+
function topicNodeCandidates(topicRef) {
|
|
2522
|
+
const normalized = topicRef.trim();
|
|
2523
|
+
if (!normalized) {
|
|
2524
|
+
return [];
|
|
2525
|
+
}
|
|
2526
|
+
const candidates = [normalized];
|
|
2527
|
+
if (normalized.startsWith("top_")) {
|
|
2528
|
+
candidates.push(normalized.slice(4));
|
|
2529
|
+
}
|
|
2530
|
+
return [...new Set(candidates)];
|
|
2531
|
+
}
|
|
2532
|
+
function readTopicNodeRef(args) {
|
|
2533
|
+
return cleanString(args.topicGlobalId) ?? cleanString(args.topicNodeId) ?? cleanString(args.topicId);
|
|
2534
|
+
}
|
|
2535
|
+
async function resolveRequiredTopicAnchor(ctx, topicRef) {
|
|
2536
|
+
for (const candidate of topicNodeCandidates(topicRef)) {
|
|
2537
|
+
try {
|
|
2538
|
+
const direct = await ctx.db.get(candidate);
|
|
2539
|
+
if (direct?.nodeType === "topic" && cleanString(direct.globalId)) {
|
|
2540
|
+
return direct;
|
|
2541
|
+
}
|
|
2542
|
+
} catch (_) {
|
|
2543
|
+
}
|
|
2544
|
+
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", candidate)).first();
|
|
2545
|
+
if (byGlobalId?.nodeType === "topic" && cleanString(byGlobalId.globalId)) {
|
|
2546
|
+
return byGlobalId;
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
throw new Error(
|
|
2550
|
+
"Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes. Legacy topics-table IDs are not valid belief anchors."
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
function scopeFromTopicAnchor(topicNode) {
|
|
2554
|
+
return {
|
|
2555
|
+
topicId: topicNode.globalId,
|
|
2556
|
+
projectId: cleanString(topicNode.projectId),
|
|
2557
|
+
tenantId: cleanString(topicNode.tenantId),
|
|
2558
|
+
workspaceId: cleanString(topicNode.workspaceId),
|
|
2559
|
+
source: "topic"
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
async function createRequiredBeliefTopicEdge(ctx, args) {
|
|
2563
|
+
const topicGlobalId = args.topicNode.globalId;
|
|
2564
|
+
const edgeGlobalId = `edge:${args.beliefGlobalId}:${topicGlobalId}:scoped_by`;
|
|
2565
|
+
const now = Date.now();
|
|
2566
|
+
const existing = await ctx.db.query("epistemicEdges").withIndex("by_globalId", (q) => q.eq("globalId", edgeGlobalId)).first();
|
|
2567
|
+
if (!existing) {
|
|
2568
|
+
await ctx.db.insert("epistemicEdges", {
|
|
2569
|
+
globalId: edgeGlobalId,
|
|
2570
|
+
fromNodeId: String(args.beliefNodeId),
|
|
2571
|
+
toNodeId: String(args.topicNode._id),
|
|
2572
|
+
sourceGlobalId: args.beliefGlobalId,
|
|
2573
|
+
targetGlobalId: topicGlobalId,
|
|
2574
|
+
edgeType: "scoped_by",
|
|
2575
|
+
weight: 1,
|
|
2576
|
+
confidence: 1,
|
|
2577
|
+
context: "Belief creation topic anchor invariant.",
|
|
2578
|
+
reasoningMethod: "implicit",
|
|
2579
|
+
derivationType: "topic_scope_invariant",
|
|
2580
|
+
metadata: { invariant: "belief.topic_edge_required" },
|
|
2581
|
+
createdBy: args.createdBy,
|
|
2582
|
+
createdAt: now,
|
|
2583
|
+
updatedAt: now,
|
|
2584
|
+
projectId: cleanString(args.topicNode.projectId),
|
|
2585
|
+
topicId: topicGlobalId,
|
|
2586
|
+
tenantId: cleanString(args.topicNode.tenantId),
|
|
2587
|
+
workspaceId: cleanString(args.topicNode.workspaceId),
|
|
2588
|
+
fromNodeType: "belief",
|
|
2589
|
+
toNodeType: "topic",
|
|
2590
|
+
fromLayer: "L3",
|
|
2591
|
+
toLayer: args.topicNode.epistemicLayer ?? "ontological"
|
|
2592
|
+
});
|
|
2593
|
+
}
|
|
2594
|
+
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
2595
|
+
globalId: edgeGlobalId,
|
|
2596
|
+
fromGlobalId: args.beliefGlobalId,
|
|
2597
|
+
toGlobalId: topicGlobalId,
|
|
2598
|
+
edgeType: "scoped_by",
|
|
2599
|
+
weight: 1,
|
|
2600
|
+
confidence: 1,
|
|
2601
|
+
context: "Belief creation topic anchor invariant.",
|
|
2602
|
+
projectId: cleanString(args.topicNode.projectId),
|
|
2603
|
+
topicId: topicGlobalId,
|
|
2604
|
+
createdBy: args.createdBy,
|
|
2605
|
+
fromNodeType: "belief",
|
|
2606
|
+
toNodeType: "topic",
|
|
2607
|
+
fromLayer: "L3",
|
|
2608
|
+
toLayer: args.topicNode.epistemicLayer ?? "ontological",
|
|
2609
|
+
metadata: { invariant: "belief.topic_edge_required" }
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2362
2613
|
// src/embeddingTrigger.ts
|
|
2363
2614
|
async function scheduleEmbeddingGeneration(args) {
|
|
2364
2615
|
try {
|
|
@@ -2408,6 +2659,8 @@ function generateGlobalId() {
|
|
|
2408
2659
|
var create = mutation({
|
|
2409
2660
|
args: {
|
|
2410
2661
|
...optionalBeliefScopeArgs,
|
|
2662
|
+
topicNodeId: v.optional(v.string()),
|
|
2663
|
+
topicGlobalId: v.optional(v.string()),
|
|
2411
2664
|
formulation: v.string(),
|
|
2412
2665
|
beliefType: v.optional(v.string()),
|
|
2413
2666
|
rationale: v.optional(v.string()),
|
|
@@ -2452,20 +2705,32 @@ var create = mutation({
|
|
|
2452
2705
|
returns: permissiveReturn,
|
|
2453
2706
|
handler: async (ctx, args) => {
|
|
2454
2707
|
const authenticatedUserId = await requireAuthenticatedUserId(ctx);
|
|
2455
|
-
const
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2708
|
+
const topicRef = readTopicNodeRef(args);
|
|
2709
|
+
if (!topicRef) {
|
|
2710
|
+
throwStructuredMutationError({
|
|
2711
|
+
message: "Belief creation requires an explicit topic epistemic node.",
|
|
2712
|
+
status: 400,
|
|
2713
|
+
code: "INVALID_ARGUMENT",
|
|
2714
|
+
invariantCode: "belief.topic_node_required",
|
|
2715
|
+
suggestion: "Pass topicGlobalId or topicNodeId for a topic in epistemicNodes before creating a belief.",
|
|
2716
|
+
details: {
|
|
2717
|
+
topicId: args.topicId,
|
|
2718
|
+
topicNodeId: args.topicNodeId,
|
|
2719
|
+
topicGlobalId: args.topicGlobalId
|
|
2720
|
+
}
|
|
2721
|
+
});
|
|
2722
|
+
}
|
|
2723
|
+
const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
|
|
2724
|
+
const scope = scopeFromTopicAnchor(topicNode);
|
|
2459
2725
|
assertWorkspaceScopedEpistemicNodeScope({
|
|
2460
2726
|
scope,
|
|
2461
2727
|
nodeType: "belief",
|
|
2462
2728
|
mutationName: "epistemicBeliefs.create"
|
|
2463
2729
|
});
|
|
2464
|
-
const topic = await ctx.db.get(scope.topicId);
|
|
2465
2730
|
const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
|
|
2466
2731
|
category: "belief_type",
|
|
2467
2732
|
value: args.beliefType,
|
|
2468
|
-
tenantId:
|
|
2733
|
+
tenantId: scope.tenantId,
|
|
2469
2734
|
context: "epistemicBeliefs.create"
|
|
2470
2735
|
});
|
|
2471
2736
|
if (scope.projectId) {
|
|
@@ -2498,7 +2763,7 @@ var create = mutation({
|
|
|
2498
2763
|
title: args.formulation.slice(0, 100) + (args.formulation.length > 100 ? "..." : ""),
|
|
2499
2764
|
metadata: {
|
|
2500
2765
|
pillar,
|
|
2501
|
-
// No confidenceLevel — only set after
|
|
2766
|
+
// No confidenceLevel — only set after evidence-backed SL scoring.
|
|
2502
2767
|
status: "active",
|
|
2503
2768
|
worktreeId: args.worktreeId,
|
|
2504
2769
|
beliefStatus: initialBeliefStatus,
|
|
@@ -2542,9 +2807,15 @@ var create = mutation({
|
|
|
2542
2807
|
rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
|
|
2543
2808
|
assessedBy: authenticatedUserId,
|
|
2544
2809
|
assessedAt: now,
|
|
2545
|
-
slOperator: "
|
|
2810
|
+
slOperator: "prior_seed"
|
|
2546
2811
|
})
|
|
2547
2812
|
);
|
|
2813
|
+
await createRequiredBeliefTopicEdge(ctx, {
|
|
2814
|
+
beliefNodeId: nodeId,
|
|
2815
|
+
beliefGlobalId,
|
|
2816
|
+
topicNode,
|
|
2817
|
+
createdBy: authenticatedUserId
|
|
2818
|
+
});
|
|
2548
2819
|
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
2549
2820
|
nodeId,
|
|
2550
2821
|
operation: "upsert"
|
|
@@ -2881,9 +3152,10 @@ var forkBelief = mutation({
|
|
|
2881
3152
|
v.literal("refinement"),
|
|
2882
3153
|
v.literal("contradiction_response"),
|
|
2883
3154
|
v.literal("scope_change"),
|
|
2884
|
-
v.literal("confidence_collapse")
|
|
2885
|
-
v.literal("manual")
|
|
3155
|
+
v.literal("confidence_collapse")
|
|
2886
3156
|
),
|
|
3157
|
+
forkMode: v.optional(v.union(v.literal("supersede"), v.literal("branch"))),
|
|
3158
|
+
triggeringEvidenceId: v.id("epistemicNodes"),
|
|
2887
3159
|
rationale: v.optional(v.string()),
|
|
2888
3160
|
userId: v.string()
|
|
2889
3161
|
},
|
|
@@ -2926,6 +3198,33 @@ var forkBelief = mutation({
|
|
|
2926
3198
|
await requireProjectWriteAccess(ctx, parent.projectId, authenticatedUserId);
|
|
2927
3199
|
const metadata = parent.metadata;
|
|
2928
3200
|
const forkBeliefStatus = "hypothesis";
|
|
3201
|
+
const forkMode = args.forkMode ?? "supersede";
|
|
3202
|
+
const triggerEvidence = await resolveForkTriggerEvidence(ctx, {
|
|
3203
|
+
parentNodeId: args.parentNodeId,
|
|
3204
|
+
parent,
|
|
3205
|
+
triggeringEvidenceId: args.triggeringEvidenceId,
|
|
3206
|
+
forkMode
|
|
3207
|
+
});
|
|
3208
|
+
const parentLifecycleStatus = resolveBeliefLifecycleStatus({
|
|
3209
|
+
beliefStatus: parent.beliefStatus,
|
|
3210
|
+
confidence: parent.confidence,
|
|
3211
|
+
predictionMeta: parent.predictionMeta,
|
|
3212
|
+
metadata
|
|
3213
|
+
});
|
|
3214
|
+
if (forkMode === "supersede" && parentLifecycleStatus !== "active") {
|
|
3215
|
+
throwStructuredMutationError({
|
|
3216
|
+
message: "Superseding fork requires an active parent belief. Attach evidence first so the lifecycle can promote deterministically.",
|
|
3217
|
+
status: 409,
|
|
3218
|
+
code: "CONFLICT",
|
|
3219
|
+
invariantCode: "belief.supersede_requires_active_parent",
|
|
3220
|
+
suggestion: "Attach the contradicting evidence to the parent belief, let the evidence path promote it to active, then supersede.",
|
|
3221
|
+
details: {
|
|
3222
|
+
parentNodeId: args.parentNodeId,
|
|
3223
|
+
parentLifecycleStatus,
|
|
3224
|
+
triggeringEvidenceId: args.triggeringEvidenceId
|
|
3225
|
+
}
|
|
3226
|
+
});
|
|
3227
|
+
}
|
|
2929
3228
|
const newBeliefGlobalId = generateGlobalId();
|
|
2930
3229
|
const newNodeId = await ctx.db.insert("epistemicNodes", {
|
|
2931
3230
|
globalId: newBeliefGlobalId,
|
|
@@ -2939,6 +3238,9 @@ var forkBelief = mutation({
|
|
|
2939
3238
|
...metadata,
|
|
2940
3239
|
forkedFrom: args.parentNodeId,
|
|
2941
3240
|
forkReason: args.forkReason,
|
|
3241
|
+
forkMode,
|
|
3242
|
+
triggeringEvidenceId: args.triggeringEvidenceId,
|
|
3243
|
+
triggeringEvidenceRelation: triggerEvidence.relation,
|
|
2942
3244
|
forkTimestamp: now,
|
|
2943
3245
|
forkedBy: authenticatedUserId,
|
|
2944
3246
|
status: "active",
|
|
@@ -2957,6 +3259,27 @@ var forkBelief = mutation({
|
|
|
2957
3259
|
createdAt: now,
|
|
2958
3260
|
updatedAt: now
|
|
2959
3261
|
});
|
|
3262
|
+
if (forkMode === "supersede") {
|
|
3263
|
+
await ctx.db.patch(args.parentNodeId, {
|
|
3264
|
+
status: "superseded",
|
|
3265
|
+
beliefStatus: "superseded",
|
|
3266
|
+
epistemicStatus: "superseded",
|
|
3267
|
+
supersededBy: newNodeId,
|
|
3268
|
+
updatedAt: now,
|
|
3269
|
+
metadata: {
|
|
3270
|
+
...metadata ?? {},
|
|
3271
|
+
status: "superseded",
|
|
3272
|
+
beliefStatus: "superseded",
|
|
3273
|
+
epistemicStatus: "superseded",
|
|
3274
|
+
supersededBy: String(newNodeId),
|
|
3275
|
+
supersededByEvidenceId: String(triggerEvidence.evidenceNodeId)
|
|
3276
|
+
}
|
|
3277
|
+
});
|
|
3278
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
3279
|
+
nodeId: args.parentNodeId,
|
|
3280
|
+
operation: "upsert"
|
|
3281
|
+
});
|
|
3282
|
+
}
|
|
2960
3283
|
const inheritedContracts = await ctx.db.query("epistemicContracts").withIndex(
|
|
2961
3284
|
"by_belief",
|
|
2962
3285
|
(q) => q.eq("beliefNodeId", args.parentNodeId)
|
|
@@ -2983,12 +3306,17 @@ var forkBelief = mutation({
|
|
|
2983
3306
|
globalId: generateGlobalId(),
|
|
2984
3307
|
fromGlobalId: newBeliefGlobalId,
|
|
2985
3308
|
toGlobalId: parent.globalId,
|
|
2986
|
-
edgeType: "supersedes",
|
|
2987
|
-
context: `Fork reason: ${args.forkReason}`,
|
|
3309
|
+
edgeType: forkMode === "supersede" ? "supersedes" : "derived_from",
|
|
3310
|
+
context: `Fork reason: ${args.forkReason}; triggering evidence: ${triggerEvidence.evidenceNodeId}`,
|
|
2988
3311
|
createdBy: authenticatedUserId,
|
|
2989
3312
|
topicId: parent.projectId ? String(parent.projectId) : void 0,
|
|
2990
3313
|
fromNodeType: "belief",
|
|
2991
|
-
toNodeType: "belief"
|
|
3314
|
+
toNodeType: "belief",
|
|
3315
|
+
metadata: {
|
|
3316
|
+
forkMode,
|
|
3317
|
+
triggeringEvidenceId: String(triggerEvidence.evidenceNodeId),
|
|
3318
|
+
triggeringEvidenceRelation: triggerEvidence.relation
|
|
3319
|
+
}
|
|
2992
3320
|
});
|
|
2993
3321
|
await scheduleEmbeddingGeneration({
|
|
2994
3322
|
ctx,
|
|
@@ -3013,6 +3341,9 @@ var forkBelief = mutation({
|
|
|
3013
3341
|
newState: {
|
|
3014
3342
|
formulation: args.newFormulation,
|
|
3015
3343
|
forkReason: args.forkReason,
|
|
3344
|
+
forkMode,
|
|
3345
|
+
triggeringEvidenceId: String(triggerEvidence.evidenceNodeId),
|
|
3346
|
+
triggeringEvidenceRelation: triggerEvidence.relation,
|
|
3016
3347
|
tupleContradicted: false
|
|
3017
3348
|
},
|
|
3018
3349
|
projectId: parent.projectId,
|
|
@@ -3047,10 +3378,17 @@ var forkBelief = mutation({
|
|
|
3047
3378
|
projectId: parent.projectId,
|
|
3048
3379
|
topicId: parent.topicId
|
|
3049
3380
|
});
|
|
3050
|
-
return {
|
|
3381
|
+
return {
|
|
3382
|
+
newNodeId,
|
|
3383
|
+
parentNodeId: args.parentNodeId,
|
|
3384
|
+
forkMode,
|
|
3385
|
+
forkReason: args.forkReason,
|
|
3386
|
+
triggeringEvidenceId: triggerEvidence.evidenceNodeId,
|
|
3387
|
+
triggeringEvidenceRelation: triggerEvidence.relation
|
|
3388
|
+
};
|
|
3051
3389
|
}
|
|
3052
3390
|
});
|
|
3053
|
-
var
|
|
3391
|
+
var appendSlScoring = mutation({
|
|
3054
3392
|
args: {
|
|
3055
3393
|
nodeId: v.id("epistemicNodes"),
|
|
3056
3394
|
// SL opinion — the ONLY confidence input (EK-7)
|
|
@@ -3067,8 +3405,6 @@ var modulateConfidence = mutation({
|
|
|
3067
3405
|
v.literal("evidence_removed"),
|
|
3068
3406
|
v.literal("contradiction_detected"),
|
|
3069
3407
|
v.literal("contradiction_resolved"),
|
|
3070
|
-
v.literal("manual"),
|
|
3071
|
-
v.literal("decay"),
|
|
3072
3408
|
v.literal("agent_assessment"),
|
|
3073
3409
|
v.literal("worktree_outcome"),
|
|
3074
3410
|
v.literal("worktree_completed"),
|
|
@@ -3080,7 +3416,7 @@ var modulateConfidence = mutation({
|
|
|
3080
3416
|
),
|
|
3081
3417
|
rationale: v.optional(v.string()),
|
|
3082
3418
|
userId: v.string(),
|
|
3083
|
-
// SL operator provenance (optional — defaults
|
|
3419
|
+
// SL operator provenance (optional — defaults inside the SL scorer)
|
|
3084
3420
|
slOperator: v.optional(
|
|
3085
3421
|
v.union(
|
|
3086
3422
|
v.literal("cumulative_fusion"),
|
|
@@ -3090,7 +3426,8 @@ var modulateConfidence = mutation({
|
|
|
3090
3426
|
v.literal("dependency_cascade"),
|
|
3091
3427
|
v.literal("negation"),
|
|
3092
3428
|
v.literal("constraint_fusion"),
|
|
3093
|
-
v.literal("
|
|
3429
|
+
v.literal("no_op"),
|
|
3430
|
+
v.literal("prior_seed")
|
|
3094
3431
|
)
|
|
3095
3432
|
),
|
|
3096
3433
|
triggeringEvidenceId: v.optional(v.id("epistemicNodes")),
|
|
@@ -3457,6 +3794,12 @@ async function getQuestionsAnsweredByEvidence(ctx, evidenceId) {
|
|
|
3457
3794
|
}
|
|
3458
3795
|
|
|
3459
3796
|
// src/epistemicBeliefs.links.ts
|
|
3797
|
+
function assertSignedImpactScore(value, context) {
|
|
3798
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value === 0 || value < -1 || value > 1) {
|
|
3799
|
+
throw new Error(`${context} requires explicit nonzero weight in [-1, 1]`);
|
|
3800
|
+
}
|
|
3801
|
+
return value;
|
|
3802
|
+
}
|
|
3460
3803
|
var updatePillar = mutation({
|
|
3461
3804
|
args: {
|
|
3462
3805
|
nodeId: v.id("epistemicNodes"),
|
|
@@ -3636,6 +3979,7 @@ var linkEvidence = mutation({
|
|
|
3636
3979
|
beliefNodeId: v.id("epistemicNodes"),
|
|
3637
3980
|
insightId: insightIdUnion,
|
|
3638
3981
|
type: v.union(v.literal("supporting"), v.literal("contradicting")),
|
|
3982
|
+
weight: v.number(),
|
|
3639
3983
|
rationale: v.optional(v.string()),
|
|
3640
3984
|
userId: v.string()
|
|
3641
3985
|
},
|
|
@@ -3659,16 +4003,54 @@ var linkEvidence = mutation({
|
|
|
3659
4003
|
}
|
|
3660
4004
|
const evidenceNodeId = insight._id;
|
|
3661
4005
|
const evidenceGlobalId = insight.globalId;
|
|
4006
|
+
const weight = assertSignedImpactScore(args.weight, "Evidence link");
|
|
4007
|
+
if (args.type === "supporting" && weight < 0) {
|
|
4008
|
+
throw new Error("Supporting evidence links require positive weight");
|
|
4009
|
+
}
|
|
4010
|
+
if (args.type === "contradicting" && weight > 0) {
|
|
4011
|
+
throw new Error("Contradicting evidence links require negative weight");
|
|
4012
|
+
}
|
|
4013
|
+
const confidence = Math.abs(weight);
|
|
3662
4014
|
const edgeType = "informs";
|
|
3663
|
-
const weight = args.type === "supporting" ? 1 : -1;
|
|
3664
4015
|
const logicalRole = evidenceNodeId ? await computeLogicalRole(ctx, evidenceNodeId, args.beliefNodeId) : "contributory";
|
|
3665
4016
|
const edgeGlobalId = generateGlobalId();
|
|
4017
|
+
await ctx.db.insert("epistemicEdges", {
|
|
4018
|
+
globalId: edgeGlobalId,
|
|
4019
|
+
fromNodeId: evidenceNodeId,
|
|
4020
|
+
toNodeId: args.beliefNodeId,
|
|
4021
|
+
sourceGlobalId: evidenceGlobalId,
|
|
4022
|
+
targetGlobalId: belief.globalId,
|
|
4023
|
+
edgeType,
|
|
4024
|
+
weight,
|
|
4025
|
+
confidence,
|
|
4026
|
+
context: args.rationale || `${args.type} evidence`,
|
|
4027
|
+
reasoningMethod: "testimonial",
|
|
4028
|
+
logicalRole,
|
|
4029
|
+
temporalClass: "structural",
|
|
4030
|
+
derivationType: "evidence_sl_scoring",
|
|
4031
|
+
metadata: {
|
|
4032
|
+
relation: args.type,
|
|
4033
|
+
confidence,
|
|
4034
|
+
impactScore: weight,
|
|
4035
|
+
invariant: "evidence.belief_impact_required"
|
|
4036
|
+
},
|
|
4037
|
+
createdBy: authenticatedUserId,
|
|
4038
|
+
createdAt: Date.now(),
|
|
4039
|
+
updatedAt: Date.now(),
|
|
4040
|
+
topicId: belief.topicId ? String(belief.topicId) : void 0,
|
|
4041
|
+
projectId: belief.projectId ? String(belief.projectId) : void 0,
|
|
4042
|
+
fromNodeType: "evidence",
|
|
4043
|
+
toNodeType: "belief",
|
|
4044
|
+
fromLayer: "L2",
|
|
4045
|
+
toLayer: "L3"
|
|
4046
|
+
});
|
|
3666
4047
|
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
3667
4048
|
globalId: edgeGlobalId,
|
|
3668
4049
|
fromGlobalId: evidenceGlobalId,
|
|
3669
4050
|
toGlobalId: belief.globalId,
|
|
3670
4051
|
edgeType,
|
|
3671
4052
|
weight,
|
|
4053
|
+
confidence,
|
|
3672
4054
|
context: args.rationale || `${args.type} evidence`,
|
|
3673
4055
|
createdBy: authenticatedUserId,
|
|
3674
4056
|
topicId: belief.projectId ? String(belief.projectId) : void 0,
|
|
@@ -4299,6 +4681,8 @@ var internalGetById = internalQuery({
|
|
|
4299
4681
|
var internalCreate = internalMutation({
|
|
4300
4682
|
args: {
|
|
4301
4683
|
...optionalBeliefScopeArgs,
|
|
4684
|
+
topicNodeId: v.optional(v.string()),
|
|
4685
|
+
topicGlobalId: v.optional(v.string()),
|
|
4302
4686
|
formulation: v.string(),
|
|
4303
4687
|
baseRate: v.optional(v.number()),
|
|
4304
4688
|
confidence: v.optional(
|
|
@@ -4337,10 +4721,14 @@ var internalCreate = internalMutation({
|
|
|
4337
4721
|
handler: async (ctx, args) => {
|
|
4338
4722
|
const now = Date.now();
|
|
4339
4723
|
const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
|
|
4340
|
-
const
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4724
|
+
const topicRef = readTopicNodeRef(args);
|
|
4725
|
+
if (!topicRef) {
|
|
4726
|
+
throw new Error(
|
|
4727
|
+
"Belief creation requires topicGlobalId or topicNodeId for a topic node in epistemicNodes."
|
|
4728
|
+
);
|
|
4729
|
+
}
|
|
4730
|
+
const topicNode = await resolveRequiredTopicAnchor(ctx, topicRef);
|
|
4731
|
+
const scope = scopeFromTopicAnchor(topicNode);
|
|
4344
4732
|
assertWorkspaceScopedEpistemicNodeScope({
|
|
4345
4733
|
scope,
|
|
4346
4734
|
nodeType: "belief",
|
|
@@ -4356,11 +4744,10 @@ var internalCreate = internalMutation({
|
|
|
4356
4744
|
},
|
|
4357
4745
|
mutationName: "epistemicBeliefs.internalCreate"
|
|
4358
4746
|
});
|
|
4359
|
-
const topic = await ctx.db.get(scope.topicId);
|
|
4360
4747
|
const normalizedBeliefType = await assertSchemaEnumValue(ctx, {
|
|
4361
4748
|
category: "belief_type",
|
|
4362
4749
|
value: args.beliefType,
|
|
4363
|
-
tenantId:
|
|
4750
|
+
tenantId: scope.tenantId,
|
|
4364
4751
|
context: "epistemicBeliefs.internalCreate"
|
|
4365
4752
|
});
|
|
4366
4753
|
const globalId = generateGlobalId();
|
|
@@ -4424,9 +4811,15 @@ var internalCreate = internalMutation({
|
|
|
4424
4811
|
rationale: "LKC-2 mandatory prior: seeded vacuous opinion at belief creation.",
|
|
4425
4812
|
assessedBy: args.userId,
|
|
4426
4813
|
assessedAt: now,
|
|
4427
|
-
slOperator: "
|
|
4814
|
+
slOperator: "prior_seed"
|
|
4428
4815
|
})
|
|
4429
4816
|
);
|
|
4817
|
+
await createRequiredBeliefTopicEdge(ctx, {
|
|
4818
|
+
beliefNodeId: nodeId,
|
|
4819
|
+
beliefGlobalId: globalId,
|
|
4820
|
+
topicNode,
|
|
4821
|
+
createdBy: args.userId
|
|
4822
|
+
});
|
|
4430
4823
|
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
4431
4824
|
nodeId,
|
|
4432
4825
|
operation: "upsert"
|
|
@@ -4600,7 +4993,7 @@ var backfillSyntheticOpinionHistory = internalMutation({
|
|
|
4600
4993
|
rationale: "LK-6 backfill: synthesized t0 from node-level opinion fields (no prior beliefConfidence row found).",
|
|
4601
4994
|
assessedAt: readFiniteNumber(node.createdAt) ?? readFiniteNumber(node.updatedAt) ?? Date.now(),
|
|
4602
4995
|
assessedBy: "system:lk-6-backfill",
|
|
4603
|
-
slOperator: "
|
|
4996
|
+
slOperator: "prior_seed"
|
|
4604
4997
|
})
|
|
4605
4998
|
);
|
|
4606
4999
|
beliefsWithHistory.add(String(node._id));
|
|
@@ -4706,7 +5099,7 @@ var backfillMandatoryPriors = internalMutation({
|
|
|
4706
5099
|
rationale: "LKC-2 backfill: inserted missing initial vacuous opinion with neutral prior.",
|
|
4707
5100
|
assessedAt: readFiniteNumber(node.createdAt) ?? readFiniteNumber(node.updatedAt) ?? Date.now(),
|
|
4708
5101
|
assessedBy: "system:lkc-2-prior-backfill",
|
|
4709
|
-
slOperator: "
|
|
5102
|
+
slOperator: "prior_seed"
|
|
4710
5103
|
})
|
|
4711
5104
|
);
|
|
4712
5105
|
insertedInitialRows++;
|
|
@@ -4814,7 +5207,7 @@ var backfillScoredBeliefEdges = internalMutation({
|
|
|
4814
5207
|
const scoredBeliefs = allBeliefs.filter((belief) => {
|
|
4815
5208
|
const metadata = belief.metadata || {};
|
|
4816
5209
|
const lifecycle = resolveBeliefStatus(belief, metadata);
|
|
4817
|
-
return lifecycle === "
|
|
5210
|
+
return lifecycle === "active" || lifecycle === "resolved_true";
|
|
4818
5211
|
});
|
|
4819
5212
|
const themeNodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
4820
5213
|
"by_topic",
|
|
@@ -6300,85 +6693,32 @@ async function resolveScopeSoft(ctx, args) {
|
|
|
6300
6693
|
...projectId ? { projectId } : {}
|
|
6301
6694
|
};
|
|
6302
6695
|
}
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
v.literal("dismissed")
|
|
6309
|
-
);
|
|
6310
|
-
var matcherMetadataValidator = v.object({
|
|
6311
|
-
surface: v.string(),
|
|
6312
|
-
matcherFamily: v.optional(v.string()),
|
|
6313
|
-
matcherKey: v.optional(v.string()),
|
|
6314
|
-
matcherVersion: v.optional(v.string()),
|
|
6315
|
-
reviewStatus: v.optional(
|
|
6316
|
-
v.union(
|
|
6317
|
-
v.literal("pending"),
|
|
6318
|
-
v.literal("accepted"),
|
|
6319
|
-
v.literal("rejected"),
|
|
6320
|
-
v.literal("auto_accepted"),
|
|
6321
|
-
v.literal("superseded")
|
|
6322
|
-
)
|
|
6323
|
-
),
|
|
6324
|
-
configSnapshot: v.optional(v.any()),
|
|
6325
|
-
signalSnapshot: v.optional(v.any()),
|
|
6326
|
-
outcomeMetadata: v.optional(v.any())
|
|
6327
|
-
});
|
|
6328
|
-
async function markProjectGraphDirty(ctx, projectId) {
|
|
6329
|
-
if (!projectId) {
|
|
6330
|
-
return;
|
|
6696
|
+
|
|
6697
|
+
// src/beliefEvidenceLinks.operational.ts
|
|
6698
|
+
function assertEvidenceImpact(args) {
|
|
6699
|
+
if (!Number.isFinite(args.weight) || args.weight === 0 || args.weight < -1 || args.weight > 1) {
|
|
6700
|
+
throw new Error("Belief evidence links require explicit nonzero weight in [-1, 1]");
|
|
6331
6701
|
}
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
}
|
|
6338
|
-
);
|
|
6339
|
-
await resolveGraphPrimitivesAppResolvers().patchProject(ctx, projectId, {
|
|
6340
|
-
lastActivityAt: Date.now()
|
|
6341
|
-
});
|
|
6342
|
-
}
|
|
6343
|
-
async function recordMatcherDecision(ctx, args) {
|
|
6344
|
-
if (!args.matcherMetadata) {
|
|
6345
|
-
return;
|
|
6702
|
+
if (args.relation === "supports" && args.weight < 0) {
|
|
6703
|
+
throw new Error("Supporting evidence links require positive weight");
|
|
6704
|
+
}
|
|
6705
|
+
if (args.relation === "contradicts" && args.weight > 0) {
|
|
6706
|
+
throw new Error("Contradicting evidence links require negative weight");
|
|
6346
6707
|
}
|
|
6347
|
-
await ctx.runMutation("matcherFeedback:recordDecision", {
|
|
6348
|
-
projectId: args.beliefNode.projectId,
|
|
6349
|
-
topicId: args.beliefNode.topicId,
|
|
6350
|
-
surface: args.matcherMetadata.surface,
|
|
6351
|
-
matcherFamily: args.matcherMetadata.matcherFamily,
|
|
6352
|
-
matcherKey: args.matcherMetadata.matcherKey,
|
|
6353
|
-
matcherVersion: args.matcherMetadata.matcherVersion,
|
|
6354
|
-
sourceEntityId: String(args.insightId),
|
|
6355
|
-
targetEntityId: String(args.beliefId),
|
|
6356
|
-
suggestionTable: "beliefEvidenceLinks",
|
|
6357
|
-
suggestionId: args.linkId,
|
|
6358
|
-
reviewStatus: deriveMatcherReviewStatus({
|
|
6359
|
-
explicitReviewStatus: args.matcherMetadata.reviewStatus,
|
|
6360
|
-
linkStatus: args.linkStatus
|
|
6361
|
-
}),
|
|
6362
|
-
reviewedBy: args.reviewedBy,
|
|
6363
|
-
decisionReason: args.decisionReason,
|
|
6364
|
-
configSnapshot: args.matcherMetadata.configSnapshot,
|
|
6365
|
-
signalSnapshot: args.matcherMetadata.signalSnapshot,
|
|
6366
|
-
outcomeMetadata: args.matcherMetadata.outcomeMetadata
|
|
6367
|
-
});
|
|
6368
6708
|
}
|
|
6369
6709
|
async function applyOperationalLinkEffects(ctx, args) {
|
|
6710
|
+
assertEvidenceImpact({ relation: args.relation, weight: args.weight });
|
|
6711
|
+
const confidence = Math.abs(args.weight);
|
|
6370
6712
|
const currentSupporting = args.beliefNode.supportingInsightIds ?? [];
|
|
6371
6713
|
const currentContradicting = args.beliefNode.contradictingInsightIds ?? [];
|
|
6372
|
-
if (args.relation === "supports") {
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
}
|
|
6381
|
-
} else if (!currentContradicting.includes(args.insightId)) {
|
|
6714
|
+
if (args.relation === "supports" && !currentSupporting.includes(args.insightId)) {
|
|
6715
|
+
await ctx.db.patch(args.beliefId, {
|
|
6716
|
+
supportingInsightIds: [...currentSupporting, args.insightId],
|
|
6717
|
+
contradictingInsightIds: currentContradicting.filter(
|
|
6718
|
+
(id) => id !== args.insightId
|
|
6719
|
+
)
|
|
6720
|
+
});
|
|
6721
|
+
} else if (args.relation === "contradicts" && !currentContradicting.includes(args.insightId)) {
|
|
6382
6722
|
await ctx.db.patch(args.beliefId, {
|
|
6383
6723
|
contradictingInsightIds: [...currentContradicting, args.insightId],
|
|
6384
6724
|
supportingInsightIds: currentSupporting.filter(
|
|
@@ -6389,7 +6729,7 @@ async function applyOperationalLinkEffects(ctx, args) {
|
|
|
6389
6729
|
try {
|
|
6390
6730
|
const beliefSpineNode = await ctx.db.get(args.beliefId);
|
|
6391
6731
|
const evidenceSpineNode = await ctx.db.get(args.insightId);
|
|
6392
|
-
if (beliefSpineNode
|
|
6732
|
+
if (beliefSpineNode?.nodeType === "belief" && evidenceSpineNode?.nodeType === "evidence") {
|
|
6393
6733
|
const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
6394
6734
|
"by_from_to",
|
|
6395
6735
|
(q) => q.eq("fromNodeId", evidenceSpineNode._id).eq("toNodeId", beliefSpineNode._id)
|
|
@@ -6402,16 +6742,44 @@ async function applyOperationalLinkEffects(ctx, args) {
|
|
|
6402
6742
|
await ctx.db.delete(edge._id);
|
|
6403
6743
|
}
|
|
6404
6744
|
}
|
|
6405
|
-
const weight = args.relation === "supports" ? args.confidence ?? 0.7 : -(args.confidence ?? 0.7);
|
|
6406
6745
|
const globalId = `edge-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
6746
|
+
const context = args.rationale || `Linked as ${args.relation}`;
|
|
6747
|
+
await ctx.db.insert("epistemicEdges", {
|
|
6748
|
+
globalId,
|
|
6749
|
+
fromNodeId: evidenceSpineNode._id,
|
|
6750
|
+
toNodeId: beliefSpineNode._id,
|
|
6751
|
+
sourceGlobalId: evidenceSpineNode.globalId,
|
|
6752
|
+
targetGlobalId: beliefSpineNode.globalId,
|
|
6753
|
+
edgeType: "informs",
|
|
6754
|
+
weight: args.weight,
|
|
6755
|
+
confidence,
|
|
6756
|
+
context,
|
|
6757
|
+
reasoningMethod: "testimonial",
|
|
6758
|
+
derivationType: "evidence_sl_scoring",
|
|
6759
|
+
metadata: {
|
|
6760
|
+
relation: args.relation,
|
|
6761
|
+
confidence,
|
|
6762
|
+
impactScore: args.weight,
|
|
6763
|
+
invariant: "evidence.belief_impact_required"
|
|
6764
|
+
},
|
|
6765
|
+
createdBy: args.createdBy,
|
|
6766
|
+
createdAt: Date.now(),
|
|
6767
|
+
updatedAt: Date.now(),
|
|
6768
|
+
projectId: args.beliefNode.projectId,
|
|
6769
|
+
topicId: args.beliefNode.topicId ? String(args.beliefNode.topicId) : void 0,
|
|
6770
|
+
fromNodeType: "evidence",
|
|
6771
|
+
toNodeType: "belief",
|
|
6772
|
+
fromLayer: "L2",
|
|
6773
|
+
toLayer: "L3"
|
|
6774
|
+
});
|
|
6407
6775
|
await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {
|
|
6408
6776
|
globalId,
|
|
6409
6777
|
fromGlobalId: evidenceSpineNode.globalId,
|
|
6410
6778
|
toGlobalId: beliefSpineNode.globalId,
|
|
6411
6779
|
edgeType: "informs",
|
|
6412
|
-
weight,
|
|
6413
|
-
confidence
|
|
6414
|
-
context
|
|
6780
|
+
weight: args.weight,
|
|
6781
|
+
confidence,
|
|
6782
|
+
context,
|
|
6415
6783
|
projectId: args.beliefNode.projectId ? String(args.beliefNode.projectId) : void 0,
|
|
6416
6784
|
createdBy: args.createdBy,
|
|
6417
6785
|
fromNodeType: "evidence",
|
|
@@ -6424,17 +6792,13 @@ async function applyOperationalLinkEffects(ctx, args) {
|
|
|
6424
6792
|
console.error("[EpistemicSpine] Failed to create informs edge:", e);
|
|
6425
6793
|
}
|
|
6426
6794
|
if (args.beliefNode.projectId) {
|
|
6427
|
-
await ctx.scheduler.runAfter(
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
projectId: args.beliefNode.projectId,
|
|
6435
|
-
userId: args.createdBy
|
|
6436
|
-
}
|
|
6437
|
-
);
|
|
6795
|
+
await ctx.scheduler.runAfter(0, "verificationActions:deepVerifyEvidence", {
|
|
6796
|
+
insightId: args.insightId,
|
|
6797
|
+
targetType: "belief",
|
|
6798
|
+
targetId: args.beliefId,
|
|
6799
|
+
projectId: args.beliefNode.projectId,
|
|
6800
|
+
userId: args.createdBy
|
|
6801
|
+
});
|
|
6438
6802
|
}
|
|
6439
6803
|
}
|
|
6440
6804
|
async function removeOperationalLinkEffects(ctx, args) {
|
|
@@ -6459,7 +6823,7 @@ async function removeOperationalLinkEffects(ctx, args) {
|
|
|
6459
6823
|
try {
|
|
6460
6824
|
const beliefSpineNode = await ctx.db.get(args.beliefId);
|
|
6461
6825
|
const evidenceSpineNode = await ctx.db.get(args.insightId);
|
|
6462
|
-
if (beliefSpineNode
|
|
6826
|
+
if (beliefSpineNode?.nodeType === "belief" && evidenceSpineNode?.nodeType === "evidence") {
|
|
6463
6827
|
const edges2 = await ctx.db.query("epistemicEdges").withIndex(
|
|
6464
6828
|
"by_from_to",
|
|
6465
6829
|
(q) => q.eq("fromNodeId", evidenceSpineNode._id).eq("toNodeId", beliefSpineNode._id)
|
|
@@ -6477,11 +6841,80 @@ async function removeOperationalLinkEffects(ctx, args) {
|
|
|
6477
6841
|
console.error("[EpistemicSpine] Failed to remove informs edge:", e);
|
|
6478
6842
|
}
|
|
6479
6843
|
}
|
|
6844
|
+
|
|
6845
|
+
// src/beliefEvidenceLinks.ts
|
|
6846
|
+
var beliefIdUnion = v.id("epistemicNodes");
|
|
6847
|
+
var insightIdUnion2 = v.id("epistemicNodes");
|
|
6848
|
+
var suggestionStatusValidator = v.union(
|
|
6849
|
+
v.literal("suggested"),
|
|
6850
|
+
v.literal("approved"),
|
|
6851
|
+
v.literal("dismissed")
|
|
6852
|
+
);
|
|
6853
|
+
var matcherMetadataValidator = v.object({
|
|
6854
|
+
surface: v.string(),
|
|
6855
|
+
matcherFamily: v.optional(v.string()),
|
|
6856
|
+
matcherKey: v.optional(v.string()),
|
|
6857
|
+
matcherVersion: v.optional(v.string()),
|
|
6858
|
+
reviewStatus: v.optional(
|
|
6859
|
+
v.union(
|
|
6860
|
+
v.literal("pending"),
|
|
6861
|
+
v.literal("accepted"),
|
|
6862
|
+
v.literal("rejected"),
|
|
6863
|
+
v.literal("auto_accepted"),
|
|
6864
|
+
v.literal("superseded")
|
|
6865
|
+
)
|
|
6866
|
+
),
|
|
6867
|
+
configSnapshot: v.optional(v.any()),
|
|
6868
|
+
signalSnapshot: v.optional(v.any()),
|
|
6869
|
+
outcomeMetadata: v.optional(v.any())
|
|
6870
|
+
});
|
|
6871
|
+
async function markProjectGraphDirty(ctx, projectId) {
|
|
6872
|
+
if (!projectId) {
|
|
6873
|
+
return;
|
|
6874
|
+
}
|
|
6875
|
+
await ctx.scheduler.runAfter(
|
|
6876
|
+
0,
|
|
6877
|
+
internal.graphAnalysisCache.markCacheStaleInternal,
|
|
6878
|
+
{
|
|
6879
|
+
projectId
|
|
6880
|
+
}
|
|
6881
|
+
);
|
|
6882
|
+
await resolveGraphPrimitivesAppResolvers().patchProject(ctx, projectId, {
|
|
6883
|
+
lastActivityAt: Date.now()
|
|
6884
|
+
});
|
|
6885
|
+
}
|
|
6886
|
+
async function recordMatcherDecision(ctx, args) {
|
|
6887
|
+
if (!args.matcherMetadata) {
|
|
6888
|
+
return;
|
|
6889
|
+
}
|
|
6890
|
+
await ctx.runMutation("matcherFeedback:recordDecision", {
|
|
6891
|
+
projectId: args.beliefNode.projectId,
|
|
6892
|
+
topicId: args.beliefNode.topicId,
|
|
6893
|
+
surface: args.matcherMetadata.surface,
|
|
6894
|
+
matcherFamily: args.matcherMetadata.matcherFamily,
|
|
6895
|
+
matcherKey: args.matcherMetadata.matcherKey,
|
|
6896
|
+
matcherVersion: args.matcherMetadata.matcherVersion,
|
|
6897
|
+
sourceEntityId: String(args.insightId),
|
|
6898
|
+
targetEntityId: String(args.beliefId),
|
|
6899
|
+
suggestionTable: "beliefEvidenceLinks",
|
|
6900
|
+
suggestionId: args.linkId,
|
|
6901
|
+
reviewStatus: deriveMatcherReviewStatus({
|
|
6902
|
+
explicitReviewStatus: args.matcherMetadata.reviewStatus,
|
|
6903
|
+
linkStatus: args.linkStatus
|
|
6904
|
+
}),
|
|
6905
|
+
reviewedBy: args.reviewedBy,
|
|
6906
|
+
decisionReason: args.decisionReason,
|
|
6907
|
+
configSnapshot: args.matcherMetadata.configSnapshot,
|
|
6908
|
+
signalSnapshot: args.matcherMetadata.signalSnapshot,
|
|
6909
|
+
outcomeMetadata: args.matcherMetadata.outcomeMetadata
|
|
6910
|
+
});
|
|
6911
|
+
}
|
|
6480
6912
|
var create2 = mutation({
|
|
6481
6913
|
args: {
|
|
6482
6914
|
beliefId: beliefIdUnion,
|
|
6483
6915
|
insightId: insightIdUnion2,
|
|
6484
6916
|
relation: v.union(v.literal("supports"), v.literal("contradicts")),
|
|
6917
|
+
weight: v.number(),
|
|
6485
6918
|
confidence: v.optional(v.number()),
|
|
6486
6919
|
rationale: v.optional(v.string()),
|
|
6487
6920
|
status: v.optional(suggestionStatusValidator),
|
|
@@ -6500,6 +6933,16 @@ var create2 = mutation({
|
|
|
6500
6933
|
if (!insightNode) {
|
|
6501
6934
|
throw new Error("Evidence node not found");
|
|
6502
6935
|
}
|
|
6936
|
+
if (!Number.isFinite(args.weight) || args.weight === 0 || args.weight < -1 || args.weight > 1) {
|
|
6937
|
+
throw new Error("Belief evidence links require explicit nonzero weight in [-1, 1]");
|
|
6938
|
+
}
|
|
6939
|
+
if (args.relation === "supports" && args.weight < 0) {
|
|
6940
|
+
throw new Error("Supporting evidence links require positive weight");
|
|
6941
|
+
}
|
|
6942
|
+
if (args.relation === "contradicts" && args.weight > 0) {
|
|
6943
|
+
throw new Error("Contradicting evidence links require negative weight");
|
|
6944
|
+
}
|
|
6945
|
+
const relationConfidence = Math.abs(args.weight);
|
|
6503
6946
|
if (beliefNode.projectId) {
|
|
6504
6947
|
const hasAccess = await checkProjectAccess(
|
|
6505
6948
|
ctx,
|
|
@@ -6524,7 +6967,7 @@ var create2 = mutation({
|
|
|
6524
6967
|
);
|
|
6525
6968
|
await ctx.db.patch(duplicate._id, {
|
|
6526
6969
|
relation: args.relation,
|
|
6527
|
-
confidence:
|
|
6970
|
+
confidence: relationConfidence,
|
|
6528
6971
|
rationale: args.rationale,
|
|
6529
6972
|
status: nextStatus
|
|
6530
6973
|
});
|
|
@@ -6536,7 +6979,7 @@ var create2 = mutation({
|
|
|
6536
6979
|
beliefId: resolvedBeliefId,
|
|
6537
6980
|
insightId: resolvedInsightId,
|
|
6538
6981
|
relation: args.relation,
|
|
6539
|
-
|
|
6982
|
+
weight: args.weight,
|
|
6540
6983
|
rationale: args.rationale,
|
|
6541
6984
|
createdBy: args.createdBy
|
|
6542
6985
|
});
|
|
@@ -6552,15 +6995,12 @@ var create2 = mutation({
|
|
|
6552
6995
|
await markProjectGraphDirty(ctx, beliefNode.projectId);
|
|
6553
6996
|
return duplicate._id;
|
|
6554
6997
|
}
|
|
6555
|
-
if (args.confidence !== void 0 && (args.confidence < 0 || args.confidence > 1)) {
|
|
6556
|
-
throw new Error("Confidence must be between 0 and 1");
|
|
6557
|
-
}
|
|
6558
6998
|
const now = Date.now();
|
|
6559
6999
|
const linkId = await ctx.db.insert("beliefEvidenceLinks", {
|
|
6560
7000
|
beliefId: args.beliefId,
|
|
6561
7001
|
insightId: args.insightId,
|
|
6562
7002
|
relation: args.relation,
|
|
6563
|
-
confidence:
|
|
7003
|
+
confidence: relationConfidence,
|
|
6564
7004
|
rationale: args.rationale,
|
|
6565
7005
|
status: args.status,
|
|
6566
7006
|
createdBy: args.createdBy,
|
|
@@ -6580,7 +7020,7 @@ var create2 = mutation({
|
|
|
6580
7020
|
beliefId: resolvedBeliefId,
|
|
6581
7021
|
insightId: resolvedInsightId,
|
|
6582
7022
|
relation: args.relation,
|
|
6583
|
-
|
|
7023
|
+
weight: args.weight,
|
|
6584
7024
|
rationale: args.rationale,
|
|
6585
7025
|
createdBy: args.createdBy
|
|
6586
7026
|
});
|
|
@@ -6688,7 +7128,7 @@ var reviewSuggestion = mutation({
|
|
|
6688
7128
|
beliefId: link.beliefId,
|
|
6689
7129
|
insightId: link.insightId,
|
|
6690
7130
|
relation: link.relation,
|
|
6691
|
-
confidence: link.confidence,
|
|
7131
|
+
weight: link.relation === "supports" ? Math.abs(link.confidence ?? 0) : -Math.abs(link.confidence ?? 0),
|
|
6692
7132
|
rationale: link.rationale,
|
|
6693
7133
|
createdBy: args.userId
|
|
6694
7134
|
});
|
|
@@ -8937,7 +9377,7 @@ async function evaluateBuiltInEvidentialContract(args) {
|
|
|
8937
9377
|
observedValue: snapshot.value,
|
|
8938
9378
|
operator: config.operator,
|
|
8939
9379
|
threshold: config.threshold,
|
|
8940
|
-
action: config.action ?? "
|
|
9380
|
+
action: config.action ?? "append_sl_scoring",
|
|
8941
9381
|
actionParams: config.actionParams
|
|
8942
9382
|
}
|
|
8943
9383
|
};
|
|
@@ -11707,6 +12147,91 @@ function formatEvidenceNode(n) {
|
|
|
11707
12147
|
updatedAt: n.updatedAt
|
|
11708
12148
|
};
|
|
11709
12149
|
}
|
|
12150
|
+
function assertSignedImpactScore2(value, context) {
|
|
12151
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value === 0 || value < -1 || value > 1) {
|
|
12152
|
+
throw new Error(`${context} requires explicit nonzero weight in [-1, 1]`);
|
|
12153
|
+
}
|
|
12154
|
+
return value;
|
|
12155
|
+
}
|
|
12156
|
+
function normalizeEvidenceRelation(relation, weight, context) {
|
|
12157
|
+
if (relation === "supports" || relation === "contradicts") {
|
|
12158
|
+
if (relation === "supports" && weight < 0) {
|
|
12159
|
+
throw new Error(`${context} supports relation requires positive weight`);
|
|
12160
|
+
}
|
|
12161
|
+
if (relation === "contradicts" && weight > 0) {
|
|
12162
|
+
throw new Error(`${context} contradicts relation requires negative weight`);
|
|
12163
|
+
}
|
|
12164
|
+
return relation;
|
|
12165
|
+
}
|
|
12166
|
+
return weight < 0 ? "contradicts" : "supports";
|
|
12167
|
+
}
|
|
12168
|
+
async function createEvidenceBeliefEdge(ctx, args) {
|
|
12169
|
+
const edgeGlobalId = crypto.randomUUID();
|
|
12170
|
+
const confidence = Math.abs(args.weight);
|
|
12171
|
+
const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
12172
|
+
"by_from_to",
|
|
12173
|
+
(q) => q.eq("fromNodeId", args.evidenceNodeId).eq("toNodeId", args.beliefNodeId)
|
|
12174
|
+
).collect();
|
|
12175
|
+
const existing = existingEdges.find((edge) => edge.edgeType === "informs");
|
|
12176
|
+
const edgeDoc = {
|
|
12177
|
+
globalId: edgeGlobalId,
|
|
12178
|
+
fromNodeId: args.evidenceNodeId,
|
|
12179
|
+
toNodeId: args.beliefNodeId,
|
|
12180
|
+
sourceGlobalId: args.evidenceGlobalId,
|
|
12181
|
+
targetGlobalId: args.beliefGlobalId,
|
|
12182
|
+
edgeType: "informs",
|
|
12183
|
+
weight: args.weight,
|
|
12184
|
+
confidence,
|
|
12185
|
+
context: args.rationale,
|
|
12186
|
+
reasoningMethod: "testimonial",
|
|
12187
|
+
derivationType: "evidence_sl_scoring",
|
|
12188
|
+
metadata: {
|
|
12189
|
+
relation: args.relation,
|
|
12190
|
+
confidence,
|
|
12191
|
+
impactScore: args.weight,
|
|
12192
|
+
invariant: "evidence.belief_impact_required"
|
|
12193
|
+
},
|
|
12194
|
+
createdBy: args.userId,
|
|
12195
|
+
createdAt: Date.now(),
|
|
12196
|
+
updatedAt: Date.now(),
|
|
12197
|
+
topicId: args.topicId,
|
|
12198
|
+
projectId: args.projectId,
|
|
12199
|
+
fromNodeType: "evidence",
|
|
12200
|
+
toNodeType: "belief",
|
|
12201
|
+
fromLayer: "L2",
|
|
12202
|
+
toLayer: "L3"
|
|
12203
|
+
};
|
|
12204
|
+
if (existing) {
|
|
12205
|
+
await ctx.db.patch(existing._id, {
|
|
12206
|
+
...edgeDoc,
|
|
12207
|
+
globalId: existing.globalId,
|
|
12208
|
+
createdAt: existing.createdAt ?? edgeDoc.createdAt
|
|
12209
|
+
});
|
|
12210
|
+
} else {
|
|
12211
|
+
await ctx.db.insert("epistemicEdges", edgeDoc);
|
|
12212
|
+
}
|
|
12213
|
+
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
12214
|
+
globalId: existing?.globalId ?? edgeGlobalId,
|
|
12215
|
+
fromGlobalId: args.evidenceGlobalId,
|
|
12216
|
+
toGlobalId: args.beliefGlobalId,
|
|
12217
|
+
edgeType: "informs",
|
|
12218
|
+
weight: args.weight,
|
|
12219
|
+
confidence,
|
|
12220
|
+
createdBy: args.userId,
|
|
12221
|
+
topicId: args.projectId ?? args.topicId,
|
|
12222
|
+
fromNodeType: "evidence",
|
|
12223
|
+
toNodeType: "belief",
|
|
12224
|
+
fromLayer: "L2",
|
|
12225
|
+
toLayer: "L3",
|
|
12226
|
+
metadata: {
|
|
12227
|
+
relation: args.relation,
|
|
12228
|
+
confidence,
|
|
12229
|
+
impactScore: args.weight,
|
|
12230
|
+
invariant: "evidence.belief_impact_required"
|
|
12231
|
+
}
|
|
12232
|
+
});
|
|
12233
|
+
return existing?.globalId ?? edgeGlobalId;
|
|
12234
|
+
}
|
|
11710
12235
|
var create6 = mutation({
|
|
11711
12236
|
args: {
|
|
11712
12237
|
...optionalEvidenceScopeArgs,
|
|
@@ -11727,11 +12252,12 @@ var create6 = mutation({
|
|
|
11727
12252
|
informationAsymmetry: v.optional(v.string()),
|
|
11728
12253
|
sourceDescription: v.optional(v.string()),
|
|
11729
12254
|
metadata: v.optional(v.any()),
|
|
11730
|
-
//
|
|
11731
|
-
linkedBeliefNodeId: v.
|
|
12255
|
+
// Required belief impact link.
|
|
12256
|
+
linkedBeliefNodeId: v.id("epistemicNodes"),
|
|
11732
12257
|
evidenceRelation: v.optional(
|
|
11733
12258
|
v.union(v.literal("supports"), v.literal("contradicts"))
|
|
11734
12259
|
),
|
|
12260
|
+
weight: v.number(),
|
|
11735
12261
|
confidence: v.optional(v.number())
|
|
11736
12262
|
},
|
|
11737
12263
|
returns: permissiveReturn,
|
|
@@ -11753,6 +12279,16 @@ var create6 = mutation({
|
|
|
11753
12279
|
const contentHash = generateContentHash5(args.text);
|
|
11754
12280
|
const kind = normalizeKind(args.kind);
|
|
11755
12281
|
const sourceType = normalizeSourceType(args.sourceType);
|
|
12282
|
+
const weight = assertSignedImpactScore2(args.weight, "Evidence creation");
|
|
12283
|
+
const evidenceRelation = normalizeEvidenceRelation(
|
|
12284
|
+
args.evidenceRelation,
|
|
12285
|
+
weight,
|
|
12286
|
+
"Evidence creation"
|
|
12287
|
+
);
|
|
12288
|
+
const linkedBeliefNode = await ctx.db.get(args.linkedBeliefNodeId);
|
|
12289
|
+
if (!linkedBeliefNode || linkedBeliefNode.nodeType !== "belief") {
|
|
12290
|
+
throw new Error("Evidence creation requires a linked belief node");
|
|
12291
|
+
}
|
|
11756
12292
|
const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
|
|
11757
12293
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
11758
12294
|
globalId,
|
|
@@ -11780,8 +12316,10 @@ var create6 = mutation({
|
|
|
11780
12316
|
sourceQuestionId: args.sourceQuestionId,
|
|
11781
12317
|
rationale: args.rationale,
|
|
11782
12318
|
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
11783
|
-
evidenceRelation
|
|
11784
|
-
confidence:
|
|
12319
|
+
evidenceRelation,
|
|
12320
|
+
confidence: Math.abs(weight),
|
|
12321
|
+
weight,
|
|
12322
|
+
impactScore: weight,
|
|
11785
12323
|
methodology: args.methodology,
|
|
11786
12324
|
informationAsymmetry: args.informationAsymmetry,
|
|
11787
12325
|
sourceDescription: args.sourceDescription,
|
|
@@ -11801,29 +12339,18 @@ var create6 = mutation({
|
|
|
11801
12339
|
nodeType: "evidence",
|
|
11802
12340
|
text: args.text
|
|
11803
12341
|
});
|
|
11804
|
-
|
|
11805
|
-
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
11814
|
-
|
|
11815
|
-
|
|
11816
|
-
fromNodeType: "evidence",
|
|
11817
|
-
toNodeType: "belief",
|
|
11818
|
-
fromLayer: "L2",
|
|
11819
|
-
toLayer: "L3",
|
|
11820
|
-
metadata: {
|
|
11821
|
-
relation: args.evidenceRelation,
|
|
11822
|
-
confidence: args.confidence
|
|
11823
|
-
}
|
|
11824
|
-
});
|
|
11825
|
-
}
|
|
11826
|
-
}
|
|
12342
|
+
await createEvidenceBeliefEdge(ctx, {
|
|
12343
|
+
evidenceNodeId: nodeId,
|
|
12344
|
+
evidenceGlobalId: globalId,
|
|
12345
|
+
beliefNodeId: args.linkedBeliefNodeId,
|
|
12346
|
+
beliefGlobalId: linkedBeliefNode.globalId,
|
|
12347
|
+
relation: evidenceRelation,
|
|
12348
|
+
weight,
|
|
12349
|
+
userId: args.userId,
|
|
12350
|
+
topicId: scope.topicId ? String(scope.topicId) : void 0,
|
|
12351
|
+
projectId: scope.projectId ? String(scope.projectId) : void 0,
|
|
12352
|
+
rationale: args.rationale
|
|
12353
|
+
});
|
|
11827
12354
|
await ctx.db.insert("epistemicAudit", {
|
|
11828
12355
|
entityType: "evidence",
|
|
11829
12356
|
entityId: nodeId,
|
|
@@ -11838,7 +12365,8 @@ var create6 = mutation({
|
|
|
11838
12365
|
kind,
|
|
11839
12366
|
sourceType,
|
|
11840
12367
|
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
11841
|
-
evidenceRelation
|
|
12368
|
+
evidenceRelation,
|
|
12369
|
+
weight
|
|
11842
12370
|
}
|
|
11843
12371
|
});
|
|
11844
12372
|
if (scope.projectId || scope.topicId) {
|
|
@@ -11881,6 +12409,7 @@ var createAndLink = mutation({
|
|
|
11881
12409
|
userId: v.string(),
|
|
11882
12410
|
beliefNodeId: v.id("epistemicNodes"),
|
|
11883
12411
|
relation: v.union(v.literal("supports"), v.literal("contradicts")),
|
|
12412
|
+
weight: v.number(),
|
|
11884
12413
|
confidence: v.optional(v.number())
|
|
11885
12414
|
},
|
|
11886
12415
|
returns: permissiveReturn,
|
|
@@ -11895,7 +12424,17 @@ var createAndLink = mutation({
|
|
|
11895
12424
|
const contentHash = generateContentHash5(args.text);
|
|
11896
12425
|
const kind = normalizeKind(args.kind);
|
|
11897
12426
|
const sourceType = normalizeSourceType(args.sourceType);
|
|
11898
|
-
const
|
|
12427
|
+
const weight = assertSignedImpactScore2(args.weight, "Evidence createAndLink");
|
|
12428
|
+
const relation = normalizeEvidenceRelation(
|
|
12429
|
+
args.relation,
|
|
12430
|
+
weight,
|
|
12431
|
+
"Evidence createAndLink"
|
|
12432
|
+
);
|
|
12433
|
+
const confidence = Math.abs(weight);
|
|
12434
|
+
const beliefNode = await ctx.db.get(args.beliefNodeId);
|
|
12435
|
+
if (!beliefNode || beliefNode.nodeType !== "belief") {
|
|
12436
|
+
throw new Error("Belief node not found for edge creation");
|
|
12437
|
+
}
|
|
11899
12438
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
11900
12439
|
globalId,
|
|
11901
12440
|
topicId: scope.topicId,
|
|
@@ -11915,36 +12454,26 @@ var createAndLink = mutation({
|
|
|
11915
12454
|
kind,
|
|
11916
12455
|
tags: args.tags || [],
|
|
11917
12456
|
linkedBeliefNodeId: args.beliefNodeId,
|
|
11918
|
-
evidenceRelation:
|
|
11919
|
-
confidence
|
|
12457
|
+
evidenceRelation: relation,
|
|
12458
|
+
confidence,
|
|
12459
|
+
weight,
|
|
12460
|
+
impactScore: weight
|
|
11920
12461
|
}
|
|
11921
12462
|
});
|
|
11922
12463
|
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
11923
12464
|
nodeId,
|
|
11924
12465
|
operation: "upsert"
|
|
11925
12466
|
});
|
|
11926
|
-
const
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
11933
|
-
globalId: edgeGlobalId,
|
|
11934
|
-
fromGlobalId: globalId,
|
|
11935
|
-
toGlobalId: beliefNode.globalId,
|
|
11936
|
-
edgeType: "informs",
|
|
12467
|
+
const edgeGlobalId = await createEvidenceBeliefEdge(ctx, {
|
|
12468
|
+
evidenceNodeId: nodeId,
|
|
12469
|
+
evidenceGlobalId: globalId,
|
|
12470
|
+
beliefNodeId: args.beliefNodeId,
|
|
12471
|
+
beliefGlobalId: beliefNode.globalId,
|
|
12472
|
+
relation,
|
|
11937
12473
|
weight,
|
|
11938
|
-
|
|
11939
|
-
topicId: scope.
|
|
11940
|
-
|
|
11941
|
-
toNodeType: "belief",
|
|
11942
|
-
fromLayer: "L2",
|
|
11943
|
-
toLayer: "L3",
|
|
11944
|
-
metadata: {
|
|
11945
|
-
relation: args.relation,
|
|
11946
|
-
confidence
|
|
11947
|
-
}
|
|
12474
|
+
userId: args.userId,
|
|
12475
|
+
topicId: scope.topicId ? String(scope.topicId) : void 0,
|
|
12476
|
+
projectId: scope.projectId ? String(scope.projectId) : void 0
|
|
11948
12477
|
});
|
|
11949
12478
|
await markProjectGraphDirty2(ctx, scope.projectId, String(scope.topicId));
|
|
11950
12479
|
return { nodeId, edgeGlobalId };
|
|
@@ -12005,8 +12534,9 @@ var internalCreate2 = internalMutation({
|
|
|
12005
12534
|
sourceQuestionId: v.optional(v.string()),
|
|
12006
12535
|
userId: v.string(),
|
|
12007
12536
|
rationale: v.string(),
|
|
12008
|
-
linkedBeliefNodeId: v.
|
|
12537
|
+
linkedBeliefNodeId: v.id("epistemicNodes"),
|
|
12009
12538
|
evidenceRelation: v.optional(v.string()),
|
|
12539
|
+
weight: v.number(),
|
|
12010
12540
|
confidence: v.optional(v.number()),
|
|
12011
12541
|
metadata: v.optional(v.any()),
|
|
12012
12542
|
runtimeToolName: v.optional(v.string()),
|
|
@@ -12041,6 +12571,16 @@ var internalCreate2 = internalMutation({
|
|
|
12041
12571
|
const contentHash = generateContentHash5(args.text);
|
|
12042
12572
|
const kind = normalizeKind(args.kind);
|
|
12043
12573
|
const sourceType = normalizeSourceType(args.sourceType);
|
|
12574
|
+
const weight = assertSignedImpactScore2(args.weight, "Internal evidence creation");
|
|
12575
|
+
const evidenceRelation = normalizeEvidenceRelation(
|
|
12576
|
+
args.evidenceRelation,
|
|
12577
|
+
weight,
|
|
12578
|
+
"Internal evidence creation"
|
|
12579
|
+
);
|
|
12580
|
+
const linkedBeliefNode = await ctx.db.get(args.linkedBeliefNodeId);
|
|
12581
|
+
if (!linkedBeliefNode || linkedBeliefNode.nodeType !== "belief") {
|
|
12582
|
+
throw new Error("Internal evidence creation requires a linked belief node");
|
|
12583
|
+
}
|
|
12044
12584
|
const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
|
|
12045
12585
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
12046
12586
|
globalId,
|
|
@@ -12068,8 +12608,10 @@ var internalCreate2 = internalMutation({
|
|
|
12068
12608
|
sourceQuestionId: args.sourceQuestionId,
|
|
12069
12609
|
rationale: args.rationale,
|
|
12070
12610
|
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
12071
|
-
evidenceRelation
|
|
12072
|
-
confidence:
|
|
12611
|
+
evidenceRelation,
|
|
12612
|
+
confidence: Math.abs(weight),
|
|
12613
|
+
weight,
|
|
12614
|
+
impactScore: weight,
|
|
12073
12615
|
...additionalMetadata
|
|
12074
12616
|
}
|
|
12075
12617
|
});
|
|
@@ -12089,8 +12631,9 @@ var internalCreate2 = internalMutation({
|
|
|
12089
12631
|
externalSourceType: args.externalSourceType,
|
|
12090
12632
|
sourceUrl: args.sourceUrl,
|
|
12091
12633
|
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
12092
|
-
evidenceRelation
|
|
12093
|
-
confidence:
|
|
12634
|
+
evidenceRelation,
|
|
12635
|
+
confidence: Math.abs(weight),
|
|
12636
|
+
weight
|
|
12094
12637
|
},
|
|
12095
12638
|
triggeringAction: "epistemicEvidence.internalCreate"
|
|
12096
12639
|
});
|
|
@@ -12098,30 +12641,18 @@ var internalCreate2 = internalMutation({
|
|
|
12098
12641
|
nodeId,
|
|
12099
12642
|
operation: "upsert"
|
|
12100
12643
|
});
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12113
|
-
topicId: scope.projectId ? String(scope.projectId) : void 0,
|
|
12114
|
-
fromNodeType: "evidence",
|
|
12115
|
-
toNodeType: "belief",
|
|
12116
|
-
fromLayer: "L2",
|
|
12117
|
-
toLayer: "L3",
|
|
12118
|
-
metadata: {
|
|
12119
|
-
relation: args.evidenceRelation,
|
|
12120
|
-
confidence
|
|
12121
|
-
}
|
|
12122
|
-
});
|
|
12123
|
-
}
|
|
12124
|
-
}
|
|
12644
|
+
await createEvidenceBeliefEdge(ctx, {
|
|
12645
|
+
evidenceNodeId: nodeId,
|
|
12646
|
+
evidenceGlobalId: globalId,
|
|
12647
|
+
beliefNodeId: args.linkedBeliefNodeId,
|
|
12648
|
+
beliefGlobalId: linkedBeliefNode.globalId,
|
|
12649
|
+
relation: evidenceRelation,
|
|
12650
|
+
weight,
|
|
12651
|
+
userId: args.userId,
|
|
12652
|
+
topicId: scope.topicId ? String(scope.topicId) : void 0,
|
|
12653
|
+
projectId: scope.projectId ? String(scope.projectId) : void 0,
|
|
12654
|
+
rationale: args.rationale
|
|
12655
|
+
});
|
|
12125
12656
|
if (scope.projectId || scope.topicId) {
|
|
12126
12657
|
await ctx.scheduler.runAfter(
|
|
12127
12658
|
0,
|
|
@@ -13412,7 +13943,7 @@ function assertBeliefNodeGenericUpdateAllowed(args) {
|
|
|
13412
13943
|
throwInvariantError({
|
|
13413
13944
|
message: "Belief confidence is append-only. Generic node updates cannot set confidence directly.",
|
|
13414
13945
|
invariantCode: "belief.confidence_append_only",
|
|
13415
|
-
suggestion: "Use epistemicBeliefs.
|
|
13946
|
+
suggestion: "Use epistemicBeliefs.appendSlScoring() so the beliefConfidence ledger and audit trail are updated together.",
|
|
13416
13947
|
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
13417
13948
|
});
|
|
13418
13949
|
}
|
|
@@ -13464,7 +13995,7 @@ function assertBeliefNodeVerifyAllowed(args) {
|
|
|
13464
13995
|
throwInvariantError({
|
|
13465
13996
|
message: "Belief verification cannot set confidence directly. Confidence changes must stay append-only.",
|
|
13466
13997
|
invariantCode: "belief.confidence_append_only",
|
|
13467
|
-
suggestion: "Call epistemicBeliefs.
|
|
13998
|
+
suggestion: "Call epistemicBeliefs.appendSlScoring() after verification so the confidence history is preserved.",
|
|
13468
13999
|
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
13469
14000
|
});
|
|
13470
14001
|
}
|
|
@@ -18904,7 +19435,7 @@ var epistemicBeliefs = {
|
|
|
18904
19435
|
internalGetByTopic,
|
|
18905
19436
|
linkBeliefs,
|
|
18906
19437
|
linkEvidence,
|
|
18907
|
-
|
|
19438
|
+
appendSlScoring,
|
|
18908
19439
|
propagateConfidenceChange,
|
|
18909
19440
|
reassignBeliefsTopic,
|
|
18910
19441
|
refineBelief,
|