## ADDED Requirements ### Requirement: CORS restricted to explicit origins The FastAPI ML service SHALL configure CORS with explicit allowed origins instead of wildcard `*`. The default allowed origins SHALL be `["http://localhost:3000"]`. Additional origins MAY be configured via the `CORS_ORIGINS` environment variable (comma-separated). #### Scenario: Same-origin request allowed - **WHEN** a request from `http://localhost:3000` hits the ML service - **THEN** the CORS headers allow the request #### Scenario: Unknown origin blocked - **WHEN** a request from `http://evil.com` hits the ML service - **THEN** the CORS headers do not include `Access-Control-Allow-Origin` for that origin ### Requirement: Generic error responses from ML service All FastAPI endpoints SHALL return generic error messages for unexpected exceptions. The response SHALL be `{ "detail": "Internal server error" }` with HTTP 500. Full exception details SHALL be logged via `logging.error` with traceback. #### Scenario: Internal error generic response - **WHEN** a predict endpoint throws an unexpected exception - **THEN** the client receives `{ "detail": "Internal server error" }` and the traceback is logged server-side ### Requirement: Model file integrity check When loading a model via `joblib.load()`, the system SHALL verify the model file's SHA256 hash against a manifest file (`models/checksums.sha256`). If the hash does not match or the manifest entry is missing, the load SHALL fail with an error. #### Scenario: Valid model file - **WHEN** `joblib.load("models/abc123.pkl")` is called and the file's SHA256 matches the manifest - **THEN** the model loads successfully #### Scenario: Tampered model file - **WHEN** the model file's SHA256 does not match the manifest entry - **THEN** the system refuses to load the model and returns HTTP 500 with `{ "detail": "Model integrity check failed" }` ### Requirement: Thread-safe model reads The ML service SHALL use a lock for model reads during prediction, not just model writes. All code that reads the current model reference SHALL acquire the `_model_swap_lock` or use an atomic reference swap pattern. #### Scenario: Concurrent prediction and model swap - **WHEN** a prediction request is in progress and a model load request arrives - **THEN** the prediction completes with the old model (or waits), and the new model is loaded atomically ### Requirement: Path traversal prevention on model operations The FastAPI endpoints that accept `run_id` for model load and delete SHALL validate the `run_id` format and verify that the resolved file path is within the expected `models/` directory using `Path.resolve()`. #### Scenario: Valid run_id resolves within models directory - **WHEN** POST `/model/load` receives `{ run_id: "abc123" }` - **THEN** the path resolves to `models/abc123.pkl` within the models directory #### Scenario: Path traversal attempt blocked - **WHEN** POST `/model/load` receives `{ run_id: "../../etc/passwd" }` - **THEN** the endpoint returns HTTP 400 before attempting any file operation ### Requirement: Real health check The `GET /health` endpoint SHALL perform actual connectivity checks instead of returning hardcoded status. It SHALL execute `SELECT 1` against PostgreSQL and attempt an MLflow API call. #### Scenario: All services healthy - **WHEN** PostgreSQL responds to `SELECT 1` and MLflow API is reachable - **THEN** the health endpoint returns `{ "status": "healthy", "database": "connected", "mlflow": "connected" }` #### Scenario: Database unreachable - **WHEN** PostgreSQL does not respond to `SELECT 1` - **THEN** the health endpoint returns `{ "status": "degraded", "database": "disconnected" }` with HTTP 200 ### Requirement: Candle time-sort validation The `POST /predict` endpoint SHALL validate that input candles are sorted by time in ascending order. If candles are not sorted, the endpoint SHALL sort them before processing. #### Scenario: Unsorted candles auto-sorted - **WHEN** candles are provided in random time order - **THEN** the endpoint sorts them by time before feature engineering and prediction