Skip to content

[P0][AI-02] Prove fail-closed chat quotas and 429 UX without exhausting live allowance #222

Open

Description

@alirezasafaei-dev

Goal

Complete the missing post-release quota/abuse behavior acceptance for the live Persian chatbot while preserving real free-provider capacity. Core chat HTTP 200 was verified; post-release 429 saturation was NOT_RUN.

Scope

  • Inspect deployed /api/ai/chat, atomic PostgreSQL quota migration/guard, signed anonymous cookie, rate limits, body/history/token and concurrency bounds. Confirm the actual limits from code; historical documented starting values (5/visitor/day, 2/visitor/minute, 40/site/day, 5/site/minute) are not a substitute for current implementation proof.
  • In an isolated local/staging database with mock provider only, test exact threshold successes and rejections, concurrent requests, UTC reset, fail-closed when database unavailable, upstream timeout/429, invalid Origin/CSRF, input invalidity, and Persian user-facing error copy.
  • Verify React/UI behavior for 429/503 and retry guidance with browser automation. Real production stress, using many anonymous cookies or exhausting the live quota, is prohibited.
  • Optionally perform one bounded safe public read/negative-contract smoke if all dependencies allow and it doesn't invoke/burn provider capacity; record exact evidence, not inferred success. Any real inference needs separate owner-approved limited test budget.
  • Produce focused unit/integration/Playwright tests, non-secret report and PR. Release requires a distinct explicit owner approval.

Acceptance

Deterministic test matrix with PASS/FAIL/NOT_RUN for quota, upstream, UI and error boundaries; no actual Cloudflare quota saturation or billing side effects. PROD_429_SATURATION remains NOT_RUN unless specifically approved.

Dependencies

Coordinate with [AI-01] billing attestation; no prod changes until approved. Reference #210 and https://github.com/alirezasafaei-dev/persiantoolbox/blob/main/docs/ai/ONLINE_CHAT_MVP_2026-10-08.md.

Status: READY_FOR_READ_ONLY_AND_ISOLATED_TESTS; production-invasive steps NOT_AUTHORIZED.

Activity

  1. alirezasafaei-dev commented on Oct 11, 2026

    @alirezasafaei-dev
    OwnerAuthor

    Read-only mainline contract audit — 2026-10-11

    Inspected deployed-lineage source at main 54561b080396754fabb3cd7fe18f1ca07d6bc67f (lib/ai/quota.ts, app/api/ai/chat/route.ts), without reading secrets or sending inference:

    • FEATURE_AI_CHAT_ENABLED=true and AI_CLOUDFLARE_FREE_PLAN_CONFIRMED=true are required; missing account ID or AI token returns public 503.
    • Signed anonymous visitor cookie uses HMAC-SHA256; limit keys are based on keyed hashes, not raw visitor identifiers.
    • Source-enforced atomic PostgreSQL limits: 5/visitor/UTC day; 2/visitor/minute; 40/site/UTC day; 5/site/minute. All four consume in a single database transaction (rollback on any unsuccessful limit).
    • Invalid Origin returns 403 when Origin supplied; unsupported content type 415; malformed/oversized body 400; internal provider throttling or local quota 429; provider or DB fault 503. Client-safe Persian messages are returned and upstream details are not printed.
    • Existing chat remains live at f58ef7ad.... This is a static code audit, not a new assertion that threshold/concurrency/UTC rollover/error UX were tested today.

    Acceptance still open: isolated disposable-database concurrency and midnight reset, mocked upstream failures, UI 429/503 and no production allowance exhaustion. The new image-provider spike in draft PR #239 is unrelated and must not silently consume these chat quotas or account Neurons.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions