Current per-account state
Transformations keep totals current from the same writes the scorer reads.
Score every event against state that is current, enrich it with the reference data that was true at the time, and show afterwards what a decision saw.
The problem
Fraud and risk scoring live or die on one property: the state you score against has to be current. A velocity check that reads a rolling total maintained somewhere else, on its own schedule, is not a check. It is a delay before the fraud clears.
Most stacks build in exactly that delay: the write goes to one system, the feature store updates asynchronously, and the scorer reads a stale snapshot. The gap is small in time and large in money.
You want per-account state kept from the same writes you score, events enriched with reference data at processing time, and a way to reproduce the state a decision was based on.
Architecture
Payments land in one table; a transformation keeps per-account totals current and a LOOKUP JOIN stamps each payment with its region’s risk weight as it is processed; every accepted version is kept, so an audit can reread the state at any commit. A committed write is visible to the very next statement on the node.
A payment is in the write-ahead log before the acknowledgement comes back.
Running totals per account are always current, maintained by a grouped CREATE TRANSFORMATION.
Each payment is stamped with the reference data that was true when it was processed, with LOOKUP JOIN; a later change never rewrites history.
Reread the state exactly as the decision saw it, with AS OF COMMIT and the sequence from the write receipt.
Examples
The examples use the same two tables on every page. See the SQL reference for full syntax.
CREATE TRANSFORMATION balance_activity INTO balances ATTRIBUTE GROUP activity ASSELECT chain_id, recipient AS address, token, COUNT(*) AS transfer_count, MAX(transferred_at) AS last_transfer_at, MAX(_index) AS activity_indexFROM transfersGROUP BY chain_id, recipient, token;Capabilities
Transformations keep totals current from the same writes the scorer reads.
Counts, sums, minimums, maximums and averages stay current, maintained by transformations.
Each event carries the reference value that was current when it was processed, with LOOKUP JOIN.
Every accepted version is kept, so you can reread a table exactly as it was at the moment that mattered, with AS OF COMMIT.
Follow the risk table as it changes, with STREAM SELECT.
Point lookups on non-key columns are served by POSTINGS and BLOOM indexes.
Learn more
Run a node, fold payments per account and enrich them with a lookup.