Skip to content

feat(golf): idempotent demo-realism refresh script (Demo University Golf) - #933

Closed
njrini99-code wants to merge 1 commit into
mainfrom
feat/golf-demo-seed-realism
Closed

feat(golf): idempotent demo-realism refresh script (Demo University Golf)#933
njrini99-code wants to merge 1 commit into
mainfrom
feat/golf-demo-seed-realism

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

Problem

A live click-through of the golf demo account (Demo University Golf, 6ecdd1a6-63fe-4beb-b094-00118f334163) surfaced several things that read as obviously fake or stale — the data-realism findings in #910:

  • Messages: every team-channel message is exactly 1 hour apart starting at 08:00 UTC → 04:00 AM America/New_York. Reads like a bot, not a coach/player chat.
  • Calendar: golf_events was seeded with day-offsets relative to whenever seed-demo-team-ops.ts last ran (mid-June). Real time has moved on, so several "near future" events are now in the past while still status: 'scheduled' — the calendar header says "N upcoming" while the agenda underneath shows April/May dates. Several events also used a raw UTC hour where an Eastern local hour was intended — "Coastal Collegiate Invitational" tees off at 3:00 AM once converted to America/New_York.
  • Courses: golf_rounds.course_name is free text with ~20 typo'd/casing variants of the team's two real library courses — poplar grove, Poplar Grove (real), Poplar Grove GC, Golden horshoe, golden horeshoe, Golden Horseshoe Gold, etc. — instead of the canonical golf_courses rows the course library already has for them.
  • CoachHelm freshness: the newest golf_rounds row is weeks old, so CoachHelm's rolling-window insights and any "updated X ago" copy read stale the moment the demo sits untouched for a few days.

Fix

One idempotent, dry-run-by-default script: scripts/refresh-golf-demo-realism.ts.

  • (a) Messages — re-times every team-channel message to a natural coach/player hour (7-9am or 3-6pm America/New_York, varied minutes), preserving each message's relative day-spacing but re-anchored so the most recent message lands yesterday (never in the future).
  • (b) Calendar — reschedules the team's 12 known named events on the SAME day-offsets-from-now the base seed used (6 always past / 6 always future — a rolling schedule regardless of when this runs), but treats every event hour as an America/New_York local time correctly converted to UTC instead of a raw UTC hour, so tee times/practices land at sane hours.
  • (c) Courses — canonicalizes every Poplar Grove / Golden Horseshoe course_name variant on the team to the exact name + course_id + city/state the course library already has for them (ilike prefix match, scoped to team_id). Every other course on the team (Pebble Beach, Forest Creek, Savannah Harbor, Jekyll Island, Cardinal, ...) is left untouched — those weren't the courses flagged as messy.
  • (d) Round freshness — if the newest golf_rounds.round_date on the team is more than 5 days old, shifts every team round forward by the same number of days (uniform, spacing-preserving) so the newest round lands ~1 day ago. CoachHelm's rolling-window reads and "updated X" copy freshen automatically since they're computed live off round_date.

The date/time math for (a)/(b)/(d) — the trickiest part, timezone-correct local hours and spacing-preserving re-anchoring — is extracted into src/lib/golf/demo-realism-schedule.ts (pure, no Supabase dependency) so it's unit-testable in isolation, including a regression lock for the exact 3 AM tee-time bug.

Scope & safety

  • REVIEWED-ONLY: not executed as part of this PR. Meant to run with --confirm against prod after review (dry run is the default — no --confirm flag ⇒ prints the plan, writes nothing).
  • Strictly scoped to the hard-coded DEMO_TEAM_ID. Every mutating query filters on team_id = DEMO_TEAM_ID (golf_events, golf_rounds) or a team-owned conversation id resolved from that team_id (golf_messages).
  • assertDemoTeamIdentity() reads the team row (name + join_code) and confirms the known demo-coach user is on staff before any write — refuses to run if DEMO_TEAM_ID no longer points at what's expected.
  • Every write is an UPDATE against rows discovered at runtime — no DELETE, no destructive rewrite. Re-running is always safe: dates/times get recomputed relative to "now" and simply overwrite the same columns.
  • Verified read-only against prod via dry run (see below) — confirms scoping and math are correct without writing anything.

Known gap (documented in the script, not fixed here)

One golf_rounds row (qualifier_id set) is loosely coupled to a golf_qualifiers.start_date/end_date and a golf_events row via target_tournament_id. Shifting round_date (d) does not cascade to golf_qualifiers dates — pre-existing drift there isn't introduced by this script, and fixing that coupling is a separate, more invasive change.

