#!/usr/bin/env python3 """Render held ingestion drafts and correction proposals as an owner decision sheet.""" from __future__ import annotations import argparse import json from pathlib import Path from typing import Any def render(items: list[dict[str, Any]]) -> str: sections = [ "# GEWU owner review sheet", "", ( "Mark one decision for each item and add a short rationale. This sheet records review " "intent only; it does not alter GEWU state or grant acceptance authority." ), "", ( "For held drafts: choose keep held, request revision, or initiate the authorized owner " "challenge workflow. For corrections: choose approve for fresh owner workflow, request " "revision, or reject. Proposal base commits may be stale; every later action must " "context and re-evaluate the proposal." ), "", ] for index, item in enumerate(items, start=1): proposal = item.get("proposal", {}) operations = proposal.get("operations", []) nodes = [operation["node"] for operation in operations if operation.get("node")] edges = [operation["edge"] for operation in operations if operation.get("edge")] node = nodes[0] if nodes else {} is_correction = item.get("source_stage") == "supersession" kind = "Correction proposal" if is_correction else "Policy-held draft" proposal_id = proposal.get("proposal_id", "unknown") revision = proposal.get("revision", "?") node_id = node.get("node_id", "not available") node_type = node.get("node_type", "unknown") sections.extend( [ f"## {index}. {kind}: {node.get('title', proposal.get('proposal_id', 'Untitled'))}", "", f"- Proposal: `{proposal_id}` revision {revision}", f"- Current state: {item.get('storage_state', 'evaluated; needs-review')}", f"- Proposal base commit: `{proposal.get('base_commit', 'unknown')}`", f"- Node: `{node_id}` ({node_type})", f"- Summary: {node.get('summary', 'No summary recorded.')}", "", "### Claims and attached evidence", "", ] ) claim_groups = [ ("Claim", node.get("claims", [])), ("Assumption", node.get("assumptions", [])), ("Limitation", node.get("limitations", [])), ] if not any(claims for _, claims in claim_groups): sections.append("No node claim payload was included in this review item.") sections.append("") for group_label, claims in claim_groups: for claim in claims: sections.extend( [ f"- **{group_label} {claim.get('claim_id', 'claim')}:** " f"{claim.get('text', '')}" ] ) for evidence in claim.get("evidence", []): locator = evidence.get("locator", {}) location = ", ".join( f"{key}={locator[key]}" for key in ("page", "block_id", "start", "end") if key in locator ) quote = evidence.get("quote", "").splitlines() sections.append( f" - Evidence `{evidence.get('source_revision_id', '?')}` ({location}):" ) sections.extend(f" > {line}" for line in quote) for edge in edges: sections.append( f"- Supersession edge: `{edge.get('source', {}).get('id', '?')}` → `" f"{edge.get('target', {}).get('id', '?')}` " f"({edge.get('edge_type', 'relationship')})" ) sections.extend(["", "### Owner decision", ""]) if is_correction: sections.extend( [ "- [ ] Approve this replacement for the owner workflow " "(fresh evaluation still required)", "- [ ] Request revision", "- [ ] Reject this correction", ] ) else: sections.extend( [ "- [ ] Keep held; do not create an exception", "- [ ] Request revision", "- [ ] Initiate the authorized owner challenge workflow", ] ) sections.extend(["- Rationale: ", "", "---", ""]) return "\n".join(sections) def main() -> None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--input", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) args = parser.parse_args() items = json.loads(args.input.read_text(encoding="utf-8")) if not isinstance(items, list) or len(items) != 19: parser.error("Expected the frozen 19-item held-draft and correction review packet") output = render(items) with args.output.open("x", encoding="utf-8") as stream: stream.write(output) print(json.dumps({"status": "created", "items": len(items), "output": str(args.output)})) if __name__ == "__main__": main()