feat(fifa17): manager contracts, from a Core-owned staff tier

ROOT CAUSE, one line. openfut-import-fifa17 emitted `"overall": 0` for every
non-player Core definition while `d.rating` already held EA's authoritative
`value` -- and the very next block wrote that same number correctly to the
adapter catalog. So the tier existed host-side but never reached Core:
Core overall 0 -> /collection effective_overall 0 -> CoreOwnedItem.rating 0 ->
tier_for_rating(0) = Bronze for a Gold (88) manager. That silent mis-grant is
exactly what the 409 was protecting against, so the refusal was correct.

The emitter now also writes `source_rating`, keeping `overall` at 0. Regenerating
the production pack changes exactly 18 entries and exactly one field each
(source_rating None -> value); same 1710 ids, same fingerprint 28c333f1e833338a.

WHY value IS the tier source, and why the thresholds are the player ladder:
LIVE_PROVEN, not inferred. The client re-rates staff from its own
managercards/*coachcards/physiocards by carddbid and applies discard_level's
65/75 ladder; coach_probe/discard_probe agree 4/4 (manager value 88 -> level 3,
coaches 66 -> level 2). The shipped coach tables corroborate: each family has
exactly 3 tiers x 2 rarities, and only 65/75 splits them 2/2/2.

Manager contracts stop refusing and now resolve the TARGET's tier from
Core-owned state. Still fail-closed everywhere it matters: a coach or physio is
`contract_target_not_a_manager` (only cardsubtypeid 4 is a manager), and a
manager Core carries no source_rating for is `manager_tier_unknown` rather than
a guessed tier. Core's own content_kind token is sent as target_kind, because
Core calls the squad manager `manager` while the catalog classifies it
`staff`+subtype 4.

NOT implemented, unchanged: STORED_MANAGER_BONUS and MATCH_CONTRACT_DECREMENT.
This commit is contained in:
funman300
2026-08-22 20:08:26 +00:00
parent f0c6dcf238
commit 9026220533
13 changed files with 541 additions and 68 deletions
@@ -118,6 +118,8 @@ fn oracle_tables() -> (HashMap<String, CoreOwnedItem>, TableIdentity) {
// contract count, so the round trip proves the PERSISTED number
// reaches the wire rather than a constant.
contract_matches: it["contract"].as_i64(),
source_rating: None,
core_content_kind: None,
},
);
ident.insert(
@@ -343,6 +345,11 @@ fn persisted_read_round_trips_via_reconstructed_canonical_and_extension() {
// carries no staff contract to mirror: this instance is untracked and
// must fall back to the pack-fresh default.
contract_matches: None,
// Core's authored staff `value`; the squad projection never reads it (the
// client re-rates a manager from its own table), so the round trip is
// unaffected either way.
source_rating: Some(88),
core_content_kind: Some("manager".to_string()),
};
let kicktakers: Vec<KicktakerRef> =
serde_json::from_value(oracle["kicktakers"].clone()).unwrap();