Batch recipe
Evaluate a file of thousands of operations against one ruleset, with any runtime, and write one decision per line.
Evaluate a file of thousands of operations against one ruleset, with any runtime, and write one decision per line. Useful to re-check stored records after a rule change, to screen an import, or to compare what two versions of a ruleset decide.
batch.py (examples/batch/batch.py) needs only the Python standard library. It starts an engine once, loads the
bundle once and streams every request through the JSON Lines engine protocol
(specification section 13). One thread writes
requests while another reads answers, so the engine never waits for the script and memory stays flat.
python examples/batch/batch.py examples/batch/transfers.csv{"line": 1, "id": "t-1", "decision": "allow", "blocking": [], "findings": [], "commands": []}
{"line": 3, "id": "t-3", "decision": "deny", "blocking": ["ORG-TRF-001"], "findings": [{"code": "ORG-TRF-001", "severity": "error", "status": "open", "message": "Transfers to KP are not permitted."}], "commands": []}
...
7 request(s): 3 allowed, 4 denied, 0 refused as malformedAny engine
--engine takes the command line of any engine. The decisions are the same whichever you choose;
the test checks that for every engine that is built.
| Engine | --engine |
|---|---|
| Python (default) | "python -m rule_cascade engine" with packages/python/src on PYTHONPATH |
| Go command | "rule-cascade engine" |
| TypeScript | "node packages/typescript/dist/cli.js engine" |
| Java | "java -cp packages/java/target/classes io.github.yarlisaisolutions.rulecascade.Main engine" |
| WebAssembly | "node packages/go/wasi/run.mjs packages/go/dist/rule-cascade.wasm engine" |
--bundle names the compiled ruleset (default: the payments example's bundle in
conformance/bundles), --channel the manifest (default server) and -o the output file.
Input
.jsonl: one evaluation request per line, as inrequests.jsonl(examples/batch/requests.jsonl):entity,operation,data, and optionallyoriginal,actor,resolutions..csv: one entity per row, as intransfers.csv(examples/batch/transfers.csv). Dotted column names build nested objects (beneficiary.country);actor.idandactor.roles(separated by;) become the actor. Cells that are JSON numbers ortrue/falsebecome numbers and booleans; empty cells are left out.--entityand--operationname the operation (defaultTransfer,create).
Output and exit status
One JSON object per input line, in input order: decision, the codes of the blocking findings,
every finding with its severity, status and message, and the commands with their idempotency keys. A
request the engine refuses as malformed gives {"line": n, "error": "..."} instead.
The exit status is 0 when every request was evaluated, whatever the decisions; 1 when any request was refused as malformed; 2 when the engine could not be started or broke the protocol.
Test
python -m unittest discover -s examples/batch -vThe Python engine always runs. The TypeScript, Go and Java engines run when they are built; set
BATCH_REQUIRE_ENGINES=python,node,go,java to fail rather than skip when one is missing (CI requires
python,node,go).
Spring Boot example
A small payments API that enforces examples/contracts/payments-transfer.ruleset.yaml with the Java runtime.
Engine clients: Rule Cascade from any language
Rule Cascade has native libraries for Python, TypeScript, Java and Go. A program in any other language uses the universal engine: the single-file command rule-cascade, or the same engine as a WebAssembly module.