## Backend closure review: findings ### P1 — Dry-run endpoint bypasses source restrictions and permits remote provider/quota consumption - `src/jarvis_finance/api/main.py:29,74-76` - Adding `/api/market/equity/update-quotes/dry-run` to `READ_ONLY_POST_PATHS` bypasses `is_write_request_allowed()` entirely. - A simulated non-loopback client received **200** and invoked the provider while the ordinary apply endpoint correctly returned **403**. - One request can cause up to 500 instruments × 4 attempts; concurrent unauthenticated requests could consume provider quota or create outbound-load denial of service. CORS does not protect against non-browser clients. - Probe: `remote_dry_run_status=200`, `provider_calls=1`, `remote_apply_status=403`. - Recommendation: retain forced `dry_run=True`, but enforce an authenticated/trusted-source or local/Tailnet policy separately from the DB-write gate, plus request-level throttling. ### P2 — The “full refresh” backend endpoint does not enforce full scope - `src/jarvis_finance/api/routers/market.py:38-41` - It forces `dry_run=True` and `only_missing=False`, but preserves caller-controlled `limit`. - Thus `{limit: 1}` calls only one eligible provider despite the route docstring promising “every eligible provider.” - The frontend currently mitigates this by sending 500 and refusing confirmation when `limit_applied`, but the backend contract itself is under-scopable. - Recommendation: force the endpoint’s limit to the supported full-scope ceiling or rename/document it as bounded preview and require consumers to validate `limit_applied`. ### P2 — Failed provider results claim a price date that was never delivered - `src/jarvis_finance/services/market_service.py:217,245-253,329` - `ts` falls back to the requested target date even when the quote has no price/timestamp. Consequently, failed items return `price_date=`. - Probe: a `price_missing` result reported `price_date: "2026-05-18"`. - This can mislead downstream consumers into treating the requested date as provider evidence. - Recommendation: expose `fetched_at`/result `price_date` only when the provider supplied a timestamp or a valid price was accepted. ### P2 — Apply can perform valuation persistence while reporting `persistence_performed=false` - `src/jarvis_finance/services/market_service.py:333-366` - If existing cached prices already provide complete coverage but every forced refresh fails, `valued == coverage_total` still triggers `run_daily_market_valuation()`. - Because `updated == 0`, the response reports `persistence_performed=false` and `complete=true` despite errors and valuation persistence. - Focused probe confirmed: `updated=0`, `skipped=1`, `errors=['missing']`, `complete=true`, valuation called and wrote, `persistence_performed=false`. - Recommendation: distinguish quote persistence from valuation persistence explicitly, and distinguish coverage completeness from refresh-run success. ## Verification performed - Focused backend file: **13 passed**. - Synthetic dry-run probe: - complete SQLite dump unchanged; - forced `dry_run` and `only_missing=False` worked; - retry counts were correct; - partial result counts and date range were correct. - Apply probe: - 2 successful quotes persisted to both `market_prices` and `equity_price_points`; - one failure remained partial; - retry/provider-call counts were correct. - `git diff --check`: passed. - No full suites run. ## Workspace impact - **Files created or modified by reviewer:** none. - Existing worktree modifications remained unchanged. - Initial `.venv/bin/python` path was absent; focused tests were rerun successfully with `PYTHONPATH=src python3 -m pytest`.