"""trust.py — Layer 04. Earned autonomy, with automatic revocation.

A task type may run unattended only after it accumulates evidence: MIN_RUNS logged runs at a
MIN_RATE verified pass rate, measured over the last WINDOW runs. Because the gate only looks at
the recent window, a task type that starts failing falls out of unattended status by itself — no
human notices the slip and demotes it; the arithmetic does. Trust decays unless it keeps being
re-earned.

Tune the constants to the blast radius. A dependency bump that `make test` fully covers can earn
autonomy at 20 runs. Anything touching auth or migrations should demand more — or never go
unattended at all.
"""
import json
from pathlib import Path

LEDGER = Path(__file__).with_name("trust.jsonl")
MIN_RUNS, MIN_RATE, WINDOW = 20, 0.95, 20


def _rows(task_type):
    if not LEDGER.exists():
        return []
    out = []
    for line in LEDGER.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line:
            continue
        row = json.loads(line)
        if row.get("type") == task_type:
            out.append(row)
    return out


def record(task_type, passed):
    """Append one run's outcome. Call after the final vote (the script), never before."""
    with LEDGER.open("a", encoding="utf-8") as f:
        f.write(json.dumps({"type": task_type, "pass": bool(passed)}) + "\n")


def may_run_unattended(task_type):
    recent = _rows(task_type)[-WINDOW:]          # only the last WINDOW runs count
    if len(recent) < MIN_RUNS:
        return False                             # not enough evidence yet → route to a human
    rate = sum(1 for r in recent if r["pass"]) / len(recent)
    return rate >= MIN_RATE                      # one bad streak drops it below the line


if __name__ == "__main__":
    import sys
    t = sys.argv[1] if len(sys.argv) > 1 else "dep-bump"
    print(f"{t}: may_run_unattended = {may_run_unattended(t)}")
