Files
AI-Trader/CHANGELOG_NEW_API.md
Bill 7aa93af6db feat: add resume mode and idempotent behavior to /simulate/trigger endpoint
BREAKING CHANGE: end_date is now required and cannot be null/empty

New Features:
- Resume mode: Set start_date to null to continue from last completed date per model
- Idempotent by default: Skip already-completed dates with replace_existing=false
- Per-model independence: Each model resumes from its own last completed date
- Cold start handling: If no data exists in resume mode, runs only end_date as single day

API Changes:
- start_date: Now optional (null enables resume mode)
- end_date: Now REQUIRED (cannot be null or empty string)
- replace_existing: New optional field (default: false for idempotent behavior)

Implementation:
- Added JobManager.get_last_completed_date_for_model() method
- Added JobManager.get_completed_model_dates() method
- Updated create_job() to support model_day_filter for selective task creation
- Fixed bug with start_date=None in price data checks

Documentation:
- Updated API_REFERENCE.md with complete examples and behavior matrix
- Updated QUICK_START.md with resume mode examples
- Updated docs/user-guide/using-the-api.md
- Added CHANGELOG_NEW_API.md with migration guide
- Updated all integration tests for new schema
- Updated client library examples (Python, TypeScript)

Migration:
- Old: {"start_date": "2025-01-16"}
- New: {"start_date": "2025-01-16", "end_date": "2025-01-16"}
- Resume: {"start_date": null, "end_date": "2025-01-31"}

See CHANGELOG_NEW_API.md for complete details.
2025-11-01 13:34:20 -04:00

6.6 KiB

API Schema Update - Resume Mode & Idempotent Behavior

Summary

Updated the /simulate/trigger endpoint to support three new use cases:

  1. Resume mode: Continue simulations from last completed date per model
  2. Idempotent behavior: Skip already-completed dates by default
  3. Explicit date ranges: Clearer API contract with required end_date

Breaking Changes

Request Schema

Before:

{
  "start_date": "2025-10-01",        // Required
  "end_date": "2025-10-02",          // Optional (defaulted to start_date)
  "models": ["gpt-5"]                // Optional
}

After:

{
  "start_date": "2025-10-01",        // Optional (null for resume mode)
  "end_date": "2025-10-02",          // REQUIRED (cannot be null/empty)
  "models": ["gpt-5"],               // Optional
  "replace_existing": false          // NEW: Optional (default: false)
}

Key Changes

  1. end_date is now REQUIRED

    • Cannot be null or empty string
    • Must always be provided
    • For single-day simulation, set start_date == end_date
  2. start_date is now OPTIONAL

    • Can be null or omitted to enable resume mode
    • When null, each model resumes from its last completed date
    • If no data exists (cold start), uses end_date as single-day simulation
  3. NEW replace_existing field

    • false (default): Skip already-completed model-days (idempotent)
    • true: Re-run all dates even if previously completed

Use Cases

1. Explicit Date Range

curl -X POST http://localhost:8080/simulate/trigger \
  -H "Content-Type: application/json" \
  -d '{
    "start_date": "2025-10-01",
    "end_date": "2025-10-31",
    "models": ["gpt-5"]
  }'

2. Single Date

curl -X POST http://localhost:8080/simulate/trigger \
  -H "Content-Type: application/json" \
  -d '{
    "start_date": "2025-10-15",
    "end_date": "2025-10-15",
    "models": ["gpt-5"]
  }'

3. Resume Mode (NEW)

curl -X POST http://localhost:8080/simulate/trigger \
  -H "Content-Type: application/json" \
  -d '{
    "start_date": null,
    "end_date": "2025-10-31",
    "models": ["gpt-5"]
  }'

Behavior:

  • Model "gpt-5" last completed: 2025-10-15
  • Will simulate: 2025-10-16 through 2025-10-31
  • If no data exists: Will simulate only 2025-10-31

4. Idempotent Simulation (NEW)

