# FMDB data wishlist and export handoff

Reviewed: **2026-09-30**, against the current `DAT_SCHEMA.md` (142-table modern
schema), schema guide, queries, V4 views and live calculations. This replaces the
2026-09-24 request status. `public/data-requests.md` is the identical public copy
linked from each page; update both together.

This is a schema and implementation audit, not a fresh population audit of every
loaded database. CSV-era databases retain their smaller schema. An exported table
can be absent, empty or contain NULLs in a particular version; “exported” never
promises a value for every entity. No missing fact should be reconstructed to fill
a design placeholder.

## How to read the page wishlists

- **Now live:** the page implements the feature where its inputs are recorded.
- **Exported; UI pending:** the modern schema contains the data, but this page does
  not yet consume it. Confirm coverage and meaning before integration.
- **Partial export:** some requested fields exist or are displayed; the detail
  explains the remaining source, interpretation or UI work.
- **Needs UI work / Needs a bounded query:** an application feature is unfinished;
  it is not a request for duplicate export columns.
- **Index-dependent:** a filter is enabled only when the selected version has its
  required index. Exported values alone do not enable a filter or sort.
- **Needs source data / Needs validation:** the catalog does not establish the fact
  or a trustworthy label. Do not guess it.
- **No reference date:** exact date-relative features cannot be established from
  the base .dat source. A nullable reference-date column is not an actual date.

## R1 — reference date: source limitation documented

`export_meta` now includes `game_start_year`, `source_extraction_at`, nullable
`reference_date`, its kind, scope and provenance. The catalog explicitly states
that the base .dat database stores no in-game reference date. A year, export time
or extraction timestamp must not be substituted for one.

The club page therefore publishes **season-start** figures only, and says so: ages at
1 July of `game_start_year`, an under-21 count on the same date, and the contracts
ending by 30 June of the following year. That is a stated convention built on the one
recorded date fact, not a substitute in-game date; exact in-game ages, wonderkid
selection by age and other date-relative features remain unavailable, and CSV-era
versions without a start year show the reason. Explicit contract-expiry-date
filtering is implemented where indexed. If a separate authoritative source can
provide a scoped reference date, document its provenance and limitations; do not
request a fabricated date from .dat.

## R2 — filters and sorts: implementation and indexes are separate

Name-prefix search, nationality and minimum position competency are implemented.
Ability, potential, value, wage and explicit expiry-date filters, plus club level
and reputation filters, are enabled per version through `FilterSupport` and
`SourceIndexes`. `fmdb:index-databases` adds the required local indexes through
maintenance tooling, never through application game connections.

Still pending:

- Export the agreed indexes so fresh loads need less maintenance. Match the actual
  predicates in `GameIndex`; do not add unused height, DOB or speculative sorts.
- Implement the combined player club/league name lookup, height filtering and a
  documented foot-category definition. The current controls do not provide these.
- Implement a competition-index level filter; it currently does not apply one.
- Implement additional server-side sorts and presets. Player lists currently order
  by name or uid, club lists by name. A filter index does not make every column
  sortable, and squad aggregates need their own bounded query shape.
- Implement free-agent lists from explicit `person_club_status.has_no_club`, with
  index and coverage checks. Missing contracts must never imply free agency.

Provide representative EXPLAIN plans and deterministic uid tie-breakers for agreed
new predicates. CSV importer parity remains FMDB's responsibility.

## R3 — player identity, training and contracts: many additions delivered

