Wielrenpoule
Menu

# Changelog

User-facing release notes for Wielrenpoule. Detailed UX phase history lives in [competition-shell-roadmap.md](./competition-shell-roadmap.md) and phase-specific docs under `docs/`.

---

Unreleased

  • **Pouleanalyse — primary/secondary + repetition** — maximaal twee zinnen (sterke primary, optionele secondary over een andere deelnemer/story). Soft repetition penalties over de laatste twee snapshots (tiers: vorige 25 / voorlaatste 12 / beide 35 / zelfde story +20); gerichte LEL hard-suppress blijft (`gap < 10`). Snapshots krijgen dual nullable provenance (`primary_*` / `secondary_*`); oude rijen blijven ongemoeid.
  • **Editorial analysis snapshots** — immutable stored paragraphs per pool and analysis stage; phased rollout via `EDITORIAL_SNAPSHOT_*` flags; backfill and reconcile commands; post-score creation after successful scoring
  • **Pouleanalyse — evolutionaire selectie** — behoudt de bestaande situation lottery en templatebibliotheek als baseline; sterke dagelijkse signalen (comeback, outlier-stijger/daler, leider loopt uit, groepsbeweging) overrulen alleen dan de loterij. Etappetype-fix: analyse-etappe i.p.v. bekeken etappe. Zie [ADR](./adr/pool-editorial-analysis-selection.md) en [vergelijking](./pool-editorial-analysis-comparison.md).
  • **Tournament forecast cache** — default TTL raised from 5 minutes to 24 hours so warm Analytics requests keep forecast simulation results across deploys and daily traffic.

---

v1.6.2 — Consolidated achievement display

Patch release grouping repeated current-pool achievements into a single badge with an occurrence counter.

  • **Achievement display** — repeated instances of the same achievement are shown as a single badge with a counter for how many times it was earned

---

v1.6.1 — Analytics movement polish, print reserve fix, and observability

Patch release improving the Analytics movement section, fixing printed stage predictions after reserve substitutions, and making pool analytics build metrics visible in production logs.

  • **Analytics risers & fallers** — compact stage overview table (newest first) with progressive disclosure after five stages; responsive mobile cards; green/red movement and rank transitions preserved
  • **Print predictions** — stage picks on the print overview now use the same reserve-resolution logic as the normal prediction and scoring views, so dropped-out riders are replaced by effective reserves when applicable
  • **Pool analytics metrics** — build-step timings and cache hits are written via `error_log()` at warning level so production Apache/PHP logs can capture them when enabled
  • **Analytics page performance** — pool analytics controller reuses the already-built page and chart data instead of building them twice per request

---

v1.6.0 — Competition Shell navigation and Insights

Feature release completing the Competition Shell UX refactor and promoting personal Insights to a primary shell tab.

  • **Competition Shell navigation** — primary tabs: Today · Predict · Standings · Summary · Analytics · Insights · More; EN **Summary** label on `/overview`; smart landing unchanged
  • **Summary page** — pool-level competition status, personal and pool snapshots, one contextual continuation link; dashboard hero and quick links removed
  • **Accessibility** — More submenu active destination styling, Predict/Classifications heading hierarchy, global nav landmark handling, nl_ams **De stand** tab label
  • **More menu** — stays closed on page load; active submenu link and More trigger styling without forcing the menu open
  • **Pool Insights** — personal playing-style analytics at `/pools/{slug}/insights` (rider contribution, prediction DNA, charts)
  • **Insights chart quality** — correct rider attribution labels and more reliable chart rendering on the Insights page
  • **Insights primary tab** — promoted from More after production usage; sits directly after Analytics; route unchanged
  • **Documentation** — Competition Shell UX refactor formally closed in roadmap and architecture docs

---

v1.5.2 — Pool stage reserve display and stage achievements

Patch release fixing reserve substitution display on pool stage comparison tables and adding stage achievements.

  • **Reserve substitution display** — pool stage comparison shows abandoned riders, reserve replacements, and match highlighting based on effective predictions after reserve logic
  • **Auto-promote + append-after-promotion** — when remaining picks shift forward and the reserve is appended, the table shows promoted riders and the reserve in their effective positions instead of placing the reserve in the abandoned rider's cell
  • **Stored-substitution mode** — with auto-promote off or first-available-position strategy, the reserve still appears in the abandoned rider's cell with struck-through styling
  • **Reserve settings** — currently selected reserve riders who have abandoned are shown with name and (uitgevallen) styling instead of appearing empty
  • **Stage achievements** — non-retroactive stage achievements awarded automatically when a stage is scored; unseen achievements show an indicator in pool navigation
  • **Editorial teaser performance** — pool stage analysis teaser no longer triggers a full analytics build on every page load

