A/B variantsA/B варіанти NEW v13
v13 finding: Claw Master uses a custom SibirGames.OnlineConfigs framework (NOT Firebase Remote Config, NOT Unity Remote Config). Architecture: each gameplay config sheet is fetched live from Google Sheets on every boot; the "Experiment" sheet (loaded first, Order=-2) routes each user to a variant by hashing their stable user_id and bucketing into a weighted group, then the variant's sheet suffix (e.g., LevelList_VariantB) is downloaded instead of the default tab. Previous notes' "5 variants" was a miscount — actually 1 experiment × 4 arms (control + 3 variants, uniform 25/25/25/25 split).
v13 знахідка: Claw Master використовує власний фреймворк SibirGames.OnlineConfigs. Кожен лист конфігу тягнеться з Google Sheets при кожному запуску; лист "Experiment" вантажиться першим і призначає користувача варіанту через хеш user_id. Замість 5 варіантів — насправді 1 експеримент × 4 руки (control + 3 варіанти, рівномірно 25/25/25/25).
FACTS / ASSUMPTIONS / MISSING:
FACT: framework architecture, class names, the baked-in TableExperiment row, group weights, sheet names, the remote endpoint URL.
INFERRED: the mapping TargetSheets="Level" → real sheet name LevelList (the LevelList sheet is the only one starting with "Level").
MISSING: the actual variant override values — they live in Google Sheets tabs LevelList_VariantB/C/D that the APK never sees. To close this gap, fetch the public Apps Script endpoint.
🧪 Active experiments — summary🧪 Активні експерименти — підсумок
⚠ ZERO active experiments in this APK snapshot. 1 experiment row exists (name='default', target=LevelList sheet, 4-arm 25/25/25/25 split) but is_active=0 (dormant). The Google Sheet at id 1q4LO8smTzrYZB...
MdafXt8-TvQK5ZlWdf2TizYZbKcSZ4, tab 'Experiment', is the source of truth at runtime — it overwrites the baked-in TableExperiment asset on every boot (LastUpdateDate is empty, Order=-2). To see what's REALLY running, fetch that sheet.
🎯 The one experiment in this APK🎯 Єдиний експеримент у цьому APK
- Experiment nameНазва експерименту
default
- Is activeАктивний
- NO (dormant) — FACT (IsActive=0 in extracted typetree)
- AudienceАудиторія
- 100% of all installs
- Target sheetsЦільові листи
Level → resolves to LevelList (LevelsListConfig)
- What it controlsЩо контролює
- Master list of all 16 biomes/levels (Neon District, Dark Catacombs, Blazing Caves, Abandoned City, Ghostly Swamp, Ancient Ruins, Frozen Tundra, Desert Oasis, Clockwork Factory, Poisonous Marsh, Scrapyard, Glacial Peaks, Mystic Woods, Crystal Caves, Enchanted Forest, Molten Fields) and per-level metadata. Could be wave counts, biome unlock order, level rewards table linkage.
- Rollout splitРозподіл rollout
- 25/25/25/25 (each group weight = 25)
- Variant countКількість варіантів
- 4
📋 The 4 variant arms📋 Чотири варіанти
| VariantВаріант |
WeightВага |
Rollout %Rollout % |
Sheet suffixСуфікс листа |
MeaningЗначення |
Override valuesЗначення оверрайдів |
| variant_a CONTROL | 25 | 25% | (empty = control) | Empty suffix = control / default LevelList sheet. Player gets the same data as if they were not in any experiment. | unknown — variant_a uses the base LevelList sheet which is fetched live from Google Sheets. No baked-in override values in the APK. |
| variant_b VARIANT | 25 | 25% | _VariantB | Player downloads sheet tab named 'LevelList_VariantB' instead of 'LevelList'. | unknown — content of LevelList_VariantB tab lives on Google Sheets, not in the APK. Could not be extracted. |
| variant_c VARIANT | 25 | 25% | _VariantC | Player downloads sheet tab named 'LevelList_VariantC' instead of 'LevelList'. | unknown — content of LevelList_VariantC tab lives on Google Sheets, not in the APK. Could not be extracted. |
| variant_d VARIANT | 25 | 25% | _VariantD | Player downloads sheet tab named 'LevelList_VariantD' instead of 'LevelList'. | unknown — content of LevelList_VariantD tab lives on Google Sheets, not in the APK. Could not be extracted. |
🌐 Remote config endpoint (Google Sheets)🌐 Endpoint віддаленого конфігу (Google Sheets)
- Apps Script URLURL Apps Script
https://script.google.com/macros/s/AKfycbxpqIS2yRH8Ext4RMAMOiOWt1H0eendUGfWRtsemN-RJJircsWalLDCOK4Kaei2LPts/exec
- Spreadsheet keyКлюч таблиці
1q4LO8smTzrYZBMdafXt8-TvQK5ZlWdf2TizYZbKcSZ4
- App nameНазва застосунку
ClawMasterBalance
- Balance versionВерсія балансу
- 4
- Experiment sheet nameНазва листа експериментів
Experiment
- Last cachedКешовано останній раз
- (empty in APK — never cached locally because Order=-2 forces fetch on every boot)
Why "Experiment sheet has no cache":Чому "лист Experiment не кешується":
The Experiment sheet has Order=-2, which forces the manager to fetch it on every boot — bypassing local cache. This means: (a) the experiment state can change at any time without an APK update, (b) the only authoritative source of "what's running right now" is the live Google Sheet, not the APK.Лист Experiment має Order=-2, що змушує менеджер тягнути його при кожному запуску — обходячи локальний кеш. Це означає: (a) стан експерименту може змінитися без оновлення APK, (b) єдине справжнє джерело "що зараз працює" — це сам Google Sheet, не APK.
🏗️ Framework architecture (key classes)🏗️ Архітектура фреймворку (ключові класи)
| ClassКлас |
PurposeПризначення |
TableExperiment | OnlineConfigBase, ISingletonConfig (dump.cs:878893). Top-level container. Field Experiments[]. |
Experiment | ITableRecord (dump.cs:878908). Fields: ExperimentName(string), IsActive(bool), AudiencePercent(float), TargetSheets(string[]), Groups(TableExperimentGroup[]). |
TableExperimentGroup | ITableRecord (dump.cs:878931). Fields: GroupName(string), GroupWeight(int), TableSuffix(string). |
TableExperimentManager | dump.cs:879128. Methods: GetUserGroup, AssignUserToGroup, IsUserInAudience, ChangeUserGroup, RemoveUserFromExperiment, CheckExperiments, GetGroupForAnalitic. Uses GetStableHash on user id for deterministic bucketing. |
ExperimentSaveDataPresent | dump.cs:880236. PlayerPrefs key prefix: 'user_group_' → groupName. So your assigned variant survives across launches. |
OnlineConfigManager.IsExperimentForSheet | dump.cs:880064. Decides whether a given live sheet should be re-downloaded with a variant suffix. (Body not decompiled in dump.cs; matching against TargetSheets[] entries.) |
Bucketing flow (verified from dump.cs)Логіка bucketing (перевірено з dump.cs)
- On boot,
OnlineConfigManager fetches the Experiment sheet first (Order=-2).
- For each experiment row,
TableExperimentManager.GetUserGroup hashes user's stable id with GetStableHash.
- If user falls within
AudiencePercent, they're assigned to a variant weighted by GroupWeight.
- Assignment is saved to
PlayerPrefs at key user_group_<experimentName>.
- For each sheet in
TargetSheets[], the variant's TableSuffix is appended to download the variant-specific tab.
- The variant assignment is exposed to analytics via
GetGroupForAnalitic (sic — typo in source).
⚠️ What's still missing⚠️ Що ще відсутнє
- FACT: Variant override values themselves are server-side — fetching Google Sheet 1q4LO8smTzrYZBMdafXt8-TvQK5ZlWdf2TizYZbKcSZ4 tab 'Experiment' + tabs 'LevelList', 'LevelList_VariantB', 'LevelList_VariantC', 'LevelList_VariantD' would close this gap. The sheet appears to be a public read-only Google Apps Script endpoint (no auth tokens required in client code).
- FACT: Country / install-date / level-gate segmentation is NOT supported by SibirGames.OnlineConfigs as designed. The framework only buckets by user id hash within an audience percent. Any country/install gating would need to be implemented client-side outside this framework (does not appear to be).
- FACT: Sheet name 'LevelList' is bound to LevelsListConfig (the master list of biomes/levels). It is plausible the variants are testing level pacing, biome unlock cadence, or specific level rewards — but without the live sheet content this is inference only.
- INFERRED: The 'default' experiment name suggests Sibir uses this slot as a 'currently running default test' rather than a permanent fixture. If you have analytics access (Amplitude), querying user property 'experiment_group' or similar for distinct values in the last 30 days would surface what's truly live.
- FACT: There is NO ABTestConfig / ABTestVariantConfig / RemoteConfigOverride / SegmentConfig / ConfigOverride class in dump.cs. The TableExperiment system above is the only experimentation infrastructure in this build.
📝 Correction vs. previous notes📝 Виправлення стосовно попередніх нотаток
EXTRACTION_NOTES.md and README.md said: '5 variants known by name only (Default, variant_a/_VariantB, variant_b/_VariantC, variant_c/_VariantD, variant_d). Actual variant overrides are server-side via OnlineConfigs.'
Now confirmed:
Тепер підтверджено:
- The 5 names were actually 4 group names plus the implicit baseline: variant_a (suffix=''), variant_b (suffix='_VariantB'), variant_c (suffix='_VariantC'), variant_d (suffix='_VariantD'). 'Default' in previous notes was a misread — there is no 'Default' group; variant_a is the control because its TableSuffix is empty.
- The single experiment is named 'default' (the experiment_name, not a group name).
- Group weights are all 25 (uniform). Audience percent is 100. Experiment is currently inactive.
- Experiment targets exactly one sheet ('Level' → LevelList).
- Bucketing is deterministic on user id (hash mod sum of weights); user assignment is saved to PlayerPrefs (user_group_default).
Still missing:
Все ще відсутнє:
- Actual numeric/structural overrides per variant — these are columns in Google Sheets tabs LevelList_VariantB / _VariantC / _VariantD that the APK never sees until runtime.
- Live is_active state on Google Sheets — could differ from the baked-in IsActive=0.
- Any experiments added to the Experiment sheet AFTER 2026-01-22 (last extraction date — the Experiment sheet itself had no LastUpdateDate cached, meaning it has not been fetched-and-saved by any local play session of this APK snapshot).
- Whether other experiments exist alongside 'default' on the live Google Sheet — the APK can support arbitrarily many Experiment rows (it's an array), but only one is baked in.
🎯 Design implications for Claw Fight🎯 Дизайнерські висновки для Claw Fight
- Sibir uses a single-experiment slot. Only 1 experiment row is ever baked in — the "default" slot is reused for whatever they're currently testing. Simple, low-overhead. If Claw Fight wants concurrent experiments, that's a deliberate framework choice not a Sibir-default.Sibir використовує один експеримент-слот. У APK зашитий один рядок — слот "default" перевикористовується для поточного тесту. Простіше, менше навантаження. Якщо CF хоче паралельні експерименти — це окремий вибір, а не дефолт Sibir.
- No segmentation logic in the framework. Bucketing is purely
hash(user_id) mod weights. No country / level / install-date / cohort gating. If CF needs targeted experiments (e.g. only paying players, only mid-game), client-side gating must be added.Немає логіки сегментації у фреймворку. Bucketing — чистий hash(user_id) mod weights. Без сегментації за країною / рівнем / датою інсталу. Якщо CF потрібні таргетовані експерименти, це окрема логіка на клієнті.
- Sheet-suffix design = whole-config swap. A variant doesn't override individual fields — it swaps the entire
LevelList sheet for LevelList_VariantB. Easy to author (just duplicate the tab) but hard to do per-field A/B (a change to one column requires copying the whole sheet). Trade-off worth noting.Дизайн з суфіксом листа = повна заміна конфігу. Варіант не оверрайдить окремі поля — він замінює весь лист LevelList на LevelList_VariantB. Просто авторити (дублюй таб), але важко робити per-field A/B (зміна однієї колонки = копіювання всього листа).
- Order=-2 forces fetch every boot. Lower order = higher priority. Pattern is clean: experiments are stateless and authoritative, never cached. Live remote control without an APK update. Worth copying for CF if liveops cadence matters.Order=-2 змушує тягнути при кожному запуску. Менший order = вищий пріоритет. Експерименти не кешуються, завжди беруться з сервера. Live remote control без оновлення APK.
- The "default" experiment is dormant. It's loaded into the APK but turned off (
IsActive=0). Sibir either had no live experiment when this build was cut, OR they enable/disable via the sheet at any time. To find out what's running NOW: fetch the spreadsheet directly. (Out of scope for this skill — needs an authorisation decision from you.)Експеримент "default" неактивний. Завантажений у APK, але вимкнений (IsActive=0). Або Sibir не тестував нічого коли білдили цю версію, або вони вмикають/вимикають через лист. Щоб побачити що йде ЗАРАЗ — потрібно тягнути лист напряму (поза межами скіла без твого дозволу).