| Feature | Current schema and remaining work |
|---|---|
| Names, birth date, measurements | Already displayed from `person`; weight is not a missing export. |
| Training and home-grown status | `person_days_at_location` stores days and training age bands; `person_trained_status` stores club/nation relationships and rule codes. UI integration is pending. Respect location kinds and rule semantics; these are not full dated training intervals or proof of eligibility under every competition rule. |
| Nationality and allegiance | `person_nationality` contains additional/resident nationalities; `person.declared_nation_uid` and nationality-info fields also exist. The player page now shows the other nationalities with their source relationship labels, eligibility (the ELIGIBLE_FOR_NATION rows) and the declared nation where a version exports them; the nation pool still uses primary nationality. |
| Contract and squad status | `person_contract_detail` includes contract, job and squad status codes. Contract type is now displayed where `contract_status` is decoded (FM24); both FM26 exports carry it as NULL on every row, a decode gap worth closing. `squad_status` has no lookup table, so its codes cannot be named. It does not establish playing-time promises, transfer/loan listing flags or asking price. |
| Club attachment | `person_club_status` explicitly distinguishes `has_no_club`, `last_club_uid` and `contract_decoded`, with documented nullable flag coverage. UI integration is pending. |
| Clauses and bonuses | Existing `person_contract_clause` rows are displayed. `person_contract_bonus` rows are counted and their raw type codes listed; the codes are not the `clause_type` lookup's id space and `cash` and `misc` have dual-purpose meanings, so amounts wait for a documented per-type mapping. |
| International record | `person_international_record` includes senior/U21 appearances and goals, nation, debut and first-goal details, now displayed on the player page where exported. The FM26 exports' 66–73 debut dates all fall in 2048 or later on players with zero caps and look like a decoder defect. Other youth categories are not established. |
| Agent | No agent identity or representation relation in the current catalog. |
| Personality/media and preferred moves | Numerical personality values and move bits exist. Verified labels and mappings by era remain outstanding; `preferred_move` still has no name column. |
| Youth club / first professional contract | Still requires explicit evidence. Neither the earliest career row nor current `contract_start_date` or `forced_initial_contract_date` proves the first professional contract. |

Modern `person_club_contract.contract_start_date` means last-signed with the
exporter's documented club-join fallback; CSV-era `joined` remains a separate
source field. Do not silently relabel these as equivalent dates.

## R4 — history, awards and identity: partial delivery

`starting_person_history` is decoded for FM24, including `record_type`, `job` and
`flags`; `starting_person_history_date` preserves day/year precision. It is no
longer correct to say there is no decoder or event-kind field. Other versions
remain explicitly unsupported. Personal-honours UI integration still needs verified
event interpretation; a club spell during a winning season does not prove a medal.

`comp_history` now documents stage, joint-winner, season-span and no-data/unfinished
flags. The honours calculation uses the available flags, counts confirmed overall
wins and reports its bound; CSV versions without those flags retain a coverage
note. Counts are not limited to the visible history page. Player career totals
already exclude overlapping summary rows and report coverage.

`award_scope` adds direct competition and award-type links. The competition page now
lists every scoped award with its latest rank-1 winner, the roll of honour takes its
top scorer from the one scoped `MOST_GOALS_SCORED` award, and season pages list that
season's winners (2026-10-02). Award and `comp_history` `season_year` share one
convention in fm26_update. Common nationality is still never a competition link, and
no award type identifies a single "player of the season". Person awards are already
displayed. `award_history_winner_slot` preserves source slots separately from
compacted rank.

