Variables
Contents
Variables#
This guide is for implementers configuring CEL variables in OpenSPP.
Variables (spp.cel.variable) define named data points that can be reused across expressions and features. Define them once, use them everywhere.
Why use variables?#
Benefit |
Example |
|---|---|
Reusability |
Define "children under 5" once, use in multiple programs |
Maintainability |
Change threshold in one place |
Readability |
|
Performance |
Cached variables compute once |
Variable anatomy#
Every variable has:
Field |
Purpose |
Example |
|---|---|---|
Name |
Human-readable label |
"Children Under 5 Count" |
CEL Accessor |
How it's referenced in expressions |
|
Applies To |
Context (individual, group, both) |
Group/Household |
Source Type |
Where value comes from |
Aggregate |
Source types#
Constant/parameter#
Fixed value, optionally program-overridable.
Field |
Value |
|---|---|
Source Type |
Constant |
Value |
|
Program Override |
Yes (optional) |
Use for thresholds like poverty lines that may vary by program.
Computed (CEL)#
Calculated from a CEL expression.
Field |
Value |
|---|---|
Source Type |
Computed |
CEL Expression |
|
Aggregate#
Computes over related records (members, enrollments, entitlements, events).
Field |
Value |
|---|---|
Source Type |
Aggregate |
Aggregate Target |
Members |
Aggregate Type |
Count |
Filter |
|
Generates expressions like:
members.count(m, age_years(m.birthdate) < 5)
External source#
Value from external data provider.
Scoring result#
Value from a scoring run (typically cached).
Vocabulary concept#
Derived from vocabulary system.
Aggregate variables#
Aggregates are the most powerful variable type. They compute values across collections.
Aggregate targets#
Target |
Collection |
Loop Variable |
|---|---|---|
Members |
Household members |
|
Enrollments |
Program memberships |
|
Entitlements |
Entitlement records |
|
Events |
Event data records |
|
Aggregate types#
Type |
Result |
Example |
|---|---|---|
Count |
Number of matches |
Children under 5 |
Sum |
Total of values |
Sum of member incomes |
Average |
Mean of values |
Average member age |
Min |
Minimum value |
Youngest member age |
Max |
Maximum value |
Highest member income |
Exists |
Boolean (any match) |
Has disabled member |
Examples#
Count children under 5:
members.count(m, age_years(m.birthdate) < 5)
Female head of household:
members.exists(m, head(m) and m.gender == "female")
Sum member income:
members.sum(m.income, true)
Any enrolled program:
enrollments.exists(e, e.state == "enrolled")
Event variables#
When the event/CEL integration module (spp_cel_event) is installed, you can aggregate over events and use event functions in expressions.
Event functions#
Function |
Purpose |
Example |
|---|---|---|
|
Check existence |
|
|
Count events |
|
|
Sum field values |
|
|
Average field values |
|
|
Minimum field value |
|
|
Maximum field value |
|
|
Get single value |
|
Event function parameters#
Parameter |
Purpose |
Example |
|---|---|---|
|
Recent events only |
|
|
Recent events only |
|
|
Specific period |
|
|
Which event |
|
|
Fallback value |
|
|
Filter by state |
|
Finding event type codes#
Go to Studio → Event Types
Click on your event type
Click View Event Type
Note the Code field (usually
x_evt_<slug>)
Finding field names#
For Studio-created event types:
Open the event type in Studio
Note the Technical Name of each field
Use that name in
event()calls
Variable caching#
For performance, variables can cache computed values.
Cache strategies#
Strategy |
Behavior |
Use Case |
|---|---|---|
None |
Always compute |
Simple/fast variables |
Session |
Cache per request |
Within batch operations |
TTL |
Persist with expiration |
Expensive computations |
Manual |
Persist until refreshed |
External/stable data |
Cache configuration#
Field |
Purpose |
|---|---|
Cache TTL (seconds) |
Expiration time for TTL strategy |
Invalidate on Member Change |
Recompute when members change |
Invalidate on Field Change |
Fields that trigger recompute |
The unified value store#
Cached values are stored in spp.data.value:
Fast SQL lookups during eligibility
Batch precomputation support
Period-based historical values
Period granularity#
Variables can store historical values by period:
Granularity |
Period Key Format |
Example |
|---|---|---|
Current |
None (latest only) |
- |
Daily |
|
|
Monthly |
|
|
Quarterly |
|
|
Yearly |
|
|
Snapshot |
Point-in-time |
At enrollment |
How features use CEL#
Different features use CEL in different ways:
Feature |
CEL Mode |
Profile |
|---|---|---|
Registry search (CEL) |
Compile-to-domain |
|
Program eligibility |
Compile-to-domain |
|
Scoring indicators |
Compile-to-domain |
Registry or scoring |
Entitlement amounts |
Runtime evaluation |
|
GRM routing |
Runtime evaluation |
|
Approval conditions |
Runtime evaluation |
Target record |
Creating a variable: step by step#
2. Basic info#
Field |
Action |
|---|---|
Name |
Enter descriptive name |
CEL Accessor |
Enter identifier (lowercase, underscores) |
Applies To |
Select context |
3. Source configuration#
Choose source type and configure:
For Aggregate:
Field |
Action |
|---|---|
Aggregate Target |
Select collection |
Aggregate Type |
Select operation |
Filter |
Enter predicate |
4. Caching (optional)#
Field |
Action |
|---|---|
Cache Strategy |
Select if needed |
Cache TTL |
Set expiration |
Invalidation |
Configure triggers |
5. Activate#
Click Save to create the variable in Draft state
Click Activate to make it available for use
Note
Variables have three states: Draft (being edited), Active (available for use), and Inactive (disabled but preserved). You can deactivate an active variable or reactivate an inactive one.
Are you stuck?#
Variable not showing in autocomplete?
Verify it's Active
Check Applies To matches your context
Confirm you're using the CEL Accessor name
Aggregate returning wrong count?
Verify filter predicate syntax
Check if relations exclude inactive records
Test with known data
Cache not updating?
Check invalidation triggers
Verify TTL hasn't cached stale value
Try manual refresh
See CEL troubleshooting for more debugging tips.
openspp.org