Reference scenario
The audiobook purchase, progress and completion rules, every edge case and its expected result.
Three rules and one historical counter reproduce the reference scenario the engine, the API and
the CLI are all tested against. Run it yourself with pnpm scenarios --only f2 in the monorepo.
Configuration
orishare api post /counter_definitions --data '{"name":"purchased_content","event":"content.purchased"}'purchase awards 100 on content.purchased, once per content per customer:
{
"schema": "orishare.rule/v1",
"trigger": { "event": "content.purchased" },
"limits": [
{ "id": "per_content", "scope": ["customer", "event.properties.content_id"], "max": 1 }
],
"actions": [{ "type": "points.award", "currency": "points", "amount": 100 }]
}half awards 50 when percent_complete reaches 50, same limit scope:
{
"schema": "orishare.rule/v1",
"trigger": { "event": "content.progressed" },
"conditions": { "path": "event.properties.percent_complete", "op": "gte", "value": 50 },
"limits": [
{ "id": "per_content", "scope": ["customer", "event.properties.content_id"], "max": 1 }
],
"actions": [{ "type": "points.award", "currency": "points", "amount": 50 }]
}complete awards 200 on content.completed, only for customers who purchased before:
{
"schema": "orishare.rule/v1",
"trigger": { "event": "content.completed" },
"conditions": { "path": "customer.counters.purchased_content", "op": "gte", "value": 1 },
"limits": [
{ "id": "per_content", "scope": ["customer", "event.properties.content_id"], "max": 1 }
],
"actions": [{ "type": "points.award", "currency": "points", "amount": 200 }]
}Expected results
| Case | Events | Result |
|---|---|---|
| happy path | purchased, progressed 50, completed | +100, +50, +200; balance 350 |
| duplicate purchase | purchased twice with different event ids | second: limit per_content exhausted, no award |
| 40 → 70 jump | progressed 40, progressed 70 | 40: condition false; 70: +50 once |
| backward progress | progressed 70, progressed 40 | second: condition false; nothing is undone |
| duplicate completion | completed twice | second: limit exhausted |
| consumption without purchase | completed only | condition on purchased_content false; trace names it |
| rule change mid-way | half v2 with 75 published between 40 and 70 | 70 evaluates under v2: +75; execution records v2 |
| late event | completed with occurred_at 40 days ago | accepted, flagged late, awards under the current rules |
| same event id twice | identical id in two requests | second returns the original result, no re-evaluation |
Every row is asserted by scripts/scenarios/run.mjs (F2) against a running API and by the engine's
own fixture suite.