// SPDX-License-Identifier: AGPL-3.0-only // SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // Merging a lens's parts: the dedupe, the cross-unit rule, the strongest // verdict, missing units; the matrix with units nobody reviews. import std; import Crafter.Review; using namespace Crafter::Review; namespace { std::int32_t Failures = 0; void Check(std::string_view name, bool cond, std::string_view detail = {}) { std::println("{}{}{}", cond ? " ok " : " FAIL ", name, !cond && !detail.empty() ? std::format(" ({})", detail) : std::string()); if (!cond) ++Failures; } // {item: verdict} of a merged result. std::map Verdicts(const Json& merged) { std::map out; for (const Json& c : merged.at("coverage")) out[c.at("item").get()] = c.at("verdict").get(); return out; } Json With(Json value, const Json& changes) { value.update(changes); return value; } } int main() { std::println("merge_parts: dedupe, cross-unit rule, strongest verdict, missing units; the matrix with not-reviewed units"); const std::string lens = "repo-bug-prover.md"; const Json note = {{"kind", "info"}, {"items", {"A", "B"}}, {"note", "shared"}}; const Json found = {{"finding", "x"}, {"items", {"A", "B"}}, {"discharged", true}, {"dischargedBy", "w1"}}; const std::vector parts = { {{"partLabel", "a"}, {"expectedIds", {"A"}}, {"findings", {found}}, {"notes", {note, note}}, {"coverage", {{{"item", "A"}, {"verdict", "clear"}}}}}, {{"partLabel", "b"}, {"expectedIds", {"B"}}, {"findings", {found}}, {"notes", {note}}, {"coverage", {{{"item", "B"}, {"verdict", "clear"}}}}}, }; Json m = Normalize::MergeParts("L", lens, parts, {}); Check("one note and one finding after the merge, verdict unchanged", m.at("notes").size() == 1 && m.at("findings").size() == 1 && m.at("verdict") == "SEND-READY"); const Json pa = {{"partLabel", "L:block:A"}, {"partKind", "block"}, {"partUnit", "A"}, {"verdict", "FIX FIRST"}, {"findings", {{{"finding", "B contradicts A"}, {"evidence", "e"}, {"proposedAction", "p"}, {"items", {"A", "B"}}, {"discharged", false}}}}, {"notes", Json::array()}, {"coverage", {{{"item", "A"}, {"verdict", "defect"}, {"basis", "b"}}}}, {"coverageMissing", Json::array()}, {"undischarged", 1}}; const Json pb = {{"partLabel", "L:block:B"}, {"partKind", "block"}, {"partUnit", "B"}, {"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()}, {"coverage", {{{"item", "B"}, {"verdict", "clear"}, {"basis", "checked"}}}}, {"coverageMissing", Json::array()}}; m = Normalize::MergeParts("L", lens, std::vector{pa, pb}, {}); Json basisOfB; for (const Json& c : m.at("coverage")) { if (c.at("item") == "B") basisOfB = c; } const bool raised = std::ranges::any_of(m.at("normalizeLogs"), [](const Json& l) { return l.get().contains("raised to defect"); }); Check("B raised to defect by the finding citing it; lens FIX FIRST", basisOfB.at("verdict") == "defect" && basisOfB.at("basis").get().starts_with("cited by finding") && m.at("verdict") == "FIX FIRST" && raised); Json dischargedFinding = pa.at("findings").at(0); dischargedFinding["discharged"] = true; dischargedFinding["dischargedBy"] = "w1"; const Json pc = With(pa, {{"findings", {dischargedFinding}}, {"coverage", {{{"item", "A"}, {"verdict", "clear"}, {"basis", "discharged"}}}}, {"verdict", "SEND-READY"}, {"undischarged", 0}}); Check("a discharged finding does not raise B", Verdicts(Normalize::MergeParts("L", lens, std::vector{pc, pb}, {}))["B"] == "clear"); const std::vector missingA = {"A"}; const Json m3 = Normalize::MergeParts("L", lens, std::vector{pb}, missingA); Check("missing unit -> coverageMissing + contract violation + verdict NOT RETURNED", m3.at("coverageMissing") == Json::array({"A"}) && !m3.at("contractViolations").empty() && m3.at("verdict") == "NOT RETURNED"); const Json pd = With(pb, {{"coverage", {{{"item", "B"}, {"verdict", "immaterial"}, {"basis", "w"}}}}}); Check("strongest verdict per unit wins (immaterial > clear)", Verdicts(Normalize::MergeParts("L", lens, std::vector{pb, pd}, {}))["B"] == "immaterial"); const Json result = Normalize::MergeParts("L", lens, std::vector{pa, pb}, {}); const std::vector notReviewed = {"p1:msg"}; const Json mx = Normalize::Matrix(Json::array({{{"id", "A"}}, {{"id", "B"}}, {{"id", "C"}}, {{"id", "p1:msg"}}}), std::vector{result}, notReviewed); std::set defects; for (auto it = mx.at("defects").begin(); it != mx.at("defects").end(); ++it) defects.insert(it.key()); Check("matrix: a unit without an entry is MISSING and a hole; a not-reviewed unit is listed, never a hole; defects per unit", mx.at("matrix").at("C").at("L").at("verdict") == "MISSING" && mx.at("holes") == Json::array({"C"}) && mx.at("notReviewed") == Json::array({"p1:msg"}) && defects == std::set{"A", "B"}, DumpCompactSorted(mx.at("holes"))); return Failures ? 1 : 0; }