# Audit Status — per docs/MASTER_AUDIT_PROMPT.md

**Last updated:** 2026-07-13 · **Auditor:** Claude (first-pass; independent human
review still required per the master prompt itself)

## A. Executive Deployment Decision

### ➜ APPROVED FOR PAPER TRADING ONLY

Evidence: no order-execution code paths exist anywhere in the codebase; the
only "trades" are database rows. Risk gating, auth, rate limiting, and
fail-closed production config are implemented and unit-tested. Everything
below must be resolved and independently verified before any restricted live
pilot.

## B. Risk Summary (initial, honest)

| Severity | Count | Notes |
|---|---|---|
| BLOCKER (for live) | 3 | B-1..B-3 — expected at this stage |
| CRITICAL | 2 | C-1, C-2 |
| HIGH | 5 | H-1..H-5 |
| MEDIUM | 6 | M-1..M-6 |
| Most audit phases | NOT TESTED | marked honestly, not assumed passed |

## C. Key Findings

### Blockers for any future live trading (not for paper use)
- **B-1 · No broker order/reconciliation layer.** By design (Phase 1). Live
  trading requires the full Phase 11 order-lifecycle work: idempotency,
  duplicate-order prevention, broker-authoritative reconciliation, kill
  switches. *None of this exists — live trading must remain impossible.*
- **B-2 · No independent validation of options math.** Black-Scholes
  implementation is unit-tested against itself, not against an independent
  reference library (audit Phase 6 requires independent verification).
- ~~**B-3 · No stale-data circuit breaker.**~~ **RESOLVED 2026-07-13:**
  `bars_are_fresh()` gate in the orchestrator skips any symbol whose latest
  bar exceeds `DATA_FRESHNESS_MAX_DAYS`; skips are logged as circuit-breaker
  events. Verified by `tests/test_risk_gates.py`.

### Critical
- **C-1 · Single-user trust model.** Auth exists (JWT) and the auth gate is
  non-bypassable middleware, but there is no MFA, no roles, no tenant
  isolation. Fine for personal use; must be rebuilt for any multi-user phase
  (Phase 10).
- **C-2 · Secrets in plaintext `.env`.** Acceptable on a personal machine;
  production requires a secrets manager or at minimum tight file permissions
  + rotation. SMTP password and API keys currently live in `backend/.env`.
  *Note: a Gmail app password was also shared in a chat conversation — rotate
  it before any deployment.*

### High
- ~~**H-1** Backtest excludes commissions, slippage, and spread costs.~~
  **RESOLVED 2026-07-13:** backtests model slippage (bps, both ways) and
  per-share commissions; paper-trade entries also pay adverse slippage.
  Verified by `tests/test_risk_gates.py::test_costs_reduce_backtest_results`.
- **H-2** Learning loop trains on its own recommendations' outcomes — the
  exact feedback loop Phase 9 warns about. Mitigation: it only *calibrates
  probability downward/upward from evidence* and cannot change risk limits or
  position sizes; cap remains hard-coded. Keep it this way.
- **H-3** Mock options chains when Tradier is absent — contract picks are not
  actionable until real chains are connected; UI/emails don't currently label
  which source produced the contract.
- **H-4** No centralized/tamper-resistant logging; logs go to console only
  (Phase 15).
- **H-5** LLM sentiment output is schema-parsed and range-clamped, but the
  prompt content includes only self-generated price context today; when real
  headlines are added (Phase 2 full), indirect prompt-injection review is
  required before trusting output (Phase 4).

### Medium
- **M-1** No account lockout/backoff on repeated login failures.
- **M-2** No HTTPS locally (fine); production TLS depends on correct nginx setup.
- **M-3** SQLite in dev has no FK enforcement; MySQL cutover needs migration testing.
- **M-4** No monitoring/alerting for scheduler failures beyond log lines.
- **M-5** Paper-trade fills assume perfect execution at signal entry price.
- **M-6** Dependency versions are ranged, not pinned; no lockfile for backend.

