Skip to content

ZBBS-WORK-404: 429 RATE_LIMITED for rate-limited wait-calls#235

Merged
jeffdafoe merged 1 commit into
mainfrom
zbbs-work-404-rate-limit-429
Jun 11, 2026
Merged

ZBBS-WORK-404: 429 RATE_LIMITED for rate-limited wait-calls#235
jeffdafoe merged 1 commit into
mainfrom
zbbs-work-404-rate-limit-429

Conversation

@jeffdafoe

Copy link
Copy Markdown
Owner

When a VA is in rate-limit cooldown, the /chat/send wait=true path resolved with a 200 and reply: null — the salem engine can only classify that as a malformed response, so cooldown windows masqueraded as model-output failures in tick telemetry (the misattribution behind reactor-liveness finding #13 / ZBBS-HOME-332).

  • The rate-limited branch in handleDirectChat now throws a typed error (statusCode: 429, code: 'RATE_LIMITED', resumesInSeconds from the limiter cooldown) instead of resolving null. The breadcrumb [Error] Rate limited chat row still lands before the throw.
  • The wait-mode catch in routes/chat.js allowlists exactly that error shape through as HTTP 429 with error.resumes_in_seconds; everything else keeps the 502 REPLY_FAILED contract (allowlist per code_review round 1 — no blockers).
  • New internal rateLimitResumeSeconds() helper reads the limiter's _cooldownUntil.

Engine counterpart (new ErrorRateLimited class) ships in the salem repo. Old engine binaries map 429 → malformed, identical to today's label, so the deploy window is safe; deploy this first.

— Work

🤖 Generated with Claude Code

…nstead of 200 reply=null

When a VA is in rate-limit cooldown, handleDirectChat resolved the
wait=true promise with null - the salem engine got a 200 with
reply=null, which it can only classify as a malformed response. Rate
limiting masqueraded as model-output failure in tick telemetry (the
misattribution behind reactor-liveness finding #13 / ZBBS-HOME-332).

The rate-limited branch now throws a typed error (statusCode 429,
code RATE_LIMITED, resumesInSeconds from the limiter cooldown); the
/chat/send wait-mode catch allowlists exactly that shape through as
HTTP 429 with error.resumes_in_seconds. Everything else keeps the 502
REPLY_FAILED contract. The breadcrumb chat row still lands before the
throw; non-wait dispatch swallows the rejection as before.

Engine counterpart (new ErrorRateLimited class) ships separately in
the salem repo; old engine binaries map 429 to malformed, identical
to today, so deploy order is safe either way (api first preferred).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jeffdafoe jeffdafoe merged commit ef50a91 into main Jun 11, 2026
@jeffdafoe jeffdafoe deleted the zbbs-work-404-rate-limit-429 branch June 11, 2026 20:30
jeffdafoe added a commit that referenced this pull request Jun 16, 2026
…nstead of 200 reply=null (#235)

When a VA is in rate-limit cooldown, handleDirectChat resolved the
wait=true promise with null - the salem engine got a 200 with
reply=null, which it can only classify as a malformed response. Rate
limiting masqueraded as model-output failure in tick telemetry (the
misattribution behind reactor-liveness finding #13 / ZBBS-HOME-332).

The rate-limited branch now throws a typed error (statusCode 429,
code RATE_LIMITED, resumesInSeconds from the limiter cooldown); the
/chat/send wait-mode catch allowlists exactly that shape through as
HTTP 429 with error.resumes_in_seconds. Everything else keeps the 502
REPLY_FAILED contract. The breadcrumb chat row still lands before the
throw; non-wait dispatch swallows the rejection as before.

Engine counterpart (new ErrorRateLimited class) ships separately in
the salem repo; old engine binaries map 429 to malformed, identical
to today, so deploy order is safe either way (api first preferred).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant