ANALYTICS & TELEMETRY

Hub › Dev Tools › Analytics & Telemetry

Canonical plan (v1, July 2026) for hypothesis-driven telemetry: what we measure, where each number comes from, and which authored lever it moves. Purpose per design notes: rebalance drop rates, abilities, stats, general strength, and upgrade chances from observed progression speed — the default analytical lens is the non-buyer (self-found) player; every tracked metric must map to a named lever (a CSV column, a formula constant, or a Remote Config value); and balance truth comes from the server plane, never from client claims. Companion to Backend, Save & Anti-Cheat, which already mandates: UGS Analytics stays OFF (MAU-metered) — use free telemetry.

Requirements traceability

The four driving design notes and where each lands in this plan:

NoteHandled by
Creature wins/losses per level · damage dealt per battle per creature · logout point & session lengthHypotheses C1–C4 (creature performance), S1/D3 (logout context), battle & session schema rows
Hypotheses + data to rebalance drops, abilities, stats, strength, upgrade chances from progression speed — non-buyers firstThe full hypothesis register (D/C/E/B/S groups), proposed target bands, segmentation (non-buyer default lens)
Steam-account login on the codex site for direct per-creature feedbackCreature Feedback System section + hypothesis C6 (feedback × telemetry quadrant)
Item slots filled per container, twice daily or at session begin/endContainer snapshot schema row + hypothesis S4 (inventory pressure); rides every server flush ≈ 20-min granularity, covering both proposed cadences

Principles

PrincipleRule
Server plane is truthBalance reads come from the Cloud Code boundary — server-computed rewards, server-rolled odds, replay-verified battles. Client-side events (sessions, UI, screens) are directional context, never balance evidence. Same doctrine as anti-cheat: the client reports events; the server derives numbers.
Free telemetry onlyPer the backend cost model, UGS Analytics is off (MAU-metered, ~$9–10k/mo at scale). Client plane: GameAnalytics free tier. Server plane: piggyback the existing Cloud Code flush — no new invocations, one outbound append per flush to owned storage.
Time is the anchor The GDD already denominates the whole economy in battles (~109 battles/h endgame, the economy simulator’s figure, dfmc-client tools/sim_econ.mjs BATTLES_PER_HOUR). Every pacing question is answered in battles/hours, matching the design sheets, so observed reality and authored intent share one axis.
Hypothesis → metric → trigger → leverNo vanity metrics. Each register row names the number, the plane it comes from, the threshold that fires, and the authored lever it moves (creatures.csv grades, moves.csv powers, encounter_weights.csv, drop rates, odds ladders, Remote Config constants).
Segment before judgingNothing is interpreted without the buyer/non-buyer split and the realm split. A number that looks fine blended can hide a starving self-found cohort behind a market-fed one.
Numbers say what, feedback says whyTelemetry cannot distinguish "weak" from "feels bad." Every balance read pairs with the site feedback channel before a lever moves.
Privacy by defaultAnalytics ID = salted hash of SteamID64. The Settings menu already ships an Analytics opt-out toggle (on, opt-out) — both planes honor it. Export My Data / Delete Account flows include the analytics store and the feedback DB.

Two collection planes + the feedback loop

Three sources, one warehouse. The client plane exists from the prototype onward and costs nothing; the server plane arrives with roadmap step #16 and is the balance authority; the site plane (Steam-login feedback) is independent and can ship any time.

GAME CLIENT (Unity) GameAnalytics SDK sessions · progression · UI events Event / request buffer battle logs — already exists (backend) CODEX SITE Steam OpenID login per-creature ratings · tags · comments Cloudflare Worker + D1 (free tier) GAMEANALYTICS free dashboards — retention, funnels, sessions, resource flow UGS CLOUD CODE validates · computes rewards rolls odds · rate-caps · replays + 1 analytics append per flush OWNED WAREHOUSE ingest Worker → NDJSON on R2 nightly compaction → Parquet DuckDB — full SQL, local weekly balance report non-buyer lens by default joins all three sources by hashed ID events flush nightly feedback export CSV export (manual, free)

