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
+7
View File
@@ -589,7 +589,14 @@ def materialise(lay: Layout) -> None:
definitions.append({
"id": mgr["card_id"],
"name": mgr["label"],
# `overall` STAYS 0. It feeds pricing and squad projection, and a
# staff card is not a player; the authoritative number lives in
# `source_rating` below, which is what the contract-tier rules read.
"overall": 0,
# managercards.value, the same number the catalog carries as
# `rating`. Core owns it so the manager-contract tier is resolved
# from Core-owned state rather than from adapter projection.
"source_rating": mgr["rating"],
"position": "",
"nation": "",
"league": "",