Files
last30days-skill/skills/last30days/scripts
Gabriel Arrillaga a717dd2b2c fix(bird_x): retry subprocess on non-JSON stdout (HTML interstitial)
Twitter's edge intermittently serves an HTML anti-bot interstitial in
place of JSON when the bird-search subprocess hits a per-query rate
limit. Before this fix, that response made json.loads raise
JSONDecodeError and _run_bird_search() returned {"error": ..., "items":
[]} with the parsed exception message — silent-empty against an
orchestrator that has no way to distinguish "Twitter served HTML; retry
likely succeeds" from "no tweets matched the query."

Surfaced during a community-signal pass where a Karpathy-LLM-wiki
subquery returned zero X items, while a second identical run a few
seconds later returned full results.

Fix:
- Extract the subprocess invocation into _invoke_bird_subprocess() so
  the retry loop can call it multiple times cleanly. Returns
  (result, terminal_error) — terminal_error is non-None for
  unrecoverable cases (subprocess timeout, spawn failure) that should
  NOT be retried.
- In _run_bird_search(), wrap the json.loads parse in a retry loop
  bounded by MAX_JSON_DECODE_RETRIES (=2) with JSON_DECODE_RETRY_DELAY
  (=5s) between attempts.
- On non-JSON stdout, log a diagnostic that names the shape
  (`looks_html`, first-80-chars stdout preview, attempt counter) so
  silent-empty failures become legible in logs.
- On retry exhaustion, return an error dict whose message explicitly
  names "anti-bot interstitial" as the likely cause, distinguishing
  this failure from a genuine no-results case.

Subprocess timeout, spawn failure, and non-zero return-code paths are
unchanged — those are terminal and don't retry.

Tests:
- Verifies HTML-then-JSON returns success on attempt 2.
- Verifies all-HTML returns the diagnostic error dict mentioning the
  anti-bot interstitial cause.
- Verifies subprocess timeout is NOT retried.

All 12 bird_x tests pass (9 baseline + 3 new).
2026-05-16 20:52:56 -07:00
..
2026-04-23 20:15:02 -04:00
2026-04-23 20:15:02 -04:00
2026-04-23 20:15:02 -04:00
2026-04-23 20:15:02 -04:00
2026-04-23 20:15:02 -04:00