Fig. 1 — Collection topology. The server plane adds zero Cloud Code invocations: the analytics record is appended inside the flush that already runs every ~20 minutes. The client plane works today, in the prototype, before any backend exists.

Segmentation

Every metric in the register is computed per segment. The two structural splits are non-negotiable; the rest are lenses.

SegmentDefinitionWhy
Market cohortnon-buyer (never bought a gameplay-affecting item/creature on the Steam market — the default lens) vs buyer (≥1 such purchase). Selling alone does not flip the flag — a seller still progressed self-found.The design question: does the game pace correctly for players who never touch the market? The market is the variance smoother — non-buyers are the ones exposed to raw RNG.
Progression bandHighest zone reached (1–10).Difficulty and economy read per band, not globally.
TenureDay 0–7 / 8–30 / 31+.Early-funnel problems and endgame problems need different levers.
PlaystyleAuto-share of battles: manual-heavy <25% / mixed / auto-heavy >75%.Ichor is the active-play premium — auto-heavy starvation is by design; measure whether it converts to manual play or to churn.
Ladder tierTop 1% / top 10% / rest, per season (PvP and floor ladders).Competitive balance reads only at the top; population reads only at the base.

Hypothesis register

Each row: the claim, the numbers that test it, the plane they come from, and the trigger → lever. IDs are stable for referencing in weekly reports.

D — Difficulty, floors & progression

IDHypothesisMetrics · planeTrigger → lever
D1The streak clear condition makes floor cost hypersensitive to win rate at depth (see the streak amplifier below). On-progression wild win rate must stay high enough that observed battles-to-clear tracks the design pace.Per-floor win rate (all parties, and level-matched parties); observed battles-to-clear p50/p90 vs the streak-math expectation. Server.Floor whose p50 battles-to-clear >2× the at-target expectation for two weeks → tune that floor's roster (floor_creature_rarity.csv, encounter_weights.csv, offending creatures' grades/moves).
D2Unintended walls appear where enemy level outpaces attainable gear — distinct from the authored XP cliffs in zones 8–10.Time-on-floor p50 normalized against the zone-local trend; next-day return rate per floor. Server + client.Return-rate dip >5 pp vs zone baseline on a non-boss floor → drop weights / roster review for that floor band.
D3Losses drive logoffs at specific floors — the "where players logged off" question.% of sessions ending ≤60 s after a loss, per floor; loss-streak length at logout; last screen at logout. Client (context) + server (loss).Floor in the top decile of rage-quit rate two consecutive weeks → difficulty review; pair with feedback before nerfing.
D4Boss gates should be tense, not grindy: keys are consumed per entry, so retry friction = key economy, and boss kill turns are budgeted by HP = 5×Floor+150.Attempts-per-kill distribution per boss; first-attempt win rate; key wait time (boss-floor arrival → key in hand); keys held at first arrival; boss fight turn counts. Server.p50 attempts >3 or key wait >1 session → key drop rate (open decision — this metric prices it), bosses.csv HP budget / Difficulty_Index / SR active tuning.
D5Auto vs manual divergence classifies floors: manual ≫ auto = strategy check (fine); both ≈100% deep = trivial; both low = stat wall (bad).Win rate by mode per floor; auto-share per floor (a dip = players forced back to manual). Server.Stat-wall floors → roster stats; trivial deep floors → encounter weights. Strategy checks are left alone unless feedback flags them.
D6The level penalty makes over-leveled XP farming pointless — but players may still park on trivial floors for Food/drops, which is an economy signal, not an XP bug.XP/h and battles by (party level − floor) offset; faucet mix on parked floors. Server.Parking concentration on one floor → check that floor's faucet outliers rather than the XP curve.

C — Creatures & moves

