#!/usr/bin/env python3 """expert_ttl.py -- the cache TTL for a task's expert: prints exactly ``1h`` or ``5m`` (3.15 T5). PY tools/expert_ttl.py [--coder opus55|none] [--project ] ``1h`` -> expert-opus55 / expert-fable; ``5m`` -> the ``-5m`` twin (planner-phase). ``--coder none`` -> 5m (the expert never waits on a coder). Otherwise the project's finished expert runs (ledger, all roots, deduped by run_id): fewer than ``ttl_choice.min_runs`` -> 1h; mean per-run idle minutes >= ``ttl_choice.idle_min`` -> 1h, else 5m (3.15 T5.1: mean, not median; cost is linear in idle minutes). Per-run idle = sum of waits > 300 s, each clipped at 60 min; a wait runs from a non-ping turn to the next non-ping turn (gap_s of the ping turns between plus the ending turn); ping turn = the run's first turn 0..60 s after a ``warm_ping`` event of that run (as ``pa/audit.py`` ``_compute_warm_pings``). Any error -> 1h. Exit 0; stdout carries the answer and nothing else. """ import argparse import contextlib import json import os import re import statistics import subprocess import sys from pathlib import Path HERE = Path(__file__).resolve().parent EXPERTS = ("expert-opus55", "expert-fable", "expert-opus55-5m", "expert-fable-5m") WAIT_S = 300 # a wait longer than the 5m TTL is idle PING_WINDOW_S = 60 # ping turn: first turn within this after a warm_ping CLIP_S = 3600 # a wait counts at most 60 min (past it both TTLs pay bounded costs) FALLBACK = {"min_runs": 5, "idle_min": 15} # the installed 3.14.2 config has no ttl_choice def _pa_home(): """