fix(fifa17): disable squad.actives by default after it emptied the squad
Populating `squad.actives` is the proven way to make a club item resident — the squad parser writes each element straight into a club-item slot, both kits came back resident with the client writing `category 4` itself, and the pre-match kit selector worked. But a populated array was then observed to cost the rest of the squad. On a full client relaunch the resident item map fell from 24 entries to just the 2 kits, the 23-slot player vector came back fully null, and the starting-11 screen was empty; the manager and staff were gone too. Every host response was 200/outcome=ok with no warning, so the loss is entirely client-side parse behaviour. `actives` sorts first in the squad object, so `captain`, `formation`, `manager`, `players` and everything else after it are lost — consistent with the element loop leaving the tokenizer misaligned. The same payload produced a correct 24-node map on an earlier relaunch, so the interaction is not yet understood and is not safely shippable. An empty squad is far worse than a missing kit, so the array is now gated behind `HostConfig::squad_actives` (env `OPENFUT_FIFA17_SQUAD_ACTIVES`) and off by default. The projection, identity plumbing and tests are kept intact: they are correct and are what the investigation will re-enable. Staging redeployed with the flag off and verified back to 23/23 populated player slots and `actives: []`.
This commit is contained in:
@@ -902,6 +902,7 @@ fn from_config(base: &str, dir: &std::path::Path) -> openfut_utas_host::config::
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
sbc_post_commit_fault: openfut_utas_host::config::SbcPostCommitFault::Off,
|
||||
squad_actives: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1150,6 +1150,7 @@ fn put_full_replacement_commits_canonical_and_extension_and_acks_id0() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let body = put_body(
|
||||
"f442",
|
||||
@@ -1192,6 +1193,7 @@ fn put_assigns_the_owned_manager_and_a_later_save_clears_it() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
|
||||
let with_manager = put_body(
|
||||
@@ -1234,6 +1236,7 @@ fn put_saves_the_squad_when_the_manager_ref_does_not_resolve() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
|
||||
let body = put_body(
|
||||
@@ -1279,6 +1282,7 @@ fn put_rejects_wire_id_owned_by_another_profile_core_unchanged() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let body = put_body(
|
||||
"f442",
|
||||
@@ -1305,6 +1309,7 @@ fn put_rejects_unknown_wire_id() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
// 999_999_999 was never allocated → unresolvable.
|
||||
let body = put_body(
|
||||
@@ -1330,6 +1335,7 @@ fn put_rejects_duplicate_owned_item() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let body = put_body(
|
||||
"f442",
|
||||
@@ -1355,6 +1361,7 @@ fn put_core_failure_returns_error_never_python() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let body = put_body("f442", w["oc-a"], &[(0, w["oc-a"], 1)], "[]", None);
|
||||
let (resp, log) = handle_put_squad(&body, &deps);
|
||||
@@ -1372,6 +1379,7 @@ fn repeated_identical_put_is_idempotent() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let body = put_body(
|
||||
"f442",
|
||||
@@ -1408,6 +1416,7 @@ fn coupled_read_after_write_list_and_usermassinfo_agree() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let body = put_body(
|
||||
"f442",
|
||||
@@ -1513,6 +1522,7 @@ fn squad_active_serves_core_backed_object_with_configured_persona() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
// Commit a squad so Core has a fresh canonical squad + extension.
|
||||
let body = put_body(
|
||||
@@ -1560,6 +1570,7 @@ fn read_path_is_bounded_no_per_slot_lookup() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let body = put_body(
|
||||
"f442",
|
||||
@@ -1614,6 +1625,7 @@ fn stale_extension_is_not_applied_on_reads() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let (resp, log) = handle_squad_list(&deps);
|
||||
assert_eq!(log.outcome, "stale_integrity");
|
||||
@@ -1635,6 +1647,7 @@ fn missing_extension_is_explicit_on_reads() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let (resp, log) = handle_squad_list(&deps);
|
||||
assert_eq!(log.outcome, "missing_integrity");
|
||||
@@ -1656,6 +1669,7 @@ fn usermassinfo_never_serves_python_squad_on_integrity_failure() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let py_body = json!({
|
||||
"userInfo": {"personaId": 7},
|
||||
@@ -1730,6 +1744,7 @@ fn duplicate_definition_instances_stay_distinct_through_host() {
|
||||
core: &core,
|
||||
resolver: &resolver,
|
||||
entities: &ent,
|
||||
squad_actives: false,
|
||||
};
|
||||
let body = put_body(
|
||||
"f442",
|
||||
|
||||
Reference in New Issue
Block a user