# dispatch-override.conf — runtime overrides for cross-runner dispatch coordination
#
# Copy to ~/.config/aidevops/dispatch-override.conf and edit.
#
# Sourced by dispatch-claim-helper.sh and dispatch-override-resolve.sh to
# filter DISPATCH_CLAIM comments from peer runners when the peer is known to
# be degraded — e.g., running stale code, fast-failing every dispatch, or
# version-skewed after a hotfix — and their stale claim comments are poisoning
# cross-runner dispatch for the full 1800s TTL.
#
# The helper supports THREE composable filter tiers, applied in order:
#
# ==============================================================================
# TIER 1 (recommended, t2422): structured per-runner overrides
# ==============================================================================
#
# Format: DISPATCH_OVERRIDE_<LOGIN_SLUG>="<action>[:<min_version>]"
#
#   <LOGIN_SLUG> = UPPERCASED login with non-alphanumerics → underscore
#                  ("alex-solovyev" → ALEX_SOLOVYEV)
#
#   <action>     = honour               — respect the claim (default)
#                  ignore               — always ignore this runner's claims
#                  honour-only-above:V  — honour ONLY IF claim version >= V
#                                         (auto-sunsets once peer upgrades)
#                  ignore-below:V       — synonym for honour-only-above
#                  warn                 — honour but log a stderr line per
#                                         runner (use during observation)
#
#   <min_version> — required for honour-only-above / ignore-below; semver
#                   (e.g., "3.8.78"). Legacy claims (pre-t2401, no version
#                   field) parse as "unknown" and are always below any floor.
#
# Examples:
#   # Ignore alex-solovyev's claims until they upgrade past v3.8.78
#   DISPATCH_OVERRIDE_ALEX_SOLOVYEV="honour-only-above:3.8.78"
#
#   # Always ignore this bot — narrower than a global block
#   DISPATCH_OVERRIDE_GITHUB_ACTIONS="ignore"
#
#   # Observe a flaky peer for a week before escalating to ignore
#   DISPATCH_OVERRIDE_BOB="warn"
#
# Advantages over TIER 2/3:
#   - Per-runner scope — doesn't affect the rest of the fleet.
#   - Auto-sunsets on upgrade — no operator action needed once peer recovers.
#   - Scales with peer count — O(1) entries per peer, O(0) for healthy peers.
#
# ==============================================================================
# TIER 2 (legacy, t2401): global version floor (DEPRECATED)
# ==============================================================================
#
# Strips claims from ANY runner whose version is below the semver floor.
# Self-sunsetting: once ALL peers upgrade to >= floor, the filter is a no-op.
# Prefer per-runner DISPATCH_OVERRIDE_<SLUG>="honour-only-above:V" because a
# global floor blocks claims from healthy peers who happen to be on older
# versions (version skew is normal during rolling upgrades).
#
# Example: DISPATCH_CLAIM_MIN_VERSION="3.9.0"
DISPATCH_CLAIM_MIN_VERSION=""

# ==============================================================================
# TIER 3 (legacy, t2400): global login ignore list (DEPRECATED)
# ==============================================================================
#
# Space- or comma-separated list of runner GitHub logins whose DISPATCH_CLAIM
# comments should be ignored entirely, regardless of version. Manual-sunset:
# operator must remove the login when the peer recovers.
# Prefer DISPATCH_OVERRIDE_<SLUG>="ignore" for clearer per-runner intent.
#
# Example: DISPATCH_CLAIM_IGNORE_RUNNERS="stale-peer1 stale-peer2"
DISPATCH_CLAIM_IGNORE_RUNNERS=""

# ==============================================================================
# Common controls
# ==============================================================================

# Default action for any runner not matched by an explicit DISPATCH_OVERRIDE_*.
# Leave empty to fall back to "honour" (safe default — honour all unlisted).
# Set to "warn" during fleet-wide observation windows.
#DISPATCH_OVERRIDE_DEFAULT="honour"

# Master switch. Set to false to keep the config file in place but temporarily
# respect all claims (useful during testing and incident rollback).
DISPATCH_OVERRIDE_ENABLED=true

# ==============================================================================
# Auto-managed section (t2932 — peer-productivity-monitor)
# ==============================================================================
#
# When `peer-productivity-monitor.sh` is installed (it runs every 30 min via
# launchd/systemd), it manages a section of THIS file between the BEGIN and
# END markers below. It observes peer GitHub activity and writes
# `DISPATCH_OVERRIDE_<SLUG>="ignore"` entries for peers whose pulse appears
# broken (claiming issues but never merging worker PRs in the last 24h),
# and clears the entry once the peer recovers (1+ merged worker PR resumes).
#
# Manual entries placed ABOVE the BEGIN marker take precedence and are NEVER
# overwritten by the monitor — this is the user-override channel.
#
# The monitor:
#   - Counts only peer's `origin:worker` PRs, never their interactive PRs
#     (their human work doesn't count toward "broken pulse" signal).
#   - Requires 3 consecutive same-vote observations before flipping (hysteresis,
#     prevents flapping during transient outages).
#   - Skips bot accounts (dependabot, renovate, github-actions, *-bot).
#   - Default for unknown peers: honour (override that with the monitor's
#     compete-by-default policy via env if you want stricter behaviour).
#
# To disable temporarily: set AIDEVOPS_PEER_MONITOR_DISABLE=1 in the launchd
# environment, or `launchctl unload ~/Library/LaunchAgents/sh.aidevops.peer-productivity-monitor.plist`.
#
# To inspect state and decisions: `peer-productivity-monitor.sh report`.

# ==============================================================================
# Safety
# ==============================================================================
#
# All filters are UNIDIRECTIONAL. If only your runner filters the peer, your
# dispatch wins the claim race and the peer backs off normally (no double-
# dispatch). If BOTH runners filter each other, double-dispatch is possible —
# intended for temporary, unilateral use during peer-degraded incidents, not
# mutual escalation.
#
# The tiebreaker logic (t2422) in dispatch-claim-helper.sh applies at claim
# time: when two claims arrive within DISPATCH_TIEBREAKER_WINDOW seconds
# (default 5s), the loser posts a CLAIM_DEFERRED comment so the deterministic
# resolution is visible in the issue timeline. This is independent of the
# filters above — tiebreakers fire for every close race, even with no
# overrides configured.