curl -X POST http://localhost:8080/simulate/trigger \
  -H "Content-Type: application/json" \
  -d '{
    "start_date": "2025-10-01",
    "end_date": "2025-10-31",
    "models": ["gpt-5"],
    "replace_existing": false
  }'

Behavior:

  • Checks database for already-completed dates
  • Only simulates dates that haven't been completed yet
  • Returns error if all dates already completed

5. Force Replace

curl -X POST http://localhost:8080/simulate/trigger \
  -H "Content-Type: application/json" \
  -d '{
    "start_date": "2025-10-01",
    "end_date": "2025-10-31",
    "models": ["gpt-5"],
    "replace_existing": true
  }'

Behavior:

  • Re-runs all dates regardless of completion status

Implementation Details

Files Modified

  1. api/main.py

    • Updated SimulateTriggerRequest Pydantic model
    • Added validators for end_date (required)
    • Added validators for start_date (optional, can be null)
    • Added resume logic per model
    • Added idempotent filtering logic
    • Fixed bug with start_date=None in price data checks
  2. api/job_manager.py

    • Added get_last_completed_date_for_model(model) method
    • Added get_completed_model_dates(models, start_date, end_date) method
    • Updated create_job() to accept model_day_filter parameter
  3. tests/integration/test_api_endpoints.py

    • Updated all tests to use new schema
    • Added tests for resume mode
    • Added tests for idempotent behavior
    • Added tests for validation rules
  4. Documentation Updated

    • API_REFERENCE.md - Complete API documentation with examples
    • QUICK_START.md - Updated getting started examples
    • docs/user-guide/using-the-api.md - Updated user guide
    • Client library examples (Python, TypeScript)

Database Schema

No changes to database schema. New functionality uses existing tables:

  • job_details table tracks completion status per model-day
  • Unique index on (job_id, date, model) ensures no duplicates

Per-Model Independence

Each model maintains its own completion state:

Model A: last_completed_date = 2025-10-15
Model B: last_completed_date = 2025-10-10

Request: start_date=null, end_date=2025-10-31

Result:
- Model A simulates: 2025-10-16 through 2025-10-31 (16 days)
- Model B simulates: 2025-10-11 through 2025-10-31 (21 days)

Migration Guide

For API Clients

Old Code:

# Single day (old)
client.trigger_simulation(start_date="2025-10-15")

New Code:

# Single day (new) - MUST provide end_date
client.trigger_simulation(start_date="2025-10-15", end_date="2025-10-15")

# Or use resume mode
client.trigger_simulation(start_date=None, end_date="2025-10-31")

Validation Changes

Will Now Fail:

{
  "start_date": "2025-10-01",
  "end_date": ""              // ❌ Empty string rejected
}
{
  "start_date": "2025-10-01",
  "end_date": null            // ❌ Null rejected
}
{
  "start_date": "2025-10-01"  // ❌ Missing end_date
}

Will Work:

{
  "end_date": "2025-10-31"    // ✓ start_date omitted = resume mode
}
{
  "start_date": null,
  "end_date": "2025-10-31"    // ✓ Explicit null = resume mode
}

Benefits

  1. Daily Automation: Resume mode perfect for cron jobs

    • No need to calculate "yesterday's date"
    • Just provide today as end_date
  2. Idempotent by Default: Safe to re-run

    • Accidentally trigger same date? No problem, it's skipped
    • Explicit replace_existing=true when you want to re-run
  3. Per-Model Independence: Flexible deployment

    • Can add new models without re-running old ones
    • Models can progress at different rates
  4. Clear API Contract: No ambiguity

    • end_date always required
    • start_date=null clearly means "resume"
    • Default behavior is safe (idempotent)

Backward Compatibility

⚠️ This is a BREAKING CHANGE for clients that:

  • Rely on end_date defaulting to start_date
  • Don't explicitly provide end_date

Migration: Update all API calls to explicitly provide end_date.

Testing

Run integration tests:

pytest tests/integration/test_api_endpoints.py -v

All tests updated to cover:

  • Single-day simulation
  • Date ranges
  • Resume mode (cold start and with existing data)
  • Idempotent behavior
  • Validation rules