IDHypothesisMetrics · planeTrigger → lever
C1At matched rarity, stage, and floor band, creature win rates should cluster; persistent outliers are mistuned lines — the note's "creatures winning and losing battles per level."Per-creature win/loss per floor band, level-matched; deviation from same-rarity cohort median. Server.±5 pp from cohort median at n≥500 battles for two weeks → creatures.csv grades / moves.csv powers & effect magnitudes / synergy-anti bands.
C2Usage × win rate quadrant separates dominance from popularity: a widely used strong creature is only a problem if it is always optimal regardless of context.Pick rate (share of party slots) × win rate, per floor band and PvP rating band. Server.High-pick + high-WR → dominance check (context dependence?); low + low → buff; low-pick + high-WR → discoverability/feedback; high-pick + low-WR → fun-but-weak: buff numbers, keep the kit.
C3Damage accounting exposes over/under-performing kits and dead moves — the note's "damage dealt per battle by creature."Per battle per creature: damage dealt/taken, KOs, faints-first rate, turns alive; per move: use count (manual vs autoplay AI), damage share. Server (client-claimed aggregates, calibrated against the replay-verified subset).A move <5% manual use on a line with ≥25% of its power budget → rework/effect-clarity pass in moves.csv. Kit-wide damage-share outliers → power band review.
C4Turn counts should hold the authored bands: wild 3–5 turns ("mowing through fodder"), bosses in the budgeted kill window.Turn-count distribution per floor band and per boss; 1-turn wipe share deep; >6-turn wild fight share. Server.Drift → move power bands / Core curve review; boss drift → HP budget. (Note the GDD lists boss turn targets both as 8–13 via the HP budget and 10–15 in the turn-target table — flagged below.)
C5Acquisition without use marks weak or unclear kits: lines players hatch but never field.Funnel per line: hatched → ever partied → 50+ battles → S3 reached. Server.High-acquisition / near-zero-use lines → cross-reference feedback tags (C6) before touching numbers — may be a clarity problem, not a power problem.
C6Feedback × telemetry mismatches route the fix: low rating + high WR = feel problem (VFX, kit legibility); high rating + low WR = fun-but-weak, buff numbers and keep identity.Site feedback (rating, tags) joined per creature with WR/pick, votes weighted by experience (≥50 battles with the creature). Site + server.Quadrant assignment feeds the weekly report; levers per quadrant as in C2/C3.
C7PvP meta health: rarity should shape identity, not gate competitiveness outright.Per-creature pick/win by rating band (fully replay-verified); comp clustering; mirror-match rate; SSR share of top-ladder party slots. Server.Top-1% ladder >80% SSR-only slots, or one comp >40% of top-tier matches → synergy/anti clause and grade levers; never a type chart.

E — Economy: drops, upgrades, market

IDHypothesisMetrics · planeTrigger → lever
E1Implemented faucets match authored tables (gear 10%/battle, enhancements 10%, Ichor ~2% on floors 61+, key rate, grade weights by floor band). The server rolls every drop, so this is a free integrity audit.Observed rate per faucet vs table, with confidence intervals. Server.Deviation outside the 99% CI at n≥1,000 → implementation bug hunt before any design change.
E2Non-buyers hit the authored milestones on pace: bracket-appropriate loadout "falls out of the journey," Epic key pieces within weeks of 100, Legendary–Divine in months.Hours/battles to each milestone, p50/p90, non-buyer lens; velocity ratio non-buyer p50 vs buyer p50 at matched playtime. Server.Milestone p50 >125% of design target, or velocity ratio <70% proposed → drop weights, craft costs (25×T), dismantle yields.
E3No-pity gates are survivable in practice: the p90 unlucky tail (≈22× spread) should grumble, not quit — and for non-buyers the market cannot smooth it, so their tail is the one to watch.Observed success per stated chance (grading 100→0.5%, soul ladder); fail-streak distributions per gate; 14-day churn delta of p90-tail rollers vs cohort; non-buyer chase abandonment (attempt cadence stops while income continues). Server.Tail churn delta >5 pp on a marquee gate proposed → revisit the no-pity stance for that gate, or lower the early Ichor costs — decision, not automatic.
E4Each currency stays tight: hoarding (balance grows, sinks idle) and starvation (attempts denied by balance) are both failure states.Per currency (Scrap, Ichor, Food, Dust, Essence, Ink): source/sink flow per hour vs the design anchors (150 / 10 / — / 20 / 20 / 20 per h endgame), days-of-stock, denied-attempt events (client UI: opened upgrade, could not afford). Server + client.Hoard: sink engagement <20% of income for a band → cost/sink review. Starve: denied-attempt rate spike at a band → drop/dismantle yield review.
E5Ichor is the active-play premium (bosses, deep drops, Rare+ dismantles). Auto-heavy players starving on Ichor is intended tension — measure whether it converts to manual play or to churn.Ichor/h by playstyle cohort; grading attempts denied by Ichor vs by materials. Server.open — prior trigger retired; replacement TBD.
E6Grade progression below Epic runs entirely on the Ichor ladder now that combining is gone, so watch that the low-grade steps stay cheap enough not to gate the Ichor gamble as the high-end path.Ichor spent per grade reached ≤ Epic; time-to-first grade-5 tradeable (also calibrates the farm-account market gate). Server.Grade-5 arrival wildly off the farm-gate assumption → per-account market unlock threshold (Remote Config).
E7Market health: prices discover, listings clear, and faucet-rate outliers surface — the "faucet & listing telemetry" the backend spec assigns to analytics.Median price per class/tier; listing velocity; sell-through; per-account faucet rate vs design curve; multi-account clustering flags. Server + Steam. (P2.)Outlier accounts → audit queue; category anomalies → per-class tradeable kill-switch (config) per backend spec.

B — Breeding, hatching, mutants

IDHypothesisMetrics · planeTrigger → lever
B1The Food loop is the egg-production ceiling by design: income caps pens, and dismantling refunds 27–30% without ever becoming an engine.Food income/h by floor vs pen drain by pair grade (breeding.csv); pen idle share among pen owners; net Food across dismantle cycles (must stay negative). Server.Dismantle cycles going net-positive anywhere → yield table bug; chronic pen idleness in a band → Food faucet (RarityMult) review.
B2Hatch outcomes match the weight matrix, and the chase for high grades paces sanely.Hatch grade distribution vs table per egg grade × hatchery level (integrity); time-to-first grade 7/8/9/10 creature, non-buyer lens. Server.Distribution deviation → bug; chase pacing off → egg-grade weights / hatchery grade-boost curve.
B3Mutant rates hold the 0.01–0.10% table and the Codex +0.1% chase actually pulls completionist play.Observed mutant rate per egg grade; codex zone-tier completion progression per cohort. Server.Rate deviation → bug; dead codex chase → surfacing/reward review (design decision).

S — Sessions, retention & containers

IDHypothesisMetrics · planeTrigger → lever
S1Session shape is the baseline health signal, and logout context tells us where the game loses people — the note's "where players logged off and session length."Session length/frequency distributions; last screen, floor, last battle result, loss streak at logout. Client (GA auto-sessions + one logout-context design event).Logout-screen concentration (e.g. inventory or upgrade screen) → that system's friction review.
S2Churn announces itself: declining session length plus a progression stall plus a fail streak is a composite early-warning signal — any single signal alone is noise.7-day session-length trend; days since last floor clear; active fail streaks; churn = no session in 14 days proposed. Client + server.Composite cohort growing → find the shared stall point (floor, gate, currency) and treat that, not the symptom.
S3The earliest funnel dominates retention — first session and first floors decide D7 more than anything endgame.Funnel: first battle → starter picked → first hatch → floor 5 → first advancement → boss 1 killed → floor 11. Client (GA progression + funnels).Any step dropping >20% vs neighbors → onboarding/difficulty fix at that step; this outranks all endgame tuning.
S5Autoplay adoption should be an arc, not a crutch: manual early, mixed later. Day-7 players already >90% auto means manual play failed to hook.Auto-share by tenure cohort; auto-toggle timing in first sessions. Client + server.Early auto-saturation → onboarding pacing / manual-play reward review.

