---
name: riyadh-grid-coverage-bug
description: "Flat 240min watchdog cut big/dense-city grid scans short at ~8% coverage; FIXED 2026-07-04 per Ahmed: 24h cap + queue restart"
metadata: 
  node_type: memory
  type: project
  originSessionId: 806b3fd7-1800-4079-b966-13ea84426fb0
---

Found 2026-07-04 (Ahmed asked "are we actually fetching all we can" after seeing only 3134 total
coffee-shop leads across 7 cities and being suspicious Riyadh couldn't really be "done" at 618 leads).

Confirmed via `data/plan.log` + `scan_ledger` query: Riyadh's coffee-shop grid = 1517 base tiles
(vs Al Khobar's ~164 — Riyadh's bbox is ~9x bigger and every tile is saturated at 100-120 places,
meaning it's the densest, least-covered market). The per-job watchdog (`JOB_TIMEOUT_MIN=240`, see
[[ultron]] project CLAUDE.md Phase 0) only let it get through 121/1517 base tiles (~8%) before
SIGTERM. Same pattern hit Jeddah (115/~600 tiles). Small cities (Khobar/Dammam/Dhahran) are near
fully scanned — their base grids are small enough to finish inside one 240min window.

**The compounding bug**: a watchdog-killed job still exits 0 (run-grid cleans up on SIGTERM), so
`plan-manager.js` records it as `done` in the completion ledger — identical to a job that actually
finished all its tiles. That means `revisit_days` (14) applies uniformly, so the biggest/densest
cities (which need the *most* passes to finish) get the same infrequent retry cadence as fully-done
small cities, and never catch up.

**Why:** the scheduler's per-job time budget doesn't scale with city size/tile count, and "done"
is binary (job ran to timeout or to completion) rather than tracking actual tile-coverage fraction.

**How to apply:** before trusting any per-city lead count as "complete," check `scan_ledger` tile
coverage against the base-tile estimate for that city's bbox (`(latMax-latMin)/step * (lngMax-lngMin)/step`
from `config/cities.json`), not just whether the job shows `done` in plan.log/plan-done ledger.
**Ahmed's decision (2026-07-04, via Telegram):** every city gets ALL the time it needs, hard cap
24h per job. Implemented same day: `plan-manager.js` now launches run-plan with
`JOB_TIMEOUT_MIN=1440` default (was 240), queue restarted from scratch (plan.log archived,
plan-done.jsonl cleared) in his chosen order Khobar → Dhahran → Dammam → Riyadh → Jeddah → Mecca
→ Medina (coffee shop pass, then same order for restaurant; also added the previously-missing
restaurant@Dhahran job). Tile-skip (FRESH_DAYS=7) makes re-runs resume, not re-scrape.
His completeness heuristic for later revisit passes: re-fetch ~4h and if the overwhelming share of
results are already-known place_ids, the city is genuinely done — the per-tile "N new" counts in
plan.log / the digest's new-lead counts are the signal for this.
