"""Offline HTML reading view of the validated v2.9 record; no model pass.""" import re from html import escape from pathlib import Path from brief_sections import CLOSING, PP_CLASSES from chat_result import ASSESSMENTS, READING_GUIDE, overview, review_limits ASSETS = Path(__file__).resolve().parent.parent / "assets" GROUPS = ( ("breaks_position", "Problems with the position"), ("internal_defect", "Contradictions to correct"), ("proof_gap", "Evidence still needed"), ("context", "Practical points and qualifications"), ("defeated", "Objections the documents answer"), ("weakens_route", "Arguments that fail without changing the conclusion"), ) def text(value): """Treat source and model text as text, allowing only bold emphasis.""" return re.sub(r"\*\*([^*\n]+)\*\*", r"\1", escape(str(value))) def paragraph(value, label=None): prefix = f"{escape(label)}: " if label else "" return f"

{prefix}{text(value)}

" def source(data, filename, root): meta = data["sources"][filename] label = escape(meta["name"]) if meta.get("date"): label += ", " + escape(meta["date"]) if root is not None: base = Path(root).resolve() path = (base / filename).resolve() if ( not Path(filename).is_absolute() and path.is_relative_to(base) and path.is_file() ): return f'{label}' return label def passages(data, anchors, root): return "".join( '
' + source(data, a["source"], root) + " โ€” " + escape(a["locator"]) + "
" + escape(a["quote"]) + "
" for a in anchors ) def finding(data, item, number, root): cls = item["classification"] opened = " open" if cls in PP_CLASSES else "" parts = [ f'
', f'{number:02}', f'{text(item["title"])}', f'{ASSESSMENTS[cls]}', '
', paragraph(item["statement"]), ] if cls in PP_CLASSES: parts.append(paragraph(item["hits"], "Affects")) parts.append(passages(data, item["anchors"], root)) answer = ( "Why this objection is answered" if cls == "defeated" else "Why the conclusion remains supported" ) for field, label in ( ("test_applied", "Assessment"), ("dispositive_anchor_note", answer), ("flip_statement", "Consequence if accepted"), ("defect_statement", "Consequence if accepted"), ("survives", "What remains supported"), ("smallest_change", "What would change this result"), ("what_would_close", "Evidence needed"), ("next_step", "Next action"), ): if item.get(field): parts.append(paragraph(item[field], label)) parts.append("
") return "".join(parts) def render_html(data, source_root=None): brief = data["brief"] findings = data["findings"] # Use the same verdict wording as the complete chat reading view. verdict = overview(data, findings)[2].strip("*") parts = [ '

PRESSURETEST ยท FOR LAWYER REVIEW

', f"

{text(brief['position_name'])}

", paragraph(brief["run_date"]), "
", '

Summary

', paragraph(verdict, "Assessment"), paragraph(brief["summary"]), paragraph(READING_GUIDE, "How to read this review"), ] if data["verdict"] == "incomplete": parts.append(paragraph(data["incomplete_reason"], "Unfinished review")) for field, label in ( ("established", "What is established"), ("follows", "What currently follows"), ): if brief.get(field): parts.append(paragraph(brief[field], label)) parts += ["

Position tested

"] for position in data["positions"]: parts.append(paragraph(position["conclusion"], position["owner"])) ordered = [f for cls, _ in GROUPS for f in findings if f["classification"] == cls] attention = [ (n, f) for n, f in enumerate(ordered, 1) if f["classification"] not in ("defeated", "weakens_route") ] if attention: parts += ['

Issues requiring attention

") parts += ['
', '', ] number = 0 for cls, title in GROUPS: if cls == "defeated": route_title = ( "Why the conclusion remains supported" if data["verdict"] == "position_holds" else "The strongest argument supporting the position" ) parts += [ f"

{route_title}

", paragraph(data["strongest_route"]["summary"]), passages(data, data["strongest_route"]["anchors"], source_root), "
", ] group = [f for f in findings if f["classification"] == cls] if group: parts.append(f'

{title}

') for item in group: number += 1 parts.append(finding(data, item, number, source_root)) parts.append("
") parts.append('
') for value in brief.get("context_items") or []: parts.append(paragraph(value)) for line in review_limits(data): if line.startswith("## "): parts.append(f"

{text(line[3:])}

") elif line.strip(): parts.append(paragraph(line.removeprefix("- "))) parts.append("

Sources reviewed

"] template = (ASSETS / "report-template.html").read_text(encoding="utf-8") replacements = { "TITLE": escape(brief["position_name"]), "CONTENT": "\n".join(parts), } return re.sub(r"\{\{(TITLE|CONTENT)\}\}", lambda m: replacements[m[1]], template) def render_handoff(data): """Short native-chat handoff; the host appends the real artifact link.""" parts = overview(data, data["findings"]) parts += [ "The full HTML report contains every finding, supporting passage, " "next action and review limit. Open the report linked below.", "", ] return "\n".join(parts).rstrip() + "\n"