fix(fifa17): key the kit home/away split on the carddbid, not assetid

Staging served `kits=2 kitsHome=0 kitsAway=0`: the split compared the catalog
`asset_id` against `fcc_kitcards.assetid` (14/15), but a kit's catalog
`asset_id` IS its carddbid (6300006), not that column, so neither family ever
matched.

The carddbid range is the same fact in the form we actually carry: across all
1482 kit rows, assetid 14 covers precisely the 828 `63xxxxx` ids and assetid 15
precisely the 654 `64xxxxx` ids, with no exceptions either way. Keying on the id
we already have avoids carrying `assetid` as a second source of truth for the
same split. Tests now use the real team-21 pair (6300006 home / 6400003 away).

Verified against the staging stack: `kits=2 kitsHome=1 kitsAway=1`, team-21
bucket 2, `?type=kit` still activeHomeKit/activeAwayKit, `?type=player` 12.
This commit is contained in:
funman300
2026-08-21 04:13:11 +00:00
parent 3442eac6f0
commit 054a912357
+33 -21
View File
@@ -66,12 +66,20 @@ const S_KITS_HOME: i64 = 0x29;
const S_KITS_AWAY: i64 = 0x2A;
const S_BADGES: i64 = 0x2D;
/// `fcc_kitcards.assetid` splits the kit table into the home and away families.
/// Verified across all 1482 rows of the FIFA 17 kit table: assetid 14 covers
/// exactly the `63xxxxx` carddbids (828 rows) and assetid 15 exactly the
/// `64xxxxx` ones (654 rows), with no exceptions in either direction.
const KIT_ASSET_HOME: i64 = 14;
const KIT_ASSET_AWAY: i64 = 15;
/// First `carddbid` of the AWAY kit family. `fcc_kitcards` is split into a
/// `63xxxxx` home family and a `64xxxxx` away family, and the table's own
/// `assetid` column agrees exactly: across all 1482 rows, assetid 14 covers
/// precisely the 828 `63xxxxx` ids and assetid 15 precisely the 654 `64xxxxx`
/// ids, with no exceptions either way. A kit's catalog `asset_id` IS its
/// carddbid, so the id itself is the family key -- the `assetid` column is not
/// carried on the wire and would be a second source of truth for the same fact.
const KIT_AWAY_FLOOR: i64 = 6_400_000;
/// Which kit family an owned kit belongs to. Only meaningful for
/// [`ContentKind::Kit`]; the caller filters first.
fn is_home_kit(kit: &ClubStatInput) -> bool {
kit.asset_id < KIT_AWAY_FLOOR
}
/// cardsubtypeid (staff family) -> stat id (STAFF_SUBTYPE_STAT).
fn staff_stat(subtype: i64) -> Option<i64> {
@@ -240,11 +248,10 @@ pub fn club_stats_body(items: &[ClubStatInput], ctx: ContextField) -> Value {
.iter()
.filter(|item| matches!(item.kind, ContentKind::Kit))
.collect();
let kits_with_asset =
|asset: i64| kits.iter().filter(|item| item.asset_id == asset).count() as i64;
let home = kits.iter().filter(|kit| is_home_kit(kit)).count() as i64;
g.insert(S_KITS, kits.len() as i64);
g.insert(S_KITS_HOME, kits_with_asset(KIT_ASSET_HOME));
g.insert(S_KITS_AWAY, kits_with_asset(KIT_ASSET_AWAY));
g.insert(S_KITS_HOME, home);
g.insert(S_KITS_AWAY, kits.len() as i64 - home);
let mut stat: Vec<Value> = g.iter().map(|(sid, v)| row(1, 0, *sid, *v)).collect();
@@ -344,22 +351,27 @@ mod tests {
team_id: None,
}
}
/// A kit of the given family (`KIT_ASSET_HOME` / `KIT_ASSET_AWAY`) worn by
/// `team`.
fn kit_of(asset_id: i64, team: i64) -> ClubStatInput {
/// A kit worn by `team`. `carddbid` is the real `fcc_kitcards` id, which is
/// also the catalog `asset_id` and therefore the home/away family key.
fn kit_of(carddbid: i64, team: i64) -> ClubStatInput {
ClubStatInput {
kind: ContentKind::Kit,
subtype: 9,
rating: 0,
rare: false,
asset_id,
asset_id: carddbid,
nation_id: None,
league_id: None,
team_id: Some(team),
}
}
/// Real team-21 kits from `fcc_kitcards`: 6300006 is its home kit and
/// 6400003 its away kit.
const HOME_KIT: i64 = 6_300_006;
const AWAY_KIT: i64 = 6_400_003;
fn kit() -> ClubStatInput {
kit_of(KIT_ASSET_HOME, 21)
kit_of(HOME_KIT, 21)
}
fn global(body: &Value) -> std::collections::HashMap<String, i64> {
@@ -432,9 +444,9 @@ mod tests {
#[test]
fn kit_counts_split_by_home_and_away_family() {
let items = vec![
kit_of(KIT_ASSET_HOME, 21),
kit_of(KIT_ASSET_HOME, 38),
kit_of(KIT_ASSET_AWAY, 21),
kit_of(HOME_KIT, 21),
kit_of(6_300_010, 38),
kit_of(AWAY_KIT, 21),
];
let g = global(&club_stats_body(&items, ContextField::Nation));
assert_eq!(g["kits"], 3);
@@ -450,9 +462,9 @@ mod tests {
with_team.team_id = Some(21);
let items = vec![
with_team,
kit_of(KIT_ASSET_HOME, 21),
kit_of(KIT_ASSET_AWAY, 21),
kit_of(KIT_ASSET_HOME, 38),
kit_of(HOME_KIT, 21),
kit_of(AWAY_KIT, 21),
kit_of(6_300_010, 38),
];
let body = club_stats_body(&items, ContextField::Team);
let kits_for = |team: i64| {