From 591d36de2f28222f322ce9eec85555fc021b143f Mon Sep 17 00:00:00 2001 From: Daniele De Dominicis Date: Sun, 23 Aug 2026 07:28:47 +0000 Subject: [PATCH] Badges, an enforced coverage floor, and two exports that were not API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Presentation, in the three places a visitor actually looks. **Badges.** CI was alone; now the licence and the four versions that decide whether somebody cares about the repository at all sit beside it, each linked to the file that states the version rather than to a vendor's home page. Six is a row, not a wall. No test-count badge and no coverage badge on purpose: both are numbers that rot, and this repository has already had two rounds of stale counts corrected. **The coverage floor is enforced instead.** CI ran `--cov` and printed the result, which nothing could fail on. It now runs `--cov-fail-under=90`, so the green CI badge means the floor held rather than merely that the suite passed. Actual coverage is 96.46%, leaving headroom for a change to be mid-flight; the lowest modules are database.py at 76% and health.py at 79%, both failure paths. Checked that the gate bites, not just that it passes: pytest exits 1 at a 99% floor and 0 at 90. **The opening says what the project refuses to do.** "No external services" was abstract; the absent map tile server is concrete, and it is the line that separates this from every other training log. Code: `IMPLAUSIBLE_SPEED_MS` and `GRID_POINTS` were exported from utils/track.js and imported by nobody. Both are used only inside their own module, so the export was speculative API surface. Now plain constants. Nothing else was found to delete. No orphan modules, no unused CSS, no dead backend definitions, no unreferenced images, every declared dependency imported, and the four empty __init__.py files are package markers rather than litter. A CHANGELOG was considered and left out: with no tags and no releases it would restate the git log and the feature list, and the question it would answer — whether a pull needs a backfill — the Updating section already answers. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019mNxXmXqwMZf6MG8PoWbq4 --- .github/workflows/ci.yml | 6 +++++- README.md | 11 +++++++++-- frontend/src/utils/track.js | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b77cde6..5a9cd5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,8 +41,12 @@ jobs: - name: Format run: ruff format --check . + # The floor is enforced rather than advertised: a number in the README + # goes stale the first time somebody adds a module and forgets, and a + # badge only reports what already happened. Actual coverage is 96%, so + # 90 leaves headroom for a change to be in progress without blocking it. - name: Test - run: pytest --cov=app --cov-report=term-missing + run: pytest --cov=app --cov-report=term-missing --cov-fail-under=90 migrations: name: Migrations on PostgreSQL diff --git a/README.md b/README.md index bfbcd68..a019629 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,20 @@ # Activity Hub [![CI](https://github.com/Danielededo/activity-hub/actions/workflows/ci.yml/badge.svg)](https://github.com/Danielededo/activity-hub/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![Python 3.11](https://img.shields.io/badge/Python-3.11-3776AB?logo=python&logoColor=white)](backend/requirements.txt) +[![FastAPI](https://img.shields.io/badge/FastAPI-0.115-009688?logo=fastapi&logoColor=white)](backend/requirements.txt) +[![React 19](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=black)](frontend/package.json) +[![PostgreSQL 16](https://img.shields.io/badge/PostgreSQL-16-4169E1?logo=postgresql&logoColor=white)](docker-compose.yml) Self-hosted training log. Feed it the FIT, TCX and GPX files your watch or Strava exports, and get your history back as numbers and charts that stay on your own machine. One user, no accounts, no external services, no telemetry. Units are metric -throughout. +throughout. There is no map tile server either: drawing your routes over a +borrowed basemap would mean telling a stranger where you exercise, which is +the opposite of the point. @@ -294,7 +301,7 @@ PostgreSQL. | Job | What it proves | | --- | --- | -| Lint and test | `ruff check` and `ruff format` are clean and the backend suite passes | +| Lint and test | `ruff check` and `ruff format` are clean, the backend suite passes, and coverage is at or above 90% — the run fails below it | | Migrations on PostgreSQL | The schema applies to a real PostgreSQL 16, `alembic check` finds no drift from the models, and the downgrade path works | | Frontend lint, test and build | ESLint is clean, the jsdom suite passes, and the bundle builds | | Images and compose stack | Both images build, the stack comes up health-gated, and a profile plus an upload round-trips through the dashboard's own origin | diff --git a/frontend/src/utils/track.js b/frontend/src/utils/track.js index d50378f..dba3678 100644 --- a/frontend/src/utils/track.js +++ b/frontend/src/utils/track.js @@ -15,7 +15,7 @@ import { haversineDistance } from './geo' * consecutive ones can be hundreds of metres apart quite legitimately, and a * distance ceiling would throw away real riding at a high stride. */ -export const IMPLAUSIBLE_SPEED_MS = 120_000 / 3_600 +const IMPLAUSIBLE_SPEED_MS = 120_000 / 3_600 /** * Cumulative metres and seconds along a track, and the speed of each hop. @@ -79,7 +79,7 @@ export function distanceSeries(samples) { } /** How many points a comparison grid gets. More than any chart has pixels for. */ -export const GRID_POINTS = 240 +const GRID_POINTS = 240 /** * Two or more distance series resampled onto one shared grid.