Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Commands and the Graph

The core functional unit of the Aranya Policy Language is the Command. A command defines a set of data and the rules for processing that data in order to add it to the Graph.

Commands

Let’s consider this command:

command AddBalance {
    fields {
        user id,
        amount int,
    }

    policy {
        check amount > 0
        let account = check_unwrap query Account[id: this.user]=>{balance: ?}
        let current_balance = account.balance
        let new_balance = current_balance + this.amount

        finish {
            update Account[id: this.user] to {balance: new_balance}
        }
    }

    ...
}

There are some more required parts here (see the reference), but we’ll omit them for brevity. First, the command has fields, which define the data stored in the command. And next it has policy, which is run both when the command is created in the local graph and when it is synced to other devices’ graphs. It checks the validity of the data, then finally updates the state of the system.

Note the use of the automatically defined name this, which refers to the fields of the command currently under evaluation.

A sequence of these commands will progressively update an account balance. We’ll dive into the details of this state mechanism later in Facts.

The Graph

Each command refers to its ancestor(s) (except for the first), creating a directed acyclic graph we simply call “the graph”. Here is a simple graph with six commands.

graph RL;
A(A); B(B); C(C); D(D); E{{E}}; F(F);
F --> E --> C & D --> B --> A;

A is the root, or the “init” command. B’s parent is A, and both C and D’s parent is B. Command E is a “merge command”, which has both C and D as parents. Merges are automatically created by Aranya after syncing. They rejoin divergent graph segments so that commands can be added linearly afterwards. F’s parent is then the merge commit E.

The Braid

The graph above is a complete view of the system, but a graph with branches introduces ambiguity about how commands affect state. Does C or D evaluate first? To solve this, Aranya creates a total ordering with the “braid function”, which deterministically flattens the graph so that it can evaluate commands linearly.

But how does this ordering happen? Without any more information, the braid function just makes an arbitrary decision1. Let’s say for the sake of demonstration that this decision is “alphabetical order” so C comes first. Then this looks like:

graph RL;
A(A); B(B); C(C); D(D); F(F);
F --> D --> C --> B --> A;

But it could just as easily have ordered them via another metric to get:

graph RL;
A(A); B(B); C(C); D(D); F(F);
F --> C --> D --> B --> A;

The order of commands can be influenced by adding a priority value to the command’s attributes block.

command C {
    attributes {
        priority: 10,
    }
    ...
}

This higher priority would tell the braid function to always order C before B.

We’ll talk a bit more about how this ordering affects state later in Facts.


  1. It actually orders them based on their command ID, which is a hash derived from their serialized contents.