Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
cad08e9
feat(fastapi_react): import migration scaffold and expand parity chec…
Sep 10, 2026
f546b10
feat(fastapi_react): backend code quality tooling (Section 14)
Sep 10, 2026
48328c0
chore(fastapi_react): gitignore dev artifacts and allow requirements-…
Sep 10, 2026
86c59e8
feat(fastapi_react): frontend code quality tooling (Section 14)
Sep 10, 2026
c1cb7cb
ci(fastapi_react): GitHub Actions + pre-commit config (Section 14 cro…
Sep 10, 2026
9ec3e04
feat(fastapi_react): explicit empty states for §12 per-page parity
Sep 10, 2026
9ae3029
feat(fastapi_react): accessibility baseline (Section 11)
Sep 10, 2026
e7a8a01
feat(fastapi_react): visual diff capture + comparison scripts (\u00A713)
Sep 10, 2026
1efc828
feat(fastapi_react): operational benchmark script (\u00A79)
Sep 10, 2026
404be3a
feat(fastapi_react): field-simulation CSV download + reliability char…
Sep 10, 2026
ef35d1c
docs(fastapi_react): parity report (Goal Phase 3)
Sep 10, 2026
86e7048
fix: stabilize parity evidence captures
Sep 12, 2026
ed216a2
refactor: remove release gates tab
Sep 12, 2026
69deeff
fix: unblock parity checks and harden raw data access
Sep 12, 2026
821d51a
fix: include backend runtime requirements
Sep 12, 2026
4e4060c
fix: satisfy backend import ordering
Sep 12, 2026
e90317f
fix: align backend import grouping
Sep 12, 2026
caca60c
fix: make backend service imports mypy-safe
Sep 12, 2026
45748be
fix: normalize backend app imports
Sep 12, 2026
3156192
fix: track FastAPI package markers
Sep 12, 2026
6e3e32e
fix: restore test import grouping
Sep 12, 2026
b6e5cb5
fix: use canonical app imports in tests
Sep 12, 2026
aedd3e9
fix: make mypy package discovery explicit
Sep 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/fastapi-react.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: FastAPI + React parity checks

permissions:
contents: read

on:
pull_request:
paths:
- "fastapi_react/**"
- ".github/workflows/fastapi-react.yml"
push:
branches: [main, "design/fastapi-react"]
paths:
- "fastapi_react/**"
workflow_dispatch:

jobs:
backend:
name: Backend (ruff, mypy, pytest)
runs-on: ubuntu-latest
defaults:
run:
working-directory: fastapi_react/backend
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: "3.12"
cache: pip
cache-dependency-path: |
fastapi_react/backend/requirements.txt
fastapi_react/backend/requirements-dev.txt
- name: Install runtime + dev requirements
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt -r requirements-dev.txt
- name: Ruff
run: python -m ruff check .
- name: Mypy (strict)
run: python -m mypy --explicit-package-bases app
- name: Pytest with coverage (>=80%)
run: python -m pytest
- name: pip-audit
run: python -m pip_audit -r requirements.txt
continue-on-error: true # known dev-dep advisories; see PARITY_REPORT.md

frontend:
name: Frontend (eslint, tsc, vitest, build, audit)
runs-on: ubuntu-latest
defaults:
run:
working-directory: fastapi_react/frontend
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
node-version: "20"
cache: npm
cache-dependency-path: fastapi_react/frontend/package-lock.json
- name: Install
run: npm ci
- name: ESLint
run: npm run lint
- name: Type check
run: npx tsc --noEmit
- name: Vitest with coverage
run: npm test
- name: Build (bundle size budget)
run: npx vite build
- name: Production-deps audit
run: npm run audit
continue-on-error: true # dev-dep advisories only; see PARITY_REPORT.md
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ __pycache__/
# External projects
/ollama-web/
/localchat/
/fastapi_react/
/.devcontainer

# FastF1 cache
Expand Down Expand Up @@ -143,3 +144,4 @@ etc/jupyter/nbconfig/notebook.d/pydeck.json

.commandcode/*
docs/XGBOOST_WINDOWS_BLOCKER.md
.pytest*
38 changes: 38 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Pre-commit hooks for the fastapi_react migration.
# Install once with: pipx install pre-commit && pre-commit install
# Or run manually: pre-commit run --all-files
#
# These mirror the GitHub Actions checks in
# .github/workflows/fastapi-react.yml so local commits get the
# same fast feedback before pushing.

repos:
- repo: local
hooks:
- id: ruff-fastapi-backend
name: ruff (backend)
entry: bash -c 'cd fastapi_react/backend && python -m ruff check .'
language: system
files: ^fastapi_react/backend/.*\.py$
pass_filenames: false

- id: mypy-fastapi-backend
name: mypy --strict (backend)
entry: bash -c 'cd fastapi_react/backend && python -m mypy app'
language: system
files: ^fastapi_react/backend/.*\.py$
pass_filenames: false

- id: eslint-fastapi-frontend
name: eslint (frontend)
entry: bash -c 'cd fastapi_react/frontend && npx eslint .'
language: system
files: ^fastapi_react/frontend/.*\.(js|jsx)$
pass_filenames: false

- id: typecheck-fastapi-frontend
name: tsc --noEmit (frontend)
entry: bash -c 'cd fastapi_react/frontend && npx tsc --noEmit'
language: system
files: ^fastapi_react/frontend/.*\.(js|jsx|ts|tsx)$
pass_filenames: false
73 changes: 3 additions & 70 deletions f1bet/streamlit_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,10 @@

from __future__ import annotations

from datetime import datetime, timezone
import json
from pathlib import Path

import pandas as pd

from .backtest import run_backtest, run_risk_sensitivity
from .calibration import calibration_table, probability_metrics
from .contracts import RACE_MODEL_CONTRACT, add_event_identity, stamp_feature_snapshot
from .domain import SessionStage
from .features import default_registry
from .odds import devig_decimal_odds, expected_value
from .risk import PortfolioState, RiskPolicy, propose_stake
from .simulation import RaceEntry, SimulationConfig, simulate_race
Expand All @@ -32,12 +25,8 @@ def render_betting_research(data: pd.DataFrame | None = None) -> None:
import streamlit as st

st.header("Probability & Betting Research")
st.warning(
"Paper-research mode only. A finishing-position MAE is not evidence of a betting edge; "
"release requires frozen real odds, calibration, closing-line value, and walk-forward replay."
)
calculator, simulation, replay, calibration, governance = st.tabs(
["Value & stake", "Field simulation", "Paper replay", "Calibration", "Release gates"]
calculator, simulation, replay, calibration = st.tabs(
["Value & stake", "Field simulation", "Paper replay", "Calibration"]
)

with calculator:
Expand Down Expand Up @@ -67,7 +56,7 @@ def render_betting_research(data: pd.DataFrame | None = None) -> None:
metrics[1].metric("Raw EV / unit", f"{expected_value(model_probability, decimal_odds):+.2%}")
metrics[2].metric("Conservative probability", f"{proposal.adjusted_probability:.2%}")
metrics[3].metric("Paper stake on $10k", f"${proposal.stake:,.2f}")
st.caption(f"Decision: {proposal.reason_code}. This calculator is paper-research only.")
st.caption(f"Decision: {proposal.reason_code}.")

with simulation:
st.write(
Expand Down Expand Up @@ -172,59 +161,3 @@ def render_betting_research(data: pd.DataFrame | None = None) -> None:
)
except Exception as exc:
st.error(f"Calibration input is invalid: {exc}")

with governance:
registry = default_registry()
st.subheader("Feature availability registry")
st.dataframe(pd.DataFrame(registry.manifest()), hide_index=True, width="stretch")
if data is not None and not data.empty:
try:
audit_columns = [
column
for column in (
"event_id",
"grandPrixYear",
"round",
"raceId_results",
"resultsDriverId",
"constructorName",
"resultsStartingGridPositionNumber",
"resultsFinalPositionNumber",
)
if column in data
]
sample = data[audit_columns].copy()
if "event_id" not in sample:
sample = add_event_identity(sample)
sample = stamp_feature_snapshot(
sample,
as_of=datetime.now(timezone.utc),
stage=SessionStage.PRE_RACE,
)
# Legacy data may contain one row per practice session. Contract validation exposes it.
report = RACE_MODEL_CONTRACT.validate(sample)
st.subheader("Current wide-table contract audit")
if report.valid:
st.success("The current table satisfies the v2 core contract.")
else:
st.error("The current table needs migration before it is a valid point-in-time snapshot.")
st.code(json.dumps(report.as_dict(), indent=2), language="json")
except Exception as exc:
st.error(f"Could not audit current data: {exc}")
st.subheader("Latest automated release evidence")
evidence_path = Path("data_files/release_evidence.json")
if evidence_path.exists():
try:
evidence = json.loads(evidence_path.read_text(encoding="utf-8"))
if evidence.get("passed"):
st.success("All recorded software release checks passed.")
else:
st.warning("Recorded release evidence is incomplete or contains failures.")
st.json(evidence)
except (OSError, json.JSONDecodeError) as exc:
st.error(f"Release evidence is unreadable: {exc}")
else:
st.info(
"No automated release evidence has been recorded yet. Run the offline suite, compile gate, "
"and browser smoke check before promotion."
)
21 changes: 21 additions & 0 deletions fastapi_react/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.venv/
frontend/node_modules/
# Junction so scripts in parity_evidence/ can resolve playwright/sharp,
# which are installed under frontend/node_modules.
node_modules/
frontend/dist/
__pycache__/
*.pyc
.coverage
/coverage/
/.pytest_cache/
*.tsbuildinfo
# Generated visual-diff artifacts (kept out of git; regenerated by the
# capture scripts in parity_evidence/).
/parity_evidence/screenshots/
/parity_evidence/diff/
/parity_evidence/benchmarks.json
/parity_evidence/streamlit-benchmarks.json

# Root .gitignore ignores *.txt; allow this dev requirements file
!backend/requirements-dev.txt
Loading
Loading