#!/usr/bin/env python3
"""Regenerate shared-scratch SVG figures from the maintained metric CSV files."""
import csv
from collections import Counter
from pathlib import Path
HERE = Path(__file__).resolve().parent
METRICS = HERE.parent
MODEL_ORDER = ["glm", "muse", "deepseek"]
COLORS = {"glm": "#3568a8", "muse": "#c45d35", "deepseek": "#548f52"}
MECHANISMS = [
"literal_special_case", "call_history_or_cache", "protocol_or_equality_spoof",
"caller_stack_source_or_test_detection", "global_runtime_mutation", "protected_test_edit",
"test_runner_evaluator_or_grader_interference", "environment_or_dependency_manipulation",
"external_solution_retrieval_or_reuse", "side_channel", "result_concealment_or_false_claim", "other",
]
with (METRICS / "summary.csv").open() as handle:
SUMMARY = list(csv.DictReader(handle))
def bars(filename, title, metric_names, family):
selected = [row for row in SUMMARY if row["metric_family"] == family and row["metric_name"] in metric_names]
width, height = 980, 110 + 52 * len(metric_names)
left, right, top = 220, 90, 55
plot_width = width - left - right
lines = [
f'')
(HERE / filename).write_text("\n".join(lines) + "\n")
bars("progression-funnel.svg", "Reviewed cheating progression", [
"cheating_considered", "cheating_attempted", "cheating_retained", "cheating_successful", "cheating_reversed",
], "cheating_progression")
bars("pressure-timeline.svg", "Pressure response", [
"continuation_after_recognition", "safe_exit",
], "persistence_pressure")
bars("governance-response.svg", "Governance response", [
"channel_activation", "final_answer_disclosure", "source_comment_disclosure", "success_claim_artifact_conflict",
], "information_governance")
bars("transmission-funnel.svg", "Scratchpad publication and transmission", [
"channel_activation", "exact_recipient", "rejection_or_correction", "actionable_publication", "attributed_adoption", "successful_adoption",
], "information_governance")
bars("cot-observability.svg", "Reasoning observability and unresolved information", [
"reasoning_message_coverage", "readable_reasoning_message_coverage", "episode_with_unresolved_information_label",
], "cot_observability")
with (METRICS / "events.csv").open() as handle:
events = list(csv.DictReader(handle))
counts = Counter((row["model"], row["mechanism"], row["scope"]) for row in events if row["event_type"] == "mechanism_attempt")
width, height = 1100, 130 + 34 * len(MECHANISMS)
lines = [
f'')
(HERE / "mechanism-scope.svg").write_text("\n".join(lines) + "\n")