---

v1.5.1 — Pool stage editorial analysis teaser

Patch release adding a playful, deterministic analysis teaser on pool stage and **Vandaag** pages.

  • **Editorial analysis teaser** — short Dutch paragraph on the pool stage page, seeded per pool and analysis stage so the same context always returns the same text
  • **Historical stage context** — viewing a completed stage shows analysis as of that stage; today’s unscored stage shows the latest scored previous stage; no misleading current forecast on older pages
  • **Rich template library** — ~150 playful templates across open race, dominant leader, close race, movers, chaos, outsider, stage-type, and fallback situations; placeholders are validated before selection
  • **Context line** — “Analyse na etappe X” shows which scored stage backs the teaser; full numbers stay on the analytics page

---

v1.5.0 — Pool stage pages, analytics chart polish, and forecast admin tooling

Feature release for following live stages in-pool, richer completed-stage views, cleaner analytics charts, and operator forecast configuration.

  • **Pool stage pages** — canonical `/pools/{slug}/stages/{stageNumber}` with all participants’ predictions; **Vandaag** shortcut resolves today’s or next relevant stage; previous/next stage navigation; pool landing redirects by edition phase (predict → today’s stage → standings); dashboard overview moved to `/pools/{slug}/overview`
  • **Completed stage detail** — official top-five result, pick highlighting (exact / top-five / miss), and per-participant stage points when scores exist
  • **Analytics Puntenverloop legend** — each participant appears once; dashed projection lines stay on the chart but are hidden from the legend
  • **Overlapping chart lines** — coincident rank/points lines are nudged a few pixels apart at draw time so every colour stays visible without changing values
  • **Admin forecast profiles** — CSV upload for edition rider stage-type forecast weights used by the outcome-based tournament forecast
  • **Admin forecast runtime settings** — configure forecast engine and weighting from the backoffice without redeploying
  • **Help & docs** — Game Guide and admin copy updated for outcome-based forecast settings and profiles

---

v1.4.0 — Outcome-based tournament forecast and analytics polish

Feature release replacing independent per-player future score sampling with shared simulated stage outcomes, plus analytics and notification fixes.

  • **Outcome-based tournament forecast** — remaining stages are simulated by drawing shared top-5 stage results from pool predictions (weighted by pick frequency and position); every participant’s predictions are scored against the same simulated outcome in each run; legacy Gaussian engine remains available via config
  • **Forecast RNG fix** — Monte Carlo random draws now correctly unpack `Mt19937` output on PHP 8.3+, restoring varied simulations instead of nearly deterministic first-candidate picks
  • **Forecast UI & help** — analytics card and Game Guide explain simulated stage outcomes, shared scoring, podium/win probabilities, and that 0.0% win chance means “almost never in simulations”, not mathematically impossible
  • **Analytics rank charts** — chart labels and help text clarify that rank/points development uses cumulative stage points only (classification and bonus excluded from those charts)
  • **Risers & fallers panel** — movement list now filters by gain/loss sign before taking top movers, so risers and fallers no longer show zero-change entries
  • **Reserve promotion emails** — notification is sent only when a reserve rider is actually inserted into an effective prediction, not when abandoned picks are present without substitution
  • **Translation fix** — percentage placeholders in analytics confidence explanations render correctly (no broken `%100%%` display)

---

v1.3.0 — Rider import performance, admin roster tooling, and prediction validation

Feature release focused on the Tour de France startlist workflow: faster and more forgiving rider imports, a sortable admin edition-rider overview, and prediction validation that catches riders who are no longer racing.

  • **Rider import performance** — edition rider CSV imports build a single in-memory rider lookup index instead of reloading and re-normalizing the full rider table for every row, so importing a full ~184-rider startlist completes comfortably within the request timeout; re-running the same import stays idempotent
  • **Accent-insensitive rider matching** — rider CSV imports match existing riders by normalized, accent-insensitive full display name (e.g. `Pogačar` ↔ `Pogacar`), with a clear validation error when a name matches multiple riders
  • **Admin edition rider sorting** — Admin → Edition riders is now edition-scoped with clickable, server-side sort headers for **bib number** (nulls last) and **rider name**; sort and edition filters are preserved in the header links (`?sort=bib_number|name&direction=asc|desc`)
  • **Prediction validation for withdrawn riders** — the “Check predictions” page now flags selected riders that are no longer active in the edition across stage predictions, rider bonus answers, and reserve riders (withdrawn / did_not_start / no longer on the roster), with actionable links to update each prediction
  • **Rider dropdown sorting preference** — prediction rider dropdowns are a flat, name-sorted list of `Rider — Team`; users can switch to team-grouped sorting under `/me/settings`
  • **Admin edition filter on result entry** — stage, classification, and bonus result-entry admin screens share a read-only active-pool edition filter
  • **Tour mountain-day theme** — Tour de France polka-dot mountain-day motif with an admin preview

