feat: separate confidence from reasoning completeness
This commit is contained in:
+170
-14
@@ -439,6 +439,30 @@ function appendUniqueValue(values = [], nextValue) {
|
||||
: values;
|
||||
}
|
||||
|
||||
function getNodeConfidenceAssessment(node) {
|
||||
return (
|
||||
node?.confidenceAssessment || {
|
||||
evidenceConfidence: node?.confidence ?? "medium",
|
||||
completenessStatus:
|
||||
node?.status === "resolved"
|
||||
? "complete"
|
||||
: node?.status === "provisional"
|
||||
? "partial"
|
||||
: "empty",
|
||||
conclusionConfidence:
|
||||
node?.status === "resolved"
|
||||
? (node?.confidence ?? "high")
|
||||
: node?.status === "provisional"
|
||||
? (node?.confidence ?? "medium")
|
||||
: "low",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function confidenceFromAssessment(assessment) {
|
||||
return assessment?.conclusionConfidence ?? "medium";
|
||||
}
|
||||
|
||||
function upsertProposalNodeUpdate(proposalSnapshot, update) {
|
||||
const existing = proposalSnapshot.updatedNodes.find(
|
||||
(candidate) => candidate.nodeId === update.nodeId,
|
||||
@@ -521,16 +545,6 @@ function buildAncestorChain(graph, node) {
|
||||
queue.push(candidate.id);
|
||||
}
|
||||
}
|
||||
|
||||
for (const edge of graph.edges || []) {
|
||||
if (
|
||||
edge.fromNodeId !== parentNode.id &&
|
||||
edge.toNodeId === parentNode.id &&
|
||||
edge.relationship === "depends_on"
|
||||
) {
|
||||
queue.push(edge.fromNodeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chain;
|
||||
@@ -562,28 +576,83 @@ function computeParentProgressState(graph, parentNode) {
|
||||
const progressedChildren = childUnknowns.filter((child) =>
|
||||
["resolved", "provisional"].includes(child.status),
|
||||
);
|
||||
const contradictoryChildren = childUnknowns.filter(
|
||||
(child) => child.status === "contradicted",
|
||||
);
|
||||
const totalChildren = childUnknowns.length;
|
||||
const resolvedCount = resolvedChildren.length;
|
||||
const unresolvedCount = childUnknowns.filter(
|
||||
(child) => child.status !== "resolved",
|
||||
).length;
|
||||
const beforeAssessment = getNodeConfidenceAssessment(parentNode);
|
||||
|
||||
if (totalChildren === 0) {
|
||||
const nextAssessment = {
|
||||
evidenceConfidence: beforeAssessment.evidenceConfidence,
|
||||
completenessStatus: beforeAssessment.completenessStatus,
|
||||
conclusionConfidence: beforeAssessment.conclusionConfidence,
|
||||
};
|
||||
return {
|
||||
totalChildren,
|
||||
resolvedChildren,
|
||||
progressedChildren,
|
||||
contradictoryChildren,
|
||||
nextStatus: parentNode.status,
|
||||
nextConfidence: parentNode.confidence,
|
||||
nextConfidence: confidenceFromAssessment(nextAssessment),
|
||||
nextConfidenceAssessment: nextAssessment,
|
||||
parentResolved: parentNode.status === "resolved",
|
||||
confidenceCapReason: "no_child_structure",
|
||||
reason: "Parent has no child unknowns to aggregate.",
|
||||
};
|
||||
}
|
||||
|
||||
let nextAssessment;
|
||||
let confidenceCapReason;
|
||||
|
||||
if (contradictoryChildren.length > 0) {
|
||||
nextAssessment = {
|
||||
evidenceConfidence: resolvedCount > 0 ? "medium" : "low",
|
||||
completenessStatus: resolvedCount === 0 ? "empty" : "partial",
|
||||
conclusionConfidence: "low",
|
||||
};
|
||||
confidenceCapReason = "contradictory_direct_children";
|
||||
} else if (resolvedCount === 0) {
|
||||
nextAssessment = {
|
||||
evidenceConfidence: "low",
|
||||
completenessStatus: "empty",
|
||||
conclusionConfidence: "low",
|
||||
};
|
||||
confidenceCapReason = "no_resolved_direct_children";
|
||||
} else if (resolvedCount < totalChildren) {
|
||||
nextAssessment = {
|
||||
evidenceConfidence: "high",
|
||||
completenessStatus: "partial",
|
||||
conclusionConfidence: "medium",
|
||||
};
|
||||
confidenceCapReason = "unresolved_direct_children_cap_conclusion";
|
||||
} else {
|
||||
nextAssessment = {
|
||||
evidenceConfidence: "high",
|
||||
completenessStatus: "complete",
|
||||
conclusionConfidence: "high",
|
||||
};
|
||||
confidenceCapReason = null;
|
||||
}
|
||||
|
||||
if (resolvedChildren.length === totalChildren) {
|
||||
return {
|
||||
totalChildren,
|
||||
resolvedChildren,
|
||||
progressedChildren,
|
||||
contradictoryChildren,
|
||||
nextStatus: "resolved",
|
||||
nextConfidence: "high",
|
||||
nextConfidence: confidenceFromAssessment(nextAssessment),
|
||||
nextConfidenceAssessment: nextAssessment,
|
||||
parentResolved: true,
|
||||
resolvedDirectChildren: resolvedCount,
|
||||
unresolvedDirectChildren: unresolvedCount,
|
||||
contradictoryDirectChildren: contradictoryChildren.length,
|
||||
confidenceCapReason,
|
||||
reason:
|
||||
"All direct child unknowns are resolved, so the parent can now resolve deterministically.",
|
||||
};
|
||||
@@ -594,9 +663,15 @@ function computeParentProgressState(graph, parentNode) {
|
||||
totalChildren,
|
||||
resolvedChildren,
|
||||
progressedChildren,
|
||||
contradictoryChildren,
|
||||
nextStatus: "provisional",
|
||||
nextConfidence: "high",
|
||||
nextConfidence: confidenceFromAssessment(nextAssessment),
|
||||
nextConfidenceAssessment: nextAssessment,
|
||||
parentResolved: false,
|
||||
resolvedDirectChildren: resolvedCount,
|
||||
unresolvedDirectChildren: unresolvedCount,
|
||||
contradictoryDirectChildren: contradictoryChildren.length,
|
||||
confidenceCapReason,
|
||||
reason:
|
||||
"At least one direct child has been progressed, so the parent becomes provisional but remains unresolved until all direct children are resolved.",
|
||||
};
|
||||
@@ -606,9 +681,15 @@ function computeParentProgressState(graph, parentNode) {
|
||||
totalChildren,
|
||||
resolvedChildren,
|
||||
progressedChildren,
|
||||
contradictoryChildren,
|
||||
nextStatus: parentNode.status,
|
||||
nextConfidence: parentNode.confidence,
|
||||
nextConfidence: confidenceFromAssessment(nextAssessment),
|
||||
nextConfidenceAssessment: nextAssessment,
|
||||
parentResolved: parentNode.status === "resolved",
|
||||
resolvedDirectChildren: resolvedCount,
|
||||
unresolvedDirectChildren: unresolvedCount,
|
||||
contradictoryDirectChildren: contradictoryChildren.length,
|
||||
confidenceCapReason,
|
||||
reason: "No direct child progress exists yet for the parent.",
|
||||
};
|
||||
}
|
||||
@@ -635,6 +716,17 @@ export function propagateResolvedChildEvidence({
|
||||
parentStatusAfter: null,
|
||||
parentConfidenceBefore: null,
|
||||
parentConfidenceAfter: null,
|
||||
evidenceConfidenceBefore: null,
|
||||
evidenceConfidenceAfter: null,
|
||||
completenessBefore: null,
|
||||
completenessAfter: null,
|
||||
conclusionConfidenceBefore: null,
|
||||
conclusionConfidenceAfter: null,
|
||||
resolvedDirectChildren: 0,
|
||||
unresolvedDirectChildren: 0,
|
||||
contradictoryDirectChildren: 0,
|
||||
confidenceCapReason: null,
|
||||
ancestorPropagationStoppedReason: "no_resolved_child_propagation_needed",
|
||||
affectedAncestorIds: [],
|
||||
nextSelectedSibling: null,
|
||||
parentResolved: false,
|
||||
@@ -646,6 +738,7 @@ export function propagateResolvedChildEvidence({
|
||||
syncParentChildReferences(graph);
|
||||
const propagationEvents = [];
|
||||
const affectedAncestorIds = new Set();
|
||||
let ancestorPropagationStoppedReason = "no_ancestor_state_changed";
|
||||
|
||||
for (const resolvedChildNode of resolvedChildNodes) {
|
||||
const liveChildNode = graph.nodes.find(
|
||||
@@ -662,10 +755,24 @@ export function propagateResolvedChildEvidence({
|
||||
for (const ancestorNode of ancestorChain) {
|
||||
const beforeStatus = ancestorNode.status;
|
||||
const beforeConfidence = ancestorNode.confidence;
|
||||
const beforeAssessment = getNodeConfidenceAssessment(ancestorNode);
|
||||
const progressState = computeParentProgressState(graph, ancestorNode);
|
||||
|
||||
ancestorNode.status = progressState.nextStatus;
|
||||
ancestorNode.confidence = progressState.nextConfidence;
|
||||
ancestorNode.confidenceAssessment =
|
||||
progressState.nextConfidenceAssessment;
|
||||
|
||||
if (
|
||||
beforeStatus === progressState.nextStatus &&
|
||||
beforeConfidence === progressState.nextConfidence &&
|
||||
JSON.stringify(beforeAssessment) ===
|
||||
JSON.stringify(progressState.nextConfidenceAssessment)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ancestorPropagationStoppedReason = "ancestor_state_changed";
|
||||
|
||||
if (progressState.parentResolved) {
|
||||
ensureResolvedUnknownId(proposalSnapshot, ancestorNode.id);
|
||||
@@ -688,6 +795,19 @@ export function propagateResolvedChildEvidence({
|
||||
parentStatusAfter: progressState.nextStatus,
|
||||
parentConfidenceBefore: beforeConfidence,
|
||||
parentConfidenceAfter: progressState.nextConfidence,
|
||||
evidenceConfidenceBefore: beforeAssessment.evidenceConfidence,
|
||||
evidenceConfidenceAfter:
|
||||
progressState.nextConfidenceAssessment.evidenceConfidence,
|
||||
completenessBefore: beforeAssessment.completenessStatus,
|
||||
completenessAfter:
|
||||
progressState.nextConfidenceAssessment.completenessStatus,
|
||||
conclusionConfidenceBefore: beforeAssessment.conclusionConfidence,
|
||||
conclusionConfidenceAfter:
|
||||
progressState.nextConfidenceAssessment.conclusionConfidence,
|
||||
resolvedDirectChildren: progressState.resolvedDirectChildren,
|
||||
unresolvedDirectChildren: progressState.unresolvedDirectChildren,
|
||||
contradictoryDirectChildren: progressState.contradictoryDirectChildren,
|
||||
confidenceCapReason: progressState.confidenceCapReason,
|
||||
parentResolved: progressState.parentResolved,
|
||||
reason: progressState.reason,
|
||||
});
|
||||
@@ -717,6 +837,17 @@ export function propagateResolvedChildEvidence({
|
||||
parentStatusAfter: firstEvent?.parentStatusAfter ?? null,
|
||||
parentConfidenceBefore: firstEvent?.parentConfidenceBefore ?? null,
|
||||
parentConfidenceAfter: firstEvent?.parentConfidenceAfter ?? null,
|
||||
evidenceConfidenceBefore: firstEvent?.evidenceConfidenceBefore ?? null,
|
||||
evidenceConfidenceAfter: firstEvent?.evidenceConfidenceAfter ?? null,
|
||||
completenessBefore: firstEvent?.completenessBefore ?? null,
|
||||
completenessAfter: firstEvent?.completenessAfter ?? null,
|
||||
conclusionConfidenceBefore: firstEvent?.conclusionConfidenceBefore ?? null,
|
||||
conclusionConfidenceAfter: firstEvent?.conclusionConfidenceAfter ?? null,
|
||||
resolvedDirectChildren: firstEvent?.resolvedDirectChildren ?? 0,
|
||||
unresolvedDirectChildren: firstEvent?.unresolvedDirectChildren ?? 0,
|
||||
contradictoryDirectChildren: firstEvent?.contradictoryDirectChildren ?? 0,
|
||||
confidenceCapReason: firstEvent?.confidenceCapReason ?? null,
|
||||
ancestorPropagationStoppedReason,
|
||||
affectedAncestorIds: [...affectedAncestorIds],
|
||||
nextSelectedSibling:
|
||||
siblingSelection?.status === "selected" ? siblingSelection.nodeId : null,
|
||||
@@ -1767,6 +1898,20 @@ export function applyValidatedProposal({
|
||||
const parentStatusAfter = propagationResult.parentStatusAfter;
|
||||
const parentConfidenceBefore = propagationResult.parentConfidenceBefore;
|
||||
const parentConfidenceAfter = propagationResult.parentConfidenceAfter;
|
||||
const evidenceConfidenceBefore = propagationResult.evidenceConfidenceBefore;
|
||||
const evidenceConfidenceAfter = propagationResult.evidenceConfidenceAfter;
|
||||
const completenessBefore = propagationResult.completenessBefore;
|
||||
const completenessAfter = propagationResult.completenessAfter;
|
||||
const conclusionConfidenceBefore =
|
||||
propagationResult.conclusionConfidenceBefore;
|
||||
const conclusionConfidenceAfter = propagationResult.conclusionConfidenceAfter;
|
||||
const resolvedDirectChildren = propagationResult.resolvedDirectChildren;
|
||||
const unresolvedDirectChildren = propagationResult.unresolvedDirectChildren;
|
||||
const contradictoryDirectChildren =
|
||||
propagationResult.contradictoryDirectChildren;
|
||||
const confidenceCapReason = propagationResult.confidenceCapReason;
|
||||
const ancestorPropagationStoppedReason =
|
||||
propagationResult.ancestorPropagationStoppedReason;
|
||||
const affectedAncestorIds = propagationResult.affectedAncestorIds;
|
||||
const nextSelectedSibling = propagationResult.nextSelectedSibling;
|
||||
const parentResolved = propagationResult.parentResolved;
|
||||
@@ -1894,6 +2039,17 @@ export function applyValidatedProposal({
|
||||
parentStatusAfter,
|
||||
parentConfidenceBefore,
|
||||
parentConfidenceAfter,
|
||||
evidenceConfidenceBefore,
|
||||
evidenceConfidenceAfter,
|
||||
completenessBefore,
|
||||
completenessAfter,
|
||||
conclusionConfidenceBefore,
|
||||
conclusionConfidenceAfter,
|
||||
resolvedDirectChildren,
|
||||
unresolvedDirectChildren,
|
||||
contradictoryDirectChildren,
|
||||
confidenceCapReason,
|
||||
ancestorPropagationStoppedReason,
|
||||
affectedAncestorIds,
|
||||
nextSelectedSibling,
|
||||
parentResolved,
|
||||
|
||||
Reference in New Issue
Block a user