## D. What IS implemented and tested (evidence)

**Added 2026-07-13 (audit-driven safety wave, all in `tests/test_risk_gates.py`):**
- Stale-data circuit breaker (Phase 5) — resolves B-3
- Backtest + paper-fill cost modeling (Phase 8) — resolves H-1
- Market regime detection: swing strategy disabled in chop; position sizing
  halved in high-volatility regimes (Phase 7: restricted strategies)
- Earnings blackout guard (Phase 7: earnings-event restrictions) — enabled
  with a Finnhub key; explicitly reported as disabled otherwise (never
  silently assumed)
- Position management: breakeven trail at +1R, scale-out at +1.5R, time stop
  after 10 days — centralized in `services/position_mgmt.py`, applied on
  every mark-to-market, cannot be bypassed by any agent


- Non-bypassable risk gating: every signal passes RiskManagerAgent; rejected
  setups cannot be paper-traded (HTTP 400) — `tests/test_api.py`.
- Position sizing capped at 1% equity risk/trade, 6% daily — `tests/test_agents.py`.
- Fail-closed production boot (weak secret or missing auth → refuses to start)
  — `tests/test_security.py`.
- Auth gate middleware on all `/api` routes — `tests/test_security.py`.
- Rate limiting + security headers — `app/security.py`.
- AI probability calibration is bounded (5–90%), blend-limited (35%), and
  cannot alter risk rules — `tests/test_backtest_learning.py`.
- Walk-forward backtest has no look-ahead (entries at next bar open) —
  `app/services/backtest.py`, `tests/test_backtest_learning.py`.
- Signals from stale scans are labeled by creation time; official SIP data
  feed with explicit fallback logging.

## E. Remediation Plan

**Before external beta (if ever multi-user):** MFA, roles, tenant isolation,
secrets manager, centralized logging, account lockout, dependency pinning.

**Before restricted live pilot:** B-1 (full broker/order lifecycle + kill
switches), B-2 (independent options-math validation), B-3 (stale-data
lockout), commissions/slippage in backtests, incident runbook, independent
security test, legal/compliance review by qualified counsel.

**Ongoing (paper phase):** accumulate ≥3 months of paper results; monitor
calibration table monthly; tune swing parameters only with documented
before/after backtests.

## F. Maturity Assessment (per docs/QA_AUDIT_PROMPTS.md, Prompt 3)

Scored 1–10, honestly. "Production-grade" for a paper-trading research tool
differs from live-trading grade — both shown.

| Dimension | Score | Rationale |
|---|---|---|
| Architecture | 8 | Clean agent/service separation, env-tunable, mock-first; single-process scheduler limits scale |
| Reliability | 7 | Every vendor call degrades gracefully; no retry queues or multi-process resilience |
| Security | 6 | Auth gate, rate limits, fail-closed prod boot; single-user model, no MFA, plaintext .env |
| Testing | 7 | ~75 tests incl. safety gates; no load/chaos/E2E-browser tests |
| AI Quality | 6 | Calibrated, bounded, explainable, deterministic briefing; sentiment mock unless keyed, single-model ensemble |
| Data Quality | 6 | Freshness circuit breaker, SIP feed, feed fallback logging; no cross-source reconciliation or corporate-action handling |
| Observability | 4 | Console logs + status endpoints only — weakest area (H-4) |
| Maintainability | 8 | Documented (PROJECT_DOCUMENTATION.md), typed, conventional, additive migrations |

**Paper-trading readiness: adequate today.** Priority order to raise scores:
observability (centralized logs + scheduler alerting) → data reconciliation
→ MFA/secrets management → load testing. Live-trading readiness remains
gated by AUDIT blockers B-1/B-2 regardless of scores.

## G. Standing Rule (from the master prompt)

This application must not approve itself through Claude's review alone.
Final approval for anything beyond paper trading requires independent
security testing, broker sandbox validation, and review by qualified
securities counsel.
