Metrics and audit
Metrics and audit
Every published number has a registry entry: a definition, formula, inputs, basis, source layer, coverage tier and verification mode. The audit is regenerated from the published payloads on every publish.
Registry 3.11.0, reviewed 2026-10-24. Dataset 2026-10-27T12:06:31+00:00-c598315, audited 27 Oct 2026, 12:06 UTC.
Audit trail
Registry and audit artefacts
- Registry version
- 3.11.0
- Registry checksum
sha256:47f21daf427a0926a215591849c408fc3f0fab8495fc3e784803708449392cb7- Audit status
- pass
- Audit checksum
sha256:53e66eee321b37f151a43e43f49d4e41de57c1cf199782db0511c01dc3785902- Rows checked
- 4042
- Fields checked
- 1855733
- Allowlist
- none
- Expires
- —
A pass proves the published values reproduce from the corpus where the mode is recompute, agree across payloads where it is cross_surface, and are present with an active source layer where it is provenance_only. It does not prove upstream provider accuracy or that a curated fact is true.
Validation: pass, 42 checks, 0 errors, 0 warnings. Report checksum sha256:54df2ddcce033536f5938b8ee09071a8614668185118aab2beb72cd15ca4d000.
Registry
Metric definitions
/competitions/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
table.recordLeague table record | Per-team league record and ranking inputs. |
| measured | league_standings | match | recompute46 rows · 462 numeric leaves | pass |
table.cutoffsLeague cutoffs | League positions and cutoff labels. | Configured league cutoffs; positions are read from config/competitions.yaml, not recomputed from results. | curated | league_standings | curated | provenance_only4 rows · 15 numeric leaves | passpresent, not recomputed |
competition.indexCompetition index | Competition identity, coverage and match counts. | One row per configured competition; counts are fixtures or table rows joined by competition_id; coverage states come from the source frame. | mixed | league_standings | derived | provenance_only1 rows · 14 numeric leaves | passpresent, not recomputed |
/competitions/league-cup/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
cup.leagueLeague Cup | League Cup groups, rounds, ties and qualifiers. | Group tables: points = 3*won + drawn + shootout bonus; ties and rounds counted from cup fixtures; qualifiers read from config/cups.yaml. | mixed | cup_fixtures | derived | provenance_only1 rows · 1435 numeric leaves | passpresent, not recomputed |
/competitions/scottish-cup/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
cup.scottishScottish Cup | Scottish Cup rounds, ties and coverage. | Rounds and ties counted from cup fixtures; coverage compares published ties with the configured official round count. | mixed | cup_fixtures | derived | provenance_only1 rows · 389 numeric leaves | passpresent, not recomputed |
/matchday/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
matchday.formMatchday form | Recent and split form for both teams. |
| measured | league_results_current | match | recompute9 rows · 244 numeric leaves | pass |
matchday.strengthMatchday strength | League strength, percentiles and comparison. | ppp = points/played; ppg = points/played; gf_pg = gf/played; ga_pg = ga/played; gd_pg = (gf-ga)/played; shots_for_pm = shots/matches; shot_share = team shots/(team + opponent shots); rank = 1 + count of better teams (lower is better for ga_pg); league_size = teams in the league; position_gap and ppg_gap = team value minus opponent value. Percentiles set the bar length; ranks set the visible label. | inferred | league_standings | derived | cross_surface4 rows · 57 numeric leaves | pass |
matchday.styleMatchday style | Shot profile, approach index and style lean. | Approach index is the mean of within-league percentiles for shots, shots on target, goals and corners; possession is not used. Style lean is the sign of the approach index against the league median. | inferred | league_team_stats | derived | provenance_only1 rows · 146 numeric leaves | passpresent, not recomputed |
matchday.lineupPredicted XI | Predicted lineups, scores, selection weights, selection confidence and availability. | Player score = 0.20*form + 0.10*minute_share + 0.15*recent_rating + 0.15*role_fit + 0.18*recency_start + 0.22*start_rate. Availability counts curated entries; opponent availability is not modelled. | inferred | lineups_roles | event | provenance_only1 rows · 411 numeric leaves | passpresent, not recomputed |
matchday.coverageMatchday coverage | Snapshot, lineup and form coverage. | age_hours = (generated_at - snapshot_at)/3600; lineup_coverage = fixtures_with_lineups/fixtures; counts are from the opponent snapshot. | measured | league_results_current | match | cross_surface2 rows · 4 numeric leaves | pass |
matchday.head-to-headHead-to-head | Recent meetings and results. | League meetings joined by date and team ids; result is W/D/L for Aberdeen; score is the final score, with shootouts shown separately. | measured | history | match | provenance_only1 rows · 6 numeric leaves | passpresent, not recomputed |
matchday.next-fixturesNext fixtures | Upcoming club fixtures. | Upcoming competitive club fixtures from the merged season schedule, ordered by local date and kickoff; current plus the next five are rendered on matchday. Conflict-review and friendly rows are excluded from the lookahead. | measured | club_fixtures | match | provenance_only1 rows · 0 numeric leaves | passpresent, not recomputed |
/recruitment/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
needs.summaryNeeds summary | Family counts and availability summary. |
| inferred | needs | derived | recompute8 rows · 5 numeric leaves | pass |
needs.familyNeeds families | Per-family depth, quality, availability, market and roster metrics. | measured_score = 100 * sum(w*x)/sum(w) over available drivers: depth_gap 0.30, quality_gap 0.20, top_share 0.10, availability_risk 0.25, age_risk 0.15. availability_risk = (out + 0.5*doubtful)/known projected players; null when known = 0. | inferred | needs | derived | provenance_only1 rows · 314 numeric leaves | passpresent, not recomputed |
needs.roster-spaceRoster space | Roster current/max and outgoing-first policy. | roster current = senior squad players under contract; max from config/needs.yaml; outgoing-first policy is a config flag, not a measured value. | curated | needs | curated | provenance_only1 rows · 0 numeric leaves | passpresent, not recomputed |
needs.coverageNeeds coverage | Needs coverage and availability status. | Counts of known and unknown availability entries, contract data and squad rows; states are available, partial or unavailable. | mixed | needs | derived | provenance_only1 rows · 21 numeric leaves | passpresent, not recomputed |
rumours.profileRumour profile | Advisory recruitment profile weights and buckets. | Advisory profile from active incoming external_target rows only; current squad, current non-official and former players are excluded, and return links are listed separately. Buckets are descriptive, not probabilities or recommendations. | inferred | rumours | derived | provenance_only1 rows · 13 numeric leaves | passpresent, not recomputed |
/transfers/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
transfers.summaryTransfer summary | Register totals, players and period. |
| curated | transfer_register | curated | recompute230 rows · 6 numeric leaves | pass |
transfers.windowTransfer windows | Per-window arrival/departure and valuation counts. |
| curated | transfer_register | curated | recompute21 rows · 420 numeric leaves | pass |
transfers.rowTransfer rows | Per-move fee, loan and verification values. | One row per confirmed move; fee is disclosed/reported/inferred/undisclosed; inferred ranges are modelled, never treated as fees; loan terms are unknown unless confirmed. | curated | transfer_register | curated | provenance_only1 rows · 792 numeric leaves | passpresent, not recomputed |
transfers.valuationTransfer valuation | Modelled fee ranges and calibration counts. | Fee range from disclosed comparables by position, age and league; calibration counts are the rows with a disclosed or reported anchor used to fit the range. | inferred | valuation | derived | provenance_only1 rows · 14 numeric leaves | passpresent, not recomputed |
transfers.sell-onSell-on clauses | Sell-on percentages, basis and summary. | Sell-on percentage is published only where confirmed; summary counts confirmed, reported and unknown clauses; unknown is not zero. | curated | transfer_register | curated | provenance_only2 rows · 19 numeric leaves | passpresent, not recomputed |
transfers.plausibilityTransfer plausibility | Withheld suspect rows and plausibility counts. | Counts of rows withheld or flagged by the plausibility audit; the audit compares fee, age, position and window against the published register. | curated | transfer_register | curated | provenance_only1 rows · 1 numeric leaves | passpresent, not recomputed |
transfers.auditTransfer completeness audit | Seniority review, position coverage and gap ledger counts. | Counts by seniority, position coverage and gap status; the ledger records unresolved or duplicate identities, not transfer claims. | curated | transfer_register | curated | provenance_only1 rows · 72 numeric leaves | passpresent, not recomputed |
transfers.coverageTransfer coverage | Audited/curated window coverage. | Windows are audited or curated partial; counts are confirmed rows per window; earlier windows are partial, not silently complete. | curated | transfer_register | curated | cross_surface2 rows · 0 numeric leaves | pass |
/loans/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
transfers.loansTransfer loans | Loan-in and loan-out slices. | Loan-in and loan-out rows from the confirmed register; one row per loan; parent club, dates and terms are source-linked. | curated | loans | curated | provenance_only2 rows · 124 numeric leaves | passpresent, not recomputed |
/history/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
history.scorecardHistory scorecard | Era aggregates: seasons, managers, honours and positions. | seasons = covered seasons; best/worst_position = min/max league position; average_position = mean season position; average_points = mean season points; manager_count = distinct people with a league match; honours_total = register count. | mixed | history | curated | cross_surface9 rows · 57 numeric leaves | pass |
history.seasonHistory seasons | Season-level history rows. | One row per season; league position/points from the club payload; cup and European outcomes from season documents; manager spells kept separate. | mixed | history | curated | provenance_only1 rows · 0 numeric leaves | passpresent, not recomputed |
history.staffHistory staff | Manager/staff stints and records. | One row per manager or staff stint; played, points, gf and ga are league matches only; interim spells are separate. | curated | history | curated | provenance_only1 rows · 117 numeric leaves | passpresent, not recomputed |
history.baselineHistory baseline | League-only baseline window. |
| measured | history | match | recompute7 rows · 77 numeric leaves | pass |
history.coverageHistory coverage | History season/backfill coverage. | Counts of seasons with history documents, backfilled lineups, staff and honours; missing seasons are labelled unavailable. | mixed | history | curated | cross_surface2 rows · 90 numeric leaves | pass |
history.season-documentHistory season documents | Per-season history documents. | Document envelope: one per season with review, style, selection, staff, transfers and honours; measured facts and the labelled assessment are kept separate. | mixed | history | curated | provenance_only8 rows · 1746 numeric leaves | passpresent, not recomputed |
history.defeatsHeavy defeats | Cormack-era defeats by four or more goals, newest first. | goals_for/goals_against are the final score for each defeat with a margin of four or more; one row per fixture, newest first; the threshold is a display parameter, not a modelled value. | measured | computed | match | provenance_only1 rows · 48 numeric leaves | passpresent, not recomputed |
/squad/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
squad.summarySquad summary | Squad size, official-roster reconciliation, loans, role evidence and coverage counts. |
| measured | squad_identity | event | recompute35 rows · 72 numeric leaves | pass |
squad.loan-scopeLoan scopes | Official team-list loans, current-register loans and all-time register loans, with the reconciliation between them. | official_list counts status loan_out in the official squad rows; register_current counts confirmed loan rows for the current season; register_all_time counts every confirmed loan row. The three are published separately and never substituted for one another. | mixed | loans | curated | cross_surface7 rows · 24 numeric leaves | pass |
squad.playersSquad players | Per-player totals, playing time, role, position and official-roster reconciliation fields. | Playing time reconstructed from lineups and substitution events; starts and minutes are competitive-only; role shares use starting-XI observations; totals sum competition rows. | mixed | squad_identity | event | provenance_only2 rows · 7033 numeric leaves | passpresent, not recomputed |
squad.metaSquad metadata | Role/career/position/attribute coverage metadata. | Coverage flags for role, career, position and attribute data; unknown fields are null, not filled. | mixed | squad_identity | event | provenance_only9 rows · 285 numeric leaves | passpresent, not recomputed |
/players/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
player.pagePlayer pages | Per-player page panels, two-figure Nightingale rose, availability projection and recent match log. | Document envelope: player totals, playing time, role evidence, position stats, the published rose axes, the curated availability projection and the latest competitive match rows for one player. The rose uses league-only rates from the provider season totals; each percentile is the midrank rank of the raw value in the player's league and role cohort (provider-group fallback), with conceded_p90 ranked on negated values. The percentile is null when the cohort or value is unavailable. Where current-season Premiership minutes are below the squad threshold, the rose uses the most recent prior Premiership season with at least 180 league minutes and a same-season cohort; season_used, cohort_season, fallback and fallback_note are published and visible. The summary minutes remain current-season. The match log is a projection of the normalized player-match rows joined to the fixture date, opponent and score; it is not recomputed in React. | mixed | player_match_stats | event | provenance_only39 rows · 8430 numeric leaves | passpresent, not recomputed |
/rumours/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
rumours.summaryRumour summary | Curated rumour counts and status. |
| curated | rumours | curated | recompute2 rows · 3 numeric leaves | pass |
forum.former-profileFormer-player forum profile | Former-player mention lane and external-target profile counts. | Signals are labelled by affiliation from the current squad and former register; position and age mixes count external_target only; the former lane is a filtered view of the same signal rows. | mixed | forum_signal | derived | recompute46 rows · 18 numeric leaves | pass |
rumours.former-laneCurated former-player rumour lane | Curated rumours whose subject is a former player. | Rows whose canonical affiliation is former_player; a return link is a former player named as an incoming target and is shown separately. | curated | rumours | curated | recompute2 rows · 0 numeric leaves | pass |
/news/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
forum.signalForum signal | Fan-signal coverage, sentiment and profile. | Mention counts from sampled first pages; each name is labelled by canonical affiliation; the position and age profile counts external_target only; topic-level VADER sentiment only; no per-player sentiment score is published. | mixed | forum_signal | curated | provenance_only1 rows · 153 numeric leaves | passpresent, not recomputed |
/sources/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
provenance.layersProvenance layers | Layer/source row counts and truth table. | Row counts by source layer; status is the source probe state; coverage gaps remain visible in the truth table. | mixed | computed | derived | provenance_only4 rows · 28 numeric leaves | passpresent, not recomputed |
/status/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
coverage.surfacesCoverage | Build coverage counts across surfaces. | Counts of built pages and published payloads per surface; used by the build status page. | mixed | computed | derived | cross_surface3 rows · 1266 numeric leaves | pass |
consistency.summaryCross-surface consistency audit | Pass/fail counts for the published cross-surface consistency checks, including the former-player, result/form, semantic, epoch and manifest checks. | One record per named consistency check; passed + failed = checks. | mixed | computed | derived | provenance_only1 rows · 55 numeric leaves | passpresent, not recomputed |
manifest.freshnessFreshness thresholds | Dataset, availability and per-source freshness states exposed to the client. | Read from config/matchday.yaml stale_after_hours, config/availability.yaml policy.max_age_days and the former-player refresh timestamp. | measured | computed | derived | provenance_only1 rows · 35 numeric leaves | passpresent, not recomputed |
availability.ledgerAvailability | Availability ledger coverage and entries. | Entries require a player key, status, source id and verified_at; known/unknown counts are over the current squad; a provider injury boolean is not team news. | curated | availability | curated | provenance_only1 rows · 62 numeric leaves | passpresent, not recomputed |
/former-players/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
former.definitionFormer-player definition | Configured former-player universe, rival list, development proxy and sell-on policy. | Read from config/former_players.yaml; the universe is the latest published permanent/free departure, excluding current squad, returns and loan-outs. | curated | former_player_record | curated | provenance_only1 rows · 5 numeric leaves | passpresent, not recomputed |
former.summaryFormer-player summary | Former-player counts by departure, destination, current status, rival spell and coverage. | One row per canonical former player; buckets count those rows; a missing value is unknown, never zero. | mixed | former_player_record | derived | recompute77 rows · 85 numeric leaves | pass |
former.playersFormer-player rows | One row per canonical former player with departure, Aberdeen record, post-career summary and sell-on reference. | The universe rule, then one Aberdeen tenure aggregation and one post-career league aggregation per player. Provider ratings stay league-relative. | mixed | former_player_record | derived | cross_surface78 rows · 3660 numeric leaves | pass |
former.post-seasonsFormer-player post-Aberdeen seasons | League season rows and per-season rates after the Aberdeen departure. | League-only provider seasons after departure; per-90 rates only above the configured minutes gate; no cross-league percentile. | measured | former_player_record | match | recompute78 rows · 2876 numeric leaves | pass |
former.sell-onFormer-player sell-on watch | Sell-on clause event, receipt and missing-input state. | Detect the first permanent/free move away from the buyer; compute a receipt only when percentage, basis and every required public fee are evidenced; otherwise return the missing inputs. | mixed | sell_on_events | curated | recompute5 rows · 18 numeric leaves | pass |
former.scorecardFormer-player development scorecard | Descriptive exit cohorts and post-Aberdeen distributions. | Counts and distributions over the canonical former players; young exits at the configured age, developed proxy at the configured debut age and starts; no composite score. | mixed | former_player_record | derived | recompute77 rows · 65 numeric leaves | pass |
former.coverageFormer-player coverage | Backfill counts, gaps and current-club coverage. | Expected player-seasons from departure to current; present league seasons; gaps and provider budget from the local backfill meta. | measured | former_player_record | derived | cross_surface78 rows · 22 numeric leaves | pass |
/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
clubs.aberdeenClub payload | Aberdeen club summary, history and news rows. | Club summary joins league table, recent results, upcoming fixtures and news metadata by club id; no commercial or attendance series is invented. | mixed | league_results_current | match | provenance_only1 rows · 301 numeric leaves | passpresent, not recomputed |
/claims/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
case.documentThe case document | Owner view, chairman frame, thesis and state. | Document envelope: owner view, chairman frame, thesis, claims and coverage state; opinion is attributed, measured counts are labelled. | mixed | themes | derived | provenance_only4 rows · 0 numeric leaves | passpresent, not recomputed |
case.claimsThe case claims | The claim register: order, domain, status and counts. | One row per claim; count is the qualifying rows in the claim evidence table; status is supported, partial, can't test yet or not supported; order is editorial. | mixed | themes | derived | provenance_only1 rows · 6 numeric leaves | passpresent, not recomputed |
case.evidenceClaim evidence | The evidence table attached to each claim. | One row per evidence item; count is the observed value, sample is the denominator or qualifying set; source and period are carried with the row. | mixed | themes | derived | provenance_only1 rows · 0 numeric leaves | passpresent, not recomputed |
case.benchmarkPeer benchmark | League performance of the other SPFL clubs. | League performance of the other SPFL clubs: best/worst/median position and points from the computed tables; current is the latest season position. | measured | themes | match | provenance_only1 rows · 39 numeric leaves | passpresent, not recomputed |
case.coverageCase coverage | Availability, history and missing data classes. | Counts of known and unknown data classes; unknown is not zero and is listed in the coverage block. | mixed | themes | derived | provenance_only1 rows · 0 numeric leaves | passpresent, not recomputed |
case.claim.team-nowThe team now | League record and kick-off shape churn. | played = competitive matches in the period; points = 3*won + drawn; gf/ga = league goals for/against; form = last five league results; churn = kick-off shape changes. | measured | themes | match | provenance_only1 rows · 1 numeric leaves | passpresent, not recomputed |
case.claim.defenceThe defence | Three-at-the-back record, wide roles and availability. | matches = matches with three centre-backs at kick-off; points_pg = points/matches; ga_pm = goals against/matches; wb_starts_pm = wing-back starts/matches; wf_starts_pm = wide-forward starts/matches; denominator = qualifying matches only. | measured | themes | match | provenance_only1 rows · 1 numeric leaves | passpresent, not recomputed |
case.claim.attackThe attack | Goals, shot share and the set-play/error gap. | gf/ga = league goals; shot_share = Aberdeen shots/(Aberdeen + opponent shots); attack_share = goals from wide forwards and strikers/total league goals; roles from the starting-XI grid. | measured | themes | match | provenance_only1 rows · 1 numeric leaves | passpresent, not recomputed |
case.claim.managersThe managers | Manager phases, runs and the cup. | played/ppg by manager stint; winning_run/winless_run = longest league run; cup outcome from the honours register; interim spells are separate. | measured | themes | match | provenance_only1 rows · 1 numeric leaves | passpresent, not recomputed |
case.claim.squadThe squad | Arrivals, departures, age, U21 minutes and the Morris sale. | arrivals/departures = confirmed register rows in the window; median_age = median current squad age; u21_minutes_share = U21 minutes/total minutes; Morris sale = confirmed transfer. | mixed | themes | curated | provenance_only1 rows · 1 numeric leaves | passpresent, not recomputed |
case.claim.chairman-recordThe chairman's record | The Cormack-era record, managers, honours and transfers. | seasons = covered seasons; positions from computed league tables; honours from the register; manager_count = distinct people; europe from season documents. | mixed | themes | curated | provenance_only1 rows · 1 numeric leaves | passpresent, not recomputed |
/matches/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
matches.documentMatch document | One played-fixture document: score, summary, scoreboard, stats, fxG with model and goals ranges, timeline, lineups, player stats, performance, form and coverage. | One document per canonical played fixture; final score is authoritative; summary, timeline and scoreboard use regular goals only; missing classes are null with coverage labels; duplicate aliases are separate. The xg block carries fxG, an 80% model range, an 80% goals range, provider xG with its source, shots, penalties, xG per shot and the over/underperformance position. | mixed | computed | match | provenance_only371 rows · 193006 numeric leaves | passpresent, not recomputed |
fixtures.indexFixture index | The fixture index: played results plus the remaining scheduled fixtures. | count = canonical played fixtures (duplicate aliases excluded); each played row carries score, result, depth and href. scheduled = remaining canonical fixtures after the played registry and conflict handling. scheduled_count = rows with status scheduled; scheduled_rows_total includes conflict_review rows; conflict_count = conflict_review rows. Conflict-review rows are retained but excluded from forward-looking surfaces. | measured | computed | match | provenance_only1 rows · 1152 numeric leaves | passpresent, not recomputed |
xg.shot-profilefxG shot profile | Measured shots, shots on target, off-target, blocked, inside-box, outside-box and penalty counts behind a team-match fxG value. | Counts are carried from the licensed team statistics and event feed; missing values are null, never zero. | measured | league_team_stats | match | provenance_only370 rows · 4274 numeric leaves | passpresent, not recomputed |
/analysis/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
analysis.summarySeason overview | Current position and form, next fixtures, official and derived availability, measured aims, squad-decision lenses and the category bridges. | A projection of the current table row, the merged season schedule, the AFC availability ledger, sourced card rules, named-squad membership, matchday contenders, the season expectations and factual squad-decision lenses. No value, fee, wage, contract expiry or medical diagnosis is derived. Counts sum to the active universe (official list minus loanees out); the five official loan-outs are separate. Aims are analyst-set targets with a measured current value and status; they are not club targets. | mixed | computed | derived | provenance_only1 rows · 297 numeric leaves | passpresent, not recomputed |
/analysis/xg/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
xg.documentfxG document | Team-match expected goals from open-play shot zones, shots on target, blocked shots and penalties; a model range, a goals range, provider-xG calibration, transfer check, provider-style estimate, manager splits, aggregates and coverage. | open_play_sot = max(0, shots_on_target - penalty_sot_subtracted); open_play_insidebox = max(0, shots_insidebox - penalty_attempts); fxG_open = a selected linear model on open-play inside-box, outside-box, shots on target, off-target and blocked counts; fxG = fxG_open + 0.76 * penalty_attempts. Coefficients are fitted by OLS to 2026-27 Premiership team rows where provider xG exists. The 80% model range is the 10th-90th percentile of match-clustered bootstrap predictions plus the leave-one-match-out residual pool. The 80% goals range is the convolution of a beta-binomial open-play distribution and a binomial penalty distribution. Aggregate variances are combined, never summed as intervals. provider_estimate = max(0, intercept + slope * fxg) for rows without provider xG; actual and estimated provider values are never summed. manager_splits sum league match rows by date-attributed manager stint, for and against separately. | inferred | computed | derived | provenance_only1 rows · 13980 numeric leaves | passpresent, not recomputed |
xg.per-shotxG per shot | Expected goals divided by shots for a team match or aggregate. | fxg_per_shot = fxg / shots; null when shots is zero or unavailable. | inferred | computed | match | provenance_only373 rows · 1166 numeric leaves | passpresent, not recomputed |
xg.goals-minusGoals minus fxG | Observed goals minus the team-match fxG estimate, with a shifted goals range. | goals_minus_fxg = goals - fxg. The shifted goals range is goals_low - fxg to goals_high - fxg. | inferred | computed | match | provenance_only373 rows · 1176 numeric leaves | passpresent, not recomputed |
xg.model-rangefxG model range | The 80% range for the fxG estimate. | 10th-90th percentile of match-clustered bootstrap predictions plus a draw from the leave-one-match-out residual pool. Aggregates sum per draw; per-match ranges are never summed as intervals. | inferred | computed | match | provenance_only744 rows · 1770 numeric leaves | passpresent, not recomputed |
xg.goals-rangeGoals range | The 80% range of goals from the same chances. | Convolution of a beta-binomial open-play goal distribution and a binomial penalty distribution; aggregate distributions are convolved across matches. The range is the 10th-90th percentile. | inferred | computed | match | provenance_only744 rows · 1770 numeric leaves | passpresent, not recomputed |
/scouting/
| Metric | Definition | Formula | Basis | Source | Coverage | Verification | Status |
|---|---|---|---|---|---|---|---|
scouting.poolScouting player pool | One row per ranked player per league with provider season statistics, within-league role percentiles and profile scores. | Per-90 values are stat * 90 / minutes. Completed passes are passes_total * pass_accuracy / 100. Duel and dribble percentages divide by their provider attempts; conversion divides goals by shots; save percentage divides saves by saves + conceded. The rating percentile is the midrank percentile of the provider rating within the league and role family at 450+ minutes; the provider-group fallback is used only when the role cohort is below its minimum. Archetype scores are 100 * Phi(sum(w * shrunk robust z) / sum(abs(w))), with winsorisation at 1/99, median/MAD scaling, minutes shrinkage and weight renormalisation. The rose uses the same league-only rates: each axis is the midrank percentile of the raw value in the same role-family cohort (provider group fallback), with conceded_p90 ranked on negated values. Missing values and insufficient cohorts are null. | mixed | scouting_pool | match | provenance_only39 rows · 584252 numeric leaves | passpresent, not recomputed |
scouting.boardScouting weakness board | Aberdeen role-family ratings against the Scottish Premiership cohort, with verified availability evidence. | The family average is the appearance-weighted mean provider rating of Aberdeen players at 300+ competitive minutes in the role family. The percentile is the midrank position of that average within the other Premiership players in the same role family at 450+ minutes; Aberdeen are excluded from their own cohort. The reading is structural below 40, at 40-60, above 60; a below-cohort family with one absent first-choice player is cover, two or more is hold. First-choice evidence is 10 starts or 900 minutes in the most recent prior season with at least 450 minutes. | mixed | scouting_pool | derived | provenance_only2 rows · 561 numeric leaves | passpresent, not recomputed |
scouting.archetypesScouting archetype profiles | Weighted player-profile scores, their feature weights, coverage, the attacker assist/goal split and the dedicated goal-scoring list. | Each archetype is a weighted composite of winsorised, robust z-scores within league and role family: z = (x - median) / (1.4826 * MAD), shrunk by minutes / (minutes + 450), combined with signed weights and mapped to 0-100 by the normal CDF. Missing features are removed and the remaining absolute weights renormalised; below 70% coverage the score is null. Weights are in config/scouting/archetypes.yaml and are published with the score. | inferred | computed | derived | provenance_only2 rows · 1353 numeric leaves | passpresent, not recomputed |
scouting.team-lensScouting team-context lens | Players outperforming teams that are underperforming in their league. | Team points per game = points / played in the provider's current league table. The team points percentile is the midrank percentile of that value among the league's teams. team_lift = player role-adjusted percentile - team points percentile. A team is underperforming when its percentile is at or below the configured maximum (default 40). The lens keeps players with a positive lift at those teams, ordered by lift then scouting priority. A league without a table is unknown, never zero-strength. | inferred | computed | derived | provenance_only36 rows · 430940 numeric leaves | passpresent, not recomputed |
scouting.squadScouting squad profile | Aberdeen registered-squad position-specific per-90 output, competitive matches only. | The same per-90 and percentage formulas as scouting.pool, applied to the registered Aberdeen squad in competitive matches only (friendlies and loan-club rows excluded), at 180+ minutes. The rating is appearance-weighted; the percentile is within the Premiership role cohort. The rose uses Premiership-only rates against the same league and role cohort. | mixed | squad_identity | match | provenance_only1 rows · 1383 numeric leaves | passpresent, not recomputed |
scouting.coverageScouting coverage | Per-league provider coverage, role coverage and pool counts. | Counts of provider player-season rows, rated rows, rows at 450+ minutes, players with at least one starting-XI role, played fixtures and lineups fetched. Role coverage is role players divided by the league pool. Searchable requires at least 25 rated players. | measured | scouting_pool | derived | provenance_only3 rows · 1470 numeric leaves | passpresent, not recomputed |
scouting.value-modelScouting value model | The 0-100 scouting value index and the anchor-gated GBP value model. | Value index = 100 * sum(w_i * component_i) / sum(w_i) over performance (league-adjusted percentile / 100), age curve, minutes reliability (min(1, minutes / 1800)) and best adjusted profile score / 100. Weights are renormalised over available components and the index is null below 70% coverage. The GBP band is fitted only after the public-source anchor gate passes: log(value_gbp) = b0 + b1*adjusted_percentile/100 + b2*age + b3*age^2 + b4*log(minutes) + role-group dummies. The published band is the 80% prediction interval. No GBP value is published before the gate. | inferred | computed | derived | provenance_only2 rows · 70 numeric leaves | passpresent, not recomputed |
scouting.priorityScouting priority | U23 and European shop-window weighting on top of the value index. | scouting_priority = value_index * age_multiplier * europe_multiplier. age_multiplier = u23_multiplier when age <= u23_max_age, else 1.0. europe_multiplier = europe_multiplier when european league-phase minutes >= europe_minutes_threshold, else 1.0. The European flag is built from the league-phase fixtures of the Champions League, Europa League and Conference League and the per-fixture player endpoint; qualifiers and play-offs are excluded. A player not found is none only when coverage is complete; otherwise the status is unknown and the multiplier is 1.0. | inferred | computed | derived | provenance_only43 rows · 585101 numeric leaves | passpresent, not recomputed |
Parameters
Config-backed thresholds and weights
matchday
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.matchday.styleMatchday style policy | {"attack_index":60,"attack_shot_share":0.5,"counter_index":40,"counter_shot_share":0.48,"min_matches":4,"overall_weight":0.4,"venue_min_matches":3,"venue_weight":0.6,"weights":{"goals_for":0.2,"shot_share":0.25,"shots_for":0.4,"shots_on_target_for":0.15}} | mixed | matchday.style | matchday.style | config_match | pass |
param.matchday.predictionMatchday prediction policy | {"formation_window":6,"min_role_fit":0.3,"position_group_fit":{"D":{"CB":0.3,"DM":0.2,"LB":0.3,"LWB":0.3,"RB":0.3,"RWB":0.3},"F":{"AM":0.2,"LW":0.3,"RW":0.3,"ST":0.3},"GK":{"GK":0.3},"M":{"AM":0.3,"CM":0.3,"DM":0.3,"LM":0.3,"RM":0.3}},"recency_weights":[6,5,4,3,2,1],"role_adjacency":{"AM":{"AM":1,"CM":0.7,"LW":0.6,"RW":0.6,"ST":0.5},"CB":{"CB":1,"DM":0.3,"LB":0.6,"RB":0.6},"CM":{"AM":0.7,"CM":1,"DM":0.8},"DM":{"CB":0.4,"CM":0.7,"DM":1},"GK":{"GK":1},"LB":{"CB":0.5,"LB":1,"LM":0.4,"LWB":0.9},"LM":{"CM":0.4,"LB":0.5,"LM":1,"LW":0.9},"LW":{"AM":0.5,"LM":0.8,"LW":1,"ST":0.5},"LWB":{"LB":0.8,"LM":0.5,"LW":0.4,"LWB":1},"RB":{"CB":0.5,"RB":1,"RM":0.4,"RWB":0.9},"RM":{"CM":0.4,"RB":0.5,"RM":1,"RW":0.9},"RW":{"AM":0.5,"RM":0.8,"RW":1,"ST":0.5},"RWB":{"RB":0.8,"RM":0.5,"RW":0.4,"RWB":1},"ST":{"AM":0.4,"LW":0.5,"RW":0.5,"ST":1}},"scoring":{"form":0.2,"minute_share":0.1,"recency_start":0.18,"recent_rating":0.15,"role_fit":0.15,"start_rate":0.22}} | mixed | matchday.lineup | matchday.prediction | config_match | pass |
param.matchday.refreshMatchday refresh and sample policy | {"contenders":6,"max_api_requests":24,"min_lineup_matches":3,"recent_fixtures":6,"refresh_after_hours":20,"stale_after_hours":48} | mixed | matchday.form, matchday.lineup, matchday.coverage | matchday | config_match | pass |
needs
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.needs.thresholdsNeeds thresholds | {"age_risk_strengthen":0.5,"availability_risk_cover":0.25,"cover_buffer":1,"depth_gap_cover":0.5,"quality_gap_strengthen":0.35,"quality_minutes":900,"ready_minutes":180,"ready_starts":2,"reliance_top_share":0.55,"starter_minutes":450,"starter_starts":5,"trusted_starts":3,"weak_family_delta":-0.15} | mixed | needs.family, needs.summary | needs.thresholds | config_match | pass |
param.needs.familiesNeeds family policy | {"AM/WM":{"label":"Attacking / wide midfield","market":["loan","free_agent","fee"],"max_squad":5,"min_available":3,"scouting_groups":["AM"],"traits":["key_passes_p90","dribbles_success_pct","shots_p90","progressive_carries_p90"]},"CB":{"label":"Centre-backs","market":["loan","free_agent","fee"],"max_squad":5,"min_available":4,"scouting_groups":["CB"],"traits":["aerial_win_pct","duel_win_pct","progressive_passes_p90","clearances_p90"]},"FB/WB":{"label":"Full-backs / wing-backs","market":["loan","free_agent","fee"],"max_squad":6,"min_available":4,"scouting_groups":["FB"],"traits":["crosses_p90","progressive_carries_p90","tackles_p90","duels_won_pct"]},"GK":{"label":"Goalkeepers","market":["loan","free_agent"],"max_squad":4,"min_available":2,"scouting_groups":["GK"],"traits":["saves_p90","save_pct","crosses_claimed_p90","pass_completion"]},"MID":{"label":"Central midfield","market":["loan","free_agent","fee"],"max_squad":7,"min_available":4,"scouting_groups":["DM","CM"],"traits":["progressive_passes_p90","tackles_p90","interceptions_p90","pass_completion"]},"ST":{"label":"Centre-forwards","market":["loan","free_agent","fee"],"max_squad":4,"min_available":2,"scouting_groups":["ST"],"traits":["shots_p90","goals_per_shot","aerial_win_pct","touches_in_box_p90"]},"W":{"label":"Wide forwards","market":["loan","free_agent","fee"],"max_squad":5,"min_available":3,"scouting_groups":["W"],"traits":["dribbles_success_pct","crosses_p90","shots_p90","touches_in_box_p90"]}} | mixed | needs.family, needs.roster-space | needs.families | config_match | pass |
transfers
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.transfers.auditTransfer audit thresholds | {"manual_finding_aids":{"allowed":true,"automated_access":false,"publication":false},"prior_seasons":["2024-25","2025-26"],"recent_windows":4,"seniority":{"established_min_career_starts":10,"established_min_minutes":450,"established_min_starts":5,"youth_max_age":20,"youth_max_appearances":4},"start_season":"2024-25"} | mixed | transfers.row, transfers.coverage | transfers.audit | config_match | pass |
param.transfers.valuationTransfer valuation policy | {"currency":"GBP","fx_to_gbp":{"EUR":0.85,"GBP":1,"USD":0.78},"note":"Manual calibration may use restricted pages as a private sanity check only; no restricted value, URL or scraped table is published. Every inferred output is a range with a confidence label.\n","range_high":1.6,"range_low":0.6} | mixed | transfers.valuation | transfers.valuation | config_match | pass |
availability
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.availability.policyAvailability policy | {"allowed_hosts":["afc.co.uk","www.afc.co.uk"],"conflict_confidence_downgrade":2,"doubtful_confidence_downgrade":1,"doubtful_weight":0.5,"filter_statuses":["out","suspended"],"fresh_days":7,"max_age_days":21,"require_source_url":true,"returned_weight":0.9,"stale_confidence_downgrade":1,"unknown_confidence_downgrade":1,"unknown_weight":1} | mixed | availability.ledger | availability.policy | config_match | pass |
param.availability.providerAvailability provider policy | {"endpoint":"/injuries","league_id":179,"never_sets":["available","returned","suspended"],"require_league_coverage":true,"source":"api_football","use_player_injured_boolean":false} | mixed | availability.ledger | availability.provider | config_match | pass |
competitions
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.competitionsCompetition policy | [{"api_football_id":179,"code":"SC0","cutoffs":[{"after_position":3,"kind":"europe","label":"European places · 1–3","note":"4th is conditional on the Scottish Cup winner already being in the top three."},{"after_position":6,"kind":"split","label":"Top-six / bottom-six split","note":"The league splits after 33 matches; the bottom six cannot finish higher than 7th."},{"after_position":10,"kind":"playoff","label":"Relegation play-off · 11th","note":"11th plays the Championship play-off winner over two legs."},{"after_position":11,"kind":"relegation","label":"Relegation · 12th","note":"12th is relegated automatically."}],"id":"sco:premiership","matches_per_season":228,"name":"Scottish Premiership","qualification_note":"Scotland has four UEFA places for 2027/28: the champions enter the Champions League second qualifying round, the Scottish Cup winner enters the Europa League first qualifying round, and 2nd and 3rd enter the Conference League second qualifying round. 4th only qualifies if the Scottish Cup winner is already in the top three. The League Cup carries no European place. Subject to the final UEFA access list and cup outcomes.\n","short_name":"Premiership","split_after_matches":33,"teams":12,"tier":1},{"api_football_id":180,"code":"SC1","cutoffs":[{"after_position":1,"kind":"promotion","label":"Automatic promotion · 1st","note":"1st is promoted to the Premiership."},{"after_position":4,"kind":"playoff","label":"Promotion play-off · 2nd–4th","note":"2nd–4th enter the Premiership play-off with 11th in the Premiership."},{"after_position":8,"kind":"playoff","label":"Relegation play-off · 9th","note":"9th enters the Championship/League One play-off with 2nd–4th in League One."},{"after_position":9,"kind":"relegation","label":"Relegation · 10th","note":"10th is relegated to League One."}],"id":"sco:championship","matches_per_season":180,"name":"Scottish Championship","qualification_note":"1st is promoted automatically. 2nd–4th enter the Premiership play-off with 11th in the Premiership. 9th enters the Championship/League One play-off, and 10th is relegated to League One.\n","short_name":"Championship","teams":10,"tier":2},{"api_football_id":183,"code":"SC2","cutoffs":[{"after_position":1,"kind":"promotion","label":"Automatic promotion · 1st","note":"1st is promoted to the Championship."},{"after_position":4,"kind":"playoff","label":"Promotion play-off · 2nd–4th","note":"2nd–4th enter the Championship/League One play-off with 9th in the Championship."},{"after_position":8,"kind":"playoff","label":"Relegation play-off · 9th","note":"9th enters the League One/League Two play-off with 2nd–4th in League Two."},{"after_position":9,"kind":"relegation","label":"Relegation · 10th","note":"10th is relegated to League Two."}],"id":"sco:league-one","matches_per_season":180,"name":"Scottish League One","qualification_note":"1st is promoted automatically. 2nd–4th enter the Championship play-off with 9th in the Championship. 9th enters the League One/League Two play-off, and 10th is relegated to League Two.\n","short_name":"League One","teams":10,"tier":3},{"api_football_id":184,"code":"SC3","cutoffs":[{"after_position":1,"kind":"promotion","label":"Automatic promotion · 1st","note":"1st is promoted to League One."},{"after_position":4,"kind":"playoff","label":"Promotion play-off · 2nd–4th","note":"2nd–4th enter the League One/League Two play-off with 9th in League One."},{"after_position":9,"kind":"pyramid","label":"Pyramid play-off · 10th","note":"10th faces the tier-five group winner; no automatic relegation."}],"id":"sco:league-two","matches_per_season":180,"name":"Scottish League Two","qualification_note":"1st is promoted automatically. 2nd–4th enter the League One play-off with 9th in League One. 10th enters the pyramid play-off against the winner of the Highland / Lowland East / Lowland West champions' group; there is no automatic relegation, and the League Two club hosts the second leg.\n","short_name":"League Two","teams":10,"tier":4}] | mixed | table.record, table.cutoffs, competition.index | competitions.competitions | config_match | pass |
param.competitions.historyCompetition history backfill | {"all_four_from":"1997-98","default_backfill_from":"2013-14","first_season":"1994-95"} | mixed | table.record, table.cutoffs | competitions.history | config_match | pass |
param.competitions.validationCompetition validation policy | {"curtailed":{"2019-20":["SC0","SC1","SC2","SC3"],"2020-21":["SC1","SC2","SC3"]}} | mixed | table.record | competitions.validation | config_match | pass |
themes
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.case.thresholdsCase thresholds | {"balance":{"medium_matches":6},"depth":{"concentration_high":0.55,"rotation_minutes":90,"starter_minutes":450,"starter_starts":5,"thin_rotation_starts":3},"family":{"high_matches":6,"high_minutes":900,"medium_matches":3,"medium_minutes":450},"mission":{"min_arrivals_for_confidence":5},"shape":{"medium_matches":3}} | mixed | case.claim.defence, case.claim.attack, case.claim.managers | themes.thresholds | config_match | pass |
param.case.scopeCase scope | {"bench":"premiership","minutes":"all_competitive","ratings":"premiership","shapes":"all_competitive"} | mixed | case.claim.team-now, case.claim.defence, case.claim.attack | themes.scope | config_match | pass |
xg
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.xgfxG model policy | {"calibration":{"competition_id":"sco:premiership","features":["inside_box","outside_box","shots_on_target","blocked"],"league_id":179,"min_matches":45,"min_team_rows":90,"min_zone_coverage":0.8,"season":"2026-27"},"evaluation":{"calibration_slope_max":1.3,"calibration_slope_min":0.7,"max_abs_bias":0.15,"max_mae":0.55,"method":"leave_one_match_out","validation_season":"2026-27"},"fit":{"before_season":"2026-27","exclude_competition_prefixes":["sco:other:friendlies"],"min_shots_on_target":120,"prior_strength_sot":250},"goals_range":{"level":0.8,"max_dispersion":3,"max_support":5000,"method":"binomial_penalty"},"interval":{"bootstrap_draws":2000,"draws":10000,"level":0.8,"seed":20261022,"z":1.2816},"penalty":{"missed_on_target":true,"source":"fixed historical penalty conversion prior; see docs/xg.md","xg":0.76},"transfer_check":{"competition_id":"sco:premiership","season":"2025-26","source":"api_football"}} | mixed | xg.document | xg | config_match | pass |
fixtures
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.fixturesFixture record policy | {"matching":{"date_tolerance_days":0,"overrides":{}},"pages":{"depth_labels":{"full":"Full record","partial":"Partial record","result":"Result, events and lineups","score":"Score only"},"full_classes":["events","lineups","team_stats","player_stats"],"partial_classes":["events","lineups","team_stats","player_stats"],"result_classes":["events","lineups"],"route_prefix":"/matches","score_classes":[],"summary":{"late_goal_minute":85,"stoppage_time_minute":90}},"scope":{"first_season":"2019-20","friendly_competition_prefixes":["sco:other:friendlies"],"include_friendlies":true,"last_season":"2026-27"}} | mixed | matches.document, fixtures.index | fixtures | config_match | pass |
scouting/model
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.scoutingScouting model policy | {"archetypes":{"min_minutes":450,"min_weight_coverage":0.7,"shrink_minutes":450,"winsor_high":0.99,"winsor_low":0.01},"board":{"first_choice_minutes":900,"first_choice_starts":10,"min_minutes":300,"prior_min_minutes":450,"prior_seasons":3,"status_above":60,"status_below":40},"coverage":{"min_rated_players":25},"pool":{"fallback_group_min":15,"low_minutes":900,"min_cohort":15,"min_cohort_by_family":{"goalkeeper":8},"min_minutes":450},"squad":{"min_minutes":180}} | mixed | scouting.pool, scouting.board, scouting.archetypes, scouting.squad, scouting.coverage | scouting/model | config_match | pass |
scouting/value
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.scouting.valueScouting value policy | {"fit":{"interval":0.8,"max_value_age_days":550,"min_age_bands":3,"min_anchors":60,"min_league_tiers":3,"min_minutes":450,"min_role_anchors":5,"top_tier_share":0.2},"index":{"age_curve":[{"factor":0.5,"max_age":18},{"factor":0.7,"max_age":20},{"factor":0.9,"max_age":23},{"factor":1,"max_age":27},{"factor":0.8,"max_age":29},{"factor":0.55,"max_age":31},{"factor":0.3,"max_age":120}],"min_weight_coverage":0.7,"minutes_full":1800,"weights":{"age":0.15,"minutes":0.15,"performance":0.55,"profile":0.15}},"priority":{"europe_minutes_threshold":90,"europe_multiplier":0.6,"u23_max_age":23,"u23_multiplier":1.3}} | mixed | scouting.value-model, scouting.priority | scouting/value | config_match | pass |
player-rose
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.player.rosePlayer rose policy | {"min_petals":4} | mixed | player.page, scouting.pool, scouting.squad | player-rose | config_match | pass |
analysis
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.analysisSeason overview policy | {"absence":{"confidence_cap":"medium","consecutive_omissions":2,"min_squad_inclusions":5,"min_starts_or_bench":3,"window_fixtures":6},"matchday_lookahead":6,"next_up":3,"selection_watch":3,"squad_decisions":{"low_minutes_age_min":23,"low_minutes_share_max":0.25,"max_per_lens":3,"peak_age_min":27,"peak_minutes_min":450,"percentile_min_cohort":8},"suspensions":{"require_verified_rule":true}} | mixed | analysis.summary | analysis | config_match | pass |
scouting/team-context
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.scouting.team-contextScouting team-context policy | {"lens_limit":12,"min_lift":0,"note":"A team is treated as underperforming when its points-per-game percentile is at or below the threshold. A player must have a positive lift. Empty leagues or teams without a current table stay unknown, never zero-strength.\n","underperforming_ppg_percentile_max":40} | mixed | scouting.team-lens | scouting/team-context | config_match | pass |
former_players
| Parameter | Value | Unit | Used by | Config | Verification | Status |
|---|---|---|---|---|---|---|
param.former-rivalsFormer-player rival list | {"rivals":[{"club_id":"sco:celtic","name":"Celtic"},{"club_id":"sco:rangers","name":"Rangers"},{"club_id":"sco:dundee-united","name":"Dundee United"}]} | mixed | former.definition, former.summary, former.players, former.scorecard | former_players | config_match | pass |
param.former-developedFormer-player development proxy | {"development":{"debut_age_max":21,"min_starts":10,"young_exit_age_max":23}} | mixed | former.players, former.scorecard | former_players | config_match | pass |
param.former-scorecardFormer-player scorecard thresholds | {"scorecard":{"min_post_minutes":90,"min_post_seasons":1}} | mixed | former.scorecard | former_players | config_match | pass |
param.former-sell-onFormer-player sell-on policy | {"sell_on":{"allowed_basis":["gross_fee","profit"],"fx_to_gbp":{"EUR":0.85,"GBP":1,"USD":0.78},"require_basis":true,"require_percentage":true,"require_public_fee":true}} | mixed | former.sell-on | former_players | config_match | pass |
param.former-backfillFormer-player backfill policy | {"post_career":{"backfill_max_requests":400,"current_season_ttl_hours":24,"historical_ttl_hours":720,"league_tiers":{"39":{"country":"England","tier":1},"61":{"country":"France","tier":1},"78":{"country":"Germany","tier":1},"135":{"country":"Italy","tier":1},"140":{"country":"Spain","tier":1}},"max_requests_per_run":400,"min_minutes_for_rates":180,"refresh_max_requests":180,"request_interval_seconds":0.3,"source":"api_football","transfers_ttl_hours":168}} | mixed | former.players, former.post-seasons, former.coverage | former_players | config_match | pass |
Method
Verification modes
| Mode | What it proves | What it does not prove | Metrics |
|---|---|---|---|
recompute | Re-derived from published rows using the registered formula. | Upstream provider accuracy. | 14 |
cross_surface | The same fact agrees across two payloads. | Formula correctness. | 9 |
config_match | The registry parameter equals config. | The config is analytically right. | 0 |
source_checksum | The curated source file is unchanged since audit. | The source fact is true. | 0 |
provenance_only | The value is present and its declared layer is active with rows. | Independent recomputation. | 60 |
Coverage tiers: event, match, curated, value_only, derived and unknown. The most detailed tier an input supports is declared; a derived or inferred value is never labelled measured.
A number is any value, rate, percentage, count, rank, range, confidence, coverage label, threshold or weight. Changing a formula, denominator, rounding mode, source, coverage tier, confidence rule or parameter needs owner approval, a metric/registry version bump and an entry in the metric changelog.
Related
Sources, method and build status
Provenance
How this page is sourced
Dataset 2026-10-27T12:06:31+00:00-c598315. Sources and coverage are listed below; the page keeps its own source and uncertainty labels.
The registry and audit describe definitions; they are not a data table.
Corrections and changes are recorded on Corrections and contact.
Cite this page
Metrics and audit. Dataset 2026-10-27T12:06:31+00:00-c598315, as of 2026-10-27T12:06:31+00:00. Source: published fitba record.