---

v1.2.0 — Edition rider pre-import diff

Feature release adding a safer two-step edition rider import workflow.

  • **Edition rider import pre-import diff** — Admin → CSV imports → Edition riders now uses a two-step flow: upload for a read-only diff report (matched, would update, would add, missing from CSV, row errors, duplicate risks), then **Import definitief uitvoeren** on the same previewed file; riders omitted from the CSV still stay active unless marked `did_not_start` or `withdrawn`; explicit confirmation required when active riders are missing from the upload. See [startlist-update-checklist.md](./startlist-update-checklist.md) and [imports.md](./imports.md).

---

v1.1.1 — Player score privacy and test hygiene

Patch release fixing pre-deadline prediction leaks on player score drill-down pages and clearing PHPUnit warning/skipped-test noise.

  • **Player score privacy** — pool member stage and bonus drill-down pages no longer expose another participant’s picks or bonus answers before the relevant deadline; own scores stay visible; superadmin visibility bypass unchanged
  • **Backup command** — writability check uses a probe write so permission tests work when PHPUnit runs as root in Docker
  • **Tournament forecast** — Monte Carlo sampling no longer triggers PHP warnings when a sampled value is non-finite

---

v1.1.0 — Print predictions, race themes, and operator tooling

Feature release adding a pool print overview, edition visual themes, and operator tooling since v1.0.2.

  • **Print predictions** — `/pools/{slug}/print/predictions` from Competition Shell → More; one A4 landscape page per participant with horizontal stage strip, classification mini-tables, and bonus answers; other members’ picks stay hidden until deadlines pass
  • **Race themes** — `body.race-theme--{default|tour|giro|vuelta}` on pool/edition pages; Tour yellow/gold, Giro pink, Vuelta red accents via CSS tokens. Admins set **Visual theme** per edition in the backoffice (`edition.visual_theme`); slug inference remains fallback when theme is Default. See [frontend-theming.md](./frontend-theming.md)
  • **Active pool navigation** — chip and dropdown show pool name only; switchable pools aligned with eligibility rules
  • **`app:purge-known-test-data`** — guarded production cleanup for a test pool and explicit `--user` targets. Two scopes: delete the pool (pool-scoped rows for all members) and delete only listed user accounts (edition-scoped data). Preserved pool members keep accounts and predictions; see [operations.md](./operations.md)
  • **Cycling aliases** — participant-inspired climb aliases added to the alias pool

---

v1.0.2 — Mobile navigation polish and compact locale labels

Patch release improving small-screen global navigation and shortening the language switcher.

  • **Mobile navigation** — mobile-first CSS hides desktop nav on ≤640px; compact header is brand + Menu toggle only (no Active Pool chip overlap); active pool remains in the drawer scores group
  • **Language switcher** — global nav shows **NL · 020 · EN** on desktop and in the mobile drawer; full locale names kept on `aria-label` for accessibility
  • **Regression tests** — locale switcher short labels and separate mobile/desktop nav structures covered in the test suite

---

v1.0.1 — Desktop navigation fix

Patch release restoring desktop global navigation after the mobile menu drawer landed in v1.0.0.

  • **Desktop navigation** — nav groups and meta links render outside the mobile `<details>` drawer again; desktop (≥641px) shows the original meta row and grouped links without opening a menu
  • **Mobile navigation** — compact header with brand, Active Pool chip, and collapsible drawer unchanged for viewports ≤640px
  • **Regression tests** — desktop and mobile nav structures are asserted separately in the test suite

---

v1.0.0 — Production release

First production release of the cycling pool platform: stable Competition Shell, full prediction and scoring flows, analytics and tournament forecast, achievement prestige, operator documentation, and production-ready pool URLs.

