# Foundational test — live custom XI via Freeze Lineup

**Status: PENDING — test has not yet been run.**

This is build-order step 1 from `docs/direction.md`: the test everything else
in the direction pivot depends on.

## What changed since the first draft of this doc

The first version of this test guessed at a "selection bias" DB field and a
candidate squad/lineup table name, based on general FIFA-modding precedent
that turned out not to hold for FLE's documented API — no such field appears
anywhere in FLE's actual Lua API docs or its own example scripts. While
researching an unrelated hotkey issue, a **confirmed, FLE-documented**
mechanism for forcing a starting XI turned up instead: the **Formation
Editor's "Freeze Lineup" feature** (FLE wiki, `Formation-Editor.md`):

> This feature can be used in player career mode if you want to manage the
> starting lineup of your team. Can be also used in manager career mode to
> manually manage your next opponent's starting lineup.

Steps (GUI, no scripting): open Formation Editor for a team → arrange players
on the pitch → tick **Freeze Lineup** → `Data → Save`.

This is real and documented, but it's GUI-only — there is no Lua function for
it, and what DB write it actually performs under the hood is undocumented.
This test is now two phases: confirm the GUI feature works at all, then
reverse the DB write it makes so it can be replicated programmatically
(required for the app→game bridge in build-order step 2, which needs this
driven from outside the game, not from a person clicking checkboxes).

Also fixed in this pass: `EditDBTableField`'s real signature, confirmed from
FLE's own docs and `lua/scripts/99ovr_99pot.lua`, is
`EditDBTableField(cell)` where `cell` is `row["fieldname"]` with `.value`
mutated in place — **not** `EditDBTableField(table, row_index, field, value)`
as originally (incorrectly) written into the first draft of the injector
script.

## What this test settles