`player_history.division_uid` is populated only in the `.dat`-sourced databases; every
CSV-era database leaves it NULL on every row, so per-division all-time records exist
for those versions only. Some competition uids also carry predecessor seasons (the
Premier League's go back to 1931), and many record-holders' `player_uid` values
resolve to no `person` row. A request: say whether the uid reuse is deliberate, and
export the missing retired people where the source holds them.

Source subtype limitations remain: CSV permits player/staff duals, modern exports
are disjoint, and history can reference unclassified or missing people. Preserve
source classification and use job spells for employment, not subtype counts.

## R5 — finances: detailed exports exist; integration remains

The app already displays bounded `club_finance` rows where present. The modern
schema now also includes:

- `club_finance_source`: the source family for each `(club_uid, ordinal)` row,
  separating budgets, debts, FFP and other records, with family-specific dates,
  rates and payments. A bare `amount` must not be relabelled as bank balance.
- `club_finance_detail`: authored cash, basic debt, raw owner type, embargo and
  ticket/rent values.
- `club_income`: dated income rows, amounts and raw income types.
- `transfer_instalment` and `transfer_wage_contribution`: outstanding payment
  obligations, not a complete historical transfer ledger.
- `club_server.rough_financial_state` and other raw administration fields.

The V4 finance panel now shows `club_finance_detail.cash` as the balance and
`basic_loan_debt` as the debt figure, the budgets from the `loan_source_type`
`budget` row, every other `club_finance` row by its source family with
`amount_meaning` on hover, the embargo flag and the `club_director` board. Owner
type, `rough_financial_state` and `club_income.income_type_id` are raw codes with no
lookup, so no owner, financial-status or sponsor label is shown; club valuation is
not established. Lookups for those three codes would complete the panel. Do not
request duplicate cash or debt columns.

The September 29 reload recorded invalid dates and out-of-range finance decimals;
its import copies retain those nullable values as NULL with an audit. Treat these
as decoder/data-quality follow-ups, not invented replacement dates or prices.

## R6 — facilities, supporters, affiliations and kits: mixed status

- **Facilities:** `club_facility` still contains only `training_facilities`. Youth
  facilities, recruitment, junior coaching and academy category remain missing;
  corporate revenue is not a facilities rating.
- **Club nickname:** still absent; neither short name nor national-team nickname
  supplies a club nickname.
- **Supporters:** `club_supporter_profile` exports researched FM23+ loyalty,
  passion, patience, affluence, temperament and expectations, and
  `club_media_expectation` the predicted finish; the club page now shows both.
  Computed supporter-type percentages are deliberately not exported.
- **Affiliations:** `club_link` now contains both club uids, type, flags, dates,
  costs and loan terms, and the club page lists them in both directions. The
  relationship is shown as its `link_type_id` code because no lookup exists; a
  `club_link_type` lookup would let it be named. `club_partnership` remains a pair
  of people, not a club affiliation.
- **Training ground:** `club_server.training_ground_stadium_uid` resolves to a
  `stadium` row and is shown under Facilities.
- **Home-grown:** `person_trained_status` is now read as recorded for the squad
  table's HG column and the home-grown count; `home_grown_rule_type` codes are not
  interpreted and would need a lookup.
- **Kits:** `club_kit_part` / `nation_kit_part`, `kit_display_type` and `kit_style`
  now describe parts, goalkeeper kits and styles. The current drawings still use
  legacy rows/colours; integration is pending. Modern kit numbers are 0–2, while
  CSV-era numbers are 1–3; FM18 can have only kit-part rows.
- **Cup runs:** `nation_cup_history` decodes national-team STARTING_TEAM_CUP_HISTORY.
  It does not establish club cup-run coverage. `won_stage_tie` is a stage tie result,
  not proof of a competition title. The nation page has not integrated these rows.

## R7 — competition format, awards and income: partial delivery

`competition.rule_*` records basic rule facts. `comps_*` tables contain archive
competition/stage fields, including some promotion, relegation and play-off
information, but they are **empty in every loaded database**: comps.dbc was not part
of any run. Exporting it, with archive-to-competition links and season/stage scope,
is the request; until then the competition page shows the clubs that joined and left
since the latest table as an FMDB comparison and never a count of places.

`competition.champions_club_uid` and `league_body_club_uid` exist in the schema but
are NULL on every row of all 41 databases; confirm whether the source carries them.
`derby.competition_uid` is likewise NULL on every row of fm26_update, so a derby is
tied to a league only when both its clubs name that division.

Nation foreign-player definitions and agreements are exported, but are not complete
competition registration quotas, home-grown rules, age exemptions or windows.
Prize/TV distribution schedules and competition sponsor contracts remain missing.
Club income cannot substitute for them. Direct competition award scope is integrated
as described in R4.

## R8 — nations: points, coefficients, definitions and rivals delivered

- `nation_fifa_ranking` stores FIFA men's ranking **points**, not a world-rank
  position or ranking date. Neither missing fact is stored in the source.
- `nation_coefficient` documents UEFA association coefficients versus CAF points,
  source ordering and season-year coverage; unset slots remain NULL.
- `nation_rival` records the other nation, level and flags, with documented scale
  and source-version differences. There is no effective date to export.
- `nation_agreement`, `nation_agreement_type`, `nation_foreign_rule` and
  `nation_tax_rule` provide dated definitions, agreements and tax records. They do
  not establish complete work-permit conditions or registration windows.

V4 has not integrated these tables. Keep primary-nationality player-pool statistics
separate from eligibility. A direct nation-language relationship is still absent;
city languages do not prove a national language list, and `source_region_index`
still cannot be treated as a region uid.

## R9 — transfer events and fee meaning: separate sources delivered

| Source | Meaning and coverage |
|---|---|
| `transfer_event` | Completed FM24/FM26 moves, including loans, signings and releases, with person and counterpart uids, event date/type and fee/code. Unsupported in FM18–FM23. Unknown/undisclosed, nominal and exchange fee codes leave fee NULL rather than zero. |
| `starting_future_transfer` | Misleading legacy name for a subset of **past** transfer events. It is not the agreed-future-moves source. |
| `future_transfer` | Actual agreed future moves for modern FM18–FM26 exports, with documented exceptions for past dates. Do not merge them into completed business. |
| `club_transfer_record` | Authored highest-fee-spent/received records, preserving an unknown fee as NULL. |
| `transfer_add_on`, instalments and wage contributions | Separate contingent/outstanding obligations; not proof of total completed transfer cost. |

The V4 transfer panel has not integrated these sources. Validate event identity,
source-version coverage, loan treatment and counterpart resolution before display.
Historical net-spend totals need explicit completeness and unknown-fee coverage;
the existence of event rows alone is insufficient. Do not infer transfers from
adjacent career rows or interpret an unknown fee as a free transfer.

## R10 — reputation scales: modern metadata delivered

`export_value_scale` now records native scale bounds, source family, provenance and
`to_research_200_divisor` where conversion is source-proven. This is metadata for
interpreting values, not browsable game content. Modern scale definitions should
no longer be requested as though no export support exists.

The competition page now prints reputation against the bound this metadata states
("187 / 200"), and versions without the table show the raw value. Across-version
charts still display raw source values and warn about differing scales; consuming the
metadata there and establishing CSV scale parity remain application work. Do not infer a multiplier from a
few familiar clubs or apply club/nation scales to competition reputation.

## FMDB calculations and UI work already delivered

The live implementation includes squad totals, a constrained best eleven,
role suitability, staff ratings, similar players, career totals, competition
strength and leading players, national player pools, a bounded whole-nation
pyramid, honours and individual cross-version charts/attribute differences.
These are FMDB calculations or bounded source reads, not new exporter requests.
See `docs/V4-LIVE-CALCULATIONS.md` for formulas, caps and coverage.

Set-piece rankings and attribute percentiles retain their precomputed application
store. General ranking presets, ranking filters, whole-database version diffs,
cross-version ranking movement, cross-version squad aggregates and league-wide
ranking lists remain unfinished. Do not mark them live merely because their input
columns exist or a single-entity calculation is available.

## Remaining handoff requirements

For remaining export work, return supported versions, source evidence, schema and
indexes, units, code meanings and reproducible fixtures. Distinguish unsupported
source, absent archive, empty relation, decoded NULL and application work. Include
zero, sentinel, dangling identity and historical-era cases. New typed child rows
need indexed owner keys; no foreign keys or game writes through the web app.

For application integration, retain optional-table/column guards, version-scoped
reads, bounded queries, honest coverage and missing values. New source rows must
not be promoted to complete rankings or financial totals without evidence. Update
the relevant page wishlist and this public handoff whenever implementation or
schema coverage changes.