**Highlights**

  • **Competition Shell** — primary pool workspace (Overview, Standings, Analytics, Predict, More) with dashboard hero, quick links, and Active Pool chip
  • **Predictions & scoring** — stage, classification, and bonus predictions; official results; score calculation; pool standings and per-player score breakdowns
  • **Analytics & forecast** — rank/points charts, risers/fallers, Monte Carlo tournament forecast with confidence explanations
  • **Achievements** — prestige badges (11 catalog entries including **Net-niet** for 4th place), player achievement pages, and Hall of Fame with cross-pool edition context and grouped historical occurrences
  • **Canonical pool URLs** — user-facing pages use `/pools/{slug}/…`; legacy numeric `/pools/{id}/…` URLs redirect permanently for bookmarks ([pool-slug-urls.md](./pool-slug-urls.md))
  • **Notifications** — email preferences, score updates, reserve promotion, edition reminders
  • **Help & locale** — Game Guide, Help Center, public changelog; Dutch (`nl`), Plat Amsterdams (`nl_ams`), and English (`en`)
  • **Admin & operations** — results entry, CSV imports, user management, and read-only Operations handbook for `app:*` CLI runbooks ([operations.md](./operations.md))

**Operations:** see [release-v1.0.0.md](./release-v1.0.0.md) (production checklist) and Admin → Operations.

---

v1.0.0-beta.3 — UX follow-up hardening

Post-beta polish for discovery, player scores, locale copy, achievements presentation, and operator documentation.

  • **Discovery & onboarding** — home race-week shortcuts and clearer pool index cards for new members
  • **Player score pages** — shared shell chrome, consistent empty states, section navigation on drill-downs, improved heading hierarchy
  • **Plat Amsterdams (`nl_ams`)** — expanded Amsterdam-flavoured copy across pool UX (falls back to standard Dutch where not overridden)
  • **Achievement Hall of Fame** — historical badges from other pools/editions shown with edition/year context; duplicate badge types grouped with occurrence details (no dependency on the pool you are viewing)
  • **Admin Operations handbook** — read-only admin page documenting `app:*` console commands with Docker examples and safety notes ([operations.md](./operations.md))

---

v1.0.0-beta.2 — Beta hardening and test hygiene

Stability and maintainability pass after the Competition Shell beta; no scoring or prediction rule changes.

  • **Beta readiness QA** — audited shell flows, empty states, mobile sub-nav, and locale switching; small presentation fixes on pool list and Active Pool chip behaviour
  • **Test hygiene** — resolved PHP 8.4 and PHPUnit 13 deprecations/notices in the test suite; documented test runtime expectations
  • **Regression coverage** — expanded Competition Shell phase tests for beta checkpoint guarantees

---

v1.0.0-beta.1 — Competition Shell beta

Major UX refactor: a unified **Competition Shell** replaces fragmented pool navigation and dashboard layouts.

  • **Competition Shell** — consistent tabs on all pool pages: Overview, Standings, Analytics, Predict, and More
  • **Predict workspace** — single hub for stage, classification, bonus, and reserve-rider actions with status summaries
  • **Dashboard redesign** — hero next action, your position, leaderboard preview, quick links, and recent results
  • **Analytics refinement** — section navigation, overview and distribution views, clearer empty states
  • **Active Pool chip** — global header shows your active competition; slim navigation hides duplicate pool links when a running pool is selected
  • **Plat Amsterdams locale (`nl_ams`)** — optional Netherlands Dutch variant with fallback to standard Dutch
  • Pool list and competition-select pages aligned with shell styling; Active Pool switcher only when you belong to multiple running pools

---

v1.0.0-alpha.1 — Initial alpha

First end-to-end alpha of the platform: predictions, scoring, pools, analytics, and supporting product features before the Competition Shell UX refactor.

**Core gameplay**

  • Pool management (public and private), memberships, and edition-scoped predictions
  • Stage predictions, classification predictions, and bonus questions
  • Official results entry, score calculation, and pool standings
  • Reserve riders with automatic promotion when a selected rider abandons

**Analytics & forecast**

  • Analytics dashboard with rank and points development charts
  • Biggest risers and fallers; pool-scoped score breakdowns (stage, classification, bonus)
  • Tournament Forecast Engine — Monte Carlo win/podium/finish estimates with confidence explanations

**Achievements & help**

  • Achievement Engine — ten prestige badges (Tour Winner, Hot Hand, Perfect Storm, and more) with player achievement pages
  • Active Pool session context — global standings and analytics resolve through your selected competition
  • Game Guide (Spelgids), Help Center (including Active Pool and analytics chapters), and public changelog page

**Accounts & notifications**

  • Google OAuth and improved registration; login with email or username
  • Email notification preferences; rider abandonment, roster removal, and edition start reminders
  • User account enable/disable; pool leave; admin user management

**Presentation & locale**

  • Rider dropdowns grouped by team in prediction forms; visual match indicators on stage score details
  • Provisional rider list warnings; cycling alias generator
  • Dutch (`nl`) and English (`en`) with locale switcher