Out of scope (other #910 findings, not addressed by this PR)

This PR only covers the data-realism portion of #910. The "18h" → "18 holes" rounds-row copy bug, the roster "No intent" chip, the Courses page image mismatches, and the CoachHelm Brief label-overlap are UI/copy issues unrelated to demo data freshness — tracked separately (see mission-control notes: Wave 2 already covers some #910 copy items; Wave 3 covers the Brief rebuild). Using "Part of #910", not "Fixes #910".

Proposed run cadence

Suggest wiring this as a weekly cron (Monday, same slot the CRM v_crosswalk → weekly_call_list cron already uses) via scripts/refresh-golf-demo-realism.ts --confirm, since:

  • Messages/rounds only need to stay within a ~1-5 day freshness window — weekly is comfortably inside that.
  • It's cheap (a handful of scoped UPDATEs) and fully idempotent, so a missed or double-run week is harmless.

Alternatively, a manual pre-demo checklist step ("run refresh-golf-demo-realism.ts --confirm before any live walkthrough") is a reasonable lower-effort fallback if cron infra for this isn't wanted yet — the safety assertion + dry-run-by-default make it safe for anyone on the team to run without deep context.

Gates (run in the worktree)

npx tsc --noEmit -p tsconfig.json                                          # clean
npx eslint scripts/refresh-golf-demo-realism.ts src/lib/golf/demo-realism-schedule.ts src/lib/golf/__tests__/demo-realism-schedule.test.ts   # clean
npx vitest run --project unit src/lib/golf/                                # 311/311 (12 files) green, incl. 20 new

Dry run against prod (read-only, confirms scoping + math against real data — no writes):

DOTENV_CONFIG_PATH=.vercel/.env.production.local npx tsx -r dotenv/config scripts/refresh-golf-demo-realism.ts
15 messages, re-anchoring so most recent lands 2026-07-16
12/12 known events matched + rescheduled
  Coastal Collegiate Invitational: 2026-06-12T11:00:00.000Z → ... (07:00 ET, not 3 AM)
[dry] would canonicalize 22 rounds matching "poplar grove%" → "Poplar Grove (real)"
[dry] would canonicalize 21 rounds matching "golden hor%" → "Golden Horseshoe gold course"
newest round is 2026-07-11 — shifting all 96 rounds forward by 5d (newest lands 2026-07-16)

Not run: npm run build, browsers/Playwright (per repo policy for this task).

🤖 Generated with Claude Code

https://claude.ai/code/session_01MMdviLDsAg2YYJ8adsM6fg

…y Golf

Part of #910 (data-realism portion) — a live click-through of the golf
demo account showed messages exactly 1h apart starting 4:00 AM ET,
calendar events frozen relative to whenever seed-demo-team-ops.ts last
ran (past events still marked "scheduled", a tee time landing at 3 AM
from a raw-UTC-as-local-hour bug), ~20 typo'd/casing course_name
variants of the team's two real library courses, and CoachHelm reading
stale because the newest round was weeks old.

scripts/refresh-golf-demo-realism.ts is a REVIEWED-ONLY, dry-run-by-default,
re-runnable script strictly scoped to the hard-coded demo team id (with a
name/join_code/coach-staff safety assertion before any write) that:
  (a) re-times team-channel messages to natural coach/player hours
      (7-9am / 3-6pm ET, varied minutes), preserving relative day-spacing
      but re-anchored so the newest message lands yesterday;
  (b) reschedules the team's 12 known events on a rolling day-offset-from-now
      schedule (6 always past / 6 always future) with ET-correct local
      hours instead of raw UTC;
  (c) canonicalizes every Poplar Grove / Golden Horseshoe course_name
      variant to the exact name + course_id the course library already
      has for them, leaving every other course untouched;
  (d) shifts all team rounds forward (uniform, spacing-preserving) once
      the newest round is more than 5 days stale, so CoachHelm's
      rolling-window reads and "updated X" copy stay fresh.

The date/time math for (a)/(b)/(d) is extracted into
src/lib/golf/demo-realism-schedule.ts (pure, no Supabase) so the
trickiest part — timezone-correct local hours and spacing-preserving
re-anchoring — is unit-tested in isolation
(src/lib/golf/__tests__/demo-realism-schedule.test.ts, 20 cases,
including a regression lock for the exact 3 AM tee-time bug).

Verified read-only against prod via dry run: 15 messages, 12/12 events
matched, 22 + 21 rounds canonicalized, 96 rounds due a 5-day forward
shift — all correctly scoped to the demo team only.

Gates: tsc --noEmit clean, eslint clean, vitest 20/20 new + 311/311
src/lib/golf/ suite green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMdviLDsAg2YYJ8adsM6fg
@cursor

cursor Bot commented Jul 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@supabase

supabase Bot commented Jul 17, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project qmnssrrolpinvwjjnufo because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
helmv3 Ignored Ignored Jul 17, 2026 10:24pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@njrini99-code, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e5d32317-d911-4944-b6e6-e44f2d5d1420

📥 Commits

Reviewing files that changed from the base of the PR and between 6d25e44 and de9fbfd.

📒 Files selected for processing (3)
  • scripts/refresh-golf-demo-realism.ts
  • src/lib/golf/__tests__/demo-realism-schedule.test.ts
  • src/lib/golf/demo-realism-schedule.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/golf-demo-seed-realism
  • 🛠️ helm safety pass
  • 🛠️ dashboard ux pass
  • 🛠️ rls test pass

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@njrini99-code

Copy link
Copy Markdown
Owner Author

🤖 Mission Control — PR summary

What it changes: Adds scripts/refresh-golf-demo-realism.ts (part of #910) — a REVIEWED-ONLY, dry-run-by-default, re-runnable script strictly scoped to the hard-coded Demo University Golf team id (guarded by a name/join_code/coach-staff safety assertion before any write). It re-times team-channel messages to natural coach/player hours, reschedules the team's 12 known events on a rolling day-of-week basis, dedups ~20 typo'd/casing course_name variants, and refreshes rounds so CoachHelm reads current. Backed by src/lib/golf/demo-realism-schedule.ts + tests.

Area: GolfHelm (demo-data tooling; script is not executed in CI).

Risk / reviewers watch:

  • The demo-team-id safety assertion — must fail closed if it ever resolves to a non-demo team.
  • Write scoping (messages / events / rounds) stays inside the single demo team.
  • Determinism / idempotency on re-run (schedule module is unit-tested).

CI: 4 required gates green. CodeRabbit advisory + REVIEW_REQUIREDBlocked. No action taken.

@njrini99-code

Copy link
Copy Markdown
Owner Author

Superseded — landed on main inside merge train #938 (commit 6ecede6). Branch kept.

@njrini99-code
njrini99-code deleted the feat/golf-demo-seed-realism branch July 20, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[QA] Golf demo-data & copy polish: calendar, messages, rounds, roster, courses

1 participant