Wraps the SessionLocal body in try/finally so db.close() is always
called, preventing connection leaks on exception. Updates the
test monkeypatch to use a no-op close() proxy so the transactional
fixture stays live after run_step returns.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Bring docs in line with the post-AM-6 state so a fresh agent can pick
up cleanly without first reconciling stale numbers:
- pytest count: 88/59/31 → 92 across all references
- live scrape: 9,960 rows / 36s → 9,980 rows / 44s (latest run, 2026-05-06)
- migrations applied: 0001-0005 → 0001-0007 in both docs
- verification gate updated with auto-minted JWT detail and the 29,779
ingredient_grocery_match rows produced post-scrape
- "What is real" / Backend: added swiftly_auth.py bullet describing
get_token() / mint_anonymous_token() / cache semantics + the
10,928-item live verification
- file map: added services/swiftly_auth.py, services/matcher.py,
services/planner/, mentioned scraper_service runs matcher post-scrape
- file map: alembic versions 0001 → 0007, tests/ count = 92, marked
config.py as no-longer-carrying SWIFTLY_BEARER_TOKEN
- spec map line for swiftly-token-auto-mint: "next-up" → "Implemented"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fetch_category() now calls swiftly_auth.get_token() to mint a fresh
Firebase JWT on demand when no explicit bearer_token override is
pinned by tests. The cache short-circuit means the per-call mint
overhead is ~zero in the steady state.
- Removed the empty-token short-circuit; auto-mint makes it moot
- Updated _AUTH_ERROR_MESSAGE: 401-after-mint now points at the spec
(Lucky tightening anon-auth) rather than asking for manual capture
- Replaced test_swiftly_auth_error_when_token_missing with a positive
test that verifies fetch_category mints when bearer_token is None
- bearer_token constructor arg preserved for the 401-path test
Full suite: 92/92 green. Live verification via
scripts/spike_swiftly_ingest.py --confirm-live deferred to next step
per HANDOFF AM-2 halt boundary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the static SWIFTLY_BEARER_TOKEN env-var lookup with a JIT
mint via the Firebase Identity Toolkit signUp endpoint, gated by the
firebaseApiKey published in luckysupermarkets.com/config.json.
- get_token(): returns cached JWT if exp > now+300s, else mints
- mint_anonymous_token(): fetches API key, posts signUp with
Origin/Referer headers, validates iss + exp on the returned JWT
- SwiftlyAuthMintError surfaces verbatim to ScrapeLog.error_message
- Process-local cache only; threading.Lock around mutate
Tests: 4 unit tests covering fresh mint, cache hit, near-expiry
re-mint, and Firebase non-200. Full suite: 92/92 green.
Spec: docs/specs/2026-05-06-swiftly-token-auto-mint.md
Wiring into lucky_ca_scraper deferred to AM-2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Breaks the auto-mint spec into 6 ordered, sized tasks with an explicit
halt-for-approval boundary at AM-2 (live scrape verification before
removing the env var). Restates the verified prerequisites (config.json
publicly readable; Firebase signUp returns valid JWT with proper headers;
Swiftly accepts the minted token) so a fresh agent doesn't have to
re-discover them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Discovery: luckysupermarkets.com/config.json is publicly readable and
exposes firebaseApiKey. With proper Origin/Referer headers, Firebase
Identity Toolkit's anonymous-signup REST endpoint mints the same JWT
shape (iss=swiftly-lu-prod, aud=swiftly-lu-prod, anon provider, 3600s
TTL) that Swiftly accepts. Verified end-to-end on 2026-05-06.
This eliminates the manual hourly token-capture toil and supersedes
the seleniumbase-based scripts/refresh_swiftly_token.py (commit
ccfb38a) which had partial UI selector issues.
- New spec: docs/specs/2026-05-06-swiftly-token-auto-mint.md
- HANDOFF.md TL;DR refreshed (Phase 9 shipped); caveat #2 + #3
rewritten to point to the auto-mint redesign; suggested-next-move
reordered to put the redesign first
- ORIENTATION.md env-var section flags SWIFTLY_BEARER_TOKEN as
scheduled-for-removal; "Where to look" lists both specs;
last-updated footer refreshed
Implementation deferred — this commit captures the design and routing
only. Estimated 2-3 hours of focused work to ship per the spec.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drives luckysupermarkets.com in stealth CDP mode: opens the store
locator, types the zip code, clicks the target store, then triggers a
category page navigation. A fetch + XHR interceptor (installed via JS)
captures the first Authorization header sent to a Swiftly host. The
captured JWT is validated (iss + exp), then written into the env file.
Runs on the host (not docker) since seleniumbase needs a real Chrome.
Defaults to .env.test, headless, zip 94806, store 757. Flags:
--debug visible Chrome window
--restart-backend rerun docker compose to pick up the new token
--env-file PATH override target env file
--zip / --store override location
Selectors are intentionally JS-based and tolerant of UI changes
(querySelectorAll fallthrough by attribute heuristics + textContent
substring match) so first-attempt failures degrade to clear errors
rather than silent breakage.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>