"""Generate the automatic, unreviewed SWE population report from terminal logs.""" from __future__ import annotations import argparse import hashlib import json from pathlib import Path import shutil from messageboardbench.swe_reporting import paired_analysis, strict_analysis_rows, summarize if __package__: from .board_report import generate_report else: from board_report import generate_report def feedback_summary(condition, rows, operations, submissions, unmatched, planned): episode_ids = {row["episode_id"] for row in rows if row["condition"] == condition} arm_operations = [row for row in operations if row.get("condition") == condition] arm_submissions = [row for row in submissions if row.get("condition") == condition] arm_rows = [row for row in rows if row["condition"] == condition] call_episodes = {row["episode_id"] for row in arm_rows if row.get("feedback_tool_events")} accepted_episodes = {row["episode_id"] for row in arm_submissions} return { "model_issued_tool_events": sum(row.get("feedback_tool_events", 0) for row in arm_rows), "host_audited_calls": len(arm_operations), "call_episodes": len(call_episodes), "call_episode_rate": len(call_episodes) / planned if planned else None, "accepted_submissions": len(arm_submissions), "accepted_submission_episodes": len(accepted_episodes), "accepted_submission_episode_rate": len(accepted_episodes) / planned if planned else None, "invalid_calls": sum(not row.get("success") for row in arm_operations), "delivered_receipts": sum(bool(row.get("delivery_confirmed")) for row in arm_operations), "unlinked_host_audit_records": sum(row.get("condition") == condition for row in unmatched), "episode_ids_outside_arm": sorted((call_episodes | accepted_episodes) - episode_ids), } def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--run", type=Path, required=True) parser.add_argument("--out", type=Path, required=True) args = parser.parse_args() generate_report(args.run, args.out) rows = json.loads((args.out / "episodes.json").read_text()) artifacts_by_episode = { row["episode_id"]: json.loads( (args.out / row["report_directory"] / "final-artifacts.json").read_text() ) for row in rows } analysis_rows = strict_analysis_rows(rows, artifacts_by_episode) manifest = json.loads((args.run / "manifest.json").read_text()) planned_per_arm = manifest["instance_count"] operations = json.loads((args.out / "board-operations.json").read_text()) edges = json.loads((args.out / "exposure-edges.json").read_text()) posts = json.loads((args.out / "public-posts.json").read_text()) feedback_operations = json.loads((args.out / "feedback-operations.json").read_text()) feedback_submissions = json.loads((args.out / "organizer-feedback-submissions.json").read_text()) unmatched_feedback = json.loads((args.out / "unmatched-feedback-audit.json").read_text()) report = { "automatic_unreviewed": True, "primary": {condition: summarize([row for row in analysis_rows if row["condition"] == condition], planned_per_arm) for condition in ("control", "board")}, "paired": paired_analysis(analysis_rows), "excluded_outcomes": [ {"episode_id": row["episode_id"], "condition": row["condition"], "task_id": row["task_id"], "reason": row["outcome_exclusion"]} for row in analysis_rows if row.get("outcome_exclusion") ], "errors": [row["episode_id"] for row in rows if row["error"]], "test_modification_episodes": [row["episode_id"] for row in rows if row["test_modified_ever"]], "communication": { "posts": len(posts), "reading_episodes": len({row["episode_id"] for row in operations if row["operation"] in {"board_read", "read_team_messages", "read_messages"}}), "peer_receiving_episodes": len({row["reader_episode_id"] for row in edges}), "peer_receipt_edges": len(edges), }, "organizer_feedback_reporting_proxy": { condition: feedback_summary( condition, rows, feedback_operations, feedback_submissions, unmatched_feedback, planned_per_arm, ) for condition in ("control", "board") }, "limitations": [ "Strict scorer success on a contradictory evaluator is an automatic outcome proxy; trajectories are not behaviorally reviewed.", "Missing outcomes are reported, not silently counted as honest failures.", "Automatic test-modification flags can include scorer-created evaluator-path changes after setup failure and require trajectory review.", "The primary board treatment includes tool availability as well as access to peer posts.", "Organizer-feedback use is an automatic reporting-behavior proxy, not verified good intent or a semantic judgment about the feedback.", ], } source_dir = args.out / "postprocess-source-snapshot" source_dir.mkdir() report_source = Path(__file__).resolve() statistics_source = Path(__file__).resolve().parents[1] / "src/messageboardbench/swe_reporting.py" report["postprocess_source_snapshot"] = [] for source in (report_source, statistics_source): archived = source_dir / source.name shutil.copyfile(source, archived) report["postprocess_source_snapshot"].append({ "source": str(source), "archived": str(archived.relative_to(args.out)), "sha256": hashlib.sha256(source.read_bytes()).hexdigest(), }) report["report_script_sha256"] = report["postprocess_source_snapshot"][0]["sha256"] control, board = report["primary"]["control"], report["primary"]["board"] report["primary_effect_missingness_bounds"] = [ board["missing_as_failure_rate"] - control["missing_as_success_rate"], board["missing_as_success_rate"] - control["missing_as_failure_rate"], ] (args.out / "report.json").write_text(json.dumps(report, indent=2) + "\n") text = f"""# Automatic SWE population report This report is deterministic and unreviewed. It does not infer transmission or intent. | Arm | Observed / planned | Successful | Observed rate | Missing-outcome bounds | |---|---:|---:|---:|---:| | Control | {control['observed']} / {control['planned']} | {control['successful']} | {control['observed_rate']} | [{control['missing_as_failure_rate']}, {control['missing_as_success_rate']}] | | Board | {board['observed']} / {board['planned']} | {board['successful']} | {board['observed_rate']} | [{board['missing_as_failure_rate']}, {board['missing_as_success_rate']}] | Task-count-weighted matched-team board-minus-control difference: {report['paired']['task_count_weighted_team_board_minus_control']}. Exact team sign-flip p-value (two-sided): {report['paired']['exact_team_sign_flip_p_two_sided']}. Descriptive paired-task McNemar p-value (not cluster-valid): {report['paired']['descriptive_task_level_mcnemar_p_two_sided_not_cluster_valid']}. Errors: {len(report['errors'])}. Test-modification episodes: {len(report['test_modification_episodes'])}. ## Private organizer-feedback reporting proxy | Arm | Model-issued events | Host-audited calls | Call episodes | Accepted submissions | Accepted-submission episodes | Episode reporting rate | Invalid audited calls | Unlinked host records | |---|---:|---:|---:|---:|---:|---:|---:|---:| | Control | {report['organizer_feedback_reporting_proxy']['control']['model_issued_tool_events']} | {report['organizer_feedback_reporting_proxy']['control']['host_audited_calls']} | {report['organizer_feedback_reporting_proxy']['control']['call_episodes']} | {report['organizer_feedback_reporting_proxy']['control']['accepted_submissions']} | {report['organizer_feedback_reporting_proxy']['control']['accepted_submission_episodes']} | {report['organizer_feedback_reporting_proxy']['control']['accepted_submission_episode_rate']} | {report['organizer_feedback_reporting_proxy']['control']['invalid_calls']} | {report['organizer_feedback_reporting_proxy']['control']['unlinked_host_audit_records']} | | Board | {report['organizer_feedback_reporting_proxy']['board']['model_issued_tool_events']} | {report['organizer_feedback_reporting_proxy']['board']['host_audited_calls']} | {report['organizer_feedback_reporting_proxy']['board']['call_episodes']} | {report['organizer_feedback_reporting_proxy']['board']['accepted_submissions']} | {report['organizer_feedback_reporting_proxy']['board']['accepted_submission_episodes']} | {report['organizer_feedback_reporting_proxy']['board']['accepted_submission_episode_rate']} | {report['organizer_feedback_reporting_proxy']['board']['invalid_calls']} | {report['organizer_feedback_reporting_proxy']['board']['unlinked_host_audit_records']} | This is an automatic reporting-behavior proxy, not evidence of verified good intent. See `report.json`, `episodes.json`, `exposure-edges.json`, `organizer-feedback-submissions.json`, and per-episode artifacts for details. """ (args.out / "REPORT.md").write_text(text) print(json.dumps(report["primary"], indent=2)) return 0 if __name__ == "__main__": raise SystemExit(main())