Banker's Wrapped v1.8.0
All five v1.7.0-roadmap workstreams shipped (the v1.7.0 tag marks the roadmap itself; this release is the implementation). Coverage 98% (gate 80%), 135 tests.
Added
- WS-2 — B2 as source of truth (ADR-008): sessions now survive Railway redeploys.
session_metadata.jsonis a self-contained manifest — fullInsightsSummarysnapshot,status,processing_time_ms,models_used, and every B2 key (including its own); uploaded last so itsb2_keysmap is complete.- Flat
index/{session_id}.jsonobject written to B2 at pipeline start mapssession_id → user_id(share URLs stay clean). GET /recap/{id}andGET /recap/{id}/downloadfall back to the B2 manifest when the SQLite row is missing; presigned URLs are re-minted per request. SQLite is now a cache (ADR-004 amended).B2Client: newdownload_json,exists,session_index_keyhelpers.
- WS-3 — B2 lifecycle + artifact integrity (ADR-009):
generation.jsonnow carries anartifactslist — SHA-256 + size for each of the 12 content artifacts uploaded per session, computed from the exact bytes stored.- Bucket retention rule committed as
infra/b2-lifecycle.json(45-day expiry — outlives the Aug 5–11 judging window for all hackathon sessions) and applied idempotently byscripts/apply_b2_lifecycle.py.
- WS-1 — Genblaze LLM routing (ADR-007): narrative script generation now runs through Genblaze SDK chat with provider-prefixed backend models, making 3 of 4 AI steps Genblaze-orchestrated.
GenblazeClient.generate_script_text()— same non-blocking (asyncio.to_thread) + tenacity-retry pattern as image gen; returns text + provenance (provider, model, latency, retries, tokens,cost_usd).NarrativeAgentis SDK-only for script generation (no direct provider path in-agent).NARRATIVE_PROVIDERselects backend model mode via SDK (genblazemodel id vsnvidia-nim/<model>), with schema retry on invalid JSON.generation.jsoncarriesllmprovenance andmodels_used.llmreflects the backend model used.- Default narrative provider mode is now
genblaze, withGMI_CHAT_MODELdefaulting tonvidia-nim/meta/llama-3.1-70b-instructfor NVIDIA NIM via SDK.
- WS-4 — Plaid sandbox connector (ADR-010): optional "Connect a bank (sandbox)" ingestion path.
backend/ingest/plaid_connector.py: Plaid REST via httpx (async; noplaid-pythondep) — link token, public-token exchange, paginated/transactions/get, category mapping to our taxonomy, sign-convention flip (Plaid outflow-positive → ours income-positive).- Plaid transactions are serialised back to our CSV schema and fed to the unchanged pipeline — identical B2 artifact trail,
DocumentAgentrevalidates everything. POST /api/v1/plaid/link-token+POST /api/v1/plaid/exchange(rate-limited 5/hr/IP, same SSE progress). Feature-flagged: withoutPLAID_CLIENT_ID/PLAID_SECRETthe routes answer 404 and the app is unchanged;/healthnow reportsplaid_enabled.- Frontend: "🏦 Connect a bank (sandbox)" button (Plaid Link via CDN, loaded on demand), shown only when the backend reports Plaid enabled.
- Test hermeticity fix:
test_settingsnow explicitly blanks Plaid keys so a developer's real.envcan never trigger live calls in the suite.
- WS-5 — hardening + polish (prompt 16):
- ADR-011: the v1.6.0 compositor + non-blocking-loop redesign recorded as a decision record.
tests/load/k6_smoke.js: manual k6 smoke test — /health p95 < 500 ms under 20 VUs; rate limiter must 429 (never 5xx) under /generate abuse.- Narrative prompt: Scene 4 advice must name the actual top spending category and cite a concrete number from the data (no generic advice).
Fixed
- Removed aspirational PostgreSQL claims (no
DATABASE_URLcode path exists): B2 is the source of truth, SQLite is a cache, Postgres stays a documented scale path only. - B2 lifecycle rule shape: the S3-compatible API requires the
Daysrule paired with anExpiredObjectDeleteMarker_markerrule (same prefix). /healthnow reports the real app version (was hardcoded1.0.0) andplaid_enabled.
Changed
- Coverage 93% → 98% (135 tests): SSE progress stream, B2 helper, Plaid HTTP/pagination/CSV-quoting, ffprobe, provider-init, and B2-fallback edge cases now covered.