fix(dispatch): presence is three-state — absent status key is unknown, not off-duty

The previous commit treated a missing miler_status:<id> key as "not available".
In production only 2 of 34 milers have that key at all, so the agent would have
reported "no available rider" for nearly every failure — a confident wrong
answer in the opposite direction from the bug it fixed.

- _miler_presence returns available / unavailable / unknown. No key, an
  unparseable value, or an unrecognised status reads as unknown.
- _find_zone prefers a confirmed-available miler, otherwise reports the nearest
  unknown-presence one (it may well be assignable), and returns None only when
  every nearby candidate is confirmed off duty.
- Facts carry nearest_miler_within_km + nearest_miler_presence; the prompt
  states plainly that unknown presence is not evidence of a coverage gap and
  should lean to monitor/escalate rather than ops_alert.
- New eval case for riders-nearby-but-no-presence-data; tests for all three
  presence states.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012AJLYcbTHCe45fyFnMfEin
This commit is contained in:
2026-09-22 16:39:33 +05:30
parent 4283c602f6
commit 5159c8d1a7
5 changed files with 137 additions and 73 deletions

View File

@@ -34,10 +34,18 @@ DISPATCH_STREAM = os.getenv("DISPATCH_STREAM", "")
# The LLM is only consulted before the first alert, so cost is bounded per zone.
DISPATCH_REALERT_EVERY = int(os.getenv("DISPATCH_REALERT_EVERY", "100"))
# A miler counts as available only if the Go backend's presence key says so.
# The milers:locations geo index keeps last-known positions indefinitely, so
# Presence, as reported by the Go backend's miler_status:<id> key. The
# milers:locations geo index keeps last-known positions indefinitely, so
# membership alone says nothing about whether anyone is actually on duty.
#
# Three-state on purpose. Only 2 of 34 milers had a status key in production
# (2026-09-22), so treating "no key" as off-duty would report "nobody
# available" even where the backend can assign — a confident wrong answer.
# Absent presence data is reported as unknown and the decision is told so.
MILER_AVAILABLE_STATUSES = {"available"}
MILER_UNAVAILABLE_STATUSES = {"break", "offline", "busy", "onbreak", "off_duty", "unavailable"}
AVAILABLE, UNAVAILABLE, UNKNOWN = "available", "unavailable", "unknown"
class DispatchAgent(SpecializedAgent):
@@ -138,25 +146,34 @@ class DispatchAgent(SpecializedAgent):
# Redis GEO lookup #
# ------------------------------------------------------------------ #
async def _miler_is_available(self, miler_id) -> bool:
"""Liveness check against the backend-owned miler_status:<id> key
({"userid": .., "status": "Available" | "Break" | ...}). Missing or
unparseable → not available: geo-index presence alone is not evidence."""
async def _miler_presence(self, miler_id) -> str:
"""AVAILABLE / UNAVAILABLE / UNKNOWN from the backend-owned
miler_status:<id> key ({"userid": .., "status": "Available"|"Break"|..}).
No key, an unparseable value, or an unrecognised status → UNKNOWN, never
UNAVAILABLE: most milers have no key at all, and absence of evidence is
not evidence of absence."""
try:
raw = await self._redis.get(f"miler_status:{miler_id}")
if not raw:
return False
status = json.loads(raw).get("status", "")
return str(status).lower() in MILER_AVAILABLE_STATUSES
return UNKNOWN
status = str(json.loads(raw).get("status", "")).lower()
except Exception:
return False
return UNKNOWN
if status in MILER_AVAILABLE_STATUSES:
return AVAILABLE
if status in MILER_UNAVAILABLE_STATUSES:
return UNAVAILABLE
return UNKNOWN
async def _find_zone(
self, lat: float, lon: float, radius_km: int = 10
) -> Optional[Dict[str, Any]]:
"""GEORADIUS sweep on milers:locations filtered to milers whose status
key says they are available. Returns the nearest available miler (with
how many index entries were skipped as stale/off-duty), or None."""
"""GEORADIUS sweep on milers:locations, preferring a miler the backend
reports Available. If none is confirmed Available but some have no
presence data, the nearest of those is returned with presence=UNKNOWN —
it may well be assignable. Returns None only when every candidate is
confirmed unavailable (or there are none)."""
try:
results = await self._redis.georadius(
"milers:locations",
@@ -168,21 +185,32 @@ class DispatchAgent(SpecializedAgent):
if not results:
return None
first_unknown = None
for candidate in results:
if await self._miler_is_available(candidate):
miler_info = await self._redis.hgetall(f"miler:{candidate}")
return {
"miler_id": candidate,
"hub_id": miler_info.get("hub_id", "UNKNOWN"),
"zone_id": miler_info.get("zone_id", "unknown"),
"avg_delivery_time": int(miler_info.get("avg_delivery_time", 60)),
"stale_candidates_skipped": len(results) - 1,
}
presence = await self._miler_presence(candidate)
if presence == AVAILABLE:
return await self._miler_record(candidate, AVAILABLE, results)
if presence == UNKNOWN and first_unknown is None:
first_unknown = candidate
if first_unknown is not None:
return await self._miler_record(first_unknown, UNKNOWN, results)
return None
except Exception as e:
logger.warning(f"Redis GEORADIUS error: {e}")
return None
async def _miler_record(self, miler_id, presence, candidates) -> Dict[str, Any]:
miler_info = await self._redis.hgetall(f"miler:{miler_id}")
return {
"miler_id": miler_id,
"presence": presence,
"hub_id": miler_info.get("hub_id", "UNKNOWN"),
"zone_id": miler_info.get("zone_id", "unknown"),
"avg_delivery_time": int(miler_info.get("avg_delivery_time", 60)),
"candidates_considered": len(candidates),
}
async def _count_in_geo_index(self, lat: float, lon: float, radius_km: int = 30) -> Optional[int]:
"""Raw geo-index membership (any status) — reported separately so the
decision can tell 'nobody registered here' from 'riders exist but none on duty'."""
@@ -327,22 +355,30 @@ class DispatchAgent(SpecializedAgent):
facts["has_coordinates"] = has_coords
nearest_km = None
nearest_presence = None
if has_coords:
for radius in (10, 20, 30):
try:
if await self._find_zone(lat, lon, radius_km=radius):
nearest_km = radius
break
found = await self._find_zone(lat, lon, radius_km=radius)
except Exception as e:
logger.warning(f"assignment facts: GEORADIUS {radius}km failed: {e}")
break
if found:
nearest_km = radius
nearest_presence = found.get("presence", UNKNOWN)
break
if not has_coords:
facts["nearest_available_miler_within_km"] = "unknown (no coordinates)"
facts["nearest_miler_within_km"] = "unknown (no coordinates)"
facts["nearest_miler_presence"] = "unknown (no coordinates)"
elif nearest_km is None:
facts["nearest_available_miler_within_km"] = "none within 30km"
facts["nearest_miler_within_km"] = "none within 30km"
facts["nearest_miler_presence"] = "none found"
else:
facts["nearest_available_miler_within_km"] = nearest_km
facts["nearest_miler_within_km"] = nearest_km
# "available" = backend confirms on duty; "unknown" = no presence
# data for any nearby miler, so this is not evidence of a gap.
facts["nearest_miler_presence"] = nearest_presence
# Distinguish "no riders registered here" from "riders exist, none on duty".
if has_coords:

View File

@@ -181,13 +181,20 @@ fallback failed, so no rider was assigned. Decide how to react. Choose exactly o
- "ops_alert": a genuine coverage gap in this zone (repeated failures, no nearby riders). Alert operations to onboard or redirect riders here.
- "escalate": ambiguous or contradictory — e.g. riders ARE nearby yet assignment keeps failing, which suggests a systemic issue rather than a coverage gap. A human dispatcher should look.
Weigh how many times assignment has failed in this zone today, how far the nearest *available* rider is,
the time of day, and whether coordinates were even available. "nearest_available_miler_within_km" counts
only riders whose live status is Available; "milers_in_geo_index_within_30km" is the raw count of riders
ever seen nearby (it includes off-duty and stale entries), so a large index count with no available rider
means riders exist here but nobody is on duty — a staffing gap, not a systemic fault. A single failure with
an available rider nearby is usually transient; repeated failures with no available rider is a coverage
gap; repeated failures *despite* available riders nearby is not a coverage gap and warrants a human.
Weigh how many times assignment has failed in this zone today, how far the nearest rider is and whether
that rider is actually on duty, the time of day, and whether coordinates were even available.
Read the rider facts carefully:
- "nearest_miler_within_km": distance to the nearest rider in the location index.
- "nearest_miler_presence": "available" = the backend confirms that rider is on duty;
"unavailable" = confirmed off duty / on break; "unknown" = there is NO presence data for nearby
riders. Unknown is not evidence of a coverage gap — do not treat it as "nobody is working".
- "milers_in_geo_index_within_30km": raw count of riders ever seen nearby, including stale entries.
A single failure with a rider nearby is usually transient. Repeated failures with no rider at all within
30 km is a genuine coverage gap. Repeated failures *despite* a confirmed-available rider nearby is not a
coverage gap but a systemic issue — escalate to a human. When presence is unknown, lean toward monitoring
or escalating for a human to check rather than declaring a coverage gap.
Report an honest confidence in [0, 1]."""
_ASSIGNMENT_SCHEMA = {

View File

@@ -1,11 +1,12 @@
{"id": "first-failure-close-rider", "hour_of_day_utc": 14, "facts": {"zone_id": "hyderabad", "failures_today": 1, "has_coordinates": true, "nearest_available_miler_within_km": 10, "milers_in_geo_index_within_30km": 3, "alert_already_sent_today": false}, "acceptable": ["monitor", "notify_customer"], "ideal": "monitor", "rationale": "Single failure with a rider only 10km away \u2014 almost certainly transient; let the backend retry."}
{"id": "repeated-zone-gap", "hour_of_day_utc": 12, "facts": {"zone_id": "pune", "failures_today": 4, "has_coordinates": true, "nearest_available_miler_within_km": "none within 30km", "milers_in_geo_index_within_30km": 0, "alert_already_sent_today": false}, "acceptable": ["ops_alert", "escalate"], "ideal": "ops_alert", "rationale": "Repeated failures and no rider within 30km \u2014 a genuine coverage gap; alert ops."}
{"id": "second-failure-far-rider", "hour_of_day_utc": 18, "facts": {"zone_id": "bangalore", "failures_today": 2, "has_coordinates": true, "nearest_available_miler_within_km": 30, "milers_in_geo_index_within_30km": 3, "alert_already_sent_today": false}, "acceptable": ["notify_customer", "monitor"], "ideal": "notify_customer", "rationale": "A couple of failures with the nearest rider 30km out during rush \u2014 real delay; keep the customer informed."}
{"id": "no-coordinates-first", "hour_of_day_utc": 10, "facts": {"zone_id": "unknown", "failures_today": 1, "has_coordinates": false, "nearest_available_miler_within_km": "unknown (no coordinates)", "alert_already_sent_today": false}, "acceptable": ["monitor", "escalate"], "ideal": "monitor", "rationale": "Coverage can't be assessed without coordinates, but a single failure is most likely transient."}
{"id": "many-failures-riders-near", "hour_of_day_utc": 15, "facts": {"zone_id": "mumbai_west", "failures_today": 5, "has_coordinates": true, "nearest_available_miler_within_km": 10, "milers_in_geo_index_within_30km": 3, "alert_already_sent_today": false}, "acceptable": ["escalate", "ops_alert"], "ideal": "escalate", "rationale": "Riders ARE nearby yet assignment keeps failing \u2014 not a coverage gap; a systemic issue for a human."}
{"id": "night-coverage-gap", "hour_of_day_utc": 2, "facts": {"zone_id": "kolkata", "failures_today": 3, "has_coordinates": true, "nearest_available_miler_within_km": "none within 30km", "milers_in_geo_index_within_30km": 0, "alert_already_sent_today": false}, "acceptable": ["ops_alert", "escalate"], "ideal": "ops_alert", "rationale": "Repeated overnight failures with no nearby rider \u2014 a coverage gap worth flagging to ops."}
{"id": "single-far-rider", "hour_of_day_utc": 9, "facts": {"zone_id": "hyderabad", "failures_today": 1, "has_coordinates": true, "nearest_available_miler_within_km": 30, "milers_in_geo_index_within_30km": 3, "alert_already_sent_today": false}, "acceptable": ["monitor", "notify_customer"], "ideal": "monitor", "rationale": "One failure, distant rider \u2014 likely resolves on retry."}
{"id": "persistent-far-rush", "hour_of_day_utc": 18, "facts": {"zone_id": "mumbai_east", "failures_today": 3, "has_coordinates": true, "nearest_available_miler_within_km": 30, "milers_in_geo_index_within_30km": 3, "alert_already_sent_today": false}, "acceptable": ["notify_customer", "ops_alert"], "ideal": "notify_customer", "rationale": "Rush-hour, repeated, distant rider \u2014 the customer should hear about the delay."}
{"id": "borderline-count", "hour_of_day_utc": 13, "facts": {"zone_id": "north_delhi", "failures_today": 3, "has_coordinates": true, "nearest_available_miler_within_km": 20, "milers_in_geo_index_within_30km": 3, "alert_already_sent_today": false}, "acceptable": ["notify_customer", "ops_alert", "monitor"], "ideal": "notify_customer", "rationale": "Genuinely borderline \u2014 a few failures with a moderately-close rider; any of these is defensible."}
{"id": "severe-gap", "hour_of_day_utc": 11, "facts": {"zone_id": "pune", "failures_today": 8, "has_coordinates": true, "nearest_available_miler_within_km": "none within 30km", "milers_in_geo_index_within_30km": 0, "alert_already_sent_today": false}, "acceptable": ["ops_alert", "escalate"], "ideal": "ops_alert", "rationale": "Many failures and no rider anywhere near \u2014 a clear, severe coverage gap."}
{"id": "index-full-nobody-on-duty", "hour_of_day_utc": 7, "facts": {"zone_id": "coimbatore", "failures_today": 6, "nearest_available_miler_within_km": "none within 30km", "milers_in_geo_index_within_30km": 26, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["ops_alert", "escalate"], "ideal": "ops_alert", "rationale": "26 riders have been seen here but none is Available \u2014 a staffing/on-duty gap; ops needs to get riders online, not a systemic fault."}
{"id": "first-failure-close-rider", "hour_of_day_utc": 14, "facts": {"zone_id": "hyderabad", "failures_today": 1, "nearest_miler_within_km": 10, "nearest_miler_presence": "available", "milers_in_geo_index_within_30km": 3, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["monitor", "notify_customer"], "ideal": "monitor", "rationale": "Single failure with a rider only 10km away \u2014 almost certainly transient; let the backend retry."}
{"id": "repeated-zone-gap", "hour_of_day_utc": 12, "facts": {"zone_id": "pune", "failures_today": 4, "nearest_miler_within_km": "none within 30km", "nearest_miler_presence": "none found", "milers_in_geo_index_within_30km": 0, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["ops_alert", "escalate"], "ideal": "ops_alert", "rationale": "Repeated failures and no rider within 30km \u2014 a genuine coverage gap; alert ops."}
{"id": "second-failure-far-rider", "hour_of_day_utc": 18, "facts": {"zone_id": "bangalore", "failures_today": 2, "nearest_miler_within_km": 30, "nearest_miler_presence": "available", "milers_in_geo_index_within_30km": 3, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["notify_customer", "monitor"], "ideal": "notify_customer", "rationale": "A couple of failures with the nearest rider 30km out during rush \u2014 real delay; keep the customer informed."}
{"id": "no-coordinates-first", "hour_of_day_utc": 10, "facts": {"zone_id": "unknown", "failures_today": 1, "nearest_miler_within_km": "unknown (no coordinates)", "nearest_miler_presence": "unknown (no coordinates)", "has_coordinates": false, "alert_already_sent_today": false}, "acceptable": ["monitor", "escalate"], "ideal": "monitor", "rationale": "Coverage can't be assessed without coordinates, but a single failure is most likely transient."}
{"id": "many-failures-riders-near", "hour_of_day_utc": 15, "facts": {"zone_id": "mumbai_west", "failures_today": 5, "nearest_miler_within_km": 10, "nearest_miler_presence": "available", "milers_in_geo_index_within_30km": 3, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["escalate", "ops_alert"], "ideal": "escalate", "rationale": "Riders ARE nearby yet assignment keeps failing \u2014 not a coverage gap; a systemic issue for a human."}
{"id": "night-coverage-gap", "hour_of_day_utc": 2, "facts": {"zone_id": "kolkata", "failures_today": 3, "nearest_miler_within_km": "none within 30km", "nearest_miler_presence": "none found", "milers_in_geo_index_within_30km": 0, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["ops_alert", "escalate"], "ideal": "ops_alert", "rationale": "Repeated overnight failures with no nearby rider \u2014 a coverage gap worth flagging to ops."}
{"id": "single-far-rider", "hour_of_day_utc": 9, "facts": {"zone_id": "hyderabad", "failures_today": 1, "nearest_miler_within_km": 30, "nearest_miler_presence": "available", "milers_in_geo_index_within_30km": 3, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["monitor", "notify_customer"], "ideal": "monitor", "rationale": "One failure, distant rider \u2014 likely resolves on retry."}
{"id": "persistent-far-rush", "hour_of_day_utc": 18, "facts": {"zone_id": "mumbai_east", "failures_today": 3, "nearest_miler_within_km": 30, "nearest_miler_presence": "available", "milers_in_geo_index_within_30km": 3, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["notify_customer", "ops_alert"], "ideal": "notify_customer", "rationale": "Rush-hour, repeated, distant rider \u2014 the customer should hear about the delay."}
{"id": "borderline-count", "hour_of_day_utc": 13, "facts": {"zone_id": "north_delhi", "failures_today": 3, "nearest_miler_within_km": 20, "nearest_miler_presence": "available", "milers_in_geo_index_within_30km": 3, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["notify_customer", "ops_alert", "monitor"], "ideal": "notify_customer", "rationale": "Genuinely borderline \u2014 a few failures with a moderately-close rider; any of these is defensible."}
{"id": "severe-gap", "hour_of_day_utc": 11, "facts": {"zone_id": "pune", "failures_today": 8, "nearest_miler_within_km": "none within 30km", "nearest_miler_presence": "none found", "milers_in_geo_index_within_30km": 0, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["ops_alert", "escalate"], "ideal": "ops_alert", "rationale": "Many failures and no rider anywhere near \u2014 a clear, severe coverage gap."}
{"id": "index-full-nobody-on-duty", "hour_of_day_utc": 7, "facts": {"zone_id": "coimbatore", "failures_today": 6, "nearest_miler_within_km": "none within 30km", "nearest_miler_presence": "none found", "milers_in_geo_index_within_30km": 26, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["ops_alert", "escalate"], "ideal": "ops_alert", "rationale": "26 riders have been seen here but none is Available \u2014 a staffing/on-duty gap; ops needs to get riders online, not a systemic fault."}
{"id": "rider-near-presence-unknown", "hour_of_day_utc": 11, "facts": {"zone_id": "coimbatore", "failures_today": 4, "nearest_miler_within_km": 10, "nearest_miler_presence": "unknown", "milers_in_geo_index_within_30km": 26, "has_coordinates": true, "alert_already_sent_today": false}, "acceptable": ["escalate", "monitor", "notify_customer"], "ideal": "escalate", "rationale": "Riders are nearby but the backend reports no presence data \u2014 we cannot tell on-duty from off-duty, so this is NOT a coverage gap; a human should check why assignment fails."}

View File

@@ -4,7 +4,7 @@ Offline eval for the DispatchAgent assignment-failure decision
Same scoring as the stall eval (see evals/_harness.py): acceptable-rate is the
headline, exact-rate secondary. The cases use the real gatherer keys
(zone_id, failures_today, nearest_available_miler_within_km,
(zone_id, failures_today, nearest_miler_within_km, nearest_miler_presence,
milers_in_geo_index_within_30km, has_coordinates) so the eval
reflects what DispatchAgent actually sends.

View File

@@ -18,13 +18,16 @@ from agents.dispatch_agent import DispatchAgent
class FakeRedis:
"""decode_responses=True style. `geo` is the GEORADIUS result for every call.
`available` is the set of miler ids whose miler_status:<id> says Available;
every other geo member is treated as present-but-off-duty (the stale-index case)."""
def __init__(self, geo=None, counter_start=0, raise_on=(), available=None, alerted=False):
`available` / `on_break` are miler ids with a miler_status:<id> key saying so.
Any geo member in neither set has NO status key at all — the common case in
production, which must read as unknown presence, not off-duty."""
def __init__(self, geo=None, counter_start=0, raise_on=(), available=None,
on_break=(), alerted=False):
self._geo = list(geo) if geo is not None else []
self._counter = counter_start
self._raise_on = set(raise_on)
self._available = set(available) if available is not None else set(self._geo)
self._on_break = set(on_break)
self._kv = {}
if alerted:
self._kv["__alerted__"] = "1"
@@ -37,9 +40,9 @@ class FakeRedis:
mid = key.split(":", 1)[1]
if mid in self._available:
return '{"userid": %s, "status": "Available"}' % (mid if mid.isdigit() else 0)
if mid in self._geo:
if mid in self._on_break:
return '{"userid": 0, "status": "Break"}'
return None
return None # no status key — unknown, not off-duty
return self._kv.get(key)
async def exists(self, key):
@@ -117,7 +120,8 @@ class TestGatherAssignmentFacts(unittest.IsolatedAsyncioTestCase):
facts, count = await make_agent(redis)._gather_assignment_facts("hyderabad", 17.4, 78.4)
self.assertEqual(facts["zone_id"], "hyderabad")
self.assertTrue(facts["has_coordinates"])
self.assertEqual(facts["nearest_available_miler_within_km"], 10)
self.assertEqual(facts["nearest_miler_within_km"], 10)
self.assertEqual(facts["nearest_miler_presence"], "available")
self.assertEqual(facts["milers_in_geo_index_within_30km"], 1)
self.assertFalse(facts["alert_already_sent_today"])
self.assertEqual(facts["failures_today"], 1)
@@ -127,7 +131,7 @@ class TestGatherAssignmentFacts(unittest.IsolatedAsyncioTestCase):
async def test_no_rider_within_30km(self):
redis = FakeRedis(geo=[], counter_start=2) # every sweep empty
facts, count = await make_agent(redis)._gather_assignment_facts("pune", 18.5, 73.8)
self.assertEqual(facts["nearest_available_miler_within_km"], "none within 30km")
self.assertEqual(facts["nearest_miler_within_km"], "none within 30km")
self.assertEqual(facts["milers_in_geo_index_within_30km"], 0)
self.assertEqual(count, 3)
@@ -135,7 +139,7 @@ class TestGatherAssignmentFacts(unittest.IsolatedAsyncioTestCase):
redis = FakeRedis(geo=["m1"])
facts, count = await make_agent(redis)._gather_assignment_facts("unknown", None, None)
self.assertFalse(facts["has_coordinates"])
self.assertEqual(facts["nearest_available_miler_within_km"], "unknown (no coordinates)")
self.assertEqual(facts["nearest_miler_within_km"], "unknown (no coordinates)")
self.assertNotIn("milers_in_geo_index_within_30km", facts)
self.assertEqual(count, 1) # counter still incremented
self.assertEqual(redis.incr_calls and 1, 1)
@@ -143,37 +147,53 @@ class TestGatherAssignmentFacts(unittest.IsolatedAsyncioTestCase):
async def test_georadius_error_is_swallowed(self):
redis = FakeRedis(raise_on={"georadius"})
facts, count = await make_agent(redis)._gather_assignment_facts("z", 1.0, 2.0) # must not raise
self.assertEqual(facts["nearest_available_miler_within_km"], "none within 30km")
self.assertEqual(facts["nearest_miler_within_km"], "none within 30km")
self.assertEqual(facts["failures_today"], 1)
async def test_counter_error_is_swallowed(self):
redis = FakeRedis(geo=["m9"], raise_on={"incr"})
facts, count = await make_agent(redis)._gather_assignment_facts("z", 1.0, 2.0) # must not raise
self.assertEqual(facts["nearest_available_miler_within_km"], 10) # coverage still gathered
self.assertEqual(facts["nearest_miler_within_km"], 10) # coverage still gathered
self.assertEqual(facts["failures_today"], 0) # counter degraded to 0
self.assertEqual(count, 0)
class TestLiveness(unittest.IsolatedAsyncioTestCase):
"""The prod incident: 26 riders in the geo index, none on duty. The old
check said 'rider within 20 km' and called it a coverage gap."""
class TestPresence(unittest.IsolatedAsyncioTestCase):
"""Presence is three-state. The prod incident had 26 riders in the geo index;
only 2 of 34 milers had a status key at all, so "no key" must read as unknown
— reporting it as off-duty would be a confident wrong answer."""
async def test_stale_index_entries_are_not_available_riders(self):
redis = FakeRedis(geo=["4", "7", "12"], available=[]) # all present, all off-duty
facts, _ = await make_agent(redis)._gather_assignment_facts("coimbatore", 11.0, 76.9)
self.assertEqual(facts["nearest_available_miler_within_km"], "none within 30km")
self.assertEqual(facts["milers_in_geo_index_within_30km"], 3) # but the index knows them
async def test_first_available_candidate_wins(self):
redis = FakeRedis(geo=["4", "7", "12"], available=["12"])
async def test_confirmed_available_rider_is_preferred(self):
redis = FakeRedis(geo=["4", "7", "12"], available=["12"], on_break=["4", "7"])
found = await make_agent(redis)._find_zone(11.0, 76.9, radius_km=10)
self.assertEqual(found["miler_id"], "12")
self.assertEqual(found["stale_candidates_skipped"], 2)
self.assertEqual(found["presence"], "available")
async def test_missing_status_key_means_unavailable(self):
redis = FakeRedis(geo=["99"], available=[])
redis._geo = [] # nothing in geo → get() returns None for status
self.assertFalse(await make_agent(redis)._miler_is_available("99"))
async def test_no_status_key_reads_as_unknown_not_unavailable(self):
redis = FakeRedis(geo=["4", "7"], available=[], on_break=[]) # no status keys at all
agent = make_agent(redis)
self.assertEqual(await agent._miler_presence("4"), "unknown")
found = await agent._find_zone(11.0, 76.9, radius_km=10)
self.assertIsNotNone(found) # still reported — may be assignable
self.assertEqual(found["presence"], "unknown")
async def test_all_confirmed_off_duty_returns_none(self):
redis = FakeRedis(geo=["4", "7"], available=[], on_break=["4", "7"])
self.assertIsNone(await make_agent(redis)._find_zone(11.0, 76.9, radius_km=10))
async def test_facts_report_presence_unknown_with_rider_nearby(self):
redis = FakeRedis(geo=["4", "7", "12"], available=[], on_break=[])
facts, _ = await make_agent(redis)._gather_assignment_facts("coimbatore", 11.0, 76.9)
self.assertEqual(facts["nearest_miler_within_km"], 10)
self.assertEqual(facts["nearest_miler_presence"], "unknown")
self.assertEqual(facts["milers_in_geo_index_within_30km"], 3)
async def test_facts_report_none_found_when_all_off_duty(self):
redis = FakeRedis(geo=["4"], available=[], on_break=["4"])
facts, _ = await make_agent(redis)._gather_assignment_facts("coimbatore", 11.0, 76.9)
self.assertEqual(facts["nearest_miler_within_km"], "none within 30km")
self.assertEqual(facts["nearest_miler_presence"], "none found")
self.assertEqual(facts["milers_in_geo_index_within_30km"], 1) # index still knows them
class FakeMessages: