Skip to content

fix(mock): gate BRIA expand ops behind MOCK_PROVIDERS — mock stacks were billing real fal#184

Merged
eren23 merged 1 commit into
mainfrom
fix/mock-expand-seam
Jul 20, 2026
Merged

fix(mock): gate BRIA expand ops behind MOCK_PROVIDERS — mock stacks were billing real fal#184
eren23 merged 1 commit into
mainfrom
fix/mock-expand-seam

Conversation

@eren23

@eren23 eren23 commented Jul 20, 2026

Copy link
Copy Markdown
Owner

The find

Self-play follow-through (2026-07-20): the local mock stack's expand-tray spec went red with an empty tray. Backend log:

FalClientHTTPError: User is locked. Reason: Exhausted balance.

A stack booted MOCK_PROVIDERS=1 was calling real fal. expand_image (BRIA map-pan) was the one image op without the mock.on() gate, and .env sets EXPAND_MAP_PAN=1 — so every Around click in "mock" dev billed four real BRIA outpaints. Nobody noticed while they succeeded; today the balance ran dry and it became a hard failure.

CI never caught it because CI's zero-key mock job doesn't set the pan flag — meaning the pan path was also never exercised under mock at all.

The fix

  • expand_image + expand_image_zoomout get the exact gate edit_image/continue_image already have: mock.on() → deterministic parchment card, before any key check or upload.
  • New test runs under the suite's FAL_KEY-deleted fixture, so a regression re-raises the key-missing error instead of billing anyone.

Receipts

  • expand-tray spec: red (90s timeout, 0 tiles) → green in 5.7s against the rebuilt container.
  • Backend log for the passing run: zero fal.ai / pan_failed / upload lines.
  • Full 11-spec suite: green in 1.0m (was 2.5m when pans hit the live API).
  • Gates: ruff clean, mypy (gate scope) clean, pytest 86.33% ≥ 85 floor.

Known hole left open (deliberate)

video.py (Animate) also has no mock gate — mock.py has no video helper and no spec exercises it. Ledgered rather than scope-crept.

🤖 Generated with Claude Code

…DERS

Live-caught 2026-07-20: expand_image was the ONE image op without the
mock gate. A stack booted with MOCK_PROVIDERS=1 but EXPAND_MAP_PAN=1
(every local dev boot — .env sets the flag) billed real BRIA outpaint
calls on each Around click. Nobody noticed while the calls succeeded;
today the fal balance ran dry ("User is locked. Reason: Exhausted
balance"), all four pans failed, and the expand-tray spec went red with
an empty tray. CI never caught it because CI doesn't set the pan flag —
i.e. the pan path was ALSO silently untested under mock.

Both BRIA entry points (edge-pinned pan + centered zoomout) now return
the deterministic parchment card, same shape as edit_image/
continue_image. The new test runs with FAL_KEY deleted, so a regression
re-raises the key-missing error instead of billing anyone.

Known remaining hole, deliberately out of scope: video.py (Animate) has
no mock gate either — mock.py has no video helper and no spec exercises
animate. Ledgered.
@cursor

cursor Bot commented Jul 20, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@eren23
eren23 merged commit 77e304b into main Jul 20, 2026
9 checks passed
@eren23
eren23 deleted the fix/mock-expand-seam branch July 20, 2026 10:00
eren23 added a commit that referenced this pull request Jul 20, 2026
…#186)

The E5 flip from the interactive-tests campaign (#176#181): delete
continue-on-error from the mock-stack Playwright step. The suite ran
green on 16 consecutive CI runs across unrelated PRs (2026-07-19→20),
including runs that caught real regressions locally before push
(expand-tray red on the mock-billing hole, fixed in #184). From this
commit, a failing browser flow fails the PR.
eren23 added a commit that referenced this pull request Jul 21, 2026
… entry point (#187)

* fix(mock): gate Animate behind MOCK_PROVIDERS with an embedded real clip

Finding #7 from the 2026-07-20 self-play ledger — the last ungated fal
entry point, same class as the expand hole (#184): an Animate click on
a MOCK_PROVIDERS stack billed a real ltx-video call.

mock.py gains mock_video_data_url(): a real 1-second 64x36 H.264
parchment clip (~1.7KB, generated once with ffmpeg, embedded base64) so
the mock stack needs no video toolchain. A VALID mp4 matters because
the client hands the URL straight to <video src> — a fake payload would
render as a broken player and read as a product bug.

animate_image returns it before the FAL_KEY check; the test runs under
the suite's FAL_KEY-deleted fixture so a regression re-raises loudly,
and asserts the ftyp magic to prove the payload is a real mp4.

* fix(mock): segment() takes the VLM arm under mock — SAM3 is per-label paid

Audit follow-up to the animate gate: grep over _fal_subscribe callers
found one more reachable-from-live path — generate.py's extraction
refinement calls segment(), and SEGMENTER_PROVIDER=sam3_fal makes that
one paid fal call PER LABEL with no gate. Default ("vlm") was already
safe via the mocked llm seam; now the flag flip is too. Test spies
_segment_sam3 and asserts it never runs under mock.
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