fix(confidence-engine): show canonical findings in previous learning

This commit is contained in:
2026-08-29 14:38:04 +01:00
parent a8539e2494
commit 0f4dfcbb17
3 changed files with 208 additions and 40 deletions
@@ -1140,3 +1140,109 @@ describe("Reopened Finding resolution via Contribution.id → contributionId", (
// Turn 1 Finding NOT merged into latest view.
});
});
// ── getHistoricalPropositions: Previous Learning renders canonical Findings ─
function getHistoricalPropositions(contribution, findings) {
const matching = (findings || []).filter(
(f) => f.contributionId === contribution.id,
);
if (matching.length === 0) {
return contribution.observations || [];
}
return matching
.filter((f) => f.userDisposition !== "not_relevant")
.map((f) => f.proposition);
}
describe("getHistoricalPropositions: Previous Learning uses canonical Findings", () => {
it("zero matching canonical Findings → fallback to Contribution.observations", () => {
const contrib = {
id: "contrib-01",
observations: ["Original observation from contribution"],
};
const findings = [];
const result = getHistoricalPropositions(contrib, findings);
expect(result).toEqual(["Original observation from contribution"]);
});
it("zero matching canonical Findings with null observations → empty array", () => {
const contrib = { id: "contrib-02" };
const findings = [];
const result = getHistoricalPropositions(contrib, findings);
expect(result).toEqual([]);
});
it("one or more matching canonical Findings → canonical Findings are authoritative", () => {
const contrib = { id: "contrib-03", observations: ["Original obs"] };
const findings = [
{ contributionId: "contrib-03", proposition: "Canonical finding A", userDisposition: "agreed" },
{ contributionId: "contrib-03", proposition: "Canonical finding B", userDisposition: "agreed" },
];
const result = getHistoricalPropositions(contrib, findings);
expect(result).toEqual(["Canonical finding A", "Canonical finding B"]);
expect(result).not.toContain("Original obs");
});
it("matching canonical Findings all have userDisposition not_relevant → render NO propositions, DO NOT fall back", () => {
const contrib = { id: "contrib-04", observations: ["Should not appear"] };
const findings = [
{ contributionId: "contrib-04", proposition: "Dismissed finding 1", userDisposition: "not_relevant" },
{ contributionId: "contrib-04", proposition: "Dismissed finding 2", userDisposition: "not_relevant" },
];
const result = getHistoricalPropositions(contrib, findings);
expect(result).toEqual([]);
expect(result).not.toContain("Should not appear");
});
it("turn ownership is strict — only Findings whose contributionId matches the Contribution.id render", () => {
const contribA = { id: "contrib-A", observations: ["A's original"] };
const contribB = { id: "contrib-B", observations: ["B's original"] };
const contribBFinding = { contributionId: "contrib-B", proposition: "Finding from B", userDisposition: "agreed" };
const contribAFinding = { contributionId: "contrib-A", proposition: "Finding from A", userDisposition: "agreed" };
const resultForB = getHistoricalPropositions(contribB, [contribBFinding]);
expect(resultForB).toEqual(["Finding from B"]);
const resultMixed = getHistoricalPropositions(contribB, [contribAFinding, contribBFinding]);
expect(resultMixed).toEqual(["Finding from B"]);
expect(resultMixed).not.toContain("Finding from A");
});
it("mixed dispositions: non-not_relevant Findings render, not_relevant are excluded", () => {
const contrib = { id: "contrib-05", observations: ["Original"] };
const findings = [
{ contributionId: "contrib-05", proposition: "Kept finding", userDisposition: "agreed" },
{ contributionId: "contrib-05", proposition: "Dismissed finding", userDisposition: "not_relevant" },
{ contributionId: "contrib-05", proposition: "Neutral finding", userDisposition: "neutral" },
];
const result = getHistoricalPropositions(contrib, findings);
expect(result).toEqual(["Kept finding", "Neutral finding"]);
expect(result).not.toContain("Dismissed finding");
});
it("null/undefined findings array handled safely — falls back to observations", () => {
const contrib = { id: "contrib-06", observations: ["Fallback safe"] };
expect(getHistoricalPropositions(contrib, null)).toEqual(["Fallback safe"]);
expect(getHistoricalPropositions(contrib, undefined)).toEqual(["Fallback safe"]);
});
it("Contribution with no observations and no matching Findings returns empty", () => {
const contrib = { id: "contrib-07" };
const findings = [
{ contributionId: "contrib-other", proposition: "Wrong contribution", userDisposition: "agreed" },
];
const result = getHistoricalPropositions(contrib, findings);
expect(result).toEqual([]);
});
});