The streak amplifier

Clearing a floor requires ceil(floor^0.65) consecutive wins, and a loss resets the streak. Expected battles to complete an n-streak at per-battle win rate p is E = (1−pⁿ) / ((1−p)·pⁿ) — exponential in n. This is why the win-rate curve per floor is the single most load-bearing chart in the plan: a 10-point win-rate dip that is invisible on floor 9 is a 6× cost multiplier on floor 99.

Win rate pFloor 9 (streak 5)Floor 25 (streak 9)Floor 55 (streak 14)Floor 99 (streak 20)
95%~6 battles~12~21~36
90%~7~16~34~72
85%~8~22~58~165
80%~10~32~109~429
70%~16~79~488~4,174

Expected battles to open the portal, by on-floor win rate: (1 − p^n) / ((1 − p) p^n) for a streak of n = floors.csv Wins_To_Clear. At ~109 battles/h (the economy simulator’s figure, dfmc-client tools/sim_econ.mjs BATTLES_PER_HOUR), 90% ≈ 0.7 h per deep clear (floor 99); 80% ≈ 3.9 h. Boss floors bypass this (always 1 battle, key-gated). Generated by tools/codex_tables.py.

Proposed target bands all pending approval

Analytics needs authored targets to alarm against. These are proposals derived from the streak math, the authored turn/pacing targets, and the research below — none is canon until approved.

TargetProposed bandRationale
On-progression wild win rate≥85% floors 1–40 · ≥90% floors 41–100Keeps expected battles-to-clear within the zone-time sheet; the streak amplifier punishes anything lower at depth.
Boss first-attempt win rate35–60%; attempts-per-kill p50 ≤3Bosses should be the tense beat; keys-per-entry makes long attempt chains expensive in farm time.
Non-buyer velocity ratio≥70% of buyer p50 at matched playtimeThe market may accelerate; it must not become the only viable pace.
Milestone pacing toleranceobserved p50 within ±25% of authored targetDesign targets exist in the GDD milestone table; this is the alarm width.
Churn definitionno session in 14 daysGrind/autoplay game: 7 is too twitchy, 28 too slow to react; literature uses 7/14/28 — pick 14.
Odds integrity alarmoutside 99% CI at n≥1,000 attempts per gateSeparates RNG noise from implementation bugs before touching design.
Turn-count bandswild 3–5 (alert: p50 >6, or 1-turn share >60% deep) · boss 8–15Authored targets; boss band spans the HP-budget (8–13) and turn-table (10–15) figures pending the flag below.

Event schema

Where this lives today (2026-07-29). The server plane is unbuilt. The battle and floor_clear records are written into the player's LOCAL save as a precursor — the adventure log's archive — using the field names below, so that when the server flush lands the shape does not change and the alpha's data is not shaped differently from launch data. Everything local is client-written and therefore tuning evidence, not balance proof.

Server plane — derived inside the existing Cloud Code flush; one compact NDJSON record batch appended per flush. Every record carries {analytics_id, realm, ts, client_version}.

