Repository navigation
Add public competition pages and scouting analytics - #82
jackshim415 wants to merge 64 commits into
Conversation
|
🚅 Deployed to the lovat-pr-82 environment in lovat
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa0bd3550c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ( | ||
| existing && | ||
| ((existing.matchKey && existing.matchKey !== match.key) || | ||
| (existing.teamNumber !== teamNumber && | ||
| existing._count.scoutReports > 0)) |
There was a problem hiding this comment.
Retire the server's competing match writer
When a TBA station assignment changes after a report exists, this guard correctly rejects reassignment, but the still-active server path calls addTournamentMatches() from apps/server/src/handler/manager/getMatches.ts:48 and unconditionally overwrites the same TeamMatchData.teamNumber in addTournamentMatches.ts:176-191. Because that writer also uses a separate legacy ETag, deploying both services lets a request to the server bypass this reconciliation check and silently attach existing scouting reports to the replacement team; disable or update the server writer as part of this cross-app ingestion change.
AGENTS.md reference: AGENTS.md:L27-L28
Useful? React with 👍 / 👎.
| const ordered = [...matches].sort( | ||
| (a, b) => | ||
| levels[a.competitionLevel] - levels[b.competitionLevel] || | ||
| a.setNumber - b.setNumber || | ||
| a.matchNumber - b.matchNumber, |
There was a problem hiding this comment.
Order bracket games by their scheduled sequence
For historical playoff formats that alternate series—such as qf1m1, qf2m1, …, followed by qf1m2—sorting by setNumber before matchNumber instead groups every game from one series together. The resulting gap rows connect matches that were not adjacent in the event schedule and can classify ordinary intervening matches as long breaks; use the imported display/scheduled order or a format-specific canonical order instead.
Useful? React with 👍 / 👎.
Expose selected public competition data for 2026cancmp and display match results, inferred breaks, and a searchable team roster using Lovat styling.
Use local TBA avatars with sampled gradients and verified event award markers for the fixed 2026cancmp page. Align participants by station, name upper and lower bracket matches, and center alliance-colored scores in each match header.
Show the eight selected alliances and connect upper/lower bracket results using imported match data. Share the tournament loader between pages and use local Material SVGs for reliable award markers.
Switch tournament views inline so schedule, teams, and alliances keep the same URL and event header.
Import alliance selections, awards, season avatars, and regular-season weeks so public pages work with any imported event. Group district events by week and championship, add credited California town backgrounds, and load roster icons near the viewport.
Show disqualified team identities with a strikethrough and size alliance cards for every selected member and backup. Add a basic season page linking imported districts and non-district events through a public competition-only API.
What changed
Add public competition browsing and Lovat scouting analytics to the Website. Season and district pages organize events by week and nest championship divisions. Tournament pages share Schedule, Teams, and Alliances views; team pages show event records, awards, alliance details, robot photos, and configurable scoring/feeding graphs with role breakdowns. Match pages show official results, scouting metrics, adjacent matches, predictions, and video/resource links.
Search provides team/event suggestions and direct team-number navigation. Shared match cards display scores, DQs, role icons, and available predictions. Credited location photos and deterministic FRC fallbacks supply event backgrounds; Worlds uses broadcast-style symbols. The layout follows Dashboard/Magnolia styling and supports mobile screens.
Public Server routes select competition fields and approved scouting aggregates only. All-team public aggregate access was explicitly approved by the maintainer. Raw reports, notes, identities, source identities, and robot paths remain private. Signed-in predictions retain existing source filters and take precedence; unsupported seasons and unavailable values remain hidden. Scouting metrics currently support 2026.
Dependency and deployment
#83 is merged. This PR is now based on
main; its diff excludes all shared schema migrations, worker code, worker CI, and API import handoff. The prerequisite was merged with a merge commit, preserving ancestry and avoiding duplicate infrastructure changes.The existing
lovat-pr-82environment and populated database are retained. Its original sanitized backup remains untouched. A fresh snapshot was also made while splitting the PR. The schema/worker preview uses a separate copy; changes in either preview do not synchronize automatically.Website/API deploy after the schema and worker. Configure Website API/signing references and Auth0 callback, web-origin, and logout allowlists for the production domain. The maintainer has already allowlisted the #82 Website preview.
Verification
Team registration indicators: approved registered teams expose only a public
usesLovatboolean. Profiles show a Lovat-mark badge beside the number; event team lists reuse a compact icon with an accessible label and tooltip, retaining centered records and separate award icons. Codes, contacts, and registration records are excluded. No migration is needed. Server build, both typechecks, lint (80 existing warnings), and all 1,101 unit tests pass. Website check/lint/build pass with existing 13/19 warnings. Fresh dependency installs pass with a project-local legacy-peer setting for Magnolia preparation, preserving existing engine/resolution settings and all pinned versions; Docker now copies this configuration before npm ci. Existing Server coverage-threshold failures remain separate from these passing tests.Scouting context and comparison
Team analytics now mark tournament boundaries, eliminations, and matches reported as broken. Charts restart rolling averages at each tournament; summaries show the arithmetic mean, median, interpolated 25th–75th percentile range, linked best match, and recent-five-match average for the selected metric and event filter. Breakdown matches remain included by default and can be excluded. Only a breakdown flag is public, never the description.
Match cards show how many participants have a scouting report, with “Fully scouted” requiring six distinct teams, three per alliance, and at least one report each. The dedicated
/predictorpage provides a configurable six-team public predictor using the existing 2026 scouting engine, linked from team analytics with that team prefilled and from the footer. District pages add a sortable Lovat leaderboard from cached season metrics, distinct from official district standings. Matches, Points, Auto, and Teleop headers toggle ascending/descending sorting; approved Collection teams receive the shared subtle icon in the district team list. Existing authenticated source filters are unchanged. No schema migration is required.Tournament graph boxes show their event key and raw match average. New tournaments use solid red boundaries, reported breakdowns use dashed red lines, and eliminations begin at dashed blue lines. Known unscouted matches retain their timeline positions as gaps and are excluded from statistics. The centered role pie uses purple shades and direct percentage labels.
Validation: Server build and test type-check; all 1,108 Server tests across 55 files pass. Website check, lint, production build, and four analytics tests pass. Existing warning baseline remains (13 Svelte check warnings, 19 Website lint warnings, 80 Server lint warnings).
Tournament points ranking
Tournament pages now include an Analytics tab with a “Total Points Dropoff” graph plotting average total scouting points per match against total-points rank. Every point is labeled with its team number, and a horizontal line marks the mean of the plotted team averages. Explanatory subtitle and hover instructions are removed. Hover or keyboard focus reveals the team, rank, score, and number of scouted matches; each point links to that team. Rankings use only reports from the selected event, retain zero scores, order equal scores by team number, and exclude teams without reports. A cached public projection reuses the existing 2026 scoring engine and returns only aggregate team data. Other seasons show an empty state.
Validation: all 1,110 Server tests pass, including event-source isolation and zero-score coverage. Server build, both typechecks, lint, and Website check/lint/build pass with existing warnings. Browser verification uses the CalGames preview data after an insert-only production report sync. No schema migration is required.
The dropoff graph also fits a decaying exponential by minimizing squared residuals in points, including zero scores, and shows its equation and original-scale R². Its top 32 teams form four consecutive eight-team cohorts with shaded bands and separate team-average lines. Smaller events show only the available cohorts. Tests cover exact exponential recovery, zero-score influence, original-scale R², flat/insufficient data, and cohort boundaries; all eight analytics tests pass. Website check/lint/build pass with the existing warning baseline.
The best-fit curve and equation, overall average, team labels, and each cohort’s shading and average can be toggled independently. All seven controls were verified in the browser; Website check, lint, and production build pass with the existing warning baseline.