Pair intro_engaged with game_started so the intro drop-off is measurable - #113
Merged
Conversation
intro_engaged was scoped once per page load (module-level flag) while game_started fires on every ModePicker pick. A player who tried the board, stepped back and picked the form logged two game_started against one intro_engaged and read as a phantom bounce, inflating the measured game_started -> intro_engaged drop. The mode picker now clears the flag alongside every game_started, so both events count the same population. Keeps the per-page-load flag's original purpose (Intro unmounts on Back and on entering the board, so a per-mount ref double-counted) while fixing the denominator. Telemetry only, no gameplay change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
green-radius-game | e5fd5be | Commit Preview URL Branch Preview URL |
Aug 18 2026, 05:48 AM |
Admins were getting bounced to the one-time-PIN email every 24h because both Access session timers sit at their 24h default. Record the two knobs, the ordering constraint between them (global must be >= application, or raising the app value alone changes nothing), our chosen values, and the policy-re-evaluation caveat that comes with a longer token. Dashboard config only. verifyAccessJwt honours whatever exp Cloudflare stamps, so there is nothing to change in the Worker. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb
Follow-up to 69bfbfc. Both timers now documented at 730h. Adds the policy session duration warning (it outranks the application duration, so a stale value there cancels both settings while looking like a save failure) and a curl recipe to read the live values without clicking through the dashboard. Note the live application session is still 336h: the API token available here has Access read but not write, so the dashboard change is manual. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb
The signage deadline lands tonight, so the announcement strip switches to the next ask: "Sign up to be included on the post-Burn online map!" Amber becomes light purple to read as a new message rather than a lingering one. Its auto-hide moves with it. SIGNUP_DEADLINE_END_MS was end of Aug 17 PDT, so left alone the new copy would have gone dark a few hours after deploy; it now runs to end of Sep 7 PDT (through the event) and still self-removes with no removal deploy. Verified rendered at 390px against a local server: computed background rgb(239,228,251), text rgb(91,46,144), no page errors. APP_VERSION already reads v113 and this is still PR #113, so it is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb
Ponytail pass on #113, no behaviour change: - green-radius.jsx: the intro_engaged comment narrated three iterations of a one-line fix. Kept the invariant (game_started fires per pick, so intro_engaged must reset per pick), dropped the history. - docs/admin-setup.md: cut the curl+jq recipe — it duplicated the two dashboard paths the table right above it already names, and needed an API token nobody keeps around. Also folded the "ours are equal" paragraph into the rule that actually matters, that global must be >= application. - src/home.jsx: SIGNUP_DEADLINE_END_MS/DeadlineBanner/data-deadline-banner guarded copy with no deadline left in it, so they read as SIGNUP_BANNER_END_MS /SignupBanner/data-signup-banner. Nothing outside this file referenced them. Banner re-verified rendering at 390px after the rename: background rgb(239,228,251), text rgb(91,46,144), no page errors. 132 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb
…isite Review of #113 caught a factual error I introduced two commits ago. The doc claimed the global session duration "must be >= the application duration or raising only the app value changes nothing". Cloudflare's wording is "usually set to equal or exceed" — a recommendation. The application token is what gates each request, so a 1-month application session alone delivers month-long admin logins; the global token only decides whether the renewal at that expiry is silent or sends you back to the one-time-PIN email. That mattered because global session is account-wide. Set to 730h it also let the preview-URLs app (24h application session) renew unattended for a month, so "the preview-URLs app stays at its own 24h" was misleading about its real effective session. Global goes back to its 24h default; the doc now says why the asymmetry is deliberate, and names all four timers rather than two. Also fixes the missing blank line between the two #113 changelog bullets, which rendered that pair as a tight item inside an otherwise loose list. Cloudflare-side change (global back to 24h) is Wes's dashboard edit; the application session stays at 730h and is already live. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb
The copy asks camps to sign up for the post-Burn online map, but the window closed end of Sep 7 — the last day of the event, before the post-Burn ask is topical at all. Window now ends Sep 30 PDT. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb
Reverts 1f3cf68. I read "after Sep 7" as "pick a date some weeks out" and took end of Sep 30; Wes meant the Sep 8 boundary, which is where it already was. Comment now states the instant the way he phrased it ("expires Sep 8 2026, 00:00 PDT") rather than "end of Sep 7 2026" — same millisecond, but the end-of-day framing is what made the ask ambiguous in the first place. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
This morning's GTCC newsletter traffic showed 39
game_started→ 25intro_engaged→ 22mode_chosen, reading as "36% of players picked a mode and never typed a character." That number is inflated by a counting artifact, not a real bounce rate.introEngagedSentis a module-level flag scoped once per page load (deliberate —Introunmounts on Back and on entering the board, so a per-mount ref double-counted engagement). Butgame_startedfires on every ModePicker pick, andIntro's Back button returns to the picker.So: pick board → type → Back → pick form = 2
game_started, 1intro_engaged. Every mode switch manufactures a phantom bounce, and the two events never shared a denominator.What
One line: the mode picker clears the flag alongside every
game_started.Resetting at
onPickrather than at the threesetPhase('pick-mode')call sites binds the reset to the exact statement that firesgame_started, so they can't drift apart — a future fourth route back to the picker won't silently reintroduce the skew.The original per-mount double-count this flag guarded against is unaffected.
Scope
Telemetry only. No gameplay, UI, or copy change. The
greenscontract, storage version, and/api/completepayload are untouched.Notably this does not change the useful half of the signal: of the 25 who engaged, 22 cleared the five-field gate (88%), with only 2
intro_blockedall morning. The gate isn't rejecting people who try — that finding stands either way. This fixes the part that was unmeasurable.Related but deliberately not included: roadmap
U5 identity-at-endstays shelved per Wes.Verification
bun run scripts/build.js+git status --porcelain -- dist→ clean (gate passes)bun test→ 132 pass, 0 faildist/green-radius.jscontains all fourintroEngagedSentsites (declaration, guard, set-true, new reset)APP_VERSION→v113, CHANGELOG entry added🤖 Generated with Claude Code
https://claude.ai/code/session_01B94AdnTqEvYxFjRLXQUMBb