scripts/stage_telemetry.py:
- StageAttempt: attempt_id/event_id/stage/issue/process_id, started/finished
ISO timestamps, terminal_status (COMPLETED|GATE_FAILED|FAILED|TIMEOUT|
INTERRUPTED), observed windows (model/tool/gate/persistence) with
monotonic pairs, counters (model_calls, tool_calls, repo_reads,
external_queries, sources, retries, reconciliation, implementation
corrections, ci_failures), provider tokens as UNKNOWN_NOT_EXPOSED when
unavailable (never estimated-as-measured)
- TelemetryLedger: append-only attempts.jsonl — survives restart; every
attempt (success AND failure) persists independently; persist() NEVER
raises into the stage path (observational invariant, narrowed excepts)
Wired into StageExecutor.execute(): every attempt gets a lifecycle record
at the terminal path; duplicate no-ops are not attempts.
Explicitly non-additive: wall_time ≠ model_time + tool_time when MiMo waits
on tools or relay overhead overlaps — records carry window counts and an
overlap note; reports must distinguish exclusive/overlapping/residual.
Sanity matrix proven: success → fail → retry → successful retry, all four
attempts present independently with unique attempt_ids; restart/reload
preserves them; DUPLICATE no-ops not recorded; telemetry-absent runs produce
identical process decisions (observational invariant as a test).
8 tests. Full suite 1138 passed (was 1130). Ruff clean; lint counts at
baseline (80/352).