-
Adds supervisor/deploy_monitor.py: run_monitor_cycle() is one sampling pass, called repeatedly by Deploy Supervisor's own poll loop (03-C's own text: not a one-shot call). process_alive/http_health/canary_task/ validator_approval_rate sampled in order, stopping at the first anomaly. validator_approval_rate's "approve rate" has no literal definition anywhere in 01-M/03-C/04-P (no such execution_event type exists) -- derived instead from a verified structural fact in scheduler.finish_task_lifecycle: PASS closes straight to done with no bug_record ever created, FAIL/INCONCLUSIVE always creates one via judge_root_cause. A task counts as approved iff no bug_record(source='validator') exists for it. Baseline is computed by the same function looking back MONITORING_WINDOW_HOURS from cutover_at rather than persisted as a new column; baseline=None (cold start) never flags an anomaly rather than defaulting to 0. Crash-count/consecutive-http-fail windows are approximated by sample count (N = CRASH_WINDOW / MONITOR_SAMPLE_INTERVAL) rather than a true rolling time window -- documented simplification, correct as long as sampling stays roughly interval-paced. Caught my own design misreading via the tests: process_alive's monitoring- phase anomaly condition is MAX_CRASH_COUNT crashes within CRASH_WINDOW (a crash-loop detector), not "currently not alive" -- unlike U-038's health check where any single failure fails closed. A single dead reading during monitoring is recorded but must not trigger an immediate rollback by itself. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>