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.
6.6 KiB
API Schema Update - Resume Mode & Idempotent Behavior
Summary
Updated the /simulate/trigger endpoint to support three new use cases:
- Resume mode: Continue simulations from last completed date per model
- Idempotent behavior: Skip already-completed dates by default
- 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
-
end_dateis now REQUIRED- Cannot be
nullor empty string - Must always be provided
- For single-day simulation, set
start_date==end_date
- Cannot be
-
start_dateis now OPTIONAL- Can be
nullor omitted to enable resume mode - When
null, each model resumes from its last completed date - If no data exists (cold start), uses
end_dateas single-day simulation
- Can be
-
NEW
replace_existingfieldfalse(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-16through2025-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
-
api/main.py- Updated
SimulateTriggerRequestPydantic 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=Nonein price data checks
- Updated
-
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 acceptmodel_day_filterparameter
- Added
-
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
-
Documentation Updated
API_REFERENCE.md- Complete API documentation with examplesQUICK_START.md- Updated getting started examplesdocs/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_detailstable 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
-
Daily Automation: Resume mode perfect for cron jobs
- No need to calculate "yesterday's date"
- Just provide today as end_date
-
Idempotent by Default: Safe to re-run
- Accidentally trigger same date? No problem, it's skipped
- Explicit
replace_existing=truewhen you want to re-run
-
Per-Model Independence: Flexible deployment
- Can add new models without re-running old ones
- Models can progress at different rates
-
Clear API Contract: No ambiguity
end_datealways requiredstart_date=nullclearly means "resume"- Default behavior is safe (idempotent)
Backward Compatibility
⚠️ This is a BREAKING CHANGE for clients that:
- Rely on
end_datedefaulting tostart_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