RecordFieldsNotes
battlebattle_id, floor, mode (auto/manual), result, turns, duration_s, streak_before→after, snap[6] and acts[] (see below), verified flagRecorded as tuples, not aggregates (D ruling 2026-07-29). Given each unit's opening attributes and the actions in resolution order, turn order is derived — and so are move usage, per-creature damage, KO attribution and the value of Speed. Storing aggregates would store this year's answers; storing the stream keeps next year's questions askable. snap is six rows of [slot, name, level, grade, atk, def, spd, maxHp, types] captured at the opening bell. acts is one tuple per resolved action, in order: [round, actor, move, target, damage_rolled, flags], flags bit 1 super-effective, 2 target downed, 4 no damage (buff/support/miss). The damage recorded is the ROLLED value, after the 0.9–1.1 band and every multiplier — a re-derived number cannot reconstruct the battle that actually happened. Multi-hit accumulates into one tuple. Capped at 400 actions so a runaway fight cannot blow the save. Party/result/floor are server-validated (the buffer already carries them). The damage figures are client-written until the server plane lands: sanity-bounded and calibrated against the replay-verified subset (bosses, PvP, ~1% sample) — sufficient for tuning, honest about trust.
floor_clearfloor, n battles_on_floor, l losses, s wall_time_s, f first_clear flag — BUILT (local save) 2026-07-29, counted per visitFeeds D1/D2 directly.
boss_attemptboss_id, result, turns, party, keys_remaining, attempt_noImmediate-tier event already; analytics rides it.
dropsper flush, folded counts: {source, family, tier, grade → qty}Never per-item rows — volume control. Server rolled them; rates are exact.
attempttype (craft/grade/soul/enchant), family, tier, from→to, stated_p, result, fail_streak, currencies_spentThe upgrade-chance dataset (E1/E3/E4). Server rolls the odds — ground truth.
hatch / breed_cycle / advance / fusehatch: egg_grade, result_grade, line_id, mutant, hatchery_lvl · breed: pair grade P, food_spent, egg_grade · advance: line, stage, level · fuse: inputs, resultB1–B3, C5 funnel entry points.
currency_flowper flush per currency: source_by_channel, sink_by_channel, balanceE4 tightness; channels = battle, dismantle, boss, craft, grade, breed…
container_snapshotper container: {slots_used, slots_max}Rides every flush; first/last flush of a session ≈ session begin/end state. Capacities read from the build (see flags).
pvp_match (P2)rating band, comps, result, rounds, per-unit aggregatesFully replay-verified — the one wholly trusted combat dataset.
market_tx (P2)list/buy/sell, class, tier/grade, price, first_buy flagSets the buyer cohort flag; feeds E7 and the farm audit queue.

Client plane — GameAnalytics free SDK. Sessions, retention, DAU, and country/device come automatic; the rest maps onto GA's four event classes. Constraint honored: custom key-value fields require paid raw export, so dimensions are encoded in event-ID hierarchies; resource itemTypes stay ≤100 by using families/tiers, never item IDs.

GA classUsage here
ProgressionStart/Complete on Zone01..10 : Floor001..100 — one hierarchy only (floors), per GA guidance. Powers the early funnel (S3) and drop-off views.
ResourceSink/source per currency, aggregated per floor-exit or session-end — never per pickup (GA's own volume rule). Six currencies + Keys.
DesignBounded-cardinality IDs: logout:screen:{name}, logout:floor (value=floor), container:{name}:fill (value=%; session start/end), upgrade:denied:{currency}, autoplay:on/off, boss:{id}:attempt/kill, battle:floorexit (value=wins/losses folded).
BusinessDeferred to monetization step (battle pass) — roadmap #20.
Volume guardrails: no per-turn data ever leaves the device — turn-by-turn detail already lives in the local Adventure Log by design. Analytics carries aggregates only. Per-item drops fold to per-flush counts. Event-ID cardinality is budgeted (≤100 resource itemTypes, design-event ID space kept small and enumerable).

Infrastructure & cost

PieceChoiceCost
Client analyticsGameAnalytics Unity SDK, free tier — retention/session/funnel dashboards out of the box; CSV export by hand when needed. (Raw export + custom fields are paid — not required by this plan.)$0
Server ingestCloud Code appends one NDJSON batch per flush (inside the existing invocation — zero new invocations) → tiny Cloudflare Worker → R2 object per flush; nightly compaction to daily Parquet.~$0 at prototype scale; ~$5–10/mo at 1k sustained CCU (object-write ops dominate; a buffering Worker halves it). Compute cost inside Cloud Code: negligible (one HTTP POST, ~1 KB).
Warehouse / queriesDuckDB over the Parquet partitions, local — full SQL, joins all three sources on analytics_id. Weekly report is a scripted notebook.$0
Site feedbackCloudflare Pages Functions/Worker + D1 (SQLite) free tier; Steam OpenID verification in the Worker.$0 within free tier (100k req/day, D1 100k writes/day — orders of magnitude of headroom)
Privacyanalytics_id = salted SteamID64 hash; Settings opt-out honored on both planes (events simply not emitted); Export/Delete flows cover R2 partitions + D1 rows.—

Creature Feedback System (codex site)

Per design note: players sign into the codex site with their Steam account and leave direct, per-creature feedback. GitHub Pages is static, so auth and storage live in a small serverless layer; the site stays exactly where it is.

ElementSpec
AuthSteam OpenID 2.0. The Worker verifies the assertion with Valve, sets a signed HttpOnly session cookie, and stores only hash(SteamID64 + salt) — the same analytics_id, making telemetry joins native. No passwords, no accounts of our own.
WidgetOn creature.html: 1–5 rating + fixed tag chips (Too weak · Too strong · Boring kit · Fun to use · Confusing · Love the art · Art needs work) + optional comment ≤500 chars. One submission per account per creature, editable; edit history retained for trend.
Storage / APID1 table feedback(creature_id, sid_hash, rating, tags, comment, ts, version). GET /feedback/:creature returns public aggregates (avg, counts, tag histogram); POST requires the session cookie. Per-account rate limit, banned-word filter, admin delete.
WeightingNightly export joins feedback to telemetry: votes from players with ≥50 battles using the creature are weighted up; never discarded, just ranked. Feeds C6 quadrants in the weekly report.
DisplayAdmin mode: per-creature rating, tag histogram, and comment stream as an overlay in the codex (Dev Tools). Public aggregate display optional, later, behind approval.

Cadence & patch protocol

RhythmContents
Weekly balance reportScripted, non-buyer lens by default: floor win-rate curve + wall detector (D1/D2), creature quadrants (C1–C3), currency flows & denied attempts (E4), gate tails (E3), boss/key friction (D4), container pressure (S4), early funnel + retention (S3/S2), feedback quadrant movers (C6).
Patch protocolEvery lever change is logged (date, lever, old→new, hypothesis ID it serves) and annotated on every chart. One lever per system per patch where possible; 7-day minimum before/after windows; the "butterfly problem" is real — expect side-effects, so re-read adjacent hypotheses after each change.
Integrity alarmsContinuous, not weekly: faucet deviation (E1), odds deviation (E3), faucet-rate/listing outliers (E7 — the backend's farm queue), error/crash rates (GA automatic).
QuarterlyRe-audit the proposed target bands against reality; retire hypotheses that never fire; add new ones from feedback themes.

Rollout — mapped to the build roadmap

PhaseLands withDelivers
P0 — nowPrototype (steps 6–15)GA SDK in the Unity client: auto sessions/retention, floor progression events, folded battle/resource design events, logout context, container fill at session boundaries. Client-claimed, which is fine pre-launch — there is nothing to cheat yet, and the early-funnel + difficulty reads start accumulating immediately.
P1 — server planeStep #16 (backend authority)The analytics append inside the Cloud Code flush; Worker + R2 + nightly Parquet; DuckDB weekly report. Balance authority switches to this plane; hooks are added while writing the flush code, not retrofitted (same lesson as the player logging system).
P2 — competitive & marketSteps #18–#19Replay-verified PvP records, ladder snapshots, market events + buyer flag, farm-telemetry dashboards.
P3 — site feedbackIndependent — any timeSteam OpenID + feedback API + admin overlay; nightly telemetry join. Can precede P1 (feedback is useful against playtest builds).

What other games & specialists do

SourcePracticeWhat we take
Turtle Rock — Evolve telemetry threadsPublished per-character win/loss curves by player level, patch by patch, and argued balance changes directly from them; later split the same curves by skill rank.Exactly the shape of C1/C7: per-creature win rate by floor band and rating band, with segment splits before judgment.
Balance practice (industry guides)Popularity ≠ dominance — intervene on always-optimal, not on well-liked; telemetry says what, never why; track win rates, pick rates, unit lifespan, and where players die/quit.C2's quadrant discipline; C6's mandatory feedback pairing; D3's quit-point tracking.
GameAnalytics docsFour event classes (business / design / progression / resource with sink–source), funnel tooling, aggregate-not-per-pickup volume rule, event-ID hierarchies.The entire client-plane mapping, verbatim discipline on cardinality and aggregation.
Economy design (Machinations, Mobile Free To Play, F2P econ guides)Anchor every economy question in time; keep currencies tight — hoarding and starvation are both failures; expect the spreadsheet to be wrong and rebalance from telemetry; cost cliffs churn players.E2/E4's structure; the battles/hour anchor the GDD already uses; denied-attempt instrumentation.
Churn literature & practiceChurn defined as absence over 7/14/28 days; declining session length/frequency is the leading indicator, but composite signals (decline + progression stall + fail streak) beat any single one; the first sessions and earliest levels dominate retention.S2's composite early-warning design; the 14-day definition; S3's early-funnel priority over endgame tuning.

Links: turtlerockstudios telemetry threads (talk.turtlerockstudios.com) · videogamedevelopmentauthority.com/game-balancing-and-tuning · docs.gameanalytics.com (event types, funnels) · gameanalytics.com/blog/exploring-gaming-funnels · machinations.io/articles/game-economy-design-free-to-play-games · mobilefreetoplay.com/bible/building-lasting-free-play-economy · joschka-huellmann.net (Rothmeier et al., churn prediction survey) · kumo.ai/solutions/industries/gaming/player-churn.

Open flags & contradictions

#Flag
1Determinism contradiction. The GDD battle section and Backend v2 build on deterministic seeded replay (state + seed + move log); system-adventure-log.html (the adventure log was retired 2026-10-22, ADVLOG-OUT; its page remains the record of that ruling) states battles are not deterministic and rules out seed-replay. This plan works either way (battle aggregates are client-claimed + verified-subset-calibrated), but one ruling is needed — it decides whether per-battle damage could instead be replay-derived server-side at 100% trust.
2Boss turn targets disagree. HP budget section: kill in 8–13 turns; turn-target table: 10–15. C4/D4 alarm bands need one canonical window.
4All target bands above are proposals — win-rate floors, boss attempt p50, 70% velocity ratio, 14-day churn window, alarm widths. Nothing alarms until approved.
5Key drop rate is an open GDD decision. D4 is built to price it: instrument first, then author the numbers from observed friction.
6Site feedback adds a small serverless surface (Worker + D1 + Steam OpenID) — the first non-UGS backend piece. Deliberately isolated from game state; it can never grant anything.

Implementation order: P0 instrumentation can begin immediately in the prototype (a day of SDK wiring). The server plane is authored as part of roadmap #16 Backend authority layer — the flush already computes every number this plan needs; the analytics append is written alongside it, not retrofitted. The feedback system is independent and site-side. This page is the source of truth for event names, hypothesis IDs, and alarm thresholds; changes land here first.

Changelog

2026-10-23 — the battles/h anchor and the portal table are generated (dfmc-client lane a8-s5-c17-tail, C17 part 4). WIKI ONLY. tools/codex_tables.py blocks bph-anchor and portal: the expected battles are (1 − p^n) / ((1 − p) p^n) on floors.csv Wins_To_Clear, the hours at ~109 battles/h (the economy simulator, tools/sim_econ.mjs; was ~30). Changed: floor 9 at 70% ~17 → ~16 (16.50 exactly, rounded down); 90% deep clear 2.4 h → 0.7 h, 80% 14 h → 3.9 h.