Skip to content

Baseball demo: freshness reseed for Rini University Baseball - #686

Merged
njrini99-code merged 1 commit into
batch/baseball-fixesfrom
fix/baseball-vv-demo-freshness
Jul 2, 2026
Merged

Baseball demo: freshness reseed for Rini University Baseball#686
njrini99-code merged 1 commit into
batch/baseball-fixesfrom
fix/baseball-vv-demo-freshness

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

Root cause

The demo team (Rini University Baseball) is seeded by
scripts/seed-rini-baseball-demo.ts, which computes every date relative
to whenever it was last run. Real calendar time keeps moving, so the
"upcoming" game/practice/meeting drifted into the past (screenshots
showed the anchor game dated Jun 28, already gone by), readiness
check-ins read as weeks stale, and a few premium surfaces the base seed
never populated at all (development plans, documents, coach<->player
messaging) had no content to demo.

Fix

New idempotent companion script: scripts/reseed-rini-demo-freshness.ts.

  1. Re-dates anchor events/games — practice (tomorrow), meeting (+2
    days), game vs Coastal State (+3 days), plus the 2 "next" scheduled
    games — so "this week" always has a future game + practice + meeting.
  2. Seeds 2 development plans (4 goals each) — Marcus Rodriguez
    (rinin376's player row) gets an in_progress plan with one completed
    goal + two in-progress + one not-started, so the player-facing "My
    Development" goal-checkbox/progress-ring UI has real content. Jake
    Thompson gets a sent plan for coach-side list/detail variety.
  3. Seeds 4 team documents — playbook, schedule, travel policy,
    conditioning manual. Real baseball_documents +
    baseball_document_versions rows backed by tiny placeholder .txt
    files uploaded through the exact same documents storage bucket +
    baseball-documents/<teamId>/<file> path convention
    uploadBaseballDocumentAction uses — not fake metadata pointing at
    nothing.
  4. Seeds 1 coach → player conversation with 4 messages (natural
    back-and-forth, most recent unread) so Messages has content.
  5. Re-dates recent lift sessions + readiness — both the live
    helm_lifting_* tables and the legacy baseball_readiness_checkins
    table a couple of surfaces still read — so the readiness / "today's
    lift" panels read as current instead of drifting stale.

Idempotency / safety

  • Rows the base seed already owns (events, games, readiness check-ins,
    lift sessions/program-assignments/results/assignments) are updated
    in place via partial-column .update().eq('id', id) on the SAME
    deterministic ids the base seed minted — never a fresh insert, never a
    delete-then-insert. (Initially tried .upsert() with a partial
    payload; Postgres validates an INSERT's column list against NOT-NULL
    constraints even when it will resolve via ON CONFLICT DO UPDATE, so
    that failed on these wide tables — switched to plain .update().)
  • New rows (dev plans, documents, conversation/messages) are keyed under
    a dedicated baseball-demo-reseed-v1 id namespace — that namespace is
    the stable dedupe key / ownership marker, so re-running just upserts
    the same rows again.
  • Scoped entirely to the demo team (2acc63ce…) / org / the two demo
    users. Golf is never touched.

What was actually written (ran against prod with --confirm)

Table Rows
baseball_events (updated) 3
baseball_games (updated) 2
baseball_developmental_plans 2
baseball_documents 4
baseball_document_versions 4
storage objects (documents bucket) 4
baseball_conversations 1
baseball_conversation_participants 2
baseball_messages 4
baseball_readiness_checkins (updated) 14
helm_lifting_readiness_checkins (updated) 14
helm_lifting_program_assignments (updated) 4
helm_lifting_sessions (updated) 56
baseball_lift_results (updated) 14
baseball_lift_assignments (updated) 28

Test plan

  • npx eslint scripts/reseed-rini-demo-freshness.ts — 0 errors, 0 warnings
  • npx tsc --noEmit --skipLibCheck ... targeted check on the file — 0 errors (the scripts/ dir is excluded from the project tsconfig)
  • npx vitest run src/contracts/baseball/demo-stats-smoke.contract.test.ts — 9/9 passed (unaffected; base seed file untouched)
  • Ran with --confirm against prod; ran a second and third --confirm pass — row counts identical each time (idempotent, no duplicates)
  • Verified via SQL: events/games dates land Jul 3–8 2026 (today is Jul 2); helm_lifting_sessions scheduled dates land -10d/-7d/today/+3d; readiness check-ins land within the last 3 days
  • Verified via SQL: get_baseball_conversations_with_details() RPC (the actual read path useConversations calls) returns the seeded conversation with correct unread count, last message, and participant emails
  • Downloaded all 4 document storage objects back from the documents bucket and confirmed readable text content

🤖 Generated with Claude Code

https://claude.ai/code/session_01CHFRrZkRsAHWTwvxhySkfe

…ball

Screenshots showed the demo team's upcoming game/practice/meeting had
drifted into the past (dates were computed relative to whenever
seed-rini-baseball-demo.ts last ran), and several premium surfaces
(development plans, documents, messaging) had no seeded content at all.

Adds scripts/reseed-rini-demo-freshness.ts, an idempotent companion to
the base seed that: re-dates the anchor events/games so "this week" has
a future game + practice + meeting; seeds 2 development plans (4 goals
each, one partially completed) so the goal-checkbox/progress UI demos
for both the player and coach; seeds 4 team documents backed by real
storage objects in the same `documents` bucket + path convention the
app's own upload action uses; seeds a 4-message coach<->player
conversation; and re-dates recent lift sessions/readiness check-ins
(both the live helm_lifting_* tables and the legacy
baseball_readiness_checkins table) so "Recent" reads as current.

Rows the base seed already owns are updated in place via partial-column
.update() on the same deterministic ids (no destructive delete-then-
insert); new rows are keyed under a dedicated 'baseball-demo-reseed-v1'
id namespace so re-runs upsert instead of duplicating. Ran against prod
with --confirm; verified via SQL (row counts stable across 3 runs,
get_baseball_conversations_with_details RPC, and a storage download
round-trip on all 4 documents).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CHFRrZkRsAHWTwvxhySkfe
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@vercel

vercel Bot commented Jul 2, 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 2, 2026 4:43am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (3)
  • main
  • develop
  • release/*

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d6b16445-5880-49fc-b1bd-4f7d4e27c392

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/baseball-vv-demo-freshness
  • 🛠️ helm safety pass
  • 🛠️ dashboard ux pass
  • 🛠️ rls test pass

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

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add idempotent freshness reseed script for Rini University Baseball demo

🐞 Bug fix ✨ Enhancement 🕐 20-40 Minutes

Grey Divider

AI Description

• Add companion reseed script to keep Rini Baseball demo dates always future/current.
• Seed missing demo surfaces: development plans, documents (real storage objects), and messaging.
• Update existing seeded rows in place using deterministic IDs for safe re-runs.
Diagram

graph TD
  A["reseed-rini-demo-freshness.ts"] --> B["Deterministic IDs"] --> C[("Supabase DB")]
  A["reseed-rini-demo-freshness.ts"] --> D[("Storage: documents")]
  C[("Supabase DB")] --> E["Update existing rows"] --> F["events/games/readiness/lifts"]
  C[("Supabase DB")] --> G["Upsert demo-owned rows"] --> H["dev plans/docs/messages"]
  D[("Storage: documents")] --> I["baseball-documents/<team>/<id>.txt"]

  subgraph Legend
    direction LR
    _script["Script"] ~~~ _db[("Database")] ~~~ _store[("Object storage")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make base seed date-anchorable (e.g., --anchor-date)
  • ➕ Single script to maintain; avoids keeping IDs/formulas in sync across two scripts
  • ➕ Re-running base seed could regenerate all relative dates consistently
  • ➖ Harder to keep safe/idempotent without overwriting unrelated seeded/edited data
  • ➖ Risk of broader changes to production demo data beyond freshness needs
2. Scheduled job / cron-based reseed in production
  • ➕ Keeps demo perpetually fresh without manual runs
  • ➕ Centralizes ownership and audit of demo refresh behavior
  • ➖ Requires infrastructure/ops work and secure credential handling
  • ➖ Higher blast radius if misconfigured; needs strong guardrails and monitoring
3. Use a dedicated 'demo fixtures' schema / separate project
  • ➕ Isolation: no risk to non-demo teams/tables
  • ➕ Can freely reset/seed without careful in-place updates
  • ➖ Significant environment and app wiring changes
  • ➖ More overhead to keep UI pointed at the right backend for demos

Recommendation: Current approach is a good pragmatic fix: a companion reseed script that updates base-seeded rows in place and adds demo-only content under a dedicated deterministic namespace. The main thing to keep an eye on is drift between the base seed’s deterministic IDs/formulas and this script—if the base seed changes, this script must be updated in lockstep. A scheduled job could be considered later if manual refresh becomes frequent.

Files changed (1) +612 / -0

Enhancement (1) +612 / -0
reseed-rini-demo-freshness.tsAdd idempotent demo reseed script to refresh dates and seed premium surfaces +612/-0

Add idempotent demo reseed script to refresh dates and seed premium surfaces

• Introduces a companion Supabase script that keeps the Rini University Baseball demo fresh by re-dating existing base-seeded events/games/readiness/lift data via deterministic IDs and partial-column updates. Adds new demo-owned content (development plans, documents with real storage uploads + signed URLs, and a coach/player conversation) using a dedicated deterministic namespace to ensure reruns upsert without duplication. Includes dry-run vs --confirm behavior plus schema-mismatch tolerance and a summary report of intended/written row counts.

scripts/reseed-rini-demo-freshness.ts

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (2) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 93 rules

Grey Divider


Action required

1. createClient imported from @supabase/supabase-js 📘 Rule violation ⌂ Architecture
Description
This script directly imports and instantiates a Supabase client via @supabase/supabase-js instead
of using the shared server-side Supabase client factory. This can bypass centralized configuration
and policy controls intended to standardize server-side DB access.
Code

scripts/reseed-rini-demo-freshness.ts[68]

+import { createClient, type SupabaseClient } from '@supabase/supabase-js';
Relevance

⭐⭐ Medium

No clear prior reviews enforcing “no direct @supabase/supabase-js createClient”; repo mostly uses
shared createClient().

PR-#336

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1519229 requires server-side code to use the shared Supabase client factory, not
direct @supabase/supabase-js client creation. The new script imports createClient from
@supabase/supabase-js and calls it with env vars to create a client used for DB/storage
operations.

Rule 1519229: Use the shared server-side Supabase client factory for all database access
scripts/reseed-rini-demo-freshness.ts[67-69]
scripts/reseed-rini-demo-freshness.ts[183-187]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`scripts/reseed-rini-demo-freshness.ts` creates a Supabase client by importing `createClient` from `@supabase/supabase-js`, instead of using the shared server-side Supabase client factory.

## Issue Context
The compliance rule requires server-side code paths to obtain Supabase clients exclusively from the shared factory (per project convention). This script runs server-side and performs DB/storage writes.

## Fix Focus Areas
- scripts/reseed-rini-demo-freshness.ts[67-69]
- scripts/reseed-rini-demo-freshness.ts[183-187]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Document version_count reset 🐞 Bug ≡ Correctness
Description
The reseed upsert always writes baseball_documents.version_count = 1, which will overwrite any
higher version_count created by user uploads and can break/lie to the Documents UI (badges/history
expectations) on reruns.
Code

scripts/reseed-rini-demo-freshness.ts[R455-468]

+    await upsert('baseball_documents', [{
+      id: docId,
+      team_id: TEAM_ID,
+      title: doc.title,
+      description: doc.description,
+      file_url: signedUrl,
+      file_type: 'text/plain',
+      file_size: buf.byteLength,
+      category: doc.category,
+      is_player_visible: true,
+      uploaded_by: COACH_USER_ID,
+      version_count: 1,
+      folder: doc.folder,
+    }]);
Relevance

⭐⭐ Medium

No historical evidence on preserving baseball_documents.version_count; recent docs work focused on
URL/version_number only.

PR-#576

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The reseed script hardcodes version_count=1 for each document. The UI explicitly reads version_count
to show a version badge and to manage version behavior; resetting it will misrepresent the real
state after uploads.

scripts/reseed-rini-demo-freshness.ts[455-468]
src/components/baseball/documents/DocumentCard.tsx[165-170]
src/app/baseball/(dashboard)/dashboard/documents/documents-client.tsx[153-160]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The reseed script upserts `baseball_documents` with `version_count: 1` every time. If the demo team has uploaded additional versions via the UI, rerunning this script will reset `version_count` back to 1 even though higher versions still exist in `baseball_document_versions`.

### Issue Context
The client UI uses `version_count` for version badges and for some version-history logic. The script is intended to be safely re-runnable in prod.

### Fix Focus Areas
- scripts/reseed-rini-demo-freshness.ts[455-468]

### Suggested fix
For each document:
- Fetch the existing row (or at least `version_count`, and possibly `file_url/file_type/file_size`) before writing.
- If the document already exists, avoid overwriting `version_count` (and consider not overwriting `file_url/file_type/file_size` either), e.g.:
 - Use an `update()` for non-version metadata only (title/description/category/folder/is_player_visible/uploaded_by) OR
 - Conditionally include `version_count: 1` only on first creation.
- Alternatively, compute `version_count` from `MAX(version_number)` in `baseball_document_versions` for that document and write that value.

This keeps reruns idempotent without regressing existing document/version state.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Idempotency comment is stale 🐞 Bug ⚙ Maintainability
Description
The header comment claims sections (1) and (5) use partial-column upserts, but the implementation
uses updateMany() (plain updates), which can mislead future maintainers about behavior and
constraints.
Code

scripts/reseed-rini-demo-freshness.ts[R40-45]

+ * Idempotency:
+ *   - (1) and (5) are partial-column UPSERTs (`onConflict: 'id'`) against
+ *     ids the base seed already created — Postgres `ON CONFLICT DO UPDATE
+ *     SET <listed columns>` never touches columns this script doesn't
+ *     list, so unrelated columns (roster, box scores, etc.) are untouched.
+ *     No destructive delete-then-insert anywhere.
Relevance

⭐⭐ Medium

Mixed history: stale/misleading comments removed in PR296, but comment-fix suggestions sometimes
rejected elsewhere.

PR-#296
PR-#238

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The comment explicitly says upsert for sections (1) and (5), but those sections call updateMany()
for baseball_events/games and lift/readiness tables.

scripts/reseed-rini-demo-freshness.ts[40-45]
scripts/reseed-rini-demo-freshness.ts[210-218]
scripts/reseed-rini-demo-freshness.ts[534-597]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The script header’s idempotency section says (1) and (5) are partial-column UPSERTs, but the code uses `updateMany()` with `.update().eq('id', ...)`.

### Issue Context
This is a demo/prod reseed script; accurate documentation matters for safe reruns and future maintenance.

### Fix Focus Areas
- scripts/reseed-rini-demo-freshness.ts[40-45]

### Suggested fix
Update the header comment to describe the actual mechanism (`updateMany` / partial-column UPDATE) and why it’s used (avoids insert-time NOT NULL validation issues), matching the detailed explanation already present above `updateMany()`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Non-prefixed helm_lifting_* tables 📘 Rule violation ⚙ Maintainability
Description
The script writes to tables with the helm_lifting_* prefix, which does not match the allowed
golf_/baseball_ prefixes required by the checklist. This weakens the enforced sport-domain table
naming convention and can complicate governance and auditing.
Code

scripts/reseed-rini-demo-freshness.ts[R529-585]

+  const hasLiftSeed = DRY ? true : await rowExists('helm_lifting_sessions', detId('sess:0:p1'));
+  if (!hasLiftSeed) {
+    console.warn('  ⚠ skipped section 5 — helm_lifting_sessions has no rows from the base seed yet');
+  } else {
+    // 5a. Legacy baseball_readiness_checkins.check_date -> today.
+    await updateMany(
+      'baseball_readiness_checkins',
+      ROSTER_KEYS.map((key) => ({ id: detId(`bready:${key}`), check_date: dateDaysAgo(0) })),
+    );
+
+    // 5b. Live helm_lifting_readiness_checkins.checkin_date -> within the
+    // last 3 days (matches the base seed's own (i % 3) + 1 formula, just
+    // re-anchored to today so it stays inside the 7-day "recent" window
+    // read models like decision-room/readiness.ts filter on).
+    await updateMany(
+      'helm_lifting_readiness_checkins',
+      ROSTER_KEYS.map((key, i) => ({ id: detId(`checkin:${key}`), checkin_date: dateDaysAgo((i % 3) + 1) })),
+    );
+
+    // 5c. Program assignments (the 2-week in-season block): 2 completed
+    // weeks in the past, "today", and one upcoming.
+    await updateMany('helm_lifting_program_assignments', [
+      { id: detId('pa:w1l'), scheduled_date: dateDaysAgo(10), player_visible_at: isoDaysAgo(10) },
+      { id: detId('pa:w1u'), scheduled_date: dateDaysAgo(7), player_visible_at: isoDaysAgo(7) },
+      { id: detId('pa:w2l'), scheduled_date: dateDaysAgo(0), player_visible_at: isoDaysAgo(0) },
+      { id: detId('pa:w2u'), scheduled_date: dateDaysFromNow(3), player_visible_at: isoDaysAgo(0) },
+    ]);
+
+    // 5d. Sessions per (program-assignment index `pi`, roster key) — same
+    // 4-slot shape the base seed created (pi 0/1 completed in the past,
+    // pi 2 = "today", pi 3 = upcoming). Title text embeds the date for
+    // completed sessions, so it's redated together with scheduled_date/
+    // started_at/completed_at to avoid a stale date baked into the title.
+    const SESSION_SLOTS = [
+      { pi: 0, exName: 'Back Squat', completed: true, date: dateDaysAgo(10), at: isoDaysAgo(10) },
+      { pi: 1, exName: 'Bench Press', completed: true, date: dateDaysAgo(7), at: isoDaysAgo(7) },
+      { pi: 2, exName: 'Back Squat', completed: false, date: dateDaysAgo(0), at: null as string | null },
+      { pi: 3, exName: 'Bench Press', completed: false, date: dateDaysFromNow(3), at: null as string | null },
+    ];
+    const sessionRows: { id: string; [key: string]: unknown }[] = [];
+    for (const slot of SESSION_SLOTS) {
+      const title = slot.completed
+        ? `${slot.exName} day — ${slot.date}`
+        : slot.pi === 2
+          ? `Today's lift — ${slot.exName} day`
+          : `Upcoming — ${slot.exName} day`;
+      for (const key of ROSTER_KEYS) {
+        sessionRows.push({
+          id: detId(`sess:${slot.pi}:${key}`),
+          title,
+          scheduled_date: slot.date,
+          started_at: slot.at,
+          completed_at: slot.at,
+        });
+      }
+    }
+    await updateMany('helm_lifting_sessions', sessionRows);
Relevance

⭐ Low

Repo actively uses helm_lifting_* tables (e.g., PR573); naming-prefix rule not enforced
historically.

PR-#573

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1519306 requires table names to start with golf_ or baseball_. The new script
references and updates helm_lifting_sessions, helm_lifting_readiness_checkins, and
helm_lifting_program_assignments, which do not match the allowed prefixes.

Rule 1519306: Enforce sport-specific table name prefixes
scripts/reseed-rini-demo-freshness.ts[529-586]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
This change performs reads/updates against `helm_lifting_*` tables, which do not match the required sport-specific prefixes (`golf_` or `baseball_`).

## Issue Context
The compliance rule requires sport-domain tables to use `golf_` or `baseball_` prefixes. If `helm_lifting_*` is an approved legacy exception, the rule or conventions should be updated/annotated; otherwise, consider migrating/aliasing to sport-prefixed tables.

## Fix Focus Areas
- scripts/reseed-rini-demo-freshness.ts[529-586]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. rowExists drops Supabase errors 🐞 Bug ☼ Reliability
Description
rowExists() ignores the Supabase response error and treats any failure as “row missing”, which can
incorrectly throw “Team not found” or skip lift freshness updates when the real problem is a
query/schema/auth failure.
Code

scripts/reseed-rini-demo-freshness.ts[R175-178]

+async function rowExists(table: string, id: string): Promise<boolean> {
+  const { data } = await supabase.from(table).select('id').eq('id', id).maybeSingle();
+  return !!data;
+}
Relevance

⭐ Low

Team often rejects adding Supabase error handling; similar “don’t ignore error” suggestion rejected
in PR564.

PR-#564

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
rowExists() ignores the error field entirely, unlike upsert()/updateMany() which check error and
either skip or throw; this makes query failures indistinguishable from missing rows.

scripts/reseed-rini-demo-freshness.ts[127-173]
scripts/reseed-rini-demo-freshness.ts[175-178]
scripts/reseed-rini-demo-freshness.ts[191-198]
scripts/reseed-rini-demo-freshness.ts[529-532]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`rowExists()` discards the Supabase `error` field and returns `false` whenever `data` is absent. This conflates “row does not exist” with “query failed”, which can lead to misleading failures (e.g., throwing `Team ... not found` when the real issue is schema cache/auth/network) or unintended skipping of later sections.

### Issue Context
This script already has explicit error-handling patterns in `upsert()` and `updateMany()`. `rowExists()` should follow the same pattern.

### Fix Focus Areas
- scripts/reseed-rini-demo-freshness.ts[175-178]

### Suggested fix
- Capture `{ data, error }` and:
 - If `error` is non-null, throw an Error with table/id context (or at minimum log+rethrow), so operators see the true cause.
 - Otherwise return `Boolean(data)`.
- Optionally: for the “base seed must already exist” guard, provide a more precise error message when the query itself fails vs when the row is genuinely absent.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

* (team + org ids below) are written.
*/
import 'dotenv/config';
import { createClient, type SupabaseClient } from '@supabase/supabase-js';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. createclient imported from @supabase/supabase-js 📘 Rule violation ⌂ Architecture

This script directly imports and instantiates a Supabase client via @supabase/supabase-js instead
of using the shared server-side Supabase client factory. This can bypass centralized configuration
and policy controls intended to standardize server-side DB access.
Agent Prompt
## Issue description
`scripts/reseed-rini-demo-freshness.ts` creates a Supabase client by importing `createClient` from `@supabase/supabase-js`, instead of using the shared server-side Supabase client factory.

## Issue Context
The compliance rule requires server-side code paths to obtain Supabase clients exclusively from the shared factory (per project convention). This script runs server-side and performs DB/storage writes.

## Fix Focus Areas
- scripts/reseed-rini-demo-freshness.ts[67-69]
- scripts/reseed-rini-demo-freshness.ts[183-187]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +455 to +468
await upsert('baseball_documents', [{
id: docId,
team_id: TEAM_ID,
title: doc.title,
description: doc.description,
file_url: signedUrl,
file_type: 'text/plain',
file_size: buf.byteLength,
category: doc.category,
is_player_visible: true,
uploaded_by: COACH_USER_ID,
version_count: 1,
folder: doc.folder,
}]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Document version_count reset 🐞 Bug ≡ Correctness

The reseed upsert always writes baseball_documents.version_count = 1, which will overwrite any
higher version_count created by user uploads and can break/lie to the Documents UI (badges/history
expectations) on reruns.
Agent Prompt
### Issue description
The reseed script upserts `baseball_documents` with `version_count: 1` every time. If the demo team has uploaded additional versions via the UI, rerunning this script will reset `version_count` back to 1 even though higher versions still exist in `baseball_document_versions`.

### Issue Context
The client UI uses `version_count` for version badges and for some version-history logic. The script is intended to be safely re-runnable in prod.

### Fix Focus Areas
- scripts/reseed-rini-demo-freshness.ts[455-468]

### Suggested fix
For each document:
- Fetch the existing row (or at least `version_count`, and possibly `file_url/file_type/file_size`) before writing.
- If the document already exists, avoid overwriting `version_count` (and consider not overwriting `file_url/file_type/file_size` either), e.g.:
  - Use an `update()` for non-version metadata only (title/description/category/folder/is_player_visible/uploaded_by) OR
  - Conditionally include `version_count: 1` only on first creation.
- Alternatively, compute `version_count` from `MAX(version_number)` in `baseball_document_versions` for that document and write that value.

This keeps reruns idempotent without regressing existing document/version state.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +40 to +45
* Idempotency:
* - (1) and (5) are partial-column UPSERTs (`onConflict: 'id'`) against
* ids the base seed already created — Postgres `ON CONFLICT DO UPDATE
* SET <listed columns>` never touches columns this script doesn't
* list, so unrelated columns (roster, box scores, etc.) are untouched.
* No destructive delete-then-insert anywhere.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Informational

5. Idempotency comment is stale 🐞 Bug ⚙ Maintainability

The header comment claims sections (1) and (5) use partial-column upserts, but the implementation
uses updateMany() (plain updates), which can mislead future maintainers about behavior and
constraints.
Agent Prompt
### Issue description
The script header’s idempotency section says (1) and (5) are partial-column UPSERTs, but the code uses `updateMany()` with `.update().eq('id', ...)`.

### Issue Context
This is a demo/prod reseed script; accurate documentation matters for safe reruns and future maintenance.

### Fix Focus Areas
- scripts/reseed-rini-demo-freshness.ts[40-45]

### Suggested fix
Update the header comment to describe the actual mechanism (`updateMany` / partial-column UPDATE) and why it’s used (avoids insert-time NOT NULL validation issues), matching the detailed explanation already present above `updateMany()`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-code-review

Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Playwright (chromium)

Failed stage: Seed BaseballHelm CI accounts [❌]

Failed test name: ""

Failure summary:

The action failed during the seed:baseball:ci step when running tsx scripts/seed-baseball-demo.ts
--confirm.
The script exited with code 1 because a required environment variable was missing:
-
SUPABASE_SERVICE_ROLE_KEY was empty (Missing required env var: SUPABASE_SERVICE_ROLE_KEY — cannot
seed baseball CI accounts, around log lines 831-834).
The earlier npm warn EBADENGINE / deprecation
messages are warnings and did not directly cause the failure.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

222:  ##[endgroup]
223:  npm warn EBADENGINE Unsupported engine {
224:  npm warn EBADENGINE   package: '@capacitor/cli@8.4.0',
225:  npm warn EBADENGINE   required: { node: '>=22.0.0' },
226:  npm warn EBADENGINE   current: { node: 'v20.20.2', npm: '10.8.2' }
227:  npm warn EBADENGINE }
228:  npm warn EBADENGINE Unsupported engine {
229:  npm warn EBADENGINE   package: 'mute-stream@4.0.0',
230:  npm warn EBADENGINE   required: { node: '^22.22.2 || ^24.15.0 || >=26.0.0' },
231:  npm warn EBADENGINE   current: { node: 'v20.20.2', npm: '10.8.2' }
232:  npm warn EBADENGINE }
233:  npm warn deprecated @types/mapbox-gl@3.5.0: This is a stub types definition. mapbox-gl provides its own type definitions, so you do not need this installed.
234:  npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
235:  npm warn deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
236:  npm warn deprecated glob@7.2.3: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
237:  npm warn deprecated serialize-error-cjs@0.1.4: Rolling release, please update to 0.2.0
238:  npm warn deprecated prebuild-install@7.1.3: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
...

575:  ├ ƒ /api/cron/v3/causality-attribute
576:  ├ ƒ /api/cron/v3/genome-backfill
577:  ├ ƒ /api/cron/v3/genome-nightly
578:  ├ ƒ /api/cron/v3/goal-suggestions-evaluate
579:  ├ ƒ /api/cron/v3/goal-suggestions-write
580:  ├ ƒ /api/cron/v3/ingest-sync
581:  ├ ƒ /api/cron/v3/standing-backfill
582:  ├ ƒ /api/cron/v3/standing-refresh
583:  ├ ƒ /api/cron/v3/weekly-coach-email
584:  ├ ƒ /api/golf/auth/login
585:  ├ ƒ /api/golf/players/[playerId]/putt-tendencies
586:  ├ ƒ /api/golf/rounds/generate-review
587:  ├ ƒ /api/golf/rounds/partial-save
588:  ├ ƒ /api/health
589:  ├ ƒ /api/inngest
590:  ├ ƒ /api/log-error
591:  ├ ƒ /api/push-subscriptions
...

819:  NEXT_PUBLIC_SUPABASE_ANON_KEY: ***
820:  NEXT_PUBLIC_REDESIGN: true
821:  E2E_GOLF_EMAIL: ***
822:  E2E_GOLF_PASSWORD: ***
823:  SUPABASE_SERVICE_ROLE_KEY: 
824:  E2E_BASEBALL_COACH_EMAIL: 
825:  E2E_BASEBALL_COACH_PASSWORD: 
826:  E2E_BASEBALL_PLAYER_EMAIL: 
827:  E2E_BASEBALL_PLAYER_PASSWORD: 
828:  COMMIT_SHA: 92a3a873fee35f80d06baef3615cacfd1084cf31
829:  NODE_OPTIONS: --max-old-space-size=8192
830:  ##[endgroup]
831:  > helmv3@1.0.0 seed:baseball:ci
832:  > tsx scripts/seed-baseball-demo.ts --confirm
833:  Missing required env var: SUPABASE_SERVICE_ROLE_KEY — cannot seed baseball CI accounts
834:  ##[error]Process completed with exit code 1.
835:  ##[group]Run actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a

@njrini99-code
njrini99-code merged commit ebf7bfd into batch/baseball-fixes Jul 2, 2026
28 of 34 checks passed
@njrini99-code
njrini99-code deleted the fix/baseball-vv-demo-freshness branch July 2, 2026 13:05
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.

1 participant