Whether a *specific, externally-chosen* 11 players can be forced into a
career (or Kick-Off) match's starting lineup, live, with no restart — and
whether the mechanism that does it (Freeze Lineup's underlying DB write) can
be driven by a script instead of a person clicking through the Formation
Editor UI.

If Freeze Lineup itself doesn't actually hold under match start (the wiki
doesn't show it being tested against a live match, only "you should be able
to see... when you play against them"), the whole bridge architecture in
`docs/direction.md` §3 needs rethinking — there is no other documented
mechanism for forcing a lineup.

## Prerequisites

- FIFA 23 launched normally (FLE injected, EAAC neutralized — same baseline
  as `track-c-fut-table-test.md`)
- A career save loaded (Freeze Lineup is documented for career mode
  specifically — confirm separately whether it does anything in Kick-Off,
  don't assume it does)
- Note 11 player IDs from your club (`tools/squad-exporter/export_squad.lua`
  output, `playerid` field) that are NOT currently your starting XI

## Phase 1 — confirm Freeze Lineup actually holds into a match

This has zero scripting and should be done first since everything else is
wasted effort if it fails.

1. Open the Live Editor overlay (F9, or `Windows → Settings` from the
   overlay's own menu bar if the hotkey isn't registering — see the umu/Wine
   hotkey note below).
2. `Features → Teams` → find your team → `Edit`.
3. `Team → Formation` to open the Formation Editor.
4. Swap players around on the pitch so the XI differs from your current
   actual starting XI in some checkable way (e.g. swap two outfield players'
   positions, or bench/start a specific player).
5. Tick **Freeze Lineup**.
6. `Data → Save`.
7. Hide Live Editor (F9), save your career **on a new slot** (don't overwrite
   your main save in case this corrupts something), exit to main menu, reload
   that save, and check the team's lineup screen / play a match and watch who
   starts.

**Record in the Results table below whether the frozen lineup actually took
the pitch.** If not, stop here — Phase 2 is moot.

## Phase 2 — find the underlying DB write

Only proceed if Phase 1 confirmed Freeze Lineup works.

1. In FLE's Lua Engine, run `tools/squad-injector/snapshot_lineup_tables.lua`.
   This dumps every DB table whose name contains `squad`, `lineup`,
   `formation`, `tactic`, `teamsheet`, `selection`, `players`, or `teams` to
   `C:\FIFA 23 Live Editor\openfut_snapshot_<timestamp>.json`. Note this
   filename — this is your **before** snapshot.
2. Without restarting or reloading, repeat the Formation Editor steps from
   Phase 1 (steps 2–6 only — open Formation Editor, change the lineup, tick
   Freeze Lineup, `Data → Save`). Don't save/reload the career between
   snapshot and this step — keep it to a single live session so the diff
   isn't polluted by other state changes.
3. Run `snapshot_lineup_tables.lua` again. This is your **after** snapshot.
4. Copy both JSON files out of the Wine prefix (same path pattern as
   `track-c-fut-table-test.md`: `~/Games/umu/.../drive_c/FIFA 23 Live
   Editor/`) and run:

   ```bash
   python3 tools/squad-injector/diff_snapshots.py before.json after.json
   ```

5. The output shows exactly which table(s) and field(s) changed. This is the
   real, confirmed write Freeze Lineup performs — record it in the Results
   table below.

## Phase 3 — replicate the write via script

1. Open `tools/squad-injector/apply_lineup_write.lua` and fill in
   `TARGET_TABLE` and `TARGET_FIELDS` using Phase 2's diff output.
2. Edit `C:\FIFA 23 Live Editor\openfut_test_xi.json`:

   ```json
   {
     "team_id": 12345,
     "xi": [
       { "player_id": 111111, "position": 0 },
       { "player_id": 222222, "position": 5 }
     ]
   }
   ```

   Use 11 entries. Position codes are **confirmed numeric 0–27**
   (`GK=0, SW=1, RWB=2, RB=3, RCB=4, CB=5, LCB=6, LB=7, LWB=8, RDM=9, CDM=10,
   LDM=11, RM=12, RCM=13, CM=14, LCM=15, LM=16, RAM=17, CAM=18, LAM=19,
   RF=20, CF=21, LF=22, RW=23, RS=24, ST=25, LS=26, LW=27`) — from
   `lua/scripts/export_season_stats.lua`'s `get_pos_name` table in FLE's own
   repo, not a guess.
3. Run `apply_lineup_write.lua` from FLE's Lua Engine.
4. Repeat the save-to-new-slot / reload / check-lineup verification from
   Phase 1, but this time without ever opening the Formation Editor — the
   write was made entirely from the script.

## Classification criteria

### "Confirmed — full mechanism works"

Phase 1 holds, Phase 2 finds a clean diff, Phase 3's scripted write produces
the same in-match result as the manual GUI path.

**Verdict:** Build-order step 1 done. Proceed to step 2 (bridge transport) in
`docs/direction.md`.

### "GUI works, script doesn't"

Phase 1 holds but Phase 3's replicated write doesn't stick, even though the
diffed fields matched what changed in Phase 2.

**Verdict:** Freeze Lineup likely does more than a single DB field write
(e.g. an internal engine call beyond `EditDBTableField`'s reach, or a second
write the diff missed because it happened in a table outside the `KEYWORDS`
filter in `snapshot_lineup_tables.lua` — widen the filter and redo Phase 2).

### "Freeze Lineup doesn't hold at all"

Phase 1 fails — the lineup reverts to the game's own AI-picked XI regardless.

**Verdict:** No confirmed mechanism exists for forcing a lineup. This kills
the bridge architecture as designed in `direction.md` §3 and needs a return
to first principles — there is no fallback documented anywhere in FLE's wiki
for this specific case.

## A note on the umu/Wine F9/F11 hotkey issue

If FLE's F9 (hide/show) hotkey isn't registering under umu, this is plausibly
a Wine keyboard-hook limitation (FLE's global hotkey detection likely uses a
low-level hook that doesn't translate cleanly through Wine's input layer) —
not something documented anywhere in FLE's own troubleshooting docs, which
don't mention Linux/Wine at all. F11 specifically has **no documented FLE
function** — F9 is the only documented toggle. Workaround: click directly
into the FLE overlay window (it should still be visible/clickable even if the
hotkey doesn't fire) and use its own menu bar instead of relying on the
hotkey.

## Results

*(To be filled in after the test is run.)*

| Field | Value |
|---|---|
| Date run | — |
| Phase 1: Freeze Lineup holds into a match? | — |
| Phase 2: table(s)/field(s) changed | — |
| Phase 3: scripted write reproduces Phase 1 result? | — |
| **Classification** | **PENDING** |
