SIENTIAPDE-1646
Update README, requirements, and E2E tests for improved configuration and functionality - Enhanced the README with updated model configuration examples, including the addition of an alias for production. - Removed the `requirements-light.txt` file and updated `requirements-local.txt` and `requirements.txt` to replace `asyncua` with `opcua`. - Refactored E2E test scenarios to utilize scenario input files for better maintainability and clarity. - Improved test coverage for MinIO offload functionality and added new helper functions for loading scenario inputs. - Updated `values.yaml` to reflect new global configurations and environment variables for the laborious worker.
This commit is contained in:
788
e2e/scenarios.md
788
e2e/scenarios.md
@@ -1,520 +1,402 @@
|
||||
# Test Scenarios for Predictions Batch Workflow
|
||||
# E2E Scenario Documentation - Predictions Batch
|
||||
|
||||
This document describes all possible test scenarios for the `predictions_batch` workflow and its child workflows `prediction_process` and `format_and_export_prediction`.
|
||||
This document describes the end-to-end scenarios for `predictions_batch` and its child workflows:
|
||||
`prediction_process` and `format_and_export_prediction`.
|
||||
|
||||
## Running automated E2E tests (`e2e/`)
|
||||
It is a functional reference of scenario behavior, inputs, and expected outcomes.
|
||||
|
||||
- **Runtime**: Docker (or a Docker-compatible daemon) must be available so [testcontainers](https://testcontainers.com/) can start **PostgreSQL** and **MinIO** containers.
|
||||
- **Dependencies**: install dev requirements (includes `testcontainers[postgres,minio]`).
|
||||
- **Invocation**: run only integration-marked tests, for example: `pytest e2e/ -m integration`.
|
||||
- **MinIO tests**: `e2e/test_minio_offload.py` exercises real S3 uploads; other E2E modules continue to mock MinIO on the worker used by most scenarios.
|
||||
## Execution Context
|
||||
|
||||
## Workflow Overview
|
||||
|
||||
The `predictions_batch` workflow:
|
||||
1. Loads data using a custom SQL query
|
||||
2. Prepares prediction configuration
|
||||
3. Delegates to `prediction_process` child workflow which:
|
||||
- Retrieves last timestamp for incremental processing
|
||||
- Applies input data quality gates
|
||||
- Executes MLFlow transform operation
|
||||
- Validates transform response
|
||||
- Executes MLFlow predict operation
|
||||
- Validates predict response
|
||||
- Delegates to `format_and_export_prediction` child workflow
|
||||
4. The `format_and_export_prediction` workflow:
|
||||
- Formats prediction data (normal or default)
|
||||
- Exports to PI Web API (optional)
|
||||
- Exports to OPC server (optional)
|
||||
- Exports to PostgreSQL
|
||||
- Writes metrics
|
||||
- Tests run under `e2e/` and are marked with `@pytest.mark.integration`.
|
||||
- PostgreSQL and MinIO are provisioned with testcontainers.
|
||||
- `test_minio_offload.py` uses real MinIO I/O; other scenario suites may use stubs/mocks for optional outputs.
|
||||
|
||||
---
|
||||
|
||||
## 1. Predictions Batch - Main Workflow Scenarios
|
||||
## 1. Main Workflow Scenarios
|
||||
Source: `e2e/test_predictions_batch_main_workflow.py`
|
||||
|
||||
### 1.1 Success Scenarios
|
||||
### 1.1.1 Happy Path - Complete Success
|
||||
**Summary**: Full workflow succeeds with valid query and default gate behavior.
|
||||
|
||||
#### Scenario 1.1.1: Happy Path - Complete Success
|
||||
**Description**: Workflow completes successfully with valid SQL query and all activities succeed
|
||||
**Description**:
|
||||
- Query returns rows for a model.
|
||||
- `prediction_process` runs transform and predict paths.
|
||||
- Final prediction and transformed data are persisted.
|
||||
|
||||
**Input**:
|
||||
- Valid `schedule_name`, `model_name`, `model_id`
|
||||
- Valid `query` returning non-empty DataFrame
|
||||
- Valid `schema`, `table_name`, `transform_table_name`
|
||||
- Optional `datetime_columns` for timestamp parsing
|
||||
- Optional `input_filters`, `mlflow_transform_filters`, `mlflow_predict_filters`
|
||||
- Optional `path_priority`, `opc_output_config`, `pi_web_api_output_config`
|
||||
**Expected Outcome**:
|
||||
- Exactly one prediction row is created.
|
||||
- Transform rows are created.
|
||||
- Confidence/status/comments are success values.
|
||||
|
||||
**Expected Behavior**:
|
||||
- `load_custom_query` returns DataFrame with data
|
||||
- Workflow prepares prediction input with all configurations
|
||||
- `prediction_process` child workflow executes successfully
|
||||
- All gates pass with no issues
|
||||
- Transform and predict operations succeed
|
||||
- Data exported to PostgreSQL
|
||||
- Metrics written
|
||||
### 1.2.1 SQL Query Execution Error
|
||||
**Summary**: Invalid SQL leads to no persisted prediction.
|
||||
|
||||
**Assertions**:
|
||||
- SQL query executed once
|
||||
- `prediction_process` workflow called with correct parameters
|
||||
- Data exists in PostgreSQL (predictions table)
|
||||
- Metrics recorded
|
||||
- No errors raised
|
||||
**Description**:
|
||||
- Input query is invalid.
|
||||
- Load step fails and workflow follows error/short-circuit path.
|
||||
|
||||
**Expected Outcome**:
|
||||
- No prediction rows for the model.
|
||||
- Workflow does not require retry-loop assumptions in assertions.
|
||||
|
||||
### 1.2.2 Missing Required Parameters
|
||||
**Summary**: Missing required fields prevent workflow completion path.
|
||||
|
||||
**Description**:
|
||||
- Required input key (e.g. `query`) is omitted.
|
||||
- Workflow fails to produce actionable input for child flow.
|
||||
|
||||
**Expected Outcome**:
|
||||
- No prediction rows are persisted.
|
||||
- Workflow handle may require explicit terminate in E2E harness.
|
||||
|
||||
### 1.2.3 Invalid Datetime Column Specification (de-prioritized)
|
||||
**Summary**: Legacy invalid datetime-column case is retained only as low-priority legacy coverage.
|
||||
|
||||
**Description**:
|
||||
- `datetime_columns` references non-existing columns.
|
||||
- Behavior may vary by query shape and parser fallback.
|
||||
|
||||
**Expected Outcome**:
|
||||
- No predictions persisted in the covered legacy assertion path.
|
||||
- Scenario is not considered primary behavior coverage.
|
||||
|
||||
---
|
||||
|
||||
### 1.2 Error Scenarios
|
||||
## 2. Prediction Process Scenarios
|
||||
Source: `e2e/test_predictions_batch_prediction_process.py`
|
||||
|
||||
#### Scenario 1.2.1: SQL Query Execution Error
|
||||
**Description**: SQL query fails due to syntax error or connection issue
|
||||
### 2.1 Input Gate Path Decisions
|
||||
|
||||
**Input**:
|
||||
- Invalid SQL query (syntax error)
|
||||
- Or database connection unavailable
|
||||
#### 2.1.1 CONTINUE
|
||||
**Summary**: Input filter flags quality issue but allows continuation via default path.
|
||||
|
||||
**Expected Behavior**:
|
||||
- `load_custom_query` raises exception (caught by Temporal retry policy)
|
||||
- Notification sent with SQL error details
|
||||
- After retries, activity may return empty data or workflow may fail
|
||||
- If empty data returned, workflow completes with early exit via input gate
|
||||
**Description**:
|
||||
- Input gate returns `CONTINUE`.
|
||||
- MLFlow transform/predict are skipped.
|
||||
- Export path persists default-style prediction with warning context.
|
||||
|
||||
**Assertions**:
|
||||
- Error notification sent
|
||||
- Workflow completes (either fails or exits early)
|
||||
- No data in predictions table
|
||||
#### 2.1.2 STOP
|
||||
**Summary**: Input filter blocks processing.
|
||||
|
||||
**Description**:
|
||||
- Input gate returns `STOP`.
|
||||
- Workflow exits without export.
|
||||
|
||||
#### 2.1.3 REPEAT with history
|
||||
**Summary**: Prior prediction is reused.
|
||||
|
||||
**Description**:
|
||||
- Input gate returns `REPEAT`.
|
||||
- `repeat_last_prediction` path is executed using existing historical row.
|
||||
|
||||
#### 2.1.4 REPEAT without history
|
||||
**Summary**: Repeat requested but no previous prediction exists.
|
||||
|
||||
**Description**:
|
||||
- Input gate returns `REPEAT`.
|
||||
- No prior row is available to duplicate.
|
||||
|
||||
**Expected Outcome**:
|
||||
- No new prediction rows are created for the model.
|
||||
|
||||
### 2.2 Transform Gate Decisions
|
||||
|
||||
#### 2.2.1 CONTINUE on transform response error
|
||||
**Summary**: Transform response is degraded, but workflow continues.
|
||||
|
||||
#### 2.2.2 STOP on transform response error
|
||||
**Summary**: Transform response error blocks downstream processing.
|
||||
|
||||
#### 2.2.3 REPEAT on transform response error
|
||||
**Summary**: Transform response error triggers repeat-last-prediction path.
|
||||
|
||||
#### 2.2.4 STOP on transform content NaN
|
||||
**Summary**: Content gate (`NAN_VALUES`) blocks on all-NaN transform payload.
|
||||
|
||||
### 2.3 Predict Gate Decisions
|
||||
|
||||
#### 2.3.1 CONTINUE on predict response error
|
||||
**Summary**: Predict response degraded; workflow exports with degraded metadata.
|
||||
|
||||
#### 2.3.2 STOP on predict response error
|
||||
**Summary**: Predict response error blocks export.
|
||||
|
||||
#### 2.3.3 REPEAT on predict response error
|
||||
**Summary**: Predict response error routes to repeat-last-prediction.
|
||||
|
||||
### 2.4.1 Priority Conflict Resolution
|
||||
**Summary**: Deterministic selection when multiple filters produce different flags.
|
||||
|
||||
**Description**:
|
||||
- Multiple filters may produce `STOP`, `CONTINUE`, and/or `REPEAT`.
|
||||
- `path_priority` defines precedence.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Highest-priority flag is applied consistently.
|
||||
- Executed branch matches configured priority ordering.
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 1.2.2: Missing Required Parameters
|
||||
**Description**: Essential parameters missing from input
|
||||
## 3. Format and Export Scenarios
|
||||
Source: `e2e/test_predictions_batch_format_export.py`
|
||||
|
||||
**Input**:
|
||||
- Missing `query` or `model_id` or `schema` or `table_name`
|
||||
### 3.1 Output Combination Scenarios
|
||||
|
||||
**Expected Behavior**:
|
||||
- Workflow or activity raises KeyError or validation error
|
||||
- Workflow fails immediately
|
||||
#### 3.1.1 Default prediction export
|
||||
**Summary**: Non-`None` path flag uses `format_default_prediction`.
|
||||
|
||||
**Assertions**:
|
||||
- Workflow fails with parameter error
|
||||
- Error notification sent
|
||||
- No child workflow called
|
||||
**Description**:
|
||||
- Default prediction is generated.
|
||||
- Transform export is skipped.
|
||||
- Optional outputs (PI/OPC) still execute when configured.
|
||||
|
||||
#### 3.1.2 OPC only
|
||||
**Summary**: Postgres + OPC writes, PI Web API disabled.
|
||||
|
||||
#### 3.1.3 PI Web API only
|
||||
**Summary**: Postgres + PI writes, OPC disabled.
|
||||
|
||||
#### 3.1.4 Postgres only
|
||||
**Summary**: Both optional outputs disabled; only Postgres persistence and metrics.
|
||||
|
||||
#### 3.1.5 No transformed data export
|
||||
**Summary**: Prediction is persisted; transformed table is not written.
|
||||
|
||||
### 3.2 Degraded-but-successful Completion
|
||||
|
||||
#### 3.2.1 PI Web API write error
|
||||
**Summary**: PI write failure does not fail workflow.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Workflow completes.
|
||||
- Prediction persisted with degraded confidence/comments (PI error semantics).
|
||||
|
||||
#### 3.2.2 OPC write error
|
||||
**Summary**: OPC write failure does not fail workflow.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Workflow completes.
|
||||
- Prediction persisted with OPC degraded confidence/comments.
|
||||
|
||||
#### 3.2.3 PI Web API partial write error
|
||||
**Summary**: Partial PI acknowledgement is treated as degraded success.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Workflow completes.
|
||||
- Prediction persisted with PI error confidence and descriptive comment.
|
||||
|
||||
### 3.3.1 Combined Optional Outputs (PI + OPC)
|
||||
**Summary**: Both external output channels are enabled together.
|
||||
|
||||
**Description**:
|
||||
- PI Web API and OPC configs are both present.
|
||||
- Output mutation order matters for final persisted payload.
|
||||
|
||||
**Expected Outcome**:
|
||||
- PI write executes before OPC write in workflow sequence.
|
||||
- Final Postgres payload reflects any confidence/comment updates.
|
||||
- OPC metrics are emitted when tag writes return response times.
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 1.2.3: Invalid Datetime Column Specification
|
||||
**Description**: Datetime column specified doesn't exist in query results
|
||||
## 4. MinIO Offload Scenarios
|
||||
Source: `e2e/test_minio_offload.py`
|
||||
|
||||
**Input**:
|
||||
- `datetime_columns: ['nonexistent_column']`
|
||||
- Query results don't have this column
|
||||
### 4.1.1 Forced offload to MinIO
|
||||
**Summary**: Very low threshold forces parquet upload.
|
||||
|
||||
**Expected Behavior**:
|
||||
- `load_custom_query` may raise KeyError or warning
|
||||
- Depending on implementation, workflow may fail or continue
|
||||
- Error notification sent
|
||||
**Description**:
|
||||
- Payload is offloaded (`object_key` present, inline data absent/empty).
|
||||
- Object is present in MinIO under `prediction_datasets/...`.
|
||||
- Retrieval reconstructs the dataframe.
|
||||
|
||||
**Assertions**:
|
||||
- Error raised or warning logged
|
||||
- Workflow behavior depends on error handling policy
|
||||
### 4.1.2 Full workflow with offloaded load payload
|
||||
**Summary**: Offload path works during full `predictions_batch` execution.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Workflow completes.
|
||||
- Prediction row is persisted.
|
||||
|
||||
### 4.2.1 Inline payload below threshold
|
||||
**Summary**: Data remains inline when threshold is not exceeded.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Payload stores inline `data`.
|
||||
- `object_key` is `None`.
|
||||
- Downstream persistence behavior matches offload scenario semantics.
|
||||
|
||||
---
|
||||
|
||||
## 2. Prediction Process - Child Workflow Scenarios
|
||||
## 5. Drift Workflow Scenarios
|
||||
Source: `e2e/test_drift.py`
|
||||
|
||||
### 2.1 Input gate Early Exit Scenarios
|
||||
The drift suite mocks `sientia.ModelAnalysis.ModelAnalysis` (not installed; see
|
||||
`CODE_ISSUES.md` issue #1) through the controllable `_FakeModelAnalysis` stub
|
||||
exposed by the `model_analysis_stub` fixture. The `mlflow_repository_stub`
|
||||
provides the reference-data CSV via `download_artifacts`. Every scenario asserts
|
||||
postgres rows in `predictions_schema.drift` against this canonical schema:
|
||||
|
||||
#### Scenario 2.1.1: Input Gate Triggers CONTINUE
|
||||
**Description**: Input gate determines data should use previous prediction
|
||||
`id, model_id, feature, method, value, drift, chunk, timestamp, timestamp_end, accurate, created_at, updated_at`.
|
||||
|
||||
**Input**:
|
||||
- Data that should continue with input data as prediction
|
||||
- `input_filters` configured with `POLICY: 'CONTINUE'`
|
||||
- `path_priority` includes CONTINUE
|
||||
### 5.1 Happy paths
|
||||
|
||||
**Expected Behavior**:
|
||||
- `input_gate` returns `path_flag='CONTINUE'`
|
||||
- `path_flag_handler` calls export workflow with input data directly
|
||||
- MLFlow transform and predict skipped
|
||||
- Data exported as-is
|
||||
#### D.1.1 Full pipeline persists all columns with reference data
|
||||
**Summary**: ModelAnalysis returns a deterministic drift dataframe; the
|
||||
reference CSV is downloaded from the MLflow stub.
|
||||
|
||||
**Assertions**:
|
||||
- `input_gate` called
|
||||
- MLFlow operations NOT called
|
||||
- Export workflow called with original data
|
||||
- Workflow completes
|
||||
**Expected Outcome**:
|
||||
- One row per `(chunk, feature, method)` plus a `multivariate` block per chunk.
|
||||
- Every drift column is populated and `accurate=True`.
|
||||
- `timestamp_end` preserves the high-precision string (`HH:MM:59.999999999`).
|
||||
- `p_value` is dropped before persistence.
|
||||
- `drift` flags propagate per `(feature, method)` configuration.
|
||||
|
||||
#### D.1.2 30% fallback when reference data is unavailable
|
||||
**Summary**: `get_reference_data` fails alias resolution and returns `None`;
|
||||
`calculate_drift` uses the first 30% of target rows as reference.
|
||||
|
||||
#### Scenario 2.1.2: Input Gate Triggers STOP
|
||||
**Description**: Input data quality gate fails with STOP policy
|
||||
**Expected Outcome**:
|
||||
- Persisted rows carry `accurate=False`.
|
||||
- A `MODEL_METRICS_REFERENCE_DATA_WARNING` notification is emitted to MongoDB.
|
||||
|
||||
**Input**:
|
||||
- Data with EMPTY_DATA or other critical issues
|
||||
- `input_filters` configured with `POLICY: 'STOP'`
|
||||
### 5.2 Filtering / dedup invariants
|
||||
|
||||
**Expected Behavior**:
|
||||
- `input_gate` returns `path_flag='STOP'`
|
||||
- `path_flag_handler` detects STOP
|
||||
- Workflow returns early without calling MLFlow
|
||||
- No prediction exported
|
||||
#### D.2.1 Deduplication and `p_value` removal
|
||||
**Summary**: ModelAnalysis returns duplicate `(timestamp, method, feature)` rows
|
||||
plus a `p_value` column.
|
||||
|
||||
**Assertions**:
|
||||
- `input_gate` called
|
||||
- `path_flag_handler` returns True (early exit)
|
||||
- MLFlow transform NOT called
|
||||
- Export workflow NOT called
|
||||
- Workflow completes without error
|
||||
**Expected Outcome**:
|
||||
- Duplicates are collapsed keeping the first occurrence.
|
||||
- `p_value` is absent from the persisted rows.
|
||||
|
||||
#### D.2.2 Out-of-range timestamps filtered
|
||||
**Summary**: Drift rows whose timestamps are not present in the target window
|
||||
must be discarded before persistence.
|
||||
|
||||
#### Scenario 2.1.3: Input Gate Triggers REPEAT
|
||||
**Description**: Input gate determines data should repeat last prediction
|
||||
### 5.3 Failure paths
|
||||
|
||||
**Input**:
|
||||
- Data with quality issues that require using previous prediction
|
||||
- `input_filters` configured with `POLICY: 'REPEAT'`
|
||||
- `path_priority` includes REPEAT
|
||||
#### D.3.1 Empty target data short-circuits the workflow
|
||||
**Summary**: `load_custom_query` returns no rows; ModelAnalysis is never
|
||||
instantiated and no drift rows are written.
|
||||
|
||||
**Expected Behavior**:
|
||||
- `input_gate` returns `path_flag='REPEAT'`
|
||||
- `path_flag_handler` calls `repeat_last_prediction` activity
|
||||
- MLFlow transform and predict skipped
|
||||
- Last prediction repeated and exported
|
||||
#### D.3.2 ModelAnalysis raises during dataframe assembly
|
||||
**Summary**: `get_drift_metrics_dataframe` raises. The activity catches the
|
||||
error, sends a `MODEL_METRICS_GET_DRIFT_METRICS_ERROR` notification, and the
|
||||
workflow completes without persisting drift rows.
|
||||
|
||||
**Assertions**:
|
||||
- `input_gate` called
|
||||
- MLFlow operations NOT called
|
||||
- `repeat_last_prediction` activity called
|
||||
- Workflow completes
|
||||
### 5.4 Configuration paths
|
||||
|
||||
#### D.4.1 Default drift metrics propagated to analyzer
|
||||
**Summary**: Omitting `drift_metrics` defaults to
|
||||
`['kolmogorov_smirnov', 'jensen_shannon', 'wasserstein']` and forwards the
|
||||
exact list to `detect_univariate_drift`.
|
||||
|
||||
#### D.4.2 Invalid `chunk_period` raises ValueError
|
||||
**Summary**: Anything other than `min` / `s` is rejected by `calculate_drift`.
|
||||
|
||||
#### D.4.3 `chunk_period='s'` keeps seconds in timestamp filtering
|
||||
**Summary**: Truncated `YYYY-MM-DD HH:MM` rows are filtered out when chunking
|
||||
runs at second granularity.
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Transform gate Early Exit Scenarios
|
||||
## 6. Simple Metrics Workflow Scenarios
|
||||
Source: `e2e/test_simple_metrics.py`
|
||||
|
||||
#### Scenario 2.2.1: Transform Gate Triggers CONTINUE
|
||||
**Description**: Transform response gate determines data should continue despite issues
|
||||
Validates `predictions_schema.simple_metrics_data` columns:
|
||||
`id, model_id, metric, value, timestamp, data_size, interval_minutes, created_at`.
|
||||
|
||||
**Input**:
|
||||
- Valid input data
|
||||
- Transform response has quality issues but policy is CONTINUE
|
||||
- `mlflow_transform_filters` configured with `POLICY: 'CONTINUE'`
|
||||
- `path_priority` includes CONTINUE
|
||||
### 6.1 Happy paths
|
||||
|
||||
**Expected Behavior**:
|
||||
- `request_transform` succeeds
|
||||
- `mlflow_response_gate` for transform returns `path_flag='CONTINUE'`
|
||||
- `path_flag_handler` calls export workflow with transform data
|
||||
- MLFlow predict skipped
|
||||
- Transform data exported as-is
|
||||
#### S.1.1 rmse/mse/mae/r2 happy path
|
||||
**Summary**: Prediction/target pairs are inserted; the activity computes all
|
||||
four metrics with closed-form expected values.
|
||||
|
||||
**Assertions**:
|
||||
- Transform completed
|
||||
- `mlflow_response_gate` called for transform
|
||||
- MLFlow predict NOT called
|
||||
- Export workflow called with transform data
|
||||
- Workflow completes
|
||||
**Expected Outcome**:
|
||||
- One row per metric is persisted; all columns populated.
|
||||
- `data_size` matches the joined row count and `interval_minutes=60`.
|
||||
|
||||
#### S.1.2 Subset metrics
|
||||
**Summary**: Requesting `metrics=['rmse']` writes only the rmse row.
|
||||
|
||||
### 6.2 Edge cases
|
||||
|
||||
#### S.2.1 Zero-variance target returns r2=0
|
||||
**Summary**: When all targets are equal, `ss_tot=0`; the activity must guard
|
||||
against division by zero and return `r2=0`.
|
||||
|
||||
### 6.3 Failure paths
|
||||
|
||||
#### S.3.1 No overlapping data short-circuits persistence
|
||||
**Summary**: With no `laborious_data` rows for the configured target variable
|
||||
the workflow exits before `calculate_simple_metrics` and writes nothing.
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 2.2.2: Transform Gate Triggers STOP
|
||||
**Description**: Transform response validation fails with STOP policy
|
||||
## 7. Minimal Retrain Workflow Scenarios
|
||||
Source: `e2e/test_minimal_retrain.py`
|
||||
|
||||
**Input**:
|
||||
- Valid input data
|
||||
- Transform response has critical errors
|
||||
- `mlflow_transform_filters` configured with `POLICY: 'STOP'`
|
||||
The MLflow registry is fully mocked (no real artifacts in test container).
|
||||
Validates `predictions_schema.retrain_reports` columns:
|
||||
`id, model_id, model_name, timestamp, status, version, mlflow_run_id, mlflow_experiment_id, created_at`.
|
||||
|
||||
**Expected Behavior**:
|
||||
- `request_transform` succeeds but response invalid
|
||||
- `mlflow_response_gate` for transform returns `path_flag='STOP'`
|
||||
- Workflow exits without calling predict or export
|
||||
### 7.1 Happy path
|
||||
|
||||
**Assertions**:
|
||||
- Transform completed but validation failed
|
||||
- `mlflow_response_gate` called for transform
|
||||
- MLFlow predict NOT called
|
||||
- Export workflow NOT called
|
||||
- Workflow completes without error
|
||||
#### MR.1.1 Successful retrain + promotion
|
||||
**Summary**: Training data loads via MinIO offload, `wrapper.retrain` succeeds,
|
||||
the new version is promoted to the `production` alias.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Report row has success status, `version='7'`, `mlflow_run_id='retrain-run-id'`,
|
||||
`mlflow_experiment_id='experiment-id'`.
|
||||
- `mlflow.log_artifact` is called with the input CSV.
|
||||
- `promote_to_alias` is called once with the resolved version and alias.
|
||||
|
||||
### 7.2 Failure paths
|
||||
|
||||
#### MR.2.1 Wrapper retrain raises
|
||||
**Summary**: `wrapper.retrain` raises `RuntimeError`. The activity returns
|
||||
`success=False`, `update_production_model` is NOT invoked.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Report row carries the error message and `version`/`mlflow_*` columns are NULL.
|
||||
|
||||
#### MR.2.2 Missing `model_config.target`
|
||||
**Summary**: Empty model config short-circuits before any MLflow call.
|
||||
|
||||
**Expected Outcome**:
|
||||
- Report row carries the explicit guard message.
|
||||
- `get_cached_model` is never invoked.
|
||||
|
||||
#### MR.3.1 No training data
|
||||
**Summary**: The training query returns no rows; the workflow does not
|
||||
persist any report row. The current code raises plain `ValueError` from the
|
||||
workflow function, which Temporal treats as a workflow-task failure (see
|
||||
`CODE_ISSUES.md` issue MR-1).
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 2.2.3: Transform Gate Triggers REPEAT
|
||||
**Description**: Transform response gate determines data should repeat last prediction
|
||||
## Input Contract Reference
|
||||
|
||||
**Input**:
|
||||
- Valid input data
|
||||
- Transform response has quality issues that require using previous prediction
|
||||
- `mlflow_transform_filters` configured with `POLICY: 'REPEAT'`
|
||||
- `path_priority` includes REPEAT
|
||||
Common scenario input fields:
|
||||
- `schedule_name`
|
||||
- `model_name`
|
||||
- `model_id`
|
||||
- `query`
|
||||
- `schema`
|
||||
- `table_name`
|
||||
- `transform_table_name`
|
||||
- `input_filters`
|
||||
- `mlflow_transform_filters`
|
||||
- `mlflow_predict_filters`
|
||||
- `path_priority` (default order: `STOP`, `CONTINUE`, `REPEAT`)
|
||||
- `save_transform`
|
||||
- `prediction_store_policy`
|
||||
- `model_config.target`
|
||||
- `datetime_columns` (when query returns temporal fields)
|
||||
|
||||
**Expected Behavior**:
|
||||
- `request_transform` succeeds but response has issues
|
||||
- `mlflow_response_gate` for transform returns `path_flag='REPEAT'`
|
||||
- `path_flag_handler` calls `repeat_last_prediction` activity
|
||||
- MLFlow predict skipped
|
||||
- Last prediction repeated and exported
|
||||
|
||||
**Assertions**:
|
||||
- Transform completed but validation triggered REPEAT
|
||||
- `mlflow_response_gate` called for transform
|
||||
- MLFlow predict NOT called
|
||||
- `repeat_last_prediction` activity called
|
||||
- Workflow completes
|
||||
|
||||
---
|
||||
|
||||
### 2.3 Predict gate Early Exit Scenarios
|
||||
|
||||
#### Scenario 2.3.1: Predict Gate Triggers CONTINUE
|
||||
**Description**: Predict response gate determines data should continue despite issues
|
||||
|
||||
**Input**:
|
||||
- Valid input and transform data
|
||||
- Predict response has quality issues but policy is CONTINUE
|
||||
- `mlflow_predict_filters` configured with `POLICY: 'CONTINUE'`
|
||||
- `path_priority` includes CONTINUE
|
||||
|
||||
**Expected Behavior**:
|
||||
- `request_predict` succeeds
|
||||
- `mlflow_response_gate` for predict returns `path_flag='CONTINUE'`
|
||||
- `path_flag_handler` calls export workflow with predict data
|
||||
- Prediction exported despite quality issues
|
||||
|
||||
**Assertions**:
|
||||
- Transform and predict completed
|
||||
- `mlflow_response_gate` called for predict
|
||||
- Export workflow called with predict data
|
||||
- Workflow completes
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 2.3.2: Predict Gate Triggers STOP
|
||||
**Description**: Prediction validation fails with STOP policy
|
||||
|
||||
**Input**:
|
||||
- Valid input and transform
|
||||
- Predict response has critical errors
|
||||
- `mlflow_predict_filters` configured with `POLICY: 'STOP'`
|
||||
|
||||
**Expected Behavior**:
|
||||
- `request_predict` succeeds but response invalid
|
||||
- `mlflow_response_gate` for predict returns `path_flag='STOP'`
|
||||
- Workflow exits without export
|
||||
|
||||
**Assertions**:
|
||||
- Transform completed
|
||||
- Predict completed but validation failed
|
||||
- Export workflow NOT called
|
||||
- Workflow completes without error
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 2.3.3: Predict Gate Triggers REPEAT
|
||||
**Description**: Predict response gate determines data should repeat last prediction
|
||||
|
||||
**Input**:
|
||||
- Valid input and transform data
|
||||
- Predict response has quality issues that require using previous prediction
|
||||
- `mlflow_predict_filters` configured with `POLICY: 'REPEAT'`
|
||||
- `path_priority` includes REPEAT
|
||||
|
||||
**Expected Behavior**:
|
||||
- `request_predict` succeeds but response has issues
|
||||
- `mlflow_response_gate` for predict returns `path_flag='REPEAT'`
|
||||
- `path_flag_handler` calls `repeat_last_prediction` activity
|
||||
- Last prediction repeated and exported
|
||||
|
||||
**Assertions**:
|
||||
- Transform and predict completed but validation triggered REPEAT
|
||||
- `mlflow_response_gate` called for predict
|
||||
- `repeat_last_prediction` activity called
|
||||
- Export workflow NOT called with current prediction
|
||||
- Workflow completes
|
||||
|
||||
---
|
||||
|
||||
## 3. Format and Export Prediction - Child Workflow Scenarios
|
||||
|
||||
### 3.1 Success Scenarios
|
||||
|
||||
#### Scenario 3.1.1: Default Prediction Export
|
||||
**Description**: Error prediction path creates default prediction
|
||||
|
||||
**Input**:
|
||||
- `path_flag: 'ERROR'` or other non-None value (not STOP/CONTINUE/REPEAT)
|
||||
- `comment` provided with error details
|
||||
|
||||
**Expected Behavior**:
|
||||
- `format_default_prediction` called instead of `format_prediction`
|
||||
- Default prediction created with error metadata
|
||||
- Exported to PostgreSQL only
|
||||
- Transformed data NOT processed
|
||||
- Metrics written
|
||||
|
||||
**Assertions**:
|
||||
- `format_default_prediction` called
|
||||
- `format_prediction` NOT called
|
||||
- `format_transformed_data` NOT called
|
||||
- One PostgreSQL export only
|
||||
- Default values in prediction data
|
||||
- Comment included
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 3.1.2: Export with OPC only
|
||||
**Description**: Export to PostgreSQL and OPC server only (no PI Web API)
|
||||
|
||||
**Input**:
|
||||
- `path_flag: None`
|
||||
- `opc_output_config` configured with valid OPC settings
|
||||
- `pi_web_api_output_config: None` or `{}`
|
||||
|
||||
**Expected Behavior**:
|
||||
- Normal formatting
|
||||
- PostgreSQL export executed
|
||||
- OPC export executed
|
||||
- PI Web API activity skipped
|
||||
- Metrics written with OPC metrics
|
||||
|
||||
**Assertions**:
|
||||
- PI Web API activity NOT called
|
||||
- OPC activity called
|
||||
- PostgreSQL export called
|
||||
- Metrics written with `opc_metrics` populated
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 3.1.3: Export with PI Web API only
|
||||
**Description**: Export to PostgreSQL and PI Web API only (no OPC)
|
||||
|
||||
**Input**:
|
||||
- `path_flag: None`
|
||||
- `pi_web_api_output_config` configured with valid PI Web API settings
|
||||
- `opc_output_config: None` or `{}`
|
||||
|
||||
**Expected Behavior**:
|
||||
- Normal formatting
|
||||
- PostgreSQL export executed
|
||||
- PI Web API export executed
|
||||
- OPC activity skipped
|
||||
- Metrics written without OPC metrics
|
||||
|
||||
**Assertions**:
|
||||
- OPC activity NOT called
|
||||
- PI Web API activity called
|
||||
- PostgreSQL export called
|
||||
- Metrics written with empty `opc_metrics`
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 3.1.4: Export Without Optional Outputs
|
||||
**Description**: Export only to PostgreSQL (no OPC or PI Web API)
|
||||
|
||||
**Input**:
|
||||
- `path_flag: None`
|
||||
- `opc_output_config: None` or `{}`
|
||||
- `pi_web_api_output_config: None` or `{}`
|
||||
|
||||
**Expected Behavior**:
|
||||
- Normal formatting
|
||||
- Only PostgreSQL export executed
|
||||
- OPC and PI Web API activities skipped
|
||||
- Metrics written without OPC metrics
|
||||
|
||||
**Assertions**:
|
||||
- PI Web API activity NOT called
|
||||
- OPC activity NOT called
|
||||
- PostgreSQL export called
|
||||
- Metrics written with empty `opc_metrics`
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 3.1.5: Export Without Transformed Data
|
||||
**Description**: Only prediction exported, no transform table
|
||||
|
||||
**Input**:
|
||||
- `path_flag: None`
|
||||
- `transformed_data: None` or `save_transform: False`
|
||||
- `opc_output_config: None` or `{}`
|
||||
- `pi_web_api_output_config: None` or `{}`
|
||||
|
||||
**Expected Behavior**:
|
||||
- Only prediction formatted and exported
|
||||
- Transform export skipped
|
||||
- Single PostgreSQL write
|
||||
|
||||
**Assertions**:
|
||||
- `format_transformed_data` NOT called
|
||||
- One PostgreSQL export
|
||||
- Transform table remains empty
|
||||
|
||||
---
|
||||
|
||||
### 3.2 Error Scenarios
|
||||
|
||||
These paths do **not** rely on Temporal activity retries for export failures: the write activities run once, errors are handled inside the activity, and the **workflow completes successfully** with degraded metadata on the persisted prediction (`prediction_confidence` and `comments`).
|
||||
|
||||
#### Scenario 3.2.1: PI Web API Write Error
|
||||
**Description**: PI Web API export fails
|
||||
|
||||
**Input**:
|
||||
- Valid prediction
|
||||
- PI Web API service unavailable or invalid config
|
||||
|
||||
**Expected Behavior**:
|
||||
- `write_pi_web_api_data` surfaces the failure (exception handled in the activity layer)
|
||||
- Notification may be sent
|
||||
- Workflow **completes** (does not fail)
|
||||
- Prediction row is still written to PostgreSQL with error confidence **13** and a comment describing the PI error
|
||||
- Subsequent steps (e.g. OPC, Postgres) still run per workflow order with the updated prediction payload
|
||||
|
||||
**Assertions**:
|
||||
- PI Web API error notification sent (when applicable)
|
||||
- Workflow completes
|
||||
- PostgreSQL contains the prediction with `prediction_confidence` 13 and expected `comments`
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 3.2.2: OPC Write Error
|
||||
**Description**: OPC server write fails
|
||||
|
||||
**Input**:
|
||||
- Valid prediction
|
||||
- OPC server unavailable or invalid configuration
|
||||
|
||||
**Expected Behavior**:
|
||||
- `write_opc_data` reports failure without aborting the workflow
|
||||
- Notification may be sent
|
||||
- Workflow **completes** (does not fail)
|
||||
- Prediction row is written to PostgreSQL with OPC error confidence **12** and a comment indicating OPC write issues
|
||||
|
||||
**Assertions**:
|
||||
- OPC error notification sent (when applicable)
|
||||
- Workflow completes
|
||||
- PostgreSQL contains the prediction with `prediction_confidence` 12 and expected `comments`
|
||||
|
||||
---
|
||||
|
||||
#### Scenario 3.2.3: PI Web API Partial Write Error
|
||||
**Description**: Two prediction tags attempt to be written to PI Web API, but only one succeeds
|
||||
|
||||
**Input**:
|
||||
- Valid prediction
|
||||
- Two prediction tags configured
|
||||
- PI Web API returns partial success (one tag succeeds, one fails)
|
||||
|
||||
**Expected Behavior**:
|
||||
- `write_pi_web_api_data` processes response
|
||||
- `process_pi_web_api_response` detects partial failure
|
||||
- Error confidence set (13)
|
||||
- Notification sent for failed tag
|
||||
- Workflow completes with error confidence (single activity attempt; no retry loop)
|
||||
|
||||
**Assertions**:
|
||||
- One tag written successfully
|
||||
- One tag failed
|
||||
- Error confidence set in prediction
|
||||
- Error notification sent
|
||||
- Workflow completes
|
||||
|
||||
---
|
||||
Optional outputs:
|
||||
- `opc_output_config`
|
||||
- `pi_web_api_output_config`
|
||||
Reference in New Issue
Block a user