# openfut-protocol-blaze

Game-independent EA Blaze wire protocol: **Fire2** framing and the **Heat2/TDF**
codec.

This is the first Rust component of the Python → Rust migration. It was chosen
first because it is the lowest layer that is genuinely game-independent, it has
an executable oracle, and both existing Rust implementations of it are wrong.

## Scope

| In | Out |
|---|---|
| Fire2 16-byte frame header, frame/stream splitting | Component and command *name* tables |
| Heat2 tag packing, varints, the 11 value types | Notification IDs, response schemas |
| A message = frame + decoded body, routed by number | Login sequencing, session identity |
| Diagnostics dumps | Anything FIFA-17-specific |

The boundary test: *could FIFA 18 or FIFA 23 use this without importing FIFA
17's command tables?* This crate knows `0x0009/0x0007` is component 9, command
7. That it means `Util::preAuth` is a FIFA 17 fact, and belongs in a FIFA 17
adapter.

## Provenance

Ported from `fifa17-recon/tools/heat2.py` (TDF codec) and
`fifa17-recon/tools/blaze_responder_v3b.py` (Fire2 framing) — the Python
implementation that drove a retail FIFA 17 client from Origin login to an
opened FUT pack. That implementation is the project's behavioural oracle, and
this crate does not claim parity with it, it *tests* parity against it.

### Two superseded framing implementations

Both other Fire2 implementations in this repository are wrong for FIFA 17, and
this crate exists partly to replace them:

* **`fifa-blaze/crates/blaze-proto/src/frame.rs`** — a **12-byte** header with a
  `u16` length, nibble-packed type/options, an `error` field, and a JUMBO-frame
  escape flag. Its own doc comment says FIFA 23's variant "is UNKNOWN" and that
  Fire2 was picked because it "is the most likely candidate". It predates the
  FIFA 17 recon and nothing has since validated it.
* **`fifa17-recon/tools/heat2.py::build_fire2_frame`** — packs `>IHHHHB3s`,
  putting a `u16 msgId` at `[10:12]` and `msgType` at `[12]`. Dead code: the
  responder carries a comment telling callers not to use it, and it is not on
  any live path. Its module docstring still describes the old layout.

The proven layout is 16 bytes, with a `u24 msgNum` at `[10:13]` and
`(msgType << 5) | userIndex` in byte 13. There is **no error field** (that is
Fire v1) and **no jumbo flag** (the length is already a `u32`). The
`payload_over_64kib_needs_no_jumbo_flag` test is the direct refutation.

## Confidence is not uniform

`int`, `string`, `blob` and `struct` are validated byte-exact against captured
FIFA 17 traffic. `list`, `map`, `union`, `varlist`, `objtype`, `objid` and
`float` are marked UNVERIFIED in the oracle — they are absent from every capture
we hold. `TypeId::is_verified()` reports which is which, and a test asserts the
unverified ones stay flagged, so "Rust and Python agree" can never be quietly
read as "this is how EA does it".

## Testing

```bash
cargo test -p openfut-protocol-blaze     # 43 unit + 10 differential + 1 doc
./check-parity.sh                        # regenerate fixtures, then re-verify
```

Differential vectors live in `fixtures/`, generated by `fixtures/generate.py`
from the Python oracle. 25 of the TDF vectors and 6 of the Fire2 vectors are
`origin: "live"` — real payloads from the responder's own builders, including
the preAuth reply (~11.8 KB) that is the first RPC FIFA 17 sends.

Comparison is **byte-for-byte**. FIFA 17's deserialisers hard-freeze on an
unexpected shape, so "semantically equivalent" is not a useful category at this
layer. (It *is* the right call one layer up at UTAS/JSON — see
`fifa17-recon/tools/test_fut_contract.py`.)

Regenerate fixtures after any change to the Python oracle:

```bash
python3 fixtures/generate.py           # rewrite
python3 fixtures/generate.py --check   # assert committed files are current
```

## No runtime dependencies

Deliberate. This is a byte-level codec whose oracle is stdlib-only Python; there
is nothing here a third-party crate can do that `std` cannot. In particular the
crates.io `tdf` crate (already a `fifa-blaze` dependency) is **not** used: it
targets a generic BlazeSDK 15.x dialect, and adopting it would substitute
someone else's reading of the format for our own captured evidence. It remains
useful as an independent cross-check, not as the implementation.

`serde_json` is a dev-dependency only, for reading fixture files.

## Not yet done

* No TLS, no sockets, no async. Framing and codec only; transport belongs to
  whatever hosts this.
* The Blaze **redirector** (HTTPS + XML `getServerInstance`) is a different
  protocol and is not here.
* Nothing consumes this crate yet. The Python backend remains the live runtime,
  untouched.
