Module 08: Quality Checks in ODSL
In this module you will write quality check scripts in ODSL, upload them to the platform, and attach them to the dataset you configured in Module 07.
What is a Quality Check Script?
A quality check script is an ODSL script stored in the script service. It contains functions that the platform calls when evaluating dataset delivery. Each function has access to two global variables:
| Variable | Description |
|---|---|
#EVENTS | An array of all the events being checked for this delivery |
#LOG | A log object for recording failure details |
#DSID | The dataset ID being checked |
#ONDATE | The delivery date being evaluated |
#DATASET | The dataset information object |
Each function must return one of three strings:
| Return value | Meaning |
|---|---|
"valid" | All checks passed |
"warning" | A potential issue was found — data is flagged but not blocked |
"failed" | A check failed — for critical checks this blocks downstream use |
The platform supports two categories of check script:
| Category | Description |
|---|---|
dataset-quality | Quality checks — return "warning" or "valid" |
dataset-critical | Critical checks — return "failed" or "valid" |
Step 1: Create the Script Files
Create two script files in your local project folder or VS Code ODSL extension workspace. Scripts uploaded to the server must not be wrapped in //#region blocks — add the test code at the bottom of each file inside a //#region for local debugging instead.
File 1: my_gas_hub_quality_checks.odsl
/**
* Quality check functions for MY.GAS.HUB settlement price dataset
* Script: my_gas_hub_quality_checks
* @category dataset-quality
*/
// ============================================================
// Quality Check: Validate settlement price is within range
// ============================================================
function checkSettlementPrice()
checkSettlementPrice = "valid"
#LOG.failures = []
print "Checking " + #EVENTS.size() + " events for settlement price range for dataset: " + #DSID + " for " + #ONDATE
if #EVENTS.size() == 0
log warn "No events to check"
checkSettlementPrice = "warning"
return
end
for evt in #EVENTS
price = evt.price
if price == null
checkSettlementPrice = "warning"
#LOG.failures.add("Missing price on event " + evt.id)
elseif price < 0.5
checkSettlementPrice = "warning"
#LOG.failures.add("Price " + price + " below minimum threshold of 0.5 for event " + evt.id)
elseif price > 5
checkSettlementPrice = "warning"
#LOG.failures.add("Price " + price + " exceeds maximum threshold of 5 for event " + evt.id)
end
next
end
// ============================================================
// Quality Check: Detect suspicious day-on-day price change
// ============================================================
function checkPriceMovement()
checkPriceMovement = "valid"
#LOG.failures = []
print "Checking " + #EVENTS.size() + " events for price movement for dataset: " + #DSID + " for " + #ONDATE
if #EVENTS.size() == 0
log warn "No events to check"
checkPriceMovement = "warning"
return
end
for evt in #EVENTS
price = evt.price
prevPrice = evt.prevPrice
if price == null or prevPrice == null
// Cannot check movement without both values — skip
checkPriceMovement = "warning"
#LOG.failures.add("Insufficient data for movement check on event " + evt.id)
elseif prevPrice != 0
change = abs((price - prevPrice) / prevPrice) * 100
if change > 20
checkPriceMovement = "warning"
#LOG.failures.add("Price moved " + formatNumber(change, "0.00") + "% vs previous day for event " + evt.id)
end
end
next
end
//#region Test checkSettlementPrice
use training
#EVENTS = ${event:"MY.GAS.HUB:SETTLEMENTS"}
#DSID = "TRAINING.MYGASHUB.SETTLEMENTS"
#ONDATE = "2025-03-03"
#LOG = Object()
result = checkSettlementPrice()
print "Settlement price check: " + result
if #LOG.failures != null
print #LOG.failures
end
//#endregion
//#region Test checkPriceMovement
use training
#EVENTS = ${event:"MY.GAS.HUB:SETTLEMENTS"}
#DSID = "TRAINING.MYGASHUB.SETTLEMENTS"
#ONDATE = "2025-03-03"
#LOG = Object()
result = checkPriceMovement()
print "Price movement check: " + result
if #LOG.failures != null
print #LOG.failures
end
//#endregion
File 2: my_gas_hub_critical_checks.odsl
Critical checks must be in a separate file with the dataset-critical category.
/**
* Critical check functions for MY.GAS.HUB settlement price dataset
* Script: my_gas_hub_critical_checks
* @category dataset-critical
*/
// ============================================================
// Critical Check: Confirm events are present for the date
// ============================================================
function criticalPriceCheck()
criticalPriceCheck = "valid"
#LOG.failures = []
print "Checking " + #EVENTS.size() + " events for critical price check for dataset: " + #DSID + " for " + #ONDATE
if #EVENTS.size() == 0
criticalPriceCheck = "failed"
#LOG.failures.add("No settlement events found for " + #ONDATE + " — downstream processes blocked")
return
end
for evt in #EVENTS
if evt.price == null
criticalPriceCheck = "failed"
#LOG.failures.add("Missing price on event " + evt.id + " — downstream processes blocked")
end
next
end
//#region Test criticalPriceCheck
use training
#EVENTS = ${event:"MY.GAS.HUB:SETTLEMENTS"}
#DSID = "TRAINING.MYGASHUB.SETTLEMENTS"
#ONDATE = "2025-03-03"
#LOG = Object()
result = criticalPriceCheck()
print "Critical price check: " + result
if #LOG.failures != null
print #LOG.failures
end
//#endregion
Step 2: Upload the Scripts to the Platform
Because we are working in the training environment, scripts must be uploaded using an ODSL script rather than the VS Code right-click upload, so that the training environment is correctly targeted.
Create a third file called upload_scripts.odsl and run it using Debug Region:
//#region
use training
s1 = ${script:file/"/src/odsl-demo/Training/my_gas_hub_quality_checks.odsl"}
s1._id = "my_gas_hub_quality_checks"
save s1
s2 = ${script:file/"/src/odsl-demo/Training/my_gas_hub_critical_checks.odsl"}
s2._id = "my_gas_hub_critical_checks"
save s2
//#endregion
Update the file paths to match the location of your script files within your project. The _id values set here are what will be used to reference the scripts everywhere else.
Verify the Upload
//#region
use training
// Confirm both scripts are available
qs = find ${script} where _id = "my_gas_hub_quality_checks"
print qs
cs = find ${script} where _id = "my_gas_hub_critical_checks"
print cs
//#endregion
Step 3: Test the Functions Locally
The test regions at the bottom of each script file let you debug directly without needing to trigger a full dataset run. In VS Code, right-click anywhere inside a //#region block and select Debug Region to run just that section.
The test code sets up the global variables (#EVENTS, #DSID, #ONDATE, #LOG) to simulate what the platform would pass at runtime, then calls the function and prints the result.
To test a failing check, temporarily modify a settlement event to have an out-of-range or missing price, then re-run the test region. Confirm the function returns "warning" or "failed" with the expected failure message logged, then restore the correct value.
Step 4: Attach the Scripts to the Dataset
Option A: Using the Portal
Once both scripts are uploaded, open the dataset in the portal and attach the checks via the dropdown selectors:
- Open the Dataset Monitoring dashboard, hover over
TRAINING.MYGASHUB.SETTLEMENTSand select Edit to open the side panel - In the Quality Checks section, add two checks:
- Script:
my_gas_hub_quality_checks/ Function:checkSettlementPrice - Script:
my_gas_hub_quality_checks/ Function:checkPriceMovement
- Script:
- In the Critical Checks section, add:
- Script:
my_gas_hub_critical_checks/ Function:criticalPriceCheck
- Script:
- Click Save
Option B: Using ODSL Code
//#region
use training
// Fetch the dataset configuration
ds = ${dataset:"TRAINING.MYGASHUB.SETTLEMENTS"}
// Add quality checks
qualityCheck1 = SimpleObject()
qualityCheck1.type = "function"
qualityCheck1.script = "my_gas_hub_quality_checks"
qualityCheck1.name = "Check settlement price"
qualityCheck1.expression = "checkSettlementPrice()"
qualityCheck2 = SimpleObject()
qualityCheck2.type = "function"
qualityCheck2.script = "my_gas_hub_quality_checks"
qualityCheck2.name = "Check price movement"
qualityCheck2.expression = "checkPriceMovement()"
// Add critical checks
criticalCheck1 = SimpleObject()
criticalCheck1.type = "function"
criticalCheck1.script = "my_gas_hub_critical_checks"
criticalCheck1.name = "Critical price check"
criticalCheck1.expression = "criticalPriceCheck()"
ds.checks = [qualityCheck1, qualityCheck2]
ds.criticalChecks = [criticalCheck1]
// Save the updated dataset
save ${dataset:ds}
print "Quality checks attached to dataset"
//#endregion
Step 5: Trigger and Review Checks in the Portal
- Open the Dataset Monitoring dashboard and select
TRAINING.MYGASHUB.SETTLEMENTS - Select a date for which you have settlement data
- Use the dataset actions to run the quality checks again
- The General tab will show the result of each check, and the Quality Status icon will show the overall result: unchecked, valid, warning, failed or severe
Step 6: Query Dataset Status in a Script
//#region
use training
// Check if the dataset is complete for today
today = format(Date(), "yyyy-MM-dd")
isComplete = isDatasetComplete("TRAINING.MYGASHUB.SETTLEMENTS", today)
if isComplete
print "Dataset is complete for " + today
else
// Get detailed delivery info
delivery = getDatasetDelivery("TRAINING.MYGASHUB.SETTLEMENTS", today)
print "Dataset not complete. Details:"
print delivery
end
//#endregion
Summary
You have now completed the full training path:
| Module | What You Did |
|---|---|
| 01 | Understood the core platform concepts |
| 02 | Created and updated events using ODSL |
| 03 | Created and updated events using Excel |
| 04 | Built EventTimeSeries from event data |
| 05 | Created SmartTimeSeries for currency and unit conversion |
| 06 | Built forward curves from events and Smart Curve expressions |
| 07 | Configured dataset monitoring in the portal |
| 08 | Wrote quality check functions and attached them to the dataset |
Next Steps
In Module 09 you will raise alerts for late or missing deliveries and quality check violations, and be notified when they happen.
You can ask the Fusion AI assistant in the portal for help writing ODSL scripts, explaining platform concepts, or diagnosing quality check failures.