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:
Note
Handled by
Creature wins/losses per level · damage dealt per battle per creature · logout point & session length
Item slots filled per container, twice daily or at session begin/end
Container snapshot schema row + hypothesis S4 (inventory pressure); rides every server flush ≈ 20-min granularity, covering both proposed cadences
Principles
Principle
Rule
Server plane is truth
Balance 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 only
Per 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 → lever
No 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 judging
Nothing 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 why
Telemetry cannot distinguish "weak" from "feels bad." Every balance read pairs with the site feedback channel before a lever moves.
Privacy by default
Analytics 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.
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.
Segment
Definition
Why
Market cohort
non-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 band
Highest zone reached (1–10).
Difficulty and economy read per band, not globally.
Tenure
Day 0–7 / 8–30 / 31+.
Early-funnel problems and endgame problems need different levers.
Playstyle
Auto-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 tier
Top 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
ID
Hypothesis
Metrics · plane
Trigger → lever
D1
The 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).
D2
Unintended 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.
D3
Losses 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.
D4
Boss 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.
D5
Auto 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.
D6
The 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
ID
Hypothesis
Metrics · plane
Trigger → lever
C1
At 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.
C2
Usage × 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.
Damage 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.
C4
Turn 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.)
C5
Acquisition without use marks weak or unclear kits: lines players hatch but never field.
High-acquisition / near-zero-use lines → cross-reference feedback tags (C6) before touching numbers — may be a clarity problem, not a power problem.
C6
Feedback × 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.
C7
PvP 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
ID
Hypothesis
Metrics · plane
Trigger → lever
E1
Implemented 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.
E2
Non-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.
E3
No-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.
E4
Each 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.
E5
Ichor 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.
E6
Grade 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).
E7
Market 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.)
The 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.
B2
Hatch 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.
B3
Mutant 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.
Session 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.
S2
Churn 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.
S3
The 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.
S5
Autoplay 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 p
Floor 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.
Target
Proposed band
Rationale
On-progression wild win rate
≥85% floors 1–40 · ≥90% floors 41–100
Keeps expected battles-to-clear within the zone-time sheet; the streak amplifier punishes anything lower at depth.
Boss first-attempt win rate
35–60%; attempts-per-kill p50 ≤3
Bosses 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 playtime
The market may accelerate; it must not become the only viable pace.
Milestone pacing tolerance
observed p50 within ±25% of authored target
Design targets exist in the GDD milestone table; this is the alarm width.
Churn definition
no session in 14 days
Grind/autoplay game: 7 is too twitchy, 28 too slow to react; literature uses 7/14/28 — pick 14.
Odds integrity alarm
outside 99% CI at n≥1,000 attempts per gate
Separates RNG noise from implementation bugs before touching design.
Turn-count bands
wild 3–5 (alert: p50 >6, or 1-turn share >60% deep) · boss 8–15
Authored 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}.
Record
Fields
Notes
battle
battle_id, floor, mode (auto/manual), result, turns, duration_s, streak_before→after, snap[6] and acts[] (see below), verified flag
Recorded 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_clear
floor, n battles_on_floor, l losses, s wall_time_s, f first_clear flag — BUILT (local save) 2026-07-29, counted per visit
Fully replay-verified — the one wholly trusted combat dataset.
market_tx (P2)
list/buy/sell, class, tier/grade, price, first_buy flag
Sets 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 class
Usage here
Progression
Start/Complete on Zone01..10 : Floor001..100 — one hierarchy only (floors), per GA guidance. Powers the early funnel (S3) and drop-off views.
Resource
Sink/source per currency, aggregated per floor-exit or session-end — never per pickup (GA's own volume rule). Six currencies + Keys.
Deferred 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
Piece
Choice
Cost
Client analytics
GameAnalytics 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 ingest
Cloud 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 / queries
DuckDB over the Parquet partitions, local — full SQL, joins all three sources on analytics_id. Weekly report is a scripted notebook.
$0
Site feedback
Cloudflare 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)
Privacy
analytics_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.
Element
Spec
Auth
Steam 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.
Widget
On 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 / API
D1 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.
Weighting
Nightly 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.
Display
Admin mode: per-creature rating, tag histogram, and comment stream as an overlay in the codex (Dev Tools). Public aggregate display optional, later, behind approval.
Every 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.
Re-audit the proposed target bands against reality; retire hypotheses that never fire; add new ones from feedback themes.
Rollout — mapped to the build roadmap
Phase
Lands with
Delivers
P0 — now
Prototype (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 plane
Step #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).
Steam OpenID + feedback API + admin overlay; nightly telemetry join. Can precede P1 (feedback is useful against playtest builds).
What other games & specialists do
Source
Practice
What we take
Turtle Rock — Evolve telemetry threads
Published 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.
Four 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 & practice
Churn 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.
Determinism 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.
2
Boss turn targets disagree. HP budget section: kill in 8–13 turns; turn-target table: 10–15. C4/D4 alarm bands need one canonical window.
4
All target bands above are proposals — win-rate floors, boss attempt p50, 70% velocity ratio, 14-day churn window, alarm widths. Nothing alarms until approved.
5
Key drop rate is an open GDD decision. D4 is built to price it: instrument first, then author the numbers from observed friction.
6
Site 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.