Skip to content

Remove release gates UI and harden FastAPI/React checks - #123

Merged
gmalbert merged 23 commits into
mainfrom
codex/data-filters
Sep 12, 2026
Merged

gmalbert merged 23 commits into
mainfrom
codex/data-filters

Conversation

@gmalbert

@gmalbert gmalbert commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • Remove the Release gates tab from both the Streamlit and React betting-research interfaces.
  • Remove the associated governance panels and obsolete warning copy.
  • Update the Streamlit smoke test and React documentation to reflect the four remaining tabs.
  • Add /fastapi_react/ to .gitignore for the current development setup.

CI and security fixes

  • Replace invalid setup-python and setup-node action pins with verified commits so the backend and frontend jobs can start.
  • Track the backend runtime requirements and package initializer files required by a clean checkout, despite the temporary fastapi_react ignore rule.
  • Use canonical app imports and explicit mypy package discovery so strict type checking has one module identity.
  • 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

  • GitHub Actions backend checks passed: Ruff, strict mypy, 38 pytest tests, coverage, and pip-audit.
  • GitHub Actions frontend checks passed: ESLint, TypeScript, 37 Vitest tests with coverage, Vite build, and production dependency audit.
  • CodeQL, dependency review, deprecated API checks, offline release checks, and Streamlit smoke checks passed.

Scope notes

  • The backend governance endpoint remains available for compatibility but is no longer exposed as a UI tab.
  • The existing raceAnalysis.py working-tree change is intentionally not included in this PR.

Greg Albert 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.
Comment thread fastapi_react/backend/app/main.py Fixed
Comment thread fastapi_react/backend/app/services/data.py Fixed
Comment thread fastapi_react/backend/app/services/data.py Fixed
Comment thread fastapi_react/backend/app/services/data.py Fixed
Comment thread fastapi_react/backend/app/services/data.py Fixed
Comment thread fastapi_react/backend/app/services/data.py Fixed
Comment thread fastapi_react/backend/app/services/data.py Fixed
Comment thread fastapi_react/backend/app/main.py Fixed
### 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.
@gmalbert gmalbert changed the title Remove release gates tab from betting research UI Remove release gates UI and harden parity checks Sep 12, 2026
### 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.
Comment thread fastapi_react/backend/app/main.py Fixed
Greg Albert 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.
@gmalbert gmalbert changed the title Remove release gates UI and harden parity checks Remove release gates UI and harden FastAPI/React checks Sep 12, 2026
@gmalbert
gmalbert merged commit 0d616b3 into main Sep 12, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants