Lesson 282: Hour-One Demo Funnel Snapshot CSV Receipt on BUILD_RECEIPT (2026)
Direct answer: Before February 2027 live-week stand-up treats Discord “wishlist spiked” as truth, complete F1–F6—normalize wishlist clicks → demo launches → first-session quits into hour-one-funnel-2027.csv, recompute launch_rate / hour_one_quit_rate, file hour_one_funnel_snapshot_receipt_v1.json, run verify_hour_one_funnel_snapshot.sh, then promote BUILD_RECEIPT hour_one_funnel_snapshot_ok: true. Pair hour-one evening tutorial, Lesson 267 CSV ingest cousin, Lesson 281 webhook lane, and Help #37 forward (Steam wishlist column drift).

Why this matters now (February 2027 live week hour one)
February 2027 D2 hour one: Steamworks exports move faster than anecdotes, HOTFIX bumps build_label, and producers ask whether quit rate spiked before refunds exist. Refund dashboards answer 48-hour lag; this lesson answers hour-one drop-off on BUILD_RECEIPT so CI and Friday closeout refuse GREEN without a verified funnel row.
Hour-one evening tutorial owns the CSV evening; 282 latches hour_one_funnel_snapshot_ok so live-ops cannot claim analytics GREEN from Slack screenshots alone. Distinct from Lesson 267 (Discord playtest CSV) and Lesson 281 (P0 webhook).
Promotion order on BUILD_RECEIPT: export/normalize CSV → receipt F1–F5 → verify exit 0 → hour_one_funnel_snapshot_ok → stand-up / Thursday row review trail.
Beginner path (CSV → receipt → verify → promote)
| Step | Action | Success check |
|---|---|---|
| 1 | Export or transcribe wishlist/launch/quit for fest day hour 1 | F1 CSV row |
| 2 | Pin FUNNEL_DEFINITION.md quit rule |
Stable denominator |
| 3 | Match build_label to RC / player footer |
F2 |
| 4 | Recompute rates (no hand-typed %) | F4 |
| 5 | File receipt + run verify script | F5–F6 / exit 0 |
| 6 | Promote BUILD_RECEIPT | hour_one_funnel_snapshot_ok: true |
Time: ~45 minutes first fest day; ~5 minutes when CSV + scripts exist.
Common mistake: Typing hour_one_quit_rate by hand—F4 fails when counts disagree.
Developer path (gates F1–F6)
| Gate | Check | Fail when |
|---|---|---|
| F1 | CSV columns + ≥1 row for fest_day |
Missing headers / empty day |
| F2 | build_label matches RC / BUILD_RECEIPT |
Label drift vs player build |
| F3 | Prior fest day row when fest_day > D1 |
No D(n-1) for jq diff |
| F4 | Rates recomputed from counts | Hand-waved percentages |
| F5 | hour_one_funnel_snapshot_receipt_v1.json filed |
Missing under release-evidence/analytics/ |
| F6 | Verify + BUILD_RECEIPT latch | Script exit ≠ 0 / bool false |
Cousin receipt crosswalk
| Field | Hour-one blog | Lesson 267 | This lesson (282) |
|---|---|---|---|
| Schema | hour_one_funnel_snapshot_receipt_v1 |
playtest_csv_ingest_receipt_v1 |
Same as blog + BUILD_RECEIPT column |
| Scope | Evening CSV tutorial | Discord playtest threads | Live Steam funnel milestone |
| BUILD_RECEIPT | Documents hour_one_funnel_snapshot_ok |
playtest_csv_ingest_ok |
hour_one_funnel_snapshot_ok |
Do not merge with March wishlist velocity (post_fest_wishlist_velocity_receipt_v1)—different cadence and columns.
F1–F2 — normalize CSV + label
release-evidence/analytics/hour-one-funnel-2027.csv
release-evidence/analytics/FUNNEL_DEFINITION.md
Required idea columns (names may map via header alias file when Steam renames exports):
fest_day,wishlist_clicks,demo_launches,first_session_quits,build_label
test -f release-evidence/analytics/hour-one-funnel-2027.csv
jq -n --arg bl "$(jq -r '.build_label' release-evidence/BUILD_RECEIPT.json)" \
'$bl != "" and $bl != "dev"'
F4–F5 — receipt skeleton
{
"schema": "hour_one_funnel_snapshot_receipt_v1",
"fest_window": "2027-02-next-fest-live",
"fest_day": "D2",
"generated_at": "2027-02-24T20:15:00Z",
"csv_path": "release-evidence/analytics/hour-one-funnel-2027.csv",
"funnel_definition": "first_session_quit = exit before tutorial_complete event",
"row": {
"wishlist_clicks": 980,
"demo_launches": 245,
"first_session_quits": 88,
"build_label": "fest-demo-2027-02-rc1",
"launch_rate": 0.25,
"hour_one_quit_rate": 0.359
},
"prior_day_diff": {
"fest_day_prev": "D1",
"hour_one_quit_rate_delta": 0.062,
"launch_rate_delta": 0.0
},
"cousin_receipts": {
"playtest_csv_ingest": "release-evidence/playtest/PLAYTEST_CSV_INGEST_RECEIPT.json"
},
"hour_one_funnel_snapshot_ok": false,
"gates": {
"F1_csv": "pass",
"F2_build_label": "pass",
"F3_prior_day": "pass",
"F4_rates": "pass",
"F5_receipt": "pass",
"F6_verify": "pending"
}
}
Save as:
release-evidence/analytics/HOUR_ONE_FUNNEL_SNAPSHOT_RECEIPT.json
F6 — verify + promote
#!/usr/bin/env bash
# scripts/verify_hour_one_funnel_snapshot.sh
set -euo pipefail
REC="${1:-release-evidence/analytics/HOUR_ONE_FUNNEL_SNAPSHOT_RECEIPT.json}"
CSV="${2:-release-evidence/analytics/hour-one-funnel-2027.csv}"
jq -e '.schema == "hour_one_funnel_snapshot_receipt_v1"' "$REC" || exit 1
jq -e '.row.build_label != ""' "$REC" || exit 2
test -f "$CSV" || exit 3
launch=$(jq -r '.row.demo_launches' "$REC")
quit=$(jq -r '.row.first_session_quits' "$REC")
rate=$(jq -r '.row.hour_one_quit_rate' "$REC")
python3 - <<PY
launch, quit, rate = $launch, $quit, float("$rate")
assert launch > 0
assert abs(quit/launch - rate) < 0.001
PY
jq -e '.hour_one_funnel_snapshot_ok == true' "$REC" || exit 6
echo "hour_one_funnel_snapshot verify: OK"
After exit 0, promote BUILD_RECEIPT:
{
"hour_one_funnel_snapshot_ok": true,
"hour_one_funnel_snapshot_receipt": "release-evidence/analytics/HOUR_ONE_FUNNEL_SNAPSHOT_RECEIPT.json",
"hour_one_funnel_last_fest_day": "D2",
"hour_one_quit_rate_last": 0.359,
"hour_one_funnel_routing": "YELLOW"
}
Routing sketch: quit-rate day-over-day delta >+0.08 with stable launch → investigate gameplay before store copy; flat launch during CDN saturation → comms_only per queue playbook—not a silent F6 pass.
Common mistakes
- Using Discord playtest CSV (Lesson 267) as Steam funnel proof.
- Overwriting prior fest-day CSV rows instead of appending.
- Skipping F3 on D2+ (no prior day for honest delta).
- Claiming GREEN while Help #37 column-drift recovery is open.
- Mixing March velocity listicle schemas into February hour-one paths.
Continuity — February 2027 live week ops (277–283)
| Lesson | Receipt focus |
|---|---|
| 277 | OBS February pager clip |
| 278 | Fest-day setlive depot |
| 279 | Godot HOTFIX visible label |
| 280 | Unity hourly live-ops jsonl |
| 281 | Discord moderation webhook |
| 282 (this) | Hour-one funnel snapshot CSV |
| 283 | February live-ops truth capstone |
Previous: Lesson 281 — Construct fest moderation webhook
Next: Lesson 283 — February live-ops truth capstone
FAQ
Same as the hour-one evening blog?
Blog = one-evening CSV tutorial; 282 = BUILD_RECEIPT hour_one_funnel_snapshot_ok + CI latch.
Same as Lesson 267?
267 = Discord playtest thread ingest; 282 = Steam wishlist→launch→quit hour-one funnel.
Steam renamed export columns?
Help #37 forward owns header-map recovery—do not waive F1 with silent defaults mid-fest.
Zero wishlist clicks?
Do not compute launch_rate; mark YELLOW and fix store visibility before flipping snapshot ok.
Related GamineAI reads
- Hour-one demo funnel evening tutorial
- February live week timebox
- February RC branch label evening
- Steam refund signal dashboard
- Thursday BUILD_RECEIPT row review
- Discord playtest CSV ingest Lesson 267
- Resource #35 forward — hour-one funnel CSV/jq bookmark list
Live week lies when stand-up is GREEN without a funnel receipt—normalize the CSV, verify F1–F6, promote hour_one_funnel_snapshot_ok, then debate HOTFIX vs store copy.