@lucern/graph-primitives 0.1.0-alpha.2
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/README.md +29 -0
- package/dist/beliefDecay-Q_26RTc-.d.ts +72 -0
- package/dist/beliefDecay.d.ts +2 -0
- package/dist/beliefDecay.js +1628 -0
- package/dist/beliefDecay.js.map +1 -0
- package/dist/beliefEvidenceLinks-42FlR48t.d.ts +77 -0
- package/dist/beliefEvidenceLinks.d.ts +1 -0
- package/dist/beliefEvidenceLinks.js +1978 -0
- package/dist/beliefEvidenceLinks.js.map +1 -0
- package/dist/beliefLifecycle-C-AehZgF.d.ts +43 -0
- package/dist/beliefLifecycle.d.ts +1 -0
- package/dist/beliefLifecycle.js +98 -0
- package/dist/beliefLifecycle.js.map +1 -0
- package/dist/confidencePropagationDispatch.d.ts +46 -0
- package/dist/confidencePropagationDispatch.js +744 -0
- package/dist/confidencePropagationDispatch.js.map +1 -0
- package/dist/contradictions-Hdwl7zid.d.ts +71 -0
- package/dist/contradictions.d.ts +1 -0
- package/dist/contradictions.js +1557 -0
- package/dist/contradictions.js.map +1 -0
- package/dist/convex.d.ts +23 -0
- package/dist/convex.js +17 -0
- package/dist/convex.js.map +1 -0
- package/dist/edgeValidation-CeI0wc0r.d.ts +35 -0
- package/dist/edgeValidation.d.ts +2 -0
- package/dist/edgeValidation.js +307 -0
- package/dist/edgeValidation.js.map +1 -0
- package/dist/edges/contains.d.ts +6 -0
- package/dist/edges/contains.js +14 -0
- package/dist/edges/contains.js.map +1 -0
- package/dist/edges/contradicts.d.ts +6 -0
- package/dist/edges/contradicts.js +183 -0
- package/dist/edges/contradicts.js.map +1 -0
- package/dist/edges/dependsOn.d.ts +6 -0
- package/dist/edges/dependsOn.js +240 -0
- package/dist/edges/dependsOn.js.map +1 -0
- package/dist/edges/derivedFrom.d.ts +6 -0
- package/dist/edges/derivedFrom.js +14 -0
- package/dist/edges/derivedFrom.js.map +1 -0
- package/dist/edges/elaborates.d.ts +6 -0
- package/dist/edges/elaborates.js +100 -0
- package/dist/edges/elaborates.js.map +1 -0
- package/dist/edges/index.d.ts +3 -0
- package/dist/edges/index.js +556 -0
- package/dist/edges/index.js.map +1 -0
- package/dist/edges/informs.d.ts +6 -0
- package/dist/edges/informs.js +112 -0
- package/dist/edges/informs.js.map +1 -0
- package/dist/edges/propagationTypes.d.ts +39 -0
- package/dist/edges/propagationTypes.js +17 -0
- package/dist/edges/propagationTypes.js.map +1 -0
- package/dist/edges/refutes.d.ts +6 -0
- package/dist/edges/refutes.js +108 -0
- package/dist/edges/refutes.js.map +1 -0
- package/dist/edges/supports.d.ts +6 -0
- package/dist/edges/supports.js +193 -0
- package/dist/edges/supports.js.map +1 -0
- package/dist/edges/tests.d.ts +6 -0
- package/dist/edges/tests.js +14 -0
- package/dist/edges/tests.js.map +1 -0
- package/dist/edges/utils.d.ts +12 -0
- package/dist/edges/utils.js +188 -0
- package/dist/edges/utils.js.map +1 -0
- package/dist/embeddingTrigger.d.ts +24 -0
- package/dist/embeddingTrigger.js +24 -0
- package/dist/embeddingTrigger.js.map +1 -0
- package/dist/entityBridge-DMaKooYn.d.ts +59 -0
- package/dist/entityBridge.d.ts +1 -0
- package/dist/entityBridge.js +663 -0
- package/dist/entityBridge.js.map +1 -0
- package/dist/entityLifecycle-BkhRJ-XI.d.ts +69 -0
- package/dist/entityLifecycle.d.ts +1 -0
- package/dist/entityLifecycle.js +2083 -0
- package/dist/entityLifecycle.js.map +1 -0
- package/dist/entityValidation-KLZ_Xl2D.d.ts +50 -0
- package/dist/entityValidation.d.ts +3 -0
- package/dist/entityValidation.js +71 -0
- package/dist/entityValidation.js.map +1 -0
- package/dist/epistemicAnswers-DSP1slZ9.d.ts +67 -0
- package/dist/epistemicAnswers.d.ts +1 -0
- package/dist/epistemicAnswers.js +1650 -0
- package/dist/epistemicAnswers.js.map +1 -0
- package/dist/epistemicBeliefs-DtFVTp-k.d.ts +377 -0
- package/dist/epistemicBeliefs.d.ts +5 -0
- package/dist/epistemicBeliefs.js +6386 -0
- package/dist/epistemicBeliefs.js.map +1 -0
- package/dist/epistemicContractHelpers.d.ts +1 -0
- package/dist/epistemicContractHelpers.js +320 -0
- package/dist/epistemicContractHelpers.js.map +1 -0
- package/dist/epistemicContracts.d.ts +77 -0
- package/dist/epistemicContracts.js +8436 -0
- package/dist/epistemicContracts.js.map +1 -0
- package/dist/epistemicEdges-DcA8ErUG.d.ts +191 -0
- package/dist/epistemicEdges.d.ts +2 -0
- package/dist/epistemicEdges.js +2749 -0
- package/dist/epistemicEdges.js.map +1 -0
- package/dist/epistemicEvidence-Bo638XDP.d.ts +128 -0
- package/dist/epistemicEvidence.d.ts +3 -0
- package/dist/epistemicEvidence.js +3282 -0
- package/dist/epistemicEvidence.js.map +1 -0
- package/dist/epistemicHelpers-Bd9xbaib.d.ts +329 -0
- package/dist/epistemicHelpers.d.ts +4 -0
- package/dist/epistemicHelpers.js +999 -0
- package/dist/epistemicHelpers.js.map +1 -0
- package/dist/epistemicLinking-CyeLOIzN.d.ts +35 -0
- package/dist/epistemicLinking.d.ts +1 -0
- package/dist/epistemicLinking.js +1391 -0
- package/dist/epistemicLinking.js.map +1 -0
- package/dist/epistemicNodes-BpD6Koud.d.ts +167 -0
- package/dist/epistemicNodes.d.ts +2 -0
- package/dist/epistemicNodes.js +2942 -0
- package/dist/epistemicNodes.js.map +1 -0
- package/dist/epistemicQuestions-CmEeY6zQ.d.ts +214 -0
- package/dist/epistemicQuestions.d.ts +3 -0
- package/dist/epistemicQuestions.js +4993 -0
- package/dist/epistemicQuestions.js.map +1 -0
- package/dist/epistemicSources-ZazxHOK1.d.ts +25 -0
- package/dist/epistemicSources.d.ts +1 -0
- package/dist/epistemicSources.js +2025 -0
- package/dist/epistemicSources.js.map +1 -0
- package/dist/evaluators/index.d.ts +9 -0
- package/dist/evaluators/index.js +8440 -0
- package/dist/evaluators/index.js.map +1 -0
- package/dist/evaluators/lintCheckerEvaluator.d.ts +11 -0
- package/dist/evaluators/lintCheckerEvaluator.js +155 -0
- package/dist/evaluators/lintCheckerEvaluator.js.map +1 -0
- package/dist/evaluators/sentryCheckerEvaluator.d.ts +11 -0
- package/dist/evaluators/sentryCheckerEvaluator.js +126 -0
- package/dist/evaluators/sentryCheckerEvaluator.js.map +1 -0
- package/dist/evaluators/shared.d.ts +27 -0
- package/dist/evaluators/shared.js +92 -0
- package/dist/evaluators/shared.js.map +1 -0
- package/dist/evaluators/testRunnerEvaluator.d.ts +17 -0
- package/dist/evaluators/testRunnerEvaluator.js +232 -0
- package/dist/evaluators/testRunnerEvaluator.js.map +1 -0
- package/dist/evaluators/tscCheckerEvaluator.d.ts +11 -0
- package/dist/evaluators/tscCheckerEvaluator.js +189 -0
- package/dist/evaluators/tscCheckerEvaluator.js.map +1 -0
- package/dist/globalId-DKh9d_uD.d.ts +20 -0
- package/dist/globalId.d.ts +1 -0
- package/dist/globalId.js +15 -0
- package/dist/globalId.js.map +1 -0
- package/dist/graphTypes-CpgIuCdo.d.ts +52 -0
- package/dist/graphTypes.d.ts +1 -0
- package/dist/graphTypes.js +120 -0
- package/dist/graphTypes.js.map +1 -0
- package/dist/helpers-BYHIk5vU.d.ts +27 -0
- package/dist/helpers.d.ts +4 -0
- package/dist/helpers.js +313 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index-Dct1T70K.d.ts +25 -0
- package/dist/index-Dq-7R-gi.d.ts +31 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +22294 -0
- package/dist/index.js.map +1 -0
- package/dist/invariantEnforcement.d.ts +52 -0
- package/dist/invariantEnforcement.js +231 -0
- package/dist/invariantEnforcement.js.map +1 -0
- package/dist/logicalRoleInference-CJxqWi3u.d.ts +16 -0
- package/dist/logicalRoleInference.d.ts +3 -0
- package/dist/logicalRoleInference.js +64 -0
- package/dist/logicalRoleInference.js.map +1 -0
- package/dist/matcherFeedbackUtils.d.ts +33 -0
- package/dist/matcherFeedbackUtils.js +95 -0
- package/dist/matcherFeedbackUtils.js.map +1 -0
- package/dist/ontology-matching-Buhu23ss.d.ts +48 -0
- package/dist/ontology-matching.d.ts +2 -0
- package/dist/ontology-matching.js +346 -0
- package/dist/ontology-matching.js.map +1 -0
- package/dist/ontologyApproval-Ba0Jjk1k.d.ts +26 -0
- package/dist/ontologyApproval.d.ts +1 -0
- package/dist/ontologyApproval.js +78 -0
- package/dist/ontologyApproval.js.map +1 -0
- package/dist/ontologyDefinitions.d.ts +72 -0
- package/dist/ontologyDefinitions.js +635 -0
- package/dist/ontologyDefinitions.js.map +1 -0
- package/dist/ontologyHelpers.d.ts +79 -0
- package/dist/ontologyHelpers.js +81 -0
- package/dist/ontologyHelpers.js.map +1 -0
- package/dist/ontologyRegistry-B67rPJ16.d.ts +31 -0
- package/dist/ontologyRegistry.d.ts +1 -0
- package/dist/ontologyRegistry.js +296 -0
- package/dist/ontologyRegistry.js.map +1 -0
- package/dist/projectionReconciliation-CxrXYGaB.d.ts +20 -0
- package/dist/projectionReconciliation.d.ts +1 -0
- package/dist/projectionReconciliation.js +261 -0
- package/dist/projectionReconciliation.js.map +1 -0
- package/dist/projectionStaleness-CAdpIsaW.d.ts +51 -0
- package/dist/projectionStaleness.d.ts +1 -0
- package/dist/projectionStaleness.js +57 -0
- package/dist/projectionStaleness.js.map +1 -0
- package/dist/questionEvidenceLinks-BdQD0TkM.d.ts +34 -0
- package/dist/questionEvidenceLinks.d.ts +1 -0
- package/dist/questionEvidenceLinks.js +1690 -0
- package/dist/questionEvidenceLinks.js.map +1 -0
- package/dist/resolverTypes-CC8Ea2E2.d.ts +20 -0
- package/dist/resolverTypes.d.ts +4 -0
- package/dist/resolverTypes.js +3 -0
- package/dist/resolverTypes.js.map +1 -0
- package/dist/resolvers-Br1a6eLV.d.ts +14 -0
- package/dist/resolvers.d.ts +5 -0
- package/dist/resolvers.js +308 -0
- package/dist/resolvers.js.map +1 -0
- package/dist/scopeResolverCompat.d.ts +26 -0
- package/dist/scopeResolverCompat.js +242 -0
- package/dist/scopeResolverCompat.js.map +1 -0
- package/dist/text-matching-CMn2WnVD.d.ts +40 -0
- package/dist/text-matching.d.ts +2 -0
- package/dist/text-matching.js +246 -0
- package/dist/text-matching.js.map +1 -0
- package/dist/topicOntologyResolver.d.ts +80 -0
- package/dist/topicOntologyResolver.js +67 -0
- package/dist/topicOntologyResolver.js.map +1 -0
- package/dist/topicProjectOverlay.d.ts +92 -0
- package/dist/topicProjectOverlay.js +249 -0
- package/dist/topicProjectOverlay.js.map +1 -0
- package/dist/topicScope-By_zp4tt.d.ts +34 -0
- package/dist/topicScope.d.ts +3 -0
- package/dist/topicScope.js +206 -0
- package/dist/topicScope.js.map +1 -0
- package/dist/workspaceIsolation.d.ts +44 -0
- package/dist/workspaceIsolation.js +950 -0
- package/dist/workspaceIsolation.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
type BeliefNodeLike = {
|
|
2
|
+
_id?: string;
|
|
3
|
+
nodeType?: unknown;
|
|
4
|
+
confidence?: unknown;
|
|
5
|
+
metadata?: unknown;
|
|
6
|
+
predictionMeta?: unknown;
|
|
7
|
+
};
|
|
8
|
+
declare function isBeliefNode(node: BeliefNodeLike | null | undefined): boolean;
|
|
9
|
+
declare function isOntologicalNode(node: BeliefNodeLike | null | undefined): boolean;
|
|
10
|
+
declare function isScoredBeliefNode(node: BeliefNodeLike): boolean;
|
|
11
|
+
declare function assertBeliefNodeGenericUpdateAllowed(args: {
|
|
12
|
+
node: BeliefNodeLike;
|
|
13
|
+
updates: Record<string, unknown>;
|
|
14
|
+
mutationName: string;
|
|
15
|
+
}): void;
|
|
16
|
+
declare function assertBeliefNodeArchiveAllowed(args: {
|
|
17
|
+
node: BeliefNodeLike;
|
|
18
|
+
mutationName: string;
|
|
19
|
+
}): void;
|
|
20
|
+
declare function assertBeliefNodeVerifyAllowed(args: {
|
|
21
|
+
node: BeliefNodeLike;
|
|
22
|
+
confidence: number | undefined;
|
|
23
|
+
mutationName: string;
|
|
24
|
+
}): void;
|
|
25
|
+
declare function assertBeliefNodeSupersedeAllowed(args: {
|
|
26
|
+
node: BeliefNodeLike;
|
|
27
|
+
mutationName: string;
|
|
28
|
+
}): void;
|
|
29
|
+
declare function assertBeliefNodeHardDeleteAllowed(args: {
|
|
30
|
+
node: BeliefNodeLike;
|
|
31
|
+
allowBeliefHardDelete: boolean;
|
|
32
|
+
reason: string;
|
|
33
|
+
mutationName: string;
|
|
34
|
+
}): void;
|
|
35
|
+
declare function assertOntologicalNodeGenericCreateAllowed(args: {
|
|
36
|
+
nodeType: string;
|
|
37
|
+
mutationName: string;
|
|
38
|
+
}): void;
|
|
39
|
+
declare function assertOntologicalNodeGenericUpdateAllowed(args: {
|
|
40
|
+
node: BeliefNodeLike;
|
|
41
|
+
mutationName: string;
|
|
42
|
+
}): void;
|
|
43
|
+
declare function assertOntologicalNodeArchiveAllowed(args: {
|
|
44
|
+
node: BeliefNodeLike;
|
|
45
|
+
mutationName: string;
|
|
46
|
+
}): void;
|
|
47
|
+
declare function assertOntologicalNodeSupersedeAllowed(args: {
|
|
48
|
+
node: BeliefNodeLike;
|
|
49
|
+
mutationName: string;
|
|
50
|
+
}): void;
|
|
51
|
+
|
|
52
|
+
export { assertBeliefNodeArchiveAllowed, assertBeliefNodeGenericUpdateAllowed, assertBeliefNodeHardDeleteAllowed, assertBeliefNodeSupersedeAllowed, assertBeliefNodeVerifyAllowed, assertOntologicalNodeArchiveAllowed, assertOntologicalNodeGenericCreateAllowed, assertOntologicalNodeGenericUpdateAllowed, assertOntologicalNodeSupersedeAllowed, isBeliefNode, isOntologicalNode, isScoredBeliefNode };
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// src/beliefLifecycle.ts
|
|
2
|
+
var RESOLVED_PREDICTION_OUTCOMES = [
|
|
3
|
+
"confirmed",
|
|
4
|
+
"disconfirmed",
|
|
5
|
+
"partial",
|
|
6
|
+
"expired"
|
|
7
|
+
];
|
|
8
|
+
function hasResolvedPredictionOutcome(predictionMeta) {
|
|
9
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const outcome = predictionMeta.outcome;
|
|
13
|
+
return typeof outcome === "string" && RESOLVED_PREDICTION_OUTCOMES.includes(outcome);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/invariantEnforcement.ts
|
|
17
|
+
var FORBIDDEN_GENERIC_BELIEF_METADATA_KEYS = /* @__PURE__ */ new Set([
|
|
18
|
+
"beliefStatus",
|
|
19
|
+
"epistemicStatus",
|
|
20
|
+
"forkedBy",
|
|
21
|
+
"forkedFrom",
|
|
22
|
+
"forkReason",
|
|
23
|
+
"forkTimestamp",
|
|
24
|
+
"status",
|
|
25
|
+
"supersededBy",
|
|
26
|
+
"supersedes"
|
|
27
|
+
]);
|
|
28
|
+
var ONTOLOGICAL_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
29
|
+
"company",
|
|
30
|
+
"person",
|
|
31
|
+
"investor",
|
|
32
|
+
"function",
|
|
33
|
+
"value_chain"
|
|
34
|
+
]);
|
|
35
|
+
function throwInvariantError(args) {
|
|
36
|
+
const error = new Error(args.message);
|
|
37
|
+
error.status = args.status ?? 409;
|
|
38
|
+
error.code = args.code ?? "INVARIANT_VIOLATION";
|
|
39
|
+
error.invariantCode = args.invariantCode;
|
|
40
|
+
error.suggestion = args.suggestion;
|
|
41
|
+
error.details = args.details;
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
function isBeliefNode(node) {
|
|
45
|
+
return node?.nodeType === "belief";
|
|
46
|
+
}
|
|
47
|
+
function isOntologicalNode(node) {
|
|
48
|
+
return typeof node?.nodeType === "string" && ONTOLOGICAL_NODE_TYPES.has(node.nodeType);
|
|
49
|
+
}
|
|
50
|
+
function isScoredBeliefNode(node) {
|
|
51
|
+
if (!isBeliefNode(node)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const metadata = node.metadata && typeof node.metadata === "object" ? node.metadata : void 0;
|
|
55
|
+
const numericConfidence = typeof node.confidence === "number" && Number.isFinite(node.confidence);
|
|
56
|
+
if (numericConfidence) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return hasResolvedPredictionOutcome(node.predictionMeta) || hasResolvedPredictionOutcome(metadata?.predictionMeta);
|
|
60
|
+
}
|
|
61
|
+
function getForbiddenMetadataKeys(metadata) {
|
|
62
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
return Object.keys(metadata).filter(
|
|
66
|
+
(key) => FORBIDDEN_GENERIC_BELIEF_METADATA_KEYS.has(key)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
function assertBeliefNodeGenericUpdateAllowed(args) {
|
|
70
|
+
if (!isBeliefNode(args.node)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (Object.hasOwn(args.updates, "confidence")) {
|
|
74
|
+
throwInvariantError({
|
|
75
|
+
message: "Belief confidence is append-only. Generic node updates cannot set confidence directly.",
|
|
76
|
+
invariantCode: "belief.confidence_append_only",
|
|
77
|
+
suggestion: "Use epistemicBeliefs.modulateConfidence() so the beliefConfidence ledger and audit trail are updated together.",
|
|
78
|
+
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (Object.hasOwn(args.updates, "status")) {
|
|
82
|
+
throwInvariantError({
|
|
83
|
+
message: "Belief status transitions must use the dedicated belief lifecycle APIs.",
|
|
84
|
+
invariantCode: "belief.status_transition_requires_belief_api",
|
|
85
|
+
suggestion: "Use epistemicBeliefs.updateStatus() or epistemicBeliefs.archive() so status transitions emit the correct audit event.",
|
|
86
|
+
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const forbiddenMetadataKeys = getForbiddenMetadataKeys(args.updates.metadata);
|
|
90
|
+
if (forbiddenMetadataKeys.length > 0) {
|
|
91
|
+
throwInvariantError({
|
|
92
|
+
message: "Belief lineage and lifecycle metadata cannot be rewritten through generic node updates.",
|
|
93
|
+
invariantCode: "belief.lineage_requires_fork_belief",
|
|
94
|
+
suggestion: "Use epistemicBeliefs.forkBelief() for lineage changes and dedicated belief lifecycle mutations for status changes.",
|
|
95
|
+
details: {
|
|
96
|
+
mutationName: args.mutationName,
|
|
97
|
+
nodeId: args.node._id,
|
|
98
|
+
forbiddenMetadataKeys
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (isScoredBeliefNode(args.node) && (Object.hasOwn(args.updates, "canonicalText") || Object.hasOwn(args.updates, "contentHash"))) {
|
|
103
|
+
throwInvariantError({
|
|
104
|
+
message: "Cannot refine a scored belief in place. Scored formulations are immutable.",
|
|
105
|
+
invariantCode: "belief.formulation_immutable_after_scoring",
|
|
106
|
+
suggestion: "Use epistemicBeliefs.forkBelief() to evolve the formulation while preserving lineage.",
|
|
107
|
+
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function assertBeliefNodeArchiveAllowed(args) {
|
|
112
|
+
if (!isBeliefNode(args.node)) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
throwInvariantError({
|
|
116
|
+
message: "Belief archiving must go through the dedicated belief lifecycle API.",
|
|
117
|
+
invariantCode: "belief.status_transition_requires_belief_api",
|
|
118
|
+
suggestion: "Use epistemicBeliefs.archive() so the belief lifecycle audit trail stays consistent.",
|
|
119
|
+
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function assertBeliefNodeVerifyAllowed(args) {
|
|
123
|
+
if (!isBeliefNode(args.node) || args.confidence === void 0) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
throwInvariantError({
|
|
127
|
+
message: "Belief verification cannot set confidence directly. Confidence changes must stay append-only.",
|
|
128
|
+
invariantCode: "belief.confidence_append_only",
|
|
129
|
+
suggestion: "Call epistemicBeliefs.modulateConfidence() after verification so the confidence history is preserved.",
|
|
130
|
+
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function assertBeliefNodeSupersedeAllowed(args) {
|
|
134
|
+
if (!isBeliefNode(args.node)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
throwInvariantError({
|
|
138
|
+
message: "Belief lineage changes must use forkBelief(), not the generic supersede path.",
|
|
139
|
+
invariantCode: "belief.lineage_requires_fork_belief",
|
|
140
|
+
suggestion: "Use epistemicBeliefs.forkBelief() so the child belief, supersedes edge, and audit trail are created together.",
|
|
141
|
+
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function assertBeliefNodeHardDeleteAllowed(args) {
|
|
145
|
+
if (!isBeliefNode(args.node)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (!args.allowBeliefHardDelete) {
|
|
149
|
+
throwInvariantError({
|
|
150
|
+
message: "Belief hard delete is forbidden by default. Beliefs must retain lineage and audit history.",
|
|
151
|
+
invariantCode: "belief.hard_delete_forbidden",
|
|
152
|
+
suggestion: "Use epistemicBeliefs.archive() or epistemicBeliefs.forkBelief() instead. Only migration repair flows may opt into hard delete explicitly.",
|
|
153
|
+
details: { mutationName: args.mutationName, nodeId: args.node._id }
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (!args.reason.trim().toLowerCase().startsWith("migration:")) {
|
|
157
|
+
throwInvariantError({
|
|
158
|
+
message: "Belief hard delete bypasses require a migration-scoped rationale.",
|
|
159
|
+
invariantCode: "belief.hard_delete_forbidden",
|
|
160
|
+
suggestion: 'Retry with allowBeliefHardDelete: true and a reason starting with "migration:" only for one-off data repair flows.',
|
|
161
|
+
details: {
|
|
162
|
+
mutationName: args.mutationName,
|
|
163
|
+
nodeId: args.node._id,
|
|
164
|
+
reason: args.reason
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function assertOntologicalNodeGenericCreateAllowed(args) {
|
|
170
|
+
if (!ONTOLOGICAL_NODE_TYPES.has(args.nodeType)) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
throwInvariantError({
|
|
174
|
+
message: "Ontological entities must be created through the dedicated entity lifecycle API.",
|
|
175
|
+
invariantCode: "entity.create_requires_entity_lifecycle",
|
|
176
|
+
suggestion: "Use entityLifecycle.createEntity() so tenant-global canonical scope and deduplication are enforced.",
|
|
177
|
+
details: {
|
|
178
|
+
mutationName: args.mutationName,
|
|
179
|
+
nodeType: args.nodeType
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function assertOntologicalNodeGenericUpdateAllowed(args) {
|
|
184
|
+
if (!isOntologicalNode(args.node)) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
throwInvariantError({
|
|
188
|
+
message: "Ontological entities must be updated through the dedicated entity lifecycle API.",
|
|
189
|
+
invariantCode: "entity.update_requires_entity_lifecycle",
|
|
190
|
+
suggestion: "Use entityLifecycle.updateEntityAttributes() so canonical entity mutations stay type-safe and audited.",
|
|
191
|
+
details: {
|
|
192
|
+
mutationName: args.mutationName,
|
|
193
|
+
nodeId: args.node._id,
|
|
194
|
+
nodeType: args.node.nodeType
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function assertOntologicalNodeArchiveAllowed(args) {
|
|
199
|
+
if (!isOntologicalNode(args.node)) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
throwInvariantError({
|
|
203
|
+
message: "Ontological entities must be archived through the dedicated entity lifecycle API.",
|
|
204
|
+
invariantCode: "entity.archive_requires_entity_lifecycle",
|
|
205
|
+
suggestion: "Use entityLifecycle.archiveEntity() so entity archival emits the correct audit trail and review hooks.",
|
|
206
|
+
details: {
|
|
207
|
+
mutationName: args.mutationName,
|
|
208
|
+
nodeId: args.node._id,
|
|
209
|
+
nodeType: args.node.nodeType
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function assertOntologicalNodeSupersedeAllowed(args) {
|
|
214
|
+
if (!isOntologicalNode(args.node)) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
throwInvariantError({
|
|
218
|
+
message: "Ontological entities do not use the generic supersede path.",
|
|
219
|
+
invariantCode: "entity.supersede_requires_entity_lifecycle",
|
|
220
|
+
suggestion: "Use entityLifecycle.updateEntityAttributes() to edit an entity in place or entityLifecycle.mergeEntities() to collapse duplicates.",
|
|
221
|
+
details: {
|
|
222
|
+
mutationName: args.mutationName,
|
|
223
|
+
nodeId: args.node._id,
|
|
224
|
+
nodeType: args.node.nodeType
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export { assertBeliefNodeArchiveAllowed, assertBeliefNodeGenericUpdateAllowed, assertBeliefNodeHardDeleteAllowed, assertBeliefNodeSupersedeAllowed, assertBeliefNodeVerifyAllowed, assertOntologicalNodeArchiveAllowed, assertOntologicalNodeGenericCreateAllowed, assertOntologicalNodeGenericUpdateAllowed, assertOntologicalNodeSupersedeAllowed, isBeliefNode, isOntologicalNode, isScoredBeliefNode };
|
|
230
|
+
//# sourceMappingURL=invariantEnforcement.js.map
|
|
231
|
+
//# sourceMappingURL=invariantEnforcement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/beliefLifecycle.ts","../src/invariantEnforcement.ts"],"names":[],"mappings":";AA2BA,IAAM,4BAAA,GAA6D;AAAA,EACjE,WAAA;AAAA,EACA,cAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAiCO,SAAS,6BAA6B,cAAA,EAAkC;AAC7E,EAAA,IAAI,CAAC,cAAA,IAAkB,OAAO,cAAA,KAAmB,QAAA,EAAU;AACzD,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,MAAM,UAAW,cAAA,CAAyC,OAAA;AAC1D,EAAA,OACE,OAAO,OAAA,KAAY,QAAA,IACnB,4BAAA,CAA6B,SAAS,OAA4B,CAAA;AAEtE;;;ACrCA,IAAM,sCAAA,uBAA6C,GAAA,CAAI;AAAA,EACrD,cAAA;AAAA,EACA,iBAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,eAAA;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAC,CAAA;AAED,IAAM,sBAAA,uBAA6B,GAAA,CAAI;AAAA,EACrC,SAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAC,CAAA;AAED,SAAS,oBAAoB,IAAA,EAA4B;AACvD,EAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,IAAA,CAAK,OAAO,CAAA;AACpC,EAAA,KAAA,CAAM,MAAA,GAAS,KAAK,MAAA,IAAU,GAAA;AAC9B,EAAA,KAAA,CAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,qBAAA;AAC1B,EAAA,KAAA,CAAM,gBAAgB,IAAA,CAAK,aAAA;AAC3B,EAAA,KAAA,CAAM,aAAa,IAAA,CAAK,UAAA;AACxB,EAAA,KAAA,CAAM,UAAU,IAAA,CAAK,OAAA;AACrB,EAAA,MAAM,KAAA;AACR;AAEO,SAAS,aAAa,IAAA,EAAkD;AAC7E,EAAA,OAAO,MAAM,QAAA,KAAa,QAAA;AAC5B;AAEO,SAAS,kBACd,IAAA,EACS;AACT,EAAA,OACE,OAAO,IAAA,EAAM,QAAA,KAAa,YAAY,sBAAA,CAAuB,GAAA,CAAI,KAAK,QAAQ,CAAA;AAElF;AAEO,SAAS,mBAAmB,IAAA,EAA+B;AAChE,EAAA,IAAI,CAAC,YAAA,CAAa,IAAI,CAAA,EAAG;AACvB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GACJ,KAAK,QAAA,IAAY,OAAO,KAAK,QAAA,KAAa,QAAA,GACrC,KAAK,QAAA,GACN,MAAA;AAEN,EAAA,MAAM,iBAAA,GACJ,OAAO,IAAA,CAAK,UAAA,KAAe,YAAY,MAAA,CAAO,QAAA,CAAS,KAAK,UAAU,CAAA;AACxE,EAAA,IAAI,iBAAA,EAAmB;AACrB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OACE,6BAA6B,IAAA,CAAK,cAAc,CAAA,IAChD,4BAAA,CAA6B,UAAU,cAAc,CAAA;AAEzD;AAEA,SAAS,yBAAyB,QAAA,EAA6B;AAC7D,EAAA,IAAI,CAAC,YAAY,OAAO,QAAA,KAAa,YAAY,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EAAG;AACxE,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA;AAAA,IAAO,CAAC,GAAA,KACnC,sCAAA,CAAuC,GAAA,CAAI,GAAG;AAAA,GAChD;AACF;AAEO,SAAS,qCAAqC,IAAA,EAI5C;AACP,EAAA,IAAI,CAAC,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,EAAG;AAC5B,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,YAAY,CAAA,EAAG;AAC7C,IAAA,mBAAA,CAAoB;AAAA,MAClB,OAAA,EACE,wFAAA;AAAA,MACF,aAAA,EAAe,+BAAA;AAAA,MACf,UAAA,EACE,gHAAA;AAAA,MACF,OAAA,EAAS,EAAE,YAAA,EAAc,IAAA,CAAK,cAAc,MAAA,EAAQ,IAAA,CAAK,KAAK,GAAA;AAAI,KACnE,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,QAAQ,CAAA,EAAG;AACzC,IAAA,mBAAA,CAAoB;AAAA,MAClB,OAAA,EACE,yEAAA;AAAA,MACF,aAAA,EAAe,8CAAA;AAAA,MACf,UAAA,EACE,uHAAA;AAAA,MACF,OAAA,EAAS,EAAE,YAAA,EAAc,IAAA,CAAK,cAAc,MAAA,EAAQ,IAAA,CAAK,KAAK,GAAA;AAAI,KACnE,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,qBAAA,GAAwB,wBAAA,CAAyB,IAAA,CAAK,OAAA,CAAQ,QAAQ,CAAA;AAC5E,EAAA,IAAI,qBAAA,CAAsB,SAAS,CAAA,EAAG;AACpC,IAAA,mBAAA,CAAoB;AAAA,MAClB,OAAA,EACE,yFAAA;AAAA,MACF,aAAA,EAAe,qCAAA;AAAA,MACf,UAAA,EACE,oHAAA;AAAA,MACF,OAAA,EAAS;AAAA,QACP,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB,MAAA,EAAQ,KAAK,IAAA,CAAK,GAAA;AAAA,QAClB;AAAA;AACF,KACD,CAAA;AAAA,EACH;AAEA,EAAA,IACE,kBAAA,CAAmB,IAAA,CAAK,IAAI,CAAA,KAC3B,OAAO,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,eAAe,KAC1C,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,aAAa,CAAA,CAAA,EAC3C;AACA,IAAA,mBAAA,CAAoB;AAAA,MAClB,OAAA,EACE,4EAAA;AAAA,MACF,aAAA,EAAe,4CAAA;AAAA,MACf,UAAA,EACE,uFAAA;AAAA,MACF,OAAA,EAAS,EAAE,YAAA,EAAc,IAAA,CAAK,cAAc,MAAA,EAAQ,IAAA,CAAK,KAAK,GAAA;AAAI,KACnE,CAAA;AAAA,EACH;AACF;AAEO,SAAS,+BAA+B,IAAA,EAGtC;AACP,EAAA,IAAI,CAAC,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,EAAG;AAC5B,IAAA;AAAA,EACF;AAEA,EAAA,mBAAA,CAAoB;AAAA,IAClB,OAAA,EACE,sEAAA;AAAA,IACF,aAAA,EAAe,8CAAA;AAAA,IACf,UAAA,EACE,sFAAA;AAAA,IACF,OAAA,EAAS,EAAE,YAAA,EAAc,IAAA,CAAK,cAAc,MAAA,EAAQ,IAAA,CAAK,KAAK,GAAA;AAAI,GACnE,CAAA;AACH;AAEO,SAAS,8BAA8B,IAAA,EAIrC;AACP,EAAA,IAAI,CAAC,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,IAAK,IAAA,CAAK,eAAe,MAAA,EAAW;AAC7D,IAAA;AAAA,EACF;AAEA,EAAA,mBAAA,CAAoB;AAAA,IAClB,OAAA,EACE,+FAAA;AAAA,IACF,aAAA,EAAe,+BAAA;AAAA,IACf,UAAA,EACE,uGAAA;AAAA,IACF,OAAA,EAAS,EAAE,YAAA,EAAc,IAAA,CAAK,cAAc,MAAA,EAAQ,IAAA,CAAK,KAAK,GAAA;AAAI,GACnE,CAAA;AACH;AAEO,SAAS,iCAAiC,IAAA,EAGxC;AACP,EAAA,IAAI,CAAC,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,EAAG;AAC5B,IAAA;AAAA,EACF;AAEA,EAAA,mBAAA,CAAoB;AAAA,IAClB,OAAA,EACE,+EAAA;AAAA,IACF,aAAA,EAAe,qCAAA;AAAA,IACf,UAAA,EACE,+GAAA;AAAA,IACF,OAAA,EAAS,EAAE,YAAA,EAAc,IAAA,CAAK,cAAc,MAAA,EAAQ,IAAA,CAAK,KAAK,GAAA;AAAI,GACnE,CAAA;AACH;AAEO,SAAS,kCAAkC,IAAA,EAKzC;AACP,EAAA,IAAI,CAAC,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,EAAG;AAC5B,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,KAAK,qBAAA,EAAuB;AAC/B,IAAA,mBAAA,CAAoB;AAAA,MAClB,OAAA,EACE,4FAAA;AAAA,MACF,aAAA,EAAe,8BAAA;AAAA,MACf,UAAA,EACE,2IAAA;AAAA,MACF,OAAA,EAAS,EAAE,YAAA,EAAc,IAAA,CAAK,cAAc,MAAA,EAAQ,IAAA,CAAK,KAAK,GAAA;AAAI,KACnE,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,CAAC,KAAK,MAAA,CAAO,IAAA,GAAO,WAAA,EAAY,CAAE,UAAA,CAAW,YAAY,CAAA,EAAG;AAC9D,IAAA,mBAAA,CAAoB;AAAA,MAClB,OAAA,EACE,mEAAA;AAAA,MACF,aAAA,EAAe,8BAAA;AAAA,MACf,UAAA,EACE,oHAAA;AAAA,MACF,OAAA,EAAS;AAAA,QACP,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB,MAAA,EAAQ,KAAK,IAAA,CAAK,GAAA;AAAA,QAClB,QAAQ,IAAA,CAAK;AAAA;AACf,KACD,CAAA;AAAA,EACH;AACF;AAEO,SAAS,0CAA0C,IAAA,EAGjD;AACP,EAAA,IAAI,CAAC,sBAAA,CAAuB,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA,EAAG;AAC9C,IAAA;AAAA,EACF;AAEA,EAAA,mBAAA,CAAoB;AAAA,IAClB,OAAA,EACE,kFAAA;AAAA,IACF,aAAA,EAAe,yCAAA;AAAA,IACf,UAAA,EACE,qGAAA;AAAA,IACF,OAAA,EAAS;AAAA,MACP,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,UAAU,IAAA,CAAK;AAAA;AACjB,GACD,CAAA;AACH;AAEO,SAAS,0CAA0C,IAAA,EAGjD;AACP,EAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,CAAK,IAAI,CAAA,EAAG;AACjC,IAAA;AAAA,EACF;AAEA,EAAA,mBAAA,CAAoB;AAAA,IAClB,OAAA,EACE,kFAAA;AAAA,IACF,aAAA,EAAe,yCAAA;AAAA,IACf,UAAA,EACE,wGAAA;AAAA,IACF,OAAA,EAAS;AAAA,MACP,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,MAAA,EAAQ,KAAK,IAAA,CAAK,GAAA;AAAA,MAClB,QAAA,EAAU,KAAK,IAAA,CAAK;AAAA;AACtB,GACD,CAAA;AACH;AAEO,SAAS,oCAAoC,IAAA,EAG3C;AACP,EAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,CAAK,IAAI,CAAA,EAAG;AACjC,IAAA;AAAA,EACF;AAEA,EAAA,mBAAA,CAAoB;AAAA,IAClB,OAAA,EACE,mFAAA;AAAA,IACF,aAAA,EAAe,0CAAA;AAAA,IACf,UAAA,EACE,wGAAA;AAAA,IACF,OAAA,EAAS;AAAA,MACP,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,MAAA,EAAQ,KAAK,IAAA,CAAK,GAAA;AAAA,MAClB,QAAA,EAAU,KAAK,IAAA,CAAK;AAAA;AACtB,GACD,CAAA;AACH;AAEO,SAAS,sCAAsC,IAAA,EAG7C;AACP,EAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,CAAK,IAAI,CAAA,EAAG;AACjC,IAAA;AAAA,EACF;AAEA,EAAA,mBAAA,CAAoB;AAAA,IAClB,OAAA,EACE,6DAAA;AAAA,IACF,aAAA,EAAe,4CAAA;AAAA,IACf,UAAA,EACE,oIAAA;AAAA,IACF,OAAA,EAAS;AAAA,MACP,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,MAAA,EAAQ,KAAK,IAAA,CAAK,GAAA;AAAA,MAClB,QAAA,EAAU,KAAK,IAAA,CAAK;AAAA;AACtB,GACD,CAAA;AACH","file":"invariantEnforcement.js","sourcesContent":["/**\n * Belief lifecycle helpers shared across Convex modules.\n *\n * Canonical lifecycle:\n * assumption -> hypothesis -> belief -> fact\n */\n\nexport type BeliefLifecycleStatus =\n | \"assumption\"\n | \"hypothesis\"\n | \"belief\"\n | \"fact\";\n\ntype PredictionOutcome =\n | \"pending\"\n | \"confirmed\"\n | \"disconfirmed\"\n | \"partial\"\n | \"expired\";\n\nconst BELIEF_STATUS_VALUES: readonly BeliefLifecycleStatus[] = [\n \"assumption\",\n \"hypothesis\",\n \"belief\",\n \"fact\",\n];\n\nconst RESOLVED_PREDICTION_OUTCOMES: readonly PredictionOutcome[] = [\n \"confirmed\",\n \"disconfirmed\",\n \"partial\",\n \"expired\",\n];\n\nexport function isBeliefLifecycleStatus(\n value: unknown\n): value is BeliefLifecycleStatus {\n return (\n typeof value === \"string\" &&\n BELIEF_STATUS_VALUES.includes(value as BeliefLifecycleStatus)\n );\n}\n\nfunction normalizeBeliefConfidence(confidence: unknown): number | null {\n if (typeof confidence !== \"number\" || !Number.isFinite(confidence)) {\n return null;\n }\n if (confidence >= 0 && confidence <= 1) {\n return confidence;\n }\n // Backward compatibility with historical percentage-scale confidence (0-100).\n if (confidence > 1 && confidence <= 100) {\n return confidence / 100;\n }\n return null;\n}\n\nexport function isResolvedByConfidence(confidence: unknown): boolean {\n const normalized = normalizeBeliefConfidence(confidence);\n if (normalized === null) {\n return false;\n }\n return normalized <= 0 || normalized >= 1;\n}\n\nexport function hasResolvedPredictionOutcome(predictionMeta: unknown): boolean {\n if (!predictionMeta || typeof predictionMeta !== \"object\") {\n return false;\n }\n const outcome = (predictionMeta as { outcome?: unknown }).outcome;\n return (\n typeof outcome === \"string\" &&\n RESOLVED_PREDICTION_OUTCOMES.includes(outcome as PredictionOutcome)\n );\n}\n\nfunction getPredictionMetaFromMetadata(\n metadata: Record<string, unknown> | undefined\n): unknown {\n return metadata?.predictionMeta;\n}\n\nexport function shouldTreatBeliefAsFact(opts: {\n confidence?: unknown;\n predictionMeta?: unknown;\n metadata?: Record<string, unknown>;\n}): boolean {\n if (isResolvedByConfidence(opts.confidence)) {\n return true;\n }\n if (hasResolvedPredictionOutcome(opts.predictionMeta)) {\n return true;\n }\n if (\n hasResolvedPredictionOutcome(getPredictionMetaFromMetadata(opts.metadata))\n ) {\n return true;\n }\n return false;\n}\n\nexport function resolveBeliefLifecycleStatus(opts: {\n beliefStatus?: unknown;\n confidence?: unknown;\n predictionMeta?: unknown;\n metadata?: Record<string, unknown>;\n}): BeliefLifecycleStatus {\n if (shouldTreatBeliefAsFact(opts)) {\n return \"fact\";\n }\n\n const direct = opts.beliefStatus;\n if (isBeliefLifecycleStatus(direct)) {\n // If the belief has been scored (has numeric credence) but stored status\n // is still pre-validation, promote to \"belief\". Scoring = merge to main.\n const normalized = normalizeBeliefConfidence(opts.confidence);\n if (normalized !== null && isPreValidationBeliefStatus(direct)) {\n return \"belief\";\n }\n return direct;\n }\n\n const metaStatus = opts.metadata?.beliefStatus;\n if (isBeliefLifecycleStatus(metaStatus)) {\n const normalized = normalizeBeliefConfidence(opts.confidence);\n if (normalized !== null && isPreValidationBeliefStatus(metaStatus)) {\n return \"belief\";\n }\n return metaStatus;\n }\n\n return \"assumption\";\n}\n\nexport function isPreValidationBeliefStatus(\n status: BeliefLifecycleStatus\n): boolean {\n return status === \"assumption\" || status === \"hypothesis\";\n}\n\nexport function isPropagationEligibleBeliefStatus(\n status: BeliefLifecycleStatus\n): boolean {\n return status === \"belief\" || status === \"fact\";\n}\n\nexport function promoteBeliefStatusAfterScoring(\n status: BeliefLifecycleStatus,\n opts?: {\n confidence?: unknown;\n predictionMeta?: unknown;\n metadata?: Record<string, unknown>;\n }\n): BeliefLifecycleStatus {\n if (shouldTreatBeliefAsFact({ ...opts })) {\n return \"fact\";\n }\n if (isPreValidationBeliefStatus(status)) {\n return \"belief\";\n }\n return status === \"fact\" ? \"fact\" : \"belief\";\n}\n","/** Invariant error helpers that protect belief lifecycle mutations. */\nimport { hasResolvedPredictionOutcome } from \"./beliefLifecycle\";\n\ntype StructuredInvariantError = Error & {\n status: number;\n code: string;\n invariantCode?: string;\n suggestion?: string;\n details?: unknown;\n};\n\ntype BeliefNodeLike = {\n _id?: string;\n nodeType?: unknown;\n confidence?: unknown;\n metadata?: unknown;\n predictionMeta?: unknown;\n};\n\ntype InvariantArgs = {\n message: string;\n invariantCode:\n | \"belief.formulation_immutable_after_scoring\"\n | \"belief.confidence_append_only\"\n | \"belief.status_transition_requires_belief_api\"\n | \"belief.lineage_requires_fork_belief\"\n | \"belief.hard_delete_forbidden\"\n | \"entity.create_requires_entity_lifecycle\"\n | \"entity.update_requires_entity_lifecycle\"\n | \"entity.archive_requires_entity_lifecycle\"\n | \"entity.supersede_requires_entity_lifecycle\";\n suggestion: string;\n status?: number;\n code?: string;\n details?: unknown;\n};\n\nconst FORBIDDEN_GENERIC_BELIEF_METADATA_KEYS = new Set([\n \"beliefStatus\",\n \"epistemicStatus\",\n \"forkedBy\",\n \"forkedFrom\",\n \"forkReason\",\n \"forkTimestamp\",\n \"status\",\n \"supersededBy\",\n \"supersedes\",\n]);\n\nconst ONTOLOGICAL_NODE_TYPES = new Set([\n \"company\",\n \"person\",\n \"investor\",\n \"function\",\n \"value_chain\",\n]);\n\nfunction throwInvariantError(args: InvariantArgs): never {\n const error = new Error(args.message) as StructuredInvariantError;\n error.status = args.status ?? 409;\n error.code = args.code ?? \"INVARIANT_VIOLATION\";\n error.invariantCode = args.invariantCode;\n error.suggestion = args.suggestion;\n error.details = args.details;\n throw error;\n}\n\nexport function isBeliefNode(node: BeliefNodeLike | null | undefined): boolean {\n return node?.nodeType === \"belief\";\n}\n\nexport function isOntologicalNode(\n node: BeliefNodeLike | null | undefined\n): boolean {\n return (\n typeof node?.nodeType === \"string\" && ONTOLOGICAL_NODE_TYPES.has(node.nodeType)\n );\n}\n\nexport function isScoredBeliefNode(node: BeliefNodeLike): boolean {\n if (!isBeliefNode(node)) {\n return false;\n }\n\n const metadata =\n node.metadata && typeof node.metadata === \"object\"\n ? (node.metadata as Record<string, unknown>)\n : undefined;\n\n const numericConfidence =\n typeof node.confidence === \"number\" && Number.isFinite(node.confidence);\n if (numericConfidence) {\n return true;\n }\n\n return (\n hasResolvedPredictionOutcome(node.predictionMeta) ||\n hasResolvedPredictionOutcome(metadata?.predictionMeta)\n );\n}\n\nfunction getForbiddenMetadataKeys(metadata: unknown): string[] {\n if (!metadata || typeof metadata !== \"object\" || Array.isArray(metadata)) {\n return [];\n }\n\n return Object.keys(metadata).filter((key) =>\n FORBIDDEN_GENERIC_BELIEF_METADATA_KEYS.has(key)\n );\n}\n\nexport function assertBeliefNodeGenericUpdateAllowed(args: {\n node: BeliefNodeLike;\n updates: Record<string, unknown>;\n mutationName: string;\n}): void {\n if (!isBeliefNode(args.node)) {\n return;\n }\n\n if (Object.hasOwn(args.updates, \"confidence\")) {\n throwInvariantError({\n message:\n \"Belief confidence is append-only. Generic node updates cannot set confidence directly.\",\n invariantCode: \"belief.confidence_append_only\",\n suggestion:\n \"Use epistemicBeliefs.modulateConfidence() so the beliefConfidence ledger and audit trail are updated together.\",\n details: { mutationName: args.mutationName, nodeId: args.node._id },\n });\n }\n\n if (Object.hasOwn(args.updates, \"status\")) {\n throwInvariantError({\n message:\n \"Belief status transitions must use the dedicated belief lifecycle APIs.\",\n invariantCode: \"belief.status_transition_requires_belief_api\",\n suggestion:\n \"Use epistemicBeliefs.updateStatus() or epistemicBeliefs.archive() so status transitions emit the correct audit event.\",\n details: { mutationName: args.mutationName, nodeId: args.node._id },\n });\n }\n\n const forbiddenMetadataKeys = getForbiddenMetadataKeys(args.updates.metadata);\n if (forbiddenMetadataKeys.length > 0) {\n throwInvariantError({\n message:\n \"Belief lineage and lifecycle metadata cannot be rewritten through generic node updates.\",\n invariantCode: \"belief.lineage_requires_fork_belief\",\n suggestion:\n \"Use epistemicBeliefs.forkBelief() for lineage changes and dedicated belief lifecycle mutations for status changes.\",\n details: {\n mutationName: args.mutationName,\n nodeId: args.node._id,\n forbiddenMetadataKeys,\n },\n });\n }\n\n if (\n isScoredBeliefNode(args.node) &&\n (Object.hasOwn(args.updates, \"canonicalText\") ||\n Object.hasOwn(args.updates, \"contentHash\"))\n ) {\n throwInvariantError({\n message:\n \"Cannot refine a scored belief in place. Scored formulations are immutable.\",\n invariantCode: \"belief.formulation_immutable_after_scoring\",\n suggestion:\n \"Use epistemicBeliefs.forkBelief() to evolve the formulation while preserving lineage.\",\n details: { mutationName: args.mutationName, nodeId: args.node._id },\n });\n }\n}\n\nexport function assertBeliefNodeArchiveAllowed(args: {\n node: BeliefNodeLike;\n mutationName: string;\n}): void {\n if (!isBeliefNode(args.node)) {\n return;\n }\n\n throwInvariantError({\n message:\n \"Belief archiving must go through the dedicated belief lifecycle API.\",\n invariantCode: \"belief.status_transition_requires_belief_api\",\n suggestion:\n \"Use epistemicBeliefs.archive() so the belief lifecycle audit trail stays consistent.\",\n details: { mutationName: args.mutationName, nodeId: args.node._id },\n });\n}\n\nexport function assertBeliefNodeVerifyAllowed(args: {\n node: BeliefNodeLike;\n confidence: number | undefined;\n mutationName: string;\n}): void {\n if (!isBeliefNode(args.node) || args.confidence === undefined) {\n return;\n }\n\n throwInvariantError({\n message:\n \"Belief verification cannot set confidence directly. Confidence changes must stay append-only.\",\n invariantCode: \"belief.confidence_append_only\",\n suggestion:\n \"Call epistemicBeliefs.modulateConfidence() after verification so the confidence history is preserved.\",\n details: { mutationName: args.mutationName, nodeId: args.node._id },\n });\n}\n\nexport function assertBeliefNodeSupersedeAllowed(args: {\n node: BeliefNodeLike;\n mutationName: string;\n}): void {\n if (!isBeliefNode(args.node)) {\n return;\n }\n\n throwInvariantError({\n message:\n \"Belief lineage changes must use forkBelief(), not the generic supersede path.\",\n invariantCode: \"belief.lineage_requires_fork_belief\",\n suggestion:\n \"Use epistemicBeliefs.forkBelief() so the child belief, supersedes edge, and audit trail are created together.\",\n details: { mutationName: args.mutationName, nodeId: args.node._id },\n });\n}\n\nexport function assertBeliefNodeHardDeleteAllowed(args: {\n node: BeliefNodeLike;\n allowBeliefHardDelete: boolean;\n reason: string;\n mutationName: string;\n}): void {\n if (!isBeliefNode(args.node)) {\n return;\n }\n\n if (!args.allowBeliefHardDelete) {\n throwInvariantError({\n message:\n \"Belief hard delete is forbidden by default. Beliefs must retain lineage and audit history.\",\n invariantCode: \"belief.hard_delete_forbidden\",\n suggestion:\n \"Use epistemicBeliefs.archive() or epistemicBeliefs.forkBelief() instead. Only migration repair flows may opt into hard delete explicitly.\",\n details: { mutationName: args.mutationName, nodeId: args.node._id },\n });\n }\n\n if (!args.reason.trim().toLowerCase().startsWith(\"migration:\")) {\n throwInvariantError({\n message:\n \"Belief hard delete bypasses require a migration-scoped rationale.\",\n invariantCode: \"belief.hard_delete_forbidden\",\n suggestion:\n 'Retry with allowBeliefHardDelete: true and a reason starting with \"migration:\" only for one-off data repair flows.',\n details: {\n mutationName: args.mutationName,\n nodeId: args.node._id,\n reason: args.reason,\n },\n });\n }\n}\n\nexport function assertOntologicalNodeGenericCreateAllowed(args: {\n nodeType: string;\n mutationName: string;\n}): void {\n if (!ONTOLOGICAL_NODE_TYPES.has(args.nodeType)) {\n return;\n }\n\n throwInvariantError({\n message:\n \"Ontological entities must be created through the dedicated entity lifecycle API.\",\n invariantCode: \"entity.create_requires_entity_lifecycle\",\n suggestion:\n \"Use entityLifecycle.createEntity() so tenant-global canonical scope and deduplication are enforced.\",\n details: {\n mutationName: args.mutationName,\n nodeType: args.nodeType,\n },\n });\n}\n\nexport function assertOntologicalNodeGenericUpdateAllowed(args: {\n node: BeliefNodeLike;\n mutationName: string;\n}): void {\n if (!isOntologicalNode(args.node)) {\n return;\n }\n\n throwInvariantError({\n message:\n \"Ontological entities must be updated through the dedicated entity lifecycle API.\",\n invariantCode: \"entity.update_requires_entity_lifecycle\",\n suggestion:\n \"Use entityLifecycle.updateEntityAttributes() so canonical entity mutations stay type-safe and audited.\",\n details: {\n mutationName: args.mutationName,\n nodeId: args.node._id,\n nodeType: args.node.nodeType,\n },\n });\n}\n\nexport function assertOntologicalNodeArchiveAllowed(args: {\n node: BeliefNodeLike;\n mutationName: string;\n}): void {\n if (!isOntologicalNode(args.node)) {\n return;\n }\n\n throwInvariantError({\n message:\n \"Ontological entities must be archived through the dedicated entity lifecycle API.\",\n invariantCode: \"entity.archive_requires_entity_lifecycle\",\n suggestion:\n \"Use entityLifecycle.archiveEntity() so entity archival emits the correct audit trail and review hooks.\",\n details: {\n mutationName: args.mutationName,\n nodeId: args.node._id,\n nodeType: args.node.nodeType,\n },\n });\n}\n\nexport function assertOntologicalNodeSupersedeAllowed(args: {\n node: BeliefNodeLike;\n mutationName: string;\n}): void {\n if (!isOntologicalNode(args.node)) {\n return;\n }\n\n throwInvariantError({\n message:\n \"Ontological entities do not use the generic supersede path.\",\n invariantCode: \"entity.supersede_requires_entity_lifecycle\",\n suggestion:\n \"Use entityLifecycle.updateEntityAttributes() to edit an entity in place or entityLifecycle.mergeEntities() to collapse duplicates.\",\n details: {\n mutationName: args.mutationName,\n nodeId: args.node._id,\n nodeType: args.node.nodeType,\n },\n });\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { QueryCtx, MutationCtx, Id } from './convex.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* logicalRoleInference module implementation.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
type LogicalRole = "necessary" | "sufficient" | "necessary_sufficient" | "contributory" | "corroborative";
|
|
8
|
+
type GraphCtx = QueryCtx | MutationCtx;
|
|
9
|
+
declare function computeLogicalRole(ctx: GraphCtx, evidenceId: Id<"epistemicNodes">, beliefId: Id<"epistemicNodes">): Promise<LogicalRole>;
|
|
10
|
+
|
|
11
|
+
declare const logicalRoleInference_computeLogicalRole: typeof computeLogicalRole;
|
|
12
|
+
declare namespace logicalRoleInference {
|
|
13
|
+
export { logicalRoleInference_computeLogicalRole as computeLogicalRole };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { computeLogicalRole as c, logicalRoleInference as l };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// src/logicalRoleInference.ts
|
|
2
|
+
var PILLAR_IMPORTANCE = {
|
|
3
|
+
market: 1,
|
|
4
|
+
competition: 2,
|
|
5
|
+
product: 3,
|
|
6
|
+
team: 4,
|
|
7
|
+
financials: 5,
|
|
8
|
+
timing: 6,
|
|
9
|
+
other: 10
|
|
10
|
+
};
|
|
11
|
+
async function computeLogicalRole(ctx, evidenceId, beliefId) {
|
|
12
|
+
const belief = await ctx.db.get(beliefId);
|
|
13
|
+
if (!belief || belief.nodeType !== "belief") {
|
|
14
|
+
return "contributory";
|
|
15
|
+
}
|
|
16
|
+
const beliefMetadata = belief.metadata;
|
|
17
|
+
const pillar = beliefMetadata?.pillar || "other";
|
|
18
|
+
const pillarRank = PILLAR_IMPORTANCE[pillar] ?? 10;
|
|
19
|
+
const isSynthesized = await checkIfSynthesizedHypothesis(ctx, beliefId);
|
|
20
|
+
const testingQuestions = await getTestingQuestionsForBelief(ctx, beliefId);
|
|
21
|
+
const answeredQuestions = await getQuestionsAnsweredByEvidence(
|
|
22
|
+
ctx,
|
|
23
|
+
evidenceId
|
|
24
|
+
);
|
|
25
|
+
const directlyTests = testingQuestions.filter(
|
|
26
|
+
(questionId) => answeredQuestions.includes(questionId)
|
|
27
|
+
);
|
|
28
|
+
if (directlyTests.length === 0) {
|
|
29
|
+
return "contributory";
|
|
30
|
+
}
|
|
31
|
+
if (isSynthesized && pillarRank <= 2) {
|
|
32
|
+
return directlyTests.length > 1 ? "necessary_sufficient" : "necessary";
|
|
33
|
+
}
|
|
34
|
+
if (isSynthesized) {
|
|
35
|
+
return "necessary";
|
|
36
|
+
}
|
|
37
|
+
return directlyTests.length > 1 ? "necessary" : "contributory";
|
|
38
|
+
}
|
|
39
|
+
async function checkIfSynthesizedHypothesis(ctx, beliefId) {
|
|
40
|
+
const belief = await ctx.db.get(beliefId);
|
|
41
|
+
if (!belief) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const metadata = belief.metadata;
|
|
45
|
+
return metadata?.isSynthesized === true || metadata?.beliefStatus === "hypothesis";
|
|
46
|
+
}
|
|
47
|
+
async function getTestingQuestionsForBelief(ctx, beliefId) {
|
|
48
|
+
const testEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
49
|
+
"by_to_type",
|
|
50
|
+
(q) => q.eq("toNodeId", beliefId).eq("edgeType", "tests")
|
|
51
|
+
).collect();
|
|
52
|
+
return testEdges.map((edge) => edge.fromNodeId).filter((id) => id !== void 0);
|
|
53
|
+
}
|
|
54
|
+
async function getQuestionsAnsweredByEvidence(ctx, evidenceId) {
|
|
55
|
+
const answerEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
56
|
+
"by_from_type",
|
|
57
|
+
(q) => q.eq("fromNodeId", evidenceId).eq("edgeType", "derived_from")
|
|
58
|
+
).collect();
|
|
59
|
+
return answerEdges.map((edge) => edge.toNodeId).filter((id) => id !== void 0);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { computeLogicalRole };
|
|
63
|
+
//# sourceMappingURL=logicalRoleInference.js.map
|
|
64
|
+
//# sourceMappingURL=logicalRoleInference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/logicalRoleInference.ts"],"names":[],"mappings":";AAaA,IAAM,iBAAA,GAA4C;AAAA,EAChD,MAAA,EAAQ,CAAA;AAAA,EACR,WAAA,EAAa,CAAA;AAAA,EACb,OAAA,EAAS,CAAA;AAAA,EACT,IAAA,EAAM,CAAA;AAAA,EACN,UAAA,EAAY,CAAA;AAAA,EACZ,MAAA,EAAQ,CAAA;AAAA,EACR,KAAA,EAAO;AACT,CAAA;AAIA,eAAsB,kBAAA,CACpB,GAAA,EACA,UAAA,EACA,QAAA,EACsB;AACtB,EAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,EAAA,CAAG,IAAI,QAAQ,CAAA;AACxC,EAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,QAAA,KAAa,QAAA,EAAU;AAC3C,IAAA,OAAO,cAAA;AAAA,EACT;AAEA,EAAA,MAAM,iBAAiB,MAAA,CAAO,QAAA;AAC9B,EAAA,MAAM,MAAA,GAAU,gBAAgB,MAAA,IAAqB,OAAA;AACrD,EAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,MAAM,CAAA,IAAK,EAAA;AAEhD,EAAA,MAAM,aAAA,GAAgB,MAAM,4BAAA,CAA6B,GAAA,EAAK,QAAQ,CAAA;AACtE,EAAA,MAAM,gBAAA,GAAmB,MAAM,4BAAA,CAA6B,GAAA,EAAK,QAAQ,CAAA;AACzE,EAAA,MAAM,oBAAoB,MAAM,8BAAA;AAAA,IAC9B,GAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,gBAAgB,gBAAA,CAAiB,MAAA;AAAA,IAAO,CAAC,UAAA,KAC7C,iBAAA,CAAkB,QAAA,CAAS,UAAU;AAAA,GACvC;AAEA,EAAA,IAAI,aAAA,CAAc,WAAW,CAAA,EAAG;AAC9B,IAAA,OAAO,cAAA;AAAA,EACT;AAEA,EAAA,IAAI,aAAA,IAAiB,cAAc,CAAA,EAAG;AACpC,IAAA,OAAO,aAAA,CAAc,MAAA,GAAS,CAAA,GAAI,sBAAA,GAAyB,WAAA;AAAA,EAC7D;AAEA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,OAAO,aAAA,CAAc,MAAA,GAAS,CAAA,GAAI,WAAA,GAAc,cAAA;AAClD;AAEA,eAAe,4BAAA,CACb,KACA,QAAA,EACkB;AAClB,EAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,EAAA,CAAG,IAAI,QAAQ,CAAA;AACxC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAW,MAAA,CAAO,QAAA;AACxB,EAAA,OACE,QAAA,EAAU,aAAA,KAAkB,IAAA,IAC5B,QAAA,EAAU,YAAA,KAAiB,YAAA;AAE/B;AAEA,eAAe,4BAAA,CACb,KACA,QAAA,EACmB;AACnB,EAAA,MAAM,YAAY,MAAM,GAAA,CAAI,EAAA,CACzB,KAAA,CAAM,gBAAgB,CAAA,CACtB,SAAA;AAAA,IAAU,YAAA;AAAA,IAAc,CAAC,MACxB,CAAA,CAAE,EAAA,CAAG,YAAY,QAAQ,CAAA,CAAE,EAAA,CAAG,UAAA,EAAY,OAAO;AAAA,IAElD,OAAA,EAAQ;AAEX,EAAA,OAAO,SAAA,CACJ,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,UAAoB,CAAA,CACvC,MAAA,CAAO,CAAC,EAAA,KAAqB,EAAA,KAAO,MAAS,CAAA;AAClD;AAEA,eAAe,8BAAA,CACb,KACA,UAAA,EACmB;AACnB,EAAA,MAAM,cAAc,MAAM,GAAA,CAAI,EAAA,CAC3B,KAAA,CAAM,gBAAgB,CAAA,CACtB,SAAA;AAAA,IAAU,cAAA;AAAA,IAAgB,CAAC,MAC1B,CAAA,CAAE,EAAA,CAAG,cAAc,UAAU,CAAA,CAAE,EAAA,CAAG,UAAA,EAAY,cAAc;AAAA,IAE7D,OAAA,EAAQ;AAEX,EAAA,OAAO,WAAA,CACJ,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,QAAkB,CAAA,CACrC,MAAA,CAAO,CAAC,EAAA,KAAqB,EAAA,KAAO,MAAS,CAAA;AAClD","file":"logicalRoleInference.js","sourcesContent":["/**\n * logicalRoleInference module implementation.\n */\n\nimport type { Id, MutationCtx, QueryCtx } from \"./convex\";\n\ntype LogicalRole =\n | \"necessary\"\n | \"sufficient\"\n | \"necessary_sufficient\"\n | \"contributory\"\n | \"corroborative\";\n\nconst PILLAR_IMPORTANCE: Record<string, number> = {\n market: 1,\n competition: 2,\n product: 3,\n team: 4,\n financials: 5,\n timing: 6,\n other: 10,\n};\n\ntype GraphCtx = QueryCtx | MutationCtx;\n\nexport async function computeLogicalRole(\n ctx: GraphCtx,\n evidenceId: Id<\"epistemicNodes\">,\n beliefId: Id<\"epistemicNodes\">\n): Promise<LogicalRole> {\n const belief = await ctx.db.get(beliefId);\n if (!belief || belief.nodeType !== \"belief\") {\n return \"contributory\";\n }\n\n const beliefMetadata = belief.metadata as Record<string, unknown> | undefined;\n const pillar = (beliefMetadata?.pillar as string) || \"other\";\n const pillarRank = PILLAR_IMPORTANCE[pillar] ?? 10;\n\n const isSynthesized = await checkIfSynthesizedHypothesis(ctx, beliefId);\n const testingQuestions = await getTestingQuestionsForBelief(ctx, beliefId);\n const answeredQuestions = await getQuestionsAnsweredByEvidence(\n ctx,\n evidenceId\n );\n const directlyTests = testingQuestions.filter((questionId) =>\n answeredQuestions.includes(questionId)\n );\n\n if (directlyTests.length === 0) {\n return \"contributory\";\n }\n\n if (isSynthesized && pillarRank <= 2) {\n return directlyTests.length > 1 ? \"necessary_sufficient\" : \"necessary\";\n }\n\n if (isSynthesized) {\n return \"necessary\";\n }\n\n return directlyTests.length > 1 ? \"necessary\" : \"contributory\";\n}\n\nasync function checkIfSynthesizedHypothesis(\n ctx: GraphCtx,\n beliefId: Id<\"epistemicNodes\">\n): Promise<boolean> {\n const belief = await ctx.db.get(beliefId);\n if (!belief) {\n return false;\n }\n\n const metadata = belief.metadata as Record<string, unknown> | undefined;\n return (\n metadata?.isSynthesized === true ||\n metadata?.beliefStatus === \"hypothesis\"\n );\n}\n\nasync function getTestingQuestionsForBelief(\n ctx: GraphCtx,\n beliefId: Id<\"epistemicNodes\">\n): Promise<string[]> {\n const testEdges = await ctx.db\n .query(\"epistemicEdges\")\n .withIndex(\"by_to_type\", (q) =>\n q.eq(\"toNodeId\", beliefId).eq(\"edgeType\", \"tests\")\n )\n .collect();\n\n return testEdges\n .map((edge) => edge.fromNodeId as string)\n .filter((id): id is string => id !== undefined);\n}\n\nasync function getQuestionsAnsweredByEvidence(\n ctx: GraphCtx,\n evidenceId: Id<\"epistemicNodes\">\n): Promise<string[]> {\n const answerEdges = await ctx.db\n .query(\"epistemicEdges\")\n .withIndex(\"by_from_type\", (q) =>\n q.eq(\"fromNodeId\", evidenceId).eq(\"edgeType\", \"derived_from\")\n )\n .collect();\n\n return answerEdges\n .map((edge) => edge.toNodeId as string)\n .filter((id): id is string => id !== undefined);\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Matcher feedback helper types shared by graph-primitive review flows. */
|
|
2
|
+
type LinkSuggestionStatus = "suggested" | "approved" | "dismissed";
|
|
3
|
+
type MatcherReviewStatus = "pending" | "accepted" | "rejected" | "auto_accepted" | "superseded";
|
|
4
|
+
type MatcherFeedbackSummaryRow = {
|
|
5
|
+
matcherKey?: string | null;
|
|
6
|
+
reviewStatus: MatcherReviewStatus;
|
|
7
|
+
rewardScore?: number | null;
|
|
8
|
+
surface?: string | null;
|
|
9
|
+
};
|
|
10
|
+
declare function isOperationalLinkStatus(status?: LinkSuggestionStatus | null): boolean;
|
|
11
|
+
declare function mergeLinkSuggestionStatus(existing?: LinkSuggestionStatus | null, requested?: LinkSuggestionStatus | null): LinkSuggestionStatus | undefined;
|
|
12
|
+
declare function resolveReviewedLinkStatus(requested: "approved" | "dismissed"): LinkSuggestionStatus;
|
|
13
|
+
declare function deriveMatcherReviewStatus(input: {
|
|
14
|
+
explicitReviewStatus?: MatcherReviewStatus | null;
|
|
15
|
+
linkStatus?: LinkSuggestionStatus | null;
|
|
16
|
+
autoAccepted?: boolean;
|
|
17
|
+
}): MatcherReviewStatus;
|
|
18
|
+
declare function deriveMatcherRewardScore(reviewStatus: MatcherReviewStatus): number;
|
|
19
|
+
declare function summarizeMatcherFeedback(rows: MatcherFeedbackSummaryRow[]): {
|
|
20
|
+
decided: number;
|
|
21
|
+
acceptanceRate: number;
|
|
22
|
+
averageReward: number;
|
|
23
|
+
uniqueSurfaces: number;
|
|
24
|
+
uniqueMatchers: number;
|
|
25
|
+
total: number;
|
|
26
|
+
pending: number;
|
|
27
|
+
accepted: number;
|
|
28
|
+
autoAccepted: number;
|
|
29
|
+
rejected: number;
|
|
30
|
+
superseded: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { type LinkSuggestionStatus, type MatcherReviewStatus, deriveMatcherReviewStatus, deriveMatcherRewardScore, isOperationalLinkStatus, mergeLinkSuggestionStatus, resolveReviewedLinkStatus, summarizeMatcherFeedback };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// src/matcherFeedbackUtils.ts
|
|
2
|
+
function isOperationalLinkStatus(status) {
|
|
3
|
+
return status !== "suggested" && status !== "dismissed";
|
|
4
|
+
}
|
|
5
|
+
function mergeLinkSuggestionStatus(existing, requested) {
|
|
6
|
+
if (requested === void 0 || requested === null) {
|
|
7
|
+
return existing ?? void 0;
|
|
8
|
+
}
|
|
9
|
+
if (existing && isOperationalLinkStatus(existing) && !isOperationalLinkStatus(requested)) {
|
|
10
|
+
return existing;
|
|
11
|
+
}
|
|
12
|
+
return requested;
|
|
13
|
+
}
|
|
14
|
+
function resolveReviewedLinkStatus(requested) {
|
|
15
|
+
return requested;
|
|
16
|
+
}
|
|
17
|
+
function deriveMatcherReviewStatus(input) {
|
|
18
|
+
if (input.explicitReviewStatus) {
|
|
19
|
+
return input.explicitReviewStatus;
|
|
20
|
+
}
|
|
21
|
+
if (input.autoAccepted) {
|
|
22
|
+
return "auto_accepted";
|
|
23
|
+
}
|
|
24
|
+
if (input.linkStatus === "suggested") {
|
|
25
|
+
return "pending";
|
|
26
|
+
}
|
|
27
|
+
if (input.linkStatus === "dismissed") {
|
|
28
|
+
return "rejected";
|
|
29
|
+
}
|
|
30
|
+
return "accepted";
|
|
31
|
+
}
|
|
32
|
+
function deriveMatcherRewardScore(reviewStatus) {
|
|
33
|
+
switch (reviewStatus) {
|
|
34
|
+
case "accepted":
|
|
35
|
+
case "auto_accepted":
|
|
36
|
+
return 1;
|
|
37
|
+
case "rejected":
|
|
38
|
+
return -1;
|
|
39
|
+
default:
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function summarizeMatcherFeedback(rows) {
|
|
44
|
+
const totals = {
|
|
45
|
+
total: rows.length,
|
|
46
|
+
pending: 0,
|
|
47
|
+
accepted: 0,
|
|
48
|
+
autoAccepted: 0,
|
|
49
|
+
rejected: 0,
|
|
50
|
+
superseded: 0
|
|
51
|
+
};
|
|
52
|
+
const surfaces = /* @__PURE__ */ new Set();
|
|
53
|
+
const matcherKeys = /* @__PURE__ */ new Set();
|
|
54
|
+
let rewardSum = 0;
|
|
55
|
+
for (const row of rows) {
|
|
56
|
+
if (row.surface) {
|
|
57
|
+
surfaces.add(row.surface);
|
|
58
|
+
}
|
|
59
|
+
if (row.matcherKey) {
|
|
60
|
+
matcherKeys.add(row.matcherKey);
|
|
61
|
+
}
|
|
62
|
+
switch (row.reviewStatus) {
|
|
63
|
+
case "pending":
|
|
64
|
+
totals.pending += 1;
|
|
65
|
+
break;
|
|
66
|
+
case "accepted":
|
|
67
|
+
totals.accepted += 1;
|
|
68
|
+
break;
|
|
69
|
+
case "auto_accepted":
|
|
70
|
+
totals.autoAccepted += 1;
|
|
71
|
+
break;
|
|
72
|
+
case "rejected":
|
|
73
|
+
totals.rejected += 1;
|
|
74
|
+
break;
|
|
75
|
+
case "superseded":
|
|
76
|
+
totals.superseded += 1;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
rewardSum += row.rewardScore ?? deriveMatcherRewardScore(row.reviewStatus);
|
|
80
|
+
}
|
|
81
|
+
const decided = totals.accepted + totals.autoAccepted + totals.rejected;
|
|
82
|
+
const positive = totals.accepted + totals.autoAccepted;
|
|
83
|
+
return {
|
|
84
|
+
...totals,
|
|
85
|
+
decided,
|
|
86
|
+
acceptanceRate: decided > 0 ? positive / decided : 0,
|
|
87
|
+
averageReward: rows.length > 0 ? rewardSum / rows.length : 0,
|
|
88
|
+
uniqueSurfaces: surfaces.size,
|
|
89
|
+
uniqueMatchers: matcherKeys.size
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export { deriveMatcherReviewStatus, deriveMatcherRewardScore, isOperationalLinkStatus, mergeLinkSuggestionStatus, resolveReviewedLinkStatus, summarizeMatcherFeedback };
|
|
94
|
+
//# sourceMappingURL=matcherFeedbackUtils.js.map
|
|
95
|
+
//# sourceMappingURL=matcherFeedbackUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/matcherFeedbackUtils.ts"],"names":[],"mappings":"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","file":"matcherFeedbackUtils.js","sourcesContent":["/** Matcher feedback helper types shared by graph-primitive review flows. */\nexport type LinkSuggestionStatus = \"suggested\" | \"approved\" | \"dismissed\";\n\nexport type MatcherReviewStatus =\n | \"pending\"\n | \"accepted\"\n | \"rejected\"\n | \"auto_accepted\"\n | \"superseded\";\n\ntype MatcherFeedbackSummaryRow = {\n matcherKey?: string | null;\n reviewStatus: MatcherReviewStatus;\n rewardScore?: number | null;\n surface?: string | null;\n};\n\nexport function isOperationalLinkStatus(\n status?: LinkSuggestionStatus | null\n): boolean {\n return status !== \"suggested\" && status !== \"dismissed\";\n}\n\nexport function mergeLinkSuggestionStatus(\n existing?: LinkSuggestionStatus | null,\n requested?: LinkSuggestionStatus | null\n): LinkSuggestionStatus | undefined {\n if (requested === undefined || requested === null) {\n return existing ?? undefined;\n }\n\n if (\n existing &&\n isOperationalLinkStatus(existing) &&\n !isOperationalLinkStatus(requested)\n ) {\n return existing;\n }\n\n return requested;\n}\n\nexport function resolveReviewedLinkStatus(\n requested: \"approved\" | \"dismissed\"\n): LinkSuggestionStatus {\n return requested;\n}\n\nexport function deriveMatcherReviewStatus(input: {\n explicitReviewStatus?: MatcherReviewStatus | null;\n linkStatus?: LinkSuggestionStatus | null;\n autoAccepted?: boolean;\n}): MatcherReviewStatus {\n if (input.explicitReviewStatus) {\n return input.explicitReviewStatus;\n }\n\n if (input.autoAccepted) {\n return \"auto_accepted\";\n }\n\n if (input.linkStatus === \"suggested\") {\n return \"pending\";\n }\n\n if (input.linkStatus === \"dismissed\") {\n return \"rejected\";\n }\n\n return \"accepted\";\n}\n\nexport function deriveMatcherRewardScore(\n reviewStatus: MatcherReviewStatus\n): number {\n switch (reviewStatus) {\n case \"accepted\":\n case \"auto_accepted\":\n return 1;\n case \"rejected\":\n return -1;\n default:\n return 0;\n }\n}\n\nexport function summarizeMatcherFeedback(rows: MatcherFeedbackSummaryRow[]) {\n const totals = {\n total: rows.length,\n pending: 0,\n accepted: 0,\n autoAccepted: 0,\n rejected: 0,\n superseded: 0,\n };\n\n const surfaces = new Set<string>();\n const matcherKeys = new Set<string>();\n let rewardSum = 0;\n\n for (const row of rows) {\n if (row.surface) {\n surfaces.add(row.surface);\n }\n if (row.matcherKey) {\n matcherKeys.add(row.matcherKey);\n }\n\n switch (row.reviewStatus) {\n case \"pending\":\n totals.pending += 1;\n break;\n case \"accepted\":\n totals.accepted += 1;\n break;\n case \"auto_accepted\":\n totals.autoAccepted += 1;\n break;\n case \"rejected\":\n totals.rejected += 1;\n break;\n case \"superseded\":\n totals.superseded += 1;\n break;\n default:\n break;\n }\n\n rewardSum += row.rewardScore ?? deriveMatcherRewardScore(row.reviewStatus);\n }\n\n const decided = totals.accepted + totals.autoAccepted + totals.rejected;\n const positive = totals.accepted + totals.autoAccepted;\n\n return {\n ...totals,\n decided,\n acceptanceRate: decided > 0 ? positive / decided : 0,\n averageReward: rows.length > 0 ? rewardSum / rows.length : 0,\n uniqueSurfaces: surfaces.size,\n uniqueMatchers: matcherKeys.size,\n };\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { rankEntityConnections, rankEntityTypeMatches, scoreEntityConnection, scoreEntityTypeMatch } from '@lucern/contracts/v1/ontologies/v1';
|
|
2
|
+
|
|
3
|
+
type OntologyEntityType = {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
subtypes?: Array<{
|
|
8
|
+
value: string;
|
|
9
|
+
label: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
type EntityTypeMatch = {
|
|
14
|
+
entityType: string;
|
|
15
|
+
label: string;
|
|
16
|
+
score: number;
|
|
17
|
+
reason: string;
|
|
18
|
+
};
|
|
19
|
+
type EntityMatchCandidate = {
|
|
20
|
+
nodeId: string;
|
|
21
|
+
entityType: string;
|
|
22
|
+
title: string;
|
|
23
|
+
canonicalText: string;
|
|
24
|
+
connectedBeliefCount: number;
|
|
25
|
+
connectedEvidenceCount: number;
|
|
26
|
+
};
|
|
27
|
+
type EntityConnectionMatch = {
|
|
28
|
+
entityNodeId: string;
|
|
29
|
+
entityType: string;
|
|
30
|
+
title: string;
|
|
31
|
+
score: number;
|
|
32
|
+
suggestedEdgeType: string;
|
|
33
|
+
reason: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type ontologyMatching_EntityConnectionMatch = EntityConnectionMatch;
|
|
37
|
+
type ontologyMatching_EntityMatchCandidate = EntityMatchCandidate;
|
|
38
|
+
type ontologyMatching_EntityTypeMatch = EntityTypeMatch;
|
|
39
|
+
type ontologyMatching_OntologyEntityType = OntologyEntityType;
|
|
40
|
+
declare const ontologyMatching_rankEntityConnections: typeof rankEntityConnections;
|
|
41
|
+
declare const ontologyMatching_rankEntityTypeMatches: typeof rankEntityTypeMatches;
|
|
42
|
+
declare const ontologyMatching_scoreEntityConnection: typeof scoreEntityConnection;
|
|
43
|
+
declare const ontologyMatching_scoreEntityTypeMatch: typeof scoreEntityTypeMatch;
|
|
44
|
+
declare namespace ontologyMatching {
|
|
45
|
+
export { type ontologyMatching_EntityConnectionMatch as EntityConnectionMatch, type ontologyMatching_EntityMatchCandidate as EntityMatchCandidate, type ontologyMatching_EntityTypeMatch as EntityTypeMatch, type ontologyMatching_OntologyEntityType as OntologyEntityType, ontologyMatching_rankEntityConnections as rankEntityConnections, ontologyMatching_rankEntityTypeMatches as rankEntityTypeMatches, ontologyMatching_scoreEntityConnection as scoreEntityConnection, ontologyMatching_scoreEntityTypeMatch as scoreEntityTypeMatch };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { type EntityTypeMatch as E, type OntologyEntityType as O, type EntityMatchCandidate as a, type EntityConnectionMatch as b, ontologyMatching as o };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { rankEntityConnections, rankEntityTypeMatches, scoreEntityConnection, scoreEntityTypeMatch } from '@lucern/contracts/v1/ontologies/v1';
|
|
2
|
+
export { b as EntityConnectionMatch, a as EntityMatchCandidate, E as EntityTypeMatch, O as OntologyEntityType } from './ontology-matching-Buhu23ss.js';
|