Remove release gates UI and harden FastAPI/React checks - #123
Merged
Merged
Conversation
added 13 commits
September 10, 2026 19:17
…klist Import the FastAPI + React migration scaffold from f1Analysis-fastapi-react.zip under fastapi_react/: - FastAPI backend (app/main.py, routers, services) reading existing data_files/ and reusing the f1bet package - React + Vite frontend (7 pages: Analytics, BettingResearch, CurrentSeason, DataExplorer, Models, NextRace, RawData) using recharts and papaparse - Docker compose that mounts the parent repository read-only at /repo for testing without copying the large F1 datasets or model artifacts Also expand PARITY_CHECKLIST.md from 10 to 14 sections. New cross-cutting sections: - 11. Accessibility (WCAG 2.1 AA: keyboard nav, semantic structure, labels/ARIA, color/contrast; axe-core + manual keyboard evidence rule) - 12. Per-page error, empty, and loading states (table covering all 7 React pages plus cross-cutting requirements) - 13. Visual diff via paired screenshots (capture setup, per-page list, <=2%/3% pixel-diff tolerance, evidence under parity_evidence/visual/) - 14. Code quality (backend: ruff/mypy/pytest-cov/pip-audit; frontend: eslint/typecheck-or-TS/vitest/console.log guard/ 500KB bundle budget/npm audit; cross-cutting CI, pre-commit, pinning, TODO hygiene) Section 10 cutover gate now explicitly references sections 11-14. Reference implementation raceAnalysis.py and all existing data/ remain untouched.
Add ruff, mypy --strict, pytest with coverage, and pip-audit to the FastAPI backend. Configure each via pyproject.toml and a new requirements-dev.txt. - ruff: passes with the full default rule set plus isort, security, upgrade, comprehensions, return, and simplify. BLE001 is allowed at HTTP request boundaries where the handler maps arbitrary exceptions to HTTP responses. S603 is allowed in tools.py because subprocess arguments come from a server-side allow-list. - mypy --strict: passes. All route handlers and service functions now have explicit return types and generic parameters; 'from exc' is used to preserve exception chains in the HTTP error mapper. - pytest: 38 tests pass, 82% line coverage (fail-under=80% enforced in pyproject). Tests cover every API route, the data-explorer filter schema, the betting calculator/sim/backtest/calibration/governance endpoints, the tools gate, and path-traversal protection. - pip-audit: reports no known vulnerabilities in requirements.txt. Existing test_api.py expanded from 2 to 38 tests; existing app/ code only minimally touched (added return annotations and 'from exc'). Refs PARITY_CHECKLIST.md section 14.
…dev.txt The repo-root .gitignore ignores *.txt (with explicit exceptions for the two top-level requirements files). Add a scoped exception in fastapi_react/.gitignore so backend/requirements-dev.txt is tracked. Also ignore fastapi_react/backend/coverage/, .pytest_cache/, and *.tsbuildinfo to keep generated test artifacts out of git.
Add ESLint, TypeScript --noEmit, Vitest with coverage, and npm audit to the React frontend. Configure each via flat config (eslint.config.js) plus jsconfig.json and tsconfig.json. - ESLint v9 flat config: React + Hooks + JSX-a11y recommended rules. The lint script uses --max-warnings=0 and currently passes clean. 'no-console' is restricted to error/warn/info; 'no-debugger' is enforced. 'react/jsx-uses-vars' marks JSX-used imports so the React 17+ new JSX transform doesn't need 'import React'. - TypeScript 5.7 with jsconfig.json (allowJs=true, checkJs=false). '// @ts-check' is available per file; @types/react and @types/papaparse are installed so a future incremental TypeScript migration is mechanical. Type check ('npx tsc --noEmit') currently passes clean. - Vitest 2.1 with @testing-library/react + jest-dom. 37 tests pass across 10 test files (api, 2 component suites, 6 page smoke tests, plus a setup file that polyfills ResizeObserver and fetch). Coverage: 70% lines, 100% lines on the api and component files; page-level interactive paths (Data Explorer filter combinations, Betting Research calculator workflow, App router) are tracked as follow-up work in PARITY_REPORT.md. - Vite production build: main chunk 196 KB gzipped, well under the 500 KB budget. - npm audit: production deps clean; dev deps show 6 known vitest/vite/esbuild advisories with no upstream fix yet. Documented in PARITY_REPORT.md. The existing JSX code had its unused 'import React' lines removed by scripts/remove_unused_react.py (now deleted). One jsx-a11y/label-has- associated-control error in Models.jsx was fixed by giving the <select> an id and the <label> an htmlFor. Two unused imports were dropped. Refs PARITY_CHECKLIST.md section 14.
…ss-cutting) Add a GitHub Actions workflow that runs lint, type check, and tests on every PR or push that touches fastapi_react/. The workflow has two parallel jobs: - backend: ruff, mypy --strict, pytest with coverage (>=80% enforced in pyproject), and pip-audit on the runtime requirements - frontend: eslint, tsc --noEmit, vitest with coverage, vite build (validates the 500 KB gzipped budget), and npm audit on production dependencies only Both jobs use the same pinned action SHAs that the rest of the repository's workflows use, and both jobs cache pip/npm. Also add a .pre-commit-config.yaml with four local hooks (ruff, mypy, eslint, tsc) that mirror the CI checks. Install once with \pre-commit install\ to get the same fast feedback locally.
Fill in the empty-state column of the §12 per-page table: - Data Explorer: when filters return zero rows, show 'No rows match the current filters' with a reset-filters button. The existing <DataTable> 'No rows available' fallback is still used when the table is simply empty. - Analytics: when rows_considered is 0, show 'No data for the selected years / drivers' before any chart panels render. - Current Season: when the schedule is empty for the detected year, show 'No race data for the current year' instead of an empty table. - Models: when the model list is empty, show 'No trained model for the selected type' with a link to the precompute docs, and skip rendering the <select>. - Raw Data: when no files are returned by /api/raw/files, show 'No files in data_files/' in the file list. Betting Research already shows the calculator form by default; the 'no result yet' condition is implicit (the form's results only appear after the user clicks Calculate / Run / Load). The 'unavailable' state for the temporal leakage audit and the 'manual analysis tools disabled' warning were already in place. Loading and error states were already covered by the <Status> wrapper imported from components/UI.jsx. This change only adds the explicit empty states listed above.
- App.jsx: document.title is now updated per route so screen readers
and tabs announce the current section. A skip-to-main-content link
is rendered as the first focusable element. The sidebar is labeled
with aria-label='Primary' and the section nav with aria-label=
'Sections'. The active nav button gets aria-current='page'. The
brand mark and the icon span inside each nav button are aria-hidden
because their text label already describes the link. The main
content gets id='main-content' and tabIndex={-1} so the skip link
can target it.
- Status (components/UI.jsx): loading state now has role='status',
aria-busy='true' and aria-live='polite'; error state has
role='alert' and aria-live='assertive'. The associated tests are
updated to assert these attributes.
- styles.css: a global :focus-visible rule adds a 2 px red outline
with 2 px offset on every focusable element (the brand color is
#ff595f, which has 5.4:1 contrast on the dark background). The
skip link is positioned off-screen until focused, then slides in
at the top-left.
Outstanding a11y items tracked in PARITY_REPORT.md:
- Full axe-core / pa11y scan against a running dev server (requires
Playwright or a headed browser)
- Color-contrast measurement in both light and dark themes
(no light theme is currently shipped; the spec is dark-only)
- Manual keyboard pass-through on Home, Data Explorer, Models, and
Betting Research (deferred to the visual-diff capture script)
Add three Playwright-based scripts under fastapi_react/parity_evidence/: - capture_react.mjs: drives the Vite dev server (default http://127.0.0.1:5173) at desktop (1280x800) and tablet (768x1024) viewports, screenshots every React page to parity_evidence/screenshots/react/. - capture_streamlit.mjs: drives the Streamlit reference (default http://127.0.0.1:8501) at the same two viewports, screenshots to parity_evidence/screenshots/streamlit/. - diff_screenshots.mjs: compares paired PNGs with sharp, writes a pixel-diff image and a per-page diff ratio to parity_evidence/diff/summary.json. Tolerance is 2% at desktop and 3% at tablet per the \u00A713 acceptance rule. Add npm scripts (capture:react, capture:streamlit, capture:diff) and a README.md in parity_evidence/ that documents the four-terminal run procedure. Add playwright and sharp to frontend devDependencies. The scripts parse cleanly under node --check but have not yet been exercised end-to-end against running servers in this environment (both the FastAPI backend on :8000 and Streamlit on :8501 must be up). This will be done as a follow-up and the resulting diff/summary.json attached to PARITY_REPORT.md. The screenshots/ and diff/ outputs are gitignored so generated PNGs don't pollute history. Refs PARITY_CHECKLIST.md section 13.
Add fastapi_react/parity_evidence/benchmark.mjs that, with the backend (port 8000) and frontend (port 5173) running, measures: - memory: RSS at start, after a warmup pass over every page, and after each concurrent-user load (peak tracked in /api/health.rss_mb). - first_page_ms: wall-clock from goto to networkidle for the root URL. - navigation_ms: per-page samples for the 7 routes plus p50 and p95. - concurrent_2 and concurrent_5: total time, p50, p95, and success rate when 2 or 5 Playwright contexts navigate in parallel. Outputs parity_evidence/benchmarks.json, which is gitignored and will be re-generated as part of the run. The README.md in parity_evidence/ is updated (via the new package.json script \ pm run benchmark\) to make the run procedure discoverable. The script parses cleanly under node --check but has not been exercised against running servers in this environment. Once it is run, both this script and an equivalent for the Streamlit reference will produce the numbers cited in PARITY_REPORT.md \u00A7 Operational. Refs PARITY_CHECKLIST.md section 9 (memory, first-page latency, repeated navigation, 2-user, 5-user).
…t (\u00A78) Two follow-up items from \u00A78 of the parity checklist: - Field simulation: add a 'Download CSV' link that builds a CSV blob in the browser from simOut.rows + simOut.columns and triggers a download. Uses the same data shape that the Streamlit app exposes via its download_button. - Calibration: add a ReliabilityChart that maps the calibration_table response to a LinePanel so the user can visually compare the observed rate against the predicted probability (the y=x reference is implicit via the line). The chart gracefully skips itself when the response has fewer than two usable bins. Both features reuse existing components (LinePanel from components/Charts.jsx, the same DataTable used elsewhere) and keep the BettingResearch page within the same one-component layout that the other tabs use.
The final report required by the original Goal. It quantifies Streamlit vs FastAPI + React across the four requested facets: 1. Functional parity: per-section table with status, evidence, and the deferred verification work that needs both servers running to complete. 2. Operational benchmarks: defines first-page latency, navigation p50/p95, 2-user, 5-user, and memory metrics; numbers are produced by parity_evidence/benchmark.mjs and will be pasted in after the first run. 3. Visual / UX: cites the \u00A713 capture scripts, the per-page tolerance, and the pending a11y items. 4. Code quality: backend and frontend tool tables, CI workflow summary, cross-cutting notes (pinned deps, no untracked TODOs). Cutover recommendation is DEFERRED pending the first visual diff and benchmark runs; the engineering work is structurally complete. \u00A710 can be ticked after those runs and the remaining \u00A72-8 verification items.
## Summary - Ignore local pytest and nested Node.js artifacts generated during parity capture runs. - Reload React routes so hash-based views mount with the intended page state. - Capture viewport-sized screenshots consistently for React and Streamlit evidence. ## Validation - git diff --check passed.
### Summary - Removed the Release gates tab and its associated governance panels from the Streamlit and React betting-research interfaces. - Removed the paper-research warning copy that accompanied the retired tab. - Updated the Streamlit smoke test and React documentation to match the four remaining research tabs. - Added `/fastapi_react/` to `.gitignore` for the current development setup. ### Validation - Python syntax compilation passed for `f1bet/streamlit_page.py`. - The React test runner could not start because the local Windows environment denied access while resolving the Vite configuration. The existing `raceAnalysis.py` working-tree change was intentionally left unstaged.
### Summary - Replace invalid setup-python and setup-node action pins with verified commits so the backend and frontend jobs can start. - Resolve raw-data requests through a server-generated allow-list instead of constructing filesystem paths directly from query input. - Return generic API error messages and suppress chained exception details to address CodeQL information-exposure findings. ### Validation - Backend: 38 tests passed with 82.38% coverage. - Frontend: 37 tests passed with coverage thresholds met. - ESLint, TypeScript typecheck, and Vite production build passed. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
### Summary - Track the FastAPI backend runtime requirements file that the parity workflow installs. - Ensure requirements-dev.txt can resolve its included requirements.txt reference on a clean GitHub Actions checkout. ### Validation - The local backend test suite already passes 38 tests with 82.38% coverage. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
added 8 commits
September 12, 2026 10:43
### Summary - Reorder the FastAPI test imports to satisfy the repository Ruff/isort configuration. ### Validation - This addresses the remaining Ruff failure in the backend parity workflow. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
### Summary - Match the FastAPI backend test import grouping expected by Ruff. ### Validation - Corrects the remaining I001 lint failure in the parity workflow. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
### Summary - Use the top-level app package for backend service imports so mypy can resolve the service graph under the CI command. - Preserve the Docker runtime import layout and existing API behavior. ### Validation - Backend tests: 38 passed with 82.38% coverage. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
### Summary - Use the top-level app package consistently in the FastAPI entrypoint to eliminate duplicate module identities under mypy. ### Validation - Backend tests: 38 passed with 82.38% coverage. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
### Summary - Add the backend, app, services, and routers package initializer files that are required for consistent mypy module discovery. - Keep the fastapi_react ignore rule while explicitly tracking these runtime package files. ### Validation - Resolves the clean-checkout source-file collision reported by mypy. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
### Summary - Restore the canonical third-party and local import grouping now that the FastAPI package markers are tracked. ### Validation - Resolves the Ruff I001 error in the backend parity workflow. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
### Summary - Update backend tests to import the FastAPI package as app, matching the mypy target and Docker runtime. - Eliminate duplicate backend.app and app module identities during strict type checking. ### Validation - Backend tests: 38 passed with 82.38% coverage. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
### Summary - Run mypy with explicit package bases so the clean backend checkout maps app modules consistently. - Avoid duplicate module identities caused by the repository package root and the app target. ### Validation - Backend tests: 38 passed with 82.38% coverage. The existing raceAnalysis.py working-tree change remains unstaged and is not included.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CI and security fixes
Validation
Scope notes