Skip to content

Bot has no time awareness: relies entirely on Shipp status field for game phase #5

Description

@buildkit-ai

Problem

The bot never compares the current time (Date.now()) against scheduledStartTime to determine game phase. It relies entirely on Shipp's status field (scheduledlivecompleted), which means:

  1. No detection of stale scheduled times — If Shipp reports a game as scheduled but the start time has passed (API lag, outage, bug), the bot will poll indefinitely with no timeout or fallback.

  2. No autonomous phase transitions — The bot can't independently determine "this game should be live by now" or "this game should be over." It's fully dependent on an external service for phase awareness.

  3. No timezone handling — Times are displayed via .toLocaleString() using the host machine's local timezone. No explicit timezone management exists.

Where it matters

Location What happens
src/trading/loop.ts:135-154 Pre-match wait loop polls DB for status change with no time-based timeout
src/adapters/shipp.ts:171-184 getLiveEvents() checks status field, never checks if scheduledStartTime has passed
src/adapters/shipp.ts:227-229 Status transitions to live only when events arrive from Shipp, not based on time
src/adapters/kalshi.ts:174-180 scheduledStartTime is used for ±24h market window, but never compared to Date.now()

How scheduledStartTime is actually used today

  • Display: converting to human-readable strings for console output
  • Market filtering: ±24h window for Kalshi market search
  • Storage: persisted in games table but never read for phase logic

Proposed Solution

Add time-aware game phase detection throughout the bot.

1. Time-based phase inference

function inferGamePhase(game: Game): 'prematch' | 'near-start' | 'should-be-live' | 'should-be-over' {
  const now = Date.now()
  const start = (game.scheduledStartTime ?? 0) * 1000

  if (now < start - 60 * 60 * 1000) return 'prematch'        // >1hr before start
  if (now < start) return 'near-start'                         // within 1hr of start
  if (now < start + 3.5 * 60 * 60 * 1000) return 'should-be-live'  // 0-3.5hrs after start
  return 'should-be-over'                                      // >3.5hrs after start
}

Use this alongside Shipp's status — trust Shipp when available, but use time as a fallback and sanity check.

2. Timeout on pre-match wait loop

If the bot is waiting for a game to go live and scheduledStartTime + buffer has passed without a status change, it should:

  • Log a warning
  • Attempt to refresh the schedule from Shipp
  • After N retries, either proceed with live polling or exit with an error

3. Auto-refresh stale games

When status === 'scheduled' but Date.now() > scheduledStartTime, proactively re-fetch the schedule from Shipp to check if the status has changed upstream.

4. Sport-aware game duration estimates

Different sports have different expected durations. Use these for "should be over" detection:

Sport Typical duration
NBA ~2.5 hours
NFL ~3.5 hours
MLB ~3 hours
Soccer ~2 hours
NCAAFB ~3.5 hours

5. Explicit timezone handling (optional)

Consider storing and displaying times in UTC internally, with configurable display timezone. This prevents issues when deploying the bot on servers in different timezones.

Impact

Without time awareness, the bot is fragile to any delay or gap in Shipp's status updates. A single slow API response can cause the bot to miss an entire game. Time-based inference provides a safety net that makes the bot resilient to upstream issues.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions