Spaces:
Sleeping
Sleeping
File size: 11,930 Bytes
06671aa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | 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>): 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);
});
});
|