import { describe, it, expect } from "vitest"; import { buildWorkflowSummary, buildWorkflowSummaryFromRows, type WorkflowFinding, type WorkflowFindingRow } from "./chatTools"; describe("buildWorkflowSummary", () => { it("produces an intro with rewrite + comment counts", () => { const findings: WorkflowFinding[] = [ { comment_key: "sec-8-3", block_id: "BMK_P_abc", op_type: "REWRITE_PARAGRAPH", status: "FAIL", section_heading: "Section 8.3", applied: true, comment: "Corrects cross-reference", target_text: "as per Section 14", new_text: "as per Section 20", reasoning: null, }, { comment_key: "sec-12", block_id: "BMK_P_def", op_type: "COMMENT", status: "RISK", section_heading: "Section 12", applied: true, comment: "Prevents testing scope creep", target_text: "verified in accordance to...", new_text: undefined, reasoning: null, }, ]; const result = buildWorkflowSummary(findings); expect(result).toContain("redlined 1 issue"); expect(result).toContain("flagged 1 concern"); expect(result).toContain("| Section 8.3 | FAIL | Rewrite |"); expect(result).toContain("| Section 12 | RISK | Comment |"); expect(result).toContain("as per Section 14"); expect(result).toContain("as per Section 20"); expect(result).toContain("Corrects cross-reference"); expect(result).toContain("Prevents testing scope creep"); }); it("shows — for comment amended/original columns", () => { const findings: WorkflowFinding[] = [ { comment_key: "c1", op_type: "COMMENT", status: "REVIEW", section_heading: "Section 5", applied: true, comment: "Note this clause", reasoning: null, }, ]; const result = buildWorkflowSummary(findings); expect(result).toContain("| Section 5 | REVIEW | Comment | — | — |"); }); it("handles insert and delete op types", () => { const findings: WorkflowFinding[] = [ { op_type: "INSERT_PARAGRAPH", status: "MISSING", section_heading: "Section 9", applied: true, comment: "Add indemnity clause", new_text: "New indemnity text", reasoning: null, }, { op_type: "DELETE_PARAGRAPH", status: "FAIL", section_heading: "Section 10", applied: true, comment: "Remove conflicting clause", target_text: "Conflicting text", reasoning: null, }, ]; const result = buildWorkflowSummary(findings); expect(result).toContain("inserted 1 clause"); expect(result).toContain("deleted 1 provision"); expect(result).toContain("| Insert |"); expect(result).toContain("| Delete |"); }); it("handles no applied findings", () => { const findings: WorkflowFinding[] = []; const result = buildWorkflowSummary(findings); expect(result).toContain("No changes were applied"); }); it("escapes pipe characters in content", () => { const findings: WorkflowFinding[] = [ { op_type: "REWRITE_PARAGRAPH", status: "FAIL", section_heading: "Section 1", applied: true, comment: "A | B | C", target_text: "X | Y", new_text: "Z | W", reasoning: null, }, ]; const result = buildWorkflowSummary(findings); expect(result).toContain("A \\| B \\| C"); expect(result).toContain("X \\| Y"); expect(result).toContain("Z \\| W"); }); it("never exposes an internal block id when section_heading is missing", () => { const findings: WorkflowFinding[] = [ { block_id: "BMK_P_xyz", op_type: "COMMENT", status: "RISK", applied: true, comment: "Some concern", reasoning: null, }, ]; const result = buildWorkflowSummary(findings); expect(result).toContain("| Relevant section | RISK | Comment |"); expect(result).not.toContain("BMK_P_xyz"); }); }); describe("buildWorkflowSummaryFromRows", () => { function makeRow(overrides: Partial): WorkflowFindingRow { return { row_id: overrides.row_id ?? "doc-0:test", doc_id: overrides.doc_id ?? "doc-0", comment_key: overrides.comment_key ?? "test", block_id: overrides.block_id ?? "P_0001", finding_status: overrides.finding_status ?? "FAIL", apply_status: overrides.apply_status ?? "applied", action: overrides.action ?? "REWRITE", issue: overrides.issue ?? "Incorrect cross-reference", source: overrides.source ?? "plan_comments_on_document", ...overrides, }; } it("status column shows FAIL, not Flagged", () => { const rows = [makeRow({ finding_status: "FAIL", apply_status: "applied" })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).toContain("| FAIL |"); expect(result.markdown).not.toContain("| Flagged |"); }); it("result column can show Applied", () => { const rows = [makeRow({ apply_status: "applied" })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.metrics.applied).toBe(1); }); it("INSERT and INSERT_PARAGRAPH both render as Insert via action field", () => { const rows = [makeRow({ action: "INSERT", apply_status: "applied" })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).toContain("| Insert |"); }); it("XML entities in section headings decode", () => { const rows = [makeRow({ section_heading: "Section 5 & 6", apply_status: "applied" })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).toContain("Section 5 & 6"); }); it("Issue, Zamil Impact, and Recommended Action parse into separate columns", () => { const rows = [makeRow({ issue: "Incorrect cross-reference", zamil_impact: "Payment may point to wrong section", recommended_action: "Correct the cross-reference", apply_status: "applied", })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).toContain("Incorrect cross-reference"); expect(result.markdown).toContain("Payment may point to wrong section"); expect(result.markdown).toContain("Correct the cross-reference"); }); it("empty rows render no-action intro", () => { const result = buildWorkflowSummaryFromRows([]); expect(result.markdown).toContain("No actionable changes were applied"); }); it("failed rows render under Not applied", () => { const rows = [makeRow({ apply_status: "failed_validation", finding_status: "RISK", action: "COMMENT", failure_code: "anchor_not_found", failure_message: "Block not found", })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).toContain("### Not applied"); expect(result.markdown).toContain("Block not found"); }); it("document_order controls sorting", () => { const rows = [ makeRow({ row_id: "doc-0:b", comment_key: "b", section_heading: "Section 5", document_order: 5, apply_status: "applied" }), makeRow({ row_id: "doc-0:a", comment_key: "a", section_heading: "Section 2", document_order: 2, apply_status: "applied" }), ]; const result = buildWorkflowSummaryFromRows(rows); const lines = result.markdown.split("\n").filter((l) => l.startsWith("| 1")); expect(lines.length).toBe(1); expect(lines[0]).toContain("Section 2"); const lines2 = result.markdown.split("\n").filter((l) => l.startsWith("| 2")); expect(lines2.length).toBe(1); expect(lines2[0]).toContain("Section 5"); }); it("ignored_pass rows do not appear in the applied table", () => { const rows = [ makeRow({ apply_status: "applied", finding_status: "FAIL", comment_key: "real" }), makeRow({ apply_status: "ignored_pass", finding_status: "REVIEW", comment_key: "pass1" }), ]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).not.toContain("pass1"); expect(result.metrics.ignoredPass).toBe(1); expect(result.metrics.applied).toBe(1); }); it("if a report omits section_heading, internal IDs never appear in the summary", () => { const rows = [makeRow({ section_heading: null, apply_status: "applied", finding_status: "FAIL", block_id: "P_0042", })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).toContain("Relevant section"); expect(result.markdown).not.toContain("P_0042"); }); it("uses reasoning clause_section when section_heading is missing", () => { const rows = [makeRow({ section_heading: null, block_id: "BMK_P_9ll3g", reasoning: { clause_section: "Section 1: Building Description", violated_standard: "Delivery protection", zamil_exposure: "Delay exposure", }, })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).toContain("Section 1: Building Description"); expect(result.markdown).not.toContain("BMK_P_9ll3g"); }); it("strips internal IDs from every user-facing summary field", () => { const rows = [makeRow({ section_heading: "Section 1 BMK_P_9ll3g", block_id: "BMK_P_9ll3g", issue: "Missing protection near BMK_P_9ll3g", zamil_impact: "See P_0042 for exposure", recommended_action: "Insert after BMK_P_9ll3g", original_wording: "Text at P_0042", })]; const result = buildWorkflowSummaryFromRows(rows); expect(result.markdown).toContain("Section 1"); expect(result.markdown).not.toMatch(/BMK_[PT]_/); expect(result.markdown).not.toMatch(/\bP_\d{4,}\b/); }); it("metrics include correct counts", () => { const rows = [ makeRow({ apply_status: "applied", action: "REWRITE", finding_status: "FAIL" }), makeRow({ apply_status: "applied", action: "COMMENT", finding_status: "RISK" }), makeRow({ apply_status: "failed_validation", action: "INSERT", finding_status: "MISSING" }), makeRow({ apply_status: "ignored_pass", action: "COMMENT", finding_status: "REVIEW" }), ]; const result = buildWorkflowSummaryFromRows(rows); expect(result.metrics.total).toBe(4); expect(result.metrics.applied).toBe(2); expect(result.metrics.failed).toBe(1); expect(result.metrics.ignoredPass).toBe(1); expect(result.metrics.actionable).toBe(3); expect(result.metrics.rewrites).toBe(1); expect(result.metrics.comments).toBe(1); }); });